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