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)) {
250 } else if ((tvc = afs_FindVCache(&tfid, 0, 0))) {
254 } else if (((tvc->states) & (CStatd | CTruth))) {
255 /* CTruth will be set if the object has
261 else if (vtype == VREG)
263 /* Don't do this until we're sure it can't be a mtpt */
264 /* else if (vtype == VLNK)
266 /* what other types does AFS support? */
275 #define AFS_MOVE_LOCK() AFS_GLOCK()
276 #define AFS_MOVE_UNLOCK() AFS_GUNLOCK()
278 #define AFS_MOVE_LOCK()
279 #define AFS_MOVE_UNLOCK()
281 char bufofzeros[64]; /* gotta fill with something */
284 afs_readdir_move(de, vc, auio, slen, rlen, off)
298 afs_uint32 Volume = vc->fid.Fid.Volume;
299 afs_uint32 Vnode = de->fid.vnode;
300 #if defined(AFS_SUN56_ENV)
301 struct dirent64 *direntp;
303 #if defined(AFS_SUN5_ENV) || (defined(AFS_AIX51_ENV) && defined(AFS_64BIT_KERNEL))
304 struct dirent *direntp;
306 #endif /* AFS_SUN56_ENV */
307 #ifndef AFS_SGI53_ENV
308 struct min_direct sdirEntry;
309 #endif /* AFS_SGI53_ENV */
311 AFS_STATCNT(afs_readdir_move);
313 #define READDIR_CORRECT_INUMS
314 #ifdef READDIR_CORRECT_INUMS
315 if (de->name[0] == '.' && !de->name[1]) {
316 /* This is the '.' entry; if we are a volume root, we need to
317 * ignore the directory and use the inum for the mount point.
319 if (!FidCmp(&afs_rootFid, &vc->fid)) {
322 } else if (vc->mvstat == 2) {
323 tvp = afs_GetVolume(&vc->fid, 0, READ_LOCK);
325 Volume = tvp->mtpoint.Fid.Volume;
326 Vnode = tvp->mtpoint.Fid.Vnode;
327 afs_PutVolume(tvp, READ_LOCK);
331 else if (de->name[0] == '.' && de->name[1] == '.' && !de->name[2]) {
332 /* This is the '..' entry. Getting this right is very tricky,
333 * because we might be a volume root (so our parent is in a
334 * different volume), or our parent might be a volume root
335 * (so we actually want the mount point) or BOTH! */
336 if (!FidCmp(&afs_rootFid, &vc->fid)) {
337 /* We are the root of the AFS root, and thus our own parent */
340 } else if (vc->mvstat == 2) {
341 /* We are a volume root, which means our parent is in another
342 * volume. Luckily, we should have his fid cached... */
344 if (!FidCmp(&afs_rootFid, vc->mvid)) {
345 /* Parent directory is the root of the AFS root */
348 } else if (vc->mvid->Fid.Vnode == 1
349 && vc->mvid->Fid.Unique == 1) {
350 /* XXX The above test is evil and probably breaks DFS */
351 /* Parent directory is the target of a mount point */
352 tvp = afs_GetVolume(vc->mvid, 0, READ_LOCK);
354 Volume = tvp->mtpoint.Fid.Volume;
355 Vnode = tvp->mtpoint.Fid.Vnode;
356 afs_PutVolume(tvp, READ_LOCK);
359 /* Parent directory is not a volume root */
360 Volume = vc->mvid->Fid.Volume;
361 Vnode = vc->mvid->Fid.Vnode;
364 } else if (de->fid.vnode == 1 && de->fid.vunique == 1) {
365 /* XXX The above test is evil and probably breaks DFS */
366 /* Parent directory is a volume root; use the right inum */
367 tvp = afs_GetVolume(&vc->fid, 0, READ_LOCK);
369 if (tvp->cell == afs_rootFid.Cell
370 && tvp->volume == afs_rootFid.Fid.Volume) {
371 /* Parent directory is the root of the AFS root */
375 /* Parent directory is the target of a mount point */
376 Volume = tvp->mtpoint.Fid.Volume;
377 Vnode = tvp->mtpoint.Fid.Vnode;
379 afs_PutVolume(tvp, READ_LOCK);
387 afs_int32 use64BitDirent;
392 ABI_IS(ABI_IRIX5_64, GETDENTS_ABI(OSI_GET_CURRENT_ABI(), auio));
396 UIO_USERSPACE) ? ABI_IRIX5_64 : (ABI_IS(ABI_IRIX5_64 |
400 #else /* AFS_SGI61_ENV */
403 UIO_USERSPACE) ? ABI_IRIX5_64 : (ABI_IS(ABI_IRIX5_64,
405 #endif /* AFS_SGI61_ENV */
407 if (use64BitDirent) {
408 struct min_dirent sdirEntry;
409 sdirEntry.d_fileno = (Volume << 16) + ntohl(Vnode);
410 FIXUPSTUPIDINODE(sdirEntry.d_fileno);
411 sdirEntry.d_reclen = rlen;
412 sdirEntry.d_off = (off_t) off;
413 AFS_UIOMOVE(&sdirEntry, AFS_DIRENT64BASESIZE, UIO_READ, auio,
416 AFS_UIOMOVE(de->name, slen - 1, UIO_READ, auio, code);
418 AFS_UIOMOVE(bufofzeros,
419 DIRENTSIZE(slen) - (AFS_DIRENT64BASESIZE + slen -
420 1), UIO_READ, auio, code);
421 if (DIRENTSIZE(slen) < rlen) {
422 while (DIRENTSIZE(slen) < rlen) {
423 int minLen = rlen - DIRENTSIZE(slen);
424 if (minLen > sizeof(bufofzeros))
425 minLen = sizeof(bufofzeros);
426 AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
431 struct irix5_min_dirent sdirEntry;
432 sdirEntry.d_fileno = (Volume << 16) + ntohl(Vnode);
433 FIXUPSTUPIDINODE(sdirEntry.d_fileno);
434 sdirEntry.d_reclen = rlen;
435 sdirEntry.d_off = (afs_int32) off;
436 AFS_UIOMOVE(&sdirEntry, AFS_DIRENT32BASESIZE, UIO_READ, auio,
439 AFS_UIOMOVE(de->name, slen - 1, UIO_READ, auio, code);
441 AFS_UIOMOVE(bufofzeros,
442 IRIX5_DIRENTSIZE(slen) - (AFS_DIRENT32BASESIZE +
445 if (IRIX5_DIRENTSIZE(slen) < rlen) {
446 while (IRIX5_DIRENTSIZE(slen) < rlen) {
447 int minLen = rlen - IRIX5_DIRENTSIZE(slen);
448 if (minLen > sizeof(bufofzeros))
449 minLen = sizeof(bufofzeros);
450 AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
456 #else /* AFS_SGI53_ENV */
457 #if defined(AFS_SUN5_ENV) || (defined(AFS_AIX51_ENV) && defined(AFS_64BIT_KERNEL))
458 #if defined(AFS_SUN56_ENV)
459 direntp = (struct dirent64 *)osi_AllocLargeSpace(AFS_LRALLOCSIZ);
461 direntp = (struct dirent *)osi_AllocLargeSpace(AFS_LRALLOCSIZ);
463 direntp->d_ino = (Volume << 16) + ntohl(Vnode);
464 FIXUPSTUPIDINODE(direntp->d_ino);
465 #if defined(AFS_AIX51_ENV) && defined(AFS_64BIT_KERNEL)
466 direntp->d_offset = off;
467 direntp->d_namlen = slen;
469 direntp->d_off = off;
471 direntp->d_reclen = rlen;
472 strcpy(direntp->d_name, de->name);
473 AFS_UIOMOVE((caddr_t) direntp, rlen, UIO_READ, auio, code);
474 osi_FreeLargeSpace((char *)direntp);
475 #else /* AFS_SUN5_ENV */
476 /* Note the odd mechanism for building the inode number */
477 sdirEntry.d_fileno = (Volume << 16) + ntohl(Vnode);
478 FIXUPSTUPIDINODE(sdirEntry.d_fileno);
479 sdirEntry.d_reclen = rlen;
480 #if !defined(AFS_SGI_ENV)
481 sdirEntry.d_namlen = slen;
483 #if defined(AFS_AIX32_ENV) || defined(AFS_SGI_ENV)
484 sdirEntry.d_off = off;
486 #if defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
487 sdirEntry.d_type = afs_readdir_type(vc, de);
490 #if defined(AFS_SGI_ENV)
491 AFS_UIOMOVE(&sdirEntry, DIRENTBASESIZE, UIO_READ, auio, code);
493 AFS_UIOMOVE(de->name, slen - 1, UIO_READ, auio, code);
495 AFS_UIOMOVE(bufofzeros,
496 DIRSIZ_LEN(slen) - (DIRENTBASESIZE + slen - 1), UIO_READ,
498 #else /* AFS_SGI_ENV */
500 AFS_UIOMOVE((char *)&sdirEntry, sizeof(sdirEntry), UIO_READ, auio, code);
503 AFS_UIOMOVE(de->name, slen, UIO_READ, auio, code);
506 /* pad out the remaining characters with zeros */
508 AFS_UIOMOVE(bufofzeros, ((slen + 1 + DIRPAD) & ~DIRPAD) - slen,
509 UIO_READ, auio, code);
512 #endif /* AFS_SGI_ENV */
514 /* pad out the difference between rlen and slen... */
515 if (DIRSIZ_LEN(slen) < rlen) {
517 while (DIRSIZ_LEN(slen) < rlen) {
518 int minLen = rlen - DIRSIZ_LEN(slen);
519 if (minLen > sizeof(bufofzeros))
520 minLen = sizeof(bufofzeros);
521 AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
526 #endif /* AFS_SUN5_ENV */
527 #endif /* AFS_SGI53_ENV */
533 *------------------------------------------------------------------------------
535 * Read directory entries.
536 * There are some weird things to look out for here. The uio_offset
537 * field is either 0 or it is the offset returned from a previous
538 * readdir. It is an opaque value used by the server to find the
539 * correct directory block to read. The byte count must be at least
540 * vtoblksz(vp) bytes. The count field is the number of blocks to
541 * read on the server. This is advisory only, the server may return
542 * only one block's worth of entries. Entries may be compressed on
545 * This routine encodes knowledge of Vice dirs.
549 afs_bulkstat_send(avc, req)
551 struct vrequest *req;
557 * Here is the bad, bad, really bad news.
558 * It has to do with 'offset' (seek locations).
562 #if defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV) || defined(AFS_OSF_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
563 afs_readdir(OSI_VC_ARG(avc), auio, acred, eofp)
566 #if defined(AFS_HPUX100_ENV)
567 afs_readdir2(OSI_VC_ARG(avc), auio, acred)
569 afs_readdir(OSI_VC_ARG(avc), auio, acred)
574 struct AFS_UCRED *acred;
576 struct vrequest treq;
577 register struct dcache *tdc;
578 afs_size_t origOffset, tlen;
581 struct DirEntry *ode = 0, *nde = 0;
582 int o_slen = 0, n_slen = 0;
584 struct afs_fakestat_state fakestate;
585 #if defined(AFS_SGI53_ENV)
586 afs_int32 use64BitDirent, dirsiz;
587 #endif /* defined(AFS_SGI53_ENV) */
592 * XXX All the hacks for alloced sdirEntry and inlining of afs_readdir_move instead of calling
593 * it is necessary for hpux due to stack problems that seem to occur when coming thru the nfs
594 * translator side XXX
596 struct min_direct *sdirEntry =
597 (struct min_direct *)osi_AllocSmallSpace(sizeof(struct min_direct));
601 /* opaque value is pointer into a vice dir; use bit map to decide
602 * if the entries are in use. Always assumed to be valid. 0 is
603 * special, means start of a new dir. Int32 inode, followed by
604 * short reclen and short namelen. Namelen does not include
605 * the null byte. Followed by null-terminated string.
607 AFS_STATCNT(afs_readdir);
609 #if defined(AFS_SGI53_ENV)
613 ABI_IS(ABI_IRIX5_64, GETDENTS_ABI(OSI_GET_CURRENT_ABI(), auio));
617 UIO_USERSPACE) ? ABI_IRIX5_64 : (ABI_IS(ABI_IRIX5_64 | ABI_IRIX5_N32,
619 #endif /* AFS_SGI62_ENV */
620 #else /* AFS_SGI61_ENV */
623 UIO_USERSPACE) ? ABI_IRIX5_64 : (ABI_IS(ABI_IRIX5_64,
625 #endif /* AFS_SGI61_ENV */
626 #endif /* defined(AFS_SGI53_ENV) */
628 #if defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV) || defined(AFS_OSF_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
629 /* Not really used by the callee so we ignore it for now */
633 #ifndef AFS_64BIT_CLIENT
634 if (AfsLargeFileUio(auio) /* file is large than 2 GB */
635 ||AfsLargeFileSize(AFS_UIO_OFFSET(auio), AFS_UIO_RESID(auio)))
639 if ((code = afs_InitReq(&treq, acred))) {
641 osi_FreeSmallSpace((char *)sdirEntry);
645 /* update the cache entry */
646 afs_InitFakeStat(&fakestate);
647 code = afs_EvalFakeStat(&avc, &fakestate, &treq);
651 code = afs_VerifyVCache(avc, &treq);
654 /* get a reference to the entire directory */
655 tdc = afs_GetDCache(avc, (afs_size_t) 0, &treq, &origOffset, &tlen, 1);
661 ObtainReadLock(&avc->lock);
662 ObtainReadLock(&tdc->lock);
665 * Make sure that the data in the cache is current. There are two
666 * cases we need to worry about:
667 * 1. The cache data is being fetched by another process.
668 * 2. The cache data is no longer valid
670 while ((avc->states & CStatd)
671 && (tdc->dflags & DFFetching)
672 && hsame(avc->m.DataVersion, tdc->f.versionNo)) {
673 afs_Trace4(afs_iclSetp, CM_TRACE_DCACHEWAIT, ICL_TYPE_STRING,
674 __FILE__, ICL_TYPE_INT32, __LINE__, ICL_TYPE_POINTER, tdc,
675 ICL_TYPE_INT32, tdc->dflags);
676 ReleaseReadLock(&tdc->lock);
677 ReleaseReadLock(&avc->lock);
678 afs_osi_Sleep(&tdc->validPos);
679 ObtainReadLock(&avc->lock);
680 ObtainReadLock(&tdc->lock);
682 if (!(avc->states & CStatd)
683 || !hsame(avc->m.DataVersion, tdc->f.versionNo)) {
684 ReleaseReadLock(&tdc->lock);
685 ReleaseReadLock(&avc->lock);
691 * iterator for the directory reads. Takes the AFS DirEntry
692 * structure and slams them into UFS direct structures.
693 * uses afs_readdir_move to get the struct to the user space.
695 * The routine works by looking ahead one AFS directory entry.
696 * That's because the AFS entry we are currenly working with
697 * may not fit into the buffer the user has provided. If it
698 * doesn't we have to change the size of the LAST AFS directory
699 * entry, so that it will FIT perfectly into the block the
702 * The 'forward looking' of the code makes it a bit tough to read.
703 * Remember we need to get an entry, see if it it fits, then
704 * set it up as the LAST entry, and find the next one.
706 * Tough to take: We give out an EINVAL if we don't have enough
707 * space in the buffer, and at the same time, don't have an entry
708 * to put into the buffer. This CAN happen if the first AFS entry
709 * we get can't fit into the 512 character buffer provided. Seems
710 * it ought not happen...
712 * Assumption: don't need to use anything but one dc entry:
713 * this means the directory ought not be greater than 64k.
717 auio->uio_fpflags = 0;
720 origOffset = AFS_UIO_OFFSET(auio);
721 /* scan for the next interesting entry scan for in-use blob otherwise up point at
722 * this blob note that ode, if non-zero, also represents a held dir page */
723 if (!(us = BlobScan(tdc, (origOffset >> 5)))
724 || !(nde = (struct DirEntry *)afs_dir_GetBlob(tdc, us))) {
725 /* failed to setup nde, return what we've got, and release ode */
727 /* something to hand over. */
729 sdirEntry->d_fileno =
730 (avc->fid.Fid.Volume << 16) + ntohl(ode->fid.vnode);
731 FIXUPSTUPIDINODE(sdirEntry->d_fileno);
732 sdirEntry->d_reclen = rlen = AFS_UIO_RESID(auio);
733 sdirEntry->d_namlen = o_slen;
734 #if defined(AFS_SUN5_ENV) || defined(AFS_AIX32_ENV) || defined(AFS_HPUX100_ENV)
735 sdirEntry->d_off = origOffset;
737 AFS_UIOMOVE((char *)sdirEntry, sizeof(*sdirEntry), UIO_READ,
740 AFS_UIOMOVE(ode->name, o_slen, UIO_READ, auio, code);
741 /* pad out the remaining characters with zeros */
743 AFS_UIOMOVE(bufofzeros,
744 ((o_slen + 1 + DIRPAD) & ~DIRPAD) - o_slen,
745 UIO_READ, auio, code);
747 /* pad out the difference between rlen and slen... */
748 if (DIRSIZ_LEN(o_slen) < rlen) {
749 while (DIRSIZ_LEN(o_slen) < rlen) {
750 int minLen = rlen - DIRSIZ_LEN(o_slen);
751 if (minLen > sizeof(bufofzeros))
752 minLen = sizeof(bufofzeros);
753 AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
758 code = afs_readdir_move(ode, avc, auio, o_slen,
759 #if defined(AFS_SUN5_ENV)
762 AFS_UIO_RESID(auio), origOffset);
764 #endif /* AFS_HPUX_ENV */
765 #if !defined(AFS_SUN5_ENV)
766 AFS_UIO_SETRESID(auio, 0);
769 /* nothin to hand over */
771 #if defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV) || defined(AFS_OSF_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
773 *eofp = 1; /* Set it properly */
776 DRelease((struct buffer *)ode, 0);
779 /* by here nde is set */
781 /* Do we have enough user space to carry out our mission? */
782 #if defined(AFS_SGI_ENV)
783 n_slen = strlen(nde->name) + 1; /* NULL terminate */
785 n_slen = strlen(nde->name);
789 use64BitDirent ? DIRENTSIZE(n_slen) : IRIX5_DIRENTSIZE(n_slen);
790 if (dirsiz >= (AFS_UIO_RESID(auio) - len)) {
792 if (DIRSIZ_LEN(n_slen) >= (AFS_UIO_RESID(auio) - len)) {
793 #endif /* AFS_SGI53_ENV */
794 /* No can do no more now; ya know... at this time */
795 DRelease((struct buffer *)nde, 0); /* can't use this one. */
798 sdirEntry->d_fileno =
799 (avc->fid.Fid.Volume << 16) + ntohl(ode->fid.vnode);
800 FIXUPSTUPIDINODE(sdirEntry->d_fileno);
801 sdirEntry->d_reclen = rlen = AFS_UIO_RESID(auio);
802 sdirEntry->d_namlen = o_slen;
803 #if defined(AFS_SUN5_ENV) || defined(AFS_AIX32_ENV) || defined(AFS_HPUX100_ENV)
804 sdirEntry->d_off = origOffset;
806 AFS_UIOMOVE((char *)sdirEntry, sizeof(*sdirEntry), UIO_READ,
809 AFS_UIOMOVE(ode->name, o_slen, UIO_READ, auio, code);
810 /* pad out the remaining characters with zeros */
812 AFS_UIOMOVE(bufofzeros,
813 ((o_slen + 1 + DIRPAD) & ~DIRPAD) - o_slen,
814 UIO_READ, auio, code);
816 /* pad out the difference between rlen and slen... */
817 if (DIRSIZ_LEN(o_slen) < rlen) {
818 while (DIRSIZ_LEN(o_slen) < rlen) {
819 int minLen = rlen - DIRSIZ_LEN(o_slen);
820 if (minLen > sizeof(bufofzeros))
821 minLen = sizeof(bufofzeros);
822 AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
826 #else /* AFS_HPUX_ENV */
828 afs_readdir_move(ode, avc, auio, o_slen,
829 AFS_UIO_RESID(auio), origOffset);
830 #endif /* AFS_HPUX_ENV */
831 /* this next line used to be AFSVFS40 or AIX 3.1, but is
833 AFS_UIO_SETOFFSET(auio, origOffset);
834 AFS_UIO_SETRESID(auio, 0);
835 } else { /* trouble, can't give anything to the user! */
836 /* even though he has given us a buffer,
837 * even though we have something to give us,
838 * Looks like we lost something somewhere.
843 DRelease((struct buffer *)ode, 0);
848 * In any event, we move out the LAST de entry, getting ready
849 * to set up for the next one.
853 sdirEntry->d_fileno =
854 (avc->fid.Fid.Volume << 16) + ntohl(ode->fid.vnode);
855 FIXUPSTUPIDINODE(sdirEntry->d_fileno);
856 sdirEntry->d_reclen = rlen = len;
857 sdirEntry->d_namlen = o_slen;
858 #if defined(AFS_SUN5_ENV) || defined(AFS_AIX32_ENV) || defined(AFS_HPUX100_ENV)
859 sdirEntry->d_off = origOffset;
861 AFS_UIOMOVE((char *)sdirEntry, sizeof(*sdirEntry), UIO_READ, auio,
864 AFS_UIOMOVE(ode->name, o_slen, UIO_READ, auio, code);
865 /* pad out the remaining characters with zeros */
867 AFS_UIOMOVE(bufofzeros,
868 ((o_slen + 1 + DIRPAD) & ~DIRPAD) - o_slen,
869 UIO_READ, auio, code);
871 /* pad out the difference between rlen and slen... */
872 if (DIRSIZ_LEN(o_slen) < rlen) {
873 while (DIRSIZ_LEN(o_slen) < rlen) {
874 int minLen = rlen - DIRSIZ_LEN(o_slen);
875 if (minLen > sizeof(bufofzeros))
876 minLen = sizeof(bufofzeros);
877 AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
881 #else /* AFS_HPUX_ENV */
882 code = afs_readdir_move(ode, avc, auio, o_slen, len, origOffset);
883 #endif /* AFS_HPUX_ENV */
886 len = use64BitDirent ? DIRENTSIZE(o_slen =
887 n_slen) : IRIX5_DIRENTSIZE(o_slen =
890 len = DIRSIZ_LEN(o_slen = n_slen);
891 #endif /* AFS_SGI53_ENV */
893 DRelease((struct buffer *)ode, 0);
895 AFS_UIO_SETOFFSET(auio, (afs_int32) ((us + afs_dir_NameBlobs(nde->name)) << 5));
898 DRelease((struct buffer *)ode, 0);
901 ReleaseReadLock(&tdc->lock);
903 ReleaseReadLock(&avc->lock);
907 osi_FreeSmallSpace((char *)sdirEntry);
909 afs_PutFakeStat(&fakestate);
910 code = afs_CheckCode(code, &treq, 28);
914 #if defined(AFS_HPUX_ENV) || defined(AFS_OSF_ENV)
916 afs1_readdir(avc, auio, acred, eofp)
919 afs1_readdir(avc, auio, acred)
923 struct AFS_UCRED *acred;
925 struct vrequest treq;
926 register struct dcache *tdc;
927 afs_size_t origOffset, len;
929 struct DirEntry *ode = 0, *nde = 0;
930 int o_slen = 0, n_slen = 0;
932 #if defined(AFS_HPUX_ENV) || defined(AFS_OSF_ENV)
934 * XXX All the hacks for alloced sdirEntry and inlining of afs_readdir_move instead of calling
935 * it is necessary for hpux due to stack problems that seem to occur when coming thru the nfs
936 * translator side XXX
938 struct minnfs_direct *sdirEntry = (struct minnfs_direct *)
939 osi_AllocSmallSpace(sizeof(struct min_direct));
942 struct afs_fakestat_state fakestate;
944 AFS_STATCNT(afs_readdir);
945 #if defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV) || defined(AFS_OSF_ENV)
949 if (code = afs_InitReq(&treq, acred)) {
951 osi_FreeSmallSpace((char *)sdirEntry);
955 afs_InitFakeStat(&fakestate);
956 code = afs_EvalFakeStat(&avc, &fakestate, &treq);
959 osi_FreeSmallSpace((char *)sdirEntry);
961 afs_PutFakeStat(&fakestate);
964 /* update the cache entry */
966 code = afs_VerifyVCache(avc, &treq);
969 /* get a reference to the entire directory */
970 tdc = afs_GetDCache(avc, (afs_size_t) 0, &treq, &origOffset, &len, 1);
975 ObtainReadLock(&avc->lock);
976 ObtainReadLock(&tdc->lock);
979 * Make sure that the data in the cache is current. There are two
980 * cases we need to worry about:
981 * 1. The cache data is being fetched by another process.
982 * 2. The cache data is no longer valid
984 while ((avc->states & CStatd)
985 && (tdc->dflags & DFFetching)
986 && hsame(avc->m.DataVersion, tdc->f.versionNo)) {
987 afs_Trace4(afs_iclSetp, CM_TRACE_DCACHEWAIT, ICL_TYPE_STRING,
988 __FILE__, ICL_TYPE_INT32, __LINE__, ICL_TYPE_POINTER, tdc,
989 ICL_TYPE_INT32, tdc->dflags);
990 ReleaseReadLock(&tdc->lock);
991 ReleaseReadLock(&avc->lock);
992 afs_osi_Sleep(&tdc->validPos);
993 ObtainReadLock(&avc->lock);
994 ObtainReadLock(&tdc->lock);
996 if (!(avc->states & CStatd)
997 || !hsame(avc->m.DataVersion, tdc->f.versionNo)) {
998 ReleaseReadLock(&tdc->lock);
999 ReleaseReadLock(&avc->lock);
1006 auio->uio_fpflags = 0;
1009 origOffset = AFS_UIO_OFFSET(auio);
1011 /* scan for the next interesting entry scan for in-use blob otherwise up point at
1012 * this blob note that ode, if non-zero, also represents a held dir page */
1013 if (!(us = BlobScan(tdc, (origOffset >> 5)))
1014 || !(nde = (struct DirEntry *)afs_dir_GetBlob(tdc, us))) {
1015 /* failed to setup nde, return what we've got, and release ode */
1017 /* something to hand over. */
1018 #if defined(AFS_HPUX_ENV) || defined(AFS_OSF_ENV)
1019 sdirEntry->d_fileno =
1020 (avc->fid.Fid.Volume << 16) + ntohl(ode->fid.vnode);
1021 FIXUPSTUPIDINODE(sdirEntry->d_fileno);
1022 sdirEntry->d_reclen = rlen = AFS_UIO_RESID(auio);
1023 sdirEntry->d_namlen = o_slen;
1024 sdirEntry->d_off = origOffset;
1025 AFS_UIOMOVE((char *)sdirEntry, sizeof(*sdirEntry), UIO_READ,
1028 AFS_UIOMOVE(ode->name, o_slen, UIO_READ, auio, code);
1030 /* pad out the remaining characters with zeros */
1032 AFS_UIOMOVE(bufofzeros,
1033 ((o_slen + 1 + DIRPAD) & ~DIRPAD) - o_slen,
1034 UIO_READ, auio, code);
1036 /* pad out the difference between rlen and slen... */
1037 if (NDIRSIZ_LEN(o_slen) < rlen) {
1038 while (NDIRSIZ_LEN(o_slen) < rlen) {
1039 int minLen = rlen - NDIRSIZ_LEN(o_slen);
1040 if (minLen > sizeof(bufofzeros))
1041 minLen = sizeof(bufofzeros);
1042 AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
1048 afs_readdir_move(ode, avc, auio, o_slen,
1049 AFS_UIO_RESID(auio), origOffset);
1050 #endif /* AFS_HPUX_ENV */
1051 AFS_UIO_SETRESID(auio, 0);
1053 /* nothin to hand over */
1055 #if defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV) || defined(AFS_OSF_ENV)
1063 /* by here nde is set */
1065 /* Do we have enough user space to carry out our mission? */
1066 #if defined(AFS_SGI_ENV)
1067 n_slen = strlen(nde->name) + 1; /* NULL terminate */
1069 n_slen = strlen(nde->name);
1071 if (NDIRSIZ_LEN(n_slen) >= (AFS_UIO_RESID(auio) - len)) {
1072 /* No can do no more now; ya know... at this time */
1073 DRelease(nde, 0); /* can't use this one. */
1075 #if defined(AFS_HPUX_ENV) || defined(AFS_OSF_ENV)
1076 sdirEntry->d_fileno =
1077 (avc->fid.Fid.Volume << 16) + ntohl(ode->fid.vnode);
1078 FIXUPSTUPIDINODE(sdirEntry->d_fileno);
1079 sdirEntry->d_reclen = rlen = AFS_UIO_RESID(auio);
1080 sdirEntry->d_namlen = o_slen;
1081 sdirEntry->d_off = origOffset;
1082 AFS_UIOMOVE((char *)sdirEntry, sizeof(*sdirEntry), UIO_READ,
1085 AFS_UIOMOVE(ode->name, o_slen, UIO_READ, auio, code);
1086 /* pad out the remaining characters with zeros */
1088 AFS_UIOMOVE(bufofzeros,
1089 ((o_slen + 1 + DIRPAD) & ~DIRPAD) - o_slen,
1090 UIO_READ, auio, code);
1092 /* pad out the difference between rlen and slen... */
1093 if (NDIRSIZ_LEN(o_slen) < rlen) {
1094 while (NDIRSIZ_LEN(o_slen) < rlen) {
1095 int minLen = rlen - NDIRSIZ_LEN(o_slen);
1096 if (minLen > sizeof(bufofzeros))
1097 minLen = sizeof(bufofzeros);
1098 AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
1104 afs_readdir_move(ode, avc, auio, o_slen,
1105 AFS_UIO_RESID(auio), origOffset);
1106 #endif /* AFS_HPUX_ENV */
1107 /* this next line used to be AFSVFS40 or AIX 3.1, but is really generic */
1108 AFS_UIO_SETOFFSET(auio, origOffset);
1109 AFS_UIO_SETRESID(auio, 0);
1110 } else { /* trouble, can't give anything to the user! */
1111 /* even though he has given us a buffer,
1112 * even though we have something to give us,
1113 * Looks like we lost something somewhere.
1123 * In any event, we move out the LAST de entry, getting ready
1124 * to set up for the next one.
1127 #if defined(AFS_HPUX_ENV) || defined(AFS_OSF_ENV)
1128 sdirEntry->d_fileno =
1129 (avc->fid.Fid.Volume << 16) + ntohl(ode->fid.vnode);
1130 FIXUPSTUPIDINODE(sdirEntry->d_fileno);
1131 sdirEntry->d_reclen = rlen = len;
1132 sdirEntry->d_namlen = o_slen;
1133 sdirEntry->d_off = origOffset;
1134 AFS_UIOMOVE((char *)sdirEntry, sizeof(*sdirEntry), UIO_READ, auio,
1137 AFS_UIOMOVE(ode->name, o_slen, UIO_READ, auio, code);
1138 /* pad out the remaining characters with zeros */
1140 AFS_UIOMOVE(bufofzeros,
1141 ((o_slen + 1 + DIRPAD) & ~DIRPAD) - o_slen,
1142 UIO_READ, auio, code);
1144 /* pad out the difference between rlen and slen... */
1145 if (NDIRSIZ_LEN(o_slen) < rlen) {
1146 while (NDIRSIZ_LEN(o_slen) < rlen) {
1147 int minLen = rlen - NDIRSIZ_LEN(o_slen);
1148 if (minLen > sizeof(bufofzeros))
1149 minLen = sizeof(bufofzeros);
1150 AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
1155 code = afs_readdir_move(ode, avc, auio, o_slen, len, origOffset);
1156 #endif /* AFS_HPUX_ENV */
1158 len = NDIRSIZ_LEN(o_slen = n_slen);
1162 AFS_UIO_OFFSET(auio) = ((us + afs_dir_NameBlobs(nde->name)) << 5);
1168 ReleaseReadLock(&tdc->lock);
1170 ReleaseReadLock(&avc->lock);
1173 #if defined(AFS_HPUX_ENV) || defined(AFS_OSF_ENV)
1174 osi_FreeSmallSpace((char *)sdirEntry);
1176 afs_PutFakeStat(&fakestate);
1177 code = afs_CheckCode(code, &treq, 29);
1182 #endif /* !AFS_LINUX20_ENV */