netbsd: rebase cm at NetBSD 4.0
[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     register afs_int32 relativeBlob;
70     afs_int32 pageBlob;
71     register struct PageHeader *tpe;
72     register afs_int32 i;
73
74     AFS_STATCNT(BlobScan);
75     /* advance ablob over free and header blobs */
76     while (1) {
77         pageBlob = ablob & ~(EPP - 1);  /* base blob in same page */
78         tpe = (struct PageHeader *)afs_dir_GetBlob(afile, pageBlob);
79         if (!tpe)
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 *) pool_get(&ufs_direct_pool, PR_WAITOK);
507         dp->d_ino =  (Volume << 16) + ntohl(Vnode);
508         FIXUPSTUPIDINODE(dp->d_ino);
509         dp->d_reclen = rlen;
510         strcpy(dp->d_name, de->name);
511         AFS_UIOMOVE((char*) dp, sizeof(struct dirent), UIO_READ, auio, code);
512         pool_put(&ufs_direct_pool, dp);
513     }
514 #else
515     AFS_UIOMOVE((char *) &sdirEntry, sizeof(sdirEntry), UIO_READ, auio, code);
516     if (code == 0) {
517         AFS_UIOMOVE(de->name, slen, UIO_READ, auio, code);
518     }
519     /* pad out the remaining characters with zeros */
520     if (code == 0) {
521         AFS_UIOMOVE(bufofzeros, ((slen + 1 + DIRPAD) & ~DIRPAD) - slen,
522                     UIO_READ, auio, code);
523     }
524 #endif
525     AFS_MOVE_LOCK();
526 #endif /* AFS_SGI_ENV */
527     /* pad out the difference between rlen and slen... */
528     if (DIRSIZ_LEN(slen) < rlen) {
529         AFS_MOVE_UNLOCK();
530         while (DIRSIZ_LEN(slen) < rlen) {
531             int minLen = rlen - DIRSIZ_LEN(slen);
532             if (minLen > sizeof(bufofzeros))
533                 minLen = sizeof(bufofzeros);
534             AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
535             rlen -= minLen;
536         }
537         AFS_MOVE_LOCK();
538     }
539 #endif /* AFS_SUN5_ENV */
540 #endif /* AFS_SGI53_ENV */
541     return (code);
542 }
543
544
545 /*
546  *------------------------------------------------------------------------------
547  *
548  * Read directory entries.
549  * There are some weird things to look out for here.  The uio_offset
550  * field is either 0 or it is the offset returned from a previous
551  * readdir.  It is an opaque value used by the server to find the
552  * correct directory block to read.  The byte count must be at least
553  * vtoblksz(vp) bytes.  The count field is the number of blocks to
554  * read on the server.  This is advisory only, the server may return
555  * only one block's worth of entries.  Entries may be compressed on
556  * the server.
557  *
558  * This routine encodes knowledge of Vice dirs.
559  */
560
561 void
562 afs_bulkstat_send(struct vcache *avc, struct vrequest *req)
563 {
564     afs_rd_stash_i = 0;
565 }
566
567 /*
568  * Here is the bad, bad, really bad news.
569  * It has to do with 'offset' (seek locations).
570 */
571
572 int
573 #if     defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
574 afs_readdir(OSI_VC_DECL(avc), struct uio *auio, afs_ucred_t *acred, 
575             int *eofp)
576 #else
577 #if defined(AFS_HPUX100_ENV)
578 afs_readdir2(OSI_VC_DECL(avc), struct uio *auio, afs_ucred_t *acred)
579 #else
580 afs_readdir(OSI_VC_DECL(avc), struct uio *auio, afs_ucred_t *acred)
581 #endif
582 #endif
583 {
584     struct vrequest treq;
585     register struct dcache *tdc;
586     afs_size_t origOffset, tlen;
587     afs_int32 len;
588     int code = 0;
589     struct DirEntry *ode = 0, *nde = 0;
590     int o_slen = 0, n_slen = 0;
591     afs_uint32 us;
592     struct afs_fakestat_state fakestate;
593 #if defined(AFS_SGI53_ENV)
594     afs_int32 use64BitDirent, dirsiz;
595 #endif /* defined(AFS_SGI53_ENV) */
596 #ifndef AFS_HPUX_ENV
597     OSI_VC_CONVERT(avc);
598 #else
599     /*
600      * XXX All the hacks for alloced sdirEntry and inlining of afs_readdir_move instead of calling
601      * it is necessary for hpux due to stack problems that seem to occur when coming thru the nfs
602      * translator side XXX
603      */
604     struct min_direct *sdirEntry =
605         (struct min_direct *)osi_AllocSmallSpace(sizeof(struct min_direct));
606     afs_int32 rlen;
607 #endif
608
609     /* opaque value is pointer into a vice dir; use bit map to decide
610      * if the entries are in use.  Always assumed to be valid.  0 is
611      * special, means start of a new dir.  Int32 inode, followed by
612      * short reclen and short namelen.  Namelen does not include
613      * the null byte.  Followed by null-terminated string.
614      */
615     AFS_STATCNT(afs_readdir);
616
617 #if defined(AFS_SGI53_ENV)
618 #ifdef AFS_SGI61_ENV
619 #ifdef AFS_SGI62_ENV
620     use64BitDirent =
621         ABI_IS(ABI_IRIX5_64, GETDENTS_ABI(OSI_GET_CURRENT_ABI(), auio));
622 #else
623     use64BitDirent =
624         (auio->uio_segflg !=
625          UIO_USERSPACE) ? ABI_IRIX5_64 : (ABI_IS(ABI_IRIX5_64 | ABI_IRIX5_N32,
626                                                  u.u_procp->p_abi));
627 #endif /* AFS_SGI62_ENV */
628 #else /* AFS_SGI61_ENV */
629     use64BitDirent =
630         (auio->uio_segflg !=
631          UIO_USERSPACE) ? ABI_IRIX5_64 : (ABI_IS(ABI_IRIX5_64,
632                                                  u.u_procp->p_abi));
633 #endif /* AFS_SGI61_ENV */
634 #endif /* defined(AFS_SGI53_ENV) */
635
636 #if     defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
637     /* Not really used by the callee so we ignore it for now */
638     if (eofp)
639         *eofp = 0;
640 #endif
641 #ifndef AFS_64BIT_CLIENT
642     if (AfsLargeFileUio(auio)   /* file is large than 2 GB */
643         ||AfsLargeFileSize(AFS_UIO_OFFSET(auio), AFS_UIO_RESID(auio)))
644         return EFBIG;
645 #endif
646
647     if ((code = afs_InitReq(&treq, acred))) {
648 #ifdef  AFS_HPUX_ENV
649         osi_FreeSmallSpace((char *)sdirEntry);
650 #endif
651         return code;
652     }
653     /* update the cache entry */
654     afs_InitFakeStat(&fakestate);
655
656     AFS_DISCON_LOCK();
657
658     code = afs_EvalFakeStat(&avc, &fakestate, &treq);
659     if (code)
660         goto done;
661   tagain:
662     code = afs_VerifyVCache(avc, &treq);
663     if (code)
664         goto done;
665     /* get a reference to the entire directory */
666     tdc = afs_GetDCache(avc, (afs_size_t) 0, &treq, &origOffset, &tlen, 1);
667     len = tlen;
668     if (!tdc) {
669         code = ENOENT;
670         goto done;
671     }
672     ObtainReadLock(&avc->lock);
673     ObtainReadLock(&tdc->lock);
674
675     /*
676      * Make sure that the data in the cache is current. There are two
677      * cases we need to worry about:
678      * 1. The cache data is being fetched by another process.
679      * 2. The cache data is no longer valid
680      */
681     while ((avc->f.states & CStatd)
682            && (tdc->dflags & DFFetching)
683            && hsame(avc->f.m.DataVersion, tdc->f.versionNo)) {
684         afs_Trace4(afs_iclSetp, CM_TRACE_DCACHEWAIT, ICL_TYPE_STRING,
685                    __FILE__, ICL_TYPE_INT32, __LINE__, ICL_TYPE_POINTER, tdc,
686                    ICL_TYPE_INT32, tdc->dflags);
687         ReleaseReadLock(&tdc->lock);
688         ReleaseReadLock(&avc->lock);
689         afs_osi_Sleep(&tdc->validPos);
690         ObtainReadLock(&avc->lock);
691         ObtainReadLock(&tdc->lock);
692     }
693     if (!(avc->f.states & CStatd)
694         || !hsame(avc->f.m.DataVersion, tdc->f.versionNo)) {
695         ReleaseReadLock(&tdc->lock);
696         ReleaseReadLock(&avc->lock);
697         afs_PutDCache(tdc);
698         goto tagain;
699     }
700
701     /*
702      *  iterator for the directory reads.  Takes the AFS DirEntry
703      *  structure and slams them into UFS direct structures.
704      *  uses afs_readdir_move to get the struct to the user space.
705      *
706      *  The routine works by looking ahead one AFS directory entry.
707      *  That's because the AFS entry we are currenly working with
708      *  may not fit into the buffer the user has provided.  If it
709      *  doesn't we have to change the size of the LAST AFS directory
710      *  entry, so that it will FIT perfectly into the block the
711      *  user has provided.
712      *  
713      *  The 'forward looking' of the code makes it a bit tough to read.
714      *  Remember we need to get an entry, see if it it fits, then
715      *  set it up as the LAST entry, and find the next one.
716      *
717      *  Tough to take: We give out an EINVAL if we don't have enough
718      *  space in the buffer, and at the same time, don't have an entry
719      *  to put into the buffer. This CAN happen if the first AFS entry
720      *  we get can't fit into the 512 character buffer provided.  Seems
721      *  it ought not happen... 
722      *
723      *  Assumption: don't need to use anything but one dc entry:
724      *  this means the directory ought not be greater than 64k.
725      */
726     len = 0;
727 #ifdef AFS_HPUX_ENV
728     auio->uio_fpflags = 0;
729 #endif
730     while (code == 0) {
731         origOffset = AFS_UIO_OFFSET(auio);
732         /* scan for the next interesting entry scan for in-use blob otherwise up point at
733          * this blob note that ode, if non-zero, also represents a held dir page */
734         if (!(us = BlobScan(tdc, (origOffset >> 5)))
735             || !(nde = (struct DirEntry *)afs_dir_GetBlob(tdc, us))) {
736             /* failed to setup nde, return what we've got, and release ode */
737             if (len) {
738                 /* something to hand over. */
739 #ifdef  AFS_HPUX_ENV
740                 sdirEntry->d_fileno =
741                     (avc->f.fid.Fid.Volume << 16) + ntohl(ode->fid.vnode);
742                 FIXUPSTUPIDINODE(sdirEntry->d_fileno);
743                 sdirEntry->d_reclen = rlen = AFS_UIO_RESID(auio);
744                 sdirEntry->d_namlen = o_slen;
745 #if defined(AFS_SUN5_ENV) || defined(AFS_AIX32_ENV) || defined(AFS_HPUX100_ENV)
746                 sdirEntry->d_off = origOffset;
747 #endif
748                 AFS_UIOMOVE((char *)sdirEntry, sizeof(*sdirEntry), UIO_READ,
749                             auio, code);
750                 if (code == 0)
751                     AFS_UIOMOVE(ode->name, o_slen, UIO_READ, auio, code);
752                 /* pad out the remaining characters with zeros */
753                 if (code == 0) {
754                     AFS_UIOMOVE(bufofzeros,
755                                 ((o_slen + 1 + DIRPAD) & ~DIRPAD) - o_slen,
756                                 UIO_READ, auio, code);
757                 }
758                 /* pad out the difference between rlen and slen... */
759                 if (DIRSIZ_LEN(o_slen) < rlen) {
760                     while (DIRSIZ_LEN(o_slen) < rlen) {
761                         int minLen = rlen - DIRSIZ_LEN(o_slen);
762                         if (minLen > sizeof(bufofzeros))
763                             minLen = sizeof(bufofzeros);
764                         AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
765                         rlen -= minLen;
766                     }
767                 }
768 #else
769                 code = afs_readdir_move(ode, avc, auio, o_slen,
770 #if defined(AFS_SUN5_ENV)
771                                         len, origOffset);
772 #else
773                                         AFS_UIO_RESID(auio), origOffset);
774 #endif
775 #endif /* AFS_HPUX_ENV */
776 #if !defined(AFS_SUN5_ENV)
777                 AFS_UIO_SETRESID(auio, 0);
778 #endif
779             } else {
780                 /* nothin to hand over */
781             }
782 #if     defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
783             if (eofp)
784                 *eofp = 1;      /* Set it properly */
785 #endif
786             if (ode)
787                 DRelease(ode, 0);
788             goto dirend;
789         }
790         /* by here nde is set */
791         /* Do we have enough user space to carry out our mission? */
792 #if defined(AFS_SGI_ENV)
793         n_slen = strlen(nde->name) + 1; /* NULL terminate */
794 #else
795         n_slen = strlen(nde->name);
796 #endif
797 #ifdef  AFS_SGI53_ENV
798         dirsiz =
799             use64BitDirent ? DIRENTSIZE(n_slen) : IRIX5_DIRENTSIZE(n_slen);
800         if (dirsiz >= (AFS_UIO_RESID(auio) - len)) {
801 #else
802         if (DIRSIZ_LEN(n_slen) >= (AFS_UIO_RESID(auio) - len)) {
803 #endif /* AFS_SGI53_ENV */
804             /* No can do no more now; ya know... at this time */
805             DRelease(nde, 0);   /* can't use this one. */
806             if (len) {
807 #ifdef  AFS_HPUX_ENV
808                 sdirEntry->d_fileno =
809                     (avc->f.fid.Fid.Volume << 16) + ntohl(ode->fid.vnode);
810                 FIXUPSTUPIDINODE(sdirEntry->d_fileno);
811                 sdirEntry->d_reclen = rlen = AFS_UIO_RESID(auio);
812                 sdirEntry->d_namlen = o_slen;
813 #if defined(AFS_SUN5_ENV) || defined(AFS_AIX32_ENV) || defined(AFS_HPUX100_ENV)
814                 sdirEntry->d_off = origOffset;
815 #endif
816                 AFS_UIOMOVE((char *)sdirEntry, sizeof(*sdirEntry), UIO_READ,
817                             auio, code);
818                 if (code == 0)
819                     AFS_UIOMOVE(ode->name, o_slen, UIO_READ, auio, code);
820                 /* pad out the remaining characters with zeros */
821                 if (code == 0) {
822                     AFS_UIOMOVE(bufofzeros,
823                                 ((o_slen + 1 + DIRPAD) & ~DIRPAD) - o_slen,
824                                 UIO_READ, auio, code);
825                 }
826                 /* pad out the difference between rlen and slen... */
827                 if (DIRSIZ_LEN(o_slen) < rlen) {
828                     while (DIRSIZ_LEN(o_slen) < rlen) {
829                         int minLen = rlen - DIRSIZ_LEN(o_slen);
830                         if (minLen > sizeof(bufofzeros))
831                             minLen = sizeof(bufofzeros);
832                         AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
833                         rlen -= minLen;
834                     }
835                 }
836 #else /* AFS_HPUX_ENV */
837                 code =
838                     afs_readdir_move(ode, avc, auio, o_slen,
839                                      AFS_UIO_RESID(auio), origOffset);
840 #endif /* AFS_HPUX_ENV */
841                 /* this next line used to be AFSVFS40 or AIX 3.1, but is
842                  * really generic */
843                 AFS_UIO_SETOFFSET(auio, origOffset);
844                 AFS_UIO_SETRESID(auio, 0);
845             } else {            /* trouble, can't give anything to the user! */
846                 /* even though he has given us a buffer, 
847                  * even though we have something to give us,
848                  * Looks like we lost something somewhere.
849                  */
850                 code = EINVAL;
851             }
852             if (ode)
853                 DRelease(ode, 0);
854             goto dirend;
855         }
856
857         /*
858          * In any event, we move out the LAST de entry, getting ready
859          * to set up for the next one.
860          */
861         if (len) {
862 #ifdef  AFS_HPUX_ENV
863             sdirEntry->d_fileno =
864                 (avc->f.fid.Fid.Volume << 16) + ntohl(ode->fid.vnode);
865             FIXUPSTUPIDINODE(sdirEntry->d_fileno);
866             sdirEntry->d_reclen = rlen = len;
867             sdirEntry->d_namlen = o_slen;
868 #if defined(AFS_SUN5_ENV) || defined(AFS_AIX32_ENV) || defined(AFS_HPUX100_ENV)
869             sdirEntry->d_off = origOffset;
870 #endif
871             AFS_UIOMOVE((char *)sdirEntry, sizeof(*sdirEntry), UIO_READ, auio,
872                         code);
873             if (code == 0)
874                 AFS_UIOMOVE(ode->name, o_slen, UIO_READ, auio, code);
875             /* pad out the remaining characters with zeros */
876             if (code == 0) {
877                 AFS_UIOMOVE(bufofzeros,
878                             ((o_slen + 1 + DIRPAD) & ~DIRPAD) - o_slen,
879                             UIO_READ, auio, code);
880             }
881             /* pad out the difference between rlen and slen... */
882             if (DIRSIZ_LEN(o_slen) < rlen) {
883                 while (DIRSIZ_LEN(o_slen) < rlen) {
884                     int minLen = rlen - DIRSIZ_LEN(o_slen);
885                     if (minLen > sizeof(bufofzeros))
886                         minLen = sizeof(bufofzeros);
887                     AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
888                     rlen -= minLen;
889                 }
890             }
891 #else /* AFS_HPUX_ENV */
892             code = afs_readdir_move(ode, avc, auio, o_slen, len, origOffset);
893 #endif /* AFS_HPUX_ENV */
894         }
895 #ifdef  AFS_SGI53_ENV
896         len = use64BitDirent ? DIRENTSIZE(o_slen =
897                                           n_slen) : IRIX5_DIRENTSIZE(o_slen =
898                                                                      n_slen);
899 #else
900         len = DIRSIZ_LEN(o_slen = n_slen);
901 #endif /* AFS_SGI53_ENV */
902         if (ode)
903             DRelease(ode, 0);
904         ode = nde;
905         AFS_UIO_SETOFFSET(auio, (afs_int32) ((us + afs_dir_NameBlobs(nde->name)) << 5));
906     }
907     if (ode)
908         DRelease(ode, 0);
909
910   dirend:
911     ReleaseReadLock(&tdc->lock);
912     afs_PutDCache(tdc);
913     ReleaseReadLock(&avc->lock);
914
915   done:
916 #ifdef  AFS_HPUX_ENV
917     osi_FreeSmallSpace((char *)sdirEntry);
918 #endif
919     AFS_DISCON_UNLOCK();
920     afs_PutFakeStat(&fakestate);
921     code = afs_CheckCode(code, &treq, 28);
922     return code;
923 }
924
925 #if defined(AFS_HPUX_ENV)
926 int
927 afs1_readdir(struct vcache *avc, struct uio *auio, afs_ucred_t *acred)
928 {
929     struct vrequest treq;
930     register struct dcache *tdc;
931     afs_size_t origOffset, len;
932     int code = 0;
933     struct DirEntry *ode = 0, *nde = 0;
934     int o_slen = 0, n_slen = 0;
935     afs_uint32 us;
936     /*
937      * XXX All the hacks for alloced sdirEntry and inlining of
938      * afs_readdir_move instead of calling it is necessary for hpux due to
939      * stack problems that seem to occur when coming thru the nfs
940      * translator side XXX
941      */
942     struct minnfs_direct *sdirEntry = (struct minnfs_direct *)
943         osi_AllocSmallSpace(sizeof(struct min_direct));
944     afs_int32 rlen;
945
946     struct afs_fakestat_state fakestate;
947
948     AFS_STATCNT(afs_readdir);
949     if (code = afs_InitReq(&treq, acred)) {
950         osi_FreeSmallSpace((char *)sdirEntry);
951         return code;
952     }
953     afs_InitFakeStat(&fakestate);
954     AFS_DISCON_LOCK();
955     code = afs_EvalFakeStat(&avc, &fakestate, &treq);
956     if (code) {
957         osi_FreeSmallSpace((char *)sdirEntry);
958         AFS_DISCON_UNLOCK();
959         afs_PutFakeStat(&fakestate);
960         return code;
961     }
962     /* update the cache entry */
963   tagain:
964     code = afs_VerifyVCache(avc, &treq);
965     if (code)
966         goto done;
967     /* get a reference to the entire directory */
968     tdc = afs_GetDCache(avc, (afs_size_t) 0, &treq, &origOffset, &len, 1);
969     if (!tdc) {
970         code = ENOENT;
971         goto done;
972     }
973     ObtainReadLock(&avc->lock);
974     ObtainReadLock(&tdc->lock);
975
976     /*
977      * Make sure that the data in the cache is current. There are two
978      * cases we need to worry about:
979      * 1. The cache data is being fetched by another process.
980      * 2. The cache data is no longer valid
981      */
982     while ((avc->f.states & CStatd)
983            && (tdc->dflags & DFFetching)
984            && hsame(avc->f.m.DataVersion, tdc->f.versionNo)) {
985         afs_Trace4(afs_iclSetp, CM_TRACE_DCACHEWAIT, ICL_TYPE_STRING,
986                    __FILE__, ICL_TYPE_INT32, __LINE__, ICL_TYPE_POINTER, tdc,
987                    ICL_TYPE_INT32, tdc->dflags);
988         ReleaseReadLock(&tdc->lock);
989         ReleaseReadLock(&avc->lock);
990         afs_osi_Sleep(&tdc->validPos);
991         ObtainReadLock(&avc->lock);
992         ObtainReadLock(&tdc->lock);
993     }
994     if (!(avc->f.states & CStatd)
995         || !hsame(avc->f.m.DataVersion, tdc->f.versionNo)) {
996         ReleaseReadLock(&tdc->lock);
997         ReleaseReadLock(&avc->lock);
998         afs_PutDCache(tdc);
999         goto tagain;
1000     }
1001
1002     len = 0;
1003     auio->uio_fpflags = 0;
1004     while (code == 0) {
1005         origOffset = AFS_UIO_OFFSET(auio);
1006
1007         /* scan for the next interesting entry scan for in-use blob
1008          * otherwise up point at this blob note that ode, if non-zero,
1009          * also represents a held dir page */
1010         if (!(us = BlobScan(tdc, (origOffset >> 5)))
1011             || !(nde = (struct DirEntry *)afs_dir_GetBlob(tdc, us))) {
1012             /* failed to setup nde, return what we've got, and release ode */
1013             if (len) {
1014                 /* something to hand over. */
1015                 sdirEntry->d_fileno =
1016                     (avc->f.fid.Fid.Volume << 16) + ntohl(ode->fid.vnode);
1017                 FIXUPSTUPIDINODE(sdirEntry->d_fileno);
1018                 sdirEntry->d_reclen = rlen = AFS_UIO_RESID(auio);
1019                 sdirEntry->d_namlen = o_slen;
1020                 sdirEntry->d_off = origOffset;
1021                 AFS_UIOMOVE((char *)sdirEntry, sizeof(*sdirEntry), UIO_READ,
1022                             auio, code);
1023                 if (code == 0) {
1024                     AFS_UIOMOVE(ode->name, o_slen, UIO_READ, auio, code);
1025                 }
1026                 /* pad out the remaining characters with zeros */
1027                 if (code == 0) {
1028                     AFS_UIOMOVE(bufofzeros,
1029                                 ((o_slen + 1 + DIRPAD) & ~DIRPAD) - o_slen,
1030                                 UIO_READ, auio, code);
1031                 }
1032                 /* pad out the difference between rlen and slen... */
1033                 if (NDIRSIZ_LEN(o_slen) < rlen) {
1034                     while (NDIRSIZ_LEN(o_slen) < rlen) {
1035                         int minLen = rlen - NDIRSIZ_LEN(o_slen);
1036                         if (minLen > sizeof(bufofzeros))
1037                             minLen = sizeof(bufofzeros);
1038                         AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
1039                         rlen -= minLen;
1040                     }
1041                 }
1042                 AFS_UIO_SETRESID(auio, 0);
1043             } else {
1044                 /* nothin to hand over */
1045             }
1046             if (ode)
1047                 DRelease(ode, 0);
1048             goto dirend;
1049         }
1050         /* by here nde is set */
1051
1052         /* Do we have enough user space to carry out our mission? */
1053         n_slen = strlen(nde->name);
1054         if (NDIRSIZ_LEN(n_slen) >= (AFS_UIO_RESID(auio) - len)) {
1055             /* No can do no more now; ya know... at this time */
1056             DRelease(nde, 0);   /* can't use this one. */
1057             if (len) {
1058                 sdirEntry->d_fileno =
1059                     (avc->f.fid.Fid.Volume << 16) + ntohl(ode->fid.vnode);
1060                 FIXUPSTUPIDINODE(sdirEntry->d_fileno);
1061                 sdirEntry->d_reclen = rlen = AFS_UIO_RESID(auio);
1062                 sdirEntry->d_namlen = o_slen;
1063                 sdirEntry->d_off = origOffset;
1064                 AFS_UIOMOVE((char *)sdirEntry, sizeof(*sdirEntry), UIO_READ,
1065                             auio, code);
1066                 if (code == 0)
1067                     AFS_UIOMOVE(ode->name, o_slen, UIO_READ, auio, code);
1068                 /* pad out the remaining characters with zeros */
1069                 if (code == 0) {
1070                     AFS_UIOMOVE(bufofzeros,
1071                                 ((o_slen + 1 + DIRPAD) & ~DIRPAD) - o_slen,
1072                                 UIO_READ, auio, code);
1073                 }
1074                 /* pad out the difference between rlen and slen... */
1075                 if (NDIRSIZ_LEN(o_slen) < rlen) {
1076                     while (NDIRSIZ_LEN(o_slen) < rlen) {
1077                         int minLen = rlen - NDIRSIZ_LEN(o_slen);
1078                         if (minLen > sizeof(bufofzeros))
1079                             minLen = sizeof(bufofzeros);
1080                         AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
1081                         rlen -= minLen;
1082                     }
1083                 }
1084                 /* this next line used to be AFSVFS40 or AIX 3.1, but is really generic */
1085                 AFS_UIO_SETOFFSET(auio, origOffset);
1086                 AFS_UIO_SETRESID(auio, 0);
1087             } else {            /* trouble, can't give anything to the user! */
1088                 /* even though he has given us a buffer, 
1089                  * even though we have something to give us,
1090                  * Looks like we lost something somewhere.
1091                  */
1092                 code = EINVAL;
1093             }
1094             if (ode)
1095                 DRelease(ode, 0);
1096             goto dirend;
1097         }
1098
1099         /*
1100          * In any event, we move out the LAST de entry, getting ready
1101          * to set up for the next one.
1102          */
1103         if (len) {
1104             sdirEntry->d_fileno =
1105                 (avc->f.fid.Fid.Volume << 16) + ntohl(ode->fid.vnode);
1106             FIXUPSTUPIDINODE(sdirEntry->d_fileno);
1107             sdirEntry->d_reclen = rlen = len;
1108             sdirEntry->d_namlen = o_slen;
1109             sdirEntry->d_off = origOffset;
1110             AFS_UIOMOVE((char *)sdirEntry, sizeof(*sdirEntry), UIO_READ, auio,
1111                         code);
1112             if (code == 0)
1113                 AFS_UIOMOVE(ode->name, o_slen, UIO_READ, auio, code);
1114             /* pad out the remaining characters with zeros */
1115             if (code == 0) {
1116                 AFS_UIOMOVE(bufofzeros,
1117                             ((o_slen + 1 + DIRPAD) & ~DIRPAD) - o_slen,
1118                             UIO_READ, auio, code);
1119             }
1120             /* pad out the difference between rlen and slen... */
1121             if (NDIRSIZ_LEN(o_slen) < rlen) {
1122                 while (NDIRSIZ_LEN(o_slen) < rlen) {
1123                     int minLen = rlen - NDIRSIZ_LEN(o_slen);
1124                     if (minLen > sizeof(bufofzeros))
1125                         minLen = sizeof(bufofzeros);
1126                     AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
1127                     rlen -= minLen;
1128                 }
1129             }
1130         }
1131         len = NDIRSIZ_LEN(o_slen = n_slen);
1132         if (ode)
1133             DRelease(ode, 0);
1134         ode = nde;
1135         AFS_UIO_OFFSET(auio) = ((us + afs_dir_NameBlobs(nde->name)) << 5);
1136     }
1137     if (ode)
1138         DRelease(ode, 0);
1139
1140   dirend:
1141     ReleaseReadLock(&tdc->lock);
1142     afs_PutDCache(tdc);
1143     ReleaseReadLock(&avc->lock);
1144
1145   done:
1146     osi_FreeSmallSpace((char *)sdirEntry);
1147     AFS_DISCON_UNLOCK();
1148     afs_PutFakeStat(&fakestate);
1149     code = afs_CheckCode(code, &treq, 29);
1150     return code;
1151 }
1152
1153 #endif
1154 #endif /* !AFS_LINUX20_ENV */