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