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