71b86fea00efbed38bc60a8ec93a9d80c62a839e
[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 #if defined(AFS_SGI53_ENV)
487     afs_int32 use64BitDirent;
488 #endif /* defined(AFS_SGI53_ENV) */
489     OSI_VC_CONVERT(avc)
490 #ifdef  AFS_HPUX_ENV
491     /*
492      * XXX All the hacks for alloced sdirEntry and inlining of afs_readdir_move instead of calling
493      * it is necessary for hpux due to stack problems that seem to occur when coming thru the nfs
494      * translator side XXX
495      */
496     struct min_direct *sdirEntry = (struct min_direct *)osi_AllocSmallSpace(sizeof(struct min_direct));
497     afs_int32 rlen;
498 #endif
499
500     /* opaque value is pointer into a vice dir; use bit map to decide
501         if the entries are in use.  Always assumed to be valid.  0 is
502         special, means start of a new dir.  Int32 inode, followed by
503         short reclen and short namelen.  Namelen does not include
504         the null byte.  Followed by null-terminated string.
505     */
506     AFS_STATCNT(afs_readdir);
507
508 #if defined(AFS_SGI53_ENV)
509 #ifdef AFS_SGI61_ENV
510 #ifdef AFS_SGI62_ENV
511     use64BitDirent = ABI_IS(ABI_IRIX5_64,
512                             GETDENTS_ABI(OSI_GET_CURRENT_ABI(), auio));
513 #else
514     use64BitDirent = (auio->uio_segflg != UIO_USERSPACE) ? ABI_IRIX5_64 :
515         (ABI_IS(ABI_IRIX5_64 | ABI_IRIX5_N32, u.u_procp->p_abi));
516 #endif /* AFS_SGI62_ENV */
517 #else /* AFS_SGI61_ENV */
518     use64BitDirent = (auio->uio_segflg != UIO_USERSPACE) ? ABI_IRIX5_64 :
519         (ABI_IS(ABI_IRIX5_64, u.u_procp->p_abi));
520 #endif /* AFS_SGI61_ENV */
521 #endif /* defined(AFS_SGI53_ENV) */
522
523 #if     defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV) || defined(AFS_OSF_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV)
524     /* Not really used by the callee so we ignore it for now */
525     if (eofp) *eofp = 0;
526 #endif
527     if ( AfsLargeFileUio(auio)                  /* file is large than 2 GB */
528         || AfsLargeFileSize(auio->uio_offset, auio->uio_resid) )
529         return EFBIG;
530
531     if (code = afs_InitReq(&treq, acred)) {
532 #ifdef  AFS_HPUX_ENV
533         osi_FreeSmallSpace((char *)sdirEntry);
534 #endif
535         return code;
536     }
537     /* update the cache entry */
538 tagain:
539     code = afs_VerifyVCache(avc, &treq);
540     if (code) goto done;
541     /* get a reference to the entire directory */
542     tdc = afs_GetDCache(avc, (afs_size_t) 0, &treq, &origOffset, &tlen, 1);
543     len = tlen;
544     if (!tdc) {
545         code = ENOENT;
546         goto done;
547     }
548     ObtainReadLock(&avc->lock);
549     ObtainReadLock(&tdc->lock);
550
551     /*
552      * Make sure that the data in the cache is current. There are two
553      * cases we need to worry about:
554      * 1. The cache data is being fetched by another process.
555      * 2. The cache data is no longer valid
556      */
557     while ((avc->states & CStatd)
558            && (tdc->dflags & DFFetching)
559            && hsame(avc->m.DataVersion, tdc->f.versionNo)) {
560         afs_Trace4(afs_iclSetp, CM_TRACE_DCACHEWAIT,
561                         ICL_TYPE_STRING, __FILE__,
562                         ICL_TYPE_INT32, __LINE__,
563                         ICL_TYPE_POINTER, tdc,
564                         ICL_TYPE_INT32, tdc->dflags);
565         ReleaseReadLock(&tdc->lock);
566         ReleaseReadLock(&avc->lock);
567         afs_osi_Sleep(&tdc->validPos);
568         ObtainReadLock(&avc->lock);
569         ObtainReadLock(&tdc->lock);
570     }
571     if (!(avc->states & CStatd)
572         || !hsame(avc->m.DataVersion, tdc->f.versionNo)) {
573         ReleaseReadLock(&tdc->lock);
574         ReleaseReadLock(&avc->lock);
575         afs_PutDCache(tdc);
576         goto tagain;
577     }
578
579     /*
580      *  iterator for the directory reads.  Takes the AFS DirEntry
581      *  structure and slams them into UFS direct structures.
582      *  uses afs_readdir_move to get the struct to the user space.
583      *
584      *  The routine works by looking ahead one AFS directory entry.
585      *  That's because the AFS entry we are currenly working with
586      *  may not fit into the buffer the user has provided.  If it
587      *  doesn't we have to change the size of the LAST AFS directory
588      *  entry, so that it will FIT perfectly into the block the
589      *  user has provided.
590      *  
591      *  The 'forward looking' of the code makes it a bit tough to read.
592      *  Remember we need to get an entry, see if it it fits, then
593      *  set it up as the LAST entry, and find the next one.
594      *
595      *  Tough to take: We give out an EINVAL if we don't have enough
596      *  space in the buffer, and at the same time, don't have an entry
597      *  to put into the buffer. This CAN happen if the first AFS entry
598      *  we get can't fit into the 512 character buffer provided.  Seems
599      *  it ought not happen... 
600      *
601      *  Assumption: don't need to use anything but one dc entry:
602      *  this means the directory ought not be greater than 64k.
603      */
604     len = 0;
605 #ifdef AFS_HPUX_ENV
606     auio->uio_fpflags = 0;
607 #endif
608     while (code==0) {
609         origOffset = auio->afsio_offset;
610         /* scan for the next interesting entry scan for in-use blob otherwise up point at
611          * this blob note that ode, if non-zero, also represents a held dir page */
612         if (!(us = BlobScan(&tdc->f.inode, (origOffset >> 5)) )
613             || !(nde = (struct DirEntry *) afs_dir_GetBlob(&tdc->f.inode, us) ) ) {
614             /* failed to setup nde, return what we've got, and release ode */
615             if (len) {
616                 /* something to hand over. */
617 #ifdef  AFS_HPUX_ENV
618                 sdirEntry->d_fileno = (avc->fid.Fid.Volume << 16) + ntohl(ode->fid.vnode);
619                 FIXUPSTUPIDINODE(sdirEntry->d_fileno);
620                 sdirEntry->d_reclen = rlen = auio->afsio_resid;
621                 sdirEntry->d_namlen = o_slen;
622 #if defined(AFS_SUN_ENV) || defined(AFS_AIX32_ENV) || defined(AFS_HPUX100_ENV)
623                 sdirEntry->d_off = origOffset;
624 #endif
625                 AFS_UIOMOVE((char *)sdirEntry, sizeof(*sdirEntry), UIO_READ, auio, code);
626                 if (code == 0)
627                     AFS_UIOMOVE(ode->name, o_slen, UIO_READ, auio, code);
628                 /* pad out the remaining characters with zeros */
629                 if (code == 0) {
630                     AFS_UIOMOVE(bufofzeros, ((o_slen + 4) & ~3) - o_slen, UIO_READ, auio, code);
631                 }
632                 /* pad out the difference between rlen and slen... */
633                 if (DIRSIZ_LEN(o_slen) < rlen) {
634                     while(DIRSIZ_LEN(o_slen) < rlen) {
635                         int minLen = rlen - DIRSIZ_LEN(o_slen);
636                         if (minLen > sizeof(bufofzeros))
637                             minLen = sizeof(bufofzeros);
638                         AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
639                         rlen -= minLen;
640                     }
641                 }
642 #else
643                 code = afs_readdir_move(ode, avc, auio, o_slen,
644 #if defined(AFS_SUN5_ENV)
645                                         len, origOffset);
646 #else
647                                         auio->afsio_resid, origOffset);
648 #endif
649 #endif /* AFS_HPUX_ENV */
650 #if !defined(AFS_SUN5_ENV)
651                 auio->afsio_resid = 0;
652 #endif
653             } else {
654                 /* nothin to hand over */
655             }
656 #if     defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV) || defined(AFS_OSF_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV)
657         if (eofp) *eofp = 1;    /* Set it properly */
658 #endif
659             if (ode) DRelease(ode, 0);
660             goto dirend;
661         }
662         /* by here nde is set */
663
664         /* Do we have enough user space to carry out our mission? */
665 #if defined(AFS_SGI_ENV)
666         n_slen = strlen(nde->name) + 1; /* NULL terminate */
667 #else
668         n_slen = strlen(nde->name);
669 #endif
670 #ifdef  AFS_SGI53_ENV
671         dirsiz = use64BitDirent ? DIRENTSIZE(n_slen) :
672             IRIX5_DIRENTSIZE(n_slen);
673         if (dirsiz >= (auio->afsio_resid-len)) {
674 #else
675         if (DIRSIZ_LEN(n_slen) >= (auio->afsio_resid-len)) {
676 #endif /* AFS_SGI53_ENV */
677             /* No can do no more now; ya know... at this time */
678             DRelease (nde, 0); /* can't use this one. */
679             if (len) {
680 #ifdef  AFS_HPUX_ENV
681                 sdirEntry->d_fileno = (avc->fid.Fid.Volume << 16) + ntohl(ode->fid.vnode);
682                 FIXUPSTUPIDINODE(sdirEntry->d_fileno);
683                 sdirEntry->d_reclen = rlen = auio->afsio_resid;
684                 sdirEntry->d_namlen = o_slen;
685 #if defined(AFS_SUN_ENV) || defined(AFS_AIX32_ENV) || defined(AFS_HPUX100_ENV)
686                 sdirEntry->d_off = origOffset;
687 #endif
688                 AFS_UIOMOVE((char *)sdirEntry, sizeof(*sdirEntry), UIO_READ, auio, code);
689                 if (code == 0)
690                     AFS_UIOMOVE(ode->name, o_slen, UIO_READ, auio, code);
691                 /* pad out the remaining characters with zeros */
692                 if (code == 0) {
693                     AFS_UIOMOVE(bufofzeros, ((o_slen + 4) & ~3) - o_slen, UIO_READ, auio, code);
694                 }
695                 /* pad out the difference between rlen and slen... */
696                 if (DIRSIZ_LEN(o_slen) < rlen) {
697                     while(DIRSIZ_LEN(o_slen) < rlen) {
698                         int minLen = rlen - DIRSIZ_LEN(o_slen);
699                         if (minLen > sizeof(bufofzeros))
700                             minLen = sizeof(bufofzeros);
701                         AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
702                         rlen -= minLen;
703                     }
704                 }
705 #else /* AFS_HPUX_ENV */
706                 code = afs_readdir_move(ode, avc, auio, o_slen,
707                                         auio->afsio_resid, origOffset);
708 #endif /* AFS_HPUX_ENV */
709                 /* this next line used to be AFSVFS40 or AIX 3.1, but is
710                  * really generic */
711                 auio->afsio_offset = origOffset;
712                 auio->afsio_resid = 0;  
713             } else { /* trouble, can't give anything to the user! */
714                 /* even though he has given us a buffer, 
715                  * even though we have something to give us,
716                  * Looks like we lost something somewhere.
717                  */
718                 code = EINVAL;
719             }
720             if (ode) DRelease(ode, 0);
721             goto dirend;
722         }
723
724         /*
725          * In any event, we move out the LAST de entry, getting ready
726          * to set up for the next one.
727          */
728         if (len) {
729 #ifdef  AFS_HPUX_ENV
730             sdirEntry->d_fileno =
731                 (avc->fid.Fid.Volume << 16) + ntohl(ode->fid.vnode);
732             FIXUPSTUPIDINODE(sdirEntry->d_fileno);
733             sdirEntry->d_reclen = rlen = len;
734             sdirEntry->d_namlen = o_slen;
735 #if defined(AFS_SUN_ENV) || defined(AFS_AIX32_ENV) || defined(AFS_HPUX100_ENV)
736             sdirEntry->d_off = origOffset;
737 #endif
738             AFS_UIOMOVE((char *)sdirEntry, sizeof(*sdirEntry), UIO_READ,
739                         auio, code);
740             if (code == 0)
741                 AFS_UIOMOVE(ode->name, o_slen, UIO_READ, auio, code);
742             /* pad out the remaining characters with zeros */
743             if (code == 0) {
744                 AFS_UIOMOVE(bufofzeros, ((o_slen + 4) & ~3) - o_slen,
745                             UIO_READ, auio, code);
746             }
747             /* pad out the difference between rlen and slen... */
748             if (DIRSIZ_LEN(o_slen) < rlen) {
749                 while(DIRSIZ_LEN(o_slen) < rlen) {
750                     int minLen = rlen - DIRSIZ_LEN(o_slen);
751                     if (minLen > sizeof(bufofzeros))
752                         minLen = sizeof(bufofzeros);
753                     AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
754                     rlen -= minLen;
755                 }
756             }
757 #else /* AFS_HPUX_ENV */
758             code = afs_readdir_move (ode, avc, auio, o_slen, len, origOffset);
759 #endif /* AFS_HPUX_ENV */
760         }
761 #ifdef  AFS_SGI53_ENV
762         len = use64BitDirent ? DIRENTSIZE(o_slen = n_slen) :
763             IRIX5_DIRENTSIZE(o_slen = n_slen);
764 #else
765         len = DIRSIZ_LEN( o_slen = n_slen );
766 #endif /* AFS_SGI53_ENV */
767         if (ode) DRelease(ode, 0);
768         ode = nde;
769         auio->afsio_offset = (afs_int32)((us + afs_dir_NameBlobs(nde->name)) << 5);
770     }
771     if (ode) DRelease(ode, 0);
772
773 dirend:
774     ReleaseReadLock(&tdc->lock);
775     afs_PutDCache(tdc);
776     ReleaseReadLock(&avc->lock);
777
778 done:
779 #ifdef  AFS_HPUX_ENV
780     osi_FreeSmallSpace((char *)sdirEntry);
781 #endif
782     code = afs_CheckCode(code, &treq, 28);
783     return code;
784 }
785
786 #if     defined(AFS_HPUX_ENV) || defined(AFS_OSF_ENV)
787 #ifdef  AFS_OSF_ENV
788 afs1_readdir(avc, auio, acred, eofp)
789     int *eofp;
790 #else
791 afs1_readdir(avc, auio, acred)
792 #endif
793     register struct vcache *avc;
794     struct uio *auio;
795     struct AFS_UCRED *acred; {
796     struct vrequest treq;
797     register struct dcache *tdc;
798     afs_size_t origOffset, len;
799     int code = 0;
800     struct DirEntry *ode = 0, *nde = 0;
801     int o_slen = 0, n_slen = 0;
802     afs_uint32 us;
803 #if     defined(AFS_HPUX_ENV) || defined(AFS_OSF_ENV)
804     /*
805      * XXX All the hacks for alloced sdirEntry and inlining of afs_readdir_move instead of calling
806      * it is necessary for hpux due to stack problems that seem to occur when coming thru the nfs
807      * translator side XXX
808      */
809     struct minnfs_direct *sdirEntry = (struct minnfs_direct *)osi_AllocSmallSpace(sizeof(struct min_direct));
810     afs_int32 rlen;
811 #endif
812
813     AFS_STATCNT(afs_readdir);
814 #if     defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV) || defined(AFS_OSF_ENV)
815     if (eofp) *eofp = 0;
816 #endif
817     if (code = afs_InitReq(&treq, acred)) {
818 #ifdef  AFS_HPUX_ENV
819         osi_FreeSmallSpace((char *)sdirEntry);
820 #endif
821         return code;
822     }
823     /* update the cache entry */
824 tagain:
825     code = afs_VerifyVCache(avc, &treq);
826     if (code) goto done;
827     /* get a reference to the entire directory */
828     tdc = afs_GetDCache(avc, (afs_size_t) 0, &treq, &origOffset, &len, 1);
829     if (!tdc) {
830         code = ENOENT;
831         goto done;
832     }
833     ObtainReadLock(&avc->lock);
834     ObtainReadLock(&tdc->lock);
835
836     /*
837      * Make sure that the data in the cache is current. There are two
838      * cases we need to worry about:
839      * 1. The cache data is being fetched by another process.
840      * 2. The cache data is no longer valid
841      */
842     while ((avc->states & CStatd)
843            && (tdc->dflags & DFFetching)
844            && hsame(avc->m.DataVersion, tdc->f.versionNo)) {
845         afs_Trace4(afs_iclSetp, CM_TRACE_DCACHEWAIT,
846                         ICL_TYPE_STRING, __FILE__,
847                         ICL_TYPE_INT32, __LINE__,
848                         ICL_TYPE_POINTER, tdc,
849                         ICL_TYPE_INT32, tdc->dflags);
850         ReleaseReadLock(&tdc->lock);
851         ReleaseReadLock(&avc->lock);
852         afs_osi_Sleep(&tdc->validPos);
853         ObtainReadLock(&avc->lock);
854         ObtainReadLock(&tdc->lock);
855     }
856     if (!(avc->states & CStatd)
857         || !hsame(avc->m.DataVersion, tdc->f.versionNo)) {
858         ReleaseReadLock(&tdc->lock);
859         ReleaseReadLock(&avc->lock);
860         afs_PutDCache(tdc);
861         goto tagain;
862     }
863
864     len = 0;
865 #ifdef AFS_HPUX_ENV
866     auio->uio_fpflags = 0;
867 #endif
868     while (code==0) {
869         origOffset = auio->afsio_offset;
870
871         /* scan for the next interesting entry scan for in-use blob otherwise up point at
872          * this blob note that ode, if non-zero, also represents a held dir page */
873         if (!(us = BlobScan(&tdc->f.inode, (origOffset >> 5)) )
874             || !(nde = (struct DirEntry *) afs_dir_GetBlob(&tdc->f.inode, us) ) ) {
875             /* failed to setup nde, return what we've got, and release ode */
876             if (len) {
877                 /* something to hand over. */
878 #if     defined(AFS_HPUX_ENV) || defined(AFS_OSF_ENV)
879                 sdirEntry->d_fileno = (avc->fid.Fid.Volume << 16) + ntohl(ode->fid.vnode);
880                 FIXUPSTUPIDINODE(sdirEntry->d_fileno);
881                 sdirEntry->d_reclen = rlen = auio->afsio_resid;
882                 sdirEntry->d_namlen = o_slen;
883                 sdirEntry->d_off = origOffset;
884                 AFS_UIOMOVE((char *)sdirEntry, sizeof(*sdirEntry), UIO_READ, auio, code);
885                 if (code == 0) {
886                     AFS_UIOMOVE(ode->name, o_slen, UIO_READ, auio, code);
887                 }
888                 /* pad out the remaining characters with zeros */
889                 if (code == 0) {
890                     AFS_UIOMOVE(bufofzeros, ((o_slen + 4) & ~3) - o_slen, UIO_READ, auio, code);
891                 }
892                 /* pad out the difference between rlen and slen... */
893                 if (NDIRSIZ_LEN(o_slen) < rlen) {
894                     while(NDIRSIZ_LEN(o_slen) < rlen) {
895                         int minLen = rlen - NDIRSIZ_LEN(o_slen);
896                         if (minLen > sizeof(bufofzeros))
897                             minLen = sizeof(bufofzeros);
898                         AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
899                         rlen -= minLen;
900                     }
901                 }
902 #else
903                 code = afs_readdir_move(ode, avc, auio, o_slen,
904                                         auio->afsio_resid, origOffset);
905 #endif /* AFS_HPUX_ENV */
906                 auio->afsio_resid = 0;  
907             } else {
908                 /* nothin to hand over */
909             }
910 #if defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV) || defined(AFS_OSF_ENV)
911         if (eofp) *eofp = 1;
912 #endif
913         if (ode) DRelease(ode, 0);
914             goto dirend;
915         }
916         /* by here nde is set */
917
918         /* Do we have enough user space to carry out our mission? */
919 #if defined(AFS_SGI_ENV)
920         n_slen = strlen(nde->name) + 1; /* NULL terminate */
921 #else
922         n_slen = strlen(nde->name);
923 #endif
924         if (NDIRSIZ_LEN(n_slen) >= (auio->afsio_resid-len)) {
925             /* No can do no more now; ya know... at this time */
926             DRelease (nde, 0); /* can't use this one. */
927             if (len) {
928 #if     defined(AFS_HPUX_ENV) || defined(AFS_OSF_ENV)
929                 sdirEntry->d_fileno = (avc->fid.Fid.Volume << 16) + ntohl(ode->fid.vnode);
930                 FIXUPSTUPIDINODE(sdirEntry->d_fileno);
931                 sdirEntry->d_reclen = rlen = auio->afsio_resid;
932                 sdirEntry->d_namlen = o_slen;
933                 sdirEntry->d_off = origOffset;
934                 AFS_UIOMOVE((char *)sdirEntry, sizeof(*sdirEntry), UIO_READ, auio, code);
935                 if (code == 0)
936                     AFS_UIOMOVE(ode->name, o_slen, UIO_READ, auio, code);
937                 /* pad out the remaining characters with zeros */
938                 if (code == 0) {
939                     AFS_UIOMOVE(bufofzeros, ((o_slen + 4) & ~3) - o_slen, UIO_READ, auio, code);
940                 }
941                 /* pad out the difference between rlen and slen... */
942                 if (NDIRSIZ_LEN(o_slen) < rlen) {
943                     while(NDIRSIZ_LEN(o_slen) < rlen) {
944                         int minLen = rlen - NDIRSIZ_LEN(o_slen);
945                         if (minLen > sizeof(bufofzeros))
946                             minLen = sizeof(bufofzeros);
947                         AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
948                         rlen -= minLen;
949                     }
950                 }
951 #else
952                 code = afs_readdir_move(ode, avc, auio, o_slen,
953                                 auio->afsio_resid, origOffset);
954 #endif /* AFS_HPUX_ENV */
955                 /* this next line used to be AFSVFS40 or AIX 3.1, but is really generic */
956                 auio->afsio_offset = origOffset;
957                 auio->afsio_resid = 0;  
958             } else { /* trouble, can't give anything to the user! */
959                 /* even though he has given us a buffer, 
960                  * even though we have something to give us,
961                  * Looks like we lost something somewhere.
962                  */
963                 code = EINVAL;
964             }
965             if (ode) DRelease(ode, 0);
966             goto dirend;
967         }
968
969         /*
970          * In any event, we move out the LAST de entry, getting ready
971          * to set up for the next one.
972          */
973         if (len) {
974 #if     defined(AFS_HPUX_ENV) || defined(AFS_OSF_ENV)
975             sdirEntry->d_fileno = (avc->fid.Fid.Volume << 16) + ntohl(ode->fid.vnode);
976             FIXUPSTUPIDINODE(sdirEntry->d_fileno);
977             sdirEntry->d_reclen = rlen = len;
978             sdirEntry->d_namlen = o_slen;
979             sdirEntry->d_off = origOffset;
980             AFS_UIOMOVE((char *)sdirEntry, sizeof(*sdirEntry), UIO_READ, auio, code);
981             if (code == 0)
982                 AFS_UIOMOVE(ode->name, o_slen, UIO_READ, auio, code);
983             /* pad out the remaining characters with zeros */
984             if (code == 0) {
985                 AFS_UIOMOVE(bufofzeros, ((o_slen + 4) & ~3) - o_slen, UIO_READ, auio, code);
986             }
987             /* pad out the difference between rlen and slen... */
988             if (NDIRSIZ_LEN(o_slen) < rlen) {
989                 while(NDIRSIZ_LEN(o_slen) < rlen) {
990                     int minLen = rlen - NDIRSIZ_LEN(o_slen);
991                     if (minLen > sizeof(bufofzeros))
992                         minLen = sizeof(bufofzeros);
993                     AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
994                     rlen -= minLen;
995                 }
996             }
997 #else
998             code = afs_readdir_move (ode, avc, auio, o_slen, len, origOffset);
999 #endif /* AFS_HPUX_ENV */
1000         }
1001         len = NDIRSIZ_LEN( o_slen = n_slen );
1002         if (ode) DRelease(ode, 0);
1003         ode = nde;
1004         auio->afsio_offset = ((us + afs_dir_NameBlobs(nde->name)) << 5);
1005     }
1006     if (ode) DRelease(ode, 0);
1007
1008 dirend:
1009     ReleaseReadLock(&tdc->lock);
1010     afs_PutDCache(tdc);
1011     ReleaseReadLock(&avc->lock);
1012
1013 done:
1014 #if     defined(AFS_HPUX_ENV) || defined(AFS_OSF_ENV)
1015     osi_FreeSmallSpace((char *)sdirEntry);
1016 #endif
1017     code = afs_CheckCode(code, &treq, 29);
1018     return code;
1019 }
1020
1021 #endif
1022 #endif /* !AFS_LINUX20_ENV */