8cfcae7ed46d3edbce4e952b4c6b3208ac42d890
[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
26     ("$Header$");
27
28 #include "afs/sysincludes.h"    /* Standard vendor system headers */
29 #include "afsincludes.h"        /* Afs-based standard headers */
30 #include "afs/afs_stats.h"      /* statistics */
31 #include "afs/afs_cbqueue.h"
32 #include "afs/nfsclient.h"
33 #include "afs/afs_osidnlc.h"
34
35
36 #if     defined(AFS_HPUX1122_ENV)
37 #define DIRPAD 7
38 #else
39 #define DIRPAD 3
40 #endif
41 /**
42  * A few definitions. This is until we have a proper header file
43  * which ahs prototypes for all functions
44  */
45
46 extern struct DirEntry *afs_dir_GetBlob();
47 /*
48  * AFS readdir vnodeop and bulk stat support.
49  */
50
51 /* Saber C hates negative inode #s.  We're not going to talk about software
52  * that could fail if it sees a negative inode #.
53  */
54 #define FIXUPSTUPIDINODE(a)     ((a) &= 0x7fffffff)
55
56 /* BlobScan is supposed to ensure that the blob reference refers to a valid
57     directory entry.  It consults the allocation map in the page header
58     to determine whether a blob is actually in use or not.
59
60     More formally, BlobScan is supposed to return a new blob number which is just like
61     the input parameter, only it is advanced over header or free blobs.
62     
63     Note that BlobScan switches pages if necessary.  BlobScan may return
64     either 0 or an out-of-range blob number for end of file.
65
66     BlobScan is used by the Linux port in a separate file, so it should not
67     become static.
68 */
69 int
70 BlobScan(struct dcache * afile, afs_int32 ablob)
71 {
72     register afs_int32 relativeBlob;
73     afs_int32 pageBlob;
74     register struct PageHeader *tpe;
75     register afs_int32 i;
76
77     AFS_STATCNT(BlobScan);
78     /* advance ablob over free and header blobs */
79     while (1) {
80         pageBlob = ablob & ~(EPP - 1);  /* base blob in same page */
81         tpe = (struct PageHeader *)afs_dir_GetBlob(afile, pageBlob);
82         if (!tpe)
83             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)
89                 relativeBlob = DHE + 1;
90         } else {                /* others have one header blob */
91             if (relativeBlob == 0)
92                 relativeBlob = 1;
93         }
94         /* make sure blob is allocated */
95         for (i = relativeBlob; i < EPP; i++) {
96             if (tpe->freebitmap[i >> 3] & (1 << (i & 7)))
97                 break;
98         }
99         /* now relativeBlob is the page-relative first allocated blob,
100          * or EPP (if there are none in this page). */
101         DRelease((struct buffer *)tpe, 0);
102         if (i != EPP)
103             return i + pageBlob;
104         ablob = pageBlob + EPP; /* go around again */
105     }
106     /* never get here */
107 }
108
109 #if !defined(AFS_LINUX20_ENV)
110 /* Changes to afs_readdir which affect dcache or vcache handling or use of
111  * bulk stat data should also be reflected in the Linux specific verison of
112  * the readdir routine.
113  */
114
115 /*
116  * The kernel don't like it so much to have large stuff on the stack.
117  * Here we use a watered down version of the direct struct, since
118  * its not too bright to double copy the strings anyway.
119 */
120 #if !defined(UKERNEL)
121 #if defined(AFS_SGI_ENV)
122 /* Long form for 64 bit apps and kernel requests. */
123 struct min_dirent {             /* miniature dirent structure */
124     /* If struct dirent changes, this must too */
125     ino_t d_fileno;             /* This is 32 bits for 3.5, 64 for 6.2+ */
126     off64_t d_off;
127     u_short d_reclen;
128 };
129 /* Short form for 32 bit apps. */
130 struct irix5_min_dirent {       /* miniature dirent structure */
131     /* If struct dirent changes, this must too */
132     afs_uint32 d_fileno;
133     afs_int32 d_off;
134     u_short d_reclen;
135 };
136 #ifdef AFS_SGI62_ENV
137 #define AFS_DIRENT32BASESIZE IRIX5_DIRENTBASESIZE
138 #define AFS_DIRENT64BASESIZE DIRENT64BASESIZE
139 #else
140 #define AFS_DIRENT32BASESIZE IRIX5_DIRENTBASESIZE
141 #define AFS_DIRENT64BASESIZE DIRENTBASESIZE
142 #endif /* AFS_SGI62_ENV */
143 #else
144 struct min_direct {             /* miniature direct structure */
145     /* If struct direct changes, this must too */
146 #if defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
147     afs_uint32 d_fileno;
148     u_short d_reclen;
149     u_char d_type;
150     u_char d_namlen;
151 #elif defined(AFS_SUN5_ENV)
152     afs_uint32 d_fileno;
153     afs_int32 d_off;
154     u_short d_reclen;
155 #else
156 #if defined(AFS_AIX32_ENV)
157     afs_int32 d_off;
158 #elif defined(AFS_HPUX100_ENV)
159     unsigned long long d_off;
160 #endif
161     afs_uint32 d_fileno;
162     u_short d_reclen;
163     u_short d_namlen;
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 + DIRPAD) &~ DIRPAD))
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
202 #if     defined(AFS_HPUX100_ENV)
203 #define DIRSIZ_LEN(len) \
204     ((sizeof (struct __dirent) - (_MAXNAMLEN+1)) + (((len)+1 + DIRPAD) &~ DIRPAD))
205 #else
206 #if     defined(AFS_SUN56_ENV)
207 #define DIRSIZ_LEN(len) ((18 + (len) + 1 + 7) & ~7 )
208 #else
209 #ifdef  AFS_SUN5_ENV
210 #define DIRSIZ_LEN(len) ((10 + (len) + 1 + (NBPW-1)) & ~(NBPW-1))
211 #else
212 #ifdef  AFS_DIRENT
213 #define DIRSIZ_LEN(len) \
214     ((sizeof (struct dirent) - (MAXNAMLEN+1)) + (((len)+1 + 3) &~ 3))
215 #else
216 #if defined(AFS_SGI_ENV)
217 #ifndef AFS_SGI53_ENV
218 /* SGI 5.3 and later use 32/64 bit versions of directory size. */
219 #define DIRSIZ_LEN(len)         DIRENTSIZE(len)
220 #endif
221 #else /* AFS_SGI_ENV */
222 #define DIRSIZ_LEN(len) \
223     ((sizeof (struct direct) - (MAXNAMLEN+1)) + (((len)+1 + 3) &~ 3))
224 #endif /* AFS_SGI_ENV */
225 #endif /* AFS_DIRENT */
226 #endif /* AFS_SUN5_ENV */
227 #endif /* AFS_SUN56_ENV */
228 #endif /* AFS_HPUX100_ENV */
229
230 #if defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
231 int
232 afs_readdir_type(avc, ade)
233      struct DirEntry *ade;
234      struct vcache *avc;
235 {
236     struct VenusFid tfid;
237     struct vcache *tvc;
238     int vtype;
239     tfid.Cell = avc->fid.Cell;
240     tfid.Fid.Volume = avc->fid.Fid.Volume;
241     tfid.Fid.Vnode = ntohl(ade->fid.vnode);
242     tfid.Fid.Unique = ntohl(ade->fid.vunique);
243     if ((avc->states & CForeign) == 0 && (ntohl(ade->fid.vnode) & 1)) {
244         return DT_DIR;
245     } else if ((tvc = afs_FindVCache(&tfid, 0, 0))) {
246         if (tvc->mvstat) {
247             afs_PutVCache(tvc);
248             return DT_DIR;
249         } else if (((tvc->states) & (CStatd | CTruth))) {
250             /* CTruth will be set if the object has
251              *ever* been statd */
252             vtype = vType(tvc);
253             afs_PutVCache(tvc);
254             if (vtype == VDIR)
255                 return DT_DIR;
256             else if (vtype == VREG)
257                 return DT_REG;
258             /* Don't do this until we're sure it can't be a mtpt */
259             /* else if (vtype == VLNK)
260              * type=DT_LNK; */
261             /* what other types does AFS support? */
262         } else
263             afs_PutVCache(tvc);
264     }
265     return DT_UNKNOWN;
266 }
267 #endif
268
269 #ifdef AFS_AIX41_ENV
270 #define AFS_MOVE_LOCK()   AFS_GLOCK()
271 #define AFS_MOVE_UNLOCK() AFS_GUNLOCK()
272 #else
273 #define AFS_MOVE_LOCK()
274 #define AFS_MOVE_UNLOCK()
275 #endif
276 char bufofzeros[64];            /* gotta fill with something */
277
278 int
279 afs_readdir_move(de, vc, auio, slen, rlen, off)
280      struct DirEntry *de;
281      struct vcache *vc;
282      struct uio *auio;
283      int slen;
284 #ifdef AFS_SGI65_ENV
285      ssize_t rlen;
286 #else
287      int rlen;
288 #endif
289      afs_size_t off;
290 {
291     int code = 0;
292     struct volume *tvp;
293     afs_uint32 Volume = vc->fid.Fid.Volume;
294     afs_uint32 Vnode  = de->fid.vnode;
295 #if     defined(AFS_SUN56_ENV)
296     struct dirent64 *direntp;
297 #else
298 #if  defined(AFS_SUN5_ENV) || (defined(AFS_AIX51_ENV) && defined(AFS_64BIT_KERNEL))
299     struct dirent *direntp;
300 #endif
301 #endif /* AFS_SUN56_ENV */
302 #ifndef AFS_SGI53_ENV
303     struct min_direct sdirEntry;
304 #endif /* AFS_SGI53_ENV */
305
306     AFS_STATCNT(afs_readdir_move);
307
308 #define READDIR_CORRECT_INUMS
309 #ifdef READDIR_CORRECT_INUMS
310     if (de->name[0] == '.' && !de->name[1]) {
311         /* This is the '.' entry; if we are a volume root, we need to
312          * ignore the directory and use the inum for the mount point.
313          */
314         if (!FidCmp(&afs_rootFid, &vc->fid)) {
315             Volume = 0;
316             Vnode  = 2;
317         } else if (vc->mvstat == 2) {
318             tvp = afs_GetVolume(&vc->fid, 0, READ_LOCK);
319             if (tvp) {
320                 Volume = tvp->mtpoint.Fid.Volume;
321                 Vnode  = tvp->mtpoint.Fid.Vnode;
322                 afs_PutVolume(tvp, READ_LOCK);
323             }
324         }
325     }
326     else if (de->name[0] == '.' && de->name[1] == '.' && !de->name[2]) {
327         /* This is the '..' entry.  Getting this right is very tricky,
328          * because we might be a volume root (so our parent is in a
329          * different volume), or our parent might be a volume root
330          * (so we actually want the mount point) or BOTH! */
331         if (!FidCmp(&afs_rootFid, &vc->fid)) {
332             /* We are the root of the AFS root, and thus our own parent */
333             Volume = 0;
334             Vnode  = 2;
335         } else if (vc->mvstat == 2) {
336             /* We are a volume root, which means our parent is in another
337              * volume.  Luckily, we should have his fid cached... */
338             if (vc->mvid) {
339                 if (!FidCmp(&afs_rootFid, vc->mvid)) {
340                     /* Parent directory is the root of the AFS root */
341                     Volume = 0;
342                     Vnode  = 2;
343                 } else if (vc->mvid->Fid.Vnode == 1
344                            && vc->mvid->Fid.Unique == 1) {
345                     /* XXX The above test is evil and probably breaks DFS */
346                     /* Parent directory is the target of a mount point */
347                     tvp = afs_GetVolume(vc->mvid, 0, READ_LOCK);
348                     if (tvp) {
349                         Volume = tvp->mtpoint.Fid.Volume;
350                         Vnode  = tvp->mtpoint.Fid.Vnode;
351                         afs_PutVolume(tvp, READ_LOCK);
352                     }
353                 } else {
354                     /* Parent directory is not a volume root */
355                     Volume = vc->mvid->Fid.Volume;
356                     Vnode  = vc->mvid->Fid.Vnode;
357                 }
358             }
359         } else if (de->fid.vnode == 1 && de->fid.vunique == 1) {
360             /* XXX The above test is evil and probably breaks DFS */
361             /* Parent directory is a volume root; use the right inum */
362             tvp = afs_GetVolume(&vc->fid, 0, READ_LOCK);
363             if (tvp) {
364                 if (tvp->cell == afs_rootFid.Cell
365                     && tvp->volume == afs_rootFid.Fid.Volume) {
366                     /* Parent directory is the root of the AFS root */
367                     Volume = 0;
368                     Vnode  = 2;
369                 } else {
370                     /* Parent directory is the target of a mount point */
371                     Volume = tvp->mtpoint.Fid.Volume;
372                     Vnode  = tvp->mtpoint.Fid.Vnode;
373                 }
374                 afs_PutVolume(tvp, READ_LOCK);
375             }
376         }
377     }
378 #endif
379
380 #ifdef  AFS_SGI53_ENV
381     {
382         afs_int32 use64BitDirent;
383
384 #ifdef AFS_SGI61_ENV
385 #ifdef AFS_SGI62_ENV
386         use64BitDirent =
387             ABI_IS(ABI_IRIX5_64, GETDENTS_ABI(OSI_GET_CURRENT_ABI(), auio));
388 #else
389         use64BitDirent =
390             (auio->uio_segflg !=
391              UIO_USERSPACE) ? ABI_IRIX5_64 : (ABI_IS(ABI_IRIX5_64 |
392                                                      ABI_IRIX5_N32,
393                                                      u.u_procp->p_abi));
394 #endif
395 #else /* AFS_SGI61_ENV */
396         use64BitDirent =
397             (auio->uio_segflg !=
398              UIO_USERSPACE) ? ABI_IRIX5_64 : (ABI_IS(ABI_IRIX5_64,
399                                                      u.u_procp->p_abi));
400 #endif /* AFS_SGI61_ENV */
401
402         if (use64BitDirent) {
403             struct min_dirent sdirEntry;
404             sdirEntry.d_fileno = (Volume << 16) + ntohl(Vnode);
405             FIXUPSTUPIDINODE(sdirEntry.d_fileno);
406             sdirEntry.d_reclen = rlen;
407             sdirEntry.d_off = (off_t) off;
408             AFS_UIOMOVE(&sdirEntry, AFS_DIRENT64BASESIZE, UIO_READ, auio,
409                         code);
410             if (code == 0)
411                 AFS_UIOMOVE(de->name, slen - 1, UIO_READ, auio, code);
412             if (code == 0)
413                 AFS_UIOMOVE(bufofzeros,
414                             DIRENTSIZE(slen) - (AFS_DIRENT64BASESIZE + slen -
415                                                 1), UIO_READ, auio, code);
416             if (DIRENTSIZE(slen) < rlen) {
417                 while (DIRENTSIZE(slen) < rlen) {
418                     int minLen = rlen - DIRENTSIZE(slen);
419                     if (minLen > sizeof(bufofzeros))
420                         minLen = sizeof(bufofzeros);
421                     AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
422                     rlen -= minLen;
423                 }
424             }
425         } else {
426             struct irix5_min_dirent sdirEntry;
427             sdirEntry.d_fileno = (Volume << 16) + ntohl(Vnode);
428             FIXUPSTUPIDINODE(sdirEntry.d_fileno);
429             sdirEntry.d_reclen = rlen;
430             sdirEntry.d_off = (afs_int32) off;
431             AFS_UIOMOVE(&sdirEntry, AFS_DIRENT32BASESIZE, UIO_READ, auio,
432                         code);
433             if (code == 0)
434                 AFS_UIOMOVE(de->name, slen - 1, UIO_READ, auio, code);
435             if (code == 0)
436                 AFS_UIOMOVE(bufofzeros,
437                             IRIX5_DIRENTSIZE(slen) - (AFS_DIRENT32BASESIZE +
438                                                       slen - 1), UIO_READ,
439                             auio, code);
440             if (IRIX5_DIRENTSIZE(slen) < rlen) {
441                 while (IRIX5_DIRENTSIZE(slen) < rlen) {
442                     int minLen = rlen - IRIX5_DIRENTSIZE(slen);
443                     if (minLen > sizeof(bufofzeros))
444                         minLen = sizeof(bufofzeros);
445                     AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
446                     rlen -= minLen;
447                 }
448             }
449         }
450     }
451 #else /* AFS_SGI53_ENV */
452 #if  defined(AFS_SUN5_ENV) || (defined(AFS_AIX51_ENV) && defined(AFS_64BIT_KERNEL))
453 #if     defined(AFS_SUN56_ENV)
454     direntp = (struct dirent64 *)osi_AllocLargeSpace(AFS_LRALLOCSIZ);
455 #else
456     direntp = (struct dirent *)osi_AllocLargeSpace(AFS_LRALLOCSIZ);
457 #endif
458     direntp->d_ino =  (Volume << 16) + ntohl(Vnode);
459     FIXUPSTUPIDINODE(direntp->d_ino);
460 #if defined(AFS_AIX51_ENV) && defined(AFS_64BIT_KERNEL)
461     direntp->d_offset = off;
462     direntp->d_namlen = slen;
463 #else
464     direntp->d_off = off;
465 #endif
466     direntp->d_reclen = rlen;
467     strcpy(direntp->d_name, de->name);
468     AFS_UIOMOVE((caddr_t) direntp, rlen, UIO_READ, auio, code);
469     osi_FreeLargeSpace((char *)direntp);
470 #else /* AFS_SUN5_ENV */
471     /* Note the odd mechanism for building the inode number */
472     sdirEntry.d_fileno = (Volume << 16) + ntohl(Vnode);
473     FIXUPSTUPIDINODE(sdirEntry.d_fileno);
474     sdirEntry.d_reclen = rlen;
475 #if !defined(AFS_SGI_ENV)
476     sdirEntry.d_namlen = slen;
477 #endif
478 #if defined(AFS_AIX32_ENV) || defined(AFS_SGI_ENV)
479     sdirEntry.d_off = off;
480 #endif
481 #if defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
482     sdirEntry.d_type = afs_readdir_type(vc, de);
483 #endif
484
485 #if defined(AFS_SGI_ENV)
486     AFS_UIOMOVE(&sdirEntry, DIRENTBASESIZE, UIO_READ, auio, code);
487     if (code == 0)
488         AFS_UIOMOVE(de->name, slen - 1, UIO_READ, auio, code);
489     if (code == 0)
490         AFS_UIOMOVE(bufofzeros,
491                     DIRSIZ_LEN(slen) - (DIRENTBASESIZE + slen - 1), UIO_READ,
492                     auio, code);
493 #else /* AFS_SGI_ENV */
494     AFS_MOVE_UNLOCK();
495     AFS_UIOMOVE((char *)&sdirEntry, sizeof(sdirEntry), UIO_READ, auio, code);
496
497     if (code == 0) {
498         AFS_UIOMOVE(de->name, slen, UIO_READ, auio, code);
499     }
500
501     /* pad out the remaining characters with zeros */
502     if (code == 0) {
503         AFS_UIOMOVE(bufofzeros, ((slen + 1 + DIRPAD) & ~DIRPAD) - slen,
504                     UIO_READ, auio, code);
505     }
506     AFS_MOVE_LOCK();
507 #endif /* AFS_SGI_ENV */
508
509     /* pad out the difference between rlen and slen... */
510     if (DIRSIZ_LEN(slen) < rlen) {
511         AFS_MOVE_UNLOCK();
512         while (DIRSIZ_LEN(slen) < rlen) {
513             int minLen = rlen - DIRSIZ_LEN(slen);
514             if (minLen > sizeof(bufofzeros))
515                 minLen = sizeof(bufofzeros);
516             AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
517             rlen -= minLen;
518         }
519         AFS_MOVE_LOCK();
520     }
521 #endif /* AFS_SUN5_ENV */
522 #endif /* AFS_SGI53_ENV */
523     return (code);
524 }
525
526
527 /*
528  *------------------------------------------------------------------------------
529  *
530  * Read directory entries.
531  * There are some weird things to look out for here.  The uio_offset
532  * field is either 0 or it is the offset returned from a previous
533  * readdir.  It is an opaque value used by the server to find the
534  * correct directory block to read.  The byte count must be at least
535  * vtoblksz(vp) bytes.  The count field is the number of blocks to
536  * read on the server.  This is advisory only, the server may return
537  * only one block's worth of entries.  Entries may be compressed on
538  * the server.
539  *
540  * This routine encodes knowledge of Vice dirs.
541  */
542
543 void
544 afs_bulkstat_send(avc, req)
545      struct vcache *avc;
546      struct vrequest *req;
547 {
548     afs_rd_stash_i = 0;
549 }
550
551 /*
552  * Here is the bad, bad, really bad news.
553  * It has to do with 'offset' (seek locations).
554 */
555
556 int
557 #if     defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV) || defined(AFS_OSF_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
558 afs_readdir(OSI_VC_ARG(avc), auio, acred, eofp)
559      int *eofp;
560 #else
561 #if defined(AFS_HPUX100_ENV)
562 afs_readdir2(OSI_VC_ARG(avc), auio, acred)
563 #else
564 afs_readdir(OSI_VC_ARG(avc), auio, acred)
565 #endif
566 #endif
567      OSI_VC_DECL(avc);
568      struct uio *auio;
569      struct AFS_UCRED *acred;
570 {
571     struct vrequest treq;
572     register struct dcache *tdc;
573     afs_size_t origOffset, tlen;
574     afs_int32 len;
575     int code = 0;
576     struct DirEntry *ode = 0, *nde = 0;
577     int o_slen = 0, n_slen = 0;
578     afs_uint32 us;
579     struct afs_fakestat_state fakestate;
580 #if defined(AFS_SGI53_ENV)
581     afs_int32 use64BitDirent, dirsiz;
582 #endif /* defined(AFS_SGI53_ENV) */
583 #ifndef AFS_HPUX_ENV
584     OSI_VC_CONVERT(avc);
585 #else
586     /*
587      * XXX All the hacks for alloced sdirEntry and inlining of afs_readdir_move instead of calling
588      * it is necessary for hpux due to stack problems that seem to occur when coming thru the nfs
589      * translator side XXX
590      */
591     struct min_direct *sdirEntry =
592         (struct min_direct *)osi_AllocSmallSpace(sizeof(struct min_direct));
593     afs_int32 rlen;
594 #endif
595
596     /* opaque value is pointer into a vice dir; use bit map to decide
597      * if the entries are in use.  Always assumed to be valid.  0 is
598      * special, means start of a new dir.  Int32 inode, followed by
599      * short reclen and short namelen.  Namelen does not include
600      * the null byte.  Followed by null-terminated string.
601      */
602     AFS_STATCNT(afs_readdir);
603
604 #if defined(AFS_SGI53_ENV)
605 #ifdef AFS_SGI61_ENV
606 #ifdef AFS_SGI62_ENV
607     use64BitDirent =
608         ABI_IS(ABI_IRIX5_64, GETDENTS_ABI(OSI_GET_CURRENT_ABI(), auio));
609 #else
610     use64BitDirent =
611         (auio->uio_segflg !=
612          UIO_USERSPACE) ? ABI_IRIX5_64 : (ABI_IS(ABI_IRIX5_64 | ABI_IRIX5_N32,
613                                                  u.u_procp->p_abi));
614 #endif /* AFS_SGI62_ENV */
615 #else /* AFS_SGI61_ENV */
616     use64BitDirent =
617         (auio->uio_segflg !=
618          UIO_USERSPACE) ? ABI_IRIX5_64 : (ABI_IS(ABI_IRIX5_64,
619                                                  u.u_procp->p_abi));
620 #endif /* AFS_SGI61_ENV */
621 #endif /* defined(AFS_SGI53_ENV) */
622
623 #if     defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV) || defined(AFS_OSF_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
624     /* Not really used by the callee so we ignore it for now */
625     if (eofp)
626         *eofp = 0;
627 #endif
628     if (AfsLargeFileUio(auio)   /* file is large than 2 GB */
629         ||AfsLargeFileSize(auio->uio_offset, auio->uio_resid))
630         return EFBIG;
631
632     if ((code = afs_InitReq(&treq, acred))) {
633 #ifdef  AFS_HPUX_ENV
634         osi_FreeSmallSpace((char *)sdirEntry);
635 #endif
636         return code;
637     }
638     /* update the cache entry */
639     afs_InitFakeStat(&fakestate);
640     code = afs_EvalFakeStat(&avc, &fakestate, &treq);
641     if (code)
642         goto done;
643   tagain:
644     code = afs_VerifyVCache(avc, &treq);
645     if (code)
646         goto done;
647     /* get a reference to the entire directory */
648     tdc = afs_GetDCache(avc, (afs_size_t) 0, &treq, &origOffset, &tlen, 1);
649     len = tlen;
650     if (!tdc) {
651         code = ENOENT;
652         goto done;
653     }
654     ObtainReadLock(&avc->lock);
655     ObtainReadLock(&tdc->lock);
656
657     /*
658      * Make sure that the data in the cache is current. There are two
659      * cases we need to worry about:
660      * 1. The cache data is being fetched by another process.
661      * 2. The cache data is no longer valid
662      */
663     while ((avc->states & CStatd)
664            && (tdc->dflags & DFFetching)
665            && hsame(avc->m.DataVersion, tdc->f.versionNo)) {
666         afs_Trace4(afs_iclSetp, CM_TRACE_DCACHEWAIT, ICL_TYPE_STRING,
667                    __FILE__, ICL_TYPE_INT32, __LINE__, ICL_TYPE_POINTER, tdc,
668                    ICL_TYPE_INT32, tdc->dflags);
669         ReleaseReadLock(&tdc->lock);
670         ReleaseReadLock(&avc->lock);
671         afs_osi_Sleep(&tdc->validPos);
672         ObtainReadLock(&avc->lock);
673         ObtainReadLock(&tdc->lock);
674     }
675     if (!(avc->states & CStatd)
676         || !hsame(avc->m.DataVersion, tdc->f.versionNo)) {
677         ReleaseReadLock(&tdc->lock);
678         ReleaseReadLock(&avc->lock);
679         afs_PutDCache(tdc);
680         goto tagain;
681     }
682
683     /*
684      *  iterator for the directory reads.  Takes the AFS DirEntry
685      *  structure and slams them into UFS direct structures.
686      *  uses afs_readdir_move to get the struct to the user space.
687      *
688      *  The routine works by looking ahead one AFS directory entry.
689      *  That's because the AFS entry we are currenly working with
690      *  may not fit into the buffer the user has provided.  If it
691      *  doesn't we have to change the size of the LAST AFS directory
692      *  entry, so that it will FIT perfectly into the block the
693      *  user has provided.
694      *  
695      *  The 'forward looking' of the code makes it a bit tough to read.
696      *  Remember we need to get an entry, see if it it fits, then
697      *  set it up as the LAST entry, and find the next one.
698      *
699      *  Tough to take: We give out an EINVAL if we don't have enough
700      *  space in the buffer, and at the same time, don't have an entry
701      *  to put into the buffer. This CAN happen if the first AFS entry
702      *  we get can't fit into the 512 character buffer provided.  Seems
703      *  it ought not happen... 
704      *
705      *  Assumption: don't need to use anything but one dc entry:
706      *  this means the directory ought not be greater than 64k.
707      */
708     len = 0;
709 #ifdef AFS_HPUX_ENV
710     auio->uio_fpflags = 0;
711 #endif
712     while (code == 0) {
713         origOffset = auio->afsio_offset;
714         /* scan for the next interesting entry scan for in-use blob otherwise up point at
715          * this blob note that ode, if non-zero, also represents a held dir page */
716         if (!(us = BlobScan(tdc, (origOffset >> 5)))
717             || !(nde = (struct DirEntry *)afs_dir_GetBlob(tdc, us))) {
718             /* failed to setup nde, return what we've got, and release ode */
719             if (len) {
720                 /* something to hand over. */
721 #ifdef  AFS_HPUX_ENV
722                 sdirEntry->d_fileno =
723                     (avc->fid.Fid.Volume << 16) + ntohl(ode->fid.vnode);
724                 FIXUPSTUPIDINODE(sdirEntry->d_fileno);
725                 sdirEntry->d_reclen = rlen = auio->afsio_resid;
726                 sdirEntry->d_namlen = o_slen;
727 #if defined(AFS_SUN5_ENV) || defined(AFS_AIX32_ENV) || defined(AFS_HPUX100_ENV)
728                 sdirEntry->d_off = origOffset;
729 #endif
730                 AFS_UIOMOVE((char *)sdirEntry, sizeof(*sdirEntry), UIO_READ,
731                             auio, code);
732                 if (code == 0)
733                     AFS_UIOMOVE(ode->name, o_slen, UIO_READ, auio, code);
734                 /* pad out the remaining characters with zeros */
735                 if (code == 0) {
736                     AFS_UIOMOVE(bufofzeros,
737                                 ((o_slen + 1 + DIRPAD) & ~DIRPAD) - o_slen,
738                                 UIO_READ, auio, code);
739                 }
740                 /* pad out the difference between rlen and slen... */
741                 if (DIRSIZ_LEN(o_slen) < rlen) {
742                     while (DIRSIZ_LEN(o_slen) < rlen) {
743                         int minLen = rlen - DIRSIZ_LEN(o_slen);
744                         if (minLen > sizeof(bufofzeros))
745                             minLen = sizeof(bufofzeros);
746                         AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
747                         rlen -= minLen;
748                     }
749                 }
750 #else
751                 code = afs_readdir_move(ode, avc, auio, o_slen,
752 #if defined(AFS_SUN5_ENV)
753                                         len, origOffset);
754 #else
755                                         auio->afsio_resid, origOffset);
756 #endif
757 #endif /* AFS_HPUX_ENV */
758 #if !defined(AFS_SUN5_ENV)
759                 auio->afsio_resid = 0;
760 #endif
761             } else {
762                 /* nothin to hand over */
763             }
764 #if     defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV) || defined(AFS_OSF_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
765             if (eofp)
766                 *eofp = 1;      /* Set it properly */
767 #endif
768             if (ode)
769                 DRelease((struct buffer *)ode, 0);
770             goto dirend;
771         }
772         /* by here nde is set */
773
774         /* Do we have enough user space to carry out our mission? */
775 #if defined(AFS_SGI_ENV)
776         n_slen = strlen(nde->name) + 1; /* NULL terminate */
777 #else
778         n_slen = strlen(nde->name);
779 #endif
780 #ifdef  AFS_SGI53_ENV
781         dirsiz =
782             use64BitDirent ? DIRENTSIZE(n_slen) : IRIX5_DIRENTSIZE(n_slen);
783         if (dirsiz >= (auio->afsio_resid - len)) {
784 #else
785         if (DIRSIZ_LEN(n_slen) >= (auio->afsio_resid - len)) {
786 #endif /* AFS_SGI53_ENV */
787             /* No can do no more now; ya know... at this time */
788             DRelease((struct buffer *)nde, 0);  /* can't use this one. */
789             if (len) {
790 #ifdef  AFS_HPUX_ENV
791                 sdirEntry->d_fileno =
792                     (avc->fid.Fid.Volume << 16) + ntohl(ode->fid.vnode);
793                 FIXUPSTUPIDINODE(sdirEntry->d_fileno);
794                 sdirEntry->d_reclen = rlen = auio->afsio_resid;
795                 sdirEntry->d_namlen = o_slen;
796 #if defined(AFS_SUN5_ENV) || defined(AFS_AIX32_ENV) || defined(AFS_HPUX100_ENV)
797                 sdirEntry->d_off = origOffset;
798 #endif
799                 AFS_UIOMOVE((char *)sdirEntry, sizeof(*sdirEntry), UIO_READ,
800                             auio, code);
801                 if (code == 0)
802                     AFS_UIOMOVE(ode->name, o_slen, UIO_READ, auio, code);
803                 /* pad out the remaining characters with zeros */
804                 if (code == 0) {
805                     AFS_UIOMOVE(bufofzeros,
806                                 ((o_slen + 1 + DIRPAD) & ~DIRPAD) - o_slen,
807                                 UIO_READ, auio, code);
808                 }
809                 /* pad out the difference between rlen and slen... */
810                 if (DIRSIZ_LEN(o_slen) < rlen) {
811                     while (DIRSIZ_LEN(o_slen) < rlen) {
812                         int minLen = rlen - DIRSIZ_LEN(o_slen);
813                         if (minLen > sizeof(bufofzeros))
814                             minLen = sizeof(bufofzeros);
815                         AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
816                         rlen -= minLen;
817                     }
818                 }
819 #else /* AFS_HPUX_ENV */
820                 code =
821                     afs_readdir_move(ode, avc, auio, o_slen,
822                                      auio->afsio_resid, origOffset);
823 #endif /* AFS_HPUX_ENV */
824                 /* this next line used to be AFSVFS40 or AIX 3.1, but is
825                  * really generic */
826                 auio->afsio_offset = origOffset;
827                 auio->afsio_resid = 0;
828             } else {            /* trouble, can't give anything to the user! */
829                 /* even though he has given us a buffer, 
830                  * even though we have something to give us,
831                  * Looks like we lost something somewhere.
832                  */
833                 code = EINVAL;
834             }
835             if (ode)
836                 DRelease((struct buffer *)ode, 0);
837             goto dirend;
838         }
839
840         /*
841          * In any event, we move out the LAST de entry, getting ready
842          * to set up for the next one.
843          */
844         if (len) {
845 #ifdef  AFS_HPUX_ENV
846             sdirEntry->d_fileno =
847                 (avc->fid.Fid.Volume << 16) + ntohl(ode->fid.vnode);
848             FIXUPSTUPIDINODE(sdirEntry->d_fileno);
849             sdirEntry->d_reclen = rlen = len;
850             sdirEntry->d_namlen = o_slen;
851 #if defined(AFS_SUN5_ENV) || defined(AFS_AIX32_ENV) || defined(AFS_HPUX100_ENV)
852             sdirEntry->d_off = origOffset;
853 #endif
854             AFS_UIOMOVE((char *)sdirEntry, sizeof(*sdirEntry), UIO_READ, auio,
855                         code);
856             if (code == 0)
857                 AFS_UIOMOVE(ode->name, o_slen, UIO_READ, auio, code);
858             /* pad out the remaining characters with zeros */
859             if (code == 0) {
860                 AFS_UIOMOVE(bufofzeros,
861                             ((o_slen + 1 + DIRPAD) & ~DIRPAD) - o_slen,
862                             UIO_READ, auio, code);
863             }
864             /* pad out the difference between rlen and slen... */
865             if (DIRSIZ_LEN(o_slen) < rlen) {
866                 while (DIRSIZ_LEN(o_slen) < rlen) {
867                     int minLen = rlen - DIRSIZ_LEN(o_slen);
868                     if (minLen > sizeof(bufofzeros))
869                         minLen = sizeof(bufofzeros);
870                     AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
871                     rlen -= minLen;
872                 }
873             }
874 #else /* AFS_HPUX_ENV */
875             code = afs_readdir_move(ode, avc, auio, o_slen, len, origOffset);
876 #endif /* AFS_HPUX_ENV */
877         }
878 #ifdef  AFS_SGI53_ENV
879         len = use64BitDirent ? DIRENTSIZE(o_slen =
880                                           n_slen) : IRIX5_DIRENTSIZE(o_slen =
881                                                                      n_slen);
882 #else
883         len = DIRSIZ_LEN(o_slen = n_slen);
884 #endif /* AFS_SGI53_ENV */
885         if (ode)
886             DRelease((struct buffer *)ode, 0);
887         ode = nde;
888         auio->afsio_offset =
889             (afs_int32) ((us + afs_dir_NameBlobs(nde->name)) << 5);
890     }
891     if (ode)
892         DRelease((struct buffer *)ode, 0);
893
894   dirend:
895     ReleaseReadLock(&tdc->lock);
896     afs_PutDCache(tdc);
897     ReleaseReadLock(&avc->lock);
898
899   done:
900 #ifdef  AFS_HPUX_ENV
901     osi_FreeSmallSpace((char *)sdirEntry);
902 #endif
903     afs_PutFakeStat(&fakestate);
904     code = afs_CheckCode(code, &treq, 28);
905     return code;
906 }
907
908 #if     defined(AFS_HPUX_ENV) || defined(AFS_OSF_ENV)
909 #ifdef  AFS_OSF_ENV
910 afs1_readdir(avc, auio, acred, eofp)
911      int *eofp;
912 #else
913 afs1_readdir(avc, auio, acred)
914 #endif
915      struct vcache *avc;
916      struct uio *auio;
917      struct AFS_UCRED *acred;
918 {
919     struct vrequest treq;
920     register struct dcache *tdc;
921     afs_size_t origOffset, len;
922     int code = 0;
923     struct DirEntry *ode = 0, *nde = 0;
924     int o_slen = 0, n_slen = 0;
925     afs_uint32 us;
926 #if     defined(AFS_HPUX_ENV) || defined(AFS_OSF_ENV)
927     /*
928      * XXX All the hacks for alloced sdirEntry and inlining of afs_readdir_move instead of calling
929      * it is necessary for hpux due to stack problems that seem to occur when coming thru the nfs
930      * translator side XXX
931      */
932     struct minnfs_direct *sdirEntry = (struct minnfs_direct *)
933         osi_AllocSmallSpace(sizeof(struct min_direct));
934     afs_int32 rlen;
935 #endif
936     struct afs_fakestat_state fakestate;
937
938     AFS_STATCNT(afs_readdir);
939 #if     defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV) || defined(AFS_OSF_ENV)
940     if (eofp)
941         *eofp = 0;
942 #endif
943     if (code = afs_InitReq(&treq, acred)) {
944 #ifdef  AFS_HPUX_ENV
945         osi_FreeSmallSpace((char *)sdirEntry);
946 #endif
947         return code;
948     }
949     afs_InitFakeStat(&fakestate);
950     code = afs_EvalFakeStat(&avc, &fakestate, &treq);
951     if (code) {
952 #ifdef  AFS_HPUX_ENV
953         osi_FreeSmallSpace((char *)sdirEntry);
954 #endif
955         afs_PutFakeStat(&fakestate);
956         return code;
957     }
958     /* update the cache entry */
959   tagain:
960     code = afs_VerifyVCache(avc, &treq);
961     if (code)
962         goto done;
963     /* get a reference to the entire directory */
964     tdc = afs_GetDCache(avc, (afs_size_t) 0, &treq, &origOffset, &len, 1);
965     if (!tdc) {
966         code = ENOENT;
967         goto done;
968     }
969     ObtainReadLock(&avc->lock);
970     ObtainReadLock(&tdc->lock);
971
972     /*
973      * Make sure that the data in the cache is current. There are two
974      * cases we need to worry about:
975      * 1. The cache data is being fetched by another process.
976      * 2. The cache data is no longer valid
977      */
978     while ((avc->states & CStatd)
979            && (tdc->dflags & DFFetching)
980            && hsame(avc->m.DataVersion, tdc->f.versionNo)) {
981         afs_Trace4(afs_iclSetp, CM_TRACE_DCACHEWAIT, ICL_TYPE_STRING,
982                    __FILE__, ICL_TYPE_INT32, __LINE__, ICL_TYPE_POINTER, tdc,
983                    ICL_TYPE_INT32, tdc->dflags);
984         ReleaseReadLock(&tdc->lock);
985         ReleaseReadLock(&avc->lock);
986         afs_osi_Sleep(&tdc->validPos);
987         ObtainReadLock(&avc->lock);
988         ObtainReadLock(&tdc->lock);
989     }
990     if (!(avc->states & CStatd)
991         || !hsame(avc->m.DataVersion, tdc->f.versionNo)) {
992         ReleaseReadLock(&tdc->lock);
993         ReleaseReadLock(&avc->lock);
994         afs_PutDCache(tdc);
995         goto tagain;
996     }
997
998     len = 0;
999 #ifdef AFS_HPUX_ENV
1000     auio->uio_fpflags = 0;
1001 #endif
1002     while (code == 0) {
1003         origOffset = auio->afsio_offset;
1004
1005         /* scan for the next interesting entry scan for in-use blob otherwise up point at
1006          * this blob note that ode, if non-zero, also represents a held dir page */
1007         if (!(us = BlobScan(tdc, (origOffset >> 5)))
1008             || !(nde = (struct DirEntry *)afs_dir_GetBlob(tdc, us))) {
1009             /* failed to setup nde, return what we've got, and release ode */
1010             if (len) {
1011                 /* something to hand over. */
1012 #if     defined(AFS_HPUX_ENV) || defined(AFS_OSF_ENV)
1013                 sdirEntry->d_fileno =
1014                     (avc->fid.Fid.Volume << 16) + ntohl(ode->fid.vnode);
1015                 FIXUPSTUPIDINODE(sdirEntry->d_fileno);
1016                 sdirEntry->d_reclen = rlen = auio->afsio_resid;
1017                 sdirEntry->d_namlen = o_slen;
1018                 sdirEntry->d_off = origOffset;
1019                 AFS_UIOMOVE((char *)sdirEntry, sizeof(*sdirEntry), UIO_READ,
1020                             auio, code);
1021                 if (code == 0) {
1022                     AFS_UIOMOVE(ode->name, o_slen, UIO_READ, auio, code);
1023                 }
1024                 /* pad out the remaining characters with zeros */
1025                 if (code == 0) {
1026                     AFS_UIOMOVE(bufofzeros,
1027                                 ((o_slen + 1 + DIRPAD) & ~DIRPAD) - o_slen,
1028                                 UIO_READ, auio, code);
1029                 }
1030                 /* pad out the difference between rlen and slen... */
1031                 if (NDIRSIZ_LEN(o_slen) < rlen) {
1032                     while (NDIRSIZ_LEN(o_slen) < rlen) {
1033                         int minLen = rlen - NDIRSIZ_LEN(o_slen);
1034                         if (minLen > sizeof(bufofzeros))
1035                             minLen = sizeof(bufofzeros);
1036                         AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
1037                         rlen -= minLen;
1038                     }
1039                 }
1040 #else
1041                 code =
1042                     afs_readdir_move(ode, avc, auio, o_slen,
1043                                      auio->afsio_resid, origOffset);
1044 #endif /* AFS_HPUX_ENV */
1045                 auio->afsio_resid = 0;
1046             } else {
1047                 /* nothin to hand over */
1048             }
1049 #if defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV) || defined(AFS_OSF_ENV)
1050             if (eofp)
1051                 *eofp = 1;
1052 #endif
1053             if (ode)
1054                 DRelease(ode, 0);
1055             goto dirend;
1056         }
1057         /* by here nde is set */
1058
1059         /* Do we have enough user space to carry out our mission? */
1060 #if defined(AFS_SGI_ENV)
1061         n_slen = strlen(nde->name) + 1; /* NULL terminate */
1062 #else
1063         n_slen = strlen(nde->name);
1064 #endif
1065         if (NDIRSIZ_LEN(n_slen) >= (auio->afsio_resid - len)) {
1066             /* No can do no more now; ya know... at this time */
1067             DRelease(nde, 0);   /* can't use this one. */
1068             if (len) {
1069 #if     defined(AFS_HPUX_ENV) || defined(AFS_OSF_ENV)
1070                 sdirEntry->d_fileno =
1071                     (avc->fid.Fid.Volume << 16) + ntohl(ode->fid.vnode);
1072                 FIXUPSTUPIDINODE(sdirEntry->d_fileno);
1073                 sdirEntry->d_reclen = rlen = auio->afsio_resid;
1074                 sdirEntry->d_namlen = o_slen;
1075                 sdirEntry->d_off = origOffset;
1076                 AFS_UIOMOVE((char *)sdirEntry, sizeof(*sdirEntry), UIO_READ,
1077                             auio, code);
1078                 if (code == 0)
1079                     AFS_UIOMOVE(ode->name, o_slen, UIO_READ, auio, code);
1080                 /* pad out the remaining characters with zeros */
1081                 if (code == 0) {
1082                     AFS_UIOMOVE(bufofzeros,
1083                                 ((o_slen + 1 + DIRPAD) & ~DIRPAD) - o_slen,
1084                                 UIO_READ, auio, code);
1085                 }
1086                 /* pad out the difference between rlen and slen... */
1087                 if (NDIRSIZ_LEN(o_slen) < rlen) {
1088                     while (NDIRSIZ_LEN(o_slen) < rlen) {
1089                         int minLen = rlen - NDIRSIZ_LEN(o_slen);
1090                         if (minLen > sizeof(bufofzeros))
1091                             minLen = sizeof(bufofzeros);
1092                         AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
1093                         rlen -= minLen;
1094                     }
1095                 }
1096 #else
1097                 code =
1098                     afs_readdir_move(ode, avc, auio, o_slen,
1099                                      auio->afsio_resid, origOffset);
1100 #endif /* AFS_HPUX_ENV */
1101                 /* this next line used to be AFSVFS40 or AIX 3.1, but is really generic */
1102                 auio->afsio_offset = origOffset;
1103                 auio->afsio_resid = 0;
1104             } else {            /* trouble, can't give anything to the user! */
1105                 /* even though he has given us a buffer, 
1106                  * even though we have something to give us,
1107                  * Looks like we lost something somewhere.
1108                  */
1109                 code = EINVAL;
1110             }
1111             if (ode)
1112                 DRelease(ode, 0);
1113             goto dirend;
1114         }
1115
1116         /*
1117          * In any event, we move out the LAST de entry, getting ready
1118          * to set up for the next one.
1119          */
1120         if (len) {
1121 #if     defined(AFS_HPUX_ENV) || defined(AFS_OSF_ENV)
1122             sdirEntry->d_fileno =
1123                 (avc->fid.Fid.Volume << 16) + ntohl(ode->fid.vnode);
1124             FIXUPSTUPIDINODE(sdirEntry->d_fileno);
1125             sdirEntry->d_reclen = rlen = len;
1126             sdirEntry->d_namlen = o_slen;
1127             sdirEntry->d_off = origOffset;
1128             AFS_UIOMOVE((char *)sdirEntry, sizeof(*sdirEntry), UIO_READ, auio,
1129                         code);
1130             if (code == 0)
1131                 AFS_UIOMOVE(ode->name, o_slen, UIO_READ, auio, code);
1132             /* pad out the remaining characters with zeros */
1133             if (code == 0) {
1134                 AFS_UIOMOVE(bufofzeros,
1135                             ((o_slen + 1 + DIRPAD) & ~DIRPAD) - o_slen,
1136                             UIO_READ, auio, code);
1137             }
1138             /* pad out the difference between rlen and slen... */
1139             if (NDIRSIZ_LEN(o_slen) < rlen) {
1140                 while (NDIRSIZ_LEN(o_slen) < rlen) {
1141                     int minLen = rlen - NDIRSIZ_LEN(o_slen);
1142                     if (minLen > sizeof(bufofzeros))
1143                         minLen = sizeof(bufofzeros);
1144                     AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
1145                     rlen -= minLen;
1146                 }
1147             }
1148 #else
1149             code = afs_readdir_move(ode, avc, auio, o_slen, len, origOffset);
1150 #endif /* AFS_HPUX_ENV */
1151         }
1152         len = NDIRSIZ_LEN(o_slen = n_slen);
1153         if (ode)
1154             DRelease(ode, 0);
1155         ode = nde;
1156         auio->afsio_offset = ((us + afs_dir_NameBlobs(nde->name)) << 5);
1157     }
1158     if (ode)
1159         DRelease(ode, 0);
1160
1161   dirend:
1162     ReleaseReadLock(&tdc->lock);
1163     afs_PutDCache(tdc);
1164     ReleaseReadLock(&avc->lock);
1165
1166   done:
1167 #if     defined(AFS_HPUX_ENV) || defined(AFS_OSF_ENV)
1168     osi_FreeSmallSpace((char *)sdirEntry);
1169 #endif
1170     afs_PutFakeStat(&fakestate);
1171     code = afs_CheckCode(code, &treq, 29);
1172     return code;
1173 }
1174
1175 #endif
1176 #endif /* !AFS_LINUX20_ENV */