]> arthur.barton.de Git - netatalk.git/blob - etc/afpd/desktop.c
8acce125e2e7c08048d0ef39bf7729834ac1658d
[netatalk.git] / etc / afpd / desktop.c
1 /*
2  * $Id: desktop.c,v 1.41 2009-10-22 05:09:56 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 (sys_sendfile(dsi->socket, 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                 goto geticon_done;
519             }
520 #endif
521             buflen = read(si.sdt_fd, rbuf, *rbuflen);
522             if (buflen < 0)
523                 goto geticon_exit;
524
525             /* dsi_read() also returns buffer size of next allocation */
526             buflen = dsi_read(dsi, rbuf, buflen); /* send it off */
527             if (buflen < 0)
528                 goto geticon_exit;
529
530             *rbuflen = buflen;
531         }
532
533 geticon_done:
534         dsi_readdone(dsi);
535         return AFP_OK;
536
537 geticon_exit:
538         LOG(log_info, logtype_afpd, "afp_geticon(%s): %s", icon_dtfile(vol, fcreator), strerror(errno));
539         dsi_readdone(dsi);
540         obj->exit(EXITERR_SYS);
541         return AFP_OK;
542
543     } else {
544         if ( read( si.sdt_fd, rbuf, rc ) < rc ) {
545             return( AFPERR_PARAM );
546         }
547         *rbuflen = rc;
548     }
549     return AFP_OK;
550 }
551
552 /* ---------------------- */
553 static const char               hexdig[] = "0123456789abcdef";
554 char *dtfile(const struct vol *vol, u_char creator[], char *ext )
555 {
556     static char path[ MAXPATHLEN + 1];
557     char        *p;
558     unsigned int i;
559
560     strcpy( path, vol->v_path );
561     strcat( path, "/.AppleDesktop/" );
562     for ( p = path; *p != '\0'; p++ )
563         ;
564
565     if ( !isprint( creator[ 0 ] ) || creator[ 0 ] == '/' ) {
566         *p++ = hexdig[ ( creator[ 0 ] & 0xf0 ) >> 4 ];
567         *p++ = hexdig[ creator[ 0 ] & 0x0f ];
568     } else {
569         *p++ = creator[ 0 ];
570     }
571
572     *p++ = '/';
573
574     for ( i = 0; i < sizeof( CreatorType ); i++ ) {
575         if ( !isprint( creator[ i ] ) || creator[ i ] == '/' ) {
576             *p++ = hexdig[ ( creator[ i ] & 0xf0 ) >> 4 ];
577             *p++ = hexdig[ creator[ i ] & 0x0f ];
578         } else {
579             *p++ = creator[ i ];
580         }
581     }
582     *p = '\0';
583     strcat( path, ext );
584
585     return( path );
586 }
587
588 /* ---------------------------
589  * mpath is only a filename 
590  * did filename parent directory ID.
591 */
592
593 char *mtoupath(const struct vol *vol, char *mpath, cnid_t did, int utf8)
594 {
595     static char  upath[ MAXPATHLEN + 2]; /* for convert_charset dest_len parameter +2 */
596     char        *m, *u;
597     size_t       inplen;
598     size_t       outlen;
599     u_int16_t    flags = 0;
600         
601     if ( *mpath == '\0' ) {
602         return( "." );
603     }
604
605     /* set conversion flags */
606     if (!(vol->v_flags & AFPVOL_NOHEX))
607         flags |= CONV_ESCAPEHEX;
608     if (!(vol->v_flags & AFPVOL_USEDOTS))
609         flags |= CONV_ESCAPEDOTS;
610
611     if ((vol->v_casefold & AFPVOL_MTOUUPPER))
612         flags |= CONV_TOUPPER;
613     else if ((vol->v_casefold & AFPVOL_MTOULOWER))
614         flags |= CONV_TOLOWER;
615
616     if ((vol->v_flags & AFPVOL_EILSEQ)) {
617         flags |= CONV__EILSEQ;
618     }
619
620     m = demangle(vol, mpath, did);
621     if (m != mpath) {
622         return m;
623     }
624
625     m = mpath;
626     u = upath;
627
628     inplen = strlen(m);
629     outlen = MAXPATHLEN;
630
631     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)) ) {
632         LOG(log_error, logtype_afpd, "conversion from %s to %s for %s failed.", (utf8)?"UTF8-MAC":vol->v_maccodepage, vol->v_volcodepage, mpath);
633             return NULL;
634     }
635
636 #ifdef DEBUG
637     LOG(log_debug, logtype_afpd, "mtoupath: '%s':'%s'", mpath, upath);
638 #endif /* DEBUG */
639     return( upath );
640 }
641
642 /* --------------- 
643  * id filename ID
644 */
645 char *utompath(const struct vol *vol, char *upath, cnid_t id, int utf8)
646 {
647     static char  mpath[ MAXPATHLEN + 2]; /* for convert_charset dest_len parameter +2 */
648     char        *m, *u;
649     u_int16_t    flags = CONV_IGNORE | CONV_UNESCAPEHEX;
650     size_t       outlen;
651
652     m = mpath;
653     outlen = strlen(upath);
654
655     if ((vol->v_casefold & AFPVOL_UTOMUPPER))
656         flags |= CONV_TOUPPER;
657     else if ((vol->v_casefold & AFPVOL_UTOMLOWER))
658         flags |= CONV_TOLOWER;
659
660     if ((vol->v_flags & AFPVOL_EILSEQ)) {
661         flags |= CONV__EILSEQ;
662     }
663
664     u = upath;
665
666     /* convert charsets */
667     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)) ) { 
668         LOG(log_error, logtype_afpd, "Conversion from %s to %s for %s (%u) failed.", vol->v_volcodepage, vol->v_maccodepage, u, ntohl(id));
669         goto utompath_error;
670     }
671
672     if (!(flags & CONV_REQMANGLE)) 
673         flags = 0;
674     else
675         flags = 1;
676
677     if (utf8)
678         flags |= 2;
679
680     m = mangle(vol, mpath, outlen, upath, id, flags);
681
682 #ifdef DEBUG
683     LOG(log_debug, logtype_afpd, "utompath: '%s':'%s':'%2.2X'", upath, m, ntohl(id));
684 #endif /* DEBUG */
685     return(m);
686
687 utompath_error:
688     u = "???";
689     m = mangle(vol, u, strlen(u), upath, id, (utf8)?3:1);
690     return(m);
691 }
692
693 /* ------------------------- */
694 static int ad_addcomment(struct vol *vol, struct path *path, char *ibuf)
695 {
696     struct ofork        *of;
697     char                *name, *upath;
698     int                 isadir;
699     int                 clen;
700     struct adouble      ad, *adp;
701
702     clen = (u_char)*ibuf++;
703     clen = min( clen, 199 );
704
705     upath = path->u_name;
706     if (!vol_unix_priv(vol) && check_access(upath, OPENACC_WR ) < 0) {
707         return AFPERR_ACCESS;
708     }
709     
710     isadir = path_isadir(path);
711     if (isadir || !(of = of_findname(path))) {
712         ad_init(&ad, vol->v_adouble, vol->v_ad_options);
713         adp = &ad;
714     } else
715         adp = of->of_ad;
716
717     if (ad_open_metadata( upath , vol_noadouble(vol) | ( (isadir) ? ADFLAGS_DIR :0),O_CREAT, adp) < 0 ) {
718         return( AFPERR_ACCESS );
719     }
720
721     if (ad_getentryoff(adp, ADEID_COMMENT)) {
722         if ( (ad_get_MD_flags( adp ) & O_CREAT) ) {
723             if ( *path->m_name == '\0' ) {
724                 name = curdir->d_m_name;
725             } else {
726                 name = path->m_name;
727             }
728             ad_setname(adp, name);
729         }
730         ad_setentrylen( adp, ADEID_COMMENT, clen );
731         memcpy( ad_entry( adp, ADEID_COMMENT ), ibuf, clen );
732         ad_flush( adp );
733     }
734     ad_close_metadata( adp);
735     return( AFP_OK );
736 }
737
738 /* ----------------------------- */
739 int afp_addcomment(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
740 {
741     struct vol          *vol;
742     struct dir          *dir;
743     struct path         *path;
744     u_int32_t           did;
745     u_int16_t           vid;
746
747     *rbuflen = 0;
748     ibuf += 2;
749
750     memcpy( &vid, ibuf, sizeof( vid ));
751     ibuf += sizeof( vid );
752     if (NULL == ( vol = getvolbyvid( vid )) ) {
753         return( AFPERR_PARAM );
754     }
755
756     memcpy( &did, ibuf, sizeof( did ));
757     ibuf += sizeof( did );
758     if (NULL == ( dir = dirlookup( vol, did )) ) {
759         return afp_errno;
760     }
761
762     if (NULL == ( path = cname( vol, dir, &ibuf )) ) {
763         return get_afp_errno(AFPERR_NOOBJ);
764     }
765
766     if ((u_long)ibuf & 1 ) {
767         ibuf++;
768     }
769
770     return ad_addcomment(vol, path, ibuf);
771 }
772
773 /* -------------------- */
774 static int ad_getcomment(struct vol *vol, struct path *path, char *rbuf, size_t *rbuflen)
775 {
776     struct adouble      ad, *adp;
777     struct ofork        *of;
778     char                *upath;
779     int                 isadir;
780     int                 clen;
781
782     upath = path->u_name;
783     isadir = path_isadir(path);
784     if (isadir || !(of = of_findname(path))) {
785         ad_init(&ad, vol->v_adouble, vol->v_ad_options);
786         adp = &ad;
787     } else
788         adp = of->of_ad;
789         
790     if ( ad_metadata( upath,( isadir) ? ADFLAGS_DIR : 0, adp) < 0 ) {
791         return( AFPERR_NOITEM );
792     }
793
794     if (!ad_getentryoff(adp, ADEID_COMMENT)) {
795         ad_close_metadata( adp );
796         return AFPERR_NOITEM;
797     }
798     /*
799      * Make sure the AD file is not bogus.
800      */
801     if ( ad_getentrylen( adp, ADEID_COMMENT ) <= 0 ||
802             ad_getentrylen( adp, ADEID_COMMENT ) > 199 ) {
803         ad_close_metadata( adp );
804         return( AFPERR_NOITEM );
805     }
806
807     clen = min( ad_getentrylen( adp, ADEID_COMMENT ), 128 ); /* OSX only use 128, greater kill Adobe CS2 */
808     *rbuf++ = clen;
809     memcpy( rbuf, ad_entry( adp, ADEID_COMMENT ), clen);
810     *rbuflen = clen + 1;
811     ad_close_metadata( adp);
812
813     return( AFP_OK );
814 }
815
816 /* -------------------- */
817 int afp_getcomment(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
818 {
819     struct vol          *vol;
820     struct dir          *dir;
821     struct path         *s_path;
822     u_int32_t           did;
823     u_int16_t           vid;
824     
825     *rbuflen = 0;
826     ibuf += 2;
827
828     memcpy( &vid, ibuf, sizeof( vid ));
829     ibuf += sizeof( vid );
830     if (NULL == ( vol = getvolbyvid( vid )) ) {
831         return( AFPERR_PARAM );
832     }
833
834     memcpy( &did, ibuf, sizeof( did ));
835     ibuf += sizeof( did );
836     if (NULL == ( dir = dirlookup( vol, did )) ) {
837         return afp_errno;
838     }
839
840     if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
841         return get_afp_errno(AFPERR_NOOBJ);
842     }
843
844     return ad_getcomment(vol, s_path, rbuf, rbuflen);
845 }
846
847 /* ----------------------- */
848 static int ad_rmvcomment(struct vol *vol, struct path *path)
849 {
850     struct adouble      ad, *adp;
851     struct ofork        *of;
852     int                 isadir;
853     char                *upath;
854
855     upath = path->u_name;
856     if (!vol_unix_priv(vol) && check_access(upath, OPENACC_WR ) < 0) {
857         return AFPERR_ACCESS;
858     }
859
860     isadir = path_isadir(path);
861     if (isadir || !(of = of_findname(path))) {
862         ad_init(&ad, vol->v_adouble, vol->v_ad_options);
863         adp = &ad;
864     } else
865         adp = of->of_ad;
866
867     if ( ad_open_metadata( upath, (isadir) ? ADFLAGS_DIR : 0, 0, adp) < 0 ) {
868         switch ( errno ) {
869         case ENOENT :
870             return( AFPERR_NOITEM );
871         case EACCES :
872             return( AFPERR_ACCESS );
873         default :
874             return( AFPERR_PARAM );
875         }
876     }
877
878     if (ad_getentryoff(adp, ADEID_COMMENT)) {
879         ad_setentrylen( adp, ADEID_COMMENT, 0 );
880         ad_flush( adp );
881     }
882     ad_close_metadata( adp);
883     return( AFP_OK );
884 }
885
886 /* ----------------------- */
887 int afp_rmvcomment(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
888 {
889     struct vol          *vol;
890     struct dir          *dir;
891     struct path         *s_path;
892     u_int32_t           did;
893     u_int16_t           vid;
894
895     *rbuflen = 0;
896     ibuf += 2;
897
898     memcpy( &vid, ibuf, sizeof( vid ));
899     ibuf += sizeof( vid );
900     if (NULL == ( vol = getvolbyvid( vid )) ) {
901         return( AFPERR_PARAM );
902     }
903
904     memcpy( &did, ibuf, sizeof( did ));
905     ibuf += sizeof( did );
906     if (NULL == ( dir = dirlookup( vol, did )) ) {
907         return afp_errno;
908     }
909
910     if (NULL == ( s_path = cname( vol, dir, &ibuf ))) {
911         return get_afp_errno(AFPERR_NOOBJ);
912     }
913     
914     return ad_rmvcomment(vol, s_path);
915 }