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