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