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