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 fcache * 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)
157 #if defined(AFS_SUN_ENV) || defined(AFS_AIX32_ENV)
160 #if defined(AFS_HPUX100_ENV)
161 unsigned long long d_off;
169 #endif /* AFS_SGI_ENV */
171 #if defined(AFS_HPUX_ENV) || defined(AFS_OSF_ENV)
172 struct minnfs_direct {
173 afs_int32 d_off; /* XXX */
178 #define NDIRSIZ_LEN(len) ((sizeof (struct dirent)+4 - (MAXNAMLEN+1)) + (((len)+1 + DIRPAD) &~ DIRPAD))
180 #endif /* !defined(UKERNEL) */
184 *------------------------------------------------------------------------------
186 * Keep a stack of about 256 fids for the bulk stat call.
187 * Fill it during the readdir_move. Later empty it...
190 #define READDIR_STASH AFSCBMAX
191 struct AFSFid afs_readdir_stash[READDIR_STASH];
192 int afs_rd_stash_i = 0;
195 *------------------------------------------------------------------------------
198 * mainly a kind of macro... makes getting the struct direct
199 * out to the user space easy... could take more parameters,
200 * but now just takes what it needs.
205 #if defined(AFS_HPUX100_ENV)
206 #define DIRSIZ_LEN(len) \
207 ((sizeof (struct __dirent) - (_MAXNAMLEN+1)) + (((len)+1 + DIRPAD) &~ DIRPAD))
209 #if defined(AFS_SUN56_ENV)
210 #define DIRSIZ_LEN(len) ((18 + (len) + 1 + 7) & ~7 )
213 #define DIRSIZ_LEN(len) ((10 + (len) + 1 + (NBPW-1)) & ~(NBPW-1))
216 #define DIRSIZ_LEN(len) \
217 ((sizeof (struct dirent) - (MAXNAMLEN+1)) + (((len)+1 + 3) &~ 3))
219 #if defined(AFS_SGI_ENV)
220 #ifndef AFS_SGI53_ENV
221 /* SGI 5.3 and later use 32/64 bit versions of directory size. */
222 #define DIRSIZ_LEN(len) DIRENTSIZE(len)
224 #else /* AFS_SGI_ENV */
225 #define DIRSIZ_LEN(len) \
226 ((sizeof (struct direct) - (MAXNAMLEN+1)) + (((len)+1 + 3) &~ 3))
227 #endif /* AFS_SGI_ENV */
228 #endif /* AFS_DIRENT */
229 #endif /* AFS_SUN5_ENV */
230 #endif /* AFS_SUN56_ENV */
231 #endif /* AFS_HPUX100_ENV */
233 #if defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
235 afs_readdir_type(avc, ade)
236 struct DirEntry *ade;
239 struct VenusFid tfid;
242 tfid.Cell = avc->fid.Cell;
243 tfid.Fid.Volume = avc->fid.Fid.Volume;
244 tfid.Fid.Vnode = ntohl(ade->fid.vnode);
245 tfid.Fid.Unique = ntohl(ade->fid.vunique);
246 if ((avc->states & CForeign) == 0 && (ntohl(ade->fid.vnode) & 1)) {
248 } else if ((tvc = afs_FindVCache(&tfid, 0, 0))) {
252 } else if (((tvc->states) & (CStatd | CTruth))) {
253 /* CTruth will be set if the object has
259 else if (vtype == VREG)
261 /* Don't do this until we're sure it can't be a mtpt */
262 /* else if (vtype == VLNK)
264 /* what other types does AFS support? */
273 #define AFS_MOVE_LOCK() AFS_GLOCK()
274 #define AFS_MOVE_UNLOCK() AFS_GUNLOCK()
276 #define AFS_MOVE_LOCK()
277 #define AFS_MOVE_UNLOCK()
279 char bufofzeros[64]; /* gotta fill with something */
282 afs_readdir_move(de, vc, auio, slen, rlen, off)
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);
309 afs_int32 use64BitDirent;
314 ABI_IS(ABI_IRIX5_64, GETDENTS_ABI(OSI_GET_CURRENT_ABI(), auio));
318 UIO_USERSPACE) ? ABI_IRIX5_64 : (ABI_IS(ABI_IRIX5_64 |
322 #else /* AFS_SGI61_ENV */
325 UIO_USERSPACE) ? ABI_IRIX5_64 : (ABI_IS(ABI_IRIX5_64,
327 #endif /* AFS_SGI61_ENV */
329 if (use64BitDirent) {
330 struct min_dirent sdirEntry;
332 (vc->fid.Fid.Volume << 16) + ntohl(de->fid.vnode);
333 FIXUPSTUPIDINODE(sdirEntry.d_fileno);
334 sdirEntry.d_reclen = rlen;
335 sdirEntry.d_off = (off_t) off;
336 AFS_UIOMOVE(&sdirEntry, AFS_DIRENT64BASESIZE, UIO_READ, auio,
339 AFS_UIOMOVE(de->name, slen - 1, UIO_READ, auio, code);
341 AFS_UIOMOVE(bufofzeros,
342 DIRENTSIZE(slen) - (AFS_DIRENT64BASESIZE + slen -
343 1), UIO_READ, auio, code);
344 if (DIRENTSIZE(slen) < rlen) {
345 while (DIRENTSIZE(slen) < rlen) {
346 int minLen = rlen - DIRENTSIZE(slen);
347 if (minLen > sizeof(bufofzeros))
348 minLen = sizeof(bufofzeros);
349 AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
354 struct irix5_min_dirent sdirEntry;
356 (vc->fid.Fid.Volume << 16) + ntohl(de->fid.vnode);
357 FIXUPSTUPIDINODE(sdirEntry.d_fileno);
358 sdirEntry.d_reclen = rlen;
359 sdirEntry.d_off = (afs_int32) off;
360 AFS_UIOMOVE(&sdirEntry, AFS_DIRENT32BASESIZE, UIO_READ, auio,
363 AFS_UIOMOVE(de->name, slen - 1, UIO_READ, auio, code);
365 AFS_UIOMOVE(bufofzeros,
366 IRIX5_DIRENTSIZE(slen) - (AFS_DIRENT32BASESIZE +
369 if (IRIX5_DIRENTSIZE(slen) < rlen) {
370 while (IRIX5_DIRENTSIZE(slen) < rlen) {
371 int minLen = rlen - IRIX5_DIRENTSIZE(slen);
372 if (minLen > sizeof(bufofzeros))
373 minLen = sizeof(bufofzeros);
374 AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
380 #else /* AFS_SGI53_ENV */
381 #if defined(AFS_SUN5_ENV) || (defined(AFS_AIX51_ENV) && defined(AFS_64BIT_KERNEL))
382 #if defined(AFS_SUN56_ENV)
383 direntp = (struct dirent64 *)osi_AllocLargeSpace(AFS_LRALLOCSIZ);
385 direntp = (struct dirent *)osi_AllocLargeSpace(AFS_LRALLOCSIZ);
387 direntp->d_ino = (vc->fid.Fid.Volume << 16) + ntohl(de->fid.vnode);
388 FIXUPSTUPIDINODE(direntp->d_ino);
389 #if defined(AFS_AIX51_ENV) && defined(AFS_64BIT_KERNEL)
390 direntp->d_offset = off;
391 direntp->d_namlen = slen;
393 direntp->d_off = off;
395 direntp->d_reclen = rlen;
396 strcpy(direntp->d_name, de->name);
397 AFS_UIOMOVE((caddr_t) direntp, rlen, UIO_READ, auio, code);
398 osi_FreeLargeSpace((char *)direntp);
399 #else /* AFS_SUN5_ENV */
400 /* Note the odd mechanism for building the inode number */
401 sdirEntry.d_fileno = (vc->fid.Fid.Volume << 16) + ntohl(de->fid.vnode);
402 FIXUPSTUPIDINODE(sdirEntry.d_fileno);
403 sdirEntry.d_reclen = rlen;
404 #if !defined(AFS_SGI_ENV)
405 sdirEntry.d_namlen = slen;
407 #if defined(AFS_SUN_ENV) || defined(AFS_AIX32_ENV) || defined(AFS_SGI_ENV)
408 sdirEntry.d_off = off;
410 #if defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
411 sdirEntry.d_type = afs_readdir_type(vc, de);
414 #if defined(AFS_SGI_ENV)
415 AFS_UIOMOVE(&sdirEntry, DIRENTBASESIZE, UIO_READ, auio, code);
417 AFS_UIOMOVE(de->name, slen - 1, UIO_READ, auio, code);
419 AFS_UIOMOVE(bufofzeros,
420 DIRSIZ_LEN(slen) - (DIRENTBASESIZE + slen - 1), UIO_READ,
422 #else /* AFS_SGI_ENV */
424 AFS_UIOMOVE((char *)&sdirEntry, sizeof(sdirEntry), UIO_READ, auio, code);
427 AFS_UIOMOVE(de->name, slen, UIO_READ, auio, code);
430 /* pad out the remaining characters with zeros */
432 AFS_UIOMOVE(bufofzeros, ((slen + 1 + DIRPAD) & ~DIRPAD) - slen,
433 UIO_READ, auio, code);
436 #endif /* AFS_SGI_ENV */
438 /* pad out the difference between rlen and slen... */
439 if (DIRSIZ_LEN(slen) < rlen) {
441 while (DIRSIZ_LEN(slen) < rlen) {
442 int minLen = rlen - DIRSIZ_LEN(slen);
443 if (minLen > sizeof(bufofzeros))
444 minLen = sizeof(bufofzeros);
445 AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
450 #endif /* AFS_SUN5_ENV */
451 #endif /* AFS_SGI53_ENV */
457 *------------------------------------------------------------------------------
459 * Read directory entries.
460 * There are some weird things to look out for here. The uio_offset
461 * field is either 0 or it is the offset returned from a previous
462 * readdir. It is an opaque value used by the server to find the
463 * correct directory block to read. The byte count must be at least
464 * vtoblksz(vp) bytes. The count field is the number of blocks to
465 * read on the server. This is advisory only, the server may return
466 * only one block's worth of entries. Entries may be compressed on
469 * This routine encodes knowledge of Vice dirs.
473 afs_bulkstat_send(avc, req)
475 struct vrequest *req;
481 * Here is the bad, bad, really bad news.
482 * It has to do with 'offset' (seek locations).
486 #if defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV) || defined(AFS_OSF_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
487 afs_readdir(OSI_VC_ARG(avc), auio, acred, eofp)
490 #if defined(AFS_HPUX100_ENV)
491 afs_readdir2(OSI_VC_ARG(avc), auio, acred)
493 afs_readdir(OSI_VC_ARG(avc), auio, acred)
498 struct AFS_UCRED *acred;
500 struct vrequest treq;
501 register struct dcache *tdc;
502 afs_size_t origOffset, tlen;
505 struct DirEntry *ode = 0, *nde = 0;
506 int o_slen = 0, n_slen = 0;
508 struct afs_fakestat_state fakestate;
509 #if defined(AFS_SGI53_ENV)
510 afs_int32 use64BitDirent, dirsiz;
511 #endif /* defined(AFS_SGI53_ENV) */
515 * XXX All the hacks for alloced sdirEntry and inlining of afs_readdir_move instead of calling
516 * it is necessary for hpux due to stack problems that seem to occur when coming thru the nfs
517 * translator side XXX
519 struct min_direct *sdirEntry =
520 (struct min_direct *)osi_AllocSmallSpace(sizeof(struct min_direct));
524 /* opaque value is pointer into a vice dir; use bit map to decide
525 * if the entries are in use. Always assumed to be valid. 0 is
526 * special, means start of a new dir. Int32 inode, followed by
527 * short reclen and short namelen. Namelen does not include
528 * the null byte. Followed by null-terminated string.
530 AFS_STATCNT(afs_readdir);
532 #if defined(AFS_SGI53_ENV)
536 ABI_IS(ABI_IRIX5_64, GETDENTS_ABI(OSI_GET_CURRENT_ABI(), auio));
540 UIO_USERSPACE) ? ABI_IRIX5_64 : (ABI_IS(ABI_IRIX5_64 | ABI_IRIX5_N32,
542 #endif /* AFS_SGI62_ENV */
543 #else /* AFS_SGI61_ENV */
546 UIO_USERSPACE) ? ABI_IRIX5_64 : (ABI_IS(ABI_IRIX5_64,
548 #endif /* AFS_SGI61_ENV */
549 #endif /* defined(AFS_SGI53_ENV) */
551 #if defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV) || defined(AFS_OSF_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
552 /* Not really used by the callee so we ignore it for now */
556 if (AfsLargeFileUio(auio) /* file is large than 2 GB */
557 ||AfsLargeFileSize(auio->uio_offset, auio->uio_resid))
560 if ((code = afs_InitReq(&treq, acred))) {
562 osi_FreeSmallSpace((char *)sdirEntry);
566 /* update the cache entry */
567 afs_InitFakeStat(&fakestate);
568 code = afs_EvalFakeStat(&avc, &fakestate, &treq);
572 code = afs_VerifyVCache(avc, &treq);
575 /* get a reference to the entire directory */
576 tdc = afs_GetDCache(avc, (afs_size_t) 0, &treq, &origOffset, &tlen, 1);
582 ObtainReadLock(&avc->lock);
583 ObtainReadLock(&tdc->lock);
586 * Make sure that the data in the cache is current. There are two
587 * cases we need to worry about:
588 * 1. The cache data is being fetched by another process.
589 * 2. The cache data is no longer valid
591 while ((avc->states & CStatd)
592 && (tdc->dflags & DFFetching)
593 && hsame(avc->m.DataVersion, tdc->f.versionNo)) {
594 afs_Trace4(afs_iclSetp, CM_TRACE_DCACHEWAIT, ICL_TYPE_STRING,
595 __FILE__, ICL_TYPE_INT32, __LINE__, ICL_TYPE_POINTER, tdc,
596 ICL_TYPE_INT32, tdc->dflags);
597 ReleaseReadLock(&tdc->lock);
598 ReleaseReadLock(&avc->lock);
599 afs_osi_Sleep(&tdc->validPos);
600 ObtainReadLock(&avc->lock);
601 ObtainReadLock(&tdc->lock);
603 if (!(avc->states & CStatd)
604 || !hsame(avc->m.DataVersion, tdc->f.versionNo)) {
605 ReleaseReadLock(&tdc->lock);
606 ReleaseReadLock(&avc->lock);
612 * iterator for the directory reads. Takes the AFS DirEntry
613 * structure and slams them into UFS direct structures.
614 * uses afs_readdir_move to get the struct to the user space.
616 * The routine works by looking ahead one AFS directory entry.
617 * That's because the AFS entry we are currenly working with
618 * may not fit into the buffer the user has provided. If it
619 * doesn't we have to change the size of the LAST AFS directory
620 * entry, so that it will FIT perfectly into the block the
623 * The 'forward looking' of the code makes it a bit tough to read.
624 * Remember we need to get an entry, see if it it fits, then
625 * set it up as the LAST entry, and find the next one.
627 * Tough to take: We give out an EINVAL if we don't have enough
628 * space in the buffer, and at the same time, don't have an entry
629 * to put into the buffer. This CAN happen if the first AFS entry
630 * we get can't fit into the 512 character buffer provided. Seems
631 * it ought not happen...
633 * Assumption: don't need to use anything but one dc entry:
634 * this means the directory ought not be greater than 64k.
638 auio->uio_fpflags = 0;
641 origOffset = auio->afsio_offset;
642 /* scan for the next interesting entry scan for in-use blob otherwise up point at
643 * this blob note that ode, if non-zero, also represents a held dir page */
644 if (!(us = BlobScan(&tdc->f, (origOffset >> 5)))
645 || !(nde = (struct DirEntry *)afs_dir_GetBlob(&tdc->f, us))) {
646 /* failed to setup nde, return what we've got, and release ode */
648 /* something to hand over. */
650 sdirEntry->d_fileno =
651 (avc->fid.Fid.Volume << 16) + ntohl(ode->fid.vnode);
652 FIXUPSTUPIDINODE(sdirEntry->d_fileno);
653 sdirEntry->d_reclen = rlen = auio->afsio_resid;
654 sdirEntry->d_namlen = o_slen;
655 #if defined(AFS_SUN_ENV) || defined(AFS_AIX32_ENV) || defined(AFS_HPUX100_ENV)
656 sdirEntry->d_off = origOffset;
658 AFS_UIOMOVE((char *)sdirEntry, sizeof(*sdirEntry), UIO_READ,
661 AFS_UIOMOVE(ode->name, o_slen, UIO_READ, auio, code);
662 /* pad out the remaining characters with zeros */
664 AFS_UIOMOVE(bufofzeros,
665 ((o_slen + 1 + DIRPAD) & ~DIRPAD) - o_slen,
666 UIO_READ, auio, code);
668 /* pad out the difference between rlen and slen... */
669 if (DIRSIZ_LEN(o_slen) < rlen) {
670 while (DIRSIZ_LEN(o_slen) < rlen) {
671 int minLen = rlen - DIRSIZ_LEN(o_slen);
672 if (minLen > sizeof(bufofzeros))
673 minLen = sizeof(bufofzeros);
674 AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
679 code = afs_readdir_move(ode, avc, auio, o_slen,
680 #if defined(AFS_SUN5_ENV)
683 auio->afsio_resid, origOffset);
685 #endif /* AFS_HPUX_ENV */
686 #if !defined(AFS_SUN5_ENV)
687 auio->afsio_resid = 0;
690 /* nothin to hand over */
692 #if defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV) || defined(AFS_OSF_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
694 *eofp = 1; /* Set it properly */
697 DRelease((struct buffer *)ode, 0);
700 /* by here nde is set */
702 /* Do we have enough user space to carry out our mission? */
703 #if defined(AFS_SGI_ENV)
704 n_slen = strlen(nde->name) + 1; /* NULL terminate */
706 n_slen = strlen(nde->name);
710 use64BitDirent ? DIRENTSIZE(n_slen) : IRIX5_DIRENTSIZE(n_slen);
711 if (dirsiz >= (auio->afsio_resid - len)) {
713 if (DIRSIZ_LEN(n_slen) >= (auio->afsio_resid - len)) {
714 #endif /* AFS_SGI53_ENV */
715 /* No can do no more now; ya know... at this time */
716 DRelease((struct buffer *)nde, 0); /* can't use this one. */
719 sdirEntry->d_fileno =
720 (avc->fid.Fid.Volume << 16) + ntohl(ode->fid.vnode);
721 FIXUPSTUPIDINODE(sdirEntry->d_fileno);
722 sdirEntry->d_reclen = rlen = auio->afsio_resid;
723 sdirEntry->d_namlen = o_slen;
724 #if defined(AFS_SUN_ENV) || defined(AFS_AIX32_ENV) || defined(AFS_HPUX100_ENV)
725 sdirEntry->d_off = origOffset;
727 AFS_UIOMOVE((char *)sdirEntry, sizeof(*sdirEntry), UIO_READ,
730 AFS_UIOMOVE(ode->name, o_slen, UIO_READ, auio, code);
731 /* pad out the remaining characters with zeros */
733 AFS_UIOMOVE(bufofzeros,
734 ((o_slen + 1 + DIRPAD) & ~DIRPAD) - o_slen,
735 UIO_READ, auio, code);
737 /* pad out the difference between rlen and slen... */
738 if (DIRSIZ_LEN(o_slen) < rlen) {
739 while (DIRSIZ_LEN(o_slen) < rlen) {
740 int minLen = rlen - DIRSIZ_LEN(o_slen);
741 if (minLen > sizeof(bufofzeros))
742 minLen = sizeof(bufofzeros);
743 AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
747 #else /* AFS_HPUX_ENV */
749 afs_readdir_move(ode, avc, auio, o_slen,
750 auio->afsio_resid, origOffset);
751 #endif /* AFS_HPUX_ENV */
752 /* this next line used to be AFSVFS40 or AIX 3.1, but is
754 auio->afsio_offset = origOffset;
755 auio->afsio_resid = 0;
756 } else { /* trouble, can't give anything to the user! */
757 /* even though he has given us a buffer,
758 * even though we have something to give us,
759 * Looks like we lost something somewhere.
764 DRelease((struct buffer *)ode, 0);
769 * In any event, we move out the LAST de entry, getting ready
770 * to set up for the next one.
774 sdirEntry->d_fileno =
775 (avc->fid.Fid.Volume << 16) + ntohl(ode->fid.vnode);
776 FIXUPSTUPIDINODE(sdirEntry->d_fileno);
777 sdirEntry->d_reclen = rlen = len;
778 sdirEntry->d_namlen = o_slen;
779 #if defined(AFS_SUN_ENV) || defined(AFS_AIX32_ENV) || defined(AFS_HPUX100_ENV)
780 sdirEntry->d_off = origOffset;
782 AFS_UIOMOVE((char *)sdirEntry, sizeof(*sdirEntry), UIO_READ, auio,
785 AFS_UIOMOVE(ode->name, o_slen, UIO_READ, auio, code);
786 /* pad out the remaining characters with zeros */
788 AFS_UIOMOVE(bufofzeros,
789 ((o_slen + 1 + DIRPAD) & ~DIRPAD) - o_slen,
790 UIO_READ, auio, code);
792 /* pad out the difference between rlen and slen... */
793 if (DIRSIZ_LEN(o_slen) < rlen) {
794 while (DIRSIZ_LEN(o_slen) < rlen) {
795 int minLen = rlen - DIRSIZ_LEN(o_slen);
796 if (minLen > sizeof(bufofzeros))
797 minLen = sizeof(bufofzeros);
798 AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
802 #else /* AFS_HPUX_ENV */
803 code = afs_readdir_move(ode, avc, auio, o_slen, len, origOffset);
804 #endif /* AFS_HPUX_ENV */
807 len = use64BitDirent ? DIRENTSIZE(o_slen =
808 n_slen) : IRIX5_DIRENTSIZE(o_slen =
811 len = DIRSIZ_LEN(o_slen = n_slen);
812 #endif /* AFS_SGI53_ENV */
814 DRelease((struct buffer *)ode, 0);
817 (afs_int32) ((us + afs_dir_NameBlobs(nde->name)) << 5);
820 DRelease((struct buffer *)ode, 0);
823 ReleaseReadLock(&tdc->lock);
825 ReleaseReadLock(&avc->lock);
829 osi_FreeSmallSpace((char *)sdirEntry);
831 afs_PutFakeStat(&fakestate);
832 code = afs_CheckCode(code, &treq, 28);
836 #if defined(AFS_HPUX_ENV) || defined(AFS_OSF_ENV)
838 afs1_readdir(avc, auio, acred, eofp)
841 afs1_readdir(avc, auio, acred)
845 struct AFS_UCRED *acred;
847 struct vrequest treq;
848 register struct dcache *tdc;
849 afs_size_t origOffset, len;
851 struct DirEntry *ode = 0, *nde = 0;
852 int o_slen = 0, n_slen = 0;
854 #if defined(AFS_HPUX_ENV) || defined(AFS_OSF_ENV)
856 * XXX All the hacks for alloced sdirEntry and inlining of afs_readdir_move instead of calling
857 * it is necessary for hpux due to stack problems that seem to occur when coming thru the nfs
858 * translator side XXX
860 struct minnfs_direct *sdirEntry = (struct minnfs_direct *)
861 osi_AllocSmallSpace(sizeof(struct min_direct));
864 struct afs_fakestat_state fakestate;
866 AFS_STATCNT(afs_readdir);
867 #if defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV) || defined(AFS_OSF_ENV)
871 if (code = afs_InitReq(&treq, acred)) {
873 osi_FreeSmallSpace((char *)sdirEntry);
877 afs_InitFakeStat(&fakestate);
878 code = afs_EvalFakeStat(&avc, &fakestate, &treq);
881 osi_FreeSmallSpace((char *)sdirEntry);
883 afs_PutFakeStat(&fakestate);
886 /* update the cache entry */
888 code = afs_VerifyVCache(avc, &treq);
891 /* get a reference to the entire directory */
892 tdc = afs_GetDCache(avc, (afs_size_t) 0, &treq, &origOffset, &len, 1);
897 ObtainReadLock(&avc->lock);
898 ObtainReadLock(&tdc->lock);
901 * Make sure that the data in the cache is current. There are two
902 * cases we need to worry about:
903 * 1. The cache data is being fetched by another process.
904 * 2. The cache data is no longer valid
906 while ((avc->states & CStatd)
907 && (tdc->dflags & DFFetching)
908 && hsame(avc->m.DataVersion, tdc->f.versionNo)) {
909 afs_Trace4(afs_iclSetp, CM_TRACE_DCACHEWAIT, ICL_TYPE_STRING,
910 __FILE__, ICL_TYPE_INT32, __LINE__, ICL_TYPE_POINTER, tdc,
911 ICL_TYPE_INT32, tdc->dflags);
912 ReleaseReadLock(&tdc->lock);
913 ReleaseReadLock(&avc->lock);
914 afs_osi_Sleep(&tdc->validPos);
915 ObtainReadLock(&avc->lock);
916 ObtainReadLock(&tdc->lock);
918 if (!(avc->states & CStatd)
919 || !hsame(avc->m.DataVersion, tdc->f.versionNo)) {
920 ReleaseReadLock(&tdc->lock);
921 ReleaseReadLock(&avc->lock);
928 auio->uio_fpflags = 0;
931 origOffset = auio->afsio_offset;
933 /* scan for the next interesting entry scan for in-use blob otherwise up point at
934 * this blob note that ode, if non-zero, also represents a held dir page */
935 if (!(us = BlobScan(&tdc->f, (origOffset >> 5)))
936 || !(nde = (struct DirEntry *)afs_dir_GetBlob(&tdc->f, us))) {
937 /* failed to setup nde, return what we've got, and release ode */
939 /* something to hand over. */
940 #if defined(AFS_HPUX_ENV) || defined(AFS_OSF_ENV)
941 sdirEntry->d_fileno =
942 (avc->fid.Fid.Volume << 16) + ntohl(ode->fid.vnode);
943 FIXUPSTUPIDINODE(sdirEntry->d_fileno);
944 sdirEntry->d_reclen = rlen = auio->afsio_resid;
945 sdirEntry->d_namlen = o_slen;
946 sdirEntry->d_off = origOffset;
947 AFS_UIOMOVE((char *)sdirEntry, sizeof(*sdirEntry), UIO_READ,
950 AFS_UIOMOVE(ode->name, o_slen, UIO_READ, auio, code);
952 /* pad out the remaining characters with zeros */
954 AFS_UIOMOVE(bufofzeros,
955 ((o_slen + 1 + DIRPAD) & ~DIRPAD) - o_slen,
956 UIO_READ, auio, code);
958 /* pad out the difference between rlen and slen... */
959 if (NDIRSIZ_LEN(o_slen) < rlen) {
960 while (NDIRSIZ_LEN(o_slen) < rlen) {
961 int minLen = rlen - NDIRSIZ_LEN(o_slen);
962 if (minLen > sizeof(bufofzeros))
963 minLen = sizeof(bufofzeros);
964 AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
970 afs_readdir_move(ode, avc, auio, o_slen,
971 auio->afsio_resid, origOffset);
972 #endif /* AFS_HPUX_ENV */
973 auio->afsio_resid = 0;
975 /* nothin to hand over */
977 #if defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV) || defined(AFS_OSF_ENV)
985 /* by here nde is set */
987 /* Do we have enough user space to carry out our mission? */
988 #if defined(AFS_SGI_ENV)
989 n_slen = strlen(nde->name) + 1; /* NULL terminate */
991 n_slen = strlen(nde->name);
993 if (NDIRSIZ_LEN(n_slen) >= (auio->afsio_resid - len)) {
994 /* No can do no more now; ya know... at this time */
995 DRelease(nde, 0); /* can't use this one. */
997 #if defined(AFS_HPUX_ENV) || defined(AFS_OSF_ENV)
998 sdirEntry->d_fileno =
999 (avc->fid.Fid.Volume << 16) + ntohl(ode->fid.vnode);
1000 FIXUPSTUPIDINODE(sdirEntry->d_fileno);
1001 sdirEntry->d_reclen = rlen = auio->afsio_resid;
1002 sdirEntry->d_namlen = o_slen;
1003 sdirEntry->d_off = origOffset;
1004 AFS_UIOMOVE((char *)sdirEntry, sizeof(*sdirEntry), UIO_READ,
1007 AFS_UIOMOVE(ode->name, o_slen, UIO_READ, auio, code);
1008 /* pad out the remaining characters with zeros */
1010 AFS_UIOMOVE(bufofzeros,
1011 ((o_slen + 1 + DIRPAD) & ~DIRPAD) - o_slen,
1012 UIO_READ, auio, code);
1014 /* pad out the difference between rlen and slen... */
1015 if (NDIRSIZ_LEN(o_slen) < rlen) {
1016 while (NDIRSIZ_LEN(o_slen) < rlen) {
1017 int minLen = rlen - NDIRSIZ_LEN(o_slen);
1018 if (minLen > sizeof(bufofzeros))
1019 minLen = sizeof(bufofzeros);
1020 AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
1026 afs_readdir_move(ode, avc, auio, o_slen,
1027 auio->afsio_resid, origOffset);
1028 #endif /* AFS_HPUX_ENV */
1029 /* this next line used to be AFSVFS40 or AIX 3.1, but is really generic */
1030 auio->afsio_offset = origOffset;
1031 auio->afsio_resid = 0;
1032 } else { /* trouble, can't give anything to the user! */
1033 /* even though he has given us a buffer,
1034 * even though we have something to give us,
1035 * Looks like we lost something somewhere.
1045 * In any event, we move out the LAST de entry, getting ready
1046 * to set up for the next one.
1049 #if defined(AFS_HPUX_ENV) || defined(AFS_OSF_ENV)
1050 sdirEntry->d_fileno =
1051 (avc->fid.Fid.Volume << 16) + ntohl(ode->fid.vnode);
1052 FIXUPSTUPIDINODE(sdirEntry->d_fileno);
1053 sdirEntry->d_reclen = rlen = len;
1054 sdirEntry->d_namlen = o_slen;
1055 sdirEntry->d_off = origOffset;
1056 AFS_UIOMOVE((char *)sdirEntry, sizeof(*sdirEntry), UIO_READ, auio,
1059 AFS_UIOMOVE(ode->name, o_slen, UIO_READ, auio, code);
1060 /* pad out the remaining characters with zeros */
1062 AFS_UIOMOVE(bufofzeros,
1063 ((o_slen + 1 + DIRPAD) & ~DIRPAD) - o_slen,
1064 UIO_READ, auio, code);
1066 /* pad out the difference between rlen and slen... */
1067 if (NDIRSIZ_LEN(o_slen) < rlen) {
1068 while (NDIRSIZ_LEN(o_slen) < rlen) {
1069 int minLen = rlen - NDIRSIZ_LEN(o_slen);
1070 if (minLen > sizeof(bufofzeros))
1071 minLen = sizeof(bufofzeros);
1072 AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
1077 code = afs_readdir_move(ode, avc, auio, o_slen, len, origOffset);
1078 #endif /* AFS_HPUX_ENV */
1080 len = NDIRSIZ_LEN(o_slen = n_slen);
1084 auio->afsio_offset = ((us + afs_dir_NameBlobs(nde->name)) << 5);
1090 ReleaseReadLock(&tdc->lock);
1092 ReleaseReadLock(&avc->lock);
1095 #if defined(AFS_HPUX_ENV) || defined(AFS_OSF_ENV)
1096 osi_FreeSmallSpace((char *)sdirEntry);
1098 afs_PutFakeStat(&fakestate);
1099 code = afs_CheckCode(code, &treq, 29);
1104 #endif /* !AFS_LINUX20_ENV */