xref: /dflybsd-src/stand/lib/nfs.c (revision 479ab7f0492f2a51b48e8537e4f1dc686fc6014b)
1*479ab7f0SSascha Wildner /* $FreeBSD: src/lib/libstand/nfs.c,v 1.2.6.3 2000/09/10 01:33:25 ps Exp $ */
2*479ab7f0SSascha Wildner /*	$NetBSD: nfs.c,v 1.2 1998/01/24 12:43:09 drochner Exp $	*/
3*479ab7f0SSascha Wildner 
4*479ab7f0SSascha Wildner /*-
5*479ab7f0SSascha Wildner  *  Copyright (c) 1993 John Brezak
6*479ab7f0SSascha Wildner  *  All rights reserved.
7*479ab7f0SSascha Wildner  *
8*479ab7f0SSascha Wildner  *  Redistribution and use in source and binary forms, with or without
9*479ab7f0SSascha Wildner  *  modification, are permitted provided that the following conditions
10*479ab7f0SSascha Wildner  *  are met:
11*479ab7f0SSascha Wildner  *  1. Redistributions of source code must retain the above copyright
12*479ab7f0SSascha Wildner  *     notice, this list of conditions and the following disclaimer.
13*479ab7f0SSascha Wildner  *  2. Redistributions in binary form must reproduce the above copyright
14*479ab7f0SSascha Wildner  *     notice, this list of conditions and the following disclaimer in the
15*479ab7f0SSascha Wildner  *     documentation and/or other materials provided with the distribution.
16*479ab7f0SSascha Wildner  *  3. The name of the author may not be used to endorse or promote products
17*479ab7f0SSascha Wildner  *     derived from this software without specific prior written permission.
18*479ab7f0SSascha Wildner  *
19*479ab7f0SSascha Wildner  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR
20*479ab7f0SSascha Wildner  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21*479ab7f0SSascha Wildner  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22*479ab7f0SSascha Wildner  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
23*479ab7f0SSascha Wildner  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24*479ab7f0SSascha Wildner  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25*479ab7f0SSascha Wildner  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26*479ab7f0SSascha Wildner  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
27*479ab7f0SSascha Wildner  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
28*479ab7f0SSascha Wildner  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29*479ab7f0SSascha Wildner  * POSSIBILITY OF SUCH DAMAGE.
30*479ab7f0SSascha Wildner  */
31*479ab7f0SSascha Wildner 
32*479ab7f0SSascha Wildner #include <sys/param.h>
33*479ab7f0SSascha Wildner #include <sys/time.h>
34*479ab7f0SSascha Wildner #include <sys/socket.h>
35*479ab7f0SSascha Wildner #include <sys/stat.h>
36*479ab7f0SSascha Wildner #include <string.h>
37*479ab7f0SSascha Wildner #include <stddef.h>
38*479ab7f0SSascha Wildner 
39*479ab7f0SSascha Wildner #include <netinet/in.h>
40*479ab7f0SSascha Wildner #include <netinet/in_systm.h>
41*479ab7f0SSascha Wildner 
42*479ab7f0SSascha Wildner #include "rpcv2.h"
43*479ab7f0SSascha Wildner #include "nfsv2.h"
44*479ab7f0SSascha Wildner 
45*479ab7f0SSascha Wildner #include "stand.h"
46*479ab7f0SSascha Wildner #include "net.h"
47*479ab7f0SSascha Wildner #include "netif.h"
48*479ab7f0SSascha Wildner #include "rpc.h"
49*479ab7f0SSascha Wildner 
50*479ab7f0SSascha Wildner #define NFS_DEBUGxx
51*479ab7f0SSascha Wildner 
52*479ab7f0SSascha Wildner /* Define our own NFS attributes without NQNFS stuff. */
53*479ab7f0SSascha Wildner struct nfsv2_fattrs {
54*479ab7f0SSascha Wildner 	n_long	fa_type;
55*479ab7f0SSascha Wildner 	n_long	fa_mode;
56*479ab7f0SSascha Wildner 	n_long	fa_nlink;
57*479ab7f0SSascha Wildner 	n_long	fa_uid;
58*479ab7f0SSascha Wildner 	n_long	fa_gid;
59*479ab7f0SSascha Wildner 	n_long	fa_size;
60*479ab7f0SSascha Wildner 	n_long	fa_blocksize;
61*479ab7f0SSascha Wildner 	n_long	fa_rdev;
62*479ab7f0SSascha Wildner 	n_long	fa_blocks;
63*479ab7f0SSascha Wildner 	n_long	fa_fsid;
64*479ab7f0SSascha Wildner 	n_long	fa_fileid;
65*479ab7f0SSascha Wildner 	struct nfsv2_time fa_atime;
66*479ab7f0SSascha Wildner 	struct nfsv2_time fa_mtime;
67*479ab7f0SSascha Wildner 	struct nfsv2_time fa_ctime;
68*479ab7f0SSascha Wildner };
69*479ab7f0SSascha Wildner 
70*479ab7f0SSascha Wildner 
71*479ab7f0SSascha Wildner struct nfs_read_args {
72*479ab7f0SSascha Wildner 	u_char	fh[NFS_FHSIZE];
73*479ab7f0SSascha Wildner 	n_long	off;
74*479ab7f0SSascha Wildner 	n_long	len;
75*479ab7f0SSascha Wildner 	n_long	xxx;			/* XXX what's this for? */
76*479ab7f0SSascha Wildner };
77*479ab7f0SSascha Wildner 
78*479ab7f0SSascha Wildner /*
79*479ab7f0SSascha Wildner  * Data part of nfs rpc reply (also the largest thing we receive).
80*479ab7f0SSascha Wildner  * Worry about the size of the structure declared on the stack.
81*479ab7f0SSascha Wildner  */
82*479ab7f0SSascha Wildner 
83*479ab7f0SSascha Wildner #define NFSREAD_MIN_SIZE 1024
84*479ab7f0SSascha Wildner #define NFSREAD_MAX_SIZE 4096
85*479ab7f0SSascha Wildner 
86*479ab7f0SSascha Wildner struct nfs_read_repl {
87*479ab7f0SSascha Wildner 	n_long	errno;
88*479ab7f0SSascha Wildner 	struct	nfsv2_fattrs fa;
89*479ab7f0SSascha Wildner 	n_long	count;
90*479ab7f0SSascha Wildner 	u_char	data[NFSREAD_MAX_SIZE];
91*479ab7f0SSascha Wildner };
92*479ab7f0SSascha Wildner 
93*479ab7f0SSascha Wildner #ifndef NFS_NOSYMLINK
94*479ab7f0SSascha Wildner struct nfs_readlnk_repl {
95*479ab7f0SSascha Wildner 	n_long	errno;
96*479ab7f0SSascha Wildner 	n_long	len;
97*479ab7f0SSascha Wildner 	char	path[NFS_MAXPATHLEN];
98*479ab7f0SSascha Wildner };
99*479ab7f0SSascha Wildner #endif
100*479ab7f0SSascha Wildner 
101*479ab7f0SSascha Wildner struct nfs_readdir_args {
102*479ab7f0SSascha Wildner 	u_char	fh[NFS_FHSIZE];
103*479ab7f0SSascha Wildner 	n_long	cookie;
104*479ab7f0SSascha Wildner 	n_long	count;
105*479ab7f0SSascha Wildner };
106*479ab7f0SSascha Wildner 
107*479ab7f0SSascha Wildner struct nfs_readdir_data {
108*479ab7f0SSascha Wildner 	n_long	fileid;
109*479ab7f0SSascha Wildner 	n_long	len;
110*479ab7f0SSascha Wildner 	char	name[0];
111*479ab7f0SSascha Wildner };
112*479ab7f0SSascha Wildner 
113*479ab7f0SSascha Wildner struct nfs_readdir_off {
114*479ab7f0SSascha Wildner 	n_long	cookie;
115*479ab7f0SSascha Wildner 	n_long	follows;
116*479ab7f0SSascha Wildner };
117*479ab7f0SSascha Wildner 
118*479ab7f0SSascha Wildner struct nfs_iodesc {
119*479ab7f0SSascha Wildner 	struct	iodesc	*iodesc;
120*479ab7f0SSascha Wildner 	off_t	off;
121*479ab7f0SSascha Wildner 	u_char	fh[NFS_FHSIZE];
122*479ab7f0SSascha Wildner 	struct nfsv2_fattrs fa;	/* all in network order */
123*479ab7f0SSascha Wildner };
124*479ab7f0SSascha Wildner 
125*479ab7f0SSascha Wildner /*
126*479ab7f0SSascha Wildner  * XXX interactions with tftp? See nfswrapper.c for a confusing
127*479ab7f0SSascha Wildner  *     issue.
128*479ab7f0SSascha Wildner  */
129*479ab7f0SSascha Wildner int		nfs_open(const char *path, struct open_file *f);
130*479ab7f0SSascha Wildner static int	nfs_close(struct open_file *f);
131*479ab7f0SSascha Wildner static int	nfs_read(struct open_file *f, void *buf, size_t size, size_t *resid);
132*479ab7f0SSascha Wildner static int	nfs_write(struct open_file *f, void *buf, size_t size, size_t *resid);
133*479ab7f0SSascha Wildner static off_t	nfs_seek(struct open_file *f, off_t offset, int where);
134*479ab7f0SSascha Wildner static int	nfs_stat(struct open_file *f, struct stat *sb);
135*479ab7f0SSascha Wildner static int	nfs_readdir(struct open_file *f, struct dirent *d);
136*479ab7f0SSascha Wildner 
137*479ab7f0SSascha Wildner struct	nfs_iodesc nfs_root_node;
138*479ab7f0SSascha Wildner 
139*479ab7f0SSascha Wildner struct fs_ops nfs_fsops = {
140*479ab7f0SSascha Wildner 	"nfs",
141*479ab7f0SSascha Wildner 	nfs_open,
142*479ab7f0SSascha Wildner 	nfs_close,
143*479ab7f0SSascha Wildner 	nfs_read,
144*479ab7f0SSascha Wildner 	nfs_write,
145*479ab7f0SSascha Wildner 	nfs_seek,
146*479ab7f0SSascha Wildner 	nfs_stat,
147*479ab7f0SSascha Wildner 	nfs_readdir
148*479ab7f0SSascha Wildner };
149*479ab7f0SSascha Wildner 
150*479ab7f0SSascha Wildner static int nfs_read_size = NFSREAD_MIN_SIZE;
151*479ab7f0SSascha Wildner 
152*479ab7f0SSascha Wildner /*
153*479ab7f0SSascha Wildner  * Fetch the root file handle (call mount daemon)
154*479ab7f0SSascha Wildner  * Return zero or error number.
155*479ab7f0SSascha Wildner  */
156*479ab7f0SSascha Wildner int
nfs_getrootfh(struct iodesc * d,char * path,u_char * fhp)157*479ab7f0SSascha Wildner nfs_getrootfh(struct iodesc *d, char *path, u_char *fhp)
158*479ab7f0SSascha Wildner {
159*479ab7f0SSascha Wildner 	int len;
160*479ab7f0SSascha Wildner 	struct args {
161*479ab7f0SSascha Wildner 		n_long	len;
162*479ab7f0SSascha Wildner 		char	path[FNAME_SIZE];
163*479ab7f0SSascha Wildner 	} *args;
164*479ab7f0SSascha Wildner 	struct repl {
165*479ab7f0SSascha Wildner 		n_long	errno;
166*479ab7f0SSascha Wildner 		u_char	fh[NFS_FHSIZE];
167*479ab7f0SSascha Wildner 	} *repl;
168*479ab7f0SSascha Wildner 	struct {
169*479ab7f0SSascha Wildner 		n_long	h[RPC_HEADER_WORDS];
170*479ab7f0SSascha Wildner 		struct args d;
171*479ab7f0SSascha Wildner 	} sdata;
172*479ab7f0SSascha Wildner 	struct {
173*479ab7f0SSascha Wildner 		n_long	h[RPC_HEADER_WORDS];
174*479ab7f0SSascha Wildner 		struct repl d;
175*479ab7f0SSascha Wildner 	} rdata;
176*479ab7f0SSascha Wildner 	size_t cc;
177*479ab7f0SSascha Wildner 
178*479ab7f0SSascha Wildner #ifdef NFS_DEBUG
179*479ab7f0SSascha Wildner 	if (debug)
180*479ab7f0SSascha Wildner 		printf("nfs_getrootfh: %s\n", path);
181*479ab7f0SSascha Wildner #endif
182*479ab7f0SSascha Wildner 
183*479ab7f0SSascha Wildner 	args = &sdata.d;
184*479ab7f0SSascha Wildner 	repl = &rdata.d;
185*479ab7f0SSascha Wildner 
186*479ab7f0SSascha Wildner 	bzero(args, sizeof(*args));
187*479ab7f0SSascha Wildner 	len = strlen(path);
188*479ab7f0SSascha Wildner 	if (len > sizeof(args->path))
189*479ab7f0SSascha Wildner 		len = sizeof(args->path);
190*479ab7f0SSascha Wildner 	args->len = htonl(len);
191*479ab7f0SSascha Wildner 	bcopy(path, args->path, len);
192*479ab7f0SSascha Wildner 	len = 4 + roundup(len, 4);
193*479ab7f0SSascha Wildner 
194*479ab7f0SSascha Wildner 	cc = rpc_call(d, RPCPROG_MNT, RPCMNT_VER1, RPCMNT_MOUNT,
195*479ab7f0SSascha Wildner 	    args, len, repl, sizeof(*repl));
196*479ab7f0SSascha Wildner 	if (cc == -1) {
197*479ab7f0SSascha Wildner 		/* errno was set by rpc_call */
198*479ab7f0SSascha Wildner 		return (errno);
199*479ab7f0SSascha Wildner 	}
200*479ab7f0SSascha Wildner 	if (cc < 4)
201*479ab7f0SSascha Wildner 		return (EBADRPC);
202*479ab7f0SSascha Wildner 	if (repl->errno)
203*479ab7f0SSascha Wildner 		return (ntohl(repl->errno));
204*479ab7f0SSascha Wildner 	bcopy(repl->fh, fhp, sizeof(repl->fh));
205*479ab7f0SSascha Wildner 
206*479ab7f0SSascha Wildner 	/*
207*479ab7f0SSascha Wildner 	 * Improve boot performance over NFS
208*479ab7f0SSascha Wildner 	 */
209*479ab7f0SSascha Wildner 	if (getenv("nfs.read_size") != NULL)
210*479ab7f0SSascha Wildner 		nfs_read_size = strtol(getenv("nfs.read_size"), NULL, 0);
211*479ab7f0SSascha Wildner 	if (nfs_read_size < NFSREAD_MIN_SIZE)
212*479ab7f0SSascha Wildner 		nfs_read_size = NFSREAD_MIN_SIZE;
213*479ab7f0SSascha Wildner 	if (nfs_read_size > NFSREAD_MAX_SIZE)
214*479ab7f0SSascha Wildner 		nfs_read_size = NFSREAD_MAX_SIZE;
215*479ab7f0SSascha Wildner 
216*479ab7f0SSascha Wildner 	return (0);
217*479ab7f0SSascha Wildner }
218*479ab7f0SSascha Wildner 
219*479ab7f0SSascha Wildner /*
220*479ab7f0SSascha Wildner  * Lookup a file.  Store handle and attributes.
221*479ab7f0SSascha Wildner  * Return zero or error number.
222*479ab7f0SSascha Wildner  */
223*479ab7f0SSascha Wildner int
nfs_lookupfh(struct nfs_iodesc * d,const char * name,struct nfs_iodesc * newfd)224*479ab7f0SSascha Wildner nfs_lookupfh(struct nfs_iodesc *d, const char *name, struct nfs_iodesc *newfd)
225*479ab7f0SSascha Wildner {
226*479ab7f0SSascha Wildner 	int len, rlen;
227*479ab7f0SSascha Wildner 	struct args {
228*479ab7f0SSascha Wildner 		u_char	fh[NFS_FHSIZE];
229*479ab7f0SSascha Wildner 		n_long	len;
230*479ab7f0SSascha Wildner 		char	name[FNAME_SIZE];
231*479ab7f0SSascha Wildner 	} *args;
232*479ab7f0SSascha Wildner 	struct repl {
233*479ab7f0SSascha Wildner 		n_long	errno;
234*479ab7f0SSascha Wildner 		u_char	fh[NFS_FHSIZE];
235*479ab7f0SSascha Wildner 		struct	nfsv2_fattrs fa;
236*479ab7f0SSascha Wildner 	} *repl;
237*479ab7f0SSascha Wildner 	struct {
238*479ab7f0SSascha Wildner 		n_long	h[RPC_HEADER_WORDS];
239*479ab7f0SSascha Wildner 		struct args d;
240*479ab7f0SSascha Wildner 	} sdata;
241*479ab7f0SSascha Wildner 	struct {
242*479ab7f0SSascha Wildner 		n_long	h[RPC_HEADER_WORDS];
243*479ab7f0SSascha Wildner 		struct repl d;
244*479ab7f0SSascha Wildner 	} rdata;
245*479ab7f0SSascha Wildner 	ssize_t cc;
246*479ab7f0SSascha Wildner 
247*479ab7f0SSascha Wildner #ifdef NFS_DEBUG
248*479ab7f0SSascha Wildner 	if (debug)
249*479ab7f0SSascha Wildner 		printf("lookupfh: called\n");
250*479ab7f0SSascha Wildner #endif
251*479ab7f0SSascha Wildner 
252*479ab7f0SSascha Wildner 	args = &sdata.d;
253*479ab7f0SSascha Wildner 	repl = &rdata.d;
254*479ab7f0SSascha Wildner 
255*479ab7f0SSascha Wildner 	bzero(args, sizeof(*args));
256*479ab7f0SSascha Wildner 	bcopy(d->fh, args->fh, sizeof(args->fh));
257*479ab7f0SSascha Wildner 	len = strlen(name);
258*479ab7f0SSascha Wildner 	if (len > sizeof(args->name))
259*479ab7f0SSascha Wildner 		len = sizeof(args->name);
260*479ab7f0SSascha Wildner 	bcopy(name, args->name, len);
261*479ab7f0SSascha Wildner 	args->len = htonl(len);
262*479ab7f0SSascha Wildner 	len = 4 + roundup(len, 4);
263*479ab7f0SSascha Wildner 	len += NFS_FHSIZE;
264*479ab7f0SSascha Wildner 
265*479ab7f0SSascha Wildner 	rlen = sizeof(*repl);
266*479ab7f0SSascha Wildner 
267*479ab7f0SSascha Wildner 	cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER2, NFSPROC_LOOKUP,
268*479ab7f0SSascha Wildner 	    args, len, repl, rlen);
269*479ab7f0SSascha Wildner 	if (cc == -1)
270*479ab7f0SSascha Wildner 		return (errno);		/* XXX - from rpc_call */
271*479ab7f0SSascha Wildner 	if (cc < 4)
272*479ab7f0SSascha Wildner 		return (EIO);
273*479ab7f0SSascha Wildner 	if (repl->errno) {
274*479ab7f0SSascha Wildner 		/* saerrno.h now matches NFS error numbers. */
275*479ab7f0SSascha Wildner 		return (ntohl(repl->errno));
276*479ab7f0SSascha Wildner 	}
277*479ab7f0SSascha Wildner 	bcopy( repl->fh, &newfd->fh, sizeof(newfd->fh));
278*479ab7f0SSascha Wildner 	bcopy(&repl->fa, &newfd->fa, sizeof(newfd->fa));
279*479ab7f0SSascha Wildner 	return (0);
280*479ab7f0SSascha Wildner }
281*479ab7f0SSascha Wildner 
282*479ab7f0SSascha Wildner #ifndef NFS_NOSYMLINK
283*479ab7f0SSascha Wildner /*
284*479ab7f0SSascha Wildner  * Get the destination of a symbolic link.
285*479ab7f0SSascha Wildner  */
286*479ab7f0SSascha Wildner int
nfs_readlink(struct nfs_iodesc * d,char * buf)287*479ab7f0SSascha Wildner nfs_readlink(struct nfs_iodesc *d, char *buf)
288*479ab7f0SSascha Wildner {
289*479ab7f0SSascha Wildner 	struct {
290*479ab7f0SSascha Wildner 		n_long	h[RPC_HEADER_WORDS];
291*479ab7f0SSascha Wildner 		u_char fh[NFS_FHSIZE];
292*479ab7f0SSascha Wildner 	} sdata;
293*479ab7f0SSascha Wildner 	struct {
294*479ab7f0SSascha Wildner 		n_long	h[RPC_HEADER_WORDS];
295*479ab7f0SSascha Wildner 		struct nfs_readlnk_repl d;
296*479ab7f0SSascha Wildner 	} rdata;
297*479ab7f0SSascha Wildner 	ssize_t cc;
298*479ab7f0SSascha Wildner 
299*479ab7f0SSascha Wildner #ifdef NFS_DEBUG
300*479ab7f0SSascha Wildner 	if (debug)
301*479ab7f0SSascha Wildner 		printf("readlink: called\n");
302*479ab7f0SSascha Wildner #endif
303*479ab7f0SSascha Wildner 
304*479ab7f0SSascha Wildner 	bcopy(d->fh, sdata.fh, NFS_FHSIZE);
305*479ab7f0SSascha Wildner 	cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER2, NFSPROC_READLINK,
306*479ab7f0SSascha Wildner 		      sdata.fh, NFS_FHSIZE,
307*479ab7f0SSascha Wildner 		      &rdata.d, sizeof(rdata.d));
308*479ab7f0SSascha Wildner 	if (cc == -1)
309*479ab7f0SSascha Wildner 		return (errno);
310*479ab7f0SSascha Wildner 
311*479ab7f0SSascha Wildner 	if (cc < 4)
312*479ab7f0SSascha Wildner 		return (EIO);
313*479ab7f0SSascha Wildner 
314*479ab7f0SSascha Wildner 	if (rdata.d.errno)
315*479ab7f0SSascha Wildner 		return (ntohl(rdata.d.errno));
316*479ab7f0SSascha Wildner 
317*479ab7f0SSascha Wildner 	rdata.d.len = ntohl(rdata.d.len);
318*479ab7f0SSascha Wildner 	if (rdata.d.len > NFS_MAXPATHLEN)
319*479ab7f0SSascha Wildner 		return (ENAMETOOLONG);
320*479ab7f0SSascha Wildner 
321*479ab7f0SSascha Wildner 	bcopy(rdata.d.path, buf, rdata.d.len);
322*479ab7f0SSascha Wildner 	buf[rdata.d.len] = 0;
323*479ab7f0SSascha Wildner 	return (0);
324*479ab7f0SSascha Wildner }
325*479ab7f0SSascha Wildner #endif
326*479ab7f0SSascha Wildner 
327*479ab7f0SSascha Wildner /*
328*479ab7f0SSascha Wildner  * Read data from a file.
329*479ab7f0SSascha Wildner  * Return transfer count or -1 (and set errno)
330*479ab7f0SSascha Wildner  */
331*479ab7f0SSascha Wildner ssize_t
nfs_readdata(struct nfs_iodesc * d,off_t off,void * addr,size_t len)332*479ab7f0SSascha Wildner nfs_readdata(struct nfs_iodesc *d, off_t off, void *addr, size_t len)
333*479ab7f0SSascha Wildner {
334*479ab7f0SSascha Wildner 	struct nfs_read_args *args;
335*479ab7f0SSascha Wildner 	struct nfs_read_repl *repl;
336*479ab7f0SSascha Wildner 	struct {
337*479ab7f0SSascha Wildner 		n_long	h[RPC_HEADER_WORDS];
338*479ab7f0SSascha Wildner 		struct nfs_read_args d;
339*479ab7f0SSascha Wildner 	} sdata;
340*479ab7f0SSascha Wildner 	struct {
341*479ab7f0SSascha Wildner 		n_long	h[RPC_HEADER_WORDS];
342*479ab7f0SSascha Wildner 		struct nfs_read_repl d;
343*479ab7f0SSascha Wildner 	} rdata;
344*479ab7f0SSascha Wildner 	size_t cc;
345*479ab7f0SSascha Wildner 	long x;
346*479ab7f0SSascha Wildner 	int hlen, rlen;
347*479ab7f0SSascha Wildner 
348*479ab7f0SSascha Wildner 	args = &sdata.d;
349*479ab7f0SSascha Wildner 	repl = &rdata.d;
350*479ab7f0SSascha Wildner 
351*479ab7f0SSascha Wildner 	bcopy(d->fh, args->fh, NFS_FHSIZE);
352*479ab7f0SSascha Wildner 	args->off = htonl((n_long)off);
353*479ab7f0SSascha Wildner 	if (len > nfs_read_size)
354*479ab7f0SSascha Wildner 		len = nfs_read_size;
355*479ab7f0SSascha Wildner 	args->len = htonl((n_long)len);
356*479ab7f0SSascha Wildner 	args->xxx = htonl((n_long)0);
357*479ab7f0SSascha Wildner 	hlen = offsetof(struct nfs_read_repl, data[0]);
358*479ab7f0SSascha Wildner 
359*479ab7f0SSascha Wildner 	cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER2, NFSPROC_READ,
360*479ab7f0SSascha Wildner 	    args, sizeof(*args),
361*479ab7f0SSascha Wildner 	    repl, sizeof(*repl));
362*479ab7f0SSascha Wildner 	if (cc == -1) {
363*479ab7f0SSascha Wildner 		/* errno was already set by rpc_call */
364*479ab7f0SSascha Wildner 		return (-1);
365*479ab7f0SSascha Wildner 	}
366*479ab7f0SSascha Wildner 	if (cc < hlen) {
367*479ab7f0SSascha Wildner 		errno = EBADRPC;
368*479ab7f0SSascha Wildner 		return (-1);
369*479ab7f0SSascha Wildner 	}
370*479ab7f0SSascha Wildner 	if (repl->errno) {
371*479ab7f0SSascha Wildner 		errno = ntohl(repl->errno);
372*479ab7f0SSascha Wildner 		return (-1);
373*479ab7f0SSascha Wildner 	}
374*479ab7f0SSascha Wildner 	rlen = cc - hlen;
375*479ab7f0SSascha Wildner 	x = ntohl(repl->count);
376*479ab7f0SSascha Wildner 	if (rlen < x) {
377*479ab7f0SSascha Wildner 		printf("nfsread: short packet, %d < %ld\n", rlen, x);
378*479ab7f0SSascha Wildner 		errno = EBADRPC;
379*479ab7f0SSascha Wildner 		return(-1);
380*479ab7f0SSascha Wildner 	}
381*479ab7f0SSascha Wildner 	bcopy(repl->data, addr, x);
382*479ab7f0SSascha Wildner 	return (x);
383*479ab7f0SSascha Wildner }
384*479ab7f0SSascha Wildner 
385*479ab7f0SSascha Wildner /*
386*479ab7f0SSascha Wildner  * Open a file.
387*479ab7f0SSascha Wildner  * return zero or error number
388*479ab7f0SSascha Wildner  */
389*479ab7f0SSascha Wildner int
nfs_open(const char * upath,struct open_file * f)390*479ab7f0SSascha Wildner nfs_open(const char *upath, struct open_file *f)
391*479ab7f0SSascha Wildner {
392*479ab7f0SSascha Wildner 	struct iodesc *desc;
393*479ab7f0SSascha Wildner 	struct nfs_iodesc *currfd;
394*479ab7f0SSascha Wildner #ifndef NFS_NOSYMLINK
395*479ab7f0SSascha Wildner 	struct nfs_iodesc *newfd;
396*479ab7f0SSascha Wildner 	struct nfsv2_fattrs *fa;
397*479ab7f0SSascha Wildner 	char *cp, *ncp;
398*479ab7f0SSascha Wildner 	int c;
399*479ab7f0SSascha Wildner 	char namebuf[NFS_MAXPATHLEN + 1];
400*479ab7f0SSascha Wildner 	char linkbuf[NFS_MAXPATHLEN + 1];
401*479ab7f0SSascha Wildner 	int nlinks = 0;
402*479ab7f0SSascha Wildner #endif
403*479ab7f0SSascha Wildner 	int error;
404*479ab7f0SSascha Wildner 	char *path;
405*479ab7f0SSascha Wildner 
406*479ab7f0SSascha Wildner #ifdef NFS_DEBUG
407*479ab7f0SSascha Wildner  	if (debug)
408*479ab7f0SSascha Wildner  	    printf("nfs_open: %s (rootpath=%s)\n", path, rootpath);
409*479ab7f0SSascha Wildner #endif
410*479ab7f0SSascha Wildner 	if (!rootpath[0]) {
411*479ab7f0SSascha Wildner 		printf("no rootpath, no nfs\n");
412*479ab7f0SSascha Wildner 		return (ENXIO);
413*479ab7f0SSascha Wildner 	}
414*479ab7f0SSascha Wildner 
415*479ab7f0SSascha Wildner 	/* Avoid trying out nfs_open for disk devices in the EFI loader */
416*479ab7f0SSascha Wildner #ifndef __i386__
417*479ab7f0SSascha Wildner 	if (strcmp(f->f_dev->dv_name, "net") != 0)
418*479ab7f0SSascha Wildner 		return (EINVAL);
419*479ab7f0SSascha Wildner #endif
420*479ab7f0SSascha Wildner 
421*479ab7f0SSascha Wildner 	if (!(desc = socktodesc(*(int *)(f->f_devdata))))
422*479ab7f0SSascha Wildner 		return(EINVAL);
423*479ab7f0SSascha Wildner 
424*479ab7f0SSascha Wildner 	/* Bind to a reserved port. */
425*479ab7f0SSascha Wildner 	desc->myport = htons(rpc_newport());
426*479ab7f0SSascha Wildner 	desc->destip = rootip;
427*479ab7f0SSascha Wildner 	if ((error = nfs_getrootfh(desc, rootpath, nfs_root_node.fh)))
428*479ab7f0SSascha Wildner 		return (error);
429*479ab7f0SSascha Wildner 	nfs_root_node.iodesc = desc;
430*479ab7f0SSascha Wildner 
431*479ab7f0SSascha Wildner #ifndef NFS_NOSYMLINK
432*479ab7f0SSascha Wildner 	/* Fake up attributes for the root dir. */
433*479ab7f0SSascha Wildner 	fa = &nfs_root_node.fa;
434*479ab7f0SSascha Wildner 	fa->fa_type  = htonl(NFDIR);
435*479ab7f0SSascha Wildner 	fa->fa_mode  = htonl(0755);
436*479ab7f0SSascha Wildner 	fa->fa_nlink = htonl(2);
437*479ab7f0SSascha Wildner 
438*479ab7f0SSascha Wildner 	currfd = &nfs_root_node;
439*479ab7f0SSascha Wildner 	newfd = NULL;
440*479ab7f0SSascha Wildner 
441*479ab7f0SSascha Wildner 	cp = path = strdup(upath);
442*479ab7f0SSascha Wildner 	if (path == NULL) {
443*479ab7f0SSascha Wildner 	    error = ENOMEM;
444*479ab7f0SSascha Wildner 	    goto out;
445*479ab7f0SSascha Wildner 	}
446*479ab7f0SSascha Wildner 	while (*cp) {
447*479ab7f0SSascha Wildner 		/*
448*479ab7f0SSascha Wildner 		 * Remove extra separators
449*479ab7f0SSascha Wildner 		 */
450*479ab7f0SSascha Wildner 		while (*cp == '/')
451*479ab7f0SSascha Wildner 			cp++;
452*479ab7f0SSascha Wildner 
453*479ab7f0SSascha Wildner 		if (*cp == '\0')
454*479ab7f0SSascha Wildner 			break;
455*479ab7f0SSascha Wildner 		/*
456*479ab7f0SSascha Wildner 		 * Check that current node is a directory.
457*479ab7f0SSascha Wildner 		 */
458*479ab7f0SSascha Wildner 		if (currfd->fa.fa_type != htonl(NFDIR)) {
459*479ab7f0SSascha Wildner 			error = ENOTDIR;
460*479ab7f0SSascha Wildner 			goto out;
461*479ab7f0SSascha Wildner 		}
462*479ab7f0SSascha Wildner 
463*479ab7f0SSascha Wildner 		/* allocate file system specific data structure */
464*479ab7f0SSascha Wildner 		newfd = malloc(sizeof(*newfd));
465*479ab7f0SSascha Wildner 		newfd->iodesc = currfd->iodesc;
466*479ab7f0SSascha Wildner 		newfd->off = 0;
467*479ab7f0SSascha Wildner 
468*479ab7f0SSascha Wildner 		/*
469*479ab7f0SSascha Wildner 		 * Get next component of path name.
470*479ab7f0SSascha Wildner 		 */
471*479ab7f0SSascha Wildner 		{
472*479ab7f0SSascha Wildner 			int len = 0;
473*479ab7f0SSascha Wildner 
474*479ab7f0SSascha Wildner 			ncp = cp;
475*479ab7f0SSascha Wildner 			while ((c = *cp) != '\0' && c != '/') {
476*479ab7f0SSascha Wildner 				if (++len > NFS_MAXNAMLEN) {
477*479ab7f0SSascha Wildner 					error = ENOENT;
478*479ab7f0SSascha Wildner 					goto out;
479*479ab7f0SSascha Wildner 				}
480*479ab7f0SSascha Wildner 				cp++;
481*479ab7f0SSascha Wildner 			}
482*479ab7f0SSascha Wildner 			*cp = '\0';
483*479ab7f0SSascha Wildner 		}
484*479ab7f0SSascha Wildner 
485*479ab7f0SSascha Wildner 		/* lookup a file handle */
486*479ab7f0SSascha Wildner 		error = nfs_lookupfh(currfd, ncp, newfd);
487*479ab7f0SSascha Wildner 		*cp = c;
488*479ab7f0SSascha Wildner 		if (error)
489*479ab7f0SSascha Wildner 			goto out;
490*479ab7f0SSascha Wildner 
491*479ab7f0SSascha Wildner 		/*
492*479ab7f0SSascha Wildner 		 * Check for symbolic link
493*479ab7f0SSascha Wildner 		 */
494*479ab7f0SSascha Wildner 		if (newfd->fa.fa_type == htonl(NFLNK)) {
495*479ab7f0SSascha Wildner 			int link_len, len;
496*479ab7f0SSascha Wildner 
497*479ab7f0SSascha Wildner 			error = nfs_readlink(newfd, linkbuf);
498*479ab7f0SSascha Wildner 			if (error)
499*479ab7f0SSascha Wildner 				goto out;
500*479ab7f0SSascha Wildner 
501*479ab7f0SSascha Wildner 			link_len = strlen(linkbuf);
502*479ab7f0SSascha Wildner 			len = strlen(cp);
503*479ab7f0SSascha Wildner 
504*479ab7f0SSascha Wildner 			if (link_len + len > MAXPATHLEN
505*479ab7f0SSascha Wildner 			    || ++nlinks > MAXSYMLINKS) {
506*479ab7f0SSascha Wildner 				error = ENOENT;
507*479ab7f0SSascha Wildner 				goto out;
508*479ab7f0SSascha Wildner 			}
509*479ab7f0SSascha Wildner 
510*479ab7f0SSascha Wildner 			bcopy(cp, &namebuf[link_len], len + 1);
511*479ab7f0SSascha Wildner 			bcopy(linkbuf, namebuf, link_len);
512*479ab7f0SSascha Wildner 
513*479ab7f0SSascha Wildner 			/*
514*479ab7f0SSascha Wildner 			 * If absolute pathname, restart at root.
515*479ab7f0SSascha Wildner 			 * If relative pathname, restart at parent directory.
516*479ab7f0SSascha Wildner 			 */
517*479ab7f0SSascha Wildner 			cp = namebuf;
518*479ab7f0SSascha Wildner 			if (*cp == '/') {
519*479ab7f0SSascha Wildner 				if (currfd != &nfs_root_node)
520*479ab7f0SSascha Wildner 					free(currfd);
521*479ab7f0SSascha Wildner 				currfd = &nfs_root_node;
522*479ab7f0SSascha Wildner 			}
523*479ab7f0SSascha Wildner 
524*479ab7f0SSascha Wildner 			free(newfd);
525*479ab7f0SSascha Wildner 			newfd = NULL;
526*479ab7f0SSascha Wildner 
527*479ab7f0SSascha Wildner 			continue;
528*479ab7f0SSascha Wildner 		}
529*479ab7f0SSascha Wildner 
530*479ab7f0SSascha Wildner 		if (currfd != &nfs_root_node)
531*479ab7f0SSascha Wildner 			free(currfd);
532*479ab7f0SSascha Wildner 		currfd = newfd;
533*479ab7f0SSascha Wildner 		newfd = NULL;
534*479ab7f0SSascha Wildner 	}
535*479ab7f0SSascha Wildner 
536*479ab7f0SSascha Wildner 	error = 0;
537*479ab7f0SSascha Wildner 
538*479ab7f0SSascha Wildner out:
539*479ab7f0SSascha Wildner 	if (newfd)
540*479ab7f0SSascha Wildner 		free(newfd);
541*479ab7f0SSascha Wildner 	if (path)
542*479ab7f0SSascha Wildner 		free(path);
543*479ab7f0SSascha Wildner #else
544*479ab7f0SSascha Wildner         /* allocate file system specific data structure */
545*479ab7f0SSascha Wildner         currfd = malloc(sizeof(*currfd));
546*479ab7f0SSascha Wildner         currfd->iodesc = desc;
547*479ab7f0SSascha Wildner         currfd->off = 0;
548*479ab7f0SSascha Wildner 
549*479ab7f0SSascha Wildner         error = nfs_lookupfh(&nfs_root_node, upath, currfd);
550*479ab7f0SSascha Wildner #endif
551*479ab7f0SSascha Wildner 	if (!error) {
552*479ab7f0SSascha Wildner 		f->f_fsdata = (void *)currfd;
553*479ab7f0SSascha Wildner 		return (0);
554*479ab7f0SSascha Wildner 	}
555*479ab7f0SSascha Wildner 
556*479ab7f0SSascha Wildner #ifdef NFS_DEBUG
557*479ab7f0SSascha Wildner 	if (debug)
558*479ab7f0SSascha Wildner 		printf("nfs_open: %s lookupfh failed: %s\n",
559*479ab7f0SSascha Wildner 		    path, strerror(error));
560*479ab7f0SSascha Wildner #endif
561*479ab7f0SSascha Wildner #ifndef NFS_NOSYMLINK
562*479ab7f0SSascha Wildner 	if (currfd != &nfs_root_node)
563*479ab7f0SSascha Wildner #endif
564*479ab7f0SSascha Wildner 		free(currfd);
565*479ab7f0SSascha Wildner 
566*479ab7f0SSascha Wildner 	return (error);
567*479ab7f0SSascha Wildner }
568*479ab7f0SSascha Wildner 
569*479ab7f0SSascha Wildner int
nfs_close(struct open_file * f)570*479ab7f0SSascha Wildner nfs_close(struct open_file *f)
571*479ab7f0SSascha Wildner {
572*479ab7f0SSascha Wildner 	struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
573*479ab7f0SSascha Wildner 
574*479ab7f0SSascha Wildner #ifdef NFS_DEBUG
575*479ab7f0SSascha Wildner 	if (debug)
576*479ab7f0SSascha Wildner 		printf("nfs_close: fp=0x%lx\n", (u_long)fp);
577*479ab7f0SSascha Wildner #endif
578*479ab7f0SSascha Wildner 
579*479ab7f0SSascha Wildner 	f->f_fsdata = NULL;
580*479ab7f0SSascha Wildner 	if (fp && fp != &nfs_root_node)
581*479ab7f0SSascha Wildner 		free(fp);
582*479ab7f0SSascha Wildner 
583*479ab7f0SSascha Wildner 	return (0);
584*479ab7f0SSascha Wildner }
585*479ab7f0SSascha Wildner 
586*479ab7f0SSascha Wildner /*
587*479ab7f0SSascha Wildner  * read a portion of a file
588*479ab7f0SSascha Wildner  *
589*479ab7f0SSascha Wildner  * Parameters:
590*479ab7f0SSascha Wildner  *	resid:	out
591*479ab7f0SSascha Wildner  */
592*479ab7f0SSascha Wildner int
nfs_read(struct open_file * f,void * buf,size_t size,size_t * resid)593*479ab7f0SSascha Wildner nfs_read(struct open_file *f, void *buf, size_t size, size_t *resid)
594*479ab7f0SSascha Wildner {
595*479ab7f0SSascha Wildner 	struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
596*479ab7f0SSascha Wildner 	ssize_t cc;
597*479ab7f0SSascha Wildner 	static int tc;
598*479ab7f0SSascha Wildner 	char *addr = buf;
599*479ab7f0SSascha Wildner 
600*479ab7f0SSascha Wildner #ifdef NFS_DEBUG
601*479ab7f0SSascha Wildner 	if (debug)
602*479ab7f0SSascha Wildner 		printf("nfs_read: size=%lu off=%d\n", (u_long)size,
603*479ab7f0SSascha Wildner 		       (int)fp->off);
604*479ab7f0SSascha Wildner #endif
605*479ab7f0SSascha Wildner 	while ((int)size > 0) {
606*479ab7f0SSascha Wildner 		if (!(tc++ % 256))
607*479ab7f0SSascha Wildner 			twiddle();
608*479ab7f0SSascha Wildner 		cc = nfs_readdata(fp, fp->off, addr, size);
609*479ab7f0SSascha Wildner 		/* XXX maybe should retry on certain errors */
610*479ab7f0SSascha Wildner 		if (cc == -1) {
611*479ab7f0SSascha Wildner #ifdef NFS_DEBUG
612*479ab7f0SSascha Wildner 			if (debug)
613*479ab7f0SSascha Wildner 				printf("nfs_read: read: %s", strerror(errno));
614*479ab7f0SSascha Wildner #endif
615*479ab7f0SSascha Wildner 			return (errno);	/* XXX - from nfs_readdata */
616*479ab7f0SSascha Wildner 		}
617*479ab7f0SSascha Wildner 		if (cc == 0) {
618*479ab7f0SSascha Wildner #ifdef NFS_DEBUG
619*479ab7f0SSascha Wildner 			if (debug)
620*479ab7f0SSascha Wildner 				printf("nfs_read: hit EOF unexpectantly");
621*479ab7f0SSascha Wildner #endif
622*479ab7f0SSascha Wildner 			goto ret;
623*479ab7f0SSascha Wildner 		}
624*479ab7f0SSascha Wildner 		fp->off += cc;
625*479ab7f0SSascha Wildner 		addr += cc;
626*479ab7f0SSascha Wildner 		size -= cc;
627*479ab7f0SSascha Wildner 	}
628*479ab7f0SSascha Wildner ret:
629*479ab7f0SSascha Wildner 	if (resid)
630*479ab7f0SSascha Wildner 		*resid = size;
631*479ab7f0SSascha Wildner 
632*479ab7f0SSascha Wildner 	return (0);
633*479ab7f0SSascha Wildner }
634*479ab7f0SSascha Wildner 
635*479ab7f0SSascha Wildner /*
636*479ab7f0SSascha Wildner  * Not implemented.
637*479ab7f0SSascha Wildner  *
638*479ab7f0SSascha Wildner  * Parameters:
639*479ab7f0SSascha Wildner  *	resid:	out
640*479ab7f0SSascha Wildner  */
641*479ab7f0SSascha Wildner int
nfs_write(struct open_file * f,void * buf,size_t size,size_t * resid)642*479ab7f0SSascha Wildner nfs_write(struct open_file *f, void *buf, size_t size, size_t *resid)
643*479ab7f0SSascha Wildner {
644*479ab7f0SSascha Wildner 	return (EROFS);
645*479ab7f0SSascha Wildner }
646*479ab7f0SSascha Wildner 
647*479ab7f0SSascha Wildner off_t
nfs_seek(struct open_file * f,off_t offset,int where)648*479ab7f0SSascha Wildner nfs_seek(struct open_file *f, off_t offset, int where)
649*479ab7f0SSascha Wildner {
650*479ab7f0SSascha Wildner 	struct nfs_iodesc *d = (struct nfs_iodesc *)f->f_fsdata;
651*479ab7f0SSascha Wildner 	n_long size = ntohl(d->fa.fa_size);
652*479ab7f0SSascha Wildner 
653*479ab7f0SSascha Wildner 	switch (where) {
654*479ab7f0SSascha Wildner 	case SEEK_SET:
655*479ab7f0SSascha Wildner 		d->off = offset;
656*479ab7f0SSascha Wildner 		break;
657*479ab7f0SSascha Wildner 	case SEEK_CUR:
658*479ab7f0SSascha Wildner 		d->off += offset;
659*479ab7f0SSascha Wildner 		break;
660*479ab7f0SSascha Wildner 	case SEEK_END:
661*479ab7f0SSascha Wildner 		d->off = size - offset;
662*479ab7f0SSascha Wildner 		break;
663*479ab7f0SSascha Wildner 	default:
664*479ab7f0SSascha Wildner 		return (-1);
665*479ab7f0SSascha Wildner 	}
666*479ab7f0SSascha Wildner 
667*479ab7f0SSascha Wildner 	return (d->off);
668*479ab7f0SSascha Wildner }
669*479ab7f0SSascha Wildner 
670*479ab7f0SSascha Wildner /* NFNON=0, NFREG=1, NFDIR=2, NFBLK=3, NFCHR=4, NFLNK=5 */
671*479ab7f0SSascha Wildner int nfs_stat_types[8] = {
672*479ab7f0SSascha Wildner 	0, S_IFREG, S_IFDIR, S_IFBLK, S_IFCHR, S_IFLNK, 0 };
673*479ab7f0SSascha Wildner 
674*479ab7f0SSascha Wildner int
nfs_stat(struct open_file * f,struct stat * sb)675*479ab7f0SSascha Wildner nfs_stat(struct open_file *f, struct stat *sb)
676*479ab7f0SSascha Wildner {
677*479ab7f0SSascha Wildner 	struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
678*479ab7f0SSascha Wildner 	n_long ftype, mode;
679*479ab7f0SSascha Wildner 
680*479ab7f0SSascha Wildner 	ftype = ntohl(fp->fa.fa_type);
681*479ab7f0SSascha Wildner 	mode  = ntohl(fp->fa.fa_mode);
682*479ab7f0SSascha Wildner 	mode |= nfs_stat_types[ftype & 7];
683*479ab7f0SSascha Wildner 
684*479ab7f0SSascha Wildner 	sb->st_mode  = mode;
685*479ab7f0SSascha Wildner 	sb->st_nlink = ntohl(fp->fa.fa_nlink);
686*479ab7f0SSascha Wildner 	sb->st_uid   = ntohl(fp->fa.fa_uid);
687*479ab7f0SSascha Wildner 	sb->st_gid   = ntohl(fp->fa.fa_gid);
688*479ab7f0SSascha Wildner 	sb->st_size  = ntohl(fp->fa.fa_size);
689*479ab7f0SSascha Wildner 
690*479ab7f0SSascha Wildner 	return (0);
691*479ab7f0SSascha Wildner }
692*479ab7f0SSascha Wildner 
693*479ab7f0SSascha Wildner static int
nfs_readdir(struct open_file * f,struct dirent * d)694*479ab7f0SSascha Wildner nfs_readdir(struct open_file *f, struct dirent *d)
695*479ab7f0SSascha Wildner {
696*479ab7f0SSascha Wildner 	struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
697*479ab7f0SSascha Wildner 	struct nfs_readdir_args *args;
698*479ab7f0SSascha Wildner 	struct nfs_readdir_data *rd;
699*479ab7f0SSascha Wildner 	struct nfs_readdir_off  *roff = NULL;
700*479ab7f0SSascha Wildner 	static char *buf;
701*479ab7f0SSascha Wildner 	static n_long cookie = 0;
702*479ab7f0SSascha Wildner 	size_t cc;
703*479ab7f0SSascha Wildner 	n_long eof;
704*479ab7f0SSascha Wildner 
705*479ab7f0SSascha Wildner 	struct {
706*479ab7f0SSascha Wildner 		n_long h[RPC_HEADER_WORDS];
707*479ab7f0SSascha Wildner 		struct nfs_readdir_args d;
708*479ab7f0SSascha Wildner 	} sdata;
709*479ab7f0SSascha Wildner 	static struct {
710*479ab7f0SSascha Wildner 		n_long h[RPC_HEADER_WORDS];
711*479ab7f0SSascha Wildner 		u_char d[NFS_READDIRSIZE];
712*479ab7f0SSascha Wildner 	} rdata;
713*479ab7f0SSascha Wildner 
714*479ab7f0SSascha Wildner 	if (cookie == 0) {
715*479ab7f0SSascha Wildner 	refill:
716*479ab7f0SSascha Wildner 		args = &sdata.d;
717*479ab7f0SSascha Wildner 		bzero(args, sizeof(*args));
718*479ab7f0SSascha Wildner 
719*479ab7f0SSascha Wildner 		bcopy(fp->fh, args->fh, NFS_FHSIZE);
720*479ab7f0SSascha Wildner 		args->cookie = htonl(cookie);
721*479ab7f0SSascha Wildner 		args->count  = htonl(NFS_READDIRSIZE);
722*479ab7f0SSascha Wildner 
723*479ab7f0SSascha Wildner 		cc = rpc_call(fp->iodesc, NFS_PROG, NFS_VER2, NFSPROC_READDIR,
724*479ab7f0SSascha Wildner 			      args, sizeof(*args),
725*479ab7f0SSascha Wildner 			      rdata.d, sizeof(rdata.d));
726*479ab7f0SSascha Wildner 		buf  = rdata.d;
727*479ab7f0SSascha Wildner 		roff = (struct nfs_readdir_off *)buf;
728*479ab7f0SSascha Wildner 		if (ntohl(roff->cookie) != 0)
729*479ab7f0SSascha Wildner 			return 1;
730*479ab7f0SSascha Wildner 	}
731*479ab7f0SSascha Wildner 	roff = (struct nfs_readdir_off *)buf;
732*479ab7f0SSascha Wildner 
733*479ab7f0SSascha Wildner 	if (ntohl(roff->follows) == 0) {
734*479ab7f0SSascha Wildner 		eof = ntohl((roff+1)->cookie);
735*479ab7f0SSascha Wildner 		if (eof) {
736*479ab7f0SSascha Wildner 			cookie = 0;
737*479ab7f0SSascha Wildner 			return 1;
738*479ab7f0SSascha Wildner 		}
739*479ab7f0SSascha Wildner 		goto refill;
740*479ab7f0SSascha Wildner 	}
741*479ab7f0SSascha Wildner 
742*479ab7f0SSascha Wildner 	buf += sizeof(struct nfs_readdir_off);
743*479ab7f0SSascha Wildner 	rd = (struct nfs_readdir_data *)buf;
744*479ab7f0SSascha Wildner 	d->d_namlen = ntohl(rd->len);
745*479ab7f0SSascha Wildner 	bcopy(rd->name, d->d_name, d->d_namlen);
746*479ab7f0SSascha Wildner 	d->d_name[d->d_namlen] = '\0';
747*479ab7f0SSascha Wildner 
748*479ab7f0SSascha Wildner 	buf += (sizeof(struct nfs_readdir_data) + roundup(htonl(rd->len),4));
749*479ab7f0SSascha Wildner 	roff = (struct nfs_readdir_off *)buf;
750*479ab7f0SSascha Wildner 	cookie = ntohl(roff->cookie);
751*479ab7f0SSascha Wildner 	return 0;
752*479ab7f0SSascha Wildner }
753