]> arthur.barton.de Git - netatalk.git/blob - etc/afpd/desktop.c
fix minor gcc warnings.
[netatalk.git] / etc / afpd / desktop.c
1 /*
2  * $Id: desktop.c,v 1.26.2.4.2.7 2004-01-10 06:40:58 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 #ifdef HAVE_UNISTD_H
20 #include <unistd.h>
21 #endif /* HAVE_UNISTD_H */
22 #ifdef HAVE_FCNTL_H
23 #include <fcntl.h>
24 #endif /* HAVE_FCNTL_H */
25 #include <errno.h>
26 #include <dirent.h>
27 #include <sys/types.h>
28 #include <sys/time.h>
29 #include <sys/uio.h>
30 #include <sys/param.h>
31 #include <sys/stat.h>
32 #include <sys/socket.h>
33 #include <netatalk/at.h>
34 #include <netatalk/endian.h>
35 #include <atalk/dsi.h>
36 #include <atalk/atp.h>
37 #include <atalk/asp.h>
38 #include <atalk/afp.h>
39 #include <atalk/adouble.h>
40 #include <atalk/util.h>
41 #include <atalk/logger.h>
42 #include "volume.h"
43 #include "directory.h"
44 #include "fork.h"
45 #include "globals.h"
46 #include "desktop.h"
47 #include "mangle.h"
48
49
50 int afp_opendt(obj, ibuf, ibuflen, rbuf, rbuflen )
51 AFPObj      *obj;
52 char    *ibuf, *rbuf;
53 int             ibuflen, *rbuflen;
54 {
55     struct vol  *vol;
56     u_int16_t   vid;
57
58     ibuf += 2;
59
60     memcpy( &vid, ibuf, sizeof(vid));
61     if (NULL == ( vol = getvolbyvid( vid )) ) {
62         *rbuflen = 0;
63         return( AFPERR_PARAM );
64     }
65
66     memcpy( rbuf, &vid, sizeof(vid));
67     *rbuflen = sizeof(vid);
68     return( AFP_OK );
69 }
70
71 int afp_closedt(obj, ibuf, ibuflen, rbuf, rbuflen )
72 AFPObj      *obj;
73 char    *ibuf, *rbuf;
74 int             ibuflen, *rbuflen;
75 {
76     *rbuflen = 0;
77     return( AFP_OK );
78 }
79
80 struct savedt   si = { { 0, 0, 0, 0 }, -1, 0 };
81
82 static int iconopen( vol, creator, flags, mode )
83 struct vol      *vol;
84 u_char  creator[ 4 ];
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 = dtfile( vol, creator, ".icon" );
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: open %s: %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     struct iovec        iov[ 2 ];
136     u_char              fcreator[ 4 ], imh[ 12 ], irh[ 12 ], *p;
137     int                 itype, cc = AFP_OK, iovcnt = 0, buflen;
138     u_int32_t           ftype, itag;
139     u_int16_t           bsize, rsize, vid;
140
141     buflen = *rbuflen;
142     *rbuflen = 0;
143     ibuf += 2;
144
145     memcpy( &vid, ibuf, sizeof( vid ));
146     ibuf += sizeof( vid );
147     if (NULL == ( vol = getvolbyvid( vid )) ) {
148         cc = AFPERR_PARAM;
149         goto addicon_err;
150     }
151
152     memcpy( fcreator, ibuf, sizeof( fcreator ));
153     ibuf += sizeof( fcreator );
154
155     memcpy( &ftype, ibuf, sizeof( ftype ));
156     ibuf += sizeof( ftype );
157
158     itype = (unsigned char) *ibuf;
159     ibuf += 2;
160
161     memcpy( &itag, ibuf, sizeof( itag ));
162     ibuf += sizeof( itag );
163
164     memcpy( &bsize, ibuf, sizeof( bsize ));
165     bsize = ntohs( bsize );
166
167     if ( si.sdt_fd != -1 ) {
168         (void)close( si.sdt_fd );
169         si.sdt_fd = -1;
170     }
171
172     if (iconopen( vol, fcreator, O_RDWR|O_CREAT, 0666 ) < 0) {
173         cc = AFPERR_NOITEM;
174         goto addicon_err;
175     }
176
177     if (lseek( si.sdt_fd, (off_t) 0L, SEEK_SET ) < 0) {
178         close(si.sdt_fd);
179         si.sdt_fd = -1;
180         LOG(log_error, logtype_afpd, "afp_addicon: lseek: %s", strerror(errno) );
181         cc = AFPERR_PARAM;
182         goto addicon_err;
183     }
184
185     /*
186      * Read icon elements until we find a match to replace, or
187      * we get to the end to insert.
188      */
189     p = imh;
190     memcpy( p, &itag, sizeof( itag ));
191     p += sizeof( itag );
192     memcpy( p, &ftype, sizeof( ftype ));
193     p += sizeof( ftype );
194     *p++ = itype;
195     *p++ = 0;
196     bsize = htons( bsize );
197     memcpy( p, &bsize, sizeof( bsize ));
198     bsize = ntohs( bsize );
199     while (( cc = read( si.sdt_fd, irh, sizeof( irh ))) > 0 ) {
200         memcpy( &rsize, irh + 10, sizeof( rsize ));
201         rsize = ntohs( rsize );
202         /*
203          * Is this our set of headers?
204          */
205         if ( memcmp( irh, imh, sizeof( irh ) - sizeof( u_short )) == 0 ) {
206             /*
207              * Is the size correct?
208              */
209             if ( bsize != rsize )
210                 cc = AFPERR_ITYPE;
211             break;
212         }
213
214         if ( lseek( si.sdt_fd, (off_t) rsize, SEEK_CUR ) < 0 ) {
215             LOG(log_error, logtype_afpd, "afp_addicon: lseek: %s", strerror(errno) );
216             cc = AFPERR_PARAM;
217         }
218     }
219
220     /*
221      * Some error occurred, return.
222      */
223 addicon_err:
224     if ( cc < 0 ) {
225         LOG(log_error, logtype_afpd, "afp_addicon: %s", strerror(errno) );
226         if (obj->proto == AFPPROTO_DSI) {
227             dsi_writeinit(obj->handle, rbuf, buflen);
228             dsi_writeflush(obj->handle);
229         }
230         return cc;
231     }
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: writev: %s", 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: write: %s", 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: write: %s", 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: write: %s", 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 u_char  utag[] = { 0, 0, 0, 0 };
315 u_char  ucreator[] = { 'U', 'N', 'I', 'X' };
316 u_char  utype[] = { 'T', 'E', 'X', 'T' };
317 short   usize = 256;
318 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: lseek: %s", 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: lseek: %s", 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: lseek: %s", strerror(errno) );
490             return( AFPERR_PARAM );
491         }
492         offset += rsize;
493     }
494
495     if ( rc < 0 ) {
496         LOG(log_error, logtype_afpd, "afp_geticon: read: %s", 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", strerror(errno));
563         dsi_readdone(dsi);
564         obj->exit(1);
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
693     m = mangle(vol, mpath, upath, id, flags);
694
695 #ifdef DEBUG
696     LOG(log_debug, logtype_afpd, "utompath: '%s':'%s':'%2.2X'", upath, m, ntohl(id));
697 #endif /* DEBUG */
698     return(m);
699
700 utompath_error:
701     u = "???";
702     m = mangle(vol, u, upath, id, 1);
703     return(m);
704 }
705
706 /* ----------------------------- */
707 int afp_addcomment(obj, ibuf, ibuflen, rbuf, rbuflen )
708 AFPObj      *obj;
709 char    *ibuf, *rbuf;
710 int             ibuflen, *rbuflen;
711 {
712     struct adouble      ad, *adp;
713     struct vol          *vol;
714     struct dir          *dir;
715     struct ofork        *of;
716     struct path         *path;
717     char                *name, *upath;
718     int                 clen;
719     u_int32_t           did;
720     u_int16_t           vid;
721     int                 isadir;
722
723     *rbuflen = 0;
724     ibuf += 2;
725
726     memcpy( &vid, ibuf, sizeof( vid ));
727     ibuf += sizeof( vid );
728     if (NULL == ( vol = getvolbyvid( vid )) ) {
729         return( AFPERR_PARAM );
730     }
731
732     memcpy( &did, ibuf, sizeof( did ));
733     ibuf += sizeof( did );
734     if (NULL == ( dir = dirlookup( vol, did )) ) {
735         return afp_errno;
736     }
737
738     if (NULL == ( path = cname( vol, dir, &ibuf )) ) {
739         return get_afp_errno(AFPERR_NOOBJ);
740     }
741
742     if ((u_long)ibuf & 1 ) {
743         ibuf++;
744     }
745
746     clen = (u_char)*ibuf++;
747     clen = min( clen, 199 );
748
749     upath = path->u_name;
750     if (!vol_unix_priv(vol) && check_access(upath, OPENACC_WR ) < 0) {
751         return AFPERR_ACCESS;
752     }
753
754     isadir = path_isadir(path);
755     if (isadir || !(of = of_findname(path))) {
756         ad_init(&ad, vol->v_adouble);
757         adp = &ad;
758     } else
759         adp = of->of_ad;
760
761     if (ad_open( upath , vol_noadouble(vol) |
762                  (( isadir) ? ADFLAGS_HF|ADFLAGS_DIR : ADFLAGS_HF),
763                  O_RDWR|O_CREAT, 0666, adp) < 0 ) {
764         return( AFPERR_ACCESS );
765     }
766
767     if ( (ad_getoflags( adp, ADFLAGS_HF ) & O_CREAT) ) {
768         if ( *path->m_name == '\0' ) {
769             name = curdir->d_m_name;
770         } else {
771             name = path->m_name;
772         }
773         ad_setentrylen( adp, ADEID_NAME, strlen( name ));
774         memcpy( ad_entry( adp, ADEID_NAME ), name,
775                 ad_getentrylen( adp, ADEID_NAME ));
776     }
777
778     ad_setentrylen( adp, ADEID_COMMENT, clen );
779     memcpy( ad_entry( adp, ADEID_COMMENT ), ibuf, clen );
780     ad_flush( adp, ADFLAGS_HF );
781     ad_close( adp, ADFLAGS_HF );
782     return( AFP_OK );
783 }
784
785 int afp_getcomment(obj, ibuf, ibuflen, rbuf, rbuflen )
786 AFPObj      *obj;
787 char    *ibuf, *rbuf;
788 int             ibuflen, *rbuflen;
789 {
790     struct adouble      ad, *adp;
791     struct vol          *vol;
792     struct dir          *dir;
793     struct ofork        *of;
794     struct path         *s_path;
795     char                *upath;
796     u_int32_t           did;
797     u_int16_t           vid;
798     int                 isadir;
799     
800     *rbuflen = 0;
801     ibuf += 2;
802
803     memcpy( &vid, ibuf, sizeof( vid ));
804     ibuf += sizeof( vid );
805     if (NULL == ( vol = getvolbyvid( vid )) ) {
806         return( AFPERR_PARAM );
807     }
808
809     memcpy( &did, ibuf, sizeof( did ));
810     ibuf += sizeof( did );
811     if (NULL == ( dir = dirlookup( vol, did )) ) {
812         return afp_errno;
813     }
814
815     if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
816         return get_afp_errno(AFPERR_NOOBJ);
817     }
818
819     upath = s_path->u_name;
820     isadir = path_isadir(s_path);
821     if (isadir || !(of = of_findname(s_path))) {
822         ad_init(&ad, vol->v_adouble);
823         adp = &ad;
824     } else
825         adp = of->of_ad;
826     if ( ad_open( upath,
827                   ( isadir) ? ADFLAGS_HF|ADFLAGS_DIR : ADFLAGS_HF,
828                   O_RDONLY, 0666, adp) < 0 ) {
829         return( AFPERR_NOITEM );
830     }
831
832     /*
833      * Make sure the AD file is not bogus.
834      */
835     if ( ad_getentrylen( adp, ADEID_COMMENT ) < 0 ||
836             ad_getentrylen( adp, ADEID_COMMENT ) > 199 ) {
837         ad_close( adp, ADFLAGS_HF );
838         return( AFPERR_NOITEM );
839     }
840
841     *rbuf++ = ad_getentrylen( adp, ADEID_COMMENT );
842     memcpy( rbuf, ad_entry( adp, ADEID_COMMENT ),
843             ad_getentrylen( adp, ADEID_COMMENT ));
844     *rbuflen = ad_getentrylen( adp, ADEID_COMMENT ) + 1;
845     ad_close( adp, ADFLAGS_HF );
846
847     /* return AFPERR_NOITEM if len == 0 ? */
848     return( AFP_OK );
849 }
850
851 int afp_rmvcomment(obj, ibuf, ibuflen, rbuf, rbuflen )
852 AFPObj      *obj;
853 char    *ibuf, *rbuf;
854 int             ibuflen, *rbuflen;
855 {
856     struct adouble      ad, *adp;
857     struct vol          *vol;
858     struct dir          *dir;
859     struct ofork        *of;
860     struct path         *s_path;
861     char                *upath;
862     u_int32_t           did;
863     u_int16_t           vid;
864     int                 isadir;
865
866     *rbuflen = 0;
867     ibuf += 2;
868
869     memcpy( &vid, ibuf, sizeof( vid ));
870     ibuf += sizeof( vid );
871     if (NULL == ( vol = getvolbyvid( vid )) ) {
872         return( AFPERR_PARAM );
873     }
874
875     memcpy( &did, ibuf, sizeof( did ));
876     ibuf += sizeof( did );
877     if (NULL == ( dir = dirlookup( vol, did )) ) {
878         return afp_errno;
879     }
880
881     if (NULL == ( s_path = cname( vol, dir, &ibuf ))) {
882         return get_afp_errno(AFPERR_NOOBJ);
883     }
884
885     upath = s_path->u_name;
886     if (!vol_unix_priv(vol) && check_access(upath, OPENACC_WR ) < 0) {
887         return AFPERR_ACCESS;
888     }
889
890     isadir = path_isadir(s_path);
891     if (isadir || !(of = of_findname(s_path))) {
892         ad_init(&ad, vol->v_adouble);
893         adp = &ad;
894     } else
895         adp = of->of_ad;
896
897     if ( ad_open( upath,
898                    (isadir) ? ADFLAGS_HF|ADFLAGS_DIR : ADFLAGS_HF,
899                   O_RDWR, 0, adp) < 0 ) {
900         switch ( errno ) {
901         case ENOENT :
902             return( AFPERR_NOITEM );
903         case EACCES :
904             return( AFPERR_ACCESS );
905         default :
906             return( AFPERR_PARAM );
907         }
908     }
909
910     ad_setentrylen( adp, ADEID_COMMENT, 0 );
911     ad_flush( adp, ADFLAGS_HF );
912     ad_close( adp, ADFLAGS_HF );
913     return( AFP_OK );
914 }