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 and DUX NFS versions
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) || defined(AFS_OSF_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 /* else if (vtype == VLNK)
260 /* what other types does AFS support? */
264 ReleaseReadLock(&afs_xvcache);
270 #define AFS_MOVE_LOCK() AFS_GLOCK()
271 #define AFS_MOVE_UNLOCK() AFS_GUNLOCK()
273 #define AFS_MOVE_LOCK()
274 #define AFS_MOVE_UNLOCK()
276 char bufofzeros[64]; /* gotta fill with something */
280 afs_readdir_move(struct DirEntry *de, struct vcache *vc, struct uio *auio,
281 int slen, ssize_t rlen, afs_size_t off)
284 afs_readdir_move(struct DirEntry *de, struct vcache *vc, struct uio *auio,
285 int slen, int rlen, afs_size_t off)
290 afs_uint32 Volume = vc->f.fid.Fid.Volume;
291 afs_uint32 Vnode = de->fid.vnode;
292 #if defined(AFS_SUN56_ENV)
293 struct dirent64 *direntp;
295 #if defined(AFS_SUN5_ENV) || (defined(AFS_AIX51_ENV) && defined(AFS_64BIT_KERNEL))
296 struct dirent *direntp;
298 #endif /* AFS_SUN56_ENV */
299 #ifndef AFS_SGI53_ENV
300 struct min_direct sdirEntry;
301 #endif /* AFS_SGI53_ENV */
303 AFS_STATCNT(afs_readdir_move);
305 #define READDIR_CORRECT_INUMS
306 #ifdef READDIR_CORRECT_INUMS
307 if (de->name[0] == '.' && !de->name[1]) {
308 /* This is the '.' entry; if we are a volume root, we need to
309 * ignore the directory and use the inum for the mount point.
311 if (!FidCmp(&afs_rootFid, &vc->f.fid)) {
314 } else if (vc->mvstat == 2) {
315 tvp = afs_GetVolume(&vc->f.fid, 0, READ_LOCK);
317 Volume = tvp->mtpoint.Fid.Volume;
318 Vnode = tvp->mtpoint.Fid.Vnode;
319 afs_PutVolume(tvp, READ_LOCK);
323 else if (de->name[0] == '.' && de->name[1] == '.' && !de->name[2]) {
324 /* This is the '..' entry. Getting this right is very tricky,
325 * because we might be a volume root (so our parent is in a
326 * different volume), or our parent might be a volume root
327 * (so we actually want the mount point) or BOTH! */
328 if (!FidCmp(&afs_rootFid, &vc->f.fid)) {
329 /* We are the root of the AFS root, and thus our own parent */
332 } else if (vc->mvstat == 2) {
333 /* We are a volume root, which means our parent is in another
334 * volume. Luckily, we should have his fid cached... */
336 if (!FidCmp(&afs_rootFid, vc->mvid)) {
337 /* Parent directory is the root of the AFS root */
340 } else if (vc->mvid->Fid.Vnode == 1
341 && vc->mvid->Fid.Unique == 1) {
342 /* XXX The above test is evil and probably breaks DFS */
343 /* Parent directory is the target of a mount point */
344 tvp = afs_GetVolume(vc->mvid, 0, READ_LOCK);
346 Volume = tvp->mtpoint.Fid.Volume;
347 Vnode = tvp->mtpoint.Fid.Vnode;
348 afs_PutVolume(tvp, READ_LOCK);
351 /* Parent directory is not a volume root */
352 Volume = vc->mvid->Fid.Volume;
353 Vnode = vc->mvid->Fid.Vnode;
356 } else if (de->fid.vnode == 1 && de->fid.vunique == 1) {
357 /* XXX The above test is evil and probably breaks DFS */
358 /* Parent directory is a volume root; use the right inum */
359 tvp = afs_GetVolume(&vc->f.fid, 0, READ_LOCK);
361 if (tvp->cell == afs_rootFid.Cell
362 && tvp->volume == afs_rootFid.Fid.Volume) {
363 /* Parent directory is the root of the AFS root */
367 /* Parent directory is the target of a mount point */
368 Volume = tvp->mtpoint.Fid.Volume;
369 Vnode = tvp->mtpoint.Fid.Vnode;
371 afs_PutVolume(tvp, READ_LOCK);
379 afs_int32 use64BitDirent;
384 ABI_IS(ABI_IRIX5_64, GETDENTS_ABI(OSI_GET_CURRENT_ABI(), auio));
388 UIO_USERSPACE) ? ABI_IRIX5_64 : (ABI_IS(ABI_IRIX5_64 |
392 #else /* AFS_SGI61_ENV */
395 UIO_USERSPACE) ? ABI_IRIX5_64 : (ABI_IS(ABI_IRIX5_64,
397 #endif /* AFS_SGI61_ENV */
399 if (use64BitDirent) {
400 struct min_dirent sdirEntry;
401 sdirEntry.d_fileno = (Volume << 16) + ntohl(Vnode);
402 FIXUPSTUPIDINODE(sdirEntry.d_fileno);
403 sdirEntry.d_reclen = rlen;
404 sdirEntry.d_off = (off_t) off;
405 AFS_UIOMOVE(&sdirEntry, AFS_DIRENT64BASESIZE, UIO_READ, auio,
408 AFS_UIOMOVE(de->name, slen - 1, UIO_READ, auio, code);
410 AFS_UIOMOVE(bufofzeros,
411 DIRENTSIZE(slen) - (AFS_DIRENT64BASESIZE + slen -
412 1), UIO_READ, auio, code);
413 if (DIRENTSIZE(slen) < rlen) {
414 while (DIRENTSIZE(slen) < rlen) {
415 int minLen = rlen - DIRENTSIZE(slen);
416 if (minLen > sizeof(bufofzeros))
417 minLen = sizeof(bufofzeros);
418 AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
423 struct irix5_min_dirent sdirEntry;
424 sdirEntry.d_fileno = (Volume << 16) + ntohl(Vnode);
425 FIXUPSTUPIDINODE(sdirEntry.d_fileno);
426 sdirEntry.d_reclen = rlen;
427 sdirEntry.d_off = (afs_int32) off;
428 AFS_UIOMOVE(&sdirEntry, AFS_DIRENT32BASESIZE, UIO_READ, auio,
431 AFS_UIOMOVE(de->name, slen - 1, UIO_READ, auio, code);
433 AFS_UIOMOVE(bufofzeros,
434 IRIX5_DIRENTSIZE(slen) - (AFS_DIRENT32BASESIZE +
437 if (IRIX5_DIRENTSIZE(slen) < rlen) {
438 while (IRIX5_DIRENTSIZE(slen) < rlen) {
439 int minLen = rlen - IRIX5_DIRENTSIZE(slen);
440 if (minLen > sizeof(bufofzeros))
441 minLen = sizeof(bufofzeros);
442 AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
448 #else /* AFS_SGI53_ENV */
449 #if defined(AFS_SUN5_ENV) || (defined(AFS_AIX51_ENV) && defined(AFS_64BIT_KERNEL))
450 #if defined(AFS_SUN56_ENV)
451 direntp = (struct dirent64 *)osi_AllocLargeSpace(AFS_LRALLOCSIZ);
453 direntp = (struct dirent *)osi_AllocLargeSpace(AFS_LRALLOCSIZ);
455 direntp->d_ino = (Volume << 16) + ntohl(Vnode);
456 FIXUPSTUPIDINODE(direntp->d_ino);
457 #if defined(AFS_AIX51_ENV) && defined(AFS_64BIT_KERNEL)
458 direntp->d_offset = off;
459 direntp->d_namlen = slen;
461 direntp->d_off = off;
463 direntp->d_reclen = rlen;
464 strcpy(direntp->d_name, de->name);
465 AFS_UIOMOVE((caddr_t) direntp, rlen, UIO_READ, auio, code);
466 osi_FreeLargeSpace((char *)direntp);
467 #else /* AFS_SUN5_ENV */
468 /* Note the odd mechanism for building the inode number */
469 sdirEntry.d_fileno = (Volume << 16) + ntohl(Vnode);
470 FIXUPSTUPIDINODE(sdirEntry.d_fileno);
471 sdirEntry.d_reclen = rlen;
472 #if !defined(AFS_SGI_ENV)
473 sdirEntry.d_namlen = slen;
475 #if defined(AFS_AIX32_ENV) || defined(AFS_SGI_ENV)
476 sdirEntry.d_off = off;
478 #if defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
479 sdirEntry.d_type = afs_readdir_type(vc, de);
482 #if defined(AFS_SGI_ENV)
483 AFS_UIOMOVE(&sdirEntry, DIRENTBASESIZE, UIO_READ, auio, code);
485 AFS_UIOMOVE(de->name, slen - 1, UIO_READ, auio, code);
487 AFS_UIOMOVE(bufofzeros,
488 DIRSIZ_LEN(slen) - (DIRENTBASESIZE + slen - 1), UIO_READ,
490 #else /* AFS_SGI_ENV */
492 AFS_UIOMOVE((char *)&sdirEntry, sizeof(sdirEntry), UIO_READ, auio, code);
495 AFS_UIOMOVE(de->name, slen, UIO_READ, auio, code);
498 /* pad out the remaining characters with zeros */
500 AFS_UIOMOVE(bufofzeros, ((slen + 1 + DIRPAD) & ~DIRPAD) - slen,
501 UIO_READ, auio, code);
504 #endif /* AFS_SGI_ENV */
506 /* pad out the difference between rlen and slen... */
507 if (DIRSIZ_LEN(slen) < rlen) {
509 while (DIRSIZ_LEN(slen) < rlen) {
510 int minLen = rlen - DIRSIZ_LEN(slen);
511 if (minLen > sizeof(bufofzeros))
512 minLen = sizeof(bufofzeros);
513 AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
518 #endif /* AFS_SUN5_ENV */
519 #endif /* AFS_SGI53_ENV */
525 *------------------------------------------------------------------------------
527 * Read directory entries.
528 * There are some weird things to look out for here. The uio_offset
529 * field is either 0 or it is the offset returned from a previous
530 * readdir. It is an opaque value used by the server to find the
531 * correct directory block to read. The byte count must be at least
532 * vtoblksz(vp) bytes. The count field is the number of blocks to
533 * read on the server. This is advisory only, the server may return
534 * only one block's worth of entries. Entries may be compressed on
537 * This routine encodes knowledge of Vice dirs.
541 afs_bulkstat_send(struct vcache *avc, struct vrequest *req)
547 * Here is the bad, bad, really bad news.
548 * It has to do with 'offset' (seek locations).
552 #if defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV) || defined(AFS_OSF_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
553 afs_readdir(OSI_VC_DECL(avc), struct uio *auio, afs_ucred_t *acred,
556 #if defined(AFS_HPUX100_ENV)
557 afs_readdir2(OSI_VC_DECL(avc), struct uio *auio, afs_ucred_t *acred)
559 afs_readdir(OSI_VC_DECL(avc), struct uio *auio, afs_ucred_t *acred)
563 struct vrequest treq;
564 register struct dcache *tdc;
565 afs_size_t origOffset, tlen;
568 struct DirEntry *ode = 0, *nde = 0;
569 int o_slen = 0, n_slen = 0;
571 struct afs_fakestat_state fakestate;
572 #if defined(AFS_SGI53_ENV)
573 afs_int32 use64BitDirent, dirsiz;
574 #endif /* defined(AFS_SGI53_ENV) */
579 * XXX All the hacks for alloced sdirEntry and inlining of afs_readdir_move instead of calling
580 * it is necessary for hpux due to stack problems that seem to occur when coming thru the nfs
581 * translator side XXX
583 struct min_direct *sdirEntry =
584 (struct min_direct *)osi_AllocSmallSpace(sizeof(struct min_direct));
588 /* opaque value is pointer into a vice dir; use bit map to decide
589 * if the entries are in use. Always assumed to be valid. 0 is
590 * special, means start of a new dir. Int32 inode, followed by
591 * short reclen and short namelen. Namelen does not include
592 * the null byte. Followed by null-terminated string.
594 AFS_STATCNT(afs_readdir);
596 #if defined(AFS_SGI53_ENV)
600 ABI_IS(ABI_IRIX5_64, GETDENTS_ABI(OSI_GET_CURRENT_ABI(), auio));
604 UIO_USERSPACE) ? ABI_IRIX5_64 : (ABI_IS(ABI_IRIX5_64 | ABI_IRIX5_N32,
606 #endif /* AFS_SGI62_ENV */
607 #else /* AFS_SGI61_ENV */
610 UIO_USERSPACE) ? ABI_IRIX5_64 : (ABI_IS(ABI_IRIX5_64,
612 #endif /* AFS_SGI61_ENV */
613 #endif /* defined(AFS_SGI53_ENV) */
615 #if defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV) || defined(AFS_OSF_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
616 /* Not really used by the callee so we ignore it for now */
620 #ifndef AFS_64BIT_CLIENT
621 if (AfsLargeFileUio(auio) /* file is large than 2 GB */
622 ||AfsLargeFileSize(AFS_UIO_OFFSET(auio), AFS_UIO_RESID(auio)))
626 if ((code = afs_InitReq(&treq, acred))) {
628 osi_FreeSmallSpace((char *)sdirEntry);
632 /* update the cache entry */
633 afs_InitFakeStat(&fakestate);
637 code = afs_EvalFakeStat(&avc, &fakestate, &treq);
641 code = afs_VerifyVCache(avc, &treq);
644 /* get a reference to the entire directory */
645 tdc = afs_GetDCache(avc, (afs_size_t) 0, &treq, &origOffset, &tlen, 1);
651 ObtainReadLock(&avc->lock);
652 ObtainReadLock(&tdc->lock);
655 * Make sure that the data in the cache is current. There are two
656 * cases we need to worry about:
657 * 1. The cache data is being fetched by another process.
658 * 2. The cache data is no longer valid
660 while ((avc->f.states & CStatd)
661 && (tdc->dflags & DFFetching)
662 && hsame(avc->f.m.DataVersion, tdc->f.versionNo)) {
663 afs_Trace4(afs_iclSetp, CM_TRACE_DCACHEWAIT, ICL_TYPE_STRING,
664 __FILE__, ICL_TYPE_INT32, __LINE__, ICL_TYPE_POINTER, tdc,
665 ICL_TYPE_INT32, tdc->dflags);
666 ReleaseReadLock(&tdc->lock);
667 ReleaseReadLock(&avc->lock);
668 afs_osi_Sleep(&tdc->validPos);
669 ObtainReadLock(&avc->lock);
670 ObtainReadLock(&tdc->lock);
672 if (!(avc->f.states & CStatd)
673 || !hsame(avc->f.m.DataVersion, tdc->f.versionNo)) {
674 ReleaseReadLock(&tdc->lock);
675 ReleaseReadLock(&avc->lock);
681 * iterator for the directory reads. Takes the AFS DirEntry
682 * structure and slams them into UFS direct structures.
683 * uses afs_readdir_move to get the struct to the user space.
685 * The routine works by looking ahead one AFS directory entry.
686 * That's because the AFS entry we are currenly working with
687 * may not fit into the buffer the user has provided. If it
688 * doesn't we have to change the size of the LAST AFS directory
689 * entry, so that it will FIT perfectly into the block the
692 * The 'forward looking' of the code makes it a bit tough to read.
693 * Remember we need to get an entry, see if it it fits, then
694 * set it up as the LAST entry, and find the next one.
696 * Tough to take: We give out an EINVAL if we don't have enough
697 * space in the buffer, and at the same time, don't have an entry
698 * to put into the buffer. This CAN happen if the first AFS entry
699 * we get can't fit into the 512 character buffer provided. Seems
700 * it ought not happen...
702 * Assumption: don't need to use anything but one dc entry:
703 * this means the directory ought not be greater than 64k.
707 auio->uio_fpflags = 0;
710 origOffset = AFS_UIO_OFFSET(auio);
711 /* scan for the next interesting entry scan for in-use blob otherwise up point at
712 * this blob note that ode, if non-zero, also represents a held dir page */
713 if (!(us = BlobScan(tdc, (origOffset >> 5)))
714 || !(nde = (struct DirEntry *)afs_dir_GetBlob(tdc, us))) {
715 /* failed to setup nde, return what we've got, and release ode */
717 /* something to hand over. */
719 sdirEntry->d_fileno =
720 (avc->f.fid.Fid.Volume << 16) + ntohl(ode->fid.vnode);
721 FIXUPSTUPIDINODE(sdirEntry->d_fileno);
722 sdirEntry->d_reclen = rlen = AFS_UIO_RESID(auio);
723 sdirEntry->d_namlen = o_slen;
724 #if defined(AFS_SUN5_ENV) || defined(AFS_AIX32_ENV) || defined(AFS_HPUX100_ENV)
725 sdirEntry->d_off = origOffset;
727 AFS_UIOMOVE((char *)sdirEntry, sizeof(*sdirEntry), UIO_READ,
730 AFS_UIOMOVE(ode->name, o_slen, UIO_READ, auio, code);
731 /* pad out the remaining characters with zeros */
733 AFS_UIOMOVE(bufofzeros,
734 ((o_slen + 1 + DIRPAD) & ~DIRPAD) - o_slen,
735 UIO_READ, auio, code);
737 /* pad out the difference between rlen and slen... */
738 if (DIRSIZ_LEN(o_slen) < rlen) {
739 while (DIRSIZ_LEN(o_slen) < rlen) {
740 int minLen = rlen - DIRSIZ_LEN(o_slen);
741 if (minLen > sizeof(bufofzeros))
742 minLen = sizeof(bufofzeros);
743 AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
748 code = afs_readdir_move(ode, avc, auio, o_slen,
749 #if defined(AFS_SUN5_ENV)
752 AFS_UIO_RESID(auio), origOffset);
754 #endif /* AFS_HPUX_ENV */
755 #if !defined(AFS_SUN5_ENV)
756 AFS_UIO_SETRESID(auio, 0);
759 /* nothin to hand over */
761 #if defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV) || defined(AFS_OSF_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
763 *eofp = 1; /* Set it properly */
769 /* by here nde is set */
771 /* Do we have enough user space to carry out our mission? */
772 #if defined(AFS_SGI_ENV)
773 n_slen = strlen(nde->name) + 1; /* NULL terminate */
775 n_slen = strlen(nde->name);
779 use64BitDirent ? DIRENTSIZE(n_slen) : IRIX5_DIRENTSIZE(n_slen);
780 if (dirsiz >= (AFS_UIO_RESID(auio) - len)) {
782 if (DIRSIZ_LEN(n_slen) >= (AFS_UIO_RESID(auio) - len)) {
783 #endif /* AFS_SGI53_ENV */
784 /* No can do no more now; ya know... at this time */
785 DRelease(nde, 0); /* can't use this one. */
788 sdirEntry->d_fileno =
789 (avc->f.fid.Fid.Volume << 16) + ntohl(ode->fid.vnode);
790 FIXUPSTUPIDINODE(sdirEntry->d_fileno);
791 sdirEntry->d_reclen = rlen = AFS_UIO_RESID(auio);
792 sdirEntry->d_namlen = o_slen;
793 #if defined(AFS_SUN5_ENV) || defined(AFS_AIX32_ENV) || defined(AFS_HPUX100_ENV)
794 sdirEntry->d_off = origOffset;
796 AFS_UIOMOVE((char *)sdirEntry, sizeof(*sdirEntry), UIO_READ,
799 AFS_UIOMOVE(ode->name, o_slen, UIO_READ, auio, code);
800 /* pad out the remaining characters with zeros */
802 AFS_UIOMOVE(bufofzeros,
803 ((o_slen + 1 + DIRPAD) & ~DIRPAD) - o_slen,
804 UIO_READ, auio, code);
806 /* pad out the difference between rlen and slen... */
807 if (DIRSIZ_LEN(o_slen) < rlen) {
808 while (DIRSIZ_LEN(o_slen) < rlen) {
809 int minLen = rlen - DIRSIZ_LEN(o_slen);
810 if (minLen > sizeof(bufofzeros))
811 minLen = sizeof(bufofzeros);
812 AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
816 #else /* AFS_HPUX_ENV */
818 afs_readdir_move(ode, avc, auio, o_slen,
819 AFS_UIO_RESID(auio), origOffset);
820 #endif /* AFS_HPUX_ENV */
821 /* this next line used to be AFSVFS40 or AIX 3.1, but is
823 AFS_UIO_SETOFFSET(auio, origOffset);
824 AFS_UIO_SETRESID(auio, 0);
825 } else { /* trouble, can't give anything to the user! */
826 /* even though he has given us a buffer,
827 * even though we have something to give us,
828 * Looks like we lost something somewhere.
838 * In any event, we move out the LAST de entry, getting ready
839 * to set up for the next one.
843 sdirEntry->d_fileno =
844 (avc->f.fid.Fid.Volume << 16) + ntohl(ode->fid.vnode);
845 FIXUPSTUPIDINODE(sdirEntry->d_fileno);
846 sdirEntry->d_reclen = rlen = len;
847 sdirEntry->d_namlen = o_slen;
848 #if defined(AFS_SUN5_ENV) || defined(AFS_AIX32_ENV) || defined(AFS_HPUX100_ENV)
849 sdirEntry->d_off = origOffset;
851 AFS_UIOMOVE((char *)sdirEntry, sizeof(*sdirEntry), UIO_READ, auio,
854 AFS_UIOMOVE(ode->name, o_slen, UIO_READ, auio, code);
855 /* pad out the remaining characters with zeros */
857 AFS_UIOMOVE(bufofzeros,
858 ((o_slen + 1 + DIRPAD) & ~DIRPAD) - o_slen,
859 UIO_READ, auio, code);
861 /* pad out the difference between rlen and slen... */
862 if (DIRSIZ_LEN(o_slen) < rlen) {
863 while (DIRSIZ_LEN(o_slen) < rlen) {
864 int minLen = rlen - DIRSIZ_LEN(o_slen);
865 if (minLen > sizeof(bufofzeros))
866 minLen = sizeof(bufofzeros);
867 AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
871 #else /* AFS_HPUX_ENV */
872 code = afs_readdir_move(ode, avc, auio, o_slen, len, origOffset);
873 #endif /* AFS_HPUX_ENV */
876 len = use64BitDirent ? DIRENTSIZE(o_slen =
877 n_slen) : IRIX5_DIRENTSIZE(o_slen =
880 len = DIRSIZ_LEN(o_slen = n_slen);
881 #endif /* AFS_SGI53_ENV */
885 AFS_UIO_SETOFFSET(auio, (afs_int32) ((us + afs_dir_NameBlobs(nde->name)) << 5));
891 ReleaseReadLock(&tdc->lock);
893 ReleaseReadLock(&avc->lock);
897 osi_FreeSmallSpace((char *)sdirEntry);
900 afs_PutFakeStat(&fakestate);
901 code = afs_CheckCode(code, &treq, 28);
905 #if defined(AFS_HPUX_ENV) || defined(AFS_OSF_ENV)
908 afs1_readdir(struct vcache *avc, struct uio *auio, afs_ucred_t *acred,
912 afs1_readdir(struct vcache *avc, struct uio *auio, afs_ucred_t *acred)
915 struct vrequest treq;
916 register struct dcache *tdc;
917 afs_size_t origOffset, len;
919 struct DirEntry *ode = 0, *nde = 0;
920 int o_slen = 0, n_slen = 0;
922 #if defined(AFS_HPUX_ENV) || defined(AFS_OSF_ENV)
924 * XXX All the hacks for alloced sdirEntry and inlining of afs_readdir_move instead of calling
925 * it is necessary for hpux due to stack problems that seem to occur when coming thru the nfs
926 * translator side XXX
928 struct minnfs_direct *sdirEntry = (struct minnfs_direct *)
929 osi_AllocSmallSpace(sizeof(struct min_direct));
932 struct afs_fakestat_state fakestate;
934 AFS_STATCNT(afs_readdir);
935 #if defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV) || defined(AFS_OSF_ENV)
939 if (code = afs_InitReq(&treq, acred)) {
941 osi_FreeSmallSpace((char *)sdirEntry);
945 afs_InitFakeStat(&fakestate);
947 code = afs_EvalFakeStat(&avc, &fakestate, &treq);
950 osi_FreeSmallSpace((char *)sdirEntry);
953 afs_PutFakeStat(&fakestate);
956 /* update the cache entry */
958 code = afs_VerifyVCache(avc, &treq);
961 /* get a reference to the entire directory */
962 tdc = afs_GetDCache(avc, (afs_size_t) 0, &treq, &origOffset, &len, 1);
967 ObtainReadLock(&avc->lock);
968 ObtainReadLock(&tdc->lock);
971 * Make sure that the data in the cache is current. There are two
972 * cases we need to worry about:
973 * 1. The cache data is being fetched by another process.
974 * 2. The cache data is no longer valid
976 while ((avc->f.states & CStatd)
977 && (tdc->dflags & DFFetching)
978 && hsame(avc->f.m.DataVersion, tdc->f.versionNo)) {
979 afs_Trace4(afs_iclSetp, CM_TRACE_DCACHEWAIT, ICL_TYPE_STRING,
980 __FILE__, ICL_TYPE_INT32, __LINE__, ICL_TYPE_POINTER, tdc,
981 ICL_TYPE_INT32, tdc->dflags);
982 ReleaseReadLock(&tdc->lock);
983 ReleaseReadLock(&avc->lock);
984 afs_osi_Sleep(&tdc->validPos);
985 ObtainReadLock(&avc->lock);
986 ObtainReadLock(&tdc->lock);
988 if (!(avc->f.states & CStatd)
989 || !hsame(avc->f.m.DataVersion, tdc->f.versionNo)) {
990 ReleaseReadLock(&tdc->lock);
991 ReleaseReadLock(&avc->lock);
998 auio->uio_fpflags = 0;
1001 origOffset = AFS_UIO_OFFSET(auio);
1003 /* scan for the next interesting entry scan for in-use blob otherwise up point at
1004 * this blob note that ode, if non-zero, also represents a held dir page */
1005 if (!(us = BlobScan(tdc, (origOffset >> 5)))
1006 || !(nde = (struct DirEntry *)afs_dir_GetBlob(tdc, us))) {
1007 /* failed to setup nde, return what we've got, and release ode */
1009 /* something to hand over. */
1010 #if defined(AFS_HPUX_ENV) || defined(AFS_OSF_ENV)
1011 sdirEntry->d_fileno =
1012 (avc->f.fid.Fid.Volume << 16) + ntohl(ode->fid.vnode);
1013 FIXUPSTUPIDINODE(sdirEntry->d_fileno);
1014 sdirEntry->d_reclen = rlen = AFS_UIO_RESID(auio);
1015 sdirEntry->d_namlen = o_slen;
1016 sdirEntry->d_off = origOffset;
1017 AFS_UIOMOVE((char *)sdirEntry, sizeof(*sdirEntry), UIO_READ,
1020 AFS_UIOMOVE(ode->name, o_slen, UIO_READ, auio, code);
1022 /* pad out the remaining characters with zeros */
1024 AFS_UIOMOVE(bufofzeros,
1025 ((o_slen + 1 + DIRPAD) & ~DIRPAD) - o_slen,
1026 UIO_READ, auio, code);
1028 /* pad out the difference between rlen and slen... */
1029 if (NDIRSIZ_LEN(o_slen) < rlen) {
1030 while (NDIRSIZ_LEN(o_slen) < rlen) {
1031 int minLen = rlen - NDIRSIZ_LEN(o_slen);
1032 if (minLen > sizeof(bufofzeros))
1033 minLen = sizeof(bufofzeros);
1034 AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
1040 afs_readdir_move(ode, avc, auio, o_slen,
1041 AFS_UIO_RESID(auio), origOffset);
1042 #endif /* AFS_HPUX_ENV */
1043 AFS_UIO_SETRESID(auio, 0);
1045 /* nothin to hand over */
1047 #if defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV) || defined(AFS_OSF_ENV)
1055 /* by here nde is set */
1057 /* Do we have enough user space to carry out our mission? */
1058 #if defined(AFS_SGI_ENV)
1059 n_slen = strlen(nde->name) + 1; /* NULL terminate */
1061 n_slen = strlen(nde->name);
1063 if (NDIRSIZ_LEN(n_slen) >= (AFS_UIO_RESID(auio) - len)) {
1064 /* No can do no more now; ya know... at this time */
1065 DRelease(nde, 0); /* can't use this one. */
1067 #if defined(AFS_HPUX_ENV) || defined(AFS_OSF_ENV)
1068 sdirEntry->d_fileno =
1069 (avc->f.fid.Fid.Volume << 16) + ntohl(ode->fid.vnode);
1070 FIXUPSTUPIDINODE(sdirEntry->d_fileno);
1071 sdirEntry->d_reclen = rlen = AFS_UIO_RESID(auio);
1072 sdirEntry->d_namlen = o_slen;
1073 sdirEntry->d_off = origOffset;
1074 AFS_UIOMOVE((char *)sdirEntry, sizeof(*sdirEntry), UIO_READ,
1077 AFS_UIOMOVE(ode->name, o_slen, UIO_READ, auio, code);
1078 /* pad out the remaining characters with zeros */
1080 AFS_UIOMOVE(bufofzeros,
1081 ((o_slen + 1 + DIRPAD) & ~DIRPAD) - o_slen,
1082 UIO_READ, auio, code);
1084 /* pad out the difference between rlen and slen... */
1085 if (NDIRSIZ_LEN(o_slen) < rlen) {
1086 while (NDIRSIZ_LEN(o_slen) < rlen) {
1087 int minLen = rlen - NDIRSIZ_LEN(o_slen);
1088 if (minLen > sizeof(bufofzeros))
1089 minLen = sizeof(bufofzeros);
1090 AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
1096 afs_readdir_move(ode, avc, auio, o_slen,
1097 AFS_UIO_RESID(auio), origOffset);
1098 #endif /* AFS_HPUX_ENV */
1099 /* this next line used to be AFSVFS40 or AIX 3.1, but is really generic */
1100 AFS_UIO_SETOFFSET(auio, origOffset);
1101 AFS_UIO_SETRESID(auio, 0);
1102 } else { /* trouble, can't give anything to the user! */
1103 /* even though he has given us a buffer,
1104 * even though we have something to give us,
1105 * Looks like we lost something somewhere.
1115 * In any event, we move out the LAST de entry, getting ready
1116 * to set up for the next one.
1119 #if defined(AFS_HPUX_ENV) || defined(AFS_OSF_ENV)
1120 sdirEntry->d_fileno =
1121 (avc->f.fid.Fid.Volume << 16) + ntohl(ode->fid.vnode);
1122 FIXUPSTUPIDINODE(sdirEntry->d_fileno);
1123 sdirEntry->d_reclen = rlen = len;
1124 sdirEntry->d_namlen = o_slen;
1125 sdirEntry->d_off = origOffset;
1126 AFS_UIOMOVE((char *)sdirEntry, sizeof(*sdirEntry), UIO_READ, auio,
1129 AFS_UIOMOVE(ode->name, o_slen, UIO_READ, auio, code);
1130 /* pad out the remaining characters with zeros */
1132 AFS_UIOMOVE(bufofzeros,
1133 ((o_slen + 1 + DIRPAD) & ~DIRPAD) - o_slen,
1134 UIO_READ, auio, code);
1136 /* pad out the difference between rlen and slen... */
1137 if (NDIRSIZ_LEN(o_slen) < rlen) {
1138 while (NDIRSIZ_LEN(o_slen) < rlen) {
1139 int minLen = rlen - NDIRSIZ_LEN(o_slen);
1140 if (minLen > sizeof(bufofzeros))
1141 minLen = sizeof(bufofzeros);
1142 AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
1147 code = afs_readdir_move(ode, avc, auio, o_slen, len, origOffset);
1148 #endif /* AFS_HPUX_ENV */
1150 len = NDIRSIZ_LEN(o_slen = n_slen);
1154 AFS_UIO_OFFSET(auio) = ((us + afs_dir_NameBlobs(nde->name)) << 5);
1160 ReleaseReadLock(&tdc->lock);
1162 ReleaseReadLock(&avc->lock);
1165 #if defined(AFS_HPUX_ENV) || defined(AFS_OSF_ENV)
1166 osi_FreeSmallSpace((char *)sdirEntry);
1168 AFS_DISCON_UNLOCK();
1169 afs_PutFakeStat(&fakestate);
1170 code = afs_CheckCode(code, &treq, 29);
1175 #endif /* !AFS_LINUX20_ENV */