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