1/*
2 * $Id: appl.c,v 1.18.4.1 2010-02-01 10:56:08 franklahm Exp $
3 *
4 * Copyright (c) 1990,1993 Regents of The University of Michigan.
5 * All Rights Reserved.  See COPYRIGHT.
6 */
7
8#ifdef HAVE_CONFIG_H
9#include "config.h"
10#endif /* HAVE_CONFIG_H */
11
12#include <stdio.h>
13#include <stdlib.h>
14#include <string.h>
15#include <ctype.h>
16
17#include <sys/param.h>
18#include <atalk/logger.h>
19#include <errno.h>
20
21#include <atalk/adouble.h>
22#include <atalk/afp.h>
23#include <atalk/bstrlib.h>
24#include <atalk/bstradd.h>
25#include <atalk/globals.h>
26
27#include "volume.h"
28#include "directory.h"
29#include "file.h"
30#include "desktop.h"
31
32static struct savedt	sa = { { 0, 0, 0, 0 }, -1, 0, 0};
33
34static int pathcmp(char *p, int plen, char *q, int qlen)
35{
36    return (( plen == qlen && memcmp( p, q, plen ) == 0 ) ? 0 : 1 );
37}
38
39static int applopen(struct vol *vol, u_char creator[ 4 ], int flags, int mode)
40{
41    char	*dtf, *adt, *adts;
42
43    if ( sa.sdt_fd != -1 ) {
44        if ( !(flags & ( O_RDWR | O_WRONLY )) &&
45                memcmp( sa.sdt_creator, creator, sizeof( CreatorType )) == 0 &&
46                sa.sdt_vid == vol->v_vid ) {
47            return( AFP_OK );
48        }
49        close( sa.sdt_fd );
50        sa.sdt_fd = -1;
51    }
52
53    dtf = dtfile( vol, creator, ".appl" );
54
55    if (( sa.sdt_fd = open( dtf, flags, ad_mode( dtf, mode ))) < 0 ) {
56        if ( errno == ENOENT && ( flags & O_CREAT )) {
57            if (( adts = strrchr( dtf, '/' )) == NULL ) {
58                return( AFPERR_PARAM );
59            }
60            *adts = '\0';
61            if (( adt = strrchr( dtf, '/' )) == NULL ) {
62                return( AFPERR_PARAM );
63            }
64            *adt = '\0';
65            (void) ad_mkdir( dtf, DIRBITS | 0777 );
66            *adt = '/';
67            (void) ad_mkdir( dtf, DIRBITS | 0777 );
68            *adts = '/';
69
70            if (( sa.sdt_fd = open( dtf, flags, ad_mode( dtf, mode ))) < 0 ) {
71                return( AFPERR_PARAM );
72            }
73        } else {
74            return( AFPERR_PARAM );
75        }
76    }
77    memcpy( sa.sdt_creator, creator, sizeof( CreatorType ));
78    sa.sdt_vid = vol->v_vid;
79    sa.sdt_index = 0;
80    return( AFP_OK );
81}
82
83/*
84 * copy appls to new file, deleting any matching (old) appl entries
85 */
86static int copyapplfile(int sfd, int dfd, char *mpath, u_short mplen)
87{
88    int		cc;
89    char	*p;
90    u_int16_t	len;
91    u_char	appltag[ 4 ];
92    char	buf[ MAXPATHLEN ];
93
94    while (( cc = read( sfd, buf, sizeof(appltag) + sizeof( u_short ))) > 0 ) {
95        p = buf + sizeof(appltag);
96        memcpy( &len, p, sizeof(len));
97        len = ntohs( len );
98        p += sizeof( len );
99        if (( cc = read( sa.sdt_fd, p, len )) < len ) {
100            break;
101        }
102        if ( pathcmp( mpath, mplen, p, len ) != 0 ) {
103            p += len;
104            if ( write( dfd, buf, p - buf ) != p - buf ) {
105                cc = -1;
106                break;
107            }
108        }
109    }
110    return( cc );
111}
112
113/*
114 * build mac. path (backwards) by traversing the directory tree
115 *
116 * The old way: dir and path refer to an app, path is a mac format
117 * pathname.  makemacpath() builds something that looks like a cname,
118 * but uses upaths instead of mac format paths.
119 *
120 * The new way: dir and path refer to an app, path is a mac format
121 * pathname.  makemacpath() builds a cname. (zero is a path separator
122 * and it's not \0 terminated).
123 *
124 * See afp_getappl() for the backward compatiblity code.
125 */
126static char *
127makemacpath(const struct vol *vol, char *mpath, int mpathlen, struct dir *dir, char *path)
128{
129    char	*p;
130
131    p = mpath + mpathlen;
132    p -= strlen( path );
133    memcpy( p, path, strlen( path ));
134
135    while ( dir->d_did != DIRDID_ROOT ) {
136        p -= blength(dir->d_m_name) + 1;
137        if (p < mpath) {
138            /* FIXME: pathname too long */
139            return NULL;
140        }
141        memcpy(p, cfrombstr(dir->d_m_name), blength(dir->d_m_name) + 1);
142        if ((dir = dirlookup(vol, dir->d_pdid)) == NULL)
143            return NULL;
144    }
145    return( p );
146
147
148#if 0
149    char buffer[12 + MAXPATHLEN + 1];
150    int buflen = 12 + MAXPATHLEN + 1;
151    char *ret = mpath;
152    char *path = name;
153    char *uname = NULL;
154    struct bstrList *pathlist = NULL;
155    cnid_t cnid = dir->d_pdid;
156
157    /* Create list for path elements, request 16 list elements for now*/
158    if ((pathlist = bstListCreateMin(16)) == NULL) {
159        LOG(log_error, logtype_afpd, "makemacpath: OOM: %s", strerror(errno));
160        return NULL;
161    }
162
163    while ( cnid != DIRDID_ROOT ) {
164
165        /* construct path, copy already found uname to path element list*/
166        if ((bstrListPush(pathlist, bfromcstr(path))) != BSTR_OK) {
167            afp_errno = AFPERR_MISC;
168            ret = NULL;
169            goto exit;
170        }
171
172        /* next part */
173        if ((uname = cnid_resolve(vol->v_cdb, &cnid, buffer, buflen)) == NULL ) {
174            afp_errno = AFPERR_NOOBJ;
175            ret = NULL;
176            goto exit;
177        }
178
179        if ((path = utompath(vol, uname, cnid, utf8_encoding())) == NULL) {
180            afp_errno = AFPERR_MISC;
181            ret = NULL;
182            goto exit;
183        }
184    }
185
186
187
188exit:
189    if (pathlist)
190        bstrListDestroy(pathlist);
191
192    return(ret);
193#endif
194}
195
196
197int afp_addappl(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
198{
199    struct vol		*vol;
200    struct dir		*dir;
201    int			tfd, cc;
202    u_int32_t           did;
203    u_int16_t		vid, mplen;
204    struct path         *path;
205    char                *dtf, *p, *mp;
206    u_char		creator[ 4 ];
207    u_char		appltag[ 4 ];
208    char		*mpath, *tempfile;
209
210    *rbuflen = 0;
211    ibuf += 2;
212
213    memcpy( &vid, ibuf, sizeof( vid ));
214    ibuf += sizeof( vid );
215    if (NULL == ( vol = getvolbyvid( vid ))) {
216        return( AFPERR_PARAM );
217    }
218
219    memcpy( &did, ibuf, sizeof( did ));
220    ibuf += sizeof( did );
221    if (NULL == ( dir = dirlookup( vol, did )) ) {
222        return afp_errno;
223    }
224
225    memcpy( creator, ibuf, sizeof( creator ));
226    ibuf += sizeof( creator );
227
228    memcpy( appltag, ibuf, sizeof( appltag ));
229    ibuf += sizeof( appltag );
230
231    if (NULL == ( path = cname( vol, dir, &ibuf )) ) {
232        return get_afp_errno(AFPERR_PARAM);
233    }
234    if ( path_isadir(path) ) {
235        return( AFPERR_BADTYPE );
236    }
237
238    if ( applopen( vol, creator, O_RDWR|O_CREAT, 0666 ) != AFP_OK ) {
239        return( AFPERR_PARAM );
240    }
241    if ( lseek( sa.sdt_fd, 0L, SEEK_SET ) < 0 ) {
242        return( AFPERR_PARAM );
243    }
244    dtf = dtfile( vol, creator, ".appl.temp" );
245    tempfile = obj->oldtmp;
246    strcpy( tempfile, dtf );
247    if (( tfd = open( tempfile, O_RDWR|O_CREAT, 0666 )) < 0 ) {
248        return( AFPERR_PARAM );
249    }
250    mpath = obj->newtmp;
251    mp = makemacpath( vol, mpath, AFPOBJ_TMPSIZ, curdir, path->m_name );
252    if (!mp) {
253        close(tfd);
254        return AFPERR_PARAM;
255    }
256    mplen =  mpath + AFPOBJ_TMPSIZ - mp;
257
258    /* write the new appl entry at start of temporary file */
259    p = mp - sizeof( u_short );
260    mplen = htons( mplen );
261    memcpy( p, &mplen, sizeof( mplen ));
262    mplen = ntohs( mplen );
263    p -= sizeof( appltag );
264    memcpy(p, appltag, sizeof( appltag ));
265    cc = mpath + AFPOBJ_TMPSIZ - p;
266    if ( write( tfd, p, cc ) != cc ) {
267        close(tfd);
268        unlink( tempfile );
269        return( AFPERR_PARAM );
270    }
271    cc = copyapplfile( sa.sdt_fd, tfd, mp, mplen );
272    close( tfd );
273    close( sa.sdt_fd );
274    sa.sdt_fd = -1;
275
276    if ( cc < 0 ) {
277        unlink( tempfile );
278        return( AFPERR_PARAM );
279    }
280    if ( rename( tempfile, dtfile( vol, creator, ".appl" )) < 0 ) {
281        return( AFPERR_PARAM );
282    }
283    return( AFP_OK );
284}
285
286int afp_rmvappl(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
287{
288    struct vol		*vol;
289    struct dir		*dir;
290    int			tfd, cc;
291    u_int32_t           did;
292    u_int16_t		vid, mplen;
293    struct path    	*path;
294    char                *dtf, *mp;
295    u_char		creator[ 4 ];
296    char                *tempfile, *mpath;
297
298    *rbuflen = 0;
299    ibuf += 2;
300
301    memcpy( &vid, ibuf, sizeof( vid ));
302    ibuf += sizeof( vid );
303    if (NULL == ( vol = getvolbyvid( vid ))) {
304        return( AFPERR_PARAM );
305    }
306
307    memcpy( &did, ibuf, sizeof( did ));
308    ibuf += sizeof( did );
309    if (NULL == ( dir = dirlookup( vol, did )) ) {
310        return afp_errno;
311    }
312
313    memcpy( creator, ibuf, sizeof( creator ));
314    ibuf += sizeof( creator );
315
316    if (NULL == ( path = cname( vol, dir, &ibuf )) ) {
317        return get_afp_errno(AFPERR_PARAM);
318    }
319    if ( path_isadir(path) ) {
320        return( AFPERR_BADTYPE );
321    }
322
323    if ( applopen( vol, creator, O_RDWR, 0666 ) != AFP_OK ) {
324        return( AFPERR_NOOBJ );
325    }
326    if ( lseek( sa.sdt_fd, 0L, SEEK_SET ) < 0 ) {
327        return( AFPERR_PARAM );
328    }
329    dtf = dtfile( vol, creator, ".appl.temp" );
330    tempfile = obj->oldtmp;
331    strcpy( tempfile, dtf );
332    if (( tfd = open( tempfile, O_RDWR|O_CREAT, 0666 )) < 0 ) {
333        return( AFPERR_PARAM );
334    }
335    mpath = obj->newtmp;
336    mp = makemacpath( vol, mpath, AFPOBJ_TMPSIZ, curdir, path->m_name );
337    if (!mp) {
338        close(tfd);
339        return AFPERR_PARAM ;
340    }
341
342    mplen =  mpath + AFPOBJ_TMPSIZ - mp;
343    cc = copyapplfile( sa.sdt_fd, tfd, mp, mplen );
344    close( tfd );
345    close( sa.sdt_fd );
346    sa.sdt_fd = -1;
347
348    if ( cc < 0 ) {
349        unlink( tempfile );
350        return( AFPERR_PARAM );
351    }
352    if ( rename( tempfile, dtfile( vol, creator, ".appl" )) < 0 ) {
353        return( AFPERR_PARAM );
354    }
355    return( AFP_OK );
356}
357
358int afp_getappl(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
359{
360    struct vol		*vol;
361    char		*p, *q;
362    int			cc;
363    size_t		buflen;
364    u_int16_t		vid, aindex, bitmap, len;
365    u_char		creator[ 4 ];
366    u_char		appltag[ 4 ];
367    char                *buf, *cbuf;
368    struct path         *path;
369
370    ibuf += 2;
371
372    memcpy( &vid, ibuf, sizeof( vid ));
373    ibuf += sizeof( vid );
374    if (NULL == ( vol = getvolbyvid( vid )) ) {
375        *rbuflen = 0;
376        return( AFPERR_PARAM );
377    }
378
379    memcpy( creator, ibuf, sizeof( creator ));
380    ibuf += sizeof( creator );
381
382    memcpy( &aindex, ibuf, sizeof( aindex ));
383    ibuf += sizeof( aindex );
384    aindex = ntohs( aindex );
385    if ( aindex ) { /* index 0 == index 1 */
386        --aindex;
387    }
388
389    memcpy( &bitmap, ibuf, sizeof( bitmap ));
390    bitmap = ntohs( bitmap );
391    ibuf += sizeof( bitmap );
392
393    if ( applopen( vol, creator, O_RDONLY, 0666 ) != AFP_OK ) {
394        *rbuflen = 0;
395        return( AFPERR_NOITEM );
396    }
397    if ( aindex < sa.sdt_index ) {
398        if ( lseek( sa.sdt_fd, 0L, SEEK_SET ) < 0 ) {
399            *rbuflen = 0;
400            return( AFPERR_PARAM );
401        }
402        sa.sdt_index = 0;
403    }
404
405    /* position to correct spot within appl file */
406    buf = obj->oldtmp;
407    while (( cc = read( sa.sdt_fd, buf, sizeof( appltag )
408                        + sizeof( u_short ))) > 0 ) {
409        p = buf + sizeof( appltag );
410        memcpy( &len, p, sizeof( len ));
411        len = ntohs( len );
412        p += sizeof( u_short );
413        if (( cc = read( sa.sdt_fd, p, len )) < len ) {
414            break;
415        }
416        if ( sa.sdt_index == aindex ) {
417            break;
418        }
419        sa.sdt_index++;
420    }
421    if ( cc <= 0 || sa.sdt_index != aindex ) {
422        *rbuflen = 0;
423        return( AFPERR_NOITEM );
424    }
425    sa.sdt_index++;
426
427#ifdef APPLCNAME
428    /*
429     * Check to see if this APPL mapping has an mpath or a upath.  If
430     * there are any ':'s in the name, it is a upath and must be converted
431     * to an mpath.  Hopefully, this code will go away.
432     */
433    {
434#define hextoint( c )	( isdigit( c ) ? c - '0' : c + 10 - 'a' )
435#define islxdigit(x)	(!isupper(x)&&isxdigit(x))
436
437        char	utomname[ MAXPATHLEN + 1];
438        char		*u, *m;
439        int		i, h;
440
441        u = p;
442        m = utomname;
443        i = len;
444        while ( i ) {
445            if ( *u == ':' && *(u+1) != '\0' && islxdigit( *(u+1)) &&
446                    *(u+2) != '\0' && islxdigit( *(u+2))) {
447                ++u, --i;
448                h = hextoint( *u ) << 4;
449                ++u, --i;
450                h |= hextoint( *u );
451                *m++ = h;
452            } else {
453                *m++ = *u;
454            }
455            ++u, --i;
456        }
457
458        len = m - utomname;
459        p = utomname;
460
461        if ( p[ len - 1 ] == '\0' ) {
462            len--;
463        }
464    }
465#endif /* APPLCNAME */
466
467    /* fake up a cname */
468    cbuf = obj->newtmp;
469    q = cbuf;
470    *q++ = 2;	/* long path type */
471    *q++ = (unsigned char)len;
472    memcpy( q, p, len );
473    q = cbuf;
474
475    if (( path = cname( vol, vol->v_root, &q )) == NULL ) {
476        *rbuflen = 0;
477        return( AFPERR_NOITEM );
478    }
479
480    if ( path_isadir(path) || path->st_errno ) {
481        *rbuflen = 0;
482        return( AFPERR_NOITEM );
483    }
484    buflen = *rbuflen - sizeof( bitmap ) - sizeof( appltag );
485    if ( getfilparams(vol, bitmap, path, curdir, rbuf + sizeof( bitmap ) +
486                      sizeof( appltag ), &buflen ) != AFP_OK ) {
487        *rbuflen = 0;
488        return( AFPERR_BITMAP );
489    }
490
491    *rbuflen = buflen + sizeof( bitmap ) + sizeof( appltag );
492    bitmap = htons( bitmap );
493    memcpy( rbuf, &bitmap, sizeof( bitmap ));
494    rbuf += sizeof( bitmap );
495    memcpy( rbuf, appltag, sizeof( appltag ));
496    rbuf += sizeof( appltag );
497    return( AFP_OK );
498}
499
500