]> arthur.barton.de Git - netatalk.git/blob - etc/afpd/desktop.c
Configurable symlink behaviour
[netatalk.git] / etc / afpd / desktop.c
1 /*
2  * $Id: desktop.c,v 1.50.2.1 2010-02-01 10:56:08 franklahm 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 <atalk/globals.h>
35 #include "volume.h"
36 #include "directory.h"
37 #include "fork.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_error, 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;
601         
602     if ( *mpath == '\0' ) {
603         strcpy(upath, ".");
604         return upath;
605     }
606
607     /* set conversion flags */
608     flags = vol->v_mtou_flags;
609     
610     m = demangle(vol, mpath, did);
611     if (m != mpath) {
612         return m;
613     }
614
615     m = mpath;
616     u = upath;
617
618     inplen = strlen(m);
619     outlen = MAXPATHLEN;
620
621     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)) ) {
622         LOG(log_error, logtype_afpd, "conversion from %s to %s for %s failed.", (utf8)?"UTF8-MAC":vol->v_maccodepage, vol->v_volcodepage, mpath);
623             return NULL;
624     }
625
626 #ifdef DEBUG
627     LOG(log_debug9, logtype_afpd, "mtoupath: '%s':'%s'", mpath, upath);
628 #endif /* DEBUG */
629     return( upath );
630 }
631
632 /* --------------- 
633  * id filename ID
634 */
635 char *utompath(const struct vol *vol, char *upath, cnid_t id, int utf8)
636 {
637     static char  mpath[ MAXPATHLEN + 2]; /* for convert_charset dest_len parameter +2 */
638     char        *m, *u;
639     u_int16_t    flags;
640     size_t       outlen;
641
642     m = mpath;
643     outlen = strlen(upath);
644
645     flags = vol->v_utom_flags;
646
647     u = upath;
648
649     /* convert charsets */
650     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)) ) { 
651         LOG(log_error, logtype_afpd, "Conversion from %s to %s for %s (%u) failed.", vol->v_volcodepage, vol->v_maccodepage, u, ntohl(id));
652         goto utompath_error;
653     }
654
655     flags = !!(flags & CONV_REQMANGLE);
656
657     if (utf8)
658         flags |= 2;
659
660     m = mangle(vol, mpath, outlen, upath, id, flags);
661
662 #ifdef DEBUG
663     LOG(log_debug9, logtype_afpd, "utompath: '%s':'%s':'%2.2X'", upath, m, ntohl(id));
664 #endif /* DEBUG */
665     return(m);
666
667 utompath_error:
668     u = "???";
669     m = mangle(vol, u, strlen(u), upath, id, (utf8)?3:1);
670     return(m);
671 }
672
673 /* ------------------------- */
674 static int ad_addcomment(struct vol *vol, struct path *path, char *ibuf)
675 {
676     struct ofork        *of;
677     char                *name, *upath;
678     int                 isadir;
679     int                 clen;
680     struct adouble      ad, *adp;
681
682     clen = (u_char)*ibuf++;
683     clen = min( clen, 199 );
684
685     upath = path->u_name;
686     if (check_access(upath, OPENACC_WR ) < 0) {
687         return AFPERR_ACCESS;
688     }
689     
690     isadir = path_isadir(path);
691     if (isadir || !(of = of_findname(vol, path))) {
692         ad_init(&ad, vol->v_adouble, vol->v_ad_options);
693         adp = &ad;
694     } else
695         adp = of->of_ad;
696
697     if (ad_open_metadata( upath , ( (isadir) ? ADFLAGS_DIR : 0), O_CREAT, adp) < 0 ) {
698         return( AFPERR_ACCESS );
699     }
700
701     if (ad_getentryoff(adp, ADEID_COMMENT)) {
702         if ( (ad_get_MD_flags( adp ) & O_CREAT) ) {
703             if ( *path->m_name == '\0' ) {
704                 name = (char *)curdir->d_m_name->data;
705             } else {
706                 name = path->m_name;
707             }
708             ad_setname(adp, name);
709         }
710         ad_setentrylen( adp, ADEID_COMMENT, clen );
711         memcpy( ad_entry( adp, ADEID_COMMENT ), ibuf, clen );
712         ad_flush( adp );
713     }
714     ad_close_metadata( adp);
715     return( AFP_OK );
716 }
717
718 /* ----------------------------- */
719 int afp_addcomment(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
720 {
721     struct vol          *vol;
722     struct dir          *dir;
723     struct path         *path;
724     u_int32_t           did;
725     u_int16_t           vid;
726
727     *rbuflen = 0;
728     ibuf += 2;
729
730     memcpy( &vid, ibuf, sizeof( vid ));
731     ibuf += sizeof( vid );
732     if (NULL == ( vol = getvolbyvid( vid )) ) {
733         return( AFPERR_PARAM );
734     }
735
736     memcpy( &did, ibuf, sizeof( did ));
737     ibuf += sizeof( did );
738     if (NULL == ( dir = dirlookup( vol, did )) ) {
739         return afp_errno;
740     }
741
742     if (NULL == ( path = cname( vol, dir, &ibuf )) ) {
743         return get_afp_errno(AFPERR_NOOBJ);
744     }
745
746     if ((u_long)ibuf & 1 ) {
747         ibuf++;
748     }
749
750     return ad_addcomment(vol, path, ibuf);
751 }
752
753 /* -------------------- */
754 static int ad_getcomment(struct vol *vol, struct path *path, char *rbuf, size_t *rbuflen)
755 {
756     struct adouble      ad, *adp;
757     struct ofork        *of;
758     char                *upath;
759     int                 isadir;
760     int                 clen;
761
762     upath = path->u_name;
763     isadir = path_isadir(path);
764     if (isadir || !(of = of_findname(vol, path))) {
765         ad_init(&ad, vol->v_adouble, vol->v_ad_options);
766         adp = &ad;
767     } else
768         adp = of->of_ad;
769         
770     if ( ad_metadata( upath, ((isadir) ? ADFLAGS_DIR : 0), adp) < 0 ) {
771         return( AFPERR_NOITEM );
772     }
773
774     if (!ad_getentryoff(adp, ADEID_COMMENT)) {
775         ad_close_metadata( adp );
776         return AFPERR_NOITEM;
777     }
778     /*
779      * Make sure the AD file is not bogus.
780      */
781     if ( ad_getentrylen( adp, ADEID_COMMENT ) <= 0 ||
782             ad_getentrylen( adp, ADEID_COMMENT ) > 199 ) {
783         ad_close_metadata( adp );
784         return( AFPERR_NOITEM );
785     }
786
787     clen = min( ad_getentrylen( adp, ADEID_COMMENT ), 128 ); /* OSX only use 128, greater kill Adobe CS2 */
788     *rbuf++ = clen;
789     memcpy( rbuf, ad_entry( adp, ADEID_COMMENT ), clen);
790     *rbuflen = clen + 1;
791     ad_close_metadata( adp);
792
793     return( AFP_OK );
794 }
795
796 /* -------------------- */
797 int afp_getcomment(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
798 {
799     struct vol          *vol;
800     struct dir          *dir;
801     struct path         *s_path;
802     u_int32_t           did;
803     u_int16_t           vid;
804     
805     *rbuflen = 0;
806     ibuf += 2;
807
808     memcpy( &vid, ibuf, sizeof( vid ));
809     ibuf += sizeof( vid );
810     if (NULL == ( vol = getvolbyvid( vid )) ) {
811         return( AFPERR_PARAM );
812     }
813
814     memcpy( &did, ibuf, sizeof( did ));
815     ibuf += sizeof( did );
816     if (NULL == ( dir = dirlookup( vol, did )) ) {
817         return afp_errno;
818     }
819
820     if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
821         return get_afp_errno(AFPERR_NOOBJ);
822     }
823
824     return ad_getcomment(vol, s_path, rbuf, rbuflen);
825 }
826
827 /* ----------------------- */
828 static int ad_rmvcomment(struct vol *vol, struct path *path)
829 {
830     struct adouble      ad, *adp;
831     struct ofork        *of;
832     int                 isadir;
833     char                *upath;
834
835     upath = path->u_name;
836     if (check_access(upath, OPENACC_WR ) < 0) {
837         return AFPERR_ACCESS;
838     }
839
840     isadir = path_isadir(path);
841     if (isadir || !(of = of_findname(vol, path))) {
842         ad_init(&ad, vol->v_adouble, vol->v_ad_options);
843         adp = &ad;
844     } else
845         adp = of->of_ad;
846
847     if ( ad_open_metadata( upath, (isadir) ? ADFLAGS_DIR : 0, 0, adp) < 0 ) {
848         switch ( errno ) {
849         case ENOENT :
850             return( AFPERR_NOITEM );
851         case EACCES :
852             return( AFPERR_ACCESS );
853         default :
854             return( AFPERR_PARAM );
855         }
856     }
857
858     if (ad_getentryoff(adp, ADEID_COMMENT)) {
859         ad_setentrylen( adp, ADEID_COMMENT, 0 );
860         ad_flush( adp );
861     }
862     ad_close_metadata( adp);
863     return( AFP_OK );
864 }
865
866 /* ----------------------- */
867 int afp_rmvcomment(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
868 {
869     struct vol          *vol;
870     struct dir          *dir;
871     struct path         *s_path;
872     u_int32_t           did;
873     u_int16_t           vid;
874
875     *rbuflen = 0;
876     ibuf += 2;
877
878     memcpy( &vid, ibuf, sizeof( vid ));
879     ibuf += sizeof( vid );
880     if (NULL == ( vol = getvolbyvid( vid )) ) {
881         return( AFPERR_PARAM );
882     }
883
884     memcpy( &did, ibuf, sizeof( did ));
885     ibuf += sizeof( did );
886     if (NULL == ( dir = dirlookup( vol, did )) ) {
887         return afp_errno;
888     }
889
890     if (NULL == ( s_path = cname( vol, dir, &ibuf ))) {
891         return get_afp_errno(AFPERR_NOOBJ);
892     }
893     
894     return ad_rmvcomment(vol, s_path);
895 }