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