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