]> arthur.barton.de Git - netatalk.git/blob - etc/afpd/desktop.c
2a408467f1591badfe13eac47ea339c4e3484b0c
[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 (dsi_stream_read_file(dsi, si.sdt_fd, offset, dsi->datasize) < 0) {
564                 switch (errno) {
565                 case ENOSYS:
566                 case EINVAL:  /* there's no guarantee that all fs support sendfile */
567                     break;
568                 default:
569                     goto geticon_exit;
570                 }
571             }
572             else {
573                 dsi_readdone(dsi);
574                 return AFP_OK;
575             }
576 #endif
577             buflen = read(si.sdt_fd, rbuf, *rbuflen);
578             if (buflen < 0)
579                 goto geticon_exit;
580
581             /* dsi_read() also returns buffer size of next allocation */
582             buflen = dsi_read(dsi, rbuf, buflen); /* send it off */
583             if (buflen < 0)
584                 goto geticon_exit;
585
586             *rbuflen = buflen;
587         }
588         
589         dsi_readdone(dsi);
590         return AFP_OK;
591
592 geticon_exit:
593         LOG(log_error, logtype_afpd, "afp_geticon(%s): %s", icon_dtfile(vol, fcreator), strerror(errno));
594         dsi_readdone(dsi);
595         obj->exit(EXITERR_SYS);
596         return AFP_OK;
597
598     } else {
599         if ( read( si.sdt_fd, rbuf, rc ) < rc ) {
600             return( AFPERR_PARAM );
601         }
602         *rbuflen = rc;
603     }
604     return AFP_OK;
605 }
606
607 /* ---------------------- */
608 static const char               hexdig[] = "0123456789abcdef";
609 char *dtfile(const struct vol *vol, u_char creator[], char *ext )
610 {
611     static char path[ MAXPATHLEN + 1];
612     char        *p;
613     unsigned int i;
614
615     strcpy( path, vol->v_path );
616     strcat( path, "/.AppleDesktop/" );
617     for ( p = path; *p != '\0'; p++ )
618         ;
619
620     if ( !isprint( creator[ 0 ] ) || creator[ 0 ] == '/' ) {
621         *p++ = hexdig[ ( creator[ 0 ] & 0xf0 ) >> 4 ];
622         *p++ = hexdig[ creator[ 0 ] & 0x0f ];
623     } else {
624         *p++ = creator[ 0 ];
625     }
626
627     *p++ = '/';
628
629     for ( i = 0; i < sizeof( CreatorType ); i++ ) {
630         if ( !isprint( creator[ i ] ) || creator[ i ] == '/' ) {
631             *p++ = hexdig[ ( creator[ i ] & 0xf0 ) >> 4 ];
632             *p++ = hexdig[ creator[ i ] & 0x0f ];
633         } else {
634             *p++ = creator[ i ];
635         }
636     }
637     *p = '\0';
638     strcat( path, ext );
639
640     return( path );
641 }
642
643 /* ---------------------------
644  * mpath is only a filename 
645  * did filename parent directory ID.
646 */
647
648 char *mtoupath(const struct vol *vol, char *mpath, cnid_t did, int utf8)
649 {
650     static char  upath[ MAXPATHLEN + 2]; /* for convert_charset dest_len parameter +2 */
651     char        *m, *u;
652     size_t       inplen;
653     size_t       outlen;
654     uint16_t     flags;
655         
656     if ( *mpath == '\0' ) {
657         strcpy(upath, ".");
658         return upath;
659     }
660
661     /* set conversion flags */
662     flags = vol->v_mtou_flags;
663     
664     m = demangle(vol, mpath, did);
665     if (m != mpath) {
666         return m;
667     }
668
669     m = mpath;
670     u = upath;
671
672     inplen = strlen(m);
673     outlen = MAXPATHLEN;
674
675     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)) ) {
676         LOG(log_error, logtype_afpd, "conversion from %s to %s for %s failed.", (utf8)?"UTF8-MAC":vol->v_maccodepage, vol->v_volcodepage, mpath);
677             return NULL;
678     }
679
680 #ifdef DEBUG
681     LOG(log_debug9, logtype_afpd, "mtoupath: '%s':'%s'", mpath, upath);
682 #endif /* DEBUG */
683     return( upath );
684 }
685
686 /* --------------- 
687  * id filename ID
688 */
689 char *utompath(const struct vol *vol, char *upath, cnid_t id, int utf8)
690 {
691     static char  mpath[ MAXPATHLEN + 2]; /* for convert_charset dest_len parameter +2 */
692     char        *m, *u;
693     uint16_t    flags;
694     size_t       outlen;
695
696     m = mpath;
697     outlen = strlen(upath);
698
699     flags = vol->v_utom_flags;
700
701     u = upath;
702
703     /* convert charsets */
704     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)) ) { 
705         LOG(log_error, logtype_afpd, "Conversion from %s to %s for %s (%u) failed.", vol->v_volcodepage, vol->v_maccodepage, u, ntohl(id));
706         goto utompath_error;
707     }
708
709     flags = !!(flags & CONV_REQMANGLE);
710
711     if (utf8)
712         flags |= 2;
713
714     m = mangle(vol, mpath, outlen, upath, id, flags);
715
716 #ifdef DEBUG
717     LOG(log_debug9, logtype_afpd, "utompath: '%s':'%s':'%2.2X'", upath, m, ntohl(id));
718 #endif /* DEBUG */
719     return(m);
720
721 utompath_error:
722     u = "???";
723     m = mangle(vol, u, strlen(u), upath, id, (utf8)?3:1);
724     return(m);
725 }
726
727 /* ------------------------- */
728 static int ad_addcomment(const AFPObj *obj, struct vol *vol, struct path *path, char *ibuf)
729 {
730     struct ofork        *of;
731     char                *name, *upath;
732     int                 isadir;
733     int                 clen;
734     struct adouble      ad, *adp;
735
736     clen = (u_char)*ibuf++;
737     clen = min( clen, 199 );
738
739     upath = path->u_name;
740     if (check_access(obj, vol, upath, OPENACC_WR ) < 0) {
741         return AFPERR_ACCESS;
742     }
743     
744     isadir = path_isadir(path);
745     if (isadir || !(of = of_findname(path))) {
746         ad_init(&ad, vol);
747         adp = &ad;
748     } else
749         adp = of->of_ad;
750
751     if (ad_open(adp, upath,
752                 ADFLAGS_HF | ( (isadir) ? ADFLAGS_DIR : 0) | ADFLAGS_CREATE | ADFLAGS_RDWR,
753                 0666) < 0 ) {
754         return( AFPERR_ACCESS );
755     }
756
757     if (ad_getentryoff(adp, ADEID_COMMENT)) {
758         if ( (ad_get_MD_flags( adp ) & O_CREAT) ) {
759             if ( *path->m_name == '\0' ) {
760                 name = (char *)curdir->d_m_name->data;
761             } else {
762                 name = path->m_name;
763             }
764             ad_setname(adp, name);
765         }
766         ad_setentrylen( adp, ADEID_COMMENT, clen );
767         memcpy( ad_entry( adp, ADEID_COMMENT ), ibuf, clen );
768         ad_flush( adp );
769     }
770     ad_close(adp, ADFLAGS_HF);
771     return( AFP_OK );
772 }
773
774 /* ----------------------------- */
775 int afp_addcomment(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
776 {
777     struct vol          *vol;
778     struct dir          *dir;
779     struct path         *path;
780     uint32_t           did;
781     uint16_t            vid;
782
783     *rbuflen = 0;
784     ibuf += 2;
785
786     memcpy( &vid, ibuf, sizeof( vid ));
787     ibuf += sizeof( vid );
788     if (NULL == ( vol = getvolbyvid( vid )) ) {
789         return( AFPERR_PARAM );
790     }
791
792     memcpy( &did, ibuf, sizeof( did ));
793     ibuf += sizeof( did );
794     if (NULL == ( dir = dirlookup( vol, did )) ) {
795         return afp_errno;
796     }
797
798     if (NULL == ( path = cname( vol, dir, &ibuf )) ) {
799         return get_afp_errno(AFPERR_NOOBJ);
800     }
801
802     if ((u_long)ibuf & 1 ) {
803         ibuf++;
804     }
805
806     return ad_addcomment(obj, vol, path, ibuf);
807 }
808
809 /* -------------------- */
810 static int ad_getcomment(struct vol *vol, struct path *path, char *rbuf, size_t *rbuflen)
811 {
812     struct adouble      ad, *adp;
813     struct ofork        *of;
814     char                *upath;
815     int                 isadir;
816     int                 clen;
817
818     upath = path->u_name;
819     isadir = path_isadir(path);
820     if (isadir || !(of = of_findname(path))) {
821         ad_init(&ad, vol);
822         adp = &ad;
823     } else
824         adp = of->of_ad;
825         
826     if ( ad_metadata( upath, ((isadir) ? ADFLAGS_DIR : 0), adp) < 0 ) {
827         return( AFPERR_NOITEM );
828     }
829
830     if (!ad_getentryoff(adp, ADEID_COMMENT)) {
831         ad_close(adp, ADFLAGS_HF);
832         return AFPERR_NOITEM;
833     }
834     /*
835      * Make sure the AD file is not bogus.
836      */
837     if ( ad_getentrylen( adp, ADEID_COMMENT ) <= 0 ||
838             ad_getentrylen( adp, ADEID_COMMENT ) > 199 ) {
839         ad_close(adp, ADFLAGS_HF);
840         return( AFPERR_NOITEM );
841     }
842
843     clen = min( ad_getentrylen( adp, ADEID_COMMENT ), 128 ); /* OSX only use 128, greater kill Adobe CS2 */
844     *rbuf++ = clen;
845     memcpy( rbuf, ad_entry( adp, ADEID_COMMENT ), clen);
846     *rbuflen = clen + 1;
847     ad_close(adp, ADFLAGS_HF);
848
849     return( AFP_OK );
850 }
851
852 /* -------------------- */
853 int afp_getcomment(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
854 {
855     struct vol          *vol;
856     struct dir          *dir;
857     struct path         *s_path;
858     uint32_t            did;
859     uint16_t            vid;
860     
861     *rbuflen = 0;
862     ibuf += 2;
863
864     memcpy( &vid, ibuf, sizeof( vid ));
865     ibuf += sizeof( vid );
866     if (NULL == ( vol = getvolbyvid( vid )) ) {
867         return( AFPERR_PARAM );
868     }
869
870     memcpy( &did, ibuf, sizeof( did ));
871     ibuf += sizeof( did );
872     if (NULL == ( dir = dirlookup( vol, did )) ) {
873         return afp_errno;
874     }
875
876     if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
877         return get_afp_errno(AFPERR_NOOBJ);
878     }
879
880     return ad_getcomment(vol, s_path, rbuf, rbuflen);
881 }
882
883 /* ----------------------- */
884 static int ad_rmvcomment(const AFPObj *obj, struct vol *vol, struct path *path)
885 {
886     struct adouble      ad, *adp;
887     struct ofork        *of;
888     int                 isadir;
889     char                *upath;
890
891     upath = path->u_name;
892     if (check_access(obj, vol, upath, OPENACC_WR ) < 0) {
893         return AFPERR_ACCESS;
894     }
895
896     isadir = path_isadir(path);
897     if (isadir || !(of = of_findname(path))) {
898         ad_init(&ad, vol);
899         adp = &ad;
900     } else
901         adp = of->of_ad;
902
903     if ( ad_open(adp, upath, ADFLAGS_HF | ADFLAGS_RDWR | ((isadir) ? ADFLAGS_DIR : 0)) < 0 ) {
904         switch ( errno ) {
905         case ENOENT :
906             return( AFPERR_NOITEM );
907         case EACCES :
908             return( AFPERR_ACCESS );
909         default :
910             return( AFPERR_PARAM );
911         }
912     }
913
914     if (ad_getentryoff(adp, ADEID_COMMENT)) {
915         ad_setentrylen( adp, ADEID_COMMENT, 0 );
916         ad_flush( adp );
917     }
918     ad_close(adp, ADFLAGS_HF);
919     return( AFP_OK );
920 }
921
922 /* ----------------------- */
923 int afp_rmvcomment(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
924 {
925     struct vol          *vol;
926     struct dir          *dir;
927     struct path         *s_path;
928     uint32_t            did;
929     uint16_t            vid;
930
931     *rbuflen = 0;
932     ibuf += 2;
933
934     memcpy( &vid, ibuf, sizeof( vid ));
935     ibuf += sizeof( vid );
936     if (NULL == ( vol = getvolbyvid( vid )) ) {
937         return( AFPERR_PARAM );
938     }
939
940     memcpy( &did, ibuf, sizeof( did ));
941     ibuf += sizeof( did );
942     if (NULL == ( dir = dirlookup( vol, did )) ) {
943         return afp_errno;
944     }
945
946     if (NULL == ( s_path = cname( vol, dir, &ibuf ))) {
947         return get_afp_errno(AFPERR_NOOBJ);
948     }
949     
950     return ad_rmvcomment(obj, vol, s_path);
951 }