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