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 /* BlobScan is supposed to ensure that the blob reference refers to a valid
46 directory entry. It consults the allocation map in the page header
47 to determine whether a blob is actually in use or not.
49 More formally, BlobScan is supposed to return a new blob number which is just like
50 the input parameter, only it is advanced over header or free blobs.
52 Note that BlobScan switches pages if necessary. BlobScan may return
53 either 0 or an out-of-range blob number for end of file.
55 BlobScan is used by the Linux port in a separate file, so it should not
59 BlobScan(struct dcache * afile, afs_int32 ablob)
61 afs_int32 relativeBlob;
63 struct PageHeader *tpe;
64 struct DirBuffer headerbuf;
68 AFS_STATCNT(BlobScan);
69 /* advance ablob over free and header blobs */
71 pageBlob = ablob & ~(EPP - 1); /* base blob in same page */
72 code = afs_dir_GetBlob(afile, pageBlob, &headerbuf);
75 tpe = (struct PageHeader *)headerbuf.data;
77 relativeBlob = ablob - pageBlob; /* relative to page's first blob */
78 /* first watch for headers */
79 if (pageBlob == 0) { /* first dir page has extra-big header */
81 if (relativeBlob < DHE + 1)
82 relativeBlob = DHE + 1;
83 } else { /* others have one header blob */
84 if (relativeBlob == 0)
87 /* make sure blob is allocated */
88 for (i = relativeBlob; i < EPP; i++) {
89 if (tpe->freebitmap[i >> 3] & (1 << (i & 7)))
92 /* now relativeBlob is the page-relative first allocated blob,
93 * or EPP (if there are none in this page). */
94 DRelease(&headerbuf, 0);
97 ablob = pageBlob + EPP; /* go around again */
103 #if !defined(AFS_LINUX20_ENV)
104 /* Changes to afs_readdir which affect dcache or vcache handling or use of
105 * bulk stat data should also be reflected in the Linux specific verison of
106 * the readdir routine.
110 * The kernel don't like it so much to have large stuff on the stack.
111 * Here we use a watered down version of the direct struct, since
112 * its not too bright to double copy the strings anyway.
114 #if !defined(UKERNEL)
115 #if defined(AFS_SGI_ENV)
116 /* Long form for 64 bit apps and kernel requests. */
117 struct min_dirent { /* miniature dirent structure */
118 /* If struct dirent changes, this must too */
119 ino_t d_fileno; /* This is 32 bits for 3.5, 64 for 6.2+ */
123 /* Short form for 32 bit apps. */
124 struct irix5_min_dirent { /* miniature dirent structure */
125 /* If struct dirent changes, this must too */
131 #define AFS_DIRENT32BASESIZE IRIX5_DIRENTBASESIZE
132 #define AFS_DIRENT64BASESIZE DIRENT64BASESIZE
134 #define AFS_DIRENT32BASESIZE IRIX5_DIRENTBASESIZE
135 #define AFS_DIRENT64BASESIZE DIRENTBASESIZE
136 #endif /* AFS_SGI62_ENV */
138 struct min_direct { /* miniature direct structure */
139 /* If struct direct changes, this must too */
140 #if defined(AFS_DARWIN80_ENV)
145 #elif defined(AFS_NBSD40_ENV)
146 ino_t d_fileno; /* file number of entry */
147 uint16_t d_reclen; /* length of this record */
148 uint16_t d_namlen; /* length of string in d_name */
149 uint8_t d_type; /* file type, see below */
150 #elif defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
155 #elif defined(AFS_SUN5_ENV)
160 #if defined(AFS_AIX32_ENV)
162 #elif defined(AFS_HPUX100_ENV)
163 unsigned long long d_off;
170 #endif /* AFS_SGI_ENV */
172 #if defined(AFS_HPUX_ENV)
173 struct minnfs_direct {
174 afs_int32 d_off; /* XXX */
179 #define NDIRSIZ_LEN(len) ((sizeof (struct dirent)+4 - (MAXNAMLEN+1)) + (((len)+1 + DIRPAD) &~ DIRPAD))
181 #endif /* !defined(UKERNEL) */
185 *------------------------------------------------------------------------------
187 * Keep a stack of about 256 fids for the bulk stat call.
188 * Fill it during the readdir_move. Later empty it...
191 #define READDIR_STASH AFSCBMAX
192 struct AFSFid afs_readdir_stash[READDIR_STASH];
193 int afs_rd_stash_i = 0;
196 *------------------------------------------------------------------------------
199 * mainly a kind of macro... makes getting the struct direct
200 * out to the user space easy... could take more parameters,
201 * but now just takes what it needs.
206 #if defined(AFS_HPUX100_ENV)
207 #define DIRSIZ_LEN(len) \
208 ((sizeof (struct __dirent) - (_MAXNAMLEN+1)) + (((len)+1 + DIRPAD) &~ DIRPAD))
210 #if defined(AFS_SUN5_ENV)
211 #define DIRSIZ_LEN(len) ((18 + (len) + 1 + 7) & ~7 )
213 #ifdef AFS_NBSD40_ENV
214 #define DIRSIZ_LEN(len) \
215 ((sizeof (struct dirent) - (MAXNAMLEN+1)) + (((len)+1 + 7) & ~7))
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_NBSD40_ENV */
232 #endif /* AFS_SUN5_ENV */
233 #endif /* AFS_HPUX100_ENV */
235 #if defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
237 afs_readdir_type(struct vcache *avc, struct DirEntry *ade)
239 struct VenusFid tfid;
242 tfid.Cell = avc->f.fid.Cell;
243 tfid.Fid.Volume = avc->f.fid.Fid.Volume;
244 tfid.Fid.Vnode = ntohl(ade->fid.vnode);
245 tfid.Fid.Unique = ntohl(ade->fid.vunique);
246 if ((avc->f.states & CForeign) == 0 && (ntohl(ade->fid.vnode) & 1)) {
249 ObtainReadLock(&afs_xvcache);
250 if ((tvc = afs_FindVCache(&tfid, 0, 0))) {
251 ReleaseReadLock(&afs_xvcache);
255 } else if (((tvc->f.states) & (CStatd | CTruth))) {
256 /* CTruth will be set if the object has
262 else if (vtype == VREG)
264 /* Don't do this until we're sure it can't be a mtpt */
265 /* if we're CStatd and CTruth and mvstat==0, it's a link */
266 else if (vtype == VLNK)
268 /* what other types does AFS support? */
272 ReleaseReadLock(&afs_xvcache);
278 #define AFS_MOVE_LOCK() AFS_GLOCK()
279 #define AFS_MOVE_UNLOCK() AFS_GUNLOCK()
281 #define AFS_MOVE_LOCK()
282 #define AFS_MOVE_UNLOCK()
284 char bufofzeros[64]; /* gotta fill with something */
288 afs_readdir_move(struct DirEntry *de, struct vcache *vc, struct uio *auio,
289 int slen, ssize_t rlen, afs_size_t off)
292 afs_readdir_move(struct DirEntry *de, struct vcache *vc, struct uio *auio,
293 int slen, int rlen, afs_size_t off)
298 afs_uint32 Volume = vc->f.fid.Fid.Volume;
299 afs_uint32 Vnode = de->fid.vnode;
300 #if defined(AFS_SUN5_ENV)
301 struct dirent64 *direntp;
303 #if (defined(AFS_AIX51_ENV) && defined(AFS_64BIT_KERNEL))
304 struct dirent *direntp;
306 #endif /* AFS_SUN5_ENV */
307 #ifndef AFS_SGI53_ENV
308 struct min_direct sdirEntry;
309 #endif /* AFS_SGI53_ENV */
311 AFS_STATCNT(afs_readdir_move);
313 #define READDIR_CORRECT_INUMS
314 #ifdef READDIR_CORRECT_INUMS
315 if (de->name[0] == '.' && !de->name[1]) {
316 /* This is the '.' entry; if we are a volume root, we need to
317 * ignore the directory and use the inum for the mount point.
319 if (!FidCmp(&afs_rootFid, &vc->f.fid)) {
322 } else if (vc->mvstat == 2) {
323 tvp = afs_GetVolume(&vc->f.fid, 0, READ_LOCK);
325 Volume = tvp->mtpoint.Fid.Volume;
326 Vnode = tvp->mtpoint.Fid.Vnode;
327 afs_PutVolume(tvp, READ_LOCK);
331 else if (de->name[0] == '.' && de->name[1] == '.' && !de->name[2]) {
332 /* This is the '..' entry. Getting this right is very tricky,
333 * because we might be a volume root (so our parent is in a
334 * different volume), or our parent might be a volume root
335 * (so we actually want the mount point) or BOTH! */
336 if (!FidCmp(&afs_rootFid, &vc->f.fid)) {
337 /* We are the root of the AFS root, and thus our own parent */
340 } else if (vc->mvstat == 2) {
341 /* We are a volume root, which means our parent is in another
342 * volume. Luckily, we should have his fid cached... */
344 if (!FidCmp(&afs_rootFid, vc->mvid)) {
345 /* Parent directory is the root of the AFS root */
348 } else if (vc->mvid->Fid.Vnode == 1
349 && vc->mvid->Fid.Unique == 1) {
350 /* XXX The above test is evil and probably breaks DFS */
351 /* Parent directory is the target of a mount point */
352 tvp = afs_GetVolume(vc->mvid, 0, READ_LOCK);
354 Volume = tvp->mtpoint.Fid.Volume;
355 Vnode = tvp->mtpoint.Fid.Vnode;
356 afs_PutVolume(tvp, READ_LOCK);
359 /* Parent directory is not a volume root */
360 Volume = vc->mvid->Fid.Volume;
361 Vnode = vc->mvid->Fid.Vnode;
364 } else if (de->fid.vnode == 1 && de->fid.vunique == 1) {
365 /* XXX The above test is evil and probably breaks DFS */
366 /* Parent directory is a volume root; use the right inum */
367 tvp = afs_GetVolume(&vc->f.fid, 0, READ_LOCK);
369 if (tvp->cell == afs_rootFid.Cell
370 && tvp->volume == afs_rootFid.Fid.Volume) {
371 /* Parent directory is the root of the AFS root */
375 /* Parent directory is the target of a mount point */
376 Volume = tvp->mtpoint.Fid.Volume;
377 Vnode = tvp->mtpoint.Fid.Vnode;
379 afs_PutVolume(tvp, READ_LOCK);
387 afs_int32 use64BitDirent;
392 ABI_IS(ABI_IRIX5_64, GETDENTS_ABI(OSI_GET_CURRENT_ABI(), auio));
396 UIO_USERSPACE) ? ABI_IRIX5_64 : (ABI_IS(ABI_IRIX5_64 |
400 #else /* AFS_SGI61_ENV */
403 UIO_USERSPACE) ? ABI_IRIX5_64 : (ABI_IS(ABI_IRIX5_64,
405 #endif /* AFS_SGI61_ENV */
407 if (use64BitDirent) {
408 struct min_dirent sdirEntry;
409 sdirEntry.d_fileno = afs_calc_inum(vc->f.fid.Cell,
410 Volume, ntohl(Vnode));
411 sdirEntry.d_reclen = rlen;
412 sdirEntry.d_off = (off_t) off;
413 AFS_UIOMOVE(&sdirEntry, AFS_DIRENT64BASESIZE, UIO_READ, auio,
416 AFS_UIOMOVE(de->name, slen - 1, UIO_READ, auio, code);
418 AFS_UIOMOVE(bufofzeros,
419 DIRENTSIZE(slen) - (AFS_DIRENT64BASESIZE + slen -
420 1), UIO_READ, auio, code);
421 if (DIRENTSIZE(slen) < rlen) {
422 while (DIRENTSIZE(slen) < rlen) {
423 int minLen = rlen - DIRENTSIZE(slen);
424 if (minLen > sizeof(bufofzeros))
425 minLen = sizeof(bufofzeros);
426 AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
431 struct irix5_min_dirent sdirEntry;
432 sdirEntry.d_fileno = afs_calc_inum(vc->f.fid.Cell,
433 Volume, ntohl(Vnode));
434 sdirEntry.d_reclen = rlen;
435 sdirEntry.d_off = (afs_int32) off;
436 AFS_UIOMOVE(&sdirEntry, AFS_DIRENT32BASESIZE, UIO_READ, auio,
439 AFS_UIOMOVE(de->name, slen - 1, UIO_READ, auio, code);
441 AFS_UIOMOVE(bufofzeros,
442 IRIX5_DIRENTSIZE(slen) - (AFS_DIRENT32BASESIZE +
445 if (IRIX5_DIRENTSIZE(slen) < rlen) {
446 while (IRIX5_DIRENTSIZE(slen) < rlen) {
447 int minLen = rlen - IRIX5_DIRENTSIZE(slen);
448 if (minLen > sizeof(bufofzeros))
449 minLen = sizeof(bufofzeros);
450 AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
456 #else /* AFS_SGI53_ENV */
457 #if defined(AFS_SUN5_ENV) || (defined(AFS_AIX51_ENV) && defined(AFS_64BIT_KERNEL))
458 #if defined(AFS_SUN5_ENV)
459 direntp = (struct dirent64 *)osi_AllocLargeSpace(AFS_LRALLOCSIZ);
461 direntp = (struct dirent *)osi_AllocLargeSpace(AFS_LRALLOCSIZ);
463 direntp->d_ino = afs_calc_inum(vc->f.fid.Cell, Volume, ntohl(Vnode));
464 #if defined(AFS_AIX51_ENV) && defined(AFS_64BIT_KERNEL)
465 direntp->d_offset = off;
466 direntp->d_namlen = slen;
468 direntp->d_off = off;
470 direntp->d_reclen = rlen;
471 strcpy(direntp->d_name, de->name);
472 AFS_UIOMOVE((caddr_t) direntp, rlen, UIO_READ, auio, code);
473 osi_FreeLargeSpace((char *)direntp);
474 #else /* AFS_SUN5_ENV */
475 /* Note the odd mechanism for building the inode number */
476 sdirEntry.d_fileno = afs_calc_inum(vc->f.fid.Cell, Volume, ntohl(Vnode));
477 sdirEntry.d_reclen = rlen;
478 #if !defined(AFS_SGI_ENV)
479 sdirEntry.d_namlen = slen;
481 #if defined(AFS_AIX32_ENV) || defined(AFS_SGI_ENV)
482 sdirEntry.d_off = off;
484 #if defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
485 sdirEntry.d_type = afs_readdir_type(vc, de);
488 #if defined(AFS_SGI_ENV)
489 AFS_UIOMOVE(&sdirEntry, DIRENTBASESIZE, UIO_READ, auio, code);
491 AFS_UIOMOVE(de->name, slen - 1, UIO_READ, auio, code);
493 AFS_UIOMOVE(bufofzeros,
494 DIRSIZ_LEN(slen) - (DIRENTBASESIZE + slen - 1), UIO_READ,
496 #else /* AFS_SGI_ENV */
498 #if defined(AFS_NBSD40_ENV)
501 dp = osi_AllocLargeSpace(sizeof(struct dirent));
502 memset(dp, 0, sizeof(struct dirent));
503 dp->d_ino = afs_calc_inum(vc->f.fid.Cell, Volume, ntohl(Vnode));
505 dp->d_type = afs_readdir_type(vc, de);
506 strcpy(dp->d_name, de->name);
507 dp->d_reclen = _DIRENT_SIZE(dp) /* rlen */;
508 if ((afs_debug & AFSDEB_VNLAYER) != 0) {
509 afs_warn("%s: %s type %d slen %d rlen %d act. rlen %zu\n", __func__,
510 dp->d_name, dp->d_type, slen, rlen, _DIRENT_SIZE(dp));
512 AFS_UIOMOVE(dp, dp->d_reclen, UIO_READ, auio, code);
513 osi_FreeLargeSpace((char *)dp);
516 AFS_UIOMOVE((char *) &sdirEntry, sizeof(sdirEntry), UIO_READ, auio, code);
518 AFS_UIOMOVE(de->name, slen, UIO_READ, auio, code);
520 /* pad out the remaining characters with zeros */
522 AFS_UIOMOVE(bufofzeros, ((slen + 1 + DIRPAD) & ~DIRPAD) - slen,
523 UIO_READ, auio, code);
527 #endif /* AFS_SGI_ENV */
528 #if !defined(AFS_NBSD_ENV)
529 /* pad out the difference between rlen and slen... */
530 if (DIRSIZ_LEN(slen) < rlen) {
532 while (DIRSIZ_LEN(slen) < rlen) {
533 int minLen = rlen - DIRSIZ_LEN(slen);
534 if (minLen > sizeof(bufofzeros))
535 minLen = sizeof(bufofzeros);
536 AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
542 #endif /* AFS_SUN5_ENV */
543 #endif /* AFS_SGI53_ENV */
549 *------------------------------------------------------------------------------
551 * Read directory entries.
552 * There are some weird things to look out for here. The uio_offset
553 * field is either 0 or it is the offset returned from a previous
554 * readdir. It is an opaque value used by the server to find the
555 * correct directory block to read. The byte count must be at least
556 * vtoblksz(vp) bytes. The count field is the number of blocks to
557 * read on the server. This is advisory only, the server may return
558 * only one block's worth of entries. Entries may be compressed on
561 * This routine encodes knowledge of Vice dirs.
565 afs_bulkstat_send(struct vcache *avc, struct vrequest *req)
571 * Here is the bad, bad, really bad news.
572 * It has to do with 'offset' (seek locations).
576 #if defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
577 afs_readdir(OSI_VC_DECL(avc), struct uio *auio, afs_ucred_t *acred,
580 #if defined(AFS_HPUX100_ENV)
581 afs_readdir2(OSI_VC_DECL(avc), struct uio *auio, afs_ucred_t *acred)
583 afs_readdir(OSI_VC_DECL(avc), struct uio *auio, afs_ucred_t *acred)
587 struct vrequest treq;
589 afs_size_t origOffset, tlen;
592 struct DirBuffer oldEntry, nextEntry;
593 struct DirEntry *ode = 0, *nde = 0;
594 int o_slen = 0, n_slen = 0;
596 struct afs_fakestat_state fakestate;
597 #if defined(AFS_SGI53_ENV)
598 afs_int32 use64BitDirent, dirsiz;
599 #endif /* defined(AFS_SGI53_ENV) */
604 * XXX All the hacks for alloced sdirEntry and inlining of afs_readdir_move instead of calling
605 * it is necessary for hpux due to stack problems that seem to occur when coming thru the nfs
606 * translator side XXX
608 struct min_direct *sdirEntry =
609 (struct min_direct *)osi_AllocSmallSpace(sizeof(struct min_direct));
613 /* opaque value is pointer into a vice dir; use bit map to decide
614 * if the entries are in use. Always assumed to be valid. 0 is
615 * special, means start of a new dir. Int32 inode, followed by
616 * short reclen and short namelen. Namelen does not include
617 * the null byte. Followed by null-terminated string.
619 AFS_STATCNT(afs_readdir);
621 memset(&oldEntry, 0, sizeof(struct DirBuffer));
622 memset(&nextEntry, 0, sizeof(struct DirBuffer));
624 #if defined(AFS_SGI53_ENV)
628 ABI_IS(ABI_IRIX5_64, GETDENTS_ABI(OSI_GET_CURRENT_ABI(), auio));
632 UIO_USERSPACE) ? ABI_IRIX5_64 : (ABI_IS(ABI_IRIX5_64 | ABI_IRIX5_N32,
634 #endif /* AFS_SGI62_ENV */
635 #else /* AFS_SGI61_ENV */
638 UIO_USERSPACE) ? ABI_IRIX5_64 : (ABI_IS(ABI_IRIX5_64,
640 #endif /* AFS_SGI61_ENV */
641 #endif /* defined(AFS_SGI53_ENV) */
643 #if defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
644 /* Not really used by the callee so we ignore it for now */
648 #ifndef AFS_64BIT_CLIENT
649 if (AfsLargeFileUio(auio) /* file is large than 2 GB */
650 ||AfsLargeFileSize(AFS_UIO_OFFSET(auio), AFS_UIO_RESID(auio)))
654 if ((code = afs_InitReq(&treq, acred))) {
656 osi_FreeSmallSpace((char *)sdirEntry);
660 /* update the cache entry */
661 afs_InitFakeStat(&fakestate);
665 code = afs_EvalFakeStat(&avc, &fakestate, &treq);
669 code = afs_VerifyVCache(avc, &treq);
672 /* get a reference to the entire directory */
673 tdc = afs_GetDCache(avc, (afs_size_t) 0, &treq, &origOffset, &tlen, 1);
679 ObtainReadLock(&avc->lock);
680 ObtainReadLock(&tdc->lock);
683 * Make sure that the data in the cache is current. There are two
684 * cases we need to worry about:
685 * 1. The cache data is being fetched by another process.
686 * 2. The cache data is no longer valid
688 while ((avc->f.states & CStatd)
689 && (tdc->dflags & DFFetching)
690 && hsame(avc->f.m.DataVersion, tdc->f.versionNo)) {
691 afs_Trace4(afs_iclSetp, CM_TRACE_DCACHEWAIT, ICL_TYPE_STRING,
692 __FILE__, ICL_TYPE_INT32, __LINE__, ICL_TYPE_POINTER, tdc,
693 ICL_TYPE_INT32, tdc->dflags);
694 ReleaseReadLock(&tdc->lock);
695 ReleaseReadLock(&avc->lock);
696 afs_osi_Sleep(&tdc->validPos);
697 ObtainReadLock(&avc->lock);
698 ObtainReadLock(&tdc->lock);
700 if (!(avc->f.states & CStatd)
701 || !hsame(avc->f.m.DataVersion, tdc->f.versionNo)) {
702 ReleaseReadLock(&tdc->lock);
703 ReleaseReadLock(&avc->lock);
709 * iterator for the directory reads. Takes the AFS DirEntry
710 * structure and slams them into UFS direct structures.
711 * uses afs_readdir_move to get the struct to the user space.
713 * The routine works by looking ahead one AFS directory entry.
714 * That's because the AFS entry we are currenly working with
715 * may not fit into the buffer the user has provided. If it
716 * doesn't we have to change the size of the LAST AFS directory
717 * entry, so that it will FIT perfectly into the block the
720 * The 'forward looking' of the code makes it a bit tough to read.
721 * Remember we need to get an entry, see if it it fits, then
722 * set it up as the LAST entry, and find the next one.
724 * Tough to take: We give out an EINVAL if we don't have enough
725 * space in the buffer, and at the same time, don't have an entry
726 * to put into the buffer. This CAN happen if the first AFS entry
727 * we get can't fit into the 512 character buffer provided. Seems
728 * it ought not happen...
730 * Assumption: don't need to use anything but one dc entry:
731 * this means the directory ought not be greater than 64k.
735 auio->uio_fpflags = 0;
738 origOffset = AFS_UIO_OFFSET(auio);
739 /* scan for the next interesting entry scan for in-use blob otherwise up point at
740 * this blob note that ode, if non-zero, also represents a held dir page */
741 us = BlobScan(tdc, (origOffset >> 5));
744 code = afs_dir_GetVerifiedBlob(tdc, us, &nextEntry);
746 if (us == 0 || code != 0) {
747 code = 0; /* Reset code - keep old failure behaviour */
748 /* failed to setup nde, return what we've got, and release ode */
750 /* something to hand over. */
752 sdirEntry->d_fileno = afs_calc_inum(avc->f.fid.Cell,
753 avc->f.fid.Fid.Volume,
754 ntohl(ode->fid.vnode));
755 sdirEntry->d_reclen = rlen = AFS_UIO_RESID(auio);
756 sdirEntry->d_namlen = o_slen;
757 #if defined(AFS_SUN5_ENV) || defined(AFS_AIX32_ENV) || defined(AFS_HPUX100_ENV)
758 sdirEntry->d_off = origOffset;
760 AFS_UIOMOVE((char *)sdirEntry, sizeof(*sdirEntry), UIO_READ,
763 AFS_UIOMOVE(ode->name, o_slen, UIO_READ, auio, code);
764 /* pad out the remaining characters with zeros */
766 AFS_UIOMOVE(bufofzeros,
767 ((o_slen + 1 + DIRPAD) & ~DIRPAD) - o_slen,
768 UIO_READ, auio, code);
770 /* pad out the difference between rlen and slen... */
771 if (DIRSIZ_LEN(o_slen) < rlen) {
772 while (DIRSIZ_LEN(o_slen) < rlen) {
773 int minLen = rlen - DIRSIZ_LEN(o_slen);
774 if (minLen > sizeof(bufofzeros))
775 minLen = sizeof(bufofzeros);
776 AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
781 code = afs_readdir_move(ode, avc, auio, o_slen,
782 #if defined(AFS_SUN5_ENV) || defined(AFS_NBSD_ENV)
785 AFS_UIO_RESID(auio), origOffset);
787 #endif /* AFS_HPUX_ENV */
788 #if !defined(AFS_SUN5_ENV) && !defined(AFS_NBSD_ENV)
789 AFS_UIO_SETRESID(auio, 0);
792 /* nothin to hand over */
794 #if defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
796 *eofp = 1; /* Set it properly */
798 DRelease(&oldEntry, 0);
801 nde = (struct DirEntry *)nextEntry.data;
803 /* Do we have enough user space to carry out our mission? */
804 #if defined(AFS_SGI_ENV)
805 n_slen = strlen(nde->name) + 1; /* NULL terminate */
807 n_slen = strlen(nde->name);
811 use64BitDirent ? DIRENTSIZE(n_slen) : IRIX5_DIRENTSIZE(n_slen);
812 if (dirsiz >= (AFS_UIO_RESID(auio) - len)) {
814 if (DIRSIZ_LEN(n_slen) >= (AFS_UIO_RESID(auio) - len)) {
815 #endif /* AFS_SGI53_ENV */
816 /* No can do no more now; ya know... at this time */
817 DRelease(&nextEntry, 0); /* can't use this one. */
820 sdirEntry->d_fileno = afs_calc_inum(avc->f.fid.Cell,
821 avc->f.fid.Fid.Volume,
822 ntohl(ode->fid.vnode));
823 sdirEntry->d_reclen = rlen = AFS_UIO_RESID(auio);
824 sdirEntry->d_namlen = o_slen;
825 #if defined(AFS_SUN5_ENV) || defined(AFS_AIX32_ENV) || defined(AFS_HPUX100_ENV)
826 sdirEntry->d_off = origOffset;
828 AFS_UIOMOVE((char *)sdirEntry, sizeof(*sdirEntry), UIO_READ,
831 AFS_UIOMOVE(ode->name, o_slen, UIO_READ, auio, code);
832 /* pad out the remaining characters with zeros */
834 AFS_UIOMOVE(bufofzeros,
835 ((o_slen + 1 + DIRPAD) & ~DIRPAD) - o_slen,
836 UIO_READ, auio, code);
838 /* pad out the difference between rlen and slen... */
839 if (DIRSIZ_LEN(o_slen) < rlen) {
840 while (DIRSIZ_LEN(o_slen) < rlen) {
841 int minLen = rlen - DIRSIZ_LEN(o_slen);
842 if (minLen > sizeof(bufofzeros))
843 minLen = sizeof(bufofzeros);
844 AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
848 #else /* AFS_HPUX_ENV */
850 afs_readdir_move(ode, avc, auio, o_slen,
851 AFS_UIO_RESID(auio), origOffset);
852 #endif /* AFS_HPUX_ENV */
853 /* this next line used to be AFSVFS40 or AIX 3.1, but is
855 AFS_UIO_SETOFFSET(auio, origOffset);
856 #if !defined(AFS_NBSD_ENV)
857 AFS_UIO_SETRESID(auio, 0);
859 } else { /* trouble, can't give anything to the user! */
860 /* even though he has given us a buffer,
861 * even though we have something to give us,
862 * Looks like we lost something somewhere.
866 DRelease(&oldEntry, 0);
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 = afs_calc_inum(avc->f.fid.Cell,
877 avc->f.fid.Fid.Volume,
878 ntohl(ode->fid.vnode));
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 */
916 DRelease(&oldEntry, 0);
917 oldEntry = nextEntry;
919 AFS_UIO_SETOFFSET(auio, (afs_int32) ((us + afs_dir_NameBlobs(nde->name)) << 5));
922 DRelease(&oldEntry, 0);
925 ReleaseReadLock(&tdc->lock);
927 ReleaseReadLock(&avc->lock);
931 osi_FreeSmallSpace((char *)sdirEntry);
934 afs_PutFakeStat(&fakestate);
935 code = afs_CheckCode(code, &treq, 28);
939 #endif /* !AFS_LINUX20_ENV */