]> arthur.barton.de Git - netatalk.git/blob - etc/afpd/desktop.c
Joe Clarke's fix for linux/quota.h checking, removed NO_DLFCN_H define
[netatalk.git] / etc / afpd / desktop.c
1 /*
2  * $Id: desktop.c,v 1.4 2001-05-31 18:48:32 srittau Exp $
3  * 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       return AFP_OK;
553
554     } else {
555       if ( read( si.sdt_fd, rbuf, rc ) < rc ) {
556         return( AFPERR_PARAM );
557       }
558       *rbuflen = rc;
559       return AFP_OK;
560     }
561 }
562
563
564 static char             hexdig[] = "0123456789abcdef";
565 char *dtfile(const struct vol *vol, u_char creator[], char *ext )
566 {
567     static char path[ MAXPATHLEN + 1];
568     char        *p;
569     int         i;
570
571     strcpy( path, vol->v_path );
572     strcat( path, "/.AppleDesktop/" );
573     for ( p = path; *p != '\0'; p++ )
574         ;
575
576     if ( !isprint( creator[ 0 ] ) || creator[ 0 ] == '/' ) {
577         *p++ = hexdig[ ( creator[ 0 ] & 0xf0 ) >> 4 ];
578         *p++ = hexdig[ creator[ 0 ] & 0x0f ];
579     } else {
580         *p++ = creator[ 0 ];
581     }
582
583     *p++ = '/';
584
585     for ( i = 0; i < sizeof( CreatorType ); i++ ) {
586         if ( !isprint( creator[ i ] ) || creator[ i ] == '/' ) {
587             *p++ = hexdig[ ( creator[ i ] & 0xf0 ) >> 4 ];
588             *p++ = hexdig[ creator[ i ] & 0x0f ];
589         } else {
590             *p++ = creator[ i ];
591         }
592     }
593     *p = '\0';
594     strcat( path, ext );
595
596     return( path );
597 }
598
599 char *mtoupath(const struct vol *vol, char *mpath)
600 {
601     static unsigned char upath[ MAXPATHLEN + 1];
602     unsigned char *m, *u;
603     int         i = 0;
604
605     if ( *mpath == '\0' ) {
606         return( "." );
607     }
608
609     m = mpath;
610     u = upath;
611     while ( *m != '\0' ) {
612         /* handle case conversion first */
613         if (vol->v_casefold & AFPVOL_MTOUUPPER)
614             *m = diatoupper( *m );
615         else if (vol->v_casefold & AFPVOL_MTOULOWER)
616             *m = diatolower( *m );
617         
618         /* we have a code page. we only use the ascii range
619          * if we have map ascii specified. */
620 #if 1
621         if (vol->v_mtoupage && ((*m > 0x7F) ||
622                                 vol->v_flags & AFPVOL_MAPASCII)) {
623             *u = vol->v_mtoupage->map[*m].value;
624         } else
625 #endif
626 #if AD_VERSION == AD_VERSION1
627           if ((((vol->v_flags & AFPVOL_NOHEX) == 0) && 
628                    (!isascii(*m) || *m == '/')) || 
629                    (((vol->v_flags & AFPVOL_USEDOTS) == 0) &&
630                     ( i == 0 && (*m == '.' )))) {
631 #else
632           if ((((vol->v_flags & AFPVOL_NOHEX) == 0) && 
633                    (!isprint(*m) || *m == '/')) || 
634                    (((vol->v_flags & AFPVOL_USEDOTS) == 0) &&
635                     ( i == 0 && (*m == '.' )))) {
636 #endif
637             /* do hex conversion. */ 
638             *u++ = ':';
639             *u++ = hexdig[ ( *m & 0xf0 ) >> 4 ];
640             *u = hexdig[ *m & 0x0f ];
641         } else 
642             *u = *m;
643         u++;
644         i++;
645         m++;
646     }
647     *u = '\0';
648
649     return( upath );
650 }
651
652 #define hextoint( c )   ( isdigit( c ) ? c - '0' : c + 10 - 'a' )
653 #define islxdigit(x)    (!isupper(x)&&isxdigit(x))
654
655 char *utompath(const struct vol *vol, char *upath)
656 {
657     static unsigned char mpath[ MAXPATHLEN + 1];
658     unsigned char       *m, *u;
659     int         h;
660
661     /* do the hex conversion */
662     u = upath;
663     m = mpath;
664     while ( *u != '\0' ) {
665         /* we have a code page */
666 #if 1
667         if (vol->v_utompage && ((*u > 0x7F) ||
668                                 (vol->v_flags & AFPVOL_MAPASCII))) {
669             *m = vol->v_utompage->map[*u].value;
670         } else 
671 #endif
672           if ( *u == ':' && *(u+1) != '\0' && islxdigit( *(u+1)) &&
673                   *(u+2) != '\0' && islxdigit( *(u+2))) {
674             ++u;
675             h = hextoint( *u ) << 4;
676             ++u;
677             h |= hextoint( *u );
678             *m = h;
679         } else 
680             *m = *u;
681
682         /* handle case conversion */
683         if (vol->v_casefold & AFPVOL_UTOMLOWER)
684             *m = diatolower( *m );
685         else if (vol->v_casefold & AFPVOL_UTOMUPPER)
686             *m = diatoupper( *m );
687
688         u++;
689         m++;
690     }
691     *m = '\0';
692     return( mpath );
693 }
694
695 int afp_addcomment(obj, ibuf, ibuflen, rbuf, rbuflen )
696     AFPObj      *obj;
697     char        *ibuf, *rbuf;
698     int         ibuflen, *rbuflen;
699 {
700     struct adouble      ad, *adp;
701     struct vol          *vol;
702     struct dir          *dir;
703     struct ofork        *of;
704     char                *path, *name;
705     int                 clen;
706     u_int32_t           did;
707     u_int16_t           vid;
708
709     *rbuflen = 0;
710     ibuf += 2;
711
712     memcpy( &vid, ibuf, sizeof( vid ));
713     ibuf += sizeof( vid );
714     if (( vol = getvolbyvid( vid )) == NULL ) {
715         return( AFPERR_PARAM );
716     }
717
718     memcpy( &did, ibuf, sizeof( did ));
719     ibuf += sizeof( did );
720     if (( dir = dirsearch( vol, did )) == NULL ) {
721         return( AFPERR_NOOBJ );
722     }
723
724     if (( path = cname( vol, dir, &ibuf )) == NULL ) {
725         return( AFPERR_NOOBJ );
726     }
727
728     if ((u_long)ibuf & 1 ) {
729         ibuf++;
730     }
731
732     clen = (u_char)*ibuf++;
733     clen = min( clen, 199 );
734
735     if ((*path == '\0') || !(of = of_findname(vol, curdir, path))) {
736       memset(&ad, 0, sizeof(ad));
737       adp = &ad;
738     } else
739       adp = of->of_ad;
740     if (ad_open( mtoupath( vol, path ), vol_noadouble(vol) | 
741                  (( *path == '\0' ) ? ADFLAGS_HF|ADFLAGS_DIR : ADFLAGS_HF),
742                  O_RDWR|O_CREAT, 0666, adp) < 0 ) {
743         return( AFPERR_ACCESS );
744     }
745
746     if ( ad_getoflags( adp, ADFLAGS_HF ) & O_CREAT ) {
747         if ( *path == '\0' ) {
748             name = curdir->d_name;
749         } else {
750             name = path;
751         }
752         ad_setentrylen( adp, ADEID_NAME, strlen( name ));
753         memcpy( ad_entry( adp, ADEID_NAME ), name, 
754                 ad_getentrylen( adp, ADEID_NAME ));
755     }
756
757     ad_setentrylen( adp, ADEID_COMMENT, clen );
758     memcpy( ad_entry( adp, ADEID_COMMENT ), ibuf, clen );
759     ad_flush( adp, ADFLAGS_HF );
760     ad_close( adp, ADFLAGS_HF );
761     return( AFP_OK );
762 }
763
764 int afp_getcomment(obj, ibuf, ibuflen, rbuf, rbuflen )
765     AFPObj      *obj;
766     char        *ibuf, *rbuf;
767     int         ibuflen, *rbuflen;
768 {
769     struct adouble      ad, *adp;
770     struct vol          *vol;
771     struct dir          *dir;
772     struct ofork        *of;
773     char                *path;
774     u_int32_t           did;
775     u_int16_t           vid;
776
777     *rbuflen = 0;
778     ibuf += 2;
779
780     memcpy( &vid, ibuf, sizeof( vid ));
781     ibuf += sizeof( vid );
782     if (( vol = getvolbyvid( vid )) == NULL ) {
783         return( AFPERR_PARAM );
784     }
785
786     memcpy( &did, ibuf, sizeof( did ));
787     ibuf += sizeof( did );
788     if (( dir = dirsearch( vol, did )) == NULL ) {
789         return( AFPERR_NOOBJ );
790     }
791
792     if (( path = cname( vol, dir, &ibuf )) == NULL ) {
793         return( AFPERR_NOOBJ );
794     }
795
796     if ((*path == '\0') || !(of = of_findname(vol, curdir, path))) {
797       memset(&ad, 0, sizeof(ad));
798       adp = &ad;
799     } else
800       adp = of->of_ad;
801     if ( ad_open( mtoupath( vol, path ), 
802                   (( *path == '\0' ) ? ADFLAGS_HF|ADFLAGS_DIR : ADFLAGS_HF), 
803                   O_RDONLY, 0666, adp) < 0 ) {
804         return( AFPERR_NOITEM );
805     }
806
807     /*
808      * Make sure the AD file is not bogus.
809      */
810     if ( ad_getentrylen( adp, ADEID_COMMENT ) < 0 ||
811             ad_getentrylen( adp, ADEID_COMMENT ) > 199 ) {
812         ad_close( adp, ADFLAGS_HF );
813         return( AFPERR_NOITEM );
814     }
815
816     *rbuf++ = ad_getentrylen( adp, ADEID_COMMENT );
817     memcpy( rbuf, ad_entry( adp, ADEID_COMMENT ), 
818             ad_getentrylen( adp, ADEID_COMMENT ));
819     *rbuflen = ad_getentrylen( adp, ADEID_COMMENT ) + 1;
820     ad_close( adp, ADFLAGS_HF );
821     return( AFP_OK );
822 }
823
824 int afp_rmvcomment(obj, ibuf, ibuflen, rbuf, rbuflen )
825     AFPObj      *obj;
826     char        *ibuf, *rbuf;
827     int         ibuflen, *rbuflen;
828 {
829     struct adouble      ad, *adp;
830     struct vol          *vol;
831     struct dir          *dir;
832     struct ofork        *of;
833     char                *path;
834     u_int32_t           did;
835     u_int16_t           vid;
836
837     *rbuflen = 0;
838     ibuf += 2;
839
840     memcpy( &vid, ibuf, sizeof( vid ));
841     ibuf += sizeof( vid );
842     if (( vol = getvolbyvid( vid )) == NULL ) {
843         return( AFPERR_PARAM );
844     }
845
846     memcpy( &did, ibuf, sizeof( did ));
847     ibuf += sizeof( did );
848     if (( dir = dirsearch( vol, did )) == NULL ) {
849         return( AFPERR_NOOBJ );
850     }
851
852     if (( path = cname( vol, dir, &ibuf )) == NULL ) {
853         return( AFPERR_NOOBJ );
854     }
855
856     if ((*path == '\0') || !(of = of_findname(vol, curdir, path))) {
857       memset(&ad, 0, sizeof(ad));
858       adp = &ad;
859     } else
860       adp = of->of_ad;
861     if ( ad_open( mtoupath( vol, path ), 
862                   (( *path == '\0' ) ? ADFLAGS_HF|ADFLAGS_DIR : ADFLAGS_HF),
863                   O_RDWR, 0, adp) < 0 ) {
864         switch ( errno ) {
865         case ENOENT :
866             return( AFPERR_NOITEM );
867         case EACCES :
868             return( AFPERR_ACCESS );
869         default :
870             return( AFPERR_PARAM );
871         }
872     }
873
874     ad_setentrylen( adp, ADEID_COMMENT, 0 );
875     ad_flush( adp, ADFLAGS_HF );
876     ad_close( adp, ADFLAGS_HF );
877     return( AFP_OK );
878 }