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