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