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