]> arthur.barton.de Git - netatalk.git/blob - etc/afpd/desktop.c
Big configure.in cleanup
[netatalk.git] / etc / afpd / desktop.c
1 /*
2  * See COPYRIGHT.
3  *
4  * bug:
5  * afp_XXXcomment are (the only) functions able to open
6  * a ressource fork when there's no data fork, eg after
7  * it was removed with samba.
8  */
9
10 #ifdef HAVE_CONFIG_H
11 #include "config.h"
12 #endif /* HAVE_CONFIG_H */
13
14 #include <stdio.h>
15 #include <string.h>
16 #include <ctype.h>
17
18 #include <errno.h>
19
20 #include <atalk/adouble.h>
21 #include <sys/uio.h>
22 #include <sys/param.h>
23 #include <sys/socket.h>
24 #include <netatalk/at.h>
25 #include <netatalk/endian.h>
26 #include <atalk/dsi.h>
27 #include <atalk/atp.h>
28 #include <atalk/asp.h>
29 #include <atalk/afp.h>
30 #include <atalk/util.h>
31 #include <atalk/logger.h>
32 #include "volume.h"
33 #include "directory.h"
34 #include "fork.h"
35 #include "globals.h"
36 #include "desktop.h"
37 #include "mangle.h"
38
39
40 int afp_opendt(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
41 {
42     struct vol  *vol;
43     u_int16_t   vid;
44
45     ibuf += 2;
46
47     memcpy( &vid, ibuf, sizeof(vid));
48     if (NULL == ( vol = getvolbyvid( vid )) ) {
49         *rbuflen = 0;
50         return( AFPERR_PARAM );
51     }
52
53     memcpy( rbuf, &vid, sizeof(vid));
54     *rbuflen = sizeof(vid);
55     return( AFP_OK );
56 }
57
58 int afp_closedt(AFPObj *obj _U_, char *ibuf _U_, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
59 {
60     *rbuflen = 0;
61     return( AFP_OK );
62 }
63
64 static struct savedt    si = { { 0, 0, 0, 0 }, -1, 0, 0 };
65
66 static char *icon_dtfile(struct vol *vol, u_char creator[ 4 ])
67 {
68     return dtfile( vol, creator, ".icon" );
69 }
70
71 static int iconopen(struct vol *vol, u_char creator[ 4 ], int flags, int mode)
72 {
73     char        *dtf, *adt, *adts;
74
75     if ( si.sdt_fd != -1 ) {
76         if ( memcmp( si.sdt_creator, creator, sizeof( CreatorType )) == 0 &&
77                 si.sdt_vid == vol->v_vid ) {
78             return 0;
79         }
80         close( si.sdt_fd );
81         si.sdt_fd = -1;
82     }
83
84     dtf = icon_dtfile( vol, creator);
85
86     if (( si.sdt_fd = open( dtf, flags, ad_mode( dtf, mode ))) < 0 ) {
87         if ( errno == ENOENT && ( flags & O_CREAT )) {
88             if (( adts = strrchr( dtf, '/' )) == NULL ) {
89                 return -1;
90             }
91             *adts = '\0';
92             if (( adt = strrchr( dtf, '/' )) == NULL ) {
93                 return -1;
94             }
95             *adt = '\0';
96             (void) ad_mkdir( dtf, DIRBITS | 0777 );
97             *adt = '/';
98             (void) ad_mkdir( dtf, DIRBITS | 0777 );
99             *adts = '/';
100
101             if (( si.sdt_fd = open( dtf, flags, ad_mode( dtf, mode ))) < 0 ) {
102                 LOG(log_error, logtype_afpd, "iconopen(%s): open: %s", dtf, strerror(errno) );
103                 return -1;
104             }
105         } else {
106             return -1;
107         }
108     }
109
110     memcpy( si.sdt_creator, creator, sizeof( CreatorType ));
111     si.sdt_vid = vol->v_vid;
112     si.sdt_index = 1;
113     return 0;
114 }
115
116 int afp_addicon(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
117 {
118     struct vol          *vol;
119 #ifndef NO_DDP
120     struct iovec        iov[ 2 ];
121 #endif
122     u_char              fcreator[ 4 ], imh[ 12 ], irh[ 12 ], *p;
123     int                 itype, cc = AFP_OK, iovcnt = 0;
124     size_t              buflen;
125     u_int32_t           ftype, itag;
126     u_int16_t           bsize, rsize, vid;
127
128     buflen = *rbuflen;
129     *rbuflen = 0;
130     ibuf += 2;
131
132     memcpy( &vid, ibuf, sizeof( vid ));
133     ibuf += sizeof( vid );
134     if (NULL == ( vol = getvolbyvid( vid )) ) {
135         cc = AFPERR_PARAM;
136         goto addicon_err;
137     }
138
139     memcpy( fcreator, ibuf, sizeof( fcreator ));
140     ibuf += sizeof( fcreator );
141
142     memcpy( &ftype, ibuf, sizeof( ftype ));
143     ibuf += sizeof( ftype );
144
145     itype = (unsigned char) *ibuf;
146     ibuf += 2;
147
148     memcpy( &itag, ibuf, sizeof( itag ));
149     ibuf += sizeof( itag );
150
151     memcpy( &bsize, ibuf, sizeof( bsize ));
152     bsize = ntohs( bsize );
153
154     if ( si.sdt_fd != -1 ) {
155         (void)close( si.sdt_fd );
156         si.sdt_fd = -1;
157     }
158
159     if (iconopen( vol, fcreator, O_RDWR|O_CREAT, 0666 ) < 0) {
160         cc = AFPERR_NOITEM;
161         goto addicon_err;
162     }
163
164     if (lseek( si.sdt_fd, (off_t) 0L, SEEK_SET ) < 0) {
165         close(si.sdt_fd);
166         si.sdt_fd = -1;
167         LOG(log_error, logtype_afpd, "afp_addicon(%s): lseek: %s", icon_dtfile(vol, fcreator), strerror(errno) );
168         cc = AFPERR_PARAM;
169         goto addicon_err;
170     }
171
172     /*
173      * Read icon elements until we find a match to replace, or
174      * we get to the end to insert.
175      */
176     p = imh;
177     memcpy( p, &itag, sizeof( itag ));
178     p += sizeof( itag );
179     memcpy( p, &ftype, sizeof( ftype ));
180     p += sizeof( ftype );
181     *p++ = itype;
182     *p++ = 0;
183     bsize = htons( bsize );
184     memcpy( p, &bsize, sizeof( bsize ));
185     bsize = ntohs( bsize );
186     while (( cc = read( si.sdt_fd, irh, sizeof( irh ))) > 0 ) {
187         memcpy( &rsize, irh + 10, sizeof( rsize ));
188         rsize = ntohs( rsize );
189         /*
190          * Is this our set of headers?
191          */
192         if ( memcmp( irh, imh, sizeof( irh ) - sizeof( u_short )) == 0 ) {
193             /*
194              * Is the size correct?
195              */
196             if ( bsize != rsize )
197                 cc = AFPERR_ITYPE;
198             break;
199         }
200
201         if ( lseek( si.sdt_fd, (off_t) rsize, SEEK_CUR ) < 0 ) {
202             LOG(log_error, logtype_afpd, "afp_addicon(%s): lseek: %s", icon_dtfile(vol, fcreator),strerror(errno) );
203             cc = AFPERR_PARAM;
204         }
205     }
206
207     /*
208      * Some error occurred, return.
209      */
210 addicon_err:
211     if ( cc < 0 ) {
212         if (obj->proto == AFPPROTO_DSI) {
213             dsi_writeinit(obj->handle, rbuf, buflen);
214             dsi_writeflush(obj->handle);
215         }
216         return cc;
217     }
218
219     switch (obj->proto) {
220 #ifndef NO_DDP
221     case AFPPROTO_ASP:
222         buflen = bsize;
223         if ((asp_wrtcont(obj->handle, rbuf, &buflen) < 0) || buflen != bsize)
224             return( AFPERR_PARAM );
225
226         /*
227          * We're at the end of the file, add the headers, etc.  */
228         if ( cc == 0 ) {
229             iov[ 0 ].iov_base = (caddr_t)imh;
230             iov[ 0 ].iov_len = sizeof( imh );
231             iov[ 1 ].iov_base = rbuf;
232             iov[ 1 ].iov_len = bsize;
233             iovcnt = 2;
234         }
235
236         /*
237          * We found an icon to replace.
238          */
239         if ( cc > 0 ) {
240             iov[ 0 ].iov_base = rbuf;
241             iov[ 0 ].iov_len = bsize;
242             iovcnt = 1;
243         }
244
245         if ( writev( si.sdt_fd, iov, iovcnt ) < 0 ) {
246             LOG(log_error, logtype_afpd, "afp_addicon(%s): writev: %s", icon_dtfile(vol, fcreator), strerror(errno) );
247             return( AFPERR_PARAM );
248         }
249         break;
250 #endif /* no afp/asp */      
251     case AFPPROTO_DSI:
252         {
253             DSI *dsi = obj->handle;
254
255             iovcnt = dsi_writeinit(dsi, rbuf, buflen);
256
257             /* add headers at end of file */
258             if ((cc == 0) && (write(si.sdt_fd, imh, sizeof(imh)) < 0)) {
259                 LOG(log_error, logtype_afpd, "afp_addicon(%s): write: %s", icon_dtfile(vol, fcreator), strerror(errno));
260                 dsi_writeflush(dsi);
261                 return AFPERR_PARAM;
262             }
263
264             if ((cc = write(si.sdt_fd, rbuf, iovcnt)) < 0) {
265                 LOG(log_error, logtype_afpd, "afp_addicon(%s): write: %s", icon_dtfile(vol, fcreator), strerror(errno));
266                 dsi_writeflush(dsi);
267                 return AFPERR_PARAM;
268             }
269
270             while ((iovcnt = dsi_write(dsi, rbuf, buflen))) {
271                 if ((cc = write(si.sdt_fd, rbuf, iovcnt)) < 0) {
272                     LOG(log_error, logtype_afpd, "afp_addicon(%s): write: %s", icon_dtfile(vol, fcreator), strerror(errno));
273                     dsi_writeflush(dsi);
274                     return AFPERR_PARAM;
275                 }
276             }
277         }
278         break;
279     }
280
281     close( si.sdt_fd );
282     si.sdt_fd = -1;
283     return( AFP_OK );
284 }
285
286 static const u_char     utag[] = { 0, 0, 0, 0 };
287 static const u_char     ucreator[] = { 0, 0, 0, 0 };/* { 'U', 'N', 'I', 'X' };*/
288 static const u_char     utype[] = { 0, 0, 0, 0 };/* { 'T', 'E', 'X', 'T' };*/
289 static const short      usize = 256;
290
291 #if 0
292 static const u_char     uicon[] = {
293     0x1F, 0xFF, 0xFC, 0x00, 0x10, 0x00, 0x06, 0x00,
294     0x10, 0x00, 0x05, 0x00, 0x10, 0x00, 0x04, 0x80,
295     0x10, 0x00, 0x04, 0x40, 0x10, 0x00, 0x04, 0x20,
296     0x10, 0x00, 0x07, 0xF0, 0x10, 0x00, 0x00, 0x10,
297     0x10, 0x00, 0x00, 0x10, 0x10, 0x00, 0x00, 0x10,
298     0x10, 0x00, 0x00, 0x10, 0x10, 0x80, 0x02, 0x10,
299     0x11, 0x80, 0x03, 0x10, 0x12, 0x80, 0x02, 0x90,
300     0x12, 0x80, 0x02, 0x90, 0x14, 0x80, 0x02, 0x50,
301     0x14, 0x87, 0xC2, 0x50, 0x14, 0x58, 0x34, 0x50,
302     0x14, 0x20, 0x08, 0x50, 0x12, 0x16, 0xD0, 0x90,
303     0x11, 0x01, 0x01, 0x10, 0x12, 0x80, 0x02, 0x90,
304     0x12, 0x9C, 0x72, 0x90, 0x14, 0x22, 0x88, 0x50,
305     0x14, 0x41, 0x04, 0x50, 0x14, 0x49, 0x24, 0x50,
306     0x14, 0x55, 0x54, 0x50, 0x14, 0x5D, 0x74, 0x50,
307     0x14, 0x5D, 0x74, 0x50, 0x12, 0x49, 0x24, 0x90,
308     0x12, 0x22, 0x88, 0x90, 0x1F, 0xFF, 0xFF, 0xF0,
309     0x1F, 0xFF, 0xFC, 0x00, 0x1F, 0xFF, 0xFE, 0x00,
310     0x1F, 0xFF, 0xFF, 0x00, 0x1F, 0xFF, 0xFF, 0x80,
311     0x1F, 0xFF, 0xFF, 0xC0, 0x1F, 0xFF, 0xFF, 0xE0,
312     0x1F, 0xFF, 0xFF, 0xF0, 0x1F, 0xFF, 0xFF, 0xF0,
313     0x1F, 0xFF, 0xFF, 0xF0, 0x1F, 0xFF, 0xFF, 0xF0,
314     0x1F, 0xFF, 0xFF, 0xF0, 0x1F, 0xFF, 0xFF, 0xF0,
315     0x1F, 0xFF, 0xFF, 0xF0, 0x1F, 0xFF, 0xFF, 0xF0,
316     0x1F, 0xFF, 0xFF, 0xF0, 0x1F, 0xFF, 0xFF, 0xF0,
317     0x1F, 0xFF, 0xFF, 0xF0, 0x1F, 0xFF, 0xFF, 0xF0,
318     0x1F, 0xFF, 0xFF, 0xF0, 0x1F, 0xFF, 0xFF, 0xF0,
319     0x1F, 0xFF, 0xFF, 0xF0, 0x1F, 0xFF, 0xFF, 0xF0,
320     0x1F, 0xFF, 0xFF, 0xF0, 0x1F, 0xFF, 0xFF, 0xF0,
321     0x1F, 0xFF, 0xFF, 0xF0, 0x1F, 0xFF, 0xFF, 0xF0,
322     0x1F, 0xFF, 0xFF, 0xF0, 0x1F, 0xFF, 0xFF, 0xF0,
323     0x1F, 0xFF, 0xFF, 0xF0, 0x1F, 0xFF, 0xFF, 0xF0,
324     0x1F, 0xFF, 0xFF, 0xF0, 0x1F, 0xFF, 0xFF, 0xF0,
325 };
326 #endif
327
328 int afp_geticoninfo(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
329 {
330     struct vol  *vol;
331     u_char      fcreator[ 4 ], ih[ 12 ];
332     u_int16_t   vid, iindex, bsize;
333
334     *rbuflen = 0;
335     ibuf += 2;
336
337     memcpy( &vid, ibuf, sizeof( vid ));
338     ibuf += sizeof( vid );
339     if (NULL == ( vol = getvolbyvid( vid )) ) {
340         return( AFPERR_PARAM );
341     }
342
343     memcpy( fcreator, ibuf, sizeof( fcreator ));
344     ibuf += sizeof( fcreator );
345     memcpy( &iindex, ibuf, sizeof( iindex ));
346     iindex = ntohs( iindex );
347
348     if ( memcmp( fcreator, ucreator, sizeof( ucreator )) == 0 ) {
349         if ( iindex > 1 ) {
350             return( AFPERR_NOITEM );
351         }
352         memcpy( ih, utag, sizeof( utag ));
353         memcpy( ih + sizeof( utag ), utype, sizeof( utype ));
354         *( ih + sizeof( utag ) + sizeof( utype )) = 1;
355         *( ih + sizeof( utag ) + sizeof( utype ) + 1 ) = 0;
356         memcpy( ih + sizeof( utag ) + sizeof( utype ) + 2, &usize,
357                 sizeof( usize ));
358         memcpy( rbuf, ih, sizeof( ih ));
359         *rbuflen = sizeof( ih );
360         return( AFP_OK );
361     }
362
363     if ( iconopen( vol, fcreator, O_RDONLY, 0 ) < 0) {
364         return( AFPERR_NOITEM );
365     }
366
367     if ( iindex < si.sdt_index ) {
368         if ( lseek( si.sdt_fd, (off_t) 0L, SEEK_SET ) < 0 ) {
369             return( AFPERR_PARAM );
370         }
371         si.sdt_index = 1;
372     }
373
374     /*
375      * Position to the correct spot.
376      */
377     for (;;) {
378         if ( read( si.sdt_fd, ih, sizeof( ih )) != sizeof( ih )) {
379             close( si.sdt_fd );
380             si.sdt_fd = -1;
381             return( AFPERR_NOITEM );
382         }
383         memcpy( &bsize, ih + 10, sizeof( bsize ));
384         bsize = ntohs(bsize);
385         if ( lseek( si.sdt_fd, (off_t) bsize, SEEK_CUR ) < 0 ) {
386             LOG(log_error, logtype_afpd, "afp_iconinfo(%s): lseek: %s", icon_dtfile(vol, fcreator), strerror(errno) );
387             return( AFPERR_PARAM );
388         }
389         if ( si.sdt_index == iindex ) {
390             memcpy( rbuf, ih, sizeof( ih ));
391             *rbuflen = sizeof( ih );
392             return( AFP_OK );
393         }
394         si.sdt_index++;
395     }
396 }
397
398
399 int afp_geticon(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
400 {
401     struct vol  *vol;
402     off_t       offset;
403     ssize_t     rc, buflen;
404     u_char      fcreator[ 4 ], ftype[ 4 ], itype, ih[ 12 ];
405     u_int16_t   vid, bsize, rsize;
406
407     buflen = *rbuflen;
408     *rbuflen = 0;
409     ibuf += 2;
410
411     memcpy( &vid, ibuf, sizeof( vid ));
412     ibuf += sizeof( vid );
413     if (NULL == ( vol = getvolbyvid( vid )) ) {
414         return( AFPERR_PARAM );
415     }
416
417     memcpy( fcreator, ibuf, sizeof( fcreator ));
418     ibuf += sizeof( fcreator );
419     memcpy( ftype, ibuf, sizeof( ftype ));
420     ibuf += sizeof( ftype );
421     itype = (unsigned char) *ibuf++;
422     ibuf++;
423     memcpy( &bsize, ibuf, sizeof( bsize ));
424     bsize = ntohs( bsize );
425
426 #if 0
427     if ( memcmp( fcreator, ucreator, sizeof( ucreator )) == 0 &&
428             memcmp( ftype, utype, sizeof( utype )) == 0 &&
429             itype == 1 &&
430             bsize <= usize ) {
431         memcpy( rbuf, uicon, bsize);
432         *rbuflen = bsize;
433         return( AFP_OK );
434     }
435 #endif
436
437     if ( iconopen( vol, fcreator, O_RDONLY, 0 ) < 0) {
438         return( AFPERR_NOITEM );
439     }
440
441     if ( lseek( si.sdt_fd, (off_t) 0L, SEEK_SET ) < 0 ) {
442         close(si.sdt_fd);
443         si.sdt_fd = -1;
444         LOG(log_error, logtype_afpd, "afp_geticon(%s): lseek: %s", icon_dtfile(vol, fcreator), strerror(errno));
445         return( AFPERR_PARAM );
446     }
447
448     si.sdt_index = 1;
449     offset = 0;
450     while (( rc = read( si.sdt_fd, ih, sizeof( ih ))) > 0 ) {
451         si.sdt_index++;
452         offset += sizeof(ih);
453         if ( memcmp( ih + sizeof( int ), ftype, sizeof( ftype )) == 0 &&
454                 *(ih + sizeof( int ) + sizeof( ftype )) == itype ) {
455             break;
456         }
457         memcpy( &rsize, ih + 10, sizeof( rsize ));
458         rsize = ntohs( rsize );
459         if ( lseek( si.sdt_fd, (off_t) rsize, SEEK_CUR ) < 0 ) {
460             LOG(log_error, logtype_afpd, "afp_geticon(%s): lseek: %s", icon_dtfile(vol, fcreator), strerror(errno) );
461             return( AFPERR_PARAM );
462         }
463         offset += rsize;
464     }
465
466     if ( rc < 0 ) {
467         LOG(log_error, logtype_afpd, "afp_geticon(%s): read: %s", icon_dtfile(vol, fcreator), strerror(errno));
468         return( AFPERR_PARAM );
469     }
470
471     if ( rc == 0 ) {
472         return( AFPERR_NOITEM );
473     }
474
475     memcpy( &rsize, ih + 10, sizeof( rsize ));
476     rsize = ntohs( rsize );
477 #define min(a,b)        ((a)<(b)?(a):(b))
478     rc = min( bsize, rsize );
479
480     if ((obj->proto == AFPPROTO_DSI) && (buflen < rc)) {
481         DSI *dsi = obj->handle;
482         struct stat st;
483         off_t size;
484
485         size = (fstat(si.sdt_fd, &st) < 0) ? 0 : st.st_size;
486         if (size < rc + offset) {
487             return AFPERR_PARAM;
488         }
489
490         if ((buflen = dsi_readinit(dsi, rbuf, buflen, rc, AFP_OK)) < 0)
491             goto geticon_exit;
492
493         *rbuflen = buflen;
494         /* do to the streaming nature, we have to exit if we encounter
495          * a problem. much confusion results otherwise. */
496         while (*rbuflen > 0) {
497 #ifdef WITH_SENDFILE
498             if (!obj->options.flags & OPTION_DEBUG) {
499                 if (dsi_stream_read_file(dsi, si.sdt_fd, offset, dsi->datasize) < 0) {
500                     switch (errno) {
501                     case ENOSYS:
502                     case EINVAL:  /* there's no guarantee that all fs support sendfile */
503                         break;
504                     default:
505                         goto geticon_exit;
506                     }
507                 }
508                 else {
509                     dsi_readdone(dsi);
510                     return AFP_OK;
511                 }
512             }
513 #endif
514             buflen = read(si.sdt_fd, rbuf, *rbuflen);
515             if (buflen < 0)
516                 goto geticon_exit;
517
518             /* dsi_read() also returns buffer size of next allocation */
519             buflen = dsi_read(dsi, rbuf, buflen); /* send it off */
520             if (buflen < 0)
521                 goto geticon_exit;
522
523             *rbuflen = buflen;
524         }
525         
526         dsi_readdone(dsi);
527         return AFP_OK;
528
529 geticon_exit:
530         LOG(log_error, logtype_afpd, "afp_geticon(%s): %s", icon_dtfile(vol, fcreator), strerror(errno));
531         dsi_readdone(dsi);
532         obj->exit(EXITERR_SYS);
533         return AFP_OK;
534
535     } else {
536         if ( read( si.sdt_fd, rbuf, rc ) < rc ) {
537             return( AFPERR_PARAM );
538         }
539         *rbuflen = rc;
540     }
541     return AFP_OK;
542 }
543
544 /* ---------------------- */
545 static const char               hexdig[] = "0123456789abcdef";
546 char *dtfile(const struct vol *vol, u_char creator[], char *ext )
547 {
548     static char path[ MAXPATHLEN + 1];
549     char        *p;
550     unsigned int i;
551
552     strcpy( path, vol->v_path );
553     strcat( path, "/.AppleDesktop/" );
554     for ( p = path; *p != '\0'; p++ )
555         ;
556
557     if ( !isprint( creator[ 0 ] ) || creator[ 0 ] == '/' ) {
558         *p++ = hexdig[ ( creator[ 0 ] & 0xf0 ) >> 4 ];
559         *p++ = hexdig[ creator[ 0 ] & 0x0f ];
560     } else {
561         *p++ = creator[ 0 ];
562     }
563
564     *p++ = '/';
565
566     for ( i = 0; i < sizeof( CreatorType ); i++ ) {
567         if ( !isprint( creator[ i ] ) || creator[ i ] == '/' ) {
568             *p++ = hexdig[ ( creator[ i ] & 0xf0 ) >> 4 ];
569             *p++ = hexdig[ creator[ i ] & 0x0f ];
570         } else {
571             *p++ = creator[ i ];
572         }
573     }
574     *p = '\0';
575     strcat( path, ext );
576
577     return( path );
578 }
579
580 /* ---------------------------
581  * mpath is only a filename 
582  * did filename parent directory ID.
583 */
584
585 char *mtoupath(const struct vol *vol, char *mpath, cnid_t did, int utf8)
586 {
587     static char  upath[ MAXPATHLEN + 2]; /* for convert_charset dest_len parameter +2 */
588     char        *m, *u;
589     size_t       inplen;
590     size_t       outlen;
591     u_int16_t    flags;
592         
593     if ( *mpath == '\0' ) {
594         strcpy(upath, ".");
595         return upath;
596     }
597
598     /* set conversion flags */
599     flags = vol->v_mtou_flags;
600     
601     m = demangle(vol, mpath, did);
602     if (m != mpath) {
603         return m;
604     }
605
606     m = mpath;
607     u = upath;
608
609     inplen = strlen(m);
610     outlen = MAXPATHLEN;
611
612     if ((size_t)-1 == (outlen = convert_charset ( (utf8)?CH_UTF8_MAC:vol->v_maccharset, vol->v_volcharset, vol->v_maccharset, m, inplen, u, outlen, &flags)) ) {
613         LOG(log_error, logtype_afpd, "conversion from %s to %s for %s failed.", (utf8)?"UTF8-MAC":vol->v_maccodepage, vol->v_volcodepage, mpath);
614             return NULL;
615     }
616
617 #ifdef DEBUG
618     LOG(log_debug9, logtype_afpd, "mtoupath: '%s':'%s'", mpath, upath);
619 #endif /* DEBUG */
620     return( upath );
621 }
622
623 /* --------------- 
624  * id filename ID
625 */
626 char *utompath(const struct vol *vol, char *upath, cnid_t id, int utf8)
627 {
628     static char  mpath[ MAXPATHLEN + 2]; /* for convert_charset dest_len parameter +2 */
629     char        *m, *u;
630     u_int16_t    flags;
631     size_t       outlen;
632
633     m = mpath;
634     outlen = strlen(upath);
635
636     flags = vol->v_utom_flags;
637
638     u = upath;
639
640     /* convert charsets */
641     if ((size_t)-1 == ( outlen = convert_charset ( vol->v_volcharset, (utf8)?CH_UTF8_MAC:vol->v_maccharset, vol->v_maccharset, u, outlen, mpath, MAXPATHLEN, &flags)) ) { 
642         LOG(log_error, logtype_afpd, "Conversion from %s to %s for %s (%u) failed.", vol->v_volcodepage, vol->v_maccodepage, u, ntohl(id));
643         goto utompath_error;
644     }
645
646     flags = !!(flags & CONV_REQMANGLE);
647
648     if (utf8)
649         flags |= 2;
650
651     m = mangle(vol, mpath, outlen, upath, id, flags);
652
653 #ifdef DEBUG
654     LOG(log_debug9, logtype_afpd, "utompath: '%s':'%s':'%2.2X'", upath, m, ntohl(id));
655 #endif /* DEBUG */
656     return(m);
657
658 utompath_error:
659     u = "???";
660     m = mangle(vol, u, strlen(u), upath, id, (utf8)?3:1);
661     return(m);
662 }
663
664 /* ------------------------- */
665 static int ad_addcomment(struct vol *vol, struct path *path, char *ibuf)
666 {
667     struct ofork        *of;
668     char                *name, *upath;
669     int                 isadir;
670     int                 clen;
671     struct adouble      ad, *adp;
672
673     clen = (u_char)*ibuf++;
674     clen = min( clen, 199 );
675
676     upath = path->u_name;
677     if (check_access(upath, OPENACC_WR ) < 0) {
678         return AFPERR_ACCESS;
679     }
680     
681     isadir = path_isadir(path);
682     if (isadir || !(of = of_findname(path))) {
683         ad_init(&ad, vol->v_adouble, vol->v_ad_options);
684         adp = &ad;
685     } else
686         adp = of->of_ad;
687
688     if (ad_open(adp, upath,
689                 ADFLAGS_HF | ( (isadir) ? ADFLAGS_DIR : 0),
690                 O_CREAT | O_RDWR,
691                 0666) < 0 ) {
692         return( AFPERR_ACCESS );
693     }
694
695     if (ad_getentryoff(adp, ADEID_COMMENT)) {
696         if ( (ad_get_MD_flags( adp ) & O_CREAT) ) {
697             if ( *path->m_name == '\0' ) {
698                 name = (char *)curdir->d_m_name->data;
699             } else {
700                 name = path->m_name;
701             }
702             ad_setname(adp, name);
703         }
704         ad_setentrylen( adp, ADEID_COMMENT, clen );
705         memcpy( ad_entry( adp, ADEID_COMMENT ), ibuf, clen );
706         ad_flush( adp );
707     }
708     ad_close_metadata( adp);
709     return( AFP_OK );
710 }
711
712 /* ----------------------------- */
713 int afp_addcomment(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
714 {
715     struct vol          *vol;
716     struct dir          *dir;
717     struct path         *path;
718     u_int32_t           did;
719     u_int16_t           vid;
720
721     *rbuflen = 0;
722     ibuf += 2;
723
724     memcpy( &vid, ibuf, sizeof( vid ));
725     ibuf += sizeof( vid );
726     if (NULL == ( vol = getvolbyvid( vid )) ) {
727         return( AFPERR_PARAM );
728     }
729
730     memcpy( &did, ibuf, sizeof( did ));
731     ibuf += sizeof( did );
732     if (NULL == ( dir = dirlookup( vol, did )) ) {
733         return afp_errno;
734     }
735
736     if (NULL == ( path = cname( vol, dir, &ibuf )) ) {
737         return get_afp_errno(AFPERR_NOOBJ);
738     }
739
740     if ((u_long)ibuf & 1 ) {
741         ibuf++;
742     }
743
744     return ad_addcomment(vol, path, ibuf);
745 }
746
747 /* -------------------- */
748 static int ad_getcomment(struct vol *vol, struct path *path, char *rbuf, size_t *rbuflen)
749 {
750     struct adouble      ad, *adp;
751     struct ofork        *of;
752     char                *upath;
753     int                 isadir;
754     int                 clen;
755
756     upath = path->u_name;
757     isadir = path_isadir(path);
758     if (isadir || !(of = of_findname(path))) {
759         ad_init(&ad, vol->v_adouble, vol->v_ad_options);
760         adp = &ad;
761     } else
762         adp = of->of_ad;
763         
764     if ( ad_metadata( upath, ((isadir) ? ADFLAGS_DIR : 0), adp) < 0 ) {
765         return( AFPERR_NOITEM );
766     }
767
768     if (!ad_getentryoff(adp, ADEID_COMMENT)) {
769         ad_close_metadata( adp );
770         return AFPERR_NOITEM;
771     }
772     /*
773      * Make sure the AD file is not bogus.
774      */
775     if ( ad_getentrylen( adp, ADEID_COMMENT ) <= 0 ||
776             ad_getentrylen( adp, ADEID_COMMENT ) > 199 ) {
777         ad_close_metadata( adp );
778         return( AFPERR_NOITEM );
779     }
780
781     clen = min( ad_getentrylen( adp, ADEID_COMMENT ), 128 ); /* OSX only use 128, greater kill Adobe CS2 */
782     *rbuf++ = clen;
783     memcpy( rbuf, ad_entry( adp, ADEID_COMMENT ), clen);
784     *rbuflen = clen + 1;
785     ad_close_metadata( adp);
786
787     return( AFP_OK );
788 }
789
790 /* -------------------- */
791 int afp_getcomment(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
792 {
793     struct vol          *vol;
794     struct dir          *dir;
795     struct path         *s_path;
796     u_int32_t           did;
797     u_int16_t           vid;
798     
799     *rbuflen = 0;
800     ibuf += 2;
801
802     memcpy( &vid, ibuf, sizeof( vid ));
803     ibuf += sizeof( vid );
804     if (NULL == ( vol = getvolbyvid( vid )) ) {
805         return( AFPERR_PARAM );
806     }
807
808     memcpy( &did, ibuf, sizeof( did ));
809     ibuf += sizeof( did );
810     if (NULL == ( dir = dirlookup( vol, did )) ) {
811         return afp_errno;
812     }
813
814     if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
815         return get_afp_errno(AFPERR_NOOBJ);
816     }
817
818     return ad_getcomment(vol, s_path, rbuf, rbuflen);
819 }
820
821 /* ----------------------- */
822 static int ad_rmvcomment(struct vol *vol, struct path *path)
823 {
824     struct adouble      ad, *adp;
825     struct ofork        *of;
826     int                 isadir;
827     char                *upath;
828
829     upath = path->u_name;
830     if (check_access(upath, OPENACC_WR ) < 0) {
831         return AFPERR_ACCESS;
832     }
833
834     isadir = path_isadir(path);
835     if (isadir || !(of = of_findname(path))) {
836         ad_init(&ad, vol->v_adouble, vol->v_ad_options);
837         adp = &ad;
838     } else
839         adp = of->of_ad;
840
841     if ( ad_open(adp, upath, ADFLAGS_HF | (isadir) ? ADFLAGS_DIR : 0, 0) < 0 ) {
842         switch ( errno ) {
843         case ENOENT :
844             return( AFPERR_NOITEM );
845         case EACCES :
846             return( AFPERR_ACCESS );
847         default :
848             return( AFPERR_PARAM );
849         }
850     }
851
852     if (ad_getentryoff(adp, ADEID_COMMENT)) {
853         ad_setentrylen( adp, ADEID_COMMENT, 0 );
854         ad_flush( adp );
855     }
856     ad_close_metadata( adp);
857     return( AFP_OK );
858 }
859
860 /* ----------------------- */
861 int afp_rmvcomment(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
862 {
863     struct vol          *vol;
864     struct dir          *dir;
865     struct path         *s_path;
866     u_int32_t           did;
867     u_int16_t           vid;
868
869     *rbuflen = 0;
870     ibuf += 2;
871
872     memcpy( &vid, ibuf, sizeof( vid ));
873     ibuf += sizeof( vid );
874     if (NULL == ( vol = getvolbyvid( vid )) ) {
875         return( AFPERR_PARAM );
876     }
877
878     memcpy( &did, ibuf, sizeof( did ));
879     ibuf += sizeof( did );
880     if (NULL == ( dir = dirlookup( vol, did )) ) {
881         return afp_errno;
882     }
883
884     if (NULL == ( s_path = cname( vol, dir, &ibuf ))) {
885         return get_afp_errno(AFPERR_NOOBJ);
886     }
887     
888     return ad_rmvcomment(vol, s_path);
889 }