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