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)
43 * AFS readdir vnodeop and bulk stat support.
46 /* Saber C hates negative inode #s. We're not going to talk about software
47 * that could fail if it sees a negative inode #.
49 #define FIXUPSTUPIDINODE(a) ((a) &= 0x7fffffff)
51 /* BlobScan is supposed to ensure that the blob reference refers to a valid
52 directory entry. It consults the allocation map in the page header
53 to determine whether a blob is actually in use or not.
55 More formally, BlobScan is supposed to return a new blob number which is just like
56 the input parameter, only it is advanced over header or free blobs.
58 Note that BlobScan switches pages if necessary. BlobScan may return
59 either 0 or an out-of-range blob number for end of file.
61 BlobScan is used by the Linux port in a separate file, so it should not
65 BlobScan(struct dcache * afile, afs_int32 ablob)
67 register afs_int32 relativeBlob;
69 register struct PageHeader *tpe;
72 AFS_STATCNT(BlobScan);
73 /* advance ablob over free and header blobs */
75 pageBlob = ablob & ~(EPP - 1); /* base blob in same page */
76 tpe = (struct PageHeader *)afs_dir_GetBlob(afile, pageBlob);
78 return 0; /* we've past the end */
79 relativeBlob = ablob - pageBlob; /* relative to page's first blob */
80 /* first watch for headers */
81 if (pageBlob == 0) { /* first dir page has extra-big header */
83 if (relativeBlob < DHE + 1)
84 relativeBlob = DHE + 1;
85 } else { /* others have one header blob */
86 if (relativeBlob == 0)
89 /* make sure blob is allocated */
90 for (i = relativeBlob; i < EPP; i++) {
91 if (tpe->freebitmap[i >> 3] & (1 << (i & 7)))
94 /* now relativeBlob is the page-relative first allocated blob,
95 * or EPP (if there are none in this page). */
96 DRelease((struct buffer *)tpe, 0);
99 ablob = pageBlob + EPP; /* go around again */
104 #if !defined(AFS_LINUX20_ENV)
105 /* Changes to afs_readdir which affect dcache or vcache handling or use of
106 * bulk stat data should also be reflected in the Linux specific verison of
107 * the readdir routine.
111 * The kernel don't like it so much to have large stuff on the stack.
112 * Here we use a watered down version of the direct struct, since
113 * its not too bright to double copy the strings anyway.
115 #if !defined(UKERNEL)
116 #if defined(AFS_SGI_ENV)
117 /* Long form for 64 bit apps and kernel requests. */
118 struct min_dirent { /* miniature dirent structure */
119 /* If struct dirent changes, this must too */
120 ino_t d_fileno; /* This is 32 bits for 3.5, 64 for 6.2+ */
124 /* Short form for 32 bit apps. */
125 struct irix5_min_dirent { /* miniature dirent structure */
126 /* If struct dirent changes, this must too */
132 #define AFS_DIRENT32BASESIZE IRIX5_DIRENTBASESIZE
133 #define AFS_DIRENT64BASESIZE DIRENT64BASESIZE
135 #define AFS_DIRENT32BASESIZE IRIX5_DIRENTBASESIZE
136 #define AFS_DIRENT64BASESIZE DIRENTBASESIZE
137 #endif /* AFS_SGI62_ENV */
139 struct min_direct { /* miniature direct structure */
140 /* If struct direct changes, this must too */
141 #if defined(AFS_DARWIN80_ENV)
146 #elif defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
151 #elif defined(AFS_SUN5_ENV)
156 #if defined(AFS_AIX32_ENV)
158 #elif defined(AFS_HPUX100_ENV)
159 unsigned long long d_off;
166 #endif /* AFS_SGI_ENV */
168 #if defined(AFS_HPUX_ENV) || defined(AFS_OSF_ENV)
169 struct minnfs_direct {
170 afs_int32 d_off; /* XXX */
175 #define NDIRSIZ_LEN(len) ((sizeof (struct dirent)+4 - (MAXNAMLEN+1)) + (((len)+1 + DIRPAD) &~ DIRPAD))
177 #endif /* !defined(UKERNEL) */
181 *------------------------------------------------------------------------------
183 * Keep a stack of about 256 fids for the bulk stat call.
184 * Fill it during the readdir_move. Later empty it...
187 #define READDIR_STASH AFSCBMAX
188 struct AFSFid afs_readdir_stash[READDIR_STASH];
189 int afs_rd_stash_i = 0;
192 *------------------------------------------------------------------------------
195 * mainly a kind of macro... makes getting the struct direct
196 * out to the user space easy... could take more parameters,
197 * but now just takes what it needs.
202 #if defined(AFS_HPUX100_ENV)
203 #define DIRSIZ_LEN(len) \
204 ((sizeof (struct __dirent) - (_MAXNAMLEN+1)) + (((len)+1 + DIRPAD) &~ DIRPAD))
206 #if defined(AFS_SUN56_ENV)
207 #define DIRSIZ_LEN(len) ((18 + (len) + 1 + 7) & ~7 )
210 #define DIRSIZ_LEN(len) ((10 + (len) + 1 + (NBPW-1)) & ~(NBPW-1))
213 #define DIRSIZ_LEN(len) \
214 ((sizeof (struct dirent) - (MAXNAMLEN+1)) + (((len)+1 + 3) &~ 3))
216 #if defined(AFS_SGI_ENV)
217 #ifndef AFS_SGI53_ENV
218 /* SGI 5.3 and later use 32/64 bit versions of directory size. */
219 #define DIRSIZ_LEN(len) DIRENTSIZE(len)
221 #else /* AFS_SGI_ENV */
222 #define DIRSIZ_LEN(len) \
223 ((sizeof (struct direct) - (MAXNAMLEN+1)) + (((len)+1 + 3) &~ 3))
224 #endif /* AFS_SGI_ENV */
225 #endif /* AFS_DIRENT */
226 #endif /* AFS_SUN5_ENV */
227 #endif /* AFS_SUN56_ENV */
228 #endif /* AFS_HPUX100_ENV */
230 #if defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
232 afs_readdir_type(struct vcache *avc, struct DirEntry *ade)
234 struct VenusFid tfid;
237 tfid.Cell = avc->fid.Cell;
238 tfid.Fid.Volume = avc->fid.Fid.Volume;
239 tfid.Fid.Vnode = ntohl(ade->fid.vnode);
240 tfid.Fid.Unique = ntohl(ade->fid.vunique);
241 if ((avc->states & CForeign) == 0 && (ntohl(ade->fid.vnode) & 1)) {
244 ObtainReadLock(&afs_xvcache);
245 if ((tvc = afs_FindVCache(&tfid, 0, 0))) {
246 ReleaseReadLock(&afs_xvcache);
250 } else if (((tvc->states) & (CStatd | CTruth))) {
251 /* CTruth will be set if the object has
257 else if (vtype == VREG)
259 /* Don't do this until we're sure it can't be a mtpt */
260 /* else if (vtype == VLNK)
262 /* what other types does AFS support? */
266 ReleaseReadLock(&afs_xvcache);
272 #define AFS_MOVE_LOCK() AFS_GLOCK()
273 #define AFS_MOVE_UNLOCK() AFS_GUNLOCK()
275 #define AFS_MOVE_LOCK()
276 #define AFS_MOVE_UNLOCK()
278 char bufofzeros[64]; /* gotta fill with something */
282 afs_readdir_move(struct DirEntry *de, struct vcache *vc, struct uio *auio,
283 int slen, ssize_t rlen, afs_size_t off)
286 afs_readdir_move(struct DirEntry *de, struct vcache *vc, struct uio *auio,
287 int slen, int rlen, afs_size_t off)
292 afs_uint32 Volume = vc->fid.Fid.Volume;
293 afs_uint32 Vnode = de->fid.vnode;
294 #if defined(AFS_SUN56_ENV)
295 struct dirent64 *direntp;
297 #if defined(AFS_SUN5_ENV) || (defined(AFS_AIX51_ENV) && defined(AFS_64BIT_KERNEL))
298 struct dirent *direntp;
300 #endif /* AFS_SUN56_ENV */
301 #ifndef AFS_SGI53_ENV
302 struct min_direct sdirEntry;
303 #endif /* AFS_SGI53_ENV */
305 AFS_STATCNT(afs_readdir_move);
307 #define READDIR_CORRECT_INUMS
308 #ifdef READDIR_CORRECT_INUMS
309 if (de->name[0] == '.' && !de->name[1]) {
310 /* This is the '.' entry; if we are a volume root, we need to
311 * ignore the directory and use the inum for the mount point.
313 if (!FidCmp(&afs_rootFid, &vc->fid)) {
316 } else if (vc->mvstat == 2) {
317 tvp = afs_GetVolume(&vc->fid, 0, READ_LOCK);
319 Volume = tvp->mtpoint.Fid.Volume;
320 Vnode = tvp->mtpoint.Fid.Vnode;
321 afs_PutVolume(tvp, READ_LOCK);
325 else if (de->name[0] == '.' && de->name[1] == '.' && !de->name[2]) {
326 /* This is the '..' entry. Getting this right is very tricky,
327 * because we might be a volume root (so our parent is in a
328 * different volume), or our parent might be a volume root
329 * (so we actually want the mount point) or BOTH! */
330 if (!FidCmp(&afs_rootFid, &vc->fid)) {
331 /* We are the root of the AFS root, and thus our own parent */
334 } else if (vc->mvstat == 2) {
335 /* We are a volume root, which means our parent is in another
336 * volume. Luckily, we should have his fid cached... */
338 if (!FidCmp(&afs_rootFid, vc->mvid)) {
339 /* Parent directory is the root of the AFS root */
342 } else if (vc->mvid->Fid.Vnode == 1
343 && vc->mvid->Fid.Unique == 1) {
344 /* XXX The above test is evil and probably breaks DFS */
345 /* Parent directory is the target of a mount point */
346 tvp = afs_GetVolume(vc->mvid, 0, READ_LOCK);
348 Volume = tvp->mtpoint.Fid.Volume;
349 Vnode = tvp->mtpoint.Fid.Vnode;
350 afs_PutVolume(tvp, READ_LOCK);
353 /* Parent directory is not a volume root */
354 Volume = vc->mvid->Fid.Volume;
355 Vnode = vc->mvid->Fid.Vnode;
358 } else if (de->fid.vnode == 1 && de->fid.vunique == 1) {
359 /* XXX The above test is evil and probably breaks DFS */
360 /* Parent directory is a volume root; use the right inum */
361 tvp = afs_GetVolume(&vc->fid, 0, READ_LOCK);
363 if (tvp->cell == afs_rootFid.Cell
364 && tvp->volume == afs_rootFid.Fid.Volume) {
365 /* Parent directory is the root of the AFS root */
369 /* Parent directory is the target of a mount point */
370 Volume = tvp->mtpoint.Fid.Volume;
371 Vnode = tvp->mtpoint.Fid.Vnode;
373 afs_PutVolume(tvp, READ_LOCK);
381 afs_int32 use64BitDirent;
386 ABI_IS(ABI_IRIX5_64, GETDENTS_ABI(OSI_GET_CURRENT_ABI(), auio));
390 UIO_USERSPACE) ? ABI_IRIX5_64 : (ABI_IS(ABI_IRIX5_64 |
394 #else /* AFS_SGI61_ENV */
397 UIO_USERSPACE) ? ABI_IRIX5_64 : (ABI_IS(ABI_IRIX5_64,
399 #endif /* AFS_SGI61_ENV */
401 if (use64BitDirent) {
402 struct min_dirent sdirEntry;
403 sdirEntry.d_fileno = (Volume << 16) + ntohl(Vnode);
404 FIXUPSTUPIDINODE(sdirEntry.d_fileno);
405 sdirEntry.d_reclen = rlen;
406 sdirEntry.d_off = (off_t) off;
407 AFS_UIOMOVE(&sdirEntry, AFS_DIRENT64BASESIZE, UIO_READ, auio,
410 AFS_UIOMOVE(de->name, slen - 1, UIO_READ, auio, code);
412 AFS_UIOMOVE(bufofzeros,
413 DIRENTSIZE(slen) - (AFS_DIRENT64BASESIZE + slen -
414 1), UIO_READ, auio, code);
415 if (DIRENTSIZE(slen) < rlen) {
416 while (DIRENTSIZE(slen) < rlen) {
417 int minLen = rlen - DIRENTSIZE(slen);
418 if (minLen > sizeof(bufofzeros))
419 minLen = sizeof(bufofzeros);
420 AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
425 struct irix5_min_dirent sdirEntry;
426 sdirEntry.d_fileno = (Volume << 16) + ntohl(Vnode);
427 FIXUPSTUPIDINODE(sdirEntry.d_fileno);
428 sdirEntry.d_reclen = rlen;
429 sdirEntry.d_off = (afs_int32) off;
430 AFS_UIOMOVE(&sdirEntry, AFS_DIRENT32BASESIZE, UIO_READ, auio,
433 AFS_UIOMOVE(de->name, slen - 1, UIO_READ, auio, code);
435 AFS_UIOMOVE(bufofzeros,
436 IRIX5_DIRENTSIZE(slen) - (AFS_DIRENT32BASESIZE +
439 if (IRIX5_DIRENTSIZE(slen) < rlen) {
440 while (IRIX5_DIRENTSIZE(slen) < rlen) {
441 int minLen = rlen - IRIX5_DIRENTSIZE(slen);
442 if (minLen > sizeof(bufofzeros))
443 minLen = sizeof(bufofzeros);
444 AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
450 #else /* AFS_SGI53_ENV */
451 #if defined(AFS_SUN5_ENV) || (defined(AFS_AIX51_ENV) && defined(AFS_64BIT_KERNEL))
452 #if defined(AFS_SUN56_ENV)
453 direntp = (struct dirent64 *)osi_AllocLargeSpace(AFS_LRALLOCSIZ);
455 direntp = (struct dirent *)osi_AllocLargeSpace(AFS_LRALLOCSIZ);
457 direntp->d_ino = (Volume << 16) + ntohl(Vnode);
458 FIXUPSTUPIDINODE(direntp->d_ino);
459 #if defined(AFS_AIX51_ENV) && defined(AFS_64BIT_KERNEL)
460 direntp->d_offset = off;
461 direntp->d_namlen = slen;
463 direntp->d_off = off;
465 direntp->d_reclen = rlen;
466 strcpy(direntp->d_name, de->name);
467 AFS_UIOMOVE((caddr_t) direntp, rlen, UIO_READ, auio, code);
468 osi_FreeLargeSpace((char *)direntp);
469 #else /* AFS_SUN5_ENV */
470 /* Note the odd mechanism for building the inode number */
471 sdirEntry.d_fileno = (Volume << 16) + ntohl(Vnode);
472 FIXUPSTUPIDINODE(sdirEntry.d_fileno);
473 sdirEntry.d_reclen = rlen;
474 #if !defined(AFS_SGI_ENV)
475 sdirEntry.d_namlen = slen;
477 #if defined(AFS_AIX32_ENV) || defined(AFS_SGI_ENV)
478 sdirEntry.d_off = off;
480 #if defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
481 sdirEntry.d_type = afs_readdir_type(vc, de);
484 #if defined(AFS_SGI_ENV)
485 AFS_UIOMOVE(&sdirEntry, DIRENTBASESIZE, UIO_READ, auio, code);
487 AFS_UIOMOVE(de->name, slen - 1, UIO_READ, auio, code);
489 AFS_UIOMOVE(bufofzeros,
490 DIRSIZ_LEN(slen) - (DIRENTBASESIZE + slen - 1), UIO_READ,
492 #else /* AFS_SGI_ENV */
494 AFS_UIOMOVE((char *)&sdirEntry, sizeof(sdirEntry), UIO_READ, auio, code);
497 AFS_UIOMOVE(de->name, slen, UIO_READ, auio, code);
500 /* pad out the remaining characters with zeros */
502 AFS_UIOMOVE(bufofzeros, ((slen + 1 + DIRPAD) & ~DIRPAD) - slen,
503 UIO_READ, auio, code);
506 #endif /* AFS_SGI_ENV */
508 /* pad out the difference between rlen and slen... */
509 if (DIRSIZ_LEN(slen) < rlen) {
511 while (DIRSIZ_LEN(slen) < rlen) {
512 int minLen = rlen - DIRSIZ_LEN(slen);
513 if (minLen > sizeof(bufofzeros))
514 minLen = sizeof(bufofzeros);
515 AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
520 #endif /* AFS_SUN5_ENV */
521 #endif /* AFS_SGI53_ENV */
527 *------------------------------------------------------------------------------
529 * Read directory entries.
530 * There are some weird things to look out for here. The uio_offset
531 * field is either 0 or it is the offset returned from a previous
532 * readdir. It is an opaque value used by the server to find the
533 * correct directory block to read. The byte count must be at least
534 * vtoblksz(vp) bytes. The count field is the number of blocks to
535 * read on the server. This is advisory only, the server may return
536 * only one block's worth of entries. Entries may be compressed on
539 * This routine encodes knowledge of Vice dirs.
543 afs_bulkstat_send(struct vcache *avc, struct vrequest *req)
549 * Here is the bad, bad, really bad news.
550 * It has to do with 'offset' (seek locations).
554 #if defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV) || defined(AFS_OSF_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
555 afs_readdir(OSI_VC_DECL(avc), struct uio *auio, struct AFS_UCRED *acred,
558 #if defined(AFS_HPUX100_ENV)
559 afs_readdir2(OSI_VC_DECL(avc), struct uio *auio, struct AFS_UCRED *acred)
561 afs_readdir(OSI_VC_DECL(avc), struct uio *auio, struct AFS_UCRED *acred)
565 struct vrequest treq;
566 register struct dcache *tdc;
567 afs_size_t origOffset, tlen;
570 struct DirEntry *ode = 0, *nde = 0;
571 int o_slen = 0, n_slen = 0;
573 struct afs_fakestat_state fakestate;
574 #if defined(AFS_SGI53_ENV)
575 afs_int32 use64BitDirent, dirsiz;
576 #endif /* defined(AFS_SGI53_ENV) */
581 * XXX All the hacks for alloced sdirEntry and inlining of afs_readdir_move instead of calling
582 * it is necessary for hpux due to stack problems that seem to occur when coming thru the nfs
583 * translator side XXX
585 struct min_direct *sdirEntry =
586 (struct min_direct *)osi_AllocSmallSpace(sizeof(struct min_direct));
590 /* opaque value is pointer into a vice dir; use bit map to decide
591 * if the entries are in use. Always assumed to be valid. 0 is
592 * special, means start of a new dir. Int32 inode, followed by
593 * short reclen and short namelen. Namelen does not include
594 * the null byte. Followed by null-terminated string.
596 AFS_STATCNT(afs_readdir);
598 #if defined(AFS_SGI53_ENV)
602 ABI_IS(ABI_IRIX5_64, GETDENTS_ABI(OSI_GET_CURRENT_ABI(), auio));
606 UIO_USERSPACE) ? ABI_IRIX5_64 : (ABI_IS(ABI_IRIX5_64 | ABI_IRIX5_N32,
608 #endif /* AFS_SGI62_ENV */
609 #else /* AFS_SGI61_ENV */
612 UIO_USERSPACE) ? ABI_IRIX5_64 : (ABI_IS(ABI_IRIX5_64,
614 #endif /* AFS_SGI61_ENV */
615 #endif /* defined(AFS_SGI53_ENV) */
617 #if defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV) || defined(AFS_OSF_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
618 /* Not really used by the callee so we ignore it for now */
622 #ifndef AFS_64BIT_CLIENT
623 if (AfsLargeFileUio(auio) /* file is large than 2 GB */
624 ||AfsLargeFileSize(AFS_UIO_OFFSET(auio), AFS_UIO_RESID(auio)))
628 if ((code = afs_InitReq(&treq, acred))) {
630 osi_FreeSmallSpace((char *)sdirEntry);
634 /* update the cache entry */
635 afs_InitFakeStat(&fakestate);
639 code = afs_EvalFakeStat(&avc, &fakestate, &treq);
643 code = afs_VerifyVCache(avc, &treq);
646 /* get a reference to the entire directory */
647 tdc = afs_GetDCache(avc, (afs_size_t) 0, &treq, &origOffset, &tlen, 1);
653 ObtainReadLock(&avc->lock);
654 ObtainReadLock(&tdc->lock);
657 * Make sure that the data in the cache is current. There are two
658 * cases we need to worry about:
659 * 1. The cache data is being fetched by another process.
660 * 2. The cache data is no longer valid
662 while ((avc->states & CStatd)
663 && (tdc->dflags & DFFetching)
664 && hsame(avc->m.DataVersion, tdc->f.versionNo)) {
665 afs_Trace4(afs_iclSetp, CM_TRACE_DCACHEWAIT, ICL_TYPE_STRING,
666 __FILE__, ICL_TYPE_INT32, __LINE__, ICL_TYPE_POINTER, tdc,
667 ICL_TYPE_INT32, tdc->dflags);
668 ReleaseReadLock(&tdc->lock);
669 ReleaseReadLock(&avc->lock);
670 afs_osi_Sleep(&tdc->validPos);
671 ObtainReadLock(&avc->lock);
672 ObtainReadLock(&tdc->lock);
674 if (!(avc->states & CStatd)
675 || !hsame(avc->m.DataVersion, tdc->f.versionNo)) {
676 ReleaseReadLock(&tdc->lock);
677 ReleaseReadLock(&avc->lock);
683 * iterator for the directory reads. Takes the AFS DirEntry
684 * structure and slams them into UFS direct structures.
685 * uses afs_readdir_move to get the struct to the user space.
687 * The routine works by looking ahead one AFS directory entry.
688 * That's because the AFS entry we are currenly working with
689 * may not fit into the buffer the user has provided. If it
690 * doesn't we have to change the size of the LAST AFS directory
691 * entry, so that it will FIT perfectly into the block the
694 * The 'forward looking' of the code makes it a bit tough to read.
695 * Remember we need to get an entry, see if it it fits, then
696 * set it up as the LAST entry, and find the next one.
698 * Tough to take: We give out an EINVAL if we don't have enough
699 * space in the buffer, and at the same time, don't have an entry
700 * to put into the buffer. This CAN happen if the first AFS entry
701 * we get can't fit into the 512 character buffer provided. Seems
702 * it ought not happen...
704 * Assumption: don't need to use anything but one dc entry:
705 * this means the directory ought not be greater than 64k.
709 auio->uio_fpflags = 0;
712 origOffset = AFS_UIO_OFFSET(auio);
713 /* scan for the next interesting entry scan for in-use blob otherwise up point at
714 * this blob note that ode, if non-zero, also represents a held dir page */
715 if (!(us = BlobScan(tdc, (origOffset >> 5)))
716 || !(nde = (struct DirEntry *)afs_dir_GetBlob(tdc, us))) {
717 /* failed to setup nde, return what we've got, and release ode */
719 /* something to hand over. */
721 sdirEntry->d_fileno =
722 (avc->fid.Fid.Volume << 16) + ntohl(ode->fid.vnode);
723 FIXUPSTUPIDINODE(sdirEntry->d_fileno);
724 sdirEntry->d_reclen = rlen = AFS_UIO_RESID(auio);
725 sdirEntry->d_namlen = o_slen;
726 #if defined(AFS_SUN5_ENV) || defined(AFS_AIX32_ENV) || defined(AFS_HPUX100_ENV)
727 sdirEntry->d_off = origOffset;
729 AFS_UIOMOVE((char *)sdirEntry, sizeof(*sdirEntry), UIO_READ,
732 AFS_UIOMOVE(ode->name, o_slen, UIO_READ, auio, code);
733 /* pad out the remaining characters with zeros */
735 AFS_UIOMOVE(bufofzeros,
736 ((o_slen + 1 + DIRPAD) & ~DIRPAD) - o_slen,
737 UIO_READ, auio, code);
739 /* pad out the difference between rlen and slen... */
740 if (DIRSIZ_LEN(o_slen) < rlen) {
741 while (DIRSIZ_LEN(o_slen) < rlen) {
742 int minLen = rlen - DIRSIZ_LEN(o_slen);
743 if (minLen > sizeof(bufofzeros))
744 minLen = sizeof(bufofzeros);
745 AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
750 code = afs_readdir_move(ode, avc, auio, o_slen,
751 #if defined(AFS_SUN5_ENV)
754 AFS_UIO_RESID(auio), origOffset);
756 #endif /* AFS_HPUX_ENV */
757 #if !defined(AFS_SUN5_ENV)
758 AFS_UIO_SETRESID(auio, 0);
761 /* nothin to hand over */
763 #if defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV) || defined(AFS_OSF_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
765 *eofp = 1; /* Set it properly */
768 DRelease((struct buffer *)ode, 0);
771 /* by here nde is set */
773 /* Do we have enough user space to carry out our mission? */
774 #if defined(AFS_SGI_ENV)
775 n_slen = strlen(nde->name) + 1; /* NULL terminate */
777 n_slen = strlen(nde->name);
781 use64BitDirent ? DIRENTSIZE(n_slen) : IRIX5_DIRENTSIZE(n_slen);
782 if (dirsiz >= (AFS_UIO_RESID(auio) - len)) {
784 if (DIRSIZ_LEN(n_slen) >= (AFS_UIO_RESID(auio) - len)) {
785 #endif /* AFS_SGI53_ENV */
786 /* No can do no more now; ya know... at this time */
787 DRelease((struct buffer *)nde, 0); /* can't use this 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 = AFS_UIO_RESID(auio);
794 sdirEntry->d_namlen = o_slen;
795 #if defined(AFS_SUN5_ENV) || defined(AFS_AIX32_ENV) || defined(AFS_HPUX100_ENV)
796 sdirEntry->d_off = origOffset;
798 AFS_UIOMOVE((char *)sdirEntry, sizeof(*sdirEntry), UIO_READ,
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 */
820 afs_readdir_move(ode, avc, auio, o_slen,
821 AFS_UIO_RESID(auio), origOffset);
822 #endif /* AFS_HPUX_ENV */
823 /* this next line used to be AFSVFS40 or AIX 3.1, but is
825 AFS_UIO_SETOFFSET(auio, origOffset);
826 AFS_UIO_SETRESID(auio, 0);
827 } else { /* trouble, can't give anything to the user! */
828 /* even though he has given us a buffer,
829 * even though we have something to give us,
830 * Looks like we lost something somewhere.
835 DRelease((struct buffer *)ode, 0);
840 * In any event, we move out the LAST de entry, getting ready
841 * to set up for the next one.
845 sdirEntry->d_fileno =
846 (avc->fid.Fid.Volume << 16) + ntohl(ode->fid.vnode);
847 FIXUPSTUPIDINODE(sdirEntry->d_fileno);
848 sdirEntry->d_reclen = rlen = len;
849 sdirEntry->d_namlen = o_slen;
850 #if defined(AFS_SUN5_ENV) || defined(AFS_AIX32_ENV) || defined(AFS_HPUX100_ENV)
851 sdirEntry->d_off = origOffset;
853 AFS_UIOMOVE((char *)sdirEntry, sizeof(*sdirEntry), UIO_READ, auio,
856 AFS_UIOMOVE(ode->name, o_slen, UIO_READ, auio, code);
857 /* pad out the remaining characters with zeros */
859 AFS_UIOMOVE(bufofzeros,
860 ((o_slen + 1 + DIRPAD) & ~DIRPAD) - o_slen,
861 UIO_READ, auio, code);
863 /* pad out the difference between rlen and slen... */
864 if (DIRSIZ_LEN(o_slen) < rlen) {
865 while (DIRSIZ_LEN(o_slen) < rlen) {
866 int minLen = rlen - DIRSIZ_LEN(o_slen);
867 if (minLen > sizeof(bufofzeros))
868 minLen = sizeof(bufofzeros);
869 AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
873 #else /* AFS_HPUX_ENV */
874 code = afs_readdir_move(ode, avc, auio, o_slen, len, origOffset);
875 #endif /* AFS_HPUX_ENV */
878 len = use64BitDirent ? DIRENTSIZE(o_slen =
879 n_slen) : IRIX5_DIRENTSIZE(o_slen =
882 len = DIRSIZ_LEN(o_slen = n_slen);
883 #endif /* AFS_SGI53_ENV */
885 DRelease((struct buffer *)ode, 0);
887 AFS_UIO_SETOFFSET(auio, (afs_int32) ((us + afs_dir_NameBlobs(nde->name)) << 5));
890 DRelease((struct buffer *)ode, 0);
893 ReleaseReadLock(&tdc->lock);
895 ReleaseReadLock(&avc->lock);
899 osi_FreeSmallSpace((char *)sdirEntry);
902 afs_PutFakeStat(&fakestate);
903 code = afs_CheckCode(code, &treq, 28);
907 #if defined(AFS_HPUX_ENV) || defined(AFS_OSF_ENV)
910 afs1_readdir(struct vcache *avc, struct uio *auio, struct AFS_UCRED *acred,
914 afs1_readdir(struct vcache *avc, struct uio *auio, struct AFS_UCRED *acred)
917 struct vrequest treq;
918 register struct dcache *tdc;
919 afs_size_t origOffset, len;
921 struct DirEntry *ode = 0, *nde = 0;
922 int o_slen = 0, n_slen = 0;
924 #if defined(AFS_HPUX_ENV) || defined(AFS_OSF_ENV)
926 * XXX All the hacks for alloced sdirEntry and inlining of afs_readdir_move instead of calling
927 * it is necessary for hpux due to stack problems that seem to occur when coming thru the nfs
928 * translator side XXX
930 struct minnfs_direct *sdirEntry = (struct minnfs_direct *)
931 osi_AllocSmallSpace(sizeof(struct min_direct));
934 struct afs_fakestat_state fakestate;
936 AFS_STATCNT(afs_readdir);
937 #if defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV) || defined(AFS_OSF_ENV)
941 if (code = afs_InitReq(&treq, acred)) {
943 osi_FreeSmallSpace((char *)sdirEntry);
947 afs_InitFakeStat(&fakestate);
949 code = afs_EvalFakeStat(&avc, &fakestate, &treq);
952 osi_FreeSmallSpace((char *)sdirEntry);
955 afs_PutFakeStat(&fakestate);
958 /* update the cache entry */
960 code = afs_VerifyVCache(avc, &treq);
963 /* get a reference to the entire directory */
964 tdc = afs_GetDCache(avc, (afs_size_t) 0, &treq, &origOffset, &len, 1);
969 ObtainReadLock(&avc->lock);
970 ObtainReadLock(&tdc->lock);
973 * Make sure that the data in the cache is current. There are two
974 * cases we need to worry about:
975 * 1. The cache data is being fetched by another process.
976 * 2. The cache data is no longer valid
978 while ((avc->states & CStatd)
979 && (tdc->dflags & DFFetching)
980 && hsame(avc->m.DataVersion, tdc->f.versionNo)) {
981 afs_Trace4(afs_iclSetp, CM_TRACE_DCACHEWAIT, ICL_TYPE_STRING,
982 __FILE__, ICL_TYPE_INT32, __LINE__, ICL_TYPE_POINTER, tdc,
983 ICL_TYPE_INT32, tdc->dflags);
984 ReleaseReadLock(&tdc->lock);
985 ReleaseReadLock(&avc->lock);
986 afs_osi_Sleep(&tdc->validPos);
987 ObtainReadLock(&avc->lock);
988 ObtainReadLock(&tdc->lock);
990 if (!(avc->states & CStatd)
991 || !hsame(avc->m.DataVersion, tdc->f.versionNo)) {
992 ReleaseReadLock(&tdc->lock);
993 ReleaseReadLock(&avc->lock);
1000 auio->uio_fpflags = 0;
1003 origOffset = AFS_UIO_OFFSET(auio);
1005 /* scan for the next interesting entry scan for in-use blob otherwise up point at
1006 * this blob note that ode, if non-zero, also represents a held dir page */
1007 if (!(us = BlobScan(tdc, (origOffset >> 5)))
1008 || !(nde = (struct DirEntry *)afs_dir_GetBlob(tdc, us))) {
1009 /* failed to setup nde, return what we've got, and release ode */
1011 /* something to hand over. */
1012 #if defined(AFS_HPUX_ENV) || defined(AFS_OSF_ENV)
1013 sdirEntry->d_fileno =
1014 (avc->fid.Fid.Volume << 16) + ntohl(ode->fid.vnode);
1015 FIXUPSTUPIDINODE(sdirEntry->d_fileno);
1016 sdirEntry->d_reclen = rlen = AFS_UIO_RESID(auio);
1017 sdirEntry->d_namlen = o_slen;
1018 sdirEntry->d_off = origOffset;
1019 AFS_UIOMOVE((char *)sdirEntry, sizeof(*sdirEntry), UIO_READ,
1022 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 AFS_UIO_RESID(auio), origOffset);
1044 #endif /* AFS_HPUX_ENV */
1045 AFS_UIO_SETRESID(auio, 0);
1047 /* nothin to hand over */
1049 #if defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV) || defined(AFS_OSF_ENV)
1057 /* by here nde is set */
1059 /* Do we have enough user space to carry out our mission? */
1060 #if defined(AFS_SGI_ENV)
1061 n_slen = strlen(nde->name) + 1; /* NULL terminate */
1063 n_slen = strlen(nde->name);
1065 if (NDIRSIZ_LEN(n_slen) >= (AFS_UIO_RESID(auio) - len)) {
1066 /* No can do no more now; ya know... at this time */
1067 DRelease(nde, 0); /* can't use this one. */
1069 #if defined(AFS_HPUX_ENV) || defined(AFS_OSF_ENV)
1070 sdirEntry->d_fileno =
1071 (avc->fid.Fid.Volume << 16) + ntohl(ode->fid.vnode);
1072 FIXUPSTUPIDINODE(sdirEntry->d_fileno);
1073 sdirEntry->d_reclen = rlen = AFS_UIO_RESID(auio);
1074 sdirEntry->d_namlen = o_slen;
1075 sdirEntry->d_off = origOffset;
1076 AFS_UIOMOVE((char *)sdirEntry, sizeof(*sdirEntry), UIO_READ,
1079 AFS_UIOMOVE(ode->name, o_slen, UIO_READ, auio, code);
1080 /* pad out the remaining characters with zeros */
1082 AFS_UIOMOVE(bufofzeros,
1083 ((o_slen + 1 + DIRPAD) & ~DIRPAD) - o_slen,
1084 UIO_READ, auio, code);
1086 /* pad out the difference between rlen and slen... */
1087 if (NDIRSIZ_LEN(o_slen) < rlen) {
1088 while (NDIRSIZ_LEN(o_slen) < rlen) {
1089 int minLen = rlen - NDIRSIZ_LEN(o_slen);
1090 if (minLen > sizeof(bufofzeros))
1091 minLen = sizeof(bufofzeros);
1092 AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
1098 afs_readdir_move(ode, avc, auio, o_slen,
1099 AFS_UIO_RESID(auio), origOffset);
1100 #endif /* AFS_HPUX_ENV */
1101 /* this next line used to be AFSVFS40 or AIX 3.1, but is really generic */
1102 AFS_UIO_SETOFFSET(auio, origOffset);
1103 AFS_UIO_SETRESID(auio, 0);
1104 } else { /* trouble, can't give anything to the user! */
1105 /* even though he has given us a buffer,
1106 * even though we have something to give us,
1107 * Looks like we lost something somewhere.
1117 * In any event, we move out the LAST de entry, getting ready
1118 * to set up for the next one.
1121 #if defined(AFS_HPUX_ENV) || defined(AFS_OSF_ENV)
1122 sdirEntry->d_fileno =
1123 (avc->fid.Fid.Volume << 16) + ntohl(ode->fid.vnode);
1124 FIXUPSTUPIDINODE(sdirEntry->d_fileno);
1125 sdirEntry->d_reclen = rlen = len;
1126 sdirEntry->d_namlen = o_slen;
1127 sdirEntry->d_off = origOffset;
1128 AFS_UIOMOVE((char *)sdirEntry, sizeof(*sdirEntry), UIO_READ, auio,
1131 AFS_UIOMOVE(ode->name, o_slen, UIO_READ, auio, code);
1132 /* pad out the remaining characters with zeros */
1134 AFS_UIOMOVE(bufofzeros,
1135 ((o_slen + 1 + DIRPAD) & ~DIRPAD) - o_slen,
1136 UIO_READ, auio, code);
1138 /* pad out the difference between rlen and slen... */
1139 if (NDIRSIZ_LEN(o_slen) < rlen) {
1140 while (NDIRSIZ_LEN(o_slen) < rlen) {
1141 int minLen = rlen - NDIRSIZ_LEN(o_slen);
1142 if (minLen > sizeof(bufofzeros))
1143 minLen = sizeof(bufofzeros);
1144 AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
1149 code = afs_readdir_move(ode, avc, auio, o_slen, len, origOffset);
1150 #endif /* AFS_HPUX_ENV */
1152 len = NDIRSIZ_LEN(o_slen = n_slen);
1156 AFS_UIO_OFFSET(auio) = ((us + afs_dir_NameBlobs(nde->name)) << 5);
1162 ReleaseReadLock(&tdc->lock);
1164 ReleaseReadLock(&avc->lock);
1167 #if defined(AFS_HPUX_ENV) || defined(AFS_OSF_ENV)
1168 osi_FreeSmallSpace((char *)sdirEntry);
1170 AFS_DISCON_UNLOCK();
1171 afs_PutFakeStat(&fakestate);
1172 code = afs_CheckCode(code, &treq, 29);
1177 #endif /* !AFS_LINUX20_ENV */