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 #if defined(AFS_HPUX1123_ENV)
74 /*DEE should use afs_inode_t for all */
76 BlobScan(ino_t *afile, afs_int32 ablob)
78 #ifdef AFS_LINUX_64BIT_KERNEL
80 BlobScan(long *afile, afs_int32 ablob)
83 BlobScan(afs_int32 * afile, afs_int32 ablob)
88 register afs_int32 relativeBlob;
90 register struct PageHeader *tpe;
93 AFS_STATCNT(BlobScan);
94 /* advance ablob over free and header blobs */
96 pageBlob = ablob & ~(EPP - 1); /* base blob in same page */
97 tpe = (struct PageHeader *)afs_dir_GetBlob(afile, pageBlob);
99 return 0; /* we've past the end */
100 relativeBlob = ablob - pageBlob; /* relative to page's first blob */
101 /* first watch for headers */
102 if (pageBlob == 0) { /* first dir page has extra-big header */
104 if (relativeBlob < DHE + 1)
105 relativeBlob = DHE + 1;
106 } else { /* others have one header blob */
107 if (relativeBlob == 0)
110 /* make sure blob is allocated */
111 for (i = relativeBlob; i < EPP; i++) {
112 if (tpe->freebitmap[i >> 3] & (1 << (i & 7)))
115 /* now relativeBlob is the page-relative first allocated blob,
116 * or EPP (if there are none in this page). */
117 DRelease((struct buffer *)tpe, 0);
120 ablob = pageBlob + EPP; /* go around again */
125 #if !defined(AFS_LINUX20_ENV)
126 /* Changes to afs_readdir which affect dcache or vcache handling or use of
127 * bulk stat data should also be reflected in the Linux specific verison of
128 * the readdir routine.
132 * The kernel don't like it so much to have large stuff on the stack.
133 * Here we use a watered down version of the direct struct, since
134 * its not too bright to double copy the strings anyway.
136 #if !defined(UKERNEL)
137 #if defined(AFS_SGI_ENV)
138 /* Long form for 64 bit apps and kernel requests. */
139 struct min_dirent { /* miniature dirent structure */
140 /* If struct dirent changes, this must too */
141 ino_t d_fileno; /* This is 32 bits for 3.5, 64 for 6.2+ */
145 /* Short form for 32 bit apps. */
146 struct irix5_min_dirent { /* miniature dirent structure */
147 /* If struct dirent changes, this must too */
153 #define AFS_DIRENT32BASESIZE IRIX5_DIRENTBASESIZE
154 #define AFS_DIRENT64BASESIZE DIRENT64BASESIZE
156 #define AFS_DIRENT32BASESIZE IRIX5_DIRENTBASESIZE
157 #define AFS_DIRENT64BASESIZE DIRENTBASESIZE
158 #endif /* AFS_SGI62_ENV */
160 struct min_direct { /* miniature direct structure */
161 /* If struct direct changes, this must too */
162 #if defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
173 #if defined(AFS_SUN_ENV) || defined(AFS_AIX32_ENV)
176 #if defined(AFS_HPUX100_ENV)
177 unsigned long long d_off;
185 #endif /* AFS_SGI_ENV */
187 #if defined(AFS_HPUX_ENV) || defined(AFS_OSF_ENV)
188 struct minnfs_direct {
189 afs_int32 d_off; /* XXX */
194 #define NDIRSIZ_LEN(len) ((sizeof (struct dirent)+4 - (MAXNAMLEN+1)) + (((len)+1 + DIRPAD) &~ DIRPAD))
196 #endif /* !defined(UKERNEL) */
200 *------------------------------------------------------------------------------
202 * Keep a stack of about 256 fids for the bulk stat call.
203 * Fill it during the readdir_move. Later empty it...
206 #define READDIR_STASH AFSCBMAX
207 struct AFSFid afs_readdir_stash[READDIR_STASH];
208 int afs_rd_stash_i = 0;
211 *------------------------------------------------------------------------------
214 * mainly a kind of macro... makes getting the struct direct
215 * out to the user space easy... could take more parameters,
216 * but now just takes what it needs.
221 #if defined(AFS_HPUX100_ENV)
222 #define DIRSIZ_LEN(len) \
223 ((sizeof (struct __dirent) - (_MAXNAMLEN+1)) + (((len)+1 + DIRPAD) &~ DIRPAD))
225 #if defined(AFS_SUN56_ENV)
226 #define DIRSIZ_LEN(len) ((18 + (len) + 1 + 7) & ~7 )
229 #define DIRSIZ_LEN(len) ((10 + (len) + 1 + (NBPW-1)) & ~(NBPW-1))
232 #define DIRSIZ_LEN(len) \
233 ((sizeof (struct dirent) - (MAXNAMLEN+1)) + (((len)+1 + 3) &~ 3))
235 #if defined(AFS_SGI_ENV)
236 #ifndef AFS_SGI53_ENV
237 /* SGI 5.3 and later use 32/64 bit versions of directory size. */
238 #define DIRSIZ_LEN(len) DIRENTSIZE(len)
240 #else /* AFS_SGI_ENV */
241 #define DIRSIZ_LEN(len) \
242 ((sizeof (struct direct) - (MAXNAMLEN+1)) + (((len)+1 + 3) &~ 3))
243 #endif /* AFS_SGI_ENV */
244 #endif /* AFS_DIRENT */
245 #endif /* AFS_SUN5_ENV */
246 #endif /* AFS_SUN56_ENV */
247 #endif /* AFS_HPUX100_ENV */
249 #if defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
251 afs_readdir_type(avc, ade)
252 struct DirEntry *ade;
255 struct VenusFid tfid;
258 tfid.Cell = avc->fid.Cell;
259 tfid.Fid.Volume = avc->fid.Fid.Volume;
260 tfid.Fid.Vnode = ntohl(ade->fid.vnode);
261 tfid.Fid.Unique = ntohl(ade->fid.vunique);
262 if ((avc->states & CForeign) == 0 && (ntohl(ade->fid.vnode) & 1)) {
264 } else if ((tvc = afs_FindVCache(&tfid, 0, 0))) {
268 } else if (((tvc->states) & (CStatd | CTruth))) {
269 /* CTruth will be set if the object has
275 else if (vtype == VREG)
277 /* Don't do this until we're sure it can't be a mtpt */
278 /* else if (vtype == VLNK)
280 /* what other types does AFS support? */
289 #define AFS_MOVE_LOCK() AFS_GLOCK()
290 #define AFS_MOVE_UNLOCK() AFS_GUNLOCK()
292 #define AFS_MOVE_LOCK()
293 #define AFS_MOVE_UNLOCK()
295 char bufofzeros[64]; /* gotta fill with something */
298 afs_readdir_move(de, vc, auio, slen, rlen, off)
311 #if defined(AFS_SUN56_ENV)
312 struct dirent64 *direntp;
314 #if defined(AFS_SUN5_ENV) || (defined(AFS_AIX51_ENV) && defined(AFS_64BIT_KERNEL))
315 struct dirent *direntp;
317 #endif /* AFS_SUN56_ENV */
318 #ifndef AFS_SGI53_ENV
319 struct min_direct sdirEntry;
320 #endif /* AFS_SGI53_ENV */
322 AFS_STATCNT(afs_readdir_move);
325 afs_int32 use64BitDirent;
330 ABI_IS(ABI_IRIX5_64, GETDENTS_ABI(OSI_GET_CURRENT_ABI(), auio));
334 UIO_USERSPACE) ? ABI_IRIX5_64 : (ABI_IS(ABI_IRIX5_64 |
338 #else /* AFS_SGI61_ENV */
341 UIO_USERSPACE) ? ABI_IRIX5_64 : (ABI_IS(ABI_IRIX5_64,
343 #endif /* AFS_SGI61_ENV */
345 if (use64BitDirent) {
346 struct min_dirent sdirEntry;
348 (vc->fid.Fid.Volume << 16) + ntohl(de->fid.vnode);
349 FIXUPSTUPIDINODE(sdirEntry.d_fileno);
350 sdirEntry.d_reclen = rlen;
351 sdirEntry.d_off = (off_t) off;
352 AFS_UIOMOVE(&sdirEntry, AFS_DIRENT64BASESIZE, UIO_READ, auio,
355 AFS_UIOMOVE(de->name, slen - 1, UIO_READ, auio, code);
357 AFS_UIOMOVE(bufofzeros,
358 DIRENTSIZE(slen) - (AFS_DIRENT64BASESIZE + slen -
359 1), UIO_READ, auio, code);
360 if (DIRENTSIZE(slen) < rlen) {
361 while (DIRENTSIZE(slen) < rlen) {
362 int minLen = rlen - DIRENTSIZE(slen);
363 if (minLen > sizeof(bufofzeros))
364 minLen = sizeof(bufofzeros);
365 AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
370 struct irix5_min_dirent sdirEntry;
372 (vc->fid.Fid.Volume << 16) + ntohl(de->fid.vnode);
373 FIXUPSTUPIDINODE(sdirEntry.d_fileno);
374 sdirEntry.d_reclen = rlen;
375 sdirEntry.d_off = (afs_int32) off;
376 AFS_UIOMOVE(&sdirEntry, AFS_DIRENT32BASESIZE, UIO_READ, auio,
379 AFS_UIOMOVE(de->name, slen - 1, UIO_READ, auio, code);
381 AFS_UIOMOVE(bufofzeros,
382 IRIX5_DIRENTSIZE(slen) - (AFS_DIRENT32BASESIZE +
385 if (IRIX5_DIRENTSIZE(slen) < rlen) {
386 while (IRIX5_DIRENTSIZE(slen) < rlen) {
387 int minLen = rlen - IRIX5_DIRENTSIZE(slen);
388 if (minLen > sizeof(bufofzeros))
389 minLen = sizeof(bufofzeros);
390 AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
396 #else /* AFS_SGI53_ENV */
397 #if defined(AFS_SUN5_ENV) || (defined(AFS_AIX51_ENV) && defined(AFS_64BIT_KERNEL))
398 #if defined(AFS_SUN56_ENV)
399 direntp = (struct dirent64 *)osi_AllocLargeSpace(AFS_LRALLOCSIZ);
401 direntp = (struct dirent *)osi_AllocLargeSpace(AFS_LRALLOCSIZ);
403 direntp->d_ino = (vc->fid.Fid.Volume << 16) + ntohl(de->fid.vnode);
404 FIXUPSTUPIDINODE(direntp->d_ino);
405 #if defined(AFS_AIX51_ENV) && defined(AFS_64BIT_KERNEL)
406 direntp->d_offset = off;
407 direntp->d_namlen = slen;
409 direntp->d_off = off;
411 direntp->d_reclen = rlen;
412 strcpy(direntp->d_name, de->name);
413 AFS_UIOMOVE((caddr_t) direntp, rlen, UIO_READ, auio, code);
414 osi_FreeLargeSpace((char *)direntp);
415 #else /* AFS_SUN5_ENV */
416 /* Note the odd mechanism for building the inode number */
417 sdirEntry.d_fileno = (vc->fid.Fid.Volume << 16) + ntohl(de->fid.vnode);
418 FIXUPSTUPIDINODE(sdirEntry.d_fileno);
419 sdirEntry.d_reclen = rlen;
420 #if !defined(AFS_SGI_ENV)
421 sdirEntry.d_namlen = slen;
423 #if defined(AFS_SUN_ENV) || defined(AFS_AIX32_ENV) || defined(AFS_SGI_ENV)
424 sdirEntry.d_off = off;
426 #if defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
427 sdirEntry.d_type = afs_readdir_type(vc, de);
430 #if defined(AFS_SGI_ENV)
431 AFS_UIOMOVE(&sdirEntry, DIRENTBASESIZE, UIO_READ, auio, code);
433 AFS_UIOMOVE(de->name, slen - 1, UIO_READ, auio, code);
435 AFS_UIOMOVE(bufofzeros,
436 DIRSIZ_LEN(slen) - (DIRENTBASESIZE + slen - 1), UIO_READ,
438 #else /* AFS_SGI_ENV */
440 AFS_UIOMOVE((char *)&sdirEntry, sizeof(sdirEntry), UIO_READ, auio, code);
443 AFS_UIOMOVE(de->name, slen, UIO_READ, auio, code);
446 /* pad out the remaining characters with zeros */
448 AFS_UIOMOVE(bufofzeros, ((slen + 1 + DIRPAD) & ~DIRPAD) - slen,
449 UIO_READ, auio, code);
452 #endif /* AFS_SGI_ENV */
454 /* pad out the difference between rlen and slen... */
455 if (DIRSIZ_LEN(slen) < rlen) {
457 while (DIRSIZ_LEN(slen) < rlen) {
458 int minLen = rlen - DIRSIZ_LEN(slen);
459 if (minLen > sizeof(bufofzeros))
460 minLen = sizeof(bufofzeros);
461 AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
466 #endif /* AFS_SUN5_ENV */
467 #endif /* AFS_SGI53_ENV */
473 *------------------------------------------------------------------------------
475 * Read directory entries.
476 * There are some weird things to look out for here. The uio_offset
477 * field is either 0 or it is the offset returned from a previous
478 * readdir. It is an opaque value used by the server to find the
479 * correct directory block to read. The byte count must be at least
480 * vtoblksz(vp) bytes. The count field is the number of blocks to
481 * read on the server. This is advisory only, the server may return
482 * only one block's worth of entries. Entries may be compressed on
485 * This routine encodes knowledge of Vice dirs.
489 afs_bulkstat_send(avc, req)
491 struct vrequest *req;
497 * Here is the bad, bad, really bad news.
498 * It has to do with 'offset' (seek locations).
502 #if defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV) || defined(AFS_OSF_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
503 afs_readdir(OSI_VC_ARG(avc), auio, acred, eofp)
506 #if defined(AFS_HPUX100_ENV)
507 afs_readdir2(OSI_VC_ARG(avc), auio, acred)
509 afs_readdir(OSI_VC_ARG(avc), auio, acred)
514 struct AFS_UCRED *acred;
516 struct vrequest treq;
517 register struct dcache *tdc;
518 afs_size_t origOffset, tlen;
521 struct DirEntry *ode = 0, *nde = 0;
522 int o_slen = 0, n_slen = 0;
524 struct afs_fakestat_state fakestate;
525 #if defined(AFS_SGI53_ENV)
526 afs_int32 use64BitDirent, dirsiz;
527 #endif /* defined(AFS_SGI53_ENV) */
531 * XXX All the hacks for alloced sdirEntry and inlining of afs_readdir_move instead of calling
532 * it is necessary for hpux due to stack problems that seem to occur when coming thru the nfs
533 * translator side XXX
535 struct min_direct *sdirEntry =
536 (struct min_direct *)osi_AllocSmallSpace(sizeof(struct min_direct));
540 /* opaque value is pointer into a vice dir; use bit map to decide
541 * if the entries are in use. Always assumed to be valid. 0 is
542 * special, means start of a new dir. Int32 inode, followed by
543 * short reclen and short namelen. Namelen does not include
544 * the null byte. Followed by null-terminated string.
546 AFS_STATCNT(afs_readdir);
548 #if defined(AFS_SGI53_ENV)
552 ABI_IS(ABI_IRIX5_64, GETDENTS_ABI(OSI_GET_CURRENT_ABI(), auio));
556 UIO_USERSPACE) ? ABI_IRIX5_64 : (ABI_IS(ABI_IRIX5_64 | ABI_IRIX5_N32,
558 #endif /* AFS_SGI62_ENV */
559 #else /* AFS_SGI61_ENV */
562 UIO_USERSPACE) ? ABI_IRIX5_64 : (ABI_IS(ABI_IRIX5_64,
564 #endif /* AFS_SGI61_ENV */
565 #endif /* defined(AFS_SGI53_ENV) */
567 #if defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV) || defined(AFS_OSF_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
568 /* Not really used by the callee so we ignore it for now */
572 if (AfsLargeFileUio(auio) /* file is large than 2 GB */
573 ||AfsLargeFileSize(auio->uio_offset, auio->uio_resid))
576 if ((code = afs_InitReq(&treq, acred))) {
578 osi_FreeSmallSpace((char *)sdirEntry);
582 /* update the cache entry */
583 afs_InitFakeStat(&fakestate);
584 code = afs_EvalFakeStat(&avc, &fakestate, &treq);
588 code = afs_VerifyVCache(avc, &treq);
591 /* get a reference to the entire directory */
592 tdc = afs_GetDCache(avc, (afs_size_t) 0, &treq, &origOffset, &tlen, 1);
598 ObtainReadLock(&avc->lock);
599 ObtainReadLock(&tdc->lock);
602 * Make sure that the data in the cache is current. There are two
603 * cases we need to worry about:
604 * 1. The cache data is being fetched by another process.
605 * 2. The cache data is no longer valid
607 while ((avc->states & CStatd)
608 && (tdc->dflags & DFFetching)
609 && hsame(avc->m.DataVersion, tdc->f.versionNo)) {
610 afs_Trace4(afs_iclSetp, CM_TRACE_DCACHEWAIT, ICL_TYPE_STRING,
611 __FILE__, ICL_TYPE_INT32, __LINE__, ICL_TYPE_POINTER, tdc,
612 ICL_TYPE_INT32, tdc->dflags);
613 ReleaseReadLock(&tdc->lock);
614 ReleaseReadLock(&avc->lock);
615 afs_osi_Sleep(&tdc->validPos);
616 ObtainReadLock(&avc->lock);
617 ObtainReadLock(&tdc->lock);
619 if (!(avc->states & CStatd)
620 || !hsame(avc->m.DataVersion, tdc->f.versionNo)) {
621 ReleaseReadLock(&tdc->lock);
622 ReleaseReadLock(&avc->lock);
628 * iterator for the directory reads. Takes the AFS DirEntry
629 * structure and slams them into UFS direct structures.
630 * uses afs_readdir_move to get the struct to the user space.
632 * The routine works by looking ahead one AFS directory entry.
633 * That's because the AFS entry we are currenly working with
634 * may not fit into the buffer the user has provided. If it
635 * doesn't we have to change the size of the LAST AFS directory
636 * entry, so that it will FIT perfectly into the block the
639 * The 'forward looking' of the code makes it a bit tough to read.
640 * Remember we need to get an entry, see if it it fits, then
641 * set it up as the LAST entry, and find the next one.
643 * Tough to take: We give out an EINVAL if we don't have enough
644 * space in the buffer, and at the same time, don't have an entry
645 * to put into the buffer. This CAN happen if the first AFS entry
646 * we get can't fit into the 512 character buffer provided. Seems
647 * it ought not happen...
649 * Assumption: don't need to use anything but one dc entry:
650 * this means the directory ought not be greater than 64k.
654 auio->uio_fpflags = 0;
657 origOffset = auio->afsio_offset;
658 /* scan for the next interesting entry scan for in-use blob otherwise up point at
659 * this blob note that ode, if non-zero, also represents a held dir page */
660 if (!(us = BlobScan(&tdc->f.inode, (origOffset >> 5)))
661 || !(nde = (struct DirEntry *)afs_dir_GetBlob(&tdc->f.inode, us))) {
662 /* failed to setup nde, return what we've got, and release ode */
664 /* something to hand over. */
666 sdirEntry->d_fileno =
667 (avc->fid.Fid.Volume << 16) + ntohl(ode->fid.vnode);
668 FIXUPSTUPIDINODE(sdirEntry->d_fileno);
669 sdirEntry->d_reclen = rlen = auio->afsio_resid;
670 sdirEntry->d_namlen = o_slen;
671 #if defined(AFS_SUN_ENV) || defined(AFS_AIX32_ENV) || defined(AFS_HPUX100_ENV)
672 sdirEntry->d_off = origOffset;
674 AFS_UIOMOVE((char *)sdirEntry, sizeof(*sdirEntry), UIO_READ,
677 AFS_UIOMOVE(ode->name, o_slen, UIO_READ, auio, code);
678 /* pad out the remaining characters with zeros */
680 AFS_UIOMOVE(bufofzeros,
681 ((o_slen + 1 + DIRPAD) & ~DIRPAD) - o_slen,
682 UIO_READ, auio, code);
684 /* pad out the difference between rlen and slen... */
685 if (DIRSIZ_LEN(o_slen) < rlen) {
686 while (DIRSIZ_LEN(o_slen) < rlen) {
687 int minLen = rlen - DIRSIZ_LEN(o_slen);
688 if (minLen > sizeof(bufofzeros))
689 minLen = sizeof(bufofzeros);
690 AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
695 code = afs_readdir_move(ode, avc, auio, o_slen,
696 #if defined(AFS_SUN5_ENV)
699 auio->afsio_resid, origOffset);
701 #endif /* AFS_HPUX_ENV */
702 #if !defined(AFS_SUN5_ENV)
703 auio->afsio_resid = 0;
706 /* nothin to hand over */
708 #if defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV) || defined(AFS_OSF_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
710 *eofp = 1; /* Set it properly */
713 DRelease((struct buffer *)ode, 0);
716 /* by here nde is set */
718 /* Do we have enough user space to carry out our mission? */
719 #if defined(AFS_SGI_ENV)
720 n_slen = strlen(nde->name) + 1; /* NULL terminate */
722 n_slen = strlen(nde->name);
726 use64BitDirent ? DIRENTSIZE(n_slen) : IRIX5_DIRENTSIZE(n_slen);
727 if (dirsiz >= (auio->afsio_resid - len)) {
729 if (DIRSIZ_LEN(n_slen) >= (auio->afsio_resid - len)) {
730 #endif /* AFS_SGI53_ENV */
731 /* No can do no more now; ya know... at this time */
732 DRelease((struct buffer *)nde, 0); /* can't use this one. */
735 sdirEntry->d_fileno =
736 (avc->fid.Fid.Volume << 16) + ntohl(ode->fid.vnode);
737 FIXUPSTUPIDINODE(sdirEntry->d_fileno);
738 sdirEntry->d_reclen = rlen = auio->afsio_resid;
739 sdirEntry->d_namlen = o_slen;
740 #if defined(AFS_SUN_ENV) || defined(AFS_AIX32_ENV) || defined(AFS_HPUX100_ENV)
741 sdirEntry->d_off = origOffset;
743 AFS_UIOMOVE((char *)sdirEntry, sizeof(*sdirEntry), UIO_READ,
746 AFS_UIOMOVE(ode->name, o_slen, UIO_READ, auio, code);
747 /* pad out the remaining characters with zeros */
749 AFS_UIOMOVE(bufofzeros,
750 ((o_slen + 1 + DIRPAD) & ~DIRPAD) - o_slen,
751 UIO_READ, auio, code);
753 /* pad out the difference between rlen and slen... */
754 if (DIRSIZ_LEN(o_slen) < rlen) {
755 while (DIRSIZ_LEN(o_slen) < rlen) {
756 int minLen = rlen - DIRSIZ_LEN(o_slen);
757 if (minLen > sizeof(bufofzeros))
758 minLen = sizeof(bufofzeros);
759 AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
763 #else /* AFS_HPUX_ENV */
765 afs_readdir_move(ode, avc, auio, o_slen,
766 auio->afsio_resid, origOffset);
767 #endif /* AFS_HPUX_ENV */
768 /* this next line used to be AFSVFS40 or AIX 3.1, but is
770 auio->afsio_offset = origOffset;
771 auio->afsio_resid = 0;
772 } else { /* trouble, can't give anything to the user! */
773 /* even though he has given us a buffer,
774 * even though we have something to give us,
775 * Looks like we lost something somewhere.
780 DRelease((struct buffer *)ode, 0);
785 * In any event, we move out the LAST de entry, getting ready
786 * to set up for the next one.
790 sdirEntry->d_fileno =
791 (avc->fid.Fid.Volume << 16) + ntohl(ode->fid.vnode);
792 FIXUPSTUPIDINODE(sdirEntry->d_fileno);
793 sdirEntry->d_reclen = rlen = len;
794 sdirEntry->d_namlen = o_slen;
795 #if defined(AFS_SUN_ENV) || defined(AFS_AIX32_ENV) || defined(AFS_HPUX100_ENV)
796 sdirEntry->d_off = origOffset;
798 AFS_UIOMOVE((char *)sdirEntry, sizeof(*sdirEntry), UIO_READ, auio,
801 AFS_UIOMOVE(ode->name, o_slen, UIO_READ, auio, code);
802 /* pad out the remaining characters with zeros */
804 AFS_UIOMOVE(bufofzeros,
805 ((o_slen + 1 + DIRPAD) & ~DIRPAD) - o_slen,
806 UIO_READ, auio, code);
808 /* pad out the difference between rlen and slen... */
809 if (DIRSIZ_LEN(o_slen) < rlen) {
810 while (DIRSIZ_LEN(o_slen) < rlen) {
811 int minLen = rlen - DIRSIZ_LEN(o_slen);
812 if (minLen > sizeof(bufofzeros))
813 minLen = sizeof(bufofzeros);
814 AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
818 #else /* AFS_HPUX_ENV */
819 code = afs_readdir_move(ode, avc, auio, o_slen, len, origOffset);
820 #endif /* AFS_HPUX_ENV */
823 len = use64BitDirent ? DIRENTSIZE(o_slen =
824 n_slen) : IRIX5_DIRENTSIZE(o_slen =
827 len = DIRSIZ_LEN(o_slen = n_slen);
828 #endif /* AFS_SGI53_ENV */
830 DRelease((struct buffer *)ode, 0);
833 (afs_int32) ((us + afs_dir_NameBlobs(nde->name)) << 5);
836 DRelease((struct buffer *)ode, 0);
839 ReleaseReadLock(&tdc->lock);
841 ReleaseReadLock(&avc->lock);
845 osi_FreeSmallSpace((char *)sdirEntry);
847 afs_PutFakeStat(&fakestate);
848 code = afs_CheckCode(code, &treq, 28);
852 #if defined(AFS_HPUX_ENV) || defined(AFS_OSF_ENV)
854 afs1_readdir(avc, auio, acred, eofp)
857 afs1_readdir(avc, auio, acred)
861 struct AFS_UCRED *acred;
863 struct vrequest treq;
864 register struct dcache *tdc;
865 afs_size_t origOffset, len;
867 struct DirEntry *ode = 0, *nde = 0;
868 int o_slen = 0, n_slen = 0;
870 #if defined(AFS_HPUX_ENV) || defined(AFS_OSF_ENV)
872 * XXX All the hacks for alloced sdirEntry and inlining of afs_readdir_move instead of calling
873 * it is necessary for hpux due to stack problems that seem to occur when coming thru the nfs
874 * translator side XXX
876 struct minnfs_direct *sdirEntry = (struct minnfs_direct *)
877 osi_AllocSmallSpace(sizeof(struct min_direct));
880 struct afs_fakestat_state fakestate;
882 AFS_STATCNT(afs_readdir);
883 #if defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV) || defined(AFS_OSF_ENV)
887 if (code = afs_InitReq(&treq, acred)) {
889 osi_FreeSmallSpace((char *)sdirEntry);
893 afs_InitFakeStat(&fakestate);
894 code = afs_EvalFakeStat(&avc, &fakestate, &treq);
897 osi_FreeSmallSpace((char *)sdirEntry);
899 afs_PutFakeStat(&fakestate);
902 /* update the cache entry */
904 code = afs_VerifyVCache(avc, &treq);
907 /* get a reference to the entire directory */
908 tdc = afs_GetDCache(avc, (afs_size_t) 0, &treq, &origOffset, &len, 1);
913 ObtainReadLock(&avc->lock);
914 ObtainReadLock(&tdc->lock);
917 * Make sure that the data in the cache is current. There are two
918 * cases we need to worry about:
919 * 1. The cache data is being fetched by another process.
920 * 2. The cache data is no longer valid
922 while ((avc->states & CStatd)
923 && (tdc->dflags & DFFetching)
924 && hsame(avc->m.DataVersion, tdc->f.versionNo)) {
925 afs_Trace4(afs_iclSetp, CM_TRACE_DCACHEWAIT, ICL_TYPE_STRING,
926 __FILE__, ICL_TYPE_INT32, __LINE__, ICL_TYPE_POINTER, tdc,
927 ICL_TYPE_INT32, tdc->dflags);
928 ReleaseReadLock(&tdc->lock);
929 ReleaseReadLock(&avc->lock);
930 afs_osi_Sleep(&tdc->validPos);
931 ObtainReadLock(&avc->lock);
932 ObtainReadLock(&tdc->lock);
934 if (!(avc->states & CStatd)
935 || !hsame(avc->m.DataVersion, tdc->f.versionNo)) {
936 ReleaseReadLock(&tdc->lock);
937 ReleaseReadLock(&avc->lock);
944 auio->uio_fpflags = 0;
947 origOffset = auio->afsio_offset;
949 /* scan for the next interesting entry scan for in-use blob otherwise up point at
950 * this blob note that ode, if non-zero, also represents a held dir page */
951 if (!(us = BlobScan(&tdc->f.inode, (origOffset >> 5)))
952 || !(nde = (struct DirEntry *)afs_dir_GetBlob(&tdc->f.inode, us))) {
953 /* failed to setup nde, return what we've got, and release ode */
955 /* something to hand over. */
956 #if defined(AFS_HPUX_ENV) || defined(AFS_OSF_ENV)
957 sdirEntry->d_fileno =
958 (avc->fid.Fid.Volume << 16) + ntohl(ode->fid.vnode);
959 FIXUPSTUPIDINODE(sdirEntry->d_fileno);
960 sdirEntry->d_reclen = rlen = auio->afsio_resid;
961 sdirEntry->d_namlen = o_slen;
962 sdirEntry->d_off = origOffset;
963 AFS_UIOMOVE((char *)sdirEntry, sizeof(*sdirEntry), UIO_READ,
966 AFS_UIOMOVE(ode->name, o_slen, UIO_READ, auio, code);
968 /* pad out the remaining characters with zeros */
970 AFS_UIOMOVE(bufofzeros,
971 ((o_slen + 1 + DIRPAD) & ~DIRPAD) - o_slen,
972 UIO_READ, auio, code);
974 /* pad out the difference between rlen and slen... */
975 if (NDIRSIZ_LEN(o_slen) < rlen) {
976 while (NDIRSIZ_LEN(o_slen) < rlen) {
977 int minLen = rlen - NDIRSIZ_LEN(o_slen);
978 if (minLen > sizeof(bufofzeros))
979 minLen = sizeof(bufofzeros);
980 AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
986 afs_readdir_move(ode, avc, auio, o_slen,
987 auio->afsio_resid, origOffset);
988 #endif /* AFS_HPUX_ENV */
989 auio->afsio_resid = 0;
991 /* nothin to hand over */
993 #if defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV) || defined(AFS_OSF_ENV)
1001 /* by here nde is set */
1003 /* Do we have enough user space to carry out our mission? */
1004 #if defined(AFS_SGI_ENV)
1005 n_slen = strlen(nde->name) + 1; /* NULL terminate */
1007 n_slen = strlen(nde->name);
1009 if (NDIRSIZ_LEN(n_slen) >= (auio->afsio_resid - len)) {
1010 /* No can do no more now; ya know... at this time */
1011 DRelease(nde, 0); /* can't use this one. */
1013 #if defined(AFS_HPUX_ENV) || defined(AFS_OSF_ENV)
1014 sdirEntry->d_fileno =
1015 (avc->fid.Fid.Volume << 16) + ntohl(ode->fid.vnode);
1016 FIXUPSTUPIDINODE(sdirEntry->d_fileno);
1017 sdirEntry->d_reclen = rlen = auio->afsio_resid;
1018 sdirEntry->d_namlen = o_slen;
1019 sdirEntry->d_off = origOffset;
1020 AFS_UIOMOVE((char *)sdirEntry, sizeof(*sdirEntry), UIO_READ,
1023 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 /* this next line used to be AFSVFS40 or AIX 3.1, but is really generic */
1046 auio->afsio_offset = origOffset;
1047 auio->afsio_resid = 0;
1048 } else { /* trouble, can't give anything to the user! */
1049 /* even though he has given us a buffer,
1050 * even though we have something to give us,
1051 * Looks like we lost something somewhere.
1061 * In any event, we move out the LAST de entry, getting ready
1062 * to set up for the next one.
1065 #if defined(AFS_HPUX_ENV) || defined(AFS_OSF_ENV)
1066 sdirEntry->d_fileno =
1067 (avc->fid.Fid.Volume << 16) + ntohl(ode->fid.vnode);
1068 FIXUPSTUPIDINODE(sdirEntry->d_fileno);
1069 sdirEntry->d_reclen = rlen = len;
1070 sdirEntry->d_namlen = o_slen;
1071 sdirEntry->d_off = origOffset;
1072 AFS_UIOMOVE((char *)sdirEntry, sizeof(*sdirEntry), UIO_READ, auio,
1075 AFS_UIOMOVE(ode->name, o_slen, UIO_READ, auio, code);
1076 /* pad out the remaining characters with zeros */
1078 AFS_UIOMOVE(bufofzeros,
1079 ((o_slen + 1 + DIRPAD) & ~DIRPAD) - o_slen,
1080 UIO_READ, auio, code);
1082 /* pad out the difference between rlen and slen... */
1083 if (NDIRSIZ_LEN(o_slen) < rlen) {
1084 while (NDIRSIZ_LEN(o_slen) < rlen) {
1085 int minLen = rlen - NDIRSIZ_LEN(o_slen);
1086 if (minLen > sizeof(bufofzeros))
1087 minLen = sizeof(bufofzeros);
1088 AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
1093 code = afs_readdir_move(ode, avc, auio, o_slen, len, origOffset);
1094 #endif /* AFS_HPUX_ENV */
1096 len = NDIRSIZ_LEN(o_slen = n_slen);
1100 auio->afsio_offset = ((us + afs_dir_NameBlobs(nde->name)) << 5);
1106 ReleaseReadLock(&tdc->lock);
1108 ReleaseReadLock(&avc->lock);
1111 #if defined(AFS_HPUX_ENV) || defined(AFS_OSF_ENV)
1112 osi_FreeSmallSpace((char *)sdirEntry);
1114 afs_PutFakeStat(&fakestate);
1115 code = afs_CheckCode(code, &treq, 29);
1120 #endif /* !AFS_LINUX20_ENV */