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