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 #ifdef AFS_DARWIN_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 */
230 #define AFS_MOVE_LOCK() AFS_GLOCK()
231 #define AFS_MOVE_UNLOCK() AFS_GUNLOCK()
233 #define AFS_MOVE_LOCK()
234 #define AFS_MOVE_UNLOCK()
237 char bufofzeros[64]; /* gotta fill with something */
238 afs_readdir_move (de, vc, auio, slen, rlen, off)
239 struct DirEntry * de;
251 #if defined(AFS_SUN56_ENV)
252 struct dirent64 *direntp;
255 struct dirent *direntp;
257 #endif /* AFS_SUN56_ENV */
258 #ifndef AFS_SGI53_ENV
259 struct min_direct sdirEntry;
260 #endif /* AFS_SGI53_ENV */
262 AFS_STATCNT(afs_readdir_move);
265 afs_int32 use64BitDirent;
269 use64BitDirent = ABI_IS(ABI_IRIX5_64,
270 GETDENTS_ABI*OSI_GET_CURRENT_ABI(), auio));
272 use64BitDirent = (auio->uio_segflg != UIO_USERSPACE) ? ABI_IRIX5_64 :
273 (ABI_IS(ABI_IRIX5_64 | ABI_IRIX5_N32, u.u_procp->p_abi));
275 #else /* AFS_SGI61_ENV */
276 use64BitDirent = (auio->uio_segflg != UIO_USERSPACE) ? ABI_IRIX5_64 :
277 (ABI_IS(ABI_IRIX5_64, u.u_procp->p_abi));
278 #endif /* AFS_SGI61_ENV */
280 if (use64BitDirent) {
281 struct min_dirent sdirEntry;
282 sdirEntry.d_fileno = (vc->fid.Fid.Volume << 16) + ntohl(de->fid.vnode);
283 FIXUPSTUPIDINODE(sdirEntry.d_fileno);
284 sdirEntry.d_reclen = rlen;
285 sdirEntry.d_off = (off_t)off;
286 AFS_UIOMOVE(&sdirEntry, AFS_DIRENT64BASESIZE, UIO_READ, auio, code);
288 AFS_UIOMOVE(de->name, slen-1, UIO_READ, auio, code);
290 AFS_UIOMOVE(bufofzeros,
291 DIRENTSIZE(slen) - (AFS_DIRENT64BASESIZE + slen - 1),
292 UIO_READ, auio, code);
293 if (DIRENTSIZE(slen) < rlen) {
294 while(DIRENTSIZE(slen) < rlen) {
295 int minLen = rlen - DIRENTSIZE(slen);
296 if (minLen > sizeof(bufofzeros)) minLen = sizeof(bufofzeros);
297 AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
302 struct irix5_min_dirent sdirEntry;
303 sdirEntry.d_fileno = (vc->fid.Fid.Volume << 16) + ntohl(de->fid.vnode);
304 FIXUPSTUPIDINODE(sdirEntry.d_fileno);
305 sdirEntry.d_reclen = rlen;
306 sdirEntry.d_off = (afs_int32)off;
307 AFS_UIOMOVE(&sdirEntry, AFS_DIRENT32BASESIZE, UIO_READ, auio, code);
309 AFS_UIOMOVE(de->name, slen-1, UIO_READ, auio, code);
311 AFS_UIOMOVE(bufofzeros,
312 IRIX5_DIRENTSIZE(slen) -
313 (AFS_DIRENT32BASESIZE + slen - 1),
314 UIO_READ, auio, code);
315 if (IRIX5_DIRENTSIZE(slen) < rlen) {
316 while(IRIX5_DIRENTSIZE(slen) < rlen) {
317 int minLen = rlen - IRIX5_DIRENTSIZE(slen);
318 if (minLen > sizeof(bufofzeros)) minLen = sizeof(bufofzeros);
319 AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
325 #else /* AFS_SGI53_ENV */
327 #if defined(AFS_SUN56_ENV)
328 direntp = (struct dirent64 *) osi_AllocLargeSpace(AFS_LRALLOCSIZ);
330 direntp = (struct dirent *) osi_AllocLargeSpace(AFS_LRALLOCSIZ);
332 direntp->d_ino = (vc->fid.Fid.Volume << 16) + ntohl(de->fid.vnode);
333 FIXUPSTUPIDINODE(direntp->d_ino);
334 direntp->d_off = off;
335 direntp->d_reclen = rlen;
336 strcpy(direntp->d_name, de->name);
337 AFS_UIOMOVE((caddr_t)direntp, rlen, UIO_READ, auio, code);
338 osi_FreeLargeSpace((char *)direntp);
339 #else /* AFS_SUN5_ENV */
340 /* Note the odd mechanism for building the inode number */
341 sdirEntry.d_fileno = (vc->fid.Fid.Volume << 16) +
342 ntohl(de->fid.vnode);
343 FIXUPSTUPIDINODE(sdirEntry.d_fileno);
344 sdirEntry.d_reclen = rlen;
345 #if !defined(AFS_SGI_ENV)
346 sdirEntry.d_namlen = slen;
348 #if defined(AFS_SUN_ENV) || defined(AFS_AIX32_ENV) || defined(AFS_SGI_ENV)
349 sdirEntry.d_off = off;
351 #if defined(AFS_DARWIN_ENV)
352 sdirEntry.d_type=DT_UNKNOWN;
355 #if defined(AFS_SGI_ENV)
356 AFS_UIOMOVE(&sdirEntry, DIRENTBASESIZE, UIO_READ, auio, code);
358 AFS_UIOMOVE(de->name, slen-1, UIO_READ, auio, code);
360 AFS_UIOMOVE(bufofzeros, DIRSIZ_LEN(slen) - (DIRENTBASESIZE + slen - 1), UIO_READ, auio, code);
361 #else /* AFS_SGI_ENV */
363 AFS_UIOMOVE((char *)&sdirEntry, sizeof(sdirEntry), UIO_READ, auio, code);
366 AFS_UIOMOVE(de->name, slen, UIO_READ, auio, code);
369 /* pad out the remaining characters with zeros */
371 AFS_UIOMOVE(bufofzeros, ((slen + 4) & ~3) - slen, UIO_READ,
375 #endif /* AFS_SGI_ENV */
377 /* pad out the difference between rlen and slen... */
378 if (DIRSIZ_LEN(slen) < rlen)
381 while(DIRSIZ_LEN(slen) < rlen)
383 int minLen = rlen - DIRSIZ_LEN(slen);
384 if (minLen > sizeof(bufofzeros))
385 minLen = sizeof(bufofzeros);
386 AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
391 #endif /* AFS_SUN5_ENV */
392 #endif /* AFS_SGI53_ENV */
398 *------------------------------------------------------------------------------
400 * Read directory entries.
401 * There are some weird things to look out for here. The uio_offset
402 * field is either 0 or it is the offset returned from a previous
403 * readdir. It is an opaque value used by the server to find the
404 * correct directory block to read. The byte count must be at least
405 * vtoblksz(vp) bytes. The count field is the number of blocks to
406 * read on the server. This is advisory only, the server may return
407 * only one block's worth of entries. Entries may be compressed on
410 * This routine encodes knowledge of Vice dirs.
413 void afs_bulkstat_send( avc, req )
415 struct vrequest * req;
422 * Here is the bad, bad, really bad news.
423 * It has to do with 'offset' (seek locations).
426 #if defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV) || defined(AFS_OSF_ENV) || defined(AFS_DARWIN_ENV)
427 afs_readdir(OSI_VC_ARG(avc), auio, acred, eofp)
430 #if defined(AFS_HPUX100_ENV)
431 afs_readdir2(OSI_VC_ARG(avc), auio, acred)
433 afs_readdir(OSI_VC_ARG(avc), auio, acred)
438 struct AFS_UCRED *acred;
440 struct vrequest treq;
441 register struct dcache *tdc;
442 afs_size_t origOffset, tlen;
443 afs_int32 len, dirsiz;
445 struct DirEntry *ode = 0, *nde = 0;
446 int o_slen = 0, n_slen = 0;
448 #if defined(AFS_SGI53_ENV)
449 afs_int32 use64BitDirent;
450 #endif /* defined(AFS_SGI53_ENV) */
454 * XXX All the hacks for alloced sdirEntry and inlining of afs_readdir_move instead of calling
455 * it is necessary for hpux due to stack problems that seem to occur when coming thru the nfs
456 * translator side XXX
458 struct min_direct *sdirEntry = (struct min_direct *)osi_AllocSmallSpace(sizeof(struct min_direct));
462 /* opaque value is pointer into a vice dir; use bit map to decide
463 if the entries are in use. Always assumed to be valid. 0 is
464 special, means start of a new dir. Int32 inode, followed by
465 short reclen and short namelen. Namelen does not include
466 the null byte. Followed by null-terminated string.
468 AFS_STATCNT(afs_readdir);
470 #if defined(AFS_SGI53_ENV)
473 use64BitDirent = ABI_IS(ABI_IRIX5_64,
474 GETDENTS_ABI(OSI_GET_CURRENT_ABI(), auio));
476 use64BitDirent = (auio->uio_segflg != UIO_USERSPACE) ? ABI_IRIX5_64 :
477 (ABI_IS(ABI_IRIX5_64 | ABI_IRIX5_N32, u.u_procp->p_abi));
478 #endif /* AFS_SGI62_ENV */
479 #else /* AFS_SGI61_ENV */
480 use64BitDirent = (auio->uio_segflg != UIO_USERSPACE) ? ABI_IRIX5_64 :
481 (ABI_IS(ABI_IRIX5_64, u.u_procp->p_abi));
482 #endif /* AFS_SGI61_ENV */
483 #endif /* defined(AFS_SGI53_ENV) */
485 #if defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV) || defined(AFS_OSF_ENV) || defined(AFS_DARWIN_ENV)
486 /* Not really used by the callee so we ignore it for now */
489 if ( AfsLargeFileUio(auio) /* file is large than 2 GB */
490 || AfsLargeFileSize(auio->uio_offset, auio->uio_resid) )
493 if (code = afs_InitReq(&treq, acred)) {
495 osi_FreeSmallSpace((char *)sdirEntry);
499 /* update the cache entry */
501 code = afs_VerifyVCache(avc, &treq);
503 /* get a reference to the entire directory */
504 tdc = afs_GetDCache(avc, (afs_size_t) 0, &treq, &origOffset, &tlen, 1);
510 ObtainReadLock(&avc->lock);
511 ObtainReadLock(&tdc->lock);
514 * Make sure that the data in the cache is current. There are two
515 * cases we need to worry about:
516 * 1. The cache data is being fetched by another process.
517 * 2. The cache data is no longer valid
519 while ((avc->states & CStatd)
520 && (tdc->dflags & DFFetching)
521 && hsame(avc->m.DataVersion, tdc->f.versionNo)) {
522 afs_Trace4(afs_iclSetp, CM_TRACE_DCACHEWAIT,
523 ICL_TYPE_STRING, __FILE__,
524 ICL_TYPE_INT32, __LINE__,
525 ICL_TYPE_POINTER, tdc,
526 ICL_TYPE_INT32, tdc->dflags);
527 ReleaseReadLock(&tdc->lock);
528 ReleaseReadLock(&avc->lock);
529 afs_osi_Sleep(&tdc->validPos);
530 ObtainReadLock(&avc->lock);
531 ObtainReadLock(&tdc->lock);
533 if (!(avc->states & CStatd)
534 || !hsame(avc->m.DataVersion, tdc->f.versionNo)) {
535 ReleaseReadLock(&tdc->lock);
536 ReleaseReadLock(&avc->lock);
542 * iterator for the directory reads. Takes the AFS DirEntry
543 * structure and slams them into UFS direct structures.
544 * uses afs_readdir_move to get the struct to the user space.
546 * The routine works by looking ahead one AFS directory entry.
547 * That's because the AFS entry we are currenly working with
548 * may not fit into the buffer the user has provided. If it
549 * doesn't we have to change the size of the LAST AFS directory
550 * entry, so that it will FIT perfectly into the block the
553 * The 'forward looking' of the code makes it a bit tough to read.
554 * Remember we need to get an entry, see if it it fits, then
555 * set it up as the LAST entry, and find the next one.
557 * Tough to take: We give out an EINVAL if we don't have enough
558 * space in the buffer, and at the same time, don't have an entry
559 * to put into the buffer. This CAN happen if the first AFS entry
560 * we get can't fit into the 512 character buffer provided. Seems
561 * it ought not happen...
563 * Assumption: don't need to use anything but one dc entry:
564 * this means the directory ought not be greater than 64k.
568 auio->uio_fpflags = 0;
571 origOffset = auio->afsio_offset;
572 /* scan for the next interesting entry scan for in-use blob otherwise up point at
573 * this blob note that ode, if non-zero, also represents a held dir page */
574 if (!(us = BlobScan(&tdc->f.inode, (origOffset >> 5)) )
575 || !(nde = (struct DirEntry *) afs_dir_GetBlob(&tdc->f.inode, us) ) ) {
576 /* failed to setup nde, return what we've got, and release ode */
578 /* something to hand over. */
580 sdirEntry->d_fileno = (avc->fid.Fid.Volume << 16) + ntohl(ode->fid.vnode);
581 FIXUPSTUPIDINODE(sdirEntry->d_fileno);
582 sdirEntry->d_reclen = rlen = auio->afsio_resid;
583 sdirEntry->d_namlen = o_slen;
584 #if defined(AFS_SUN_ENV) || defined(AFS_AIX32_ENV) || defined(AFS_HPUX100_ENV)
585 sdirEntry->d_off = origOffset;
587 AFS_UIOMOVE((char *)sdirEntry, sizeof(*sdirEntry), UIO_READ, auio, code);
589 AFS_UIOMOVE(ode->name, o_slen, UIO_READ, auio, code);
590 /* pad out the remaining characters with zeros */
592 AFS_UIOMOVE(bufofzeros, ((o_slen + 4) & ~3) - o_slen, UIO_READ, auio, code);
594 /* pad out the difference between rlen and slen... */
595 if (DIRSIZ_LEN(o_slen) < rlen) {
596 while(DIRSIZ_LEN(o_slen) < rlen) {
597 int minLen = rlen - DIRSIZ_LEN(o_slen);
598 if (minLen > sizeof(bufofzeros))
599 minLen = sizeof(bufofzeros);
600 AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
605 code = afs_readdir_move(ode, avc, auio, o_slen,
606 #if defined(AFS_SUN5_ENV)
609 auio->afsio_resid, origOffset);
611 #endif /* AFS_HPUX_ENV */
612 #if !defined(AFS_SUN5_ENV)
613 auio->afsio_resid = 0;
616 /* nothin to hand over */
618 #if defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV) || defined(AFS_OSF_ENV)
619 if (eofp) *eofp = 1; /* Set it properly */
621 if (ode) DRelease(ode, 0);
624 /* by here nde is set */
626 /* Do we have enough user space to carry out our mission? */
627 #if defined(AFS_SGI_ENV)
628 n_slen = strlen(nde->name) + 1; /* NULL terminate */
630 n_slen = strlen(nde->name);
633 dirsiz = use64BitDirent ? DIRENTSIZE(n_slen) :
634 IRIX5_DIRENTSIZE(n_slen);
635 if (dirsiz >= (auio->afsio_resid-len)) {
637 if (DIRSIZ_LEN(n_slen) >= (auio->afsio_resid-len)) {
638 #endif /* AFS_SGI53_ENV */
639 /* No can do no more now; ya know... at this time */
640 DRelease (nde, 0); /* can't use this one. */
643 sdirEntry->d_fileno = (avc->fid.Fid.Volume << 16) + ntohl(ode->fid.vnode);
644 FIXUPSTUPIDINODE(sdirEntry->d_fileno);
645 sdirEntry->d_reclen = rlen = auio->afsio_resid;
646 sdirEntry->d_namlen = o_slen;
647 #if defined(AFS_SUN_ENV) || defined(AFS_AIX32_ENV) || defined(AFS_HPUX100_ENV)
648 sdirEntry->d_off = origOffset;
650 AFS_UIOMOVE((char *)sdirEntry, sizeof(*sdirEntry), UIO_READ, auio, code);
652 AFS_UIOMOVE(ode->name, o_slen, UIO_READ, auio, code);
653 /* pad out the remaining characters with zeros */
655 AFS_UIOMOVE(bufofzeros, ((o_slen + 4) & ~3) - o_slen, UIO_READ, auio, code);
657 /* pad out the difference between rlen and slen... */
658 if (DIRSIZ_LEN(o_slen) < rlen) {
659 while(DIRSIZ_LEN(o_slen) < rlen) {
660 int minLen = rlen - DIRSIZ_LEN(o_slen);
661 if (minLen > sizeof(bufofzeros))
662 minLen = sizeof(bufofzeros);
663 AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
667 #else /* AFS_HPUX_ENV */
668 code = afs_readdir_move(ode, avc, auio, o_slen,
669 auio->afsio_resid, origOffset);
670 #endif /* AFS_HPUX_ENV */
671 /* this next line used to be AFSVFS40 or AIX 3.1, but is
673 auio->afsio_offset = origOffset;
674 auio->afsio_resid = 0;
675 } else { /* trouble, can't give anything to the user! */
676 /* even though he has given us a buffer,
677 * even though we have something to give us,
678 * Looks like we lost something somewhere.
682 if (ode) DRelease(ode, 0);
687 * In any event, we move out the LAST de entry, getting ready
688 * to set up for the next one.
692 sdirEntry->d_fileno =
693 (avc->fid.Fid.Volume << 16) + ntohl(ode->fid.vnode);
694 FIXUPSTUPIDINODE(sdirEntry->d_fileno);
695 sdirEntry->d_reclen = rlen = len;
696 sdirEntry->d_namlen = o_slen;
697 #if defined(AFS_SUN_ENV) || defined(AFS_AIX32_ENV) || defined(AFS_HPUX100_ENV)
698 sdirEntry->d_off = origOffset;
700 AFS_UIOMOVE((char *)sdirEntry, sizeof(*sdirEntry), UIO_READ,
703 AFS_UIOMOVE(ode->name, o_slen, UIO_READ, auio, code);
704 /* pad out the remaining characters with zeros */
706 AFS_UIOMOVE(bufofzeros, ((o_slen + 4) & ~3) - o_slen,
707 UIO_READ, auio, code);
709 /* pad out the difference between rlen and slen... */
710 if (DIRSIZ_LEN(o_slen) < rlen) {
711 while(DIRSIZ_LEN(o_slen) < rlen) {
712 int minLen = rlen - DIRSIZ_LEN(o_slen);
713 if (minLen > sizeof(bufofzeros))
714 minLen = sizeof(bufofzeros);
715 AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
719 #else /* AFS_HPUX_ENV */
720 code = afs_readdir_move (ode, avc, auio, o_slen, len, origOffset);
721 #endif /* AFS_HPUX_ENV */
724 len = use64BitDirent ? DIRENTSIZE(o_slen = n_slen) :
725 IRIX5_DIRENTSIZE(o_slen = n_slen);
727 len = DIRSIZ_LEN( o_slen = n_slen );
728 #endif /* AFS_SGI53_ENV */
729 if (ode) DRelease(ode, 0);
731 auio->afsio_offset = (afs_int32)((us + afs_dir_NameBlobs(nde->name)) << 5);
733 if (ode) DRelease(ode, 0);
736 ReleaseReadLock(&tdc->lock);
738 ReleaseReadLock(&avc->lock);
742 osi_FreeSmallSpace((char *)sdirEntry);
744 code = afs_CheckCode(code, &treq, 28);
748 #if defined(AFS_HPUX_ENV) || defined(AFS_OSF_ENV)
750 afs1_readdir(avc, auio, acred, eofp)
753 afs1_readdir(avc, auio, acred)
755 register struct vcache *avc;
757 struct AFS_UCRED *acred; {
758 struct vrequest treq;
759 register struct dcache *tdc;
760 afs_size_t origOffset, len;
762 struct DirEntry *ode = 0, *nde = 0;
763 int o_slen = 0, n_slen = 0;
765 #if defined(AFS_HPUX_ENV) || defined(AFS_OSF_ENV)
767 * XXX All the hacks for alloced sdirEntry and inlining of afs_readdir_move instead of calling
768 * it is necessary for hpux due to stack problems that seem to occur when coming thru the nfs
769 * translator side XXX
771 struct minnfs_direct *sdirEntry = (struct minnfs_direct *)osi_AllocSmallSpace(sizeof(struct min_direct));
775 AFS_STATCNT(afs_readdir);
776 #if defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV) || defined(AFS_OSF_ENV)
779 if (code = afs_InitReq(&treq, acred)) {
781 osi_FreeSmallSpace((char *)sdirEntry);
785 /* update the cache entry */
787 code = afs_VerifyVCache(avc, &treq);
789 /* get a reference to the entire directory */
790 tdc = afs_GetDCache(avc, (afs_size_t) 0, &treq, &origOffset, &len, 1);
795 ObtainReadLock(&avc->lock);
796 ObtainReadLock(&tdc->lock);
799 * Make sure that the data in the cache is current. There are two
800 * cases we need to worry about:
801 * 1. The cache data is being fetched by another process.
802 * 2. The cache data is no longer valid
804 while ((avc->states & CStatd)
805 && (tdc->dflags & DFFetching)
806 && hsame(avc->m.DataVersion, tdc->f.versionNo)) {
807 afs_Trace4(afs_iclSetp, CM_TRACE_DCACHEWAIT,
808 ICL_TYPE_STRING, __FILE__,
809 ICL_TYPE_INT32, __LINE__,
810 ICL_TYPE_POINTER, tdc,
811 ICL_TYPE_INT32, tdc->dflags);
812 ReleaseReadLock(&tdc->lock);
813 ReleaseReadLock(&avc->lock);
814 afs_osi_Sleep(&tdc->validPos);
815 ObtainReadLock(&avc->lock);
816 ObtainReadLock(&tdc->lock);
818 if (!(avc->states & CStatd)
819 || !hsame(avc->m.DataVersion, tdc->f.versionNo)) {
820 ReleaseReadLock(&tdc->lock);
821 ReleaseReadLock(&avc->lock);
828 auio->uio_fpflags = 0;
831 origOffset = auio->afsio_offset;
833 /* scan for the next interesting entry scan for in-use blob otherwise up point at
834 * this blob note that ode, if non-zero, also represents a held dir page */
835 if (!(us = BlobScan(&tdc->f.inode, (origOffset >> 5)) )
836 || !(nde = (struct DirEntry *) afs_dir_GetBlob(&tdc->f.inode, us) ) ) {
837 /* failed to setup nde, return what we've got, and release ode */
839 /* something to hand over. */
840 #if defined(AFS_HPUX_ENV) || defined(AFS_OSF_ENV)
841 sdirEntry->d_fileno = (avc->fid.Fid.Volume << 16) + ntohl(ode->fid.vnode);
842 FIXUPSTUPIDINODE(sdirEntry->d_fileno);
843 sdirEntry->d_reclen = rlen = auio->afsio_resid;
844 sdirEntry->d_namlen = o_slen;
845 sdirEntry->d_off = origOffset;
846 AFS_UIOMOVE((char *)sdirEntry, sizeof(*sdirEntry), UIO_READ, auio, code);
848 AFS_UIOMOVE(ode->name, o_slen, UIO_READ, auio, code);
850 /* pad out the remaining characters with zeros */
852 AFS_UIOMOVE(bufofzeros, ((o_slen + 4) & ~3) - o_slen, UIO_READ, auio, code);
854 /* pad out the difference between rlen and slen... */
855 if (NDIRSIZ_LEN(o_slen) < rlen) {
856 while(NDIRSIZ_LEN(o_slen) < rlen) {
857 int minLen = rlen - NDIRSIZ_LEN(o_slen);
858 if (minLen > sizeof(bufofzeros))
859 minLen = sizeof(bufofzeros);
860 AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
865 code = afs_readdir_move(ode, avc, auio, o_slen,
866 auio->afsio_resid, origOffset);
867 #endif /* AFS_HPUX_ENV */
868 auio->afsio_resid = 0;
870 /* nothin to hand over */
872 #if defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV) || defined(AFS_OSF_ENV)
875 if (ode) DRelease(ode, 0);
878 /* by here nde is set */
880 /* Do we have enough user space to carry out our mission? */
881 #if defined(AFS_SGI_ENV)
882 n_slen = strlen(nde->name) + 1; /* NULL terminate */
884 n_slen = strlen(nde->name);
886 if (NDIRSIZ_LEN(n_slen) >= (auio->afsio_resid-len)) {
887 /* No can do no more now; ya know... at this time */
888 DRelease (nde, 0); /* can't use this one. */
890 #if defined(AFS_HPUX_ENV) || defined(AFS_OSF_ENV)
891 sdirEntry->d_fileno = (avc->fid.Fid.Volume << 16) + ntohl(ode->fid.vnode);
892 FIXUPSTUPIDINODE(sdirEntry->d_fileno);
893 sdirEntry->d_reclen = rlen = auio->afsio_resid;
894 sdirEntry->d_namlen = o_slen;
895 sdirEntry->d_off = origOffset;
896 AFS_UIOMOVE((char *)sdirEntry, sizeof(*sdirEntry), UIO_READ, auio, code);
898 AFS_UIOMOVE(ode->name, o_slen, UIO_READ, auio, code);
899 /* pad out the remaining characters with zeros */
901 AFS_UIOMOVE(bufofzeros, ((o_slen + 4) & ~3) - o_slen, UIO_READ, auio, code);
903 /* pad out the difference between rlen and slen... */
904 if (NDIRSIZ_LEN(o_slen) < rlen) {
905 while(NDIRSIZ_LEN(o_slen) < rlen) {
906 int minLen = rlen - NDIRSIZ_LEN(o_slen);
907 if (minLen > sizeof(bufofzeros))
908 minLen = sizeof(bufofzeros);
909 AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
914 code = afs_readdir_move(ode, avc, auio, o_slen,
915 auio->afsio_resid, origOffset);
916 #endif /* AFS_HPUX_ENV */
917 /* this next line used to be AFSVFS40 or AIX 3.1, but is really generic */
918 auio->afsio_offset = origOffset;
919 auio->afsio_resid = 0;
920 } else { /* trouble, can't give anything to the user! */
921 /* even though he has given us a buffer,
922 * even though we have something to give us,
923 * Looks like we lost something somewhere.
927 if (ode) DRelease(ode, 0);
932 * In any event, we move out the LAST de entry, getting ready
933 * to set up for the next one.
936 #if defined(AFS_HPUX_ENV) || defined(AFS_OSF_ENV)
937 sdirEntry->d_fileno = (avc->fid.Fid.Volume << 16) + ntohl(ode->fid.vnode);
938 FIXUPSTUPIDINODE(sdirEntry->d_fileno);
939 sdirEntry->d_reclen = rlen = len;
940 sdirEntry->d_namlen = o_slen;
941 sdirEntry->d_off = origOffset;
942 AFS_UIOMOVE((char *)sdirEntry, sizeof(*sdirEntry), UIO_READ, auio, code);
944 AFS_UIOMOVE(ode->name, o_slen, UIO_READ, auio, code);
945 /* pad out the remaining characters with zeros */
947 AFS_UIOMOVE(bufofzeros, ((o_slen + 4) & ~3) - o_slen, UIO_READ, auio, code);
949 /* pad out the difference between rlen and slen... */
950 if (NDIRSIZ_LEN(o_slen) < rlen) {
951 while(NDIRSIZ_LEN(o_slen) < rlen) {
952 int minLen = rlen - NDIRSIZ_LEN(o_slen);
953 if (minLen > sizeof(bufofzeros))
954 minLen = sizeof(bufofzeros);
955 AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
960 code = afs_readdir_move (ode, avc, auio, o_slen, len, origOffset);
961 #endif /* AFS_HPUX_ENV */
963 len = NDIRSIZ_LEN( o_slen = n_slen );
964 if (ode) DRelease(ode, 0);
966 auio->afsio_offset = ((us + afs_dir_NameBlobs(nde->name)) << 5);
968 if (ode) DRelease(ode, 0);
971 ReleaseReadLock(&tdc->lock);
973 ReleaseReadLock(&avc->lock);
976 #if defined(AFS_HPUX_ENV) || defined(AFS_OSF_ENV)
977 osi_FreeSmallSpace((char *)sdirEntry);
979 code = afs_CheckCode(code, &treq, 29);
984 #endif /* !AFS_LINUX20_ENV */