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