]> arthur.barton.de Git - netatalk.git/blob - etc/afpd/desktop.c
43672599126386072a4d87f7e9e2320585e02451
[netatalk.git] / etc / afpd / desktop.c
1 /*
2  * $Id: desktop.c,v 1.15 2002-09-05 14:52:05 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         } else
637 #endif /* 1 */
638 #if AD_VERSION == AD_VERSION1
639             if ((((vol->v_flags & AFPVOL_NOHEX) == 0) &&
640                     (!isascii(*m) || *m == '/')) ||
641                     (((vol->v_flags & AFPVOL_USEDOTS) == 0) &&
642                      ( i == 0 && (*m == '.' )))) {
643 #else /* AD_VERSION == AD_VERSION1 */
644             if ((((vol->v_flags & AFPVOL_NOHEX) == 0) &&
645                     (!isprint(*m) || *m == '/')) ||
646                     (((vol->v_flags & AFPVOL_USEDOTS) == 0) &&
647                      ( i == 0 && (*m == '.' )))) {
648 #endif /* AD_VERSION == AD_VERSION1 */
649                 /* do hex conversion. */
650                 *u++ = ':';
651                 *u++ = hexdig[ ( *m & 0xf0 ) >> 4 ];
652                 *u = hexdig[ *m & 0x0f ];
653             } else
654                 *u = *m;
655         u++;
656         i++;
657         m++;
658     }
659     *u = '\0';
660
661     return( upath );
662 }
663
664 #define hextoint( c )   ( isdigit( c ) ? c - '0' : c + 10 - 'a' )
665 #define islxdigit(x)    (!isupper(x)&&isxdigit(x))
666
667 char *utompath(const struct vol *vol, char *upath)
668 {
669     static char  mpath[ MAXPATHLEN + 1];
670     char        *m, *u;
671     int          h;
672
673 #ifdef FILE_MANGLING
674     upath = mangle(vol, upath);
675 #endif /* FILE_MANGLING */
676
677     /* do the hex conversion */
678     u = upath;
679     m = mpath;
680     while ( *u != '\0' ) {
681         /* we have a code page */
682 #if 1
683         if (vol->v_utompage && ((*u & 0x80) ||
684                                 (vol->v_flags & AFPVOL_MAPASCII))) {
685             *m = vol->v_utompage->map[(unsigned char) *u].value;
686         } else
687 #endif /* 1 */
688             if ( *u == ':' && *(u+1) != '\0' && islxdigit( *(u+1)) &&
689                     *(u+2) != '\0' && islxdigit( *(u+2))) {
690                 ++u;
691                 h = hextoint( *u ) << 4;
692                 ++u;
693                 h |= hextoint( *u );
694                 *m = h;
695             } else
696                 *m = *u;
697
698         /* handle case conversion */
699         if (vol->v_casefold & AFPVOL_UTOMLOWER)
700             *m = diatolower( *m );
701         else if (vol->v_casefold & AFPVOL_UTOMUPPER)
702             *m = diatoupper( *m );
703
704         u++;
705         m++;
706     }
707     *m = '\0';
708     return( mpath );
709 }
710
711 int afp_addcomment(obj, ibuf, ibuflen, rbuf, rbuflen )
712 AFPObj      *obj;
713 char    *ibuf, *rbuf;
714 int             ibuflen, *rbuflen;
715 {
716     struct adouble      ad, *adp;
717     struct vol          *vol;
718     struct dir          *dir;
719     struct ofork        *of;
720     char                *path, *name, *upath;
721     int                 clen;
722     u_int32_t           did;
723     u_int16_t           vid;
724
725     *rbuflen = 0;
726     ibuf += 2;
727
728     memcpy( &vid, ibuf, sizeof( vid ));
729     ibuf += sizeof( vid );
730     if (( vol = getvolbyvid( vid )) == NULL ) {
731         return( AFPERR_PARAM );
732     }
733
734     memcpy( &did, ibuf, sizeof( did ));
735     ibuf += sizeof( did );
736     if (( dir = dirsearch( vol, did )) == NULL ) {
737         return( AFPERR_NOOBJ );
738     }
739
740     if (( path = cname( vol, dir, &ibuf )) == NULL ) {
741         return( AFPERR_NOOBJ );
742     }
743
744     if ((u_long)ibuf & 1 ) {
745         ibuf++;
746     }
747
748     clen = (u_char)*ibuf++;
749     clen = min( clen, 199 );
750     upath = mtoupath( vol, path );
751     if ((*path == '\0') || !(of = of_findname(upath, NULL))) {
752         memset(&ad, 0, sizeof(ad));
753         adp = &ad;
754     } else
755         adp = of->of_ad;
756     if (ad_open( upath , vol_noadouble(vol) |
757                  (( *path == '\0' ) ? ADFLAGS_HF|ADFLAGS_DIR : ADFLAGS_HF),
758                  O_RDWR|O_CREAT, 0666, adp) < 0 ) {
759         return( AFPERR_ACCESS );
760     }
761
762     if ( ad_getoflags( adp, ADFLAGS_HF ) & O_CREAT ) {
763         if ( *path == '\0' ) {
764             name = curdir->d_name;
765         } else {
766             name = path;
767         }
768         ad_setentrylen( adp, ADEID_NAME, strlen( name ));
769         memcpy( ad_entry( adp, ADEID_NAME ), name,
770                 ad_getentrylen( adp, ADEID_NAME ));
771     }
772
773     ad_setentrylen( adp, ADEID_COMMENT, clen );
774     memcpy( ad_entry( adp, ADEID_COMMENT ), ibuf, clen );
775     ad_flush( adp, ADFLAGS_HF );
776     ad_close( adp, ADFLAGS_HF );
777     return( AFP_OK );
778 }
779
780 int afp_getcomment(obj, ibuf, ibuflen, rbuf, rbuflen )
781 AFPObj      *obj;
782 char    *ibuf, *rbuf;
783 int             ibuflen, *rbuflen;
784 {
785     struct adouble      ad, *adp;
786     struct vol          *vol;
787     struct dir          *dir;
788     struct ofork        *of;
789     char                *path, *upath;
790     u_int32_t           did;
791     u_int16_t           vid;
792
793     *rbuflen = 0;
794     ibuf += 2;
795
796     memcpy( &vid, ibuf, sizeof( vid ));
797     ibuf += sizeof( vid );
798     if (( vol = getvolbyvid( vid )) == NULL ) {
799         return( AFPERR_PARAM );
800     }
801
802     memcpy( &did, ibuf, sizeof( did ));
803     ibuf += sizeof( did );
804     if (( dir = dirsearch( vol, did )) == NULL ) {
805         return( AFPERR_NOOBJ );
806     }
807
808     if (( path = cname( vol, dir, &ibuf )) == NULL ) {
809         return( AFPERR_NOOBJ );
810     }
811
812
813     upath = mtoupath( vol, path );
814     if ((*path == '\0') || !(of = of_findname(upath, NULL))) {
815         memset(&ad, 0, sizeof(ad));
816         adp = &ad;
817     } else
818         adp = of->of_ad;
819     if ( ad_open( upath,
820                   (( *path == '\0' ) ? ADFLAGS_HF|ADFLAGS_DIR : ADFLAGS_HF),
821                   O_RDONLY, 0666, adp) < 0 ) {
822         return( AFPERR_NOITEM );
823     }
824
825     /*
826      * Make sure the AD file is not bogus.
827      */
828     if ( ad_getentrylen( adp, ADEID_COMMENT ) < 0 ||
829             ad_getentrylen( adp, ADEID_COMMENT ) > 199 ) {
830         ad_close( adp, ADFLAGS_HF );
831         return( AFPERR_NOITEM );
832     }
833
834     *rbuf++ = ad_getentrylen( adp, ADEID_COMMENT );
835     memcpy( rbuf, ad_entry( adp, ADEID_COMMENT ),
836             ad_getentrylen( adp, ADEID_COMMENT ));
837     *rbuflen = ad_getentrylen( adp, ADEID_COMMENT ) + 1;
838     ad_close( adp, ADFLAGS_HF );
839     return( AFP_OK );
840 }
841
842 int afp_rmvcomment(obj, ibuf, ibuflen, rbuf, rbuflen )
843 AFPObj      *obj;
844 char    *ibuf, *rbuf;
845 int             ibuflen, *rbuflen;
846 {
847     struct adouble      ad, *adp;
848     struct vol          *vol;
849     struct dir          *dir;
850     struct ofork        *of;
851     char                *path, *upath;
852     u_int32_t           did;
853     u_int16_t           vid;
854
855     *rbuflen = 0;
856     ibuf += 2;
857
858     memcpy( &vid, ibuf, sizeof( vid ));
859     ibuf += sizeof( vid );
860     if (( vol = getvolbyvid( vid )) == NULL ) {
861         return( AFPERR_PARAM );
862     }
863
864     memcpy( &did, ibuf, sizeof( did ));
865     ibuf += sizeof( did );
866     if (( dir = dirsearch( vol, did )) == NULL ) {
867         return( AFPERR_NOOBJ );
868     }
869
870     if (( path = cname( vol, dir, &ibuf )) == NULL ) {
871         return( AFPERR_NOOBJ );
872     }
873
874     upath = mtoupath( vol, path );
875     if ((*path == '\0') || !(of = of_findname(upath, NULL))) {
876         memset(&ad, 0, sizeof(ad));
877         adp = &ad;
878     } else
879         adp = of->of_ad;
880
881     if ( ad_open( upath,
882                   (( *path == '\0' ) ? ADFLAGS_HF|ADFLAGS_DIR : ADFLAGS_HF),
883                   O_RDWR, 0, adp) < 0 ) {
884         switch ( errno ) {
885         case ENOENT :
886             return( AFPERR_NOITEM );
887         case EACCES :
888             return( AFPERR_ACCESS );
889         default :
890             return( AFPERR_PARAM );
891         }
892     }
893
894     ad_setentrylen( adp, ADEID_COMMENT, 0 );
895     ad_flush( adp, ADFLAGS_HF );
896     ad_close( adp, ADFLAGS_HF );
897     return( AFP_OK );
898 }