1 /*	$NetBSD: nfs.c,v 1.2 1998/01/24 12:43:09 drochner Exp $	*/
2 
3 /*-
4  *  Copyright (c) 1993 John Brezak
5  *  All rights reserved.
6  *
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.
17  *
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.
29  */
30 
31 #include <sys/cdefs.h>
32 __FBSDID("$FreeBSD: stable/9/lib/libstand/nfs.c 252701 2013-07-04 15:21:27Z mav $");
33 
34 #include <sys/param.h>
35 #include <sys/time.h>
36 #include <sys/socket.h>
37 #include <sys/stat.h>
38 #include <string.h>
39 
40 #include <netinet/in.h>
41 #include <netinet/in_systm.h>
42 
43 #include "rpcv2.h"
44 #include "nfsv2.h"
45 
46 #include "stand.h"
47 #include "net.h"
48 #include "netif.h"
49 #include "rpc.h"
50 
51 #define NFS_DEBUGxx
52 
53 #define NFSREAD_SIZE 1024
54 
55 /* Define our own NFS attributes without NQNFS stuff. */
56 #ifdef OLD_NFSV2
57 struct nfsv2_fattrs {
58 	n_long	fa_type;
59 	n_long	fa_mode;
60 	n_long	fa_nlink;
61 	n_long	fa_uid;
62 	n_long	fa_gid;
63 	n_long	fa_size;
64 	n_long	fa_blocksize;
65 	n_long	fa_rdev;
66 	n_long	fa_blocks;
67 	n_long	fa_fsid;
68 	n_long	fa_fileid;
69 	struct nfsv2_time fa_atime;
70 	struct nfsv2_time fa_mtime;
71 	struct nfsv2_time fa_ctime;
72 };
73 
74 struct nfs_read_args {
75 	u_char	fh[NFS_FHSIZE];
76 	n_long	off;
77 	n_long	len;
78 	n_long	xxx;			/* XXX what's this for? */
79 };
80 
81 /* Data part of nfs rpc reply (also the largest thing we receive) */
82 struct nfs_read_repl {
83 	n_long	errno;
84 	struct	nfsv2_fattrs fa;
85 	n_long	count;
86 	u_char	data[NFSREAD_SIZE];
87 };
88 
89 #ifndef NFS_NOSYMLINK
90 struct nfs_readlnk_repl {
91 	n_long	errno;
92 	n_long	len;
93 	char	path[NFS_MAXPATHLEN];
94 };
95 #endif
96 
97 struct nfs_readdir_args {
98 	u_char	fh[NFS_FHSIZE];
99 	n_long	cookie;
100 	n_long	count;
101 };
102 
103 struct nfs_readdir_data {
104 	n_long	fileid;
105 	n_long	len;
106 	char	name[0];
107 };
108 
109 struct nfs_readdir_off {
110 	n_long	cookie;
111 	n_long	follows;
112 };
113 
114 struct nfs_iodesc {
115 	struct	iodesc	*iodesc;
116 	off_t	off;
117 	u_char	fh[NFS_FHSIZE];
118 	struct nfsv2_fattrs fa;	/* all in network order */
119 };
120 #else	/* !OLD_NFSV2 */
121 
122 /* NFSv3 definitions */
123 #define	NFS_V3MAXFHSIZE		64
124 #define	NFS_VER3		3
125 #define	RPCMNT_VER3		3
126 #define	NFSPROCV3_LOOKUP	3
127 #define	NFSPROCV3_READLINK	5
128 #define	NFSPROCV3_READ		6
129 #define	NFSPROCV3_READDIR	16
130 
131 typedef struct {
132 	uint32_t val[2];
133 } n_quad;
134 
135 struct nfsv3_time {
136 	uint32_t nfs_sec;
137 	uint32_t nfs_nsec;
138 };
139 
140 struct nfsv3_fattrs {
141 	uint32_t fa_type;
142 	uint32_t fa_mode;
143 	uint32_t fa_nlink;
144 	uint32_t fa_uid;
145 	uint32_t fa_gid;
146 	n_quad fa_size;
147 	n_quad fa_used;
148 	n_quad fa_rdev;
149 	n_quad fa_fsid;
150 	n_quad fa_fileid;
151 	struct nfsv3_time fa_atime;
152 	struct nfsv3_time fa_mtime;
153 	struct nfsv3_time fa_ctime;
154 };
155 
156 /*
157  * For NFSv3, the file handle is variable in size, so most fixed sized
158  * structures for arguments won't work. For most cases, a structure
159  * that starts with any fixed size section is followed by an array
160  * that covers the maximum size required.
161  */
162 struct nfsv3_readdir_repl {
163 	uint32_t errno;
164 	uint32_t ok;
165 	struct nfsv3_fattrs fa;
166 	uint32_t cookiev0;
167 	uint32_t cookiev1;
168 };
169 
170 struct nfsv3_readdir_entry {
171 	uint32_t follows;
172 	uint32_t fid0;
173 	uint32_t fid1;
174 	uint32_t len;
175 	uint32_t nameplus[0];
176 };
177 
178 struct nfs_iodesc {
179 	struct iodesc *iodesc;
180 	off_t off;
181 	uint32_t fhsize;
182 	u_char fh[NFS_V3MAXFHSIZE];
183 	struct nfsv3_fattrs fa;	/* all in network order */
184 	uint64_t cookie;
185 };
186 #endif	/* OLD_NFSV2 */
187 
188 /*
189  * XXX interactions with tftp? See nfswrapper.c for a confusing
190  *     issue.
191  */
192 int		nfs_open(const char *path, struct open_file *f);
193 static int	nfs_close(struct open_file *f);
194 static int	nfs_read(struct open_file *f, void *buf, size_t size, size_t *resid);
195 static int	nfs_write(struct open_file *f, void *buf, size_t size, size_t *resid);
196 static off_t	nfs_seek(struct open_file *f, off_t offset, int where);
197 static int	nfs_stat(struct open_file *f, struct stat *sb);
198 static int	nfs_readdir(struct open_file *f, struct dirent *d);
199 
200 struct	nfs_iodesc nfs_root_node;
201 
202 struct fs_ops nfs_fsops = {
203 	"nfs",
204 	nfs_open,
205 	nfs_close,
206 	nfs_read,
207 	nfs_write,
208 	nfs_seek,
209 	nfs_stat,
210 	nfs_readdir
211 };
212 
213 #ifdef	OLD_NFSV2
214 /*
215  * Fetch the root file handle (call mount daemon)
216  * Return zero or error number.
217  */
218 int
nfs_getrootfh(struct iodesc * d,char * path,u_char * fhp)219 nfs_getrootfh(struct iodesc *d, char *path, u_char *fhp)
220 {
221 	int len;
222 	struct args {
223 		n_long	len;
224 		char	path[FNAME_SIZE];
225 	} *args;
226 	struct repl {
227 		n_long	errno;
228 		u_char	fh[NFS_FHSIZE];
229 	} *repl;
230 	struct {
231 		n_long	h[RPC_HEADER_WORDS];
232 		struct args d;
233 	} sdata;
234 	struct {
235 		n_long	h[RPC_HEADER_WORDS];
236 		struct repl d;
237 	} rdata;
238 	size_t cc;
239 
240 #ifdef NFS_DEBUG
241 	if (debug)
242 		printf("nfs_getrootfh: %s\n", path);
243 #endif
244 
245 	args = &sdata.d;
246 	repl = &rdata.d;
247 
248 	bzero(args, sizeof(*args));
249 	len = strlen(path);
250 	if (len > sizeof(args->path))
251 		len = sizeof(args->path);
252 	args->len = htonl(len);
253 	bcopy(path, args->path, len);
254 	len = 4 + roundup(len, 4);
255 
256 	cc = rpc_call(d, RPCPROG_MNT, RPCMNT_VER1, RPCMNT_MOUNT,
257 	    args, len, repl, sizeof(*repl));
258 	if (cc == -1) {
259 		/* errno was set by rpc_call */
260 		return (errno);
261 	}
262 	if (cc < 4)
263 		return (EBADRPC);
264 	if (repl->errno)
265 		return (ntohl(repl->errno));
266 	bcopy(repl->fh, fhp, sizeof(repl->fh));
267 	return (0);
268 }
269 
270 /*
271  * Lookup a file.  Store handle and attributes.
272  * Return zero or error number.
273  */
274 int
nfs_lookupfh(struct nfs_iodesc * d,const char * name,struct nfs_iodesc * newfd)275 nfs_lookupfh(struct nfs_iodesc *d, const char *name, struct nfs_iodesc *newfd)
276 {
277 	int len, rlen;
278 	struct args {
279 		u_char	fh[NFS_FHSIZE];
280 		n_long	len;
281 		char	name[FNAME_SIZE];
282 	} *args;
283 	struct repl {
284 		n_long	errno;
285 		u_char	fh[NFS_FHSIZE];
286 		struct	nfsv2_fattrs fa;
287 	} *repl;
288 	struct {
289 		n_long	h[RPC_HEADER_WORDS];
290 		struct args d;
291 	} sdata;
292 	struct {
293 		n_long	h[RPC_HEADER_WORDS];
294 		struct repl d;
295 	} rdata;
296 	ssize_t cc;
297 
298 #ifdef NFS_DEBUG
299 	if (debug)
300 		printf("lookupfh: called\n");
301 #endif
302 
303 	args = &sdata.d;
304 	repl = &rdata.d;
305 
306 	bzero(args, sizeof(*args));
307 	bcopy(d->fh, args->fh, sizeof(args->fh));
308 	len = strlen(name);
309 	if (len > sizeof(args->name))
310 		len = sizeof(args->name);
311 	bcopy(name, args->name, len);
312 	args->len = htonl(len);
313 	len = 4 + roundup(len, 4);
314 	len += NFS_FHSIZE;
315 
316 	rlen = sizeof(*repl);
317 
318 	cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER2, NFSPROC_LOOKUP,
319 	    args, len, repl, rlen);
320 	if (cc == -1)
321 		return (errno);		/* XXX - from rpc_call */
322 	if (cc < 4)
323 		return (EIO);
324 	if (repl->errno) {
325 		/* saerrno.h now matches NFS error numbers. */
326 		return (ntohl(repl->errno));
327 	}
328 	bcopy( repl->fh, &newfd->fh, sizeof(newfd->fh));
329 	bcopy(&repl->fa, &newfd->fa, sizeof(newfd->fa));
330 	return (0);
331 }
332 
333 #ifndef NFS_NOSYMLINK
334 /*
335  * Get the destination of a symbolic link.
336  */
337 int
nfs_readlink(struct nfs_iodesc * d,char * buf)338 nfs_readlink(struct nfs_iodesc *d, char *buf)
339 {
340 	struct {
341 		n_long	h[RPC_HEADER_WORDS];
342 		u_char fh[NFS_FHSIZE];
343 	} sdata;
344 	struct {
345 		n_long	h[RPC_HEADER_WORDS];
346 		struct nfs_readlnk_repl d;
347 	} rdata;
348 	ssize_t cc;
349 
350 #ifdef NFS_DEBUG
351 	if (debug)
352 		printf("readlink: called\n");
353 #endif
354 
355 	bcopy(d->fh, sdata.fh, NFS_FHSIZE);
356 	cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER2, NFSPROC_READLINK,
357 		      sdata.fh, NFS_FHSIZE,
358 		      &rdata.d, sizeof(rdata.d));
359 	if (cc == -1)
360 		return (errno);
361 
362 	if (cc < 4)
363 		return (EIO);
364 
365 	if (rdata.d.errno)
366 		return (ntohl(rdata.d.errno));
367 
368 	rdata.d.len = ntohl(rdata.d.len);
369 	if (rdata.d.len > NFS_MAXPATHLEN)
370 		return (ENAMETOOLONG);
371 
372 	bcopy(rdata.d.path, buf, rdata.d.len);
373 	buf[rdata.d.len] = 0;
374 	return (0);
375 }
376 #endif
377 
378 /*
379  * Read data from a file.
380  * Return transfer count or -1 (and set errno)
381  */
382 ssize_t
nfs_readdata(struct nfs_iodesc * d,off_t off,void * addr,size_t len)383 nfs_readdata(struct nfs_iodesc *d, off_t off, void *addr, size_t len)
384 {
385 	struct nfs_read_args *args;
386 	struct nfs_read_repl *repl;
387 	struct {
388 		n_long	h[RPC_HEADER_WORDS];
389 		struct nfs_read_args d;
390 	} sdata;
391 	struct {
392 		n_long	h[RPC_HEADER_WORDS];
393 		struct nfs_read_repl d;
394 	} rdata;
395 	size_t cc;
396 	long x;
397 	int hlen, rlen;
398 
399 	args = &sdata.d;
400 	repl = &rdata.d;
401 
402 	bcopy(d->fh, args->fh, NFS_FHSIZE);
403 	args->off = htonl((n_long)off);
404 	if (len > NFSREAD_SIZE)
405 		len = NFSREAD_SIZE;
406 	args->len = htonl((n_long)len);
407 	args->xxx = htonl((n_long)0);
408 	hlen = sizeof(*repl) - NFSREAD_SIZE;
409 
410 	cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER2, NFSPROC_READ,
411 	    args, sizeof(*args),
412 	    repl, sizeof(*repl));
413 	if (cc == -1) {
414 		/* errno was already set by rpc_call */
415 		return (-1);
416 	}
417 	if (cc < hlen) {
418 		errno = EBADRPC;
419 		return (-1);
420 	}
421 	if (repl->errno) {
422 		errno = ntohl(repl->errno);
423 		return (-1);
424 	}
425 	rlen = cc - hlen;
426 	x = ntohl(repl->count);
427 	if (rlen < x) {
428 		printf("nfsread: short packet, %d < %ld\n", rlen, x);
429 		errno = EBADRPC;
430 		return(-1);
431 	}
432 	bcopy(repl->data, addr, x);
433 	return (x);
434 }
435 
436 /*
437  * Open a file.
438  * return zero or error number
439  */
440 int
nfs_open(const char * upath,struct open_file * f)441 nfs_open(const char *upath, struct open_file *f)
442 {
443 	struct iodesc *desc;
444 	struct nfs_iodesc *currfd;
445 	char buf[2 * NFS_FHSIZE + 3];
446 	u_char *fh;
447 	char *cp;
448 	int i;
449 #ifndef NFS_NOSYMLINK
450 	struct nfs_iodesc *newfd;
451 	struct nfsv2_fattrs *fa;
452 	char *ncp;
453 	int c;
454 	char namebuf[NFS_MAXPATHLEN + 1];
455 	char linkbuf[NFS_MAXPATHLEN + 1];
456 	int nlinks = 0;
457 #endif
458 	int error;
459 	char *path;
460 
461 #ifdef NFS_DEBUG
462  	if (debug)
463  	    printf("nfs_open: %s (rootpath=%s)\n", upath, rootpath);
464 #endif
465 	if (!rootpath[0]) {
466 		printf("no rootpath, no nfs\n");
467 		return (ENXIO);
468 	}
469 
470 	/*
471 	 * This is silly - we should look at dv_type but that value is
472 	 * arch dependant and we can't use it here.
473 	 */
474 #ifndef __i386__
475 	if (strcmp(f->f_dev->dv_name, "net") != 0)
476 		return(EINVAL);
477 #else
478 	if (strcmp(f->f_dev->dv_name, "pxe") != 0)
479 		return(EINVAL);
480 #endif
481 
482 	if (!(desc = socktodesc(*(int *)(f->f_devdata))))
483 		return(EINVAL);
484 
485 	/* Bind to a reserved port. */
486 	desc->myport = htons(--rpc_port);
487 	desc->destip = rootip;
488 	if ((error = nfs_getrootfh(desc, rootpath, nfs_root_node.fh)))
489 		return (error);
490 	nfs_root_node.fa.fa_type  = htonl(NFDIR);
491 	nfs_root_node.fa.fa_mode  = htonl(0755);
492 	nfs_root_node.fa.fa_nlink = htonl(2);
493 	nfs_root_node.iodesc = desc;
494 
495 	fh = &nfs_root_node.fh[0];
496 	buf[0] = 'X';
497 	cp = &buf[1];
498 	for (i = 0; i < NFS_FHSIZE; i++, cp += 2)
499 		sprintf(cp, "%02x", fh[i]);
500 	sprintf(cp, "X");
501 	setenv("boot.nfsroot.server", inet_ntoa(rootip), 1);
502 	setenv("boot.nfsroot.path", rootpath, 1);
503 	setenv("boot.nfsroot.nfshandle", buf, 1);
504 
505 	/* Allocate file system specific data structure */
506 	currfd = malloc(sizeof(*newfd));
507 	if (currfd == NULL) {
508 		error = ENOMEM;
509 		goto out;
510 	}
511 
512 #ifndef NFS_NOSYMLINK
513 	bcopy(&nfs_root_node, currfd, sizeof(*currfd));
514 	newfd = 0;
515 
516 	cp = path = strdup(upath);
517 	if (path == NULL) {
518 	    error = ENOMEM;
519 	    goto out;
520 	}
521 	while (*cp) {
522 		/*
523 		 * Remove extra separators
524 		 */
525 		while (*cp == '/')
526 			cp++;
527 
528 		if (*cp == '\0')
529 			break;
530 		/*
531 		 * Check that current node is a directory.
532 		 */
533 		if (currfd->fa.fa_type != htonl(NFDIR)) {
534 			error = ENOTDIR;
535 			goto out;
536 		}
537 
538 		/* allocate file system specific data structure */
539 		newfd = malloc(sizeof(*newfd));
540 		newfd->iodesc = currfd->iodesc;
541 
542 		/*
543 		 * Get next component of path name.
544 		 */
545 		{
546 			int len = 0;
547 
548 			ncp = cp;
549 			while ((c = *cp) != '\0' && c != '/') {
550 				if (++len > NFS_MAXNAMLEN) {
551 					error = ENOENT;
552 					goto out;
553 				}
554 				cp++;
555 			}
556 			*cp = '\0';
557 		}
558 
559 		/* lookup a file handle */
560 		error = nfs_lookupfh(currfd, ncp, newfd);
561 		*cp = c;
562 		if (error)
563 			goto out;
564 
565 		/*
566 		 * Check for symbolic link
567 		 */
568 		if (newfd->fa.fa_type == htonl(NFLNK)) {
569 			int link_len, len;
570 
571 			error = nfs_readlink(newfd, linkbuf);
572 			if (error)
573 				goto out;
574 
575 			link_len = strlen(linkbuf);
576 			len = strlen(cp);
577 
578 			if (link_len + len > MAXPATHLEN
579 			    || ++nlinks > MAXSYMLINKS) {
580 				error = ENOENT;
581 				goto out;
582 			}
583 
584 			bcopy(cp, &namebuf[link_len], len + 1);
585 			bcopy(linkbuf, namebuf, link_len);
586 
587 			/*
588 			 * If absolute pathname, restart at root.
589 			 * If relative pathname, restart at parent directory.
590 			 */
591 			cp = namebuf;
592 			if (*cp == '/')
593 				bcopy(&nfs_root_node, currfd, sizeof(*currfd));
594 
595 			free(newfd);
596 			newfd = 0;
597 
598 			continue;
599 		}
600 
601 		free(currfd);
602 		currfd = newfd;
603 		newfd = 0;
604 	}
605 
606 	error = 0;
607 
608 out:
609 	if (newfd)
610 		free(newfd);
611 	if (path)
612 		free(path);
613 #else
614         currfd->iodesc = desc;
615 
616         error = nfs_lookupfh(&nfs_root_node, upath, currfd);
617 #endif
618 	if (!error) {
619 		currfd->off = 0;
620 		f->f_fsdata = (void *)currfd;
621 		return (0);
622 	}
623 
624 #ifdef NFS_DEBUG
625 	if (debug)
626 		printf("nfs_open: %s lookupfh failed: %s\n",
627 		    path, strerror(error));
628 #endif
629 	free(currfd);
630 
631 	return (error);
632 }
633 
634 int
nfs_close(struct open_file * f)635 nfs_close(struct open_file *f)
636 {
637 	struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
638 
639 #ifdef NFS_DEBUG
640 	if (debug)
641 		printf("nfs_close: fp=0x%lx\n", (u_long)fp);
642 #endif
643 
644 	if (fp)
645 		free(fp);
646 	f->f_fsdata = (void *)0;
647 
648 	return (0);
649 }
650 
651 /*
652  * read a portion of a file
653  */
654 int
nfs_read(struct open_file * f,void * buf,size_t size,size_t * resid)655 nfs_read(struct open_file *f, void *buf, size_t size, size_t *resid)
656 {
657 	struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
658 	ssize_t cc;
659 	char *addr = buf;
660 
661 #ifdef NFS_DEBUG
662 	if (debug)
663 		printf("nfs_read: size=%lu off=%d\n", (u_long)size,
664 		       (int)fp->off);
665 #endif
666 	while ((int)size > 0) {
667 		twiddle();
668 		cc = nfs_readdata(fp, fp->off, (void *)addr, size);
669 		/* XXX maybe should retry on certain errors */
670 		if (cc == -1) {
671 #ifdef NFS_DEBUG
672 			if (debug)
673 				printf("nfs_read: read: %s", strerror(errno));
674 #endif
675 			return (errno);	/* XXX - from nfs_readdata */
676 		}
677 		if (cc == 0) {
678 #ifdef NFS_DEBUG
679 			if (debug)
680 				printf("nfs_read: hit EOF unexpectantly");
681 #endif
682 			goto ret;
683 		}
684 		fp->off += cc;
685 		addr += cc;
686 		size -= cc;
687 	}
688 ret:
689 	if (resid)
690 		*resid = size;
691 
692 	return (0);
693 }
694 
695 /*
696  * Not implemented.
697  */
698 int
nfs_write(struct open_file * f,void * buf,size_t size,size_t * resid)699 nfs_write(struct open_file *f, void *buf, size_t size, size_t *resid)
700 {
701 	return (EROFS);
702 }
703 
704 off_t
nfs_seek(struct open_file * f,off_t offset,int where)705 nfs_seek(struct open_file *f, off_t offset, int where)
706 {
707 	struct nfs_iodesc *d = (struct nfs_iodesc *)f->f_fsdata;
708 	n_long size = ntohl(d->fa.fa_size);
709 
710 	switch (where) {
711 	case SEEK_SET:
712 		d->off = offset;
713 		break;
714 	case SEEK_CUR:
715 		d->off += offset;
716 		break;
717 	case SEEK_END:
718 		d->off = size - offset;
719 		break;
720 	default:
721 		errno = EINVAL;
722 		return (-1);
723 	}
724 
725 	return (d->off);
726 }
727 
728 /* NFNON=0, NFREG=1, NFDIR=2, NFBLK=3, NFCHR=4, NFLNK=5 */
729 int nfs_stat_types[8] = {
730 	0, S_IFREG, S_IFDIR, S_IFBLK, S_IFCHR, S_IFLNK, 0 };
731 
732 int
nfs_stat(struct open_file * f,struct stat * sb)733 nfs_stat(struct open_file *f, struct stat *sb)
734 {
735 	struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
736 	n_long ftype, mode;
737 
738 	ftype = ntohl(fp->fa.fa_type);
739 	mode  = ntohl(fp->fa.fa_mode);
740 	mode |= nfs_stat_types[ftype & 7];
741 
742 	sb->st_mode  = mode;
743 	sb->st_nlink = ntohl(fp->fa.fa_nlink);
744 	sb->st_uid   = ntohl(fp->fa.fa_uid);
745 	sb->st_gid   = ntohl(fp->fa.fa_gid);
746 	sb->st_size  = ntohl(fp->fa.fa_size);
747 
748 	return (0);
749 }
750 
751 static int
nfs_readdir(struct open_file * f,struct dirent * d)752 nfs_readdir(struct open_file *f, struct dirent *d)
753 {
754 	struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
755 	struct nfs_readdir_args *args;
756 	struct nfs_readdir_data *rd;
757 	struct nfs_readdir_off  *roff = NULL;
758 	static char *buf;
759 	static struct nfs_iodesc *pfp = NULL;
760 	static n_long cookie = 0;
761 	size_t cc;
762 	n_long eof;
763 
764 	struct {
765 		n_long h[RPC_HEADER_WORDS];
766 		struct nfs_readdir_args d;
767 	} sdata;
768 	static struct {
769 		n_long h[RPC_HEADER_WORDS];
770 		u_char d[NFS_READDIRSIZE];
771 	} rdata;
772 
773 	if (fp != pfp || fp->off != cookie) {
774 		pfp = NULL;
775 	refill:
776 		args = &sdata.d;
777 		bzero(args, sizeof(*args));
778 
779 		bcopy(fp->fh, args->fh, NFS_FHSIZE);
780 		args->cookie = htonl(fp->off);
781 		args->count  = htonl(NFS_READDIRSIZE);
782 
783 		cc = rpc_call(fp->iodesc, NFS_PROG, NFS_VER2, NFSPROC_READDIR,
784 			      args, sizeof(*args),
785 			      rdata.d, sizeof(rdata.d));
786 		buf  = rdata.d;
787 		roff = (struct nfs_readdir_off *)buf;
788 		if (ntohl(roff->cookie) != 0)
789 			return EIO;
790 		pfp = fp;
791 		cookie = fp->off;
792 	}
793 	roff = (struct nfs_readdir_off *)buf;
794 
795 	if (ntohl(roff->follows) == 0) {
796 		eof = ntohl((roff+1)->cookie);
797 		if (eof) {
798 			cookie = 0;
799 			return ENOENT;
800 		}
801 		goto refill;
802 	}
803 
804 	buf += sizeof(struct nfs_readdir_off);
805 	rd = (struct nfs_readdir_data *)buf;
806 	d->d_namlen = ntohl(rd->len);
807 	bcopy(rd->name, d->d_name, d->d_namlen);
808 	d->d_name[d->d_namlen] = '\0';
809 
810 	buf += (sizeof(struct nfs_readdir_data) + roundup(htonl(rd->len),4));
811 	roff = (struct nfs_readdir_off *)buf;
812 	fp->off = cookie = ntohl(roff->cookie);
813 	return 0;
814 }
815 #else	/* !OLD_NFSV2 */
816 /*
817  * Fetch the root file handle (call mount daemon)
818  * Return zero or error number.
819  */
820 int
nfs_getrootfh(struct iodesc * d,char * path,uint32_t * fhlenp,u_char * fhp)821 nfs_getrootfh(struct iodesc *d, char *path, uint32_t *fhlenp, u_char *fhp)
822 {
823 	int len;
824 	struct args {
825 		uint32_t len;
826 		char path[FNAME_SIZE];
827 	} *args;
828 	struct repl {
829 		uint32_t errno;
830 		uint32_t fhsize;
831 		u_char fh[NFS_V3MAXFHSIZE];
832 		uint32_t authcnt;
833 		uint32_t auth[7];
834 	} *repl;
835 	struct {
836 		uint32_t h[RPC_HEADER_WORDS];
837 		struct args d;
838 	} sdata;
839 	struct {
840 		uint32_t h[RPC_HEADER_WORDS];
841 		struct repl d;
842 	} rdata;
843 	size_t cc;
844 
845 #ifdef NFS_DEBUG
846 	if (debug)
847 		printf("nfs_getrootfh: %s\n", path);
848 #endif
849 
850 	args = &sdata.d;
851 	repl = &rdata.d;
852 
853 	bzero(args, sizeof(*args));
854 	len = strlen(path);
855 	if (len > sizeof(args->path))
856 		len = sizeof(args->path);
857 	args->len = htonl(len);
858 	bcopy(path, args->path, len);
859 	len = sizeof(uint32_t) + roundup(len, sizeof(uint32_t));
860 
861 	cc = rpc_call(d, RPCPROG_MNT, RPCMNT_VER3, RPCMNT_MOUNT,
862 	    args, len, repl, sizeof(*repl));
863 	if (cc == -1)
864 		/* errno was set by rpc_call */
865 		return (errno);
866 	if (cc < 2 * sizeof (uint32_t))
867 		return (EBADRPC);
868 	if (repl->errno != 0)
869 		return (ntohl(repl->errno));
870 	*fhlenp = ntohl(repl->fhsize);
871 	bcopy(repl->fh, fhp, *fhlenp);
872 	return (0);
873 }
874 
875 /*
876  * Lookup a file.  Store handle and attributes.
877  * Return zero or error number.
878  */
879 int
nfs_lookupfh(struct nfs_iodesc * d,const char * name,struct nfs_iodesc * newfd)880 nfs_lookupfh(struct nfs_iodesc *d, const char *name, struct nfs_iodesc *newfd)
881 {
882 	int len, rlen, pos;
883 	struct args {
884 		uint32_t fhsize;
885 		uint32_t fhplusname[1 +
886 		    (NFS_V3MAXFHSIZE + FNAME_SIZE) / sizeof(uint32_t)];
887 	} *args;
888 	struct repl {
889 		uint32_t errno;
890 		uint32_t fhsize;
891 		uint32_t fhplusattr[(NFS_V3MAXFHSIZE +
892 		    2 * (sizeof(uint32_t) +
893 		    sizeof(struct nfsv3_fattrs))) / sizeof(uint32_t)];
894 	} *repl;
895 	struct {
896 		uint32_t h[RPC_HEADER_WORDS];
897 		struct args d;
898 	} sdata;
899 	struct {
900 		uint32_t h[RPC_HEADER_WORDS];
901 		struct repl d;
902 	} rdata;
903 	ssize_t cc;
904 
905 #ifdef NFS_DEBUG
906 	if (debug)
907 		printf("lookupfh: called\n");
908 #endif
909 
910 	args = &sdata.d;
911 	repl = &rdata.d;
912 
913 	bzero(args, sizeof(*args));
914 	args->fhsize = htonl(d->fhsize);
915 	bcopy(d->fh, args->fhplusname, d->fhsize);
916 	len = strlen(name);
917 	if (len > FNAME_SIZE)
918 		len = FNAME_SIZE;
919 	pos = roundup(d->fhsize, sizeof(uint32_t)) / sizeof(uint32_t);
920 	args->fhplusname[pos++] = htonl(len);
921 	bcopy(name, &args->fhplusname[pos], len);
922 	len = sizeof(uint32_t) + pos * sizeof(uint32_t) +
923 	    roundup(len, sizeof(uint32_t));
924 
925 	rlen = sizeof(*repl);
926 
927 	cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER3, NFSPROCV3_LOOKUP,
928 	    args, len, repl, rlen);
929 	if (cc == -1)
930 		return (errno);		/* XXX - from rpc_call */
931 	if (cc < 2 * sizeof(uint32_t))
932 		return (EIO);
933 	if (repl->errno != 0)
934 		/* saerrno.h now matches NFS error numbers. */
935 		return (ntohl(repl->errno));
936 	newfd->fhsize = ntohl(repl->fhsize);
937 	bcopy(repl->fhplusattr, &newfd->fh, newfd->fhsize);
938 	pos = roundup(newfd->fhsize, sizeof(uint32_t)) / sizeof(uint32_t);
939 	if (repl->fhplusattr[pos++] == 0)
940 		return (EIO);
941 	bcopy(&repl->fhplusattr[pos], &newfd->fa, sizeof(newfd->fa));
942 	return (0);
943 }
944 
945 #ifndef NFS_NOSYMLINK
946 /*
947  * Get the destination of a symbolic link.
948  */
949 int
nfs_readlink(struct nfs_iodesc * d,char * buf)950 nfs_readlink(struct nfs_iodesc *d, char *buf)
951 {
952 	struct args {
953 		uint32_t fhsize;
954 		u_char fh[NFS_V3MAXFHSIZE];
955 	} *args;
956 	struct repl {
957 		uint32_t errno;
958 		uint32_t ok;
959 		struct nfsv3_fattrs fa;
960 		uint32_t len;
961 		u_char path[NFS_MAXPATHLEN];
962 	} *repl;
963 	struct {
964 		uint32_t h[RPC_HEADER_WORDS];
965 		struct args d;
966 	} sdata;
967 	struct {
968 		uint32_t h[RPC_HEADER_WORDS];
969 		struct repl d;
970 	} rdata;
971 	ssize_t cc;
972 
973 #ifdef NFS_DEBUG
974 	if (debug)
975 		printf("readlink: called\n");
976 #endif
977 
978 	args = &sdata.d;
979 	repl = &rdata.d;
980 
981 	bzero(args, sizeof(*args));
982 	args->fhsize = htonl(d->fhsize);
983 	bcopy(d->fh, args->fh, d->fhsize);
984 	cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER3, NFSPROCV3_READLINK,
985 	    args, sizeof(uint32_t) + roundup(d->fhsize, sizeof(uint32_t)),
986 	    repl, sizeof(*repl));
987 	if (cc == -1)
988 		return (errno);
989 
990 	if (cc < 2 * sizeof(uint32_t))
991 		return (EIO);
992 
993 	if (repl->errno != 0)
994 		return (ntohl(repl->errno));
995 
996 	if (repl->ok == 0)
997 		return (EIO);
998 
999 	repl->len = ntohl(repl->len);
1000 	if (repl->len > NFS_MAXPATHLEN)
1001 		return (ENAMETOOLONG);
1002 
1003 	bcopy(repl->path, buf, repl->len);
1004 	buf[repl->len] = 0;
1005 	return (0);
1006 }
1007 #endif
1008 
1009 /*
1010  * Read data from a file.
1011  * Return transfer count or -1 (and set errno)
1012  */
1013 ssize_t
nfs_readdata(struct nfs_iodesc * d,off_t off,void * addr,size_t len)1014 nfs_readdata(struct nfs_iodesc *d, off_t off, void *addr, size_t len)
1015 {
1016 	struct args {
1017 		uint32_t fhsize;
1018 		uint32_t fhoffcnt[NFS_V3MAXFHSIZE / sizeof(uint32_t) + 3];
1019 	} *args;
1020 	struct repl {
1021 		uint32_t errno;
1022 		uint32_t ok;
1023 		struct nfsv3_fattrs fa;
1024 		uint32_t count;
1025 		uint32_t eof;
1026 		uint32_t len;
1027 		u_char data[NFSREAD_SIZE];
1028 	} *repl;
1029 	struct {
1030 		uint32_t h[RPC_HEADER_WORDS];
1031 		struct args d;
1032 	} sdata;
1033 	struct {
1034 		uint32_t h[RPC_HEADER_WORDS];
1035 		struct repl d;
1036 	} rdata;
1037 	size_t cc;
1038 	long x;
1039 	int hlen, rlen, pos;
1040 
1041 	args = &sdata.d;
1042 	repl = &rdata.d;
1043 
1044 	bzero(args, sizeof(*args));
1045 	args->fhsize = htonl(d->fhsize);
1046 	bcopy(d->fh, args->fhoffcnt, d->fhsize);
1047 	pos = roundup(d->fhsize, sizeof(uint32_t)) / sizeof(uint32_t);
1048 	args->fhoffcnt[pos++] = 0;
1049 	args->fhoffcnt[pos++] = htonl((uint32_t)off);
1050 	if (len > NFSREAD_SIZE)
1051 		len = NFSREAD_SIZE;
1052 	args->fhoffcnt[pos] = htonl((uint32_t)len);
1053 	hlen = sizeof(*repl) - NFSREAD_SIZE;
1054 
1055 	cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER3, NFSPROCV3_READ,
1056 	    args, 4 * sizeof(uint32_t) + roundup(d->fhsize, sizeof(uint32_t)),
1057 	    repl, sizeof(*repl));
1058 	if (cc == -1)
1059 		/* errno was already set by rpc_call */
1060 		return (-1);
1061 	if (cc < hlen) {
1062 		errno = EBADRPC;
1063 		return (-1);
1064 	}
1065 	if (repl->errno != 0) {
1066 		errno = ntohl(repl->errno);
1067 		return (-1);
1068 	}
1069 	rlen = cc - hlen;
1070 	x = ntohl(repl->count);
1071 	if (rlen < x) {
1072 		printf("nfsread: short packet, %d < %ld\n", rlen, x);
1073 		errno = EBADRPC;
1074 		return (-1);
1075 	}
1076 	bcopy(repl->data, addr, x);
1077 	return (x);
1078 }
1079 
1080 /*
1081  * Open a file.
1082  * return zero or error number
1083  */
1084 int
nfs_open(const char * upath,struct open_file * f)1085 nfs_open(const char *upath, struct open_file *f)
1086 {
1087 	struct iodesc *desc;
1088 	struct nfs_iodesc *currfd;
1089 	char buf[2 * NFS_V3MAXFHSIZE + 3];
1090 	u_char *fh;
1091 	char *cp;
1092 	int i;
1093 #ifndef NFS_NOSYMLINK
1094 	struct nfs_iodesc *newfd;
1095 	struct nfsv3_fattrs *fa;
1096 	char *ncp;
1097 	int c;
1098 	char namebuf[NFS_MAXPATHLEN + 1];
1099 	char linkbuf[NFS_MAXPATHLEN + 1];
1100 	int nlinks = 0;
1101 #endif
1102 	int error;
1103 	char *path;
1104 
1105 #ifdef NFS_DEBUG
1106  	if (debug)
1107  	    printf("nfs_open: %s (rootpath=%s)\n", upath, rootpath);
1108 #endif
1109 	if (!rootpath[0]) {
1110 		printf("no rootpath, no nfs\n");
1111 		return (ENXIO);
1112 	}
1113 
1114 	/*
1115 	 * This is silly - we should look at dv_type but that value is
1116 	 * arch dependant and we can't use it here.
1117 	 */
1118 #ifndef __i386__
1119 	if (strcmp(f->f_dev->dv_name, "net") != 0)
1120 		return (EINVAL);
1121 #else
1122 	if (strcmp(f->f_dev->dv_name, "pxe") != 0)
1123 		return (EINVAL);
1124 #endif
1125 
1126 	if (!(desc = socktodesc(*(int *)(f->f_devdata))))
1127 		return (EINVAL);
1128 
1129 	/* Bind to a reserved port. */
1130 	desc->myport = htons(--rpc_port);
1131 	desc->destip = rootip;
1132 	if ((error = nfs_getrootfh(desc, rootpath, &nfs_root_node.fhsize,
1133 	    nfs_root_node.fh)))
1134 		return (error);
1135 	nfs_root_node.fa.fa_type  = htonl(NFDIR);
1136 	nfs_root_node.fa.fa_mode  = htonl(0755);
1137 	nfs_root_node.fa.fa_nlink = htonl(2);
1138 	nfs_root_node.iodesc = desc;
1139 
1140 	fh = &nfs_root_node.fh[0];
1141 	buf[0] = 'X';
1142 	cp = &buf[1];
1143 	for (i = 0; i < nfs_root_node.fhsize; i++, cp += 2)
1144 		sprintf(cp, "%02x", fh[i]);
1145 	sprintf(cp, "X");
1146 	setenv("boot.nfsroot.server", inet_ntoa(rootip), 1);
1147 	setenv("boot.nfsroot.path", rootpath, 1);
1148 	setenv("boot.nfsroot.nfshandle", buf, 1);
1149 	sprintf(buf, "%d", nfs_root_node.fhsize);
1150 	setenv("boot.nfsroot.nfshandlelen", buf, 1);
1151 
1152 	/* Allocate file system specific data structure */
1153 	currfd = malloc(sizeof(*newfd));
1154 	if (currfd == NULL) {
1155 		error = ENOMEM;
1156 		goto out;
1157 	}
1158 #ifndef NFS_NOSYMLINK
1159 	bcopy(&nfs_root_node, currfd, sizeof(*currfd));
1160 	newfd = 0;
1161 
1162 	cp = path = strdup(upath);
1163 	if (path == NULL) {
1164 		error = ENOMEM;
1165 		goto out;
1166 	}
1167 	while (*cp) {
1168 		/*
1169 		 * Remove extra separators
1170 		 */
1171 		while (*cp == '/')
1172 			cp++;
1173 
1174 		if (*cp == '\0')
1175 			break;
1176 		/*
1177 		 * Check that current node is a directory.
1178 		 */
1179 		if (currfd->fa.fa_type != htonl(NFDIR)) {
1180 			error = ENOTDIR;
1181 			goto out;
1182 		}
1183 
1184 		/* allocate file system specific data structure */
1185 		newfd = malloc(sizeof(*newfd));
1186 		if (newfd == NULL) {
1187 			error = ENOMEM;
1188 			goto out;
1189 		}
1190 		newfd->iodesc = currfd->iodesc;
1191 
1192 		/*
1193 		 * Get next component of path name.
1194 		 */
1195 		{
1196 			int len = 0;
1197 
1198 			ncp = cp;
1199 			while ((c = *cp) != '\0' && c != '/') {
1200 				if (++len > NFS_MAXNAMLEN) {
1201 					error = ENOENT;
1202 					goto out;
1203 				}
1204 				cp++;
1205 			}
1206 			*cp = '\0';
1207 		}
1208 
1209 		/* lookup a file handle */
1210 		error = nfs_lookupfh(currfd, ncp, newfd);
1211 		*cp = c;
1212 		if (error)
1213 			goto out;
1214 
1215 		/*
1216 		 * Check for symbolic link
1217 		 */
1218 		if (newfd->fa.fa_type == htonl(NFLNK)) {
1219 			int link_len, len;
1220 
1221 			error = nfs_readlink(newfd, linkbuf);
1222 			if (error)
1223 				goto out;
1224 
1225 			link_len = strlen(linkbuf);
1226 			len = strlen(cp);
1227 
1228 			if (link_len + len > MAXPATHLEN
1229 			    || ++nlinks > MAXSYMLINKS) {
1230 				error = ENOENT;
1231 				goto out;
1232 			}
1233 
1234 			bcopy(cp, &namebuf[link_len], len + 1);
1235 			bcopy(linkbuf, namebuf, link_len);
1236 
1237 			/*
1238 			 * If absolute pathname, restart at root.
1239 			 * If relative pathname, restart at parent directory.
1240 			 */
1241 			cp = namebuf;
1242 			if (*cp == '/')
1243 				bcopy(&nfs_root_node, currfd, sizeof(*currfd));
1244 
1245 			free(newfd);
1246 			newfd = 0;
1247 
1248 			continue;
1249 		}
1250 
1251 		free(currfd);
1252 		currfd = newfd;
1253 		newfd = 0;
1254 	}
1255 
1256 	error = 0;
1257 
1258 out:
1259 	free(newfd);
1260 	free(path);
1261 #else
1262 	currfd->iodesc = desc;
1263 
1264 	error = nfs_lookupfh(&nfs_root_node, upath, currfd);
1265 #endif
1266 	if (!error) {
1267 		currfd->off = 0;
1268 		currfd->cookie = 0;
1269 		f->f_fsdata = (void *)currfd;
1270 		return (0);
1271 	}
1272 
1273 #ifdef NFS_DEBUG
1274 	if (debug)
1275 		printf("nfs_open: %s lookupfh failed: %s\n",
1276 		    path, strerror(error));
1277 #endif
1278 	free(currfd);
1279 
1280 	return (error);
1281 }
1282 
1283 int
nfs_close(struct open_file * f)1284 nfs_close(struct open_file *f)
1285 {
1286 	struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
1287 
1288 #ifdef NFS_DEBUG
1289 	if (debug)
1290 		printf("nfs_close: fp=0x%lx\n", (u_long)fp);
1291 #endif
1292 
1293 	if (fp)
1294 		free(fp);
1295 	f->f_fsdata = (void *)0;
1296 
1297 	return (0);
1298 }
1299 
1300 /*
1301  * read a portion of a file
1302  */
1303 int
nfs_read(struct open_file * f,void * buf,size_t size,size_t * resid)1304 nfs_read(struct open_file *f, void *buf, size_t size, size_t *resid)
1305 {
1306 	struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
1307 	ssize_t cc;
1308 	char *addr = buf;
1309 
1310 #ifdef NFS_DEBUG
1311 	if (debug)
1312 		printf("nfs_read: size=%lu off=%d\n", (u_long)size,
1313 		       (int)fp->off);
1314 #endif
1315 	while ((int)size > 0) {
1316 		twiddle();
1317 		cc = nfs_readdata(fp, fp->off, (void *)addr, size);
1318 		/* XXX maybe should retry on certain errors */
1319 		if (cc == -1) {
1320 #ifdef NFS_DEBUG
1321 			if (debug)
1322 				printf("nfs_read: read: %s", strerror(errno));
1323 #endif
1324 			return (errno);	/* XXX - from nfs_readdata */
1325 		}
1326 		if (cc == 0) {
1327 #ifdef NFS_DEBUG
1328 			if (debug)
1329 				printf("nfs_read: hit EOF unexpectantly");
1330 #endif
1331 			goto ret;
1332 		}
1333 		fp->off += cc;
1334 		addr += cc;
1335 		size -= cc;
1336 	}
1337 ret:
1338 	if (resid)
1339 		*resid = size;
1340 
1341 	return (0);
1342 }
1343 
1344 /*
1345  * Not implemented.
1346  */
1347 int
nfs_write(struct open_file * f,void * buf,size_t size,size_t * resid)1348 nfs_write(struct open_file *f, void *buf, size_t size, size_t *resid)
1349 {
1350 	return (EROFS);
1351 }
1352 
1353 off_t
nfs_seek(struct open_file * f,off_t offset,int where)1354 nfs_seek(struct open_file *f, off_t offset, int where)
1355 {
1356 	struct nfs_iodesc *d = (struct nfs_iodesc *)f->f_fsdata;
1357 	uint32_t size = ntohl(d->fa.fa_size.val[1]);
1358 
1359 	switch (where) {
1360 	case SEEK_SET:
1361 		d->off = offset;
1362 		break;
1363 	case SEEK_CUR:
1364 		d->off += offset;
1365 		break;
1366 	case SEEK_END:
1367 		d->off = size - offset;
1368 		break;
1369 	default:
1370 		errno = EINVAL;
1371 		return (-1);
1372 	}
1373 
1374 	return (d->off);
1375 }
1376 
1377 /* NFNON=0, NFREG=1, NFDIR=2, NFBLK=3, NFCHR=4, NFLNK=5, NFSOCK=6, NFFIFO=7 */
1378 int nfs_stat_types[9] = {
1379 	0, S_IFREG, S_IFDIR, S_IFBLK, S_IFCHR, S_IFLNK, S_IFSOCK, S_IFIFO, 0 };
1380 
1381 int
nfs_stat(struct open_file * f,struct stat * sb)1382 nfs_stat(struct open_file *f, struct stat *sb)
1383 {
1384 	struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
1385 	uint32_t ftype, mode;
1386 
1387 	ftype = ntohl(fp->fa.fa_type);
1388 	mode  = ntohl(fp->fa.fa_mode);
1389 	mode |= nfs_stat_types[ftype & 7];
1390 
1391 	sb->st_mode  = mode;
1392 	sb->st_nlink = ntohl(fp->fa.fa_nlink);
1393 	sb->st_uid   = ntohl(fp->fa.fa_uid);
1394 	sb->st_gid   = ntohl(fp->fa.fa_gid);
1395 	sb->st_size  = ntohl(fp->fa.fa_size.val[1]);
1396 
1397 	return (0);
1398 }
1399 
1400 static int
nfs_readdir(struct open_file * f,struct dirent * d)1401 nfs_readdir(struct open_file *f, struct dirent *d)
1402 {
1403 	struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
1404 	struct nfsv3_readdir_repl *repl;
1405 	struct nfsv3_readdir_entry *rent;
1406 	static char *buf;
1407 	static struct nfs_iodesc *pfp = NULL;
1408 	static uint64_t cookie = 0;
1409 	size_t cc;
1410 	int pos;
1411 
1412 	struct args {
1413 		uint32_t fhsize;
1414 		uint32_t fhpluscookie[5 + NFS_V3MAXFHSIZE];
1415 	} *args;
1416 	struct {
1417 		uint32_t h[RPC_HEADER_WORDS];
1418 		struct args d;
1419 	} sdata;
1420 	static struct {
1421 		uint32_t h[RPC_HEADER_WORDS];
1422 		u_char d[NFS_READDIRSIZE];
1423 	} rdata;
1424 
1425 	if (fp != pfp || fp->off != cookie) {
1426 		pfp = NULL;
1427 	refill:
1428 		args = &sdata.d;
1429 		bzero(args, sizeof(*args));
1430 
1431 		args->fhsize = htonl(fp->fhsize);
1432 		bcopy(fp->fh, args->fhpluscookie, fp->fhsize);
1433 		pos = roundup(fp->fhsize, sizeof(uint32_t)) / sizeof(uint32_t);
1434 		args->fhpluscookie[pos++] = htonl(fp->off >> 32);
1435 		args->fhpluscookie[pos++] = htonl(fp->off);
1436 		args->fhpluscookie[pos++] = htonl(fp->cookie >> 32);
1437 		args->fhpluscookie[pos++] = htonl(fp->cookie);
1438 		args->fhpluscookie[pos] = htonl(NFS_READDIRSIZE);
1439 
1440 		cc = rpc_call(fp->iodesc, NFS_PROG, NFS_VER3, NFSPROCV3_READDIR,
1441 		    args, 6 * sizeof(uint32_t) +
1442 		    roundup(fp->fhsize, sizeof(uint32_t)),
1443 		    rdata.d, sizeof(rdata.d));
1444 		buf  = rdata.d;
1445 		repl = (struct nfsv3_readdir_repl *)buf;
1446 		if (repl->errno != 0)
1447 			return (ntohl(repl->errno));
1448 		pfp = fp;
1449 		cookie = fp->off;
1450 		fp->cookie = ((uint64_t)ntohl(repl->cookiev0) << 32) |
1451 		    ntohl(repl->cookiev1);
1452 		buf += sizeof (struct nfsv3_readdir_repl);
1453 	}
1454 	rent = (struct nfsv3_readdir_entry *)buf;
1455 
1456 	if (rent->follows == 0) {
1457 		/* fid0 is actually eof */
1458 		if (rent->fid0 != 0) {
1459 			cookie = 0;
1460 			return (ENOENT);
1461 		}
1462 		goto refill;
1463 	}
1464 
1465 	d->d_namlen = ntohl(rent->len);
1466 	bcopy(rent->nameplus, d->d_name, d->d_namlen);
1467 	d->d_name[d->d_namlen] = '\0';
1468 
1469 	pos = roundup(d->d_namlen, sizeof(uint32_t)) / sizeof(uint32_t);
1470 	fp->off = cookie = ((uint64_t)ntohl(rent->nameplus[pos]) << 32) |
1471 	    ntohl(rent->nameplus[pos + 1]);
1472 	pos += 2;
1473 	buf = (u_char *)&rent->nameplus[pos];
1474 	return (0);
1475 }
1476 #endif	/* OLD_NFSV2 */
1477