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