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 NFS version
22 #include <afsconfig.h>
23 #include "afs/param.h"
26 #include "afs/sysincludes.h" /* Standard vendor system headers */
27 #include "afsincludes.h" /* Afs-based standard headers */
28 #include "afs/afs_stats.h" /* statistics */
29 #include "afs/afs_cbqueue.h"
30 #include "afs/nfsclient.h"
31 #include "afs/afs_osidnlc.h"
33 #if defined(AFS_HPUX1122_ENV)
35 #elif defined(AFS_NBSD40_ENV)
42 * AFS readdir vnodeop and bulk stat support.
45 /* Saber C hates negative inode #s. We're not going to talk about software
46 * that could fail if it sees a negative inode #.
48 #define FIXUPSTUPIDINODE(a) ((a) &= 0x7fffffff)
50 /* BlobScan is supposed to ensure that the blob reference refers to a valid
51 directory entry. It consults the allocation map in the page header
52 to determine whether a blob is actually in use or not.
54 More formally, BlobScan is supposed to return a new blob number which is just like
55 the input parameter, only it is advanced over header or free blobs.
57 Note that BlobScan switches pages if necessary. BlobScan may return
58 either 0 or an out-of-range blob number for end of file.
60 BlobScan is used by the Linux port in a separate file, so it should not
64 BlobScan(struct dcache * afile, afs_int32 ablob)
66 afs_int32 relativeBlob;
68 struct PageHeader *tpe;
71 AFS_STATCNT(BlobScan);
72 /* advance ablob over free and header blobs */
74 pageBlob = ablob & ~(EPP - 1); /* base blob in same page */
75 tpe = (struct PageHeader *)afs_dir_GetBlob(afile, pageBlob);
77 return 0; /* we've past the end */
78 relativeBlob = ablob - pageBlob; /* relative to page's first blob */
79 /* first watch for headers */
80 if (pageBlob == 0) { /* first dir page has extra-big header */
82 if (relativeBlob < DHE + 1)
83 relativeBlob = DHE + 1;
84 } else { /* others have one header blob */
85 if (relativeBlob == 0)
88 /* make sure blob is allocated */
89 for (i = relativeBlob; i < EPP; i++) {
90 if (tpe->freebitmap[i >> 3] & (1 << (i & 7)))
93 /* now relativeBlob is the page-relative first allocated blob,
94 * or EPP (if there are none in this page). */
98 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_NBSD40_ENV)
147 ino_t d_fileno; /* file number of entry */
148 uint16_t d_reclen; /* length of this record */
149 uint16_t d_namlen; /* length of string in d_name */
150 uint8_t d_type; /* file type, see below */
151 #elif defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
156 #elif defined(AFS_SUN5_ENV)
161 #if defined(AFS_AIX32_ENV)
163 #elif defined(AFS_HPUX100_ENV)
164 unsigned long long d_off;
171 #endif /* AFS_SGI_ENV */
173 #if defined(AFS_HPUX_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))
217 #ifdef AFS_NBSD40_ENV
218 #define DIRSIZ_LEN(len) \
219 ((sizeof (struct dirent) - (MAXNAMLEN+1)) + (((len)+1 + 7) & ~7))
222 #define DIRSIZ_LEN(len) \
223 ((sizeof (struct dirent) - (MAXNAMLEN+1)) + (((len)+1 + 3) &~ 3))
225 #if defined(AFS_SGI_ENV)
226 #ifndef AFS_SGI53_ENV
227 /* SGI 5.3 and later use 32/64 bit versions of directory size. */
228 #define DIRSIZ_LEN(len) DIRENTSIZE(len)
230 #else /* AFS_SGI_ENV */
231 #define DIRSIZ_LEN(len) \
232 ((sizeof (struct direct) - (MAXNAMLEN+1)) + (((len)+1 + 3) &~ 3))
233 #endif /* AFS_SGI_ENV */
234 #endif /* AFS_DIRENT */
235 #endif /* AFS_NBSD40_ENV */
236 #endif /* AFS_SUN5_ENV */
237 #endif /* AFS_SUN56_ENV */
238 #endif /* AFS_HPUX100_ENV */
240 #if defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
242 afs_readdir_type(struct vcache *avc, struct DirEntry *ade)
244 struct VenusFid tfid;
247 tfid.Cell = avc->f.fid.Cell;
248 tfid.Fid.Volume = avc->f.fid.Fid.Volume;
249 tfid.Fid.Vnode = ntohl(ade->fid.vnode);
250 tfid.Fid.Unique = ntohl(ade->fid.vunique);
251 if ((avc->f.states & CForeign) == 0 && (ntohl(ade->fid.vnode) & 1)) {
254 ObtainReadLock(&afs_xvcache);
255 if ((tvc = afs_FindVCache(&tfid, 0, 0))) {
256 ReleaseReadLock(&afs_xvcache);
260 } else if (((tvc->f.states) & (CStatd | CTruth))) {
261 /* CTruth will be set if the object has
267 else if (vtype == VREG)
269 /* Don't do this until we're sure it can't be a mtpt */
270 /* if we're CStatd and CTruth and mvstat==0, it's a link */
271 else if (vtype == VLNK)
273 /* what other types does AFS support? */
277 ReleaseReadLock(&afs_xvcache);
283 #define AFS_MOVE_LOCK() AFS_GLOCK()
284 #define AFS_MOVE_UNLOCK() AFS_GUNLOCK()
286 #define AFS_MOVE_LOCK()
287 #define AFS_MOVE_UNLOCK()
289 char bufofzeros[64]; /* gotta fill with something */
293 afs_readdir_move(struct DirEntry *de, struct vcache *vc, struct uio *auio,
294 int slen, ssize_t rlen, afs_size_t off)
297 afs_readdir_move(struct DirEntry *de, struct vcache *vc, struct uio *auio,
298 int slen, int rlen, afs_size_t off)
303 afs_uint32 Volume = vc->f.fid.Fid.Volume;
304 afs_uint32 Vnode = de->fid.vnode;
305 #if defined(AFS_SUN56_ENV)
306 struct dirent64 *direntp;
308 #if defined(AFS_SUN5_ENV) || (defined(AFS_AIX51_ENV) && defined(AFS_64BIT_KERNEL))
309 struct dirent *direntp;
311 #endif /* AFS_SUN56_ENV */
312 #ifndef AFS_SGI53_ENV
313 struct min_direct sdirEntry;
314 #endif /* AFS_SGI53_ENV */
316 AFS_STATCNT(afs_readdir_move);
318 #define READDIR_CORRECT_INUMS
319 #ifdef READDIR_CORRECT_INUMS
320 if (de->name[0] == '.' && !de->name[1]) {
321 /* This is the '.' entry; if we are a volume root, we need to
322 * ignore the directory and use the inum for the mount point.
324 if (!FidCmp(&afs_rootFid, &vc->f.fid)) {
327 } else if (vc->mvstat == 2) {
328 tvp = afs_GetVolume(&vc->f.fid, 0, READ_LOCK);
330 Volume = tvp->mtpoint.Fid.Volume;
331 Vnode = tvp->mtpoint.Fid.Vnode;
332 afs_PutVolume(tvp, READ_LOCK);
336 else if (de->name[0] == '.' && de->name[1] == '.' && !de->name[2]) {
337 /* This is the '..' entry. Getting this right is very tricky,
338 * because we might be a volume root (so our parent is in a
339 * different volume), or our parent might be a volume root
340 * (so we actually want the mount point) or BOTH! */
341 if (!FidCmp(&afs_rootFid, &vc->f.fid)) {
342 /* We are the root of the AFS root, and thus our own parent */
345 } else if (vc->mvstat == 2) {
346 /* We are a volume root, which means our parent is in another
347 * volume. Luckily, we should have his fid cached... */
349 if (!FidCmp(&afs_rootFid, vc->mvid)) {
350 /* Parent directory is the root of the AFS root */
353 } else if (vc->mvid->Fid.Vnode == 1
354 && vc->mvid->Fid.Unique == 1) {
355 /* XXX The above test is evil and probably breaks DFS */
356 /* Parent directory is the target of a mount point */
357 tvp = afs_GetVolume(vc->mvid, 0, READ_LOCK);
359 Volume = tvp->mtpoint.Fid.Volume;
360 Vnode = tvp->mtpoint.Fid.Vnode;
361 afs_PutVolume(tvp, READ_LOCK);
364 /* Parent directory is not a volume root */
365 Volume = vc->mvid->Fid.Volume;
366 Vnode = vc->mvid->Fid.Vnode;
369 } else if (de->fid.vnode == 1 && de->fid.vunique == 1) {
370 /* XXX The above test is evil and probably breaks DFS */
371 /* Parent directory is a volume root; use the right inum */
372 tvp = afs_GetVolume(&vc->f.fid, 0, READ_LOCK);
374 if (tvp->cell == afs_rootFid.Cell
375 && tvp->volume == afs_rootFid.Fid.Volume) {
376 /* Parent directory is the root of the AFS root */
380 /* Parent directory is the target of a mount point */
381 Volume = tvp->mtpoint.Fid.Volume;
382 Vnode = tvp->mtpoint.Fid.Vnode;
384 afs_PutVolume(tvp, READ_LOCK);
392 afs_int32 use64BitDirent;
397 ABI_IS(ABI_IRIX5_64, GETDENTS_ABI(OSI_GET_CURRENT_ABI(), auio));
401 UIO_USERSPACE) ? ABI_IRIX5_64 : (ABI_IS(ABI_IRIX5_64 |
405 #else /* AFS_SGI61_ENV */
408 UIO_USERSPACE) ? ABI_IRIX5_64 : (ABI_IS(ABI_IRIX5_64,
410 #endif /* AFS_SGI61_ENV */
412 if (use64BitDirent) {
413 struct min_dirent sdirEntry;
414 sdirEntry.d_fileno = (Volume << 16) + ntohl(Vnode);
415 FIXUPSTUPIDINODE(sdirEntry.d_fileno);
416 sdirEntry.d_reclen = rlen;
417 sdirEntry.d_off = (off_t) off;
418 AFS_UIOMOVE(&sdirEntry, AFS_DIRENT64BASESIZE, UIO_READ, auio,
421 AFS_UIOMOVE(de->name, slen - 1, UIO_READ, auio, code);
423 AFS_UIOMOVE(bufofzeros,
424 DIRENTSIZE(slen) - (AFS_DIRENT64BASESIZE + slen -
425 1), UIO_READ, auio, code);
426 if (DIRENTSIZE(slen) < rlen) {
427 while (DIRENTSIZE(slen) < rlen) {
428 int minLen = rlen - DIRENTSIZE(slen);
429 if (minLen > sizeof(bufofzeros))
430 minLen = sizeof(bufofzeros);
431 AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
436 struct irix5_min_dirent sdirEntry;
437 sdirEntry.d_fileno = (Volume << 16) + ntohl(Vnode);
438 FIXUPSTUPIDINODE(sdirEntry.d_fileno);
439 sdirEntry.d_reclen = rlen;
440 sdirEntry.d_off = (afs_int32) off;
441 AFS_UIOMOVE(&sdirEntry, AFS_DIRENT32BASESIZE, UIO_READ, auio,
444 AFS_UIOMOVE(de->name, slen - 1, UIO_READ, auio, code);
446 AFS_UIOMOVE(bufofzeros,
447 IRIX5_DIRENTSIZE(slen) - (AFS_DIRENT32BASESIZE +
450 if (IRIX5_DIRENTSIZE(slen) < rlen) {
451 while (IRIX5_DIRENTSIZE(slen) < rlen) {
452 int minLen = rlen - IRIX5_DIRENTSIZE(slen);
453 if (minLen > sizeof(bufofzeros))
454 minLen = sizeof(bufofzeros);
455 AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
461 #else /* AFS_SGI53_ENV */
462 #if defined(AFS_SUN5_ENV) || (defined(AFS_AIX51_ENV) && defined(AFS_64BIT_KERNEL))
463 #if defined(AFS_SUN56_ENV)
464 direntp = (struct dirent64 *)osi_AllocLargeSpace(AFS_LRALLOCSIZ);
466 direntp = (struct dirent *)osi_AllocLargeSpace(AFS_LRALLOCSIZ);
468 direntp->d_ino = (Volume << 16) + ntohl(Vnode);
469 FIXUPSTUPIDINODE(direntp->d_ino);
470 #if defined(AFS_AIX51_ENV) && defined(AFS_64BIT_KERNEL)
471 direntp->d_offset = off;
472 direntp->d_namlen = slen;
474 direntp->d_off = off;
476 direntp->d_reclen = rlen;
477 strcpy(direntp->d_name, de->name);
478 AFS_UIOMOVE((caddr_t) direntp, rlen, UIO_READ, auio, code);
479 osi_FreeLargeSpace((char *)direntp);
480 #else /* AFS_SUN5_ENV */
481 /* Note the odd mechanism for building the inode number */
482 sdirEntry.d_fileno = (Volume << 16) + ntohl(Vnode);
483 FIXUPSTUPIDINODE(sdirEntry.d_fileno);
484 sdirEntry.d_reclen = rlen;
485 #if !defined(AFS_SGI_ENV)
486 sdirEntry.d_namlen = slen;
488 #if defined(AFS_AIX32_ENV) || defined(AFS_SGI_ENV)
489 sdirEntry.d_off = off;
491 #if defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
492 sdirEntry.d_type = afs_readdir_type(vc, de);
495 #if defined(AFS_SGI_ENV)
496 AFS_UIOMOVE(&sdirEntry, DIRENTBASESIZE, UIO_READ, auio, code);
498 AFS_UIOMOVE(de->name, slen - 1, UIO_READ, auio, code);
500 AFS_UIOMOVE(bufofzeros,
501 DIRSIZ_LEN(slen) - (DIRENTBASESIZE + slen - 1), UIO_READ,
503 #else /* AFS_SGI_ENV */
505 #if defined(AFS_NBSD40_ENV)
508 dp = osi_AllocLargeSpace(sizeof(struct dirent));
509 memset(dp, 0, sizeof(struct dirent));
510 dp->d_ino = (Volume << 16) + ntohl(Vnode);
511 FIXUPSTUPIDINODE(dp->d_ino);
513 dp->d_type = afs_readdir_type(vc, de);
514 strcpy(dp->d_name, de->name);
515 dp->d_reclen = _DIRENT_SIZE(dp) /* rlen */;
516 if ((afs_debug & AFSDEB_VNLAYER) != 0) {
517 afs_warn("%s: %s type %d slen %d rlen %d act. rlen %zu\n", __func__,
518 dp->d_name, dp->d_type, slen, rlen, _DIRENT_SIZE(dp));
520 AFS_UIOMOVE(dp, dp->d_reclen, UIO_READ, auio, code);
521 osi_FreeLargeSpace((char *)dp);
524 AFS_UIOMOVE((char *) &sdirEntry, sizeof(sdirEntry), UIO_READ, auio, code);
526 AFS_UIOMOVE(de->name, slen, UIO_READ, auio, code);
528 /* pad out the remaining characters with zeros */
530 AFS_UIOMOVE(bufofzeros, ((slen + 1 + DIRPAD) & ~DIRPAD) - slen,
531 UIO_READ, auio, code);
535 #endif /* AFS_SGI_ENV */
536 #if !defined(AFS_NBSD_ENV)
537 /* pad out the difference between rlen and slen... */
538 if (DIRSIZ_LEN(slen) < rlen) {
540 while (DIRSIZ_LEN(slen) < rlen) {
541 int minLen = rlen - DIRSIZ_LEN(slen);
542 if (minLen > sizeof(bufofzeros))
543 minLen = sizeof(bufofzeros);
544 AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
550 #endif /* AFS_SUN5_ENV */
551 #endif /* AFS_SGI53_ENV */
557 *------------------------------------------------------------------------------
559 * Read directory entries.
560 * There are some weird things to look out for here. The uio_offset
561 * field is either 0 or it is the offset returned from a previous
562 * readdir. It is an opaque value used by the server to find the
563 * correct directory block to read. The byte count must be at least
564 * vtoblksz(vp) bytes. The count field is the number of blocks to
565 * read on the server. This is advisory only, the server may return
566 * only one block's worth of entries. Entries may be compressed on
569 * This routine encodes knowledge of Vice dirs.
573 afs_bulkstat_send(struct vcache *avc, struct vrequest *req)
579 * Here is the bad, bad, really bad news.
580 * It has to do with 'offset' (seek locations).
584 #if defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
585 afs_readdir(OSI_VC_DECL(avc), struct uio *auio, afs_ucred_t *acred,
588 #if defined(AFS_HPUX100_ENV)
589 afs_readdir2(OSI_VC_DECL(avc), struct uio *auio, afs_ucred_t *acred)
591 afs_readdir(OSI_VC_DECL(avc), struct uio *auio, afs_ucred_t *acred)
595 struct vrequest treq;
597 afs_size_t origOffset, tlen;
600 struct DirEntry *ode = 0, *nde = 0;
601 int o_slen = 0, n_slen = 0;
603 struct afs_fakestat_state fakestate;
604 #if defined(AFS_SGI53_ENV)
605 afs_int32 use64BitDirent, dirsiz;
606 #endif /* defined(AFS_SGI53_ENV) */
611 * XXX All the hacks for alloced sdirEntry and inlining of afs_readdir_move instead of calling
612 * it is necessary for hpux due to stack problems that seem to occur when coming thru the nfs
613 * translator side XXX
615 struct min_direct *sdirEntry =
616 (struct min_direct *)osi_AllocSmallSpace(sizeof(struct min_direct));
620 /* opaque value is pointer into a vice dir; use bit map to decide
621 * if the entries are in use. Always assumed to be valid. 0 is
622 * special, means start of a new dir. Int32 inode, followed by
623 * short reclen and short namelen. Namelen does not include
624 * the null byte. Followed by null-terminated string.
626 AFS_STATCNT(afs_readdir);
628 #if defined(AFS_SGI53_ENV)
632 ABI_IS(ABI_IRIX5_64, GETDENTS_ABI(OSI_GET_CURRENT_ABI(), auio));
636 UIO_USERSPACE) ? ABI_IRIX5_64 : (ABI_IS(ABI_IRIX5_64 | ABI_IRIX5_N32,
638 #endif /* AFS_SGI62_ENV */
639 #else /* AFS_SGI61_ENV */
642 UIO_USERSPACE) ? ABI_IRIX5_64 : (ABI_IS(ABI_IRIX5_64,
644 #endif /* AFS_SGI61_ENV */
645 #endif /* defined(AFS_SGI53_ENV) */
647 #if defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
648 /* Not really used by the callee so we ignore it for now */
652 #ifndef AFS_64BIT_CLIENT
653 if (AfsLargeFileUio(auio) /* file is large than 2 GB */
654 ||AfsLargeFileSize(AFS_UIO_OFFSET(auio), AFS_UIO_RESID(auio)))
658 if ((code = afs_InitReq(&treq, acred))) {
660 osi_FreeSmallSpace((char *)sdirEntry);
664 /* update the cache entry */
665 afs_InitFakeStat(&fakestate);
669 code = afs_EvalFakeStat(&avc, &fakestate, &treq);
673 code = afs_VerifyVCache(avc, &treq);
676 /* get a reference to the entire directory */
677 tdc = afs_GetDCache(avc, (afs_size_t) 0, &treq, &origOffset, &tlen, 1);
683 ObtainReadLock(&avc->lock);
684 ObtainReadLock(&tdc->lock);
687 * Make sure that the data in the cache is current. There are two
688 * cases we need to worry about:
689 * 1. The cache data is being fetched by another process.
690 * 2. The cache data is no longer valid
692 while ((avc->f.states & CStatd)
693 && (tdc->dflags & DFFetching)
694 && hsame(avc->f.m.DataVersion, tdc->f.versionNo)) {
695 afs_Trace4(afs_iclSetp, CM_TRACE_DCACHEWAIT, ICL_TYPE_STRING,
696 __FILE__, ICL_TYPE_INT32, __LINE__, ICL_TYPE_POINTER, tdc,
697 ICL_TYPE_INT32, tdc->dflags);
698 ReleaseReadLock(&tdc->lock);
699 ReleaseReadLock(&avc->lock);
700 afs_osi_Sleep(&tdc->validPos);
701 ObtainReadLock(&avc->lock);
702 ObtainReadLock(&tdc->lock);
704 if (!(avc->f.states & CStatd)
705 || !hsame(avc->f.m.DataVersion, tdc->f.versionNo)) {
706 ReleaseReadLock(&tdc->lock);
707 ReleaseReadLock(&avc->lock);
713 * iterator for the directory reads. Takes the AFS DirEntry
714 * structure and slams them into UFS direct structures.
715 * uses afs_readdir_move to get the struct to the user space.
717 * The routine works by looking ahead one AFS directory entry.
718 * That's because the AFS entry we are currenly working with
719 * may not fit into the buffer the user has provided. If it
720 * doesn't we have to change the size of the LAST AFS directory
721 * entry, so that it will FIT perfectly into the block the
724 * The 'forward looking' of the code makes it a bit tough to read.
725 * Remember we need to get an entry, see if it it fits, then
726 * set it up as the LAST entry, and find the next one.
728 * Tough to take: We give out an EINVAL if we don't have enough
729 * space in the buffer, and at the same time, don't have an entry
730 * to put into the buffer. This CAN happen if the first AFS entry
731 * we get can't fit into the 512 character buffer provided. Seems
732 * it ought not happen...
734 * Assumption: don't need to use anything but one dc entry:
735 * this means the directory ought not be greater than 64k.
739 auio->uio_fpflags = 0;
742 origOffset = AFS_UIO_OFFSET(auio);
743 /* scan for the next interesting entry scan for in-use blob otherwise up point at
744 * this blob note that ode, if non-zero, also represents a held dir page */
745 if (!(us = BlobScan(tdc, (origOffset >> 5)))
746 || !(nde = (struct DirEntry *)afs_dir_GetBlob(tdc, us))) {
747 /* failed to setup nde, return what we've got, and release ode */
749 /* something to hand over. */
751 sdirEntry->d_fileno =
752 (avc->f.fid.Fid.Volume << 16) + ntohl(ode->fid.vnode);
753 FIXUPSTUPIDINODE(sdirEntry->d_fileno);
754 sdirEntry->d_reclen = rlen = AFS_UIO_RESID(auio);
755 sdirEntry->d_namlen = o_slen;
756 #if defined(AFS_SUN5_ENV) || defined(AFS_AIX32_ENV) || defined(AFS_HPUX100_ENV)
757 sdirEntry->d_off = origOffset;
759 AFS_UIOMOVE((char *)sdirEntry, sizeof(*sdirEntry), UIO_READ,
762 AFS_UIOMOVE(ode->name, o_slen, UIO_READ, auio, code);
763 /* pad out the remaining characters with zeros */
765 AFS_UIOMOVE(bufofzeros,
766 ((o_slen + 1 + DIRPAD) & ~DIRPAD) - o_slen,
767 UIO_READ, auio, code);
769 /* pad out the difference between rlen and slen... */
770 if (DIRSIZ_LEN(o_slen) < rlen) {
771 while (DIRSIZ_LEN(o_slen) < rlen) {
772 int minLen = rlen - DIRSIZ_LEN(o_slen);
773 if (minLen > sizeof(bufofzeros))
774 minLen = sizeof(bufofzeros);
775 AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
780 code = afs_readdir_move(ode, avc, auio, o_slen,
781 #if defined(AFS_SUN5_ENV) || defined(AFS_NBSD_ENV)
784 AFS_UIO_RESID(auio), origOffset);
786 #endif /* AFS_HPUX_ENV */
787 #if !defined(AFS_SUN5_ENV) && !defined(AFS_NBSD_ENV)
788 AFS_UIO_SETRESID(auio, 0);
791 /* nothin to hand over */
793 #if defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
795 *eofp = 1; /* Set it properly */
801 /* by here nde is set */
802 /* Do we have enough user space to carry out our mission? */
803 #if defined(AFS_SGI_ENV)
804 n_slen = strlen(nde->name) + 1; /* NULL terminate */
806 n_slen = strlen(nde->name);
810 use64BitDirent ? DIRENTSIZE(n_slen) : IRIX5_DIRENTSIZE(n_slen);
811 if (dirsiz >= (AFS_UIO_RESID(auio) - len)) {
813 if (DIRSIZ_LEN(n_slen) >= (AFS_UIO_RESID(auio) - len)) {
814 #endif /* AFS_SGI53_ENV */
815 /* No can do no more now; ya know... at this time */
816 DRelease(nde, 0); /* can't use this one. */
819 sdirEntry->d_fileno =
820 (avc->f.fid.Fid.Volume << 16) + ntohl(ode->fid.vnode);
821 FIXUPSTUPIDINODE(sdirEntry->d_fileno);
822 sdirEntry->d_reclen = rlen = AFS_UIO_RESID(auio);
823 sdirEntry->d_namlen = o_slen;
824 #if defined(AFS_SUN5_ENV) || defined(AFS_AIX32_ENV) || defined(AFS_HPUX100_ENV)
825 sdirEntry->d_off = origOffset;
827 AFS_UIOMOVE((char *)sdirEntry, sizeof(*sdirEntry), UIO_READ,
830 AFS_UIOMOVE(ode->name, o_slen, UIO_READ, auio, code);
831 /* pad out the remaining characters with zeros */
833 AFS_UIOMOVE(bufofzeros,
834 ((o_slen + 1 + DIRPAD) & ~DIRPAD) - o_slen,
835 UIO_READ, auio, code);
837 /* pad out the difference between rlen and slen... */
838 if (DIRSIZ_LEN(o_slen) < rlen) {
839 while (DIRSIZ_LEN(o_slen) < rlen) {
840 int minLen = rlen - DIRSIZ_LEN(o_slen);
841 if (minLen > sizeof(bufofzeros))
842 minLen = sizeof(bufofzeros);
843 AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
847 #else /* AFS_HPUX_ENV */
849 afs_readdir_move(ode, avc, auio, o_slen,
850 AFS_UIO_RESID(auio), origOffset);
851 #endif /* AFS_HPUX_ENV */
852 /* this next line used to be AFSVFS40 or AIX 3.1, but is
854 AFS_UIO_SETOFFSET(auio, origOffset);
855 #if !defined(AFS_NBSD_ENV)
856 AFS_UIO_SETRESID(auio, 0);
858 } else { /* trouble, can't give anything to the user! */
859 /* even though he has given us a buffer,
860 * even though we have something to give us,
861 * Looks like we lost something somewhere.
871 * In any event, we move out the LAST de entry, getting ready
872 * to set up for the next one.
876 sdirEntry->d_fileno =
877 (avc->f.fid.Fid.Volume << 16) + ntohl(ode->fid.vnode);
878 FIXUPSTUPIDINODE(sdirEntry->d_fileno);
879 sdirEntry->d_reclen = rlen = len;
880 sdirEntry->d_namlen = o_slen;
881 #if defined(AFS_SUN5_ENV) || defined(AFS_AIX32_ENV) || defined(AFS_HPUX100_ENV)
882 sdirEntry->d_off = origOffset;
884 AFS_UIOMOVE((char *)sdirEntry, sizeof(*sdirEntry), UIO_READ, auio,
887 AFS_UIOMOVE(ode->name, o_slen, UIO_READ, auio, code);
888 /* pad out the remaining characters with zeros */
890 AFS_UIOMOVE(bufofzeros,
891 ((o_slen + 1 + DIRPAD) & ~DIRPAD) - o_slen,
892 UIO_READ, auio, code);
894 /* pad out the difference between rlen and slen... */
895 if (DIRSIZ_LEN(o_slen) < rlen) {
896 while (DIRSIZ_LEN(o_slen) < rlen) {
897 int minLen = rlen - DIRSIZ_LEN(o_slen);
898 if (minLen > sizeof(bufofzeros))
899 minLen = sizeof(bufofzeros);
900 AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
904 #else /* AFS_HPUX_ENV */
905 code = afs_readdir_move(ode, avc, auio, o_slen, len, origOffset);
906 #endif /* AFS_HPUX_ENV */
909 len = use64BitDirent ? DIRENTSIZE(o_slen =
910 n_slen) : IRIX5_DIRENTSIZE(o_slen =
913 len = DIRSIZ_LEN(o_slen = n_slen);
914 #endif /* AFS_SGI53_ENV */
918 AFS_UIO_SETOFFSET(auio, (afs_int32) ((us + afs_dir_NameBlobs(nde->name)) << 5));
924 ReleaseReadLock(&tdc->lock);
926 ReleaseReadLock(&avc->lock);
930 osi_FreeSmallSpace((char *)sdirEntry);
933 afs_PutFakeStat(&fakestate);
934 code = afs_CheckCode(code, &treq, 28);
938 #if defined(AFS_HPUX_ENV)
940 afs1_readdir(struct vcache *avc, struct uio *auio, afs_ucred_t *acred)
942 struct vrequest treq;
944 afs_size_t origOffset, len;
946 struct DirEntry *ode = 0, *nde = 0;
947 int o_slen = 0, n_slen = 0;
950 * XXX All the hacks for alloced sdirEntry and inlining of
951 * afs_readdir_move instead of calling it is necessary for hpux due to
952 * stack problems that seem to occur when coming thru the nfs
953 * translator side XXX
955 struct minnfs_direct *sdirEntry = (struct minnfs_direct *)
956 osi_AllocSmallSpace(sizeof(struct min_direct));
959 struct afs_fakestat_state fakestate;
961 AFS_STATCNT(afs_readdir);
962 if (code = afs_InitReq(&treq, acred)) {
963 osi_FreeSmallSpace((char *)sdirEntry);
966 afs_InitFakeStat(&fakestate);
968 code = afs_EvalFakeStat(&avc, &fakestate, &treq);
970 osi_FreeSmallSpace((char *)sdirEntry);
972 afs_PutFakeStat(&fakestate);
975 /* update the cache entry */
977 code = afs_VerifyVCache(avc, &treq);
980 /* get a reference to the entire directory */
981 tdc = afs_GetDCache(avc, (afs_size_t) 0, &treq, &origOffset, &len, 1);
986 ObtainReadLock(&avc->lock);
987 ObtainReadLock(&tdc->lock);
990 * Make sure that the data in the cache is current. There are two
991 * cases we need to worry about:
992 * 1. The cache data is being fetched by another process.
993 * 2. The cache data is no longer valid
995 while ((avc->f.states & CStatd)
996 && (tdc->dflags & DFFetching)
997 && hsame(avc->f.m.DataVersion, tdc->f.versionNo)) {
998 afs_Trace4(afs_iclSetp, CM_TRACE_DCACHEWAIT, ICL_TYPE_STRING,
999 __FILE__, ICL_TYPE_INT32, __LINE__, ICL_TYPE_POINTER, tdc,
1000 ICL_TYPE_INT32, tdc->dflags);
1001 ReleaseReadLock(&tdc->lock);
1002 ReleaseReadLock(&avc->lock);
1003 afs_osi_Sleep(&tdc->validPos);
1004 ObtainReadLock(&avc->lock);
1005 ObtainReadLock(&tdc->lock);
1007 if (!(avc->f.states & CStatd)
1008 || !hsame(avc->f.m.DataVersion, tdc->f.versionNo)) {
1009 ReleaseReadLock(&tdc->lock);
1010 ReleaseReadLock(&avc->lock);
1016 auio->uio_fpflags = 0;
1018 origOffset = AFS_UIO_OFFSET(auio);
1020 /* scan for the next interesting entry scan for in-use blob
1021 * otherwise up point at this blob note that ode, if non-zero,
1022 * also represents a held dir page */
1023 if (!(us = BlobScan(tdc, (origOffset >> 5)))
1024 || !(nde = (struct DirEntry *)afs_dir_GetBlob(tdc, us))) {
1025 /* failed to setup nde, return what we've got, and release ode */
1027 /* something to hand over. */
1028 sdirEntry->d_fileno =
1029 (avc->f.fid.Fid.Volume << 16) + ntohl(ode->fid.vnode);
1030 FIXUPSTUPIDINODE(sdirEntry->d_fileno);
1031 sdirEntry->d_reclen = rlen = AFS_UIO_RESID(auio);
1032 sdirEntry->d_namlen = o_slen;
1033 sdirEntry->d_off = origOffset;
1034 AFS_UIOMOVE((char *)sdirEntry, sizeof(*sdirEntry), UIO_READ,
1037 AFS_UIOMOVE(ode->name, o_slen, UIO_READ, auio, code);
1039 /* pad out the remaining characters with zeros */
1041 AFS_UIOMOVE(bufofzeros,
1042 ((o_slen + 1 + DIRPAD) & ~DIRPAD) - o_slen,
1043 UIO_READ, auio, code);
1045 /* pad out the difference between rlen and slen... */
1046 if (NDIRSIZ_LEN(o_slen) < rlen) {
1047 while (NDIRSIZ_LEN(o_slen) < rlen) {
1048 int minLen = rlen - NDIRSIZ_LEN(o_slen);
1049 if (minLen > sizeof(bufofzeros))
1050 minLen = sizeof(bufofzeros);
1051 AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
1055 AFS_UIO_SETRESID(auio, 0);
1057 /* nothin to hand over */
1063 /* by here nde is set */
1065 /* Do we have enough user space to carry out our mission? */
1066 n_slen = strlen(nde->name);
1067 if (NDIRSIZ_LEN(n_slen) >= (AFS_UIO_RESID(auio) - len)) {
1068 /* No can do no more now; ya know... at this time */
1069 DRelease(nde, 0); /* can't use this one. */
1071 sdirEntry->d_fileno =
1072 (avc->f.fid.Fid.Volume << 16) + ntohl(ode->fid.vnode);
1073 FIXUPSTUPIDINODE(sdirEntry->d_fileno);
1074 sdirEntry->d_reclen = rlen = AFS_UIO_RESID(auio);
1075 sdirEntry->d_namlen = o_slen;
1076 sdirEntry->d_off = origOffset;
1077 AFS_UIOMOVE((char *)sdirEntry, sizeof(*sdirEntry), UIO_READ,
1080 AFS_UIOMOVE(ode->name, o_slen, UIO_READ, auio, code);
1081 /* pad out the remaining characters with zeros */
1083 AFS_UIOMOVE(bufofzeros,
1084 ((o_slen + 1 + DIRPAD) & ~DIRPAD) - o_slen,
1085 UIO_READ, auio, code);
1087 /* pad out the difference between rlen and slen... */
1088 if (NDIRSIZ_LEN(o_slen) < rlen) {
1089 while (NDIRSIZ_LEN(o_slen) < rlen) {
1090 int minLen = rlen - NDIRSIZ_LEN(o_slen);
1091 if (minLen > sizeof(bufofzeros))
1092 minLen = sizeof(bufofzeros);
1093 AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
1097 /* this next line used to be AFSVFS40 or AIX 3.1, but is really generic */
1098 AFS_UIO_SETOFFSET(auio, origOffset);
1099 AFS_UIO_SETRESID(auio, 0);
1100 } else { /* trouble, can't give anything to the user! */
1101 /* even though he has given us a buffer,
1102 * even though we have something to give us,
1103 * Looks like we lost something somewhere.
1113 * In any event, we move out the LAST de entry, getting ready
1114 * to set up for the next one.
1117 sdirEntry->d_fileno =
1118 (avc->f.fid.Fid.Volume << 16) + ntohl(ode->fid.vnode);
1119 FIXUPSTUPIDINODE(sdirEntry->d_fileno);
1120 sdirEntry->d_reclen = rlen = len;
1121 sdirEntry->d_namlen = o_slen;
1122 sdirEntry->d_off = origOffset;
1123 AFS_UIOMOVE((char *)sdirEntry, sizeof(*sdirEntry), UIO_READ, auio,
1126 AFS_UIOMOVE(ode->name, o_slen, UIO_READ, auio, code);
1127 /* pad out the remaining characters with zeros */
1129 AFS_UIOMOVE(bufofzeros,
1130 ((o_slen + 1 + DIRPAD) & ~DIRPAD) - o_slen,
1131 UIO_READ, auio, code);
1133 /* pad out the difference between rlen and slen... */
1134 if (NDIRSIZ_LEN(o_slen) < rlen) {
1135 while (NDIRSIZ_LEN(o_slen) < rlen) {
1136 int minLen = rlen - NDIRSIZ_LEN(o_slen);
1137 if (minLen > sizeof(bufofzeros))
1138 minLen = sizeof(bufofzeros);
1139 AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
1144 len = NDIRSIZ_LEN(o_slen = n_slen);
1148 AFS_UIO_OFFSET(auio) = ((us + afs_dir_NameBlobs(nde->name)) << 5);
1154 ReleaseReadLock(&tdc->lock);
1156 ReleaseReadLock(&avc->lock);
1159 osi_FreeSmallSpace((char *)sdirEntry);
1160 AFS_DISCON_UNLOCK();
1161 afs_PutFakeStat(&fakestate);
1162 code = afs_CheckCode(code, &treq, 29);
1167 #endif /* !AFS_LINUX20_ENV */