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