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 #ifndef AFS_64BIT_CLIENT
629 if (AfsLargeFileUio(auio) /* file is large than 2 GB */
630 ||AfsLargeFileSize(auio->uio_offset, auio->uio_resid))
634 if ((code = afs_InitReq(&treq, acred))) {
636 osi_FreeSmallSpace((char *)sdirEntry);
640 /* update the cache entry */
641 afs_InitFakeStat(&fakestate);
642 code = afs_EvalFakeStat(&avc, &fakestate, &treq);
646 code = afs_VerifyVCache(avc, &treq);
649 /* get a reference to the entire directory */
650 tdc = afs_GetDCache(avc, (afs_size_t) 0, &treq, &origOffset, &tlen, 1);
656 ObtainReadLock(&avc->lock);
657 ObtainReadLock(&tdc->lock);
660 * Make sure that the data in the cache is current. There are two
661 * cases we need to worry about:
662 * 1. The cache data is being fetched by another process.
663 * 2. The cache data is no longer valid
665 while ((avc->states & CStatd)
666 && (tdc->dflags & DFFetching)
667 && hsame(avc->m.DataVersion, tdc->f.versionNo)) {
668 afs_Trace4(afs_iclSetp, CM_TRACE_DCACHEWAIT, ICL_TYPE_STRING,
669 __FILE__, ICL_TYPE_INT32, __LINE__, ICL_TYPE_POINTER, tdc,
670 ICL_TYPE_INT32, tdc->dflags);
671 ReleaseReadLock(&tdc->lock);
672 ReleaseReadLock(&avc->lock);
673 afs_osi_Sleep(&tdc->validPos);
674 ObtainReadLock(&avc->lock);
675 ObtainReadLock(&tdc->lock);
677 if (!(avc->states & CStatd)
678 || !hsame(avc->m.DataVersion, tdc->f.versionNo)) {
679 ReleaseReadLock(&tdc->lock);
680 ReleaseReadLock(&avc->lock);
686 * iterator for the directory reads. Takes the AFS DirEntry
687 * structure and slams them into UFS direct structures.
688 * uses afs_readdir_move to get the struct to the user space.
690 * The routine works by looking ahead one AFS directory entry.
691 * That's because the AFS entry we are currenly working with
692 * may not fit into the buffer the user has provided. If it
693 * doesn't we have to change the size of the LAST AFS directory
694 * entry, so that it will FIT perfectly into the block the
697 * The 'forward looking' of the code makes it a bit tough to read.
698 * Remember we need to get an entry, see if it it fits, then
699 * set it up as the LAST entry, and find the next one.
701 * Tough to take: We give out an EINVAL if we don't have enough
702 * space in the buffer, and at the same time, don't have an entry
703 * to put into the buffer. This CAN happen if the first AFS entry
704 * we get can't fit into the 512 character buffer provided. Seems
705 * it ought not happen...
707 * Assumption: don't need to use anything but one dc entry:
708 * this means the directory ought not be greater than 64k.
712 auio->uio_fpflags = 0;
715 origOffset = auio->afsio_offset;
716 /* scan for the next interesting entry scan for in-use blob otherwise up point at
717 * this blob note that ode, if non-zero, also represents a held dir page */
718 if (!(us = BlobScan(tdc, (origOffset >> 5)))
719 || !(nde = (struct DirEntry *)afs_dir_GetBlob(tdc, us))) {
720 /* failed to setup nde, return what we've got, and release ode */
722 /* something to hand over. */
724 sdirEntry->d_fileno =
725 (avc->fid.Fid.Volume << 16) + ntohl(ode->fid.vnode);
726 FIXUPSTUPIDINODE(sdirEntry->d_fileno);
727 sdirEntry->d_reclen = rlen = auio->afsio_resid;
728 sdirEntry->d_namlen = o_slen;
729 #if defined(AFS_SUN5_ENV) || defined(AFS_AIX32_ENV) || defined(AFS_HPUX100_ENV)
730 sdirEntry->d_off = origOffset;
732 AFS_UIOMOVE((char *)sdirEntry, sizeof(*sdirEntry), UIO_READ,
735 AFS_UIOMOVE(ode->name, o_slen, UIO_READ, auio, code);
736 /* pad out the remaining characters with zeros */
738 AFS_UIOMOVE(bufofzeros,
739 ((o_slen + 1 + DIRPAD) & ~DIRPAD) - o_slen,
740 UIO_READ, auio, code);
742 /* pad out the difference between rlen and slen... */
743 if (DIRSIZ_LEN(o_slen) < rlen) {
744 while (DIRSIZ_LEN(o_slen) < rlen) {
745 int minLen = rlen - DIRSIZ_LEN(o_slen);
746 if (minLen > sizeof(bufofzeros))
747 minLen = sizeof(bufofzeros);
748 AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
753 code = afs_readdir_move(ode, avc, auio, o_slen,
754 #if defined(AFS_SUN5_ENV)
757 auio->afsio_resid, origOffset);
759 #endif /* AFS_HPUX_ENV */
760 #if !defined(AFS_SUN5_ENV)
761 auio->afsio_resid = 0;
764 /* nothin to hand over */
766 #if defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV) || defined(AFS_OSF_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
768 *eofp = 1; /* Set it properly */
771 DRelease((struct buffer *)ode, 0);
774 /* by here nde is set */
776 /* Do we have enough user space to carry out our mission? */
777 #if defined(AFS_SGI_ENV)
778 n_slen = strlen(nde->name) + 1; /* NULL terminate */
780 n_slen = strlen(nde->name);
784 use64BitDirent ? DIRENTSIZE(n_slen) : IRIX5_DIRENTSIZE(n_slen);
785 if (dirsiz >= (auio->afsio_resid - len)) {
787 if (DIRSIZ_LEN(n_slen) >= (auio->afsio_resid - len)) {
788 #endif /* AFS_SGI53_ENV */
789 /* No can do no more now; ya know... at this time */
790 DRelease((struct buffer *)nde, 0); /* can't use this one. */
793 sdirEntry->d_fileno =
794 (avc->fid.Fid.Volume << 16) + ntohl(ode->fid.vnode);
795 FIXUPSTUPIDINODE(sdirEntry->d_fileno);
796 sdirEntry->d_reclen = rlen = auio->afsio_resid;
797 sdirEntry->d_namlen = o_slen;
798 #if defined(AFS_SUN5_ENV) || defined(AFS_AIX32_ENV) || defined(AFS_HPUX100_ENV)
799 sdirEntry->d_off = origOffset;
801 AFS_UIOMOVE((char *)sdirEntry, sizeof(*sdirEntry), UIO_READ,
804 AFS_UIOMOVE(ode->name, o_slen, UIO_READ, auio, code);
805 /* pad out the remaining characters with zeros */
807 AFS_UIOMOVE(bufofzeros,
808 ((o_slen + 1 + DIRPAD) & ~DIRPAD) - o_slen,
809 UIO_READ, auio, code);
811 /* pad out the difference between rlen and slen... */
812 if (DIRSIZ_LEN(o_slen) < rlen) {
813 while (DIRSIZ_LEN(o_slen) < rlen) {
814 int minLen = rlen - DIRSIZ_LEN(o_slen);
815 if (minLen > sizeof(bufofzeros))
816 minLen = sizeof(bufofzeros);
817 AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
821 #else /* AFS_HPUX_ENV */
823 afs_readdir_move(ode, avc, auio, o_slen,
824 auio->afsio_resid, origOffset);
825 #endif /* AFS_HPUX_ENV */
826 /* this next line used to be AFSVFS40 or AIX 3.1, but is
828 auio->afsio_offset = origOffset;
829 auio->afsio_resid = 0;
830 } else { /* trouble, can't give anything to the user! */
831 /* even though he has given us a buffer,
832 * even though we have something to give us,
833 * Looks like we lost something somewhere.
838 DRelease((struct buffer *)ode, 0);
843 * In any event, we move out the LAST de entry, getting ready
844 * to set up for the next one.
848 sdirEntry->d_fileno =
849 (avc->fid.Fid.Volume << 16) + ntohl(ode->fid.vnode);
850 FIXUPSTUPIDINODE(sdirEntry->d_fileno);
851 sdirEntry->d_reclen = rlen = len;
852 sdirEntry->d_namlen = o_slen;
853 #if defined(AFS_SUN5_ENV) || defined(AFS_AIX32_ENV) || defined(AFS_HPUX100_ENV)
854 sdirEntry->d_off = origOffset;
856 AFS_UIOMOVE((char *)sdirEntry, sizeof(*sdirEntry), UIO_READ, auio,
859 AFS_UIOMOVE(ode->name, o_slen, UIO_READ, auio, code);
860 /* pad out the remaining characters with zeros */
862 AFS_UIOMOVE(bufofzeros,
863 ((o_slen + 1 + DIRPAD) & ~DIRPAD) - o_slen,
864 UIO_READ, auio, code);
866 /* pad out the difference between rlen and slen... */
867 if (DIRSIZ_LEN(o_slen) < rlen) {
868 while (DIRSIZ_LEN(o_slen) < rlen) {
869 int minLen = rlen - DIRSIZ_LEN(o_slen);
870 if (minLen > sizeof(bufofzeros))
871 minLen = sizeof(bufofzeros);
872 AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
876 #else /* AFS_HPUX_ENV */
877 code = afs_readdir_move(ode, avc, auio, o_slen, len, origOffset);
878 #endif /* AFS_HPUX_ENV */
881 len = use64BitDirent ? DIRENTSIZE(o_slen =
882 n_slen) : IRIX5_DIRENTSIZE(o_slen =
885 len = DIRSIZ_LEN(o_slen = n_slen);
886 #endif /* AFS_SGI53_ENV */
888 DRelease((struct buffer *)ode, 0);
891 (afs_int32) ((us + afs_dir_NameBlobs(nde->name)) << 5);
894 DRelease((struct buffer *)ode, 0);
897 ReleaseReadLock(&tdc->lock);
899 ReleaseReadLock(&avc->lock);
903 osi_FreeSmallSpace((char *)sdirEntry);
905 afs_PutFakeStat(&fakestate);
906 code = afs_CheckCode(code, &treq, 28);
910 #if defined(AFS_HPUX_ENV) || defined(AFS_OSF_ENV)
912 afs1_readdir(avc, auio, acred, eofp)
915 afs1_readdir(avc, auio, acred)
919 struct AFS_UCRED *acred;
921 struct vrequest treq;
922 register struct dcache *tdc;
923 afs_size_t origOffset, len;
925 struct DirEntry *ode = 0, *nde = 0;
926 int o_slen = 0, n_slen = 0;
928 #if defined(AFS_HPUX_ENV) || defined(AFS_OSF_ENV)
930 * XXX All the hacks for alloced sdirEntry and inlining of afs_readdir_move instead of calling
931 * it is necessary for hpux due to stack problems that seem to occur when coming thru the nfs
932 * translator side XXX
934 struct minnfs_direct *sdirEntry = (struct minnfs_direct *)
935 osi_AllocSmallSpace(sizeof(struct min_direct));
938 struct afs_fakestat_state fakestate;
940 AFS_STATCNT(afs_readdir);
941 #if defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV) || defined(AFS_OSF_ENV)
945 if (code = afs_InitReq(&treq, acred)) {
947 osi_FreeSmallSpace((char *)sdirEntry);
951 afs_InitFakeStat(&fakestate);
952 code = afs_EvalFakeStat(&avc, &fakestate, &treq);
955 osi_FreeSmallSpace((char *)sdirEntry);
957 afs_PutFakeStat(&fakestate);
960 /* update the cache entry */
962 code = afs_VerifyVCache(avc, &treq);
965 /* get a reference to the entire directory */
966 tdc = afs_GetDCache(avc, (afs_size_t) 0, &treq, &origOffset, &len, 1);
971 ObtainReadLock(&avc->lock);
972 ObtainReadLock(&tdc->lock);
975 * Make sure that the data in the cache is current. There are two
976 * cases we need to worry about:
977 * 1. The cache data is being fetched by another process.
978 * 2. The cache data is no longer valid
980 while ((avc->states & CStatd)
981 && (tdc->dflags & DFFetching)
982 && hsame(avc->m.DataVersion, tdc->f.versionNo)) {
983 afs_Trace4(afs_iclSetp, CM_TRACE_DCACHEWAIT, ICL_TYPE_STRING,
984 __FILE__, ICL_TYPE_INT32, __LINE__, ICL_TYPE_POINTER, tdc,
985 ICL_TYPE_INT32, tdc->dflags);
986 ReleaseReadLock(&tdc->lock);
987 ReleaseReadLock(&avc->lock);
988 afs_osi_Sleep(&tdc->validPos);
989 ObtainReadLock(&avc->lock);
990 ObtainReadLock(&tdc->lock);
992 if (!(avc->states & CStatd)
993 || !hsame(avc->m.DataVersion, tdc->f.versionNo)) {
994 ReleaseReadLock(&tdc->lock);
995 ReleaseReadLock(&avc->lock);
1002 auio->uio_fpflags = 0;
1005 origOffset = auio->afsio_offset;
1007 /* scan for the next interesting entry scan for in-use blob otherwise up point at
1008 * this blob note that ode, if non-zero, also represents a held dir page */
1009 if (!(us = BlobScan(tdc, (origOffset >> 5)))
1010 || !(nde = (struct DirEntry *)afs_dir_GetBlob(tdc, us))) {
1011 /* failed to setup nde, return what we've got, and release ode */
1013 /* something to hand over. */
1014 #if defined(AFS_HPUX_ENV) || defined(AFS_OSF_ENV)
1015 sdirEntry->d_fileno =
1016 (avc->fid.Fid.Volume << 16) + ntohl(ode->fid.vnode);
1017 FIXUPSTUPIDINODE(sdirEntry->d_fileno);
1018 sdirEntry->d_reclen = rlen = auio->afsio_resid;
1019 sdirEntry->d_namlen = o_slen;
1020 sdirEntry->d_off = origOffset;
1021 AFS_UIOMOVE((char *)sdirEntry, sizeof(*sdirEntry), UIO_READ,
1024 AFS_UIOMOVE(ode->name, o_slen, UIO_READ, auio, code);
1026 /* pad out the remaining characters with zeros */
1028 AFS_UIOMOVE(bufofzeros,
1029 ((o_slen + 1 + DIRPAD) & ~DIRPAD) - o_slen,
1030 UIO_READ, auio, code);
1032 /* pad out the difference between rlen and slen... */
1033 if (NDIRSIZ_LEN(o_slen) < rlen) {
1034 while (NDIRSIZ_LEN(o_slen) < rlen) {
1035 int minLen = rlen - NDIRSIZ_LEN(o_slen);
1036 if (minLen > sizeof(bufofzeros))
1037 minLen = sizeof(bufofzeros);
1038 AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
1044 afs_readdir_move(ode, avc, auio, o_slen,
1045 auio->afsio_resid, origOffset);
1046 #endif /* AFS_HPUX_ENV */
1047 auio->afsio_resid = 0;
1049 /* nothin to hand over */
1051 #if defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV) || defined(AFS_OSF_ENV)
1059 /* by here nde is set */
1061 /* Do we have enough user space to carry out our mission? */
1062 #if defined(AFS_SGI_ENV)
1063 n_slen = strlen(nde->name) + 1; /* NULL terminate */
1065 n_slen = strlen(nde->name);
1067 if (NDIRSIZ_LEN(n_slen) >= (auio->afsio_resid - len)) {
1068 /* No can do no more now; ya know... at this time */
1069 DRelease(nde, 0); /* can't use this one. */
1071 #if defined(AFS_HPUX_ENV) || defined(AFS_OSF_ENV)
1072 sdirEntry->d_fileno =
1073 (avc->fid.Fid.Volume << 16) + ntohl(ode->fid.vnode);
1074 FIXUPSTUPIDINODE(sdirEntry->d_fileno);
1075 sdirEntry->d_reclen = rlen = auio->afsio_resid;
1076 sdirEntry->d_namlen = o_slen;
1077 sdirEntry->d_off = origOffset;
1078 AFS_UIOMOVE((char *)sdirEntry, sizeof(*sdirEntry), UIO_READ,
1081 AFS_UIOMOVE(ode->name, o_slen, UIO_READ, auio, code);
1082 /* pad out the remaining characters with zeros */
1084 AFS_UIOMOVE(bufofzeros,
1085 ((o_slen + 1 + DIRPAD) & ~DIRPAD) - o_slen,
1086 UIO_READ, auio, code);
1088 /* pad out the difference between rlen and slen... */
1089 if (NDIRSIZ_LEN(o_slen) < rlen) {
1090 while (NDIRSIZ_LEN(o_slen) < rlen) {
1091 int minLen = rlen - NDIRSIZ_LEN(o_slen);
1092 if (minLen > sizeof(bufofzeros))
1093 minLen = sizeof(bufofzeros);
1094 AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
1100 afs_readdir_move(ode, avc, auio, o_slen,
1101 auio->afsio_resid, origOffset);
1102 #endif /* AFS_HPUX_ENV */
1103 /* this next line used to be AFSVFS40 or AIX 3.1, but is really generic */
1104 auio->afsio_offset = origOffset;
1105 auio->afsio_resid = 0;
1106 } else { /* trouble, can't give anything to the user! */
1107 /* even though he has given us a buffer,
1108 * even though we have something to give us,
1109 * Looks like we lost something somewhere.
1119 * In any event, we move out the LAST de entry, getting ready
1120 * to set up for the next one.
1123 #if defined(AFS_HPUX_ENV) || defined(AFS_OSF_ENV)
1124 sdirEntry->d_fileno =
1125 (avc->fid.Fid.Volume << 16) + ntohl(ode->fid.vnode);
1126 FIXUPSTUPIDINODE(sdirEntry->d_fileno);
1127 sdirEntry->d_reclen = rlen = len;
1128 sdirEntry->d_namlen = o_slen;
1129 sdirEntry->d_off = origOffset;
1130 AFS_UIOMOVE((char *)sdirEntry, sizeof(*sdirEntry), UIO_READ, auio,
1133 AFS_UIOMOVE(ode->name, o_slen, UIO_READ, auio, code);
1134 /* pad out the remaining characters with zeros */
1136 AFS_UIOMOVE(bufofzeros,
1137 ((o_slen + 1 + DIRPAD) & ~DIRPAD) - o_slen,
1138 UIO_READ, auio, code);
1140 /* pad out the difference between rlen and slen... */
1141 if (NDIRSIZ_LEN(o_slen) < rlen) {
1142 while (NDIRSIZ_LEN(o_slen) < rlen) {
1143 int minLen = rlen - NDIRSIZ_LEN(o_slen);
1144 if (minLen > sizeof(bufofzeros))
1145 minLen = sizeof(bufofzeros);
1146 AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
1151 code = afs_readdir_move(ode, avc, auio, o_slen, len, origOffset);
1152 #endif /* AFS_HPUX_ENV */
1154 len = NDIRSIZ_LEN(o_slen = n_slen);
1158 auio->afsio_offset = ((us + afs_dir_NameBlobs(nde->name)) << 5);
1164 ReleaseReadLock(&tdc->lock);
1166 ReleaseReadLock(&avc->lock);
1169 #if defined(AFS_HPUX_ENV) || defined(AFS_OSF_ENV)
1170 osi_FreeSmallSpace((char *)sdirEntry);
1172 afs_PutFakeStat(&fakestate);
1173 code = afs_CheckCode(code, &treq, 29);
1178 #endif /* !AFS_LINUX20_ENV */