8010 loader: want mechanism to avoid RA with bcache
[unleashed.git] / usr / src / boot / lib / libstand / nfs.c
blobe97449183c8c28793bb0941b98340abb5ab36cdf
1 /* $NetBSD: nfs.c,v 1.2 1998/01/24 12:43:09 drochner Exp $ */
3 /*-
4 * Copyright (c) 1993 John Brezak
5 * All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
22 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
26 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
27 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 * POSSIBILITY OF SUCH DAMAGE.
31 #include <sys/cdefs.h>
33 #include <sys/param.h>
34 #include <sys/time.h>
35 #include <sys/socket.h>
36 #include <sys/stat.h>
37 #include <string.h>
38 #include <stddef.h>
40 #include <netinet/in.h>
41 #include <netinet/in_systm.h>
43 #include "rpcv2.h"
44 #include "nfsv2.h"
46 #include "stand.h"
47 #include "net.h"
48 #include "netif.h"
49 #include "rpc.h"
51 #define NFS_DEBUGxx
53 #define NFSREAD_MIN_SIZE 1024
54 #define NFSREAD_MAX_SIZE 4096
56 /* NFSv3 definitions */
57 #define NFS_V3MAXFHSIZE 64
58 #define NFS_VER3 3
59 #define RPCMNT_VER3 3
60 #define NFSPROCV3_LOOKUP 3
61 #define NFSPROCV3_READLINK 5
62 #define NFSPROCV3_READ 6
63 #define NFSPROCV3_READDIR 16
65 typedef struct {
66 uint32_t val[2];
67 } n_quad;
69 struct nfsv3_time {
70 uint32_t nfs_sec;
71 uint32_t nfs_nsec;
74 struct nfsv3_fattrs {
75 uint32_t fa_type;
76 uint32_t fa_mode;
77 uint32_t fa_nlink;
78 uint32_t fa_uid;
79 uint32_t fa_gid;
80 n_quad fa_size;
81 n_quad fa_used;
82 n_quad fa_rdev;
83 n_quad fa_fsid;
84 n_quad fa_fileid;
85 struct nfsv3_time fa_atime;
86 struct nfsv3_time fa_mtime;
87 struct nfsv3_time fa_ctime;
91 * For NFSv3, the file handle is variable in size, so most fixed sized
92 * structures for arguments won't work. For most cases, a structure
93 * that starts with any fixed size section is followed by an array
94 * that covers the maximum size required.
96 struct nfsv3_readdir_repl {
97 uint32_t errno;
98 uint32_t ok;
99 struct nfsv3_fattrs fa;
100 uint32_t cookiev0;
101 uint32_t cookiev1;
104 struct nfsv3_readdir_entry {
105 uint32_t follows;
106 uint32_t fid0;
107 uint32_t fid1;
108 uint32_t len;
109 uint32_t nameplus[0];
112 struct nfs_iodesc {
113 struct iodesc *iodesc;
114 off_t off;
115 uint32_t fhsize;
116 u_char fh[NFS_V3MAXFHSIZE];
117 struct nfsv3_fattrs fa; /* all in network order */
118 uint64_t cookie;
122 * XXX interactions with tftp? See nfswrapper.c for a confusing
123 * issue.
125 int nfs_open(const char *path, struct open_file *f);
126 static int nfs_close(struct open_file *f);
127 static int nfs_read(struct open_file *f, void *buf, size_t size, size_t *resid);
128 static int nfs_write(struct open_file *f, void *buf, size_t size, size_t *resid);
129 static off_t nfs_seek(struct open_file *f, off_t offset, int where);
130 static int nfs_stat(struct open_file *f, struct stat *sb);
131 static int nfs_readdir(struct open_file *f, struct dirent *d);
133 struct nfs_iodesc nfs_root_node;
135 struct fs_ops nfs_fsops = {
136 "nfs",
137 nfs_open,
138 nfs_close,
139 nfs_read,
140 nfs_write,
141 nfs_seek,
142 nfs_stat,
143 nfs_readdir
146 static int nfs_read_size = NFSREAD_MIN_SIZE;
149 * Improve boot performance over NFS
151 static void
152 set_nfs_read_size(void)
154 char *env, *end;
155 char buf[10];
157 if ((env = getenv("nfs.read_size")) != NULL) {
158 errno = 0;
159 nfs_read_size = strtol(env, &end, 0);
160 if (errno != 0 || *env == '\0' || *end != '\0') {
161 printf("%s: bad value: \"%s\", defaulting to %d\n",
162 "nfs.read_size", env, NFSREAD_MIN_SIZE);
163 nfs_read_size = NFSREAD_MIN_SIZE;
166 if (nfs_read_size < NFSREAD_MIN_SIZE) {
167 printf("%s: bad value: \"%d\", defaulting to %d\n",
168 "nfs.read_size", nfs_read_size, NFSREAD_MIN_SIZE);
169 nfs_read_size = NFSREAD_MIN_SIZE;
171 if (nfs_read_size > NFSREAD_MAX_SIZE) {
172 printf("%s: bad value: \"%d\", defaulting to %d\n",
173 "nfs.read_size", nfs_read_size, NFSREAD_MIN_SIZE);
174 nfs_read_size = NFSREAD_MAX_SIZE;
176 snprintf(buf, sizeof (buf), "%d", nfs_read_size);
177 setenv("nfs.read_size", buf, 1);
181 * Fetch the root file handle (call mount daemon)
182 * Return zero or error number.
185 nfs_getrootfh(struct iodesc *d, char *path, uint32_t *fhlenp, u_char *fhp)
187 int len;
188 struct args {
189 uint32_t len;
190 char path[FNAME_SIZE];
191 } *args;
192 struct repl {
193 uint32_t errno;
194 uint32_t fhsize;
195 u_char fh[NFS_V3MAXFHSIZE];
196 uint32_t authcnt;
197 uint32_t auth[7];
198 } *repl;
199 struct {
200 uint32_t h[RPC_HEADER_WORDS];
201 struct args d;
202 } sdata;
203 struct {
204 uint32_t h[RPC_HEADER_WORDS];
205 struct repl d;
206 } rdata;
207 size_t cc;
209 #ifdef NFS_DEBUG
210 if (debug)
211 printf("nfs_getrootfh: %s\n", path);
212 #endif
214 args = &sdata.d;
215 repl = &rdata.d;
217 bzero(args, sizeof(*args));
218 len = strlen(path);
219 if (len > sizeof(args->path))
220 len = sizeof(args->path);
221 args->len = htonl(len);
222 bcopy(path, args->path, len);
223 len = sizeof(uint32_t) + roundup(len, sizeof(uint32_t));
225 cc = rpc_call(d, RPCPROG_MNT, RPCMNT_VER3, RPCMNT_MOUNT,
226 args, len, repl, sizeof(*repl));
227 if (cc == -1)
228 /* errno was set by rpc_call */
229 return (errno);
230 if (cc < 2 * sizeof (uint32_t))
231 return (EBADRPC);
232 if (repl->errno != 0)
233 return (ntohl(repl->errno));
234 *fhlenp = ntohl(repl->fhsize);
235 bcopy(repl->fh, fhp, *fhlenp);
237 set_nfs_read_size();
238 return (0);
242 * Lookup a file. Store handle and attributes.
243 * Return zero or error number.
246 nfs_lookupfh(struct nfs_iodesc *d, const char *name, struct nfs_iodesc *newfd)
248 int len, rlen, pos;
249 struct args {
250 uint32_t fhsize;
251 uint32_t fhplusname[1 +
252 (NFS_V3MAXFHSIZE + FNAME_SIZE) / sizeof(uint32_t)];
253 } *args;
254 struct repl {
255 uint32_t errno;
256 uint32_t fhsize;
257 uint32_t fhplusattr[(NFS_V3MAXFHSIZE +
258 2 * (sizeof(uint32_t) +
259 sizeof(struct nfsv3_fattrs))) / sizeof(uint32_t)];
260 } *repl;
261 struct {
262 uint32_t h[RPC_HEADER_WORDS];
263 struct args d;
264 } sdata;
265 struct {
266 uint32_t h[RPC_HEADER_WORDS];
267 struct repl d;
268 } rdata;
269 ssize_t cc;
271 #ifdef NFS_DEBUG
272 if (debug)
273 printf("lookupfh: called\n");
274 #endif
276 args = &sdata.d;
277 repl = &rdata.d;
279 bzero(args, sizeof(*args));
280 args->fhsize = htonl(d->fhsize);
281 bcopy(d->fh, args->fhplusname, d->fhsize);
282 len = strlen(name);
283 if (len > FNAME_SIZE)
284 len = FNAME_SIZE;
285 pos = roundup(d->fhsize, sizeof(uint32_t)) / sizeof(uint32_t);
286 args->fhplusname[pos++] = htonl(len);
287 bcopy(name, &args->fhplusname[pos], len);
288 len = sizeof(uint32_t) + pos * sizeof(uint32_t) +
289 roundup(len, sizeof(uint32_t));
291 rlen = sizeof(*repl);
293 cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER3, NFSPROCV3_LOOKUP,
294 args, len, repl, rlen);
295 if (cc == -1)
296 return (errno); /* XXX - from rpc_call */
297 if (cc < 2 * sizeof(uint32_t))
298 return (EIO);
299 if (repl->errno != 0)
300 /* saerrno.h now matches NFS error numbers. */
301 return (ntohl(repl->errno));
302 newfd->fhsize = ntohl(repl->fhsize);
303 bcopy(repl->fhplusattr, &newfd->fh, newfd->fhsize);
304 pos = roundup(newfd->fhsize, sizeof(uint32_t)) / sizeof(uint32_t);
305 if (repl->fhplusattr[pos++] == 0)
306 return (EIO);
307 bcopy(&repl->fhplusattr[pos], &newfd->fa, sizeof(newfd->fa));
308 return (0);
311 #ifndef NFS_NOSYMLINK
313 * Get the destination of a symbolic link.
316 nfs_readlink(struct nfs_iodesc *d, char *buf)
318 struct args {
319 uint32_t fhsize;
320 u_char fh[NFS_V3MAXFHSIZE];
321 } *args;
322 struct repl {
323 uint32_t errno;
324 uint32_t ok;
325 struct nfsv3_fattrs fa;
326 uint32_t len;
327 u_char path[NFS_MAXPATHLEN];
328 } *repl;
329 struct {
330 uint32_t h[RPC_HEADER_WORDS];
331 struct args d;
332 } sdata;
333 struct {
334 uint32_t h[RPC_HEADER_WORDS];
335 struct repl d;
336 } rdata;
337 ssize_t cc;
339 #ifdef NFS_DEBUG
340 if (debug)
341 printf("readlink: called\n");
342 #endif
344 args = &sdata.d;
345 repl = &rdata.d;
347 bzero(args, sizeof(*args));
348 args->fhsize = htonl(d->fhsize);
349 bcopy(d->fh, args->fh, d->fhsize);
350 cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER3, NFSPROCV3_READLINK,
351 args, sizeof(uint32_t) + roundup(d->fhsize, sizeof(uint32_t)),
352 repl, sizeof(*repl));
353 if (cc == -1)
354 return (errno);
356 if (cc < 2 * sizeof(uint32_t))
357 return (EIO);
359 if (repl->errno != 0)
360 return (ntohl(repl->errno));
362 if (repl->ok == 0)
363 return (EIO);
365 repl->len = ntohl(repl->len);
366 if (repl->len > NFS_MAXPATHLEN)
367 return (ENAMETOOLONG);
369 bcopy(repl->path, buf, repl->len);
370 buf[repl->len] = 0;
371 return (0);
373 #endif
376 * Read data from a file.
377 * Return transfer count or -1 (and set errno)
379 ssize_t
380 nfs_readdata(struct nfs_iodesc *d, off_t off, void *addr, size_t len)
382 struct args {
383 uint32_t fhsize;
384 uint32_t fhoffcnt[NFS_V3MAXFHSIZE / sizeof(uint32_t) + 3];
385 } *args;
386 struct repl {
387 uint32_t errno;
388 uint32_t ok;
389 struct nfsv3_fattrs fa;
390 uint32_t count;
391 uint32_t eof;
392 uint32_t len;
393 u_char data[NFSREAD_MAX_SIZE];
394 } *repl;
395 struct {
396 uint32_t h[RPC_HEADER_WORDS];
397 struct args d;
398 } sdata;
399 struct {
400 uint32_t h[RPC_HEADER_WORDS];
401 struct repl d;
402 } rdata;
403 size_t cc;
404 long x;
405 int hlen, rlen, pos;
407 args = &sdata.d;
408 repl = &rdata.d;
410 bzero(args, sizeof(*args));
411 args->fhsize = htonl(d->fhsize);
412 bcopy(d->fh, args->fhoffcnt, d->fhsize);
413 pos = roundup(d->fhsize, sizeof(uint32_t)) / sizeof(uint32_t);
414 args->fhoffcnt[pos++] = 0;
415 args->fhoffcnt[pos++] = htonl((uint32_t)off);
416 if (len > nfs_read_size)
417 len = nfs_read_size;
418 args->fhoffcnt[pos] = htonl((uint32_t)len);
419 hlen = offsetof(struct repl, data[0]);
421 cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER3, NFSPROCV3_READ,
422 args, 4 * sizeof(uint32_t) + roundup(d->fhsize, sizeof(uint32_t)),
423 repl, sizeof(*repl));
424 if (cc == -1)
425 /* errno was already set by rpc_call */
426 return (-1);
427 if (cc < hlen) {
428 errno = EBADRPC;
429 return (-1);
431 if (repl->errno != 0) {
432 errno = ntohl(repl->errno);
433 return (-1);
435 rlen = cc - hlen;
436 x = ntohl(repl->count);
437 if (rlen < x) {
438 printf("nfsread: short packet, %d < %ld\n", rlen, x);
439 errno = EBADRPC;
440 return (-1);
442 bcopy(repl->data, addr, x);
443 return (x);
447 * Open a file.
448 * return zero or error number
451 nfs_open(const char *upath, struct open_file *f)
453 struct iodesc *desc;
454 struct nfs_iodesc *currfd;
455 char buf[2 * NFS_V3MAXFHSIZE + 3];
456 u_char *fh;
457 char *cp;
458 int i;
459 #ifndef NFS_NOSYMLINK
460 struct nfs_iodesc *newfd;
461 struct nfsv3_fattrs *fa;
462 char *ncp;
463 int c;
464 char namebuf[NFS_MAXPATHLEN + 1];
465 char linkbuf[NFS_MAXPATHLEN + 1];
466 int nlinks = 0;
467 #endif
468 int error;
469 char *path;
471 if (netproto != NET_NFS)
472 return (EINVAL);
474 #ifdef NFS_DEBUG
475 if (debug)
476 printf("nfs_open: %s (rootpath=%s)\n", upath, rootpath);
477 #endif
478 if (!rootpath[0]) {
479 printf("no rootpath, no nfs\n");
480 return (ENXIO);
484 * This is silly - we should look at dv_type but that value is
485 * arch dependant and we can't use it here.
487 #ifndef __i386__
488 if (strcmp(f->f_dev->dv_name, "net") != 0)
489 return (EINVAL);
490 #else
491 if (strcmp(f->f_dev->dv_name, "pxe") != 0)
492 return (EINVAL);
493 #endif
495 if (!(desc = socktodesc(*(int *)(f->f_devdata))))
496 return (EINVAL);
498 /* Bind to a reserved port. */
499 desc->myport = htons(--rpc_port);
500 desc->destip = rootip;
501 if ((error = nfs_getrootfh(desc, rootpath, &nfs_root_node.fhsize,
502 nfs_root_node.fh)))
503 return (error);
504 nfs_root_node.fa.fa_type = htonl(NFDIR);
505 nfs_root_node.fa.fa_mode = htonl(0755);
506 nfs_root_node.fa.fa_nlink = htonl(2);
507 nfs_root_node.iodesc = desc;
509 fh = &nfs_root_node.fh[0];
510 buf[0] = 'X';
511 cp = &buf[1];
512 for (i = 0; i < nfs_root_node.fhsize; i++, cp += 2)
513 sprintf(cp, "%02x", fh[i]);
514 sprintf(cp, "X");
515 setenv("boot.nfsroot.server", inet_ntoa(rootip), 1);
516 setenv("boot.nfsroot.path", rootpath, 1);
517 setenv("boot.nfsroot.nfshandle", buf, 1);
518 sprintf(buf, "%d", nfs_root_node.fhsize);
519 setenv("boot.nfsroot.nfshandlelen", buf, 1);
521 /* Allocate file system specific data structure */
522 currfd = malloc(sizeof(*newfd));
523 if (currfd == NULL) {
524 error = ENOMEM;
525 goto out;
527 #ifndef NFS_NOSYMLINK
528 bcopy(&nfs_root_node, currfd, sizeof(*currfd));
529 newfd = NULL;
531 cp = path = strdup(upath);
532 if (path == NULL) {
533 error = ENOMEM;
534 goto out;
536 while (*cp) {
538 * Remove extra separators
540 while (*cp == '/')
541 cp++;
543 if (*cp == '\0')
544 break;
546 * Check that current node is a directory.
548 if (currfd->fa.fa_type != htonl(NFDIR)) {
549 error = ENOTDIR;
550 goto out;
553 /* allocate file system specific data structure */
554 newfd = malloc(sizeof(*newfd));
555 if (newfd == NULL) {
556 error = ENOMEM;
557 goto out;
559 newfd->iodesc = currfd->iodesc;
562 * Get next component of path name.
565 int len = 0;
567 ncp = cp;
568 while ((c = *cp) != '\0' && c != '/') {
569 if (++len > NFS_MAXNAMLEN) {
570 error = ENOENT;
571 goto out;
573 cp++;
575 *cp = '\0';
578 /* lookup a file handle */
579 error = nfs_lookupfh(currfd, ncp, newfd);
580 *cp = c;
581 if (error)
582 goto out;
585 * Check for symbolic link
587 if (newfd->fa.fa_type == htonl(NFLNK)) {
588 int link_len, len;
590 error = nfs_readlink(newfd, linkbuf);
591 if (error)
592 goto out;
594 link_len = strlen(linkbuf);
595 len = strlen(cp);
597 if (link_len + len > MAXPATHLEN
598 || ++nlinks > MAXSYMLINKS) {
599 error = ENOENT;
600 goto out;
603 bcopy(cp, &namebuf[link_len], len + 1);
604 bcopy(linkbuf, namebuf, link_len);
607 * If absolute pathname, restart at root.
608 * If relative pathname, restart at parent directory.
610 cp = namebuf;
611 if (*cp == '/')
612 bcopy(&nfs_root_node, currfd, sizeof(*currfd));
614 free(newfd);
615 newfd = NULL;
617 continue;
620 free(currfd);
621 currfd = newfd;
622 newfd = NULL;
625 error = 0;
627 out:
628 free(newfd);
629 free(path);
630 #else
631 currfd->iodesc = desc;
633 error = nfs_lookupfh(&nfs_root_node, upath, currfd);
634 #endif
635 if (!error) {
636 currfd->off = 0;
637 currfd->cookie = 0;
638 f->f_fsdata = (void *)currfd;
639 return (0);
642 #ifdef NFS_DEBUG
643 if (debug)
644 printf("nfs_open: %s lookupfh failed: %s\n",
645 path, strerror(error));
646 #endif
647 free(currfd);
649 return (error);
653 nfs_close(struct open_file *f)
655 struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
657 #ifdef NFS_DEBUG
658 if (debug)
659 printf("nfs_close: fp=0x%lx\n", (u_long)fp);
660 #endif
662 if (fp)
663 free(fp);
664 f->f_fsdata = (void *)0;
666 return (0);
670 * read a portion of a file
673 nfs_read(struct open_file *f, void *buf, size_t size, size_t *resid)
675 struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
676 ssize_t cc;
677 char *addr = buf;
679 #ifdef NFS_DEBUG
680 if (debug)
681 printf("nfs_read: size=%lu off=%d\n", (u_long)size,
682 (int)fp->off);
683 #endif
684 while ((int)size > 0) {
685 twiddle(16);
686 cc = nfs_readdata(fp, fp->off, (void *)addr, size);
687 /* XXX maybe should retry on certain errors */
688 if (cc == -1) {
689 #ifdef NFS_DEBUG
690 if (debug)
691 printf("nfs_read: read: %s", strerror(errno));
692 #endif
693 return (errno); /* XXX - from nfs_readdata */
695 if (cc == 0) {
696 #ifdef NFS_DEBUG
697 if (debug)
698 printf("nfs_read: hit EOF unexpectantly");
699 #endif
700 goto ret;
702 fp->off += cc;
703 addr += cc;
704 size -= cc;
706 ret:
707 if (resid)
708 *resid = size;
710 return (0);
714 * Not implemented.
717 nfs_write(struct open_file *f, void *buf, size_t size, size_t *resid)
719 return (EROFS);
722 off_t
723 nfs_seek(struct open_file *f, off_t offset, int where)
725 struct nfs_iodesc *d = (struct nfs_iodesc *)f->f_fsdata;
726 uint32_t size = ntohl(d->fa.fa_size.val[1]);
728 switch (where) {
729 case SEEK_SET:
730 d->off = offset;
731 break;
732 case SEEK_CUR:
733 d->off += offset;
734 break;
735 case SEEK_END:
736 d->off = size - offset;
737 break;
738 default:
739 errno = EINVAL;
740 return (-1);
743 return (d->off);
746 /* NFNON=0, NFREG=1, NFDIR=2, NFBLK=3, NFCHR=4, NFLNK=5, NFSOCK=6, NFFIFO=7 */
747 int nfs_stat_types[9] = {
748 0, S_IFREG, S_IFDIR, S_IFBLK, S_IFCHR, S_IFLNK, S_IFSOCK, S_IFIFO, 0 };
751 nfs_stat(struct open_file *f, struct stat *sb)
753 struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
754 uint32_t ftype, mode;
756 ftype = ntohl(fp->fa.fa_type);
757 mode = ntohl(fp->fa.fa_mode);
758 mode |= nfs_stat_types[ftype & 7];
760 sb->st_mode = mode;
761 sb->st_nlink = ntohl(fp->fa.fa_nlink);
762 sb->st_uid = ntohl(fp->fa.fa_uid);
763 sb->st_gid = ntohl(fp->fa.fa_gid);
764 sb->st_size = ntohl(fp->fa.fa_size.val[1]);
766 return (0);
769 static int
770 nfs_readdir(struct open_file *f, struct dirent *d)
772 struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
773 struct nfsv3_readdir_repl *repl;
774 struct nfsv3_readdir_entry *rent;
775 static char *buf;
776 static struct nfs_iodesc *pfp = NULL;
777 static uint64_t cookie = 0;
778 size_t cc;
779 int pos;
781 struct args {
782 uint32_t fhsize;
783 uint32_t fhpluscookie[5 + NFS_V3MAXFHSIZE];
784 } *args;
785 struct {
786 uint32_t h[RPC_HEADER_WORDS];
787 struct args d;
788 } sdata;
789 static struct {
790 uint32_t h[RPC_HEADER_WORDS];
791 u_char d[NFS_READDIRSIZE];
792 } rdata;
794 if (fp != pfp || fp->off != cookie) {
795 pfp = NULL;
796 refill:
797 args = &sdata.d;
798 bzero(args, sizeof(*args));
800 args->fhsize = htonl(fp->fhsize);
801 bcopy(fp->fh, args->fhpluscookie, fp->fhsize);
802 pos = roundup(fp->fhsize, sizeof(uint32_t)) / sizeof(uint32_t);
803 args->fhpluscookie[pos++] = htonl(fp->off >> 32);
804 args->fhpluscookie[pos++] = htonl(fp->off);
805 args->fhpluscookie[pos++] = htonl(fp->cookie >> 32);
806 args->fhpluscookie[pos++] = htonl(fp->cookie);
807 args->fhpluscookie[pos] = htonl(NFS_READDIRSIZE);
809 cc = rpc_call(fp->iodesc, NFS_PROG, NFS_VER3, NFSPROCV3_READDIR,
810 args, 6 * sizeof(uint32_t) +
811 roundup(fp->fhsize, sizeof(uint32_t)),
812 rdata.d, sizeof(rdata.d));
813 buf = rdata.d;
814 repl = (struct nfsv3_readdir_repl *)buf;
815 if (repl->errno != 0)
816 return (ntohl(repl->errno));
817 pfp = fp;
818 cookie = fp->off;
819 fp->cookie = ((uint64_t)ntohl(repl->cookiev0) << 32) |
820 ntohl(repl->cookiev1);
821 buf += sizeof (struct nfsv3_readdir_repl);
823 rent = (struct nfsv3_readdir_entry *)buf;
825 if (rent->follows == 0) {
826 /* fid0 is actually eof */
827 if (rent->fid0 != 0) {
828 cookie = 0;
829 return (ENOENT);
831 goto refill;
834 d->d_namlen = ntohl(rent->len);
835 bcopy(rent->nameplus, d->d_name, d->d_namlen);
836 d->d_name[d->d_namlen] = '\0';
838 pos = roundup(d->d_namlen, sizeof(uint32_t)) / sizeof(uint32_t);
839 fp->off = cookie = ((uint64_t)ntohl(rent->nameplus[pos]) << 32) |
840 ntohl(rent->nameplus[pos + 1]);
841 pos += 2;
842 buf = (u_char *)&rent->nameplus[pos];
843 return (0);