~ubuntu-branches/ubuntu/precise/netatalk/precise

« back to all changes in this revision

Viewing changes to etc/afpd/enumerate.c

  • Committer: Bazaar Package Importer
  • Author(s): Sebastian Rittau
  • Date: 2004-01-19 12:43:49 UTC
  • Revision ID: james.westby@ubuntu.com-20040119124349-es563jbp0hk0ae51
Tags: upstream-1.6.4
ImportĀ upstreamĀ versionĀ 1.6.4

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * $Id: enumerate.c,v 1.23.2.1 2003/02/04 19:10:30 didg 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 <dirent.h>
 
16
#include <errno.h>
 
17
 
 
18
#include <atalk/logger.h>
 
19
#include <sys/types.h>
 
20
#include <sys/stat.h>
 
21
#include <sys/file.h>
 
22
#include <sys/param.h>
 
23
 
 
24
#include <netatalk/endian.h>
 
25
#include <atalk/afp.h>
 
26
#include <atalk/adouble.h>
 
27
#ifdef CNID_DB
 
28
#include <atalk/cnid.h>
 
29
#endif /* CNID_DB */
 
30
#include "desktop.h"
 
31
#include "directory.h"
 
32
#include "volume.h"
 
33
#include "globals.h"
 
34
#include "file.h"
 
35
#include "filedir.h"
 
36
 
 
37
#define min(a,b)        ((a)<(b)?(a):(b))
 
38
 
 
39
struct dir *
 
40
            adddir( vol, dir, name, namlen, upath, upathlen, st )
 
41
            struct vol  *vol;
 
42
struct dir      *dir;
 
43
char    *name, *upath;
 
44
int             namlen, upathlen;
 
45
struct stat *st;
 
46
{
 
47
    struct dir  *cdir, *edir;
 
48
#if AD_VERSION > AD_VERSION1
 
49
    struct adouble ad;
 
50
#endif /* AD_VERSION > AD_VERSION1 */
 
51
 
 
52
#ifndef USE_LASTDID
 
53
    struct stat lst, *lstp;
 
54
#endif /* USE_LASTDID */
 
55
 
 
56
    if ((cdir = dirnew(namlen + 1)) == NULL) {
 
57
        LOG(log_error, logtype_afpd, "adddir: malloc: %s", strerror(errno) );
 
58
        return NULL;
 
59
    }
 
60
    strcpy( cdir->d_name, name );
 
61
    cdir->d_name[namlen] = '\0';
 
62
 
 
63
    cdir->d_did = 0;
 
64
 
 
65
#if AD_VERSION > AD_VERSION1
 
66
    /* look in AD v2 header */
 
67
    memset(&ad, 0, sizeof(ad));
 
68
    if (ad_open(upath, ADFLAGS_HF|ADFLAGS_DIR, O_RDONLY, 0, &ad) >= 0) {
 
69
        /* if we can parse the AppleDouble header, retrieve the DID entry into cdir->d_did */
 
70
        memcpy(&cdir->d_did, ad_entry(&ad, ADEID_DID), sizeof(cdir->d_did));
 
71
        ad_close(&ad, ADFLAGS_HF);
 
72
    }
 
73
#endif /* AD_VERSION */
 
74
 
 
75
#ifdef CNID_DB
 
76
    /* add to cnid db */
 
77
    cdir->d_did = cnid_add(vol->v_db, st, dir->d_did, upath,
 
78
                           upathlen, cdir->d_did);
 
79
    /* Fail out if things go bad with CNID. */
 
80
    if (cdir->d_did == CNID_INVALID) {
 
81
        switch (errno) {
 
82
        case CNID_ERR_PARAM:
 
83
            LOG(log_error, logtype_afpd, "adddir: Incorrect parameters passed to cnid_add");
 
84
            return NULL;
 
85
        case CNID_ERR_PATH:
 
86
        case CNID_ERR_DB:
 
87
        case CNID_ERR_MAX:
 
88
            return NULL;
 
89
        }
 
90
    }
 
91
#endif /* CNID_DB */
 
92
 
 
93
    if (cdir->d_did == 0) {
 
94
#ifdef USE_LASTDID
 
95
        /* last way of doing DIDs */
 
96
        cdir->d_did = htonl( vol->v_lastdid++ );
 
97
#else /* USE_LASTDID */
 
98
        lstp = lstat(upath, &lst) < 0 ? st : &lst;
 
99
        /* the old way of doing DIDs (default) */
 
100
        cdir->d_did = htonl( CNID(lstp, 0) );
 
101
#endif /* USE_LASTDID */
 
102
    }
 
103
 
 
104
    if ((edir = dirinsert( vol, cdir ))) {
 
105
#ifndef CNID_DB
 
106
        if (edir->d_name) {
 
107
            if (strcmp(edir->d_name, cdir->d_name)) {
 
108
                LOG(log_info, logtype_afpd, "WARNING: DID conflict for '%s' and '%s'. Are these the same file?", edir->d_name, cdir->d_name);
 
109
            }
 
110
            free(cdir->d_name);
 
111
            free(cdir);
 
112
            return edir;
 
113
        }
 
114
#endif /* CNID_DB */
 
115
        /* it's not possible with LASTDID
 
116
           for CNID:
 
117
           - someone else have moved the directory.
 
118
           - it's a symlink inside the share.
 
119
           - it's an ID reused, the old directory was deleted but not
 
120
             the cnid record and the server reused the inode for 
 
121
             the new dir.
 
122
           for HASH (we should get ride of HASH) 
 
123
           - someone else have moved the directory.
 
124
           - it's an ID reused as above
 
125
           - it's a hash duplicate and we are in big trouble
 
126
        */
 
127
        edir->d_name = cdir->d_name;
 
128
        free(cdir);
 
129
        cdir = edir;
 
130
        if (!cdir->d_parent || cdir->d_parent == dir) 
 
131
            return cdir;
 
132
            
 
133
        /* the old was not in the same folder, remove and add to the new */
 
134
        dirchildremove(cdir->d_parent, cdir);
 
135
    }
 
136
 
 
137
    /* parent/child directories */
 
138
    cdir->d_parent = dir;
 
139
    dirchildadd(dir, cdir);
 
140
    return( cdir );
 
141
}
 
142
 
 
143
/*
 
144
 * Struct to save directory reading context in. Used to prevent
 
145
 * O(n^2) searches on a directory.
 
146
 */
 
147
struct savedir {
 
148
    u_short     sd_vid;
 
149
    int         sd_did;
 
150
    int         sd_buflen;
 
151
    char        *sd_buf;
 
152
    char        *sd_last;
 
153
    int         sd_sindex;
 
154
};
 
155
#define SDBUFBRK        1024
 
156
 
 
157
int afp_enumerate(obj, ibuf, ibuflen, rbuf, rbuflen )
 
158
AFPObj      *obj;
 
159
char    *ibuf, *rbuf;
 
160
int             ibuflen, *rbuflen;
 
161
{
 
162
    struct stat                 st;
 
163
    static struct savedir       sd = { 0, 0, 0, NULL, NULL, 0 };
 
164
    struct vol                  *vol;
 
165
    struct dir                  *dir;
 
166
    struct dirent               *de;
 
167
    DIR                         *dp;
 
168
    int                         did, ret, esz, len, first = 1;
 
169
    char                        *path, *data, *end, *start;
 
170
    u_int16_t                   vid, fbitmap, dbitmap, reqcnt, actcnt = 0;
 
171
    u_int16_t                   sindex, maxsz, sz = 0;
 
172
 
 
173
    if ( sd.sd_buflen == 0 ) {
 
174
        if (( sd.sd_buf = (char *)malloc( SDBUFBRK )) == NULL ) {
 
175
            LOG(log_error, logtype_afpd, "afp_enumerate: malloc: %s", strerror(errno) );
 
176
            *rbuflen = 0;
 
177
            return AFPERR_MISC;
 
178
        }
 
179
        sd.sd_buflen = SDBUFBRK;
 
180
    }
 
181
 
 
182
    ibuf += 2;
 
183
 
 
184
    memcpy( &vid, ibuf, sizeof( vid ));
 
185
    ibuf += sizeof( vid );
 
186
 
 
187
    if (( vol = getvolbyvid( vid )) == NULL ) {
 
188
        *rbuflen = 0;
 
189
        return( AFPERR_PARAM );
 
190
    }
 
191
 
 
192
    memcpy( &did, ibuf, sizeof( did ));
 
193
    ibuf += sizeof( did );
 
194
 
 
195
    if (( dir = dirlookup( vol, did )) == NULL ) {
 
196
        *rbuflen = 0;
 
197
        return( AFPERR_NODIR );
 
198
    }
 
199
 
 
200
    memcpy( &fbitmap, ibuf, sizeof( fbitmap ));
 
201
    fbitmap = ntohs( fbitmap );
 
202
    ibuf += sizeof( fbitmap );
 
203
 
 
204
    memcpy( &dbitmap, ibuf, sizeof( dbitmap ));
 
205
    dbitmap = ntohs( dbitmap );
 
206
    ibuf += sizeof( dbitmap );
 
207
 
 
208
    /* check for proper bitmaps -- the stuff in comments is for
 
209
     * variable directory ids. */
 
210
    if (!(fbitmap || dbitmap)
 
211
            /*|| (fbitmap & (1 << FILPBIT_PDID)) ||
 
212
              (dbitmap & (1 << DIRPBIT_PDID))*/) {
 
213
        *rbuflen = 0;
 
214
        return AFPERR_BITMAP;
 
215
    }
 
216
 
 
217
    memcpy( &reqcnt, ibuf, sizeof( reqcnt ));
 
218
    reqcnt = ntohs( reqcnt );
 
219
    ibuf += sizeof( reqcnt );
 
220
 
 
221
    memcpy( &sindex, ibuf, sizeof( sindex ));
 
222
    sindex = ntohs( sindex );
 
223
    ibuf += sizeof( sindex );
 
224
 
 
225
    memcpy( &maxsz, ibuf, sizeof( maxsz ));
 
226
    maxsz = ntohs( maxsz );
 
227
    ibuf += sizeof( maxsz );
 
228
 
 
229
    maxsz = min(maxsz, *rbuflen);
 
230
 
 
231
    if (( path = cname( vol, dir, &ibuf )) == NULL ) {
 
232
        *rbuflen = 0;
 
233
        return( AFPERR_NODIR );
 
234
    }
 
235
    data = rbuf + 3 * sizeof( u_int16_t );
 
236
    sz = 3 * sizeof( u_int16_t );
 
237
 
 
238
    /*
 
239
     * Read the directory into a pre-malloced buffer, stored
 
240
     *          len <name> \0
 
241
     * The end is indicated by a len of 0.
 
242
     */
 
243
    if ( sindex == 1 || curdir->d_did != sd.sd_did || vid != sd.sd_vid ) {
 
244
        sd.sd_last = sd.sd_buf;
 
245
 
 
246
        if (( dp = opendir( mtoupath(vol, path ))) == NULL ) {
 
247
            *rbuflen = 0;
 
248
            return (errno == ENOTDIR) ? AFPERR_BADTYPE : AFPERR_NODIR;
 
249
        }
 
250
 
 
251
        end = sd.sd_buf + sd.sd_buflen;
 
252
        for ( de = readdir( dp ); de != NULL; de = readdir( dp )) {
 
253
            if (!strcmp(de->d_name, "..") || !strcmp(de->d_name, "."))
 
254
                continue;
 
255
 
 
256
            if (!(validupath(vol, de->d_name)))
 
257
                continue;
 
258
 
 
259
            /* check for vetoed filenames */
 
260
            if (veto_file(vol->v_veto, de->d_name))
 
261
                continue;
 
262
 
 
263
            /* now check against too big a file */
 
264
            if (strlen(utompath(vol, de->d_name)) > MACFILELEN)
 
265
                continue;
 
266
 
 
267
            len = strlen(de->d_name);
 
268
            *(sd.sd_last)++ = len;
 
269
 
 
270
            if ( sd.sd_last + len + 2 > end ) {
 
271
                char *buf;
 
272
 
 
273
                start = sd.sd_buf;
 
274
                if ((buf = (char *) realloc( sd.sd_buf, sd.sd_buflen +
 
275
                                             SDBUFBRK )) == NULL ) {
 
276
                    LOG(log_error, logtype_afpd, "afp_enumerate: realloc: %s",
 
277
                        strerror(errno) );
 
278
                    closedir(dp);
 
279
                    *rbuflen = 0;
 
280
                    return AFPERR_MISC;
 
281
                }
 
282
                sd.sd_buf = buf;
 
283
                sd.sd_buflen += SDBUFBRK;
 
284
                sd.sd_last = ( sd.sd_last - start ) + sd.sd_buf;
 
285
                end = sd.sd_buf + sd.sd_buflen;
 
286
            }
 
287
 
 
288
            memcpy( sd.sd_last, de->d_name, len + 1 );
 
289
            sd.sd_last += len + 1;
 
290
        }
 
291
        *sd.sd_last = 0;
 
292
 
 
293
        sd.sd_last = sd.sd_buf;
 
294
        sd.sd_sindex = 1;
 
295
 
 
296
        closedir( dp );
 
297
        sd.sd_vid = vid;
 
298
        sd.sd_did = did;
 
299
    }
 
300
 
 
301
    /*
 
302
     * Position sd_last as dictated by sindex.
 
303
     */
 
304
    if ( sindex < sd.sd_sindex ) {
 
305
        sd.sd_sindex = 1;
 
306
        sd.sd_last = sd.sd_buf;
 
307
    }
 
308
    while ( sd.sd_sindex < sindex ) {
 
309
        len = *(sd.sd_last)++;
 
310
        if ( len == 0 ) {
 
311
            sd.sd_did = -1;     /* invalidate sd struct to force re-read */
 
312
            *rbuflen = 0;
 
313
            return( AFPERR_NOOBJ );
 
314
        }
 
315
        sd.sd_last += len + 1;
 
316
        sd.sd_sindex++;
 
317
    }
 
318
 
 
319
    while (( len = *(sd.sd_last)) != 0 ) {
 
320
        /*
 
321
         * If we've got all we need, send it.
 
322
         */
 
323
        if ( actcnt == reqcnt ) {
 
324
            break;
 
325
        }
 
326
 
 
327
        /*
 
328
         * Save the start position, in case we exceed the buffer
 
329
         * limitation, and have to back up one.
 
330
         */
 
331
        start = sd.sd_last;
 
332
        sd.sd_last++;
 
333
 
 
334
        if (*sd.sd_last == 0) {
 
335
            /* stat() already failed on this one */
 
336
            sd.sd_last += len + 1;
 
337
            continue;
 
338
        }
 
339
 
 
340
        if (stat( sd.sd_last, &st ) < 0 ) {
 
341
            /*
 
342
             * Somebody else plays with the dir, well it can be us with 
 
343
            * "Empty Trash..."
 
344
            */
 
345
 
 
346
            /* so the next time it won't try to stat it again
 
347
             * another solution would be to invalidate the cache with 
 
348
             * sd.sd_did = -1 but if it's not ENOENT error it will start again
 
349
             */
 
350
            *sd.sd_last = 0;
 
351
            sd.sd_last += len + 1;
 
352
            continue;
 
353
        }
 
354
 
 
355
        /*
 
356
         * If a fil/dir is not a dir, it's a file. This is slightly
 
357
         * inaccurate, since that means /dev/null is a file, /dev/printer
 
358
         * is a file, etc.
 
359
         */
 
360
        if ( S_ISDIR(st.st_mode)) {
 
361
            if ( dbitmap == 0 ) {
 
362
                sd.sd_last += len + 1;
 
363
                continue;
 
364
            }
 
365
            path = utompath(vol, sd.sd_last);
 
366
            dir = curdir->d_child;
 
367
            while (dir) {
 
368
                if ( strcmp( dir->d_name, path ) == 0 ) {
 
369
                    break;
 
370
                }
 
371
                dir = (dir == curdir->d_child->d_prev) ? NULL : dir->d_next;
 
372
            }
 
373
            if (!dir && ((dir = adddir( vol, curdir, path, strlen( path ),
 
374
                                        sd.sd_last, len, &st)) == NULL)) {
 
375
                *rbuflen = 0;
 
376
                return AFPERR_MISC;
 
377
            }
 
378
 
 
379
 
 
380
            if (( ret = getdirparams(vol, dbitmap, sd.sd_last, dir,
 
381
                                     &st, data + 2 * sizeof( u_char ), &esz )) != AFP_OK ) {
 
382
                *rbuflen = 0;
 
383
                return( ret );
 
384
            }
 
385
 
 
386
        } else {
 
387
            if ( fbitmap == 0 ) {
 
388
                sd.sd_last += len + 1;
 
389
                continue;
 
390
            }
 
391
 
 
392
            if (( ret = getfilparams(vol, fbitmap, utompath(vol, sd.sd_last),
 
393
                                     curdir, &st, data + 2 * sizeof( u_char ), &esz )) !=
 
394
                    AFP_OK ) {
 
395
                *rbuflen = 0;
 
396
                return( ret );
 
397
            }
 
398
        }
 
399
 
 
400
        /*
 
401
         * Make sure entry is an even length, possibly with a null
 
402
         * byte on the end.
 
403
         */
 
404
        if ( esz & 1 ) {
 
405
            *(data + 2 * sizeof( u_char ) + esz ) = '\0';
 
406
            esz++;
 
407
        }
 
408
 
 
409
        /*
 
410
         * Check if we've exceeded the size limit.
 
411
         */
 
412
        if ( maxsz < sz + esz + 2 * sizeof( u_char )) {
 
413
            if (first) { /* maxsz can't hold a single reply */
 
414
                *rbuflen = 0;
 
415
                return AFPERR_PARAM;
 
416
            }
 
417
            sd.sd_last = start;
 
418
            break;
 
419
        }
 
420
 
 
421
        if (first)
 
422
            first = 0;
 
423
 
 
424
        sz += esz + 2 * sizeof( u_char );
 
425
        *data++ = esz + 2 * sizeof( u_char );
 
426
        *data++ = S_ISDIR(st.st_mode) ? FILDIRBIT_ISDIR : FILDIRBIT_ISFILE;
 
427
        data += esz;
 
428
        actcnt++;
 
429
        sd.sd_last += len + 1;
 
430
    }
 
431
 
 
432
    if ( actcnt == 0 ) {
 
433
        *rbuflen = 0;
 
434
        sd.sd_did = -1;         /* invalidate sd struct to force re-read */
 
435
        return( AFPERR_NOOBJ );
 
436
    }
 
437
    sd.sd_sindex = sindex + actcnt;
 
438
 
 
439
    /*
 
440
     * All done, fill in misc junk in rbuf
 
441
     */
 
442
    fbitmap = htons( fbitmap );
 
443
    memcpy( rbuf, &fbitmap, sizeof( fbitmap ));
 
444
    rbuf += sizeof( fbitmap );
 
445
    dbitmap = htons( dbitmap );
 
446
    memcpy( rbuf, &dbitmap, sizeof( dbitmap ));
 
447
    rbuf += sizeof( dbitmap );
 
448
    actcnt = htons( actcnt );
 
449
    memcpy( rbuf, &actcnt, sizeof( actcnt ));
 
450
    rbuf += sizeof( actcnt );
 
451
    *rbuflen = sz;
 
452
    return( AFP_OK );
 
453
}
 
454
 
 
455