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