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"
32 #if defined(AFS_NBSD40_ENV)
33 #include <ufs/ufs/ufs_extern.h> /* direct_pool */
36 #if defined(AFS_HPUX1122_ENV)
38 #elif defined(AFS_NBSD40_ENV)
45 * AFS readdir vnodeop and bulk stat support.
48 /* Saber C hates negative inode #s. We're not going to talk about software
49 * that could fail if it sees a negative inode #.
51 #define FIXUPSTUPIDINODE(a) ((a) &= 0x7fffffff)
53 /* BlobScan is supposed to ensure that the blob reference refers to a valid
54 directory entry. It consults the allocation map in the page header
55 to determine whether a blob is actually in use or not.
57 More formally, BlobScan is supposed to return a new blob number which is just like
58 the input parameter, only it is advanced over header or free blobs.
60 Note that BlobScan switches pages if necessary. BlobScan may return
61 either 0 or an out-of-range blob number for end of file.
63 BlobScan is used by the Linux port in a separate file, so it should not
67 BlobScan(struct dcache * afile, afs_int32 ablob)
69 afs_int32 relativeBlob;
71 struct PageHeader *tpe;
74 AFS_STATCNT(BlobScan);
75 /* advance ablob over free and header blobs */
77 pageBlob = ablob & ~(EPP - 1); /* base blob in same page */
78 tpe = (struct PageHeader *)afs_dir_GetBlob(afile, pageBlob);
80 return 0; /* we've past the end */
81 relativeBlob = ablob - pageBlob; /* relative to page's first blob */
82 /* first watch for headers */
83 if (pageBlob == 0) { /* first dir page has extra-big header */
85 if (relativeBlob < DHE + 1)
86 relativeBlob = DHE + 1;
87 } else { /* others have one header blob */
88 if (relativeBlob == 0)
91 /* make sure blob is allocated */
92 for (i = relativeBlob; i < EPP; i++) {
93 if (tpe->freebitmap[i >> 3] & (1 << (i & 7)))
96 /* now relativeBlob is the page-relative first allocated blob,
97 * or EPP (if there are none in this page). */
101 ablob = pageBlob + EPP; /* go around again */
107 #if !defined(AFS_LINUX20_ENV)
108 /* Changes to afs_readdir which affect dcache or vcache handling or use of
109 * bulk stat data should also be reflected in the Linux specific verison of
110 * the readdir routine.
114 * The kernel don't like it so much to have large stuff on the stack.
115 * Here we use a watered down version of the direct struct, since
116 * its not too bright to double copy the strings anyway.
118 #if !defined(UKERNEL)
119 #if defined(AFS_SGI_ENV)
120 /* Long form for 64 bit apps and kernel requests. */
121 struct min_dirent { /* miniature dirent structure */
122 /* If struct dirent changes, this must too */
123 ino_t d_fileno; /* This is 32 bits for 3.5, 64 for 6.2+ */
127 /* Short form for 32 bit apps. */
128 struct irix5_min_dirent { /* miniature dirent structure */
129 /* If struct dirent changes, this must too */
135 #define AFS_DIRENT32BASESIZE IRIX5_DIRENTBASESIZE
136 #define AFS_DIRENT64BASESIZE DIRENT64BASESIZE
138 #define AFS_DIRENT32BASESIZE IRIX5_DIRENTBASESIZE
139 #define AFS_DIRENT64BASESIZE DIRENTBASESIZE
140 #endif /* AFS_SGI62_ENV */
142 struct min_direct { /* miniature direct structure */
143 /* If struct direct changes, this must too */
144 #if defined(AFS_DARWIN80_ENV)
149 #elif defined(AFS_NBSD40_ENV)
150 ino_t d_fileno; /* file number of entry */
151 uint16_t d_reclen; /* length of this record */
152 uint16_t d_namlen; /* length of string in d_name */
153 uint8_t d_type; /* file type, see below */
154 #elif defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
159 #elif defined(AFS_SUN5_ENV)
164 #if defined(AFS_AIX32_ENV)
166 #elif defined(AFS_HPUX100_ENV)
167 unsigned long long d_off;
174 #endif /* AFS_SGI_ENV */
176 #if defined(AFS_HPUX_ENV)
177 struct minnfs_direct {
178 afs_int32 d_off; /* XXX */
183 #define NDIRSIZ_LEN(len) ((sizeof (struct dirent)+4 - (MAXNAMLEN+1)) + (((len)+1 + DIRPAD) &~ DIRPAD))
185 #endif /* !defined(UKERNEL) */
189 *------------------------------------------------------------------------------
191 * Keep a stack of about 256 fids for the bulk stat call.
192 * Fill it during the readdir_move. Later empty it...
195 #define READDIR_STASH AFSCBMAX
196 struct AFSFid afs_readdir_stash[READDIR_STASH];
197 int afs_rd_stash_i = 0;
200 *------------------------------------------------------------------------------
203 * mainly a kind of macro... makes getting the struct direct
204 * out to the user space easy... could take more parameters,
205 * but now just takes what it needs.
210 #if defined(AFS_HPUX100_ENV)
211 #define DIRSIZ_LEN(len) \
212 ((sizeof (struct __dirent) - (_MAXNAMLEN+1)) + (((len)+1 + DIRPAD) &~ DIRPAD))
214 #if defined(AFS_SUN56_ENV)
215 #define DIRSIZ_LEN(len) ((18 + (len) + 1 + 7) & ~7 )
218 #define DIRSIZ_LEN(len) ((10 + (len) + 1 + (NBPW-1)) & ~(NBPW-1))
221 #define DIRSIZ_LEN(len) \
222 ((sizeof (struct dirent) - (MAXNAMLEN+1)) + (((len)+1 + 3) &~ 3))
224 #if defined(AFS_SGI_ENV)
225 #ifndef AFS_SGI53_ENV
226 /* SGI 5.3 and later use 32/64 bit versions of directory size. */
227 #define DIRSIZ_LEN(len) DIRENTSIZE(len)
229 #else /* AFS_SGI_ENV */
230 #define DIRSIZ_LEN(len) \
231 ((sizeof (struct direct) - (MAXNAMLEN+1)) + (((len)+1 + 3) &~ 3))
232 #endif /* AFS_SGI_ENV */
233 #endif /* AFS_DIRENT */
234 #endif /* AFS_SUN5_ENV */
235 #endif /* AFS_SUN56_ENV */
236 #endif /* AFS_HPUX100_ENV */
238 #if defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
240 afs_readdir_type(struct vcache *avc, struct DirEntry *ade)
242 struct VenusFid tfid;
245 tfid.Cell = avc->f.fid.Cell;
246 tfid.Fid.Volume = avc->f.fid.Fid.Volume;
247 tfid.Fid.Vnode = ntohl(ade->fid.vnode);
248 tfid.Fid.Unique = ntohl(ade->fid.vunique);
249 if ((avc->f.states & CForeign) == 0 && (ntohl(ade->fid.vnode) & 1)) {
252 ObtainReadLock(&afs_xvcache);
253 if ((tvc = afs_FindVCache(&tfid, 0, 0))) {
254 ReleaseReadLock(&afs_xvcache);
258 } else if (((tvc->f.states) & (CStatd | CTruth))) {
259 /* CTruth will be set if the object has
265 else if (vtype == VREG)
267 /* Don't do this until we're sure it can't be a mtpt */
268 /* if we're CStatd and CTruth and mvstat==0, it's a link */
269 else if (vtype == VLNK)
271 /* what other types does AFS support? */
275 ReleaseReadLock(&afs_xvcache);
281 #define AFS_MOVE_LOCK() AFS_GLOCK()
282 #define AFS_MOVE_UNLOCK() AFS_GUNLOCK()
284 #define AFS_MOVE_LOCK()
285 #define AFS_MOVE_UNLOCK()
287 char bufofzeros[64]; /* gotta fill with something */
291 afs_readdir_move(struct DirEntry *de, struct vcache *vc, struct uio *auio,
292 int slen, ssize_t rlen, afs_size_t off)
295 afs_readdir_move(struct DirEntry *de, struct vcache *vc, struct uio *auio,
296 int slen, int rlen, afs_size_t off)
301 afs_uint32 Volume = vc->f.fid.Fid.Volume;
302 afs_uint32 Vnode = de->fid.vnode;
303 #if defined(AFS_SUN56_ENV)
304 struct dirent64 *direntp;
306 #if defined(AFS_SUN5_ENV) || (defined(AFS_AIX51_ENV) && defined(AFS_64BIT_KERNEL))
307 struct dirent *direntp;
309 #endif /* AFS_SUN56_ENV */
310 #ifndef AFS_SGI53_ENV
311 struct min_direct sdirEntry;
312 #endif /* AFS_SGI53_ENV */
314 AFS_STATCNT(afs_readdir_move);
316 #define READDIR_CORRECT_INUMS
317 #ifdef READDIR_CORRECT_INUMS
318 if (de->name[0] == '.' && !de->name[1]) {
319 /* This is the '.' entry; if we are a volume root, we need to
320 * ignore the directory and use the inum for the mount point.
322 if (!FidCmp(&afs_rootFid, &vc->f.fid)) {
325 } else if (vc->mvstat == 2) {
326 tvp = afs_GetVolume(&vc->f.fid, 0, READ_LOCK);
328 Volume = tvp->mtpoint.Fid.Volume;
329 Vnode = tvp->mtpoint.Fid.Vnode;
330 afs_PutVolume(tvp, READ_LOCK);
334 else if (de->name[0] == '.' && de->name[1] == '.' && !de->name[2]) {
335 /* This is the '..' entry. Getting this right is very tricky,
336 * because we might be a volume root (so our parent is in a
337 * different volume), or our parent might be a volume root
338 * (so we actually want the mount point) or BOTH! */
339 if (!FidCmp(&afs_rootFid, &vc->f.fid)) {
340 /* We are the root of the AFS root, and thus our own parent */
343 } else if (vc->mvstat == 2) {
344 /* We are a volume root, which means our parent is in another
345 * volume. Luckily, we should have his fid cached... */
347 if (!FidCmp(&afs_rootFid, vc->mvid)) {
348 /* Parent directory is the root of the AFS root */
351 } else if (vc->mvid->Fid.Vnode == 1
352 && vc->mvid->Fid.Unique == 1) {
353 /* XXX The above test is evil and probably breaks DFS */
354 /* Parent directory is the target of a mount point */
355 tvp = afs_GetVolume(vc->mvid, 0, READ_LOCK);
357 Volume = tvp->mtpoint.Fid.Volume;
358 Vnode = tvp->mtpoint.Fid.Vnode;
359 afs_PutVolume(tvp, READ_LOCK);
362 /* Parent directory is not a volume root */
363 Volume = vc->mvid->Fid.Volume;
364 Vnode = vc->mvid->Fid.Vnode;
367 } else if (de->fid.vnode == 1 && de->fid.vunique == 1) {
368 /* XXX The above test is evil and probably breaks DFS */
369 /* Parent directory is a volume root; use the right inum */
370 tvp = afs_GetVolume(&vc->f.fid, 0, READ_LOCK);
372 if (tvp->cell == afs_rootFid.Cell
373 && tvp->volume == afs_rootFid.Fid.Volume) {
374 /* Parent directory is the root of the AFS root */
378 /* Parent directory is the target of a mount point */
379 Volume = tvp->mtpoint.Fid.Volume;
380 Vnode = tvp->mtpoint.Fid.Vnode;
382 afs_PutVolume(tvp, READ_LOCK);
390 afs_int32 use64BitDirent;
395 ABI_IS(ABI_IRIX5_64, GETDENTS_ABI(OSI_GET_CURRENT_ABI(), auio));
399 UIO_USERSPACE) ? ABI_IRIX5_64 : (ABI_IS(ABI_IRIX5_64 |
403 #else /* AFS_SGI61_ENV */
406 UIO_USERSPACE) ? ABI_IRIX5_64 : (ABI_IS(ABI_IRIX5_64,
408 #endif /* AFS_SGI61_ENV */
410 if (use64BitDirent) {
411 struct min_dirent sdirEntry;
412 sdirEntry.d_fileno = (Volume << 16) + ntohl(Vnode);
413 FIXUPSTUPIDINODE(sdirEntry.d_fileno);
414 sdirEntry.d_reclen = rlen;
415 sdirEntry.d_off = (off_t) off;
416 AFS_UIOMOVE(&sdirEntry, AFS_DIRENT64BASESIZE, UIO_READ, auio,
419 AFS_UIOMOVE(de->name, slen - 1, UIO_READ, auio, code);
421 AFS_UIOMOVE(bufofzeros,
422 DIRENTSIZE(slen) - (AFS_DIRENT64BASESIZE + slen -
423 1), UIO_READ, auio, code);
424 if (DIRENTSIZE(slen) < rlen) {
425 while (DIRENTSIZE(slen) < rlen) {
426 int minLen = rlen - DIRENTSIZE(slen);
427 if (minLen > sizeof(bufofzeros))
428 minLen = sizeof(bufofzeros);
429 AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
434 struct irix5_min_dirent sdirEntry;
435 sdirEntry.d_fileno = (Volume << 16) + ntohl(Vnode);
436 FIXUPSTUPIDINODE(sdirEntry.d_fileno);
437 sdirEntry.d_reclen = rlen;
438 sdirEntry.d_off = (afs_int32) off;
439 AFS_UIOMOVE(&sdirEntry, AFS_DIRENT32BASESIZE, UIO_READ, auio,
442 AFS_UIOMOVE(de->name, slen - 1, UIO_READ, auio, code);
444 AFS_UIOMOVE(bufofzeros,
445 IRIX5_DIRENTSIZE(slen) - (AFS_DIRENT32BASESIZE +
448 if (IRIX5_DIRENTSIZE(slen) < rlen) {
449 while (IRIX5_DIRENTSIZE(slen) < rlen) {
450 int minLen = rlen - IRIX5_DIRENTSIZE(slen);
451 if (minLen > sizeof(bufofzeros))
452 minLen = sizeof(bufofzeros);
453 AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
459 #else /* AFS_SGI53_ENV */
460 #if defined(AFS_SUN5_ENV) || (defined(AFS_AIX51_ENV) && defined(AFS_64BIT_KERNEL))
461 #if defined(AFS_SUN56_ENV)
462 direntp = (struct dirent64 *)osi_AllocLargeSpace(AFS_LRALLOCSIZ);
464 direntp = (struct dirent *)osi_AllocLargeSpace(AFS_LRALLOCSIZ);
466 direntp->d_ino = (Volume << 16) + ntohl(Vnode);
467 FIXUPSTUPIDINODE(direntp->d_ino);
468 #if defined(AFS_AIX51_ENV) && defined(AFS_64BIT_KERNEL)
469 direntp->d_offset = off;
470 direntp->d_namlen = slen;
472 direntp->d_off = off;
474 direntp->d_reclen = rlen;
475 strcpy(direntp->d_name, de->name);
476 AFS_UIOMOVE((caddr_t) direntp, rlen, UIO_READ, auio, code);
477 osi_FreeLargeSpace((char *)direntp);
478 #else /* AFS_SUN5_ENV */
479 /* Note the odd mechanism for building the inode number */
480 sdirEntry.d_fileno = (Volume << 16) + ntohl(Vnode);
481 FIXUPSTUPIDINODE(sdirEntry.d_fileno);
482 sdirEntry.d_reclen = rlen;
483 #if !defined(AFS_SGI_ENV)
484 sdirEntry.d_namlen = slen;
486 #if defined(AFS_AIX32_ENV) || defined(AFS_SGI_ENV)
487 sdirEntry.d_off = off;
489 #if defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
490 sdirEntry.d_type = afs_readdir_type(vc, de);
493 #if defined(AFS_SGI_ENV)
494 AFS_UIOMOVE(&sdirEntry, DIRENTBASESIZE, UIO_READ, auio, code);
496 AFS_UIOMOVE(de->name, slen - 1, UIO_READ, auio, code);
498 AFS_UIOMOVE(bufofzeros,
499 DIRSIZ_LEN(slen) - (DIRENTBASESIZE + slen - 1), UIO_READ,
501 #else /* AFS_SGI_ENV */
503 #if defined(AFS_NBSD40_ENV)
506 dp = (struct dirent *) pool_get(&ufs_direct_pool, PR_WAITOK);
507 dp->d_ino = (Volume << 16) + ntohl(Vnode);
508 FIXUPSTUPIDINODE(dp->d_ino);
510 strcpy(dp->d_name, de->name);
511 AFS_UIOMOVE((char*) dp, sizeof(struct dirent), UIO_READ, auio, code);
512 pool_put(&ufs_direct_pool, dp);
515 AFS_UIOMOVE((char *) &sdirEntry, sizeof(sdirEntry), UIO_READ, auio, code);
517 AFS_UIOMOVE(de->name, slen, UIO_READ, auio, code);
519 /* pad out the remaining characters with zeros */
521 AFS_UIOMOVE(bufofzeros, ((slen + 1 + DIRPAD) & ~DIRPAD) - slen,
522 UIO_READ, auio, code);
526 #endif /* AFS_SGI_ENV */
527 /* pad out the difference between rlen and slen... */
528 if (DIRSIZ_LEN(slen) < rlen) {
530 while (DIRSIZ_LEN(slen) < rlen) {
531 int minLen = rlen - DIRSIZ_LEN(slen);
532 if (minLen > sizeof(bufofzeros))
533 minLen = sizeof(bufofzeros);
534 AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
539 #endif /* AFS_SUN5_ENV */
540 #endif /* AFS_SGI53_ENV */
546 *------------------------------------------------------------------------------
548 * Read directory entries.
549 * There are some weird things to look out for here. The uio_offset
550 * field is either 0 or it is the offset returned from a previous
551 * readdir. It is an opaque value used by the server to find the
552 * correct directory block to read. The byte count must be at least
553 * vtoblksz(vp) bytes. The count field is the number of blocks to
554 * read on the server. This is advisory only, the server may return
555 * only one block's worth of entries. Entries may be compressed on
558 * This routine encodes knowledge of Vice dirs.
562 afs_bulkstat_send(struct vcache *avc, struct vrequest *req)
568 * Here is the bad, bad, really bad news.
569 * It has to do with 'offset' (seek locations).
573 #if defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
574 afs_readdir(OSI_VC_DECL(avc), struct uio *auio, afs_ucred_t *acred,
577 #if defined(AFS_HPUX100_ENV)
578 afs_readdir2(OSI_VC_DECL(avc), struct uio *auio, afs_ucred_t *acred)
580 afs_readdir(OSI_VC_DECL(avc), struct uio *auio, afs_ucred_t *acred)
584 struct vrequest treq;
586 afs_size_t origOffset, tlen;
589 struct DirEntry *ode = 0, *nde = 0;
590 int o_slen = 0, n_slen = 0;
592 struct afs_fakestat_state fakestate;
593 #if defined(AFS_SGI53_ENV)
594 afs_int32 use64BitDirent, dirsiz;
595 #endif /* defined(AFS_SGI53_ENV) */
600 * XXX All the hacks for alloced sdirEntry and inlining of afs_readdir_move instead of calling
601 * it is necessary for hpux due to stack problems that seem to occur when coming thru the nfs
602 * translator side XXX
604 struct min_direct *sdirEntry =
605 (struct min_direct *)osi_AllocSmallSpace(sizeof(struct min_direct));
609 /* opaque value is pointer into a vice dir; use bit map to decide
610 * if the entries are in use. Always assumed to be valid. 0 is
611 * special, means start of a new dir. Int32 inode, followed by
612 * short reclen and short namelen. Namelen does not include
613 * the null byte. Followed by null-terminated string.
615 AFS_STATCNT(afs_readdir);
617 #if defined(AFS_SGI53_ENV)
621 ABI_IS(ABI_IRIX5_64, GETDENTS_ABI(OSI_GET_CURRENT_ABI(), auio));
625 UIO_USERSPACE) ? ABI_IRIX5_64 : (ABI_IS(ABI_IRIX5_64 | ABI_IRIX5_N32,
627 #endif /* AFS_SGI62_ENV */
628 #else /* AFS_SGI61_ENV */
631 UIO_USERSPACE) ? ABI_IRIX5_64 : (ABI_IS(ABI_IRIX5_64,
633 #endif /* AFS_SGI61_ENV */
634 #endif /* defined(AFS_SGI53_ENV) */
636 #if defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
637 /* Not really used by the callee so we ignore it for now */
641 #ifndef AFS_64BIT_CLIENT
642 if (AfsLargeFileUio(auio) /* file is large than 2 GB */
643 ||AfsLargeFileSize(AFS_UIO_OFFSET(auio), AFS_UIO_RESID(auio)))
647 if ((code = afs_InitReq(&treq, acred))) {
649 osi_FreeSmallSpace((char *)sdirEntry);
653 /* update the cache entry */
654 afs_InitFakeStat(&fakestate);
658 code = afs_EvalFakeStat(&avc, &fakestate, &treq);
662 code = afs_VerifyVCache(avc, &treq);
665 /* get a reference to the entire directory */
666 tdc = afs_GetDCache(avc, (afs_size_t) 0, &treq, &origOffset, &tlen, 1);
672 ObtainReadLock(&avc->lock);
673 ObtainReadLock(&tdc->lock);
676 * Make sure that the data in the cache is current. There are two
677 * cases we need to worry about:
678 * 1. The cache data is being fetched by another process.
679 * 2. The cache data is no longer valid
681 while ((avc->f.states & CStatd)
682 && (tdc->dflags & DFFetching)
683 && hsame(avc->f.m.DataVersion, tdc->f.versionNo)) {
684 afs_Trace4(afs_iclSetp, CM_TRACE_DCACHEWAIT, ICL_TYPE_STRING,
685 __FILE__, ICL_TYPE_INT32, __LINE__, ICL_TYPE_POINTER, tdc,
686 ICL_TYPE_INT32, tdc->dflags);
687 ReleaseReadLock(&tdc->lock);
688 ReleaseReadLock(&avc->lock);
689 afs_osi_Sleep(&tdc->validPos);
690 ObtainReadLock(&avc->lock);
691 ObtainReadLock(&tdc->lock);
693 if (!(avc->f.states & CStatd)
694 || !hsame(avc->f.m.DataVersion, tdc->f.versionNo)) {
695 ReleaseReadLock(&tdc->lock);
696 ReleaseReadLock(&avc->lock);
702 * iterator for the directory reads. Takes the AFS DirEntry
703 * structure and slams them into UFS direct structures.
704 * uses afs_readdir_move to get the struct to the user space.
706 * The routine works by looking ahead one AFS directory entry.
707 * That's because the AFS entry we are currenly working with
708 * may not fit into the buffer the user has provided. If it
709 * doesn't we have to change the size of the LAST AFS directory
710 * entry, so that it will FIT perfectly into the block the
713 * The 'forward looking' of the code makes it a bit tough to read.
714 * Remember we need to get an entry, see if it it fits, then
715 * set it up as the LAST entry, and find the next one.
717 * Tough to take: We give out an EINVAL if we don't have enough
718 * space in the buffer, and at the same time, don't have an entry
719 * to put into the buffer. This CAN happen if the first AFS entry
720 * we get can't fit into the 512 character buffer provided. Seems
721 * it ought not happen...
723 * Assumption: don't need to use anything but one dc entry:
724 * this means the directory ought not be greater than 64k.
728 auio->uio_fpflags = 0;
731 origOffset = AFS_UIO_OFFSET(auio);
732 /* scan for the next interesting entry scan for in-use blob otherwise up point at
733 * this blob note that ode, if non-zero, also represents a held dir page */
734 if (!(us = BlobScan(tdc, (origOffset >> 5)))
735 || !(nde = (struct DirEntry *)afs_dir_GetBlob(tdc, us))) {
736 /* failed to setup nde, return what we've got, and release ode */
738 /* something to hand over. */
740 sdirEntry->d_fileno =
741 (avc->f.fid.Fid.Volume << 16) + ntohl(ode->fid.vnode);
742 FIXUPSTUPIDINODE(sdirEntry->d_fileno);
743 sdirEntry->d_reclen = rlen = AFS_UIO_RESID(auio);
744 sdirEntry->d_namlen = o_slen;
745 #if defined(AFS_SUN5_ENV) || defined(AFS_AIX32_ENV) || defined(AFS_HPUX100_ENV)
746 sdirEntry->d_off = origOffset;
748 AFS_UIOMOVE((char *)sdirEntry, sizeof(*sdirEntry), UIO_READ,
751 AFS_UIOMOVE(ode->name, o_slen, UIO_READ, auio, code);
752 /* pad out the remaining characters with zeros */
754 AFS_UIOMOVE(bufofzeros,
755 ((o_slen + 1 + DIRPAD) & ~DIRPAD) - o_slen,
756 UIO_READ, auio, code);
758 /* pad out the difference between rlen and slen... */
759 if (DIRSIZ_LEN(o_slen) < rlen) {
760 while (DIRSIZ_LEN(o_slen) < rlen) {
761 int minLen = rlen - DIRSIZ_LEN(o_slen);
762 if (minLen > sizeof(bufofzeros))
763 minLen = sizeof(bufofzeros);
764 AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
769 code = afs_readdir_move(ode, avc, auio, o_slen,
770 #if defined(AFS_SUN5_ENV)
773 AFS_UIO_RESID(auio), origOffset);
775 #endif /* AFS_HPUX_ENV */
776 #if !defined(AFS_SUN5_ENV)
777 AFS_UIO_SETRESID(auio, 0);
780 /* nothin to hand over */
782 #if defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
784 *eofp = 1; /* Set it properly */
790 /* by here nde is set */
791 /* Do we have enough user space to carry out our mission? */
792 #if defined(AFS_SGI_ENV)
793 n_slen = strlen(nde->name) + 1; /* NULL terminate */
795 n_slen = strlen(nde->name);
799 use64BitDirent ? DIRENTSIZE(n_slen) : IRIX5_DIRENTSIZE(n_slen);
800 if (dirsiz >= (AFS_UIO_RESID(auio) - len)) {
802 if (DIRSIZ_LEN(n_slen) >= (AFS_UIO_RESID(auio) - len)) {
803 #endif /* AFS_SGI53_ENV */
804 /* No can do no more now; ya know... at this time */
805 DRelease(nde, 0); /* can't use this one. */
808 sdirEntry->d_fileno =
809 (avc->f.fid.Fid.Volume << 16) + ntohl(ode->fid.vnode);
810 FIXUPSTUPIDINODE(sdirEntry->d_fileno);
811 sdirEntry->d_reclen = rlen = AFS_UIO_RESID(auio);
812 sdirEntry->d_namlen = o_slen;
813 #if defined(AFS_SUN5_ENV) || defined(AFS_AIX32_ENV) || defined(AFS_HPUX100_ENV)
814 sdirEntry->d_off = origOffset;
816 AFS_UIOMOVE((char *)sdirEntry, sizeof(*sdirEntry), UIO_READ,
819 AFS_UIOMOVE(ode->name, o_slen, UIO_READ, auio, code);
820 /* pad out the remaining characters with zeros */
822 AFS_UIOMOVE(bufofzeros,
823 ((o_slen + 1 + DIRPAD) & ~DIRPAD) - o_slen,
824 UIO_READ, auio, code);
826 /* pad out the difference between rlen and slen... */
827 if (DIRSIZ_LEN(o_slen) < rlen) {
828 while (DIRSIZ_LEN(o_slen) < rlen) {
829 int minLen = rlen - DIRSIZ_LEN(o_slen);
830 if (minLen > sizeof(bufofzeros))
831 minLen = sizeof(bufofzeros);
832 AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
836 #else /* AFS_HPUX_ENV */
838 afs_readdir_move(ode, avc, auio, o_slen,
839 AFS_UIO_RESID(auio), origOffset);
840 #endif /* AFS_HPUX_ENV */
841 /* this next line used to be AFSVFS40 or AIX 3.1, but is
843 AFS_UIO_SETOFFSET(auio, origOffset);
844 AFS_UIO_SETRESID(auio, 0);
845 } else { /* trouble, can't give anything to the user! */
846 /* even though he has given us a buffer,
847 * even though we have something to give us,
848 * Looks like we lost something somewhere.
858 * In any event, we move out the LAST de entry, getting ready
859 * to set up for the next one.
863 sdirEntry->d_fileno =
864 (avc->f.fid.Fid.Volume << 16) + ntohl(ode->fid.vnode);
865 FIXUPSTUPIDINODE(sdirEntry->d_fileno);
866 sdirEntry->d_reclen = rlen = len;
867 sdirEntry->d_namlen = o_slen;
868 #if defined(AFS_SUN5_ENV) || defined(AFS_AIX32_ENV) || defined(AFS_HPUX100_ENV)
869 sdirEntry->d_off = origOffset;
871 AFS_UIOMOVE((char *)sdirEntry, sizeof(*sdirEntry), UIO_READ, auio,
874 AFS_UIOMOVE(ode->name, o_slen, UIO_READ, auio, code);
875 /* pad out the remaining characters with zeros */
877 AFS_UIOMOVE(bufofzeros,
878 ((o_slen + 1 + DIRPAD) & ~DIRPAD) - o_slen,
879 UIO_READ, auio, code);
881 /* pad out the difference between rlen and slen... */
882 if (DIRSIZ_LEN(o_slen) < rlen) {
883 while (DIRSIZ_LEN(o_slen) < rlen) {
884 int minLen = rlen - DIRSIZ_LEN(o_slen);
885 if (minLen > sizeof(bufofzeros))
886 minLen = sizeof(bufofzeros);
887 AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
891 #else /* AFS_HPUX_ENV */
892 code = afs_readdir_move(ode, avc, auio, o_slen, len, origOffset);
893 #endif /* AFS_HPUX_ENV */
896 len = use64BitDirent ? DIRENTSIZE(o_slen =
897 n_slen) : IRIX5_DIRENTSIZE(o_slen =
900 len = DIRSIZ_LEN(o_slen = n_slen);
901 #endif /* AFS_SGI53_ENV */
905 AFS_UIO_SETOFFSET(auio, (afs_int32) ((us + afs_dir_NameBlobs(nde->name)) << 5));
911 ReleaseReadLock(&tdc->lock);
913 ReleaseReadLock(&avc->lock);
917 osi_FreeSmallSpace((char *)sdirEntry);
920 afs_PutFakeStat(&fakestate);
921 code = afs_CheckCode(code, &treq, 28);
925 #if defined(AFS_HPUX_ENV)
927 afs1_readdir(struct vcache *avc, struct uio *auio, afs_ucred_t *acred)
929 struct vrequest treq;
931 afs_size_t origOffset, len;
933 struct DirEntry *ode = 0, *nde = 0;
934 int o_slen = 0, n_slen = 0;
937 * XXX All the hacks for alloced sdirEntry and inlining of
938 * afs_readdir_move instead of calling it is necessary for hpux due to
939 * stack problems that seem to occur when coming thru the nfs
940 * translator side XXX
942 struct minnfs_direct *sdirEntry = (struct minnfs_direct *)
943 osi_AllocSmallSpace(sizeof(struct min_direct));
946 struct afs_fakestat_state fakestate;
948 AFS_STATCNT(afs_readdir);
949 if (code = afs_InitReq(&treq, acred)) {
950 osi_FreeSmallSpace((char *)sdirEntry);
953 afs_InitFakeStat(&fakestate);
955 code = afs_EvalFakeStat(&avc, &fakestate, &treq);
957 osi_FreeSmallSpace((char *)sdirEntry);
959 afs_PutFakeStat(&fakestate);
962 /* update the cache entry */
964 code = afs_VerifyVCache(avc, &treq);
967 /* get a reference to the entire directory */
968 tdc = afs_GetDCache(avc, (afs_size_t) 0, &treq, &origOffset, &len, 1);
973 ObtainReadLock(&avc->lock);
974 ObtainReadLock(&tdc->lock);
977 * Make sure that the data in the cache is current. There are two
978 * cases we need to worry about:
979 * 1. The cache data is being fetched by another process.
980 * 2. The cache data is no longer valid
982 while ((avc->f.states & CStatd)
983 && (tdc->dflags & DFFetching)
984 && hsame(avc->f.m.DataVersion, tdc->f.versionNo)) {
985 afs_Trace4(afs_iclSetp, CM_TRACE_DCACHEWAIT, ICL_TYPE_STRING,
986 __FILE__, ICL_TYPE_INT32, __LINE__, ICL_TYPE_POINTER, tdc,
987 ICL_TYPE_INT32, tdc->dflags);
988 ReleaseReadLock(&tdc->lock);
989 ReleaseReadLock(&avc->lock);
990 afs_osi_Sleep(&tdc->validPos);
991 ObtainReadLock(&avc->lock);
992 ObtainReadLock(&tdc->lock);
994 if (!(avc->f.states & CStatd)
995 || !hsame(avc->f.m.DataVersion, tdc->f.versionNo)) {
996 ReleaseReadLock(&tdc->lock);
997 ReleaseReadLock(&avc->lock);
1003 auio->uio_fpflags = 0;
1005 origOffset = AFS_UIO_OFFSET(auio);
1007 /* scan for the next interesting entry scan for in-use blob
1008 * otherwise up point at this blob note that ode, if non-zero,
1009 * also represents a held dir page */
1010 if (!(us = BlobScan(tdc, (origOffset >> 5)))
1011 || !(nde = (struct DirEntry *)afs_dir_GetBlob(tdc, us))) {
1012 /* failed to setup nde, return what we've got, and release ode */
1014 /* something to hand over. */
1015 sdirEntry->d_fileno =
1016 (avc->f.fid.Fid.Volume << 16) + ntohl(ode->fid.vnode);
1017 FIXUPSTUPIDINODE(sdirEntry->d_fileno);
1018 sdirEntry->d_reclen = rlen = AFS_UIO_RESID(auio);
1019 sdirEntry->d_namlen = o_slen;
1020 sdirEntry->d_off = origOffset;
1021 AFS_UIOMOVE((char *)sdirEntry, sizeof(*sdirEntry), UIO_READ,
1024 AFS_UIOMOVE(ode->name, o_slen, UIO_READ, auio, code);
1026 /* pad out the remaining characters with zeros */
1028 AFS_UIOMOVE(bufofzeros,
1029 ((o_slen + 1 + DIRPAD) & ~DIRPAD) - o_slen,
1030 UIO_READ, auio, code);
1032 /* pad out the difference between rlen and slen... */
1033 if (NDIRSIZ_LEN(o_slen) < rlen) {
1034 while (NDIRSIZ_LEN(o_slen) < rlen) {
1035 int minLen = rlen - NDIRSIZ_LEN(o_slen);
1036 if (minLen > sizeof(bufofzeros))
1037 minLen = sizeof(bufofzeros);
1038 AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
1042 AFS_UIO_SETRESID(auio, 0);
1044 /* nothin to hand over */
1050 /* by here nde is set */
1052 /* Do we have enough user space to carry out our mission? */
1053 n_slen = strlen(nde->name);
1054 if (NDIRSIZ_LEN(n_slen) >= (AFS_UIO_RESID(auio) - len)) {
1055 /* No can do no more now; ya know... at this time */
1056 DRelease(nde, 0); /* can't use this one. */
1058 sdirEntry->d_fileno =
1059 (avc->f.fid.Fid.Volume << 16) + ntohl(ode->fid.vnode);
1060 FIXUPSTUPIDINODE(sdirEntry->d_fileno);
1061 sdirEntry->d_reclen = rlen = AFS_UIO_RESID(auio);
1062 sdirEntry->d_namlen = o_slen;
1063 sdirEntry->d_off = origOffset;
1064 AFS_UIOMOVE((char *)sdirEntry, sizeof(*sdirEntry), UIO_READ,
1067 AFS_UIOMOVE(ode->name, o_slen, UIO_READ, auio, code);
1068 /* pad out the remaining characters with zeros */
1070 AFS_UIOMOVE(bufofzeros,
1071 ((o_slen + 1 + DIRPAD) & ~DIRPAD) - o_slen,
1072 UIO_READ, auio, code);
1074 /* pad out the difference between rlen and slen... */
1075 if (NDIRSIZ_LEN(o_slen) < rlen) {
1076 while (NDIRSIZ_LEN(o_slen) < rlen) {
1077 int minLen = rlen - NDIRSIZ_LEN(o_slen);
1078 if (minLen > sizeof(bufofzeros))
1079 minLen = sizeof(bufofzeros);
1080 AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
1084 /* this next line used to be AFSVFS40 or AIX 3.1, but is really generic */
1085 AFS_UIO_SETOFFSET(auio, origOffset);
1086 AFS_UIO_SETRESID(auio, 0);
1087 } else { /* trouble, can't give anything to the user! */
1088 /* even though he has given us a buffer,
1089 * even though we have something to give us,
1090 * Looks like we lost something somewhere.
1100 * In any event, we move out the LAST de entry, getting ready
1101 * to set up for the next one.
1104 sdirEntry->d_fileno =
1105 (avc->f.fid.Fid.Volume << 16) + ntohl(ode->fid.vnode);
1106 FIXUPSTUPIDINODE(sdirEntry->d_fileno);
1107 sdirEntry->d_reclen = rlen = len;
1108 sdirEntry->d_namlen = o_slen;
1109 sdirEntry->d_off = origOffset;
1110 AFS_UIOMOVE((char *)sdirEntry, sizeof(*sdirEntry), UIO_READ, auio,
1113 AFS_UIOMOVE(ode->name, o_slen, UIO_READ, auio, code);
1114 /* pad out the remaining characters with zeros */
1116 AFS_UIOMOVE(bufofzeros,
1117 ((o_slen + 1 + DIRPAD) & ~DIRPAD) - o_slen,
1118 UIO_READ, auio, code);
1120 /* pad out the difference between rlen and slen... */
1121 if (NDIRSIZ_LEN(o_slen) < rlen) {
1122 while (NDIRSIZ_LEN(o_slen) < rlen) {
1123 int minLen = rlen - NDIRSIZ_LEN(o_slen);
1124 if (minLen > sizeof(bufofzeros))
1125 minLen = sizeof(bufofzeros);
1126 AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
1131 len = NDIRSIZ_LEN(o_slen = n_slen);
1135 AFS_UIO_OFFSET(auio) = ((us + afs_dir_NameBlobs(nde->name)) << 5);
1141 ReleaseReadLock(&tdc->lock);
1143 ReleaseReadLock(&avc->lock);
1146 osi_FreeSmallSpace((char *)sdirEntry);
1147 AFS_DISCON_UNLOCK();
1148 afs_PutFakeStat(&fakestate);
1149 code = afs_CheckCode(code, &treq, 29);
1154 #endif /* !AFS_LINUX20_ENV */