]> arthur.barton.de Git - netatalk.git/blob - etc/afpd/desktop.c
Warning fixes.
[netatalk.git] / etc / afpd / desktop.c
1 /*
2  * $Id: desktop.c,v 1.30 2003-06-09 14:42:38 srittau 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 <atalk/logger.h>
17 #include <errno.h>
18 #include <sys/types.h>
19 #include <sys/time.h>
20 #include <sys/uio.h>
21 #include <sys/param.h>
22 #include <sys/stat.h>
23 #include <sys/socket.h>
24 #include <netatalk/at.h>
25 #include <netatalk/endian.h>
26 #include <atalk/dsi.h>
27 #include <atalk/atp.h>
28 #include <atalk/asp.h>
29 #include <atalk/afp.h>
30 #include <atalk/adouble.h>
31 #include <atalk/util.h>
32 #include <dirent.h>
33 #ifdef HAVE_FCNTL_H
34 #include <fcntl.h>
35 #endif /* HAVE_FCNTL_H */
36 #include <stdio.h>
37 #include <string.h>
38 #include <ctype.h>
39 #ifdef HAVE_FCNTL_H
40 #include <unistd.h>
41 #endif /* HAVE_FCNTL_H */
42
43 #include "volume.h"
44 #include "directory.h"
45 #include "fork.h"
46 #include "globals.h"
47 #include "desktop.h"
48
49 #ifdef FILE_MANGLING
50 #include "mangle.h"
51 #endif /* CNID_DB */
52
53 #ifdef AFP3x
54 #include <iconv.h>
55 #endif
56
57 int afp_opendt(obj, ibuf, ibuflen, rbuf, rbuflen )
58 AFPObj      *obj;
59 char    *ibuf, *rbuf;
60 int             ibuflen, *rbuflen;
61 {
62     struct vol  *vol;
63     u_int16_t   vid;
64
65     ibuf += 2;
66
67     memcpy( &vid, ibuf, sizeof(vid));
68     if (NULL == ( vol = getvolbyvid( vid )) ) {
69         *rbuflen = 0;
70         return( AFPERR_PARAM );
71     }
72
73     memcpy( rbuf, &vid, sizeof(vid));
74     *rbuflen = sizeof(vid);
75     return( AFP_OK );
76 }
77
78 int afp_closedt(obj, ibuf, ibuflen, rbuf, rbuflen )
79 AFPObj      *obj;
80 char    *ibuf, *rbuf;
81 int             ibuflen, *rbuflen;
82 {
83     *rbuflen = 0;
84     return( AFP_OK );
85 }
86
87 struct savedt   si = { { 0, 0, 0, 0 }, -1, 0 };
88
89 static int iconopen( vol, creator, flags, mode )
90 struct vol      *vol;
91 u_char  creator[ 4 ];
92 {
93     char        *dtf, *adt, *adts;
94
95     if ( si.sdt_fd != -1 ) {
96         if ( memcmp( si.sdt_creator, creator, sizeof( CreatorType )) == 0 &&
97                 si.sdt_vid == vol->v_vid ) {
98             return 0;
99         }
100         close( si.sdt_fd );
101         si.sdt_fd = -1;
102     }
103
104     dtf = dtfile( vol, creator, ".icon" );
105
106     if (( si.sdt_fd = open( dtf, flags, ad_mode( dtf, mode ))) < 0 ) {
107         if ( errno == ENOENT && ( flags & O_CREAT )) {
108             if (( adts = strrchr( dtf, '/' )) == NULL ) {
109                 return -1;
110             }
111             *adts = '\0';
112             if (( adt = strrchr( dtf, '/' )) == NULL ) {
113                 return -1;
114             }
115             *adt = '\0';
116             (void) ad_mkdir( dtf, DIRBITS | 0777 );
117             *adt = '/';
118             (void) ad_mkdir( dtf, DIRBITS | 0777 );
119             *adts = '/';
120
121             if (( si.sdt_fd = open( dtf, flags, ad_mode( dtf, mode ))) < 0 ) {
122                 LOG(log_error, logtype_afpd, "iconopen: open %s: %s", dtf, strerror(errno) );
123                 return -1;
124             }
125         } else {
126             return -1;
127         }
128     }
129
130     memcpy( si.sdt_creator, creator, sizeof( CreatorType ));
131     si.sdt_vid = vol->v_vid;
132     si.sdt_index = 1;
133     return 0;
134 }
135
136 int afp_addicon(obj, ibuf, ibuflen, rbuf, rbuflen)
137 AFPObj      *obj;
138 char    *ibuf, *rbuf;
139 int             ibuflen, *rbuflen;
140 {
141     struct vol          *vol;
142     struct iovec        iov[ 2 ];
143     u_char              fcreator[ 4 ], imh[ 12 ], irh[ 12 ], *p;
144     int                 itype, cc = AFP_OK, iovcnt = 0, buflen;
145     u_int32_t           ftype, itag;
146     u_int16_t           bsize, rsize, vid;
147
148     buflen = *rbuflen;
149     *rbuflen = 0;
150     ibuf += 2;
151
152     memcpy( &vid, ibuf, sizeof( vid ));
153     ibuf += sizeof( vid );
154     if (NULL == ( vol = getvolbyvid( vid )) ) {
155         cc = AFPERR_PARAM;
156         goto addicon_err;
157     }
158
159     memcpy( fcreator, ibuf, sizeof( fcreator ));
160     ibuf += sizeof( fcreator );
161
162     memcpy( &ftype, ibuf, sizeof( ftype ));
163     ibuf += sizeof( ftype );
164
165     itype = (unsigned char) *ibuf;
166     ibuf += 2;
167
168     memcpy( &itag, ibuf, sizeof( itag ));
169     ibuf += sizeof( itag );
170
171     memcpy( &bsize, ibuf, sizeof( bsize ));
172     bsize = ntohs( bsize );
173
174     if ( si.sdt_fd != -1 ) {
175         (void)close( si.sdt_fd );
176         si.sdt_fd = -1;
177     }
178
179     if (iconopen( vol, fcreator, O_RDWR|O_CREAT, 0666 ) < 0) {
180         cc = AFPERR_NOITEM;
181         goto addicon_err;
182     }
183
184     if (lseek( si.sdt_fd, (off_t) 0L, SEEK_SET ) < 0) {
185         close(si.sdt_fd);
186         si.sdt_fd = -1;
187         LOG(log_error, logtype_afpd, "afp_addicon: lseek: %s", strerror(errno) );
188         cc = AFPERR_PARAM;
189         goto addicon_err;
190     }
191
192     /*
193      * Read icon elements until we find a match to replace, or
194      * we get to the end to insert.
195      */
196     p = imh;
197     memcpy( p, &itag, sizeof( itag ));
198     p += sizeof( itag );
199     memcpy( p, &ftype, sizeof( ftype ));
200     p += sizeof( ftype );
201     *p++ = itype;
202     *p++ = 0;
203     bsize = htons( bsize );
204     memcpy( p, &bsize, sizeof( bsize ));
205     bsize = ntohs( bsize );
206     while (( cc = read( si.sdt_fd, irh, sizeof( irh ))) > 0 ) {
207         memcpy( &rsize, irh + 10, sizeof( rsize ));
208         rsize = ntohs( rsize );
209         /*
210          * Is this our set of headers?
211          */
212         if ( memcmp( irh, imh, sizeof( irh ) - sizeof( u_short )) == 0 ) {
213             /*
214              * Is the size correct?
215              */
216             if ( bsize != rsize )
217                 cc = AFPERR_ITYPE;
218             break;
219         }
220
221         if ( lseek( si.sdt_fd, (off_t) rsize, SEEK_CUR ) < 0 ) {
222             LOG(log_error, logtype_afpd, "afp_addicon: lseek: %s", strerror(errno) );
223             cc = AFPERR_PARAM;
224         }
225     }
226
227     /*
228      * Some error occurred, return.
229      */
230 addicon_err:
231     if ( cc < 0 ) {
232         LOG(log_error, logtype_afpd, "afp_addicon: %s", strerror(errno) );
233         if (obj->proto == AFPPROTO_DSI) {
234             dsi_writeinit(obj->handle, rbuf, buflen);
235             dsi_writeflush(obj->handle);
236         }
237         return cc;
238     }
239
240
241     switch (obj->proto) {
242 #ifndef NO_DDP
243     case AFPPROTO_ASP:
244         buflen = bsize;
245         if ((asp_wrtcont(obj->handle, rbuf, &buflen) < 0) || buflen != bsize)
246             return( AFPERR_PARAM );
247
248         if (obj->options.flags & OPTION_DEBUG) {
249             printf("(write) len: %d\n", buflen);
250             bprint(rbuf, buflen);
251         }
252
253         /*
254          * We're at the end of the file, add the headers, etc.  */
255         if ( cc == 0 ) {
256             iov[ 0 ].iov_base = (caddr_t)imh;
257             iov[ 0 ].iov_len = sizeof( imh );
258             iov[ 1 ].iov_base = rbuf;
259             iov[ 1 ].iov_len = bsize;
260             iovcnt = 2;
261         }
262
263         /*
264          * We found an icon to replace.
265          */
266         if ( cc > 0 ) {
267             iov[ 0 ].iov_base = rbuf;
268             iov[ 0 ].iov_len = bsize;
269             iovcnt = 1;
270         }
271
272         if ( writev( si.sdt_fd, iov, iovcnt ) < 0 ) {
273             LOG(log_error, logtype_afpd, "afp_addicon: writev: %s", strerror(errno) );
274             return( AFPERR_PARAM );
275         }
276         break;
277 #endif /* no afp/asp */      
278     case AFPPROTO_DSI:
279         {
280             DSI *dsi = obj->handle;
281
282             iovcnt = dsi_writeinit(dsi, rbuf, buflen);
283
284             /* add headers at end of file */
285             if ((cc == 0) && (write(si.sdt_fd, imh, sizeof(imh)) < 0)) {
286                 LOG(log_error, logtype_afpd, "afp_addicon: write: %s", strerror(errno));
287                 dsi_writeflush(dsi);
288                 return AFPERR_PARAM;
289             }
290
291             if ((cc = write(si.sdt_fd, rbuf, iovcnt)) < 0) {
292                 LOG(log_error, logtype_afpd, "afp_addicon: write: %s", strerror(errno));
293                 dsi_writeflush(dsi);
294                 return AFPERR_PARAM;
295             }
296
297             while ((iovcnt = dsi_write(dsi, rbuf, buflen))) {
298                 if ( obj->options.flags & OPTION_DEBUG ) {
299                     printf("(write) command cont'd: %d\n", iovcnt);
300                     bprint(rbuf, iovcnt);
301                 }
302
303                 if ((cc = write(si.sdt_fd, rbuf, iovcnt)) < 0) {
304                     LOG(log_error, logtype_afpd, "afp_addicon: write: %s", strerror(errno));
305                     dsi_writeflush(dsi);
306                     return AFPERR_PARAM;
307                 }
308             }
309         }
310         break;
311     }
312
313     close( si.sdt_fd );
314     si.sdt_fd = -1;
315     return( AFP_OK );
316 }
317
318 u_char  utag[] = { 0, 0, 0, 0 };
319 u_char  ucreator[] = { 'U', 'N', 'I', 'X' };
320 u_char  utype[] = { 'T', 'E', 'X', 'T' };
321 short   usize = 256;
322 u_char  uicon[] = {
323     0x1F, 0xFF, 0xFC, 0x00, 0x10, 0x00, 0x06, 0x00,
324     0x10, 0x00, 0x05, 0x00, 0x10, 0x00, 0x04, 0x80,
325     0x10, 0x00, 0x04, 0x40, 0x10, 0x00, 0x04, 0x20,
326     0x10, 0x00, 0x07, 0xF0, 0x10, 0x00, 0x00, 0x10,
327     0x10, 0x00, 0x00, 0x10, 0x10, 0x00, 0x00, 0x10,
328     0x10, 0x00, 0x00, 0x10, 0x10, 0x80, 0x02, 0x10,
329     0x11, 0x80, 0x03, 0x10, 0x12, 0x80, 0x02, 0x90,
330     0x12, 0x80, 0x02, 0x90, 0x14, 0x80, 0x02, 0x50,
331     0x14, 0x87, 0xC2, 0x50, 0x14, 0x58, 0x34, 0x50,
332     0x14, 0x20, 0x08, 0x50, 0x12, 0x16, 0xD0, 0x90,
333     0x11, 0x01, 0x01, 0x10, 0x12, 0x80, 0x02, 0x90,
334     0x12, 0x9C, 0x72, 0x90, 0x14, 0x22, 0x88, 0x50,
335     0x14, 0x41, 0x04, 0x50, 0x14, 0x49, 0x24, 0x50,
336     0x14, 0x55, 0x54, 0x50, 0x14, 0x5D, 0x74, 0x50,
337     0x14, 0x5D, 0x74, 0x50, 0x12, 0x49, 0x24, 0x90,
338     0x12, 0x22, 0x88, 0x90, 0x1F, 0xFF, 0xFF, 0xF0,
339     0x1F, 0xFF, 0xFC, 0x00, 0x1F, 0xFF, 0xFE, 0x00,
340     0x1F, 0xFF, 0xFF, 0x00, 0x1F, 0xFF, 0xFF, 0x80,
341     0x1F, 0xFF, 0xFF, 0xC0, 0x1F, 0xFF, 0xFF, 0xE0,
342     0x1F, 0xFF, 0xFF, 0xF0, 0x1F, 0xFF, 0xFF, 0xF0,
343     0x1F, 0xFF, 0xFF, 0xF0, 0x1F, 0xFF, 0xFF, 0xF0,
344     0x1F, 0xFF, 0xFF, 0xF0, 0x1F, 0xFF, 0xFF, 0xF0,
345     0x1F, 0xFF, 0xFF, 0xF0, 0x1F, 0xFF, 0xFF, 0xF0,
346     0x1F, 0xFF, 0xFF, 0xF0, 0x1F, 0xFF, 0xFF, 0xF0,
347     0x1F, 0xFF, 0xFF, 0xF0, 0x1F, 0xFF, 0xFF, 0xF0,
348     0x1F, 0xFF, 0xFF, 0xF0, 0x1F, 0xFF, 0xFF, 0xF0,
349     0x1F, 0xFF, 0xFF, 0xF0, 0x1F, 0xFF, 0xFF, 0xF0,
350     0x1F, 0xFF, 0xFF, 0xF0, 0x1F, 0xFF, 0xFF, 0xF0,
351     0x1F, 0xFF, 0xFF, 0xF0, 0x1F, 0xFF, 0xFF, 0xF0,
352     0x1F, 0xFF, 0xFF, 0xF0, 0x1F, 0xFF, 0xFF, 0xF0,
353     0x1F, 0xFF, 0xFF, 0xF0, 0x1F, 0xFF, 0xFF, 0xF0,
354     0x1F, 0xFF, 0xFF, 0xF0, 0x1F, 0xFF, 0xFF, 0xF0,
355 };
356
357 int afp_geticoninfo(obj, ibuf, ibuflen, rbuf, rbuflen )
358 AFPObj      *obj;
359 char    *ibuf, *rbuf;
360 int             ibuflen, *rbuflen;
361 {
362     struct vol  *vol;
363     u_char      fcreator[ 4 ], ih[ 12 ];
364     u_int16_t   vid, iindex, bsize;
365
366     *rbuflen = 0;
367     ibuf += 2;
368
369     memcpy( &vid, ibuf, sizeof( vid ));
370     ibuf += sizeof( vid );
371     if (NULL == ( vol = getvolbyvid( vid )) ) {
372         return( AFPERR_PARAM );
373     }
374
375     memcpy( fcreator, ibuf, sizeof( fcreator ));
376     ibuf += sizeof( fcreator );
377     memcpy( &iindex, ibuf, sizeof( iindex ));
378     iindex = ntohs( iindex );
379
380     if ( memcmp( fcreator, ucreator, sizeof( ucreator )) == 0 ) {
381         if ( iindex > 1 ) {
382             return( AFPERR_NOITEM );
383         }
384         memcpy( ih, utag, sizeof( utag ));
385         memcpy( ih + sizeof( utag ), utype, sizeof( utype ));
386         *( ih + sizeof( utag ) + sizeof( utype )) = 1;
387         *( ih + sizeof( utag ) + sizeof( utype ) + 1 ) = 0;
388         memcpy( ih + sizeof( utag ) + sizeof( utype ) + 2, &usize,
389                 sizeof( usize ));
390         memcpy( rbuf, ih, sizeof( ih ));
391         *rbuflen = sizeof( ih );
392         return( AFP_OK );
393     }
394
395     if ( iconopen( vol, fcreator, O_RDONLY, 0 ) < 0) {
396         return( AFPERR_NOITEM );
397     }
398
399     if ( iindex < si.sdt_index ) {
400         if ( lseek( si.sdt_fd, (off_t) 0L, SEEK_SET ) < 0 ) {
401             return( AFPERR_PARAM );
402         }
403         si.sdt_index = 1;
404     }
405
406     /*
407      * Position to the correct spot.
408      */
409     for (;;) {
410         if ( read( si.sdt_fd, ih, sizeof( ih )) != sizeof( ih )) {
411             close( si.sdt_fd );
412             si.sdt_fd = -1;
413             return( AFPERR_NOITEM );
414         }
415         memcpy( &bsize, ih + 10, sizeof( bsize ));
416         bsize = ntohs(bsize);
417         if ( lseek( si.sdt_fd, (off_t) bsize, SEEK_CUR ) < 0 ) {
418             LOG(log_error, logtype_afpd, "afp_iconinfo: lseek: %s", strerror(errno) );
419             return( AFPERR_PARAM );
420         }
421         if ( si.sdt_index == iindex ) {
422             memcpy( rbuf, ih, sizeof( ih ));
423             *rbuflen = sizeof( ih );
424             return( AFP_OK );
425         }
426         si.sdt_index++;
427     }
428 }
429
430
431 int afp_geticon(obj, ibuf, ibuflen, rbuf, rbuflen )
432 AFPObj      *obj;
433 char    *ibuf, *rbuf;
434 int             ibuflen, *rbuflen;
435 {
436     struct vol  *vol;
437     off_t       offset;
438     int         rc, buflen;
439     u_char      fcreator[ 4 ], ftype[ 4 ], itype, ih[ 12 ];
440     u_int16_t   vid, bsize, rsize;
441
442     buflen = *rbuflen;
443     *rbuflen = 0;
444     ibuf += 2;
445
446     memcpy( &vid, ibuf, sizeof( vid ));
447     ibuf += sizeof( vid );
448     if (NULL == ( vol = getvolbyvid( vid )) ) {
449         return( AFPERR_PARAM );
450     }
451
452     memcpy( fcreator, ibuf, sizeof( fcreator ));
453     ibuf += sizeof( fcreator );
454     memcpy( ftype, ibuf, sizeof( ftype ));
455     ibuf += sizeof( ftype );
456     itype = (unsigned char) *ibuf++;
457     ibuf++;
458     memcpy( &bsize, ibuf, sizeof( bsize ));
459     bsize = ntohs( bsize );
460
461     if ( memcmp( fcreator, ucreator, sizeof( ucreator )) == 0 &&
462             memcmp( ftype, utype, sizeof( utype )) == 0 &&
463             itype == 1 &&
464             bsize <= usize ) {
465         memcpy( rbuf, uicon, bsize);
466         *rbuflen = bsize;
467         return( AFP_OK );
468     }
469
470     if ( iconopen( vol, fcreator, O_RDONLY, 0 ) < 0) {
471         return( AFPERR_NOITEM );
472     }
473
474     if ( lseek( si.sdt_fd, (off_t) 0L, SEEK_SET ) < 0 ) {
475         close(si.sdt_fd);
476         si.sdt_fd = -1;
477         LOG(log_error, logtype_afpd, "afp_geticon: lseek: %s", strerror(errno));
478         return( AFPERR_PARAM );
479     }
480
481     si.sdt_index = 1;
482     offset = 0;
483     while (( rc = read( si.sdt_fd, ih, sizeof( ih ))) > 0 ) {
484         si.sdt_index++;
485         offset += sizeof(ih);
486         if ( memcmp( ih + sizeof( int ), ftype, sizeof( ftype )) == 0 &&
487                 *(ih + sizeof( int ) + sizeof( ftype )) == itype ) {
488             break;
489         }
490         memcpy( &rsize, ih + 10, sizeof( rsize ));
491         rsize = ntohs( rsize );
492         if ( lseek( si.sdt_fd, (off_t) rsize, SEEK_CUR ) < 0 ) {
493             LOG(log_error, logtype_afpd, "afp_geticon: lseek: %s", strerror(errno) );
494             return( AFPERR_PARAM );
495         }
496         offset += rsize;
497     }
498
499     if ( rc < 0 ) {
500         LOG(log_error, logtype_afpd, "afp_geticon: read: %s", strerror(errno));
501         return( AFPERR_PARAM );
502     }
503
504     if ( rc == 0 ) {
505         return( AFPERR_NOITEM );
506     }
507
508     memcpy( &rsize, ih + 10, sizeof( rsize ));
509     rsize = ntohs( rsize );
510 #define min(a,b)        ((a)<(b)?(a):(b))
511     rc = min( bsize, rsize );
512
513     if ((obj->proto == AFPPROTO_DSI) && (buflen < rc)) {
514         DSI *dsi = obj->handle;
515         struct stat st;
516         off_t size;
517
518         size = (fstat(si.sdt_fd, &st) < 0) ? 0 : st.st_size;
519         if (size < rc + offset) {
520             return AFPERR_PARAM;
521         }
522
523         if ((*rbuflen = dsi_readinit(dsi, rbuf, buflen, rc, AFP_OK)) < 0)
524             goto geticon_exit;
525
526         /* do to the streaming nature, we have to exit if we encounter
527          * a problem. much confusion results otherwise. */
528         while (*rbuflen > 0) {
529 #if defined(SENDFILE_FLAVOR_LINUX) || defined(SENDFILE_FLAVOR_BSD)
530             if (!obj->options.flags & OPTION_DEBUG) {
531 #ifdef SENDFILE_FLAVOR_LINUX
532                 if (sendfile(dsi->socket, si.sdt_fd, &offset, dsi->datasize) < 0)
533                     goto geticon_exit;
534 #endif /* SENDFILE_FLAVOR_LINUX */
535
536 #ifdef SENDFILE_FLAVOR_BSD
537                 if (sendfile(si.sdt_fd, dsi->socket, offset, rc, NULL, NULL, 0) < 0)
538                     goto geticon_exit;
539 #endif /* SENDFILE_FLAVOR_BSD */
540
541                 goto geticon_done;
542             }
543 #endif /* SENDFILE_FLAVOR_LINUX || SENDFILE_FLAVOR_BSD */
544
545             buflen = read(si.sdt_fd, rbuf, *rbuflen);
546             if (buflen < 0)
547                 goto geticon_exit;
548
549             if (obj->options.flags & OPTION_DEBUG) {
550                 printf( "(read) reply: %d, %d\n", buflen, dsi->clientID);
551                 bprint(rbuf, buflen);
552             }
553
554             /* dsi_read() also returns buffer size of next allocation */
555             buflen = dsi_read(dsi, rbuf, buflen); /* send it off */
556             if (buflen < 0)
557                 goto geticon_exit;
558
559             *rbuflen = buflen;
560         }
561
562 geticon_done:
563         dsi_readdone(dsi);
564         return AFP_OK;
565
566 geticon_exit:
567         LOG(log_info, logtype_afpd, "afp_geticon: %s", strerror(errno));
568         dsi_readdone(dsi);
569         obj->exit(1);
570         return AFP_OK;
571
572     } else {
573         if ( read( si.sdt_fd, rbuf, rc ) < rc ) {
574             return( AFPERR_PARAM );
575         }
576         *rbuflen = rc;
577         return AFP_OK;
578     }
579 }
580
581
582 static char             hexdig[] = "0123456789abcdef";
583 char *dtfile(const struct vol *vol, u_char creator[], char *ext )
584 {
585     static char path[ MAXPATHLEN + 1];
586     char        *p;
587     unsigned int i;
588
589     strcpy( path, vol->v_path );
590     strcat( path, "/.AppleDesktop/" );
591     for ( p = path; *p != '\0'; p++ )
592         ;
593
594     if ( !isprint( creator[ 0 ] ) || creator[ 0 ] == '/' ) {
595         *p++ = hexdig[ ( creator[ 0 ] & 0xf0 ) >> 4 ];
596         *p++ = hexdig[ creator[ 0 ] & 0x0f ];
597     } else {
598         *p++ = creator[ 0 ];
599     }
600
601     *p++ = '/';
602
603     for ( i = 0; i < sizeof( CreatorType ); i++ ) {
604         if ( !isprint( creator[ i ] ) || creator[ i ] == '/' ) {
605             *p++ = hexdig[ ( creator[ i ] & 0xf0 ) >> 4 ];
606             *p++ = hexdig[ creator[ i ] & 0x0f ];
607         } else {
608             *p++ = creator[ i ];
609         }
610     }
611     *p = '\0';
612     strcat( path, ext );
613
614     return( path );
615 }
616
617 /* ---------------------------
618  * mpath is only a filename 
619 */
620 static char  upath[ MAXPATHLEN + 1];
621 static char  mpath[ MAXPATHLEN + 1];
622 #ifdef AFP3x
623 static char  ucs2[ MAXPATHLEN + 1];
624 #endif
625
626 static char *old_mtoupath(const struct vol *vol, char *mpath)
627 {
628     char        *m, *u;
629     int          i = 0;
630     int          changed = 0;
631         
632     m = mpath;
633     u = upath;
634     if ((vol->v_casefold & (AFPVOL_MTOUUPPER| AFPVOL_MTOULOWER))) {
635         changed = 1;
636     }
637     while ( *m != '\0' ) {
638         /* handle case conversion first */
639         if (vol->v_casefold & AFPVOL_MTOUUPPER)
640             *m = diatoupper( *m );
641         else if (vol->v_casefold & AFPVOL_MTOULOWER)
642             *m = diatolower( *m );
643
644         /* we have a code page. we only use the ascii range
645          * if we have map ascii specified. */
646         if (vol->v_mtoupage && ((*m & 0x80) ||
647                                 vol->v_flags & AFPVOL_MAPASCII)) {
648             *u = vol->v_mtoupage->map[(unsigned char) *m].value;
649             changed = 1;
650             if (!*u && *m) {
651                 /* if conversion failed, encode in hex
652                  * to prevent silly truncation
653                  * H.P. Jansen <hpj@urpla.net> */
654 #ifdef DEBUG
655                 LOG(log_debug, logtype_afpd, "mtoupath: hex encode: 0x%x", (unsigned char) *m);
656 #endif
657                 *u++ = ':';
658                 *u++ = hexdig[ ( *m & 0xf0 ) >> 4 ];
659                 *u = hexdig[ *m & 0x0f ];
660             }
661         } else {
662 #if AD_VERSION == AD_VERSION1
663             if ((((vol->v_flags & AFPVOL_NOHEX) == 0) &&
664                     (!isascii(*m) || *m == '/')) ||
665                     (((vol->v_flags & AFPVOL_USEDOTS) == 0) &&
666                      ( i == 0 && (*m == '.' )))) {
667 #else 
668             if ((((vol->v_flags & AFPVOL_NOHEX) == 0) &&
669                     (!isprint(*m) || *m == '/')) ||
670                     (((vol->v_flags & AFPVOL_USEDOTS) == 0) &&
671                      ( i == 0 && (*m == '.' )))) {
672 #endif
673                 /* do hex conversion. */
674                 *u++ = ':';
675                 *u++ = hexdig[ ( *m & 0xf0 ) >> 4 ];
676                 *u = hexdig[ *m & 0x0f ];
677                 changed = 1;
678             } else
679                 *u = *m;
680         }
681         u++;
682         i++;
683         m++;
684     }
685     *u = '\0';
686
687 #ifdef DEBUG
688     LOG(log_debug, logtype_afpd, "mtoupath: '%s':'%s'", mpath, upath);
689 #endif /* DEBUG */
690
691     return( (changed)?upath:mpath );
692 }
693
694 /* ---------------------------- */
695 #define hextoint( c )   ( isdigit( c ) ? c - '0' : c + 10 - 'a' )
696 #define islxdigit(x)    (!isupper(x)&&isxdigit(x))
697
698 static char *old_utompath(const struct vol *vol, char *upath)
699 {
700     char        *m, *u;
701     int          h;
702     int          changed = 0;
703
704     /* do the hex conversion */
705     u = upath;
706     m = mpath;
707     if ((vol->v_casefold & (AFPVOL_MTOUUPPER| AFPVOL_MTOULOWER))) {
708         changed = 1;
709     }
710     while ( *u != '\0' ) {
711         /* we have a code page */
712         if (vol->v_utompage && ((*u & 0x80) ||
713                                 (vol->v_flags & AFPVOL_MAPASCII))) {
714             *m = vol->v_utompage->map[(unsigned char) *u].value;
715             changed = 1;
716         } else
717             if ( *u == ':' && *(u+1) != '\0' && islxdigit( *(u+1)) &&
718                     *(u+2) != '\0' && islxdigit( *(u+2))) {
719                 ++u;
720                 h = hextoint( *u ) << 4;
721                 ++u;
722                 h |= hextoint( *u );
723                 *m = h;
724                 changed = 1;
725             } else
726                 *m = *u;
727
728         /* handle case conversion */
729         if (vol->v_casefold & AFPVOL_UTOMLOWER)
730             *m = diatolower( *m );
731         else if (vol->v_casefold & AFPVOL_UTOMUPPER)
732             *m = diatoupper( *m );
733
734         u++;
735         m++;
736     }
737     *m = '\0';
738     m = mpath;
739
740 #ifdef FILE_MANGLING
741     m = mangle(vol, mpath, upath, 0);
742     if (m != mpath) {
743         changed = 1;
744     }
745 #endif /* FILE_MANGLING */
746
747 #ifdef DEBUG
748     LOG(log_debug, logtype_afpd, "utompath: '%s':'%s'", upath, mpath);
749 #endif /* DEBUG */
750
751     return((changed)? m:upath );
752 }
753
754 /* --------------- */
755 #ifdef AFP3x
756 extern unsigned int do_precomposition(unsigned int base, unsigned int comb);
757
758 static char comp[MAXPATHLEN +1];
759
760 static char *precompose(u_int16_t  *name, size_t inplen, size_t *outlen)
761 {
762 size_t i;
763 u_int16_t base, comb;
764 u_int16_t *in, *out;
765 u_int16_t result;
766
767     if (!inplen || (inplen & 1) || inplen > sizeof(comp)/sizeof(u_int16_t))
768         return NULL;
769     i = 0;
770     in  = name;
771     out = (u_int16_t *)comp;
772     *outlen = 0;
773     
774     base = *in;
775     while (1) {
776         i += 2;
777         in++;
778         if (i == inplen) {
779            *out = base;
780            *outlen += 2;
781            return comp;
782         }
783         comb = *in;
784         if (comb >= 0x300 && (result = do_precomposition(base, comb))) {
785            *out = result;
786            out++;
787            *outlen += 2;
788            i += 2;
789            in++;
790            if (i == inplen) 
791               return comp;
792            base = *in;
793         }
794         else {
795            *out = base;
796            out++;
797            *outlen += 2;
798            base = comb;
799         }
800     }
801 }
802
803 /* --------------- */
804 extern unsigned int do_decomposition(unsigned int base);
805
806 static char *decompose(u_int16_t  *name, size_t inplen, size_t *outlen)
807 {
808 size_t i;
809 u_int16_t base;
810 u_int16_t *in, *out;
811 unsigned int result;
812
813     if (!inplen || (inplen & 1))
814         return NULL;
815     i = 0;
816     in  = name;
817     out = (u_int16_t *)comp;
818     *outlen = 0;
819     
820     while (i < inplen) {
821         if (*outlen >= sizeof(comp)/sizeof(u_int16_t) +2) {
822             return NULL;
823         }
824         base = *in;
825         if ((result = do_decomposition(base))) {
826            *out = result  >> 16;
827            out++;
828            *outlen += 2;
829            *out = result & 0xffff;
830            out++;
831            *outlen += 2;
832         }
833         else {
834            *out = base;
835            out++;
836            *outlen += 2;
837         }
838         i += 2;
839         in++;
840      }
841      return comp;
842 }
843 #endif
844
845 /* --------------------------- */
846 char *mtoupath(const struct vol *vol, char *mpath, int utf8)
847 {
848     int         i = 0;
849     char        *m, *u;
850 #ifdef AFP3x
851     char        *r;
852     size_t       inplen;
853     size_t       outlen;
854 #endif
855         
856     if ( *mpath == '\0' ) {
857         return( "." );
858     }
859
860 #ifdef FILE_MANGLING
861     m = demangle(vol, mpath);
862     if (m != mpath) {
863         return m;
864     }
865 #endif /* FILE_MANGLING */
866
867     if (!vol_utf8(vol))
868         return old_mtoupath(vol, mpath);
869
870     m = mpath;
871     u = upath;
872     while ( *m != '\0' ) {
873         if ( (!(vol->v_flags & AFPVOL_NOHEX) && *m == '/') ||
874              (!(vol->v_flags & AFPVOL_USEDOTS) && i == 0 && *m == '.') ||
875              (!utf8 && (unsigned char)*m == 0xf0) /* Apple logo */
876         ) {
877           /* do hex conversion. */
878           *u++ = ':';
879           *u++ = hexdig[ ( *m & 0xf0 ) >> 4 ];
880           *u = hexdig[ *m & 0x0f ];
881         } else
882            *u = *m;
883         u++;
884         i++;
885         m++;
886     }
887     *u = '\0';
888     u = upath;
889 #ifdef AFP3x
890     inplen = strlen(u);
891     outlen = MAXPATHLEN;
892     r = ucs2;
893     if (!utf8) {
894         if ((size_t)(-1) == iconv(vol->v_mactoutf8, 0,0,0,0) )
895             return NULL;
896         /* assume precompose */
897         if ((size_t)(-1) == iconv(vol->v_mactoutf8, &u, &inplen, &r, &outlen))
898             return NULL;
899         u = ucs2;
900     }
901     else { 
902         if ((size_t)(-1) == iconv(vol->v_utf8toucs2, 0,0,0,0) )
903             return NULL;
904
905         if ((size_t)(-1) == iconv(vol->v_utf8toucs2, &u, &inplen, &r, &outlen))
906             return NULL;
907
908         u = precompose((u_int16_t *)ucs2, MAXPATHLEN -outlen, &inplen);
909
910         if ((size_t)(-1) == iconv(vol->v_ucs2toutf8, 0,0,0,0))
911             return NULL;
912             
913         outlen = MAXPATHLEN;
914         r = upath;
915         if ((size_t)(-1) == iconv(vol->v_ucs2toutf8, &u, &inplen, &r, &outlen))
916             return NULL;
917         u = upath;
918     }
919     u[MAXPATHLEN -outlen] = 0;
920 #endif
921 #ifdef DEBUG
922     LOG(log_debug, logtype_afpd, "mtoupath: '%s':'%s'", mpath, upath);
923 #endif /* DEBUG */
924     return( u );
925 }
926
927 /* --------------- */
928 char *utompath(const struct vol *vol, char *upath, int utf8)
929 {
930     int          h;
931     int          mangleflag = 0;
932     char        *m, *u;
933 #ifdef AFP3x
934     char        *r;
935     size_t       inplen;
936     size_t       outlen;
937 #endif
938
939     if (!vol_utf8(vol))
940         return old_utompath(vol, upath);
941     /* do the hex conversion */
942     u = upath;
943     m = mpath;
944     while ( *u != '\0' ) {
945         if ( *u == ':' && islxdigit( *(u+1)) && islxdigit( *(u+2))) {
946             ++u;
947             h = hextoint( *u ) << 4;
948             ++u;
949             h |= hextoint( *u );
950             *m = h;
951         } else
952             *m = *u;
953         u++;
954         m++;
955     }
956     *m = '\0';
957     m = mpath;
958 #ifdef AFP3x    
959     if ((size_t)(-1) == iconv(vol->v_utf8toucs2, 0,0,0,0) )
960         return NULL;
961     inplen = strlen(mpath);
962     outlen = MAXPATHLEN;
963     r = ucs2;
964     if ((size_t)(-1) == iconv(vol->v_utf8toucs2, &m, &inplen, &r, &outlen))
965         return NULL;
966
967     if (utf8) {
968         if ( NULL == (m = decompose((u_int16_t *)ucs2, MAXPATHLEN -outlen, &inplen)))
969             return NULL;
970
971         if ((size_t)(-1) == iconv(vol->v_ucs2toutf8, 0,0,0,0))
972             return NULL;
973             
974         outlen = MAXPATHLEN;
975         r = mpath;
976         if ((size_t)(-1) == iconv(vol->v_ucs2toutf8, &m, &inplen, &r, &outlen))
977             return NULL;
978     }
979     else {
980         m = precompose((u_int16_t *)ucs2, MAXPATHLEN -outlen, &inplen);
981
982         if ((size_t)(-1) == iconv(vol->v_ucs2tomac, 0,0,0,0))
983             return NULL;
984             
985         outlen = MAXPATHLEN;
986         r = mpath;
987         if ((size_t)(-1) == iconv(vol->v_ucs2tomac, &m, &inplen, &r, &outlen)) {
988             switch (errno) {
989             case EILSEQ:
990                 if (outlen != MAXPATHLEN) {
991                     mangleflag = 1;
992                 }
993             default:
994                 return NULL;
995             }
996         }
997     }
998     mpath[MAXPATHLEN -outlen] = 0;
999 #endif
1000 #ifdef FILE_MANGLING
1001     m = mangle(vol, mpath, upath, mangleflag);
1002 #else
1003     if (mangleflag)
1004         return NULL;
1005     m = mpath;
1006 #endif /* FILE_MANGLING */
1007
1008     return(m);
1009 }
1010
1011 /* ----------------------------- */
1012 int afp_addcomment(obj, ibuf, ibuflen, rbuf, rbuflen )
1013 AFPObj      *obj;
1014 char    *ibuf, *rbuf;
1015 int             ibuflen, *rbuflen;
1016 {
1017     struct adouble      ad, *adp;
1018     struct vol          *vol;
1019     struct dir          *dir;
1020     struct ofork        *of;
1021     struct path         *path;
1022     char                *name, *upath;
1023     int                 clen;
1024     u_int32_t           did;
1025     u_int16_t           vid;
1026     int                 isadir;
1027
1028     *rbuflen = 0;
1029     ibuf += 2;
1030
1031     memcpy( &vid, ibuf, sizeof( vid ));
1032     ibuf += sizeof( vid );
1033     if (NULL == ( vol = getvolbyvid( vid )) ) {
1034         return( AFPERR_PARAM );
1035     }
1036
1037     memcpy( &did, ibuf, sizeof( did ));
1038     ibuf += sizeof( did );
1039     if (NULL == ( dir = dirlookup( vol, did )) ) {
1040         return afp_errno;
1041     }
1042
1043     if (NULL == ( path = cname( vol, dir, &ibuf )) ) {
1044         return get_afp_errno(AFPERR_NOOBJ);
1045     }
1046
1047     if ((u_long)ibuf & 1 ) {
1048         ibuf++;
1049     }
1050
1051     clen = (u_char)*ibuf++;
1052     clen = min( clen, 199 );
1053
1054     upath = path->u_name;
1055     if (!vol_unix_priv(vol) && check_access(upath, OPENACC_WR ) < 0) {
1056         return AFPERR_ACCESS;
1057     }
1058
1059     isadir = path_isadir(path);
1060     if (isadir || !(of = of_findname(path))) {
1061         memset(&ad, 0, sizeof(ad));
1062         adp = &ad;
1063     } else
1064         adp = of->of_ad;
1065
1066     if (ad_open( upath , vol_noadouble(vol) |
1067                  (( isadir) ? ADFLAGS_HF|ADFLAGS_DIR : ADFLAGS_HF),
1068                  O_RDWR|O_CREAT, 0666, adp) < 0 ) {
1069         return( AFPERR_ACCESS );
1070     }
1071
1072     if ( (ad_getoflags( adp, ADFLAGS_HF ) & O_CREAT) ) {
1073         if ( *path->m_name == '\0' ) {
1074             name = curdir->d_m_name;
1075         } else {
1076             name = path->m_name;
1077         }
1078         ad_setentrylen( adp, ADEID_NAME, strlen( name ));
1079         memcpy( ad_entry( adp, ADEID_NAME ), name,
1080                 ad_getentrylen( adp, ADEID_NAME ));
1081     }
1082
1083     ad_setentrylen( adp, ADEID_COMMENT, clen );
1084     memcpy( ad_entry( adp, ADEID_COMMENT ), ibuf, clen );
1085     ad_flush( adp, ADFLAGS_HF );
1086     ad_close( adp, ADFLAGS_HF );
1087     return( AFP_OK );
1088 }
1089
1090 int afp_getcomment(obj, ibuf, ibuflen, rbuf, rbuflen )
1091 AFPObj      *obj;
1092 char    *ibuf, *rbuf;
1093 int             ibuflen, *rbuflen;
1094 {
1095     struct adouble      ad, *adp;
1096     struct vol          *vol;
1097     struct dir          *dir;
1098     struct ofork        *of;
1099     struct path         *s_path;
1100     char                *upath;
1101     u_int32_t           did;
1102     u_int16_t           vid;
1103     int                 isadir;
1104     
1105     *rbuflen = 0;
1106     ibuf += 2;
1107
1108     memcpy( &vid, ibuf, sizeof( vid ));
1109     ibuf += sizeof( vid );
1110     if (NULL == ( vol = getvolbyvid( vid )) ) {
1111         return( AFPERR_PARAM );
1112     }
1113
1114     memcpy( &did, ibuf, sizeof( did ));
1115     ibuf += sizeof( did );
1116     if (NULL == ( dir = dirlookup( vol, did )) ) {
1117         return afp_errno;
1118     }
1119
1120     if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
1121         return get_afp_errno(AFPERR_NOOBJ);
1122     }
1123
1124     upath = s_path->u_name;
1125     isadir = path_isadir(s_path);
1126     if (isadir || !(of = of_findname(s_path))) {
1127         memset(&ad, 0, sizeof(ad));
1128         adp = &ad;
1129     } else
1130         adp = of->of_ad;
1131     if ( ad_open( upath,
1132                   ( isadir) ? ADFLAGS_HF|ADFLAGS_DIR : ADFLAGS_HF,
1133                   O_RDONLY, 0666, adp) < 0 ) {
1134         return( AFPERR_NOITEM );
1135     }
1136
1137     /*
1138      * Make sure the AD file is not bogus.
1139      */
1140     if ( ad_getentrylen( adp, ADEID_COMMENT ) < 0 ||
1141             ad_getentrylen( adp, ADEID_COMMENT ) > 199 ) {
1142         ad_close( adp, ADFLAGS_HF );
1143         return( AFPERR_NOITEM );
1144     }
1145
1146     *rbuf++ = ad_getentrylen( adp, ADEID_COMMENT );
1147     memcpy( rbuf, ad_entry( adp, ADEID_COMMENT ),
1148             ad_getentrylen( adp, ADEID_COMMENT ));
1149     *rbuflen = ad_getentrylen( adp, ADEID_COMMENT ) + 1;
1150     ad_close( adp, ADFLAGS_HF );
1151
1152     /* return AFPERR_NOITEM if len == 0 ? */
1153     return( AFP_OK );
1154 }
1155
1156 int afp_rmvcomment(obj, ibuf, ibuflen, rbuf, rbuflen )
1157 AFPObj      *obj;
1158 char    *ibuf, *rbuf;
1159 int             ibuflen, *rbuflen;
1160 {
1161     struct adouble      ad, *adp;
1162     struct vol          *vol;
1163     struct dir          *dir;
1164     struct ofork        *of;
1165     struct path         *s_path;
1166     char                *upath;
1167     u_int32_t           did;
1168     u_int16_t           vid;
1169     int                 isadir;
1170
1171     *rbuflen = 0;
1172     ibuf += 2;
1173
1174     memcpy( &vid, ibuf, sizeof( vid ));
1175     ibuf += sizeof( vid );
1176     if (NULL == ( vol = getvolbyvid( vid )) ) {
1177         return( AFPERR_PARAM );
1178     }
1179
1180     memcpy( &did, ibuf, sizeof( did ));
1181     ibuf += sizeof( did );
1182     if (NULL == ( dir = dirlookup( vol, did )) ) {
1183         return afp_errno;
1184     }
1185
1186     if (NULL == ( s_path = cname( vol, dir, &ibuf ))) {
1187         return get_afp_errno(AFPERR_NOOBJ);
1188     }
1189
1190     upath = s_path->u_name;
1191     if (!vol_unix_priv(vol) && check_access(upath, OPENACC_WR ) < 0) {
1192         return AFPERR_ACCESS;
1193     }
1194
1195     isadir = path_isadir(s_path);
1196     if (isadir || !(of = of_findname(s_path))) {
1197         memset(&ad, 0, sizeof(ad));
1198         adp = &ad;
1199     } else
1200         adp = of->of_ad;
1201
1202     if ( ad_open( upath,
1203                    (isadir) ? ADFLAGS_HF|ADFLAGS_DIR : ADFLAGS_HF,
1204                   O_RDWR, 0, adp) < 0 ) {
1205         switch ( errno ) {
1206         case ENOENT :
1207             return( AFPERR_NOITEM );
1208         case EACCES :
1209             return( AFPERR_ACCESS );
1210         default :
1211             return( AFPERR_PARAM );
1212         }
1213     }
1214
1215     ad_setentrylen( adp, ADEID_COMMENT, 0 );
1216     ad_flush( adp, ADFLAGS_HF );
1217     ad_close( adp, ADFLAGS_HF );
1218     return( AFP_OK );
1219 }