]> arthur.barton.de Git - netatalk.git/blob - etc/afpd/desktop.c
Add a timeout when reading data from afpd client in cnid_metad, from Tsiyon Sadiky...
[netatalk.git] / etc / afpd / desktop.c
1 /*
2  * $Id: desktop.c,v 1.26.2.4.2.18.2.7 2006-09-19 00:08:00 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
319 #if 0
320 static const u_char     uicon[] = {
321     0x1F, 0xFF, 0xFC, 0x00, 0x10, 0x00, 0x06, 0x00,
322     0x10, 0x00, 0x05, 0x00, 0x10, 0x00, 0x04, 0x80,
323     0x10, 0x00, 0x04, 0x40, 0x10, 0x00, 0x04, 0x20,
324     0x10, 0x00, 0x07, 0xF0, 0x10, 0x00, 0x00, 0x10,
325     0x10, 0x00, 0x00, 0x10, 0x10, 0x00, 0x00, 0x10,
326     0x10, 0x00, 0x00, 0x10, 0x10, 0x80, 0x02, 0x10,
327     0x11, 0x80, 0x03, 0x10, 0x12, 0x80, 0x02, 0x90,
328     0x12, 0x80, 0x02, 0x90, 0x14, 0x80, 0x02, 0x50,
329     0x14, 0x87, 0xC2, 0x50, 0x14, 0x58, 0x34, 0x50,
330     0x14, 0x20, 0x08, 0x50, 0x12, 0x16, 0xD0, 0x90,
331     0x11, 0x01, 0x01, 0x10, 0x12, 0x80, 0x02, 0x90,
332     0x12, 0x9C, 0x72, 0x90, 0x14, 0x22, 0x88, 0x50,
333     0x14, 0x41, 0x04, 0x50, 0x14, 0x49, 0x24, 0x50,
334     0x14, 0x55, 0x54, 0x50, 0x14, 0x5D, 0x74, 0x50,
335     0x14, 0x5D, 0x74, 0x50, 0x12, 0x49, 0x24, 0x90,
336     0x12, 0x22, 0x88, 0x90, 0x1F, 0xFF, 0xFF, 0xF0,
337     0x1F, 0xFF, 0xFC, 0x00, 0x1F, 0xFF, 0xFE, 0x00,
338     0x1F, 0xFF, 0xFF, 0x00, 0x1F, 0xFF, 0xFF, 0x80,
339     0x1F, 0xFF, 0xFF, 0xC0, 0x1F, 0xFF, 0xFF, 0xE0,
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     0x1F, 0xFF, 0xFF, 0xF0, 0x1F, 0xFF, 0xFF, 0xF0,
352     0x1F, 0xFF, 0xFF, 0xF0, 0x1F, 0xFF, 0xFF, 0xF0,
353 };
354 #endif
355
356 int afp_geticoninfo(obj, ibuf, ibuflen, rbuf, rbuflen )
357 AFPObj  *obj _U_;
358 char    *ibuf, *rbuf;
359 int     ibuflen _U_, *rbuflen;
360 {
361     struct vol  *vol;
362     u_char      fcreator[ 4 ], ih[ 12 ];
363     u_int16_t   vid, iindex, bsize;
364
365     *rbuflen = 0;
366     ibuf += 2;
367
368     memcpy( &vid, ibuf, sizeof( vid ));
369     ibuf += sizeof( vid );
370     if (NULL == ( vol = getvolbyvid( vid )) ) {
371         return( AFPERR_PARAM );
372     }
373
374     memcpy( fcreator, ibuf, sizeof( fcreator ));
375     ibuf += sizeof( fcreator );
376     memcpy( &iindex, ibuf, sizeof( iindex ));
377     iindex = ntohs( iindex );
378
379     if ( memcmp( fcreator, ucreator, sizeof( ucreator )) == 0 ) {
380         if ( iindex > 1 ) {
381             return( AFPERR_NOITEM );
382         }
383         memcpy( ih, utag, sizeof( utag ));
384         memcpy( ih + sizeof( utag ), utype, sizeof( utype ));
385         *( ih + sizeof( utag ) + sizeof( utype )) = 1;
386         *( ih + sizeof( utag ) + sizeof( utype ) + 1 ) = 0;
387         memcpy( ih + sizeof( utag ) + sizeof( utype ) + 2, &usize,
388                 sizeof( usize ));
389         memcpy( rbuf, ih, sizeof( ih ));
390         *rbuflen = sizeof( ih );
391         return( AFP_OK );
392     }
393
394     if ( iconopen( vol, fcreator, O_RDONLY, 0 ) < 0) {
395         return( AFPERR_NOITEM );
396     }
397
398     if ( iindex < si.sdt_index ) {
399         if ( lseek( si.sdt_fd, (off_t) 0L, SEEK_SET ) < 0 ) {
400             return( AFPERR_PARAM );
401         }
402         si.sdt_index = 1;
403     }
404
405     /*
406      * Position to the correct spot.
407      */
408     for (;;) {
409         if ( read( si.sdt_fd, ih, sizeof( ih )) != sizeof( ih )) {
410             close( si.sdt_fd );
411             si.sdt_fd = -1;
412             return( AFPERR_NOITEM );
413         }
414         memcpy( &bsize, ih + 10, sizeof( bsize ));
415         bsize = ntohs(bsize);
416         if ( lseek( si.sdt_fd, (off_t) bsize, SEEK_CUR ) < 0 ) {
417             LOG(log_error, logtype_afpd, "afp_iconinfo(%s): lseek: %s", icon_dtfile(vol, fcreator), strerror(errno) );
418             return( AFPERR_PARAM );
419         }
420         if ( si.sdt_index == iindex ) {
421             memcpy( rbuf, ih, sizeof( ih ));
422             *rbuflen = sizeof( ih );
423             return( AFP_OK );
424         }
425         si.sdt_index++;
426     }
427 }
428
429
430 int afp_geticon(obj, ibuf, ibuflen, rbuf, rbuflen )
431 AFPObj  *obj;
432 char    *ibuf, *rbuf;
433 int     ibuflen _U_, *rbuflen;
434 {
435     struct vol  *vol;
436     off_t       offset;
437     int         rc, buflen;
438     u_char      fcreator[ 4 ], ftype[ 4 ], itype, ih[ 12 ];
439     u_int16_t   vid, bsize, rsize;
440
441     buflen = *rbuflen;
442     *rbuflen = 0;
443     ibuf += 2;
444
445     memcpy( &vid, ibuf, sizeof( vid ));
446     ibuf += sizeof( vid );
447     if (NULL == ( vol = getvolbyvid( vid )) ) {
448         return( AFPERR_PARAM );
449     }
450
451     memcpy( fcreator, ibuf, sizeof( fcreator ));
452     ibuf += sizeof( fcreator );
453     memcpy( ftype, ibuf, sizeof( ftype ));
454     ibuf += sizeof( ftype );
455     itype = (unsigned char) *ibuf++;
456     ibuf++;
457     memcpy( &bsize, ibuf, sizeof( bsize ));
458     bsize = ntohs( bsize );
459
460 #if 0
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 #endif
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(%s): lseek: %s", icon_dtfile(vol, fcreator), 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(%s): lseek: %s", icon_dtfile(vol, fcreator), strerror(errno) );
495             return( AFPERR_PARAM );
496         }
497         offset += rsize;
498     }
499
500     if ( rc < 0 ) {
501         LOG(log_error, logtype_afpd, "afp_geticon(%s): read: %s", icon_dtfile(vol, fcreator), 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 #ifdef WITH_SENDFILE
531             if (!obj->options.flags & OPTION_DEBUG) {
532                 if (sys_sendfile(dsi->socket, si.sdt_fd, &offset, dsi->datasize) < 0) {
533                     switch (errno) {
534                     case ENOSYS:
535                     case EINVAL:  /* there's no guarantee that all fs support sendfile */
536                         break;
537                     default:
538                         goto geticon_exit;
539                     }
540                 }
541                 goto geticon_done;
542             }
543 #endif
544             buflen = read(si.sdt_fd, rbuf, *rbuflen);
545             if (buflen < 0)
546                 goto geticon_exit;
547
548 #ifdef DEBUG1
549             if (obj->options.flags & OPTION_DEBUG) {
550                 printf( "(read) reply: %d, %d\n", buflen, dsi->clientID);
551                 bprint(rbuf, buflen);
552             }
553 #endif
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): %s", icon_dtfile(vol, fcreator), strerror(errno));
568         dsi_readdone(dsi);
569         obj->exit(EXITERR_SYS);
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     }
578     return AFP_OK;
579 }
580
581 /* ---------------------- */
582 static const 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  * did filename parent directory ID.
620 */
621 static char  upath[ MAXPATHLEN + 2]; /* for convert_charset dest_len parameter +2 */
622 static char  mpath[ MAXPATHLEN + 2];/* for convert_charset dest_len parameter +2 */
623
624 char *mtoupath(const struct vol *vol, char *mpath, cnid_t did, int utf8)
625 {
626     char        *m, *u;
627     size_t       inplen;
628     size_t       outlen;
629     u_int16_t    flags = 0;
630         
631     if ( *mpath == '\0' ) {
632         return( "." );
633     }
634
635     /* set conversion flags */
636     if (!(vol->v_flags & AFPVOL_NOHEX))
637         flags |= CONV_ESCAPEHEX;
638     if (!(vol->v_flags & AFPVOL_USEDOTS))
639         flags |= CONV_ESCAPEDOTS;
640
641     if ((vol->v_casefold & AFPVOL_MTOUUPPER))
642         flags |= CONV_TOUPPER;
643     else if ((vol->v_casefold & AFPVOL_MTOULOWER))
644         flags |= CONV_TOLOWER;
645
646     m = demangle(vol, mpath, did);
647     if (m != mpath) {
648         return m;
649     }
650
651     m = mpath;
652     u = upath;
653
654     inplen = strlen(m);
655     outlen = MAXPATHLEN;
656
657     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)) ) {
658         LOG(log_error, logtype_afpd, "conversion from %s to %s for %s failed.", (utf8)?"UTF8-MAC":vol->v_maccodepage, vol->v_volcodepage, mpath);
659             return NULL;
660     }
661
662 #ifdef DEBUG
663     LOG(log_debug, logtype_afpd, "mtoupath: '%s':'%s'", mpath, upath);
664 #endif /* DEBUG */
665     return( upath );
666 }
667
668 /* --------------- 
669  * id filename ID
670 */
671 char *utompath(const struct vol *vol, char *upath, cnid_t id, int utf8)
672 {
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     u = upath;
686
687     /* convert charsets */
688     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)) ) { 
689         LOG(log_error, logtype_afpd, "Conversion from %s to %s for %s (%u) failed.", vol->v_volcodepage, vol->v_maccodepage, u, ntohl(id));
690         goto utompath_error;
691     }
692
693     if (!(flags & CONV_REQMANGLE)) 
694         flags = 0;
695     else
696         flags = 1;
697
698     if (utf8)
699         flags |= 2;
700
701     m = mangle(vol, mpath, outlen, upath, id, flags);
702
703 #ifdef DEBUG
704     LOG(log_debug, logtype_afpd, "utompath: '%s':'%s':'%2.2X'", upath, m, ntohl(id));
705 #endif /* DEBUG */
706     return(m);
707
708 utompath_error:
709     u = "???";
710     m = mangle(vol, u, strlen(u), upath, id, (utf8)?3:1);
711     return(m);
712 }
713
714 /* ------------------------- */
715 static int ad_addcomment(struct vol *vol, struct path *path, char *ibuf)
716 {
717     struct ofork        *of;
718     char                *name, *upath;
719     int                 isadir;
720     int                 clen;
721     struct adouble      ad, *adp;
722
723     clen = (u_char)*ibuf++;
724     clen = min( clen, 199 );
725
726     upath = path->u_name;
727     if (!vol_unix_priv(vol) && check_access(upath, OPENACC_WR ) < 0) {
728         return AFPERR_ACCESS;
729     }
730     
731     isadir = path_isadir(path);
732     if (isadir || !(of = of_findname(path))) {
733         ad_init(&ad, vol->v_adouble, vol->v_ad_options);
734         adp = &ad;
735     } else
736         adp = of->of_ad;
737
738     if (ad_open( upath , vol_noadouble(vol) |
739                  (( isadir) ? ADFLAGS_HF|ADFLAGS_DIR : ADFLAGS_HF),
740                  O_RDWR|O_CREAT, 0666, adp) < 0 ) {
741         return( AFPERR_ACCESS );
742     }
743
744     if (ad_getentryoff(adp, ADEID_COMMENT)) {
745         if ( (ad_getoflags( adp, ADFLAGS_HF ) & O_CREAT) ) {
746             if ( *path->m_name == '\0' ) {
747                 name = curdir->d_m_name;
748             } else {
749                 name = path->m_name;
750             }
751             ad_setname(adp, name);
752         }
753         ad_setentrylen( adp, ADEID_COMMENT, clen );
754         memcpy( ad_entry( adp, ADEID_COMMENT ), ibuf, clen );
755         ad_flush( adp, ADFLAGS_HF );
756     }
757     ad_close( adp, ADFLAGS_HF );
758     return( AFP_OK );
759 }
760
761 /* ----------------------------- */
762 int afp_addcomment(obj, ibuf, ibuflen, rbuf, rbuflen )
763 AFPObj      *obj _U_;
764 char    *ibuf, *rbuf _U_;
765 int             ibuflen _U_, *rbuflen;
766 {
767     struct vol          *vol;
768     struct dir          *dir;
769     struct path         *path;
770     u_int32_t           did;
771     u_int16_t           vid;
772
773     *rbuflen = 0;
774     ibuf += 2;
775
776     memcpy( &vid, ibuf, sizeof( vid ));
777     ibuf += sizeof( vid );
778     if (NULL == ( vol = getvolbyvid( vid )) ) {
779         return( AFPERR_PARAM );
780     }
781
782     memcpy( &did, ibuf, sizeof( did ));
783     ibuf += sizeof( did );
784     if (NULL == ( dir = dirlookup( vol, did )) ) {
785         return afp_errno;
786     }
787
788     if (NULL == ( path = cname( vol, dir, &ibuf )) ) {
789         return get_afp_errno(AFPERR_NOOBJ);
790     }
791
792     if ((u_long)ibuf & 1 ) {
793         ibuf++;
794     }
795
796     return ad_addcomment(vol, path, ibuf);
797 }
798
799 /* -------------------- */
800 static int ad_getcomment(struct vol *vol, struct path *path, char *rbuf, int *rbuflen)
801 {
802     struct adouble      ad, *adp;
803     struct ofork        *of;
804     char                *upath;
805     int                 isadir;
806     int                 clen;
807
808     upath = path->u_name;
809     isadir = path_isadir(path);
810     if (isadir || !(of = of_findname(path))) {
811         ad_init(&ad, vol->v_adouble, vol->v_ad_options);
812         adp = &ad;
813     } else
814         adp = of->of_ad;
815         
816     if ( ad_metadata( upath,( isadir) ? ADFLAGS_DIR : 0, adp) < 0 ) {
817         return( AFPERR_NOITEM );
818     }
819
820     if (!ad_getentryoff(adp, ADEID_COMMENT)) {
821         ad_close( adp, ADFLAGS_HF );
822         return AFPERR_NOITEM;
823     }
824     /*
825      * Make sure the AD file is not bogus.
826      */
827     if ( ad_getentrylen( adp, ADEID_COMMENT ) <= 0 ||
828             ad_getentrylen( adp, ADEID_COMMENT ) > 199 ) {
829         ad_close( adp, ADFLAGS_HF );
830         return( AFPERR_NOITEM );
831     }
832
833     clen = min( ad_getentrylen( adp, ADEID_COMMENT ), 128 ); /* OSX only use 128, greater kill Adobe CS2 */
834     *rbuf++ = clen;
835     memcpy( rbuf, ad_entry( adp, ADEID_COMMENT ), clen);
836     *rbuflen = clen + 1;
837     ad_close( adp, ADFLAGS_HF );
838
839     return( AFP_OK );
840 }
841
842 /* -------------------- */
843 int afp_getcomment(obj, ibuf, ibuflen, rbuf, rbuflen )
844 AFPObj      *obj _U_;
845 char    *ibuf, *rbuf;
846 int             ibuflen _U_, *rbuflen;
847 {
848     struct vol          *vol;
849     struct dir          *dir;
850     struct path         *s_path;
851     u_int32_t           did;
852     u_int16_t           vid;
853     
854     *rbuflen = 0;
855     ibuf += 2;
856
857     memcpy( &vid, ibuf, sizeof( vid ));
858     ibuf += sizeof( vid );
859     if (NULL == ( vol = getvolbyvid( vid )) ) {
860         return( AFPERR_PARAM );
861     }
862
863     memcpy( &did, ibuf, sizeof( did ));
864     ibuf += sizeof( did );
865     if (NULL == ( dir = dirlookup( vol, did )) ) {
866         return afp_errno;
867     }
868
869     if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
870         return get_afp_errno(AFPERR_NOOBJ);
871     }
872
873     return ad_getcomment(vol, s_path, rbuf, rbuflen);
874 }
875
876 /* ----------------------- */
877 static int ad_rmvcomment(struct vol *vol, struct path *path)
878 {
879     struct adouble      ad, *adp;
880     struct ofork        *of;
881     int                 isadir;
882     char                *upath;
883
884     upath = path->u_name;
885     if (!vol_unix_priv(vol) && check_access(upath, OPENACC_WR ) < 0) {
886         return AFPERR_ACCESS;
887     }
888
889     isadir = path_isadir(path);
890     if (isadir || !(of = of_findname(path))) {
891         ad_init(&ad, vol->v_adouble, vol->v_ad_options);
892         adp = &ad;
893     } else
894         adp = of->of_ad;
895
896     if ( ad_open( upath,
897                    (isadir) ? ADFLAGS_HF|ADFLAGS_DIR : ADFLAGS_HF,
898                   O_RDWR, 0, adp) < 0 ) {
899         switch ( errno ) {
900         case ENOENT :
901             return( AFPERR_NOITEM );
902         case EACCES :
903             return( AFPERR_ACCESS );
904         default :
905             return( AFPERR_PARAM );
906         }
907     }
908
909     if (ad_getentryoff(adp, ADEID_COMMENT)) {
910         ad_setentrylen( adp, ADEID_COMMENT, 0 );
911         ad_flush( adp, ADFLAGS_HF );
912     }
913     ad_close( adp, ADFLAGS_HF );
914     return( AFP_OK );
915 }
916
917 /* ----------------------- */
918 int afp_rmvcomment(obj, ibuf, ibuflen, rbuf, rbuflen )
919 AFPObj      *obj _U_;
920 char    *ibuf, *rbuf _U_;
921 int             ibuflen _U_, *rbuflen;
922 {
923     struct vol          *vol;
924     struct dir          *dir;
925     struct path         *s_path;
926     u_int32_t           did;
927     u_int16_t           vid;
928
929     *rbuflen = 0;
930     ibuf += 2;
931
932     memcpy( &vid, ibuf, sizeof( vid ));
933     ibuf += sizeof( vid );
934     if (NULL == ( vol = getvolbyvid( vid )) ) {
935         return( AFPERR_PARAM );
936     }
937
938     memcpy( &did, ibuf, sizeof( did ));
939     ibuf += sizeof( did );
940     if (NULL == ( dir = dirlookup( vol, did )) ) {
941         return afp_errno;
942     }
943
944     if (NULL == ( s_path = cname( vol, dir, &ibuf ))) {
945         return get_afp_errno(AFPERR_NOOBJ);
946     }
947     
948     return ad_rmvcomment(vol, s_path);
949 }