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