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"
27 #include "afs/sysincludes.h" /* Standard vendor system headers */
28 #include "afsincludes.h" /* Afs-based standard headers */
29 #include "afs/afs_stats.h" /* statistics */
30 #include "afs/afs_cbqueue.h"
31 #include "afs/nfsclient.h"
32 #include "afs/afs_osidnlc.h"
35 #if defined(AFS_HPUX1122_ENV)
41 * A few definitions. This is until we have a proper header file
42 * which ahs prototypes for all functions
45 extern struct DirEntry * afs_dir_GetBlob();
47 * AFS readdir vnodeop and bulk stat support.
50 /* Saber C hates negative inode #s. We're not going to talk about software
51 * that could fail if it sees a negative inode #.
53 #define FIXUPSTUPIDINODE(a) ((a) &= 0x7fffffff)
55 /* BlobScan is supposed to ensure that the blob reference refers to a valid
56 directory entry. It consults the allocation map in the page header
57 to determine whether a blob is actually in use or not.
59 More formally, BlobScan is supposed to return a new blob number which is just like
60 the input parameter, only it is advanced over header or free blobs.
62 Note that BlobScan switches pages if necessary. BlobScan may return
63 either 0 or an out-of-range blob number for end of file.
65 BlobScan is used by the Linux port in a separate file, so it should not
68 #if defined(AFS_SGI62_ENV) || defined(AFS_SUN57_64BIT_ENV)
69 int BlobScan(ino64_t *afile, afs_int32 ablob)
71 #ifdef AFS_LINUX_64BIT_KERNEL
72 int BlobScan(long *afile, afs_int32 ablob)
74 int BlobScan(afs_int32 *afile, afs_int32 ablob)
78 register afs_int32 relativeBlob;
80 register struct PageHeader *tpe;
83 AFS_STATCNT(BlobScan);
84 /* advance ablob over free and header blobs */
86 pageBlob = ablob & ~(EPP-1); /* base blob in same page */
87 tpe = (struct PageHeader *) afs_dir_GetBlob(afile, pageBlob);
88 if (!tpe) return 0; /* we've past the end */
89 relativeBlob = ablob - pageBlob; /* relative to page's first blob */
90 /* first watch for headers */
91 if (pageBlob == 0) { /* first dir page has extra-big header */
93 if (relativeBlob < DHE+1) relativeBlob = DHE+1;
95 else { /* others have one header blob */
96 if (relativeBlob == 0) relativeBlob = 1;
98 /* make sure blob is allocated */
99 for(i = relativeBlob; i < EPP; i++) {
100 if (tpe->freebitmap[i>>3] & (1<<(i&7))) break;
102 /* now relativeBlob is the page-relative first allocated blob,
103 or EPP (if there are none in this page). */
104 DRelease((struct buffer *) tpe, 0);
105 if (i != EPP) return i+pageBlob;
106 ablob = pageBlob + EPP; /* go around again */
111 #if !defined(AFS_LINUX20_ENV)
112 /* Changes to afs_readdir which affect dcache or vcache handling or use of
113 * bulk stat data should also be reflected in the Linux specific verison of
114 * the readdir routine.
118 * The kernel don't like it so much to have large stuff on the stack.
119 * Here we use a watered down version of the direct struct, since
120 * its not too bright to double copy the strings anyway.
122 #if !defined(UKERNEL)
123 #if defined(AFS_SGI_ENV)
124 /* Long form for 64 bit apps and kernel requests. */
125 struct min_dirent { /* miniature dirent structure */
126 /* If struct dirent changes, this must too */
127 ino_t d_fileno; /* This is 32 bits for 3.5, 64 for 6.2+ */
131 /* Short form for 32 bit apps. */
132 struct irix5_min_dirent { /* miniature dirent structure */
133 /* If struct dirent changes, this must too */
139 #define AFS_DIRENT32BASESIZE IRIX5_DIRENTBASESIZE
140 #define AFS_DIRENT64BASESIZE DIRENT64BASESIZE
142 #define AFS_DIRENT32BASESIZE IRIX5_DIRENTBASESIZE
143 #define AFS_DIRENT64BASESIZE DIRENTBASESIZE
144 #endif /* AFS_SGI62_ENV */
146 struct min_direct { /* miniature direct structure */
147 /* If struct direct changes, this must too */
148 #if defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
159 #if defined(AFS_SUN_ENV) || defined(AFS_AIX32_ENV)
162 #if defined(AFS_HPUX100_ENV)
163 unsigned long long d_off;
171 #endif /* AFS_SGI_ENV */
173 #if defined(AFS_HPUX_ENV) || defined(AFS_OSF_ENV)
174 struct minnfs_direct {
175 afs_int32 d_off; /* XXX */
180 #define NDIRSIZ_LEN(len) ((sizeof (struct dirent)+4 - (MAXNAMLEN+1)) + (((len)+1 + DIRPAD) &~ DIRPAD))
182 #endif /* !defined(UKERNEL) */
186 *------------------------------------------------------------------------------
188 * Keep a stack of about 256 fids for the bulk stat call.
189 * Fill it during the readdir_move. Later empty it...
192 #define READDIR_STASH AFSCBMAX
193 struct AFSFid afs_readdir_stash[READDIR_STASH];
194 int afs_rd_stash_i = 0;
197 *------------------------------------------------------------------------------
200 * mainly a kind of macro... makes getting the struct direct
201 * out to the user space easy... could take more parameters,
202 * but now just takes what it needs.
207 #if defined(AFS_HPUX100_ENV)
208 #define DIRSIZ_LEN(len) \
209 ((sizeof (struct __dirent) - (_MAXNAMLEN+1)) + (((len)+1 + DIRPAD) &~ DIRPAD))
211 #if defined(AFS_SUN56_ENV)
212 #define DIRSIZ_LEN(len) ((18 + (len) + 1 + 7) & ~7 )
215 #define DIRSIZ_LEN(len) ((10 + (len) + 1 + (NBPW-1)) & ~(NBPW-1))
218 #define DIRSIZ_LEN(len) \
219 ((sizeof (struct dirent) - (MAXNAMLEN+1)) + (((len)+1 + 3) &~ 3))
221 #if defined(AFS_SGI_ENV)
222 #ifndef AFS_SGI53_ENV
223 /* SGI 5.3 and later use 32/64 bit versions of directory size. */
224 #define DIRSIZ_LEN(len) DIRENTSIZE(len)
226 #else /* AFS_SGI_ENV */
227 #define DIRSIZ_LEN(len) \
228 ((sizeof (struct direct) - (MAXNAMLEN+1)) + (((len)+1 + 3) &~ 3))
229 #endif /* AFS_SGI_ENV */
230 #endif /* AFS_DIRENT */
231 #endif /* AFS_SUN5_ENV */
232 #endif /* AFS_SUN56_ENV */
233 #endif /* AFS_HPUX100_ENV */
235 #if defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
236 int afs_readdir_type(avc, ade)
237 struct DirEntry * ade;
240 struct VenusFid tfid;
243 tfid.Cell=avc->fid.Cell;
244 tfid.Fid.Volume=avc->fid.Fid.Volume;
245 tfid.Fid.Vnode=ntohl(ade->fid.vnode);
246 tfid.Fid.Unique=ntohl(ade->fid.vunique);
247 if ((avc->states & CForeign) == 0 &&
248 (ntohl(ade->fid.vnode) & 1)) {
250 } else if ((tvc=afs_FindVCache(&tfid,0,0))) {
254 } else if (((tvc->states) & (CStatd|CTruth))) {
255 /* CTruth will be set if the object has
261 else if (vtype == VREG)
263 /* Don't do this until we're sure it can't be a mtpt */
264 /* else if (vtype == VLNK)
266 /* what other types does AFS support? */
275 #define AFS_MOVE_LOCK() AFS_GLOCK()
276 #define AFS_MOVE_UNLOCK() AFS_GUNLOCK()
278 #define AFS_MOVE_LOCK()
279 #define AFS_MOVE_UNLOCK()
281 char bufofzeros[64]; /* gotta fill with something */
282 afs_readdir_move (de, vc, auio, slen, rlen, off)
283 struct DirEntry * de;
295 #if defined(AFS_SUN56_ENV)
296 struct dirent64 *direntp;
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;
313 use64BitDirent = ABI_IS(ABI_IRIX5_64,
314 GETDENTS_ABI*OSI_GET_CURRENT_ABI(), auio));
316 use64BitDirent = (auio->uio_segflg != UIO_USERSPACE) ? ABI_IRIX5_64 :
317 (ABI_IS(ABI_IRIX5_64 | ABI_IRIX5_N32, u.u_procp->p_abi));
319 #else /* AFS_SGI61_ENV */
320 use64BitDirent = (auio->uio_segflg != UIO_USERSPACE) ? ABI_IRIX5_64 :
321 (ABI_IS(ABI_IRIX5_64, u.u_procp->p_abi));
322 #endif /* AFS_SGI61_ENV */
324 if (use64BitDirent) {
325 struct min_dirent sdirEntry;
326 sdirEntry.d_fileno = (vc->fid.Fid.Volume << 16) + ntohl(de->fid.vnode);
327 FIXUPSTUPIDINODE(sdirEntry.d_fileno);
328 sdirEntry.d_reclen = rlen;
329 sdirEntry.d_off = (off_t)off;
330 AFS_UIOMOVE(&sdirEntry, AFS_DIRENT64BASESIZE, UIO_READ, auio, code);
332 AFS_UIOMOVE(de->name, slen-1, UIO_READ, auio, code);
334 AFS_UIOMOVE(bufofzeros,
335 DIRENTSIZE(slen) - (AFS_DIRENT64BASESIZE + slen - 1),
336 UIO_READ, auio, code);
337 if (DIRENTSIZE(slen) < rlen) {
338 while(DIRENTSIZE(slen) < rlen) {
339 int minLen = rlen - DIRENTSIZE(slen);
340 if (minLen > sizeof(bufofzeros)) minLen = sizeof(bufofzeros);
341 AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
346 struct irix5_min_dirent sdirEntry;
347 sdirEntry.d_fileno = (vc->fid.Fid.Volume << 16) + ntohl(de->fid.vnode);
348 FIXUPSTUPIDINODE(sdirEntry.d_fileno);
349 sdirEntry.d_reclen = rlen;
350 sdirEntry.d_off = (afs_int32)off;
351 AFS_UIOMOVE(&sdirEntry, AFS_DIRENT32BASESIZE, UIO_READ, auio, code);
353 AFS_UIOMOVE(de->name, slen-1, UIO_READ, auio, code);
355 AFS_UIOMOVE(bufofzeros,
356 IRIX5_DIRENTSIZE(slen) -
357 (AFS_DIRENT32BASESIZE + slen - 1),
358 UIO_READ, auio, code);
359 if (IRIX5_DIRENTSIZE(slen) < rlen) {
360 while(IRIX5_DIRENTSIZE(slen) < rlen) {
361 int minLen = rlen - IRIX5_DIRENTSIZE(slen);
362 if (minLen > sizeof(bufofzeros)) minLen = sizeof(bufofzeros);
363 AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
369 #else /* AFS_SGI53_ENV */
371 #if defined(AFS_SUN56_ENV)
372 direntp = (struct dirent64 *) osi_AllocLargeSpace(AFS_LRALLOCSIZ);
374 direntp = (struct dirent *) osi_AllocLargeSpace(AFS_LRALLOCSIZ);
376 direntp->d_ino = (vc->fid.Fid.Volume << 16) + ntohl(de->fid.vnode);
377 FIXUPSTUPIDINODE(direntp->d_ino);
378 direntp->d_off = off;
379 direntp->d_reclen = rlen;
380 strcpy(direntp->d_name, de->name);
381 AFS_UIOMOVE((caddr_t)direntp, rlen, UIO_READ, auio, code);
382 osi_FreeLargeSpace((char *)direntp);
383 #else /* AFS_SUN5_ENV */
384 /* Note the odd mechanism for building the inode number */
385 sdirEntry.d_fileno = (vc->fid.Fid.Volume << 16) +
386 ntohl(de->fid.vnode);
387 FIXUPSTUPIDINODE(sdirEntry.d_fileno);
388 sdirEntry.d_reclen = rlen;
389 #if !defined(AFS_SGI_ENV)
390 sdirEntry.d_namlen = slen;
392 #if defined(AFS_SUN_ENV) || defined(AFS_AIX32_ENV) || defined(AFS_SGI_ENV)
393 sdirEntry.d_off = off;
395 #if defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
396 sdirEntry.d_type=afs_readdir_type(vc, de);
399 #if defined(AFS_SGI_ENV)
400 AFS_UIOMOVE(&sdirEntry, DIRENTBASESIZE, UIO_READ, auio, code);
402 AFS_UIOMOVE(de->name, slen-1, UIO_READ, auio, code);
404 AFS_UIOMOVE(bufofzeros, DIRSIZ_LEN(slen) - (DIRENTBASESIZE + slen - 1), UIO_READ, auio, code);
405 #else /* AFS_SGI_ENV */
407 AFS_UIOMOVE((char *)&sdirEntry, sizeof(sdirEntry), UIO_READ, auio, code);
410 AFS_UIOMOVE(de->name, slen, UIO_READ, auio, code);
413 /* pad out the remaining characters with zeros */
415 AFS_UIOMOVE(bufofzeros, ((slen + 1 + DIRPAD) & ~DIRPAD) - slen, UIO_READ,
419 #endif /* AFS_SGI_ENV */
421 /* pad out the difference between rlen and slen... */
422 if (DIRSIZ_LEN(slen) < rlen)
425 while(DIRSIZ_LEN(slen) < rlen)
427 int minLen = rlen - DIRSIZ_LEN(slen);
428 if (minLen > sizeof(bufofzeros))
429 minLen = sizeof(bufofzeros);
430 AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
435 #endif /* AFS_SUN5_ENV */
436 #endif /* AFS_SGI53_ENV */
442 *------------------------------------------------------------------------------
444 * Read directory entries.
445 * There are some weird things to look out for here. The uio_offset
446 * field is either 0 or it is the offset returned from a previous
447 * readdir. It is an opaque value used by the server to find the
448 * correct directory block to read. The byte count must be at least
449 * vtoblksz(vp) bytes. The count field is the number of blocks to
450 * read on the server. This is advisory only, the server may return
451 * only one block's worth of entries. Entries may be compressed on
454 * This routine encodes knowledge of Vice dirs.
457 void afs_bulkstat_send( avc, req )
459 struct vrequest * req;
465 * Here is the bad, bad, really bad news.
466 * It has to do with 'offset' (seek locations).
469 #if defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV) || defined(AFS_OSF_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
470 afs_readdir(OSI_VC_ARG(avc), auio, acred, eofp)
473 #if defined(AFS_HPUX100_ENV)
474 afs_readdir2(OSI_VC_ARG(avc), auio, acred)
476 afs_readdir(OSI_VC_ARG(avc), auio, acred)
481 struct AFS_UCRED *acred;
483 struct vrequest treq;
484 register struct dcache *tdc;
485 afs_size_t origOffset, tlen;
488 struct DirEntry *ode = 0, *nde = 0;
489 int o_slen = 0, n_slen = 0;
491 struct afs_fakestat_state fakestate;
492 #if defined(AFS_SGI53_ENV)
493 afs_int32 use64BitDirent, dirsiz;
494 #endif /* defined(AFS_SGI53_ENV) */
498 * XXX All the hacks for alloced sdirEntry and inlining of afs_readdir_move instead of calling
499 * it is necessary for hpux due to stack problems that seem to occur when coming thru the nfs
500 * translator side XXX
502 struct min_direct *sdirEntry = (struct min_direct *)osi_AllocSmallSpace(sizeof(struct min_direct));
506 /* opaque value is pointer into a vice dir; use bit map to decide
507 if the entries are in use. Always assumed to be valid. 0 is
508 special, means start of a new dir. Int32 inode, followed by
509 short reclen and short namelen. Namelen does not include
510 the null byte. Followed by null-terminated string.
512 AFS_STATCNT(afs_readdir);
514 #if defined(AFS_SGI53_ENV)
517 use64BitDirent = ABI_IS(ABI_IRIX5_64,
518 GETDENTS_ABI(OSI_GET_CURRENT_ABI(), auio));
520 use64BitDirent = (auio->uio_segflg != UIO_USERSPACE) ? ABI_IRIX5_64 :
521 (ABI_IS(ABI_IRIX5_64 | ABI_IRIX5_N32, u.u_procp->p_abi));
522 #endif /* AFS_SGI62_ENV */
523 #else /* AFS_SGI61_ENV */
524 use64BitDirent = (auio->uio_segflg != UIO_USERSPACE) ? ABI_IRIX5_64 :
525 (ABI_IS(ABI_IRIX5_64, u.u_procp->p_abi));
526 #endif /* AFS_SGI61_ENV */
527 #endif /* defined(AFS_SGI53_ENV) */
529 #if defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV) || defined(AFS_OSF_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
530 /* Not really used by the callee so we ignore it for now */
533 if ( AfsLargeFileUio(auio) /* file is large than 2 GB */
534 || AfsLargeFileSize(auio->uio_offset, auio->uio_resid) )
537 if ((code = afs_InitReq(&treq, acred))) {
539 osi_FreeSmallSpace((char *)sdirEntry);
543 /* update the cache entry */
544 afs_InitFakeStat(&fakestate);
545 code = afs_EvalFakeStat(&avc, &fakestate, &treq);
548 code = afs_VerifyVCache(avc, &treq);
550 /* get a reference to the entire directory */
551 tdc = afs_GetDCache(avc, (afs_size_t) 0, &treq, &origOffset, &tlen, 1);
557 ObtainReadLock(&avc->lock);
558 ObtainReadLock(&tdc->lock);
561 * Make sure that the data in the cache is current. There are two
562 * cases we need to worry about:
563 * 1. The cache data is being fetched by another process.
564 * 2. The cache data is no longer valid
566 while ((avc->states & CStatd)
567 && (tdc->dflags & DFFetching)
568 && hsame(avc->m.DataVersion, tdc->f.versionNo)) {
569 afs_Trace4(afs_iclSetp, CM_TRACE_DCACHEWAIT,
570 ICL_TYPE_STRING, __FILE__,
571 ICL_TYPE_INT32, __LINE__,
572 ICL_TYPE_POINTER, tdc,
573 ICL_TYPE_INT32, tdc->dflags);
574 ReleaseReadLock(&tdc->lock);
575 ReleaseReadLock(&avc->lock);
576 afs_osi_Sleep(&tdc->validPos);
577 ObtainReadLock(&avc->lock);
578 ObtainReadLock(&tdc->lock);
580 if (!(avc->states & CStatd)
581 || !hsame(avc->m.DataVersion, tdc->f.versionNo)) {
582 ReleaseReadLock(&tdc->lock);
583 ReleaseReadLock(&avc->lock);
589 * iterator for the directory reads. Takes the AFS DirEntry
590 * structure and slams them into UFS direct structures.
591 * uses afs_readdir_move to get the struct to the user space.
593 * The routine works by looking ahead one AFS directory entry.
594 * That's because the AFS entry we are currenly working with
595 * may not fit into the buffer the user has provided. If it
596 * doesn't we have to change the size of the LAST AFS directory
597 * entry, so that it will FIT perfectly into the block the
600 * The 'forward looking' of the code makes it a bit tough to read.
601 * Remember we need to get an entry, see if it it fits, then
602 * set it up as the LAST entry, and find the next one.
604 * Tough to take: We give out an EINVAL if we don't have enough
605 * space in the buffer, and at the same time, don't have an entry
606 * to put into the buffer. This CAN happen if the first AFS entry
607 * we get can't fit into the 512 character buffer provided. Seems
608 * it ought not happen...
610 * Assumption: don't need to use anything but one dc entry:
611 * this means the directory ought not be greater than 64k.
615 auio->uio_fpflags = 0;
618 origOffset = auio->afsio_offset;
619 /* scan for the next interesting entry scan for in-use blob otherwise up point at
620 * this blob note that ode, if non-zero, also represents a held dir page */
621 if (!(us = BlobScan(&tdc->f.inode, (origOffset >> 5)) )
622 || !(nde = (struct DirEntry *) afs_dir_GetBlob(&tdc->f.inode, us) ) ) {
623 /* failed to setup nde, return what we've got, and release ode */
625 /* something to hand over. */
627 sdirEntry->d_fileno = (avc->fid.Fid.Volume << 16) + ntohl(ode->fid.vnode);
628 FIXUPSTUPIDINODE(sdirEntry->d_fileno);
629 sdirEntry->d_reclen = rlen = auio->afsio_resid;
630 sdirEntry->d_namlen = o_slen;
631 #if defined(AFS_SUN_ENV) || defined(AFS_AIX32_ENV) || defined(AFS_HPUX100_ENV)
632 sdirEntry->d_off = origOffset;
634 AFS_UIOMOVE((char *)sdirEntry, sizeof(*sdirEntry), UIO_READ, auio, code);
636 AFS_UIOMOVE(ode->name, o_slen, UIO_READ, auio, code);
637 /* pad out the remaining characters with zeros */
639 AFS_UIOMOVE(bufofzeros, ((o_slen + 1 + DIRPAD) & ~DIRPAD) - o_slen, UIO_READ, auio, code);
641 /* pad out the difference between rlen and slen... */
642 if (DIRSIZ_LEN(o_slen) < rlen) {
643 while(DIRSIZ_LEN(o_slen) < rlen) {
644 int minLen = rlen - DIRSIZ_LEN(o_slen);
645 if (minLen > sizeof(bufofzeros))
646 minLen = sizeof(bufofzeros);
647 AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
652 code = afs_readdir_move(ode, avc, auio, o_slen,
653 #if defined(AFS_SUN5_ENV)
656 auio->afsio_resid, origOffset);
658 #endif /* AFS_HPUX_ENV */
659 #if !defined(AFS_SUN5_ENV)
660 auio->afsio_resid = 0;
663 /* nothin to hand over */
665 #if defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV) || defined(AFS_OSF_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
666 if (eofp) *eofp = 1; /* Set it properly */
668 if (ode) DRelease((struct buffer *) ode, 0);
671 /* by here nde is set */
673 /* Do we have enough user space to carry out our mission? */
674 #if defined(AFS_SGI_ENV)
675 n_slen = strlen(nde->name) + 1; /* NULL terminate */
677 n_slen = strlen(nde->name);
680 dirsiz = use64BitDirent ? DIRENTSIZE(n_slen) :
681 IRIX5_DIRENTSIZE(n_slen);
682 if (dirsiz >= (auio->afsio_resid-len)) {
684 if (DIRSIZ_LEN(n_slen) >= (auio->afsio_resid-len)) {
685 #endif /* AFS_SGI53_ENV */
686 /* No can do no more now; ya know... at this time */
687 DRelease ((struct buffer *) nde, 0); /* can't use this one. */
690 sdirEntry->d_fileno = (avc->fid.Fid.Volume << 16) + ntohl(ode->fid.vnode);
691 FIXUPSTUPIDINODE(sdirEntry->d_fileno);
692 sdirEntry->d_reclen = rlen = auio->afsio_resid;
693 sdirEntry->d_namlen = o_slen;
694 #if defined(AFS_SUN_ENV) || defined(AFS_AIX32_ENV) || defined(AFS_HPUX100_ENV)
695 sdirEntry->d_off = origOffset;
697 AFS_UIOMOVE((char *)sdirEntry, sizeof(*sdirEntry), UIO_READ, auio, code);
699 AFS_UIOMOVE(ode->name, o_slen, UIO_READ, auio, code);
700 /* pad out the remaining characters with zeros */
702 AFS_UIOMOVE(bufofzeros, ((o_slen + 1 + DIRPAD) & ~DIRPAD) - o_slen, UIO_READ, auio, code);
704 /* pad out the difference between rlen and slen... */
705 if (DIRSIZ_LEN(o_slen) < rlen) {
706 while(DIRSIZ_LEN(o_slen) < rlen) {
707 int minLen = rlen - DIRSIZ_LEN(o_slen);
708 if (minLen > sizeof(bufofzeros))
709 minLen = sizeof(bufofzeros);
710 AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
714 #else /* AFS_HPUX_ENV */
715 code = afs_readdir_move(ode, avc, auio, o_slen,
716 auio->afsio_resid, origOffset);
717 #endif /* AFS_HPUX_ENV */
718 /* this next line used to be AFSVFS40 or AIX 3.1, but is
720 auio->afsio_offset = origOffset;
721 auio->afsio_resid = 0;
722 } else { /* trouble, can't give anything to the user! */
723 /* even though he has given us a buffer,
724 * even though we have something to give us,
725 * Looks like we lost something somewhere.
729 if (ode) DRelease((struct buffer *) ode, 0);
734 * In any event, we move out the LAST de entry, getting ready
735 * to set up for the next one.
739 sdirEntry->d_fileno =
740 (avc->fid.Fid.Volume << 16) + ntohl(ode->fid.vnode);
741 FIXUPSTUPIDINODE(sdirEntry->d_fileno);
742 sdirEntry->d_reclen = rlen = len;
743 sdirEntry->d_namlen = o_slen;
744 #if defined(AFS_SUN_ENV) || defined(AFS_AIX32_ENV) || defined(AFS_HPUX100_ENV)
745 sdirEntry->d_off = origOffset;
747 AFS_UIOMOVE((char *)sdirEntry, sizeof(*sdirEntry), UIO_READ,
750 AFS_UIOMOVE(ode->name, o_slen, UIO_READ, auio, code);
751 /* pad out the remaining characters with zeros */
753 AFS_UIOMOVE(bufofzeros, ((o_slen + 1 + DIRPAD) & ~DIRPAD) - o_slen,
754 UIO_READ, auio, code);
756 /* pad out the difference between rlen and slen... */
757 if (DIRSIZ_LEN(o_slen) < rlen) {
758 while(DIRSIZ_LEN(o_slen) < rlen) {
759 int minLen = rlen - DIRSIZ_LEN(o_slen);
760 if (minLen > sizeof(bufofzeros))
761 minLen = sizeof(bufofzeros);
762 AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
766 #else /* AFS_HPUX_ENV */
767 code = afs_readdir_move (ode, avc, auio, o_slen, len, origOffset);
768 #endif /* AFS_HPUX_ENV */
771 len = use64BitDirent ? DIRENTSIZE(o_slen = n_slen) :
772 IRIX5_DIRENTSIZE(o_slen = n_slen);
774 len = DIRSIZ_LEN( o_slen = n_slen );
775 #endif /* AFS_SGI53_ENV */
776 if (ode) DRelease((struct buffer *) ode, 0);
778 auio->afsio_offset = (afs_int32)((us + afs_dir_NameBlobs(nde->name)) << 5);
780 if (ode) DRelease((struct buffer *) ode, 0);
783 ReleaseReadLock(&tdc->lock);
785 ReleaseReadLock(&avc->lock);
789 osi_FreeSmallSpace((char *)sdirEntry);
791 afs_PutFakeStat(&fakestate);
792 code = afs_CheckCode(code, &treq, 28);
796 #if defined(AFS_HPUX_ENV) || defined(AFS_OSF_ENV)
798 afs1_readdir(avc, auio, acred, eofp)
801 afs1_readdir(avc, auio, acred)
805 struct AFS_UCRED *acred; {
806 struct vrequest treq;
807 register struct dcache *tdc;
808 afs_size_t origOffset, len;
810 struct DirEntry *ode = 0, *nde = 0;
811 int o_slen = 0, n_slen = 0;
813 #if defined(AFS_HPUX_ENV) || defined(AFS_OSF_ENV)
815 * XXX All the hacks for alloced sdirEntry and inlining of afs_readdir_move instead of calling
816 * it is necessary for hpux due to stack problems that seem to occur when coming thru the nfs
817 * translator side XXX
819 struct minnfs_direct *sdirEntry = (struct minnfs_direct *)osi_AllocSmallSpace(sizeof(struct min_direct));
822 struct afs_fakestat_state fakestate;
824 AFS_STATCNT(afs_readdir);
825 #if defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV) || defined(AFS_OSF_ENV)
828 if (code = afs_InitReq(&treq, acred)) {
830 osi_FreeSmallSpace((char *)sdirEntry);
834 afs_InitFakeStat(&fakestate);
835 code = afs_EvalFakeStat(&avc, &fakestate, &treq);
838 osi_FreeSmallSpace((char *)sdirEntry);
840 afs_PutFakeStat(&fakestate);
843 /* update the cache entry */
845 code = afs_VerifyVCache(avc, &treq);
847 /* get a reference to the entire directory */
848 tdc = afs_GetDCache(avc, (afs_size_t) 0, &treq, &origOffset, &len, 1);
853 ObtainReadLock(&avc->lock);
854 ObtainReadLock(&tdc->lock);
857 * Make sure that the data in the cache is current. There are two
858 * cases we need to worry about:
859 * 1. The cache data is being fetched by another process.
860 * 2. The cache data is no longer valid
862 while ((avc->states & CStatd)
863 && (tdc->dflags & DFFetching)
864 && hsame(avc->m.DataVersion, tdc->f.versionNo)) {
865 afs_Trace4(afs_iclSetp, CM_TRACE_DCACHEWAIT,
866 ICL_TYPE_STRING, __FILE__,
867 ICL_TYPE_INT32, __LINE__,
868 ICL_TYPE_POINTER, tdc,
869 ICL_TYPE_INT32, tdc->dflags);
870 ReleaseReadLock(&tdc->lock);
871 ReleaseReadLock(&avc->lock);
872 afs_osi_Sleep(&tdc->validPos);
873 ObtainReadLock(&avc->lock);
874 ObtainReadLock(&tdc->lock);
876 if (!(avc->states & CStatd)
877 || !hsame(avc->m.DataVersion, tdc->f.versionNo)) {
878 ReleaseReadLock(&tdc->lock);
879 ReleaseReadLock(&avc->lock);
886 auio->uio_fpflags = 0;
889 origOffset = auio->afsio_offset;
891 /* scan for the next interesting entry scan for in-use blob otherwise up point at
892 * this blob note that ode, if non-zero, also represents a held dir page */
893 if (!(us = BlobScan(&tdc->f.inode, (origOffset >> 5)) )
894 || !(nde = (struct DirEntry *) afs_dir_GetBlob(&tdc->f.inode, us) ) ) {
895 /* failed to setup nde, return what we've got, and release ode */
897 /* something to hand over. */
898 #if defined(AFS_HPUX_ENV) || defined(AFS_OSF_ENV)
899 sdirEntry->d_fileno = (avc->fid.Fid.Volume << 16) + ntohl(ode->fid.vnode);
900 FIXUPSTUPIDINODE(sdirEntry->d_fileno);
901 sdirEntry->d_reclen = rlen = auio->afsio_resid;
902 sdirEntry->d_namlen = o_slen;
903 sdirEntry->d_off = origOffset;
904 AFS_UIOMOVE((char *)sdirEntry, sizeof(*sdirEntry), UIO_READ, auio, code);
906 AFS_UIOMOVE(ode->name, o_slen, UIO_READ, auio, code);
908 /* pad out the remaining characters with zeros */
910 AFS_UIOMOVE(bufofzeros, ((o_slen + 1 + DIRPAD) & ~DIRPAD) - o_slen, UIO_READ, auio, code);
912 /* pad out the difference between rlen and slen... */
913 if (NDIRSIZ_LEN(o_slen) < rlen) {
914 while(NDIRSIZ_LEN(o_slen) < rlen) {
915 int minLen = rlen - NDIRSIZ_LEN(o_slen);
916 if (minLen > sizeof(bufofzeros))
917 minLen = sizeof(bufofzeros);
918 AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
923 code = afs_readdir_move(ode, avc, auio, o_slen,
924 auio->afsio_resid, origOffset);
925 #endif /* AFS_HPUX_ENV */
926 auio->afsio_resid = 0;
928 /* nothin to hand over */
930 #if defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV) || defined(AFS_OSF_ENV)
933 if (ode) DRelease(ode, 0);
936 /* by here nde is set */
938 /* Do we have enough user space to carry out our mission? */
939 #if defined(AFS_SGI_ENV)
940 n_slen = strlen(nde->name) + 1; /* NULL terminate */
942 n_slen = strlen(nde->name);
944 if (NDIRSIZ_LEN(n_slen) >= (auio->afsio_resid-len)) {
945 /* No can do no more now; ya know... at this time */
946 DRelease (nde, 0); /* can't use this one. */
948 #if defined(AFS_HPUX_ENV) || defined(AFS_OSF_ENV)
949 sdirEntry->d_fileno = (avc->fid.Fid.Volume << 16) + ntohl(ode->fid.vnode);
950 FIXUPSTUPIDINODE(sdirEntry->d_fileno);
951 sdirEntry->d_reclen = rlen = auio->afsio_resid;
952 sdirEntry->d_namlen = o_slen;
953 sdirEntry->d_off = origOffset;
954 AFS_UIOMOVE((char *)sdirEntry, sizeof(*sdirEntry), UIO_READ, auio, code);
956 AFS_UIOMOVE(ode->name, o_slen, UIO_READ, auio, code);
957 /* pad out the remaining characters with zeros */
959 AFS_UIOMOVE(bufofzeros, ((o_slen + 1 + DIRPAD) & ~DIRPAD) - o_slen, UIO_READ, auio, code);
961 /* pad out the difference between rlen and slen... */
962 if (NDIRSIZ_LEN(o_slen) < rlen) {
963 while(NDIRSIZ_LEN(o_slen) < rlen) {
964 int minLen = rlen - NDIRSIZ_LEN(o_slen);
965 if (minLen > sizeof(bufofzeros))
966 minLen = sizeof(bufofzeros);
967 AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
972 code = afs_readdir_move(ode, avc, auio, o_slen,
973 auio->afsio_resid, origOffset);
974 #endif /* AFS_HPUX_ENV */
975 /* this next line used to be AFSVFS40 or AIX 3.1, but is really generic */
976 auio->afsio_offset = origOffset;
977 auio->afsio_resid = 0;
978 } else { /* trouble, can't give anything to the user! */
979 /* even though he has given us a buffer,
980 * even though we have something to give us,
981 * Looks like we lost something somewhere.
985 if (ode) DRelease(ode, 0);
990 * In any event, we move out the LAST de entry, getting ready
991 * to set up for the next one.
994 #if defined(AFS_HPUX_ENV) || defined(AFS_OSF_ENV)
995 sdirEntry->d_fileno = (avc->fid.Fid.Volume << 16) + ntohl(ode->fid.vnode);
996 FIXUPSTUPIDINODE(sdirEntry->d_fileno);
997 sdirEntry->d_reclen = rlen = len;
998 sdirEntry->d_namlen = o_slen;
999 sdirEntry->d_off = origOffset;
1000 AFS_UIOMOVE((char *)sdirEntry, sizeof(*sdirEntry), UIO_READ, auio, code);
1002 AFS_UIOMOVE(ode->name, o_slen, UIO_READ, auio, code);
1003 /* pad out the remaining characters with zeros */
1005 AFS_UIOMOVE(bufofzeros, ((o_slen + 1 + DIRPAD) & ~DIRPAD) - o_slen, UIO_READ, auio, code);
1007 /* pad out the difference between rlen and slen... */
1008 if (NDIRSIZ_LEN(o_slen) < rlen) {
1009 while(NDIRSIZ_LEN(o_slen) < rlen) {
1010 int minLen = rlen - NDIRSIZ_LEN(o_slen);
1011 if (minLen > sizeof(bufofzeros))
1012 minLen = sizeof(bufofzeros);
1013 AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
1018 code = afs_readdir_move (ode, avc, auio, o_slen, len, origOffset);
1019 #endif /* AFS_HPUX_ENV */
1021 len = NDIRSIZ_LEN( o_slen = n_slen );
1022 if (ode) DRelease(ode, 0);
1024 auio->afsio_offset = ((us + afs_dir_NameBlobs(nde->name)) << 5);
1026 if (ode) DRelease(ode, 0);
1029 ReleaseReadLock(&tdc->lock);
1031 ReleaseReadLock(&avc->lock);
1034 #if defined(AFS_HPUX_ENV) || defined(AFS_OSF_ENV)
1035 osi_FreeSmallSpace((char *)sdirEntry);
1037 afs_PutFakeStat(&fakestate);
1038 code = afs_CheckCode(code, &treq, 29);
1043 #endif /* !AFS_LINUX20_ENV */