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