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"
34 #if defined(AFS_HPUX1122_ENV)
41 * AFS readdir vnodeop and bulk stat support.
44 /* Saber C hates negative inode #s. We're not going to talk about software
45 * that could fail if it sees a negative inode #.
47 #define FIXUPSTUPIDINODE(a) ((a) &= 0x7fffffff)
49 /* BlobScan is supposed to ensure that the blob reference refers to a valid
50 directory entry. It consults the allocation map in the page header
51 to determine whether a blob is actually in use or not.
53 More formally, BlobScan is supposed to return a new blob number which is just like
54 the input parameter, only it is advanced over header or free blobs.
56 Note that BlobScan switches pages if necessary. BlobScan may return
57 either 0 or an out-of-range blob number for end of file.
59 BlobScan is used by the Linux port in a separate file, so it should not
63 BlobScan(struct dcache * afile, afs_int32 ablob)
65 register afs_int32 relativeBlob;
67 register struct PageHeader *tpe;
70 AFS_STATCNT(BlobScan);
71 /* advance ablob over free and header blobs */
73 pageBlob = ablob & ~(EPP - 1); /* base blob in same page */
74 tpe = (struct PageHeader *)afs_dir_GetBlob(afile, pageBlob);
76 return 0; /* we've past the end */
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). */
97 ablob = pageBlob + EPP; /* go around again */
102 #if !defined(AFS_LINUX20_ENV)
103 /* Changes to afs_readdir which affect dcache or vcache handling or use of
104 * bulk stat data should also be reflected in the Linux specific verison of
105 * the readdir routine.
109 * The kernel don't like it so much to have large stuff on the stack.
110 * Here we use a watered down version of the direct struct, since
111 * its not too bright to double copy the strings anyway.
113 #if !defined(UKERNEL)
114 #if defined(AFS_SGI_ENV)
115 /* Long form for 64 bit apps and kernel requests. */
116 struct min_dirent { /* miniature dirent structure */
117 /* If struct dirent changes, this must too */
118 ino_t d_fileno; /* This is 32 bits for 3.5, 64 for 6.2+ */
122 /* Short form for 32 bit apps. */
123 struct irix5_min_dirent { /* miniature dirent structure */
124 /* If struct dirent changes, this must too */
130 #define AFS_DIRENT32BASESIZE IRIX5_DIRENTBASESIZE
131 #define AFS_DIRENT64BASESIZE DIRENT64BASESIZE
133 #define AFS_DIRENT32BASESIZE IRIX5_DIRENTBASESIZE
134 #define AFS_DIRENT64BASESIZE DIRENTBASESIZE
135 #endif /* AFS_SGI62_ENV */
137 struct min_direct { /* miniature direct structure */
138 /* If struct direct changes, this must too */
139 #if defined(AFS_DARWIN80_ENV)
144 #elif defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
149 #elif defined(AFS_SUN5_ENV)
154 #if defined(AFS_AIX32_ENV)
156 #elif defined(AFS_HPUX100_ENV)
157 unsigned long long d_off;
164 #endif /* AFS_SGI_ENV */
166 #if defined(AFS_HPUX_ENV)
167 struct minnfs_direct {
168 afs_int32 d_off; /* XXX */
173 #define NDIRSIZ_LEN(len) ((sizeof (struct dirent)+4 - (MAXNAMLEN+1)) + (((len)+1 + DIRPAD) &~ DIRPAD))
175 #endif /* !defined(UKERNEL) */
179 *------------------------------------------------------------------------------
181 * Keep a stack of about 256 fids for the bulk stat call.
182 * Fill it during the readdir_move. Later empty it...
185 #define READDIR_STASH AFSCBMAX
186 struct AFSFid afs_readdir_stash[READDIR_STASH];
187 int afs_rd_stash_i = 0;
190 *------------------------------------------------------------------------------
193 * mainly a kind of macro... makes getting the struct direct
194 * out to the user space easy... could take more parameters,
195 * but now just takes what it needs.
200 #if defined(AFS_HPUX100_ENV)
201 #define DIRSIZ_LEN(len) \
202 ((sizeof (struct __dirent) - (_MAXNAMLEN+1)) + (((len)+1 + DIRPAD) &~ DIRPAD))
204 #if defined(AFS_SUN56_ENV)
205 #define DIRSIZ_LEN(len) ((18 + (len) + 1 + 7) & ~7 )
208 #define DIRSIZ_LEN(len) ((10 + (len) + 1 + (NBPW-1)) & ~(NBPW-1))
211 #define DIRSIZ_LEN(len) \
212 ((sizeof (struct dirent) - (MAXNAMLEN+1)) + (((len)+1 + 3) &~ 3))
214 #if defined(AFS_SGI_ENV)
215 #ifndef AFS_SGI53_ENV
216 /* SGI 5.3 and later use 32/64 bit versions of directory size. */
217 #define DIRSIZ_LEN(len) DIRENTSIZE(len)
219 #else /* AFS_SGI_ENV */
220 #define DIRSIZ_LEN(len) \
221 ((sizeof (struct direct) - (MAXNAMLEN+1)) + (((len)+1 + 3) &~ 3))
222 #endif /* AFS_SGI_ENV */
223 #endif /* AFS_DIRENT */
224 #endif /* AFS_SUN5_ENV */
225 #endif /* AFS_SUN56_ENV */
226 #endif /* AFS_HPUX100_ENV */
228 #if defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
230 afs_readdir_type(struct vcache *avc, struct DirEntry *ade)
232 struct VenusFid tfid;
235 tfid.Cell = avc->f.fid.Cell;
236 tfid.Fid.Volume = avc->f.fid.Fid.Volume;
237 tfid.Fid.Vnode = ntohl(ade->fid.vnode);
238 tfid.Fid.Unique = ntohl(ade->fid.vunique);
239 if ((avc->f.states & CForeign) == 0 && (ntohl(ade->fid.vnode) & 1)) {
242 ObtainReadLock(&afs_xvcache);
243 if ((tvc = afs_FindVCache(&tfid, 0, 0))) {
244 ReleaseReadLock(&afs_xvcache);
248 } else if (((tvc->f.states) & (CStatd | CTruth))) {
249 /* CTruth will be set if the object has
255 else if (vtype == VREG)
257 /* Don't do this until we're sure it can't be a mtpt */
258 /* if we're CStatd and CTruth and mvstat==0, it's a link */
259 else if (vtype == VLNK)
261 /* what other types does AFS support? */
265 ReleaseReadLock(&afs_xvcache);
271 #define AFS_MOVE_LOCK() AFS_GLOCK()
272 #define AFS_MOVE_UNLOCK() AFS_GUNLOCK()
274 #define AFS_MOVE_LOCK()
275 #define AFS_MOVE_UNLOCK()
277 char bufofzeros[64]; /* gotta fill with something */
281 afs_readdir_move(struct DirEntry *de, struct vcache *vc, struct uio *auio,
282 int slen, ssize_t rlen, afs_size_t off)
285 afs_readdir_move(struct DirEntry *de, struct vcache *vc, struct uio *auio,
286 int slen, int rlen, afs_size_t off)
291 afs_uint32 Volume = vc->f.fid.Fid.Volume;
292 afs_uint32 Vnode = de->fid.vnode;
293 #if defined(AFS_SUN56_ENV)
294 struct dirent64 *direntp;
296 #if defined(AFS_SUN5_ENV) || (defined(AFS_AIX51_ENV) && defined(AFS_64BIT_KERNEL))
297 struct dirent *direntp;
299 #endif /* AFS_SUN56_ENV */
300 #ifndef AFS_SGI53_ENV
301 struct min_direct sdirEntry;
302 #endif /* AFS_SGI53_ENV */
304 AFS_STATCNT(afs_readdir_move);
306 #define READDIR_CORRECT_INUMS
307 #ifdef READDIR_CORRECT_INUMS
308 if (de->name[0] == '.' && !de->name[1]) {
309 /* This is the '.' entry; if we are a volume root, we need to
310 * ignore the directory and use the inum for the mount point.
312 if (!FidCmp(&afs_rootFid, &vc->f.fid)) {
315 } else if (vc->mvstat == 2) {
316 tvp = afs_GetVolume(&vc->f.fid, 0, READ_LOCK);
318 Volume = tvp->mtpoint.Fid.Volume;
319 Vnode = tvp->mtpoint.Fid.Vnode;
320 afs_PutVolume(tvp, READ_LOCK);
324 else if (de->name[0] == '.' && de->name[1] == '.' && !de->name[2]) {
325 /* This is the '..' entry. Getting this right is very tricky,
326 * because we might be a volume root (so our parent is in a
327 * different volume), or our parent might be a volume root
328 * (so we actually want the mount point) or BOTH! */
329 if (!FidCmp(&afs_rootFid, &vc->f.fid)) {
330 /* We are the root of the AFS root, and thus our own parent */
333 } else if (vc->mvstat == 2) {
334 /* We are a volume root, which means our parent is in another
335 * volume. Luckily, we should have his fid cached... */
337 if (!FidCmp(&afs_rootFid, vc->mvid)) {
338 /* Parent directory is the root of the AFS root */
341 } else if (vc->mvid->Fid.Vnode == 1
342 && vc->mvid->Fid.Unique == 1) {
343 /* XXX The above test is evil and probably breaks DFS */
344 /* Parent directory is the target of a mount point */
345 tvp = afs_GetVolume(vc->mvid, 0, READ_LOCK);
347 Volume = tvp->mtpoint.Fid.Volume;
348 Vnode = tvp->mtpoint.Fid.Vnode;
349 afs_PutVolume(tvp, READ_LOCK);
352 /* Parent directory is not a volume root */
353 Volume = vc->mvid->Fid.Volume;
354 Vnode = vc->mvid->Fid.Vnode;
357 } else if (de->fid.vnode == 1 && de->fid.vunique == 1) {
358 /* XXX The above test is evil and probably breaks DFS */
359 /* Parent directory is a volume root; use the right inum */
360 tvp = afs_GetVolume(&vc->f.fid, 0, READ_LOCK);
362 if (tvp->cell == afs_rootFid.Cell
363 && tvp->volume == afs_rootFid.Fid.Volume) {
364 /* Parent directory is the root of the AFS root */
368 /* Parent directory is the target of a mount point */
369 Volume = tvp->mtpoint.Fid.Volume;
370 Vnode = tvp->mtpoint.Fid.Vnode;
372 afs_PutVolume(tvp, READ_LOCK);
380 afs_int32 use64BitDirent;
385 ABI_IS(ABI_IRIX5_64, GETDENTS_ABI(OSI_GET_CURRENT_ABI(), auio));
389 UIO_USERSPACE) ? ABI_IRIX5_64 : (ABI_IS(ABI_IRIX5_64 |
393 #else /* AFS_SGI61_ENV */
396 UIO_USERSPACE) ? ABI_IRIX5_64 : (ABI_IS(ABI_IRIX5_64,
398 #endif /* AFS_SGI61_ENV */
400 if (use64BitDirent) {
401 struct min_dirent sdirEntry;
402 sdirEntry.d_fileno = (Volume << 16) + ntohl(Vnode);
403 FIXUPSTUPIDINODE(sdirEntry.d_fileno);
404 sdirEntry.d_reclen = rlen;
405 sdirEntry.d_off = (off_t) off;
406 AFS_UIOMOVE(&sdirEntry, AFS_DIRENT64BASESIZE, UIO_READ, auio,
409 AFS_UIOMOVE(de->name, slen - 1, UIO_READ, auio, code);
411 AFS_UIOMOVE(bufofzeros,
412 DIRENTSIZE(slen) - (AFS_DIRENT64BASESIZE + slen -
413 1), UIO_READ, auio, code);
414 if (DIRENTSIZE(slen) < rlen) {
415 while (DIRENTSIZE(slen) < rlen) {
416 int minLen = rlen - DIRENTSIZE(slen);
417 if (minLen > sizeof(bufofzeros))
418 minLen = sizeof(bufofzeros);
419 AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
424 struct irix5_min_dirent sdirEntry;
425 sdirEntry.d_fileno = (Volume << 16) + ntohl(Vnode);
426 FIXUPSTUPIDINODE(sdirEntry.d_fileno);
427 sdirEntry.d_reclen = rlen;
428 sdirEntry.d_off = (afs_int32) off;
429 AFS_UIOMOVE(&sdirEntry, AFS_DIRENT32BASESIZE, UIO_READ, auio,
432 AFS_UIOMOVE(de->name, slen - 1, UIO_READ, auio, code);
434 AFS_UIOMOVE(bufofzeros,
435 IRIX5_DIRENTSIZE(slen) - (AFS_DIRENT32BASESIZE +
438 if (IRIX5_DIRENTSIZE(slen) < rlen) {
439 while (IRIX5_DIRENTSIZE(slen) < rlen) {
440 int minLen = rlen - IRIX5_DIRENTSIZE(slen);
441 if (minLen > sizeof(bufofzeros))
442 minLen = sizeof(bufofzeros);
443 AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
449 #else /* AFS_SGI53_ENV */
450 #if defined(AFS_SUN5_ENV) || (defined(AFS_AIX51_ENV) && defined(AFS_64BIT_KERNEL))
451 #if defined(AFS_SUN56_ENV)
452 direntp = (struct dirent64 *)osi_AllocLargeSpace(AFS_LRALLOCSIZ);
454 direntp = (struct dirent *)osi_AllocLargeSpace(AFS_LRALLOCSIZ);
456 direntp->d_ino = (Volume << 16) + ntohl(Vnode);
457 FIXUPSTUPIDINODE(direntp->d_ino);
458 #if defined(AFS_AIX51_ENV) && defined(AFS_64BIT_KERNEL)
459 direntp->d_offset = off;
460 direntp->d_namlen = slen;
462 direntp->d_off = off;
464 direntp->d_reclen = rlen;
465 strcpy(direntp->d_name, de->name);
466 AFS_UIOMOVE((caddr_t) direntp, rlen, UIO_READ, auio, code);
467 osi_FreeLargeSpace((char *)direntp);
468 #else /* AFS_SUN5_ENV */
469 /* Note the odd mechanism for building the inode number */
470 sdirEntry.d_fileno = (Volume << 16) + ntohl(Vnode);
471 FIXUPSTUPIDINODE(sdirEntry.d_fileno);
472 sdirEntry.d_reclen = rlen;
473 #if !defined(AFS_SGI_ENV)
474 sdirEntry.d_namlen = slen;
476 #if defined(AFS_AIX32_ENV) || defined(AFS_SGI_ENV)
477 sdirEntry.d_off = off;
479 #if defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
480 sdirEntry.d_type = afs_readdir_type(vc, de);
483 #if defined(AFS_SGI_ENV)
484 AFS_UIOMOVE(&sdirEntry, DIRENTBASESIZE, UIO_READ, auio, code);
486 AFS_UIOMOVE(de->name, slen - 1, UIO_READ, auio, code);
488 AFS_UIOMOVE(bufofzeros,
489 DIRSIZ_LEN(slen) - (DIRENTBASESIZE + slen - 1), UIO_READ,
491 #else /* AFS_SGI_ENV */
493 AFS_UIOMOVE((char *)&sdirEntry, sizeof(sdirEntry), UIO_READ, auio, code);
496 AFS_UIOMOVE(de->name, slen, UIO_READ, auio, code);
499 /* pad out the remaining characters with zeros */
501 AFS_UIOMOVE(bufofzeros, ((slen + 1 + DIRPAD) & ~DIRPAD) - slen,
502 UIO_READ, auio, code);
505 #endif /* AFS_SGI_ENV */
507 /* pad out the difference between rlen and slen... */
508 if (DIRSIZ_LEN(slen) < rlen) {
510 while (DIRSIZ_LEN(slen) < rlen) {
511 int minLen = rlen - DIRSIZ_LEN(slen);
512 if (minLen > sizeof(bufofzeros))
513 minLen = sizeof(bufofzeros);
514 AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
519 #endif /* AFS_SUN5_ENV */
520 #endif /* AFS_SGI53_ENV */
526 *------------------------------------------------------------------------------
528 * Read directory entries.
529 * There are some weird things to look out for here. The uio_offset
530 * field is either 0 or it is the offset returned from a previous
531 * readdir. It is an opaque value used by the server to find the
532 * correct directory block to read. The byte count must be at least
533 * vtoblksz(vp) bytes. The count field is the number of blocks to
534 * read on the server. This is advisory only, the server may return
535 * only one block's worth of entries. Entries may be compressed on
538 * This routine encodes knowledge of Vice dirs.
542 afs_bulkstat_send(struct vcache *avc, struct vrequest *req)
548 * Here is the bad, bad, really bad news.
549 * It has to do with 'offset' (seek locations).
553 #if defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
554 afs_readdir(OSI_VC_DECL(avc), struct uio *auio, afs_ucred_t *acred,
557 #if defined(AFS_HPUX100_ENV)
558 afs_readdir2(OSI_VC_DECL(avc), struct uio *auio, afs_ucred_t *acred)
560 afs_readdir(OSI_VC_DECL(avc), struct uio *auio, afs_ucred_t *acred)
564 struct vrequest treq;
565 register struct dcache *tdc;
566 afs_size_t origOffset, tlen;
569 struct DirEntry *ode = 0, *nde = 0;
570 int o_slen = 0, n_slen = 0;
572 struct afs_fakestat_state fakestate;
573 #if defined(AFS_SGI53_ENV)
574 afs_int32 use64BitDirent, dirsiz;
575 #endif /* defined(AFS_SGI53_ENV) */
580 * XXX All the hacks for alloced sdirEntry and inlining of afs_readdir_move instead of calling
581 * it is necessary for hpux due to stack problems that seem to occur when coming thru the nfs
582 * translator side XXX
584 struct min_direct *sdirEntry =
585 (struct min_direct *)osi_AllocSmallSpace(sizeof(struct min_direct));
589 /* opaque value is pointer into a vice dir; use bit map to decide
590 * if the entries are in use. Always assumed to be valid. 0 is
591 * special, means start of a new dir. Int32 inode, followed by
592 * short reclen and short namelen. Namelen does not include
593 * the null byte. Followed by null-terminated string.
595 AFS_STATCNT(afs_readdir);
597 #if defined(AFS_SGI53_ENV)
601 ABI_IS(ABI_IRIX5_64, GETDENTS_ABI(OSI_GET_CURRENT_ABI(), auio));
605 UIO_USERSPACE) ? ABI_IRIX5_64 : (ABI_IS(ABI_IRIX5_64 | ABI_IRIX5_N32,
607 #endif /* AFS_SGI62_ENV */
608 #else /* AFS_SGI61_ENV */
611 UIO_USERSPACE) ? ABI_IRIX5_64 : (ABI_IS(ABI_IRIX5_64,
613 #endif /* AFS_SGI61_ENV */
614 #endif /* defined(AFS_SGI53_ENV) */
616 #if defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
617 /* Not really used by the callee so we ignore it for now */
621 #ifndef AFS_64BIT_CLIENT
622 if (AfsLargeFileUio(auio) /* file is large than 2 GB */
623 ||AfsLargeFileSize(AFS_UIO_OFFSET(auio), AFS_UIO_RESID(auio)))
627 if ((code = afs_InitReq(&treq, acred))) {
629 osi_FreeSmallSpace((char *)sdirEntry);
633 /* update the cache entry */
634 afs_InitFakeStat(&fakestate);
638 code = afs_EvalFakeStat(&avc, &fakestate, &treq);
642 code = afs_VerifyVCache(avc, &treq);
645 /* get a reference to the entire directory */
646 tdc = afs_GetDCache(avc, (afs_size_t) 0, &treq, &origOffset, &tlen, 1);
652 ObtainReadLock(&avc->lock);
653 ObtainReadLock(&tdc->lock);
656 * Make sure that the data in the cache is current. There are two
657 * cases we need to worry about:
658 * 1. The cache data is being fetched by another process.
659 * 2. The cache data is no longer valid
661 while ((avc->f.states & CStatd)
662 && (tdc->dflags & DFFetching)
663 && hsame(avc->f.m.DataVersion, tdc->f.versionNo)) {
664 afs_Trace4(afs_iclSetp, CM_TRACE_DCACHEWAIT, ICL_TYPE_STRING,
665 __FILE__, ICL_TYPE_INT32, __LINE__, ICL_TYPE_POINTER, tdc,
666 ICL_TYPE_INT32, tdc->dflags);
667 ReleaseReadLock(&tdc->lock);
668 ReleaseReadLock(&avc->lock);
669 afs_osi_Sleep(&tdc->validPos);
670 ObtainReadLock(&avc->lock);
671 ObtainReadLock(&tdc->lock);
673 if (!(avc->f.states & CStatd)
674 || !hsame(avc->f.m.DataVersion, tdc->f.versionNo)) {
675 ReleaseReadLock(&tdc->lock);
676 ReleaseReadLock(&avc->lock);
682 * iterator for the directory reads. Takes the AFS DirEntry
683 * structure and slams them into UFS direct structures.
684 * uses afs_readdir_move to get the struct to the user space.
686 * The routine works by looking ahead one AFS directory entry.
687 * That's because the AFS entry we are currenly working with
688 * may not fit into the buffer the user has provided. If it
689 * doesn't we have to change the size of the LAST AFS directory
690 * entry, so that it will FIT perfectly into the block the
693 * The 'forward looking' of the code makes it a bit tough to read.
694 * Remember we need to get an entry, see if it it fits, then
695 * set it up as the LAST entry, and find the next one.
697 * Tough to take: We give out an EINVAL if we don't have enough
698 * space in the buffer, and at the same time, don't have an entry
699 * to put into the buffer. This CAN happen if the first AFS entry
700 * we get can't fit into the 512 character buffer provided. Seems
701 * it ought not happen...
703 * Assumption: don't need to use anything but one dc entry:
704 * this means the directory ought not be greater than 64k.
708 auio->uio_fpflags = 0;
711 origOffset = AFS_UIO_OFFSET(auio);
712 /* scan for the next interesting entry scan for in-use blob otherwise up point at
713 * this blob note that ode, if non-zero, also represents a held dir page */
714 if (!(us = BlobScan(tdc, (origOffset >> 5)))
715 || !(nde = (struct DirEntry *)afs_dir_GetBlob(tdc, us))) {
716 /* failed to setup nde, return what we've got, and release ode */
718 /* something to hand over. */
720 sdirEntry->d_fileno =
721 (avc->f.fid.Fid.Volume << 16) + ntohl(ode->fid.vnode);
722 FIXUPSTUPIDINODE(sdirEntry->d_fileno);
723 sdirEntry->d_reclen = rlen = AFS_UIO_RESID(auio);
724 sdirEntry->d_namlen = o_slen;
725 #if defined(AFS_SUN5_ENV) || defined(AFS_AIX32_ENV) || defined(AFS_HPUX100_ENV)
726 sdirEntry->d_off = origOffset;
728 AFS_UIOMOVE((char *)sdirEntry, sizeof(*sdirEntry), UIO_READ,
731 AFS_UIOMOVE(ode->name, o_slen, UIO_READ, auio, code);
732 /* pad out the remaining characters with zeros */
734 AFS_UIOMOVE(bufofzeros,
735 ((o_slen + 1 + DIRPAD) & ~DIRPAD) - o_slen,
736 UIO_READ, auio, code);
738 /* pad out the difference between rlen and slen... */
739 if (DIRSIZ_LEN(o_slen) < rlen) {
740 while (DIRSIZ_LEN(o_slen) < rlen) {
741 int minLen = rlen - DIRSIZ_LEN(o_slen);
742 if (minLen > sizeof(bufofzeros))
743 minLen = sizeof(bufofzeros);
744 AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
749 code = afs_readdir_move(ode, avc, auio, o_slen,
750 #if defined(AFS_SUN5_ENV)
753 AFS_UIO_RESID(auio), origOffset);
755 #endif /* AFS_HPUX_ENV */
756 #if !defined(AFS_SUN5_ENV)
757 AFS_UIO_SETRESID(auio, 0);
760 /* nothin to hand over */
762 #if defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
764 *eofp = 1; /* Set it properly */
770 /* by here nde is set */
772 /* Do we have enough user space to carry out our mission? */
773 #if defined(AFS_SGI_ENV)
774 n_slen = strlen(nde->name) + 1; /* NULL terminate */
776 n_slen = strlen(nde->name);
780 use64BitDirent ? DIRENTSIZE(n_slen) : IRIX5_DIRENTSIZE(n_slen);
781 if (dirsiz >= (AFS_UIO_RESID(auio) - len)) {
783 if (DIRSIZ_LEN(n_slen) >= (AFS_UIO_RESID(auio) - len)) {
784 #endif /* AFS_SGI53_ENV */
785 /* No can do no more now; ya know... at this time */
786 DRelease(nde, 0); /* can't use this one. */
789 sdirEntry->d_fileno =
790 (avc->f.fid.Fid.Volume << 16) + ntohl(ode->fid.vnode);
791 FIXUPSTUPIDINODE(sdirEntry->d_fileno);
792 sdirEntry->d_reclen = rlen = AFS_UIO_RESID(auio);
793 sdirEntry->d_namlen = o_slen;
794 #if defined(AFS_SUN5_ENV) || defined(AFS_AIX32_ENV) || defined(AFS_HPUX100_ENV)
795 sdirEntry->d_off = origOffset;
797 AFS_UIOMOVE((char *)sdirEntry, sizeof(*sdirEntry), UIO_READ,
800 AFS_UIOMOVE(ode->name, o_slen, UIO_READ, auio, code);
801 /* pad out the remaining characters with zeros */
803 AFS_UIOMOVE(bufofzeros,
804 ((o_slen + 1 + DIRPAD) & ~DIRPAD) - o_slen,
805 UIO_READ, auio, code);
807 /* pad out the difference between rlen and slen... */
808 if (DIRSIZ_LEN(o_slen) < rlen) {
809 while (DIRSIZ_LEN(o_slen) < rlen) {
810 int minLen = rlen - DIRSIZ_LEN(o_slen);
811 if (minLen > sizeof(bufofzeros))
812 minLen = sizeof(bufofzeros);
813 AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
817 #else /* AFS_HPUX_ENV */
819 afs_readdir_move(ode, avc, auio, o_slen,
820 AFS_UIO_RESID(auio), origOffset);
821 #endif /* AFS_HPUX_ENV */
822 /* this next line used to be AFSVFS40 or AIX 3.1, but is
824 AFS_UIO_SETOFFSET(auio, origOffset);
825 AFS_UIO_SETRESID(auio, 0);
826 } else { /* trouble, can't give anything to the user! */
827 /* even though he has given us a buffer,
828 * even though we have something to give us,
829 * Looks like we lost something somewhere.
839 * In any event, we move out the LAST de entry, getting ready
840 * to set up for the next one.
844 sdirEntry->d_fileno =
845 (avc->f.fid.Fid.Volume << 16) + ntohl(ode->fid.vnode);
846 FIXUPSTUPIDINODE(sdirEntry->d_fileno);
847 sdirEntry->d_reclen = rlen = len;
848 sdirEntry->d_namlen = o_slen;
849 #if defined(AFS_SUN5_ENV) || defined(AFS_AIX32_ENV) || defined(AFS_HPUX100_ENV)
850 sdirEntry->d_off = origOffset;
852 AFS_UIOMOVE((char *)sdirEntry, sizeof(*sdirEntry), UIO_READ, auio,
855 AFS_UIOMOVE(ode->name, o_slen, UIO_READ, auio, code);
856 /* pad out the remaining characters with zeros */
858 AFS_UIOMOVE(bufofzeros,
859 ((o_slen + 1 + DIRPAD) & ~DIRPAD) - o_slen,
860 UIO_READ, auio, code);
862 /* pad out the difference between rlen and slen... */
863 if (DIRSIZ_LEN(o_slen) < rlen) {
864 while (DIRSIZ_LEN(o_slen) < rlen) {
865 int minLen = rlen - DIRSIZ_LEN(o_slen);
866 if (minLen > sizeof(bufofzeros))
867 minLen = sizeof(bufofzeros);
868 AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
872 #else /* AFS_HPUX_ENV */
873 code = afs_readdir_move(ode, avc, auio, o_slen, len, origOffset);
874 #endif /* AFS_HPUX_ENV */
877 len = use64BitDirent ? DIRENTSIZE(o_slen =
878 n_slen) : IRIX5_DIRENTSIZE(o_slen =
881 len = DIRSIZ_LEN(o_slen = n_slen);
882 #endif /* AFS_SGI53_ENV */
886 AFS_UIO_SETOFFSET(auio, (afs_int32) ((us + afs_dir_NameBlobs(nde->name)) << 5));
892 ReleaseReadLock(&tdc->lock);
894 ReleaseReadLock(&avc->lock);
898 osi_FreeSmallSpace((char *)sdirEntry);
901 afs_PutFakeStat(&fakestate);
902 code = afs_CheckCode(code, &treq, 28);
906 #if defined(AFS_HPUX_ENV)
908 afs1_readdir(struct vcache *avc, struct uio *auio, afs_ucred_t *acred)
910 struct vrequest treq;
911 register struct dcache *tdc;
912 afs_size_t origOffset, len;
914 struct DirEntry *ode = 0, *nde = 0;
915 int o_slen = 0, n_slen = 0;
918 * XXX All the hacks for alloced sdirEntry and inlining of
919 * afs_readdir_move instead of calling it is necessary for hpux due to
920 * stack problems that seem to occur when coming thru the nfs
921 * translator side XXX
923 struct minnfs_direct *sdirEntry = (struct minnfs_direct *)
924 osi_AllocSmallSpace(sizeof(struct min_direct));
927 struct afs_fakestat_state fakestate;
929 AFS_STATCNT(afs_readdir);
930 if (code = afs_InitReq(&treq, acred)) {
931 osi_FreeSmallSpace((char *)sdirEntry);
934 afs_InitFakeStat(&fakestate);
936 code = afs_EvalFakeStat(&avc, &fakestate, &treq);
938 osi_FreeSmallSpace((char *)sdirEntry);
940 afs_PutFakeStat(&fakestate);
943 /* update the cache entry */
945 code = afs_VerifyVCache(avc, &treq);
948 /* get a reference to the entire directory */
949 tdc = afs_GetDCache(avc, (afs_size_t) 0, &treq, &origOffset, &len, 1);
954 ObtainReadLock(&avc->lock);
955 ObtainReadLock(&tdc->lock);
958 * Make sure that the data in the cache is current. There are two
959 * cases we need to worry about:
960 * 1. The cache data is being fetched by another process.
961 * 2. The cache data is no longer valid
963 while ((avc->f.states & CStatd)
964 && (tdc->dflags & DFFetching)
965 && hsame(avc->f.m.DataVersion, tdc->f.versionNo)) {
966 afs_Trace4(afs_iclSetp, CM_TRACE_DCACHEWAIT, ICL_TYPE_STRING,
967 __FILE__, ICL_TYPE_INT32, __LINE__, ICL_TYPE_POINTER, tdc,
968 ICL_TYPE_INT32, tdc->dflags);
969 ReleaseReadLock(&tdc->lock);
970 ReleaseReadLock(&avc->lock);
971 afs_osi_Sleep(&tdc->validPos);
972 ObtainReadLock(&avc->lock);
973 ObtainReadLock(&tdc->lock);
975 if (!(avc->f.states & CStatd)
976 || !hsame(avc->f.m.DataVersion, tdc->f.versionNo)) {
977 ReleaseReadLock(&tdc->lock);
978 ReleaseReadLock(&avc->lock);
984 auio->uio_fpflags = 0;
986 origOffset = AFS_UIO_OFFSET(auio);
988 /* scan for the next interesting entry scan for in-use blob
989 * otherwise up point at this blob note that ode, if non-zero,
990 * also represents a held dir page */
991 if (!(us = BlobScan(tdc, (origOffset >> 5)))
992 || !(nde = (struct DirEntry *)afs_dir_GetBlob(tdc, us))) {
993 /* failed to setup nde, return what we've got, and release ode */
995 /* something to hand over. */
996 sdirEntry->d_fileno =
997 (avc->f.fid.Fid.Volume << 16) + ntohl(ode->fid.vnode);
998 FIXUPSTUPIDINODE(sdirEntry->d_fileno);
999 sdirEntry->d_reclen = rlen = AFS_UIO_RESID(auio);
1000 sdirEntry->d_namlen = o_slen;
1001 sdirEntry->d_off = origOffset;
1002 AFS_UIOMOVE((char *)sdirEntry, sizeof(*sdirEntry), UIO_READ,
1005 AFS_UIOMOVE(ode->name, o_slen, UIO_READ, auio, code);
1007 /* pad out the remaining characters with zeros */
1009 AFS_UIOMOVE(bufofzeros,
1010 ((o_slen + 1 + DIRPAD) & ~DIRPAD) - o_slen,
1011 UIO_READ, auio, code);
1013 /* pad out the difference between rlen and slen... */
1014 if (NDIRSIZ_LEN(o_slen) < rlen) {
1015 while (NDIRSIZ_LEN(o_slen) < rlen) {
1016 int minLen = rlen - NDIRSIZ_LEN(o_slen);
1017 if (minLen > sizeof(bufofzeros))
1018 minLen = sizeof(bufofzeros);
1019 AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
1023 AFS_UIO_SETRESID(auio, 0);
1025 /* nothin to hand over */
1031 /* by here nde is set */
1033 /* Do we have enough user space to carry out our mission? */
1034 n_slen = strlen(nde->name);
1035 if (NDIRSIZ_LEN(n_slen) >= (AFS_UIO_RESID(auio) - len)) {
1036 /* No can do no more now; ya know... at this time */
1037 DRelease(nde, 0); /* can't use this one. */
1039 sdirEntry->d_fileno =
1040 (avc->f.fid.Fid.Volume << 16) + ntohl(ode->fid.vnode);
1041 FIXUPSTUPIDINODE(sdirEntry->d_fileno);
1042 sdirEntry->d_reclen = rlen = AFS_UIO_RESID(auio);
1043 sdirEntry->d_namlen = o_slen;
1044 sdirEntry->d_off = origOffset;
1045 AFS_UIOMOVE((char *)sdirEntry, sizeof(*sdirEntry), UIO_READ,
1048 AFS_UIOMOVE(ode->name, o_slen, UIO_READ, auio, code);
1049 /* pad out the remaining characters with zeros */
1051 AFS_UIOMOVE(bufofzeros,
1052 ((o_slen + 1 + DIRPAD) & ~DIRPAD) - o_slen,
1053 UIO_READ, auio, code);
1055 /* pad out the difference between rlen and slen... */
1056 if (NDIRSIZ_LEN(o_slen) < rlen) {
1057 while (NDIRSIZ_LEN(o_slen) < rlen) {
1058 int minLen = rlen - NDIRSIZ_LEN(o_slen);
1059 if (minLen > sizeof(bufofzeros))
1060 minLen = sizeof(bufofzeros);
1061 AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
1065 /* this next line used to be AFSVFS40 or AIX 3.1, but is really generic */
1066 AFS_UIO_SETOFFSET(auio, origOffset);
1067 AFS_UIO_SETRESID(auio, 0);
1068 } else { /* trouble, can't give anything to the user! */
1069 /* even though he has given us a buffer,
1070 * even though we have something to give us,
1071 * Looks like we lost something somewhere.
1081 * In any event, we move out the LAST de entry, getting ready
1082 * to set up for the next one.
1085 sdirEntry->d_fileno =
1086 (avc->f.fid.Fid.Volume << 16) + ntohl(ode->fid.vnode);
1087 FIXUPSTUPIDINODE(sdirEntry->d_fileno);
1088 sdirEntry->d_reclen = rlen = len;
1089 sdirEntry->d_namlen = o_slen;
1090 sdirEntry->d_off = origOffset;
1091 AFS_UIOMOVE((char *)sdirEntry, sizeof(*sdirEntry), UIO_READ, auio,
1094 AFS_UIOMOVE(ode->name, o_slen, UIO_READ, auio, code);
1095 /* pad out the remaining characters with zeros */
1097 AFS_UIOMOVE(bufofzeros,
1098 ((o_slen + 1 + DIRPAD) & ~DIRPAD) - o_slen,
1099 UIO_READ, auio, code);
1101 /* pad out the difference between rlen and slen... */
1102 if (NDIRSIZ_LEN(o_slen) < rlen) {
1103 while (NDIRSIZ_LEN(o_slen) < rlen) {
1104 int minLen = rlen - NDIRSIZ_LEN(o_slen);
1105 if (minLen > sizeof(bufofzeros))
1106 minLen = sizeof(bufofzeros);
1107 AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
1112 len = NDIRSIZ_LEN(o_slen = n_slen);
1116 AFS_UIO_OFFSET(auio) = ((us + afs_dir_NameBlobs(nde->name)) << 5);
1122 ReleaseReadLock(&tdc->lock);
1124 ReleaseReadLock(&avc->lock);
1127 osi_FreeSmallSpace((char *)sdirEntry);
1128 AFS_DISCON_UNLOCK();
1129 afs_PutFakeStat(&fakestate);
1130 code = afs_CheckCode(code, &treq, 29);
1135 #endif /* !AFS_LINUX20_ENV */