9c024a1c6b5c77a4eff3c7365ffeb33630802d65
[openafs.git] / src / afs / VNOPS / afs_vnop_readdir.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  * 
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
8  */
9
10 /*
11  * afs_vnop_readdir.c - afs_readdir and bulk stat
12  *
13  * Implements:
14  * BlobScan
15  * afs_readdir_move
16  * afs_bulkstat_send
17  * afs_readdir/afs_readdir2(HP)
18  * afs_readdir1 - HP and DUX NFS versions
19  * 
20  */
21
22 #include <afsconfig.h>
23 #include "../afs/param.h"
24
25 RCSID("$Header$");
26
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"
33
34
35 /**
36  * A few definitions. This is until we have a proper header file
37  * which ahs prototypes for all functions
38  */
39     
40 extern struct DirEntry * afs_dir_GetBlob();
41 /*
42  * AFS readdir vnodeop and bulk stat support.
43  */
44
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 #.
47  */
48 #define FIXUPSTUPIDINODE(a)     ((a) &= 0x7fffffff)
49
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.
53
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.
56     
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.
59
60     BlobScan is used by the Linux port in a separate file, so it should not
61     become static.
62 */
63 #if defined(AFS_SGI62_ENV) || defined(AFS_SUN57_64BIT_ENV)
64 int BlobScan(ino64_t *afile, afs_int32 ablob)
65 #else
66 #ifdef AFS_LINUX_64BIT_KERNEL
67 int BlobScan(long *afile, afs_int32 ablob)
68 #else
69 int BlobScan(afs_int32 *afile, afs_int32 ablob)
70 #endif
71 #endif
72 {
73     register afs_int32 relativeBlob;
74     afs_int32 pageBlob;
75     register struct PageHeader *tpe;
76     register afs_int32 i;
77
78     AFS_STATCNT(BlobScan);
79     /* advance ablob over free and header blobs */
80     while (1) {
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 */
87             /* first page */
88             if (relativeBlob < DHE+1) relativeBlob = DHE+1;
89         }
90         else {                              /* others have one header blob */
91             if (relativeBlob == 0) relativeBlob = 1;
92         }
93         /* make sure blob is allocated */
94         for(i = relativeBlob; i < EPP; i++) {
95             if (tpe->freebitmap[i>>3] & (1<<(i&7))) break;
96         }
97         /* now relativeBlob is the page-relative first allocated blob,
98          or EPP (if there are none in this page). */
99         DRelease(tpe, 0);
100         if (i != EPP) return i+pageBlob;
101         ablob = pageBlob + EPP; /* go around again */
102     }
103     /* never get here */
104 }
105
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.
110  */
111
112 /*
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.
116 */
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+ */
123     off64_t     d_off;
124     u_short     d_reclen;
125 };
126 /* Short form for 32 bit apps. */
127 struct irix5_min_dirent {     /* miniature dirent structure */
128                         /* If struct dirent changes, this must too */
129     afs_uint32  d_fileno;
130     afs_int32   d_off;
131     u_short     d_reclen;
132 };
133 #ifdef AFS_SGI62_ENV
134 #define AFS_DIRENT32BASESIZE IRIX5_DIRENTBASESIZE
135 #define AFS_DIRENT64BASESIZE DIRENT64BASESIZE
136 #else
137 #define AFS_DIRENT32BASESIZE IRIX5_DIRENTBASESIZE
138 #define AFS_DIRENT64BASESIZE DIRENTBASESIZE
139 #endif /* AFS_SGI62_ENV */
140 #else
141 struct min_direct {     /* miniature direct structure */
142                         /* If struct direct changes, this must too */
143 #ifdef AFS_DARWIN_ENV
144     afs_uint32  d_fileno;
145     u_short     d_reclen;
146     u_char      d_type;
147     u_char      d_namlen;
148 #else   
149 #ifdef  AFS_SUN5_ENV
150     afs_uint32  d_fileno;
151     afs_int32   d_off;
152     u_short     d_reclen;
153 #else
154 #if defined(AFS_SUN_ENV) || defined(AFS_AIX32_ENV)
155     afs_int32   d_off;
156 #endif
157 #if     defined(AFS_HPUX100_ENV)
158     unsigned long long d_off;
159 #endif
160     afs_uint32  d_fileno;
161     u_short     d_reclen;
162     u_short     d_namlen;
163 #endif
164 #endif
165 };
166 #endif /* AFS_SGI_ENV */
167
168 #if     defined(AFS_HPUX_ENV) || defined(AFS_OSF_ENV)
169 struct minnfs_direct {
170     afs_int32   d_off;          /* XXX */
171     afs_uint32  d_fileno;
172     u_short     d_reclen;
173     u_short     d_namlen;
174 };
175 #define NDIRSIZ_LEN(len)   ((sizeof (struct dirent)+4 - (MAXNAMLEN+1)) + (((len)+1 + 3) &~ 3))
176 #endif
177 #endif /* !defined(UKERNEL) */
178
179
180 /*
181  *------------------------------------------------------------------------------
182  *
183  * Keep a stack of about 256 fids for the bulk stat call.
184  * Fill it during the readdir_move.  Later empty it...
185  */
186
187 #define READDIR_STASH   AFSCBMAX
188 struct AFSFid   afs_readdir_stash[READDIR_STASH];
189 int     afs_rd_stash_i = 0;
190
191 /*
192  *------------------------------------------------------------------------------
193  *
194  * afs_readdir_move.
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.
198  *
199  *
200 */
201 #if     defined(AFS_HPUX100_ENV)
202 #define DIRSIZ_LEN(len) \
203     ((sizeof (struct __dirent) - (_MAXNAMLEN+1)) + (((len)+1 + 3) &~ 3))
204 #else
205 #if     defined(AFS_SUN56_ENV)
206 #define DIRSIZ_LEN(len) ((18 + (len) + 1 + 7) & ~7 )
207 #else
208 #ifdef  AFS_SUN5_ENV
209 #define DIRSIZ_LEN(len) ((10 + (len) + 1 + (NBPW-1)) & ~(NBPW-1))
210 #else
211 #ifdef  AFS_DIRENT
212 #define DIRSIZ_LEN(len) \
213     ((sizeof (struct dirent) - (MAXNAMLEN+1)) + (((len)+1 + 3) &~ 3))
214 #else
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)
219 #endif
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 */
228
229 #ifdef AFS_AIX41_ENV
230 #define AFS_MOVE_LOCK()   AFS_GLOCK()
231 #define AFS_MOVE_UNLOCK() AFS_GUNLOCK()
232 #else
233 #define AFS_MOVE_LOCK()
234 #define AFS_MOVE_UNLOCK()
235 #endif
236
237 char bufofzeros[64];    /* gotta fill with something */
238 afs_readdir_move (de, vc, auio, slen, rlen, off) 
239 struct DirEntry *       de;
240 struct vcache *         vc;
241 struct  uio *           auio;
242 int                     slen;
243 #ifdef AFS_SGI65_ENV
244 ssize_t                 rlen;
245 #else
246 int                     rlen;
247 #endif
248 afs_size_t              off;
249 {
250     int code = 0;
251 #if     defined(AFS_SUN56_ENV)
252     struct dirent64 *direntp;
253 #else
254 #ifdef  AFS_SUN5_ENV
255     struct dirent *direntp;
256 #endif
257 #endif /* AFS_SUN56_ENV */
258 #ifndef AFS_SGI53_ENV
259     struct min_direct sdirEntry;
260 #endif /* AFS_SGI53_ENV */
261
262     AFS_STATCNT(afs_readdir_move);
263 #ifdef  AFS_SGI53_ENV
264 {
265     afs_int32   use64BitDirent;
266
267 #ifdef AFS_SGI61_ENV
268 #ifdef AFS_SGI62_ENV
269     use64BitDirent = ABI_IS(ABI_IRIX5_64,
270                             GETDENTS_ABI*OSI_GET_CURRENT_ABI(), auio));
271 #else
272     use64BitDirent = (auio->uio_segflg != UIO_USERSPACE) ? ABI_IRIX5_64 :
273         (ABI_IS(ABI_IRIX5_64 | ABI_IRIX5_N32, u.u_procp->p_abi));
274 #endif
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 */
279
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);
287         if (code == 0)
288             AFS_UIOMOVE(de->name, slen-1, UIO_READ, auio, code);
289         if (code == 0)
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);
298                 rlen -= minLen;
299             }
300         }
301     } else {
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);
308         if (code == 0)
309             AFS_UIOMOVE(de->name, slen-1, UIO_READ, auio, code);
310         if (code == 0)
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);
320                 rlen -= minLen;
321             }
322         }
323     }
324 }
325 #else /* AFS_SGI53_ENV */
326 #ifdef  AFS_SUN5_ENV
327 #if     defined(AFS_SUN56_ENV)
328     direntp = (struct dirent64 *) osi_AllocLargeSpace(AFS_LRALLOCSIZ);
329 #else
330     direntp = (struct dirent *) osi_AllocLargeSpace(AFS_LRALLOCSIZ);
331 #endif
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;
347 #endif
348 #if defined(AFS_SUN_ENV) || defined(AFS_AIX32_ENV) || defined(AFS_SGI_ENV)
349     sdirEntry.d_off = off;
350 #endif
351 #if defined(AFS_DARWIN_ENV)
352     sdirEntry.d_type=DT_UNKNOWN;
353 #endif
354
355 #if defined(AFS_SGI_ENV)
356     AFS_UIOMOVE(&sdirEntry, DIRENTBASESIZE, UIO_READ, auio, code);
357     if (code == 0)
358         AFS_UIOMOVE(de->name, slen-1, UIO_READ, auio, code);
359     if (code == 0)
360         AFS_UIOMOVE(bufofzeros, DIRSIZ_LEN(slen) - (DIRENTBASESIZE + slen - 1), UIO_READ, auio, code);
361 #else /* AFS_SGI_ENV */
362     AFS_MOVE_UNLOCK();
363     AFS_UIOMOVE((char *)&sdirEntry, sizeof(sdirEntry), UIO_READ, auio, code);
364
365     if (code == 0) {
366         AFS_UIOMOVE(de->name, slen, UIO_READ, auio, code);
367     }
368
369     /* pad out the remaining characters with zeros */
370     if (code == 0) { 
371         AFS_UIOMOVE(bufofzeros, ((slen + 4) & ~3) - slen, UIO_READ,
372                     auio, code);
373     }
374     AFS_MOVE_LOCK();
375 #endif /* AFS_SGI_ENV */
376
377     /* pad out the difference between rlen and slen... */
378     if (DIRSIZ_LEN(slen) < rlen)
379         {
380         AFS_MOVE_UNLOCK();
381         while(DIRSIZ_LEN(slen) < rlen)
382                 {
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);
387                 rlen -= minLen;
388                 }
389         AFS_MOVE_LOCK();
390         }
391 #endif  /* AFS_SUN5_ENV */
392 #endif  /* AFS_SGI53_ENV */
393     return(code);
394 }
395
396
397 /*
398  *------------------------------------------------------------------------------
399  *
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
408  * the server.
409  *
410  * This routine encodes knowledge of Vice dirs.
411  */
412
413 void afs_bulkstat_send( avc, req )
414     struct vcache * avc;
415     struct vrequest * req;
416 {
417     XSTATS_DECLS
418     afs_rd_stash_i = 0;
419 }
420
421 /*
422  * Here is the bad, bad, really bad news.
423  * It has to do with 'offset' (seek locations).
424 */
425
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)
428     int *eofp;
429 #else
430 #if defined(AFS_HPUX100_ENV) 
431 afs_readdir2(OSI_VC_ARG(avc), auio, acred)
432 #else
433 afs_readdir(OSI_VC_ARG(avc), auio, acred)
434 #endif 
435 #endif
436     OSI_VC_DECL(avc);
437     struct uio *auio;
438     struct AFS_UCRED *acred; 
439 {
440     struct vrequest treq;
441     register struct dcache *tdc;
442     afs_size_t origOffset, tlen;
443     afs_int32 len, dirsiz;
444     int code = 0;
445     struct DirEntry *ode = 0, *nde = 0;
446     int o_slen = 0, n_slen = 0;
447     afs_uint32 us;
448 #if defined(AFS_SGI53_ENV)
449     afs_int32 use64BitDirent;
450 #endif /* defined(AFS_SGI53_ENV) */
451     OSI_VC_CONVERT(avc)
452 #ifdef  AFS_HPUX_ENV
453     /*
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
457      */
458     struct min_direct *sdirEntry = (struct min_direct *)osi_AllocSmallSpace(sizeof(struct min_direct));
459     afs_int32 rlen;
460 #endif
461
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.
467     */
468     AFS_STATCNT(afs_readdir);
469
470 #if defined(AFS_SGI53_ENV)
471 #ifdef AFS_SGI61_ENV
472 #ifdef AFS_SGI62_ENV
473     use64BitDirent = ABI_IS(ABI_IRIX5_64,
474                             GETDENTS_ABI(OSI_GET_CURRENT_ABI(), auio));
475 #else
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) */
484
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 */
487     if (eofp) *eofp = 0;
488 #endif
489     if ( AfsLargeFileUio(auio)                  /* file is large than 2 GB */
490         || AfsLargeFileSize(auio->uio_offset, auio->uio_resid) )
491         return EFBIG;
492
493     if (code = afs_InitReq(&treq, acred)) {
494 #ifdef  AFS_HPUX_ENV
495         osi_FreeSmallSpace((char *)sdirEntry);
496 #endif
497         return code;
498     }
499     /* update the cache entry */
500 tagain:
501     code = afs_VerifyVCache(avc, &treq);
502     if (code) goto done;
503     /* get a reference to the entire directory */
504     tdc = afs_GetDCache(avc, (afs_size_t) 0, &treq, &origOffset, &tlen, 1);
505     len = tlen;
506     if (!tdc) {
507         code = ENOENT;
508         goto done;
509     }
510     ObtainReadLock(&avc->lock);
511     ObtainReadLock(&tdc->lock);
512
513     /*
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
518      */
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);
532     }
533     if (!(avc->states & CStatd)
534         || !hsame(avc->m.DataVersion, tdc->f.versionNo)) {
535         ReleaseReadLock(&tdc->lock);
536         ReleaseReadLock(&avc->lock);
537         afs_PutDCache(tdc);
538         goto tagain;
539     }
540
541     /*
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.
545      *
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
551      *  user has provided.
552      *  
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.
556      *
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... 
562      *
563      *  Assumption: don't need to use anything but one dc entry:
564      *  this means the directory ought not be greater than 64k.
565      */
566     len = 0;
567 #ifdef AFS_HPUX_ENV
568     auio->uio_fpflags = 0;
569 #endif
570     while (code==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 */
577             if (len) {
578                 /* something to hand over. */
579 #ifdef  AFS_HPUX_ENV
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;
586 #endif
587                 AFS_UIOMOVE((char *)sdirEntry, sizeof(*sdirEntry), UIO_READ, auio, code);
588                 if (code == 0)
589                     AFS_UIOMOVE(ode->name, o_slen, UIO_READ, auio, code);
590                 /* pad out the remaining characters with zeros */
591                 if (code == 0) {
592                     AFS_UIOMOVE(bufofzeros, ((o_slen + 4) & ~3) - o_slen, UIO_READ, auio, code);
593                 }
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);
601                         rlen -= minLen;
602                     }
603                 }
604 #else
605                 code = afs_readdir_move(ode, avc, auio, o_slen,
606 #if defined(AFS_SUN5_ENV)
607                                         len, origOffset);
608 #else
609                                         auio->afsio_resid, origOffset);
610 #endif
611 #endif /* AFS_HPUX_ENV */
612 #if !defined(AFS_SUN5_ENV)
613                 auio->afsio_resid = 0;
614 #endif
615             } else {
616                 /* nothin to hand over */
617             }
618 #if     defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV) || defined(AFS_OSF_ENV)
619         if (eofp) *eofp = 1;    /* Set it properly */
620 #endif
621             if (ode) DRelease(ode, 0);
622             goto dirend;
623         }
624         /* by here nde is set */
625
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 */
629 #else
630         n_slen = strlen(nde->name);
631 #endif
632 #ifdef  AFS_SGI53_ENV
633         dirsiz = use64BitDirent ? DIRENTSIZE(n_slen) :
634             IRIX5_DIRENTSIZE(n_slen);
635         if (dirsiz >= (auio->afsio_resid-len)) {
636 #else
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. */
641             if (len) {
642 #ifdef  AFS_HPUX_ENV
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;
649 #endif
650                 AFS_UIOMOVE((char *)sdirEntry, sizeof(*sdirEntry), UIO_READ, auio, code);
651                 if (code == 0)
652                     AFS_UIOMOVE(ode->name, o_slen, UIO_READ, auio, code);
653                 /* pad out the remaining characters with zeros */
654                 if (code == 0) {
655                     AFS_UIOMOVE(bufofzeros, ((o_slen + 4) & ~3) - o_slen, UIO_READ, auio, code);
656                 }
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);
664                         rlen -= minLen;
665                     }
666                 }
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
672                  * really generic */
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.
679                  */
680                 code = EINVAL;
681             }
682             if (ode) DRelease(ode, 0);
683             goto dirend;
684         }
685
686         /*
687          * In any event, we move out the LAST de entry, getting ready
688          * to set up for the next one.
689          */
690         if (len) {
691 #ifdef  AFS_HPUX_ENV
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;
699 #endif
700             AFS_UIOMOVE((char *)sdirEntry, sizeof(*sdirEntry), UIO_READ,
701                         auio, code);
702             if (code == 0)
703                 AFS_UIOMOVE(ode->name, o_slen, UIO_READ, auio, code);
704             /* pad out the remaining characters with zeros */
705             if (code == 0) {
706                 AFS_UIOMOVE(bufofzeros, ((o_slen + 4) & ~3) - o_slen,
707                             UIO_READ, auio, code);
708             }
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);
716                     rlen -= minLen;
717                 }
718             }
719 #else /* AFS_HPUX_ENV */
720             code = afs_readdir_move (ode, avc, auio, o_slen, len, origOffset);
721 #endif /* AFS_HPUX_ENV */
722         }
723 #ifdef  AFS_SGI53_ENV
724         len = use64BitDirent ? DIRENTSIZE(o_slen = n_slen) :
725             IRIX5_DIRENTSIZE(o_slen = n_slen);
726 #else
727         len = DIRSIZ_LEN( o_slen = n_slen );
728 #endif /* AFS_SGI53_ENV */
729         if (ode) DRelease(ode, 0);
730         ode = nde;
731         auio->afsio_offset = (afs_int32)((us + afs_dir_NameBlobs(nde->name)) << 5);
732     }
733     if (ode) DRelease(ode, 0);
734
735 dirend:
736     ReleaseReadLock(&tdc->lock);
737     afs_PutDCache(tdc);
738     ReleaseReadLock(&avc->lock);
739
740 done:
741 #ifdef  AFS_HPUX_ENV
742     osi_FreeSmallSpace((char *)sdirEntry);
743 #endif
744     code = afs_CheckCode(code, &treq, 28);
745     return code;
746 }
747
748 #if     defined(AFS_HPUX_ENV) || defined(AFS_OSF_ENV)
749 #ifdef  AFS_OSF_ENV
750 afs1_readdir(avc, auio, acred, eofp)
751     int *eofp;
752 #else
753 afs1_readdir(avc, auio, acred)
754 #endif
755     register struct vcache *avc;
756     struct uio *auio;
757     struct AFS_UCRED *acred; {
758     struct vrequest treq;
759     register struct dcache *tdc;
760     afs_size_t origOffset, len;
761     int code = 0;
762     struct DirEntry *ode = 0, *nde = 0;
763     int o_slen = 0, n_slen = 0;
764     afs_uint32 us;
765 #if     defined(AFS_HPUX_ENV) || defined(AFS_OSF_ENV)
766     /*
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
770      */
771     struct minnfs_direct *sdirEntry = (struct minnfs_direct *)osi_AllocSmallSpace(sizeof(struct min_direct));
772     afs_int32 rlen;
773 #endif
774
775     AFS_STATCNT(afs_readdir);
776 #if     defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV) || defined(AFS_OSF_ENV)
777     if (eofp) *eofp = 0;
778 #endif
779     if (code = afs_InitReq(&treq, acred)) {
780 #ifdef  AFS_HPUX_ENV
781         osi_FreeSmallSpace((char *)sdirEntry);
782 #endif
783         return code;
784     }
785     /* update the cache entry */
786 tagain:
787     code = afs_VerifyVCache(avc, &treq);
788     if (code) goto done;
789     /* get a reference to the entire directory */
790     tdc = afs_GetDCache(avc, (afs_size_t) 0, &treq, &origOffset, &len, 1);
791     if (!tdc) {
792         code = ENOENT;
793         goto done;
794     }
795     ObtainReadLock(&avc->lock);
796     ObtainReadLock(&tdc->lock);
797
798     /*
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
803      */
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);
817     }
818     if (!(avc->states & CStatd)
819         || !hsame(avc->m.DataVersion, tdc->f.versionNo)) {
820         ReleaseReadLock(&tdc->lock);
821         ReleaseReadLock(&avc->lock);
822         afs_PutDCache(tdc);
823         goto tagain;
824     }
825
826     len = 0;
827 #ifdef AFS_HPUX_ENV
828     auio->uio_fpflags = 0;
829 #endif
830     while (code==0) {
831         origOffset = auio->afsio_offset;
832
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 */
838             if (len) {
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);
847                 if (code == 0) {
848                     AFS_UIOMOVE(ode->name, o_slen, UIO_READ, auio, code);
849                 }
850                 /* pad out the remaining characters with zeros */
851                 if (code == 0) {
852                     AFS_UIOMOVE(bufofzeros, ((o_slen + 4) & ~3) - o_slen, UIO_READ, auio, code);
853                 }
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);
861                         rlen -= minLen;
862                     }
863                 }
864 #else
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;  
869             } else {
870                 /* nothin to hand over */
871             }
872 #if defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV) || defined(AFS_OSF_ENV)
873         if (eofp) *eofp = 1;
874 #endif
875         if (ode) DRelease(ode, 0);
876             goto dirend;
877         }
878         /* by here nde is set */
879
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 */
883 #else
884         n_slen = strlen(nde->name);
885 #endif
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. */
889             if (len) {
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);
897                 if (code == 0)
898                     AFS_UIOMOVE(ode->name, o_slen, UIO_READ, auio, code);
899                 /* pad out the remaining characters with zeros */
900                 if (code == 0) {
901                     AFS_UIOMOVE(bufofzeros, ((o_slen + 4) & ~3) - o_slen, UIO_READ, auio, code);
902                 }
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);
910                         rlen -= minLen;
911                     }
912                 }
913 #else
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.
924                  */
925                 code = EINVAL;
926             }
927             if (ode) DRelease(ode, 0);
928             goto dirend;
929         }
930
931         /*
932          * In any event, we move out the LAST de entry, getting ready
933          * to set up for the next one.
934          */
935         if (len) {
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);
943             if (code == 0)
944                 AFS_UIOMOVE(ode->name, o_slen, UIO_READ, auio, code);
945             /* pad out the remaining characters with zeros */
946             if (code == 0) {
947                 AFS_UIOMOVE(bufofzeros, ((o_slen + 4) & ~3) - o_slen, UIO_READ, auio, code);
948             }
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);
956                     rlen -= minLen;
957                 }
958             }
959 #else
960             code = afs_readdir_move (ode, avc, auio, o_slen, len, origOffset);
961 #endif /* AFS_HPUX_ENV */
962         }
963         len = NDIRSIZ_LEN( o_slen = n_slen );
964         if (ode) DRelease(ode, 0);
965         ode = nde;
966         auio->afsio_offset = ((us + afs_dir_NameBlobs(nde->name)) << 5);
967     }
968     if (ode) DRelease(ode, 0);
969
970 dirend:
971     ReleaseReadLock(&tdc->lock);
972     afs_PutDCache(tdc);
973     ReleaseReadLock(&avc->lock);
974
975 done:
976 #if     defined(AFS_HPUX_ENV) || defined(AFS_OSF_ENV)
977     osi_FreeSmallSpace((char *)sdirEntry);
978 #endif
979     code = afs_CheckCode(code, &treq, 29);
980     return code;
981 }
982
983 #endif
984 #endif /* !AFS_LINUX20_ENV */