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
69 #if defined(AFS_SGI62_ENV) || defined(AFS_SUN57_64BIT_ENV)
71 BlobScan(ino64_t * afile, afs_int32 ablob)
73 #ifdef AFS_LINUX_64BIT_KERNEL
75 BlobScan(long *afile, afs_int32 ablob)
78 BlobScan(afs_int32 * afile, afs_int32 ablob)
82 register afs_int32 relativeBlob;
84 register struct PageHeader *tpe;
87 AFS_STATCNT(BlobScan);
88 /* advance ablob over free and header blobs */
90 pageBlob = ablob & ~(EPP - 1); /* base blob in same page */
91 tpe = (struct PageHeader *)afs_dir_GetBlob(afile, pageBlob);
93 return 0; /* we've past the end */
94 relativeBlob = ablob - pageBlob; /* relative to page's first blob */
95 /* first watch for headers */
96 if (pageBlob == 0) { /* first dir page has extra-big header */
98 if (relativeBlob < DHE + 1)
99 relativeBlob = DHE + 1;
100 } else { /* others have one header blob */
101 if (relativeBlob == 0)
104 /* make sure blob is allocated */
105 for (i = relativeBlob; i < EPP; i++) {
106 if (tpe->freebitmap[i >> 3] & (1 << (i & 7)))
109 /* now relativeBlob is the page-relative first allocated blob,
110 * or EPP (if there are none in this page). */
111 DRelease((struct buffer *)tpe, 0);
114 ablob = pageBlob + EPP; /* go around again */
119 #if !defined(AFS_LINUX20_ENV)
120 /* Changes to afs_readdir which affect dcache or vcache handling or use of
121 * bulk stat data should also be reflected in the Linux specific verison of
122 * the readdir routine.
126 * The kernel don't like it so much to have large stuff on the stack.
127 * Here we use a watered down version of the direct struct, since
128 * its not too bright to double copy the strings anyway.
130 #if !defined(UKERNEL)
131 #if defined(AFS_SGI_ENV)
132 /* Long form for 64 bit apps and kernel requests. */
133 struct min_dirent { /* miniature dirent structure */
134 /* If struct dirent changes, this must too */
135 ino_t d_fileno; /* This is 32 bits for 3.5, 64 for 6.2+ */
139 /* Short form for 32 bit apps. */
140 struct irix5_min_dirent { /* miniature dirent structure */
141 /* If struct dirent changes, this must too */
147 #define AFS_DIRENT32BASESIZE IRIX5_DIRENTBASESIZE
148 #define AFS_DIRENT64BASESIZE DIRENT64BASESIZE
150 #define AFS_DIRENT32BASESIZE IRIX5_DIRENTBASESIZE
151 #define AFS_DIRENT64BASESIZE DIRENTBASESIZE
152 #endif /* AFS_SGI62_ENV */
154 struct min_direct { /* miniature direct structure */
155 /* If struct direct changes, this must too */
156 #if defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
167 #if defined(AFS_SUN_ENV) || defined(AFS_AIX32_ENV)
171 #if defined(AFS_HPUX100_ENV)
172 unsigned long long d_off;
180 #endif /* AFS_SGI_ENV */
182 #if defined(AFS_HPUX_ENV) || defined(AFS_OSF_ENV)
183 struct minnfs_direct {
184 afs_int32 d_off; /* XXX */
189 #define NDIRSIZ_LEN(len) ((sizeof (struct dirent)+4 - (MAXNAMLEN+1)) + (((len)+1 + DIRPAD) &~ DIRPAD))
191 #endif /* !defined(UKERNEL) */
195 *------------------------------------------------------------------------------
197 * Keep a stack of about 256 fids for the bulk stat call.
198 * Fill it during the readdir_move. Later empty it...
201 #define READDIR_STASH AFSCBMAX
202 struct AFSFid afs_readdir_stash[READDIR_STASH];
203 int afs_rd_stash_i = 0;
206 *------------------------------------------------------------------------------
209 * mainly a kind of macro... makes getting the struct direct
210 * out to the user space easy... could take more parameters,
211 * but now just takes what it needs.
216 #if defined(AFS_HPUX100_ENV)
217 #define DIRSIZ_LEN(len) \
218 ((sizeof (struct __dirent) - (_MAXNAMLEN+1)) + (((len)+1 + DIRPAD) &~ DIRPAD))
220 #if defined(AFS_SUN56_ENV)
221 #define DIRSIZ_LEN(len) ((18 + (len) + 1 + 7) & ~7 )
224 #define DIRSIZ_LEN(len) ((10 + (len) + 1 + (NBPW-1)) & ~(NBPW-1))
227 #define DIRSIZ_LEN(len) \
228 ((sizeof (struct dirent) - (MAXNAMLEN+1)) + (((len)+1 + 3) &~ 3))
230 #if defined(AFS_SGI_ENV)
231 #ifndef AFS_SGI53_ENV
232 /* SGI 5.3 and later use 32/64 bit versions of directory size. */
233 #define DIRSIZ_LEN(len) DIRENTSIZE(len)
235 #else /* AFS_SGI_ENV */
236 #define DIRSIZ_LEN(len) \
237 ((sizeof (struct direct) - (MAXNAMLEN+1)) + (((len)+1 + 3) &~ 3))
238 #endif /* AFS_SGI_ENV */
239 #endif /* AFS_DIRENT */
240 #endif /* AFS_SUN5_ENV */
241 #endif /* AFS_SUN56_ENV */
242 #endif /* AFS_HPUX100_ENV */
244 #if defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
246 afs_readdir_type(avc, ade)
247 struct DirEntry *ade;
250 struct VenusFid tfid;
253 tfid.Cell = avc->fid.Cell;
254 tfid.Fid.Volume = avc->fid.Fid.Volume;
255 tfid.Fid.Vnode = ntohl(ade->fid.vnode);
256 tfid.Fid.Unique = ntohl(ade->fid.vunique);
257 if ((avc->states & CForeign) == 0 && (ntohl(ade->fid.vnode) & 1)) {
259 } else if ((tvc = afs_FindVCache(&tfid, 0, 0))) {
263 } else if (((tvc->states) & (CStatd | CTruth))) {
264 /* CTruth will be set if the object has
270 else if (vtype == VREG)
272 /* Don't do this until we're sure it can't be a mtpt */
273 /* else if (vtype == VLNK)
275 /* what other types does AFS support? */
284 #define AFS_MOVE_LOCK() AFS_GLOCK()
285 #define AFS_MOVE_UNLOCK() AFS_GUNLOCK()
287 #define AFS_MOVE_LOCK()
288 #define AFS_MOVE_UNLOCK()
290 char bufofzeros[64]; /* gotta fill with something */
293 afs_readdir_move(de, vc, auio, slen, rlen, off)
306 #if defined(AFS_SUN56_ENV)
307 struct dirent64 *direntp;
309 #if defined(AFS_SUN5_ENV) || (defined(AFS_AIX51_ENV) && defined(AFS_64BIT_KERNEL))
310 struct dirent *direntp;
312 #endif /* AFS_SUN56_ENV */
313 #ifndef AFS_SGI53_ENV
314 struct min_direct sdirEntry;
315 #endif /* AFS_SGI53_ENV */
317 AFS_STATCNT(afs_readdir_move);
320 afs_int32 use64BitDirent;
325 ABI_IS(ABI_IRIX5_64, GETDENTS_ABI(OSI_GET_CURRENT_ABI(), auio));
329 UIO_USERSPACE) ? ABI_IRIX5_64 : (ABI_IS(ABI_IRIX5_64 |
333 #else /* AFS_SGI61_ENV */
336 UIO_USERSPACE) ? ABI_IRIX5_64 : (ABI_IS(ABI_IRIX5_64,
338 #endif /* AFS_SGI61_ENV */
340 if (use64BitDirent) {
341 struct min_dirent sdirEntry;
343 (vc->fid.Fid.Volume << 16) + ntohl(de->fid.vnode);
344 FIXUPSTUPIDINODE(sdirEntry.d_fileno);
345 sdirEntry.d_reclen = rlen;
346 sdirEntry.d_off = (off_t) off;
347 AFS_UIOMOVE(&sdirEntry, AFS_DIRENT64BASESIZE, UIO_READ, auio,
350 AFS_UIOMOVE(de->name, slen - 1, UIO_READ, auio, code);
352 AFS_UIOMOVE(bufofzeros,
353 DIRENTSIZE(slen) - (AFS_DIRENT64BASESIZE + slen -
354 1), UIO_READ, auio, code);
355 if (DIRENTSIZE(slen) < rlen) {
356 while (DIRENTSIZE(slen) < rlen) {
357 int minLen = rlen - DIRENTSIZE(slen);
358 if (minLen > sizeof(bufofzeros))
359 minLen = sizeof(bufofzeros);
360 AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
365 struct irix5_min_dirent sdirEntry;
367 (vc->fid.Fid.Volume << 16) + ntohl(de->fid.vnode);
368 FIXUPSTUPIDINODE(sdirEntry.d_fileno);
369 sdirEntry.d_reclen = rlen;
370 sdirEntry.d_off = (afs_int32) off;
371 AFS_UIOMOVE(&sdirEntry, AFS_DIRENT32BASESIZE, UIO_READ, auio,
374 AFS_UIOMOVE(de->name, slen - 1, UIO_READ, auio, code);
376 AFS_UIOMOVE(bufofzeros,
377 IRIX5_DIRENTSIZE(slen) - (AFS_DIRENT32BASESIZE +
380 if (IRIX5_DIRENTSIZE(slen) < rlen) {
381 while (IRIX5_DIRENTSIZE(slen) < rlen) {
382 int minLen = rlen - IRIX5_DIRENTSIZE(slen);
383 if (minLen > sizeof(bufofzeros))
384 minLen = sizeof(bufofzeros);
385 AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
391 #else /* AFS_SGI53_ENV */
392 #if defined(AFS_SUN5_ENV) || (defined(AFS_AIX51_ENV) && defined(AFS_64BIT_KERNEL))
393 #if defined(AFS_SUN56_ENV)
394 direntp = (struct dirent64 *)osi_AllocLargeSpace(AFS_LRALLOCSIZ);
396 direntp = (struct dirent *)osi_AllocLargeSpace(AFS_LRALLOCSIZ);
398 direntp->d_ino = (vc->fid.Fid.Volume << 16) + ntohl(de->fid.vnode);
399 FIXUPSTUPIDINODE(direntp->d_ino);
400 #if defined(AFS_AIX51_ENV) && defined(AFS_64BIT_KERNEL)
401 direntp->d_offset = off;
402 direntp->d_namlen = slen;
404 direntp->d_off = off;
406 direntp->d_reclen = rlen;
407 strcpy(direntp->d_name, de->name);
408 AFS_UIOMOVE((caddr_t) direntp, rlen, UIO_READ, auio, code);
409 osi_FreeLargeSpace((char *)direntp);
410 #else /* AFS_SUN5_ENV */
411 /* Note the odd mechanism for building the inode number */
412 sdirEntry.d_fileno = (vc->fid.Fid.Volume << 16) + ntohl(de->fid.vnode);
413 FIXUPSTUPIDINODE(sdirEntry.d_fileno);
414 sdirEntry.d_reclen = rlen;
415 #if !defined(AFS_SGI_ENV)
416 sdirEntry.d_namlen = slen;
418 #if defined(AFS_SUN_ENV) || defined(AFS_AIX32_ENV) || defined(AFS_SGI_ENV)
419 sdirEntry.d_off = off;
421 #if defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
422 sdirEntry.d_type = afs_readdir_type(vc, de);
425 #if defined(AFS_SGI_ENV)
426 AFS_UIOMOVE(&sdirEntry, DIRENTBASESIZE, UIO_READ, auio, code);
428 AFS_UIOMOVE(de->name, slen - 1, UIO_READ, auio, code);
430 AFS_UIOMOVE(bufofzeros,
431 DIRSIZ_LEN(slen) - (DIRENTBASESIZE + slen - 1), UIO_READ,
433 #else /* AFS_SGI_ENV */
435 AFS_UIOMOVE((char *)&sdirEntry, sizeof(sdirEntry), UIO_READ, auio, code);
438 AFS_UIOMOVE(de->name, slen, UIO_READ, auio, code);
441 /* pad out the remaining characters with zeros */
443 AFS_UIOMOVE(bufofzeros, ((slen + 1 + DIRPAD) & ~DIRPAD) - slen,
444 UIO_READ, auio, code);
447 #endif /* AFS_SGI_ENV */
449 /* pad out the difference between rlen and slen... */
450 if (DIRSIZ_LEN(slen) < rlen) {
452 while (DIRSIZ_LEN(slen) < rlen) {
453 int minLen = rlen - DIRSIZ_LEN(slen);
454 if (minLen > sizeof(bufofzeros))
455 minLen = sizeof(bufofzeros);
456 AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
461 #endif /* AFS_SUN5_ENV */
462 #endif /* AFS_SGI53_ENV */
468 *------------------------------------------------------------------------------
470 * Read directory entries.
471 * There are some weird things to look out for here. The uio_offset
472 * field is either 0 or it is the offset returned from a previous
473 * readdir. It is an opaque value used by the server to find the
474 * correct directory block to read. The byte count must be at least
475 * vtoblksz(vp) bytes. The count field is the number of blocks to
476 * read on the server. This is advisory only, the server may return
477 * only one block's worth of entries. Entries may be compressed on
480 * This routine encodes knowledge of Vice dirs.
484 afs_bulkstat_send(avc, req)
486 struct vrequest *req;
492 * Here is the bad, bad, really bad news.
493 * It has to do with 'offset' (seek locations).
497 #if defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV) || defined(AFS_OSF_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
498 afs_readdir(OSI_VC_ARG(avc), auio, acred, eofp)
501 #if defined(AFS_HPUX100_ENV)
502 afs_readdir2(OSI_VC_ARG(avc), auio, acred)
504 afs_readdir(OSI_VC_ARG(avc), auio, acred)
509 struct AFS_UCRED *acred;
511 struct vrequest treq;
512 register struct dcache *tdc;
513 afs_size_t origOffset, tlen;
516 struct DirEntry *ode = 0, *nde = 0;
517 int o_slen = 0, n_slen = 0;
519 struct afs_fakestat_state fakestate;
520 #if defined(AFS_SGI53_ENV)
521 afs_int32 use64BitDirent, dirsiz;
522 #endif /* defined(AFS_SGI53_ENV) */
526 * XXX All the hacks for alloced sdirEntry and inlining of afs_readdir_move instead of calling
527 * it is necessary for hpux due to stack problems that seem to occur when coming thru the nfs
528 * translator side XXX
530 struct min_direct *sdirEntry =
531 (struct min_direct *)osi_AllocSmallSpace(sizeof(struct min_direct));
535 /* opaque value is pointer into a vice dir; use bit map to decide
536 * if the entries are in use. Always assumed to be valid. 0 is
537 * special, means start of a new dir. Int32 inode, followed by
538 * short reclen and short namelen. Namelen does not include
539 * the null byte. Followed by null-terminated string.
541 AFS_STATCNT(afs_readdir);
543 #if defined(AFS_SGI53_ENV)
547 ABI_IS(ABI_IRIX5_64, GETDENTS_ABI(OSI_GET_CURRENT_ABI(), auio));
551 UIO_USERSPACE) ? ABI_IRIX5_64 : (ABI_IS(ABI_IRIX5_64 | ABI_IRIX5_N32,
553 #endif /* AFS_SGI62_ENV */
554 #else /* AFS_SGI61_ENV */
557 UIO_USERSPACE) ? ABI_IRIX5_64 : (ABI_IS(ABI_IRIX5_64,
559 #endif /* AFS_SGI61_ENV */
560 #endif /* defined(AFS_SGI53_ENV) */
562 #if defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV) || defined(AFS_OSF_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
563 /* Not really used by the callee so we ignore it for now */
567 if (AfsLargeFileUio(auio) /* file is large than 2 GB */
568 ||AfsLargeFileSize(auio->uio_offset, auio->uio_resid))
571 if ((code = afs_InitReq(&treq, acred))) {
573 osi_FreeSmallSpace((char *)sdirEntry);
577 /* update the cache entry */
578 afs_InitFakeStat(&fakestate);
579 code = afs_EvalFakeStat(&avc, &fakestate, &treq);
583 code = afs_VerifyVCache(avc, &treq);
586 /* get a reference to the entire directory */
587 tdc = afs_GetDCache(avc, (afs_size_t) 0, &treq, &origOffset, &tlen, 1);
593 ObtainReadLock(&avc->lock);
594 ObtainReadLock(&tdc->lock);
597 * Make sure that the data in the cache is current. There are two
598 * cases we need to worry about:
599 * 1. The cache data is being fetched by another process.
600 * 2. The cache data is no longer valid
602 while ((avc->states & CStatd)
603 && (tdc->dflags & DFFetching)
604 && hsame(avc->m.DataVersion, tdc->f.versionNo)) {
605 afs_Trace4(afs_iclSetp, CM_TRACE_DCACHEWAIT, ICL_TYPE_STRING,
606 __FILE__, ICL_TYPE_INT32, __LINE__, ICL_TYPE_POINTER, tdc,
607 ICL_TYPE_INT32, tdc->dflags);
608 ReleaseReadLock(&tdc->lock);
609 ReleaseReadLock(&avc->lock);
610 afs_osi_Sleep(&tdc->validPos);
611 ObtainReadLock(&avc->lock);
612 ObtainReadLock(&tdc->lock);
614 if (!(avc->states & CStatd)
615 || !hsame(avc->m.DataVersion, tdc->f.versionNo)) {
616 ReleaseReadLock(&tdc->lock);
617 ReleaseReadLock(&avc->lock);
623 * iterator for the directory reads. Takes the AFS DirEntry
624 * structure and slams them into UFS direct structures.
625 * uses afs_readdir_move to get the struct to the user space.
627 * The routine works by looking ahead one AFS directory entry.
628 * That's because the AFS entry we are currenly working with
629 * may not fit into the buffer the user has provided. If it
630 * doesn't we have to change the size of the LAST AFS directory
631 * entry, so that it will FIT perfectly into the block the
634 * The 'forward looking' of the code makes it a bit tough to read.
635 * Remember we need to get an entry, see if it it fits, then
636 * set it up as the LAST entry, and find the next one.
638 * Tough to take: We give out an EINVAL if we don't have enough
639 * space in the buffer, and at the same time, don't have an entry
640 * to put into the buffer. This CAN happen if the first AFS entry
641 * we get can't fit into the 512 character buffer provided. Seems
642 * it ought not happen...
644 * Assumption: don't need to use anything but one dc entry:
645 * this means the directory ought not be greater than 64k.
649 auio->uio_fpflags = 0;
652 origOffset = auio->afsio_offset;
653 /* scan for the next interesting entry scan for in-use blob otherwise up point at
654 * this blob note that ode, if non-zero, also represents a held dir page */
655 if (!(us = BlobScan(&tdc->f.inode, (origOffset >> 5)))
656 || !(nde = (struct DirEntry *)afs_dir_GetBlob(&tdc->f.inode, us))) {
657 /* failed to setup nde, return what we've got, and release ode */
659 /* something to hand over. */
661 sdirEntry->d_fileno =
662 (avc->fid.Fid.Volume << 16) + ntohl(ode->fid.vnode);
663 FIXUPSTUPIDINODE(sdirEntry->d_fileno);
664 sdirEntry->d_reclen = rlen = auio->afsio_resid;
665 sdirEntry->d_namlen = o_slen;
666 #if defined(AFS_SUN_ENV) || defined(AFS_AIX32_ENV) || defined(AFS_HPUX100_ENV)
667 sdirEntry->d_off = origOffset;
669 AFS_UIOMOVE((char *)sdirEntry, sizeof(*sdirEntry), UIO_READ,
672 AFS_UIOMOVE(ode->name, o_slen, UIO_READ, auio, code);
673 /* pad out the remaining characters with zeros */
675 AFS_UIOMOVE(bufofzeros,
676 ((o_slen + 1 + DIRPAD) & ~DIRPAD) - o_slen,
677 UIO_READ, auio, code);
679 /* pad out the difference between rlen and slen... */
680 if (DIRSIZ_LEN(o_slen) < rlen) {
681 while (DIRSIZ_LEN(o_slen) < rlen) {
682 int minLen = rlen - DIRSIZ_LEN(o_slen);
683 if (minLen > sizeof(bufofzeros))
684 minLen = sizeof(bufofzeros);
685 AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
690 code = afs_readdir_move(ode, avc, auio, o_slen,
691 #if defined(AFS_SUN5_ENV)
694 auio->afsio_resid, origOffset);
696 #endif /* AFS_HPUX_ENV */
697 #if !defined(AFS_SUN5_ENV)
698 auio->afsio_resid = 0;
701 /* nothin to hand over */
703 #if defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV) || defined(AFS_OSF_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
705 *eofp = 1; /* Set it properly */
708 DRelease((struct buffer *)ode, 0);
711 /* by here nde is set */
713 /* Do we have enough user space to carry out our mission? */
714 #if defined(AFS_SGI_ENV)
715 n_slen = strlen(nde->name) + 1; /* NULL terminate */
717 n_slen = strlen(nde->name);
721 use64BitDirent ? DIRENTSIZE(n_slen) : IRIX5_DIRENTSIZE(n_slen);
722 if (dirsiz >= (auio->afsio_resid - len)) {
724 if (DIRSIZ_LEN(n_slen) >= (auio->afsio_resid - len)) {
725 #endif /* AFS_SGI53_ENV */
726 /* No can do no more now; ya know... at this time */
727 DRelease((struct buffer *)nde, 0); /* can't use this one. */
730 sdirEntry->d_fileno =
731 (avc->fid.Fid.Volume << 16) + ntohl(ode->fid.vnode);
732 FIXUPSTUPIDINODE(sdirEntry->d_fileno);
733 sdirEntry->d_reclen = rlen = auio->afsio_resid;
734 sdirEntry->d_namlen = o_slen;
735 #if defined(AFS_SUN_ENV) || defined(AFS_AIX32_ENV) || defined(AFS_HPUX100_ENV)
736 sdirEntry->d_off = origOffset;
738 AFS_UIOMOVE((char *)sdirEntry, sizeof(*sdirEntry), UIO_READ,
741 AFS_UIOMOVE(ode->name, o_slen, UIO_READ, auio, code);
742 /* pad out the remaining characters with zeros */
744 AFS_UIOMOVE(bufofzeros,
745 ((o_slen + 1 + DIRPAD) & ~DIRPAD) - o_slen,
746 UIO_READ, auio, code);
748 /* pad out the difference between rlen and slen... */
749 if (DIRSIZ_LEN(o_slen) < rlen) {
750 while (DIRSIZ_LEN(o_slen) < rlen) {
751 int minLen = rlen - DIRSIZ_LEN(o_slen);
752 if (minLen > sizeof(bufofzeros))
753 minLen = sizeof(bufofzeros);
754 AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
758 #else /* AFS_HPUX_ENV */
760 afs_readdir_move(ode, avc, auio, o_slen,
761 auio->afsio_resid, origOffset);
762 #endif /* AFS_HPUX_ENV */
763 /* this next line used to be AFSVFS40 or AIX 3.1, but is
765 auio->afsio_offset = origOffset;
766 auio->afsio_resid = 0;
767 } else { /* trouble, can't give anything to the user! */
768 /* even though he has given us a buffer,
769 * even though we have something to give us,
770 * Looks like we lost something somewhere.
775 DRelease((struct buffer *)ode, 0);
780 * In any event, we move out the LAST de entry, getting ready
781 * to set up for the next one.
785 sdirEntry->d_fileno =
786 (avc->fid.Fid.Volume << 16) + ntohl(ode->fid.vnode);
787 FIXUPSTUPIDINODE(sdirEntry->d_fileno);
788 sdirEntry->d_reclen = rlen = len;
789 sdirEntry->d_namlen = o_slen;
790 #if defined(AFS_SUN_ENV) || defined(AFS_AIX32_ENV) || defined(AFS_HPUX100_ENV)
791 sdirEntry->d_off = origOffset;
793 AFS_UIOMOVE((char *)sdirEntry, sizeof(*sdirEntry), UIO_READ, auio,
796 AFS_UIOMOVE(ode->name, o_slen, UIO_READ, auio, code);
797 /* pad out the remaining characters with zeros */
799 AFS_UIOMOVE(bufofzeros,
800 ((o_slen + 1 + DIRPAD) & ~DIRPAD) - o_slen,
801 UIO_READ, auio, code);
803 /* pad out the difference between rlen and slen... */
804 if (DIRSIZ_LEN(o_slen) < rlen) {
805 while (DIRSIZ_LEN(o_slen) < rlen) {
806 int minLen = rlen - DIRSIZ_LEN(o_slen);
807 if (minLen > sizeof(bufofzeros))
808 minLen = sizeof(bufofzeros);
809 AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
813 #else /* AFS_HPUX_ENV */
814 code = afs_readdir_move(ode, avc, auio, o_slen, len, origOffset);
815 #endif /* AFS_HPUX_ENV */
818 len = use64BitDirent ? DIRENTSIZE(o_slen =
819 n_slen) : IRIX5_DIRENTSIZE(o_slen =
822 len = DIRSIZ_LEN(o_slen = n_slen);
823 #endif /* AFS_SGI53_ENV */
825 DRelease((struct buffer *)ode, 0);
828 (afs_int32) ((us + afs_dir_NameBlobs(nde->name)) << 5);
831 DRelease((struct buffer *)ode, 0);
834 ReleaseReadLock(&tdc->lock);
836 ReleaseReadLock(&avc->lock);
840 osi_FreeSmallSpace((char *)sdirEntry);
842 afs_PutFakeStat(&fakestate);
843 code = afs_CheckCode(code, &treq, 28);
847 #if defined(AFS_HPUX_ENV) || defined(AFS_OSF_ENV)
849 afs1_readdir(avc, auio, acred, eofp)
852 afs1_readdir(avc, auio, acred)
856 struct AFS_UCRED *acred;
858 struct vrequest treq;
859 register struct dcache *tdc;
860 afs_size_t origOffset, len;
862 struct DirEntry *ode = 0, *nde = 0;
863 int o_slen = 0, n_slen = 0;
865 #if defined(AFS_HPUX_ENV) || defined(AFS_OSF_ENV)
867 * XXX All the hacks for alloced sdirEntry and inlining of afs_readdir_move instead of calling
868 * it is necessary for hpux due to stack problems that seem to occur when coming thru the nfs
869 * translator side XXX
871 struct minnfs_direct *sdirEntry = (struct minnfs_direct *)
872 osi_AllocSmallSpace(sizeof(struct min_direct));
875 struct afs_fakestat_state fakestate;
877 AFS_STATCNT(afs_readdir);
878 #if defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV) || defined(AFS_OSF_ENV)
882 if (code = afs_InitReq(&treq, acred)) {
884 osi_FreeSmallSpace((char *)sdirEntry);
888 afs_InitFakeStat(&fakestate);
889 code = afs_EvalFakeStat(&avc, &fakestate, &treq);
892 osi_FreeSmallSpace((char *)sdirEntry);
894 afs_PutFakeStat(&fakestate);
897 /* update the cache entry */
899 code = afs_VerifyVCache(avc, &treq);
902 /* get a reference to the entire directory */
903 tdc = afs_GetDCache(avc, (afs_size_t) 0, &treq, &origOffset, &len, 1);
908 ObtainReadLock(&avc->lock);
909 ObtainReadLock(&tdc->lock);
912 * Make sure that the data in the cache is current. There are two
913 * cases we need to worry about:
914 * 1. The cache data is being fetched by another process.
915 * 2. The cache data is no longer valid
917 while ((avc->states & CStatd)
918 && (tdc->dflags & DFFetching)
919 && hsame(avc->m.DataVersion, tdc->f.versionNo)) {
920 afs_Trace4(afs_iclSetp, CM_TRACE_DCACHEWAIT, ICL_TYPE_STRING,
921 __FILE__, ICL_TYPE_INT32, __LINE__, ICL_TYPE_POINTER, tdc,
922 ICL_TYPE_INT32, tdc->dflags);
923 ReleaseReadLock(&tdc->lock);
924 ReleaseReadLock(&avc->lock);
925 afs_osi_Sleep(&tdc->validPos);
926 ObtainReadLock(&avc->lock);
927 ObtainReadLock(&tdc->lock);
929 if (!(avc->states & CStatd)
930 || !hsame(avc->m.DataVersion, tdc->f.versionNo)) {
931 ReleaseReadLock(&tdc->lock);
932 ReleaseReadLock(&avc->lock);
939 auio->uio_fpflags = 0;
942 origOffset = auio->afsio_offset;
944 /* scan for the next interesting entry scan for in-use blob otherwise up point at
945 * this blob note that ode, if non-zero, also represents a held dir page */
946 if (!(us = BlobScan(&tdc->f.inode, (origOffset >> 5)))
947 || !(nde = (struct DirEntry *)afs_dir_GetBlob(&tdc->f.inode, us))) {
948 /* failed to setup nde, return what we've got, and release ode */
950 /* something to hand over. */
951 #if defined(AFS_HPUX_ENV) || defined(AFS_OSF_ENV)
952 sdirEntry->d_fileno =
953 (avc->fid.Fid.Volume << 16) + ntohl(ode->fid.vnode);
954 FIXUPSTUPIDINODE(sdirEntry->d_fileno);
955 sdirEntry->d_reclen = rlen = auio->afsio_resid;
956 sdirEntry->d_namlen = o_slen;
957 sdirEntry->d_off = origOffset;
958 AFS_UIOMOVE((char *)sdirEntry, sizeof(*sdirEntry), UIO_READ,
961 AFS_UIOMOVE(ode->name, o_slen, UIO_READ, auio, code);
963 /* pad out the remaining characters with zeros */
965 AFS_UIOMOVE(bufofzeros,
966 ((o_slen + 1 + DIRPAD) & ~DIRPAD) - o_slen,
967 UIO_READ, auio, code);
969 /* pad out the difference between rlen and slen... */
970 if (NDIRSIZ_LEN(o_slen) < rlen) {
971 while (NDIRSIZ_LEN(o_slen) < rlen) {
972 int minLen = rlen - NDIRSIZ_LEN(o_slen);
973 if (minLen > sizeof(bufofzeros))
974 minLen = sizeof(bufofzeros);
975 AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
981 afs_readdir_move(ode, avc, auio, o_slen,
982 auio->afsio_resid, origOffset);
983 #endif /* AFS_HPUX_ENV */
984 auio->afsio_resid = 0;
986 /* nothin to hand over */
988 #if defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV) || defined(AFS_OSF_ENV)
996 /* by here nde is set */
998 /* Do we have enough user space to carry out our mission? */
999 #if defined(AFS_SGI_ENV)
1000 n_slen = strlen(nde->name) + 1; /* NULL terminate */
1002 n_slen = strlen(nde->name);
1004 if (NDIRSIZ_LEN(n_slen) >= (auio->afsio_resid - len)) {
1005 /* No can do no more now; ya know... at this time */
1006 DRelease(nde, 0); /* can't use this one. */
1008 #if defined(AFS_HPUX_ENV) || defined(AFS_OSF_ENV)
1009 sdirEntry->d_fileno =
1010 (avc->fid.Fid.Volume << 16) + ntohl(ode->fid.vnode);
1011 FIXUPSTUPIDINODE(sdirEntry->d_fileno);
1012 sdirEntry->d_reclen = rlen = auio->afsio_resid;
1013 sdirEntry->d_namlen = o_slen;
1014 sdirEntry->d_off = origOffset;
1015 AFS_UIOMOVE((char *)sdirEntry, sizeof(*sdirEntry), UIO_READ,
1018 AFS_UIOMOVE(ode->name, o_slen, UIO_READ, auio, code);
1019 /* pad out the remaining characters with zeros */
1021 AFS_UIOMOVE(bufofzeros,
1022 ((o_slen + 1 + DIRPAD) & ~DIRPAD) - o_slen,
1023 UIO_READ, auio, code);
1025 /* pad out the difference between rlen and slen... */
1026 if (NDIRSIZ_LEN(o_slen) < rlen) {
1027 while (NDIRSIZ_LEN(o_slen) < rlen) {
1028 int minLen = rlen - NDIRSIZ_LEN(o_slen);
1029 if (minLen > sizeof(bufofzeros))
1030 minLen = sizeof(bufofzeros);
1031 AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
1037 afs_readdir_move(ode, avc, auio, o_slen,
1038 auio->afsio_resid, origOffset);
1039 #endif /* AFS_HPUX_ENV */
1040 /* this next line used to be AFSVFS40 or AIX 3.1, but is really generic */
1041 auio->afsio_offset = origOffset;
1042 auio->afsio_resid = 0;
1043 } else { /* trouble, can't give anything to the user! */
1044 /* even though he has given us a buffer,
1045 * even though we have something to give us,
1046 * Looks like we lost something somewhere.
1056 * In any event, we move out the LAST de entry, getting ready
1057 * to set up for the next one.
1060 #if defined(AFS_HPUX_ENV) || defined(AFS_OSF_ENV)
1061 sdirEntry->d_fileno =
1062 (avc->fid.Fid.Volume << 16) + ntohl(ode->fid.vnode);
1063 FIXUPSTUPIDINODE(sdirEntry->d_fileno);
1064 sdirEntry->d_reclen = rlen = len;
1065 sdirEntry->d_namlen = o_slen;
1066 sdirEntry->d_off = origOffset;
1067 AFS_UIOMOVE((char *)sdirEntry, sizeof(*sdirEntry), UIO_READ, auio,
1070 AFS_UIOMOVE(ode->name, o_slen, UIO_READ, auio, code);
1071 /* pad out the remaining characters with zeros */
1073 AFS_UIOMOVE(bufofzeros,
1074 ((o_slen + 1 + DIRPAD) & ~DIRPAD) - o_slen,
1075 UIO_READ, auio, code);
1077 /* pad out the difference between rlen and slen... */
1078 if (NDIRSIZ_LEN(o_slen) < rlen) {
1079 while (NDIRSIZ_LEN(o_slen) < rlen) {
1080 int minLen = rlen - NDIRSIZ_LEN(o_slen);
1081 if (minLen > sizeof(bufofzeros))
1082 minLen = sizeof(bufofzeros);
1083 AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
1088 code = afs_readdir_move(ode, avc, auio, o_slen, len, origOffset);
1089 #endif /* AFS_HPUX_ENV */
1091 len = NDIRSIZ_LEN(o_slen = n_slen);
1095 auio->afsio_offset = ((us + afs_dir_NameBlobs(nde->name)) << 5);
1101 ReleaseReadLock(&tdc->lock);
1103 ReleaseReadLock(&avc->lock);
1106 #if defined(AFS_HPUX_ENV) || defined(AFS_OSF_ENV)
1107 osi_FreeSmallSpace((char *)sdirEntry);
1109 afs_PutFakeStat(&fakestate);
1110 code = afs_CheckCode(code, &treq, 29);
1115 #endif /* !AFS_LINUX20_ENV */