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