96db7faff4a0d54cf817f5803f0ee9089381255d
[openafs.git] / src / afs / VNOPS / afs_vnop_readdir.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  * 
5  * This software has been released under the terms of the IBM Public
6  * License.  For details, see the LICENSE file in the top-level source
7  * directory or online at http://www.openafs.org/dl/license10.html
8  */
9
10 /*
11  * afs_vnop_readdir.c - afs_readdir and bulk stat
12  *
13  * Implements:
14  * BlobScan
15  * afs_readdir_move
16  * afs_bulkstat_send
17  * afs_readdir/afs_readdir2(HP)
18  * afs_readdir1 - HP and DUX NFS versions
19  * 
20  */
21
22 #include <afsconfig.h>
23 #include "afs/param.h"
24
25 RCSID("$Header$");
26
27 #include "afs/sysincludes.h"    /* Standard vendor system headers */
28 #include "afsincludes.h"        /* Afs-based standard headers */
29 #include "afs/afs_stats.h" /* statistics */
30 #include "afs/afs_cbqueue.h"
31 #include "afs/nfsclient.h"
32 #include "afs/afs_osidnlc.h"
33
34
35 #if     defined(AFS_HPUX1122_ENV)
36 #define DIRPAD 7
37 #else
38 #define DIRPAD 3
39 #endif
40 /**
41  * A few definitions. This is until we have a proper header file
42  * which ahs prototypes for all functions
43  */
44     
45 extern struct DirEntry * afs_dir_GetBlob();
46 /*
47  * AFS readdir vnodeop and bulk stat support.
48  */
49
50 /* Saber C hates negative inode #s.  We're not going to talk about software
51  * that could fail if it sees a negative inode #.
52  */
53 #define FIXUPSTUPIDINODE(a)     ((a) &= 0x7fffffff)
54
55 /* BlobScan is supposed to ensure that the blob reference refers to a valid
56     directory entry.  It consults the allocation map in the page header
57     to determine whether a blob is actually in use or not.
58
59     More formally, BlobScan is supposed to return a new blob number which is just like
60     the input parameter, only it is advanced over header or free blobs.
61     
62     Note that BlobScan switches pages if necessary.  BlobScan may return
63     either 0 or an out-of-range blob number for end of file.
64
65     BlobScan is used by the Linux port in a separate file, so it should not
66     become static.
67 */
68 #if defined(AFS_SGI62_ENV) || defined(AFS_SUN57_64BIT_ENV)
69 int BlobScan(ino64_t *afile, afs_int32 ablob)
70 #else
71 #ifdef AFS_LINUX_64BIT_KERNEL
72 int BlobScan(long *afile, afs_int32 ablob)
73 #else
74 int BlobScan(afs_int32 *afile, afs_int32 ablob)
75 #endif
76 #endif
77 {
78     register afs_int32 relativeBlob;
79     afs_int32 pageBlob;
80     register struct PageHeader *tpe;
81     register afs_int32 i;
82
83     AFS_STATCNT(BlobScan);
84     /* advance ablob over free and header blobs */
85     while (1) {
86         pageBlob = ablob & ~(EPP-1);    /* base blob in same page */
87         tpe = (struct PageHeader *) afs_dir_GetBlob(afile, pageBlob);
88         if (!tpe) return 0;                 /* we've past the end */
89         relativeBlob = ablob - pageBlob;    /* relative to page's first blob */
90         /* first watch for headers */
91         if (pageBlob == 0) {                /* first dir page has extra-big header */
92             /* first page */
93             if (relativeBlob < DHE+1) relativeBlob = DHE+1;
94         }
95         else {                              /* others have one header blob */
96             if (relativeBlob == 0) relativeBlob = 1;
97         }
98         /* make sure blob is allocated */
99         for(i = relativeBlob; i < EPP; i++) {
100             if (tpe->freebitmap[i>>3] & (1<<(i&7))) break;
101         }
102         /* now relativeBlob is the page-relative first allocated blob,
103          or EPP (if there are none in this page). */
104         DRelease((struct buffer *) tpe, 0);
105         if (i != EPP) return i+pageBlob;
106         ablob = pageBlob + EPP; /* go around again */
107     }
108     /* never get here */
109 }
110
111 #if !defined(AFS_LINUX20_ENV)
112 /* Changes to afs_readdir which affect dcache or vcache handling or use of
113  * bulk stat data should also be reflected in the Linux specific verison of
114  * the readdir routine.
115  */
116
117 /*
118  * The kernel don't like it so much to have large stuff on the stack.
119  * Here we use a watered down version of the direct struct, since
120  * its not too bright to double copy the strings anyway.
121 */
122 #if !defined(UKERNEL)
123 #if defined(AFS_SGI_ENV)
124 /* Long form for 64 bit apps and kernel requests. */
125 struct min_dirent {     /* miniature dirent structure */
126                         /* If struct dirent changes, this must too */
127     ino_t       d_fileno; /* This is 32 bits for 3.5, 64 for 6.2+ */
128     off64_t     d_off;
129     u_short     d_reclen;
130 };
131 /* Short form for 32 bit apps. */
132 struct irix5_min_dirent {     /* miniature dirent structure */
133                         /* If struct dirent changes, this must too */
134     afs_uint32  d_fileno;
135     afs_int32   d_off;
136     u_short     d_reclen;
137 };
138 #ifdef AFS_SGI62_ENV
139 #define AFS_DIRENT32BASESIZE IRIX5_DIRENTBASESIZE
140 #define AFS_DIRENT64BASESIZE DIRENT64BASESIZE
141 #else
142 #define AFS_DIRENT32BASESIZE IRIX5_DIRENTBASESIZE
143 #define AFS_DIRENT64BASESIZE DIRENTBASESIZE
144 #endif /* AFS_SGI62_ENV */
145 #else
146 struct min_direct {     /* miniature direct structure */
147                         /* If struct direct changes, this must too */
148 #if defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
149     afs_uint32  d_fileno;
150     u_short     d_reclen;
151     u_char      d_type;
152     u_char      d_namlen;
153 #else   
154 #ifdef  AFS_SUN5_ENV
155     afs_uint32  d_fileno;
156     afs_int32   d_off;
157     u_short     d_reclen;
158 #else
159 #if defined(AFS_SUN_ENV) || defined(AFS_AIX32_ENV)
160     afs_int32   d_off;
161 #endif
162 #if     defined(AFS_HPUX100_ENV)
163     unsigned long long d_off;
164 #endif
165     afs_uint32  d_fileno;
166     u_short     d_reclen;
167     u_short     d_namlen;
168 #endif
169 #endif
170 };
171 #endif /* AFS_SGI_ENV */
172
173 #if     defined(AFS_HPUX_ENV) || defined(AFS_OSF_ENV)
174 struct minnfs_direct {
175     afs_int32   d_off;          /* XXX */
176     afs_uint32  d_fileno;
177     u_short     d_reclen;
178     u_short     d_namlen;
179 };
180 #define NDIRSIZ_LEN(len)   ((sizeof (struct dirent)+4 - (MAXNAMLEN+1)) + (((len)+1 + DIRPAD) &~ DIRPAD))
181 #endif
182 #endif /* !defined(UKERNEL) */
183
184
185 /*
186  *------------------------------------------------------------------------------
187  *
188  * Keep a stack of about 256 fids for the bulk stat call.
189  * Fill it during the readdir_move.  Later empty it...
190  */
191
192 #define READDIR_STASH   AFSCBMAX
193 struct AFSFid   afs_readdir_stash[READDIR_STASH];
194 int     afs_rd_stash_i = 0;
195
196 /*
197  *------------------------------------------------------------------------------
198  *
199  * afs_readdir_move.
200  *      mainly a kind of macro... makes getting the struct direct
201  *      out to the user space easy... could take more parameters,
202  *      but now just takes what it needs.
203  *
204  *
205 */
206
207 #if     defined(AFS_HPUX100_ENV)
208 #define DIRSIZ_LEN(len) \
209     ((sizeof (struct __dirent) - (_MAXNAMLEN+1)) + (((len)+1 + DIRPAD) &~ DIRPAD))
210 #else
211 #if     defined(AFS_SUN56_ENV)
212 #define DIRSIZ_LEN(len) ((18 + (len) + 1 + 7) & ~7 )
213 #else
214 #ifdef  AFS_SUN5_ENV
215 #define DIRSIZ_LEN(len) ((10 + (len) + 1 + (NBPW-1)) & ~(NBPW-1))
216 #else
217 #ifdef  AFS_DIRENT
218 #define DIRSIZ_LEN(len) \
219     ((sizeof (struct dirent) - (MAXNAMLEN+1)) + (((len)+1 + 3) &~ 3))
220 #else
221 #if defined(AFS_SGI_ENV)
222 #ifndef AFS_SGI53_ENV
223 /* SGI 5.3 and later use 32/64 bit versions of directory size. */
224 #define DIRSIZ_LEN(len)         DIRENTSIZE(len)
225 #endif
226 #else /* AFS_SGI_ENV */
227 #define DIRSIZ_LEN(len) \
228     ((sizeof (struct direct) - (MAXNAMLEN+1)) + (((len)+1 + 3) &~ 3))
229 #endif /* AFS_SGI_ENV */
230 #endif /* AFS_DIRENT */
231 #endif /* AFS_SUN5_ENV */
232 #endif /* AFS_SUN56_ENV */
233 #endif  /* AFS_HPUX100_ENV */
234
235 #if defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
236 int afs_readdir_type(avc, ade) 
237 struct DirEntry *       ade;
238 struct vcache *         avc;
239 {
240      struct VenusFid tfid;
241      struct vcache *tvc;
242      int vtype;
243      tfid.Cell=avc->fid.Cell;
244      tfid.Fid.Volume=avc->fid.Fid.Volume;
245      tfid.Fid.Vnode=ntohl(ade->fid.vnode);
246      tfid.Fid.Unique=ntohl(ade->fid.vunique);
247      if ((avc->states & CForeign) == 0 &&
248          (ntohl(ade->fid.vnode) & 1)) {
249           return DT_DIR;
250      } else if ((tvc=afs_FindVCache(&tfid,0,0))) {
251            if (tvc->mvstat) {
252                afs_PutVCache(tvc);
253                return DT_DIR;
254           } else if (((tvc->states) & (CStatd|CTruth))) {
255                /* CTruth will be set if the object has
256                 *ever* been statd */
257                vtype=vType(tvc);
258                afs_PutVCache(tvc);
259                if (vtype == VDIR)
260                     return DT_DIR;
261                else if (vtype == VREG)
262                     return DT_REG;
263                /* Don't do this until we're sure it can't be a mtpt */
264                /* else if (vtype == VLNK)
265                   type=DT_LNK; */
266                /* what other types does AFS support? */
267           } else
268                afs_PutVCache(tvc);
269     }
270     return DT_UNKNOWN;
271 }
272 #endif
273
274 #ifdef AFS_AIX41_ENV
275 #define AFS_MOVE_LOCK()   AFS_GLOCK()
276 #define AFS_MOVE_UNLOCK() AFS_GUNLOCK()
277 #else
278 #define AFS_MOVE_LOCK()
279 #define AFS_MOVE_UNLOCK()
280 #endif
281 char bufofzeros[64];    /* gotta fill with something */
282 afs_readdir_move (de, vc, auio, slen, rlen, off) 
283 struct DirEntry *       de;
284 struct vcache *         vc;
285 struct  uio *           auio;
286 int                     slen;
287 #ifdef AFS_SGI65_ENV
288 ssize_t                 rlen;
289 #else
290 int                     rlen;
291 #endif
292 afs_size_t              off;
293 {
294     int code = 0;
295 #if     defined(AFS_SUN56_ENV)
296     struct dirent64 *direntp;
297 #else
298 #ifdef  AFS_SUN5_ENV
299     struct dirent *direntp;
300 #endif
301 #endif /* AFS_SUN56_ENV */
302 #ifndef AFS_SGI53_ENV
303     struct min_direct sdirEntry;
304 #endif /* AFS_SGI53_ENV */
305
306     AFS_STATCNT(afs_readdir_move);
307 #ifdef  AFS_SGI53_ENV
308 {
309     afs_int32   use64BitDirent;
310
311 #ifdef AFS_SGI61_ENV
312 #ifdef AFS_SGI62_ENV
313     use64BitDirent = ABI_IS(ABI_IRIX5_64,
314                             GETDENTS_ABI*OSI_GET_CURRENT_ABI(), auio));
315 #else
316     use64BitDirent = (auio->uio_segflg != UIO_USERSPACE) ? ABI_IRIX5_64 :
317         (ABI_IS(ABI_IRIX5_64 | ABI_IRIX5_N32, u.u_procp->p_abi));
318 #endif
319 #else /* AFS_SGI61_ENV */
320     use64BitDirent = (auio->uio_segflg != UIO_USERSPACE) ? ABI_IRIX5_64 :
321         (ABI_IS(ABI_IRIX5_64, u.u_procp->p_abi));
322 #endif /* AFS_SGI61_ENV */
323
324     if (use64BitDirent) {
325         struct min_dirent sdirEntry;
326         sdirEntry.d_fileno = (vc->fid.Fid.Volume << 16) + ntohl(de->fid.vnode);
327         FIXUPSTUPIDINODE(sdirEntry.d_fileno);
328         sdirEntry.d_reclen = rlen;
329         sdirEntry.d_off = (off_t)off;
330         AFS_UIOMOVE(&sdirEntry, AFS_DIRENT64BASESIZE, UIO_READ, auio, code);
331         if (code == 0)
332             AFS_UIOMOVE(de->name, slen-1, UIO_READ, auio, code);
333         if (code == 0)
334             AFS_UIOMOVE(bufofzeros,
335                         DIRENTSIZE(slen) - (AFS_DIRENT64BASESIZE + slen - 1),
336                         UIO_READ, auio, code);
337         if (DIRENTSIZE(slen) < rlen) {
338             while(DIRENTSIZE(slen) < rlen) {
339                 int minLen = rlen - DIRENTSIZE(slen);
340                 if (minLen > sizeof(bufofzeros)) minLen = sizeof(bufofzeros);
341                 AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
342                 rlen -= minLen;
343             }
344         }
345     } else {
346         struct irix5_min_dirent sdirEntry;
347         sdirEntry.d_fileno = (vc->fid.Fid.Volume << 16) + ntohl(de->fid.vnode);
348         FIXUPSTUPIDINODE(sdirEntry.d_fileno);
349         sdirEntry.d_reclen = rlen;
350         sdirEntry.d_off = (afs_int32)off;
351         AFS_UIOMOVE(&sdirEntry, AFS_DIRENT32BASESIZE, UIO_READ, auio, code);
352         if (code == 0)
353             AFS_UIOMOVE(de->name, slen-1, UIO_READ, auio, code);
354         if (code == 0)
355             AFS_UIOMOVE(bufofzeros,
356                         IRIX5_DIRENTSIZE(slen) -
357                         (AFS_DIRENT32BASESIZE + slen - 1),
358                            UIO_READ, auio, code);
359         if (IRIX5_DIRENTSIZE(slen) < rlen) {
360             while(IRIX5_DIRENTSIZE(slen) < rlen) {
361                 int minLen = rlen - IRIX5_DIRENTSIZE(slen);
362                 if (minLen > sizeof(bufofzeros)) minLen = sizeof(bufofzeros);
363                 AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
364                 rlen -= minLen;
365             }
366         }
367     }
368 }
369 #else /* AFS_SGI53_ENV */
370 #ifdef  AFS_SUN5_ENV
371 #if     defined(AFS_SUN56_ENV)
372     direntp = (struct dirent64 *) osi_AllocLargeSpace(AFS_LRALLOCSIZ);
373 #else
374     direntp = (struct dirent *) osi_AllocLargeSpace(AFS_LRALLOCSIZ);
375 #endif
376     direntp->d_ino =  (vc->fid.Fid.Volume << 16) + ntohl(de->fid.vnode);
377     FIXUPSTUPIDINODE(direntp->d_ino);
378     direntp->d_off = off;
379     direntp->d_reclen = rlen;
380     strcpy(direntp->d_name, de->name);
381     AFS_UIOMOVE((caddr_t)direntp, rlen, UIO_READ, auio, code);
382     osi_FreeLargeSpace((char *)direntp);
383 #else /* AFS_SUN5_ENV */
384     /* Note the odd mechanism for building the inode number */
385     sdirEntry.d_fileno = (vc->fid.Fid.Volume << 16) +
386       ntohl(de->fid.vnode);
387     FIXUPSTUPIDINODE(sdirEntry.d_fileno);
388     sdirEntry.d_reclen = rlen;
389 #if !defined(AFS_SGI_ENV)
390     sdirEntry.d_namlen = slen;
391 #endif
392 #if defined(AFS_SUN_ENV) || defined(AFS_AIX32_ENV) || defined(AFS_SGI_ENV)
393     sdirEntry.d_off = off;
394 #endif
395 #if defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
396     sdirEntry.d_type=afs_readdir_type(vc, de);
397 #endif
398
399 #if defined(AFS_SGI_ENV)
400     AFS_UIOMOVE(&sdirEntry, DIRENTBASESIZE, UIO_READ, auio, code);
401     if (code == 0)
402         AFS_UIOMOVE(de->name, slen-1, UIO_READ, auio, code);
403     if (code == 0)
404         AFS_UIOMOVE(bufofzeros, DIRSIZ_LEN(slen) - (DIRENTBASESIZE + slen - 1), UIO_READ, auio, code);
405 #else /* AFS_SGI_ENV */
406     AFS_MOVE_UNLOCK();
407     AFS_UIOMOVE((char *)&sdirEntry, sizeof(sdirEntry), UIO_READ, auio, code);
408
409     if (code == 0) {
410         AFS_UIOMOVE(de->name, slen, UIO_READ, auio, code);
411     }
412
413     /* pad out the remaining characters with zeros */
414     if (code == 0) { 
415         AFS_UIOMOVE(bufofzeros, ((slen + 1 + DIRPAD) & ~DIRPAD) - slen, UIO_READ,
416                     auio, code);
417     }
418     AFS_MOVE_LOCK();
419 #endif /* AFS_SGI_ENV */
420
421     /* pad out the difference between rlen and slen... */
422     if (DIRSIZ_LEN(slen) < rlen)
423         {
424         AFS_MOVE_UNLOCK();
425         while(DIRSIZ_LEN(slen) < rlen)
426                 {
427                 int minLen = rlen - DIRSIZ_LEN(slen);
428                 if (minLen > sizeof(bufofzeros))
429                         minLen = sizeof(bufofzeros);
430                 AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
431                 rlen -= minLen;
432                 }
433         AFS_MOVE_LOCK();
434         }
435 #endif  /* AFS_SUN5_ENV */
436 #endif  /* AFS_SGI53_ENV */
437     return(code);
438 }
439
440
441 /*
442  *------------------------------------------------------------------------------
443  *
444  * Read directory entries.
445  * There are some weird things to look out for here.  The uio_offset
446  * field is either 0 or it is the offset returned from a previous
447  * readdir.  It is an opaque value used by the server to find the
448  * correct directory block to read.  The byte count must be at least
449  * vtoblksz(vp) bytes.  The count field is the number of blocks to
450  * read on the server.  This is advisory only, the server may return
451  * only one block's worth of entries.  Entries may be compressed on
452  * the server.
453  *
454  * This routine encodes knowledge of Vice dirs.
455  */
456
457 void afs_bulkstat_send( avc, req )
458     struct vcache * avc;
459     struct vrequest * req;
460 {
461     afs_rd_stash_i = 0;
462 }
463
464 /*
465  * Here is the bad, bad, really bad news.
466  * It has to do with 'offset' (seek locations).
467 */
468
469 #if     defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV) || defined(AFS_OSF_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
470 afs_readdir(OSI_VC_ARG(avc), auio, acred, eofp)
471     int *eofp;
472 #else
473 #if defined(AFS_HPUX100_ENV) 
474 afs_readdir2(OSI_VC_ARG(avc), auio, acred)
475 #else
476 afs_readdir(OSI_VC_ARG(avc), auio, acred)
477 #endif 
478 #endif
479     OSI_VC_DECL(avc);
480     struct uio *auio;
481     struct AFS_UCRED *acred; 
482 {
483     struct vrequest treq;
484     register struct dcache *tdc;
485     afs_size_t origOffset, tlen;
486     afs_int32 len;
487     int code = 0;
488     struct DirEntry *ode = 0, *nde = 0;
489     int o_slen = 0, n_slen = 0;
490     afs_uint32 us;
491     struct afs_fakestat_state fakestate;
492 #if defined(AFS_SGI53_ENV)
493     afs_int32 use64BitDirent, dirsiz;
494 #endif /* defined(AFS_SGI53_ENV) */
495     OSI_VC_CONVERT(avc)
496 #ifdef  AFS_HPUX_ENV
497     /*
498      * XXX All the hacks for alloced sdirEntry and inlining of afs_readdir_move instead of calling
499      * it is necessary for hpux due to stack problems that seem to occur when coming thru the nfs
500      * translator side XXX
501      */
502     struct min_direct *sdirEntry = (struct min_direct *)osi_AllocSmallSpace(sizeof(struct min_direct));
503     afs_int32 rlen;
504 #endif
505
506     /* opaque value is pointer into a vice dir; use bit map to decide
507         if the entries are in use.  Always assumed to be valid.  0 is
508         special, means start of a new dir.  Int32 inode, followed by
509         short reclen and short namelen.  Namelen does not include
510         the null byte.  Followed by null-terminated string.
511     */
512     AFS_STATCNT(afs_readdir);
513
514 #if defined(AFS_SGI53_ENV)
515 #ifdef AFS_SGI61_ENV
516 #ifdef AFS_SGI62_ENV
517     use64BitDirent = ABI_IS(ABI_IRIX5_64,
518                             GETDENTS_ABI(OSI_GET_CURRENT_ABI(), auio));
519 #else
520     use64BitDirent = (auio->uio_segflg != UIO_USERSPACE) ? ABI_IRIX5_64 :
521         (ABI_IS(ABI_IRIX5_64 | ABI_IRIX5_N32, u.u_procp->p_abi));
522 #endif /* AFS_SGI62_ENV */
523 #else /* AFS_SGI61_ENV */
524     use64BitDirent = (auio->uio_segflg != UIO_USERSPACE) ? ABI_IRIX5_64 :
525         (ABI_IS(ABI_IRIX5_64, u.u_procp->p_abi));
526 #endif /* AFS_SGI61_ENV */
527 #endif /* defined(AFS_SGI53_ENV) */
528
529 #if     defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV) || defined(AFS_OSF_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
530     /* Not really used by the callee so we ignore it for now */
531     if (eofp) *eofp = 0;
532 #endif
533     if ( AfsLargeFileUio(auio)                  /* file is large than 2 GB */
534         || AfsLargeFileSize(auio->uio_offset, auio->uio_resid) )
535         return EFBIG;
536
537     if ((code = afs_InitReq(&treq, acred))) {
538 #ifdef  AFS_HPUX_ENV
539         osi_FreeSmallSpace((char *)sdirEntry);
540 #endif
541         return code;
542     }
543     /* update the cache entry */
544     afs_InitFakeStat(&fakestate);
545     code = afs_EvalFakeStat(&avc, &fakestate, &treq);
546     if (code) goto done;
547 tagain:
548     code = afs_VerifyVCache(avc, &treq);
549     if (code) goto done;
550     /* get a reference to the entire directory */
551     tdc = afs_GetDCache(avc, (afs_size_t) 0, &treq, &origOffset, &tlen, 1);
552     len = tlen;
553     if (!tdc) {
554         code = ENOENT;
555         goto done;
556     }
557     ObtainReadLock(&avc->lock);
558     ObtainReadLock(&tdc->lock);
559
560     /*
561      * Make sure that the data in the cache is current. There are two
562      * cases we need to worry about:
563      * 1. The cache data is being fetched by another process.
564      * 2. The cache data is no longer valid
565      */
566     while ((avc->states & CStatd)
567            && (tdc->dflags & DFFetching)
568            && hsame(avc->m.DataVersion, tdc->f.versionNo)) {
569         afs_Trace4(afs_iclSetp, CM_TRACE_DCACHEWAIT,
570                         ICL_TYPE_STRING, __FILE__,
571                         ICL_TYPE_INT32, __LINE__,
572                         ICL_TYPE_POINTER, tdc,
573                         ICL_TYPE_INT32, tdc->dflags);
574         ReleaseReadLock(&tdc->lock);
575         ReleaseReadLock(&avc->lock);
576         afs_osi_Sleep(&tdc->validPos);
577         ObtainReadLock(&avc->lock);
578         ObtainReadLock(&tdc->lock);
579     }
580     if (!(avc->states & CStatd)
581         || !hsame(avc->m.DataVersion, tdc->f.versionNo)) {
582         ReleaseReadLock(&tdc->lock);
583         ReleaseReadLock(&avc->lock);
584         afs_PutDCache(tdc);
585         goto tagain;
586     }
587
588     /*
589      *  iterator for the directory reads.  Takes the AFS DirEntry
590      *  structure and slams them into UFS direct structures.
591      *  uses afs_readdir_move to get the struct to the user space.
592      *
593      *  The routine works by looking ahead one AFS directory entry.
594      *  That's because the AFS entry we are currenly working with
595      *  may not fit into the buffer the user has provided.  If it
596      *  doesn't we have to change the size of the LAST AFS directory
597      *  entry, so that it will FIT perfectly into the block the
598      *  user has provided.
599      *  
600      *  The 'forward looking' of the code makes it a bit tough to read.
601      *  Remember we need to get an entry, see if it it fits, then
602      *  set it up as the LAST entry, and find the next one.
603      *
604      *  Tough to take: We give out an EINVAL if we don't have enough
605      *  space in the buffer, and at the same time, don't have an entry
606      *  to put into the buffer. This CAN happen if the first AFS entry
607      *  we get can't fit into the 512 character buffer provided.  Seems
608      *  it ought not happen... 
609      *
610      *  Assumption: don't need to use anything but one dc entry:
611      *  this means the directory ought not be greater than 64k.
612      */
613     len = 0;
614 #ifdef AFS_HPUX_ENV
615     auio->uio_fpflags = 0;
616 #endif
617     while (code==0) {
618         origOffset = auio->afsio_offset;
619         /* scan for the next interesting entry scan for in-use blob otherwise up point at
620          * this blob note that ode, if non-zero, also represents a held dir page */
621         if (!(us = BlobScan(&tdc->f.inode, (origOffset >> 5)) )
622             || !(nde = (struct DirEntry *) afs_dir_GetBlob(&tdc->f.inode, us) ) ) {
623             /* failed to setup nde, return what we've got, and release ode */
624             if (len) {
625                 /* something to hand over. */
626 #ifdef  AFS_HPUX_ENV
627                 sdirEntry->d_fileno = (avc->fid.Fid.Volume << 16) + ntohl(ode->fid.vnode);
628                 FIXUPSTUPIDINODE(sdirEntry->d_fileno);
629                 sdirEntry->d_reclen = rlen = auio->afsio_resid;
630                 sdirEntry->d_namlen = o_slen;
631 #if defined(AFS_SUN_ENV) || defined(AFS_AIX32_ENV) || defined(AFS_HPUX100_ENV)
632                 sdirEntry->d_off = origOffset;
633 #endif
634                 AFS_UIOMOVE((char *)sdirEntry, sizeof(*sdirEntry), UIO_READ, auio, code);
635                 if (code == 0)
636                     AFS_UIOMOVE(ode->name, o_slen, UIO_READ, auio, code);
637                 /* pad out the remaining characters with zeros */
638                 if (code == 0) {
639                     AFS_UIOMOVE(bufofzeros, ((o_slen + 1 + DIRPAD) & ~DIRPAD) - o_slen, UIO_READ, auio, code);
640                 }
641                 /* pad out the difference between rlen and slen... */
642                 if (DIRSIZ_LEN(o_slen) < rlen) {
643                     while(DIRSIZ_LEN(o_slen) < rlen) {
644                         int minLen = rlen - DIRSIZ_LEN(o_slen);
645                         if (minLen > sizeof(bufofzeros))
646                             minLen = sizeof(bufofzeros);
647                         AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
648                         rlen -= minLen;
649                     }
650                 }
651 #else
652                 code = afs_readdir_move(ode, avc, auio, o_slen,
653 #if defined(AFS_SUN5_ENV)
654                                         len, origOffset);
655 #else
656                                         auio->afsio_resid, origOffset);
657 #endif
658 #endif /* AFS_HPUX_ENV */
659 #if !defined(AFS_SUN5_ENV)
660                 auio->afsio_resid = 0;
661 #endif
662             } else {
663                 /* nothin to hand over */
664             }
665 #if     defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV) || defined(AFS_OSF_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
666         if (eofp) *eofp = 1;    /* Set it properly */
667 #endif
668             if (ode) DRelease((struct buffer *) ode, 0);
669             goto dirend;
670         }
671         /* by here nde is set */
672
673         /* Do we have enough user space to carry out our mission? */
674 #if defined(AFS_SGI_ENV)
675         n_slen = strlen(nde->name) + 1; /* NULL terminate */
676 #else
677         n_slen = strlen(nde->name);
678 #endif
679 #ifdef  AFS_SGI53_ENV
680         dirsiz = use64BitDirent ? DIRENTSIZE(n_slen) :
681             IRIX5_DIRENTSIZE(n_slen);
682         if (dirsiz >= (auio->afsio_resid-len)) {
683 #else
684         if (DIRSIZ_LEN(n_slen) >= (auio->afsio_resid-len)) {
685 #endif /* AFS_SGI53_ENV */
686             /* No can do no more now; ya know... at this time */
687             DRelease ((struct buffer *) nde, 0); /* can't use this one. */
688             if (len) {
689 #ifdef  AFS_HPUX_ENV
690                 sdirEntry->d_fileno = (avc->fid.Fid.Volume << 16) + ntohl(ode->fid.vnode);
691                 FIXUPSTUPIDINODE(sdirEntry->d_fileno);
692                 sdirEntry->d_reclen = rlen = auio->afsio_resid;
693                 sdirEntry->d_namlen = o_slen;
694 #if defined(AFS_SUN_ENV) || defined(AFS_AIX32_ENV) || defined(AFS_HPUX100_ENV)
695                 sdirEntry->d_off = origOffset;
696 #endif
697                 AFS_UIOMOVE((char *)sdirEntry, sizeof(*sdirEntry), UIO_READ, auio, code);
698                 if (code == 0)
699                     AFS_UIOMOVE(ode->name, o_slen, UIO_READ, auio, code);
700                 /* pad out the remaining characters with zeros */
701                 if (code == 0) {
702                     AFS_UIOMOVE(bufofzeros, ((o_slen + 1 + DIRPAD) & ~DIRPAD) - o_slen, UIO_READ, auio, code);
703                 }
704                 /* pad out the difference between rlen and slen... */
705                 if (DIRSIZ_LEN(o_slen) < rlen) {
706                     while(DIRSIZ_LEN(o_slen) < rlen) {
707                         int minLen = rlen - DIRSIZ_LEN(o_slen);
708                         if (minLen > sizeof(bufofzeros))
709                             minLen = sizeof(bufofzeros);
710                         AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
711                         rlen -= minLen;
712                     }
713                 }
714 #else /* AFS_HPUX_ENV */
715                 code = afs_readdir_move(ode, avc, auio, o_slen,
716                                         auio->afsio_resid, origOffset);
717 #endif /* AFS_HPUX_ENV */
718                 /* this next line used to be AFSVFS40 or AIX 3.1, but is
719                  * really generic */
720                 auio->afsio_offset = origOffset;
721                 auio->afsio_resid = 0;  
722             } else { /* trouble, can't give anything to the user! */
723                 /* even though he has given us a buffer, 
724                  * even though we have something to give us,
725                  * Looks like we lost something somewhere.
726                  */
727                 code = EINVAL;
728             }
729             if (ode) DRelease((struct buffer *) ode, 0);
730             goto dirend;
731         }
732
733         /*
734          * In any event, we move out the LAST de entry, getting ready
735          * to set up for the next one.
736          */
737         if (len) {
738 #ifdef  AFS_HPUX_ENV
739             sdirEntry->d_fileno =
740                 (avc->fid.Fid.Volume << 16) + ntohl(ode->fid.vnode);
741             FIXUPSTUPIDINODE(sdirEntry->d_fileno);
742             sdirEntry->d_reclen = rlen = len;
743             sdirEntry->d_namlen = o_slen;
744 #if defined(AFS_SUN_ENV) || defined(AFS_AIX32_ENV) || defined(AFS_HPUX100_ENV)
745             sdirEntry->d_off = origOffset;
746 #endif
747             AFS_UIOMOVE((char *)sdirEntry, sizeof(*sdirEntry), UIO_READ,
748                         auio, code);
749             if (code == 0)
750                 AFS_UIOMOVE(ode->name, o_slen, UIO_READ, auio, code);
751             /* pad out the remaining characters with zeros */
752             if (code == 0) {
753                 AFS_UIOMOVE(bufofzeros, ((o_slen + 1 + DIRPAD) & ~DIRPAD) - o_slen,
754                             UIO_READ, auio, code);
755             }
756             /* pad out the difference between rlen and slen... */
757             if (DIRSIZ_LEN(o_slen) < rlen) {
758                 while(DIRSIZ_LEN(o_slen) < rlen) {
759                     int minLen = rlen - DIRSIZ_LEN(o_slen);
760                     if (minLen > sizeof(bufofzeros))
761                         minLen = sizeof(bufofzeros);
762                     AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
763                     rlen -= minLen;
764                 }
765             }
766 #else /* AFS_HPUX_ENV */
767             code = afs_readdir_move (ode, avc, auio, o_slen, len, origOffset);
768 #endif /* AFS_HPUX_ENV */
769         }
770 #ifdef  AFS_SGI53_ENV
771         len = use64BitDirent ? DIRENTSIZE(o_slen = n_slen) :
772             IRIX5_DIRENTSIZE(o_slen = n_slen);
773 #else
774         len = DIRSIZ_LEN( o_slen = n_slen );
775 #endif /* AFS_SGI53_ENV */
776         if (ode) DRelease((struct buffer *) ode, 0);
777         ode = nde;
778         auio->afsio_offset = (afs_int32)((us + afs_dir_NameBlobs(nde->name)) << 5);
779     }
780     if (ode) DRelease((struct buffer *) ode, 0);
781
782 dirend:
783     ReleaseReadLock(&tdc->lock);
784     afs_PutDCache(tdc);
785     ReleaseReadLock(&avc->lock);
786
787 done:
788 #ifdef  AFS_HPUX_ENV
789     osi_FreeSmallSpace((char *)sdirEntry);
790 #endif
791     afs_PutFakeStat(&fakestate);
792     code = afs_CheckCode(code, &treq, 28);
793     return code;
794 }
795
796 #if     defined(AFS_HPUX_ENV) || defined(AFS_OSF_ENV)
797 #ifdef  AFS_OSF_ENV
798 afs1_readdir(avc, auio, acred, eofp)
799     int *eofp;
800 #else
801 afs1_readdir(avc, auio, acred)
802 #endif
803     struct vcache *avc;
804     struct uio *auio;
805     struct AFS_UCRED *acred; {
806     struct vrequest treq;
807     register struct dcache *tdc;
808     afs_size_t origOffset, len;
809     int code = 0;
810     struct DirEntry *ode = 0, *nde = 0;
811     int o_slen = 0, n_slen = 0;
812     afs_uint32 us;
813 #if     defined(AFS_HPUX_ENV) || defined(AFS_OSF_ENV)
814     /*
815      * XXX All the hacks for alloced sdirEntry and inlining of afs_readdir_move instead of calling
816      * it is necessary for hpux due to stack problems that seem to occur when coming thru the nfs
817      * translator side XXX
818      */
819     struct minnfs_direct *sdirEntry = (struct minnfs_direct *)osi_AllocSmallSpace(sizeof(struct min_direct));
820     afs_int32 rlen;
821 #endif
822     struct afs_fakestat_state fakestate;
823
824     AFS_STATCNT(afs_readdir);
825 #if     defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV) || defined(AFS_OSF_ENV)
826     if (eofp) *eofp = 0;
827 #endif
828     if (code = afs_InitReq(&treq, acred)) {
829 #ifdef  AFS_HPUX_ENV
830         osi_FreeSmallSpace((char *)sdirEntry);
831 #endif
832         return code;
833     }
834     afs_InitFakeStat(&fakestate);
835     code = afs_EvalFakeStat(&avc, &fakestate, &treq);
836     if (code) {
837 #ifdef  AFS_HPUX_ENV
838         osi_FreeSmallSpace((char *)sdirEntry);
839 #endif
840         afs_PutFakeStat(&fakestate);
841         return code;
842     }
843     /* update the cache entry */
844 tagain:
845     code = afs_VerifyVCache(avc, &treq);
846     if (code) goto done;
847     /* get a reference to the entire directory */
848     tdc = afs_GetDCache(avc, (afs_size_t) 0, &treq, &origOffset, &len, 1);
849     if (!tdc) {
850         code = ENOENT;
851         goto done;
852     }
853     ObtainReadLock(&avc->lock);
854     ObtainReadLock(&tdc->lock);
855
856     /*
857      * Make sure that the data in the cache is current. There are two
858      * cases we need to worry about:
859      * 1. The cache data is being fetched by another process.
860      * 2. The cache data is no longer valid
861      */
862     while ((avc->states & CStatd)
863            && (tdc->dflags & DFFetching)
864            && hsame(avc->m.DataVersion, tdc->f.versionNo)) {
865         afs_Trace4(afs_iclSetp, CM_TRACE_DCACHEWAIT,
866                         ICL_TYPE_STRING, __FILE__,
867                         ICL_TYPE_INT32, __LINE__,
868                         ICL_TYPE_POINTER, tdc,
869                         ICL_TYPE_INT32, tdc->dflags);
870         ReleaseReadLock(&tdc->lock);
871         ReleaseReadLock(&avc->lock);
872         afs_osi_Sleep(&tdc->validPos);
873         ObtainReadLock(&avc->lock);
874         ObtainReadLock(&tdc->lock);
875     }
876     if (!(avc->states & CStatd)
877         || !hsame(avc->m.DataVersion, tdc->f.versionNo)) {
878         ReleaseReadLock(&tdc->lock);
879         ReleaseReadLock(&avc->lock);
880         afs_PutDCache(tdc);
881         goto tagain;
882     }
883
884     len = 0;
885 #ifdef AFS_HPUX_ENV
886     auio->uio_fpflags = 0;
887 #endif
888     while (code==0) {
889         origOffset = auio->afsio_offset;
890
891         /* scan for the next interesting entry scan for in-use blob otherwise up point at
892          * this blob note that ode, if non-zero, also represents a held dir page */
893         if (!(us = BlobScan(&tdc->f.inode, (origOffset >> 5)) )
894             || !(nde = (struct DirEntry *) afs_dir_GetBlob(&tdc->f.inode, us) ) ) {
895             /* failed to setup nde, return what we've got, and release ode */
896             if (len) {
897                 /* something to hand over. */
898 #if     defined(AFS_HPUX_ENV) || defined(AFS_OSF_ENV)
899                 sdirEntry->d_fileno = (avc->fid.Fid.Volume << 16) + ntohl(ode->fid.vnode);
900                 FIXUPSTUPIDINODE(sdirEntry->d_fileno);
901                 sdirEntry->d_reclen = rlen = auio->afsio_resid;
902                 sdirEntry->d_namlen = o_slen;
903                 sdirEntry->d_off = origOffset;
904                 AFS_UIOMOVE((char *)sdirEntry, sizeof(*sdirEntry), UIO_READ, auio, code);
905                 if (code == 0) {
906                     AFS_UIOMOVE(ode->name, o_slen, UIO_READ, auio, code);
907                 }
908                 /* pad out the remaining characters with zeros */
909                 if (code == 0) {
910                     AFS_UIOMOVE(bufofzeros, ((o_slen + 1 + DIRPAD) & ~DIRPAD) - o_slen, UIO_READ, auio, code);
911                 }
912                 /* pad out the difference between rlen and slen... */
913                 if (NDIRSIZ_LEN(o_slen) < rlen) {
914                     while(NDIRSIZ_LEN(o_slen) < rlen) {
915                         int minLen = rlen - NDIRSIZ_LEN(o_slen);
916                         if (minLen > sizeof(bufofzeros))
917                             minLen = sizeof(bufofzeros);
918                         AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
919                         rlen -= minLen;
920                     }
921                 }
922 #else
923                 code = afs_readdir_move(ode, avc, auio, o_slen,
924                                         auio->afsio_resid, origOffset);
925 #endif /* AFS_HPUX_ENV */
926                 auio->afsio_resid = 0;  
927             } else {
928                 /* nothin to hand over */
929             }
930 #if defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV) || defined(AFS_OSF_ENV)
931         if (eofp) *eofp = 1;
932 #endif
933         if (ode) DRelease(ode, 0);
934             goto dirend;
935         }
936         /* by here nde is set */
937
938         /* Do we have enough user space to carry out our mission? */
939 #if defined(AFS_SGI_ENV)
940         n_slen = strlen(nde->name) + 1; /* NULL terminate */
941 #else
942         n_slen = strlen(nde->name);
943 #endif
944         if (NDIRSIZ_LEN(n_slen) >= (auio->afsio_resid-len)) {
945             /* No can do no more now; ya know... at this time */
946             DRelease (nde, 0); /* can't use this one. */
947             if (len) {
948 #if     defined(AFS_HPUX_ENV) || defined(AFS_OSF_ENV)
949                 sdirEntry->d_fileno = (avc->fid.Fid.Volume << 16) + ntohl(ode->fid.vnode);
950                 FIXUPSTUPIDINODE(sdirEntry->d_fileno);
951                 sdirEntry->d_reclen = rlen = auio->afsio_resid;
952                 sdirEntry->d_namlen = o_slen;
953                 sdirEntry->d_off = origOffset;
954                 AFS_UIOMOVE((char *)sdirEntry, sizeof(*sdirEntry), UIO_READ, auio, code);
955                 if (code == 0)
956                     AFS_UIOMOVE(ode->name, o_slen, UIO_READ, auio, code);
957                 /* pad out the remaining characters with zeros */
958                 if (code == 0) {
959                     AFS_UIOMOVE(bufofzeros, ((o_slen + 1 + DIRPAD) & ~DIRPAD) - o_slen, UIO_READ, auio, code);
960                 }
961                 /* pad out the difference between rlen and slen... */
962                 if (NDIRSIZ_LEN(o_slen) < rlen) {
963                     while(NDIRSIZ_LEN(o_slen) < rlen) {
964                         int minLen = rlen - NDIRSIZ_LEN(o_slen);
965                         if (minLen > sizeof(bufofzeros))
966                             minLen = sizeof(bufofzeros);
967                         AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
968                         rlen -= minLen;
969                     }
970                 }
971 #else
972                 code = afs_readdir_move(ode, avc, auio, o_slen,
973                                 auio->afsio_resid, origOffset);
974 #endif /* AFS_HPUX_ENV */
975                 /* this next line used to be AFSVFS40 or AIX 3.1, but is really generic */
976                 auio->afsio_offset = origOffset;
977                 auio->afsio_resid = 0;  
978             } else { /* trouble, can't give anything to the user! */
979                 /* even though he has given us a buffer, 
980                  * even though we have something to give us,
981                  * Looks like we lost something somewhere.
982                  */
983                 code = EINVAL;
984             }
985             if (ode) DRelease(ode, 0);
986             goto dirend;
987         }
988
989         /*
990          * In any event, we move out the LAST de entry, getting ready
991          * to set up for the next one.
992          */
993         if (len) {
994 #if     defined(AFS_HPUX_ENV) || defined(AFS_OSF_ENV)
995             sdirEntry->d_fileno = (avc->fid.Fid.Volume << 16) + ntohl(ode->fid.vnode);
996             FIXUPSTUPIDINODE(sdirEntry->d_fileno);
997             sdirEntry->d_reclen = rlen = len;
998             sdirEntry->d_namlen = o_slen;
999             sdirEntry->d_off = origOffset;
1000             AFS_UIOMOVE((char *)sdirEntry, sizeof(*sdirEntry), UIO_READ, auio, code);
1001             if (code == 0)
1002                 AFS_UIOMOVE(ode->name, o_slen, UIO_READ, auio, code);
1003             /* pad out the remaining characters with zeros */
1004             if (code == 0) {
1005                 AFS_UIOMOVE(bufofzeros, ((o_slen + 1 + DIRPAD) & ~DIRPAD) - o_slen, UIO_READ, auio, code);
1006             }
1007             /* pad out the difference between rlen and slen... */
1008             if (NDIRSIZ_LEN(o_slen) < rlen) {
1009                 while(NDIRSIZ_LEN(o_slen) < rlen) {
1010                     int minLen = rlen - NDIRSIZ_LEN(o_slen);
1011                     if (minLen > sizeof(bufofzeros))
1012                         minLen = sizeof(bufofzeros);
1013                     AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
1014                     rlen -= minLen;
1015                 }
1016             }
1017 #else
1018             code = afs_readdir_move (ode, avc, auio, o_slen, len, origOffset);
1019 #endif /* AFS_HPUX_ENV */
1020         }
1021         len = NDIRSIZ_LEN( o_slen = n_slen );
1022         if (ode) DRelease(ode, 0);
1023         ode = nde;
1024         auio->afsio_offset = ((us + afs_dir_NameBlobs(nde->name)) << 5);
1025     }
1026     if (ode) DRelease(ode, 0);
1027
1028 dirend:
1029     ReleaseReadLock(&tdc->lock);
1030     afs_PutDCache(tdc);
1031     ReleaseReadLock(&avc->lock);
1032
1033 done:
1034 #if     defined(AFS_HPUX_ENV) || defined(AFS_OSF_ENV)
1035     osi_FreeSmallSpace((char *)sdirEntry);
1036 #endif
1037     afs_PutFakeStat(&fakestate);
1038     code = afs_CheckCode(code, &treq, 29);
1039     return code;
1040 }
1041
1042 #endif
1043 #endif /* !AFS_LINUX20_ENV */