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