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.
46 * Ensure that the blob reference refers to a valid directory entry.
47 * It consults the allocation map in the page header to determine
48 * whether a blob is actually in use or not.
50 * More formally, BlobScan is supposed to return a new blob number
51 * which is just like the input parameter, only it is advanced over
52 * header or free blobs.
54 * Note that BlobScan switches pages if necessary. BlobScan may
55 * return either 0 for success or an error code. Upon successful
56 * return, the new blob value is assigned to *ablobOut. The new
57 * blob value (*ablobOut) is set to 0 when the end of the file has
60 * BlobScan is used by the Linux port in a separate file, so it should not
64 BlobScan(struct dcache * afile, afs_int32 ablob, int *ablobOut)
66 afs_int32 relativeBlob;
68 struct PageHeader *tpe;
69 struct DirBuffer headerbuf;
73 AFS_STATCNT(BlobScan);
74 /* advance ablob over free and header blobs */
76 pageBlob = ablob & ~(EPP - 1); /* base blob in same page */
77 code = afs_dir_GetBlob(afile, pageBlob, &headerbuf);
79 *ablobOut = 0; /* past the end of file */
80 return 0; /* not an error */
84 tpe = (struct PageHeader *)headerbuf.data;
86 relativeBlob = ablob - pageBlob; /* relative to page's first blob */
87 /* first watch for headers */
88 if (pageBlob == 0) { /* first dir page has extra-big header */
90 if (relativeBlob < DHE + 1)
91 relativeBlob = DHE + 1;
92 } else { /* others have one header blob */
93 if (relativeBlob == 0)
96 /* make sure blob is allocated */
97 for (i = relativeBlob; i < EPP; i++) {
98 if (tpe->freebitmap[i >> 3] & (1 << (i & 7)))
101 /* now relativeBlob is the page-relative first allocated blob,
102 * or EPP (if there are none in this page). */
103 DRelease(&headerbuf, 0);
105 *ablobOut = i + pageBlob;
108 ablob = pageBlob + EPP; /* go around again */
114 #if !defined(AFS_LINUX_ENV)
115 /* Changes to afs_readdir which affect dcache or vcache handling or use of
116 * bulk stat data should also be reflected in the Linux specific verison of
117 * the readdir routine.
121 * The kernel don't like it so much to have large stuff on the stack.
122 * Here we use a watered down version of the direct struct, since
123 * its not too bright to double copy the strings anyway.
125 #if !defined(UKERNEL)
126 #if defined(AFS_SGI_ENV)
127 /* Long form for 64 bit apps and kernel requests. */
128 struct min_dirent { /* miniature dirent structure */
129 /* If struct dirent changes, this must too */
130 ino_t d_fileno; /* This is 32 bits for 3.5, 64 for 6.2+ */
134 /* Short form for 32 bit apps. */
135 struct irix5_min_dirent { /* miniature dirent structure */
136 /* If struct dirent changes, this must too */
141 #define AFS_DIRENT32BASESIZE IRIX5_DIRENTBASESIZE
142 #define AFS_DIRENT64BASESIZE DIRENT64BASESIZE
144 struct min_direct { /* miniature direct structure */
145 /* If struct direct changes, this must too */
146 #if defined(AFS_DARWIN80_ENV)
151 #elif defined(AFS_NBSD40_ENV)
152 ino_t d_fileno; /* file number of entry */
153 uint16_t d_reclen; /* length of this record */
154 uint16_t d_namlen; /* length of string in d_name */
155 uint8_t d_type; /* file type, see below */
156 #elif defined(AFS_FBSD120_ENV)
157 /* FreeBSD 12.0 moved to 64-bit inodes and bumped d_namlen to 16 bits. */
165 #elif defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
170 #elif defined(AFS_SUN5_ENV)
175 #if defined(AFS_AIX32_ENV)
177 #elif defined(AFS_HPUX100_ENV)
178 unsigned long long d_off;
185 #endif /* AFS_SGI_ENV */
187 #if defined(AFS_HPUX_ENV)
188 struct minnfs_direct {
189 afs_int32 d_off; /* XXX */
194 #define NDIRSIZ_LEN(len) ((sizeof (struct dirent)+4 - (MAXNAMLEN+1)) + (((len)+1 + DIRPAD) &~ DIRPAD))
196 #endif /* !defined(UKERNEL) */
200 *------------------------------------------------------------------------------
202 * Keep a stack of about 256 fids for the bulk stat call.
203 * Fill it during the readdir_move. Later empty it...
206 #define READDIR_STASH AFSCBMAX
207 struct AFSFid afs_readdir_stash[READDIR_STASH];
208 int afs_rd_stash_i = 0;
211 *------------------------------------------------------------------------------
214 * mainly a kind of macro... makes getting the struct direct
215 * out to the user space easy... could take more parameters,
216 * but now just takes what it needs.
221 #if defined(AFS_HPUX100_ENV)
222 #define DIRSIZ_LEN(len) \
223 ((sizeof (struct __dirent) - (_MAXNAMLEN+1)) + (((len)+1 + DIRPAD) &~ DIRPAD))
225 #if defined(AFS_SUN5_ENV)
226 #define DIRSIZ_LEN(len) ((18 + (len) + 1 + 7) & ~7 )
228 #ifdef AFS_NBSD40_ENV
229 #define DIRSIZ_LEN(len) \
230 ((sizeof (struct dirent) - (MAXNAMLEN+1)) + (((len)+1 + 7) & ~7))
233 #define DIRSIZ_LEN(len) \
234 ((sizeof (struct dirent) - (MAXNAMLEN+1)) + (((len)+1 + 3) &~ 3))
237 #define DIRSIZ_LEN(len) \
238 ((sizeof (struct direct) - (MAXNAMLEN+1)) + (((len)+1 + 3) &~ 3))
239 #endif /* AFS_SGI_ENV */
240 #endif /* AFS_DIRENT */
241 #endif /* AFS_NBSD40_ENV */
242 #endif /* AFS_SUN5_ENV */
243 #endif /* AFS_HPUX100_ENV */
245 #if defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
247 afs_readdir_type(struct vcache *avc, struct DirEntry *ade)
249 struct VenusFid tfid;
252 tfid.Cell = avc->f.fid.Cell;
253 tfid.Fid.Volume = avc->f.fid.Fid.Volume;
254 tfid.Fid.Vnode = ntohl(ade->fid.vnode);
255 tfid.Fid.Unique = ntohl(ade->fid.vunique);
256 if ((avc->f.states & CForeign) == 0 && (ntohl(ade->fid.vnode) & 1)) {
259 ObtainReadLock(&afs_xvcache);
260 if ((tvc = afs_FindVCache(&tfid, 0))) {
261 ReleaseReadLock(&afs_xvcache);
262 if (tvc->mvstat != AFS_MVSTAT_FILE) {
265 } else if (((tvc->f.states) & (CStatd | CTruth))) {
266 /* CTruth will be set if the object has
272 else if (vtype == VREG)
274 /* Don't do this until we're sure it can't be a mtpt */
275 /* if we're CStatd and CTruth and mvstat==AFS_MVSTAT_FILE, it's a link */
276 else if (vtype == VLNK)
278 /* what other types does AFS support? */
282 ReleaseReadLock(&afs_xvcache);
288 #define AFS_MOVE_LOCK() AFS_GLOCK()
289 #define AFS_MOVE_UNLOCK() AFS_GUNLOCK()
291 #define AFS_MOVE_LOCK()
292 #define AFS_MOVE_UNLOCK()
294 char bufofzeros[64]; /* gotta fill with something */
298 afs_readdir_move(struct DirEntry *de, struct vcache *vc, struct uio *auio,
299 int slen, ssize_t rlen, afs_size_t off)
302 afs_readdir_move(struct DirEntry *de, struct vcache *vc, struct uio *auio,
303 int slen, int rlen, afs_size_t off)
308 afs_uint32 Volume = vc->f.fid.Fid.Volume;
309 afs_uint32 Vnode = de->fid.vnode;
310 #if defined(AFS_SUN5_ENV)
311 struct dirent64 *direntp;
313 #if (defined(AFS_AIX51_ENV) && defined(AFS_64BIT_KERNEL))
314 struct dirent *direntp;
316 #endif /* AFS_SUN5_ENV */
318 struct min_direct sdirEntry;
319 memset(&sdirEntry, 0, sizeof(sdirEntry));
320 #endif /* AFS_SGI_ENV */
322 AFS_STATCNT(afs_readdir_move);
324 #define READDIR_CORRECT_INUMS
325 #ifdef READDIR_CORRECT_INUMS
326 if (de->name[0] == '.' && !de->name[1]) {
327 /* This is the '.' entry; if we are a volume root, we need to
328 * ignore the directory and use the inum for the mount point.
330 if (!FidCmp(&afs_rootFid, &vc->f.fid)) {
333 } else if (vc->mvstat == AFS_MVSTAT_ROOT) {
334 tvp = afs_GetVolume(&vc->f.fid, 0, READ_LOCK);
336 Volume = tvp->mtpoint.Fid.Volume;
337 Vnode = tvp->mtpoint.Fid.Vnode;
338 afs_PutVolume(tvp, READ_LOCK);
342 else if (de->name[0] == '.' && de->name[1] == '.' && !de->name[2]) {
343 /* This is the '..' entry. Getting this right is very tricky,
344 * because we might be a volume root (so our parent is in a
345 * different volume), or our parent might be a volume root
346 * (so we actually want the mount point) or BOTH! */
347 if (!FidCmp(&afs_rootFid, &vc->f.fid)) {
348 /* We are the root of the AFS root, and thus our own parent */
351 } else if (vc->mvstat == AFS_MVSTAT_ROOT) {
352 /* We are a volume root, which means our parent is in another
353 * volume. Luckily, we should have his fid cached... */
354 if (vc->mvid.parent) {
355 if (!FidCmp(&afs_rootFid, vc->mvid.parent)) {
356 /* Parent directory is the root of the AFS root */
359 } else if (vc->mvid.parent->Fid.Vnode == 1
360 && vc->mvid.parent->Fid.Unique == 1) {
361 /* XXX The above test is evil and probably breaks DFS */
362 /* Parent directory is the target of a mount point */
363 tvp = afs_GetVolume(vc->mvid.parent, 0, READ_LOCK);
365 Volume = tvp->mtpoint.Fid.Volume;
366 Vnode = tvp->mtpoint.Fid.Vnode;
367 afs_PutVolume(tvp, READ_LOCK);
370 /* Parent directory is not a volume root */
371 Volume = vc->mvid.parent->Fid.Volume;
372 Vnode = vc->mvid.parent->Fid.Vnode;
375 } else if (de->fid.vnode == 1 && de->fid.vunique == 1) {
376 /* XXX The above test is evil and probably breaks DFS */
377 /* Parent directory is a volume root; use the right inum */
378 tvp = afs_GetVolume(&vc->f.fid, 0, READ_LOCK);
380 if (tvp->cell == afs_rootFid.Cell
381 && tvp->volume == afs_rootFid.Fid.Volume) {
382 /* Parent directory is the root of the AFS root */
386 /* Parent directory is the target of a mount point */
387 Volume = tvp->mtpoint.Fid.Volume;
388 Vnode = tvp->mtpoint.Fid.Vnode;
390 afs_PutVolume(tvp, READ_LOCK);
398 afs_int32 use64BitDirent;
401 ABI_IS(ABI_IRIX5_64, GETDENTS_ABI(OSI_GET_CURRENT_ABI(), auio));
403 if (use64BitDirent) {
404 struct min_dirent sdirEntry;
405 sdirEntry.d_fileno = afs_calc_inum(vc->f.fid.Cell,
406 Volume, ntohl(Vnode));
407 sdirEntry.d_reclen = rlen;
408 sdirEntry.d_off = (off_t) off;
409 AFS_UIOMOVE(&sdirEntry, AFS_DIRENT64BASESIZE, UIO_READ, auio,
412 AFS_UIOMOVE(de->name, slen - 1, UIO_READ, auio, code);
414 AFS_UIOMOVE(bufofzeros,
415 DIRENTSIZE(slen) - (AFS_DIRENT64BASESIZE + slen -
416 1), UIO_READ, auio, code);
417 if (DIRENTSIZE(slen) < rlen) {
418 while (DIRENTSIZE(slen) < rlen) {
419 int minLen = rlen - DIRENTSIZE(slen);
420 if (minLen > sizeof(bufofzeros))
421 minLen = sizeof(bufofzeros);
422 AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
427 struct irix5_min_dirent sdirEntry;
428 sdirEntry.d_fileno = afs_calc_inum(vc->f.fid.Cell,
429 Volume, ntohl(Vnode));
430 sdirEntry.d_reclen = rlen;
431 sdirEntry.d_off = (afs_int32) off;
432 AFS_UIOMOVE(&sdirEntry, AFS_DIRENT32BASESIZE, UIO_READ, auio,
435 AFS_UIOMOVE(de->name, slen - 1, UIO_READ, auio, code);
437 AFS_UIOMOVE(bufofzeros,
438 IRIX5_DIRENTSIZE(slen) - (AFS_DIRENT32BASESIZE +
441 if (IRIX5_DIRENTSIZE(slen) < rlen) {
442 while (IRIX5_DIRENTSIZE(slen) < rlen) {
443 int minLen = rlen - IRIX5_DIRENTSIZE(slen);
444 if (minLen > sizeof(bufofzeros))
445 minLen = sizeof(bufofzeros);
446 AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
452 #else /* AFS_SGI_ENV */
453 #if defined(AFS_SUN5_ENV) || (defined(AFS_AIX51_ENV) && defined(AFS_64BIT_KERNEL))
454 direntp = osi_AllocLargeSpace(AFS_LRALLOCSIZ);
455 direntp->d_ino = afs_calc_inum(vc->f.fid.Cell, Volume, ntohl(Vnode));
456 #if defined(AFS_AIX51_ENV) && defined(AFS_64BIT_KERNEL)
457 direntp->d_offset = off;
458 direntp->d_namlen = slen;
460 direntp->d_off = off;
462 direntp->d_reclen = rlen;
463 strcpy(direntp->d_name, de->name);
464 AFS_UIOMOVE((caddr_t) direntp, rlen, UIO_READ, auio, code);
465 osi_FreeLargeSpace((char *)direntp);
466 #else /* AFS_SUN5_ENV */
467 /* Note the odd mechanism for building the inode number */
468 sdirEntry.d_fileno = afs_calc_inum(vc->f.fid.Cell, Volume, ntohl(Vnode));
469 sdirEntry.d_reclen = rlen;
470 #if !defined(AFS_SGI_ENV)
471 sdirEntry.d_namlen = slen;
473 #if defined(AFS_AIX32_ENV) || defined(AFS_SGI_ENV)
474 sdirEntry.d_off = off;
476 #if defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
477 sdirEntry.d_type = afs_readdir_type(vc, de);
480 #if defined(AFS_SGI_ENV)
481 AFS_UIOMOVE(&sdirEntry, DIRENTBASESIZE, UIO_READ, auio, code);
483 AFS_UIOMOVE(de->name, slen - 1, UIO_READ, auio, code);
485 AFS_UIOMOVE(bufofzeros,
486 DIRSIZ_LEN(slen) - (DIRENTBASESIZE + slen - 1), UIO_READ,
488 #else /* AFS_SGI_ENV */
490 #if defined(AFS_NBSD40_ENV)
493 dp = osi_AllocLargeSpace(sizeof(struct dirent));
494 memset(dp, 0, sizeof(struct dirent));
495 dp->d_ino = afs_calc_inum(vc->f.fid.Cell, Volume, ntohl(Vnode));
497 dp->d_type = afs_readdir_type(vc, de);
498 strcpy(dp->d_name, de->name);
499 dp->d_reclen = _DIRENT_SIZE(dp) /* rlen */;
500 if ((afs_debug & AFSDEB_VNLAYER) != 0) {
501 afs_warn("%s: %s type %d slen %d rlen %d act. rlen %zu\n", __func__,
502 dp->d_name, dp->d_type, slen, rlen, _DIRENT_SIZE(dp));
504 AFS_UIOMOVE(dp, dp->d_reclen, UIO_READ, auio, code);
505 osi_FreeLargeSpace((char *)dp);
508 AFS_UIOMOVE((char *) &sdirEntry, sizeof(sdirEntry), UIO_READ, auio, code);
510 AFS_UIOMOVE(de->name, slen, UIO_READ, auio, code);
512 /* pad out the remaining characters with zeros */
514 AFS_UIOMOVE(bufofzeros, ((slen + 1 + DIRPAD) & ~DIRPAD) - slen,
515 UIO_READ, auio, code);
519 #endif /* AFS_SGI_ENV */
520 #if !defined(AFS_NBSD_ENV)
521 /* pad out the difference between rlen and slen... */
522 if (DIRSIZ_LEN(slen) < rlen) {
524 while (DIRSIZ_LEN(slen) < rlen) {
525 int minLen = rlen - DIRSIZ_LEN(slen);
526 if (minLen > sizeof(bufofzeros))
527 minLen = sizeof(bufofzeros);
528 AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
534 #endif /* AFS_SUN5_ENV */
535 #endif /* AFS_SGI_ENV */
541 *------------------------------------------------------------------------------
543 * Read directory entries.
544 * There are some weird things to look out for here. The uio_offset
545 * field is either 0 or it is the offset returned from a previous
546 * readdir. It is an opaque value used by the server to find the
547 * correct directory block to read. The byte count must be at least
548 * vtoblksz(vp) bytes. The count field is the number of blocks to
549 * read on the server. This is advisory only, the server may return
550 * only one block's worth of entries. Entries may be compressed on
553 * This routine encodes knowledge of Vice dirs.
557 afs_bulkstat_send(struct vcache *avc, struct vrequest *req)
563 * Here is the bad, bad, really bad news.
564 * It has to do with 'offset' (seek locations).
568 #if defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
569 afs_readdir(OSI_VC_DECL(avc), struct uio *auio, afs_ucred_t *acred,
572 #if defined(AFS_HPUX100_ENV)
573 afs_readdir2(OSI_VC_DECL(avc), struct uio *auio, afs_ucred_t *acred)
575 afs_readdir(OSI_VC_DECL(avc), struct uio *auio, afs_ucred_t *acred)
579 struct vrequest *treq = NULL;
581 afs_size_t origOffset, tlen;
584 struct DirBuffer oldEntry, nextEntry;
585 struct DirEntry *ode = 0, *nde = 0;
586 int o_slen = 0, n_slen = 0;
588 struct afs_fakestat_state fakestate;
589 #if defined(AFS_SGI_ENV)
590 afs_int32 use64BitDirent, dirsiz;
591 #endif /* defined(AFS_SGI_ENV) */
596 * XXX All the hacks for alloced sdirEntry and inlining of afs_readdir_move instead of calling
597 * it is necessary for hpux due to stack problems that seem to occur when coming thru the nfs
598 * translator side XXX
600 struct min_direct *sdirEntry = osi_AllocSmallSpace(sizeof(struct min_direct));
604 /* opaque value is pointer into a vice dir; use bit map to decide
605 * if the entries are in use. Always assumed to be valid. 0 is
606 * special, means start of a new dir. Int32 inode, followed by
607 * short reclen and short namelen. Namelen does not include
608 * the null byte. Followed by null-terminated string.
610 AFS_STATCNT(afs_readdir);
612 memset(&oldEntry, 0, sizeof(struct DirBuffer));
613 memset(&nextEntry, 0, sizeof(struct DirBuffer));
615 #if defined(AFS_SGI_ENV)
617 ABI_IS(ABI_IRIX5_64, GETDENTS_ABI(OSI_GET_CURRENT_ABI(), auio));
618 #endif /* defined(AFS_SGI_ENV) */
620 #if defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
621 /* Not really used by the callee so we ignore it for now */
625 #ifndef AFS_64BIT_CLIENT
626 if (AfsLargeFileUio(auio) /* file is large than 2 GB */
627 ||AfsLargeFileSize(AFS_UIO_OFFSET(auio), AFS_UIO_RESID(auio)))
631 if ((code = afs_CreateReq(&treq, acred))) {
633 osi_FreeSmallSpace((char *)sdirEntry);
637 /* update the cache entry */
638 afs_InitFakeStat(&fakestate);
642 code = afs_EvalFakeStat(&avc, &fakestate, treq);
646 code = afs_VerifyVCache(avc, treq);
649 /* get a reference to the entire directory */
650 tdc = afs_GetDCache(avc, (afs_size_t) 0, treq, &origOffset, &tlen, 1);
655 ObtainReadLock(&avc->lock);
656 ObtainReadLock(&tdc->lock);
659 * Make sure that the data in the cache is current. There are two
660 * cases we need to worry about:
661 * 1. The cache data is being fetched by another process.
662 * 2. The cache data is no longer valid
664 while ((avc->f.states & CStatd)
665 && (tdc->dflags & DFFetching)
666 && afs_IsDCacheFresh(tdc, avc)) {
667 afs_Trace4(afs_iclSetp, CM_TRACE_DCACHEWAIT, ICL_TYPE_STRING,
668 __FILE__, ICL_TYPE_INT32, __LINE__, ICL_TYPE_POINTER, tdc,
669 ICL_TYPE_INT32, tdc->dflags);
670 ReleaseReadLock(&tdc->lock);
671 ReleaseReadLock(&avc->lock);
672 afs_osi_Sleep(&tdc->validPos);
673 ObtainReadLock(&avc->lock);
674 ObtainReadLock(&tdc->lock);
676 if (!(avc->f.states & CStatd)
677 || !afs_IsDCacheFresh(tdc, avc)) {
678 ReleaseReadLock(&tdc->lock);
679 ReleaseReadLock(&avc->lock);
685 * iterator for the directory reads. Takes the AFS DirEntry
686 * structure and slams them into UFS direct structures.
687 * uses afs_readdir_move to get the struct to the user space.
689 * The routine works by looking ahead one AFS directory entry.
690 * That's because the AFS entry we are currenly working with
691 * may not fit into the buffer the user has provided. If it
692 * doesn't we have to change the size of the LAST AFS directory
693 * entry, so that it will FIT perfectly into the block the
696 * The 'forward looking' of the code makes it a bit tough to read.
697 * Remember we need to get an entry, see if it it fits, then
698 * set it up as the LAST entry, and find the next one.
700 * Tough to take: We give out an EINVAL if we don't have enough
701 * space in the buffer, and at the same time, don't have an entry
702 * to put into the buffer. This CAN happen if the first AFS entry
703 * we get can't fit into the 512 character buffer provided. Seems
704 * it ought not happen...
706 * Assumption: don't need to use anything but one dc entry:
707 * this means the directory ought not be greater than 64k.
711 auio->uio_fpflags = 0;
714 origOffset = AFS_UIO_OFFSET(auio);
715 /* scan for the next interesting entry scan for in-use blob otherwise up point at
716 * this blob note that ode, if non-zero, also represents a held dir page */
717 code = BlobScan(tdc, (origOffset >> 5), &us);
720 code = afs_dir_GetVerifiedBlob(tdc, us, &nextEntry);
722 if (us == 0 || code != 0) {
723 code = 0; /* Reset code - keep old failure behaviour */
724 /* failed to setup nde, return what we've got, and release ode */
726 /* something to hand over. */
728 sdirEntry->d_fileno = afs_calc_inum(avc->f.fid.Cell,
729 avc->f.fid.Fid.Volume,
730 ntohl(ode->fid.vnode));
731 sdirEntry->d_reclen = rlen = AFS_UIO_RESID(auio);
732 sdirEntry->d_namlen = o_slen;
733 #if defined(AFS_SUN5_ENV) || defined(AFS_AIX32_ENV) || defined(AFS_HPUX100_ENV)
734 sdirEntry->d_off = origOffset;
736 AFS_UIOMOVE((char *)sdirEntry, sizeof(*sdirEntry), UIO_READ,
739 AFS_UIOMOVE(ode->name, o_slen, UIO_READ, auio, code);
740 /* pad out the remaining characters with zeros */
742 AFS_UIOMOVE(bufofzeros,
743 ((o_slen + 1 + DIRPAD) & ~DIRPAD) - o_slen,
744 UIO_READ, auio, code);
746 /* pad out the difference between rlen and slen... */
747 if (DIRSIZ_LEN(o_slen) < rlen) {
748 while (DIRSIZ_LEN(o_slen) < rlen) {
749 int minLen = rlen - DIRSIZ_LEN(o_slen);
750 if (minLen > sizeof(bufofzeros))
751 minLen = sizeof(bufofzeros);
752 AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
757 code = afs_readdir_move(ode, avc, auio, o_slen,
758 #if defined(AFS_SUN5_ENV) || defined(AFS_NBSD_ENV)
761 AFS_UIO_RESID(auio), origOffset);
763 #endif /* AFS_HPUX_ENV */
764 #if !defined(AFS_SUN5_ENV) && !defined(AFS_NBSD_ENV)
765 AFS_UIO_SETRESID(auio, 0);
768 /* nothin to hand over */
770 #if defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
772 *eofp = 1; /* Set it properly */
774 DRelease(&oldEntry, 0);
777 nde = (struct DirEntry *)nextEntry.data;
779 /* Do we have enough user space to carry out our mission? */
780 #if defined(AFS_SGI_ENV)
781 n_slen = strlen(nde->name) + 1; /* NULL terminate */
783 n_slen = strlen(nde->name);
787 use64BitDirent ? DIRENTSIZE(n_slen) : IRIX5_DIRENTSIZE(n_slen);
788 if (dirsiz >= (AFS_UIO_RESID(auio) - len)) {
790 if (DIRSIZ_LEN(n_slen) >= (AFS_UIO_RESID(auio) - len)) {
791 #endif /* AFS_SGI_ENV */
792 /* No can do no more now; ya know... at this time */
793 DRelease(&nextEntry, 0); /* can't use this one. */
796 sdirEntry->d_fileno = afs_calc_inum(avc->f.fid.Cell,
797 avc->f.fid.Fid.Volume,
798 ntohl(ode->fid.vnode));
799 sdirEntry->d_reclen = rlen = AFS_UIO_RESID(auio);
800 sdirEntry->d_namlen = o_slen;
801 #if defined(AFS_SUN5_ENV) || defined(AFS_AIX32_ENV) || defined(AFS_HPUX100_ENV)
802 sdirEntry->d_off = origOffset;
804 AFS_UIOMOVE((char *)sdirEntry, sizeof(*sdirEntry), UIO_READ,
807 AFS_UIOMOVE(ode->name, o_slen, UIO_READ, auio, code);
808 /* pad out the remaining characters with zeros */
810 AFS_UIOMOVE(bufofzeros,
811 ((o_slen + 1 + DIRPAD) & ~DIRPAD) - o_slen,
812 UIO_READ, auio, code);
814 /* pad out the difference between rlen and slen... */
815 if (DIRSIZ_LEN(o_slen) < rlen) {
816 while (DIRSIZ_LEN(o_slen) < rlen) {
817 int minLen = rlen - DIRSIZ_LEN(o_slen);
818 if (minLen > sizeof(bufofzeros))
819 minLen = sizeof(bufofzeros);
820 AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
824 #else /* AFS_HPUX_ENV */
826 afs_readdir_move(ode, avc, auio, o_slen,
827 AFS_UIO_RESID(auio), origOffset);
828 #endif /* AFS_HPUX_ENV */
829 /* this next line used to be AFSVFS40 or AIX 3.1, but is
831 AFS_UIO_SETOFFSET(auio, origOffset);
832 #if !defined(AFS_NBSD_ENV)
833 AFS_UIO_SETRESID(auio, 0);
835 } else { /* trouble, can't give anything to the user! */
836 /* even though he has given us a buffer,
837 * even though we have something to give us,
838 * Looks like we lost something somewhere.
842 DRelease(&oldEntry, 0);
847 * In any event, we move out the LAST de entry, getting ready
848 * to set up for the next one.
852 sdirEntry->d_fileno = afs_calc_inum(avc->f.fid.Cell,
853 avc->f.fid.Fid.Volume,
854 ntohl(ode->fid.vnode));
855 sdirEntry->d_reclen = rlen = len;
856 sdirEntry->d_namlen = o_slen;
857 #if defined(AFS_SUN5_ENV) || defined(AFS_AIX32_ENV) || defined(AFS_HPUX100_ENV)
858 sdirEntry->d_off = origOffset;
860 AFS_UIOMOVE((char *)sdirEntry, sizeof(*sdirEntry), UIO_READ, auio,
863 AFS_UIOMOVE(ode->name, o_slen, UIO_READ, auio, code);
864 /* pad out the remaining characters with zeros */
866 AFS_UIOMOVE(bufofzeros,
867 ((o_slen + 1 + DIRPAD) & ~DIRPAD) - o_slen,
868 UIO_READ, auio, code);
870 /* pad out the difference between rlen and slen... */
871 if (DIRSIZ_LEN(o_slen) < rlen) {
872 while (DIRSIZ_LEN(o_slen) < rlen) {
873 int minLen = rlen - DIRSIZ_LEN(o_slen);
874 if (minLen > sizeof(bufofzeros))
875 minLen = sizeof(bufofzeros);
876 AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
880 #else /* AFS_HPUX_ENV */
881 code = afs_readdir_move(ode, avc, auio, o_slen, len, origOffset);
882 #endif /* AFS_HPUX_ENV */
885 len = use64BitDirent ? DIRENTSIZE(o_slen =
886 n_slen) : IRIX5_DIRENTSIZE(o_slen =
889 len = DIRSIZ_LEN(o_slen = n_slen);
890 #endif /* AFS_SGI_ENV */
892 DRelease(&oldEntry, 0);
893 oldEntry = nextEntry;
895 AFS_UIO_SETOFFSET(auio, (us + afs_dir_NameBlobs(nde->name)) << 5);
898 DRelease(&oldEntry, 0);
901 ReleaseReadLock(&tdc->lock);
903 ReleaseReadLock(&avc->lock);
907 osi_FreeSmallSpace((char *)sdirEntry);
910 afs_PutFakeStat(&fakestate);
911 code = afs_CheckCode(code, treq, 28);
912 afs_DestroyReq(treq);
916 #endif /* !AFS_LINUX_ENV */