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