]> arthur.barton.de Git - netatalk.git/blob - etc/afpd/desktop.c
fix compiler warning, from Olaf Hering.
[netatalk.git] / etc / afpd / desktop.c
1 /*
2  * $Id: desktop.c,v 1.26.2.4.2.18.2.1 2005-02-06 10:16:01 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;
45 char    *ibuf, *rbuf;
46 int             ibuflen, *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;
66 char    *ibuf, *rbuf;
67 int             ibuflen, *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, *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 u_char   utag[] = { 0, 0, 0, 0 };
315 static u_char   ucreator[] = { 0, 0, 0, 0 };/* { 'U', 'N', 'I', 'X' };*/
316 static u_char   utype[] = { 0, 0, 0, 0 };/* { 'T', 'E', 'X', 'T' };*/
317 static short    usize = 256;
318 static 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;
355 char    *ibuf, *rbuf;
356 int             ibuflen, *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, *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 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);
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;
761 char    *ibuf, *rbuf;
762 int             ibuflen, *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);
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         return AFPERR_NOITEM;
819     }
820     /*
821      * Make sure the AD file is not bogus.
822      */
823     if ( ad_getentrylen( adp, ADEID_COMMENT ) <= 0 ||
824             ad_getentrylen( adp, ADEID_COMMENT ) > 199 ) {
825         ad_close( adp, ADFLAGS_HF );
826         return( AFPERR_NOITEM );
827     }
828
829     *rbuf++ = ad_getentrylen( adp, ADEID_COMMENT );
830     memcpy( rbuf, ad_entry( adp, ADEID_COMMENT ),
831             ad_getentrylen( adp, ADEID_COMMENT ));
832     *rbuflen = ad_getentrylen( adp, ADEID_COMMENT ) + 1;
833     ad_close( adp, ADFLAGS_HF );
834
835     return( AFP_OK );
836 }
837
838 /* -------------------- */
839 int afp_getcomment(obj, ibuf, ibuflen, rbuf, rbuflen )
840 AFPObj      *obj;
841 char    *ibuf, *rbuf;
842 int             ibuflen, *rbuflen;
843 {
844     struct vol          *vol;
845     struct dir          *dir;
846     struct path         *s_path;
847     u_int32_t           did;
848     u_int16_t           vid;
849     
850     *rbuflen = 0;
851     ibuf += 2;
852
853     memcpy( &vid, ibuf, sizeof( vid ));
854     ibuf += sizeof( vid );
855     if (NULL == ( vol = getvolbyvid( vid )) ) {
856         return( AFPERR_PARAM );
857     }
858
859     memcpy( &did, ibuf, sizeof( did ));
860     ibuf += sizeof( did );
861     if (NULL == ( dir = dirlookup( vol, did )) ) {
862         return afp_errno;
863     }
864
865     if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
866         return get_afp_errno(AFPERR_NOOBJ);
867     }
868
869     return ad_getcomment(vol, s_path, rbuf, rbuflen);
870 }
871
872 /* ----------------------- */
873 static int ad_rmvcomment(struct vol *vol, struct path *path)
874 {
875     struct adouble      ad, *adp;
876     struct ofork        *of;
877     int                 isadir;
878     char                *upath;
879
880     upath = path->u_name;
881     if (!vol_unix_priv(vol) && check_access(upath, OPENACC_WR ) < 0) {
882         return AFPERR_ACCESS;
883     }
884
885     isadir = path_isadir(path);
886     if (isadir || !(of = of_findname(path))) {
887         ad_init(&ad, vol->v_adouble);
888         adp = &ad;
889     } else
890         adp = of->of_ad;
891
892     if ( ad_open( upath,
893                    (isadir) ? ADFLAGS_HF|ADFLAGS_DIR : ADFLAGS_HF,
894                   O_RDWR, 0, adp) < 0 ) {
895         switch ( errno ) {
896         case ENOENT :
897             return( AFPERR_NOITEM );
898         case EACCES :
899             return( AFPERR_ACCESS );
900         default :
901             return( AFPERR_PARAM );
902         }
903     }
904
905     if (ad_getentryoff(adp, ADEID_COMMENT)) {
906         ad_setentrylen( adp, ADEID_COMMENT, 0 );
907         ad_flush( adp, ADFLAGS_HF );
908     }
909     ad_close( adp, ADFLAGS_HF );
910     return( AFP_OK );
911 }
912
913 /* ----------------------- */
914 int afp_rmvcomment(obj, ibuf, ibuflen, rbuf, rbuflen )
915 AFPObj      *obj;
916 char    *ibuf, *rbuf;
917 int             ibuflen, *rbuflen;
918 {
919     struct vol          *vol;
920     struct dir          *dir;
921     struct path         *s_path;
922     u_int32_t           did;
923     u_int16_t           vid;
924
925     *rbuflen = 0;
926     ibuf += 2;
927
928     memcpy( &vid, ibuf, sizeof( vid ));
929     ibuf += sizeof( vid );
930     if (NULL == ( vol = getvolbyvid( vid )) ) {
931         return( AFPERR_PARAM );
932     }
933
934     memcpy( &did, ibuf, sizeof( did ));
935     ibuf += sizeof( did );
936     if (NULL == ( dir = dirlookup( vol, did )) ) {
937         return afp_errno;
938     }
939
940     if (NULL == ( s_path = cname( vol, dir, &ibuf ))) {
941         return get_afp_errno(AFPERR_NOOBJ);
942     }
943     
944     return ad_rmvcomment(vol, s_path);
945 }