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