]> arthur.barton.de Git - netatalk.git/blob - etc/afpd/desktop.c
bugfix: dirlookup() return dirsearch error if any (AFPERR_PARAM).
[netatalk.git] / etc / afpd / desktop.c
1 /*
2  * $Id: desktop.c,v 1.22 2003-01-24 07:08:42 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     int                 isadir;
766
767     *rbuflen = 0;
768     ibuf += 2;
769
770     memcpy( &vid, ibuf, sizeof( vid ));
771     ibuf += sizeof( vid );
772     if (NULL == ( vol = getvolbyvid( vid )) ) {
773         return( AFPERR_PARAM );
774     }
775
776     memcpy( &did, ibuf, sizeof( did ));
777     ibuf += sizeof( did );
778     if (NULL == ( dir = dirlookup( vol, did )) ) {
779         return afp_errno;
780     }
781
782     if (NULL == ( path = cname( vol, dir, &ibuf )) ) {
783         return afp_errno;
784     }
785
786     if ((u_long)ibuf & 1 ) {
787         ibuf++;
788     }
789
790     clen = (u_char)*ibuf++;
791     clen = min( clen, 199 );
792
793     upath = path->u_name;
794     if (check_access(upath, OPENACC_WR ) < 0) {
795         return AFPERR_ACCESS;
796     }
797
798     isadir = path_isadir(path);
799     if (isadir || !(of = of_findname(path))) {
800         memset(&ad, 0, sizeof(ad));
801         adp = &ad;
802     } else
803         adp = of->of_ad;
804
805     if (ad_open( upath , vol_noadouble(vol) |
806                  (( isadir) ? ADFLAGS_HF|ADFLAGS_DIR : ADFLAGS_HF),
807                  O_RDWR|O_CREAT, 0666, adp) < 0 ) {
808         return( AFPERR_ACCESS );
809     }
810
811     if ( (ad_getoflags( adp, ADFLAGS_HF ) & O_CREAT) ) {
812         if ( *path->m_name == '\0' ) {
813             name = curdir->d_m_name;
814         } else {
815             name = path->m_name;
816         }
817         ad_setentrylen( adp, ADEID_NAME, strlen( name ));
818         memcpy( ad_entry( adp, ADEID_NAME ), name,
819                 ad_getentrylen( adp, ADEID_NAME ));
820     }
821
822     ad_setentrylen( adp, ADEID_COMMENT, clen );
823     memcpy( ad_entry( adp, ADEID_COMMENT ), ibuf, clen );
824     ad_flush( adp, ADFLAGS_HF );
825     ad_close( adp, ADFLAGS_HF );
826     return( AFP_OK );
827 }
828
829 int afp_getcomment(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     struct path         *s_path;
839     char                *upath;
840     u_int32_t           did;
841     u_int16_t           vid;
842     int                 isadir;
843     
844     *rbuflen = 0;
845     ibuf += 2;
846
847     memcpy( &vid, ibuf, sizeof( vid ));
848     ibuf += sizeof( vid );
849     if (NULL == ( vol = getvolbyvid( vid )) ) {
850         return( AFPERR_PARAM );
851     }
852
853     memcpy( &did, ibuf, sizeof( did ));
854     ibuf += sizeof( did );
855     if (NULL == ( dir = dirlookup( vol, did )) ) {
856         return afp_errno;
857     }
858
859     if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
860         return afp_errno;
861     }
862
863     upath = s_path->u_name;
864     isadir = path_isadir(s_path);
865     if (isadir || !(of = of_findname(s_path))) {
866         memset(&ad, 0, sizeof(ad));
867         adp = &ad;
868     } else
869         adp = of->of_ad;
870     if ( ad_open( upath,
871                   ( isadir) ? ADFLAGS_HF|ADFLAGS_DIR : ADFLAGS_HF,
872                   O_RDONLY, 0666, adp) < 0 ) {
873         return( AFPERR_NOITEM );
874     }
875
876     /*
877      * Make sure the AD file is not bogus.
878      */
879     if ( ad_getentrylen( adp, ADEID_COMMENT ) < 0 ||
880             ad_getentrylen( adp, ADEID_COMMENT ) > 199 ) {
881         ad_close( adp, ADFLAGS_HF );
882         return( AFPERR_NOITEM );
883     }
884
885     *rbuf++ = ad_getentrylen( adp, ADEID_COMMENT );
886     memcpy( rbuf, ad_entry( adp, ADEID_COMMENT ),
887             ad_getentrylen( adp, ADEID_COMMENT ));
888     *rbuflen = ad_getentrylen( adp, ADEID_COMMENT ) + 1;
889     ad_close( adp, ADFLAGS_HF );
890
891     /* return AFPERR_NOITEM if len == 0 ? */
892     return( AFP_OK );
893 }
894
895 int afp_rmvcomment(obj, ibuf, ibuflen, rbuf, rbuflen )
896 AFPObj      *obj;
897 char    *ibuf, *rbuf;
898 int             ibuflen, *rbuflen;
899 {
900     struct adouble      ad, *adp;
901     struct vol          *vol;
902     struct dir          *dir;
903     struct ofork        *of;
904     struct path         *s_path;
905     char                *upath;
906     u_int32_t           did;
907     u_int16_t           vid;
908     int                 isadir;
909
910     *rbuflen = 0;
911     ibuf += 2;
912
913     memcpy( &vid, ibuf, sizeof( vid ));
914     ibuf += sizeof( vid );
915     if (NULL == ( vol = getvolbyvid( vid )) ) {
916         return( AFPERR_PARAM );
917     }
918
919     memcpy( &did, ibuf, sizeof( did ));
920     ibuf += sizeof( did );
921     if (NULL == ( dir = dirlookup( vol, did )) ) {
922         return afp_errno;
923     }
924
925     if (NULL == ( s_path = cname( vol, dir, &ibuf ))) {
926         return afp_errno;
927     }
928
929     upath = s_path->u_name;
930     if (check_access(upath, OPENACC_WR ) < 0) {
931         return AFPERR_ACCESS;
932     }
933
934     isadir = path_isadir(s_path);
935     if (isadir || !(of = of_findname(s_path))) {
936         memset(&ad, 0, sizeof(ad));
937         adp = &ad;
938     } else
939         adp = of->of_ad;
940
941     if ( ad_open( upath,
942                    (isadir) ? ADFLAGS_HF|ADFLAGS_DIR : ADFLAGS_HF,
943                   O_RDWR, 0, adp) < 0 ) {
944         switch ( errno ) {
945         case ENOENT :
946             return( AFPERR_NOITEM );
947         case EACCES :
948             return( AFPERR_ACCESS );
949         default :
950             return( AFPERR_PARAM );
951         }
952     }
953
954     ad_setentrylen( adp, ADEID_COMMENT, 0 );
955     ad_flush( adp, ADFLAGS_HF );
956     ad_close( adp, ADFLAGS_HF );
957     return( AFP_OK );
958 }