]> arthur.barton.de Git - netatalk.git/blob - etc/afpd/desktop.c
return AFPERR_NOITEM for 0 len comment
[netatalk.git] / etc / afpd / desktop.c
1 /*
2  * $Id: desktop.c,v 1.26.2.4.2.12 2004-03-11 23:01:40 bfernhomberg 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_setname(adp, name);
741     }
742
743     ad_setentrylen( adp, ADEID_COMMENT, clen );
744     memcpy( ad_entry( adp, ADEID_COMMENT ), ibuf, clen );
745     ad_flush( adp, ADFLAGS_HF );
746     ad_close( adp, ADFLAGS_HF );
747     return( AFP_OK );
748 }
749
750 /* ----------------------------- */
751 int afp_addcomment(obj, ibuf, ibuflen, rbuf, rbuflen )
752 AFPObj      *obj;
753 char    *ibuf, *rbuf;
754 int             ibuflen, *rbuflen;
755 {
756     struct vol          *vol;
757     struct dir          *dir;
758     struct path         *path;
759     u_int32_t           did;
760     u_int16_t           vid;
761
762     *rbuflen = 0;
763     ibuf += 2;
764
765     memcpy( &vid, ibuf, sizeof( vid ));
766     ibuf += sizeof( vid );
767     if (NULL == ( vol = getvolbyvid( vid )) ) {
768         return( AFPERR_PARAM );
769     }
770
771     memcpy( &did, ibuf, sizeof( did ));
772     ibuf += sizeof( did );
773     if (NULL == ( dir = dirlookup( vol, did )) ) {
774         return afp_errno;
775     }
776
777     if (NULL == ( path = cname( vol, dir, &ibuf )) ) {
778         return get_afp_errno(AFPERR_NOOBJ);
779     }
780
781     if ((u_long)ibuf & 1 ) {
782         ibuf++;
783     }
784
785     return ad_addcomment(vol, path, ibuf);
786 }
787
788 /* -------------------- */
789 static int ad_getcomment(struct vol *vol, struct path *path, char *rbuf, int *rbuflen)
790 {
791     struct adouble      ad, *adp;
792     struct ofork        *of;
793     char                *upath;
794     int                 isadir;
795
796
797     upath = path->u_name;
798     isadir = path_isadir(path);
799     if (isadir || !(of = of_findname(path))) {
800         ad_init(&ad, vol->v_adouble);
801         adp = &ad;
802     } else
803         adp = of->of_ad;
804         
805     if ( ad_open( upath,
806                   ( isadir) ? ADFLAGS_HF|ADFLAGS_DIR : ADFLAGS_HF,
807                   O_RDONLY, 0666, adp) < 0 ) {
808         return( AFPERR_NOITEM );
809     }
810
811     if (!ad_getentryoff(adp, ADEID_COMMENT)) {
812         return AFPERR_NOITEM;
813     }
814     /*
815      * Make sure the AD file is not bogus.
816      */
817     if ( ad_getentrylen( adp, ADEID_COMMENT ) <= 0 ||
818             ad_getentrylen( adp, ADEID_COMMENT ) > 199 ) {
819         ad_close( adp, ADFLAGS_HF );
820         return( AFPERR_NOITEM );
821     }
822
823     *rbuf++ = ad_getentrylen( adp, ADEID_COMMENT );
824     memcpy( rbuf, ad_entry( adp, ADEID_COMMENT ),
825             ad_getentrylen( adp, ADEID_COMMENT ));
826     *rbuflen = ad_getentrylen( adp, ADEID_COMMENT ) + 1;
827     ad_close( adp, ADFLAGS_HF );
828
829     return( AFP_OK );
830 }
831
832 /* -------------------- */
833 int afp_getcomment(obj, ibuf, ibuflen, rbuf, rbuflen )
834 AFPObj      *obj;
835 char    *ibuf, *rbuf;
836 int             ibuflen, *rbuflen;
837 {
838     struct vol          *vol;
839     struct dir          *dir;
840     struct path         *s_path;
841     u_int32_t           did;
842     u_int16_t           vid;
843     
844     *rbuflen = 0;
845     ibuf += 2;
846
847     memcpy( &vid, ibuf, sizeof( vid ));
848     ibuf += sizeof( vid );
849     if (NULL == ( vol = getvolbyvid( vid )) ) {
850         return( AFPERR_PARAM );
851     }
852
853     memcpy( &did, ibuf, sizeof( did ));
854     ibuf += sizeof( did );
855     if (NULL == ( dir = dirlookup( vol, did )) ) {
856         return afp_errno;
857     }
858
859     if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
860         return get_afp_errno(AFPERR_NOOBJ);
861     }
862
863     return ad_getcomment(vol, s_path, rbuf, rbuflen);
864 }
865
866 /* ----------------------- */
867 static int ad_rmvcomment(struct vol *vol, struct path *path)
868 {
869     struct adouble      ad, *adp;
870     struct ofork        *of;
871     int                 isadir;
872     char                *upath;
873
874     upath = path->u_name;
875     if (!vol_unix_priv(vol) && check_access(upath, OPENACC_WR ) < 0) {
876         return AFPERR_ACCESS;
877     }
878
879     isadir = path_isadir(path);
880     if (isadir || !(of = of_findname(path))) {
881         ad_init(&ad, vol->v_adouble);
882         adp = &ad;
883     } else
884         adp = of->of_ad;
885
886     if ( ad_open( upath,
887                    (isadir) ? ADFLAGS_HF|ADFLAGS_DIR : ADFLAGS_HF,
888                   O_RDWR, 0, adp) < 0 ) {
889         switch ( errno ) {
890         case ENOENT :
891             return( AFPERR_NOITEM );
892         case EACCES :
893             return( AFPERR_ACCESS );
894         default :
895             return( AFPERR_PARAM );
896         }
897     }
898
899     if (!ad_getentryoff(adp, ADEID_COMMENT)) {
900         return AFP_OK;
901     }
902
903     ad_setentrylen( adp, ADEID_COMMENT, 0 );
904     ad_flush( adp, ADFLAGS_HF );
905     ad_close( adp, ADFLAGS_HF );
906     return( AFP_OK );
907 }
908
909 /* ----------------------- */
910 int afp_rmvcomment(obj, ibuf, ibuflen, rbuf, rbuflen )
911 AFPObj      *obj;
912 char    *ibuf, *rbuf;
913 int             ibuflen, *rbuflen;
914 {
915     struct vol          *vol;
916     struct dir          *dir;
917     struct path         *s_path;
918     u_int32_t           did;
919     u_int16_t           vid;
920
921     *rbuflen = 0;
922     ibuf += 2;
923
924     memcpy( &vid, ibuf, sizeof( vid ));
925     ibuf += sizeof( vid );
926     if (NULL == ( vol = getvolbyvid( vid )) ) {
927         return( AFPERR_PARAM );
928     }
929
930     memcpy( &did, ibuf, sizeof( did ));
931     ibuf += sizeof( did );
932     if (NULL == ( dir = dirlookup( vol, did )) ) {
933         return afp_errno;
934     }
935
936     if (NULL == ( s_path = cname( vol, dir, &ibuf ))) {
937         return get_afp_errno(AFPERR_NOOBJ);
938     }
939     
940     return ad_rmvcomment(vol, s_path);
941 }