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