2 * Copyright 2000, International Business Machines Corporation and others.
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
11 * afs_vnop_readdir.c - afs_readdir and bulk stat
17 * afs_readdir/afs_readdir2(HP)
18 * afs_readdir1 - HP and DUX NFS versions
22 #include <afsconfig.h>
23 #include "afs/param.h"
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"
36 #if defined(AFS_HPUX1122_ENV)
42 * A few definitions. This is until we have a proper header file
43 * which ahs prototypes for all functions
46 extern struct DirEntry *afs_dir_GetBlob();
48 * AFS readdir vnodeop and bulk stat support.
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 #.
54 #define FIXUPSTUPIDINODE(a) ((a) &= 0x7fffffff)
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.
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.
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.
66 BlobScan is used by the Linux port in a separate file, so it should not
70 BlobScan(struct dcache * afile, afs_int32 ablob)
72 register afs_int32 relativeBlob;
74 register struct PageHeader *tpe;
77 AFS_STATCNT(BlobScan);
78 /* advance ablob over free and header blobs */
80 pageBlob = ablob & ~(EPP - 1); /* base blob in same page */
81 tpe = (struct PageHeader *)afs_dir_GetBlob(afile, pageBlob);
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 */
88 if (relativeBlob < DHE + 1)
89 relativeBlob = DHE + 1;
90 } else { /* others have one header blob */
91 if (relativeBlob == 0)
94 /* make sure blob is allocated */
95 for (i = relativeBlob; i < EPP; i++) {
96 if (tpe->freebitmap[i >> 3] & (1 << (i & 7)))
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);
104 ablob = pageBlob + EPP; /* go around again */
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.
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.
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+ */
129 /* Short form for 32 bit apps. */
130 struct irix5_min_dirent { /* miniature dirent structure */
131 /* If struct dirent changes, this must too */
137 #define AFS_DIRENT32BASESIZE IRIX5_DIRENTBASESIZE
138 #define AFS_DIRENT64BASESIZE DIRENT64BASESIZE
140 #define AFS_DIRENT32BASESIZE IRIX5_DIRENTBASESIZE
141 #define AFS_DIRENT64BASESIZE DIRENTBASESIZE
142 #endif /* AFS_SGI62_ENV */
144 struct min_direct { /* miniature direct structure */
145 /* If struct direct changes, this must too */
146 #if defined(AFS_DARWIN80_ENV)
151 #elif defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
156 #elif defined(AFS_SUN5_ENV)
161 #if defined(AFS_AIX32_ENV)
163 #elif defined(AFS_HPUX100_ENV)
164 unsigned long long d_off;
171 #endif /* AFS_SGI_ENV */
173 #if defined(AFS_HPUX_ENV) || defined(AFS_OSF_ENV)
174 struct minnfs_direct {
175 afs_int32 d_off; /* XXX */
180 #define NDIRSIZ_LEN(len) ((sizeof (struct dirent)+4 - (MAXNAMLEN+1)) + (((len)+1 + DIRPAD) &~ DIRPAD))
182 #endif /* !defined(UKERNEL) */
186 *------------------------------------------------------------------------------
188 * Keep a stack of about 256 fids for the bulk stat call.
189 * Fill it during the readdir_move. Later empty it...
192 #define READDIR_STASH AFSCBMAX
193 struct AFSFid afs_readdir_stash[READDIR_STASH];
194 int afs_rd_stash_i = 0;
197 *------------------------------------------------------------------------------
200 * mainly a kind of macro... makes getting the struct direct
201 * out to the user space easy... could take more parameters,
202 * but now just takes what it needs.
207 #if defined(AFS_HPUX100_ENV)
208 #define DIRSIZ_LEN(len) \
209 ((sizeof (struct __dirent) - (_MAXNAMLEN+1)) + (((len)+1 + DIRPAD) &~ DIRPAD))
211 #if defined(AFS_SUN56_ENV)
212 #define DIRSIZ_LEN(len) ((18 + (len) + 1 + 7) & ~7 )
215 #define DIRSIZ_LEN(len) ((10 + (len) + 1 + (NBPW-1)) & ~(NBPW-1))
218 #define DIRSIZ_LEN(len) \
219 ((sizeof (struct dirent) - (MAXNAMLEN+1)) + (((len)+1 + 3) &~ 3))
221 #if defined(AFS_SGI_ENV)
222 #ifndef AFS_SGI53_ENV
223 /* SGI 5.3 and later use 32/64 bit versions of directory size. */
224 #define DIRSIZ_LEN(len) DIRENTSIZE(len)
226 #else /* AFS_SGI_ENV */
227 #define DIRSIZ_LEN(len) \
228 ((sizeof (struct direct) - (MAXNAMLEN+1)) + (((len)+1 + 3) &~ 3))
229 #endif /* AFS_SGI_ENV */
230 #endif /* AFS_DIRENT */
231 #endif /* AFS_SUN5_ENV */
232 #endif /* AFS_SUN56_ENV */
233 #endif /* AFS_HPUX100_ENV */
235 #if defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
237 afs_readdir_type(avc, ade)
238 struct DirEntry *ade;
241 struct VenusFid tfid;
244 tfid.Cell = avc->fid.Cell;
245 tfid.Fid.Volume = avc->fid.Fid.Volume;
246 tfid.Fid.Vnode = ntohl(ade->fid.vnode);
247 tfid.Fid.Unique = ntohl(ade->fid.vunique);
248 if ((avc->states & CForeign) == 0 && (ntohl(ade->fid.vnode) & 1)) {
251 ObtainReadLock(&afs_xvcache);
252 if ((tvc = afs_FindVCache(&tfid, 0, 0))) {
253 ReleaseReadLock(&afs_xvcache);
257 } else if (((tvc->states) & (CStatd | CTruth))) {
258 /* CTruth will be set if the object has
264 else if (vtype == VREG)
266 /* Don't do this until we're sure it can't be a mtpt */
267 /* else if (vtype == VLNK)
269 /* what other types does AFS support? */
273 ReleaseReadLock(&afs_xvcache);
279 #define AFS_MOVE_LOCK() AFS_GLOCK()
280 #define AFS_MOVE_UNLOCK() AFS_GUNLOCK()
282 #define AFS_MOVE_LOCK()
283 #define AFS_MOVE_UNLOCK()
285 char bufofzeros[64]; /* gotta fill with something */
288 afs_readdir_move(de, vc, auio, slen, rlen, off)
302 afs_uint32 Volume = vc->fid.Fid.Volume;
303 afs_uint32 Vnode = de->fid.vnode;
304 #if defined(AFS_SUN56_ENV)
305 struct dirent64 *direntp;
307 #if defined(AFS_SUN5_ENV) || (defined(AFS_AIX51_ENV) && defined(AFS_64BIT_KERNEL))
308 struct dirent *direntp;
310 #endif /* AFS_SUN56_ENV */
311 #ifndef AFS_SGI53_ENV
312 struct min_direct sdirEntry;
313 #endif /* AFS_SGI53_ENV */
315 AFS_STATCNT(afs_readdir_move);
317 #define READDIR_CORRECT_INUMS
318 #ifdef READDIR_CORRECT_INUMS
319 if (de->name[0] == '.' && !de->name[1]) {
320 /* This is the '.' entry; if we are a volume root, we need to
321 * ignore the directory and use the inum for the mount point.
323 if (!FidCmp(&afs_rootFid, &vc->fid)) {
326 } else if (vc->mvstat == 2) {
327 tvp = afs_GetVolume(&vc->fid, 0, READ_LOCK);
329 Volume = tvp->mtpoint.Fid.Volume;
330 Vnode = tvp->mtpoint.Fid.Vnode;
331 afs_PutVolume(tvp, READ_LOCK);
335 else if (de->name[0] == '.' && de->name[1] == '.' && !de->name[2]) {
336 /* This is the '..' entry. Getting this right is very tricky,
337 * because we might be a volume root (so our parent is in a
338 * different volume), or our parent might be a volume root
339 * (so we actually want the mount point) or BOTH! */
340 if (!FidCmp(&afs_rootFid, &vc->fid)) {
341 /* We are the root of the AFS root, and thus our own parent */
344 } else if (vc->mvstat == 2) {
345 /* We are a volume root, which means our parent is in another
346 * volume. Luckily, we should have his fid cached... */
348 if (!FidCmp(&afs_rootFid, vc->mvid)) {
349 /* Parent directory is the root of the AFS root */
352 } else if (vc->mvid->Fid.Vnode == 1
353 && vc->mvid->Fid.Unique == 1) {
354 /* XXX The above test is evil and probably breaks DFS */
355 /* Parent directory is the target of a mount point */
356 tvp = afs_GetVolume(vc->mvid, 0, READ_LOCK);
358 Volume = tvp->mtpoint.Fid.Volume;
359 Vnode = tvp->mtpoint.Fid.Vnode;
360 afs_PutVolume(tvp, READ_LOCK);
363 /* Parent directory is not a volume root */
364 Volume = vc->mvid->Fid.Volume;
365 Vnode = vc->mvid->Fid.Vnode;
368 } else if (de->fid.vnode == 1 && de->fid.vunique == 1) {
369 /* XXX The above test is evil and probably breaks DFS */
370 /* Parent directory is a volume root; use the right inum */
371 tvp = afs_GetVolume(&vc->fid, 0, READ_LOCK);
373 if (tvp->cell == afs_rootFid.Cell
374 && tvp->volume == afs_rootFid.Fid.Volume) {
375 /* Parent directory is the root of the AFS root */
379 /* Parent directory is the target of a mount point */
380 Volume = tvp->mtpoint.Fid.Volume;
381 Vnode = tvp->mtpoint.Fid.Vnode;
383 afs_PutVolume(tvp, READ_LOCK);
391 afs_int32 use64BitDirent;
396 ABI_IS(ABI_IRIX5_64, GETDENTS_ABI(OSI_GET_CURRENT_ABI(), auio));
400 UIO_USERSPACE) ? ABI_IRIX5_64 : (ABI_IS(ABI_IRIX5_64 |
404 #else /* AFS_SGI61_ENV */
407 UIO_USERSPACE) ? ABI_IRIX5_64 : (ABI_IS(ABI_IRIX5_64,
409 #endif /* AFS_SGI61_ENV */
411 if (use64BitDirent) {
412 struct min_dirent sdirEntry;
413 sdirEntry.d_fileno = (Volume << 16) + ntohl(Vnode);
414 FIXUPSTUPIDINODE(sdirEntry.d_fileno);
415 sdirEntry.d_reclen = rlen;
416 sdirEntry.d_off = (off_t) off;
417 AFS_UIOMOVE(&sdirEntry, AFS_DIRENT64BASESIZE, UIO_READ, auio,
420 AFS_UIOMOVE(de->name, slen - 1, UIO_READ, auio, code);
422 AFS_UIOMOVE(bufofzeros,
423 DIRENTSIZE(slen) - (AFS_DIRENT64BASESIZE + slen -
424 1), UIO_READ, auio, code);
425 if (DIRENTSIZE(slen) < rlen) {
426 while (DIRENTSIZE(slen) < rlen) {
427 int minLen = rlen - DIRENTSIZE(slen);
428 if (minLen > sizeof(bufofzeros))
429 minLen = sizeof(bufofzeros);
430 AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
435 struct irix5_min_dirent sdirEntry;
436 sdirEntry.d_fileno = (Volume << 16) + ntohl(Vnode);
437 FIXUPSTUPIDINODE(sdirEntry.d_fileno);
438 sdirEntry.d_reclen = rlen;
439 sdirEntry.d_off = (afs_int32) off;
440 AFS_UIOMOVE(&sdirEntry, AFS_DIRENT32BASESIZE, UIO_READ, auio,
443 AFS_UIOMOVE(de->name, slen - 1, UIO_READ, auio, code);
445 AFS_UIOMOVE(bufofzeros,
446 IRIX5_DIRENTSIZE(slen) - (AFS_DIRENT32BASESIZE +
449 if (IRIX5_DIRENTSIZE(slen) < rlen) {
450 while (IRIX5_DIRENTSIZE(slen) < rlen) {
451 int minLen = rlen - IRIX5_DIRENTSIZE(slen);
452 if (minLen > sizeof(bufofzeros))
453 minLen = sizeof(bufofzeros);
454 AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
460 #else /* AFS_SGI53_ENV */
461 #if defined(AFS_SUN5_ENV) || (defined(AFS_AIX51_ENV) && defined(AFS_64BIT_KERNEL))
462 #if defined(AFS_SUN56_ENV)
463 direntp = (struct dirent64 *)osi_AllocLargeSpace(AFS_LRALLOCSIZ);
465 direntp = (struct dirent *)osi_AllocLargeSpace(AFS_LRALLOCSIZ);
467 direntp->d_ino = (Volume << 16) + ntohl(Vnode);
468 FIXUPSTUPIDINODE(direntp->d_ino);
469 #if defined(AFS_AIX51_ENV) && defined(AFS_64BIT_KERNEL)
470 direntp->d_offset = off;
471 direntp->d_namlen = slen;
473 direntp->d_off = off;
475 direntp->d_reclen = rlen;
476 strcpy(direntp->d_name, de->name);
477 AFS_UIOMOVE((caddr_t) direntp, rlen, UIO_READ, auio, code);
478 osi_FreeLargeSpace((char *)direntp);
479 #else /* AFS_SUN5_ENV */
480 /* Note the odd mechanism for building the inode number */
481 sdirEntry.d_fileno = (Volume << 16) + ntohl(Vnode);
482 FIXUPSTUPIDINODE(sdirEntry.d_fileno);
483 sdirEntry.d_reclen = rlen;
484 #if !defined(AFS_SGI_ENV)
485 sdirEntry.d_namlen = slen;
487 #if defined(AFS_AIX32_ENV) || defined(AFS_SGI_ENV)
488 sdirEntry.d_off = off;
490 #if defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
491 sdirEntry.d_type = afs_readdir_type(vc, de);
494 #if defined(AFS_SGI_ENV)
495 AFS_UIOMOVE(&sdirEntry, DIRENTBASESIZE, UIO_READ, auio, code);
497 AFS_UIOMOVE(de->name, slen - 1, UIO_READ, auio, code);
499 AFS_UIOMOVE(bufofzeros,
500 DIRSIZ_LEN(slen) - (DIRENTBASESIZE + slen - 1), UIO_READ,
502 #else /* AFS_SGI_ENV */
504 AFS_UIOMOVE((char *)&sdirEntry, sizeof(sdirEntry), UIO_READ, auio, code);
507 AFS_UIOMOVE(de->name, slen, UIO_READ, auio, code);
510 /* pad out the remaining characters with zeros */
512 AFS_UIOMOVE(bufofzeros, ((slen + 1 + DIRPAD) & ~DIRPAD) - slen,
513 UIO_READ, auio, code);
516 #endif /* AFS_SGI_ENV */
518 /* pad out the difference between rlen and slen... */
519 if (DIRSIZ_LEN(slen) < rlen) {
521 while (DIRSIZ_LEN(slen) < rlen) {
522 int minLen = rlen - DIRSIZ_LEN(slen);
523 if (minLen > sizeof(bufofzeros))
524 minLen = sizeof(bufofzeros);
525 AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
530 #endif /* AFS_SUN5_ENV */
531 #endif /* AFS_SGI53_ENV */
537 *------------------------------------------------------------------------------
539 * Read directory entries.
540 * There are some weird things to look out for here. The uio_offset
541 * field is either 0 or it is the offset returned from a previous
542 * readdir. It is an opaque value used by the server to find the
543 * correct directory block to read. The byte count must be at least
544 * vtoblksz(vp) bytes. The count field is the number of blocks to
545 * read on the server. This is advisory only, the server may return
546 * only one block's worth of entries. Entries may be compressed on
549 * This routine encodes knowledge of Vice dirs.
553 afs_bulkstat_send(avc, req)
555 struct vrequest *req;
561 * Here is the bad, bad, really bad news.
562 * It has to do with 'offset' (seek locations).
566 #if defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV) || defined(AFS_OSF_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
567 afs_readdir(OSI_VC_ARG(avc), auio, acred, eofp)
570 #if defined(AFS_HPUX100_ENV)
571 afs_readdir2(OSI_VC_ARG(avc), auio, acred)
573 afs_readdir(OSI_VC_ARG(avc), auio, acred)
578 struct AFS_UCRED *acred;
580 struct vrequest treq;
581 register struct dcache *tdc;
582 afs_size_t origOffset, tlen;
585 struct DirEntry *ode = 0, *nde = 0;
586 int o_slen = 0, n_slen = 0;
588 struct afs_fakestat_state fakestate;
589 #if defined(AFS_SGI53_ENV)
590 afs_int32 use64BitDirent, dirsiz;
591 #endif /* defined(AFS_SGI53_ENV) */
596 * XXX All the hacks for alloced sdirEntry and inlining of afs_readdir_move instead of calling
597 * it is necessary for hpux due to stack problems that seem to occur when coming thru the nfs
598 * translator side XXX
600 struct min_direct *sdirEntry =
601 (struct min_direct *)osi_AllocSmallSpace(sizeof(struct min_direct));
605 /* opaque value is pointer into a vice dir; use bit map to decide
606 * if the entries are in use. Always assumed to be valid. 0 is
607 * special, means start of a new dir. Int32 inode, followed by
608 * short reclen and short namelen. Namelen does not include
609 * the null byte. Followed by null-terminated string.
611 AFS_STATCNT(afs_readdir);
613 #if defined(AFS_SGI53_ENV)
617 ABI_IS(ABI_IRIX5_64, GETDENTS_ABI(OSI_GET_CURRENT_ABI(), auio));
621 UIO_USERSPACE) ? ABI_IRIX5_64 : (ABI_IS(ABI_IRIX5_64 | ABI_IRIX5_N32,
623 #endif /* AFS_SGI62_ENV */
624 #else /* AFS_SGI61_ENV */
627 UIO_USERSPACE) ? ABI_IRIX5_64 : (ABI_IS(ABI_IRIX5_64,
629 #endif /* AFS_SGI61_ENV */
630 #endif /* defined(AFS_SGI53_ENV) */
632 #if defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV) || defined(AFS_OSF_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
633 /* Not really used by the callee so we ignore it for now */
637 #ifndef AFS_64BIT_CLIENT
638 if (AfsLargeFileUio(auio) /* file is large than 2 GB */
639 ||AfsLargeFileSize(AFS_UIO_OFFSET(auio), AFS_UIO_RESID(auio)))
643 if ((code = afs_InitReq(&treq, acred))) {
645 osi_FreeSmallSpace((char *)sdirEntry);
649 /* update the cache entry */
650 afs_InitFakeStat(&fakestate);
651 code = afs_EvalFakeStat(&avc, &fakestate, &treq);
655 code = afs_VerifyVCache(avc, &treq);
658 /* get a reference to the entire directory */
659 tdc = afs_GetDCache(avc, (afs_size_t) 0, &treq, &origOffset, &tlen, 1);
665 ObtainReadLock(&avc->lock);
666 ObtainReadLock(&tdc->lock);
669 * Make sure that the data in the cache is current. There are two
670 * cases we need to worry about:
671 * 1. The cache data is being fetched by another process.
672 * 2. The cache data is no longer valid
674 while ((avc->states & CStatd)
675 && (tdc->dflags & DFFetching)
676 && hsame(avc->m.DataVersion, tdc->f.versionNo)) {
677 afs_Trace4(afs_iclSetp, CM_TRACE_DCACHEWAIT, ICL_TYPE_STRING,
678 __FILE__, ICL_TYPE_INT32, __LINE__, ICL_TYPE_POINTER, tdc,
679 ICL_TYPE_INT32, tdc->dflags);
680 ReleaseReadLock(&tdc->lock);
681 ReleaseReadLock(&avc->lock);
682 afs_osi_Sleep(&tdc->validPos);
683 ObtainReadLock(&avc->lock);
684 ObtainReadLock(&tdc->lock);
686 if (!(avc->states & CStatd)
687 || !hsame(avc->m.DataVersion, tdc->f.versionNo)) {
688 ReleaseReadLock(&tdc->lock);
689 ReleaseReadLock(&avc->lock);
695 * iterator for the directory reads. Takes the AFS DirEntry
696 * structure and slams them into UFS direct structures.
697 * uses afs_readdir_move to get the struct to the user space.
699 * The routine works by looking ahead one AFS directory entry.
700 * That's because the AFS entry we are currenly working with
701 * may not fit into the buffer the user has provided. If it
702 * doesn't we have to change the size of the LAST AFS directory
703 * entry, so that it will FIT perfectly into the block the
706 * The 'forward looking' of the code makes it a bit tough to read.
707 * Remember we need to get an entry, see if it it fits, then
708 * set it up as the LAST entry, and find the next one.
710 * Tough to take: We give out an EINVAL if we don't have enough
711 * space in the buffer, and at the same time, don't have an entry
712 * to put into the buffer. This CAN happen if the first AFS entry
713 * we get can't fit into the 512 character buffer provided. Seems
714 * it ought not happen...
716 * Assumption: don't need to use anything but one dc entry:
717 * this means the directory ought not be greater than 64k.
721 auio->uio_fpflags = 0;
724 origOffset = AFS_UIO_OFFSET(auio);
725 /* scan for the next interesting entry scan for in-use blob otherwise up point at
726 * this blob note that ode, if non-zero, also represents a held dir page */
727 if (!(us = BlobScan(tdc, (origOffset >> 5)))
728 || !(nde = (struct DirEntry *)afs_dir_GetBlob(tdc, us))) {
729 /* failed to setup nde, return what we've got, and release ode */
731 /* something to hand over. */
733 sdirEntry->d_fileno =
734 (avc->fid.Fid.Volume << 16) + ntohl(ode->fid.vnode);
735 FIXUPSTUPIDINODE(sdirEntry->d_fileno);
736 sdirEntry->d_reclen = rlen = AFS_UIO_RESID(auio);
737 sdirEntry->d_namlen = o_slen;
738 #if defined(AFS_SUN5_ENV) || defined(AFS_AIX32_ENV) || defined(AFS_HPUX100_ENV)
739 sdirEntry->d_off = origOffset;
741 AFS_UIOMOVE((char *)sdirEntry, sizeof(*sdirEntry), UIO_READ,
744 AFS_UIOMOVE(ode->name, o_slen, UIO_READ, auio, code);
745 /* pad out the remaining characters with zeros */
747 AFS_UIOMOVE(bufofzeros,
748 ((o_slen + 1 + DIRPAD) & ~DIRPAD) - o_slen,
749 UIO_READ, auio, code);
751 /* pad out the difference between rlen and slen... */
752 if (DIRSIZ_LEN(o_slen) < rlen) {
753 while (DIRSIZ_LEN(o_slen) < rlen) {
754 int minLen = rlen - DIRSIZ_LEN(o_slen);
755 if (minLen > sizeof(bufofzeros))
756 minLen = sizeof(bufofzeros);
757 AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
762 code = afs_readdir_move(ode, avc, auio, o_slen,
763 #if defined(AFS_SUN5_ENV)
766 AFS_UIO_RESID(auio), origOffset);
768 #endif /* AFS_HPUX_ENV */
769 #if !defined(AFS_SUN5_ENV)
770 AFS_UIO_SETRESID(auio, 0);
773 /* nothin to hand over */
775 #if defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV) || defined(AFS_OSF_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
777 *eofp = 1; /* Set it properly */
780 DRelease((struct buffer *)ode, 0);
783 /* by here nde is set */
785 /* Do we have enough user space to carry out our mission? */
786 #if defined(AFS_SGI_ENV)
787 n_slen = strlen(nde->name) + 1; /* NULL terminate */
789 n_slen = strlen(nde->name);
793 use64BitDirent ? DIRENTSIZE(n_slen) : IRIX5_DIRENTSIZE(n_slen);
794 if (dirsiz >= (AFS_UIO_RESID(auio) - len)) {
796 if (DIRSIZ_LEN(n_slen) >= (AFS_UIO_RESID(auio) - len)) {
797 #endif /* AFS_SGI53_ENV */
798 /* No can do no more now; ya know... at this time */
799 DRelease((struct buffer *)nde, 0); /* can't use this one. */
802 sdirEntry->d_fileno =
803 (avc->fid.Fid.Volume << 16) + ntohl(ode->fid.vnode);
804 FIXUPSTUPIDINODE(sdirEntry->d_fileno);
805 sdirEntry->d_reclen = rlen = AFS_UIO_RESID(auio);
806 sdirEntry->d_namlen = o_slen;
807 #if defined(AFS_SUN5_ENV) || defined(AFS_AIX32_ENV) || defined(AFS_HPUX100_ENV)
808 sdirEntry->d_off = origOffset;
810 AFS_UIOMOVE((char *)sdirEntry, sizeof(*sdirEntry), UIO_READ,
813 AFS_UIOMOVE(ode->name, o_slen, UIO_READ, auio, code);
814 /* pad out the remaining characters with zeros */
816 AFS_UIOMOVE(bufofzeros,
817 ((o_slen + 1 + DIRPAD) & ~DIRPAD) - o_slen,
818 UIO_READ, auio, code);
820 /* pad out the difference between rlen and slen... */
821 if (DIRSIZ_LEN(o_slen) < rlen) {
822 while (DIRSIZ_LEN(o_slen) < rlen) {
823 int minLen = rlen - DIRSIZ_LEN(o_slen);
824 if (minLen > sizeof(bufofzeros))
825 minLen = sizeof(bufofzeros);
826 AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
830 #else /* AFS_HPUX_ENV */
832 afs_readdir_move(ode, avc, auio, o_slen,
833 AFS_UIO_RESID(auio), origOffset);
834 #endif /* AFS_HPUX_ENV */
835 /* this next line used to be AFSVFS40 or AIX 3.1, but is
837 AFS_UIO_SETOFFSET(auio, origOffset);
838 AFS_UIO_SETRESID(auio, 0);
839 } else { /* trouble, can't give anything to the user! */
840 /* even though he has given us a buffer,
841 * even though we have something to give us,
842 * Looks like we lost something somewhere.
847 DRelease((struct buffer *)ode, 0);
852 * In any event, we move out the LAST de entry, getting ready
853 * to set up for the next one.
857 sdirEntry->d_fileno =
858 (avc->fid.Fid.Volume << 16) + ntohl(ode->fid.vnode);
859 FIXUPSTUPIDINODE(sdirEntry->d_fileno);
860 sdirEntry->d_reclen = rlen = len;
861 sdirEntry->d_namlen = o_slen;
862 #if defined(AFS_SUN5_ENV) || defined(AFS_AIX32_ENV) || defined(AFS_HPUX100_ENV)
863 sdirEntry->d_off = origOffset;
865 AFS_UIOMOVE((char *)sdirEntry, sizeof(*sdirEntry), UIO_READ, auio,
868 AFS_UIOMOVE(ode->name, o_slen, UIO_READ, auio, code);
869 /* pad out the remaining characters with zeros */
871 AFS_UIOMOVE(bufofzeros,
872 ((o_slen + 1 + DIRPAD) & ~DIRPAD) - o_slen,
873 UIO_READ, auio, code);
875 /* pad out the difference between rlen and slen... */
876 if (DIRSIZ_LEN(o_slen) < rlen) {
877 while (DIRSIZ_LEN(o_slen) < rlen) {
878 int minLen = rlen - DIRSIZ_LEN(o_slen);
879 if (minLen > sizeof(bufofzeros))
880 minLen = sizeof(bufofzeros);
881 AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
885 #else /* AFS_HPUX_ENV */
886 code = afs_readdir_move(ode, avc, auio, o_slen, len, origOffset);
887 #endif /* AFS_HPUX_ENV */
890 len = use64BitDirent ? DIRENTSIZE(o_slen =
891 n_slen) : IRIX5_DIRENTSIZE(o_slen =
894 len = DIRSIZ_LEN(o_slen = n_slen);
895 #endif /* AFS_SGI53_ENV */
897 DRelease((struct buffer *)ode, 0);
899 AFS_UIO_SETOFFSET(auio, (afs_int32) ((us + afs_dir_NameBlobs(nde->name)) << 5));
902 DRelease((struct buffer *)ode, 0);
905 ReleaseReadLock(&tdc->lock);
907 ReleaseReadLock(&avc->lock);
911 osi_FreeSmallSpace((char *)sdirEntry);
913 afs_PutFakeStat(&fakestate);
914 code = afs_CheckCode(code, &treq, 28);
918 #if defined(AFS_HPUX_ENV) || defined(AFS_OSF_ENV)
920 afs1_readdir(avc, auio, acred, eofp)
923 afs1_readdir(avc, auio, acred)
927 struct AFS_UCRED *acred;
929 struct vrequest treq;
930 register struct dcache *tdc;
931 afs_size_t origOffset, len;
933 struct DirEntry *ode = 0, *nde = 0;
934 int o_slen = 0, n_slen = 0;
936 #if defined(AFS_HPUX_ENV) || defined(AFS_OSF_ENV)
938 * XXX All the hacks for alloced sdirEntry and inlining of afs_readdir_move instead of calling
939 * it is necessary for hpux due to stack problems that seem to occur when coming thru the nfs
940 * translator side XXX
942 struct minnfs_direct *sdirEntry = (struct minnfs_direct *)
943 osi_AllocSmallSpace(sizeof(struct min_direct));
946 struct afs_fakestat_state fakestate;
948 AFS_STATCNT(afs_readdir);
949 #if defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV) || defined(AFS_OSF_ENV)
953 if (code = afs_InitReq(&treq, acred)) {
955 osi_FreeSmallSpace((char *)sdirEntry);
959 afs_InitFakeStat(&fakestate);
960 code = afs_EvalFakeStat(&avc, &fakestate, &treq);
963 osi_FreeSmallSpace((char *)sdirEntry);
965 afs_PutFakeStat(&fakestate);
968 /* update the cache entry */
970 code = afs_VerifyVCache(avc, &treq);
973 /* get a reference to the entire directory */
974 tdc = afs_GetDCache(avc, (afs_size_t) 0, &treq, &origOffset, &len, 1);
979 ObtainReadLock(&avc->lock);
980 ObtainReadLock(&tdc->lock);
983 * Make sure that the data in the cache is current. There are two
984 * cases we need to worry about:
985 * 1. The cache data is being fetched by another process.
986 * 2. The cache data is no longer valid
988 while ((avc->states & CStatd)
989 && (tdc->dflags & DFFetching)
990 && hsame(avc->m.DataVersion, tdc->f.versionNo)) {
991 afs_Trace4(afs_iclSetp, CM_TRACE_DCACHEWAIT, ICL_TYPE_STRING,
992 __FILE__, ICL_TYPE_INT32, __LINE__, ICL_TYPE_POINTER, tdc,
993 ICL_TYPE_INT32, tdc->dflags);
994 ReleaseReadLock(&tdc->lock);
995 ReleaseReadLock(&avc->lock);
996 afs_osi_Sleep(&tdc->validPos);
997 ObtainReadLock(&avc->lock);
998 ObtainReadLock(&tdc->lock);
1000 if (!(avc->states & CStatd)
1001 || !hsame(avc->m.DataVersion, tdc->f.versionNo)) {
1002 ReleaseReadLock(&tdc->lock);
1003 ReleaseReadLock(&avc->lock);
1010 auio->uio_fpflags = 0;
1013 origOffset = AFS_UIO_OFFSET(auio);
1015 /* scan for the next interesting entry scan for in-use blob otherwise up point at
1016 * this blob note that ode, if non-zero, also represents a held dir page */
1017 if (!(us = BlobScan(tdc, (origOffset >> 5)))
1018 || !(nde = (struct DirEntry *)afs_dir_GetBlob(tdc, us))) {
1019 /* failed to setup nde, return what we've got, and release ode */
1021 /* something to hand over. */
1022 #if defined(AFS_HPUX_ENV) || defined(AFS_OSF_ENV)
1023 sdirEntry->d_fileno =
1024 (avc->fid.Fid.Volume << 16) + ntohl(ode->fid.vnode);
1025 FIXUPSTUPIDINODE(sdirEntry->d_fileno);
1026 sdirEntry->d_reclen = rlen = AFS_UIO_RESID(auio);
1027 sdirEntry->d_namlen = o_slen;
1028 sdirEntry->d_off = origOffset;
1029 AFS_UIOMOVE((char *)sdirEntry, sizeof(*sdirEntry), UIO_READ,
1032 AFS_UIOMOVE(ode->name, o_slen, UIO_READ, auio, code);
1034 /* pad out the remaining characters with zeros */
1036 AFS_UIOMOVE(bufofzeros,
1037 ((o_slen + 1 + DIRPAD) & ~DIRPAD) - o_slen,
1038 UIO_READ, auio, code);
1040 /* pad out the difference between rlen and slen... */
1041 if (NDIRSIZ_LEN(o_slen) < rlen) {
1042 while (NDIRSIZ_LEN(o_slen) < rlen) {
1043 int minLen = rlen - NDIRSIZ_LEN(o_slen);
1044 if (minLen > sizeof(bufofzeros))
1045 minLen = sizeof(bufofzeros);
1046 AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
1052 afs_readdir_move(ode, avc, auio, o_slen,
1053 AFS_UIO_RESID(auio), origOffset);
1054 #endif /* AFS_HPUX_ENV */
1055 AFS_UIO_SETRESID(auio, 0);
1057 /* nothin to hand over */
1059 #if defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV) || defined(AFS_OSF_ENV)
1067 /* by here nde is set */
1069 /* Do we have enough user space to carry out our mission? */
1070 #if defined(AFS_SGI_ENV)
1071 n_slen = strlen(nde->name) + 1; /* NULL terminate */
1073 n_slen = strlen(nde->name);
1075 if (NDIRSIZ_LEN(n_slen) >= (AFS_UIO_RESID(auio) - len)) {
1076 /* No can do no more now; ya know... at this time */
1077 DRelease(nde, 0); /* can't use this one. */
1079 #if defined(AFS_HPUX_ENV) || defined(AFS_OSF_ENV)
1080 sdirEntry->d_fileno =
1081 (avc->fid.Fid.Volume << 16) + ntohl(ode->fid.vnode);
1082 FIXUPSTUPIDINODE(sdirEntry->d_fileno);
1083 sdirEntry->d_reclen = rlen = AFS_UIO_RESID(auio);
1084 sdirEntry->d_namlen = o_slen;
1085 sdirEntry->d_off = origOffset;
1086 AFS_UIOMOVE((char *)sdirEntry, sizeof(*sdirEntry), UIO_READ,
1089 AFS_UIOMOVE(ode->name, o_slen, UIO_READ, auio, code);
1090 /* pad out the remaining characters with zeros */
1092 AFS_UIOMOVE(bufofzeros,
1093 ((o_slen + 1 + DIRPAD) & ~DIRPAD) - o_slen,
1094 UIO_READ, auio, code);
1096 /* pad out the difference between rlen and slen... */
1097 if (NDIRSIZ_LEN(o_slen) < rlen) {
1098 while (NDIRSIZ_LEN(o_slen) < rlen) {
1099 int minLen = rlen - NDIRSIZ_LEN(o_slen);
1100 if (minLen > sizeof(bufofzeros))
1101 minLen = sizeof(bufofzeros);
1102 AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
1108 afs_readdir_move(ode, avc, auio, o_slen,
1109 AFS_UIO_RESID(auio), origOffset);
1110 #endif /* AFS_HPUX_ENV */
1111 /* this next line used to be AFSVFS40 or AIX 3.1, but is really generic */
1112 AFS_UIO_SETOFFSET(auio, origOffset);
1113 AFS_UIO_SETRESID(auio, 0);
1114 } else { /* trouble, can't give anything to the user! */
1115 /* even though he has given us a buffer,
1116 * even though we have something to give us,
1117 * Looks like we lost something somewhere.
1127 * In any event, we move out the LAST de entry, getting ready
1128 * to set up for the next one.
1131 #if defined(AFS_HPUX_ENV) || defined(AFS_OSF_ENV)
1132 sdirEntry->d_fileno =
1133 (avc->fid.Fid.Volume << 16) + ntohl(ode->fid.vnode);
1134 FIXUPSTUPIDINODE(sdirEntry->d_fileno);
1135 sdirEntry->d_reclen = rlen = len;
1136 sdirEntry->d_namlen = o_slen;
1137 sdirEntry->d_off = origOffset;
1138 AFS_UIOMOVE((char *)sdirEntry, sizeof(*sdirEntry), UIO_READ, auio,
1141 AFS_UIOMOVE(ode->name, o_slen, UIO_READ, auio, code);
1142 /* pad out the remaining characters with zeros */
1144 AFS_UIOMOVE(bufofzeros,
1145 ((o_slen + 1 + DIRPAD) & ~DIRPAD) - o_slen,
1146 UIO_READ, auio, code);
1148 /* pad out the difference between rlen and slen... */
1149 if (NDIRSIZ_LEN(o_slen) < rlen) {
1150 while (NDIRSIZ_LEN(o_slen) < rlen) {
1151 int minLen = rlen - NDIRSIZ_LEN(o_slen);
1152 if (minLen > sizeof(bufofzeros))
1153 minLen = sizeof(bufofzeros);
1154 AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
1159 code = afs_readdir_move(ode, avc, auio, o_slen, len, origOffset);
1160 #endif /* AFS_HPUX_ENV */
1162 len = NDIRSIZ_LEN(o_slen = n_slen);
1166 AFS_UIO_OFFSET(auio) = ((us + afs_dir_NameBlobs(nde->name)) << 5);
1172 ReleaseReadLock(&tdc->lock);
1174 ReleaseReadLock(&avc->lock);
1177 #if defined(AFS_HPUX_ENV) || defined(AFS_OSF_ENV)
1178 osi_FreeSmallSpace((char *)sdirEntry);
1180 afs_PutFakeStat(&fakestate);
1181 code = afs_CheckCode(code, &treq, 29);
1186 #endif /* !AFS_LINUX20_ENV */