]> arthur.barton.de Git - netatalk.git/blob - etc/afpd/desktop.c
UTF8 is defined but not mangled
[netatalk.git] / etc / afpd / desktop.c
1 /*
2  * $Id: desktop.c,v 1.26 2003-04-09 06:05:24 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 <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 (( vol = getvolbyvid( vid )) == NULL ) {
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 static char  ucs2[ MAXPATHLEN + 1];
623
624 static char *old_mtoupath(const struct vol *vol, char *mpath)
625 {
626     char        *m, *u;
627     int          i = 0;
628     int          changed = 0;
629         
630     m = mpath;
631     u = upath;
632     while ( *m != '\0' ) {
633         /* handle case conversion first */
634         if (vol->v_casefold & AFPVOL_MTOUUPPER)
635             *m = diatoupper( *m );
636         else if (vol->v_casefold & AFPVOL_MTOULOWER)
637             *m = diatolower( *m );
638
639         /* we have a code page. we only use the ascii range
640          * if we have map ascii specified. */
641         if (vol->v_mtoupage && ((*m & 0x80) ||
642                                 vol->v_flags & AFPVOL_MAPASCII)) {
643             *u = vol->v_mtoupage->map[(unsigned char) *m].value;
644             changed = 1;
645             if (!*u && *m) {
646                 /* if conversion failed, encode in hex
647                  * to prevent silly truncation
648                  * H.P. Jansen <hpj@urpla.net> */
649 #ifdef DEBUG
650                 LOG(log_debug, logtype_afpd, "mtoupath: hex encode: 0x%x", (unsigned char) *m);
651 #endif
652                 *u++ = ':';
653                 *u++ = hexdig[ ( *m & 0xf0 ) >> 4 ];
654                 *u = hexdig[ *m & 0x0f ];
655             }
656         } else {
657 #if AD_VERSION == AD_VERSION1
658             if ((((vol->v_flags & AFPVOL_NOHEX) == 0) &&
659                     (!isascii(*m) || *m == '/')) ||
660                     (((vol->v_flags & AFPVOL_USEDOTS) == 0) &&
661                      ( i == 0 && (*m == '.' )))) {
662 #else 
663             if ((((vol->v_flags & AFPVOL_NOHEX) == 0) &&
664                     (!isprint(*m) || *m == '/')) ||
665                     (((vol->v_flags & AFPVOL_USEDOTS) == 0) &&
666                      ( i == 0 && (*m == '.' )))) {
667 #endif
668                 /* do hex conversion. */
669                 *u++ = ':';
670                 *u++ = hexdig[ ( *m & 0xf0 ) >> 4 ];
671                 *u = hexdig[ *m & 0x0f ];
672                 changed = 1;
673             } else
674                 *u = *m;
675         }
676         u++;
677         i++;
678         m++;
679     }
680     *u = '\0';
681
682 #ifdef DEBUG
683     LOG(log_debug, logtype_afpd, "mtoupath: '%s':'%s'", mpath, upath);
684 #endif /* DEBUG */
685
686     return( (changed)?upath:mpath );
687 }
688
689 /* ---------------------------- */
690 #define hextoint( c )   ( isdigit( c ) ? c - '0' : c + 10 - 'a' )
691 #define islxdigit(x)    (!isupper(x)&&isxdigit(x))
692
693 static char *old_utompath(const struct vol *vol, char *upath)
694 {
695     char        *m, *u;
696     int          h;
697     int          changed = 0;
698
699     /* do the hex conversion */
700     u = upath;
701     m = mpath;
702     while ( *u != '\0' ) {
703         /* we have a code page */
704         if (vol->v_utompage && ((*u & 0x80) ||
705                                 (vol->v_flags & AFPVOL_MAPASCII))) {
706             *m = vol->v_utompage->map[(unsigned char) *u].value;
707             changed = 1;
708         } else
709             if ( *u == ':' && *(u+1) != '\0' && islxdigit( *(u+1)) &&
710                     *(u+2) != '\0' && islxdigit( *(u+2))) {
711                 ++u;
712                 h = hextoint( *u ) << 4;
713                 ++u;
714                 h |= hextoint( *u );
715                 *m = h;
716                 changed = 1;
717             } else
718                 *m = *u;
719
720         /* handle case conversion */
721         if (vol->v_casefold & AFPVOL_UTOMLOWER)
722             *m = diatolower( *m );
723         else if (vol->v_casefold & AFPVOL_UTOMUPPER)
724             *m = diatoupper( *m );
725
726         u++;
727         m++;
728     }
729     *m = '\0';
730     m = mpath;
731
732 #ifdef FILE_MANGLING
733     m = mangle(vol, mpath, upath, 0);
734     if (m != mpath) {
735         changed = 1;
736     }
737 #endif /* FILE_MANGLING */
738
739 #ifdef DEBUG
740     LOG(log_debug, logtype_afpd, "utompath: '%s':'%s'", upath, mpath);
741 #endif /* DEBUG */
742
743     return((changed)? m:upath );
744 }
745
746 /* --------------- */
747 extern unsigned int do_precomposition(unsigned int base, unsigned int comb);
748
749 static char comp[MAXPATHLEN +1];
750
751 static char *precompose(u_int16_t  *name, size_t inplen, size_t *outlen)
752 {
753 size_t i;
754 u_int16_t base, comb;
755 u_int16_t *in, *out;
756 u_int16_t result;
757
758     if (!inplen || (inplen & 1) || inplen > sizeof(comp)/sizeof(u_int16_t))
759         return NULL;
760     i = 0;
761     in  = name;
762     out = (u_int16_t *)comp;
763     *outlen = 0;
764     
765     base = *in;
766     while (1) {
767         i += 2;
768         in++;
769         if (i == inplen) {
770            *out = base;
771            *outlen += 2;
772            return comp;
773         }
774         comb = *in;
775         if (comb >= 0x300 && (result = do_precomposition(base, comb))) {
776            *out = result;
777            out++;
778            *outlen += 2;
779            i += 2;
780            in++;
781            if (i == inplen) 
782               return comp;
783            base = *in;
784         }
785         else {
786            *out = base;
787            out++;
788            *outlen += 2;
789            base = comb;
790         }
791     }
792 }
793
794 /* --------------- */
795 extern unsigned int do_decomposition(unsigned int base);
796
797 static char *decompose(u_int16_t  *name, size_t inplen, size_t *outlen)
798 {
799 size_t i;
800 u_int16_t base;
801 u_int16_t *in, *out;
802 unsigned int result;
803
804     if (!inplen || (inplen & 1))
805         return NULL;
806     i = 0;
807     in  = name;
808     out = (u_int16_t *)comp;
809     *outlen = 0;
810     
811     while (i < inplen) {
812         if (*outlen >= sizeof(comp)/sizeof(u_int16_t) +2) {
813             return NULL;
814         }
815         base = *in;
816         if ((result = do_decomposition(base))) {
817            *out = result  >> 16;
818            out++;
819            *outlen += 2;
820            *out = result & 0xffff;
821            out++;
822            *outlen += 2;
823         }
824         else {
825            *out = base;
826            out++;
827            *outlen += 2;
828         }
829         i += 2;
830         in++;
831      }
832      return comp;
833 }
834
835 /* --------------------------- */
836 char *mtoupath(const struct vol *vol, char *mpath, int utf8)
837 {
838     char        *m, *u, *r;
839     int          i = 0;
840     size_t       inplen;
841     size_t       outlen;
842         
843     if ( *mpath == '\0' ) {
844         return( "." );
845     }
846
847 #ifdef FILE_MANGLING
848     m = demangle(vol, mpath);
849     if (m != mpath) {
850         return m;
851     }
852 #endif /* FILE_MANGLING */
853
854     if (!vol_utf8(vol))
855         return old_mtoupath(vol, mpath);
856
857     m = mpath;
858     u = upath;
859     while ( *m != '\0' ) {
860         if ( (!(vol->v_flags & AFPVOL_NOHEX) && *m == '/') ||
861              (!(vol->v_flags & AFPVOL_USEDOTS) && i == 0 && *m == '.') ||
862              (!utf8 && (unsigned char)*m == 0xf0) /* Apple logo */
863         ) {
864           /* do hex conversion. */
865           *u++ = ':';
866           *u++ = hexdig[ ( *m & 0xf0 ) >> 4 ];
867           *u = hexdig[ *m & 0x0f ];
868         } else
869            *u = *m;
870         u++;
871         i++;
872         m++;
873     }
874     *u = '\0';
875     u = upath;
876 #ifdef AFP3x
877     inplen = strlen(u);
878     outlen = MAXPATHLEN;
879     r = ucs2;
880     if (!utf8) {
881         if ((size_t)(-1) == iconv(vol->v_mactoutf8, 0,0,0,0) )
882             return NULL;
883         /* assume precompose */
884         if ((size_t)(-1) == iconv(vol->v_mactoutf8, &u, &inplen, &r, &outlen))
885             return NULL;
886         u = ucs2;
887     }
888     else { 
889         if ((size_t)(-1) == iconv(vol->v_utf8toucs2, 0,0,0,0) )
890             return NULL;
891
892         if ((size_t)(-1) == iconv(vol->v_utf8toucs2, &u, &inplen, &r, &outlen))
893             return NULL;
894
895         u = precompose((u_int16_t *)ucs2, MAXPATHLEN -outlen, &inplen);
896
897         if ((size_t)(-1) == iconv(vol->v_ucs2toutf8, 0,0,0,0))
898             return NULL;
899             
900         outlen = MAXPATHLEN;
901         r = upath;
902         if ((size_t)(-1) == iconv(vol->v_ucs2toutf8, &u, &inplen, &r, &outlen))
903             return NULL;
904         u = upath;
905     }
906     u[MAXPATHLEN -outlen] = 0;
907 #endif
908 #ifdef DEBUG
909     LOG(log_debug, logtype_afpd, "mtoupath: '%s':'%s'", mpath, upath);
910 #endif /* DEBUG */
911     return( u );
912 }
913
914 /* --------------- */
915 char *utompath(const struct vol *vol, char *upath, int utf8)
916 {
917     char        *m, *u, *r;
918     int          h;
919     int          mangleflag = 0;
920     size_t       inplen;
921     size_t       outlen;
922
923     if (!vol_utf8(vol))
924         return old_utompath(vol, upath);
925     /* do the hex conversion */
926     u = upath;
927     m = mpath;
928     while ( *u != '\0' ) {
929         if ( *u == ':' && islxdigit( *(u+1)) && islxdigit( *(u+2))) {
930             ++u;
931             h = hextoint( *u ) << 4;
932             ++u;
933             h |= hextoint( *u );
934             *m = h;
935         } else
936             *m = *u;
937         u++;
938         m++;
939     }
940     *m = '\0';
941     m = mpath;
942 #ifdef AFP3x    
943     if ((size_t)(-1) == iconv(vol->v_utf8toucs2, 0,0,0,0) )
944         return NULL;
945     inplen = strlen(mpath);
946     outlen = MAXPATHLEN;
947     r = ucs2;
948     if ((size_t)(-1) == iconv(vol->v_utf8toucs2, &m, &inplen, &r, &outlen))
949         return NULL;
950
951     if (utf8) {
952         if ( NULL == (m = decompose((u_int16_t *)ucs2, MAXPATHLEN -outlen, &inplen)))
953             return NULL;
954
955         if ((size_t)(-1) == iconv(vol->v_ucs2toutf8, 0,0,0,0))
956             return NULL;
957             
958         outlen = MAXPATHLEN;
959         r = mpath;
960         if ((size_t)(-1) == iconv(vol->v_ucs2toutf8, &m, &inplen, &r, &outlen))
961             return NULL;
962     }
963     else {
964         m = precompose((u_int16_t *)ucs2, MAXPATHLEN -outlen, &inplen);
965
966         if ((size_t)(-1) == iconv(vol->v_ucs2tomac, 0,0,0,0))
967             return NULL;
968             
969         outlen = MAXPATHLEN;
970         r = mpath;
971         if ((size_t)(-1) == iconv(vol->v_ucs2tomac, &m, &inplen, &r, &outlen)) {
972             switch (errno) {
973             case EILSEQ:
974                 if (outlen != MAXPATHLEN) {
975                     mangleflag = 1;
976                 }
977             default:
978                 return NULL;
979             }
980         }
981     }
982     mpath[MAXPATHLEN -outlen] = 0;
983 #endif
984 #ifdef FILE_MANGLING
985     m = mangle(vol, mpath, upath, mangleflag);
986 #else
987     if (mangleflag)
988         return NULL;
989     m = mpath;
990 #endif /* FILE_MANGLING */
991
992     return(m);
993 }
994
995 /* ----------------------------- */
996 int afp_addcomment(obj, ibuf, ibuflen, rbuf, rbuflen )
997 AFPObj      *obj;
998 char    *ibuf, *rbuf;
999 int             ibuflen, *rbuflen;
1000 {
1001     struct adouble      ad, *adp;
1002     struct vol          *vol;
1003     struct dir          *dir;
1004     struct ofork        *of;
1005     struct path         *path;
1006     char                *name, *upath;
1007     int                 clen;
1008     u_int32_t           did;
1009     u_int16_t           vid;
1010     int                 isadir;
1011
1012     *rbuflen = 0;
1013     ibuf += 2;
1014
1015     memcpy( &vid, ibuf, sizeof( vid ));
1016     ibuf += sizeof( vid );
1017     if (NULL == ( vol = getvolbyvid( vid )) ) {
1018         return( AFPERR_PARAM );
1019     }
1020
1021     memcpy( &did, ibuf, sizeof( did ));
1022     ibuf += sizeof( did );
1023     if (NULL == ( dir = dirlookup( vol, did )) ) {
1024         return afp_errno;
1025     }
1026
1027     if (NULL == ( path = cname( vol, dir, &ibuf )) ) {
1028         return get_afp_errno(AFPERR_NOOBJ);
1029     }
1030
1031     if ((u_long)ibuf & 1 ) {
1032         ibuf++;
1033     }
1034
1035     clen = (u_char)*ibuf++;
1036     clen = min( clen, 199 );
1037
1038     upath = path->u_name;
1039     if (check_access(upath, OPENACC_WR ) < 0) {
1040         return AFPERR_ACCESS;
1041     }
1042
1043     isadir = path_isadir(path);
1044     if (isadir || !(of = of_findname(path))) {
1045         memset(&ad, 0, sizeof(ad));
1046         adp = &ad;
1047     } else
1048         adp = of->of_ad;
1049
1050     if (ad_open( upath , vol_noadouble(vol) |
1051                  (( isadir) ? ADFLAGS_HF|ADFLAGS_DIR : ADFLAGS_HF),
1052                  O_RDWR|O_CREAT, 0666, adp) < 0 ) {
1053         return( AFPERR_ACCESS );
1054     }
1055
1056     if ( (ad_getoflags( adp, ADFLAGS_HF ) & O_CREAT) ) {
1057         if ( *path->m_name == '\0' ) {
1058             name = curdir->d_m_name;
1059         } else {
1060             name = path->m_name;
1061         }
1062         ad_setentrylen( adp, ADEID_NAME, strlen( name ));
1063         memcpy( ad_entry( adp, ADEID_NAME ), name,
1064                 ad_getentrylen( adp, ADEID_NAME ));
1065     }
1066
1067     ad_setentrylen( adp, ADEID_COMMENT, clen );
1068     memcpy( ad_entry( adp, ADEID_COMMENT ), ibuf, clen );
1069     ad_flush( adp, ADFLAGS_HF );
1070     ad_close( adp, ADFLAGS_HF );
1071     return( AFP_OK );
1072 }
1073
1074 int afp_getcomment(obj, ibuf, ibuflen, rbuf, rbuflen )
1075 AFPObj      *obj;
1076 char    *ibuf, *rbuf;
1077 int             ibuflen, *rbuflen;
1078 {
1079     struct adouble      ad, *adp;
1080     struct vol          *vol;
1081     struct dir          *dir;
1082     struct ofork        *of;
1083     struct path         *s_path;
1084     char                *upath;
1085     u_int32_t           did;
1086     u_int16_t           vid;
1087     int                 isadir;
1088     
1089     *rbuflen = 0;
1090     ibuf += 2;
1091
1092     memcpy( &vid, ibuf, sizeof( vid ));
1093     ibuf += sizeof( vid );
1094     if (NULL == ( vol = getvolbyvid( vid )) ) {
1095         return( AFPERR_PARAM );
1096     }
1097
1098     memcpy( &did, ibuf, sizeof( did ));
1099     ibuf += sizeof( did );
1100     if (NULL == ( dir = dirlookup( vol, did )) ) {
1101         return afp_errno;
1102     }
1103
1104     if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
1105         return get_afp_errno(AFPERR_NOOBJ);
1106     }
1107
1108     upath = s_path->u_name;
1109     isadir = path_isadir(s_path);
1110     if (isadir || !(of = of_findname(s_path))) {
1111         memset(&ad, 0, sizeof(ad));
1112         adp = &ad;
1113     } else
1114         adp = of->of_ad;
1115     if ( ad_open( upath,
1116                   ( isadir) ? ADFLAGS_HF|ADFLAGS_DIR : ADFLAGS_HF,
1117                   O_RDONLY, 0666, adp) < 0 ) {
1118         return( AFPERR_NOITEM );
1119     }
1120
1121     /*
1122      * Make sure the AD file is not bogus.
1123      */
1124     if ( ad_getentrylen( adp, ADEID_COMMENT ) < 0 ||
1125             ad_getentrylen( adp, ADEID_COMMENT ) > 199 ) {
1126         ad_close( adp, ADFLAGS_HF );
1127         return( AFPERR_NOITEM );
1128     }
1129
1130     *rbuf++ = ad_getentrylen( adp, ADEID_COMMENT );
1131     memcpy( rbuf, ad_entry( adp, ADEID_COMMENT ),
1132             ad_getentrylen( adp, ADEID_COMMENT ));
1133     *rbuflen = ad_getentrylen( adp, ADEID_COMMENT ) + 1;
1134     ad_close( adp, ADFLAGS_HF );
1135
1136     /* return AFPERR_NOITEM if len == 0 ? */
1137     return( AFP_OK );
1138 }
1139
1140 int afp_rmvcomment(obj, ibuf, ibuflen, rbuf, rbuflen )
1141 AFPObj      *obj;
1142 char    *ibuf, *rbuf;
1143 int             ibuflen, *rbuflen;
1144 {
1145     struct adouble      ad, *adp;
1146     struct vol          *vol;
1147     struct dir          *dir;
1148     struct ofork        *of;
1149     struct path         *s_path;
1150     char                *upath;
1151     u_int32_t           did;
1152     u_int16_t           vid;
1153     int                 isadir;
1154
1155     *rbuflen = 0;
1156     ibuf += 2;
1157
1158     memcpy( &vid, ibuf, sizeof( vid ));
1159     ibuf += sizeof( vid );
1160     if (NULL == ( vol = getvolbyvid( vid )) ) {
1161         return( AFPERR_PARAM );
1162     }
1163
1164     memcpy( &did, ibuf, sizeof( did ));
1165     ibuf += sizeof( did );
1166     if (NULL == ( dir = dirlookup( vol, did )) ) {
1167         return afp_errno;
1168     }
1169
1170     if (NULL == ( s_path = cname( vol, dir, &ibuf ))) {
1171         return get_afp_errno(AFPERR_NOOBJ);
1172     }
1173
1174     upath = s_path->u_name;
1175     if (check_access(upath, OPENACC_WR ) < 0) {
1176         return AFPERR_ACCESS;
1177     }
1178
1179     isadir = path_isadir(s_path);
1180     if (isadir || !(of = of_findname(s_path))) {
1181         memset(&ad, 0, sizeof(ad));
1182         adp = &ad;
1183     } else
1184         adp = of->of_ad;
1185
1186     if ( ad_open( upath,
1187                    (isadir) ? ADFLAGS_HF|ADFLAGS_DIR : ADFLAGS_HF,
1188                   O_RDWR, 0, adp) < 0 ) {
1189         switch ( errno ) {
1190         case ENOENT :
1191             return( AFPERR_NOITEM );
1192         case EACCES :
1193             return( AFPERR_ACCESS );
1194         default :
1195             return( AFPERR_PARAM );
1196         }
1197     }
1198
1199     ad_setentrylen( adp, ADEID_COMMENT, 0 );
1200     ad_flush( adp, ADFLAGS_HF );
1201     ad_close( adp, ADFLAGS_HF );
1202     return( AFP_OK );
1203 }