2 * Copyright 2000, International Business Machines Corporation and others.
5 * This software has been released under the terms of the IBM Public
6 * License. For details, see the LICENSE file in the top-level source
7 * directory or online at http://www.openafs.org/dl/license10.html
11 * afs_vnop_readdir.c - afs_readdir and bulk stat
17 * afs_readdir/afs_readdir2(HP)
18 * afs_readdir1 - HP NFS version
22 #include <afsconfig.h>
23 #include "afs/param.h"
26 #include "afs/sysincludes.h" /* Standard vendor system headers */
27 #include "afsincludes.h" /* Afs-based standard headers */
28 #include "afs/afs_stats.h" /* statistics */
29 #include "afs/afs_cbqueue.h"
30 #include "afs/nfsclient.h"
31 #include "afs/afs_osidnlc.h"
33 #if defined(AFS_HPUX1122_ENV)
35 #elif defined(AFS_NBSD40_ENV)
42 * AFS readdir vnodeop and bulk stat support.
46 * Ensure that the blob reference refers to a valid directory entry.
47 * It consults the allocation map in the page header to determine
48 * whether a blob is actually in use or not.
50 * More formally, BlobScan is supposed to return a new blob number
51 * which is just like the input parameter, only it is advanced over
52 * header or free blobs.
54 * Note that BlobScan switches pages if necessary. BlobScan may
55 * return either 0 for success or an error code. Upon successful
56 * return, the new blob value is assigned to *ablobOut. The new
57 * blob value (*ablobOut) is set to 0 when the end of the file has
60 * BlobScan is used by the Linux port in a separate file, so it should not
64 BlobScan(struct dcache
* afile
, afs_int32 ablob
, int *ablobOut
)
66 afs_int32 relativeBlob
;
68 struct PageHeader
*tpe
;
69 struct DirBuffer headerbuf
;
73 AFS_STATCNT(BlobScan
);
74 /* advance ablob over free and header blobs */
76 pageBlob
= ablob
& ~(EPP
- 1); /* base blob in same page */
77 code
= afs_dir_GetBlob(afile
, pageBlob
, &headerbuf
);
79 *ablobOut
= 0; /* past the end of file */
80 return 0; /* not an error */
84 tpe
= (struct PageHeader
*)headerbuf
.data
;
86 relativeBlob
= ablob
- pageBlob
; /* relative to page's first blob */
87 /* first watch for headers */
88 if (pageBlob
== 0) { /* first dir page has extra-big header */
90 if (relativeBlob
< DHE
+ 1)
91 relativeBlob
= DHE
+ 1;
92 } else { /* others have one header blob */
93 if (relativeBlob
== 0)
96 /* make sure blob is allocated */
97 for (i
= relativeBlob
; i
< EPP
; i
++) {
98 if (tpe
->freebitmap
[i
>> 3] & (1 << (i
& 7)))
101 /* now relativeBlob is the page-relative first allocated blob,
102 * or EPP (if there are none in this page). */
103 DRelease(&headerbuf
, 0);
105 *ablobOut
= i
+ pageBlob
;
108 ablob
= pageBlob
+ EPP
; /* go around again */
114 #if !defined(AFS_LINUX20_ENV)
115 /* Changes to afs_readdir which affect dcache or vcache handling or use of
116 * bulk stat data should also be reflected in the Linux specific verison of
117 * the readdir routine.
121 * The kernel don't like it so much to have large stuff on the stack.
122 * Here we use a watered down version of the direct struct, since
123 * its not too bright to double copy the strings anyway.
125 #if !defined(UKERNEL)
126 #if defined(AFS_SGI_ENV)
127 /* Long form for 64 bit apps and kernel requests. */
128 struct min_dirent
{ /* miniature dirent structure */
129 /* If struct dirent changes, this must too */
130 ino_t d_fileno
; /* This is 32 bits for 3.5, 64 for 6.2+ */
134 /* Short form for 32 bit apps. */
135 struct irix5_min_dirent
{ /* miniature dirent structure */
136 /* If struct dirent changes, this must too */
142 #define AFS_DIRENT32BASESIZE IRIX5_DIRENTBASESIZE
143 #define AFS_DIRENT64BASESIZE DIRENT64BASESIZE
145 #define AFS_DIRENT32BASESIZE IRIX5_DIRENTBASESIZE
146 #define AFS_DIRENT64BASESIZE DIRENTBASESIZE
147 #endif /* AFS_SGI62_ENV */
149 struct min_direct
{ /* miniature direct structure */
150 /* If struct direct changes, this must too */
151 #if defined(AFS_DARWIN80_ENV)
156 #elif defined(AFS_NBSD40_ENV)
157 ino_t d_fileno
; /* file number of entry */
158 uint16_t d_reclen
; /* length of this record */
159 uint16_t d_namlen
; /* length of string in d_name */
160 uint8_t d_type
; /* file type, see below */
161 #elif defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
166 #elif defined(AFS_SUN5_ENV)
171 #if defined(AFS_AIX32_ENV)
173 #elif defined(AFS_HPUX100_ENV)
174 unsigned long long d_off
;
181 #endif /* AFS_SGI_ENV */
183 #if defined(AFS_HPUX_ENV)
184 struct minnfs_direct
{
185 afs_int32 d_off
; /* XXX */
190 #define NDIRSIZ_LEN(len) ((sizeof (struct dirent)+4 - (MAXNAMLEN+1)) + (((len)+1 + DIRPAD) &~ DIRPAD))
192 #endif /* !defined(UKERNEL) */
196 *------------------------------------------------------------------------------
198 * Keep a stack of about 256 fids for the bulk stat call.
199 * Fill it during the readdir_move. Later empty it...
202 #define READDIR_STASH AFSCBMAX
203 struct AFSFid afs_readdir_stash
[READDIR_STASH
];
204 int afs_rd_stash_i
= 0;
207 *------------------------------------------------------------------------------
210 * mainly a kind of macro... makes getting the struct direct
211 * out to the user space easy... could take more parameters,
212 * but now just takes what it needs.
217 #if defined(AFS_HPUX100_ENV)
218 #define DIRSIZ_LEN(len) \
219 ((sizeof (struct __dirent) - (_MAXNAMLEN+1)) + (((len)+1 + DIRPAD) &~ DIRPAD))
221 #if defined(AFS_SUN5_ENV)
222 #define DIRSIZ_LEN(len) ((18 + (len) + 1 + 7) & ~7 )
224 #ifdef AFS_NBSD40_ENV
225 #define DIRSIZ_LEN(len) \
226 ((sizeof (struct dirent) - (MAXNAMLEN+1)) + (((len)+1 + 7) & ~7))
229 #define DIRSIZ_LEN(len) \
230 ((sizeof (struct dirent) - (MAXNAMLEN+1)) + (((len)+1 + 3) &~ 3))
232 #if defined(AFS_SGI_ENV)
233 #ifndef AFS_SGI53_ENV
234 /* SGI 5.3 and later use 32/64 bit versions of directory size. */
235 #define DIRSIZ_LEN(len) DIRENTSIZE(len)
237 #else /* AFS_SGI_ENV */
238 #define DIRSIZ_LEN(len) \
239 ((sizeof (struct direct) - (MAXNAMLEN+1)) + (((len)+1 + 3) &~ 3))
240 #endif /* AFS_SGI_ENV */
241 #endif /* AFS_DIRENT */
242 #endif /* AFS_NBSD40_ENV */
243 #endif /* AFS_SUN5_ENV */
244 #endif /* AFS_HPUX100_ENV */
246 #if defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
248 afs_readdir_type(struct vcache
*avc
, struct DirEntry
*ade
)
250 struct VenusFid tfid
;
253 tfid
.Cell
= avc
->f
.fid
.Cell
;
254 tfid
.Fid
.Volume
= avc
->f
.fid
.Fid
.Volume
;
255 tfid
.Fid
.Vnode
= ntohl(ade
->fid
.vnode
);
256 tfid
.Fid
.Unique
= ntohl(ade
->fid
.vunique
);
257 if ((avc
->f
.states
& CForeign
) == 0 && (ntohl(ade
->fid
.vnode
) & 1)) {
260 ObtainReadLock(&afs_xvcache
);
261 if ((tvc
= afs_FindVCache(&tfid
, 0, 0))) {
262 ReleaseReadLock(&afs_xvcache
);
263 if (tvc
->mvstat
!= AFS_MVSTAT_FILE
) {
266 } else if (((tvc
->f
.states
) & (CStatd
| CTruth
))) {
267 /* CTruth will be set if the object has
273 else if (vtype
== VREG
)
275 /* Don't do this until we're sure it can't be a mtpt */
276 /* if we're CStatd and CTruth and mvstat==AFS_MVSTAT_FILE, it's a link */
277 else if (vtype
== VLNK
)
279 /* what other types does AFS support? */
283 ReleaseReadLock(&afs_xvcache
);
289 #define AFS_MOVE_LOCK() AFS_GLOCK()
290 #define AFS_MOVE_UNLOCK() AFS_GUNLOCK()
292 #define AFS_MOVE_LOCK()
293 #define AFS_MOVE_UNLOCK()
295 char bufofzeros
[64]; /* gotta fill with something */
299 afs_readdir_move(struct DirEntry
*de
, struct vcache
*vc
, struct uio
*auio
,
300 int slen
, ssize_t rlen
, afs_size_t off
)
303 afs_readdir_move(struct DirEntry
*de
, struct vcache
*vc
, struct uio
*auio
,
304 int slen
, int rlen
, afs_size_t off
)
309 afs_uint32 Volume
= vc
->f
.fid
.Fid
.Volume
;
310 afs_uint32 Vnode
= de
->fid
.vnode
;
311 #if defined(AFS_SUN5_ENV)
312 struct dirent64
*direntp
;
314 #if (defined(AFS_AIX51_ENV) && defined(AFS_64BIT_KERNEL))
315 struct dirent
*direntp
;
317 #endif /* AFS_SUN5_ENV */
318 #ifndef AFS_SGI53_ENV
319 struct min_direct sdirEntry
;
320 #endif /* AFS_SGI53_ENV */
322 AFS_STATCNT(afs_readdir_move
);
324 #define READDIR_CORRECT_INUMS
325 #ifdef READDIR_CORRECT_INUMS
326 if (de
->name
[0] == '.' && !de
->name
[1]) {
327 /* This is the '.' entry; if we are a volume root, we need to
328 * ignore the directory and use the inum for the mount point.
330 if (!FidCmp(&afs_rootFid
, &vc
->f
.fid
)) {
333 } else if (vc
->mvstat
== AFS_MVSTAT_ROOT
) {
334 tvp
= afs_GetVolume(&vc
->f
.fid
, 0, READ_LOCK
);
336 Volume
= tvp
->mtpoint
.Fid
.Volume
;
337 Vnode
= tvp
->mtpoint
.Fid
.Vnode
;
338 afs_PutVolume(tvp
, READ_LOCK
);
342 else if (de
->name
[0] == '.' && de
->name
[1] == '.' && !de
->name
[2]) {
343 /* This is the '..' entry. Getting this right is very tricky,
344 * because we might be a volume root (so our parent is in a
345 * different volume), or our parent might be a volume root
346 * (so we actually want the mount point) or BOTH! */
347 if (!FidCmp(&afs_rootFid
, &vc
->f
.fid
)) {
348 /* We are the root of the AFS root, and thus our own parent */
351 } else if (vc
->mvstat
== AFS_MVSTAT_ROOT
) {
352 /* We are a volume root, which means our parent is in another
353 * volume. Luckily, we should have his fid cached... */
354 if (vc
->mvid
.parent
) {
355 if (!FidCmp(&afs_rootFid
, vc
->mvid
.parent
)) {
356 /* Parent directory is the root of the AFS root */
359 } else if (vc
->mvid
.parent
->Fid
.Vnode
== 1
360 && vc
->mvid
.parent
->Fid
.Unique
== 1) {
361 /* XXX The above test is evil and probably breaks DFS */
362 /* Parent directory is the target of a mount point */
363 tvp
= afs_GetVolume(vc
->mvid
.parent
, 0, READ_LOCK
);
365 Volume
= tvp
->mtpoint
.Fid
.Volume
;
366 Vnode
= tvp
->mtpoint
.Fid
.Vnode
;
367 afs_PutVolume(tvp
, READ_LOCK
);
370 /* Parent directory is not a volume root */
371 Volume
= vc
->mvid
.parent
->Fid
.Volume
;
372 Vnode
= vc
->mvid
.parent
->Fid
.Vnode
;
375 } else if (de
->fid
.vnode
== 1 && de
->fid
.vunique
== 1) {
376 /* XXX The above test is evil and probably breaks DFS */
377 /* Parent directory is a volume root; use the right inum */
378 tvp
= afs_GetVolume(&vc
->f
.fid
, 0, READ_LOCK
);
380 if (tvp
->cell
== afs_rootFid
.Cell
381 && tvp
->volume
== afs_rootFid
.Fid
.Volume
) {
382 /* Parent directory is the root of the AFS root */
386 /* Parent directory is the target of a mount point */
387 Volume
= tvp
->mtpoint
.Fid
.Volume
;
388 Vnode
= tvp
->mtpoint
.Fid
.Vnode
;
390 afs_PutVolume(tvp
, READ_LOCK
);
398 afs_int32 use64BitDirent
;
403 ABI_IS(ABI_IRIX5_64
, GETDENTS_ABI(OSI_GET_CURRENT_ABI(), auio
));
407 UIO_USERSPACE
) ? ABI_IRIX5_64
: (ABI_IS(ABI_IRIX5_64
|
411 #else /* AFS_SGI61_ENV */
414 UIO_USERSPACE
) ? ABI_IRIX5_64
: (ABI_IS(ABI_IRIX5_64
,
416 #endif /* AFS_SGI61_ENV */
418 if (use64BitDirent
) {
419 struct min_dirent sdirEntry
;
420 sdirEntry
.d_fileno
= afs_calc_inum(vc
->f
.fid
.Cell
,
421 Volume
, ntohl(Vnode
));
422 sdirEntry
.d_reclen
= rlen
;
423 sdirEntry
.d_off
= (off_t
) off
;
424 AFS_UIOMOVE(&sdirEntry
, AFS_DIRENT64BASESIZE
, UIO_READ
, auio
,
427 AFS_UIOMOVE(de
->name
, slen
- 1, UIO_READ
, auio
, code
);
429 AFS_UIOMOVE(bufofzeros
,
430 DIRENTSIZE(slen
) - (AFS_DIRENT64BASESIZE
+ slen
-
431 1), UIO_READ
, auio
, code
);
432 if (DIRENTSIZE(slen
) < rlen
) {
433 while (DIRENTSIZE(slen
) < rlen
) {
434 int minLen
= rlen
- DIRENTSIZE(slen
);
435 if (minLen
> sizeof(bufofzeros
))
436 minLen
= sizeof(bufofzeros
);
437 AFS_UIOMOVE(bufofzeros
, minLen
, UIO_READ
, auio
, code
);
442 struct irix5_min_dirent sdirEntry
;
443 sdirEntry
.d_fileno
= afs_calc_inum(vc
->f
.fid
.Cell
,
444 Volume
, ntohl(Vnode
));
445 sdirEntry
.d_reclen
= rlen
;
446 sdirEntry
.d_off
= (afs_int32
) off
;
447 AFS_UIOMOVE(&sdirEntry
, AFS_DIRENT32BASESIZE
, UIO_READ
, auio
,
450 AFS_UIOMOVE(de
->name
, slen
- 1, UIO_READ
, auio
, code
);
452 AFS_UIOMOVE(bufofzeros
,
453 IRIX5_DIRENTSIZE(slen
) - (AFS_DIRENT32BASESIZE
+
456 if (IRIX5_DIRENTSIZE(slen
) < rlen
) {
457 while (IRIX5_DIRENTSIZE(slen
) < rlen
) {
458 int minLen
= rlen
- IRIX5_DIRENTSIZE(slen
);
459 if (minLen
> sizeof(bufofzeros
))
460 minLen
= sizeof(bufofzeros
);
461 AFS_UIOMOVE(bufofzeros
, minLen
, UIO_READ
, auio
, code
);
467 #else /* AFS_SGI53_ENV */
468 #if defined(AFS_SUN5_ENV) || (defined(AFS_AIX51_ENV) && defined(AFS_64BIT_KERNEL))
469 direntp
= osi_AllocLargeSpace(AFS_LRALLOCSIZ
);
470 direntp
->d_ino
= afs_calc_inum(vc
->f
.fid
.Cell
, Volume
, ntohl(Vnode
));
471 #if defined(AFS_AIX51_ENV) && defined(AFS_64BIT_KERNEL)
472 direntp
->d_offset
= off
;
473 direntp
->d_namlen
= slen
;
475 direntp
->d_off
= off
;
477 direntp
->d_reclen
= rlen
;
478 strcpy(direntp
->d_name
, de
->name
);
479 AFS_UIOMOVE((caddr_t
) direntp
, rlen
, UIO_READ
, auio
, code
);
480 osi_FreeLargeSpace((char *)direntp
);
481 #else /* AFS_SUN5_ENV */
482 /* Note the odd mechanism for building the inode number */
483 sdirEntry
.d_fileno
= afs_calc_inum(vc
->f
.fid
.Cell
, Volume
, ntohl(Vnode
));
484 sdirEntry
.d_reclen
= rlen
;
485 #if !defined(AFS_SGI_ENV)
486 sdirEntry
.d_namlen
= slen
;
488 #if defined(AFS_AIX32_ENV) || defined(AFS_SGI_ENV)
489 sdirEntry
.d_off
= off
;
491 #if defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
492 sdirEntry
.d_type
= afs_readdir_type(vc
, de
);
495 #if defined(AFS_SGI_ENV)
496 AFS_UIOMOVE(&sdirEntry
, DIRENTBASESIZE
, UIO_READ
, auio
, code
);
498 AFS_UIOMOVE(de
->name
, slen
- 1, UIO_READ
, auio
, code
);
500 AFS_UIOMOVE(bufofzeros
,
501 DIRSIZ_LEN(slen
) - (DIRENTBASESIZE
+ slen
- 1), UIO_READ
,
503 #else /* AFS_SGI_ENV */
505 #if defined(AFS_NBSD40_ENV)
508 dp
= osi_AllocLargeSpace(sizeof(struct dirent
));
509 memset(dp
, 0, sizeof(struct dirent
));
510 dp
->d_ino
= afs_calc_inum(vc
->f
.fid
.Cell
, Volume
, ntohl(Vnode
));
512 dp
->d_type
= afs_readdir_type(vc
, de
);
513 strcpy(dp
->d_name
, de
->name
);
514 dp
->d_reclen
= _DIRENT_SIZE(dp
) /* rlen */;
515 if ((afs_debug
& AFSDEB_VNLAYER
) != 0) {
516 afs_warn("%s: %s type %d slen %d rlen %d act. rlen %zu\n", __func__
,
517 dp
->d_name
, dp
->d_type
, slen
, rlen
, _DIRENT_SIZE(dp
));
519 AFS_UIOMOVE(dp
, dp
->d_reclen
, UIO_READ
, auio
, code
);
520 osi_FreeLargeSpace((char *)dp
);
523 AFS_UIOMOVE((char *) &sdirEntry
, sizeof(sdirEntry
), UIO_READ
, auio
, code
);
525 AFS_UIOMOVE(de
->name
, slen
, UIO_READ
, auio
, code
);
527 /* pad out the remaining characters with zeros */
529 AFS_UIOMOVE(bufofzeros
, ((slen
+ 1 + DIRPAD
) & ~DIRPAD
) - slen
,
530 UIO_READ
, auio
, code
);
534 #endif /* AFS_SGI_ENV */
535 #if !defined(AFS_NBSD_ENV)
536 /* pad out the difference between rlen and slen... */
537 if (DIRSIZ_LEN(slen
) < rlen
) {
539 while (DIRSIZ_LEN(slen
) < rlen
) {
540 int minLen
= rlen
- DIRSIZ_LEN(slen
);
541 if (minLen
> sizeof(bufofzeros
))
542 minLen
= sizeof(bufofzeros
);
543 AFS_UIOMOVE(bufofzeros
, minLen
, UIO_READ
, auio
, code
);
549 #endif /* AFS_SUN5_ENV */
550 #endif /* AFS_SGI53_ENV */
556 *------------------------------------------------------------------------------
558 * Read directory entries.
559 * There are some weird things to look out for here. The uio_offset
560 * field is either 0 or it is the offset returned from a previous
561 * readdir. It is an opaque value used by the server to find the
562 * correct directory block to read. The byte count must be at least
563 * vtoblksz(vp) bytes. The count field is the number of blocks to
564 * read on the server. This is advisory only, the server may return
565 * only one block's worth of entries. Entries may be compressed on
568 * This routine encodes knowledge of Vice dirs.
572 afs_bulkstat_send(struct vcache
*avc
, struct vrequest
*req
)
578 * Here is the bad, bad, really bad news.
579 * It has to do with 'offset' (seek locations).
583 #if defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
584 afs_readdir(OSI_VC_DECL(avc
), struct uio
*auio
, afs_ucred_t
*acred
,
587 #if defined(AFS_HPUX100_ENV)
588 afs_readdir2(OSI_VC_DECL(avc
), struct uio
*auio
, afs_ucred_t
*acred
)
590 afs_readdir(OSI_VC_DECL(avc
), struct uio
*auio
, afs_ucred_t
*acred
)
594 struct vrequest
*treq
= NULL
;
596 afs_size_t origOffset
, tlen
;
599 struct DirBuffer oldEntry
, nextEntry
;
600 struct DirEntry
*ode
= 0, *nde
= 0;
601 int o_slen
= 0, n_slen
= 0;
603 struct afs_fakestat_state fakestate
;
604 #if defined(AFS_SGI53_ENV)
605 afs_int32 use64BitDirent
, dirsiz
;
606 #endif /* defined(AFS_SGI53_ENV) */
611 * XXX All the hacks for alloced sdirEntry and inlining of afs_readdir_move instead of calling
612 * it is necessary for hpux due to stack problems that seem to occur when coming thru the nfs
613 * translator side XXX
615 struct min_direct
*sdirEntry
= osi_AllocSmallSpace(sizeof(struct min_direct
));
619 /* opaque value is pointer into a vice dir; use bit map to decide
620 * if the entries are in use. Always assumed to be valid. 0 is
621 * special, means start of a new dir. Int32 inode, followed by
622 * short reclen and short namelen. Namelen does not include
623 * the null byte. Followed by null-terminated string.
625 AFS_STATCNT(afs_readdir
);
627 memset(&oldEntry
, 0, sizeof(struct DirBuffer
));
628 memset(&nextEntry
, 0, sizeof(struct DirBuffer
));
630 #if defined(AFS_SGI53_ENV)
634 ABI_IS(ABI_IRIX5_64
, GETDENTS_ABI(OSI_GET_CURRENT_ABI(), auio
));
638 UIO_USERSPACE
) ? ABI_IRIX5_64
: (ABI_IS(ABI_IRIX5_64
| ABI_IRIX5_N32
,
640 #endif /* AFS_SGI62_ENV */
641 #else /* AFS_SGI61_ENV */
644 UIO_USERSPACE
) ? ABI_IRIX5_64
: (ABI_IS(ABI_IRIX5_64
,
646 #endif /* AFS_SGI61_ENV */
647 #endif /* defined(AFS_SGI53_ENV) */
649 #if defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
650 /* Not really used by the callee so we ignore it for now */
654 #ifndef AFS_64BIT_CLIENT
655 if (AfsLargeFileUio(auio
) /* file is large than 2 GB */
656 ||AfsLargeFileSize(AFS_UIO_OFFSET(auio
), AFS_UIO_RESID(auio
)))
660 if ((code
= afs_CreateReq(&treq
, acred
))) {
662 osi_FreeSmallSpace((char *)sdirEntry
);
666 /* update the cache entry */
667 afs_InitFakeStat(&fakestate
);
671 code
= afs_EvalFakeStat(&avc
, &fakestate
, treq
);
675 code
= afs_VerifyVCache(avc
, treq
);
678 /* get a reference to the entire directory */
679 tdc
= afs_GetDCache(avc
, (afs_size_t
) 0, treq
, &origOffset
, &tlen
, 1);
684 ObtainReadLock(&avc
->lock
);
685 ObtainReadLock(&tdc
->lock
);
688 * Make sure that the data in the cache is current. There are two
689 * cases we need to worry about:
690 * 1. The cache data is being fetched by another process.
691 * 2. The cache data is no longer valid
693 while ((avc
->f
.states
& CStatd
)
694 && (tdc
->dflags
& DFFetching
)
695 && hsame(avc
->f
.m
.DataVersion
, tdc
->f
.versionNo
)) {
696 afs_Trace4(afs_iclSetp
, CM_TRACE_DCACHEWAIT
, ICL_TYPE_STRING
,
697 __FILE__
, ICL_TYPE_INT32
, __LINE__
, ICL_TYPE_POINTER
, tdc
,
698 ICL_TYPE_INT32
, tdc
->dflags
);
699 ReleaseReadLock(&tdc
->lock
);
700 ReleaseReadLock(&avc
->lock
);
701 afs_osi_Sleep(&tdc
->validPos
);
702 ObtainReadLock(&avc
->lock
);
703 ObtainReadLock(&tdc
->lock
);
705 if (!(avc
->f
.states
& CStatd
)
706 || !hsame(avc
->f
.m
.DataVersion
, tdc
->f
.versionNo
)) {
707 ReleaseReadLock(&tdc
->lock
);
708 ReleaseReadLock(&avc
->lock
);
714 * iterator for the directory reads. Takes the AFS DirEntry
715 * structure and slams them into UFS direct structures.
716 * uses afs_readdir_move to get the struct to the user space.
718 * The routine works by looking ahead one AFS directory entry.
719 * That's because the AFS entry we are currenly working with
720 * may not fit into the buffer the user has provided. If it
721 * doesn't we have to change the size of the LAST AFS directory
722 * entry, so that it will FIT perfectly into the block the
725 * The 'forward looking' of the code makes it a bit tough to read.
726 * Remember we need to get an entry, see if it it fits, then
727 * set it up as the LAST entry, and find the next one.
729 * Tough to take: We give out an EINVAL if we don't have enough
730 * space in the buffer, and at the same time, don't have an entry
731 * to put into the buffer. This CAN happen if the first AFS entry
732 * we get can't fit into the 512 character buffer provided. Seems
733 * it ought not happen...
735 * Assumption: don't need to use anything but one dc entry:
736 * this means the directory ought not be greater than 64k.
740 auio
->uio_fpflags
= 0;
743 origOffset
= AFS_UIO_OFFSET(auio
);
744 /* scan for the next interesting entry scan for in-use blob otherwise up point at
745 * this blob note that ode, if non-zero, also represents a held dir page */
746 code
= BlobScan(tdc
, (origOffset
>> 5), &us
);
749 code
= afs_dir_GetVerifiedBlob(tdc
, us
, &nextEntry
);
751 if (us
== 0 || code
!= 0) {
752 code
= 0; /* Reset code - keep old failure behaviour */
753 /* failed to setup nde, return what we've got, and release ode */
755 /* something to hand over. */
757 sdirEntry
->d_fileno
= afs_calc_inum(avc
->f
.fid
.Cell
,
758 avc
->f
.fid
.Fid
.Volume
,
759 ntohl(ode
->fid
.vnode
));
760 sdirEntry
->d_reclen
= rlen
= AFS_UIO_RESID(auio
);
761 sdirEntry
->d_namlen
= o_slen
;
762 #if defined(AFS_SUN5_ENV) || defined(AFS_AIX32_ENV) || defined(AFS_HPUX100_ENV)
763 sdirEntry
->d_off
= origOffset
;
765 AFS_UIOMOVE((char *)sdirEntry
, sizeof(*sdirEntry
), UIO_READ
,
768 AFS_UIOMOVE(ode
->name
, o_slen
, UIO_READ
, auio
, code
);
769 /* pad out the remaining characters with zeros */
771 AFS_UIOMOVE(bufofzeros
,
772 ((o_slen
+ 1 + DIRPAD
) & ~DIRPAD
) - o_slen
,
773 UIO_READ
, auio
, code
);
775 /* pad out the difference between rlen and slen... */
776 if (DIRSIZ_LEN(o_slen
) < rlen
) {
777 while (DIRSIZ_LEN(o_slen
) < rlen
) {
778 int minLen
= rlen
- DIRSIZ_LEN(o_slen
);
779 if (minLen
> sizeof(bufofzeros
))
780 minLen
= sizeof(bufofzeros
);
781 AFS_UIOMOVE(bufofzeros
, minLen
, UIO_READ
, auio
, code
);
786 code
= afs_readdir_move(ode
, avc
, auio
, o_slen
,
787 #if defined(AFS_SUN5_ENV) || defined(AFS_NBSD_ENV)
790 AFS_UIO_RESID(auio
), origOffset
);
792 #endif /* AFS_HPUX_ENV */
793 #if !defined(AFS_SUN5_ENV) && !defined(AFS_NBSD_ENV)
794 AFS_UIO_SETRESID(auio
, 0);
797 /* nothin to hand over */
799 #if defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
801 *eofp
= 1; /* Set it properly */
803 DRelease(&oldEntry
, 0);
806 nde
= (struct DirEntry
*)nextEntry
.data
;
808 /* Do we have enough user space to carry out our mission? */
809 #if defined(AFS_SGI_ENV)
810 n_slen
= strlen(nde
->name
) + 1; /* NULL terminate */
812 n_slen
= strlen(nde
->name
);
816 use64BitDirent
? DIRENTSIZE(n_slen
) : IRIX5_DIRENTSIZE(n_slen
);
817 if (dirsiz
>= (AFS_UIO_RESID(auio
) - len
)) {
819 if (DIRSIZ_LEN(n_slen
) >= (AFS_UIO_RESID(auio
) - len
)) {
820 #endif /* AFS_SGI53_ENV */
821 /* No can do no more now; ya know... at this time */
822 DRelease(&nextEntry
, 0); /* can't use this one. */
825 sdirEntry
->d_fileno
= afs_calc_inum(avc
->f
.fid
.Cell
,
826 avc
->f
.fid
.Fid
.Volume
,
827 ntohl(ode
->fid
.vnode
));
828 sdirEntry
->d_reclen
= rlen
= AFS_UIO_RESID(auio
);
829 sdirEntry
->d_namlen
= o_slen
;
830 #if defined(AFS_SUN5_ENV) || defined(AFS_AIX32_ENV) || defined(AFS_HPUX100_ENV)
831 sdirEntry
->d_off
= origOffset
;
833 AFS_UIOMOVE((char *)sdirEntry
, sizeof(*sdirEntry
), UIO_READ
,
836 AFS_UIOMOVE(ode
->name
, o_slen
, UIO_READ
, auio
, code
);
837 /* pad out the remaining characters with zeros */
839 AFS_UIOMOVE(bufofzeros
,
840 ((o_slen
+ 1 + DIRPAD
) & ~DIRPAD
) - o_slen
,
841 UIO_READ
, auio
, code
);
843 /* pad out the difference between rlen and slen... */
844 if (DIRSIZ_LEN(o_slen
) < rlen
) {
845 while (DIRSIZ_LEN(o_slen
) < rlen
) {
846 int minLen
= rlen
- DIRSIZ_LEN(o_slen
);
847 if (minLen
> sizeof(bufofzeros
))
848 minLen
= sizeof(bufofzeros
);
849 AFS_UIOMOVE(bufofzeros
, minLen
, UIO_READ
, auio
, code
);
853 #else /* AFS_HPUX_ENV */
855 afs_readdir_move(ode
, avc
, auio
, o_slen
,
856 AFS_UIO_RESID(auio
), origOffset
);
857 #endif /* AFS_HPUX_ENV */
858 /* this next line used to be AFSVFS40 or AIX 3.1, but is
860 AFS_UIO_SETOFFSET(auio
, origOffset
);
861 #if !defined(AFS_NBSD_ENV)
862 AFS_UIO_SETRESID(auio
, 0);
864 } else { /* trouble, can't give anything to the user! */
865 /* even though he has given us a buffer,
866 * even though we have something to give us,
867 * Looks like we lost something somewhere.
871 DRelease(&oldEntry
, 0);
876 * In any event, we move out the LAST de entry, getting ready
877 * to set up for the next one.
881 sdirEntry
->d_fileno
= afs_calc_inum(avc
->f
.fid
.Cell
,
882 avc
->f
.fid
.Fid
.Volume
,
883 ntohl(ode
->fid
.vnode
));
884 sdirEntry
->d_reclen
= rlen
= len
;
885 sdirEntry
->d_namlen
= o_slen
;
886 #if defined(AFS_SUN5_ENV) || defined(AFS_AIX32_ENV) || defined(AFS_HPUX100_ENV)
887 sdirEntry
->d_off
= origOffset
;
889 AFS_UIOMOVE((char *)sdirEntry
, sizeof(*sdirEntry
), UIO_READ
, auio
,
892 AFS_UIOMOVE(ode
->name
, o_slen
, UIO_READ
, auio
, code
);
893 /* pad out the remaining characters with zeros */
895 AFS_UIOMOVE(bufofzeros
,
896 ((o_slen
+ 1 + DIRPAD
) & ~DIRPAD
) - o_slen
,
897 UIO_READ
, auio
, code
);
899 /* pad out the difference between rlen and slen... */
900 if (DIRSIZ_LEN(o_slen
) < rlen
) {
901 while (DIRSIZ_LEN(o_slen
) < rlen
) {
902 int minLen
= rlen
- DIRSIZ_LEN(o_slen
);
903 if (minLen
> sizeof(bufofzeros
))
904 minLen
= sizeof(bufofzeros
);
905 AFS_UIOMOVE(bufofzeros
, minLen
, UIO_READ
, auio
, code
);
909 #else /* AFS_HPUX_ENV */
910 code
= afs_readdir_move(ode
, avc
, auio
, o_slen
, len
, origOffset
);
911 #endif /* AFS_HPUX_ENV */
914 len
= use64BitDirent
? DIRENTSIZE(o_slen
=
915 n_slen
) : IRIX5_DIRENTSIZE(o_slen
=
918 len
= DIRSIZ_LEN(o_slen
= n_slen
);
919 #endif /* AFS_SGI53_ENV */
921 DRelease(&oldEntry
, 0);
922 oldEntry
= nextEntry
;
924 AFS_UIO_SETOFFSET(auio
, (us
+ afs_dir_NameBlobs(nde
->name
)) << 5);
927 DRelease(&oldEntry
, 0);
930 ReleaseReadLock(&tdc
->lock
);
932 ReleaseReadLock(&avc
->lock
);
936 osi_FreeSmallSpace((char *)sdirEntry
);
939 afs_PutFakeStat(&fakestate
);
940 code
= afs_CheckCode(code
, treq
, 28);
941 afs_DestroyReq(treq
);
945 #endif /* !AFS_LINUX20_ENV */