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