]> arthur.barton.de Git - netatalk.git/blob - etc/afpd/desktop.c
add a SFM compatible format for adouble
[netatalk.git] / etc / afpd / desktop.c
1 /*
2  * $Id: desktop.c,v 1.37 2006-09-29 09:39:16 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
622 char *mtoupath(const struct vol *vol, char *mpath, cnid_t did, int utf8)
623 {
624     static char  upath[ MAXPATHLEN + 2]; /* for convert_charset dest_len parameter +2 */
625     char        *m, *u;
626     size_t       inplen;
627     size_t       outlen;
628     u_int16_t    flags = 0;
629         
630     if ( *mpath == '\0' ) {
631         return( "." );
632     }
633
634     /* set conversion flags */
635     if (!(vol->v_flags & AFPVOL_NOHEX))
636         flags |= CONV_ESCAPEHEX;
637     if (!(vol->v_flags & AFPVOL_USEDOTS))
638         flags |= CONV_ESCAPEDOTS;
639
640     if ((vol->v_casefold & AFPVOL_MTOUUPPER))
641         flags |= CONV_TOUPPER;
642     else if ((vol->v_casefold & AFPVOL_MTOULOWER))
643         flags |= CONV_TOLOWER;
644
645     if ((vol->v_flags & AFPVOL_EILSEQ)) {
646         flags |= CONV__EILSEQ;
647     }
648
649     m = demangle(vol, mpath, did);
650     if (m != mpath) {
651         return m;
652     }
653
654     m = mpath;
655     u = upath;
656
657     inplen = strlen(m);
658     outlen = MAXPATHLEN;
659
660     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)) ) {
661         LOG(log_error, logtype_afpd, "conversion from %s to %s for %s failed.", (utf8)?"UTF8-MAC":vol->v_maccodepage, vol->v_volcodepage, mpath);
662             return NULL;
663     }
664
665 #ifdef DEBUG
666     LOG(log_debug, logtype_afpd, "mtoupath: '%s':'%s'", mpath, upath);
667 #endif /* DEBUG */
668     return( upath );
669 }
670
671 /* --------------- 
672  * id filename ID
673 */
674 char *utompath(const struct vol *vol, char *upath, cnid_t id, int utf8)
675 {
676     static char  mpath[ MAXPATHLEN + 2]; /* for convert_charset dest_len parameter +2 */
677     char        *m, *u;
678     u_int16_t    flags = CONV_IGNORE | CONV_UNESCAPEHEX;
679     size_t       outlen;
680
681     m = mpath;
682     outlen = strlen(upath);
683
684     if ((vol->v_casefold & AFPVOL_UTOMUPPER))
685         flags |= CONV_TOUPPER;
686     else if ((vol->v_casefold & AFPVOL_UTOMLOWER))
687         flags |= CONV_TOLOWER;
688
689     if ((vol->v_flags & AFPVOL_EILSEQ)) {
690         flags |= CONV__EILSEQ;
691     }
692
693     u = upath;
694
695     /* convert charsets */
696     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)) ) { 
697         LOG(log_error, logtype_afpd, "Conversion from %s to %s for %s (%u) failed.", vol->v_volcodepage, vol->v_maccodepage, u, ntohl(id));
698         goto utompath_error;
699     }
700
701     if (!(flags & CONV_REQMANGLE)) 
702         flags = 0;
703     else
704         flags = 1;
705
706     if (utf8)
707         flags |= 2;
708
709     m = mangle(vol, mpath, outlen, upath, id, flags);
710
711 #ifdef DEBUG
712     LOG(log_debug, logtype_afpd, "utompath: '%s':'%s':'%2.2X'", upath, m, ntohl(id));
713 #endif /* DEBUG */
714     return(m);
715
716 utompath_error:
717     u = "???";
718     m = mangle(vol, u, strlen(u), upath, id, (utf8)?3:1);
719     return(m);
720 }
721
722 /* ------------------------- */
723 static int ad_addcomment(struct vol *vol, struct path *path, char *ibuf)
724 {
725     struct ofork        *of;
726     char                *name, *upath;
727     int                 isadir;
728     int                 clen;
729     struct adouble      ad, *adp;
730
731     clen = (u_char)*ibuf++;
732     clen = min( clen, 199 );
733
734     upath = path->u_name;
735     if (!vol_unix_priv(vol) && check_access(upath, OPENACC_WR ) < 0) {
736         return AFPERR_ACCESS;
737     }
738     
739     isadir = path_isadir(path);
740     if (isadir || !(of = of_findname(path))) {
741         ad_init(&ad, vol->v_adouble, vol->v_ad_options);
742         adp = &ad;
743     } else
744         adp = of->of_ad;
745
746     if (ad_open_metadata( upath , vol_noadouble(vol) | ( (isadir) ? ADFLAGS_DIR :0),O_CREAT, adp) < 0 ) {
747         return( AFPERR_ACCESS );
748     }
749
750     if (ad_getentryoff(adp, ADEID_COMMENT)) {
751         if ( (ad_get_MD_flags( adp ) & O_CREAT) ) {
752             if ( *path->m_name == '\0' ) {
753                 name = curdir->d_m_name;
754             } else {
755                 name = path->m_name;
756             }
757             ad_setname(adp, name);
758         }
759         ad_setentrylen( adp, ADEID_COMMENT, clen );
760         memcpy( ad_entry( adp, ADEID_COMMENT ), ibuf, clen );
761         ad_flush( adp );
762     }
763     ad_close_metadata( adp);
764     return( AFP_OK );
765 }
766
767 /* ----------------------------- */
768 int afp_addcomment(obj, ibuf, ibuflen, rbuf, rbuflen )
769 AFPObj  *obj _U_;
770 char    *ibuf, *rbuf _U_;
771 int     ibuflen _U_, *rbuflen;
772 {
773     struct vol          *vol;
774     struct dir          *dir;
775     struct path         *path;
776     u_int32_t           did;
777     u_int16_t           vid;
778
779     *rbuflen = 0;
780     ibuf += 2;
781
782     memcpy( &vid, ibuf, sizeof( vid ));
783     ibuf += sizeof( vid );
784     if (NULL == ( vol = getvolbyvid( vid )) ) {
785         return( AFPERR_PARAM );
786     }
787
788     memcpy( &did, ibuf, sizeof( did ));
789     ibuf += sizeof( did );
790     if (NULL == ( dir = dirlookup( vol, did )) ) {
791         return afp_errno;
792     }
793
794     if (NULL == ( path = cname( vol, dir, &ibuf )) ) {
795         return get_afp_errno(AFPERR_NOOBJ);
796     }
797
798     if ((u_long)ibuf & 1 ) {
799         ibuf++;
800     }
801
802     return ad_addcomment(vol, path, ibuf);
803 }
804
805 /* -------------------- */
806 static int ad_getcomment(struct vol *vol, struct path *path, char *rbuf, int *rbuflen)
807 {
808     struct adouble      ad, *adp;
809     struct ofork        *of;
810     char                *upath;
811     int                 isadir;
812     int                 clen;
813
814     upath = path->u_name;
815     isadir = path_isadir(path);
816     if (isadir || !(of = of_findname(path))) {
817         ad_init(&ad, vol->v_adouble, vol->v_ad_options);
818         adp = &ad;
819     } else
820         adp = of->of_ad;
821         
822     if ( ad_metadata( upath,( isadir) ? ADFLAGS_DIR : 0, adp) < 0 ) {
823         return( AFPERR_NOITEM );
824     }
825
826     if (!ad_getentryoff(adp, ADEID_COMMENT)) {
827         ad_close_metadata( adp );
828         return AFPERR_NOITEM;
829     }
830     /*
831      * Make sure the AD file is not bogus.
832      */
833     if ( ad_getentrylen( adp, ADEID_COMMENT ) <= 0 ||
834             ad_getentrylen( adp, ADEID_COMMENT ) > 199 ) {
835         ad_close_metadata( adp );
836         return( AFPERR_NOITEM );
837     }
838
839     clen = min( ad_getentrylen( adp, ADEID_COMMENT ), 128 ); /* OSX only use 128, greater kill Adobe CS2 */
840     *rbuf++ = clen;
841     memcpy( rbuf, ad_entry( adp, ADEID_COMMENT ), clen);
842     *rbuflen = clen + 1;
843     ad_close_metadata( adp);
844
845     return( AFP_OK );
846 }
847
848 /* -------------------- */
849 int afp_getcomment(obj, ibuf, ibuflen, rbuf, rbuflen )
850 AFPObj  *obj _U_;
851 char    *ibuf, *rbuf;
852 int     ibuflen _U_, *rbuflen;
853 {
854     struct vol          *vol;
855     struct dir          *dir;
856     struct path         *s_path;
857     u_int32_t           did;
858     u_int16_t           vid;
859     
860     *rbuflen = 0;
861     ibuf += 2;
862
863     memcpy( &vid, ibuf, sizeof( vid ));
864     ibuf += sizeof( vid );
865     if (NULL == ( vol = getvolbyvid( vid )) ) {
866         return( AFPERR_PARAM );
867     }
868
869     memcpy( &did, ibuf, sizeof( did ));
870     ibuf += sizeof( did );
871     if (NULL == ( dir = dirlookup( vol, did )) ) {
872         return afp_errno;
873     }
874
875     if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
876         return get_afp_errno(AFPERR_NOOBJ);
877     }
878
879     return ad_getcomment(vol, s_path, rbuf, rbuflen);
880 }
881
882 /* ----------------------- */
883 static int ad_rmvcomment(struct vol *vol, struct path *path)
884 {
885     struct adouble      ad, *adp;
886     struct ofork        *of;
887     int                 isadir;
888     char                *upath;
889
890     upath = path->u_name;
891     if (!vol_unix_priv(vol) && check_access(upath, OPENACC_WR ) < 0) {
892         return AFPERR_ACCESS;
893     }
894
895     isadir = path_isadir(path);
896     if (isadir || !(of = of_findname(path))) {
897         ad_init(&ad, vol->v_adouble, vol->v_ad_options);
898         adp = &ad;
899     } else
900         adp = of->of_ad;
901
902     if ( ad_open_metadata( upath, (isadir) ? ADFLAGS_DIR : 0, 0, adp) < 0 ) {
903         switch ( errno ) {
904         case ENOENT :
905             return( AFPERR_NOITEM );
906         case EACCES :
907             return( AFPERR_ACCESS );
908         default :
909             return( AFPERR_PARAM );
910         }
911     }
912
913     if (ad_getentryoff(adp, ADEID_COMMENT)) {
914         ad_setentrylen( adp, ADEID_COMMENT, 0 );
915         ad_flush( adp );
916     }
917     ad_close_metadata( adp);
918     return( AFP_OK );
919 }
920
921 /* ----------------------- */
922 int afp_rmvcomment(obj, ibuf, ibuflen, rbuf, rbuflen )
923 AFPObj  *obj _U_;
924 char    *ibuf, *rbuf _U_;
925 int     ibuflen _U_, *rbuflen;
926 {
927     struct vol          *vol;
928     struct dir          *dir;
929     struct path         *s_path;
930     u_int32_t           did;
931     u_int16_t           vid;
932
933     *rbuflen = 0;
934     ibuf += 2;
935
936     memcpy( &vid, ibuf, sizeof( vid ));
937     ibuf += sizeof( vid );
938     if (NULL == ( vol = getvolbyvid( vid )) ) {
939         return( AFPERR_PARAM );
940     }
941
942     memcpy( &did, ibuf, sizeof( did ));
943     ibuf += sizeof( did );
944     if (NULL == ( dir = dirlookup( vol, did )) ) {
945         return afp_errno;
946     }
947
948     if (NULL == ( s_path = cname( vol, dir, &ibuf ))) {
949         return get_afp_errno(AFPERR_NOOBJ);
950     }
951     
952     return ad_rmvcomment(vol, s_path);
953 }