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