xref: /openbsd/sys/lib/libsa/nfs.c (revision 599546b3)
1*599546b3Sderaadt /*	$OpenBSD: nfs.c,v 1.10 2003/08/11 06:23:09 deraadt Exp $	*/
279dbd5ceSniklas /*	$NetBSD: nfs.c,v 1.19 1996/10/13 02:29:04 christos Exp $	*/
3df930be7Sderaadt 
4df930be7Sderaadt /*-
5df930be7Sderaadt  *  Copyright (c) 1993 John Brezak
6df930be7Sderaadt  *  All rights reserved.
7df930be7Sderaadt  *
8df930be7Sderaadt  *  Redistribution and use in source and binary forms, with or without
9df930be7Sderaadt  *  modification, are permitted provided that the following conditions
10df930be7Sderaadt  *  are met:
11df930be7Sderaadt  *  1. Redistributions of source code must retain the above copyright
12df930be7Sderaadt  *     notice, this list of conditions and the following disclaimer.
13df930be7Sderaadt  *  2. Redistributions in binary form must reproduce the above copyright
14df930be7Sderaadt  *     notice, this list of conditions and the following disclaimer in the
15df930be7Sderaadt  *     documentation and/or other materials provided with the distribution.
16df930be7Sderaadt  *  3. The name of the author may not be used to endorse or promote products
17df930be7Sderaadt  *     derived from this software without specific prior written permission.
18df930be7Sderaadt  *
19df930be7Sderaadt  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR
20df930be7Sderaadt  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21df930be7Sderaadt  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22df930be7Sderaadt  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
23df930be7Sderaadt  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24df930be7Sderaadt  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25df930be7Sderaadt  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26df930be7Sderaadt  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
27df930be7Sderaadt  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
28df930be7Sderaadt  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29df930be7Sderaadt  * POSSIBILITY OF SUCH DAMAGE.
30df930be7Sderaadt  */
31df930be7Sderaadt 
32df930be7Sderaadt #include <sys/param.h>
33df930be7Sderaadt #include <sys/time.h>
34df930be7Sderaadt #include <sys/socket.h>
35df930be7Sderaadt #include <sys/stat.h>
36df930be7Sderaadt 
37df930be7Sderaadt #include <netinet/in.h>
38df930be7Sderaadt #include <netinet/in_systm.h>
39df930be7Sderaadt 
4079dbd5ceSniklas #include "rpcv2.h"
4179dbd5ceSniklas #include "nfsv2.h"
42df930be7Sderaadt 
43df930be7Sderaadt #include "stand.h"
44e76f679cSmickey #include "saerrno.h"
45df930be7Sderaadt #include "net.h"
46df930be7Sderaadt #include "netif.h"
47df930be7Sderaadt #include "nfs.h"
48df930be7Sderaadt #include "rpc.h"
49df930be7Sderaadt 
50df930be7Sderaadt /* Define our own NFS attributes without NQNFS stuff. */
51df930be7Sderaadt struct nfsv2_fattrs {
52df930be7Sderaadt 	n_long	fa_type;
53df930be7Sderaadt 	n_long	fa_mode;
54df930be7Sderaadt 	n_long	fa_nlink;
55df930be7Sderaadt 	n_long	fa_uid;
56df930be7Sderaadt 	n_long	fa_gid;
57df930be7Sderaadt 	n_long	fa_size;
58df930be7Sderaadt 	n_long	fa_blocksize;
59df930be7Sderaadt 	n_long	fa_rdev;
60df930be7Sderaadt 	n_long	fa_blocks;
61df930be7Sderaadt 	n_long	fa_fsid;
62df930be7Sderaadt 	n_long	fa_fileid;
63df930be7Sderaadt 	struct nfsv2_time fa_atime;
64df930be7Sderaadt 	struct nfsv2_time fa_mtime;
65df930be7Sderaadt 	struct nfsv2_time fa_ctime;
66df930be7Sderaadt };
67df930be7Sderaadt 
68df930be7Sderaadt 
69df930be7Sderaadt struct nfs_read_args {
70df930be7Sderaadt 	u_char	fh[NFS_FHSIZE];
71df930be7Sderaadt 	n_long	off;
72df930be7Sderaadt 	n_long	len;
73df930be7Sderaadt 	n_long	xxx;			/* XXX what's this for? */
74df930be7Sderaadt };
75df930be7Sderaadt 
76df930be7Sderaadt /* Data part of nfs rpc reply (also the largest thing we receive) */
77df930be7Sderaadt #define NFSREAD_SIZE 1024
78df930be7Sderaadt struct nfs_read_repl {
79df930be7Sderaadt 	n_long	errno;
80df930be7Sderaadt 	struct	nfsv2_fattrs fa;
81df930be7Sderaadt 	n_long	count;
82df930be7Sderaadt 	u_char	data[NFSREAD_SIZE];
83df930be7Sderaadt };
84df930be7Sderaadt 
8579dbd5ceSniklas struct nfs_readlnk_repl {
8679dbd5ceSniklas 	n_long	errno;
8779dbd5ceSniklas 	n_long	len;
8879dbd5ceSniklas 	char	path[NFS_MAXPATHLEN];
8979dbd5ceSniklas };
9079dbd5ceSniklas 
91df930be7Sderaadt struct nfs_iodesc {
92df930be7Sderaadt 	struct	iodesc	*iodesc;
93df930be7Sderaadt 	off_t	off;
94df930be7Sderaadt 	u_char	fh[NFS_FHSIZE];
95df930be7Sderaadt 	struct nfsv2_fattrs fa;	/* all in network order */
96df930be7Sderaadt };
97df930be7Sderaadt 
98df930be7Sderaadt struct nfs_iodesc nfs_root_node;
99df930be7Sderaadt 
100df930be7Sderaadt 
101df930be7Sderaadt /*
102df930be7Sderaadt  * Fetch the root file handle (call mount daemon)
103df930be7Sderaadt  * On error, return non-zero and set errno.
104df930be7Sderaadt  */
105*599546b3Sderaadt static int
106*599546b3Sderaadt nfs_getrootfh(struct iodesc *d, char *path, u_char *fhp)
107df930be7Sderaadt {
108*599546b3Sderaadt 	int len;
109df930be7Sderaadt 	struct args {
110df930be7Sderaadt 		n_long	len;
111df930be7Sderaadt 		char	path[FNAME_SIZE];
112df930be7Sderaadt 	} *args;
113df930be7Sderaadt 	struct repl {
114df930be7Sderaadt 		n_long	errno;
115df930be7Sderaadt 		u_char	fh[NFS_FHSIZE];
116df930be7Sderaadt 	} *repl;
117df930be7Sderaadt 	struct {
118df930be7Sderaadt 		n_long	h[RPC_HEADER_WORDS];
119df930be7Sderaadt 		struct args d;
120df930be7Sderaadt 	} sdata;
121df930be7Sderaadt 	struct {
122df930be7Sderaadt 		n_long	h[RPC_HEADER_WORDS];
123df930be7Sderaadt 		struct repl d;
124df930be7Sderaadt 	} rdata;
125df930be7Sderaadt 	size_t cc;
126df930be7Sderaadt 
127df930be7Sderaadt #ifdef NFS_DEBUG
128df930be7Sderaadt 	if (debug)
129df930be7Sderaadt 		printf("nfs_getrootfh: %s\n", path);
130df930be7Sderaadt #endif
131df930be7Sderaadt 
132df930be7Sderaadt 	args = &sdata.d;
133df930be7Sderaadt 	repl = &rdata.d;
134df930be7Sderaadt 
135df930be7Sderaadt 	bzero(args, sizeof(*args));
136df930be7Sderaadt 	len = strlen(path);
137df930be7Sderaadt 	if (len > sizeof(args->path))
138df930be7Sderaadt 		len = sizeof(args->path);
139df930be7Sderaadt 	args->len = htonl(len);
140df930be7Sderaadt 	bcopy(path, args->path, len);
141df930be7Sderaadt 	len = 4 + roundup(len, 4);
142df930be7Sderaadt 
143df930be7Sderaadt 	cc = rpc_call(d, RPCPROG_MNT, RPCMNT_VER1, RPCMNT_MOUNT,
144df930be7Sderaadt 	    args, len, repl, sizeof(*repl));
145df930be7Sderaadt 	if (cc == -1) {
146df930be7Sderaadt 		/* errno was set by rpc_call */
147df930be7Sderaadt 		return (-1);
148df930be7Sderaadt 	}
149df930be7Sderaadt 	if (cc < 4) {
150df930be7Sderaadt 		errno = EBADRPC;
151df930be7Sderaadt 		return (-1);
152df930be7Sderaadt 	}
153df930be7Sderaadt 	if (repl->errno) {
154df930be7Sderaadt 		errno = ntohl(repl->errno);
155df930be7Sderaadt 		return (-1);
156df930be7Sderaadt 	}
157df930be7Sderaadt 	bcopy(repl->fh, fhp, sizeof(repl->fh));
158df930be7Sderaadt 	return (0);
159df930be7Sderaadt }
160df930be7Sderaadt 
161df930be7Sderaadt /*
162df930be7Sderaadt  * Lookup a file.  Store handle and attributes.
163df930be7Sderaadt  * Return zero or error number.
164df930be7Sderaadt  */
165*599546b3Sderaadt static int
166*599546b3Sderaadt nfs_lookupfh(struct nfs_iodesc *d, char *name, struct nfs_iodesc *newfd)
167df930be7Sderaadt {
168*599546b3Sderaadt 	int len, rlen;
169df930be7Sderaadt 	struct args {
170df930be7Sderaadt 		u_char	fh[NFS_FHSIZE];
171df930be7Sderaadt 		n_long	len;
172df930be7Sderaadt 		char	name[FNAME_SIZE];
173df930be7Sderaadt 	} *args;
174df930be7Sderaadt 	struct repl {
175df930be7Sderaadt 		n_long	errno;
176df930be7Sderaadt 		u_char	fh[NFS_FHSIZE];
177df930be7Sderaadt 		struct	nfsv2_fattrs fa;
178df930be7Sderaadt 	} *repl;
179df930be7Sderaadt 	struct {
180df930be7Sderaadt 		n_long	h[RPC_HEADER_WORDS];
181df930be7Sderaadt 		struct args d;
182df930be7Sderaadt 	} sdata;
183df930be7Sderaadt 	struct {
184df930be7Sderaadt 		n_long	h[RPC_HEADER_WORDS];
185df930be7Sderaadt 		struct repl d;
186df930be7Sderaadt 	} rdata;
187df930be7Sderaadt 	ssize_t cc;
188df930be7Sderaadt 
189df930be7Sderaadt #ifdef NFS_DEBUG
190df930be7Sderaadt 	if (debug)
191df930be7Sderaadt 		printf("lookupfh: called\n");
192df930be7Sderaadt #endif
193df930be7Sderaadt 
194df930be7Sderaadt 	args = &sdata.d;
195df930be7Sderaadt 	repl = &rdata.d;
196df930be7Sderaadt 
197df930be7Sderaadt 	bzero(args, sizeof(*args));
198df930be7Sderaadt 	bcopy(d->fh, args->fh, sizeof(args->fh));
199df930be7Sderaadt 	len = strlen(name);
200df930be7Sderaadt 	if (len > sizeof(args->name))
201df930be7Sderaadt 		len = sizeof(args->name);
202df930be7Sderaadt 	bcopy(name, args->name, len);
203df930be7Sderaadt 	args->len = htonl(len);
204df930be7Sderaadt 	len = 4 + roundup(len, 4);
205df930be7Sderaadt 	len += NFS_FHSIZE;
206df930be7Sderaadt 
207df930be7Sderaadt 	rlen = sizeof(*repl);
208df930be7Sderaadt 
209df930be7Sderaadt 	cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER2, NFSPROC_LOOKUP,
210df930be7Sderaadt 	    args, len, repl, rlen);
211df930be7Sderaadt 	if (cc == -1)
212df930be7Sderaadt 		return (errno);		/* XXX - from rpc_call */
213df930be7Sderaadt 	if (cc < 4)
214df930be7Sderaadt 		return (EIO);
215df930be7Sderaadt 	if (repl->errno) {
216df930be7Sderaadt 		/* saerrno.h now matches NFS error numbers. */
217df930be7Sderaadt 		return (ntohl(repl->errno));
218df930be7Sderaadt 	}
219df930be7Sderaadt 	bcopy( repl->fh, &newfd->fh, sizeof(newfd->fh));
220df930be7Sderaadt 	bcopy(&repl->fa, &newfd->fa, sizeof(newfd->fa));
221df930be7Sderaadt 	return (0);
222df930be7Sderaadt }
223df930be7Sderaadt 
224df930be7Sderaadt /*
22579dbd5ceSniklas  * Get the destination of a symbolic link.
22679dbd5ceSniklas  */
227*599546b3Sderaadt static int
228*599546b3Sderaadt nfs_readlink(struct nfs_iodesc *d, char *buf)
22979dbd5ceSniklas {
23079dbd5ceSniklas 	struct {
23179dbd5ceSniklas 		n_long	h[RPC_HEADER_WORDS];
23279dbd5ceSniklas 		u_char fh[NFS_FHSIZE];
23379dbd5ceSniklas 	} sdata;
23479dbd5ceSniklas 	struct {
23579dbd5ceSniklas 		n_long	h[RPC_HEADER_WORDS];
23679dbd5ceSniklas 		struct nfs_readlnk_repl d;
23779dbd5ceSniklas 	} rdata;
23879dbd5ceSniklas 	ssize_t cc;
23979dbd5ceSniklas 
24079dbd5ceSniklas #ifdef NFS_DEBUG
24179dbd5ceSniklas 	if (debug)
24279dbd5ceSniklas 		printf("readlink: called\n");
24379dbd5ceSniklas #endif
24479dbd5ceSniklas 
24579dbd5ceSniklas 	bcopy(d->fh, sdata.fh, NFS_FHSIZE);
24679dbd5ceSniklas 	cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER2, NFSPROC_READLINK,
24779dbd5ceSniklas 	    sdata.fh, NFS_FHSIZE,
24879dbd5ceSniklas 	    &rdata.d, sizeof(rdata.d));
24979dbd5ceSniklas 	if (cc == -1)
25079dbd5ceSniklas 		return (errno);
25179dbd5ceSniklas 
25279dbd5ceSniklas 	if (cc < 4)
25379dbd5ceSniklas 		return (EIO);
25479dbd5ceSniklas 
25579dbd5ceSniklas 	if (rdata.d.errno)
25679dbd5ceSniklas 		return (ntohl(rdata.d.errno));
25779dbd5ceSniklas 
25879dbd5ceSniklas 	rdata.d.len = ntohl(rdata.d.len);
25979dbd5ceSniklas 	if (rdata.d.len > NFS_MAXPATHLEN)
26079dbd5ceSniklas 		return (ENAMETOOLONG);
26179dbd5ceSniklas 
26279dbd5ceSniklas 	bcopy(rdata.d.path, buf, rdata.d.len);
26379dbd5ceSniklas 	buf[rdata.d.len] = 0;
26479dbd5ceSniklas 	return (0);
26579dbd5ceSniklas }
26679dbd5ceSniklas 
26779dbd5ceSniklas /*
268df930be7Sderaadt  * Read data from a file.
269df930be7Sderaadt  * Return transfer count or -1 (and set errno)
270df930be7Sderaadt  */
271*599546b3Sderaadt static ssize_t
272*599546b3Sderaadt nfs_readdata(struct nfs_iodesc *d, off_t off, void *addr, size_t len)
273df930be7Sderaadt {
274df930be7Sderaadt 	struct nfs_read_args *args;
275df930be7Sderaadt 	struct nfs_read_repl *repl;
276df930be7Sderaadt 	struct {
277df930be7Sderaadt 		n_long	h[RPC_HEADER_WORDS];
278df930be7Sderaadt 		struct nfs_read_args d;
279df930be7Sderaadt 	} sdata;
280df930be7Sderaadt 	struct {
281df930be7Sderaadt 		n_long	h[RPC_HEADER_WORDS];
282df930be7Sderaadt 		struct nfs_read_repl d;
283df930be7Sderaadt 	} rdata;
284df930be7Sderaadt 	size_t cc;
285df930be7Sderaadt 	long x;
286df930be7Sderaadt 	int hlen, rlen;
287df930be7Sderaadt 
288df930be7Sderaadt 	args = &sdata.d;
289df930be7Sderaadt 	repl = &rdata.d;
290df930be7Sderaadt 
291df930be7Sderaadt 	bcopy(d->fh, args->fh, NFS_FHSIZE);
2920c0430f8Sniklas 	args->off = htonl((n_long)off);
293df930be7Sderaadt 	if (len > NFSREAD_SIZE)
294df930be7Sderaadt 		len = NFSREAD_SIZE;
2950c0430f8Sniklas 	args->len = htonl((n_long)len);
2960c0430f8Sniklas 	args->xxx = htonl((n_long)0);
297df930be7Sderaadt 	hlen = sizeof(*repl) - NFSREAD_SIZE;
298df930be7Sderaadt 
299df930be7Sderaadt 	cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER2, NFSPROC_READ,
300df930be7Sderaadt 	    args, sizeof(*args),
301df930be7Sderaadt 	    repl, sizeof(*repl));
302df930be7Sderaadt 	if (cc == -1) {
303df930be7Sderaadt 		/* errno was already set by rpc_call */
304df930be7Sderaadt 		return (-1);
305df930be7Sderaadt 	}
306df930be7Sderaadt 	if (cc < hlen) {
307df930be7Sderaadt 		errno = EBADRPC;
308df930be7Sderaadt 		return (-1);
309df930be7Sderaadt 	}
310df930be7Sderaadt 	if (repl->errno) {
311df930be7Sderaadt 		errno = ntohl(repl->errno);
312df930be7Sderaadt 		return (-1);
313df930be7Sderaadt 	}
314df930be7Sderaadt 	rlen = cc - hlen;
315df930be7Sderaadt 	x = ntohl(repl->count);
316df930be7Sderaadt 	if (rlen < x) {
317a4bb608eSderaadt 		printf("nfsread: short packet, %d < %ld\n", rlen, x);
318df930be7Sderaadt 		errno = EBADRPC;
319df930be7Sderaadt 		return(-1);
320df930be7Sderaadt 	}
321df930be7Sderaadt 	bcopy(repl->data, addr, x);
322df930be7Sderaadt 	return (x);
323df930be7Sderaadt }
324df930be7Sderaadt 
325df930be7Sderaadt /*
326df930be7Sderaadt  * nfs_mount - mount this nfs filesystem to a host
327df930be7Sderaadt  * On error, return non-zero and set errno.
328df930be7Sderaadt  */
329df930be7Sderaadt int
330*599546b3Sderaadt nfs_mount(int sock, struct in_addr ip, char *path)
331df930be7Sderaadt {
332df930be7Sderaadt 	struct iodesc *desc;
333df930be7Sderaadt 	struct nfsv2_fattrs *fa;
334df930be7Sderaadt 
335df930be7Sderaadt 	if (!(desc = socktodesc(sock))) {
336df930be7Sderaadt 		errno = EINVAL;
337df930be7Sderaadt 		return(-1);
338df930be7Sderaadt 	}
339df930be7Sderaadt 
340df930be7Sderaadt 	/* Bind to a reserved port. */
341df930be7Sderaadt 	desc->myport = htons(--rpc_port);
342df930be7Sderaadt 	desc->destip = ip;
343df930be7Sderaadt 	if (nfs_getrootfh(desc, path, nfs_root_node.fh))
344df930be7Sderaadt 		return (-1);
345df930be7Sderaadt 	nfs_root_node.iodesc = desc;
346df930be7Sderaadt 	/* Fake up attributes for the root dir. */
347df930be7Sderaadt 	fa = &nfs_root_node.fa;
348df930be7Sderaadt 	fa->fa_type  = htonl(NFDIR);
349df930be7Sderaadt 	fa->fa_mode  = htonl(0755);
350df930be7Sderaadt 	fa->fa_nlink = htonl(2);
351df930be7Sderaadt 
352df930be7Sderaadt #ifdef NFS_DEBUG
353df930be7Sderaadt 	if (debug)
354df930be7Sderaadt 		printf("nfs_mount: got fh for %s\n", path);
355df930be7Sderaadt #endif
356df930be7Sderaadt 
357df930be7Sderaadt 	return(0);
358df930be7Sderaadt }
359df930be7Sderaadt 
360df930be7Sderaadt /*
361df930be7Sderaadt  * Open a file.
362df930be7Sderaadt  * return zero or error number
363df930be7Sderaadt  */
364df930be7Sderaadt int
365*599546b3Sderaadt nfs_open(char *path, struct open_file *f)
366df930be7Sderaadt {
36779dbd5ceSniklas 	struct nfs_iodesc *newfd, *currfd;
368*599546b3Sderaadt 	char namebuf[NFS_MAXPATHLEN + 1], *cp, *ncp;
36979dbd5ceSniklas 	char linkbuf[NFS_MAXPATHLEN + 1];
370*599546b3Sderaadt 	int nlinks = 0, error = 0, c;
371df930be7Sderaadt 
372df930be7Sderaadt #ifdef NFS_DEBUG
373df930be7Sderaadt 	if (debug)
374df930be7Sderaadt 		printf("nfs_open: %s\n", path);
375df930be7Sderaadt #endif
376df930be7Sderaadt 	if (nfs_root_node.iodesc == NULL) {
377df930be7Sderaadt 		printf("nfs_open: must mount first.\n");
378df930be7Sderaadt 		return (ENXIO);
379df930be7Sderaadt 	}
380df930be7Sderaadt 
38179dbd5ceSniklas 	currfd = &nfs_root_node;
38279dbd5ceSniklas 	newfd = 0;
38379dbd5ceSniklas 
38479dbd5ceSniklas 	cp = path;
38579dbd5ceSniklas 	while (*cp) {
38679dbd5ceSniklas 		/*
38779dbd5ceSniklas 		 * Remove extra separators
38879dbd5ceSniklas 		 */
38979dbd5ceSniklas 		while (*cp == '/')
39079dbd5ceSniklas 			cp++;
39179dbd5ceSniklas 
39279dbd5ceSniklas 		if (*cp == '\0')
39379dbd5ceSniklas 			break;
39479dbd5ceSniklas 		/*
39579dbd5ceSniklas 		 * Check that current node is a directory.
39679dbd5ceSniklas 		 */
39779dbd5ceSniklas 		if (currfd->fa.fa_type != htonl(NFDIR)) {
39879dbd5ceSniklas 			error = ENOTDIR;
39979dbd5ceSniklas 			goto out;
40079dbd5ceSniklas 		}
40179dbd5ceSniklas 
402df930be7Sderaadt 		/* allocate file system specific data structure */
403df930be7Sderaadt 		newfd = alloc(sizeof(*newfd));
40479dbd5ceSniklas 		newfd->iodesc = currfd->iodesc;
405df930be7Sderaadt 		newfd->off = 0;
406df930be7Sderaadt 
40779dbd5ceSniklas 		/*
40879dbd5ceSniklas 		 * Get next component of path name.
40979dbd5ceSniklas 		 */
41079dbd5ceSniklas 		{
411*599546b3Sderaadt 			int len = 0;
41279dbd5ceSniklas 
41379dbd5ceSniklas 			ncp = cp;
41479dbd5ceSniklas 			while ((c = *cp) != '\0' && c != '/') {
41579dbd5ceSniklas 				if (++len > NFS_MAXNAMLEN) {
41679dbd5ceSniklas 					error = ENOENT;
41779dbd5ceSniklas 					goto out;
41879dbd5ceSniklas 				}
41979dbd5ceSniklas 				cp++;
42079dbd5ceSniklas 			}
42179dbd5ceSniklas 			*cp = '\0';
42279dbd5ceSniklas 		}
42379dbd5ceSniklas 
424df930be7Sderaadt 		/* lookup a file handle */
42579dbd5ceSniklas 		error = nfs_lookupfh(currfd, ncp, newfd);
42679dbd5ceSniklas 		*cp = c;
42779dbd5ceSniklas 		if (error)
42879dbd5ceSniklas 			goto out;
42979dbd5ceSniklas 
43079dbd5ceSniklas 		/*
43179dbd5ceSniklas 		 * Check for symbolic link
43279dbd5ceSniklas 		 */
43379dbd5ceSniklas 		if (newfd->fa.fa_type == htonl(NFLNK)) {
43479dbd5ceSniklas 			int link_len, len;
43579dbd5ceSniklas 
43679dbd5ceSniklas 			error = nfs_readlink(newfd, linkbuf);
43779dbd5ceSniklas 			if (error)
43879dbd5ceSniklas 				goto out;
43979dbd5ceSniklas 
44079dbd5ceSniklas 			link_len = strlen(linkbuf);
44179dbd5ceSniklas 			len = strlen(cp);
44279dbd5ceSniklas 
443*599546b3Sderaadt 			if (link_len + len > MAXPATHLEN ||
444*599546b3Sderaadt 			    ++nlinks > MAXSYMLINKS) {
44579dbd5ceSniklas 				error = ENOENT;
44679dbd5ceSniklas 				goto out;
44779dbd5ceSniklas 			}
44879dbd5ceSniklas 
44979dbd5ceSniklas 			bcopy(cp, &namebuf[link_len], len + 1);
45079dbd5ceSniklas 			bcopy(linkbuf, namebuf, link_len);
45179dbd5ceSniklas 
45279dbd5ceSniklas 			/*
45379dbd5ceSniklas 			 * If absolute pathname, restart at root.
45479dbd5ceSniklas 			 * If relative pathname, restart at parent directory.
45579dbd5ceSniklas 			 */
45679dbd5ceSniklas 			cp = namebuf;
45779dbd5ceSniklas 			if (*cp == '/') {
45879dbd5ceSniklas 				if (currfd != &nfs_root_node)
45979dbd5ceSniklas 					free(currfd, sizeof(*currfd));
46079dbd5ceSniklas 				currfd = &nfs_root_node;
46179dbd5ceSniklas 			}
46279dbd5ceSniklas 
46379dbd5ceSniklas 			free(newfd, sizeof(*newfd));
46479dbd5ceSniklas 			newfd = 0;
46579dbd5ceSniklas 
46679dbd5ceSniklas 			continue;
46779dbd5ceSniklas 		}
46879dbd5ceSniklas 
46979dbd5ceSniklas 		if (currfd != &nfs_root_node)
47079dbd5ceSniklas 			free(currfd, sizeof(*currfd));
47179dbd5ceSniklas 		currfd = newfd;
47279dbd5ceSniklas 		newfd = 0;
47379dbd5ceSniklas 	}
47479dbd5ceSniklas 
47579dbd5ceSniklas 	error = 0;
47679dbd5ceSniklas 
47779dbd5ceSniklas out:
478df930be7Sderaadt 	if (!error) {
47979dbd5ceSniklas 		f->f_fsdata = (void *)currfd;
480df930be7Sderaadt 		return (0);
481df930be7Sderaadt 	}
482df930be7Sderaadt 
483df930be7Sderaadt #ifdef NFS_DEBUG
484df930be7Sderaadt 	if (debug)
485df930be7Sderaadt 		printf("nfs_open: %s lookupfh failed: %s\n",
486df930be7Sderaadt 		    path, strerror(error));
487df930be7Sderaadt #endif
48879dbd5ceSniklas 	if (currfd != &nfs_root_node)
48979dbd5ceSniklas 		free(currfd, sizeof(*currfd));
49079dbd5ceSniklas 	if (newfd)
491df930be7Sderaadt 		free(newfd, sizeof(*newfd));
49279dbd5ceSniklas 
493df930be7Sderaadt 	return (error);
494df930be7Sderaadt }
495df930be7Sderaadt 
496df930be7Sderaadt int
497*599546b3Sderaadt nfs_close(struct open_file *f)
498df930be7Sderaadt {
499*599546b3Sderaadt 	struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
500df930be7Sderaadt 
501df930be7Sderaadt #ifdef NFS_DEBUG
502df930be7Sderaadt 	if (debug)
5036d86dcc1Smickey 		printf("nfs_close: fp=%p\n", fp);
504df930be7Sderaadt #endif
505df930be7Sderaadt 
506df930be7Sderaadt 	if (fp)
507df930be7Sderaadt 		free(fp, sizeof(struct nfs_iodesc));
508df930be7Sderaadt 	f->f_fsdata = (void *)0;
509df930be7Sderaadt 
510df930be7Sderaadt 	return (0);
511df930be7Sderaadt }
512df930be7Sderaadt 
513df930be7Sderaadt /*
514df930be7Sderaadt  * read a portion of a file
515df930be7Sderaadt  */
516df930be7Sderaadt int
517*599546b3Sderaadt nfs_read(struct open_file *f, void *buf, size_t size, size_t *resid)
518df930be7Sderaadt {
519*599546b3Sderaadt 	struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
520*599546b3Sderaadt 	ssize_t cc;
521*599546b3Sderaadt 	char *addr = buf;
522df930be7Sderaadt 
523df930be7Sderaadt #ifdef NFS_DEBUG
524df930be7Sderaadt 	if (debug)
525df930be7Sderaadt 		printf("nfs_read: size=%d off=%d\n", size, (int)fp->off);
526df930be7Sderaadt #endif
527df930be7Sderaadt 	while ((int)size > 0) {
528df930be7Sderaadt 		twiddle();
529df930be7Sderaadt 		cc = nfs_readdata(fp, fp->off, (void *)addr, size);
530df930be7Sderaadt 		/* XXX maybe should retry on certain errors */
531df930be7Sderaadt 		if (cc == -1) {
532df930be7Sderaadt #ifdef NFS_DEBUG
533df930be7Sderaadt 			if (debug)
534df930be7Sderaadt 				printf("nfs_read: read: %s", strerror(errno));
535df930be7Sderaadt #endif
536df930be7Sderaadt 			return (errno);	/* XXX - from nfs_readdata */
537df930be7Sderaadt 		}
538df930be7Sderaadt 		if (cc == 0) {
539df930be7Sderaadt 			if (debug)
540df930be7Sderaadt 				printf("nfs_read: hit EOF unexpectantly");
541df930be7Sderaadt 			goto ret;
542df930be7Sderaadt 		}
543df930be7Sderaadt 		fp->off += cc;
544df930be7Sderaadt 		addr += cc;
545df930be7Sderaadt 		size -= cc;
546df930be7Sderaadt 	}
547df930be7Sderaadt ret:
548df930be7Sderaadt 	if (resid)
549df930be7Sderaadt 		*resid = size;
550df930be7Sderaadt 
551df930be7Sderaadt 	return (0);
552df930be7Sderaadt }
553df930be7Sderaadt 
554df930be7Sderaadt /*
555df930be7Sderaadt  * Not implemented.
556df930be7Sderaadt  */
557df930be7Sderaadt int
558*599546b3Sderaadt nfs_write(struct open_file *f, void *buf, size_t size, size_t *resid)
559df930be7Sderaadt {
560df930be7Sderaadt 	return (EROFS);
561df930be7Sderaadt }
562df930be7Sderaadt 
563df930be7Sderaadt off_t
564*599546b3Sderaadt nfs_seek(struct open_file *f, off_t offset, int where)
565df930be7Sderaadt {
566*599546b3Sderaadt 	struct nfs_iodesc *d = (struct nfs_iodesc *)f->f_fsdata;
567df930be7Sderaadt 	n_long size = ntohl(d->fa.fa_size);
568df930be7Sderaadt 
569df930be7Sderaadt 	switch (where) {
570df930be7Sderaadt 	case SEEK_SET:
571df930be7Sderaadt 		d->off = offset;
572df930be7Sderaadt 		break;
573df930be7Sderaadt 	case SEEK_CUR:
574df930be7Sderaadt 		d->off += offset;
575df930be7Sderaadt 		break;
576df930be7Sderaadt 	case SEEK_END:
577df930be7Sderaadt 		d->off = size - offset;
578df930be7Sderaadt 		break;
579df930be7Sderaadt 	default:
580df930be7Sderaadt 		return (-1);
581df930be7Sderaadt 	}
582df930be7Sderaadt 
583df930be7Sderaadt 	return (d->off);
584df930be7Sderaadt }
585df930be7Sderaadt 
586df930be7Sderaadt /* NFNON=0, NFREG=1, NFDIR=2, NFBLK=3, NFCHR=4, NFLNK=5 */
587df930be7Sderaadt int nfs_stat_types[8] = {
588df930be7Sderaadt 	0, S_IFREG, S_IFDIR, S_IFBLK, S_IFCHR, S_IFLNK, 0 };
589df930be7Sderaadt 
590df930be7Sderaadt int
591*599546b3Sderaadt nfs_stat(struct open_file *f, struct stat *sb)
592df930be7Sderaadt {
593df930be7Sderaadt 	struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
594*599546b3Sderaadt 	n_long ftype, mode;
595df930be7Sderaadt 
596df930be7Sderaadt 	ftype = ntohl(fp->fa.fa_type);
597df930be7Sderaadt 	mode  = ntohl(fp->fa.fa_mode);
598df930be7Sderaadt 	mode |= nfs_stat_types[ftype & 7];
599df930be7Sderaadt 
600df930be7Sderaadt 	sb->st_mode  = mode;
601df930be7Sderaadt 	sb->st_nlink = ntohl(fp->fa.fa_nlink);
602df930be7Sderaadt 	sb->st_uid   = ntohl(fp->fa.fa_uid);
603df930be7Sderaadt 	sb->st_gid   = ntohl(fp->fa.fa_gid);
604df930be7Sderaadt 	sb->st_size  = ntohl(fp->fa.fa_size);
605df930be7Sderaadt 
606df930be7Sderaadt 	return (0);
607df930be7Sderaadt }
608e76f679cSmickey 
609e76f679cSmickey /*
610e76f679cSmickey  * Not implemented.
611e76f679cSmickey  */
612e76f679cSmickey #ifndef NO_READDIR
613e76f679cSmickey int
614*599546b3Sderaadt nfs_readdir(struct open_file *f, char *name)
615e76f679cSmickey {
616e76f679cSmickey 	return (EROFS);
617e76f679cSmickey }
618e76f679cSmickey #endif
619