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