Standardize License information
[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 "../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"
29
30
31 /**
32  * A few definitions. This is until we have a proper header file
33  * which ahs prototypes for all functions
34  */
35     
36 extern struct DirEntry * afs_dir_GetBlob();
37 /*
38  * AFS readdir vnodeop and bulk stat support.
39  */
40
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 #.
43  */
44 #define FIXUPSTUPIDINODE(a)     ((a) &= 0x7fffffff)
45
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.
49
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.
52     
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.
55
56     BlobScan is used by the Linux port in a separate file, so it should not
57     become static.
58 */
59 #if defined(AFS_SGI62_ENV) || defined(AFS_SUN57_64BIT_ENV)
60 int BlobScan(ino64_t *afile, afs_int32 ablob)
61 #else
62 int BlobScan(afs_int32 *afile, afs_int32 ablob)
63 #endif
64 {
65     register afs_int32 relativeBlob;
66     afs_int32 pageBlob;
67     register struct PageHeader *tpe;
68     register afs_int32 i;
69
70     AFS_STATCNT(BlobScan);
71     /* advance ablob over free and header blobs */
72     while (1) {
73         pageBlob = ablob & ~(EPP-1);    /* base blob in same page */
74         tpe = (struct PageHeader *) afs_dir_GetBlob(afile, pageBlob);
75         if (!tpe) return 0;                 /* we've past the end */
76         relativeBlob = ablob - pageBlob;    /* relative to page's first blob */
77         /* first watch for headers */
78         if (pageBlob == 0) {                /* first dir page has extra-big header */
79             /* first page */
80             if (relativeBlob < DHE+1) relativeBlob = DHE+1;
81         }
82         else {                              /* others have one header blob */
83             if (relativeBlob == 0) relativeBlob = 1;
84         }
85         /* make sure blob is allocated */
86         for(i = relativeBlob; i < EPP; i++) {
87             if (tpe->freebitmap[i>>3] & (1<<(i&7))) break;
88         }
89         /* now relativeBlob is the page-relative first allocated blob,
90          or EPP (if there are none in this page). */
91         DRelease(tpe, 0);
92         if (i != EPP) return i+pageBlob;
93         ablob = pageBlob + EPP; /* go around again */
94     }
95     /* never get here */
96 }
97
98 #if !defined(AFS_LINUX20_ENV)
99 /* Changes to afs_readdir which affect dcache or vcache handling or use of
100  * bulk stat data should also be reflected in the Linux specific verison of
101  * the readdir routine.
102  */
103
104 /*
105  * The kernel don't like it so much to have large stuff on the stack.
106  * Here we use a watered down version of the direct struct, since
107  * its not too bright to double copy the strings anyway.
108 */
109 #if !defined(UKERNEL)
110 #if defined(AFS_SGI_ENV)
111 /* Long form for 64 bit apps and kernel requests. */
112 struct min_dirent {     /* miniature dirent structure */
113                         /* If struct dirent changes, this must too */
114     ino_t       d_fileno; /* This is 32 bits for 3.5, 64 for 6.2+ */
115     off64_t     d_off;
116     u_short     d_reclen;
117 };
118 /* Short form for 32 bit apps. */
119 struct irix5_min_dirent {     /* miniature dirent structure */
120                         /* If struct dirent changes, this must too */
121     afs_uint32  d_fileno;
122     afs_int32   d_off;
123     u_short     d_reclen;
124 };
125 #ifdef AFS_SGI62_ENV
126 #define AFS_DIRENT32BASESIZE IRIX5_DIRENTBASESIZE
127 #define AFS_DIRENT64BASESIZE DIRENT64BASESIZE
128 #else
129 #define AFS_DIRENT32BASESIZE IRIX5_DIRENTBASESIZE
130 #define AFS_DIRENT64BASESIZE DIRENTBASESIZE
131 #endif /* AFS_SGI62_ENV */
132 #else
133 struct min_direct {     /* miniature direct structure */
134                         /* If struct direct changes, this must too */
135 #ifdef  AFS_SUN5_ENV
136     afs_uint32  d_fileno;
137     afs_int32   d_off;
138     u_short     d_reclen;
139 #else
140 #if defined(AFS_SUN_ENV) || defined(AFS_AIX32_ENV)
141     afs_int32   d_off;
142 #endif
143 #if     defined(AFS_HPUX100_ENV)
144     unsigned long long d_off;
145 #endif
146     afs_uint32  d_fileno;
147     u_short     d_reclen;
148     u_short     d_namlen;
149 #endif
150 };
151 #endif /* AFS_SGI_ENV */
152
153 #if     defined(AFS_HPUX_ENV) || defined(AFS_OSF_ENV)
154 struct minnfs_direct {
155     afs_int32   d_off;          /* XXX */
156     afs_uint32  d_fileno;
157     u_short     d_reclen;
158     u_short     d_namlen;
159 };
160 #define NDIRSIZ_LEN(len)   ((sizeof (struct dirent)+4 - (MAXNAMLEN+1)) + (((len)+1 + 3) &~ 3))
161 #endif
162 #endif /* !defined(UKERNEL) */
163
164
165 /*
166  *------------------------------------------------------------------------------
167  *
168  * Keep a stack of about 256 fids for the bulk stat call.
169  * Fill it during the readdir_move.  Later empty it...
170  */
171
172 #define READDIR_STASH   AFSCBMAX
173 struct AFSFid   afs_readdir_stash[READDIR_STASH];
174 int     afs_rd_stash_i = 0;
175
176 /*
177  *------------------------------------------------------------------------------
178  *
179  * afs_readdir_move.
180  *      mainly a kind of macro... makes getting the struct direct
181  *      out to the user space easy... could take more parameters,
182  *      but now just takes what it needs.
183  *
184  *
185 */
186 #if     defined(AFS_HPUX100_ENV)
187 #define DIRSIZ_LEN(len) \
188     ((sizeof (struct __dirent) - (_MAXNAMLEN+1)) + (((len)+1 + 3) &~ 3))
189 #else
190 #if     defined(AFS_SUN56_ENV)
191 #define DIRSIZ_LEN(len) ((18 + (len) + 1 + 7) & ~7 )
192 #else
193 #ifdef  AFS_SUN5_ENV
194 #define DIRSIZ_LEN(len) ((10 + (len) + 1 + (NBPW-1)) & ~(NBPW-1))
195 #else
196 #ifdef  AFS_DIRENT
197 #define DIRSIZ_LEN(len) \
198     ((sizeof (struct dirent) - (MAXNAMLEN+1)) + (((len)+1 + 3) &~ 3))
199 #else
200 #if defined(AFS_SGI_ENV)
201 #ifndef AFS_SGI53_ENV
202 /* SGI 5.3 and later use 32/64 bit versions of directory size. */
203 #define DIRSIZ_LEN(len)         DIRENTSIZE(len)
204 #endif
205 #else /* AFS_SGI_ENV */
206 #define DIRSIZ_LEN(len) \
207     ((sizeof (struct direct) - (MAXNAMLEN+1)) + (((len)+1 + 3) &~ 3))
208 #endif /* AFS_SGI_ENV */
209 #endif /* AFS_DIRENT */
210 #endif /* AFS_SUN5_ENV */
211 #endif /* AFS_SUN56_ENV */
212 #endif  /* AFS_HPUX100_ENV */
213
214 #ifdef AFS_AIX41_ENV
215 #define AFS_MOVE_LOCK()   AFS_GLOCK()
216 #define AFS_MOVE_UNLOCK() AFS_GUNLOCK()
217 #else
218 #define AFS_MOVE_LOCK()
219 #define AFS_MOVE_UNLOCK()
220 #endif
221
222 char bufofzeros[64];    /* gotta fill with something */
223 afs_readdir_move (de, vc, auio, slen, rlen, off) 
224 struct DirEntry *       de;
225 struct vcache *         vc;
226 struct  uio *           auio;
227 int                     slen;
228 #ifdef AFS_SGI65_ENV
229 ssize_t                 rlen;
230 #else
231 int                     rlen;
232 #endif
233 int                     off;
234 {
235     int code = 0;
236 #if     defined(AFS_SUN56_ENV)
237     struct dirent64 *direntp;
238 #else
239 #ifdef  AFS_SUN5_ENV
240     struct dirent *direntp;
241 #endif
242 #endif /* AFS_SUN56_ENV */
243 #ifndef AFS_SGI53_ENV
244     struct min_direct sdirEntry;
245 #endif /* AFS_SGI53_ENV */
246
247     AFS_STATCNT(afs_readdir_move);
248 #ifdef  AFS_SGI53_ENV
249 {
250     afs_int32   use64BitDirent;
251
252 #ifdef AFS_SGI61_ENV
253 #ifdef AFS_SGI62_ENV
254     use64BitDirent = ABI_IS(ABI_IRIX5_64,
255                             GETDENTS_ABI*OSI_GET_CURRENT_ABI(), auio));
256 #else
257     use64BitDirent = (auio->uio_segflg != UIO_USERSPACE) ? ABI_IRIX5_64 :
258         (ABI_IS(ABI_IRIX5_64 | ABI_IRIX5_N32, u.u_procp->p_abi));
259 #endif
260 #else /* AFS_SGI61_ENV */
261     use64BitDirent = (auio->uio_segflg != UIO_USERSPACE) ? ABI_IRIX5_64 :
262         (ABI_IS(ABI_IRIX5_64, u.u_procp->p_abi));
263 #endif /* AFS_SGI61_ENV */
264
265     if (use64BitDirent) {
266         struct min_dirent sdirEntry;
267         sdirEntry.d_fileno = (vc->fid.Fid.Volume << 16) + ntohl(de->fid.vnode);
268         FIXUPSTUPIDINODE(sdirEntry.d_fileno);
269         sdirEntry.d_reclen = rlen;
270         sdirEntry.d_off = (off_t)off;
271         AFS_UIOMOVE(&sdirEntry, AFS_DIRENT64BASESIZE, UIO_READ, auio, code);
272         if (code == 0)
273             AFS_UIOMOVE(de->name, slen-1, UIO_READ, auio, code);
274         if (code == 0)
275             AFS_UIOMOVE(bufofzeros,
276                         DIRENTSIZE(slen) - (AFS_DIRENT64BASESIZE + slen - 1),
277                         UIO_READ, auio, code);
278         if (DIRENTSIZE(slen) < rlen) {
279             while(DIRENTSIZE(slen) < rlen) {
280                 int minLen = rlen - DIRENTSIZE(slen);
281                 if (minLen > sizeof(bufofzeros)) minLen = sizeof(bufofzeros);
282                 AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
283                 rlen -= minLen;
284             }
285         }
286     } else {
287         struct irix5_min_dirent sdirEntry;
288         sdirEntry.d_fileno = (vc->fid.Fid.Volume << 16) + ntohl(de->fid.vnode);
289         FIXUPSTUPIDINODE(sdirEntry.d_fileno);
290         sdirEntry.d_reclen = rlen;
291         sdirEntry.d_off = (afs_int32)off;
292         AFS_UIOMOVE(&sdirEntry, AFS_DIRENT32BASESIZE, UIO_READ, auio, code);
293         if (code == 0)
294             AFS_UIOMOVE(de->name, slen-1, UIO_READ, auio, code);
295         if (code == 0)
296             AFS_UIOMOVE(bufofzeros,
297                         IRIX5_DIRENTSIZE(slen) -
298                         (AFS_DIRENT32BASESIZE + slen - 1),
299                            UIO_READ, auio, code);
300         if (IRIX5_DIRENTSIZE(slen) < rlen) {
301             while(IRIX5_DIRENTSIZE(slen) < rlen) {
302                 int minLen = rlen - IRIX5_DIRENTSIZE(slen);
303                 if (minLen > sizeof(bufofzeros)) minLen = sizeof(bufofzeros);
304                 AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
305                 rlen -= minLen;
306             }
307         }
308     }
309 }
310 #else /* AFS_SGI53_ENV */
311 #ifdef  AFS_SUN5_ENV
312 #if     defined(AFS_SUN56_ENV)
313     direntp = (struct dirent64 *) osi_AllocLargeSpace(AFS_LRALLOCSIZ);
314 #else
315     direntp = (struct dirent *) osi_AllocLargeSpace(AFS_LRALLOCSIZ);
316 #endif
317     direntp->d_ino =  (vc->fid.Fid.Volume << 16) + ntohl(de->fid.vnode);
318     FIXUPSTUPIDINODE(direntp->d_ino);
319     direntp->d_off = off;
320     direntp->d_reclen = rlen;
321     strcpy(direntp->d_name, de->name);
322     AFS_UIOMOVE((caddr_t)direntp, rlen, UIO_READ, auio, code);
323     osi_FreeLargeSpace((char *)direntp);
324 #else /* AFS_SUN5_ENV */
325     /* Note the odd mechanism for building the inode number */
326     sdirEntry.d_fileno = (vc->fid.Fid.Volume << 16) +
327       ntohl(de->fid.vnode);
328     FIXUPSTUPIDINODE(sdirEntry.d_fileno);
329     sdirEntry.d_reclen = rlen;
330 #if !defined(AFS_SGI_ENV)
331     sdirEntry.d_namlen = slen;
332 #endif
333 #if defined(AFS_SUN_ENV) || defined(AFS_AIX32_ENV) || defined(AFS_SGI_ENV)
334     sdirEntry.d_off = off;
335 #endif
336
337 #if defined(AFS_SGI_ENV)
338     AFS_UIOMOVE(&sdirEntry, DIRENTBASESIZE, UIO_READ, auio, code);
339     if (code == 0)
340         AFS_UIOMOVE(de->name, slen-1, UIO_READ, auio, code);
341     if (code == 0)
342         AFS_UIOMOVE(bufofzeros, DIRSIZ_LEN(slen) - (DIRENTBASESIZE + slen - 1), UIO_READ, auio, code);
343 #else /* AFS_SGI_ENV */
344     AFS_MOVE_UNLOCK();
345     AFS_UIOMOVE((char *)&sdirEntry, sizeof(sdirEntry), UIO_READ, auio, code);
346
347     if (code == 0) {
348         AFS_UIOMOVE(de->name, slen, UIO_READ, auio, code);
349     }
350
351     /* pad out the remaining characters with zeros */
352     if (code == 0) { 
353         AFS_UIOMOVE(bufofzeros, ((slen + 4) & ~3) - slen, UIO_READ,
354                     auio, code);
355     }
356     AFS_MOVE_LOCK();
357 #endif /* AFS_SGI_ENV */
358
359     /* pad out the difference between rlen and slen... */
360     if (DIRSIZ_LEN(slen) < rlen)
361         {
362         AFS_MOVE_UNLOCK();
363         while(DIRSIZ_LEN(slen) < rlen)
364                 {
365                 int minLen = rlen - DIRSIZ_LEN(slen);
366                 if (minLen > sizeof(bufofzeros))
367                         minLen = sizeof(bufofzeros);
368                 AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
369                 rlen -= minLen;
370                 }
371         AFS_MOVE_LOCK();
372         }
373 #endif  /* AFS_SUN5_ENV */
374 #endif  /* AFS_SGI53_ENV */
375     return(code);
376 }
377
378
379 /*
380  *------------------------------------------------------------------------------
381  *
382  * Read directory entries.
383  * There are some weird things to look out for here.  The uio_offset
384  * field is either 0 or it is the offset returned from a previous
385  * readdir.  It is an opaque value used by the server to find the
386  * correct directory block to read.  The byte count must be at least
387  * vtoblksz(vp) bytes.  The count field is the number of blocks to
388  * read on the server.  This is advisory only, the server may return
389  * only one block's worth of entries.  Entries may be compressed on
390  * the server.
391  *
392  * This routine encodes knowledge of Vice dirs.
393  */
394
395 void afs_bulkstat_send( avc, req )
396     struct vcache * avc;
397     struct vrequest * req;
398 {
399     XSTATS_DECLS
400     afs_rd_stash_i = 0;
401 }
402
403 /*
404  * Here is the bad, bad, really bad news.
405  * It has to do with 'offset' (seek locations).
406 */
407
408 #if     defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV) || defined(AFS_OSF_ENV)
409 afs_readdir(OSI_VC_ARG(avc), auio, acred, eofp)
410     int *eofp;
411 #else
412 #if defined(AFS_HPUX100_ENV) 
413 afs_readdir2(OSI_VC_ARG(avc), auio, acred)
414 #else
415 afs_readdir(OSI_VC_ARG(avc), auio, acred)
416 #endif 
417 #endif
418     OSI_VC_DECL(avc);
419     struct uio *auio;
420     struct AFS_UCRED *acred; {
421     struct vrequest treq;
422     register struct dcache *tdc;
423     afs_int32 origOffset, len, dirsiz;
424     int code = 0;
425     struct DirEntry *ode = 0, *nde = 0;
426     int o_slen = 0, n_slen = 0;
427     afs_uint32 us;
428 #if defined(AFS_SGI53_ENV)
429     afs_int32 use64BitDirent;
430 #endif /* defined(AFS_SGI53_ENV) */
431     OSI_VC_CONVERT(avc)
432 #ifdef  AFS_HPUX_ENV
433     /*
434      * XXX All the hacks for alloced sdirEntry and inlining of afs_readdir_move instead of calling
435      * it is necessary for hpux due to stack problems that seem to occur when coming thru the nfs
436      * translator side XXX
437      */
438     struct min_direct *sdirEntry = (struct min_direct *)osi_AllocSmallSpace(sizeof(struct min_direct));
439     afs_int32 rlen;
440 #endif
441
442     /* opaque value is pointer into a vice dir; use bit map to decide
443         if the entries are in use.  Always assumed to be valid.  0 is
444         special, means start of a new dir.  Int32 inode, followed by
445         short reclen and short namelen.  Namelen does not include
446         the null byte.  Followed by null-terminated string.
447     */
448     AFS_STATCNT(afs_readdir);
449
450 #if defined(AFS_SGI53_ENV)
451 #ifdef AFS_SGI61_ENV
452 #ifdef AFS_SGI62_ENV
453     use64BitDirent = ABI_IS(ABI_IRIX5_64,
454                             GETDENTS_ABI(OSI_GET_CURRENT_ABI(), auio));
455 #else
456     use64BitDirent = (auio->uio_segflg != UIO_USERSPACE) ? ABI_IRIX5_64 :
457         (ABI_IS(ABI_IRIX5_64 | ABI_IRIX5_N32, u.u_procp->p_abi));
458 #endif /* AFS_SGI62_ENV */
459 #else /* AFS_SGI61_ENV */
460     use64BitDirent = (auio->uio_segflg != UIO_USERSPACE) ? ABI_IRIX5_64 :
461         (ABI_IS(ABI_IRIX5_64, u.u_procp->p_abi));
462 #endif /* AFS_SGI61_ENV */
463 #endif /* defined(AFS_SGI53_ENV) */
464
465 #if     defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV) || defined(AFS_OSF_ENV)
466     /* Not really used by the callee so we ignore it for now */
467     if (eofp) *eofp = 0;
468 #endif
469     if ( AfsLargeFileUio(auio)                  /* file is large than 2 GB */
470         || AfsLargeFileSize(auio->uio_offset, auio->uio_resid) )
471         return EFBIG;
472
473     if (code = afs_InitReq(&treq, acred)) {
474 #ifdef  AFS_HPUX_ENV
475         osi_FreeSmallSpace((char *)sdirEntry);
476 #endif
477         return code;
478     }
479     /* update the cache entry */
480 tagain:
481     code = afs_VerifyVCache(avc, &treq);
482     if (code) goto done;
483     /* get a reference to the entire directory */
484     tdc = afs_GetDCache(avc, 0, &treq, &origOffset, &len, 1);
485     if (!tdc) {
486         code = ENOENT;
487         goto done;
488     }
489     ObtainReadLock(&avc->lock);
490
491     /*
492      * Make sure that the data in the cache is current. There are two
493      * cases we need to worry about:
494      * 1. The cache data is being fetched by another process.
495      * 2. The cache data is no longer valid
496      */
497     while ((avc->states & CStatd)
498            && (tdc->flags & DFFetching)
499            && hsame(avc->m.DataVersion, tdc->f.versionNo)) {
500         tdc->flags |= DFWaiting;
501         ReleaseReadLock(&avc->lock);
502         afs_osi_Sleep(&tdc->validPos);
503         ObtainReadLock(&avc->lock);
504     }
505     if (!(avc->states & CStatd)
506         || !hsame(avc->m.DataVersion, tdc->f.versionNo)) {
507         ReleaseReadLock(&avc->lock);
508         afs_PutDCache(tdc);
509         goto tagain;
510     }
511
512     /*
513      *  iterator for the directory reads.  Takes the AFS DirEntry
514      *  structure and slams them into UFS direct structures.
515      *  uses afs_readdir_move to get the struct to the user space.
516      *
517      *  The routine works by looking ahead one AFS directory entry.
518      *  That's because the AFS entry we are currenly working with
519      *  may not fit into the buffer the user has provided.  If it
520      *  doesn't we have to change the size of the LAST AFS directory
521      *  entry, so that it will FIT perfectly into the block the
522      *  user has provided.
523      *  
524      *  The 'forward looking' of the code makes it a bit tough to read.
525      *  Remember we need to get an entry, see if it it fits, then
526      *  set it up as the LAST entry, and find the next one.
527      *
528      *  Tough to take: We give out an EINVAL if we don't have enough
529      *  space in the buffer, and at the same time, don't have an entry
530      *  to put into the buffer. This CAN happen if the first AFS entry
531      *  we get can't fit into the 512 character buffer provided.  Seems
532      *  it ought not happen... 
533      *
534      *  Assumption: don't need to use anything but one dc entry:
535      *  this means the directory ought not be greater than 64k.
536      */
537     len = 0;
538 #ifdef AFS_HPUX_ENV
539     auio->uio_fpflags = 0;
540 #endif
541     while (code==0) {
542         origOffset = auio->afsio_offset;
543         /* scan for the next interesting entry scan for in-use blob otherwise up point at
544          * this blob note that ode, if non-zero, also represents a held dir page */
545         if (!(us = BlobScan(&tdc->f.inode, (origOffset >> 5)) )
546             || !(nde = (struct DirEntry *) afs_dir_GetBlob(&tdc->f.inode, us) ) ) {
547             /* failed to setup nde, return what we've got, and release ode */
548             if (len) {
549                 /* something to hand over. */
550 #ifdef  AFS_HPUX_ENV
551                 sdirEntry->d_fileno = (avc->fid.Fid.Volume << 16) + ntohl(ode->fid.vnode);
552                 FIXUPSTUPIDINODE(sdirEntry->d_fileno);
553                 sdirEntry->d_reclen = rlen = auio->afsio_resid;
554                 sdirEntry->d_namlen = o_slen;
555 #if defined(AFS_SUN_ENV) || defined(AFS_AIX32_ENV) || defined(AFS_HPUX100_ENV)
556                 sdirEntry->d_off = origOffset;
557 #endif
558                 AFS_UIOMOVE((char *)sdirEntry, sizeof(*sdirEntry), UIO_READ, auio, code);
559                 if (code == 0)
560                     AFS_UIOMOVE(ode->name, o_slen, UIO_READ, auio, code);
561                 /* pad out the remaining characters with zeros */
562                 if (code == 0) {
563                     AFS_UIOMOVE(bufofzeros, ((o_slen + 4) & ~3) - o_slen, UIO_READ, auio, code);
564                 }
565                 /* pad out the difference between rlen and slen... */
566                 if (DIRSIZ_LEN(o_slen) < rlen) {
567                     while(DIRSIZ_LEN(o_slen) < rlen) {
568                         int minLen = rlen - DIRSIZ_LEN(o_slen);
569                         if (minLen > sizeof(bufofzeros))
570                             minLen = sizeof(bufofzeros);
571                         AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
572                         rlen -= minLen;
573                     }
574                 }
575 #else
576                 code = afs_readdir_move(ode, avc, auio, o_slen,
577 #if defined(AFS_SUN5_ENV)
578                                         len, origOffset);
579 #else
580                                         auio->afsio_resid, origOffset);
581 #endif
582 #endif /* AFS_HPUX_ENV */
583 #if !defined(AFS_SUN5_ENV)
584                 auio->afsio_resid = 0;
585 #endif
586             } else {
587                 /* nothin to hand over */
588             }
589 #if     defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV) || defined(AFS_OSF_ENV)
590         if (eofp) *eofp = 1;    /* Set it properly */
591 #endif
592             if (ode) DRelease(ode, 0);
593             goto dirend;
594         }
595         /* by here nde is set */
596
597         /* Do we have enough user space to carry out our mission? */
598 #if defined(AFS_SGI_ENV)
599         n_slen = strlen(nde->name) + 1; /* NULL terminate */
600 #else
601         n_slen = strlen(nde->name);
602 #endif
603 #ifdef  AFS_SGI53_ENV
604         dirsiz = use64BitDirent ? DIRENTSIZE(n_slen) :
605             IRIX5_DIRENTSIZE(n_slen);
606         if (dirsiz >= (auio->afsio_resid-len)) {
607 #else
608         if (DIRSIZ_LEN(n_slen) >= (auio->afsio_resid-len)) {
609 #endif /* AFS_SGI53_ENV */
610             /* No can do no more now; ya know... at this time */
611             DRelease (nde, 0); /* can't use this one. */
612             if (len) {
613 #ifdef  AFS_HPUX_ENV
614                 sdirEntry->d_fileno = (avc->fid.Fid.Volume << 16) + ntohl(ode->fid.vnode);
615                 FIXUPSTUPIDINODE(sdirEntry->d_fileno);
616                 sdirEntry->d_reclen = rlen = auio->afsio_resid;
617                 sdirEntry->d_namlen = o_slen;
618 #if defined(AFS_SUN_ENV) || defined(AFS_AIX32_ENV) || defined(AFS_HPUX100_ENV)
619                 sdirEntry->d_off = origOffset;
620 #endif
621                 AFS_UIOMOVE((char *)sdirEntry, sizeof(*sdirEntry), UIO_READ, auio, code);
622                 if (code == 0)
623                     AFS_UIOMOVE(ode->name, o_slen, UIO_READ, auio, code);
624                 /* pad out the remaining characters with zeros */
625                 if (code == 0) {
626                     AFS_UIOMOVE(bufofzeros, ((o_slen + 4) & ~3) - o_slen, UIO_READ, auio, code);
627                 }
628                 /* pad out the difference between rlen and slen... */
629                 if (DIRSIZ_LEN(o_slen) < rlen) {
630                     while(DIRSIZ_LEN(o_slen) < rlen) {
631                         int minLen = rlen - DIRSIZ_LEN(o_slen);
632                         if (minLen > sizeof(bufofzeros))
633                             minLen = sizeof(bufofzeros);
634                         AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
635                         rlen -= minLen;
636                     }
637                 }
638 #else /* AFS_HPUX_ENV */
639                 code = afs_readdir_move(ode, avc, auio, o_slen,
640 #ifdef defined(AFS_SUN5_ENV)
641                                         len, origOffset);
642 #else
643                                         auio->afsio_resid, origOffset);
644 #endif
645 #endif /* AFS_HPUX_ENV */
646                 /* this next line used to be AFSVFS40 or AIX 3.1, but is
647                  * really generic */
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.
654                  */
655                 code = EINVAL;
656             }
657             if (ode) DRelease(ode, 0);
658             goto dirend;
659         }
660
661         /*
662          * In any event, we move out the LAST de entry, getting ready
663          * to set up for the next one.
664          */
665         if (len) {
666 #ifdef  AFS_HPUX_ENV
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;
674 #endif
675             AFS_UIOMOVE((char *)sdirEntry, sizeof(*sdirEntry), UIO_READ,
676                         auio, code);
677             if (code == 0)
678                 AFS_UIOMOVE(ode->name, o_slen, UIO_READ, auio, code);
679             /* pad out the remaining characters with zeros */
680             if (code == 0) {
681                 AFS_UIOMOVE(bufofzeros, ((o_slen + 4) & ~3) - o_slen,
682                             UIO_READ, auio, code);
683             }
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);
691                     rlen -= minLen;
692                 }
693             }
694 #else /* AFS_HPUX_ENV */
695             code = afs_readdir_move (ode, avc, auio, o_slen, len, origOffset);
696 #endif /* AFS_HPUX_ENV */
697         }
698 #ifdef  AFS_SGI53_ENV
699         len = use64BitDirent ? DIRENTSIZE(o_slen = n_slen) :
700             IRIX5_DIRENTSIZE(o_slen = n_slen);
701 #else
702         len = DIRSIZ_LEN( o_slen = n_slen );
703 #endif /* AFS_SGI53_ENV */
704         if (ode) DRelease(ode, 0);
705         ode = nde;
706         auio->afsio_offset = (afs_int32)((us + afs_dir_NameBlobs(nde->name)) << 5);
707     }
708     if (ode) DRelease(ode, 0);
709
710 dirend:
711     afs_PutDCache(tdc);
712     ReleaseReadLock(&avc->lock);
713
714 done:
715 #ifdef  AFS_HPUX_ENV
716     osi_FreeSmallSpace((char *)sdirEntry);
717 #endif
718     code = afs_CheckCode(code, &treq, 28);
719     return code;
720 }
721
722 #if     defined(AFS_HPUX_ENV) || defined(AFS_OSF_ENV)
723 #ifdef  AFS_OSF_ENV
724 afs1_readdir(avc, auio, acred, eofp)
725     int *eofp;
726 #else
727 afs1_readdir(avc, auio, acred)
728 #endif
729     register struct vcache *avc;
730     struct uio *auio;
731     struct AFS_UCRED *acred; {
732     struct vrequest treq;
733     register struct dcache *tdc;
734     afs_int32 origOffset, len;
735     int code = 0;
736     struct DirEntry *ode = 0, *nde = 0;
737     int o_slen = 0, n_slen = 0;
738     afs_uint32 us;
739 #if     defined(AFS_HPUX_ENV) || defined(AFS_OSF_ENV)
740     /*
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
744      */
745     struct minnfs_direct *sdirEntry = (struct minnfs_direct *)osi_AllocSmallSpace(sizeof(struct min_direct));
746     afs_int32 rlen;
747 #endif
748
749     AFS_STATCNT(afs_readdir);
750 #if     defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV) || defined(AFS_OSF_ENV)
751     if (eofp) *eofp = 0;
752 #endif
753     if (code = afs_InitReq(&treq, acred)) {
754 #ifdef  AFS_HPUX_ENV
755         osi_FreeSmallSpace((char *)sdirEntry);
756 #endif
757         return code;
758     }
759     /* update the cache entry */
760 tagain:
761     code = afs_VerifyVCache(avc, &treq);
762     if (code) goto done;
763     /* get a reference to the entire directory */
764     tdc = afs_GetDCache(avc, 0, &treq, &origOffset, &len, 1);
765     if (!tdc) {
766         code = ENOENT;
767         goto done;
768     }
769     ObtainReadLock(&avc->lock);
770
771     /*
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
776      */
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);
784     }
785     if (!(avc->states & CStatd)
786         || !hsame(avc->m.DataVersion, tdc->f.versionNo)) {
787         ReleaseReadLock(&avc->lock);
788         afs_PutDCache(tdc);
789         goto tagain;
790     }
791
792     len = 0;
793 #ifdef AFS_HPUX_ENV
794     auio->uio_fpflags = 0;
795 #endif
796     while (code==0) {
797         origOffset = auio->afsio_offset;
798
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 */
804             if (len) {
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);
813                 if (code == 0) {
814                     AFS_UIOMOVE(ode->name, o_slen, UIO_READ, auio, code);
815                 }
816                 /* pad out the remaining characters with zeros */
817                 if (code == 0) {
818                     AFS_UIOMOVE(bufofzeros, ((o_slen + 4) & ~3) - o_slen, UIO_READ, auio, code);
819                 }
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);
827                         rlen -= minLen;
828                     }
829                 }
830 #else
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;  
835             } else {
836                 /* nothin to hand over */
837             }
838 #if defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV) || defined(AFS_OSF_ENV)
839         if (eofp) *eofp = 1;
840 #endif
841         if (ode) DRelease(ode, 0);
842             goto dirend;
843         }
844         /* by here nde is set */
845
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 */
849 #else
850         n_slen = strlen(nde->name);
851 #endif
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. */
855             if (len) {
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);
863                 if (code == 0)
864                     AFS_UIOMOVE(ode->name, o_slen, UIO_READ, auio, code);
865                 /* pad out the remaining characters with zeros */
866                 if (code == 0) {
867                     AFS_UIOMOVE(bufofzeros, ((o_slen + 4) & ~3) - o_slen, UIO_READ, auio, code);
868                 }
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);
876                         rlen -= minLen;
877                     }
878                 }
879 #else
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.
890                  */
891                 code = EINVAL;
892             }
893             if (ode) DRelease(ode, 0);
894             goto dirend;
895         }
896
897         /*
898          * In any event, we move out the LAST de entry, getting ready
899          * to set up for the next one.
900          */
901         if (len) {
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);
909             if (code == 0)
910                 AFS_UIOMOVE(ode->name, o_slen, UIO_READ, auio, code);
911             /* pad out the remaining characters with zeros */
912             if (code == 0) {
913                 AFS_UIOMOVE(bufofzeros, ((o_slen + 4) & ~3) - o_slen, UIO_READ, auio, code);
914             }
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);
922                     rlen -= minLen;
923                 }
924             }
925 #else
926             code = afs_readdir_move (ode, avc, auio, o_slen, len, origOffset);
927 #endif /* AFS_HPUX_ENV */
928         }
929         len = NDIRSIZ_LEN( o_slen = n_slen );
930         if (ode) DRelease(ode, 0);
931         ode = nde;
932         auio->afsio_offset = ((us + afs_dir_NameBlobs(nde->name)) << 5);
933     }
934     if (ode) DRelease(ode, 0);
935
936 dirend:
937     afs_PutDCache(tdc);
938     ReleaseReadLock(&avc->lock);
939
940 done:
941 #if     defined(AFS_HPUX_ENV) || defined(AFS_OSF_ENV)
942     osi_FreeSmallSpace((char *)sdirEntry);
943 #endif
944     code = afs_CheckCode(code, &treq, 29);
945     return code;
946 }
947
948 #endif
949 #endif /* !AFS_LINUX20_ENV */