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