]> arthur.barton.de Git - netatalk.git/blob - etc/afpd/desktop.c
error code for dirlookup, cname.
[netatalk.git] / etc / afpd / desktop.c
1 /*
2  * $Id: desktop.c,v 1.25 2003-03-15 01:34:35 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
49 #ifdef FILE_MANGLING
50 #include "mangle.h"
51 #endif /* CNID_DB */
52
53 #ifdef AFP3x
54 #include <iconv.h>
55 #endif
56
57 int afp_opendt(obj, ibuf, ibuflen, rbuf, rbuflen )
58 AFPObj      *obj;
59 char    *ibuf, *rbuf;
60 int             ibuflen, *rbuflen;
61 {
62     struct vol  *vol;
63     u_int16_t   vid;
64
65     ibuf += 2;
66
67     memcpy( &vid, ibuf, sizeof(vid));
68     if (NULL == ( vol = getvolbyvid( vid )) ) {
69         *rbuflen = 0;
70         return( AFPERR_PARAM );
71     }
72
73     memcpy( rbuf, &vid, sizeof(vid));
74     *rbuflen = sizeof(vid);
75     return( AFP_OK );
76 }
77
78 int afp_closedt(obj, ibuf, ibuflen, rbuf, rbuflen )
79 AFPObj      *obj;
80 char    *ibuf, *rbuf;
81 int             ibuflen, *rbuflen;
82 {
83     *rbuflen = 0;
84     return( AFP_OK );
85 }
86
87 struct savedt   si = { { 0, 0, 0, 0 }, -1, 0 };
88
89 static int iconopen( vol, creator, flags, mode )
90 struct vol      *vol;
91 u_char  creator[ 4 ];
92 {
93     char        *dtf, *adt, *adts;
94
95     if ( si.sdt_fd != -1 ) {
96         if ( memcmp( si.sdt_creator, creator, sizeof( CreatorType )) == 0 &&
97                 si.sdt_vid == vol->v_vid ) {
98             return 0;
99         }
100         close( si.sdt_fd );
101         si.sdt_fd = -1;
102     }
103
104     dtf = dtfile( vol, creator, ".icon" );
105
106     if (( si.sdt_fd = open( dtf, flags, ad_mode( dtf, mode ))) < 0 ) {
107         if ( errno == ENOENT && ( flags & O_CREAT )) {
108             if (( adts = strrchr( dtf, '/' )) == NULL ) {
109                 return -1;
110             }
111             *adts = '\0';
112             if (( adt = strrchr( dtf, '/' )) == NULL ) {
113                 return -1;
114             }
115             *adt = '\0';
116             (void) ad_mkdir( dtf, DIRBITS | 0777 );
117             *adt = '/';
118             (void) ad_mkdir( dtf, DIRBITS | 0777 );
119             *adts = '/';
120
121             if (( si.sdt_fd = open( dtf, flags, ad_mode( dtf, mode ))) < 0 ) {
122                 LOG(log_error, logtype_afpd, "iconopen: open %s: %s", dtf, strerror(errno) );
123                 return -1;
124             }
125         } else {
126             return -1;
127         }
128     }
129
130     memcpy( si.sdt_creator, creator, sizeof( CreatorType ));
131     si.sdt_vid = vol->v_vid;
132     si.sdt_index = 1;
133     return 0;
134 }
135
136 int afp_addicon(obj, ibuf, ibuflen, rbuf, rbuflen)
137 AFPObj      *obj;
138 char    *ibuf, *rbuf;
139 int             ibuflen, *rbuflen;
140 {
141     struct vol          *vol;
142     struct iovec        iov[ 2 ];
143     u_char              fcreator[ 4 ], imh[ 12 ], irh[ 12 ], *p;
144     int                 itype, cc = AFP_OK, iovcnt = 0, buflen;
145     u_int32_t           ftype, itag;
146     u_int16_t           bsize, rsize, vid;
147
148     buflen = *rbuflen;
149     *rbuflen = 0;
150     ibuf += 2;
151
152     memcpy( &vid, ibuf, sizeof( vid ));
153     ibuf += sizeof( vid );
154     if (( vol = getvolbyvid( vid )) == NULL ) {
155         cc = AFPERR_PARAM;
156         goto addicon_err;
157     }
158
159     memcpy( fcreator, ibuf, sizeof( fcreator ));
160     ibuf += sizeof( fcreator );
161
162     memcpy( &ftype, ibuf, sizeof( ftype ));
163     ibuf += sizeof( ftype );
164
165     itype = (unsigned char) *ibuf;
166     ibuf += 2;
167
168     memcpy( &itag, ibuf, sizeof( itag ));
169     ibuf += sizeof( itag );
170
171     memcpy( &bsize, ibuf, sizeof( bsize ));
172     bsize = ntohs( bsize );
173
174     if ( si.sdt_fd != -1 ) {
175         (void)close( si.sdt_fd );
176         si.sdt_fd = -1;
177     }
178
179     if (iconopen( vol, fcreator, O_RDWR|O_CREAT, 0666 ) < 0) {
180         cc = AFPERR_NOITEM;
181         goto addicon_err;
182     }
183
184     if (lseek( si.sdt_fd, (off_t) 0L, SEEK_SET ) < 0) {
185         close(si.sdt_fd);
186         si.sdt_fd = -1;
187         LOG(log_error, logtype_afpd, "afp_addicon: lseek: %s", strerror(errno) );
188         cc = AFPERR_PARAM;
189         goto addicon_err;
190     }
191
192     /*
193      * Read icon elements until we find a match to replace, or
194      * we get to the end to insert.
195      */
196     p = imh;
197     memcpy( p, &itag, sizeof( itag ));
198     p += sizeof( itag );
199     memcpy( p, &ftype, sizeof( ftype ));
200     p += sizeof( ftype );
201     *p++ = itype;
202     *p++ = 0;
203     bsize = htons( bsize );
204     memcpy( p, &bsize, sizeof( bsize ));
205     bsize = ntohs( bsize );
206     while (( cc = read( si.sdt_fd, irh, sizeof( irh ))) > 0 ) {
207         memcpy( &rsize, irh + 10, sizeof( rsize ));
208         rsize = ntohs( rsize );
209         /*
210          * Is this our set of headers?
211          */
212         if ( memcmp( irh, imh, sizeof( irh ) - sizeof( u_short )) == 0 ) {
213             /*
214              * Is the size correct?
215              */
216             if ( bsize != rsize )
217                 cc = AFPERR_ITYPE;
218             break;
219         }
220
221         if ( lseek( si.sdt_fd, (off_t) rsize, SEEK_CUR ) < 0 ) {
222             LOG(log_error, logtype_afpd, "afp_addicon: lseek: %s", strerror(errno) );
223             cc = AFPERR_PARAM;
224         }
225     }
226
227     /*
228      * Some error occurred, return.
229      */
230 addicon_err:
231     if ( cc < 0 ) {
232         LOG(log_error, logtype_afpd, "afp_addicon: %s", strerror(errno) );
233         if (obj->proto == AFPPROTO_DSI) {
234             dsi_writeinit(obj->handle, rbuf, buflen);
235             dsi_writeflush(obj->handle);
236         }
237         return cc;
238     }
239
240
241     switch (obj->proto) {
242 #ifndef NO_DDP
243     case AFPPROTO_ASP:
244         buflen = bsize;
245         if ((asp_wrtcont(obj->handle, rbuf, &buflen) < 0) || buflen != bsize)
246             return( AFPERR_PARAM );
247
248         if (obj->options.flags & OPTION_DEBUG) {
249             printf("(write) len: %d\n", buflen);
250             bprint(rbuf, buflen);
251         }
252
253         /*
254          * We're at the end of the file, add the headers, etc.  */
255         if ( cc == 0 ) {
256             iov[ 0 ].iov_base = (caddr_t)imh;
257             iov[ 0 ].iov_len = sizeof( imh );
258             iov[ 1 ].iov_base = rbuf;
259             iov[ 1 ].iov_len = bsize;
260             iovcnt = 2;
261         }
262
263         /*
264          * We found an icon to replace.
265          */
266         if ( cc > 0 ) {
267             iov[ 0 ].iov_base = rbuf;
268             iov[ 0 ].iov_len = bsize;
269             iovcnt = 1;
270         }
271
272         if ( writev( si.sdt_fd, iov, iovcnt ) < 0 ) {
273             LOG(log_error, logtype_afpd, "afp_addicon: writev: %s", strerror(errno) );
274             return( AFPERR_PARAM );
275         }
276         break;
277 #endif /* no afp/asp */      
278     case AFPPROTO_DSI:
279         {
280             DSI *dsi = obj->handle;
281
282             iovcnt = dsi_writeinit(dsi, rbuf, buflen);
283
284             /* add headers at end of file */
285             if ((cc == 0) && (write(si.sdt_fd, imh, sizeof(imh)) < 0)) {
286                 LOG(log_error, logtype_afpd, "afp_addicon: write: %s", strerror(errno));
287                 dsi_writeflush(dsi);
288                 return AFPERR_PARAM;
289             }
290
291             if ((cc = write(si.sdt_fd, rbuf, iovcnt)) < 0) {
292                 LOG(log_error, logtype_afpd, "afp_addicon: write: %s", strerror(errno));
293                 dsi_writeflush(dsi);
294                 return AFPERR_PARAM;
295             }
296
297             while ((iovcnt = dsi_write(dsi, rbuf, buflen))) {
298                 if ( obj->options.flags & OPTION_DEBUG ) {
299                     printf("(write) command cont'd: %d\n", iovcnt);
300                     bprint(rbuf, iovcnt);
301                 }
302
303                 if ((cc = write(si.sdt_fd, rbuf, iovcnt)) < 0) {
304                     LOG(log_error, logtype_afpd, "afp_addicon: write: %s", strerror(errno));
305                     dsi_writeflush(dsi);
306                     return AFPERR_PARAM;
307                 }
308             }
309         }
310         break;
311     }
312
313     close( si.sdt_fd );
314     si.sdt_fd = -1;
315     return( AFP_OK );
316 }
317
318 u_char  utag[] = { 0, 0, 0, 0 };
319 u_char  ucreator[] = { 'U', 'N', 'I', 'X' };
320 u_char  utype[] = { 'T', 'E', 'X', 'T' };
321 short   usize = 256;
322 u_char  uicon[] = {
323     0x1F, 0xFF, 0xFC, 0x00, 0x10, 0x00, 0x06, 0x00,
324     0x10, 0x00, 0x05, 0x00, 0x10, 0x00, 0x04, 0x80,
325     0x10, 0x00, 0x04, 0x40, 0x10, 0x00, 0x04, 0x20,
326     0x10, 0x00, 0x07, 0xF0, 0x10, 0x00, 0x00, 0x10,
327     0x10, 0x00, 0x00, 0x10, 0x10, 0x00, 0x00, 0x10,
328     0x10, 0x00, 0x00, 0x10, 0x10, 0x80, 0x02, 0x10,
329     0x11, 0x80, 0x03, 0x10, 0x12, 0x80, 0x02, 0x90,
330     0x12, 0x80, 0x02, 0x90, 0x14, 0x80, 0x02, 0x50,
331     0x14, 0x87, 0xC2, 0x50, 0x14, 0x58, 0x34, 0x50,
332     0x14, 0x20, 0x08, 0x50, 0x12, 0x16, 0xD0, 0x90,
333     0x11, 0x01, 0x01, 0x10, 0x12, 0x80, 0x02, 0x90,
334     0x12, 0x9C, 0x72, 0x90, 0x14, 0x22, 0x88, 0x50,
335     0x14, 0x41, 0x04, 0x50, 0x14, 0x49, 0x24, 0x50,
336     0x14, 0x55, 0x54, 0x50, 0x14, 0x5D, 0x74, 0x50,
337     0x14, 0x5D, 0x74, 0x50, 0x12, 0x49, 0x24, 0x90,
338     0x12, 0x22, 0x88, 0x90, 0x1F, 0xFF, 0xFF, 0xF0,
339     0x1F, 0xFF, 0xFC, 0x00, 0x1F, 0xFF, 0xFE, 0x00,
340     0x1F, 0xFF, 0xFF, 0x00, 0x1F, 0xFF, 0xFF, 0x80,
341     0x1F, 0xFF, 0xFF, 0xC0, 0x1F, 0xFF, 0xFF, 0xE0,
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     0x1F, 0xFF, 0xFF, 0xF0, 0x1F, 0xFF, 0xFF, 0xF0,
351     0x1F, 0xFF, 0xFF, 0xF0, 0x1F, 0xFF, 0xFF, 0xF0,
352     0x1F, 0xFF, 0xFF, 0xF0, 0x1F, 0xFF, 0xFF, 0xF0,
353     0x1F, 0xFF, 0xFF, 0xF0, 0x1F, 0xFF, 0xFF, 0xF0,
354     0x1F, 0xFF, 0xFF, 0xF0, 0x1F, 0xFF, 0xFF, 0xF0,
355 };
356
357 int afp_geticoninfo(obj, ibuf, ibuflen, rbuf, rbuflen )
358 AFPObj      *obj;
359 char    *ibuf, *rbuf;
360 int             ibuflen, *rbuflen;
361 {
362     struct vol  *vol;
363     u_char      fcreator[ 4 ], ih[ 12 ];
364     u_int16_t   vid, iindex, bsize;
365
366     *rbuflen = 0;
367     ibuf += 2;
368
369     memcpy( &vid, ibuf, sizeof( vid ));
370     ibuf += sizeof( vid );
371     if (NULL == ( vol = getvolbyvid( vid )) ) {
372         return( AFPERR_PARAM );
373     }
374
375     memcpy( fcreator, ibuf, sizeof( fcreator ));
376     ibuf += sizeof( fcreator );
377     memcpy( &iindex, ibuf, sizeof( iindex ));
378     iindex = ntohs( iindex );
379
380     if ( memcmp( fcreator, ucreator, sizeof( ucreator )) == 0 ) {
381         if ( iindex > 1 ) {
382             return( AFPERR_NOITEM );
383         }
384         memcpy( ih, utag, sizeof( utag ));
385         memcpy( ih + sizeof( utag ), utype, sizeof( utype ));
386         *( ih + sizeof( utag ) + sizeof( utype )) = 1;
387         *( ih + sizeof( utag ) + sizeof( utype ) + 1 ) = 0;
388         memcpy( ih + sizeof( utag ) + sizeof( utype ) + 2, &usize,
389                 sizeof( usize ));
390         memcpy( rbuf, ih, sizeof( ih ));
391         *rbuflen = sizeof( ih );
392         return( AFP_OK );
393     }
394
395     if ( iconopen( vol, fcreator, O_RDONLY, 0 ) < 0) {
396         return( AFPERR_NOITEM );
397     }
398
399     if ( iindex < si.sdt_index ) {
400         if ( lseek( si.sdt_fd, (off_t) 0L, SEEK_SET ) < 0 ) {
401             return( AFPERR_PARAM );
402         }
403         si.sdt_index = 1;
404     }
405
406     /*
407      * Position to the correct spot.
408      */
409     for (;;) {
410         if ( read( si.sdt_fd, ih, sizeof( ih )) != sizeof( ih )) {
411             close( si.sdt_fd );
412             si.sdt_fd = -1;
413             return( AFPERR_NOITEM );
414         }
415         memcpy( &bsize, ih + 10, sizeof( bsize ));
416         bsize = ntohs(bsize);
417         if ( lseek( si.sdt_fd, (off_t) bsize, SEEK_CUR ) < 0 ) {
418             LOG(log_error, logtype_afpd, "afp_iconinfo: lseek: %s", strerror(errno) );
419             return( AFPERR_PARAM );
420         }
421         if ( si.sdt_index == iindex ) {
422             memcpy( rbuf, ih, sizeof( ih ));
423             *rbuflen = sizeof( ih );
424             return( AFP_OK );
425         }
426         si.sdt_index++;
427     }
428 }
429
430
431 int afp_geticon(obj, ibuf, ibuflen, rbuf, rbuflen )
432 AFPObj      *obj;
433 char    *ibuf, *rbuf;
434 int             ibuflen, *rbuflen;
435 {
436     struct vol  *vol;
437     off_t       offset;
438     int         rc, buflen;
439     u_char      fcreator[ 4 ], ftype[ 4 ], itype, ih[ 12 ];
440     u_int16_t   vid, bsize, rsize;
441
442     buflen = *rbuflen;
443     *rbuflen = 0;
444     ibuf += 2;
445
446     memcpy( &vid, ibuf, sizeof( vid ));
447     ibuf += sizeof( vid );
448     if (NULL == ( vol = getvolbyvid( vid )) ) {
449         return( AFPERR_PARAM );
450     }
451
452     memcpy( fcreator, ibuf, sizeof( fcreator ));
453     ibuf += sizeof( fcreator );
454     memcpy( ftype, ibuf, sizeof( ftype ));
455     ibuf += sizeof( ftype );
456     itype = (unsigned char) *ibuf++;
457     ibuf++;
458     memcpy( &bsize, ibuf, sizeof( bsize ));
459     bsize = ntohs( bsize );
460
461     if ( memcmp( fcreator, ucreator, sizeof( ucreator )) == 0 &&
462             memcmp( ftype, utype, sizeof( utype )) == 0 &&
463             itype == 1 &&
464             bsize <= usize ) {
465         memcpy( rbuf, uicon, bsize);
466         *rbuflen = bsize;
467         return( AFP_OK );
468     }
469
470     if ( iconopen( vol, fcreator, O_RDONLY, 0 ) < 0) {
471         return( AFPERR_NOITEM );
472     }
473
474     if ( lseek( si.sdt_fd, (off_t) 0L, SEEK_SET ) < 0 ) {
475         close(si.sdt_fd);
476         si.sdt_fd = -1;
477         LOG(log_error, logtype_afpd, "afp_geticon: lseek: %s", strerror(errno));
478         return( AFPERR_PARAM );
479     }
480
481     si.sdt_index = 1;
482     offset = 0;
483     while (( rc = read( si.sdt_fd, ih, sizeof( ih ))) > 0 ) {
484         si.sdt_index++;
485         offset += sizeof(ih);
486         if ( memcmp( ih + sizeof( int ), ftype, sizeof( ftype )) == 0 &&
487                 *(ih + sizeof( int ) + sizeof( ftype )) == itype ) {
488             break;
489         }
490         memcpy( &rsize, ih + 10, sizeof( rsize ));
491         rsize = ntohs( rsize );
492         if ( lseek( si.sdt_fd, (off_t) rsize, SEEK_CUR ) < 0 ) {
493             LOG(log_error, logtype_afpd, "afp_geticon: lseek: %s", strerror(errno) );
494             return( AFPERR_PARAM );
495         }
496         offset += rsize;
497     }
498
499     if ( rc < 0 ) {
500         LOG(log_error, logtype_afpd, "afp_geticon: read: %s", strerror(errno));
501         return( AFPERR_PARAM );
502     }
503
504     if ( rc == 0 ) {
505         return( AFPERR_NOITEM );
506     }
507
508     memcpy( &rsize, ih + 10, sizeof( rsize ));
509     rsize = ntohs( rsize );
510 #define min(a,b)        ((a)<(b)?(a):(b))
511     rc = min( bsize, rsize );
512
513     if ((obj->proto == AFPPROTO_DSI) && (buflen < rc)) {
514         DSI *dsi = obj->handle;
515         struct stat st;
516         off_t size;
517
518         size = (fstat(si.sdt_fd, &st) < 0) ? 0 : st.st_size;
519         if (size < rc + offset) {
520             return AFPERR_PARAM;
521         }
522
523         if ((*rbuflen = dsi_readinit(dsi, rbuf, buflen, rc, AFP_OK)) < 0)
524             goto geticon_exit;
525
526         /* do to the streaming nature, we have to exit if we encounter
527          * a problem. much confusion results otherwise. */
528         while (*rbuflen > 0) {
529 #if defined(SENDFILE_FLAVOR_LINUX) || defined(SENDFILE_FLAVOR_BSD)
530             if (!obj->options.flags & OPTION_DEBUG) {
531 #ifdef SENDFILE_FLAVOR_LINUX
532                 if (sendfile(dsi->socket, si.sdt_fd, &offset, dsi->datasize) < 0)
533                     goto geticon_exit;
534 #endif /* SENDFILE_FLAVOR_LINUX */
535
536 #ifdef SENDFILE_FLAVOR_BSD
537                 if (sendfile(si.sdt_fd, dsi->socket, offset, rc, NULL, NULL, 0) < 0)
538                     goto geticon_exit;
539 #endif /* SENDFILE_FLAVOR_BSD */
540
541                 goto geticon_done;
542             }
543 #endif /* SENDFILE_FLAVOR_LINUX || SENDFILE_FLAVOR_BSD */
544
545             buflen = read(si.sdt_fd, rbuf, *rbuflen);
546             if (buflen < 0)
547                 goto geticon_exit;
548
549             if (obj->options.flags & OPTION_DEBUG) {
550                 printf( "(read) reply: %d, %d\n", buflen, dsi->clientID);
551                 bprint(rbuf, buflen);
552             }
553
554             /* dsi_read() also returns buffer size of next allocation */
555             buflen = dsi_read(dsi, rbuf, buflen); /* send it off */
556             if (buflen < 0)
557                 goto geticon_exit;
558
559             *rbuflen = buflen;
560         }
561
562 geticon_done:
563         dsi_readdone(dsi);
564         return AFP_OK;
565
566 geticon_exit:
567         LOG(log_info, logtype_afpd, "afp_geticon: %s", strerror(errno));
568         dsi_readdone(dsi);
569         obj->exit(1);
570         return AFP_OK;
571
572     } else {
573         if ( read( si.sdt_fd, rbuf, rc ) < rc ) {
574             return( AFPERR_PARAM );
575         }
576         *rbuflen = rc;
577         return AFP_OK;
578     }
579 }
580
581
582 static char             hexdig[] = "0123456789abcdef";
583 char *dtfile(const struct vol *vol, u_char creator[], char *ext )
584 {
585     static char path[ MAXPATHLEN + 1];
586     char        *p;
587     unsigned int i;
588
589     strcpy( path, vol->v_path );
590     strcat( path, "/.AppleDesktop/" );
591     for ( p = path; *p != '\0'; p++ )
592         ;
593
594     if ( !isprint( creator[ 0 ] ) || creator[ 0 ] == '/' ) {
595         *p++ = hexdig[ ( creator[ 0 ] & 0xf0 ) >> 4 ];
596         *p++ = hexdig[ creator[ 0 ] & 0x0f ];
597     } else {
598         *p++ = creator[ 0 ];
599     }
600
601     *p++ = '/';
602
603     for ( i = 0; i < sizeof( CreatorType ); i++ ) {
604         if ( !isprint( creator[ i ] ) || creator[ i ] == '/' ) {
605             *p++ = hexdig[ ( creator[ i ] & 0xf0 ) >> 4 ];
606             *p++ = hexdig[ creator[ i ] & 0x0f ];
607         } else {
608             *p++ = creator[ i ];
609         }
610     }
611     *p = '\0';
612     strcat( path, ext );
613
614     return( path );
615 }
616
617 /* ---------------------------
618  * mpath is only a filename 
619 */
620 static char  upath[ MAXPATHLEN + 1];
621 static char  mpath[ MAXPATHLEN + 1];
622 static char  ucs2[ MAXPATHLEN + 1];
623
624 static char *old_mtoupath(const struct vol *vol, char *mpath)
625 {
626     char        *m, *u;
627     int          i = 0;
628     int          changed = 0;
629         
630     m = mpath;
631     u = upath;
632     while ( *m != '\0' ) {
633         /* handle case conversion first */
634         if (vol->v_casefold & AFPVOL_MTOUUPPER)
635             *m = diatoupper( *m );
636         else if (vol->v_casefold & AFPVOL_MTOULOWER)
637             *m = diatolower( *m );
638
639         /* we have a code page. we only use the ascii range
640          * if we have map ascii specified. */
641         if (vol->v_mtoupage && ((*m & 0x80) ||
642                                 vol->v_flags & AFPVOL_MAPASCII)) {
643             *u = vol->v_mtoupage->map[(unsigned char) *m].value;
644             changed = 1;
645             if (!*u && *m) {
646                 /* if conversion failed, encode in hex
647                  * to prevent silly truncation
648                  * H.P. Jansen <hpj@urpla.net> */
649 #ifdef DEBUG
650                 LOG(log_debug, logtype_afpd, "mtoupath: hex encode: 0x%x", (unsigned char) *m);
651 #endif
652                 *u++ = ':';
653                 *u++ = hexdig[ ( *m & 0xf0 ) >> 4 ];
654                 *u = hexdig[ *m & 0x0f ];
655             }
656         } else {
657 #if AD_VERSION == AD_VERSION1
658             if ((((vol->v_flags & AFPVOL_NOHEX) == 0) &&
659                     (!isascii(*m) || *m == '/')) ||
660                     (((vol->v_flags & AFPVOL_USEDOTS) == 0) &&
661                      ( i == 0 && (*m == '.' )))) {
662 #else 
663             if ((((vol->v_flags & AFPVOL_NOHEX) == 0) &&
664                     (!isprint(*m) || *m == '/')) ||
665                     (((vol->v_flags & AFPVOL_USEDOTS) == 0) &&
666                      ( i == 0 && (*m == '.' )))) {
667 #endif
668                 /* do hex conversion. */
669                 *u++ = ':';
670                 *u++ = hexdig[ ( *m & 0xf0 ) >> 4 ];
671                 *u = hexdig[ *m & 0x0f ];
672                 changed = 1;
673             } else
674                 *u = *m;
675         }
676         u++;
677         i++;
678         m++;
679     }
680     *u = '\0';
681
682 #ifdef DEBUG
683     LOG(log_debug, logtype_afpd, "mtoupath: '%s':'%s'", mpath, upath);
684 #endif /* DEBUG */
685
686     return( (changed)?upath:mpath );
687 }
688
689 /* ---------------------------- */
690 #define hextoint( c )   ( isdigit( c ) ? c - '0' : c + 10 - 'a' )
691 #define islxdigit(x)    (!isupper(x)&&isxdigit(x))
692
693 static char *old_utompath(const struct vol *vol, char *upath)
694 {
695     char        *m, *u;
696     int          h;
697     int          changed = 0;
698
699     /* do the hex conversion */
700     u = upath;
701     m = mpath;
702     while ( *u != '\0' ) {
703         /* we have a code page */
704         if (vol->v_utompage && ((*u & 0x80) ||
705                                 (vol->v_flags & AFPVOL_MAPASCII))) {
706             *m = vol->v_utompage->map[(unsigned char) *u].value;
707             changed = 1;
708         } else
709             if ( *u == ':' && *(u+1) != '\0' && islxdigit( *(u+1)) &&
710                     *(u+2) != '\0' && islxdigit( *(u+2))) {
711                 ++u;
712                 h = hextoint( *u ) << 4;
713                 ++u;
714                 h |= hextoint( *u );
715                 *m = h;
716                 changed = 1;
717             } else
718                 *m = *u;
719
720         /* handle case conversion */
721         if (vol->v_casefold & AFPVOL_UTOMLOWER)
722             *m = diatolower( *m );
723         else if (vol->v_casefold & AFPVOL_UTOMUPPER)
724             *m = diatoupper( *m );
725
726         u++;
727         m++;
728     }
729     *m = '\0';
730     m = mpath;
731
732 #ifdef FILE_MANGLING
733     m = mangle(vol, mpath, upath, 0);
734     if (m != mpath) {
735         changed = 1;
736     }
737 #endif /* FILE_MANGLING */
738
739 #ifdef DEBUG
740     LOG(log_debug, logtype_afpd, "utompath: '%s':'%s'", upath, mpath);
741 #endif /* DEBUG */
742
743     return((changed)? m:upath );
744 }
745
746 /* --------------- */
747 extern unsigned int do_precomposition(unsigned int base, unsigned int comb);
748
749 static char comp[MAXPATHLEN +1];
750
751 static char *precompose(u_int16_t  *name, size_t inplen, size_t *outlen)
752 {
753 size_t i;
754 u_int16_t base, comb;
755 u_int16_t *in, *out;
756 u_int16_t result;
757
758     if (!inplen || (inplen & 1) || inplen > sizeof(comp)/sizeof(u_int16_t))
759         return NULL;
760     i = 0;
761     in  = name;
762     out = (u_int16_t *)comp;
763     *outlen = 0;
764     
765     base = *in;
766     while (1) {
767         i += 2;
768         in++;
769         if (i == inplen) {
770            *out = base;
771            *outlen += 2;
772            return comp;
773         }
774         comb = *in;
775         if (comb >= 0x300 && (result = do_precomposition(base, comb))) {
776            *out = result;
777            out++;
778            *outlen += 2;
779            i += 2;
780            in++;
781            if (i == inplen) 
782               return comp;
783            base = *in;
784         }
785         else {
786            *out = base;
787            out++;
788            *outlen += 2;
789            base = comb;
790         }
791     }
792 }
793
794 /* --------------- */
795 extern unsigned int do_decomposition(unsigned int base);
796
797 static char *decompose(u_int16_t  *name, size_t inplen, size_t *outlen)
798 {
799 size_t i;
800 u_int16_t base;
801 u_int16_t *in, *out;
802 unsigned int result;
803
804     if (!inplen || (inplen & 1))
805         return NULL;
806     i = 0;
807     in  = name;
808     out = (u_int16_t *)comp;
809     *outlen = 0;
810     
811     while (i < inplen) {
812         if (*outlen >= sizeof(comp)/sizeof(u_int16_t) +2) {
813             return NULL;
814         }
815         base = *in;
816         if ((result = do_decomposition(base))) {
817            *out = result  >> 16;
818            out++;
819            *outlen += 2;
820            *out = result & 0xffff;
821            out++;
822            *outlen += 2;
823         }
824         else {
825            *out = base;
826            out++;
827            *outlen += 2;
828         }
829         i += 2;
830         in++;
831      }
832      return comp;
833 }
834
835 /* --------------------------- */
836 char *mtoupath(const struct vol *vol, char *mpath, int utf8)
837 {
838     char        *m, *u, *r;
839     int          i = 0;
840     size_t       inplen;
841     size_t       outlen;
842         
843     if ( *mpath == '\0' ) {
844         return( "." );
845     }
846
847 #ifdef FILE_MANGLING
848     m = demangle(vol, mpath);
849     if (m != mpath) {
850         return m;
851     }
852 #endif /* FILE_MANGLING */
853
854     if (!vol_utf8(vol))
855         return old_mtoupath(vol, mpath);
856
857     m = mpath;
858     u = upath;
859     while ( *m != '\0' ) {
860         if ( (!(vol->v_flags & AFPVOL_NOHEX) && *m == '/') ||
861              (!(vol->v_flags & AFPVOL_USEDOTS) && i == 0 && *m == '.') ||
862              (!utf8 && (unsigned char)*m == 0xf0) /* Apple logo */
863         ) {
864           /* do hex conversion. */
865           *u++ = ':';
866           *u++ = hexdig[ ( *m & 0xf0 ) >> 4 ];
867           *u = hexdig[ *m & 0x0f ];
868         } else
869            *u = *m;
870         u++;
871         i++;
872         m++;
873     }
874     *u = '\0';
875     u = upath;
876 #ifdef AFP3x
877     inplen = strlen(u);
878     outlen = MAXPATHLEN;
879     r = ucs2;
880     if (!utf8) {
881         if ((size_t)(-1) == iconv(vol->v_mactoutf8, 0,0,0,0) )
882             return NULL;
883         /* assume precompose */
884         if ((size_t)(-1) == iconv(vol->v_mactoutf8, &u, &inplen, &r, &outlen))
885             return NULL;
886         u = ucs2;
887     }
888     else { 
889         if ((size_t)(-1) == iconv(vol->v_utf8toucs2, 0,0,0,0) )
890             return NULL;
891
892         if ((size_t)(-1) == iconv(vol->v_utf8toucs2, &u, &inplen, &r, &outlen))
893             return NULL;
894
895         u = precompose((u_int16_t *)ucs2, MAXPATHLEN -outlen, &inplen);
896
897         if ((size_t)(-1) == iconv(vol->v_ucs2toutf8, 0,0,0,0))
898             return NULL;
899             
900         outlen = MAXPATHLEN;
901         r = upath;
902         if ((size_t)(-1) == iconv(vol->v_ucs2toutf8, &u, &inplen, &r, &outlen))
903             return NULL;
904         u = upath;
905     }
906     u[MAXPATHLEN -outlen] = 0;
907 #endif
908 #ifdef DEBUG
909     LOG(log_debug, logtype_afpd, "mtoupath: '%s':'%s'", mpath, upath);
910 #endif /* DEBUG */
911     return( u );
912 }
913
914 /* --------------- */
915 char *utompath(const struct vol *vol, char *upath, int utf8)
916 {
917     char        *m, *u, *r;
918     int          h;
919     int          mangleflag = 0;
920     size_t       inplen;
921     size_t       outlen;
922
923     if (!vol_utf8(vol))
924         return old_utompath(vol, upath);
925     /* do the hex conversion */
926     u = upath;
927     m = mpath;
928     while ( *u != '\0' ) {
929         if ( *u == ':' && islxdigit( *(u+1)) && islxdigit( *(u+2))) {
930             ++u;
931             h = hextoint( *u ) << 4;
932             ++u;
933             h |= hextoint( *u );
934             *m = h;
935         } else
936             *m = *u;
937         u++;
938         m++;
939     }
940     *m = '\0';
941     m = mpath;
942 #ifdef AFP3x    
943     if ((size_t)(-1) == iconv(vol->v_utf8toucs2, 0,0,0,0) )
944         return NULL;
945     inplen = strlen(mpath);
946     outlen = MAXPATHLEN;
947     r = ucs2;
948     if ((size_t)(-1) == iconv(vol->v_utf8toucs2, &m, &inplen, &r, &outlen))
949         return NULL;
950
951     if (utf8) {
952         if ( NULL == (m = decompose((u_int16_t *)ucs2, MAXPATHLEN -outlen, &inplen)))
953             return NULL;
954
955         if ((size_t)(-1) == iconv(vol->v_ucs2toutf8, 0,0,0,0))
956             return NULL;
957             
958         outlen = MAXPATHLEN;
959         r = mpath;
960         if ((size_t)(-1) == iconv(vol->v_ucs2toutf8, &m, &inplen, &r, &outlen))
961             return NULL;
962     }
963     else {
964         m = precompose((u_int16_t *)ucs2, MAXPATHLEN -outlen, &inplen);
965
966         if ((size_t)(-1) == iconv(vol->v_ucs2tomac, 0,0,0,0))
967             return NULL;
968             
969         outlen = MAXPATHLEN;
970         r = mpath;
971         if ((size_t)(-1) == iconv(vol->v_ucs2tomac, &m, &inplen, &r, &outlen)) {
972             switch (errno) {
973             case EILSEQ:
974                 if (outlen != MAXPATHLEN) {
975                     mangleflag = 1;
976                 }
977             default:
978                 return NULL;
979             }
980         }
981     }
982     mpath[MAXPATHLEN -outlen] = 0;
983 #endif
984 #ifdef FILE_MANGLING
985     m = mangle(vol, mpath, upath, mangleflag);
986 #endif /* FILE_MANGLING */
987
988     return(m);
989 }
990
991 /* ----------------------------- */
992 int afp_addcomment(obj, ibuf, ibuflen, rbuf, rbuflen )
993 AFPObj      *obj;
994 char    *ibuf, *rbuf;
995 int             ibuflen, *rbuflen;
996 {
997     struct adouble      ad, *adp;
998     struct vol          *vol;
999     struct dir          *dir;
1000     struct ofork        *of;
1001     struct path         *path;
1002     char                *name, *upath;
1003     int                 clen;
1004     u_int32_t           did;
1005     u_int16_t           vid;
1006     int                 isadir;
1007
1008     *rbuflen = 0;
1009     ibuf += 2;
1010
1011     memcpy( &vid, ibuf, sizeof( vid ));
1012     ibuf += sizeof( vid );
1013     if (NULL == ( vol = getvolbyvid( vid )) ) {
1014         return( AFPERR_PARAM );
1015     }
1016
1017     memcpy( &did, ibuf, sizeof( did ));
1018     ibuf += sizeof( did );
1019     if (NULL == ( dir = dirlookup( vol, did )) ) {
1020         return afp_errno;
1021     }
1022
1023     if (NULL == ( path = cname( vol, dir, &ibuf )) ) {
1024         return get_afp_errno(AFPERR_NOOBJ);
1025     }
1026
1027     if ((u_long)ibuf & 1 ) {
1028         ibuf++;
1029     }
1030
1031     clen = (u_char)*ibuf++;
1032     clen = min( clen, 199 );
1033
1034     upath = path->u_name;
1035     if (check_access(upath, OPENACC_WR ) < 0) {
1036         return AFPERR_ACCESS;
1037     }
1038
1039     isadir = path_isadir(path);
1040     if (isadir || !(of = of_findname(path))) {
1041         memset(&ad, 0, sizeof(ad));
1042         adp = &ad;
1043     } else
1044         adp = of->of_ad;
1045
1046     if (ad_open( upath , vol_noadouble(vol) |
1047                  (( isadir) ? ADFLAGS_HF|ADFLAGS_DIR : ADFLAGS_HF),
1048                  O_RDWR|O_CREAT, 0666, adp) < 0 ) {
1049         return( AFPERR_ACCESS );
1050     }
1051
1052     if ( (ad_getoflags( adp, ADFLAGS_HF ) & O_CREAT) ) {
1053         if ( *path->m_name == '\0' ) {
1054             name = curdir->d_m_name;
1055         } else {
1056             name = path->m_name;
1057         }
1058         ad_setentrylen( adp, ADEID_NAME, strlen( name ));
1059         memcpy( ad_entry( adp, ADEID_NAME ), name,
1060                 ad_getentrylen( adp, ADEID_NAME ));
1061     }
1062
1063     ad_setentrylen( adp, ADEID_COMMENT, clen );
1064     memcpy( ad_entry( adp, ADEID_COMMENT ), ibuf, clen );
1065     ad_flush( adp, ADFLAGS_HF );
1066     ad_close( adp, ADFLAGS_HF );
1067     return( AFP_OK );
1068 }
1069
1070 int afp_getcomment(obj, ibuf, ibuflen, rbuf, rbuflen )
1071 AFPObj      *obj;
1072 char    *ibuf, *rbuf;
1073 int             ibuflen, *rbuflen;
1074 {
1075     struct adouble      ad, *adp;
1076     struct vol          *vol;
1077     struct dir          *dir;
1078     struct ofork        *of;
1079     struct path         *s_path;
1080     char                *upath;
1081     u_int32_t           did;
1082     u_int16_t           vid;
1083     int                 isadir;
1084     
1085     *rbuflen = 0;
1086     ibuf += 2;
1087
1088     memcpy( &vid, ibuf, sizeof( vid ));
1089     ibuf += sizeof( vid );
1090     if (NULL == ( vol = getvolbyvid( vid )) ) {
1091         return( AFPERR_PARAM );
1092     }
1093
1094     memcpy( &did, ibuf, sizeof( did ));
1095     ibuf += sizeof( did );
1096     if (NULL == ( dir = dirlookup( vol, did )) ) {
1097         return afp_errno;
1098     }
1099
1100     if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
1101         return get_afp_errno(AFPERR_NOOBJ);
1102     }
1103
1104     upath = s_path->u_name;
1105     isadir = path_isadir(s_path);
1106     if (isadir || !(of = of_findname(s_path))) {
1107         memset(&ad, 0, sizeof(ad));
1108         adp = &ad;
1109     } else
1110         adp = of->of_ad;
1111     if ( ad_open( upath,
1112                   ( isadir) ? ADFLAGS_HF|ADFLAGS_DIR : ADFLAGS_HF,
1113                   O_RDONLY, 0666, adp) < 0 ) {
1114         return( AFPERR_NOITEM );
1115     }
1116
1117     /*
1118      * Make sure the AD file is not bogus.
1119      */
1120     if ( ad_getentrylen( adp, ADEID_COMMENT ) < 0 ||
1121             ad_getentrylen( adp, ADEID_COMMENT ) > 199 ) {
1122         ad_close( adp, ADFLAGS_HF );
1123         return( AFPERR_NOITEM );
1124     }
1125
1126     *rbuf++ = ad_getentrylen( adp, ADEID_COMMENT );
1127     memcpy( rbuf, ad_entry( adp, ADEID_COMMENT ),
1128             ad_getentrylen( adp, ADEID_COMMENT ));
1129     *rbuflen = ad_getentrylen( adp, ADEID_COMMENT ) + 1;
1130     ad_close( adp, ADFLAGS_HF );
1131
1132     /* return AFPERR_NOITEM if len == 0 ? */
1133     return( AFP_OK );
1134 }
1135
1136 int afp_rmvcomment(obj, ibuf, ibuflen, rbuf, rbuflen )
1137 AFPObj      *obj;
1138 char    *ibuf, *rbuf;
1139 int             ibuflen, *rbuflen;
1140 {
1141     struct adouble      ad, *adp;
1142     struct vol          *vol;
1143     struct dir          *dir;
1144     struct ofork        *of;
1145     struct path         *s_path;
1146     char                *upath;
1147     u_int32_t           did;
1148     u_int16_t           vid;
1149     int                 isadir;
1150
1151     *rbuflen = 0;
1152     ibuf += 2;
1153
1154     memcpy( &vid, ibuf, sizeof( vid ));
1155     ibuf += sizeof( vid );
1156     if (NULL == ( vol = getvolbyvid( vid )) ) {
1157         return( AFPERR_PARAM );
1158     }
1159
1160     memcpy( &did, ibuf, sizeof( did ));
1161     ibuf += sizeof( did );
1162     if (NULL == ( dir = dirlookup( vol, did )) ) {
1163         return afp_errno;
1164     }
1165
1166     if (NULL == ( s_path = cname( vol, dir, &ibuf ))) {
1167         return get_afp_errno(AFPERR_NOOBJ);
1168     }
1169
1170     upath = s_path->u_name;
1171     if (check_access(upath, OPENACC_WR ) < 0) {
1172         return AFPERR_ACCESS;
1173     }
1174
1175     isadir = path_isadir(s_path);
1176     if (isadir || !(of = of_findname(s_path))) {
1177         memset(&ad, 0, sizeof(ad));
1178         adp = &ad;
1179     } else
1180         adp = of->of_ad;
1181
1182     if ( ad_open( upath,
1183                    (isadir) ? ADFLAGS_HF|ADFLAGS_DIR : ADFLAGS_HF,
1184                   O_RDWR, 0, adp) < 0 ) {
1185         switch ( errno ) {
1186         case ENOENT :
1187             return( AFPERR_NOITEM );
1188         case EACCES :
1189             return( AFPERR_ACCESS );
1190         default :
1191             return( AFPERR_PARAM );
1192         }
1193     }
1194
1195     ad_setentrylen( adp, ADEID_COMMENT, 0 );
1196     ad_flush( adp, ADFLAGS_HF );
1197     ad_close( adp, ADFLAGS_HF );
1198     return( AFP_OK );
1199 }