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