]> arthur.barton.de Git - netatalk.git/blob - etc/afpd/desktop.c
fcd764fa44b61b06a9ad64d14939e7a00570703a
[netatalk.git] / etc / afpd / desktop.c
1 /*
2  * $Id: desktop.c,v 1.32 2005-05-14 12:54:49 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 <stdio.h>
17 #include <string.h>
18 #include <ctype.h>
19
20 #include <errno.h>
21 #include <dirent.h>
22
23 #include <atalk/adouble.h>
24 #include <sys/uio.h>
25 #include <sys/param.h>
26 #include <sys/socket.h>
27 #include <netatalk/at.h>
28 #include <netatalk/endian.h>
29 #include <atalk/dsi.h>
30 #include <atalk/atp.h>
31 #include <atalk/asp.h>
32 #include <atalk/afp.h>
33 #include <atalk/util.h>
34 #include <atalk/logger.h>
35 #include "volume.h"
36 #include "directory.h"
37 #include "fork.h"
38 #include "globals.h"
39 #include "desktop.h"
40 #include "mangle.h"
41
42
43 int afp_opendt(obj, ibuf, ibuflen, rbuf, rbuflen )
44 AFPObj  *obj _U_;
45 char    *ibuf, *rbuf;
46 int     ibuflen _U_, *rbuflen;
47 {
48     struct vol  *vol;
49     u_int16_t   vid;
50
51     ibuf += 2;
52
53     memcpy( &vid, ibuf, sizeof(vid));
54     if (NULL == ( vol = getvolbyvid( vid )) ) {
55         *rbuflen = 0;
56         return( AFPERR_PARAM );
57     }
58
59     memcpy( rbuf, &vid, sizeof(vid));
60     *rbuflen = sizeof(vid);
61     return( AFP_OK );
62 }
63
64 int afp_closedt(obj, ibuf, ibuflen, rbuf, rbuflen )
65 AFPObj  *obj _U_;
66 char    *ibuf _U_, *rbuf _U_;
67 int     ibuflen _U_, *rbuflen;
68 {
69     *rbuflen = 0;
70     return( AFP_OK );
71 }
72
73 struct savedt   si = { { 0, 0, 0, 0 }, -1, 0, 0 };
74
75 static char *icon_dtfile(struct vol *vol, u_char creator[ 4 ])
76 {
77     return dtfile( vol, creator, ".icon" );
78 }
79
80 static int iconopen( vol, creator, flags, mode )
81 struct vol      *vol;
82 u_char  creator[ 4 ];
83 int flags;
84 int mode;
85 {
86     char        *dtf, *adt, *adts;
87
88     if ( si.sdt_fd != -1 ) {
89         if ( memcmp( si.sdt_creator, creator, sizeof( CreatorType )) == 0 &&
90                 si.sdt_vid == vol->v_vid ) {
91             return 0;
92         }
93         close( si.sdt_fd );
94         si.sdt_fd = -1;
95     }
96
97     dtf = icon_dtfile( vol, creator);
98
99     if (( si.sdt_fd = open( dtf, flags, ad_mode( dtf, mode ))) < 0 ) {
100         if ( errno == ENOENT && ( flags & O_CREAT )) {
101             if (( adts = strrchr( dtf, '/' )) == NULL ) {
102                 return -1;
103             }
104             *adts = '\0';
105             if (( adt = strrchr( dtf, '/' )) == NULL ) {
106                 return -1;
107             }
108             *adt = '\0';
109             (void) ad_mkdir( dtf, DIRBITS | 0777 );
110             *adt = '/';
111             (void) ad_mkdir( dtf, DIRBITS | 0777 );
112             *adts = '/';
113
114             if (( si.sdt_fd = open( dtf, flags, ad_mode( dtf, mode ))) < 0 ) {
115                 LOG(log_error, logtype_afpd, "iconopen(%s): open: %s", dtf, strerror(errno) );
116                 return -1;
117             }
118         } else {
119             return -1;
120         }
121     }
122
123     memcpy( si.sdt_creator, creator, sizeof( CreatorType ));
124     si.sdt_vid = vol->v_vid;
125     si.sdt_index = 1;
126     return 0;
127 }
128
129 int afp_addicon(obj, ibuf, ibuflen, rbuf, rbuflen)
130 AFPObj  *obj;
131 char    *ibuf, *rbuf;
132 int     ibuflen _U_, *rbuflen;
133 {
134     struct vol          *vol;
135 #ifndef NO_DDP
136     struct iovec        iov[ 2 ];
137 #endif
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 (NULL == ( vol = getvolbyvid( vid )) ) {
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(%s): lseek: %s", icon_dtfile(vol, fcreator), 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(%s): lseek: %s", icon_dtfile(vol, fcreator),strerror(errno) );
218             cc = AFPERR_PARAM;
219         }
220     }
221
222     /*
223      * Some error occurred, return.
224      */
225 addicon_err:
226     if ( cc < 0 ) {
227         if (obj->proto == AFPPROTO_DSI) {
228             dsi_writeinit(obj->handle, rbuf, buflen);
229             dsi_writeflush(obj->handle);
230         }
231         return cc;
232     }
233
234     switch (obj->proto) {
235 #ifndef NO_DDP
236     case AFPPROTO_ASP:
237         buflen = bsize;
238         if ((asp_wrtcont(obj->handle, rbuf, &buflen) < 0) || buflen != bsize)
239             return( AFPERR_PARAM );
240
241 #ifdef DEBUG1
242         if (obj->options.flags & OPTION_DEBUG) {
243             printf("(write) len: %d\n", buflen);
244             bprint(rbuf, buflen);
245         }
246 #endif
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(%s): writev: %s", icon_dtfile(vol, fcreator), 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(%s): write: %s", icon_dtfile(vol, fcreator), 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(%s): write: %s", icon_dtfile(vol, fcreator), strerror(errno));
288                 dsi_writeflush(dsi);
289                 return AFPERR_PARAM;
290             }
291
292             while ((iovcnt = dsi_write(dsi, rbuf, buflen))) {
293 #ifdef DEBUG1
294                 if ( obj->options.flags & OPTION_DEBUG ) {
295                     printf("(write) command cont'd: %d\n", iovcnt);
296                     bprint(rbuf, iovcnt);
297                 }
298 #endif
299                 if ((cc = write(si.sdt_fd, rbuf, iovcnt)) < 0) {
300                     LOG(log_error, logtype_afpd, "afp_addicon(%s): write: %s", icon_dtfile(vol, fcreator), strerror(errno));
301                     dsi_writeflush(dsi);
302                     return AFPERR_PARAM;
303                 }
304             }
305         }
306         break;
307     }
308
309     close( si.sdt_fd );
310     si.sdt_fd = -1;
311     return( AFP_OK );
312 }
313
314 static const u_char     utag[] = { 0, 0, 0, 0 };
315 static const u_char     ucreator[] = { 0, 0, 0, 0 };/* { 'U', 'N', 'I', 'X' };*/
316 static const u_char     utype[] = { 0, 0, 0, 0 };/* { 'T', 'E', 'X', 'T' };*/
317 static const short      usize = 256;
318 static const u_char     uicon[] = {
319     0x1F, 0xFF, 0xFC, 0x00, 0x10, 0x00, 0x06, 0x00,
320     0x10, 0x00, 0x05, 0x00, 0x10, 0x00, 0x04, 0x80,
321     0x10, 0x00, 0x04, 0x40, 0x10, 0x00, 0x04, 0x20,
322     0x10, 0x00, 0x07, 0xF0, 0x10, 0x00, 0x00, 0x10,
323     0x10, 0x00, 0x00, 0x10, 0x10, 0x00, 0x00, 0x10,
324     0x10, 0x00, 0x00, 0x10, 0x10, 0x80, 0x02, 0x10,
325     0x11, 0x80, 0x03, 0x10, 0x12, 0x80, 0x02, 0x90,
326     0x12, 0x80, 0x02, 0x90, 0x14, 0x80, 0x02, 0x50,
327     0x14, 0x87, 0xC2, 0x50, 0x14, 0x58, 0x34, 0x50,
328     0x14, 0x20, 0x08, 0x50, 0x12, 0x16, 0xD0, 0x90,
329     0x11, 0x01, 0x01, 0x10, 0x12, 0x80, 0x02, 0x90,
330     0x12, 0x9C, 0x72, 0x90, 0x14, 0x22, 0x88, 0x50,
331     0x14, 0x41, 0x04, 0x50, 0x14, 0x49, 0x24, 0x50,
332     0x14, 0x55, 0x54, 0x50, 0x14, 0x5D, 0x74, 0x50,
333     0x14, 0x5D, 0x74, 0x50, 0x12, 0x49, 0x24, 0x90,
334     0x12, 0x22, 0x88, 0x90, 0x1F, 0xFF, 0xFF, 0xF0,
335     0x1F, 0xFF, 0xFC, 0x00, 0x1F, 0xFF, 0xFE, 0x00,
336     0x1F, 0xFF, 0xFF, 0x00, 0x1F, 0xFF, 0xFF, 0x80,
337     0x1F, 0xFF, 0xFF, 0xC0, 0x1F, 0xFF, 0xFF, 0xE0,
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     0x1F, 0xFF, 0xFF, 0xF0, 0x1F, 0xFF, 0xFF, 0xF0,
351 };
352
353 int afp_geticoninfo(obj, ibuf, ibuflen, rbuf, rbuflen )
354 AFPObj  *obj _U_;
355 char    *ibuf, *rbuf;
356 int     ibuflen _U_, *rbuflen;
357 {
358     struct vol  *vol;
359     u_char      fcreator[ 4 ], ih[ 12 ];
360     u_int16_t   vid, iindex, bsize;
361
362     *rbuflen = 0;
363     ibuf += 2;
364
365     memcpy( &vid, ibuf, sizeof( vid ));
366     ibuf += sizeof( vid );
367     if (NULL == ( vol = getvolbyvid( vid )) ) {
368         return( AFPERR_PARAM );
369     }
370
371     memcpy( fcreator, ibuf, sizeof( fcreator ));
372     ibuf += sizeof( fcreator );
373     memcpy( &iindex, ibuf, sizeof( iindex ));
374     iindex = ntohs( iindex );
375
376     if ( memcmp( fcreator, ucreator, sizeof( ucreator )) == 0 ) {
377         if ( iindex > 1 ) {
378             return( AFPERR_NOITEM );
379         }
380         memcpy( ih, utag, sizeof( utag ));
381         memcpy( ih + sizeof( utag ), utype, sizeof( utype ));
382         *( ih + sizeof( utag ) + sizeof( utype )) = 1;
383         *( ih + sizeof( utag ) + sizeof( utype ) + 1 ) = 0;
384         memcpy( ih + sizeof( utag ) + sizeof( utype ) + 2, &usize,
385                 sizeof( usize ));
386         memcpy( rbuf, ih, sizeof( ih ));
387         *rbuflen = sizeof( ih );
388         return( AFP_OK );
389     }
390
391     if ( iconopen( vol, fcreator, O_RDONLY, 0 ) < 0) {
392         return( AFPERR_NOITEM );
393     }
394
395     if ( iindex < si.sdt_index ) {
396         if ( lseek( si.sdt_fd, (off_t) 0L, SEEK_SET ) < 0 ) {
397             return( AFPERR_PARAM );
398         }
399         si.sdt_index = 1;
400     }
401
402     /*
403      * Position to the correct spot.
404      */
405     for (;;) {
406         if ( read( si.sdt_fd, ih, sizeof( ih )) != sizeof( ih )) {
407             close( si.sdt_fd );
408             si.sdt_fd = -1;
409             return( AFPERR_NOITEM );
410         }
411         memcpy( &bsize, ih + 10, sizeof( bsize ));
412         bsize = ntohs(bsize);
413         if ( lseek( si.sdt_fd, (off_t) bsize, SEEK_CUR ) < 0 ) {
414             LOG(log_error, logtype_afpd, "afp_iconinfo(%s): lseek: %s", icon_dtfile(vol, fcreator), strerror(errno) );
415             return( AFPERR_PARAM );
416         }
417         if ( si.sdt_index == iindex ) {
418             memcpy( rbuf, ih, sizeof( ih ));
419             *rbuflen = sizeof( ih );
420             return( AFP_OK );
421         }
422         si.sdt_index++;
423     }
424 }
425
426
427 int afp_geticon(obj, ibuf, ibuflen, rbuf, rbuflen )
428 AFPObj  *obj;
429 char    *ibuf, *rbuf;
430 int     ibuflen _U_, *rbuflen;
431 {
432     struct vol  *vol;
433     off_t       offset;
434     int         rc, buflen;
435     u_char      fcreator[ 4 ], ftype[ 4 ], itype, ih[ 12 ];
436     u_int16_t   vid, bsize, rsize;
437
438     buflen = *rbuflen;
439     *rbuflen = 0;
440     ibuf += 2;
441
442     memcpy( &vid, ibuf, sizeof( vid ));
443     ibuf += sizeof( vid );
444     if (NULL == ( vol = getvolbyvid( vid )) ) {
445         return( AFPERR_PARAM );
446     }
447
448     memcpy( fcreator, ibuf, sizeof( fcreator ));
449     ibuf += sizeof( fcreator );
450     memcpy( ftype, ibuf, sizeof( ftype ));
451     ibuf += sizeof( ftype );
452     itype = (unsigned char) *ibuf++;
453     ibuf++;
454     memcpy( &bsize, ibuf, sizeof( bsize ));
455     bsize = ntohs( bsize );
456
457     if ( memcmp( fcreator, ucreator, sizeof( ucreator )) == 0 &&
458             memcmp( ftype, utype, sizeof( utype )) == 0 &&
459             itype == 1 &&
460             bsize <= usize ) {
461         memcpy( rbuf, uicon, bsize);
462         *rbuflen = bsize;
463         return( AFP_OK );
464     }
465
466     if ( iconopen( vol, fcreator, O_RDONLY, 0 ) < 0) {
467         return( AFPERR_NOITEM );
468     }
469
470     if ( lseek( si.sdt_fd, (off_t) 0L, SEEK_SET ) < 0 ) {
471         close(si.sdt_fd);
472         si.sdt_fd = -1;
473         LOG(log_error, logtype_afpd, "afp_geticon(%s): lseek: %s", icon_dtfile(vol, fcreator), strerror(errno));
474         return( AFPERR_PARAM );
475     }
476
477     si.sdt_index = 1;
478     offset = 0;
479     while (( rc = read( si.sdt_fd, ih, sizeof( ih ))) > 0 ) {
480         si.sdt_index++;
481         offset += sizeof(ih);
482         if ( memcmp( ih + sizeof( int ), ftype, sizeof( ftype )) == 0 &&
483                 *(ih + sizeof( int ) + sizeof( ftype )) == itype ) {
484             break;
485         }
486         memcpy( &rsize, ih + 10, sizeof( rsize ));
487         rsize = ntohs( rsize );
488         if ( lseek( si.sdt_fd, (off_t) rsize, SEEK_CUR ) < 0 ) {
489             LOG(log_error, logtype_afpd, "afp_geticon(%s): lseek: %s", icon_dtfile(vol, fcreator), strerror(errno) );
490             return( AFPERR_PARAM );
491         }
492         offset += rsize;
493     }
494
495     if ( rc < 0 ) {
496         LOG(log_error, logtype_afpd, "afp_geticon(%s): read: %s", icon_dtfile(vol, fcreator), strerror(errno));
497         return( AFPERR_PARAM );
498     }
499
500     if ( rc == 0 ) {
501         return( AFPERR_NOITEM );
502     }
503
504     memcpy( &rsize, ih + 10, sizeof( rsize ));
505     rsize = ntohs( rsize );
506 #define min(a,b)        ((a)<(b)?(a):(b))
507     rc = min( bsize, rsize );
508
509     if ((obj->proto == AFPPROTO_DSI) && (buflen < rc)) {
510         DSI *dsi = obj->handle;
511         struct stat st;
512         off_t size;
513
514         size = (fstat(si.sdt_fd, &st) < 0) ? 0 : st.st_size;
515         if (size < rc + offset) {
516             return AFPERR_PARAM;
517         }
518
519         if ((*rbuflen = dsi_readinit(dsi, rbuf, buflen, rc, AFP_OK)) < 0)
520             goto geticon_exit;
521
522         /* do to the streaming nature, we have to exit if we encounter
523          * a problem. much confusion results otherwise. */
524         while (*rbuflen > 0) {
525 #ifdef WITH_SENDFILE
526             if (!obj->options.flags & OPTION_DEBUG) {
527                 if (sys_sendfile(dsi->socket, si.sdt_fd, &offset, dsi->datasize) < 0) {
528                     switch (errno) {
529                     case ENOSYS:
530                     case EINVAL:  /* there's no guarantee that all fs support sendfile */
531                         break;
532                     default:
533                         goto geticon_exit;
534                     }
535                 }
536                 goto geticon_done;
537             }
538 #endif
539             buflen = read(si.sdt_fd, rbuf, *rbuflen);
540             if (buflen < 0)
541                 goto geticon_exit;
542
543 #ifdef DEBUG1
544             if (obj->options.flags & OPTION_DEBUG) {
545                 printf( "(read) reply: %d, %d\n", buflen, dsi->clientID);
546                 bprint(rbuf, buflen);
547             }
548 #endif
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): %s", icon_dtfile(vol, fcreator), strerror(errno));
563         dsi_readdone(dsi);
564         obj->exit(EXITERR_SYS);
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     }
573     return AFP_OK;
574 }
575
576 /* ---------------------- */
577 static const 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  * did filename parent directory ID.
615 */
616
617 char *mtoupath(const struct vol *vol, char *mpath, cnid_t did, int utf8)
618 {
619     static char  upath[ MAXPATHLEN + 1];
620     char        *m, *u;
621     size_t       inplen;
622     size_t       outlen;
623     u_int16_t    flags = 0;
624         
625     if ( *mpath == '\0' ) {
626         return( "." );
627     }
628
629     /* set conversion flags */
630     if (!(vol->v_flags & AFPVOL_NOHEX))
631         flags |= CONV_ESCAPEHEX;
632     if (!(vol->v_flags & AFPVOL_USEDOTS))
633         flags |= CONV_ESCAPEDOTS;
634
635     if ((vol->v_casefold & AFPVOL_MTOUUPPER))
636         flags |= CONV_TOUPPER;
637     else if ((vol->v_casefold & AFPVOL_MTOULOWER))
638         flags |= CONV_TOLOWER;
639
640     if ((vol->v_flags & AFPVOL_EILSEQ)) {
641         flags |= CONV__EILSEQ;
642     }
643
644     m = demangle(vol, mpath, did);
645     if (m != mpath) {
646         return m;
647     }
648
649     m = mpath;
650     u = upath;
651
652     inplen = strlen(m);
653     outlen = MAXPATHLEN;
654
655     if ((size_t)-1 == (outlen = convert_charset ( (utf8)?CH_UTF8_MAC:vol->v_maccharset, vol->v_volcharset, vol->v_maccharset, m, inplen, u, outlen, &flags)) ) {
656         LOG(log_error, logtype_afpd, "conversion from %s to %s for %s failed.", (utf8)?"UTF8-MAC":vol->v_maccodepage, vol->v_volcodepage, mpath);
657             return NULL;
658     }
659     upath[outlen] = 0;
660
661 #ifdef DEBUG
662     LOG(log_debug, logtype_afpd, "mtoupath: '%s':'%s'", mpath, upath);
663 #endif /* DEBUG */
664     return( upath );
665 }
666
667 /* --------------- 
668  * id filename ID
669 */
670 char *utompath(const struct vol *vol, char *upath, cnid_t id, int utf8)
671 {
672     static char  mpath[ MAXPATHLEN + 1];
673     char        *m, *u;
674     u_int16_t    flags = CONV_IGNORE | CONV_UNESCAPEHEX;
675     size_t       outlen;
676
677     m = mpath;
678     outlen = strlen(upath);
679
680     if ((vol->v_casefold & AFPVOL_UTOMUPPER))
681         flags |= CONV_TOUPPER;
682     else if ((vol->v_casefold & AFPVOL_UTOMLOWER))
683         flags |= CONV_TOLOWER;
684
685     if ((vol->v_flags & AFPVOL_EILSEQ)) {
686         flags |= CONV__EILSEQ;
687     }
688
689     u = upath;
690
691     /* convert charsets */
692     if ((size_t)-1 == ( outlen = convert_charset ( vol->v_volcharset, (utf8)?CH_UTF8_MAC:vol->v_maccharset, vol->v_maccharset, u, outlen, mpath, MAXPATHLEN, &flags)) ) { 
693         LOG(log_error, logtype_afpd, "Conversion from %s to %s for %s (%u) failed.", vol->v_volcodepage, vol->v_maccodepage, u, ntohl(id));
694         goto utompath_error;
695     }
696
697     mpath[outlen] = 0; 
698     if (!(flags & CONV_REQMANGLE)) 
699         flags = 0;
700     else
701         flags = 1;
702
703     if (utf8)
704         flags |= 2;
705
706     m = mangle(vol, mpath, outlen, upath, id, flags);
707
708 #ifdef DEBUG
709     LOG(log_debug, logtype_afpd, "utompath: '%s':'%s':'%2.2X'", upath, m, ntohl(id));
710 #endif /* DEBUG */
711     return(m);
712
713 utompath_error:
714     u = "???";
715     m = mangle(vol, u, strlen(u), upath, id, (utf8)?3:1);
716     return(m);
717 }
718
719 /* ------------------------- */
720 static int ad_addcomment(struct vol *vol, struct path *path, char *ibuf)
721 {
722     struct ofork        *of;
723     char                *name, *upath;
724     int                 isadir;
725     int                 clen;
726     struct adouble      ad, *adp;
727
728     clen = (u_char)*ibuf++;
729     clen = min( clen, 199 );
730
731     upath = path->u_name;
732     if (!vol_unix_priv(vol) && check_access(upath, OPENACC_WR ) < 0) {
733         return AFPERR_ACCESS;
734     }
735     
736     isadir = path_isadir(path);
737     if (isadir || !(of = of_findname(path))) {
738         ad_init(&ad, vol->v_adouble, vol->v_ad_options);
739         adp = &ad;
740     } else
741         adp = of->of_ad;
742
743     if (ad_open_metadata( upath , vol_noadouble(vol) | ( (isadir) ? ADFLAGS_DIR :0),O_CREAT, adp) < 0 ) {
744         return( AFPERR_ACCESS );
745     }
746
747     if (ad_getentryoff(adp, ADEID_COMMENT)) {
748         if ( (ad_getoflags( adp, ADFLAGS_HF ) & O_CREAT) ) {
749             if ( *path->m_name == '\0' ) {
750                 name = curdir->d_m_name;
751             } else {
752                 name = path->m_name;
753             }
754             ad_setname(adp, name);
755         }
756         ad_setentrylen( adp, ADEID_COMMENT, clen );
757         memcpy( ad_entry( adp, ADEID_COMMENT ), ibuf, clen );
758         ad_flush_metadata( adp );
759     }
760     ad_close_metadata( adp);
761     return( AFP_OK );
762 }
763
764 /* ----------------------------- */
765 int afp_addcomment(obj, ibuf, ibuflen, rbuf, rbuflen )
766 AFPObj  *obj _U_;
767 char    *ibuf, *rbuf _U_;
768 int     ibuflen _U_, *rbuflen;
769 {
770     struct vol          *vol;
771     struct dir          *dir;
772     struct path         *path;
773     u_int32_t           did;
774     u_int16_t           vid;
775
776     *rbuflen = 0;
777     ibuf += 2;
778
779     memcpy( &vid, ibuf, sizeof( vid ));
780     ibuf += sizeof( vid );
781     if (NULL == ( vol = getvolbyvid( vid )) ) {
782         return( AFPERR_PARAM );
783     }
784
785     memcpy( &did, ibuf, sizeof( did ));
786     ibuf += sizeof( did );
787     if (NULL == ( dir = dirlookup( vol, did )) ) {
788         return afp_errno;
789     }
790
791     if (NULL == ( path = cname( vol, dir, &ibuf )) ) {
792         return get_afp_errno(AFPERR_NOOBJ);
793     }
794
795     if ((u_long)ibuf & 1 ) {
796         ibuf++;
797     }
798
799     return ad_addcomment(vol, path, ibuf);
800 }
801
802 /* -------------------- */
803 static int ad_getcomment(struct vol *vol, struct path *path, char *rbuf, int *rbuflen)
804 {
805     struct adouble      ad, *adp;
806     struct ofork        *of;
807     char                *upath;
808     int                 isadir;
809
810
811     upath = path->u_name;
812     isadir = path_isadir(path);
813     if (isadir || !(of = of_findname(path))) {
814         ad_init(&ad, vol->v_adouble, vol->v_ad_options);
815         adp = &ad;
816     } else
817         adp = of->of_ad;
818         
819     if ( ad_metadata( upath,( isadir) ? ADFLAGS_DIR : 0, adp) < 0 ) {
820         return( AFPERR_NOITEM );
821     }
822
823     if (!ad_getentryoff(adp, ADEID_COMMENT)) {
824         return AFPERR_NOITEM;
825     }
826     /*
827      * Make sure the AD file is not bogus.
828      */
829     if ( ad_getentrylen( adp, ADEID_COMMENT ) <= 0 ||
830             ad_getentrylen( adp, ADEID_COMMENT ) > 199 ) {
831         ad_close_metadata( adp );
832         return( AFPERR_NOITEM );
833     }
834
835     *rbuf++ = ad_getentrylen( adp, ADEID_COMMENT );
836     memcpy( rbuf, ad_entry( adp, ADEID_COMMENT ), ad_getentrylen( adp, ADEID_COMMENT ));
837     *rbuflen = ad_getentrylen( adp, ADEID_COMMENT ) + 1;
838     ad_close_metadata( adp);
839
840     return( AFP_OK );
841 }
842
843 /* -------------------- */
844 int afp_getcomment(obj, ibuf, ibuflen, rbuf, rbuflen )
845 AFPObj  *obj _U_;
846 char    *ibuf, *rbuf;
847 int     ibuflen _U_, *rbuflen;
848 {
849     struct vol          *vol;
850     struct dir          *dir;
851     struct path         *s_path;
852     u_int32_t           did;
853     u_int16_t           vid;
854     
855     *rbuflen = 0;
856     ibuf += 2;
857
858     memcpy( &vid, ibuf, sizeof( vid ));
859     ibuf += sizeof( vid );
860     if (NULL == ( vol = getvolbyvid( vid )) ) {
861         return( AFPERR_PARAM );
862     }
863
864     memcpy( &did, ibuf, sizeof( did ));
865     ibuf += sizeof( did );
866     if (NULL == ( dir = dirlookup( vol, did )) ) {
867         return afp_errno;
868     }
869
870     if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
871         return get_afp_errno(AFPERR_NOOBJ);
872     }
873
874     return ad_getcomment(vol, s_path, rbuf, rbuflen);
875 }
876
877 /* ----------------------- */
878 static int ad_rmvcomment(struct vol *vol, struct path *path)
879 {
880     struct adouble      ad, *adp;
881     struct ofork        *of;
882     int                 isadir;
883     char                *upath;
884
885     upath = path->u_name;
886     if (!vol_unix_priv(vol) && check_access(upath, OPENACC_WR ) < 0) {
887         return AFPERR_ACCESS;
888     }
889
890     isadir = path_isadir(path);
891     if (isadir || !(of = of_findname(path))) {
892         ad_init(&ad, vol->v_adouble, vol->v_ad_options);
893         adp = &ad;
894     } else
895         adp = of->of_ad;
896
897     if ( ad_open_metadata( upath, (isadir) ? ADFLAGS_DIR : 0, 0, adp) < 0 ) {
898         switch ( errno ) {
899         case ENOENT :
900             return( AFPERR_NOITEM );
901         case EACCES :
902             return( AFPERR_ACCESS );
903         default :
904             return( AFPERR_PARAM );
905         }
906     }
907
908     if (ad_getentryoff(adp, ADEID_COMMENT)) {
909         ad_setentrylen( adp, ADEID_COMMENT, 0 );
910         ad_flush_metadata( adp );
911     }
912     ad_close_metadata( adp);
913     return( AFP_OK );
914 }
915
916 /* ----------------------- */
917 int afp_rmvcomment(obj, ibuf, ibuflen, rbuf, rbuflen )
918 AFPObj  *obj _U_;
919 char    *ibuf, *rbuf _U_;
920 int     ibuflen _U_, *rbuflen;
921 {
922     struct vol          *vol;
923     struct dir          *dir;
924     struct path         *s_path;
925     u_int32_t           did;
926     u_int16_t           vid;
927
928     *rbuflen = 0;
929     ibuf += 2;
930
931     memcpy( &vid, ibuf, sizeof( vid ));
932     ibuf += sizeof( vid );
933     if (NULL == ( vol = getvolbyvid( vid )) ) {
934         return( AFPERR_PARAM );
935     }
936
937     memcpy( &did, ibuf, sizeof( did ));
938     ibuf += sizeof( did );
939     if (NULL == ( dir = dirlookup( vol, did )) ) {
940         return afp_errno;
941     }
942
943     if (NULL == ( s_path = cname( vol, dir, &ibuf ))) {
944         return get_afp_errno(AFPERR_NOOBJ);
945     }
946     
947     return ad_rmvcomment(vol, s_path);
948 }