]> arthur.barton.de Git - netatalk.git/blob - etc/afpd/desktop.c
limit comments size to 128 bytes, cf. Adobe CS2 bug
[netatalk.git] / etc / afpd / desktop.c
1 /*
2  * $Id: desktop.c,v 1.35 2006-09-18 09:22:25 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 + 1];
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     upath[outlen] = 0;
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     static char  mpath[ MAXPATHLEN + 1];
678     char        *m, *u;
679     u_int16_t    flags = CONV_IGNORE | CONV_UNESCAPEHEX;
680     size_t       outlen;
681
682     m = mpath;
683     outlen = strlen(upath);
684
685     if ((vol->v_casefold & AFPVOL_UTOMUPPER))
686         flags |= CONV_TOUPPER;
687     else if ((vol->v_casefold & AFPVOL_UTOMLOWER))
688         flags |= CONV_TOLOWER;
689
690     if ((vol->v_flags & AFPVOL_EILSEQ)) {
691         flags |= CONV__EILSEQ;
692     }
693
694     u = upath;
695
696     /* convert charsets */
697     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)) ) { 
698         LOG(log_error, logtype_afpd, "Conversion from %s to %s for %s (%u) failed.", vol->v_volcodepage, vol->v_maccodepage, u, ntohl(id));
699         goto utompath_error;
700     }
701
702     mpath[outlen] = 0; 
703     if (!(flags & CONV_REQMANGLE)) 
704         flags = 0;
705     else
706         flags = 1;
707
708     if (utf8)
709         flags |= 2;
710
711     m = mangle(vol, mpath, outlen, upath, id, flags);
712
713 #ifdef DEBUG
714     LOG(log_debug, logtype_afpd, "utompath: '%s':'%s':'%2.2X'", upath, m, ntohl(id));
715 #endif /* DEBUG */
716     return(m);
717
718 utompath_error:
719     u = "???";
720     m = mangle(vol, u, strlen(u), upath, id, (utf8)?3:1);
721     return(m);
722 }
723
724 /* ------------------------- */
725 static int ad_addcomment(struct vol *vol, struct path *path, char *ibuf)
726 {
727     struct ofork        *of;
728     char                *name, *upath;
729     int                 isadir;
730     int                 clen;
731     struct adouble      ad, *adp;
732
733     clen = (u_char)*ibuf++;
734     clen = min( clen, 199 );
735
736     upath = path->u_name;
737     if (!vol_unix_priv(vol) && check_access(upath, OPENACC_WR ) < 0) {
738         return AFPERR_ACCESS;
739     }
740     
741     isadir = path_isadir(path);
742     if (isadir || !(of = of_findname(path))) {
743         ad_init(&ad, vol->v_adouble, vol->v_ad_options);
744         adp = &ad;
745     } else
746         adp = of->of_ad;
747
748     if (ad_open_metadata( upath , vol_noadouble(vol) | ( (isadir) ? ADFLAGS_DIR :0),O_CREAT, 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_metadata( adp );
764     }
765     ad_close_metadata( adp);
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_metadata( adp );
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_metadata( adp );
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_metadata( adp);
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_metadata( upath, (isadir) ? ADFLAGS_DIR : 0, 0, adp) < 0 ) {
905         switch ( errno ) {
906         case ENOENT :
907             return( AFPERR_NOITEM );
908         case EACCES :
909             return( AFPERR_ACCESS );
910         default :
911             return( AFPERR_PARAM );
912         }
913     }
914
915     if (ad_getentryoff(adp, ADEID_COMMENT)) {
916         ad_setentrylen( adp, ADEID_COMMENT, 0 );
917         ad_flush_metadata( adp );
918     }
919     ad_close_metadata( adp);
920     return( AFP_OK );
921 }
922
923 /* ----------------------- */
924 int afp_rmvcomment(obj, ibuf, ibuflen, rbuf, rbuflen )
925 AFPObj  *obj _U_;
926 char    *ibuf, *rbuf _U_;
927 int     ibuflen _U_, *rbuflen;
928 {
929     struct vol          *vol;
930     struct dir          *dir;
931     struct path         *s_path;
932     u_int32_t           did;
933     u_int16_t           vid;
934
935     *rbuflen = 0;
936     ibuf += 2;
937
938     memcpy( &vid, ibuf, sizeof( vid ));
939     ibuf += sizeof( vid );
940     if (NULL == ( vol = getvolbyvid( vid )) ) {
941         return( AFPERR_PARAM );
942     }
943
944     memcpy( &did, ibuf, sizeof( did ));
945     ibuf += sizeof( did );
946     if (NULL == ( dir = dirlookup( vol, did )) ) {
947         return afp_errno;
948     }
949
950     if (NULL == ( s_path = cname( vol, dir, &ibuf ))) {
951         return get_afp_errno(AFPERR_NOOBJ);
952     }
953     
954     return ad_rmvcomment(vol, s_path);
955 }