solars-sparc32-largefile-20051011
[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 #ifndef AFS_64BIT_CLIENT
629     if (AfsLargeFileUio(auio)   /* file is large than 2 GB */
630         ||AfsLargeFileSize(auio->uio_offset, auio->uio_resid))
631         return EFBIG;
632 #endif
633
634     if ((code = afs_InitReq(&treq, acred))) {
635 #ifdef  AFS_HPUX_ENV
636         osi_FreeSmallSpace((char *)sdirEntry);
637 #endif
638         return code;
639     }
640     /* update the cache entry */
641     afs_InitFakeStat(&fakestate);
642     code = afs_EvalFakeStat(&avc, &fakestate, &treq);
643     if (code)
644         goto done;
645   tagain:
646     code = afs_VerifyVCache(avc, &treq);
647     if (code)
648         goto done;
649     /* get a reference to the entire directory */
650     tdc = afs_GetDCache(avc, (afs_size_t) 0, &treq, &origOffset, &tlen, 1);
651     len = tlen;
652     if (!tdc) {
653         code = ENOENT;
654         goto done;
655     }
656     ObtainReadLock(&avc->lock);
657     ObtainReadLock(&tdc->lock);
658
659     /*
660      * Make sure that the data in the cache is current. There are two
661      * cases we need to worry about:
662      * 1. The cache data is being fetched by another process.
663      * 2. The cache data is no longer valid
664      */
665     while ((avc->states & CStatd)
666            && (tdc->dflags & DFFetching)
667            && hsame(avc->m.DataVersion, tdc->f.versionNo)) {
668         afs_Trace4(afs_iclSetp, CM_TRACE_DCACHEWAIT, ICL_TYPE_STRING,
669                    __FILE__, ICL_TYPE_INT32, __LINE__, ICL_TYPE_POINTER, tdc,
670                    ICL_TYPE_INT32, tdc->dflags);
671         ReleaseReadLock(&tdc->lock);
672         ReleaseReadLock(&avc->lock);
673         afs_osi_Sleep(&tdc->validPos);
674         ObtainReadLock(&avc->lock);
675         ObtainReadLock(&tdc->lock);
676     }
677     if (!(avc->states & CStatd)
678         || !hsame(avc->m.DataVersion, tdc->f.versionNo)) {
679         ReleaseReadLock(&tdc->lock);
680         ReleaseReadLock(&avc->lock);
681         afs_PutDCache(tdc);
682         goto tagain;
683     }
684
685     /*
686      *  iterator for the directory reads.  Takes the AFS DirEntry
687      *  structure and slams them into UFS direct structures.
688      *  uses afs_readdir_move to get the struct to the user space.
689      *
690      *  The routine works by looking ahead one AFS directory entry.
691      *  That's because the AFS entry we are currenly working with
692      *  may not fit into the buffer the user has provided.  If it
693      *  doesn't we have to change the size of the LAST AFS directory
694      *  entry, so that it will FIT perfectly into the block the
695      *  user has provided.
696      *  
697      *  The 'forward looking' of the code makes it a bit tough to read.
698      *  Remember we need to get an entry, see if it it fits, then
699      *  set it up as the LAST entry, and find the next one.
700      *
701      *  Tough to take: We give out an EINVAL if we don't have enough
702      *  space in the buffer, and at the same time, don't have an entry
703      *  to put into the buffer. This CAN happen if the first AFS entry
704      *  we get can't fit into the 512 character buffer provided.  Seems
705      *  it ought not happen... 
706      *
707      *  Assumption: don't need to use anything but one dc entry:
708      *  this means the directory ought not be greater than 64k.
709      */
710     len = 0;
711 #ifdef AFS_HPUX_ENV
712     auio->uio_fpflags = 0;
713 #endif
714     while (code == 0) {
715         origOffset = auio->afsio_offset;
716         /* scan for the next interesting entry scan for in-use blob otherwise up point at
717          * this blob note that ode, if non-zero, also represents a held dir page */
718         if (!(us = BlobScan(tdc, (origOffset >> 5)))
719             || !(nde = (struct DirEntry *)afs_dir_GetBlob(tdc, us))) {
720             /* failed to setup nde, return what we've got, and release ode */
721             if (len) {
722                 /* something to hand over. */
723 #ifdef  AFS_HPUX_ENV
724                 sdirEntry->d_fileno =
725                     (avc->fid.Fid.Volume << 16) + ntohl(ode->fid.vnode);
726                 FIXUPSTUPIDINODE(sdirEntry->d_fileno);
727                 sdirEntry->d_reclen = rlen = auio->afsio_resid;
728                 sdirEntry->d_namlen = o_slen;
729 #if defined(AFS_SUN5_ENV) || defined(AFS_AIX32_ENV) || defined(AFS_HPUX100_ENV)
730                 sdirEntry->d_off = origOffset;
731 #endif
732                 AFS_UIOMOVE((char *)sdirEntry, sizeof(*sdirEntry), UIO_READ,
733                             auio, code);
734                 if (code == 0)
735                     AFS_UIOMOVE(ode->name, o_slen, UIO_READ, auio, code);
736                 /* pad out the remaining characters with zeros */
737                 if (code == 0) {
738                     AFS_UIOMOVE(bufofzeros,
739                                 ((o_slen + 1 + DIRPAD) & ~DIRPAD) - o_slen,
740                                 UIO_READ, auio, code);
741                 }
742                 /* pad out the difference between rlen and slen... */
743                 if (DIRSIZ_LEN(o_slen) < rlen) {
744                     while (DIRSIZ_LEN(o_slen) < rlen) {
745                         int minLen = rlen - DIRSIZ_LEN(o_slen);
746                         if (minLen > sizeof(bufofzeros))
747                             minLen = sizeof(bufofzeros);
748                         AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
749                         rlen -= minLen;
750                     }
751                 }
752 #else
753                 code = afs_readdir_move(ode, avc, auio, o_slen,
754 #if defined(AFS_SUN5_ENV)
755                                         len, origOffset);
756 #else
757                                         auio->afsio_resid, origOffset);
758 #endif
759 #endif /* AFS_HPUX_ENV */
760 #if !defined(AFS_SUN5_ENV)
761                 auio->afsio_resid = 0;
762 #endif
763             } else {
764                 /* nothin to hand over */
765             }
766 #if     defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV) || defined(AFS_OSF_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
767             if (eofp)
768                 *eofp = 1;      /* Set it properly */
769 #endif
770             if (ode)
771                 DRelease((struct buffer *)ode, 0);
772             goto dirend;
773         }
774         /* by here nde is set */
775
776         /* Do we have enough user space to carry out our mission? */
777 #if defined(AFS_SGI_ENV)
778         n_slen = strlen(nde->name) + 1; /* NULL terminate */
779 #else
780         n_slen = strlen(nde->name);
781 #endif
782 #ifdef  AFS_SGI53_ENV
783         dirsiz =
784             use64BitDirent ? DIRENTSIZE(n_slen) : IRIX5_DIRENTSIZE(n_slen);
785         if (dirsiz >= (auio->afsio_resid - len)) {
786 #else
787         if (DIRSIZ_LEN(n_slen) >= (auio->afsio_resid - len)) {
788 #endif /* AFS_SGI53_ENV */
789             /* No can do no more now; ya know... at this time */
790             DRelease((struct buffer *)nde, 0);  /* can't use this one. */
791             if (len) {
792 #ifdef  AFS_HPUX_ENV
793                 sdirEntry->d_fileno =
794                     (avc->fid.Fid.Volume << 16) + ntohl(ode->fid.vnode);
795                 FIXUPSTUPIDINODE(sdirEntry->d_fileno);
796                 sdirEntry->d_reclen = rlen = auio->afsio_resid;
797                 sdirEntry->d_namlen = o_slen;
798 #if defined(AFS_SUN5_ENV) || defined(AFS_AIX32_ENV) || defined(AFS_HPUX100_ENV)
799                 sdirEntry->d_off = origOffset;
800 #endif
801                 AFS_UIOMOVE((char *)sdirEntry, sizeof(*sdirEntry), UIO_READ,
802                             auio, code);
803                 if (code == 0)
804                     AFS_UIOMOVE(ode->name, o_slen, UIO_READ, auio, code);
805                 /* pad out the remaining characters with zeros */
806                 if (code == 0) {
807                     AFS_UIOMOVE(bufofzeros,
808                                 ((o_slen + 1 + DIRPAD) & ~DIRPAD) - o_slen,
809                                 UIO_READ, auio, code);
810                 }
811                 /* pad out the difference between rlen and slen... */
812                 if (DIRSIZ_LEN(o_slen) < rlen) {
813                     while (DIRSIZ_LEN(o_slen) < rlen) {
814                         int minLen = rlen - DIRSIZ_LEN(o_slen);
815                         if (minLen > sizeof(bufofzeros))
816                             minLen = sizeof(bufofzeros);
817                         AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
818                         rlen -= minLen;
819                     }
820                 }
821 #else /* AFS_HPUX_ENV */
822                 code =
823                     afs_readdir_move(ode, avc, auio, o_slen,
824                                      auio->afsio_resid, origOffset);
825 #endif /* AFS_HPUX_ENV */
826                 /* this next line used to be AFSVFS40 or AIX 3.1, but is
827                  * really generic */
828                 auio->afsio_offset = origOffset;
829                 auio->afsio_resid = 0;
830             } else {            /* trouble, can't give anything to the user! */
831                 /* even though he has given us a buffer, 
832                  * even though we have something to give us,
833                  * Looks like we lost something somewhere.
834                  */
835                 code = EINVAL;
836             }
837             if (ode)
838                 DRelease((struct buffer *)ode, 0);
839             goto dirend;
840         }
841
842         /*
843          * In any event, we move out the LAST de entry, getting ready
844          * to set up for the next one.
845          */
846         if (len) {
847 #ifdef  AFS_HPUX_ENV
848             sdirEntry->d_fileno =
849                 (avc->fid.Fid.Volume << 16) + ntohl(ode->fid.vnode);
850             FIXUPSTUPIDINODE(sdirEntry->d_fileno);
851             sdirEntry->d_reclen = rlen = len;
852             sdirEntry->d_namlen = o_slen;
853 #if defined(AFS_SUN5_ENV) || defined(AFS_AIX32_ENV) || defined(AFS_HPUX100_ENV)
854             sdirEntry->d_off = origOffset;
855 #endif
856             AFS_UIOMOVE((char *)sdirEntry, sizeof(*sdirEntry), UIO_READ, auio,
857                         code);
858             if (code == 0)
859                 AFS_UIOMOVE(ode->name, o_slen, UIO_READ, auio, code);
860             /* pad out the remaining characters with zeros */
861             if (code == 0) {
862                 AFS_UIOMOVE(bufofzeros,
863                             ((o_slen + 1 + DIRPAD) & ~DIRPAD) - o_slen,
864                             UIO_READ, auio, code);
865             }
866             /* pad out the difference between rlen and slen... */
867             if (DIRSIZ_LEN(o_slen) < rlen) {
868                 while (DIRSIZ_LEN(o_slen) < rlen) {
869                     int minLen = rlen - DIRSIZ_LEN(o_slen);
870                     if (minLen > sizeof(bufofzeros))
871                         minLen = sizeof(bufofzeros);
872                     AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
873                     rlen -= minLen;
874                 }
875             }
876 #else /* AFS_HPUX_ENV */
877             code = afs_readdir_move(ode, avc, auio, o_slen, len, origOffset);
878 #endif /* AFS_HPUX_ENV */
879         }
880 #ifdef  AFS_SGI53_ENV
881         len = use64BitDirent ? DIRENTSIZE(o_slen =
882                                           n_slen) : IRIX5_DIRENTSIZE(o_slen =
883                                                                      n_slen);
884 #else
885         len = DIRSIZ_LEN(o_slen = n_slen);
886 #endif /* AFS_SGI53_ENV */
887         if (ode)
888             DRelease((struct buffer *)ode, 0);
889         ode = nde;
890         auio->afsio_offset =
891             (afs_int32) ((us + afs_dir_NameBlobs(nde->name)) << 5);
892     }
893     if (ode)
894         DRelease((struct buffer *)ode, 0);
895
896   dirend:
897     ReleaseReadLock(&tdc->lock);
898     afs_PutDCache(tdc);
899     ReleaseReadLock(&avc->lock);
900
901   done:
902 #ifdef  AFS_HPUX_ENV
903     osi_FreeSmallSpace((char *)sdirEntry);
904 #endif
905     afs_PutFakeStat(&fakestate);
906     code = afs_CheckCode(code, &treq, 28);
907     return code;
908 }
909
910 #if     defined(AFS_HPUX_ENV) || defined(AFS_OSF_ENV)
911 #ifdef  AFS_OSF_ENV
912 afs1_readdir(avc, auio, acred, eofp)
913      int *eofp;
914 #else
915 afs1_readdir(avc, auio, acred)
916 #endif
917      struct vcache *avc;
918      struct uio *auio;
919      struct AFS_UCRED *acred;
920 {
921     struct vrequest treq;
922     register struct dcache *tdc;
923     afs_size_t origOffset, len;
924     int code = 0;
925     struct DirEntry *ode = 0, *nde = 0;
926     int o_slen = 0, n_slen = 0;
927     afs_uint32 us;
928 #if     defined(AFS_HPUX_ENV) || defined(AFS_OSF_ENV)
929     /*
930      * XXX All the hacks for alloced sdirEntry and inlining of afs_readdir_move instead of calling
931      * it is necessary for hpux due to stack problems that seem to occur when coming thru the nfs
932      * translator side XXX
933      */
934     struct minnfs_direct *sdirEntry = (struct minnfs_direct *)
935         osi_AllocSmallSpace(sizeof(struct min_direct));
936     afs_int32 rlen;
937 #endif
938     struct afs_fakestat_state fakestate;
939
940     AFS_STATCNT(afs_readdir);
941 #if     defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV) || defined(AFS_OSF_ENV)
942     if (eofp)
943         *eofp = 0;
944 #endif
945     if (code = afs_InitReq(&treq, acred)) {
946 #ifdef  AFS_HPUX_ENV
947         osi_FreeSmallSpace((char *)sdirEntry);
948 #endif
949         return code;
950     }
951     afs_InitFakeStat(&fakestate);
952     code = afs_EvalFakeStat(&avc, &fakestate, &treq);
953     if (code) {
954 #ifdef  AFS_HPUX_ENV
955         osi_FreeSmallSpace((char *)sdirEntry);
956 #endif
957         afs_PutFakeStat(&fakestate);
958         return code;
959     }
960     /* update the cache entry */
961   tagain:
962     code = afs_VerifyVCache(avc, &treq);
963     if (code)
964         goto done;
965     /* get a reference to the entire directory */
966     tdc = afs_GetDCache(avc, (afs_size_t) 0, &treq, &origOffset, &len, 1);
967     if (!tdc) {
968         code = ENOENT;
969         goto done;
970     }
971     ObtainReadLock(&avc->lock);
972     ObtainReadLock(&tdc->lock);
973
974     /*
975      * Make sure that the data in the cache is current. There are two
976      * cases we need to worry about:
977      * 1. The cache data is being fetched by another process.
978      * 2. The cache data is no longer valid
979      */
980     while ((avc->states & CStatd)
981            && (tdc->dflags & DFFetching)
982            && hsame(avc->m.DataVersion, tdc->f.versionNo)) {
983         afs_Trace4(afs_iclSetp, CM_TRACE_DCACHEWAIT, ICL_TYPE_STRING,
984                    __FILE__, ICL_TYPE_INT32, __LINE__, ICL_TYPE_POINTER, tdc,
985                    ICL_TYPE_INT32, tdc->dflags);
986         ReleaseReadLock(&tdc->lock);
987         ReleaseReadLock(&avc->lock);
988         afs_osi_Sleep(&tdc->validPos);
989         ObtainReadLock(&avc->lock);
990         ObtainReadLock(&tdc->lock);
991     }
992     if (!(avc->states & CStatd)
993         || !hsame(avc->m.DataVersion, tdc->f.versionNo)) {
994         ReleaseReadLock(&tdc->lock);
995         ReleaseReadLock(&avc->lock);
996         afs_PutDCache(tdc);
997         goto tagain;
998     }
999
1000     len = 0;
1001 #ifdef AFS_HPUX_ENV
1002     auio->uio_fpflags = 0;
1003 #endif
1004     while (code == 0) {
1005         origOffset = auio->afsio_offset;
1006
1007         /* scan for the next interesting entry scan for in-use blob otherwise up point at
1008          * this blob note that ode, if non-zero, also represents a held dir page */
1009         if (!(us = BlobScan(tdc, (origOffset >> 5)))
1010             || !(nde = (struct DirEntry *)afs_dir_GetBlob(tdc, us))) {
1011             /* failed to setup nde, return what we've got, and release ode */
1012             if (len) {
1013                 /* something to hand over. */
1014 #if     defined(AFS_HPUX_ENV) || defined(AFS_OSF_ENV)
1015                 sdirEntry->d_fileno =
1016                     (avc->fid.Fid.Volume << 16) + ntohl(ode->fid.vnode);
1017                 FIXUPSTUPIDINODE(sdirEntry->d_fileno);
1018                 sdirEntry->d_reclen = rlen = auio->afsio_resid;
1019                 sdirEntry->d_namlen = o_slen;
1020                 sdirEntry->d_off = origOffset;
1021                 AFS_UIOMOVE((char *)sdirEntry, sizeof(*sdirEntry), UIO_READ,
1022                             auio, code);
1023                 if (code == 0) {
1024                     AFS_UIOMOVE(ode->name, o_slen, UIO_READ, auio, code);
1025                 }
1026                 /* pad out the remaining characters with zeros */
1027                 if (code == 0) {
1028                     AFS_UIOMOVE(bufofzeros,
1029                                 ((o_slen + 1 + DIRPAD) & ~DIRPAD) - o_slen,
1030                                 UIO_READ, auio, code);
1031                 }
1032                 /* pad out the difference between rlen and slen... */
1033                 if (NDIRSIZ_LEN(o_slen) < rlen) {
1034                     while (NDIRSIZ_LEN(o_slen) < rlen) {
1035                         int minLen = rlen - NDIRSIZ_LEN(o_slen);
1036                         if (minLen > sizeof(bufofzeros))
1037                             minLen = sizeof(bufofzeros);
1038                         AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
1039                         rlen -= minLen;
1040                     }
1041                 }
1042 #else
1043                 code =
1044                     afs_readdir_move(ode, avc, auio, o_slen,
1045                                      auio->afsio_resid, origOffset);
1046 #endif /* AFS_HPUX_ENV */
1047                 auio->afsio_resid = 0;
1048             } else {
1049                 /* nothin to hand over */
1050             }
1051 #if defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV) || defined(AFS_OSF_ENV)
1052             if (eofp)
1053                 *eofp = 1;
1054 #endif
1055             if (ode)
1056                 DRelease(ode, 0);
1057             goto dirend;
1058         }
1059         /* by here nde is set */
1060
1061         /* Do we have enough user space to carry out our mission? */
1062 #if defined(AFS_SGI_ENV)
1063         n_slen = strlen(nde->name) + 1; /* NULL terminate */
1064 #else
1065         n_slen = strlen(nde->name);
1066 #endif
1067         if (NDIRSIZ_LEN(n_slen) >= (auio->afsio_resid - len)) {
1068             /* No can do no more now; ya know... at this time */
1069             DRelease(nde, 0);   /* can't use this one. */
1070             if (len) {
1071 #if     defined(AFS_HPUX_ENV) || defined(AFS_OSF_ENV)
1072                 sdirEntry->d_fileno =
1073                     (avc->fid.Fid.Volume << 16) + ntohl(ode->fid.vnode);
1074                 FIXUPSTUPIDINODE(sdirEntry->d_fileno);
1075                 sdirEntry->d_reclen = rlen = auio->afsio_resid;
1076                 sdirEntry->d_namlen = o_slen;
1077                 sdirEntry->d_off = origOffset;
1078                 AFS_UIOMOVE((char *)sdirEntry, sizeof(*sdirEntry), UIO_READ,
1079                             auio, code);
1080                 if (code == 0)
1081                     AFS_UIOMOVE(ode->name, o_slen, UIO_READ, auio, code);
1082                 /* pad out the remaining characters with zeros */
1083                 if (code == 0) {
1084                     AFS_UIOMOVE(bufofzeros,
1085                                 ((o_slen + 1 + DIRPAD) & ~DIRPAD) - o_slen,
1086                                 UIO_READ, auio, code);
1087                 }
1088                 /* pad out the difference between rlen and slen... */
1089                 if (NDIRSIZ_LEN(o_slen) < rlen) {
1090                     while (NDIRSIZ_LEN(o_slen) < rlen) {
1091                         int minLen = rlen - NDIRSIZ_LEN(o_slen);
1092                         if (minLen > sizeof(bufofzeros))
1093                             minLen = sizeof(bufofzeros);
1094                         AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
1095                         rlen -= minLen;
1096                     }
1097                 }
1098 #else
1099                 code =
1100                     afs_readdir_move(ode, avc, auio, o_slen,
1101                                      auio->afsio_resid, origOffset);
1102 #endif /* AFS_HPUX_ENV */
1103                 /* this next line used to be AFSVFS40 or AIX 3.1, but is really generic */
1104                 auio->afsio_offset = origOffset;
1105                 auio->afsio_resid = 0;
1106             } else {            /* trouble, can't give anything to the user! */
1107                 /* even though he has given us a buffer, 
1108                  * even though we have something to give us,
1109                  * Looks like we lost something somewhere.
1110                  */
1111                 code = EINVAL;
1112             }
1113             if (ode)
1114                 DRelease(ode, 0);
1115             goto dirend;
1116         }
1117
1118         /*
1119          * In any event, we move out the LAST de entry, getting ready
1120          * to set up for the next one.
1121          */
1122         if (len) {
1123 #if     defined(AFS_HPUX_ENV) || defined(AFS_OSF_ENV)
1124             sdirEntry->d_fileno =
1125                 (avc->fid.Fid.Volume << 16) + ntohl(ode->fid.vnode);
1126             FIXUPSTUPIDINODE(sdirEntry->d_fileno);
1127             sdirEntry->d_reclen = rlen = len;
1128             sdirEntry->d_namlen = o_slen;
1129             sdirEntry->d_off = origOffset;
1130             AFS_UIOMOVE((char *)sdirEntry, sizeof(*sdirEntry), UIO_READ, auio,
1131                         code);
1132             if (code == 0)
1133                 AFS_UIOMOVE(ode->name, o_slen, UIO_READ, auio, code);
1134             /* pad out the remaining characters with zeros */
1135             if (code == 0) {
1136                 AFS_UIOMOVE(bufofzeros,
1137                             ((o_slen + 1 + DIRPAD) & ~DIRPAD) - o_slen,
1138                             UIO_READ, auio, code);
1139             }
1140             /* pad out the difference between rlen and slen... */
1141             if (NDIRSIZ_LEN(o_slen) < rlen) {
1142                 while (NDIRSIZ_LEN(o_slen) < rlen) {
1143                     int minLen = rlen - NDIRSIZ_LEN(o_slen);
1144                     if (minLen > sizeof(bufofzeros))
1145                         minLen = sizeof(bufofzeros);
1146                     AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
1147                     rlen -= minLen;
1148                 }
1149             }
1150 #else
1151             code = afs_readdir_move(ode, avc, auio, o_slen, len, origOffset);
1152 #endif /* AFS_HPUX_ENV */
1153         }
1154         len = NDIRSIZ_LEN(o_slen = n_slen);
1155         if (ode)
1156             DRelease(ode, 0);
1157         ode = nde;
1158         auio->afsio_offset = ((us + afs_dir_NameBlobs(nde->name)) << 5);
1159     }
1160     if (ode)
1161         DRelease(ode, 0);
1162
1163   dirend:
1164     ReleaseReadLock(&tdc->lock);
1165     afs_PutDCache(tdc);
1166     ReleaseReadLock(&avc->lock);
1167
1168   done:
1169 #if     defined(AFS_HPUX_ENV) || defined(AFS_OSF_ENV)
1170     osi_FreeSmallSpace((char *)sdirEntry);
1171 #endif
1172     afs_PutFakeStat(&fakestate);
1173     code = afs_CheckCode(code, &treq, 29);
1174     return code;
1175 }
1176
1177 #endif
1178 #endif /* !AFS_LINUX20_ENV */