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