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