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 "../afs/param.h" /* Should be always first */
23 #include "../afs/sysincludes.h" /* Standard vendor system headers */
24 #include "../afs/afsincludes.h" /* Afs-based standard headers */
25 #include "../afs/afs_stats.h" /* statistics */
26 #include "../afs/afs_cbqueue.h"
27 #include "../afs/nfsclient.h"
28 #include "../afs/afs_osidnlc.h"
32 * A few definitions. This is until we have a proper header file
33 * which ahs prototypes for all functions
36 extern struct DirEntry * afs_dir_GetBlob();
38 * AFS readdir vnodeop and bulk stat support.
41 /* Saber C hates negative inode #s. We're not going to talk about software
42 * that could fail if it sees a negative inode #.
44 #define FIXUPSTUPIDINODE(a) ((a) &= 0x7fffffff)
46 /* BlobScan is supposed to ensure that the blob reference refers to a valid
47 directory entry. It consults the allocation map in the page header
48 to determine whether a blob is actually in use or not.
50 More formally, BlobScan is supposed to return a new blob number which is just like
51 the input parameter, only it is advanced over header or free blobs.
53 Note that BlobScan switches pages if necessary. BlobScan may return
54 either 0 or an out-of-range blob number for end of file.
56 BlobScan is used by the Linux port in a separate file, so it should not
59 #if defined(AFS_SGI62_ENV) || defined(AFS_SUN57_64BIT_ENV)
60 int BlobScan(ino64_t *afile, afs_int32 ablob)
62 #ifdef AFS_LINUX_64BIT_KERNEL
63 int BlobScan(long *afile, afs_int32 ablob)
65 int BlobScan(afs_int32 *afile, afs_int32 ablob)
69 register afs_int32 relativeBlob;
71 register 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);
79 if (!tpe) return 0; /* we've past the end */
80 relativeBlob = ablob - pageBlob; /* relative to page's first blob */
81 /* first watch for headers */
82 if (pageBlob == 0) { /* first dir page has extra-big header */
84 if (relativeBlob < DHE+1) relativeBlob = DHE+1;
86 else { /* others have one header blob */
87 if (relativeBlob == 0) relativeBlob = 1;
89 /* make sure blob is allocated */
90 for(i = relativeBlob; i < EPP; i++) {
91 if (tpe->freebitmap[i>>3] & (1<<(i&7))) break;
93 /* now relativeBlob is the page-relative first allocated blob,
94 or EPP (if there are none in this page). */
96 if (i != EPP) return i+pageBlob;
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 */
144 #if defined(AFS_SUN_ENV) || defined(AFS_AIX32_ENV)
147 #if defined(AFS_HPUX100_ENV)
148 unsigned long long d_off;
155 #endif /* AFS_SGI_ENV */
157 #if defined(AFS_HPUX_ENV) || defined(AFS_OSF_ENV)
158 struct minnfs_direct {
159 afs_int32 d_off; /* XXX */
164 #define NDIRSIZ_LEN(len) ((sizeof (struct dirent)+4 - (MAXNAMLEN+1)) + (((len)+1 + 3) &~ 3))
166 #endif /* !defined(UKERNEL) */
170 *------------------------------------------------------------------------------
172 * Keep a stack of about 256 fids for the bulk stat call.
173 * Fill it during the readdir_move. Later empty it...
176 #define READDIR_STASH AFSCBMAX
177 struct AFSFid afs_readdir_stash[READDIR_STASH];
178 int afs_rd_stash_i = 0;
181 *------------------------------------------------------------------------------
184 * mainly a kind of macro... makes getting the struct direct
185 * out to the user space easy... could take more parameters,
186 * but now just takes what it needs.
190 #if defined(AFS_HPUX100_ENV)
191 #define DIRSIZ_LEN(len) \
192 ((sizeof (struct __dirent) - (_MAXNAMLEN+1)) + (((len)+1 + 3) &~ 3))
194 #if defined(AFS_SUN56_ENV)
195 #define DIRSIZ_LEN(len) ((18 + (len) + 1 + 7) & ~7 )
198 #define DIRSIZ_LEN(len) ((10 + (len) + 1 + (NBPW-1)) & ~(NBPW-1))
201 #define DIRSIZ_LEN(len) \
202 ((sizeof (struct dirent) - (MAXNAMLEN+1)) + (((len)+1 + 3) &~ 3))
204 #if defined(AFS_SGI_ENV)
205 #ifndef AFS_SGI53_ENV
206 /* SGI 5.3 and later use 32/64 bit versions of directory size. */
207 #define DIRSIZ_LEN(len) DIRENTSIZE(len)
209 #else /* AFS_SGI_ENV */
210 #define DIRSIZ_LEN(len) \
211 ((sizeof (struct direct) - (MAXNAMLEN+1)) + (((len)+1 + 3) &~ 3))
212 #endif /* AFS_SGI_ENV */
213 #endif /* AFS_DIRENT */
214 #endif /* AFS_SUN5_ENV */
215 #endif /* AFS_SUN56_ENV */
216 #endif /* AFS_HPUX100_ENV */
219 #define AFS_MOVE_LOCK() AFS_GLOCK()
220 #define AFS_MOVE_UNLOCK() AFS_GUNLOCK()
222 #define AFS_MOVE_LOCK()
223 #define AFS_MOVE_UNLOCK()
226 char bufofzeros[64]; /* gotta fill with something */
227 afs_readdir_move (de, vc, auio, slen, rlen, off)
228 struct DirEntry * de;
240 #if defined(AFS_SUN56_ENV)
241 struct dirent64 *direntp;
244 struct dirent *direntp;
246 #endif /* AFS_SUN56_ENV */
247 #ifndef AFS_SGI53_ENV
248 struct min_direct sdirEntry;
249 #endif /* AFS_SGI53_ENV */
251 AFS_STATCNT(afs_readdir_move);
254 afs_int32 use64BitDirent;
258 use64BitDirent = ABI_IS(ABI_IRIX5_64,
259 GETDENTS_ABI*OSI_GET_CURRENT_ABI(), auio));
261 use64BitDirent = (auio->uio_segflg != UIO_USERSPACE) ? ABI_IRIX5_64 :
262 (ABI_IS(ABI_IRIX5_64 | ABI_IRIX5_N32, u.u_procp->p_abi));
264 #else /* AFS_SGI61_ENV */
265 use64BitDirent = (auio->uio_segflg != UIO_USERSPACE) ? ABI_IRIX5_64 :
266 (ABI_IS(ABI_IRIX5_64, u.u_procp->p_abi));
267 #endif /* AFS_SGI61_ENV */
269 if (use64BitDirent) {
270 struct min_dirent sdirEntry;
271 sdirEntry.d_fileno = (vc->fid.Fid.Volume << 16) + ntohl(de->fid.vnode);
272 FIXUPSTUPIDINODE(sdirEntry.d_fileno);
273 sdirEntry.d_reclen = rlen;
274 sdirEntry.d_off = (off_t)off;
275 AFS_UIOMOVE(&sdirEntry, AFS_DIRENT64BASESIZE, UIO_READ, auio, code);
277 AFS_UIOMOVE(de->name, slen-1, UIO_READ, auio, code);
279 AFS_UIOMOVE(bufofzeros,
280 DIRENTSIZE(slen) - (AFS_DIRENT64BASESIZE + slen - 1),
281 UIO_READ, auio, code);
282 if (DIRENTSIZE(slen) < rlen) {
283 while(DIRENTSIZE(slen) < rlen) {
284 int minLen = rlen - DIRENTSIZE(slen);
285 if (minLen > sizeof(bufofzeros)) minLen = sizeof(bufofzeros);
286 AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
291 struct irix5_min_dirent sdirEntry;
292 sdirEntry.d_fileno = (vc->fid.Fid.Volume << 16) + ntohl(de->fid.vnode);
293 FIXUPSTUPIDINODE(sdirEntry.d_fileno);
294 sdirEntry.d_reclen = rlen;
295 sdirEntry.d_off = (afs_int32)off;
296 AFS_UIOMOVE(&sdirEntry, AFS_DIRENT32BASESIZE, UIO_READ, auio, code);
298 AFS_UIOMOVE(de->name, slen-1, UIO_READ, auio, code);
300 AFS_UIOMOVE(bufofzeros,
301 IRIX5_DIRENTSIZE(slen) -
302 (AFS_DIRENT32BASESIZE + slen - 1),
303 UIO_READ, auio, code);
304 if (IRIX5_DIRENTSIZE(slen) < rlen) {
305 while(IRIX5_DIRENTSIZE(slen) < rlen) {
306 int minLen = rlen - IRIX5_DIRENTSIZE(slen);
307 if (minLen > sizeof(bufofzeros)) minLen = sizeof(bufofzeros);
308 AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
314 #else /* AFS_SGI53_ENV */
316 #if defined(AFS_SUN56_ENV)
317 direntp = (struct dirent64 *) osi_AllocLargeSpace(AFS_LRALLOCSIZ);
319 direntp = (struct dirent *) osi_AllocLargeSpace(AFS_LRALLOCSIZ);
321 direntp->d_ino = (vc->fid.Fid.Volume << 16) + ntohl(de->fid.vnode);
322 FIXUPSTUPIDINODE(direntp->d_ino);
323 direntp->d_off = off;
324 direntp->d_reclen = rlen;
325 strcpy(direntp->d_name, de->name);
326 AFS_UIOMOVE((caddr_t)direntp, rlen, UIO_READ, auio, code);
327 osi_FreeLargeSpace((char *)direntp);
328 #else /* AFS_SUN5_ENV */
329 /* Note the odd mechanism for building the inode number */
330 sdirEntry.d_fileno = (vc->fid.Fid.Volume << 16) +
331 ntohl(de->fid.vnode);
332 FIXUPSTUPIDINODE(sdirEntry.d_fileno);
333 sdirEntry.d_reclen = rlen;
334 #if !defined(AFS_SGI_ENV)
335 sdirEntry.d_namlen = slen;
337 #if defined(AFS_SUN_ENV) || defined(AFS_AIX32_ENV) || defined(AFS_SGI_ENV)
338 sdirEntry.d_off = off;
341 #if defined(AFS_SGI_ENV)
342 AFS_UIOMOVE(&sdirEntry, DIRENTBASESIZE, UIO_READ, auio, code);
344 AFS_UIOMOVE(de->name, slen-1, UIO_READ, auio, code);
346 AFS_UIOMOVE(bufofzeros, DIRSIZ_LEN(slen) - (DIRENTBASESIZE + slen - 1), UIO_READ, auio, code);
347 #else /* AFS_SGI_ENV */
349 AFS_UIOMOVE((char *)&sdirEntry, sizeof(sdirEntry), UIO_READ, auio, code);
352 AFS_UIOMOVE(de->name, slen, UIO_READ, auio, code);
355 /* pad out the remaining characters with zeros */
357 AFS_UIOMOVE(bufofzeros, ((slen + 4) & ~3) - slen, UIO_READ,
361 #endif /* AFS_SGI_ENV */
363 /* pad out the difference between rlen and slen... */
364 if (DIRSIZ_LEN(slen) < rlen)
367 while(DIRSIZ_LEN(slen) < rlen)
369 int minLen = rlen - DIRSIZ_LEN(slen);
370 if (minLen > sizeof(bufofzeros))
371 minLen = sizeof(bufofzeros);
372 AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
377 #endif /* AFS_SUN5_ENV */
378 #endif /* AFS_SGI53_ENV */
384 *------------------------------------------------------------------------------
386 * Read directory entries.
387 * There are some weird things to look out for here. The uio_offset
388 * field is either 0 or it is the offset returned from a previous
389 * readdir. It is an opaque value used by the server to find the
390 * correct directory block to read. The byte count must be at least
391 * vtoblksz(vp) bytes. The count field is the number of blocks to
392 * read on the server. This is advisory only, the server may return
393 * only one block's worth of entries. Entries may be compressed on
396 * This routine encodes knowledge of Vice dirs.
399 void afs_bulkstat_send( avc, req )
401 struct vrequest * req;
408 * Here is the bad, bad, really bad news.
409 * It has to do with 'offset' (seek locations).
412 #if defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV) || defined(AFS_OSF_ENV)
413 afs_readdir(OSI_VC_ARG(avc), auio, acred, eofp)
416 #if defined(AFS_HPUX100_ENV)
417 afs_readdir2(OSI_VC_ARG(avc), auio, acred)
419 afs_readdir(OSI_VC_ARG(avc), auio, acred)
424 struct AFS_UCRED *acred; {
425 struct vrequest treq;
426 register struct dcache *tdc;
427 afs_int32 origOffset, len, dirsiz;
429 struct DirEntry *ode = 0, *nde = 0;
430 int o_slen = 0, n_slen = 0;
432 #if defined(AFS_SGI53_ENV)
433 afs_int32 use64BitDirent;
434 #endif /* defined(AFS_SGI53_ENV) */
438 * XXX All the hacks for alloced sdirEntry and inlining of afs_readdir_move instead of calling
439 * it is necessary for hpux due to stack problems that seem to occur when coming thru the nfs
440 * translator side XXX
442 struct min_direct *sdirEntry = (struct min_direct *)osi_AllocSmallSpace(sizeof(struct min_direct));
446 /* opaque value is pointer into a vice dir; use bit map to decide
447 if the entries are in use. Always assumed to be valid. 0 is
448 special, means start of a new dir. Int32 inode, followed by
449 short reclen and short namelen. Namelen does not include
450 the null byte. Followed by null-terminated string.
452 AFS_STATCNT(afs_readdir);
454 #if defined(AFS_SGI53_ENV)
457 use64BitDirent = ABI_IS(ABI_IRIX5_64,
458 GETDENTS_ABI(OSI_GET_CURRENT_ABI(), auio));
460 use64BitDirent = (auio->uio_segflg != UIO_USERSPACE) ? ABI_IRIX5_64 :
461 (ABI_IS(ABI_IRIX5_64 | ABI_IRIX5_N32, u.u_procp->p_abi));
462 #endif /* AFS_SGI62_ENV */
463 #else /* AFS_SGI61_ENV */
464 use64BitDirent = (auio->uio_segflg != UIO_USERSPACE) ? ABI_IRIX5_64 :
465 (ABI_IS(ABI_IRIX5_64, u.u_procp->p_abi));
466 #endif /* AFS_SGI61_ENV */
467 #endif /* defined(AFS_SGI53_ENV) */
469 #if defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV) || defined(AFS_OSF_ENV)
470 /* Not really used by the callee so we ignore it for now */
473 if ( AfsLargeFileUio(auio) /* file is large than 2 GB */
474 || AfsLargeFileSize(auio->uio_offset, auio->uio_resid) )
477 if (code = afs_InitReq(&treq, acred)) {
479 osi_FreeSmallSpace((char *)sdirEntry);
483 /* update the cache entry */
485 code = afs_VerifyVCache(avc, &treq);
487 /* get a reference to the entire directory */
488 tdc = afs_GetDCache(avc, 0, &treq, &origOffset, &len, 1);
493 ObtainReadLock(&avc->lock);
496 * Make sure that the data in the cache is current. There are two
497 * cases we need to worry about:
498 * 1. The cache data is being fetched by another process.
499 * 2. The cache data is no longer valid
501 while ((avc->states & CStatd)
502 && (tdc->flags & DFFetching)
503 && hsame(avc->m.DataVersion, tdc->f.versionNo)) {
504 tdc->flags |= DFWaiting;
505 ReleaseReadLock(&avc->lock);
506 afs_osi_Sleep(&tdc->validPos);
507 ObtainReadLock(&avc->lock);
509 if (!(avc->states & CStatd)
510 || !hsame(avc->m.DataVersion, tdc->f.versionNo)) {
511 ReleaseReadLock(&avc->lock);
517 * iterator for the directory reads. Takes the AFS DirEntry
518 * structure and slams them into UFS direct structures.
519 * uses afs_readdir_move to get the struct to the user space.
521 * The routine works by looking ahead one AFS directory entry.
522 * That's because the AFS entry we are currenly working with
523 * may not fit into the buffer the user has provided. If it
524 * doesn't we have to change the size of the LAST AFS directory
525 * entry, so that it will FIT perfectly into the block the
528 * The 'forward looking' of the code makes it a bit tough to read.
529 * Remember we need to get an entry, see if it it fits, then
530 * set it up as the LAST entry, and find the next one.
532 * Tough to take: We give out an EINVAL if we don't have enough
533 * space in the buffer, and at the same time, don't have an entry
534 * to put into the buffer. This CAN happen if the first AFS entry
535 * we get can't fit into the 512 character buffer provided. Seems
536 * it ought not happen...
538 * Assumption: don't need to use anything but one dc entry:
539 * this means the directory ought not be greater than 64k.
543 auio->uio_fpflags = 0;
546 origOffset = auio->afsio_offset;
547 /* scan for the next interesting entry scan for in-use blob otherwise up point at
548 * this blob note that ode, if non-zero, also represents a held dir page */
549 if (!(us = BlobScan(&tdc->f.inode, (origOffset >> 5)) )
550 || !(nde = (struct DirEntry *) afs_dir_GetBlob(&tdc->f.inode, us) ) ) {
551 /* failed to setup nde, return what we've got, and release ode */
553 /* something to hand over. */
555 sdirEntry->d_fileno = (avc->fid.Fid.Volume << 16) + ntohl(ode->fid.vnode);
556 FIXUPSTUPIDINODE(sdirEntry->d_fileno);
557 sdirEntry->d_reclen = rlen = auio->afsio_resid;
558 sdirEntry->d_namlen = o_slen;
559 #if defined(AFS_SUN_ENV) || defined(AFS_AIX32_ENV) || defined(AFS_HPUX100_ENV)
560 sdirEntry->d_off = origOffset;
562 AFS_UIOMOVE((char *)sdirEntry, sizeof(*sdirEntry), UIO_READ, auio, code);
564 AFS_UIOMOVE(ode->name, o_slen, UIO_READ, auio, code);
565 /* pad out the remaining characters with zeros */
567 AFS_UIOMOVE(bufofzeros, ((o_slen + 4) & ~3) - o_slen, UIO_READ, auio, code);
569 /* pad out the difference between rlen and slen... */
570 if (DIRSIZ_LEN(o_slen) < rlen) {
571 while(DIRSIZ_LEN(o_slen) < rlen) {
572 int minLen = rlen - DIRSIZ_LEN(o_slen);
573 if (minLen > sizeof(bufofzeros))
574 minLen = sizeof(bufofzeros);
575 AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
580 code = afs_readdir_move(ode, avc, auio, o_slen,
581 #if defined(AFS_SUN5_ENV)
584 auio->afsio_resid, origOffset);
586 #endif /* AFS_HPUX_ENV */
587 #if !defined(AFS_SUN5_ENV)
588 auio->afsio_resid = 0;
591 /* nothin to hand over */
593 #if defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV) || defined(AFS_OSF_ENV)
594 if (eofp) *eofp = 1; /* Set it properly */
596 if (ode) DRelease(ode, 0);
599 /* by here nde is set */
601 /* Do we have enough user space to carry out our mission? */
602 #if defined(AFS_SGI_ENV)
603 n_slen = strlen(nde->name) + 1; /* NULL terminate */
605 n_slen = strlen(nde->name);
608 dirsiz = use64BitDirent ? DIRENTSIZE(n_slen) :
609 IRIX5_DIRENTSIZE(n_slen);
610 if (dirsiz >= (auio->afsio_resid-len)) {
612 if (DIRSIZ_LEN(n_slen) >= (auio->afsio_resid-len)) {
613 #endif /* AFS_SGI53_ENV */
614 /* No can do no more now; ya know... at this time */
615 DRelease (nde, 0); /* can't use this one. */
618 sdirEntry->d_fileno = (avc->fid.Fid.Volume << 16) + ntohl(ode->fid.vnode);
619 FIXUPSTUPIDINODE(sdirEntry->d_fileno);
620 sdirEntry->d_reclen = rlen = auio->afsio_resid;
621 sdirEntry->d_namlen = o_slen;
622 #if defined(AFS_SUN_ENV) || defined(AFS_AIX32_ENV) || defined(AFS_HPUX100_ENV)
623 sdirEntry->d_off = origOffset;
625 AFS_UIOMOVE((char *)sdirEntry, sizeof(*sdirEntry), UIO_READ, auio, code);
627 AFS_UIOMOVE(ode->name, o_slen, UIO_READ, auio, code);
628 /* pad out the remaining characters with zeros */
630 AFS_UIOMOVE(bufofzeros, ((o_slen + 4) & ~3) - o_slen, UIO_READ, auio, code);
632 /* pad out the difference between rlen and slen... */
633 if (DIRSIZ_LEN(o_slen) < rlen) {
634 while(DIRSIZ_LEN(o_slen) < rlen) {
635 int minLen = rlen - DIRSIZ_LEN(o_slen);
636 if (minLen > sizeof(bufofzeros))
637 minLen = sizeof(bufofzeros);
638 AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
642 #else /* AFS_HPUX_ENV */
643 code = afs_readdir_move(ode, avc, auio, o_slen,
644 auio->afsio_resid, origOffset);
645 #endif /* AFS_HPUX_ENV */
646 /* this next line used to be AFSVFS40 or AIX 3.1, but is
648 auio->afsio_offset = origOffset;
649 auio->afsio_resid = 0;
650 } else { /* trouble, can't give anything to the user! */
651 /* even though he has given us a buffer,
652 * even though we have something to give us,
653 * Looks like we lost something somewhere.
657 if (ode) DRelease(ode, 0);
662 * In any event, we move out the LAST de entry, getting ready
663 * to set up for the next one.
667 sdirEntry->d_fileno =
668 (avc->fid.Fid.Volume << 16) + ntohl(ode->fid.vnode);
669 FIXUPSTUPIDINODE(sdirEntry->d_fileno);
670 sdirEntry->d_reclen = rlen = len;
671 sdirEntry->d_namlen = o_slen;
672 #if defined(AFS_SUN_ENV) || defined(AFS_AIX32_ENV) || defined(AFS_HPUX100_ENV)
673 sdirEntry->d_off = origOffset;
675 AFS_UIOMOVE((char *)sdirEntry, sizeof(*sdirEntry), UIO_READ,
678 AFS_UIOMOVE(ode->name, o_slen, UIO_READ, auio, code);
679 /* pad out the remaining characters with zeros */
681 AFS_UIOMOVE(bufofzeros, ((o_slen + 4) & ~3) - o_slen,
682 UIO_READ, auio, code);
684 /* pad out the difference between rlen and slen... */
685 if (DIRSIZ_LEN(o_slen) < rlen) {
686 while(DIRSIZ_LEN(o_slen) < rlen) {
687 int minLen = rlen - DIRSIZ_LEN(o_slen);
688 if (minLen > sizeof(bufofzeros))
689 minLen = sizeof(bufofzeros);
690 AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
694 #else /* AFS_HPUX_ENV */
695 code = afs_readdir_move (ode, avc, auio, o_slen, len, origOffset);
696 #endif /* AFS_HPUX_ENV */
699 len = use64BitDirent ? DIRENTSIZE(o_slen = n_slen) :
700 IRIX5_DIRENTSIZE(o_slen = n_slen);
702 len = DIRSIZ_LEN( o_slen = n_slen );
703 #endif /* AFS_SGI53_ENV */
704 if (ode) DRelease(ode, 0);
706 auio->afsio_offset = (afs_int32)((us + afs_dir_NameBlobs(nde->name)) << 5);
708 if (ode) DRelease(ode, 0);
712 ReleaseReadLock(&avc->lock);
716 osi_FreeSmallSpace((char *)sdirEntry);
718 code = afs_CheckCode(code, &treq, 28);
722 #if defined(AFS_HPUX_ENV) || defined(AFS_OSF_ENV)
724 afs1_readdir(avc, auio, acred, eofp)
727 afs1_readdir(avc, auio, acred)
729 register struct vcache *avc;
731 struct AFS_UCRED *acred; {
732 struct vrequest treq;
733 register struct dcache *tdc;
734 afs_int32 origOffset, len;
736 struct DirEntry *ode = 0, *nde = 0;
737 int o_slen = 0, n_slen = 0;
739 #if defined(AFS_HPUX_ENV) || defined(AFS_OSF_ENV)
741 * XXX All the hacks for alloced sdirEntry and inlining of afs_readdir_move instead of calling
742 * it is necessary for hpux due to stack problems that seem to occur when coming thru the nfs
743 * translator side XXX
745 struct minnfs_direct *sdirEntry = (struct minnfs_direct *)osi_AllocSmallSpace(sizeof(struct min_direct));
749 AFS_STATCNT(afs_readdir);
750 #if defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV) || defined(AFS_OSF_ENV)
753 if (code = afs_InitReq(&treq, acred)) {
755 osi_FreeSmallSpace((char *)sdirEntry);
759 /* update the cache entry */
761 code = afs_VerifyVCache(avc, &treq);
763 /* get a reference to the entire directory */
764 tdc = afs_GetDCache(avc, 0, &treq, &origOffset, &len, 1);
769 ObtainReadLock(&avc->lock);
772 * Make sure that the data in the cache is current. There are two
773 * cases we need to worry about:
774 * 1. The cache data is being fetched by another process.
775 * 2. The cache data is no longer valid
777 while ((avc->states & CStatd)
778 && (tdc->flags & DFFetching)
779 && hsame(avc->m.DataVersion, tdc->f.versionNo)) {
780 tdc->flags |= DFWaiting;
781 ReleaseReadLock(&avc->lock);
782 afs_osi_Sleep(&tdc->validPos);
783 ObtainReadLock(&avc->lock);
785 if (!(avc->states & CStatd)
786 || !hsame(avc->m.DataVersion, tdc->f.versionNo)) {
787 ReleaseReadLock(&avc->lock);
794 auio->uio_fpflags = 0;
797 origOffset = auio->afsio_offset;
799 /* scan for the next interesting entry scan for in-use blob otherwise up point at
800 * this blob note that ode, if non-zero, also represents a held dir page */
801 if (!(us = BlobScan(&tdc->f.inode, (origOffset >> 5)) )
802 || !(nde = (struct DirEntry *) afs_dir_GetBlob(&tdc->f.inode, us) ) ) {
803 /* failed to setup nde, return what we've got, and release ode */
805 /* something to hand over. */
806 #if defined(AFS_HPUX_ENV) || defined(AFS_OSF_ENV)
807 sdirEntry->d_fileno = (avc->fid.Fid.Volume << 16) + ntohl(ode->fid.vnode);
808 FIXUPSTUPIDINODE(sdirEntry->d_fileno);
809 sdirEntry->d_reclen = rlen = auio->afsio_resid;
810 sdirEntry->d_namlen = o_slen;
811 sdirEntry->d_off = origOffset;
812 AFS_UIOMOVE((char *)sdirEntry, sizeof(*sdirEntry), UIO_READ, auio, code);
814 AFS_UIOMOVE(ode->name, o_slen, UIO_READ, auio, code);
816 /* pad out the remaining characters with zeros */
818 AFS_UIOMOVE(bufofzeros, ((o_slen + 4) & ~3) - o_slen, UIO_READ, auio, code);
820 /* pad out the difference between rlen and slen... */
821 if (NDIRSIZ_LEN(o_slen) < rlen) {
822 while(NDIRSIZ_LEN(o_slen) < rlen) {
823 int minLen = rlen - NDIRSIZ_LEN(o_slen);
824 if (minLen > sizeof(bufofzeros))
825 minLen = sizeof(bufofzeros);
826 AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
831 code = afs_readdir_move(ode, avc, auio, o_slen,
832 auio->afsio_resid, origOffset);
833 #endif /* AFS_HPUX_ENV */
834 auio->afsio_resid = 0;
836 /* nothin to hand over */
838 #if defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV) || defined(AFS_OSF_ENV)
841 if (ode) DRelease(ode, 0);
844 /* by here nde is set */
846 /* Do we have enough user space to carry out our mission? */
847 #if defined(AFS_SGI_ENV)
848 n_slen = strlen(nde->name) + 1; /* NULL terminate */
850 n_slen = strlen(nde->name);
852 if (NDIRSIZ_LEN(n_slen) >= (auio->afsio_resid-len)) {
853 /* No can do no more now; ya know... at this time */
854 DRelease (nde, 0); /* can't use this one. */
856 #if defined(AFS_HPUX_ENV) || defined(AFS_OSF_ENV)
857 sdirEntry->d_fileno = (avc->fid.Fid.Volume << 16) + ntohl(ode->fid.vnode);
858 FIXUPSTUPIDINODE(sdirEntry->d_fileno);
859 sdirEntry->d_reclen = rlen = auio->afsio_resid;
860 sdirEntry->d_namlen = o_slen;
861 sdirEntry->d_off = origOffset;
862 AFS_UIOMOVE((char *)sdirEntry, sizeof(*sdirEntry), UIO_READ, auio, code);
864 AFS_UIOMOVE(ode->name, o_slen, UIO_READ, auio, code);
865 /* pad out the remaining characters with zeros */
867 AFS_UIOMOVE(bufofzeros, ((o_slen + 4) & ~3) - o_slen, UIO_READ, auio, code);
869 /* pad out the difference between rlen and slen... */
870 if (NDIRSIZ_LEN(o_slen) < rlen) {
871 while(NDIRSIZ_LEN(o_slen) < rlen) {
872 int minLen = rlen - NDIRSIZ_LEN(o_slen);
873 if (minLen > sizeof(bufofzeros))
874 minLen = sizeof(bufofzeros);
875 AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
880 code = afs_readdir_move(ode, avc, auio, o_slen,
881 auio->afsio_resid, origOffset);
882 #endif /* AFS_HPUX_ENV */
883 /* this next line used to be AFSVFS40 or AIX 3.1, but is really generic */
884 auio->afsio_offset = origOffset;
885 auio->afsio_resid = 0;
886 } else { /* trouble, can't give anything to the user! */
887 /* even though he has given us a buffer,
888 * even though we have something to give us,
889 * Looks like we lost something somewhere.
893 if (ode) DRelease(ode, 0);
898 * In any event, we move out the LAST de entry, getting ready
899 * to set up for the next one.
902 #if defined(AFS_HPUX_ENV) || defined(AFS_OSF_ENV)
903 sdirEntry->d_fileno = (avc->fid.Fid.Volume << 16) + ntohl(ode->fid.vnode);
904 FIXUPSTUPIDINODE(sdirEntry->d_fileno);
905 sdirEntry->d_reclen = rlen = len;
906 sdirEntry->d_namlen = o_slen;
907 sdirEntry->d_off = origOffset;
908 AFS_UIOMOVE((char *)sdirEntry, sizeof(*sdirEntry), UIO_READ, auio, code);
910 AFS_UIOMOVE(ode->name, o_slen, UIO_READ, auio, code);
911 /* pad out the remaining characters with zeros */
913 AFS_UIOMOVE(bufofzeros, ((o_slen + 4) & ~3) - o_slen, UIO_READ, auio, code);
915 /* pad out the difference between rlen and slen... */
916 if (NDIRSIZ_LEN(o_slen) < rlen) {
917 while(NDIRSIZ_LEN(o_slen) < rlen) {
918 int minLen = rlen - NDIRSIZ_LEN(o_slen);
919 if (minLen > sizeof(bufofzeros))
920 minLen = sizeof(bufofzeros);
921 AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
926 code = afs_readdir_move (ode, avc, auio, o_slen, len, origOffset);
927 #endif /* AFS_HPUX_ENV */
929 len = NDIRSIZ_LEN( o_slen = n_slen );
930 if (ode) DRelease(ode, 0);
932 auio->afsio_offset = ((us + afs_dir_NameBlobs(nde->name)) << 5);
934 if (ode) DRelease(ode, 0);
938 ReleaseReadLock(&avc->lock);
941 #if defined(AFS_HPUX_ENV) || defined(AFS_OSF_ENV)
942 osi_FreeSmallSpace((char *)sdirEntry);
944 code = afs_CheckCode(code, &treq, 29);
949 #endif /* !AFS_LINUX20_ENV */