]> arthur.barton.de Git - netatalk.git/blob - etc/afpd/desktop.c
0b9e2a56363680ed3aa26ccb5be5ed9398e7d350
[netatalk.git] / etc / afpd / desktop.c
1 /*
2  * $Id: desktop.c,v 1.26.2.4.2.18.2.4 2006-03-14 06:14:51 didg Exp $
3  *
4  * See COPYRIGHT.
5  *
6  * bug:
7  * afp_XXXcomment are (the only) functions able to open
8  * a ressource fork when there's no data fork, eg after
9  * it was removed with samba.
10  */
11
12 #ifdef HAVE_CONFIG_H
13 #include "config.h"
14 #endif /* HAVE_CONFIG_H */
15
16 #include <stdio.h>
17 #include <string.h>
18 #include <ctype.h>
19
20 #include <errno.h>
21 #include <dirent.h>
22
23 #include <atalk/adouble.h>
24 #include <sys/uio.h>
25 #include <sys/param.h>
26 #include <sys/socket.h>
27 #include <netatalk/at.h>
28 #include <netatalk/endian.h>
29 #include <atalk/dsi.h>
30 #include <atalk/atp.h>
31 #include <atalk/asp.h>
32 #include <atalk/afp.h>
33 #include <atalk/util.h>
34 #include <atalk/logger.h>
35 #include "volume.h"
36 #include "directory.h"
37 #include "fork.h"
38 #include "globals.h"
39 #include "desktop.h"
40 #include "mangle.h"
41
42
43 int afp_opendt(obj, ibuf, ibuflen, rbuf, rbuflen )
44 AFPObj  *obj _U_;
45 char    *ibuf, *rbuf;
46 int     ibuflen _U_, *rbuflen;
47 {
48     struct vol  *vol;
49     u_int16_t   vid;
50
51     ibuf += 2;
52
53     memcpy( &vid, ibuf, sizeof(vid));
54     if (NULL == ( vol = getvolbyvid( vid )) ) {
55         *rbuflen = 0;
56         return( AFPERR_PARAM );
57     }
58
59     memcpy( rbuf, &vid, sizeof(vid));
60     *rbuflen = sizeof(vid);
61     return( AFP_OK );
62 }
63
64 int afp_closedt(obj, ibuf, ibuflen, rbuf, rbuflen )
65 AFPObj  *obj _U_;
66 char    *ibuf _U_, *rbuf _U_;
67 int     ibuflen _U_, *rbuflen;
68 {
69     *rbuflen = 0;
70     return( AFP_OK );
71 }
72
73 struct savedt   si = { { 0, 0, 0, 0 }, -1, 0, 0 };
74
75 static char *icon_dtfile(struct vol *vol, u_char creator[ 4 ])
76 {
77     return dtfile( vol, creator, ".icon" );
78 }
79
80 static int iconopen( vol, creator, flags, mode )
81 struct vol      *vol;
82 u_char  creator[ 4 ];
83 int flags;
84 int mode;
85 {
86     char        *dtf, *adt, *adts;
87
88     if ( si.sdt_fd != -1 ) {
89         if ( memcmp( si.sdt_creator, creator, sizeof( CreatorType )) == 0 &&
90                 si.sdt_vid == vol->v_vid ) {
91             return 0;
92         }
93         close( si.sdt_fd );
94         si.sdt_fd = -1;
95     }
96
97     dtf = icon_dtfile( vol, creator);
98
99     if (( si.sdt_fd = open( dtf, flags, ad_mode( dtf, mode ))) < 0 ) {
100         if ( errno == ENOENT && ( flags & O_CREAT )) {
101             if (( adts = strrchr( dtf, '/' )) == NULL ) {
102                 return -1;
103             }
104             *adts = '\0';
105             if (( adt = strrchr( dtf, '/' )) == NULL ) {
106                 return -1;
107             }
108             *adt = '\0';
109             (void) ad_mkdir( dtf, DIRBITS | 0777 );
110             *adt = '/';
111             (void) ad_mkdir( dtf, DIRBITS | 0777 );
112             *adts = '/';
113
114             if (( si.sdt_fd = open( dtf, flags, ad_mode( dtf, mode ))) < 0 ) {
115                 LOG(log_error, logtype_afpd, "iconopen(%s): open: %s", dtf, strerror(errno) );
116                 return -1;
117             }
118         } else {
119             return -1;
120         }
121     }
122
123     memcpy( si.sdt_creator, creator, sizeof( CreatorType ));
124     si.sdt_vid = vol->v_vid;
125     si.sdt_index = 1;
126     return 0;
127 }
128
129 int afp_addicon(obj, ibuf, ibuflen, rbuf, rbuflen)
130 AFPObj  *obj;
131 char    *ibuf, *rbuf;
132 int     ibuflen _U_, *rbuflen;
133 {
134     struct vol          *vol;
135 #ifndef NO_DDP
136     struct iovec        iov[ 2 ];
137 #endif
138     u_char              fcreator[ 4 ], imh[ 12 ], irh[ 12 ], *p;
139     int                 itype, cc = AFP_OK, iovcnt = 0, buflen;
140     u_int32_t           ftype, itag;
141     u_int16_t           bsize, rsize, vid;
142
143     buflen = *rbuflen;
144     *rbuflen = 0;
145     ibuf += 2;
146
147     memcpy( &vid, ibuf, sizeof( vid ));
148     ibuf += sizeof( vid );
149     if (NULL == ( vol = getvolbyvid( vid )) ) {
150         cc = AFPERR_PARAM;
151         goto addicon_err;
152     }
153
154     memcpy( fcreator, ibuf, sizeof( fcreator ));
155     ibuf += sizeof( fcreator );
156
157     memcpy( &ftype, ibuf, sizeof( ftype ));
158     ibuf += sizeof( ftype );
159
160     itype = (unsigned char) *ibuf;
161     ibuf += 2;
162
163     memcpy( &itag, ibuf, sizeof( itag ));
164     ibuf += sizeof( itag );
165
166     memcpy( &bsize, ibuf, sizeof( bsize ));
167     bsize = ntohs( bsize );
168
169     if ( si.sdt_fd != -1 ) {
170         (void)close( si.sdt_fd );
171         si.sdt_fd = -1;
172     }
173
174     if (iconopen( vol, fcreator, O_RDWR|O_CREAT, 0666 ) < 0) {
175         cc = AFPERR_NOITEM;
176         goto addicon_err;
177     }
178
179     if (lseek( si.sdt_fd, (off_t) 0L, SEEK_SET ) < 0) {
180         close(si.sdt_fd);
181         si.sdt_fd = -1;
182         LOG(log_error, logtype_afpd, "afp_addicon(%s): lseek: %s", icon_dtfile(vol, fcreator), strerror(errno) );
183         cc = AFPERR_PARAM;
184         goto addicon_err;
185     }
186
187     /*
188      * Read icon elements until we find a match to replace, or
189      * we get to the end to insert.
190      */
191     p = imh;
192     memcpy( p, &itag, sizeof( itag ));
193     p += sizeof( itag );
194     memcpy( p, &ftype, sizeof( ftype ));
195     p += sizeof( ftype );
196     *p++ = itype;
197     *p++ = 0;
198     bsize = htons( bsize );
199     memcpy( p, &bsize, sizeof( bsize ));
200     bsize = ntohs( bsize );
201     while (( cc = read( si.sdt_fd, irh, sizeof( irh ))) > 0 ) {
202         memcpy( &rsize, irh + 10, sizeof( rsize ));
203         rsize = ntohs( rsize );
204         /*
205          * Is this our set of headers?
206          */
207         if ( memcmp( irh, imh, sizeof( irh ) - sizeof( u_short )) == 0 ) {
208             /*
209              * Is the size correct?
210              */
211             if ( bsize != rsize )
212                 cc = AFPERR_ITYPE;
213             break;
214         }
215
216         if ( lseek( si.sdt_fd, (off_t) rsize, SEEK_CUR ) < 0 ) {
217             LOG(log_error, logtype_afpd, "afp_addicon(%s): lseek: %s", icon_dtfile(vol, fcreator),strerror(errno) );
218             cc = AFPERR_PARAM;
219         }
220     }
221
222     /*
223      * Some error occurred, return.
224      */
225 addicon_err:
226     if ( cc < 0 ) {
227         if (obj->proto == AFPPROTO_DSI) {
228             dsi_writeinit(obj->handle, rbuf, buflen);
229             dsi_writeflush(obj->handle);
230         }
231         return cc;
232     }
233
234     switch (obj->proto) {
235 #ifndef NO_DDP
236     case AFPPROTO_ASP:
237         buflen = bsize;
238         if ((asp_wrtcont(obj->handle, rbuf, &buflen) < 0) || buflen != bsize)
239             return( AFPERR_PARAM );
240
241 #ifdef DEBUG1
242         if (obj->options.flags & OPTION_DEBUG) {
243             printf("(write) len: %d\n", buflen);
244             bprint(rbuf, buflen);
245         }
246 #endif
247
248         /*
249          * We're at the end of the file, add the headers, etc.  */
250         if ( cc == 0 ) {
251             iov[ 0 ].iov_base = (caddr_t)imh;
252             iov[ 0 ].iov_len = sizeof( imh );
253             iov[ 1 ].iov_base = rbuf;
254             iov[ 1 ].iov_len = bsize;
255             iovcnt = 2;
256         }
257
258         /*
259          * We found an icon to replace.
260          */
261         if ( cc > 0 ) {
262             iov[ 0 ].iov_base = rbuf;
263             iov[ 0 ].iov_len = bsize;
264             iovcnt = 1;
265         }
266
267         if ( writev( si.sdt_fd, iov, iovcnt ) < 0 ) {
268             LOG(log_error, logtype_afpd, "afp_addicon(%s): writev: %s", icon_dtfile(vol, fcreator), strerror(errno) );
269             return( AFPERR_PARAM );
270         }
271         break;
272 #endif /* no afp/asp */      
273     case AFPPROTO_DSI:
274         {
275             DSI *dsi = obj->handle;
276
277             iovcnt = dsi_writeinit(dsi, rbuf, buflen);
278
279             /* add headers at end of file */
280             if ((cc == 0) && (write(si.sdt_fd, imh, sizeof(imh)) < 0)) {
281                 LOG(log_error, logtype_afpd, "afp_addicon(%s): write: %s", icon_dtfile(vol, fcreator), strerror(errno));
282                 dsi_writeflush(dsi);
283                 return AFPERR_PARAM;
284             }
285
286             if ((cc = write(si.sdt_fd, rbuf, iovcnt)) < 0) {
287                 LOG(log_error, logtype_afpd, "afp_addicon(%s): write: %s", icon_dtfile(vol, fcreator), strerror(errno));
288                 dsi_writeflush(dsi);
289                 return AFPERR_PARAM;
290             }
291
292             while ((iovcnt = dsi_write(dsi, rbuf, buflen))) {
293 #ifdef DEBUG1
294                 if ( obj->options.flags & OPTION_DEBUG ) {
295                     printf("(write) command cont'd: %d\n", iovcnt);
296                     bprint(rbuf, iovcnt);
297                 }
298 #endif
299                 if ((cc = write(si.sdt_fd, rbuf, iovcnt)) < 0) {
300                     LOG(log_error, logtype_afpd, "afp_addicon(%s): write: %s", icon_dtfile(vol, fcreator), strerror(errno));
301                     dsi_writeflush(dsi);
302                     return AFPERR_PARAM;
303                 }
304             }
305         }
306         break;
307     }
308
309     close( si.sdt_fd );
310     si.sdt_fd = -1;
311     return( AFP_OK );
312 }
313
314 static const u_char     utag[] = { 0, 0, 0, 0 };
315 static const u_char     ucreator[] = { 0, 0, 0, 0 };/* { 'U', 'N', 'I', 'X' };*/
316 static const u_char     utype[] = { 0, 0, 0, 0 };/* { 'T', 'E', 'X', 'T' };*/
317 static const short      usize = 256;
318 static const u_char     uicon[] = {
319     0x1F, 0xFF, 0xFC, 0x00, 0x10, 0x00, 0x06, 0x00,
320     0x10, 0x00, 0x05, 0x00, 0x10, 0x00, 0x04, 0x80,
321     0x10, 0x00, 0x04, 0x40, 0x10, 0x00, 0x04, 0x20,
322     0x10, 0x00, 0x07, 0xF0, 0x10, 0x00, 0x00, 0x10,
323     0x10, 0x00, 0x00, 0x10, 0x10, 0x00, 0x00, 0x10,
324     0x10, 0x00, 0x00, 0x10, 0x10, 0x80, 0x02, 0x10,
325     0x11, 0x80, 0x03, 0x10, 0x12, 0x80, 0x02, 0x90,
326     0x12, 0x80, 0x02, 0x90, 0x14, 0x80, 0x02, 0x50,
327     0x14, 0x87, 0xC2, 0x50, 0x14, 0x58, 0x34, 0x50,
328     0x14, 0x20, 0x08, 0x50, 0x12, 0x16, 0xD0, 0x90,
329     0x11, 0x01, 0x01, 0x10, 0x12, 0x80, 0x02, 0x90,
330     0x12, 0x9C, 0x72, 0x90, 0x14, 0x22, 0x88, 0x50,
331     0x14, 0x41, 0x04, 0x50, 0x14, 0x49, 0x24, 0x50,
332     0x14, 0x55, 0x54, 0x50, 0x14, 0x5D, 0x74, 0x50,
333     0x14, 0x5D, 0x74, 0x50, 0x12, 0x49, 0x24, 0x90,
334     0x12, 0x22, 0x88, 0x90, 0x1F, 0xFF, 0xFF, 0xF0,
335     0x1F, 0xFF, 0xFC, 0x00, 0x1F, 0xFF, 0xFE, 0x00,
336     0x1F, 0xFF, 0xFF, 0x00, 0x1F, 0xFF, 0xFF, 0x80,
337     0x1F, 0xFF, 0xFF, 0xC0, 0x1F, 0xFF, 0xFF, 0xE0,
338     0x1F, 0xFF, 0xFF, 0xF0, 0x1F, 0xFF, 0xFF, 0xF0,
339     0x1F, 0xFF, 0xFF, 0xF0, 0x1F, 0xFF, 0xFF, 0xF0,
340     0x1F, 0xFF, 0xFF, 0xF0, 0x1F, 0xFF, 0xFF, 0xF0,
341     0x1F, 0xFF, 0xFF, 0xF0, 0x1F, 0xFF, 0xFF, 0xF0,
342     0x1F, 0xFF, 0xFF, 0xF0, 0x1F, 0xFF, 0xFF, 0xF0,
343     0x1F, 0xFF, 0xFF, 0xF0, 0x1F, 0xFF, 0xFF, 0xF0,
344     0x1F, 0xFF, 0xFF, 0xF0, 0x1F, 0xFF, 0xFF, 0xF0,
345     0x1F, 0xFF, 0xFF, 0xF0, 0x1F, 0xFF, 0xFF, 0xF0,
346     0x1F, 0xFF, 0xFF, 0xF0, 0x1F, 0xFF, 0xFF, 0xF0,
347     0x1F, 0xFF, 0xFF, 0xF0, 0x1F, 0xFF, 0xFF, 0xF0,
348     0x1F, 0xFF, 0xFF, 0xF0, 0x1F, 0xFF, 0xFF, 0xF0,
349     0x1F, 0xFF, 0xFF, 0xF0, 0x1F, 0xFF, 0xFF, 0xF0,
350     0x1F, 0xFF, 0xFF, 0xF0, 0x1F, 0xFF, 0xFF, 0xF0,
351 };
352
353 int afp_geticoninfo(obj, ibuf, ibuflen, rbuf, rbuflen )
354 AFPObj  *obj _U_;
355 char    *ibuf, *rbuf;
356 int     ibuflen _U_, *rbuflen;
357 {
358     struct vol  *vol;
359     u_char      fcreator[ 4 ], ih[ 12 ];
360     u_int16_t   vid, iindex, bsize;
361
362     *rbuflen = 0;
363     ibuf += 2;
364
365     memcpy( &vid, ibuf, sizeof( vid ));
366     ibuf += sizeof( vid );
367     if (NULL == ( vol = getvolbyvid( vid )) ) {
368         return( AFPERR_PARAM );
369     }
370
371     memcpy( fcreator, ibuf, sizeof( fcreator ));
372     ibuf += sizeof( fcreator );
373     memcpy( &iindex, ibuf, sizeof( iindex ));
374     iindex = ntohs( iindex );
375
376     if ( memcmp( fcreator, ucreator, sizeof( ucreator )) == 0 ) {
377         if ( iindex > 1 ) {
378             return( AFPERR_NOITEM );
379         }
380         memcpy( ih, utag, sizeof( utag ));
381         memcpy( ih + sizeof( utag ), utype, sizeof( utype ));
382         *( ih + sizeof( utag ) + sizeof( utype )) = 1;
383         *( ih + sizeof( utag ) + sizeof( utype ) + 1 ) = 0;
384         memcpy( ih + sizeof( utag ) + sizeof( utype ) + 2, &usize,
385                 sizeof( usize ));
386         memcpy( rbuf, ih, sizeof( ih ));
387         *rbuflen = sizeof( ih );
388         return( AFP_OK );
389     }
390
391     if ( iconopen( vol, fcreator, O_RDONLY, 0 ) < 0) {
392         return( AFPERR_NOITEM );
393     }
394
395     if ( iindex < si.sdt_index ) {
396         if ( lseek( si.sdt_fd, (off_t) 0L, SEEK_SET ) < 0 ) {
397             return( AFPERR_PARAM );
398         }
399         si.sdt_index = 1;
400     }
401
402     /*
403      * Position to the correct spot.
404      */
405     for (;;) {
406         if ( read( si.sdt_fd, ih, sizeof( ih )) != sizeof( ih )) {
407             close( si.sdt_fd );
408             si.sdt_fd = -1;
409             return( AFPERR_NOITEM );
410         }
411         memcpy( &bsize, ih + 10, sizeof( bsize ));
412         bsize = ntohs(bsize);
413         if ( lseek( si.sdt_fd, (off_t) bsize, SEEK_CUR ) < 0 ) {
414             LOG(log_error, logtype_afpd, "afp_iconinfo(%s): lseek: %s", icon_dtfile(vol, fcreator), strerror(errno) );
415             return( AFPERR_PARAM );
416         }
417         if ( si.sdt_index == iindex ) {
418             memcpy( rbuf, ih, sizeof( ih ));
419             *rbuflen = sizeof( ih );
420             return( AFP_OK );
421         }
422         si.sdt_index++;
423     }
424 }
425
426
427 int afp_geticon(obj, ibuf, ibuflen, rbuf, rbuflen )
428 AFPObj  *obj;
429 char    *ibuf, *rbuf;
430 int     ibuflen _U_, *rbuflen;
431 {
432     struct vol  *vol;
433     off_t       offset;
434     int         rc, buflen;
435     u_char      fcreator[ 4 ], ftype[ 4 ], itype, ih[ 12 ];
436     u_int16_t   vid, bsize, rsize;
437
438     buflen = *rbuflen;
439     *rbuflen = 0;
440     ibuf += 2;
441
442     memcpy( &vid, ibuf, sizeof( vid ));
443     ibuf += sizeof( vid );
444     if (NULL == ( vol = getvolbyvid( vid )) ) {
445         return( AFPERR_PARAM );
446     }
447
448     memcpy( fcreator, ibuf, sizeof( fcreator ));
449     ibuf += sizeof( fcreator );
450     memcpy( ftype, ibuf, sizeof( ftype ));
451     ibuf += sizeof( ftype );
452     itype = (unsigned char) *ibuf++;
453     ibuf++;
454     memcpy( &bsize, ibuf, sizeof( bsize ));
455     bsize = ntohs( bsize );
456
457     if ( memcmp( fcreator, ucreator, sizeof( ucreator )) == 0 &&
458             memcmp( ftype, utype, sizeof( utype )) == 0 &&
459             itype == 1 &&
460             bsize <= usize ) {
461         memcpy( rbuf, uicon, bsize);
462         *rbuflen = bsize;
463         return( AFP_OK );
464     }
465
466     if ( iconopen( vol, fcreator, O_RDONLY, 0 ) < 0) {
467         return( AFPERR_NOITEM );
468     }
469
470     if ( lseek( si.sdt_fd, (off_t) 0L, SEEK_SET ) < 0 ) {
471         close(si.sdt_fd);
472         si.sdt_fd = -1;
473         LOG(log_error, logtype_afpd, "afp_geticon(%s): lseek: %s", icon_dtfile(vol, fcreator), strerror(errno));
474         return( AFPERR_PARAM );
475     }
476
477     si.sdt_index = 1;
478     offset = 0;
479     while (( rc = read( si.sdt_fd, ih, sizeof( ih ))) > 0 ) {
480         si.sdt_index++;
481         offset += sizeof(ih);
482         if ( memcmp( ih + sizeof( int ), ftype, sizeof( ftype )) == 0 &&
483                 *(ih + sizeof( int ) + sizeof( ftype )) == itype ) {
484             break;
485         }
486         memcpy( &rsize, ih + 10, sizeof( rsize ));
487         rsize = ntohs( rsize );
488         if ( lseek( si.sdt_fd, (off_t) rsize, SEEK_CUR ) < 0 ) {
489             LOG(log_error, logtype_afpd, "afp_geticon(%s): lseek: %s", icon_dtfile(vol, fcreator), strerror(errno) );
490             return( AFPERR_PARAM );
491         }
492         offset += rsize;
493     }
494
495     if ( rc < 0 ) {
496         LOG(log_error, logtype_afpd, "afp_geticon(%s): read: %s", icon_dtfile(vol, fcreator), strerror(errno));
497         return( AFPERR_PARAM );
498     }
499
500     if ( rc == 0 ) {
501         return( AFPERR_NOITEM );
502     }
503
504     memcpy( &rsize, ih + 10, sizeof( rsize ));
505     rsize = ntohs( rsize );
506 #define min(a,b)        ((a)<(b)?(a):(b))
507     rc = min( bsize, rsize );
508
509     if ((obj->proto == AFPPROTO_DSI) && (buflen < rc)) {
510         DSI *dsi = obj->handle;
511         struct stat st;
512         off_t size;
513
514         size = (fstat(si.sdt_fd, &st) < 0) ? 0 : st.st_size;
515         if (size < rc + offset) {
516             return AFPERR_PARAM;
517         }
518
519         if ((*rbuflen = dsi_readinit(dsi, rbuf, buflen, rc, AFP_OK)) < 0)
520             goto geticon_exit;
521
522         /* do to the streaming nature, we have to exit if we encounter
523          * a problem. much confusion results otherwise. */
524         while (*rbuflen > 0) {
525 #ifdef WITH_SENDFILE
526             if (!obj->options.flags & OPTION_DEBUG) {
527                 if (sys_sendfile(dsi->socket, si.sdt_fd, &offset, dsi->datasize) < 0) {
528                     switch (errno) {
529                     case ENOSYS:
530                     case EINVAL:  /* there's no guarantee that all fs support sendfile */
531                         break;
532                     default:
533                         goto geticon_exit;
534                     }
535                 }
536                 goto geticon_done;
537             }
538 #endif
539             buflen = read(si.sdt_fd, rbuf, *rbuflen);
540             if (buflen < 0)
541                 goto geticon_exit;
542
543 #ifdef DEBUG1
544             if (obj->options.flags & OPTION_DEBUG) {
545                 printf( "(read) reply: %d, %d\n", buflen, dsi->clientID);
546                 bprint(rbuf, buflen);
547             }
548 #endif
549             /* dsi_read() also returns buffer size of next allocation */
550             buflen = dsi_read(dsi, rbuf, buflen); /* send it off */
551             if (buflen < 0)
552                 goto geticon_exit;
553
554             *rbuflen = buflen;
555         }
556
557 geticon_done:
558         dsi_readdone(dsi);
559         return AFP_OK;
560
561 geticon_exit:
562         LOG(log_info, logtype_afpd, "afp_geticon(%s): %s", icon_dtfile(vol, fcreator), strerror(errno));
563         dsi_readdone(dsi);
564         obj->exit(EXITERR_SYS);
565         return AFP_OK;
566
567     } else {
568         if ( read( si.sdt_fd, rbuf, rc ) < rc ) {
569             return( AFPERR_PARAM );
570         }
571         *rbuflen = rc;
572     }
573     return AFP_OK;
574 }
575
576 /* ---------------------- */
577 static const char               hexdig[] = "0123456789abcdef";
578 char *dtfile(const struct vol *vol, u_char creator[], char *ext )
579 {
580     static char path[ MAXPATHLEN + 1];
581     char        *p;
582     unsigned int i;
583
584     strcpy( path, vol->v_path );
585     strcat( path, "/.AppleDesktop/" );
586     for ( p = path; *p != '\0'; p++ )
587         ;
588
589     if ( !isprint( creator[ 0 ] ) || creator[ 0 ] == '/' ) {
590         *p++ = hexdig[ ( creator[ 0 ] & 0xf0 ) >> 4 ];
591         *p++ = hexdig[ creator[ 0 ] & 0x0f ];
592     } else {
593         *p++ = creator[ 0 ];
594     }
595
596     *p++ = '/';
597
598     for ( i = 0; i < sizeof( CreatorType ); i++ ) {
599         if ( !isprint( creator[ i ] ) || creator[ i ] == '/' ) {
600             *p++ = hexdig[ ( creator[ i ] & 0xf0 ) >> 4 ];
601             *p++ = hexdig[ creator[ i ] & 0x0f ];
602         } else {
603             *p++ = creator[ i ];
604         }
605     }
606     *p = '\0';
607     strcat( path, ext );
608
609     return( path );
610 }
611
612 /* ---------------------------
613  * mpath is only a filename 
614  * did filename parent directory ID.
615 */
616 static char  upath[ MAXPATHLEN + 1];
617 static char  mpath[ MAXPATHLEN + 1];
618
619 char *mtoupath(const struct vol *vol, char *mpath, cnid_t did, int utf8)
620 {
621     char        *m, *u;
622     size_t       inplen;
623     size_t       outlen;
624     u_int16_t    flags = 0;
625         
626     if ( *mpath == '\0' ) {
627         return( "." );
628     }
629
630     /* set conversion flags */
631     if (!(vol->v_flags & AFPVOL_NOHEX))
632         flags |= CONV_ESCAPEHEX;
633     if (!(vol->v_flags & AFPVOL_USEDOTS))
634         flags |= CONV_ESCAPEDOTS;
635
636     if ((vol->v_casefold & AFPVOL_MTOUUPPER))
637         flags |= CONV_TOUPPER;
638     else if ((vol->v_casefold & AFPVOL_MTOULOWER))
639         flags |= CONV_TOLOWER;
640
641     m = demangle(vol, mpath, did);
642     if (m != mpath) {
643         return m;
644     }
645
646     m = mpath;
647     u = upath;
648
649     inplen = strlen(m);
650     outlen = MAXPATHLEN;
651
652     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)) ) {
653         LOG(log_error, logtype_afpd, "conversion from %s to %s for %s failed.", (utf8)?"UTF8-MAC":vol->v_maccodepage, vol->v_volcodepage, mpath);
654             return NULL;
655     }
656     upath[outlen] = 0;
657
658 #ifdef DEBUG
659     LOG(log_debug, logtype_afpd, "mtoupath: '%s':'%s'", mpath, upath);
660 #endif /* DEBUG */
661     return( upath );
662 }
663
664 /* --------------- 
665  * id filename ID
666 */
667 char *utompath(const struct vol *vol, char *upath, cnid_t id, int utf8)
668 {
669     char        *m, *u;
670     u_int16_t    flags = CONV_IGNORE | CONV_UNESCAPEHEX;
671     size_t       outlen;
672
673     m = mpath;
674     outlen = strlen(upath);
675
676     if (vol->v_casefold & AFPVOL_UTOMUPPER)
677         flags |= CONV_TOUPPER;
678     else if (vol->v_casefold & AFPVOL_UTOMLOWER)
679         flags |= CONV_TOLOWER;
680
681     u = upath;
682
683     /* convert charsets */
684     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)) ) { 
685         LOG(log_error, logtype_afpd, "Conversion from %s to %s for %s (%u) failed.", vol->v_volcodepage, vol->v_maccodepage, u, ntohl(id));
686         goto utompath_error;
687     }
688
689     mpath[outlen] = 0; 
690     if (!(flags & CONV_REQMANGLE)) 
691         flags = 0;
692     else
693         flags = 1;
694
695     if (utf8)
696         flags |= 2;
697
698     m = mangle(vol, mpath, outlen, upath, id, flags);
699
700 #ifdef DEBUG
701     LOG(log_debug, logtype_afpd, "utompath: '%s':'%s':'%2.2X'", upath, m, ntohl(id));
702 #endif /* DEBUG */
703     return(m);
704
705 utompath_error:
706     u = "???";
707     m = mangle(vol, u, strlen(u), upath, id, (utf8)?3:1);
708     return(m);
709 }
710
711 /* ------------------------- */
712 static int ad_addcomment(struct vol *vol, struct path *path, char *ibuf)
713 {
714     struct ofork        *of;
715     char                *name, *upath;
716     int                 isadir;
717     int                 clen;
718     struct adouble      ad, *adp;
719
720     clen = (u_char)*ibuf++;
721     clen = min( clen, 199 );
722
723     upath = path->u_name;
724     if (!vol_unix_priv(vol) && check_access(upath, OPENACC_WR ) < 0) {
725         return AFPERR_ACCESS;
726     }
727     
728     isadir = path_isadir(path);
729     if (isadir || !(of = of_findname(path))) {
730         ad_init(&ad, vol->v_adouble, vol->v_ad_options);
731         adp = &ad;
732     } else
733         adp = of->of_ad;
734
735     if (ad_open( upath , vol_noadouble(vol) |
736                  (( isadir) ? ADFLAGS_HF|ADFLAGS_DIR : ADFLAGS_HF),
737                  O_RDWR|O_CREAT, 0666, adp) < 0 ) {
738         return( AFPERR_ACCESS );
739     }
740
741     if (ad_getentryoff(adp, ADEID_COMMENT)) {
742         if ( (ad_getoflags( adp, ADFLAGS_HF ) & O_CREAT) ) {
743             if ( *path->m_name == '\0' ) {
744                 name = curdir->d_m_name;
745             } else {
746                 name = path->m_name;
747             }
748             ad_setname(adp, name);
749         }
750         ad_setentrylen( adp, ADEID_COMMENT, clen );
751         memcpy( ad_entry( adp, ADEID_COMMENT ), ibuf, clen );
752         ad_flush( adp, ADFLAGS_HF );
753     }
754     ad_close( adp, ADFLAGS_HF );
755     return( AFP_OK );
756 }
757
758 /* ----------------------------- */
759 int afp_addcomment(obj, ibuf, ibuflen, rbuf, rbuflen )
760 AFPObj      *obj _U_;
761 char    *ibuf, *rbuf _U_;
762 int             ibuflen _U_, *rbuflen;
763 {
764     struct vol          *vol;
765     struct dir          *dir;
766     struct path         *path;
767     u_int32_t           did;
768     u_int16_t           vid;
769
770     *rbuflen = 0;
771     ibuf += 2;
772
773     memcpy( &vid, ibuf, sizeof( vid ));
774     ibuf += sizeof( vid );
775     if (NULL == ( vol = getvolbyvid( vid )) ) {
776         return( AFPERR_PARAM );
777     }
778
779     memcpy( &did, ibuf, sizeof( did ));
780     ibuf += sizeof( did );
781     if (NULL == ( dir = dirlookup( vol, did )) ) {
782         return afp_errno;
783     }
784
785     if (NULL == ( path = cname( vol, dir, &ibuf )) ) {
786         return get_afp_errno(AFPERR_NOOBJ);
787     }
788
789     if ((u_long)ibuf & 1 ) {
790         ibuf++;
791     }
792
793     return ad_addcomment(vol, path, ibuf);
794 }
795
796 /* -------------------- */
797 static int ad_getcomment(struct vol *vol, struct path *path, char *rbuf, int *rbuflen)
798 {
799     struct adouble      ad, *adp;
800     struct ofork        *of;
801     char                *upath;
802     int                 isadir;
803
804
805     upath = path->u_name;
806     isadir = path_isadir(path);
807     if (isadir || !(of = of_findname(path))) {
808         ad_init(&ad, vol->v_adouble, vol->v_ad_options);
809         adp = &ad;
810     } else
811         adp = of->of_ad;
812         
813     if ( ad_metadata( upath,( isadir) ? ADFLAGS_DIR : 0, adp) < 0 ) {
814         return( AFPERR_NOITEM );
815     }
816
817     if (!ad_getentryoff(adp, ADEID_COMMENT)) {
818         ad_close( adp, ADFLAGS_HF );
819         return AFPERR_NOITEM;
820     }
821     /*
822      * Make sure the AD file is not bogus.
823      */
824     if ( ad_getentrylen( adp, ADEID_COMMENT ) <= 0 ||
825             ad_getentrylen( adp, ADEID_COMMENT ) > 199 ) {
826         ad_close( adp, ADFLAGS_HF );
827         return( AFPERR_NOITEM );
828     }
829
830     *rbuf++ = ad_getentrylen( adp, ADEID_COMMENT );
831     memcpy( rbuf, ad_entry( adp, ADEID_COMMENT ),
832             ad_getentrylen( adp, ADEID_COMMENT ));
833     *rbuflen = ad_getentrylen( adp, ADEID_COMMENT ) + 1;
834     ad_close( adp, ADFLAGS_HF );
835
836     return( AFP_OK );
837 }
838
839 /* -------------------- */
840 int afp_getcomment(obj, ibuf, ibuflen, rbuf, rbuflen )
841 AFPObj      *obj _U_;
842 char    *ibuf, *rbuf;
843 int             ibuflen _U_, *rbuflen;
844 {
845     struct vol          *vol;
846     struct dir          *dir;
847     struct path         *s_path;
848     u_int32_t           did;
849     u_int16_t           vid;
850     
851     *rbuflen = 0;
852     ibuf += 2;
853
854     memcpy( &vid, ibuf, sizeof( vid ));
855     ibuf += sizeof( vid );
856     if (NULL == ( vol = getvolbyvid( vid )) ) {
857         return( AFPERR_PARAM );
858     }
859
860     memcpy( &did, ibuf, sizeof( did ));
861     ibuf += sizeof( did );
862     if (NULL == ( dir = dirlookup( vol, did )) ) {
863         return afp_errno;
864     }
865
866     if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
867         return get_afp_errno(AFPERR_NOOBJ);
868     }
869
870     return ad_getcomment(vol, s_path, rbuf, rbuflen);
871 }
872
873 /* ----------------------- */
874 static int ad_rmvcomment(struct vol *vol, struct path *path)
875 {
876     struct adouble      ad, *adp;
877     struct ofork        *of;
878     int                 isadir;
879     char                *upath;
880
881     upath = path->u_name;
882     if (!vol_unix_priv(vol) && check_access(upath, OPENACC_WR ) < 0) {
883         return AFPERR_ACCESS;
884     }
885
886     isadir = path_isadir(path);
887     if (isadir || !(of = of_findname(path))) {
888         ad_init(&ad, vol->v_adouble, vol->v_ad_options);
889         adp = &ad;
890     } else
891         adp = of->of_ad;
892
893     if ( ad_open( upath,
894                    (isadir) ? ADFLAGS_HF|ADFLAGS_DIR : ADFLAGS_HF,
895                   O_RDWR, 0, adp) < 0 ) {
896         switch ( errno ) {
897         case ENOENT :
898             return( AFPERR_NOITEM );
899         case EACCES :
900             return( AFPERR_ACCESS );
901         default :
902             return( AFPERR_PARAM );
903         }
904     }
905
906     if (ad_getentryoff(adp, ADEID_COMMENT)) {
907         ad_setentrylen( adp, ADEID_COMMENT, 0 );
908         ad_flush( adp, ADFLAGS_HF );
909     }
910     ad_close( adp, ADFLAGS_HF );
911     return( AFP_OK );
912 }
913
914 /* ----------------------- */
915 int afp_rmvcomment(obj, ibuf, ibuflen, rbuf, rbuflen )
916 AFPObj      *obj _U_;
917 char    *ibuf, *rbuf _U_;
918 int             ibuflen _U_, *rbuflen;
919 {
920     struct vol          *vol;
921     struct dir          *dir;
922     struct path         *s_path;
923     u_int32_t           did;
924     u_int16_t           vid;
925
926     *rbuflen = 0;
927     ibuf += 2;
928
929     memcpy( &vid, ibuf, sizeof( vid ));
930     ibuf += sizeof( vid );
931     if (NULL == ( vol = getvolbyvid( vid )) ) {
932         return( AFPERR_PARAM );
933     }
934
935     memcpy( &did, ibuf, sizeof( did ));
936     ibuf += sizeof( did );
937     if (NULL == ( dir = dirlookup( vol, did )) ) {
938         return afp_errno;
939     }
940
941     if (NULL == ( s_path = cname( vol, dir, &ibuf ))) {
942         return get_afp_errno(AFPERR_NOOBJ);
943     }
944     
945     return ad_rmvcomment(vol, s_path);
946 }