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