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