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