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"
27 #include "../afs/sysincludes.h" /* Standard vendor system headers */
28 #include "../afs/afsincludes.h" /* Afs-based standard headers */
29 #include "../afs/afs_stats.h" /* statistics */
30 #include "../afs/afs_cbqueue.h"
31 #include "../afs/nfsclient.h"
32 #include "../afs/afs_osidnlc.h"
36 * A few definitions. This is until we have a proper header file
37 * which ahs prototypes for all functions
40 extern struct DirEntry * afs_dir_GetBlob();
42 * AFS readdir vnodeop and bulk stat support.
45 /* Saber C hates negative inode #s. We're not going to talk about software
46 * that could fail if it sees a negative inode #.
48 #define FIXUPSTUPIDINODE(a) ((a) &= 0x7fffffff)
50 /* BlobScan is supposed to ensure that the blob reference refers to a valid
51 directory entry. It consults the allocation map in the page header
52 to determine whether a blob is actually in use or not.
54 More formally, BlobScan is supposed to return a new blob number which is just like
55 the input parameter, only it is advanced over header or free blobs.
57 Note that BlobScan switches pages if necessary. BlobScan may return
58 either 0 or an out-of-range blob number for end of file.
60 BlobScan is used by the Linux port in a separate file, so it should not
63 #if defined(AFS_SGI62_ENV) || defined(AFS_SUN57_64BIT_ENV)
64 int BlobScan(ino64_t *afile, afs_int32 ablob)
66 #ifdef AFS_LINUX_64BIT_KERNEL
67 int BlobScan(long *afile, afs_int32 ablob)
69 int BlobScan(afs_int32 *afile, afs_int32 ablob)
73 register afs_int32 relativeBlob;
75 register struct PageHeader *tpe;
78 AFS_STATCNT(BlobScan);
79 /* advance ablob over free and header blobs */
81 pageBlob = ablob & ~(EPP-1); /* base blob in same page */
82 tpe = (struct PageHeader *) afs_dir_GetBlob(afile, pageBlob);
83 if (!tpe) return 0; /* we've past the end */
84 relativeBlob = ablob - pageBlob; /* relative to page's first blob */
85 /* first watch for headers */
86 if (pageBlob == 0) { /* first dir page has extra-big header */
88 if (relativeBlob < DHE+1) relativeBlob = DHE+1;
90 else { /* others have one header blob */
91 if (relativeBlob == 0) relativeBlob = 1;
93 /* make sure blob is allocated */
94 for(i = relativeBlob; i < EPP; i++) {
95 if (tpe->freebitmap[i>>3] & (1<<(i&7))) break;
97 /* now relativeBlob is the page-relative first allocated blob,
98 or EPP (if there are none in this page). */
100 if (i != EPP) return i+pageBlob;
101 ablob = pageBlob + EPP; /* go around again */
106 #if !defined(AFS_LINUX20_ENV)
107 /* Changes to afs_readdir which affect dcache or vcache handling or use of
108 * bulk stat data should also be reflected in the Linux specific verison of
109 * the readdir routine.
113 * The kernel don't like it so much to have large stuff on the stack.
114 * Here we use a watered down version of the direct struct, since
115 * its not too bright to double copy the strings anyway.
117 #if !defined(UKERNEL)
118 #if defined(AFS_SGI_ENV)
119 /* Long form for 64 bit apps and kernel requests. */
120 struct min_dirent { /* miniature dirent structure */
121 /* If struct dirent changes, this must too */
122 ino_t d_fileno; /* This is 32 bits for 3.5, 64 for 6.2+ */
126 /* Short form for 32 bit apps. */
127 struct irix5_min_dirent { /* miniature dirent structure */
128 /* If struct dirent changes, this must too */
134 #define AFS_DIRENT32BASESIZE IRIX5_DIRENTBASESIZE
135 #define AFS_DIRENT64BASESIZE DIRENT64BASESIZE
137 #define AFS_DIRENT32BASESIZE IRIX5_DIRENTBASESIZE
138 #define AFS_DIRENT64BASESIZE DIRENTBASESIZE
139 #endif /* AFS_SGI62_ENV */
141 struct min_direct { /* miniature direct structure */
142 /* If struct direct changes, this must too */
143 #if defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV)
154 #if defined(AFS_SUN_ENV) || defined(AFS_AIX32_ENV)
157 #if defined(AFS_HPUX100_ENV)
158 unsigned long long d_off;
166 #endif /* AFS_SGI_ENV */
168 #if defined(AFS_HPUX_ENV) || defined(AFS_OSF_ENV)
169 struct minnfs_direct {
170 afs_int32 d_off; /* XXX */
175 #define NDIRSIZ_LEN(len) ((sizeof (struct dirent)+4 - (MAXNAMLEN+1)) + (((len)+1 + 3) &~ 3))
177 #endif /* !defined(UKERNEL) */
181 *------------------------------------------------------------------------------
183 * Keep a stack of about 256 fids for the bulk stat call.
184 * Fill it during the readdir_move. Later empty it...
187 #define READDIR_STASH AFSCBMAX
188 struct AFSFid afs_readdir_stash[READDIR_STASH];
189 int afs_rd_stash_i = 0;
192 *------------------------------------------------------------------------------
195 * mainly a kind of macro... makes getting the struct direct
196 * out to the user space easy... could take more parameters,
197 * but now just takes what it needs.
201 #if defined(AFS_HPUX100_ENV)
202 #define DIRSIZ_LEN(len) \
203 ((sizeof (struct __dirent) - (_MAXNAMLEN+1)) + (((len)+1 + 3) &~ 3))
205 #if defined(AFS_SUN56_ENV)
206 #define DIRSIZ_LEN(len) ((18 + (len) + 1 + 7) & ~7 )
209 #define DIRSIZ_LEN(len) ((10 + (len) + 1 + (NBPW-1)) & ~(NBPW-1))
212 #define DIRSIZ_LEN(len) \
213 ((sizeof (struct dirent) - (MAXNAMLEN+1)) + (((len)+1 + 3) &~ 3))
215 #if defined(AFS_SGI_ENV)
216 #ifndef AFS_SGI53_ENV
217 /* SGI 5.3 and later use 32/64 bit versions of directory size. */
218 #define DIRSIZ_LEN(len) DIRENTSIZE(len)
220 #else /* AFS_SGI_ENV */
221 #define DIRSIZ_LEN(len) \
222 ((sizeof (struct direct) - (MAXNAMLEN+1)) + (((len)+1 + 3) &~ 3))
223 #endif /* AFS_SGI_ENV */
224 #endif /* AFS_DIRENT */
225 #endif /* AFS_SUN5_ENV */
226 #endif /* AFS_SUN56_ENV */
227 #endif /* AFS_HPUX100_ENV */
229 #if defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV)
230 int afs_readdir_type(avc, ade)
231 struct DirEntry * ade;
234 struct VenusFid tfid;
237 tfid.Cell=avc->fid.Cell;
238 tfid.Fid.Volume=avc->fid.Fid.Volume;
239 tfid.Fid.Vnode=ntohl(ade->fid.vnode);
240 tfid.Fid.Unique=ntohl(ade->fid.vunique);
241 if ((avc->states & CForeign) == 0 &&
242 (ntohl(ade->fid.vnode) & 1)) {
244 } else if ((tvc=afs_FindVCache(&tfid,0,0,0,0))) {
246 afs_PutVCache(tvc, WRITE_LOCK);
248 } else if (((tvc->states) & (CStatd|CTruth))) {
249 /* CTruth will be set if the object has
252 afs_PutVCache(tvc, WRITE_LOCK);
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? */
262 afs_PutVCache(tvc, WRITE_LOCK);
269 #define AFS_MOVE_LOCK() AFS_GLOCK()
270 #define AFS_MOVE_UNLOCK() AFS_GUNLOCK()
272 #define AFS_MOVE_LOCK()
273 #define AFS_MOVE_UNLOCK()
275 char bufofzeros[64]; /* gotta fill with something */
276 afs_readdir_move (de, vc, auio, slen, rlen, off)
277 struct DirEntry * de;
289 #if defined(AFS_SUN56_ENV)
290 struct dirent64 *direntp;
293 struct dirent *direntp;
295 #endif /* AFS_SUN56_ENV */
296 #ifndef AFS_SGI53_ENV
297 struct min_direct sdirEntry;
298 #endif /* AFS_SGI53_ENV */
300 AFS_STATCNT(afs_readdir_move);
303 afs_int32 use64BitDirent;
307 use64BitDirent = ABI_IS(ABI_IRIX5_64,
308 GETDENTS_ABI*OSI_GET_CURRENT_ABI(), auio));
310 use64BitDirent = (auio->uio_segflg != UIO_USERSPACE) ? ABI_IRIX5_64 :
311 (ABI_IS(ABI_IRIX5_64 | ABI_IRIX5_N32, u.u_procp->p_abi));
313 #else /* AFS_SGI61_ENV */
314 use64BitDirent = (auio->uio_segflg != UIO_USERSPACE) ? ABI_IRIX5_64 :
315 (ABI_IS(ABI_IRIX5_64, u.u_procp->p_abi));
316 #endif /* AFS_SGI61_ENV */
318 if (use64BitDirent) {
319 struct min_dirent sdirEntry;
320 sdirEntry.d_fileno = (vc->fid.Fid.Volume << 16) + ntohl(de->fid.vnode);
321 FIXUPSTUPIDINODE(sdirEntry.d_fileno);
322 sdirEntry.d_reclen = rlen;
323 sdirEntry.d_off = (off_t)off;
324 AFS_UIOMOVE(&sdirEntry, AFS_DIRENT64BASESIZE, UIO_READ, auio, code);
326 AFS_UIOMOVE(de->name, slen-1, UIO_READ, auio, code);
328 AFS_UIOMOVE(bufofzeros,
329 DIRENTSIZE(slen) - (AFS_DIRENT64BASESIZE + slen - 1),
330 UIO_READ, auio, code);
331 if (DIRENTSIZE(slen) < rlen) {
332 while(DIRENTSIZE(slen) < rlen) {
333 int minLen = rlen - DIRENTSIZE(slen);
334 if (minLen > sizeof(bufofzeros)) minLen = sizeof(bufofzeros);
335 AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
340 struct irix5_min_dirent sdirEntry;
341 sdirEntry.d_fileno = (vc->fid.Fid.Volume << 16) + ntohl(de->fid.vnode);
342 FIXUPSTUPIDINODE(sdirEntry.d_fileno);
343 sdirEntry.d_reclen = rlen;
344 sdirEntry.d_off = (afs_int32)off;
345 AFS_UIOMOVE(&sdirEntry, AFS_DIRENT32BASESIZE, UIO_READ, auio, code);
347 AFS_UIOMOVE(de->name, slen-1, UIO_READ, auio, code);
349 AFS_UIOMOVE(bufofzeros,
350 IRIX5_DIRENTSIZE(slen) -
351 (AFS_DIRENT32BASESIZE + slen - 1),
352 UIO_READ, auio, code);
353 if (IRIX5_DIRENTSIZE(slen) < rlen) {
354 while(IRIX5_DIRENTSIZE(slen) < rlen) {
355 int minLen = rlen - IRIX5_DIRENTSIZE(slen);
356 if (minLen > sizeof(bufofzeros)) minLen = sizeof(bufofzeros);
357 AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
363 #else /* AFS_SGI53_ENV */
365 #if defined(AFS_SUN56_ENV)
366 direntp = (struct dirent64 *) osi_AllocLargeSpace(AFS_LRALLOCSIZ);
368 direntp = (struct dirent *) osi_AllocLargeSpace(AFS_LRALLOCSIZ);
370 direntp->d_ino = (vc->fid.Fid.Volume << 16) + ntohl(de->fid.vnode);
371 FIXUPSTUPIDINODE(direntp->d_ino);
372 direntp->d_off = off;
373 direntp->d_reclen = rlen;
374 strcpy(direntp->d_name, de->name);
375 AFS_UIOMOVE((caddr_t)direntp, rlen, UIO_READ, auio, code);
376 osi_FreeLargeSpace((char *)direntp);
377 #else /* AFS_SUN5_ENV */
378 /* Note the odd mechanism for building the inode number */
379 sdirEntry.d_fileno = (vc->fid.Fid.Volume << 16) +
380 ntohl(de->fid.vnode);
381 FIXUPSTUPIDINODE(sdirEntry.d_fileno);
382 sdirEntry.d_reclen = rlen;
383 #if !defined(AFS_SGI_ENV)
384 sdirEntry.d_namlen = slen;
386 #if defined(AFS_SUN_ENV) || defined(AFS_AIX32_ENV) || defined(AFS_SGI_ENV)
387 sdirEntry.d_off = off;
389 #if defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV)
390 sdirEntry.d_type=afs_readdir_type(vc, de);
393 #if defined(AFS_SGI_ENV)
394 AFS_UIOMOVE(&sdirEntry, DIRENTBASESIZE, UIO_READ, auio, code);
396 AFS_UIOMOVE(de->name, slen-1, UIO_READ, auio, code);
398 AFS_UIOMOVE(bufofzeros, DIRSIZ_LEN(slen) - (DIRENTBASESIZE + slen - 1), UIO_READ, auio, code);
399 #else /* AFS_SGI_ENV */
401 AFS_UIOMOVE((char *)&sdirEntry, sizeof(sdirEntry), UIO_READ, auio, code);
404 AFS_UIOMOVE(de->name, slen, UIO_READ, auio, code);
407 /* pad out the remaining characters with zeros */
409 AFS_UIOMOVE(bufofzeros, ((slen + 4) & ~3) - slen, UIO_READ,
413 #endif /* AFS_SGI_ENV */
415 /* pad out the difference between rlen and slen... */
416 if (DIRSIZ_LEN(slen) < rlen)
419 while(DIRSIZ_LEN(slen) < rlen)
421 int minLen = rlen - DIRSIZ_LEN(slen);
422 if (minLen > sizeof(bufofzeros))
423 minLen = sizeof(bufofzeros);
424 AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
429 #endif /* AFS_SUN5_ENV */
430 #endif /* AFS_SGI53_ENV */
436 *------------------------------------------------------------------------------
438 * Read directory entries.
439 * There are some weird things to look out for here. The uio_offset
440 * field is either 0 or it is the offset returned from a previous
441 * readdir. It is an opaque value used by the server to find the
442 * correct directory block to read. The byte count must be at least
443 * vtoblksz(vp) bytes. The count field is the number of blocks to
444 * read on the server. This is advisory only, the server may return
445 * only one block's worth of entries. Entries may be compressed on
448 * This routine encodes knowledge of Vice dirs.
451 void afs_bulkstat_send( avc, req )
453 struct vrequest * req;
460 * Here is the bad, bad, really bad news.
461 * It has to do with 'offset' (seek locations).
464 #if defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV) || defined(AFS_OSF_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV)
465 afs_readdir(OSI_VC_ARG(avc), auio, acred, eofp)
468 #if defined(AFS_HPUX100_ENV)
469 afs_readdir2(OSI_VC_ARG(avc), auio, acred)
471 afs_readdir(OSI_VC_ARG(avc), auio, acred)
476 struct AFS_UCRED *acred;
478 struct vrequest treq;
479 register struct dcache *tdc;
480 afs_size_t origOffset, tlen;
481 afs_int32 len, dirsiz;
483 struct DirEntry *ode = 0, *nde = 0;
484 int o_slen = 0, n_slen = 0;
486 struct afs_fakestat_state fakestate;
487 #if defined(AFS_SGI53_ENV)
488 afs_int32 use64BitDirent;
489 #endif /* defined(AFS_SGI53_ENV) */
493 * XXX All the hacks for alloced sdirEntry and inlining of afs_readdir_move instead of calling
494 * it is necessary for hpux due to stack problems that seem to occur when coming thru the nfs
495 * translator side XXX
497 struct min_direct *sdirEntry = (struct min_direct *)osi_AllocSmallSpace(sizeof(struct min_direct));
501 /* opaque value is pointer into a vice dir; use bit map to decide
502 if the entries are in use. Always assumed to be valid. 0 is
503 special, means start of a new dir. Int32 inode, followed by
504 short reclen and short namelen. Namelen does not include
505 the null byte. Followed by null-terminated string.
507 AFS_STATCNT(afs_readdir);
509 #if defined(AFS_SGI53_ENV)
512 use64BitDirent = ABI_IS(ABI_IRIX5_64,
513 GETDENTS_ABI(OSI_GET_CURRENT_ABI(), auio));
515 use64BitDirent = (auio->uio_segflg != UIO_USERSPACE) ? ABI_IRIX5_64 :
516 (ABI_IS(ABI_IRIX5_64 | ABI_IRIX5_N32, u.u_procp->p_abi));
517 #endif /* AFS_SGI62_ENV */
518 #else /* AFS_SGI61_ENV */
519 use64BitDirent = (auio->uio_segflg != UIO_USERSPACE) ? ABI_IRIX5_64 :
520 (ABI_IS(ABI_IRIX5_64, u.u_procp->p_abi));
521 #endif /* AFS_SGI61_ENV */
522 #endif /* defined(AFS_SGI53_ENV) */
524 #if defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV) || defined(AFS_OSF_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV)
525 /* Not really used by the callee so we ignore it for now */
528 if ( AfsLargeFileUio(auio) /* file is large than 2 GB */
529 || AfsLargeFileSize(auio->uio_offset, auio->uio_resid) )
532 if (code = afs_InitReq(&treq, acred)) {
534 osi_FreeSmallSpace((char *)sdirEntry);
538 /* update the cache entry */
539 afs_InitFakeStat(&fakestate);
540 code = afs_EvalFakeStat(&avc, &fakestate, &treq);
543 code = afs_VerifyVCache(avc, &treq);
545 /* get a reference to the entire directory */
546 tdc = afs_GetDCache(avc, (afs_size_t) 0, &treq, &origOffset, &tlen, 1);
552 ObtainReadLock(&avc->lock);
553 ObtainReadLock(&tdc->lock);
556 * Make sure that the data in the cache is current. There are two
557 * cases we need to worry about:
558 * 1. The cache data is being fetched by another process.
559 * 2. The cache data is no longer valid
561 while ((avc->states & CStatd)
562 && (tdc->dflags & DFFetching)
563 && hsame(avc->m.DataVersion, tdc->f.versionNo)) {
564 afs_Trace4(afs_iclSetp, CM_TRACE_DCACHEWAIT,
565 ICL_TYPE_STRING, __FILE__,
566 ICL_TYPE_INT32, __LINE__,
567 ICL_TYPE_POINTER, tdc,
568 ICL_TYPE_INT32, tdc->dflags);
569 ReleaseReadLock(&tdc->lock);
570 ReleaseReadLock(&avc->lock);
571 afs_osi_Sleep(&tdc->validPos);
572 ObtainReadLock(&avc->lock);
573 ObtainReadLock(&tdc->lock);
575 if (!(avc->states & CStatd)
576 || !hsame(avc->m.DataVersion, tdc->f.versionNo)) {
577 ReleaseReadLock(&tdc->lock);
578 ReleaseReadLock(&avc->lock);
584 * iterator for the directory reads. Takes the AFS DirEntry
585 * structure and slams them into UFS direct structures.
586 * uses afs_readdir_move to get the struct to the user space.
588 * The routine works by looking ahead one AFS directory entry.
589 * That's because the AFS entry we are currenly working with
590 * may not fit into the buffer the user has provided. If it
591 * doesn't we have to change the size of the LAST AFS directory
592 * entry, so that it will FIT perfectly into the block the
595 * The 'forward looking' of the code makes it a bit tough to read.
596 * Remember we need to get an entry, see if it it fits, then
597 * set it up as the LAST entry, and find the next one.
599 * Tough to take: We give out an EINVAL if we don't have enough
600 * space in the buffer, and at the same time, don't have an entry
601 * to put into the buffer. This CAN happen if the first AFS entry
602 * we get can't fit into the 512 character buffer provided. Seems
603 * it ought not happen...
605 * Assumption: don't need to use anything but one dc entry:
606 * this means the directory ought not be greater than 64k.
610 auio->uio_fpflags = 0;
613 origOffset = auio->afsio_offset;
614 /* scan for the next interesting entry scan for in-use blob otherwise up point at
615 * this blob note that ode, if non-zero, also represents a held dir page */
616 if (!(us = BlobScan(&tdc->f.inode, (origOffset >> 5)) )
617 || !(nde = (struct DirEntry *) afs_dir_GetBlob(&tdc->f.inode, us) ) ) {
618 /* failed to setup nde, return what we've got, and release ode */
620 /* something to hand over. */
622 sdirEntry->d_fileno = (avc->fid.Fid.Volume << 16) + ntohl(ode->fid.vnode);
623 FIXUPSTUPIDINODE(sdirEntry->d_fileno);
624 sdirEntry->d_reclen = rlen = auio->afsio_resid;
625 sdirEntry->d_namlen = o_slen;
626 #if defined(AFS_SUN_ENV) || defined(AFS_AIX32_ENV) || defined(AFS_HPUX100_ENV)
627 sdirEntry->d_off = origOffset;
629 AFS_UIOMOVE((char *)sdirEntry, sizeof(*sdirEntry), UIO_READ, auio, code);
631 AFS_UIOMOVE(ode->name, o_slen, UIO_READ, auio, code);
632 /* pad out the remaining characters with zeros */
634 AFS_UIOMOVE(bufofzeros, ((o_slen + 4) & ~3) - o_slen, UIO_READ, auio, code);
636 /* pad out the difference between rlen and slen... */
637 if (DIRSIZ_LEN(o_slen) < rlen) {
638 while(DIRSIZ_LEN(o_slen) < rlen) {
639 int minLen = rlen - DIRSIZ_LEN(o_slen);
640 if (minLen > sizeof(bufofzeros))
641 minLen = sizeof(bufofzeros);
642 AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
647 code = afs_readdir_move(ode, avc, auio, o_slen,
648 #if defined(AFS_SUN5_ENV)
651 auio->afsio_resid, origOffset);
653 #endif /* AFS_HPUX_ENV */
654 #if !defined(AFS_SUN5_ENV)
655 auio->afsio_resid = 0;
658 /* nothin to hand over */
660 #if defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV) || defined(AFS_OSF_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV)
661 if (eofp) *eofp = 1; /* Set it properly */
663 if (ode) DRelease(ode, 0);
666 /* by here nde is set */
668 /* Do we have enough user space to carry out our mission? */
669 #if defined(AFS_SGI_ENV)
670 n_slen = strlen(nde->name) + 1; /* NULL terminate */
672 n_slen = strlen(nde->name);
675 dirsiz = use64BitDirent ? DIRENTSIZE(n_slen) :
676 IRIX5_DIRENTSIZE(n_slen);
677 if (dirsiz >= (auio->afsio_resid-len)) {
679 if (DIRSIZ_LEN(n_slen) >= (auio->afsio_resid-len)) {
680 #endif /* AFS_SGI53_ENV */
681 /* No can do no more now; ya know... at this time */
682 DRelease (nde, 0); /* can't use this one. */
685 sdirEntry->d_fileno = (avc->fid.Fid.Volume << 16) + ntohl(ode->fid.vnode);
686 FIXUPSTUPIDINODE(sdirEntry->d_fileno);
687 sdirEntry->d_reclen = rlen = auio->afsio_resid;
688 sdirEntry->d_namlen = o_slen;
689 #if defined(AFS_SUN_ENV) || defined(AFS_AIX32_ENV) || defined(AFS_HPUX100_ENV)
690 sdirEntry->d_off = origOffset;
692 AFS_UIOMOVE((char *)sdirEntry, sizeof(*sdirEntry), UIO_READ, auio, code);
694 AFS_UIOMOVE(ode->name, o_slen, UIO_READ, auio, code);
695 /* pad out the remaining characters with zeros */
697 AFS_UIOMOVE(bufofzeros, ((o_slen + 4) & ~3) - o_slen, UIO_READ, auio, code);
699 /* pad out the difference between rlen and slen... */
700 if (DIRSIZ_LEN(o_slen) < rlen) {
701 while(DIRSIZ_LEN(o_slen) < rlen) {
702 int minLen = rlen - DIRSIZ_LEN(o_slen);
703 if (minLen > sizeof(bufofzeros))
704 minLen = sizeof(bufofzeros);
705 AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
709 #else /* AFS_HPUX_ENV */
710 code = afs_readdir_move(ode, avc, auio, o_slen,
711 auio->afsio_resid, origOffset);
712 #endif /* AFS_HPUX_ENV */
713 /* this next line used to be AFSVFS40 or AIX 3.1, but is
715 auio->afsio_offset = origOffset;
716 auio->afsio_resid = 0;
717 } else { /* trouble, can't give anything to the user! */
718 /* even though he has given us a buffer,
719 * even though we have something to give us,
720 * Looks like we lost something somewhere.
724 if (ode) DRelease(ode, 0);
729 * In any event, we move out the LAST de entry, getting ready
730 * to set up for the next one.
734 sdirEntry->d_fileno =
735 (avc->fid.Fid.Volume << 16) + ntohl(ode->fid.vnode);
736 FIXUPSTUPIDINODE(sdirEntry->d_fileno);
737 sdirEntry->d_reclen = rlen = len;
738 sdirEntry->d_namlen = o_slen;
739 #if defined(AFS_SUN_ENV) || defined(AFS_AIX32_ENV) || defined(AFS_HPUX100_ENV)
740 sdirEntry->d_off = origOffset;
742 AFS_UIOMOVE((char *)sdirEntry, sizeof(*sdirEntry), UIO_READ,
745 AFS_UIOMOVE(ode->name, o_slen, UIO_READ, auio, code);
746 /* pad out the remaining characters with zeros */
748 AFS_UIOMOVE(bufofzeros, ((o_slen + 4) & ~3) - o_slen,
749 UIO_READ, auio, code);
751 /* pad out the difference between rlen and slen... */
752 if (DIRSIZ_LEN(o_slen) < rlen) {
753 while(DIRSIZ_LEN(o_slen) < rlen) {
754 int minLen = rlen - DIRSIZ_LEN(o_slen);
755 if (minLen > sizeof(bufofzeros))
756 minLen = sizeof(bufofzeros);
757 AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
761 #else /* AFS_HPUX_ENV */
762 code = afs_readdir_move (ode, avc, auio, o_slen, len, origOffset);
763 #endif /* AFS_HPUX_ENV */
766 len = use64BitDirent ? DIRENTSIZE(o_slen = n_slen) :
767 IRIX5_DIRENTSIZE(o_slen = n_slen);
769 len = DIRSIZ_LEN( o_slen = n_slen );
770 #endif /* AFS_SGI53_ENV */
771 if (ode) DRelease(ode, 0);
773 auio->afsio_offset = (afs_int32)((us + afs_dir_NameBlobs(nde->name)) << 5);
775 if (ode) DRelease(ode, 0);
778 ReleaseReadLock(&tdc->lock);
780 ReleaseReadLock(&avc->lock);
784 osi_FreeSmallSpace((char *)sdirEntry);
786 afs_PutFakeStat(&fakestate);
787 code = afs_CheckCode(code, &treq, 28);
791 #if defined(AFS_HPUX_ENV) || defined(AFS_OSF_ENV)
793 afs1_readdir(avc, auio, acred, eofp)
796 afs1_readdir(avc, auio, acred)
798 register struct vcache *avc;
800 struct AFS_UCRED *acred; {
801 struct vrequest treq;
802 register struct dcache *tdc;
803 afs_size_t origOffset, len;
805 struct DirEntry *ode = 0, *nde = 0;
806 int o_slen = 0, n_slen = 0;
808 #if defined(AFS_HPUX_ENV) || defined(AFS_OSF_ENV)
810 * XXX All the hacks for alloced sdirEntry and inlining of afs_readdir_move instead of calling
811 * it is necessary for hpux due to stack problems that seem to occur when coming thru the nfs
812 * translator side XXX
814 struct minnfs_direct *sdirEntry = (struct minnfs_direct *)osi_AllocSmallSpace(sizeof(struct min_direct));
817 struct afs_fakestat_state fakestate;
819 AFS_STATCNT(afs_readdir);
820 #if defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV) || defined(AFS_OSF_ENV)
823 if (code = afs_InitReq(&treq, acred)) {
825 osi_FreeSmallSpace((char *)sdirEntry);
829 afs_InitFakeStat(&fakestate);
830 code = afs_EvalFakeStat(&avc, &fakestate, &treq);
833 osi_FreeSmallSpace((char *)sdirEntry);
835 afs_PutFakeStat(&fakestate);
838 /* update the cache entry */
840 code = afs_VerifyVCache(avc, &treq);
842 /* get a reference to the entire directory */
843 tdc = afs_GetDCache(avc, (afs_size_t) 0, &treq, &origOffset, &len, 1);
848 ObtainReadLock(&avc->lock);
849 ObtainReadLock(&tdc->lock);
852 * Make sure that the data in the cache is current. There are two
853 * cases we need to worry about:
854 * 1. The cache data is being fetched by another process.
855 * 2. The cache data is no longer valid
857 while ((avc->states & CStatd)
858 && (tdc->dflags & DFFetching)
859 && hsame(avc->m.DataVersion, tdc->f.versionNo)) {
860 afs_Trace4(afs_iclSetp, CM_TRACE_DCACHEWAIT,
861 ICL_TYPE_STRING, __FILE__,
862 ICL_TYPE_INT32, __LINE__,
863 ICL_TYPE_POINTER, tdc,
864 ICL_TYPE_INT32, tdc->dflags);
865 ReleaseReadLock(&tdc->lock);
866 ReleaseReadLock(&avc->lock);
867 afs_osi_Sleep(&tdc->validPos);
868 ObtainReadLock(&avc->lock);
869 ObtainReadLock(&tdc->lock);
871 if (!(avc->states & CStatd)
872 || !hsame(avc->m.DataVersion, tdc->f.versionNo)) {
873 ReleaseReadLock(&tdc->lock);
874 ReleaseReadLock(&avc->lock);
881 auio->uio_fpflags = 0;
884 origOffset = auio->afsio_offset;
886 /* scan for the next interesting entry scan for in-use blob otherwise up point at
887 * this blob note that ode, if non-zero, also represents a held dir page */
888 if (!(us = BlobScan(&tdc->f.inode, (origOffset >> 5)) )
889 || !(nde = (struct DirEntry *) afs_dir_GetBlob(&tdc->f.inode, us) ) ) {
890 /* failed to setup nde, return what we've got, and release ode */
892 /* something to hand over. */
893 #if defined(AFS_HPUX_ENV) || defined(AFS_OSF_ENV)
894 sdirEntry->d_fileno = (avc->fid.Fid.Volume << 16) + ntohl(ode->fid.vnode);
895 FIXUPSTUPIDINODE(sdirEntry->d_fileno);
896 sdirEntry->d_reclen = rlen = auio->afsio_resid;
897 sdirEntry->d_namlen = o_slen;
898 sdirEntry->d_off = origOffset;
899 AFS_UIOMOVE((char *)sdirEntry, sizeof(*sdirEntry), UIO_READ, auio, code);
901 AFS_UIOMOVE(ode->name, o_slen, UIO_READ, auio, code);
903 /* pad out the remaining characters with zeros */
905 AFS_UIOMOVE(bufofzeros, ((o_slen + 4) & ~3) - o_slen, UIO_READ, auio, code);
907 /* pad out the difference between rlen and slen... */
908 if (NDIRSIZ_LEN(o_slen) < rlen) {
909 while(NDIRSIZ_LEN(o_slen) < rlen) {
910 int minLen = rlen - NDIRSIZ_LEN(o_slen);
911 if (minLen > sizeof(bufofzeros))
912 minLen = sizeof(bufofzeros);
913 AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
918 code = afs_readdir_move(ode, avc, auio, o_slen,
919 auio->afsio_resid, origOffset);
920 #endif /* AFS_HPUX_ENV */
921 auio->afsio_resid = 0;
923 /* nothin to hand over */
925 #if defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV) || defined(AFS_OSF_ENV)
928 if (ode) DRelease(ode, 0);
931 /* by here nde is set */
933 /* Do we have enough user space to carry out our mission? */
934 #if defined(AFS_SGI_ENV)
935 n_slen = strlen(nde->name) + 1; /* NULL terminate */
937 n_slen = strlen(nde->name);
939 if (NDIRSIZ_LEN(n_slen) >= (auio->afsio_resid-len)) {
940 /* No can do no more now; ya know... at this time */
941 DRelease (nde, 0); /* can't use this one. */
943 #if defined(AFS_HPUX_ENV) || defined(AFS_OSF_ENV)
944 sdirEntry->d_fileno = (avc->fid.Fid.Volume << 16) + ntohl(ode->fid.vnode);
945 FIXUPSTUPIDINODE(sdirEntry->d_fileno);
946 sdirEntry->d_reclen = rlen = auio->afsio_resid;
947 sdirEntry->d_namlen = o_slen;
948 sdirEntry->d_off = origOffset;
949 AFS_UIOMOVE((char *)sdirEntry, sizeof(*sdirEntry), UIO_READ, auio, code);
951 AFS_UIOMOVE(ode->name, o_slen, UIO_READ, auio, code);
952 /* pad out the remaining characters with zeros */
954 AFS_UIOMOVE(bufofzeros, ((o_slen + 4) & ~3) - o_slen, UIO_READ, auio, code);
956 /* pad out the difference between rlen and slen... */
957 if (NDIRSIZ_LEN(o_slen) < rlen) {
958 while(NDIRSIZ_LEN(o_slen) < rlen) {
959 int minLen = rlen - NDIRSIZ_LEN(o_slen);
960 if (minLen > sizeof(bufofzeros))
961 minLen = sizeof(bufofzeros);
962 AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
967 code = afs_readdir_move(ode, avc, auio, o_slen,
968 auio->afsio_resid, origOffset);
969 #endif /* AFS_HPUX_ENV */
970 /* this next line used to be AFSVFS40 or AIX 3.1, but is really generic */
971 auio->afsio_offset = origOffset;
972 auio->afsio_resid = 0;
973 } else { /* trouble, can't give anything to the user! */
974 /* even though he has given us a buffer,
975 * even though we have something to give us,
976 * Looks like we lost something somewhere.
980 if (ode) DRelease(ode, 0);
985 * In any event, we move out the LAST de entry, getting ready
986 * to set up for the next one.
989 #if defined(AFS_HPUX_ENV) || defined(AFS_OSF_ENV)
990 sdirEntry->d_fileno = (avc->fid.Fid.Volume << 16) + ntohl(ode->fid.vnode);
991 FIXUPSTUPIDINODE(sdirEntry->d_fileno);
992 sdirEntry->d_reclen = rlen = len;
993 sdirEntry->d_namlen = o_slen;
994 sdirEntry->d_off = origOffset;
995 AFS_UIOMOVE((char *)sdirEntry, sizeof(*sdirEntry), UIO_READ, auio, code);
997 AFS_UIOMOVE(ode->name, o_slen, UIO_READ, auio, code);
998 /* pad out the remaining characters with zeros */
1000 AFS_UIOMOVE(bufofzeros, ((o_slen + 4) & ~3) - o_slen, UIO_READ, auio, code);
1002 /* pad out the difference between rlen and slen... */
1003 if (NDIRSIZ_LEN(o_slen) < rlen) {
1004 while(NDIRSIZ_LEN(o_slen) < rlen) {
1005 int minLen = rlen - NDIRSIZ_LEN(o_slen);
1006 if (minLen > sizeof(bufofzeros))
1007 minLen = sizeof(bufofzeros);
1008 AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
1013 code = afs_readdir_move (ode, avc, auio, o_slen, len, origOffset);
1014 #endif /* AFS_HPUX_ENV */
1016 len = NDIRSIZ_LEN( o_slen = n_slen );
1017 if (ode) DRelease(ode, 0);
1019 auio->afsio_offset = ((us + afs_dir_NameBlobs(nde->name)) << 5);
1021 if (ode) DRelease(ode, 0);
1024 ReleaseReadLock(&tdc->lock);
1026 ReleaseReadLock(&avc->lock);
1029 #if defined(AFS_HPUX_ENV) || defined(AFS_OSF_ENV)
1030 osi_FreeSmallSpace((char *)sdirEntry);
1032 afs_PutFakeStat(&fakestate);
1033 code = afs_CheckCode(code, &treq, 29);
1038 #endif /* !AFS_LINUX20_ENV */