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