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_DARWIN_ENV) || defined(AFS_XBSD_ENV)
151 #elif defined(AFS_SUN5_ENV)
156 #if defined(AFS_AIX32_ENV)
158 #elif defined(AFS_HPUX100_ENV)
159 unsigned long long d_off;
166 #endif /* AFS_SGI_ENV */
168 #if defined(AFS_HPUX_ENV) || defined(AFS_OSF_ENV)
169 struct minnfs_direct {
170 afs_int32 d_off; /* XXX */
175 #define NDIRSIZ_LEN(len) ((sizeof (struct dirent)+4 - (MAXNAMLEN+1)) + (((len)+1 + DIRPAD) &~ DIRPAD))
177 #endif /* !defined(UKERNEL) */
181 *------------------------------------------------------------------------------
183 * Keep a stack of about 256 fids for the bulk stat call.
184 * Fill it during the readdir_move. Later empty it...
187 #define READDIR_STASH AFSCBMAX
188 struct AFSFid afs_readdir_stash[READDIR_STASH];
189 int afs_rd_stash_i = 0;
192 *------------------------------------------------------------------------------
195 * mainly a kind of macro... makes getting the struct direct
196 * out to the user space easy... could take more parameters,
197 * but now just takes what it needs.
202 #if defined(AFS_HPUX100_ENV)
203 #define DIRSIZ_LEN(len) \
204 ((sizeof (struct __dirent) - (_MAXNAMLEN+1)) + (((len)+1 + DIRPAD) &~ DIRPAD))
206 #if defined(AFS_SUN56_ENV)
207 #define DIRSIZ_LEN(len) ((18 + (len) + 1 + 7) & ~7 )
210 #define DIRSIZ_LEN(len) ((10 + (len) + 1 + (NBPW-1)) & ~(NBPW-1))
213 #define DIRSIZ_LEN(len) \
214 ((sizeof (struct dirent) - (MAXNAMLEN+1)) + (((len)+1 + 3) &~ 3))
216 #if defined(AFS_SGI_ENV)
217 #ifndef AFS_SGI53_ENV
218 /* SGI 5.3 and later use 32/64 bit versions of directory size. */
219 #define DIRSIZ_LEN(len) DIRENTSIZE(len)
221 #else /* AFS_SGI_ENV */
222 #define DIRSIZ_LEN(len) \
223 ((sizeof (struct direct) - (MAXNAMLEN+1)) + (((len)+1 + 3) &~ 3))
224 #endif /* AFS_SGI_ENV */
225 #endif /* AFS_DIRENT */
226 #endif /* AFS_SUN5_ENV */
227 #endif /* AFS_SUN56_ENV */
228 #endif /* AFS_HPUX100_ENV */
230 #if defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
232 afs_readdir_type(avc, ade)
233 struct DirEntry *ade;
236 struct VenusFid tfid;
239 tfid.Cell = avc->fid.Cell;
240 tfid.Fid.Volume = avc->fid.Fid.Volume;
241 tfid.Fid.Vnode = ntohl(ade->fid.vnode);
242 tfid.Fid.Unique = ntohl(ade->fid.vunique);
243 if ((avc->states & CForeign) == 0 && (ntohl(ade->fid.vnode) & 1)) {
245 } else if ((tvc = afs_FindVCache(&tfid, 0, 0))) {
249 } else if (((tvc->states) & (CStatd | CTruth))) {
250 /* CTruth will be set if the object has
256 else if (vtype == VREG)
258 /* Don't do this until we're sure it can't be a mtpt */
259 /* else if (vtype == VLNK)
261 /* what other types does AFS support? */
270 #define AFS_MOVE_LOCK() AFS_GLOCK()
271 #define AFS_MOVE_UNLOCK() AFS_GUNLOCK()
273 #define AFS_MOVE_LOCK()
274 #define AFS_MOVE_UNLOCK()
276 char bufofzeros[64]; /* gotta fill with something */
279 afs_readdir_move(de, vc, auio, slen, rlen, off)
293 afs_uint32 Volume = vc->fid.Fid.Volume;
294 afs_uint32 Vnode = de->fid.vnode;
295 #if defined(AFS_SUN56_ENV)
296 struct dirent64 *direntp;
298 #if defined(AFS_SUN5_ENV) || (defined(AFS_AIX51_ENV) && defined(AFS_64BIT_KERNEL))
299 struct dirent *direntp;
301 #endif /* AFS_SUN56_ENV */
302 #ifndef AFS_SGI53_ENV
303 struct min_direct sdirEntry;
304 #endif /* AFS_SGI53_ENV */
306 AFS_STATCNT(afs_readdir_move);
308 #define READDIR_CORRECT_INUMS
309 #ifdef READDIR_CORRECT_INUMS
310 if (de->name[0] == '.' && !de->name[1]) {
311 /* This is the '.' entry; if we are a volume root, we need to
312 * ignore the directory and use the inum for the mount point.
314 if (!FidCmp(&afs_rootFid, &vc->fid)) {
317 } else if (vc->mvstat == 2) {
318 tvp = afs_GetVolume(&vc->fid, 0, READ_LOCK);
320 Volume = tvp->mtpoint.Fid.Volume;
321 Vnode = tvp->mtpoint.Fid.Vnode;
322 afs_PutVolume(tvp, READ_LOCK);
326 else if (de->name[0] == '.' && de->name[1] == '.' && !de->name[2]) {
327 /* This is the '..' entry. Getting this right is very tricky,
328 * because we might be a volume root (so our parent is in a
329 * different volume), or our parent might be a volume root
330 * (so we actually want the mount point) or BOTH! */
331 if (!FidCmp(&afs_rootFid, &vc->fid)) {
332 /* We are the root of the AFS root, and thus our own parent */
335 } else if (vc->mvstat == 2) {
336 /* We are a volume root, which means our parent is in another
337 * volume. Luckily, we should have his fid cached... */
339 if (!FidCmp(&afs_rootFid, vc->mvid)) {
340 /* Parent directory is the root of the AFS root */
343 } else if (vc->mvid->Fid.Vnode == 1
344 && vc->mvid->Fid.Unique == 1) {
345 /* XXX The above test is evil and probably breaks DFS */
346 /* Parent directory is the target of a mount point */
347 tvp = afs_GetVolume(vc->mvid, 0, READ_LOCK);
349 Volume = tvp->mtpoint.Fid.Volume;
350 Vnode = tvp->mtpoint.Fid.Vnode;
351 afs_PutVolume(tvp, READ_LOCK);
354 /* Parent directory is not a volume root */
355 Volume = vc->mvid->Fid.Volume;
356 Vnode = vc->mvid->Fid.Vnode;
359 } else if (de->fid.vnode == 1 && de->fid.vunique == 1) {
360 /* XXX The above test is evil and probably breaks DFS */
361 /* Parent directory is a volume root; use the right inum */
362 tvp = afs_GetVolume(&vc->fid, 0, READ_LOCK);
364 if (tvp->cell == afs_rootFid.Cell
365 && tvp->volume == afs_rootFid.Fid.Volume) {
366 /* Parent directory is the root of the AFS root */
370 /* Parent directory is the target of a mount point */
371 Volume = tvp->mtpoint.Fid.Volume;
372 Vnode = tvp->mtpoint.Fid.Vnode;
374 afs_PutVolume(tvp, READ_LOCK);
382 afs_int32 use64BitDirent;
387 ABI_IS(ABI_IRIX5_64, GETDENTS_ABI(OSI_GET_CURRENT_ABI(), auio));
391 UIO_USERSPACE) ? ABI_IRIX5_64 : (ABI_IS(ABI_IRIX5_64 |
395 #else /* AFS_SGI61_ENV */
398 UIO_USERSPACE) ? ABI_IRIX5_64 : (ABI_IS(ABI_IRIX5_64,
400 #endif /* AFS_SGI61_ENV */
402 if (use64BitDirent) {
403 struct min_dirent sdirEntry;
404 sdirEntry.d_fileno = (Volume << 16) + ntohl(Vnode);
405 FIXUPSTUPIDINODE(sdirEntry.d_fileno);
406 sdirEntry.d_reclen = rlen;
407 sdirEntry.d_off = (off_t) off;
408 AFS_UIOMOVE(&sdirEntry, AFS_DIRENT64BASESIZE, UIO_READ, auio,
411 AFS_UIOMOVE(de->name, slen - 1, UIO_READ, auio, code);
413 AFS_UIOMOVE(bufofzeros,
414 DIRENTSIZE(slen) - (AFS_DIRENT64BASESIZE + slen -
415 1), UIO_READ, auio, code);
416 if (DIRENTSIZE(slen) < rlen) {
417 while (DIRENTSIZE(slen) < rlen) {
418 int minLen = rlen - DIRENTSIZE(slen);
419 if (minLen > sizeof(bufofzeros))
420 minLen = sizeof(bufofzeros);
421 AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
426 struct irix5_min_dirent sdirEntry;
427 sdirEntry.d_fileno = (Volume << 16) + ntohl(Vnode);
428 FIXUPSTUPIDINODE(sdirEntry.d_fileno);
429 sdirEntry.d_reclen = rlen;
430 sdirEntry.d_off = (afs_int32) off;
431 AFS_UIOMOVE(&sdirEntry, AFS_DIRENT32BASESIZE, UIO_READ, auio,
434 AFS_UIOMOVE(de->name, slen - 1, UIO_READ, auio, code);
436 AFS_UIOMOVE(bufofzeros,
437 IRIX5_DIRENTSIZE(slen) - (AFS_DIRENT32BASESIZE +
440 if (IRIX5_DIRENTSIZE(slen) < rlen) {
441 while (IRIX5_DIRENTSIZE(slen) < rlen) {
442 int minLen = rlen - IRIX5_DIRENTSIZE(slen);
443 if (minLen > sizeof(bufofzeros))
444 minLen = sizeof(bufofzeros);
445 AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
451 #else /* AFS_SGI53_ENV */
452 #if defined(AFS_SUN5_ENV) || (defined(AFS_AIX51_ENV) && defined(AFS_64BIT_KERNEL))
453 #if defined(AFS_SUN56_ENV)
454 direntp = (struct dirent64 *)osi_AllocLargeSpace(AFS_LRALLOCSIZ);
456 direntp = (struct dirent *)osi_AllocLargeSpace(AFS_LRALLOCSIZ);
458 direntp->d_ino = (Volume << 16) + ntohl(Vnode);
459 FIXUPSTUPIDINODE(direntp->d_ino);
460 #if defined(AFS_AIX51_ENV) && defined(AFS_64BIT_KERNEL)
461 direntp->d_offset = off;
462 direntp->d_namlen = slen;
464 direntp->d_off = off;
466 direntp->d_reclen = rlen;
467 strcpy(direntp->d_name, de->name);
468 AFS_UIOMOVE((caddr_t) direntp, rlen, UIO_READ, auio, code);
469 osi_FreeLargeSpace((char *)direntp);
470 #else /* AFS_SUN5_ENV */
471 /* Note the odd mechanism for building the inode number */
472 sdirEntry.d_fileno = (Volume << 16) + ntohl(Vnode);
473 FIXUPSTUPIDINODE(sdirEntry.d_fileno);
474 sdirEntry.d_reclen = rlen;
475 #if !defined(AFS_SGI_ENV)
476 sdirEntry.d_namlen = slen;
478 #if defined(AFS_AIX32_ENV) || defined(AFS_SGI_ENV)
479 sdirEntry.d_off = off;
481 #if defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
482 sdirEntry.d_type = afs_readdir_type(vc, de);
485 #if defined(AFS_SGI_ENV)
486 AFS_UIOMOVE(&sdirEntry, DIRENTBASESIZE, UIO_READ, auio, code);
488 AFS_UIOMOVE(de->name, slen - 1, UIO_READ, auio, code);
490 AFS_UIOMOVE(bufofzeros,
491 DIRSIZ_LEN(slen) - (DIRENTBASESIZE + slen - 1), UIO_READ,
493 #else /* AFS_SGI_ENV */
495 AFS_UIOMOVE((char *)&sdirEntry, sizeof(sdirEntry), UIO_READ, auio, code);
498 AFS_UIOMOVE(de->name, slen, UIO_READ, auio, code);
501 /* pad out the remaining characters with zeros */
503 AFS_UIOMOVE(bufofzeros, ((slen + 1 + DIRPAD) & ~DIRPAD) - slen,
504 UIO_READ, auio, code);
507 #endif /* AFS_SGI_ENV */
509 /* pad out the difference between rlen and slen... */
510 if (DIRSIZ_LEN(slen) < rlen) {
512 while (DIRSIZ_LEN(slen) < rlen) {
513 int minLen = rlen - DIRSIZ_LEN(slen);
514 if (minLen > sizeof(bufofzeros))
515 minLen = sizeof(bufofzeros);
516 AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
521 #endif /* AFS_SUN5_ENV */
522 #endif /* AFS_SGI53_ENV */
528 *------------------------------------------------------------------------------
530 * Read directory entries.
531 * There are some weird things to look out for here. The uio_offset
532 * field is either 0 or it is the offset returned from a previous
533 * readdir. It is an opaque value used by the server to find the
534 * correct directory block to read. The byte count must be at least
535 * vtoblksz(vp) bytes. The count field is the number of blocks to
536 * read on the server. This is advisory only, the server may return
537 * only one block's worth of entries. Entries may be compressed on
540 * This routine encodes knowledge of Vice dirs.
544 afs_bulkstat_send(avc, req)
546 struct vrequest *req;
552 * Here is the bad, bad, really bad news.
553 * It has to do with 'offset' (seek locations).
557 #if defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV) || defined(AFS_OSF_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
558 afs_readdir(OSI_VC_ARG(avc), auio, acred, eofp)
561 #if defined(AFS_HPUX100_ENV)
562 afs_readdir2(OSI_VC_ARG(avc), auio, acred)
564 afs_readdir(OSI_VC_ARG(avc), auio, acred)
569 struct AFS_UCRED *acred;
571 struct vrequest treq;
572 register struct dcache *tdc;
573 afs_size_t origOffset, tlen;
576 struct DirEntry *ode = 0, *nde = 0;
577 int o_slen = 0, n_slen = 0;
579 struct afs_fakestat_state fakestate;
580 #if defined(AFS_SGI53_ENV)
581 afs_int32 use64BitDirent, dirsiz;
582 #endif /* defined(AFS_SGI53_ENV) */
587 * XXX All the hacks for alloced sdirEntry and inlining of afs_readdir_move instead of calling
588 * it is necessary for hpux due to stack problems that seem to occur when coming thru the nfs
589 * translator side XXX
591 struct min_direct *sdirEntry =
592 (struct min_direct *)osi_AllocSmallSpace(sizeof(struct min_direct));
596 /* opaque value is pointer into a vice dir; use bit map to decide
597 * if the entries are in use. Always assumed to be valid. 0 is
598 * special, means start of a new dir. Int32 inode, followed by
599 * short reclen and short namelen. Namelen does not include
600 * the null byte. Followed by null-terminated string.
602 AFS_STATCNT(afs_readdir);
604 #if defined(AFS_SGI53_ENV)
608 ABI_IS(ABI_IRIX5_64, GETDENTS_ABI(OSI_GET_CURRENT_ABI(), auio));
612 UIO_USERSPACE) ? ABI_IRIX5_64 : (ABI_IS(ABI_IRIX5_64 | ABI_IRIX5_N32,
614 #endif /* AFS_SGI62_ENV */
615 #else /* AFS_SGI61_ENV */
618 UIO_USERSPACE) ? ABI_IRIX5_64 : (ABI_IS(ABI_IRIX5_64,
620 #endif /* AFS_SGI61_ENV */
621 #endif /* defined(AFS_SGI53_ENV) */
623 #if defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV) || defined(AFS_OSF_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
624 /* Not really used by the callee so we ignore it for now */
628 if (AfsLargeFileUio(auio) /* file is large than 2 GB */
629 ||AfsLargeFileSize(auio->uio_offset, auio->uio_resid))
632 if ((code = afs_InitReq(&treq, acred))) {
634 osi_FreeSmallSpace((char *)sdirEntry);
638 /* update the cache entry */
639 afs_InitFakeStat(&fakestate);
640 code = afs_EvalFakeStat(&avc, &fakestate, &treq);
644 code = afs_VerifyVCache(avc, &treq);
647 /* get a reference to the entire directory */
648 tdc = afs_GetDCache(avc, (afs_size_t) 0, &treq, &origOffset, &tlen, 1);
654 ObtainReadLock(&avc->lock);
655 ObtainReadLock(&tdc->lock);
658 * Make sure that the data in the cache is current. There are two
659 * cases we need to worry about:
660 * 1. The cache data is being fetched by another process.
661 * 2. The cache data is no longer valid
663 while ((avc->states & CStatd)
664 && (tdc->dflags & DFFetching)
665 && hsame(avc->m.DataVersion, tdc->f.versionNo)) {
666 afs_Trace4(afs_iclSetp, CM_TRACE_DCACHEWAIT, ICL_TYPE_STRING,
667 __FILE__, ICL_TYPE_INT32, __LINE__, ICL_TYPE_POINTER, tdc,
668 ICL_TYPE_INT32, tdc->dflags);
669 ReleaseReadLock(&tdc->lock);
670 ReleaseReadLock(&avc->lock);
671 afs_osi_Sleep(&tdc->validPos);
672 ObtainReadLock(&avc->lock);
673 ObtainReadLock(&tdc->lock);
675 if (!(avc->states & CStatd)
676 || !hsame(avc->m.DataVersion, tdc->f.versionNo)) {
677 ReleaseReadLock(&tdc->lock);
678 ReleaseReadLock(&avc->lock);
684 * iterator for the directory reads. Takes the AFS DirEntry
685 * structure and slams them into UFS direct structures.
686 * uses afs_readdir_move to get the struct to the user space.
688 * The routine works by looking ahead one AFS directory entry.
689 * That's because the AFS entry we are currenly working with
690 * may not fit into the buffer the user has provided. If it
691 * doesn't we have to change the size of the LAST AFS directory
692 * entry, so that it will FIT perfectly into the block the
695 * The 'forward looking' of the code makes it a bit tough to read.
696 * Remember we need to get an entry, see if it it fits, then
697 * set it up as the LAST entry, and find the next one.
699 * Tough to take: We give out an EINVAL if we don't have enough
700 * space in the buffer, and at the same time, don't have an entry
701 * to put into the buffer. This CAN happen if the first AFS entry
702 * we get can't fit into the 512 character buffer provided. Seems
703 * it ought not happen...
705 * Assumption: don't need to use anything but one dc entry:
706 * this means the directory ought not be greater than 64k.
710 auio->uio_fpflags = 0;
713 origOffset = auio->afsio_offset;
714 /* scan for the next interesting entry scan for in-use blob otherwise up point at
715 * this blob note that ode, if non-zero, also represents a held dir page */
716 if (!(us = BlobScan(tdc, (origOffset >> 5)))
717 || !(nde = (struct DirEntry *)afs_dir_GetBlob(tdc, us))) {
718 /* failed to setup nde, return what we've got, and release ode */
720 /* something to hand over. */
722 sdirEntry->d_fileno =
723 (avc->fid.Fid.Volume << 16) + ntohl(ode->fid.vnode);
724 FIXUPSTUPIDINODE(sdirEntry->d_fileno);
725 sdirEntry->d_reclen = rlen = auio->afsio_resid;
726 sdirEntry->d_namlen = o_slen;
727 #if defined(AFS_SUN5_ENV) || defined(AFS_AIX32_ENV) || defined(AFS_HPUX100_ENV)
728 sdirEntry->d_off = origOffset;
730 AFS_UIOMOVE((char *)sdirEntry, sizeof(*sdirEntry), UIO_READ,
733 AFS_UIOMOVE(ode->name, o_slen, UIO_READ, auio, code);
734 /* pad out the remaining characters with zeros */
736 AFS_UIOMOVE(bufofzeros,
737 ((o_slen + 1 + DIRPAD) & ~DIRPAD) - o_slen,
738 UIO_READ, auio, code);
740 /* pad out the difference between rlen and slen... */
741 if (DIRSIZ_LEN(o_slen) < rlen) {
742 while (DIRSIZ_LEN(o_slen) < rlen) {
743 int minLen = rlen - DIRSIZ_LEN(o_slen);
744 if (minLen > sizeof(bufofzeros))
745 minLen = sizeof(bufofzeros);
746 AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
751 code = afs_readdir_move(ode, avc, auio, o_slen,
752 #if defined(AFS_SUN5_ENV)
755 auio->afsio_resid, origOffset);
757 #endif /* AFS_HPUX_ENV */
758 #if !defined(AFS_SUN5_ENV)
759 auio->afsio_resid = 0;
762 /* nothin to hand over */
764 #if defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV) || defined(AFS_OSF_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
766 *eofp = 1; /* Set it properly */
769 DRelease((struct buffer *)ode, 0);
772 /* by here nde is set */
774 /* Do we have enough user space to carry out our mission? */
775 #if defined(AFS_SGI_ENV)
776 n_slen = strlen(nde->name) + 1; /* NULL terminate */
778 n_slen = strlen(nde->name);
782 use64BitDirent ? DIRENTSIZE(n_slen) : IRIX5_DIRENTSIZE(n_slen);
783 if (dirsiz >= (auio->afsio_resid - len)) {
785 if (DIRSIZ_LEN(n_slen) >= (auio->afsio_resid - len)) {
786 #endif /* AFS_SGI53_ENV */
787 /* No can do no more now; ya know... at this time */
788 DRelease((struct buffer *)nde, 0); /* can't use this one. */
791 sdirEntry->d_fileno =
792 (avc->fid.Fid.Volume << 16) + ntohl(ode->fid.vnode);
793 FIXUPSTUPIDINODE(sdirEntry->d_fileno);
794 sdirEntry->d_reclen = rlen = auio->afsio_resid;
795 sdirEntry->d_namlen = o_slen;
796 #if defined(AFS_SUN5_ENV) || defined(AFS_AIX32_ENV) || defined(AFS_HPUX100_ENV)
797 sdirEntry->d_off = origOffset;
799 AFS_UIOMOVE((char *)sdirEntry, sizeof(*sdirEntry), UIO_READ,
802 AFS_UIOMOVE(ode->name, o_slen, UIO_READ, auio, code);
803 /* pad out the remaining characters with zeros */
805 AFS_UIOMOVE(bufofzeros,
806 ((o_slen + 1 + DIRPAD) & ~DIRPAD) - o_slen,
807 UIO_READ, auio, code);
809 /* pad out the difference between rlen and slen... */
810 if (DIRSIZ_LEN(o_slen) < rlen) {
811 while (DIRSIZ_LEN(o_slen) < rlen) {
812 int minLen = rlen - DIRSIZ_LEN(o_slen);
813 if (minLen > sizeof(bufofzeros))
814 minLen = sizeof(bufofzeros);
815 AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
819 #else /* AFS_HPUX_ENV */
821 afs_readdir_move(ode, avc, auio, o_slen,
822 auio->afsio_resid, origOffset);
823 #endif /* AFS_HPUX_ENV */
824 /* this next line used to be AFSVFS40 or AIX 3.1, but is
826 auio->afsio_offset = origOffset;
827 auio->afsio_resid = 0;
828 } else { /* trouble, can't give anything to the user! */
829 /* even though he has given us a buffer,
830 * even though we have something to give us,
831 * Looks like we lost something somewhere.
836 DRelease((struct buffer *)ode, 0);
841 * In any event, we move out the LAST de entry, getting ready
842 * to set up for the next one.
846 sdirEntry->d_fileno =
847 (avc->fid.Fid.Volume << 16) + ntohl(ode->fid.vnode);
848 FIXUPSTUPIDINODE(sdirEntry->d_fileno);
849 sdirEntry->d_reclen = rlen = len;
850 sdirEntry->d_namlen = o_slen;
851 #if defined(AFS_SUN5_ENV) || defined(AFS_AIX32_ENV) || defined(AFS_HPUX100_ENV)
852 sdirEntry->d_off = origOffset;
854 AFS_UIOMOVE((char *)sdirEntry, sizeof(*sdirEntry), UIO_READ, auio,
857 AFS_UIOMOVE(ode->name, o_slen, UIO_READ, auio, code);
858 /* pad out the remaining characters with zeros */
860 AFS_UIOMOVE(bufofzeros,
861 ((o_slen + 1 + DIRPAD) & ~DIRPAD) - o_slen,
862 UIO_READ, auio, code);
864 /* pad out the difference between rlen and slen... */
865 if (DIRSIZ_LEN(o_slen) < rlen) {
866 while (DIRSIZ_LEN(o_slen) < rlen) {
867 int minLen = rlen - DIRSIZ_LEN(o_slen);
868 if (minLen > sizeof(bufofzeros))
869 minLen = sizeof(bufofzeros);
870 AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
874 #else /* AFS_HPUX_ENV */
875 code = afs_readdir_move(ode, avc, auio, o_slen, len, origOffset);
876 #endif /* AFS_HPUX_ENV */
879 len = use64BitDirent ? DIRENTSIZE(o_slen =
880 n_slen) : IRIX5_DIRENTSIZE(o_slen =
883 len = DIRSIZ_LEN(o_slen = n_slen);
884 #endif /* AFS_SGI53_ENV */
886 DRelease((struct buffer *)ode, 0);
889 (afs_int32) ((us + afs_dir_NameBlobs(nde->name)) << 5);
892 DRelease((struct buffer *)ode, 0);
895 ReleaseReadLock(&tdc->lock);
897 ReleaseReadLock(&avc->lock);
901 osi_FreeSmallSpace((char *)sdirEntry);
903 afs_PutFakeStat(&fakestate);
904 code = afs_CheckCode(code, &treq, 28);
908 #if defined(AFS_HPUX_ENV) || defined(AFS_OSF_ENV)
910 afs1_readdir(avc, auio, acred, eofp)
913 afs1_readdir(avc, auio, acred)
917 struct AFS_UCRED *acred;
919 struct vrequest treq;
920 register struct dcache *tdc;
921 afs_size_t origOffset, len;
923 struct DirEntry *ode = 0, *nde = 0;
924 int o_slen = 0, n_slen = 0;
926 #if defined(AFS_HPUX_ENV) || defined(AFS_OSF_ENV)
928 * XXX All the hacks for alloced sdirEntry and inlining of afs_readdir_move instead of calling
929 * it is necessary for hpux due to stack problems that seem to occur when coming thru the nfs
930 * translator side XXX
932 struct minnfs_direct *sdirEntry = (struct minnfs_direct *)
933 osi_AllocSmallSpace(sizeof(struct min_direct));
936 struct afs_fakestat_state fakestate;
938 AFS_STATCNT(afs_readdir);
939 #if defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV) || defined(AFS_OSF_ENV)
943 if (code = afs_InitReq(&treq, acred)) {
945 osi_FreeSmallSpace((char *)sdirEntry);
949 afs_InitFakeStat(&fakestate);
950 code = afs_EvalFakeStat(&avc, &fakestate, &treq);
953 osi_FreeSmallSpace((char *)sdirEntry);
955 afs_PutFakeStat(&fakestate);
958 /* update the cache entry */
960 code = afs_VerifyVCache(avc, &treq);
963 /* get a reference to the entire directory */
964 tdc = afs_GetDCache(avc, (afs_size_t) 0, &treq, &origOffset, &len, 1);
969 ObtainReadLock(&avc->lock);
970 ObtainReadLock(&tdc->lock);
973 * Make sure that the data in the cache is current. There are two
974 * cases we need to worry about:
975 * 1. The cache data is being fetched by another process.
976 * 2. The cache data is no longer valid
978 while ((avc->states & CStatd)
979 && (tdc->dflags & DFFetching)
980 && hsame(avc->m.DataVersion, tdc->f.versionNo)) {
981 afs_Trace4(afs_iclSetp, CM_TRACE_DCACHEWAIT, ICL_TYPE_STRING,
982 __FILE__, ICL_TYPE_INT32, __LINE__, ICL_TYPE_POINTER, tdc,
983 ICL_TYPE_INT32, tdc->dflags);
984 ReleaseReadLock(&tdc->lock);
985 ReleaseReadLock(&avc->lock);
986 afs_osi_Sleep(&tdc->validPos);
987 ObtainReadLock(&avc->lock);
988 ObtainReadLock(&tdc->lock);
990 if (!(avc->states & CStatd)
991 || !hsame(avc->m.DataVersion, tdc->f.versionNo)) {
992 ReleaseReadLock(&tdc->lock);
993 ReleaseReadLock(&avc->lock);
1000 auio->uio_fpflags = 0;
1003 origOffset = auio->afsio_offset;
1005 /* scan for the next interesting entry scan for in-use blob otherwise up point at
1006 * this blob note that ode, if non-zero, also represents a held dir page */
1007 if (!(us = BlobScan(tdc, (origOffset >> 5)))
1008 || !(nde = (struct DirEntry *)afs_dir_GetBlob(tdc, us))) {
1009 /* failed to setup nde, return what we've got, and release ode */
1011 /* something to hand over. */
1012 #if defined(AFS_HPUX_ENV) || defined(AFS_OSF_ENV)
1013 sdirEntry->d_fileno =
1014 (avc->fid.Fid.Volume << 16) + ntohl(ode->fid.vnode);
1015 FIXUPSTUPIDINODE(sdirEntry->d_fileno);
1016 sdirEntry->d_reclen = rlen = auio->afsio_resid;
1017 sdirEntry->d_namlen = o_slen;
1018 sdirEntry->d_off = origOffset;
1019 AFS_UIOMOVE((char *)sdirEntry, sizeof(*sdirEntry), UIO_READ,
1022 AFS_UIOMOVE(ode->name, o_slen, UIO_READ, auio, code);
1024 /* pad out the remaining characters with zeros */
1026 AFS_UIOMOVE(bufofzeros,
1027 ((o_slen + 1 + DIRPAD) & ~DIRPAD) - o_slen,
1028 UIO_READ, auio, code);
1030 /* pad out the difference between rlen and slen... */
1031 if (NDIRSIZ_LEN(o_slen) < rlen) {
1032 while (NDIRSIZ_LEN(o_slen) < rlen) {
1033 int minLen = rlen - NDIRSIZ_LEN(o_slen);
1034 if (minLen > sizeof(bufofzeros))
1035 minLen = sizeof(bufofzeros);
1036 AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
1042 afs_readdir_move(ode, avc, auio, o_slen,
1043 auio->afsio_resid, origOffset);
1044 #endif /* AFS_HPUX_ENV */
1045 auio->afsio_resid = 0;
1047 /* nothin to hand over */
1049 #if defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV) || defined(AFS_OSF_ENV)
1057 /* by here nde is set */
1059 /* Do we have enough user space to carry out our mission? */
1060 #if defined(AFS_SGI_ENV)
1061 n_slen = strlen(nde->name) + 1; /* NULL terminate */
1063 n_slen = strlen(nde->name);
1065 if (NDIRSIZ_LEN(n_slen) >= (auio->afsio_resid - len)) {
1066 /* No can do no more now; ya know... at this time */
1067 DRelease(nde, 0); /* can't use this one. */
1069 #if defined(AFS_HPUX_ENV) || defined(AFS_OSF_ENV)
1070 sdirEntry->d_fileno =
1071 (avc->fid.Fid.Volume << 16) + ntohl(ode->fid.vnode);
1072 FIXUPSTUPIDINODE(sdirEntry->d_fileno);
1073 sdirEntry->d_reclen = rlen = auio->afsio_resid;
1074 sdirEntry->d_namlen = o_slen;
1075 sdirEntry->d_off = origOffset;
1076 AFS_UIOMOVE((char *)sdirEntry, sizeof(*sdirEntry), UIO_READ,
1079 AFS_UIOMOVE(ode->name, o_slen, UIO_READ, auio, code);
1080 /* pad out the remaining characters with zeros */
1082 AFS_UIOMOVE(bufofzeros,
1083 ((o_slen + 1 + DIRPAD) & ~DIRPAD) - o_slen,
1084 UIO_READ, auio, code);
1086 /* pad out the difference between rlen and slen... */
1087 if (NDIRSIZ_LEN(o_slen) < rlen) {
1088 while (NDIRSIZ_LEN(o_slen) < rlen) {
1089 int minLen = rlen - NDIRSIZ_LEN(o_slen);
1090 if (minLen > sizeof(bufofzeros))
1091 minLen = sizeof(bufofzeros);
1092 AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
1098 afs_readdir_move(ode, avc, auio, o_slen,
1099 auio->afsio_resid, origOffset);
1100 #endif /* AFS_HPUX_ENV */
1101 /* this next line used to be AFSVFS40 or AIX 3.1, but is really generic */
1102 auio->afsio_offset = origOffset;
1103 auio->afsio_resid = 0;
1104 } else { /* trouble, can't give anything to the user! */
1105 /* even though he has given us a buffer,
1106 * even though we have something to give us,
1107 * Looks like we lost something somewhere.
1117 * In any event, we move out the LAST de entry, getting ready
1118 * to set up for the next one.
1121 #if defined(AFS_HPUX_ENV) || defined(AFS_OSF_ENV)
1122 sdirEntry->d_fileno =
1123 (avc->fid.Fid.Volume << 16) + ntohl(ode->fid.vnode);
1124 FIXUPSTUPIDINODE(sdirEntry->d_fileno);
1125 sdirEntry->d_reclen = rlen = len;
1126 sdirEntry->d_namlen = o_slen;
1127 sdirEntry->d_off = origOffset;
1128 AFS_UIOMOVE((char *)sdirEntry, sizeof(*sdirEntry), UIO_READ, auio,
1131 AFS_UIOMOVE(ode->name, o_slen, UIO_READ, auio, code);
1132 /* pad out the remaining characters with zeros */
1134 AFS_UIOMOVE(bufofzeros,
1135 ((o_slen + 1 + DIRPAD) & ~DIRPAD) - o_slen,
1136 UIO_READ, auio, code);
1138 /* pad out the difference between rlen and slen... */
1139 if (NDIRSIZ_LEN(o_slen) < rlen) {
1140 while (NDIRSIZ_LEN(o_slen) < rlen) {
1141 int minLen = rlen - NDIRSIZ_LEN(o_slen);
1142 if (minLen > sizeof(bufofzeros))
1143 minLen = sizeof(bufofzeros);
1144 AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
1149 code = afs_readdir_move(ode, avc, auio, o_slen, len, origOffset);
1150 #endif /* AFS_HPUX_ENV */
1152 len = NDIRSIZ_LEN(o_slen = n_slen);
1156 auio->afsio_offset = ((us + afs_dir_NameBlobs(nde->name)) << 5);
1162 ReleaseReadLock(&tdc->lock);
1164 ReleaseReadLock(&avc->lock);
1167 #if defined(AFS_HPUX_ENV) || defined(AFS_OSF_ENV)
1168 osi_FreeSmallSpace((char *)sdirEntry);
1170 afs_PutFakeStat(&fakestate);
1171 code = afs_CheckCode(code, &treq, 29);
1176 #endif /* !AFS_LINUX20_ENV */