]> arthur.barton.de Git - netatalk.git/blob - etc/afpd/desktop.c
Merge master
[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     u_int16_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     u_int32_t           ftype, itag;
121     u_int16_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->handle, rbuf, buflen);
209             dsi_writeflush(obj->handle);
210         }
211         return cc;
212     }
213
214     switch (obj->proto) {
215     case AFPPROTO_DSI:
216         {
217             DSI *dsi = obj->handle;
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     u_char      fcreator[ 4 ], ih[ 12 ];
296     u_int16_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     u_int16_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->handle;
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     u_int16_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     u_int16_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->v_adouble, vol->v_ad_options);
648         adp = &ad;
649     } else
650         adp = of->of_ad;
651
652     if (ad_open(adp, upath,
653                 ADFLAGS_HF | ( (isadir) ? ADFLAGS_DIR : 0),
654                 O_CREAT | O_RDWR,
655                 0666) < 0 ) {
656         return( AFPERR_ACCESS );
657     }
658
659     if (ad_getentryoff(adp, ADEID_COMMENT)) {
660         if ( (ad_get_MD_flags( adp ) & O_CREAT) ) {
661             if ( *path->m_name == '\0' ) {
662                 name = (char *)curdir->d_m_name->data;
663             } else {
664                 name = path->m_name;
665             }
666             ad_setname(adp, name);
667         }
668         ad_setentrylen( adp, ADEID_COMMENT, clen );
669         memcpy( ad_entry( adp, ADEID_COMMENT ), ibuf, clen );
670         ad_flush( adp );
671     }
672     ad_close_metadata( adp);
673     return( AFP_OK );
674 }
675
676 /* ----------------------------- */
677 int afp_addcomment(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
678 {
679     struct vol          *vol;
680     struct dir          *dir;
681     struct path         *path;
682     u_int32_t           did;
683     u_int16_t           vid;
684
685     *rbuflen = 0;
686     ibuf += 2;
687
688     memcpy( &vid, ibuf, sizeof( vid ));
689     ibuf += sizeof( vid );
690     if (NULL == ( vol = getvolbyvid( vid )) ) {
691         return( AFPERR_PARAM );
692     }
693
694     memcpy( &did, ibuf, sizeof( did ));
695     ibuf += sizeof( did );
696     if (NULL == ( dir = dirlookup( vol, did )) ) {
697         return afp_errno;
698     }
699
700     if (NULL == ( path = cname( vol, dir, &ibuf )) ) {
701         return get_afp_errno(AFPERR_NOOBJ);
702     }
703
704     if ((u_long)ibuf & 1 ) {
705         ibuf++;
706     }
707
708     return ad_addcomment(vol, path, ibuf);
709 }
710
711 /* -------------------- */
712 static int ad_getcomment(struct vol *vol, struct path *path, char *rbuf, size_t *rbuflen)
713 {
714     struct adouble      ad, *adp;
715     struct ofork        *of;
716     char                *upath;
717     int                 isadir;
718     int                 clen;
719
720     upath = path->u_name;
721     isadir = path_isadir(path);
722     if (isadir || !(of = of_findname(path))) {
723         ad_init(&ad, vol->v_adouble, vol->v_ad_options);
724         adp = &ad;
725     } else
726         adp = of->of_ad;
727         
728     if ( ad_metadata( upath, ((isadir) ? ADFLAGS_DIR : 0), adp) < 0 ) {
729         return( AFPERR_NOITEM );
730     }
731
732     if (!ad_getentryoff(adp, ADEID_COMMENT)) {
733         ad_close_metadata( adp );
734         return AFPERR_NOITEM;
735     }
736     /*
737      * Make sure the AD file is not bogus.
738      */
739     if ( ad_getentrylen( adp, ADEID_COMMENT ) <= 0 ||
740             ad_getentrylen( adp, ADEID_COMMENT ) > 199 ) {
741         ad_close_metadata( adp );
742         return( AFPERR_NOITEM );
743     }
744
745     clen = min( ad_getentrylen( adp, ADEID_COMMENT ), 128 ); /* OSX only use 128, greater kill Adobe CS2 */
746     *rbuf++ = clen;
747     memcpy( rbuf, ad_entry( adp, ADEID_COMMENT ), clen);
748     *rbuflen = clen + 1;
749     ad_close_metadata( adp);
750
751     return( AFP_OK );
752 }
753
754 /* -------------------- */
755 int afp_getcomment(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
756 {
757     struct vol          *vol;
758     struct dir          *dir;
759     struct path         *s_path;
760     u_int32_t           did;
761     u_int16_t           vid;
762     
763     *rbuflen = 0;
764     ibuf += 2;
765
766     memcpy( &vid, ibuf, sizeof( vid ));
767     ibuf += sizeof( vid );
768     if (NULL == ( vol = getvolbyvid( vid )) ) {
769         return( AFPERR_PARAM );
770     }
771
772     memcpy( &did, ibuf, sizeof( did ));
773     ibuf += sizeof( did );
774     if (NULL == ( dir = dirlookup( vol, did )) ) {
775         return afp_errno;
776     }
777
778     if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
779         return get_afp_errno(AFPERR_NOOBJ);
780     }
781
782     return ad_getcomment(vol, s_path, rbuf, rbuflen);
783 }
784
785 /* ----------------------- */
786 static int ad_rmvcomment(struct vol *vol, struct path *path)
787 {
788     struct adouble      ad, *adp;
789     struct ofork        *of;
790     int                 isadir;
791     char                *upath;
792
793     upath = path->u_name;
794     if (check_access(upath, OPENACC_WR ) < 0) {
795         return AFPERR_ACCESS;
796     }
797
798     isadir = path_isadir(path);
799     if (isadir || !(of = of_findname(path))) {
800         ad_init(&ad, vol->v_adouble, vol->v_ad_options);
801         adp = &ad;
802     } else
803         adp = of->of_ad;
804
805     if ( ad_open(adp, upath, ADFLAGS_HF | (isadir) ? ADFLAGS_DIR : 0, 0) < 0 ) {
806         switch ( errno ) {
807         case ENOENT :
808             return( AFPERR_NOITEM );
809         case EACCES :
810             return( AFPERR_ACCESS );
811         default :
812             return( AFPERR_PARAM );
813         }
814     }
815
816     if (ad_getentryoff(adp, ADEID_COMMENT)) {
817         ad_setentrylen( adp, ADEID_COMMENT, 0 );
818         ad_flush( adp );
819     }
820     ad_close_metadata( adp);
821     return( AFP_OK );
822 }
823
824 /* ----------------------- */
825 int afp_rmvcomment(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
826 {
827     struct vol          *vol;
828     struct dir          *dir;
829     struct path         *s_path;
830     u_int32_t           did;
831     u_int16_t           vid;
832
833     *rbuflen = 0;
834     ibuf += 2;
835
836     memcpy( &vid, ibuf, sizeof( vid ));
837     ibuf += sizeof( vid );
838     if (NULL == ( vol = getvolbyvid( vid )) ) {
839         return( AFPERR_PARAM );
840     }
841
842     memcpy( &did, ibuf, sizeof( did ));
843     ibuf += sizeof( did );
844     if (NULL == ( dir = dirlookup( vol, did )) ) {
845         return afp_errno;
846     }
847
848     if (NULL == ( s_path = cname( vol, dir, &ibuf ))) {
849         return get_afp_errno(AFPERR_NOOBJ);
850     }
851     
852     return ad_rmvcomment(vol, s_path);
853 }