]> arthur.barton.de Git - netatalk.git/blob - etc/afpd/desktop.c
more verbose error msgs.
[netatalk.git] / etc / afpd / desktop.c
1 /*
2  * $Id: desktop.c,v 1.26.2.4.2.13 2004-05-04 15:38:24 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_open( upath,
811                   ( isadir) ? ADFLAGS_HF|ADFLAGS_DIR : ADFLAGS_HF,
812                   O_RDONLY, 0666, adp) < 0 ) {
813         return( AFPERR_NOITEM );
814     }
815
816     if (!ad_getentryoff(adp, ADEID_COMMENT)) {
817         return AFPERR_NOITEM;
818     }
819     /*
820      * Make sure the AD file is not bogus.
821      */
822     if ( ad_getentrylen( adp, ADEID_COMMENT ) <= 0 ||
823             ad_getentrylen( adp, ADEID_COMMENT ) > 199 ) {
824         ad_close( adp, ADFLAGS_HF );
825         return( AFPERR_NOITEM );
826     }
827
828     *rbuf++ = ad_getentrylen( adp, ADEID_COMMENT );
829     memcpy( rbuf, ad_entry( adp, ADEID_COMMENT ),
830             ad_getentrylen( adp, ADEID_COMMENT ));
831     *rbuflen = ad_getentrylen( adp, ADEID_COMMENT ) + 1;
832     ad_close( adp, ADFLAGS_HF );
833
834     return( AFP_OK );
835 }
836
837 /* -------------------- */
838 int afp_getcomment(obj, ibuf, ibuflen, rbuf, rbuflen )
839 AFPObj      *obj;
840 char    *ibuf, *rbuf;
841 int             ibuflen, *rbuflen;
842 {
843     struct vol          *vol;
844     struct dir          *dir;
845     struct path         *s_path;
846     u_int32_t           did;
847     u_int16_t           vid;
848     
849     *rbuflen = 0;
850     ibuf += 2;
851
852     memcpy( &vid, ibuf, sizeof( vid ));
853     ibuf += sizeof( vid );
854     if (NULL == ( vol = getvolbyvid( vid )) ) {
855         return( AFPERR_PARAM );
856     }
857
858     memcpy( &did, ibuf, sizeof( did ));
859     ibuf += sizeof( did );
860     if (NULL == ( dir = dirlookup( vol, did )) ) {
861         return afp_errno;
862     }
863
864     if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
865         return get_afp_errno(AFPERR_NOOBJ);
866     }
867
868     return ad_getcomment(vol, s_path, rbuf, rbuflen);
869 }
870
871 /* ----------------------- */
872 static int ad_rmvcomment(struct vol *vol, struct path *path)
873 {
874     struct adouble      ad, *adp;
875     struct ofork        *of;
876     int                 isadir;
877     char                *upath;
878
879     upath = path->u_name;
880     if (!vol_unix_priv(vol) && check_access(upath, OPENACC_WR ) < 0) {
881         return AFPERR_ACCESS;
882     }
883
884     isadir = path_isadir(path);
885     if (isadir || !(of = of_findname(path))) {
886         ad_init(&ad, vol->v_adouble);
887         adp = &ad;
888     } else
889         adp = of->of_ad;
890
891     if ( ad_open( upath,
892                    (isadir) ? ADFLAGS_HF|ADFLAGS_DIR : ADFLAGS_HF,
893                   O_RDWR, 0, adp) < 0 ) {
894         switch ( errno ) {
895         case ENOENT :
896             return( AFPERR_NOITEM );
897         case EACCES :
898             return( AFPERR_ACCESS );
899         default :
900             return( AFPERR_PARAM );
901         }
902     }
903
904     if (!ad_getentryoff(adp, ADEID_COMMENT)) {
905         return AFP_OK;
906     }
907
908     ad_setentrylen( adp, ADEID_COMMENT, 0 );
909     ad_flush( adp, ADFLAGS_HF );
910     ad_close( adp, ADFLAGS_HF );
911     return( AFP_OK );
912 }
913
914 /* ----------------------- */
915 int afp_rmvcomment(obj, ibuf, ibuflen, rbuf, rbuflen )
916 AFPObj      *obj;
917 char    *ibuf, *rbuf;
918 int             ibuflen, *rbuflen;
919 {
920     struct vol          *vol;
921     struct dir          *dir;
922     struct path         *s_path;
923     u_int32_t           did;
924     u_int16_t           vid;
925
926     *rbuflen = 0;
927     ibuf += 2;
928
929     memcpy( &vid, ibuf, sizeof( vid ));
930     ibuf += sizeof( vid );
931     if (NULL == ( vol = getvolbyvid( vid )) ) {
932         return( AFPERR_PARAM );
933     }
934
935     memcpy( &did, ibuf, sizeof( did ));
936     ibuf += sizeof( did );
937     if (NULL == ( dir = dirlookup( vol, did )) ) {
938         return afp_errno;
939     }
940
941     if (NULL == ( s_path = cname( vol, dir, &ibuf ))) {
942         return get_afp_errno(AFPERR_NOOBJ);
943     }
944     
945     return ad_rmvcomment(vol, s_path);
946 }