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