2
* $Id: enumerate.c,v 1.23.2.1 2003/02/04 19:10:30 didg Exp $
4
* Copyright (c) 1990,1993 Regents of The University of Michigan.
5
* All Rights Reserved. See COPYRIGHT.
10
#endif /* HAVE_CONFIG_H */
18
#include <atalk/logger.h>
19
#include <sys/types.h>
22
#include <sys/param.h>
24
#include <netatalk/endian.h>
25
#include <atalk/afp.h>
26
#include <atalk/adouble.h>
28
#include <atalk/cnid.h>
31
#include "directory.h"
37
#define min(a,b) ((a)<(b)?(a):(b))
40
adddir( vol, dir, name, namlen, upath, upathlen, st )
47
struct dir *cdir, *edir;
48
#if AD_VERSION > AD_VERSION1
50
#endif /* AD_VERSION > AD_VERSION1 */
53
struct stat lst, *lstp;
54
#endif /* USE_LASTDID */
56
if ((cdir = dirnew(namlen + 1)) == NULL) {
57
LOG(log_error, logtype_afpd, "adddir: malloc: %s", strerror(errno) );
60
strcpy( cdir->d_name, name );
61
cdir->d_name[namlen] = '\0';
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);
73
#endif /* AD_VERSION */
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) {
83
LOG(log_error, logtype_afpd, "adddir: Incorrect parameters passed to cnid_add");
93
if (cdir->d_did == 0) {
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 */
104
if ((edir = dirinsert( vol, cdir ))) {
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);
115
/* it's not possible with LASTDID
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
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
127
edir->d_name = cdir->d_name;
130
if (!cdir->d_parent || cdir->d_parent == dir)
133
/* the old was not in the same folder, remove and add to the new */
134
dirchildremove(cdir->d_parent, cdir);
137
/* parent/child directories */
138
cdir->d_parent = dir;
139
dirchildadd(dir, cdir);
144
* Struct to save directory reading context in. Used to prevent
145
* O(n^2) searches on a directory.
155
#define SDBUFBRK 1024
157
int afp_enumerate(obj, ibuf, ibuflen, rbuf, rbuflen )
160
int ibuflen, *rbuflen;
163
static struct savedir sd = { 0, 0, 0, NULL, NULL, 0 };
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;
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) );
179
sd.sd_buflen = SDBUFBRK;
184
memcpy( &vid, ibuf, sizeof( vid ));
185
ibuf += sizeof( vid );
187
if (( vol = getvolbyvid( vid )) == NULL ) {
189
return( AFPERR_PARAM );
192
memcpy( &did, ibuf, sizeof( did ));
193
ibuf += sizeof( did );
195
if (( dir = dirlookup( vol, did )) == NULL ) {
197
return( AFPERR_NODIR );
200
memcpy( &fbitmap, ibuf, sizeof( fbitmap ));
201
fbitmap = ntohs( fbitmap );
202
ibuf += sizeof( fbitmap );
204
memcpy( &dbitmap, ibuf, sizeof( dbitmap ));
205
dbitmap = ntohs( dbitmap );
206
ibuf += sizeof( dbitmap );
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))*/) {
214
return AFPERR_BITMAP;
217
memcpy( &reqcnt, ibuf, sizeof( reqcnt ));
218
reqcnt = ntohs( reqcnt );
219
ibuf += sizeof( reqcnt );
221
memcpy( &sindex, ibuf, sizeof( sindex ));
222
sindex = ntohs( sindex );
223
ibuf += sizeof( sindex );
225
memcpy( &maxsz, ibuf, sizeof( maxsz ));
226
maxsz = ntohs( maxsz );
227
ibuf += sizeof( maxsz );
229
maxsz = min(maxsz, *rbuflen);
231
if (( path = cname( vol, dir, &ibuf )) == NULL ) {
233
return( AFPERR_NODIR );
235
data = rbuf + 3 * sizeof( u_int16_t );
236
sz = 3 * sizeof( u_int16_t );
239
* Read the directory into a pre-malloced buffer, stored
241
* The end is indicated by a len of 0.
243
if ( sindex == 1 || curdir->d_did != sd.sd_did || vid != sd.sd_vid ) {
244
sd.sd_last = sd.sd_buf;
246
if (( dp = opendir( mtoupath(vol, path ))) == NULL ) {
248
return (errno == ENOTDIR) ? AFPERR_BADTYPE : AFPERR_NODIR;
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, "."))
256
if (!(validupath(vol, de->d_name)))
259
/* check for vetoed filenames */
260
if (veto_file(vol->v_veto, de->d_name))
263
/* now check against too big a file */
264
if (strlen(utompath(vol, de->d_name)) > MACFILELEN)
267
len = strlen(de->d_name);
268
*(sd.sd_last)++ = len;
270
if ( sd.sd_last + len + 2 > end ) {
274
if ((buf = (char *) realloc( sd.sd_buf, sd.sd_buflen +
275
SDBUFBRK )) == NULL ) {
276
LOG(log_error, logtype_afpd, "afp_enumerate: realloc: %s",
283
sd.sd_buflen += SDBUFBRK;
284
sd.sd_last = ( sd.sd_last - start ) + sd.sd_buf;
285
end = sd.sd_buf + sd.sd_buflen;
288
memcpy( sd.sd_last, de->d_name, len + 1 );
289
sd.sd_last += len + 1;
293
sd.sd_last = sd.sd_buf;
302
* Position sd_last as dictated by sindex.
304
if ( sindex < sd.sd_sindex ) {
306
sd.sd_last = sd.sd_buf;
308
while ( sd.sd_sindex < sindex ) {
309
len = *(sd.sd_last)++;
311
sd.sd_did = -1; /* invalidate sd struct to force re-read */
313
return( AFPERR_NOOBJ );
315
sd.sd_last += len + 1;
319
while (( len = *(sd.sd_last)) != 0 ) {
321
* If we've got all we need, send it.
323
if ( actcnt == reqcnt ) {
328
* Save the start position, in case we exceed the buffer
329
* limitation, and have to back up one.
334
if (*sd.sd_last == 0) {
335
/* stat() already failed on this one */
336
sd.sd_last += len + 1;
340
if (stat( sd.sd_last, &st ) < 0 ) {
342
* Somebody else plays with the dir, well it can be us with
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
351
sd.sd_last += len + 1;
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
360
if ( S_ISDIR(st.st_mode)) {
361
if ( dbitmap == 0 ) {
362
sd.sd_last += len + 1;
365
path = utompath(vol, sd.sd_last);
366
dir = curdir->d_child;
368
if ( strcmp( dir->d_name, path ) == 0 ) {
371
dir = (dir == curdir->d_child->d_prev) ? NULL : dir->d_next;
373
if (!dir && ((dir = adddir( vol, curdir, path, strlen( path ),
374
sd.sd_last, len, &st)) == NULL)) {
380
if (( ret = getdirparams(vol, dbitmap, sd.sd_last, dir,
381
&st, data + 2 * sizeof( u_char ), &esz )) != AFP_OK ) {
387
if ( fbitmap == 0 ) {
388
sd.sd_last += len + 1;
392
if (( ret = getfilparams(vol, fbitmap, utompath(vol, sd.sd_last),
393
curdir, &st, data + 2 * sizeof( u_char ), &esz )) !=
401
* Make sure entry is an even length, possibly with a null
405
*(data + 2 * sizeof( u_char ) + esz ) = '\0';
410
* Check if we've exceeded the size limit.
412
if ( maxsz < sz + esz + 2 * sizeof( u_char )) {
413
if (first) { /* maxsz can't hold a single reply */
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;
429
sd.sd_last += len + 1;
434
sd.sd_did = -1; /* invalidate sd struct to force re-read */
435
return( AFPERR_NOOBJ );
437
sd.sd_sindex = sindex + actcnt;
440
* All done, fill in misc junk in rbuf
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 );