2 * Copyright (c) 1990,1993 Regents of The University of Michigan.
3 * All Rights Reserved. See COPYRIGHT.
16 #include <sys/syslog.h>
17 #include <sys/types.h>
20 #include <sys/param.h>
22 #include <netatalk/endian.h>
23 #include <atalk/afp.h>
24 #include <atalk/adouble.h>
25 #include <atalk/cnid.h>
28 #include "directory.h"
35 adddir( vol, dir, name, namlen, upath, upathlen, st )
42 struct dir *cdir, *edir;
43 #if AD_VERSION > AD_VERSION1
48 struct stat lst, *lstp;
51 if ((cdir = dirnew(namlen + 1)) == NULL) {
52 syslog( LOG_ERR, "adddir: malloc: %m" );
55 strcpy( cdir->d_name, name );
56 cdir->d_name[namlen] = '\0';
58 #if AD_VERSION > AD_VERSION1
59 /* find out if we have a fixed did already */
60 if (!(cdir->d_did = cnid_lookup(vol->v_db, st, dir->d_did, upath,
62 memset(&ad, 0, sizeof(ad));
63 if (ad_open(upath, ADFLAGS_HF|ADFLAGS_DIR, O_RDONLY, 0, &ad) < 0)
66 memcpy(&cdir->d_did, ad_entry(&ad, ADEID_DID), sizeof(cdir->d_did));
67 ad_close(&ad, ADFLAGS_HF);
70 if (!(cdir->d_did = cnid_add(vol->v_db, st, dir->d_did, upath,
71 upathlen, cdir->d_did))) {
73 cdir->d_did = htonl( vol->v_lastdid++ );
75 lstp = lstat(upath, &lst) < 0 ? st : &lst;
76 cdir->d_did = htonl( CNID(lstp, 0) );
83 cdir->d_did = htonl( vol->v_lastdid++ );
85 lstp = lstat(upath, &lst) < 0 ? st : &lst;
86 cdir->d_did = htonl( CNID(lstp, 0) );
90 if (edir = dirinsert( vol, cdir )) {
92 if (strcmp(edir->d_name, cdir->d_name)) {
93 syslog(LOG_INFO, "WARNING: DID conflict for '%s' and '%s'. Are these the same file?", edir->d_name, cdir->d_name);
99 edir->d_name = cdir->d_name;
104 /* parent/child directories */
105 cdir->d_parent = dir;
106 dirchildadd(dir, cdir);
111 * Struct to save directory reading context in. Used to prevent
112 * O(n^2) searches on a directory.
122 #define SDBUFBRK 1024
124 int afp_enumerate(obj, ibuf, ibuflen, rbuf, rbuflen )
127 int ibuflen, *rbuflen;
130 static struct savedir sd = { 0, 0, 0, NULL, NULL, 0 };
135 int did, ret, esz, len, first = 1;
136 char *path, *data, *end, *start;
137 u_int16_t vid, fbitmap, dbitmap, reqcnt, actcnt = 0;
138 u_int16_t sindex, maxsz, sz = 0;
140 if ( sd.sd_buflen == 0 ) {
141 if (( sd.sd_buf = (char *)malloc( SDBUFBRK )) == NULL ) {
142 syslog( LOG_ERR, "afp_enumerate: malloc: %m" );
146 sd.sd_buflen = SDBUFBRK;
151 memcpy( &vid, ibuf, sizeof( vid ));
152 ibuf += sizeof( vid );
154 if (( vol = getvolbyvid( vid )) == NULL ) {
156 return( AFPERR_PARAM );
159 memcpy( &did, ibuf, sizeof( did ));
160 ibuf += sizeof( did );
162 if (( dir = dirsearch( vol, did )) == NULL ) {
164 return( AFPERR_NODIR );
167 memcpy( &fbitmap, ibuf, sizeof( fbitmap ));
168 fbitmap = ntohs( fbitmap );
169 ibuf += sizeof( fbitmap );
171 memcpy( &dbitmap, ibuf, sizeof( dbitmap ));
172 dbitmap = ntohs( dbitmap );
173 ibuf += sizeof( dbitmap );
175 /* check for proper bitmaps -- the stuff in comments is for
176 * variable directory ids. */
177 if (!(fbitmap || dbitmap)
178 /*|| (fbitmap & (1 << FILPBIT_PDID)) ||
179 (dbitmap & (1 << DIRPBIT_PDID))*/) {
181 return AFPERR_BITMAP;
184 memcpy( &reqcnt, ibuf, sizeof( reqcnt ));
185 reqcnt = ntohs( reqcnt );
186 ibuf += sizeof( reqcnt );
188 memcpy( &sindex, ibuf, sizeof( sindex ));
189 sindex = ntohs( sindex );
190 ibuf += sizeof( sindex );
192 memcpy( &maxsz, ibuf, sizeof( maxsz ));
193 maxsz = ntohs( maxsz );
194 ibuf += sizeof( maxsz );
196 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
198 return( AFPERR_NODIR );
200 data = rbuf + 3 * sizeof( u_int16_t );
201 sz = 3 * sizeof( u_int16_t );
204 * Read the directory into a pre-malloced buffer, stored
206 * The end is indicated by a len of 0.
208 if ( sindex == 1 || curdir->d_did != sd.sd_did || vid != sd.sd_vid ) {
209 sd.sd_last = sd.sd_buf;
211 if (( dp = opendir( mtoupath(vol, path ))) == NULL ) {
213 return (errno == ENOTDIR) ? AFPERR_BADTYPE : AFPERR_NODIR;
216 end = sd.sd_buf + sd.sd_buflen;
217 for ( de = readdir( dp ); de != NULL; de = readdir( dp )) {
218 if (!strcmp(de->d_name, "..") || !strcmp(de->d_name, "."))
221 if (!(validupath(vol, de->d_name)))
224 /* now check against too big a file */
225 if (strlen(utompath(vol, de->d_name)) > MACFILELEN)
228 len = strlen(de->d_name);
229 *(sd.sd_last)++ = len;
231 if ( sd.sd_last + len + 2 > end ) {
235 if ((buf = (char *) realloc( sd.sd_buf, sd.sd_buflen +
236 SDBUFBRK )) == NULL ) {
237 syslog( LOG_ERR, "afp_enumerate: realloc: %m" );
243 sd.sd_buflen += SDBUFBRK;
244 sd.sd_last = ( sd.sd_last - start ) + sd.sd_buf;
245 end = sd.sd_buf + sd.sd_buflen;
248 memcpy( sd.sd_last, de->d_name, len + 1 );
249 sd.sd_last += len + 1;
253 sd.sd_last = sd.sd_buf;
262 * Position sd_last as dictated by sindex.
264 if ( sindex < sd.sd_sindex ) {
266 sd.sd_last = sd.sd_buf;
268 while ( sd.sd_sindex < sindex ) {
269 len = *(sd.sd_last)++;
271 sd.sd_did = -1; /* invalidate sd struct to force re-read */
273 return( AFPERR_NOOBJ );
275 sd.sd_last += len + 1;
279 while (( len = *(sd.sd_last)) != 0 ) {
281 * If we've got all we need, send it.
283 if ( actcnt == reqcnt ) {
288 * Save the start position, in case we exceed the buffer
289 * limitation, and have to back up one.
294 if ( stat( sd.sd_last, &st ) < 0 ) {
295 syslog( LOG_DEBUG, "afp_enumerate: stat %s: %m", sd.sd_last );
296 sd.sd_last += len + 1;
301 * If a fil/dir is not a dir, it's a file. This is slightly
302 * inaccurate, since that means /dev/null is a file, /dev/printer
305 if ( S_ISDIR(st.st_mode)) {
306 if ( dbitmap == 0 ) {
307 sd.sd_last += len + 1;
310 path = utompath(vol, sd.sd_last);
311 dir = curdir->d_child;
313 if ( strcmp( dir->d_name, path ) == 0 ) {
316 dir = (dir == curdir->d_child->d_prev) ? NULL : dir->d_next;
318 if (!dir && ((dir = adddir( vol, curdir, path, strlen( path ),
319 sd.sd_last, len, &st)) == NULL)) {
325 if (( ret = getdirparams(vol, dbitmap, sd.sd_last, dir,
326 &st, data + 2 * sizeof( u_char ), &esz )) != AFP_OK ) {
332 if ( fbitmap == 0 ) {
333 sd.sd_last += len + 1;
337 if (( ret = getfilparams(vol, fbitmap, utompath(vol, sd.sd_last),
338 curdir, &st, data + 2 * sizeof( u_char ), &esz )) !=
346 * Make sure entry is an even length, possibly with a null
350 *(data + 2 * sizeof( u_char ) + esz ) = '\0';
355 * Check if we've exceeded the size limit.
357 if ( maxsz < sz + esz + 2 * sizeof( u_char )) {
358 if (first) { /* maxsz can't hold a single reply */
369 sz += esz + 2 * sizeof( u_char );
370 *data++ = esz + 2 * sizeof( u_char );
371 *data++ = S_ISDIR(st.st_mode) ? FILDIRBIT_ISDIR : FILDIRBIT_ISFILE;
374 sd.sd_last += len + 1;
379 sd.sd_did = -1; /* invalidate sd struct to force re-read */
380 return( AFPERR_NOOBJ );
382 sd.sd_sindex = sindex + actcnt;
385 * All done, fill in misc junk in rbuf
387 fbitmap = htons( fbitmap );
388 memcpy( rbuf, &fbitmap, sizeof( fbitmap ));
389 rbuf += sizeof( fbitmap );
390 dbitmap = htons( dbitmap );
391 memcpy( rbuf, &dbitmap, sizeof( dbitmap ));
392 rbuf += sizeof( dbitmap );
393 actcnt = htons( actcnt );
394 memcpy( rbuf, &actcnt, sizeof( actcnt ));
395 rbuf += sizeof( actcnt );
401 /* why is this here? well, FPCatSearch is essentially an FPEnumerate
403 int afp_catsearch(AFPObj *obj, char *ibuf, int ibuflen,
404 char *rbuf, int *rbuflen)
410 memcpy(&vid, ibuf, sizeof(vid));
414 if ((vol = getvolbyvid(vid)) == NULL)
418 * do a breadth-first search of directories:
419 * lookup did/name info.
420 * add to result if match
421 * check to see if we've exceeded our timelimit
422 * if yes, return current position
425 * we keep a copy of our current position in struct vol.
426 * if the next catsearch request for that volume isn't at
427 * at the current position, bail and return catchanged.