]> arthur.barton.de Git - netatalk.git/blob - etc/afpd/desktop.c
better handling for file without read access.
[netatalk.git] / etc / afpd / desktop.c
1 /*
2  * $Id: desktop.c,v 1.26.2.4.2.14 2004-05-10 18:40:32 didg 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
691     m = mangle(vol, mpath, upath, id, flags);
692
693 #ifdef DEBUG
694     LOG(log_debug, logtype_afpd, "utompath: '%s':'%s':'%2.2X'", upath, m, ntohl(id));
695 #endif /* DEBUG */
696     return(m);
697
698 utompath_error:
699     u = "???";
700     m = mangle(vol, u, upath, id, 1);
701     return(m);
702 }
703
704 /* ------------------------- */
705 static int ad_addcomment(struct vol *vol, struct path *path, char *ibuf)
706 {
707     struct ofork        *of;
708     char                *name, *upath;
709     int                 isadir;
710     int                 clen;
711     struct adouble      ad, *adp;
712
713     clen = (u_char)*ibuf++;
714     clen = min( clen, 199 );
715
716     upath = path->u_name;
717     if (!vol_unix_priv(vol) && check_access(upath, OPENACC_WR ) < 0) {
718         return AFPERR_ACCESS;
719     }
720     
721     isadir = path_isadir(path);
722     if (isadir || !(of = of_findname(path))) {
723         ad_init(&ad, vol->v_adouble);
724         adp = &ad;
725     } else
726         adp = of->of_ad;
727
728     if (ad_open( upath , vol_noadouble(vol) |
729                  (( isadir) ? ADFLAGS_HF|ADFLAGS_DIR : ADFLAGS_HF),
730                  O_RDWR|O_CREAT, 0666, adp) < 0 ) {
731         return( AFPERR_ACCESS );
732     }
733
734     if (!ad_getentryoff(adp, ADEID_COMMENT)) {
735         /* not defined, save nothing but return success */
736         return AFP_OK;
737     }
738
739     if ( (ad_getoflags( adp, ADFLAGS_HF ) & O_CREAT) ) {
740         if ( *path->m_name == '\0' ) {
741             name = curdir->d_m_name;
742         } else {
743             name = path->m_name;
744         }
745         ad_setname(adp, name);
746     }
747
748     ad_setentrylen( adp, ADEID_COMMENT, clen );
749     memcpy( ad_entry( adp, ADEID_COMMENT ), ibuf, clen );
750     ad_flush( adp, ADFLAGS_HF );
751     ad_close( adp, ADFLAGS_HF );
752     return( AFP_OK );
753 }
754
755 /* ----------------------------- */
756 int afp_addcomment(obj, ibuf, ibuflen, rbuf, rbuflen )
757 AFPObj      *obj;
758 char    *ibuf, *rbuf;
759 int             ibuflen, *rbuflen;
760 {
761     struct vol          *vol;
762     struct dir          *dir;
763     struct path         *path;
764     u_int32_t           did;
765     u_int16_t           vid;
766
767     *rbuflen = 0;
768     ibuf += 2;
769
770     memcpy( &vid, ibuf, sizeof( vid ));
771     ibuf += sizeof( vid );
772     if (NULL == ( vol = getvolbyvid( vid )) ) {
773         return( AFPERR_PARAM );
774     }
775
776     memcpy( &did, ibuf, sizeof( did ));
777     ibuf += sizeof( did );
778     if (NULL == ( dir = dirlookup( vol, did )) ) {
779         return afp_errno;
780     }
781
782     if (NULL == ( path = cname( vol, dir, &ibuf )) ) {
783         return get_afp_errno(AFPERR_NOOBJ);
784     }
785
786     if ((u_long)ibuf & 1 ) {
787         ibuf++;
788     }
789
790     return ad_addcomment(vol, path, ibuf);
791 }
792
793 /* -------------------- */
794 static int ad_getcomment(struct vol *vol, struct path *path, char *rbuf, int *rbuflen)
795 {
796     struct adouble      ad, *adp;
797     struct ofork        *of;
798     char                *upath;
799     int                 isadir;
800
801
802     upath = path->u_name;
803     isadir = path_isadir(path);
804     if (isadir || !(of = of_findname(path))) {
805         ad_init(&ad, vol->v_adouble);
806         adp = &ad;
807     } else
808         adp = of->of_ad;
809         
810     if ( ad_metadata( upath,( isadir) ? ADFLAGS_DIR : 0, adp) < 0 ) {
811         return( AFPERR_NOITEM );
812     }
813
814     if (!ad_getentryoff(adp, ADEID_COMMENT)) {
815         return AFPERR_NOITEM;
816     }
817     /*
818      * Make sure the AD file is not bogus.
819      */
820     if ( ad_getentrylen( adp, ADEID_COMMENT ) <= 0 ||
821             ad_getentrylen( adp, ADEID_COMMENT ) > 199 ) {
822         ad_close( adp, ADFLAGS_HF );
823         return( AFPERR_NOITEM );
824     }
825
826     *rbuf++ = ad_getentrylen( adp, ADEID_COMMENT );
827     memcpy( rbuf, ad_entry( adp, ADEID_COMMENT ),
828             ad_getentrylen( adp, ADEID_COMMENT ));
829     *rbuflen = ad_getentrylen( adp, ADEID_COMMENT ) + 1;
830     ad_close( adp, ADFLAGS_HF );
831
832     return( AFP_OK );
833 }
834
835 /* -------------------- */
836 int afp_getcomment(obj, ibuf, ibuflen, rbuf, rbuflen )
837 AFPObj      *obj;
838 char    *ibuf, *rbuf;
839 int             ibuflen, *rbuflen;
840 {
841     struct vol          *vol;
842     struct dir          *dir;
843     struct path         *s_path;
844     u_int32_t           did;
845     u_int16_t           vid;
846     
847     *rbuflen = 0;
848     ibuf += 2;
849
850     memcpy( &vid, ibuf, sizeof( vid ));
851     ibuf += sizeof( vid );
852     if (NULL == ( vol = getvolbyvid( vid )) ) {
853         return( AFPERR_PARAM );
854     }
855
856     memcpy( &did, ibuf, sizeof( did ));
857     ibuf += sizeof( did );
858     if (NULL == ( dir = dirlookup( vol, did )) ) {
859         return afp_errno;
860     }
861
862     if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
863         return get_afp_errno(AFPERR_NOOBJ);
864     }
865
866     return ad_getcomment(vol, s_path, rbuf, rbuflen);
867 }
868
869 /* ----------------------- */
870 static int ad_rmvcomment(struct vol *vol, struct path *path)
871 {
872     struct adouble      ad, *adp;
873     struct ofork        *of;
874     int                 isadir;
875     char                *upath;
876
877     upath = path->u_name;
878     if (!vol_unix_priv(vol) && check_access(upath, OPENACC_WR ) < 0) {
879         return AFPERR_ACCESS;
880     }
881
882     isadir = path_isadir(path);
883     if (isadir || !(of = of_findname(path))) {
884         ad_init(&ad, vol->v_adouble);
885         adp = &ad;
886     } else
887         adp = of->of_ad;
888
889     if ( ad_open( upath,
890                    (isadir) ? ADFLAGS_HF|ADFLAGS_DIR : ADFLAGS_HF,
891                   O_RDWR, 0, adp) < 0 ) {
892         switch ( errno ) {
893         case ENOENT :
894             return( AFPERR_NOITEM );
895         case EACCES :
896             return( AFPERR_ACCESS );
897         default :
898             return( AFPERR_PARAM );
899         }
900     }
901
902     if (!ad_getentryoff(adp, ADEID_COMMENT)) {
903         return AFP_OK;
904     }
905
906     ad_setentrylen( adp, ADEID_COMMENT, 0 );
907     ad_flush( adp, ADFLAGS_HF );
908     ad_close( adp, ADFLAGS_HF );
909     return( AFP_OK );
910 }
911
912 /* ----------------------- */
913 int afp_rmvcomment(obj, ibuf, ibuflen, rbuf, rbuflen )
914 AFPObj      *obj;
915 char    *ibuf, *rbuf;
916 int             ibuflen, *rbuflen;
917 {
918     struct vol          *vol;
919     struct dir          *dir;
920     struct path         *s_path;
921     u_int32_t           did;
922     u_int16_t           vid;
923
924     *rbuflen = 0;
925     ibuf += 2;
926
927     memcpy( &vid, ibuf, sizeof( vid ));
928     ibuf += sizeof( vid );
929     if (NULL == ( vol = getvolbyvid( vid )) ) {
930         return( AFPERR_PARAM );
931     }
932
933     memcpy( &did, ibuf, sizeof( did ));
934     ibuf += sizeof( did );
935     if (NULL == ( dir = dirlookup( vol, did )) ) {
936         return afp_errno;
937     }
938
939     if (NULL == ( s_path = cname( vol, dir, &ibuf ))) {
940         return get_afp_errno(AFPERR_NOOBJ);
941     }
942     
943     return ad_rmvcomment(vol, s_path);
944 }