3b09007dd9a8978678674377693347c578652b60
[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
512     /*
513      * Make sure that the data in the cache is current. There are two
514      * cases we need to worry about:
515      * 1. The cache data is being fetched by another process.
516      * 2. The cache data is no longer valid
517      */
518     while ((avc->states & CStatd)
519            && (tdc->flags & DFFetching)
520            && hsame(avc->m.DataVersion, tdc->f.versionNo)) {
521         afs_Trace4(afs_iclSetp, CM_TRACE_DCACHEWAIT,
522                         ICL_TYPE_STRING, __FILE__,
523                         ICL_TYPE_INT32, __LINE__,
524                         ICL_TYPE_POINTER, tdc,
525                         ICL_TYPE_INT32, tdc->flags);
526         tdc->flags |= DFWaiting;
527         ReleaseReadLock(&avc->lock);
528         afs_osi_Sleep(&tdc->validPos);
529         ObtainReadLock(&avc->lock);
530     }
531     if (!(avc->states & CStatd)
532         || !hsame(avc->m.DataVersion, tdc->f.versionNo)) {
533         ReleaseReadLock(&avc->lock);
534         afs_PutDCache(tdc);
535         goto tagain;
536     }
537
538     /*
539      *  iterator for the directory reads.  Takes the AFS DirEntry
540      *  structure and slams them into UFS direct structures.
541      *  uses afs_readdir_move to get the struct to the user space.
542      *
543      *  The routine works by looking ahead one AFS directory entry.
544      *  That's because the AFS entry we are currenly working with
545      *  may not fit into the buffer the user has provided.  If it
546      *  doesn't we have to change the size of the LAST AFS directory
547      *  entry, so that it will FIT perfectly into the block the
548      *  user has provided.
549      *  
550      *  The 'forward looking' of the code makes it a bit tough to read.
551      *  Remember we need to get an entry, see if it it fits, then
552      *  set it up as the LAST entry, and find the next one.
553      *
554      *  Tough to take: We give out an EINVAL if we don't have enough
555      *  space in the buffer, and at the same time, don't have an entry
556      *  to put into the buffer. This CAN happen if the first AFS entry
557      *  we get can't fit into the 512 character buffer provided.  Seems
558      *  it ought not happen... 
559      *
560      *  Assumption: don't need to use anything but one dc entry:
561      *  this means the directory ought not be greater than 64k.
562      */
563     len = 0;
564 #ifdef AFS_HPUX_ENV
565     auio->uio_fpflags = 0;
566 #endif
567     while (code==0) {
568         origOffset = auio->afsio_offset;
569         /* scan for the next interesting entry scan for in-use blob otherwise up point at
570          * this blob note that ode, if non-zero, also represents a held dir page */
571         if (!(us = BlobScan(&tdc->f.inode, (origOffset >> 5)) )
572             || !(nde = (struct DirEntry *) afs_dir_GetBlob(&tdc->f.inode, us) ) ) {
573             /* failed to setup nde, return what we've got, and release ode */
574             if (len) {
575                 /* something to hand over. */
576 #ifdef  AFS_HPUX_ENV
577                 sdirEntry->d_fileno = (avc->fid.Fid.Volume << 16) + ntohl(ode->fid.vnode);
578                 FIXUPSTUPIDINODE(sdirEntry->d_fileno);
579                 sdirEntry->d_reclen = rlen = auio->afsio_resid;
580                 sdirEntry->d_namlen = o_slen;
581 #if defined(AFS_SUN_ENV) || defined(AFS_AIX32_ENV) || defined(AFS_HPUX100_ENV)
582                 sdirEntry->d_off = origOffset;
583 #endif
584                 AFS_UIOMOVE((char *)sdirEntry, sizeof(*sdirEntry), UIO_READ, auio, code);
585                 if (code == 0)
586                     AFS_UIOMOVE(ode->name, o_slen, UIO_READ, auio, code);
587                 /* pad out the remaining characters with zeros */
588                 if (code == 0) {
589                     AFS_UIOMOVE(bufofzeros, ((o_slen + 4) & ~3) - o_slen, UIO_READ, auio, code);
590                 }
591                 /* pad out the difference between rlen and slen... */
592                 if (DIRSIZ_LEN(o_slen) < rlen) {
593                     while(DIRSIZ_LEN(o_slen) < rlen) {
594                         int minLen = rlen - DIRSIZ_LEN(o_slen);
595                         if (minLen > sizeof(bufofzeros))
596                             minLen = sizeof(bufofzeros);
597                         AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
598                         rlen -= minLen;
599                     }
600                 }
601 #else
602                 code = afs_readdir_move(ode, avc, auio, o_slen,
603 #if defined(AFS_SUN5_ENV)
604                                         len, origOffset);
605 #else
606                                         auio->afsio_resid, origOffset);
607 #endif
608 #endif /* AFS_HPUX_ENV */
609 #if !defined(AFS_SUN5_ENV)
610                 auio->afsio_resid = 0;
611 #endif
612             } else {
613                 /* nothin to hand over */
614             }
615 #if     defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV) || defined(AFS_OSF_ENV)
616         if (eofp) *eofp = 1;    /* Set it properly */
617 #endif
618             if (ode) DRelease(ode, 0);
619             goto dirend;
620         }
621         /* by here nde is set */
622
623         /* Do we have enough user space to carry out our mission? */
624 #if defined(AFS_SGI_ENV)
625         n_slen = strlen(nde->name) + 1; /* NULL terminate */
626 #else
627         n_slen = strlen(nde->name);
628 #endif
629 #ifdef  AFS_SGI53_ENV
630         dirsiz = use64BitDirent ? DIRENTSIZE(n_slen) :
631             IRIX5_DIRENTSIZE(n_slen);
632         if (dirsiz >= (auio->afsio_resid-len)) {
633 #else
634         if (DIRSIZ_LEN(n_slen) >= (auio->afsio_resid-len)) {
635 #endif /* AFS_SGI53_ENV */
636             /* No can do no more now; ya know... at this time */
637             DRelease (nde, 0); /* can't use this one. */
638             if (len) {
639 #ifdef  AFS_HPUX_ENV
640                 sdirEntry->d_fileno = (avc->fid.Fid.Volume << 16) + ntohl(ode->fid.vnode);
641                 FIXUPSTUPIDINODE(sdirEntry->d_fileno);
642                 sdirEntry->d_reclen = rlen = auio->afsio_resid;
643                 sdirEntry->d_namlen = o_slen;
644 #if defined(AFS_SUN_ENV) || defined(AFS_AIX32_ENV) || defined(AFS_HPUX100_ENV)
645                 sdirEntry->d_off = origOffset;
646 #endif
647                 AFS_UIOMOVE((char *)sdirEntry, sizeof(*sdirEntry), UIO_READ, auio, code);
648                 if (code == 0)
649                     AFS_UIOMOVE(ode->name, o_slen, UIO_READ, auio, code);
650                 /* pad out the remaining characters with zeros */
651                 if (code == 0) {
652                     AFS_UIOMOVE(bufofzeros, ((o_slen + 4) & ~3) - o_slen, UIO_READ, auio, code);
653                 }
654                 /* pad out the difference between rlen and slen... */
655                 if (DIRSIZ_LEN(o_slen) < rlen) {
656                     while(DIRSIZ_LEN(o_slen) < rlen) {
657                         int minLen = rlen - DIRSIZ_LEN(o_slen);
658                         if (minLen > sizeof(bufofzeros))
659                             minLen = sizeof(bufofzeros);
660                         AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
661                         rlen -= minLen;
662                     }
663                 }
664 #else /* AFS_HPUX_ENV */
665                 code = afs_readdir_move(ode, avc, auio, o_slen,
666                                         auio->afsio_resid, origOffset);
667 #endif /* AFS_HPUX_ENV */
668                 /* this next line used to be AFSVFS40 or AIX 3.1, but is
669                  * really generic */
670                 auio->afsio_offset = origOffset;
671                 auio->afsio_resid = 0;  
672             } else { /* trouble, can't give anything to the user! */
673                 /* even though he has given us a buffer, 
674                  * even though we have something to give us,
675                  * Looks like we lost something somewhere.
676                  */
677                 code = EINVAL;
678             }
679             if (ode) DRelease(ode, 0);
680             goto dirend;
681         }
682
683         /*
684          * In any event, we move out the LAST de entry, getting ready
685          * to set up for the next one.
686          */
687         if (len) {
688 #ifdef  AFS_HPUX_ENV
689             sdirEntry->d_fileno =
690                 (avc->fid.Fid.Volume << 16) + ntohl(ode->fid.vnode);
691             FIXUPSTUPIDINODE(sdirEntry->d_fileno);
692             sdirEntry->d_reclen = rlen = len;
693             sdirEntry->d_namlen = o_slen;
694 #if defined(AFS_SUN_ENV) || defined(AFS_AIX32_ENV) || defined(AFS_HPUX100_ENV)
695             sdirEntry->d_off = origOffset;
696 #endif
697             AFS_UIOMOVE((char *)sdirEntry, sizeof(*sdirEntry), UIO_READ,
698                         auio, code);
699             if (code == 0)
700                 AFS_UIOMOVE(ode->name, o_slen, UIO_READ, auio, code);
701             /* pad out the remaining characters with zeros */
702             if (code == 0) {
703                 AFS_UIOMOVE(bufofzeros, ((o_slen + 4) & ~3) - o_slen,
704                             UIO_READ, auio, code);
705             }
706             /* pad out the difference between rlen and slen... */
707             if (DIRSIZ_LEN(o_slen) < rlen) {
708                 while(DIRSIZ_LEN(o_slen) < rlen) {
709                     int minLen = rlen - DIRSIZ_LEN(o_slen);
710                     if (minLen > sizeof(bufofzeros))
711                         minLen = sizeof(bufofzeros);
712                     AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
713                     rlen -= minLen;
714                 }
715             }
716 #else /* AFS_HPUX_ENV */
717             code = afs_readdir_move (ode, avc, auio, o_slen, len, origOffset);
718 #endif /* AFS_HPUX_ENV */
719         }
720 #ifdef  AFS_SGI53_ENV
721         len = use64BitDirent ? DIRENTSIZE(o_slen = n_slen) :
722             IRIX5_DIRENTSIZE(o_slen = n_slen);
723 #else
724         len = DIRSIZ_LEN( o_slen = n_slen );
725 #endif /* AFS_SGI53_ENV */
726         if (ode) DRelease(ode, 0);
727         ode = nde;
728         auio->afsio_offset = (afs_int32)((us + afs_dir_NameBlobs(nde->name)) << 5);
729     }
730     if (ode) DRelease(ode, 0);
731
732 dirend:
733     afs_PutDCache(tdc);
734     ReleaseReadLock(&avc->lock);
735
736 done:
737 #ifdef  AFS_HPUX_ENV
738     osi_FreeSmallSpace((char *)sdirEntry);
739 #endif
740     code = afs_CheckCode(code, &treq, 28);
741     return code;
742 }
743
744 #if     defined(AFS_HPUX_ENV) || defined(AFS_OSF_ENV)
745 #ifdef  AFS_OSF_ENV
746 afs1_readdir(avc, auio, acred, eofp)
747     int *eofp;
748 #else
749 afs1_readdir(avc, auio, acred)
750 #endif
751     register struct vcache *avc;
752     struct uio *auio;
753     struct AFS_UCRED *acred; {
754     struct vrequest treq;
755     register struct dcache *tdc;
756     afs_size_t origOffset, len;
757     int code = 0;
758     struct DirEntry *ode = 0, *nde = 0;
759     int o_slen = 0, n_slen = 0;
760     afs_uint32 us;
761 #if     defined(AFS_HPUX_ENV) || defined(AFS_OSF_ENV)
762     /*
763      * XXX All the hacks for alloced sdirEntry and inlining of afs_readdir_move instead of calling
764      * it is necessary for hpux due to stack problems that seem to occur when coming thru the nfs
765      * translator side XXX
766      */
767     struct minnfs_direct *sdirEntry = (struct minnfs_direct *)osi_AllocSmallSpace(sizeof(struct min_direct));
768     afs_int32 rlen;
769 #endif
770
771     AFS_STATCNT(afs_readdir);
772 #if     defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV) || defined(AFS_OSF_ENV)
773     if (eofp) *eofp = 0;
774 #endif
775     if (code = afs_InitReq(&treq, acred)) {
776 #ifdef  AFS_HPUX_ENV
777         osi_FreeSmallSpace((char *)sdirEntry);
778 #endif
779         return code;
780     }
781     /* update the cache entry */
782 tagain:
783     code = afs_VerifyVCache(avc, &treq);
784     if (code) goto done;
785     /* get a reference to the entire directory */
786     tdc = afs_GetDCache(avc, (afs_size_t) 0, &treq, &origOffset, &len, 1);
787     if (!tdc) {
788         code = ENOENT;
789         goto done;
790     }
791     ObtainReadLock(&avc->lock);
792
793     /*
794      * Make sure that the data in the cache is current. There are two
795      * cases we need to worry about:
796      * 1. The cache data is being fetched by another process.
797      * 2. The cache data is no longer valid
798      */
799     while ((avc->states & CStatd)
800            && (tdc->flags & DFFetching)
801            && hsame(avc->m.DataVersion, tdc->f.versionNo)) {
802         afs_Trace4(afs_iclSetp, CM_TRACE_DCACHEWAIT,
803                         ICL_TYPE_STRING, __FILE__,
804                         ICL_TYPE_INT32, __LINE__,
805                         ICL_TYPE_POINTER, tdc,
806                         ICL_TYPE_INT32, tdc->flags);
807         tdc->flags |= DFWaiting;
808         ReleaseReadLock(&avc->lock);
809         afs_osi_Sleep(&tdc->validPos);
810         ObtainReadLock(&avc->lock);
811     }
812     if (!(avc->states & CStatd)
813         || !hsame(avc->m.DataVersion, tdc->f.versionNo)) {
814         ReleaseReadLock(&avc->lock);
815         afs_PutDCache(tdc);
816         goto tagain;
817     }
818
819     len = 0;
820 #ifdef AFS_HPUX_ENV
821     auio->uio_fpflags = 0;
822 #endif
823     while (code==0) {
824         origOffset = auio->afsio_offset;
825
826         /* scan for the next interesting entry scan for in-use blob otherwise up point at
827          * this blob note that ode, if non-zero, also represents a held dir page */
828         if (!(us = BlobScan(&tdc->f.inode, (origOffset >> 5)) )
829             || !(nde = (struct DirEntry *) afs_dir_GetBlob(&tdc->f.inode, us) ) ) {
830             /* failed to setup nde, return what we've got, and release ode */
831             if (len) {
832                 /* something to hand over. */
833 #if     defined(AFS_HPUX_ENV) || defined(AFS_OSF_ENV)
834                 sdirEntry->d_fileno = (avc->fid.Fid.Volume << 16) + ntohl(ode->fid.vnode);
835                 FIXUPSTUPIDINODE(sdirEntry->d_fileno);
836                 sdirEntry->d_reclen = rlen = auio->afsio_resid;
837                 sdirEntry->d_namlen = o_slen;
838                 sdirEntry->d_off = origOffset;
839                 AFS_UIOMOVE((char *)sdirEntry, sizeof(*sdirEntry), UIO_READ, auio, code);
840                 if (code == 0) {
841                     AFS_UIOMOVE(ode->name, o_slen, UIO_READ, auio, code);
842                 }
843                 /* pad out the remaining characters with zeros */
844                 if (code == 0) {
845                     AFS_UIOMOVE(bufofzeros, ((o_slen + 4) & ~3) - o_slen, UIO_READ, auio, code);
846                 }
847                 /* pad out the difference between rlen and slen... */
848                 if (NDIRSIZ_LEN(o_slen) < rlen) {
849                     while(NDIRSIZ_LEN(o_slen) < rlen) {
850                         int minLen = rlen - NDIRSIZ_LEN(o_slen);
851                         if (minLen > sizeof(bufofzeros))
852                             minLen = sizeof(bufofzeros);
853                         AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
854                         rlen -= minLen;
855                     }
856                 }
857 #else
858                 code = afs_readdir_move(ode, avc, auio, o_slen,
859                                         auio->afsio_resid, origOffset);
860 #endif /* AFS_HPUX_ENV */
861                 auio->afsio_resid = 0;  
862             } else {
863                 /* nothin to hand over */
864             }
865 #if defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV) || defined(AFS_OSF_ENV)
866         if (eofp) *eofp = 1;
867 #endif
868         if (ode) DRelease(ode, 0);
869             goto dirend;
870         }
871         /* by here nde is set */
872
873         /* Do we have enough user space to carry out our mission? */
874 #if defined(AFS_SGI_ENV)
875         n_slen = strlen(nde->name) + 1; /* NULL terminate */
876 #else
877         n_slen = strlen(nde->name);
878 #endif
879         if (NDIRSIZ_LEN(n_slen) >= (auio->afsio_resid-len)) {
880             /* No can do no more now; ya know... at this time */
881             DRelease (nde, 0); /* can't use this one. */
882             if (len) {
883 #if     defined(AFS_HPUX_ENV) || defined(AFS_OSF_ENV)
884                 sdirEntry->d_fileno = (avc->fid.Fid.Volume << 16) + ntohl(ode->fid.vnode);
885                 FIXUPSTUPIDINODE(sdirEntry->d_fileno);
886                 sdirEntry->d_reclen = rlen = auio->afsio_resid;
887                 sdirEntry->d_namlen = o_slen;
888                 sdirEntry->d_off = origOffset;
889                 AFS_UIOMOVE((char *)sdirEntry, sizeof(*sdirEntry), UIO_READ, auio, code);
890                 if (code == 0)
891                     AFS_UIOMOVE(ode->name, o_slen, UIO_READ, auio, code);
892                 /* pad out the remaining characters with zeros */
893                 if (code == 0) {
894                     AFS_UIOMOVE(bufofzeros, ((o_slen + 4) & ~3) - o_slen, UIO_READ, auio, code);
895                 }
896                 /* pad out the difference between rlen and slen... */
897                 if (NDIRSIZ_LEN(o_slen) < rlen) {
898                     while(NDIRSIZ_LEN(o_slen) < rlen) {
899                         int minLen = rlen - NDIRSIZ_LEN(o_slen);
900                         if (minLen > sizeof(bufofzeros))
901                             minLen = sizeof(bufofzeros);
902                         AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
903                         rlen -= minLen;
904                     }
905                 }
906 #else
907                 code = afs_readdir_move(ode, avc, auio, o_slen,
908                                 auio->afsio_resid, origOffset);
909 #endif /* AFS_HPUX_ENV */
910                 /* this next line used to be AFSVFS40 or AIX 3.1, but is really generic */
911                 auio->afsio_offset = origOffset;
912                 auio->afsio_resid = 0;  
913             } else { /* trouble, can't give anything to the user! */
914                 /* even though he has given us a buffer, 
915                  * even though we have something to give us,
916                  * Looks like we lost something somewhere.
917                  */
918                 code = EINVAL;
919             }
920             if (ode) DRelease(ode, 0);
921             goto dirend;
922         }
923
924         /*
925          * In any event, we move out the LAST de entry, getting ready
926          * to set up for the next one.
927          */
928         if (len) {
929 #if     defined(AFS_HPUX_ENV) || defined(AFS_OSF_ENV)
930             sdirEntry->d_fileno = (avc->fid.Fid.Volume << 16) + ntohl(ode->fid.vnode);
931             FIXUPSTUPIDINODE(sdirEntry->d_fileno);
932             sdirEntry->d_reclen = rlen = len;
933             sdirEntry->d_namlen = o_slen;
934             sdirEntry->d_off = origOffset;
935             AFS_UIOMOVE((char *)sdirEntry, sizeof(*sdirEntry), UIO_READ, auio, code);
936             if (code == 0)
937                 AFS_UIOMOVE(ode->name, o_slen, UIO_READ, auio, code);
938             /* pad out the remaining characters with zeros */
939             if (code == 0) {
940                 AFS_UIOMOVE(bufofzeros, ((o_slen + 4) & ~3) - o_slen, UIO_READ, auio, code);
941             }
942             /* pad out the difference between rlen and slen... */
943             if (NDIRSIZ_LEN(o_slen) < rlen) {
944                 while(NDIRSIZ_LEN(o_slen) < rlen) {
945                     int minLen = rlen - NDIRSIZ_LEN(o_slen);
946                     if (minLen > sizeof(bufofzeros))
947                         minLen = sizeof(bufofzeros);
948                     AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
949                     rlen -= minLen;
950                 }
951             }
952 #else
953             code = afs_readdir_move (ode, avc, auio, o_slen, len, origOffset);
954 #endif /* AFS_HPUX_ENV */
955         }
956         len = NDIRSIZ_LEN( o_slen = n_slen );
957         if (ode) DRelease(ode, 0);
958         ode = nde;
959         auio->afsio_offset = ((us + afs_dir_NameBlobs(nde->name)) << 5);
960     }
961     if (ode) DRelease(ode, 0);
962
963 dirend:
964     afs_PutDCache(tdc);
965     ReleaseReadLock(&avc->lock);
966
967 done:
968 #if     defined(AFS_HPUX_ENV) || defined(AFS_OSF_ENV)
969     osi_FreeSmallSpace((char *)sdirEntry);
970 #endif
971     code = afs_CheckCode(code, &treq, 29);
972     return code;
973 }
974
975 #endif
976 #endif /* !AFS_LINUX20_ENV */