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