]> arthur.barton.de Git - netatalk.git/blob - etc/afpd/desktop.c
backport CJK encoding from HEAD
[netatalk.git] / etc / afpd / desktop.c
1 /*
2  * $Id: desktop.c,v 1.26.2.4.2.18.2.8 2009-01-13 01:05:53 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     if (vol->v_flags & AFPVOL_EILSEQ) {
647         flags |= CONV__EILSEQ;
648     }
649
650     m = demangle(vol, mpath, did);
651     if (m != mpath) {
652         return m;
653     }
654
655     m = mpath;
656     u = upath;
657
658     inplen = strlen(m);
659     outlen = MAXPATHLEN;
660
661     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)) ) {
662         LOG(log_error, logtype_afpd, "conversion from %s to %s for %s failed.", (utf8)?"UTF8-MAC":vol->v_maccodepage, vol->v_volcodepage, mpath);
663             return NULL;
664     }
665
666 #ifdef DEBUG
667     LOG(log_debug, logtype_afpd, "mtoupath: '%s':'%s'", mpath, upath);
668 #endif /* DEBUG */
669     return( upath );
670 }
671
672 /* --------------- 
673  * id filename ID
674 */
675 char *utompath(const struct vol *vol, char *upath, cnid_t id, int utf8)
676 {
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( upath , vol_noadouble(vol) |
747                  (( isadir) ? ADFLAGS_HF|ADFLAGS_DIR : ADFLAGS_HF),
748                  O_RDWR|O_CREAT, 0666, adp) < 0 ) {
749         return( AFPERR_ACCESS );
750     }
751
752     if (ad_getentryoff(adp, ADEID_COMMENT)) {
753         if ( (ad_getoflags( adp, ADFLAGS_HF ) & O_CREAT) ) {
754             if ( *path->m_name == '\0' ) {
755                 name = curdir->d_m_name;
756             } else {
757                 name = path->m_name;
758             }
759             ad_setname(adp, name);
760         }
761         ad_setentrylen( adp, ADEID_COMMENT, clen );
762         memcpy( ad_entry( adp, ADEID_COMMENT ), ibuf, clen );
763         ad_flush( adp, ADFLAGS_HF );
764     }
765     ad_close( adp, ADFLAGS_HF );
766     return( AFP_OK );
767 }
768
769 /* ----------------------------- */
770 int afp_addcomment(obj, ibuf, ibuflen, rbuf, rbuflen )
771 AFPObj      *obj _U_;
772 char    *ibuf, *rbuf _U_;
773 int             ibuflen _U_, *rbuflen;
774 {
775     struct vol          *vol;
776     struct dir          *dir;
777     struct path         *path;
778     u_int32_t           did;
779     u_int16_t           vid;
780
781     *rbuflen = 0;
782     ibuf += 2;
783
784     memcpy( &vid, ibuf, sizeof( vid ));
785     ibuf += sizeof( vid );
786     if (NULL == ( vol = getvolbyvid( vid )) ) {
787         return( AFPERR_PARAM );
788     }
789
790     memcpy( &did, ibuf, sizeof( did ));
791     ibuf += sizeof( did );
792     if (NULL == ( dir = dirlookup( vol, did )) ) {
793         return afp_errno;
794     }
795
796     if (NULL == ( path = cname( vol, dir, &ibuf )) ) {
797         return get_afp_errno(AFPERR_NOOBJ);
798     }
799
800     if ((u_long)ibuf & 1 ) {
801         ibuf++;
802     }
803
804     return ad_addcomment(vol, path, ibuf);
805 }
806
807 /* -------------------- */
808 static int ad_getcomment(struct vol *vol, struct path *path, char *rbuf, int *rbuflen)
809 {
810     struct adouble      ad, *adp;
811     struct ofork        *of;
812     char                *upath;
813     int                 isadir;
814     int                 clen;
815
816     upath = path->u_name;
817     isadir = path_isadir(path);
818     if (isadir || !(of = of_findname(path))) {
819         ad_init(&ad, vol->v_adouble, vol->v_ad_options);
820         adp = &ad;
821     } else
822         adp = of->of_ad;
823         
824     if ( ad_metadata( upath,( isadir) ? ADFLAGS_DIR : 0, adp) < 0 ) {
825         return( AFPERR_NOITEM );
826     }
827
828     if (!ad_getentryoff(adp, ADEID_COMMENT)) {
829         ad_close( adp, ADFLAGS_HF );
830         return AFPERR_NOITEM;
831     }
832     /*
833      * Make sure the AD file is not bogus.
834      */
835     if ( ad_getentrylen( adp, ADEID_COMMENT ) <= 0 ||
836             ad_getentrylen( adp, ADEID_COMMENT ) > 199 ) {
837         ad_close( adp, ADFLAGS_HF );
838         return( AFPERR_NOITEM );
839     }
840
841     clen = min( ad_getentrylen( adp, ADEID_COMMENT ), 128 ); /* OSX only use 128, greater kill Adobe CS2 */
842     *rbuf++ = clen;
843     memcpy( rbuf, ad_entry( adp, ADEID_COMMENT ), clen);
844     *rbuflen = clen + 1;
845     ad_close( adp, ADFLAGS_HF );
846
847     return( AFP_OK );
848 }
849
850 /* -------------------- */
851 int afp_getcomment(obj, ibuf, ibuflen, rbuf, rbuflen )
852 AFPObj      *obj _U_;
853 char    *ibuf, *rbuf;
854 int             ibuflen _U_, *rbuflen;
855 {
856     struct vol          *vol;
857     struct dir          *dir;
858     struct path         *s_path;
859     u_int32_t           did;
860     u_int16_t           vid;
861     
862     *rbuflen = 0;
863     ibuf += 2;
864
865     memcpy( &vid, ibuf, sizeof( vid ));
866     ibuf += sizeof( vid );
867     if (NULL == ( vol = getvolbyvid( vid )) ) {
868         return( AFPERR_PARAM );
869     }
870
871     memcpy( &did, ibuf, sizeof( did ));
872     ibuf += sizeof( did );
873     if (NULL == ( dir = dirlookup( vol, did )) ) {
874         return afp_errno;
875     }
876
877     if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
878         return get_afp_errno(AFPERR_NOOBJ);
879     }
880
881     return ad_getcomment(vol, s_path, rbuf, rbuflen);
882 }
883
884 /* ----------------------- */
885 static int ad_rmvcomment(struct vol *vol, struct path *path)
886 {
887     struct adouble      ad, *adp;
888     struct ofork        *of;
889     int                 isadir;
890     char                *upath;
891
892     upath = path->u_name;
893     if (!vol_unix_priv(vol) && check_access(upath, OPENACC_WR ) < 0) {
894         return AFPERR_ACCESS;
895     }
896
897     isadir = path_isadir(path);
898     if (isadir || !(of = of_findname(path))) {
899         ad_init(&ad, vol->v_adouble, vol->v_ad_options);
900         adp = &ad;
901     } else
902         adp = of->of_ad;
903
904     if ( ad_open( upath,
905                    (isadir) ? ADFLAGS_HF|ADFLAGS_DIR : ADFLAGS_HF,
906                   O_RDWR, 0, adp) < 0 ) {
907         switch ( errno ) {
908         case ENOENT :
909             return( AFPERR_NOITEM );
910         case EACCES :
911             return( AFPERR_ACCESS );
912         default :
913             return( AFPERR_PARAM );
914         }
915     }
916
917     if (ad_getentryoff(adp, ADEID_COMMENT)) {
918         ad_setentrylen( adp, ADEID_COMMENT, 0 );
919         ad_flush( adp, ADFLAGS_HF );
920     }
921     ad_close( adp, ADFLAGS_HF );
922     return( AFP_OK );
923 }
924
925 /* ----------------------- */
926 int afp_rmvcomment(obj, ibuf, ibuflen, rbuf, rbuflen )
927 AFPObj      *obj _U_;
928 char    *ibuf, *rbuf _U_;
929 int             ibuflen _U_, *rbuflen;
930 {
931     struct vol          *vol;
932     struct dir          *dir;
933     struct path         *s_path;
934     u_int32_t           did;
935     u_int16_t           vid;
936
937     *rbuflen = 0;
938     ibuf += 2;
939
940     memcpy( &vid, ibuf, sizeof( vid ));
941     ibuf += sizeof( vid );
942     if (NULL == ( vol = getvolbyvid( vid )) ) {
943         return( AFPERR_PARAM );
944     }
945
946     memcpy( &did, ibuf, sizeof( did ));
947     ibuf += sizeof( did );
948     if (NULL == ( dir = dirlookup( vol, did )) ) {
949         return afp_errno;
950     }
951
952     if (NULL == ( s_path = cname( vol, dir, &ibuf ))) {
953         return get_afp_errno(AFPERR_NOOBJ);
954     }
955     
956     return ad_rmvcomment(vol, s_path);
957 }