nfs.c revision 39468
138451Smsmith/*	$NetBSD: nfs.c,v 1.2 1998/01/24 12:43:09 drochner Exp $	*/
238451Smsmith
338451Smsmith/*-
438451Smsmith *  Copyright (c) 1993 John Brezak
538451Smsmith *  All rights reserved.
638451Smsmith *
738451Smsmith *  Redistribution and use in source and binary forms, with or without
838451Smsmith *  modification, are permitted provided that the following conditions
938451Smsmith *  are met:
1038451Smsmith *  1. Redistributions of source code must retain the above copyright
1138451Smsmith *     notice, this list of conditions and the following disclaimer.
1238451Smsmith *  2. Redistributions in binary form must reproduce the above copyright
1338451Smsmith *     notice, this list of conditions and the following disclaimer in the
1438451Smsmith *     documentation and/or other materials provided with the distribution.
1538451Smsmith *  3. The name of the author may not be used to endorse or promote products
1638451Smsmith *     derived from this software without specific prior written permission.
1738451Smsmith *
1838451Smsmith * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR
1938451Smsmith * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
2038451Smsmith * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
2138451Smsmith * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
2238451Smsmith * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
2338451Smsmith * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
2438451Smsmith * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2538451Smsmith * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
2638451Smsmith * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
2738451Smsmith * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
2838451Smsmith * POSSIBILITY OF SUCH DAMAGE.
2938451Smsmith */
3038451Smsmith
3138451Smsmith#include <sys/param.h>
3238451Smsmith#include <sys/time.h>
3338451Smsmith#include <sys/socket.h>
3438451Smsmith#include <sys/stat.h>
3538451Smsmith#include <string.h>
3638451Smsmith
3738451Smsmith#include <netinet/in.h>
3838451Smsmith#include <netinet/in_systm.h>
3938451Smsmith
4038451Smsmith#include "rpcv2.h"
4138451Smsmith#include "nfsv2.h"
4238451Smsmith
4338451Smsmith#include "stand.h"
4438451Smsmith#include "net.h"
4538451Smsmith#include "netif.h"
4638451Smsmith#include "rpc.h"
4738451Smsmith
4838451Smsmith#define NFS_DEBUGxx
4938451Smsmith
5038451Smsmith/* Define our own NFS attributes without NQNFS stuff. */
5138451Smsmithstruct nfsv2_fattrs {
5238451Smsmith	n_long	fa_type;
5338451Smsmith	n_long	fa_mode;
5438451Smsmith	n_long	fa_nlink;
5538451Smsmith	n_long	fa_uid;
5638451Smsmith	n_long	fa_gid;
5738451Smsmith	n_long	fa_size;
5838451Smsmith	n_long	fa_blocksize;
5938451Smsmith	n_long	fa_rdev;
6038451Smsmith	n_long	fa_blocks;
6138451Smsmith	n_long	fa_fsid;
6238451Smsmith	n_long	fa_fileid;
6338451Smsmith	struct nfsv2_time fa_atime;
6438451Smsmith	struct nfsv2_time fa_mtime;
6538451Smsmith	struct nfsv2_time fa_ctime;
6638451Smsmith};
6738451Smsmith
6838451Smsmith
6938451Smsmithstruct nfs_read_args {
7038451Smsmith	u_char	fh[NFS_FHSIZE];
7138451Smsmith	n_long	off;
7238451Smsmith	n_long	len;
7338451Smsmith	n_long	xxx;			/* XXX what's this for? */
7438451Smsmith};
7538451Smsmith
7638451Smsmith/* Data part of nfs rpc reply (also the largest thing we receive) */
7738451Smsmith#define NFSREAD_SIZE 1024
7838451Smsmithstruct nfs_read_repl {
7938451Smsmith	n_long	errno;
8038451Smsmith	struct	nfsv2_fattrs fa;
8138451Smsmith	n_long	count;
8238451Smsmith	u_char	data[NFSREAD_SIZE];
8338451Smsmith};
8438451Smsmith
8538451Smsmith#ifndef NFS_NOSYMLINK
8638451Smsmithstruct nfs_readlnk_repl {
8738451Smsmith	n_long	errno;
8838451Smsmith	n_long	len;
8938451Smsmith	char	path[NFS_MAXPATHLEN];
9038451Smsmith};
9138451Smsmith#endif
9238451Smsmith
9338451Smsmithstruct nfs_iodesc {
9438451Smsmith	struct	iodesc	*iodesc;
9538451Smsmith	off_t	off;
9638451Smsmith	u_char	fh[NFS_FHSIZE];
9738451Smsmith	struct nfsv2_fattrs fa;	/* all in network order */
9838451Smsmith};
9938451Smsmith
10038451Smsmith/*
10138451Smsmith * XXX interactions with tftp? See nfswrapper.c for a confusing
10238451Smsmith *     issue.
10338451Smsmith */
10439468Smsmithint		nfs_open(const char *path, struct open_file *f);
10538451Smsmithstatic int	nfs_close(struct open_file *f);
10638451Smsmithstatic int	nfs_read(struct open_file *f, void *buf, size_t size, size_t *resid);
10738451Smsmithstatic int	nfs_write(struct open_file *f, void *buf, size_t size, size_t *resid);
10838451Smsmithstatic off_t	nfs_seek(struct open_file *f, off_t offset, int where);
10938451Smsmithstatic int	nfs_stat(struct open_file *f, struct stat *sb);
11038451Smsmith
11138451Smsmithstruct fs_ops nfs_fsops = {
11238451Smsmith	"nfs", nfs_open, nfs_close, nfs_read, nfs_write, nfs_seek, nfs_stat
11338451Smsmith};
11438451Smsmith
11538451Smsmith
11638451Smsmith/*
11738451Smsmith * Fetch the root file handle (call mount daemon)
11838451Smsmith * Return zero or error number.
11938451Smsmith */
12038451Smsmithint
12138451Smsmithnfs_getrootfh(d, path, fhp)
12238451Smsmith	register struct iodesc *d;
12338451Smsmith	char *path;
12438451Smsmith	u_char *fhp;
12538451Smsmith{
12638451Smsmith	register int len;
12738451Smsmith	struct args {
12838451Smsmith		n_long	len;
12938451Smsmith		char	path[FNAME_SIZE];
13038451Smsmith	} *args;
13138451Smsmith	struct repl {
13238451Smsmith		n_long	errno;
13338451Smsmith		u_char	fh[NFS_FHSIZE];
13438451Smsmith	} *repl;
13538451Smsmith	struct {
13638451Smsmith		n_long	h[RPC_HEADER_WORDS];
13738451Smsmith		struct args d;
13838451Smsmith	} sdata;
13938451Smsmith	struct {
14038451Smsmith		n_long	h[RPC_HEADER_WORDS];
14138451Smsmith		struct repl d;
14238451Smsmith	} rdata;
14338451Smsmith	size_t cc;
14438451Smsmith
14538451Smsmith#ifdef NFS_DEBUG
14638451Smsmith	if (debug)
14738451Smsmith		printf("nfs_getrootfh: %s\n", path);
14838451Smsmith#endif
14938451Smsmith
15038451Smsmith	args = &sdata.d;
15138451Smsmith	repl = &rdata.d;
15238451Smsmith
15338451Smsmith	bzero(args, sizeof(*args));
15438451Smsmith	len = strlen(path);
15538451Smsmith	if (len > sizeof(args->path))
15638451Smsmith		len = sizeof(args->path);
15738451Smsmith	args->len = htonl(len);
15838451Smsmith	bcopy(path, args->path, len);
15938451Smsmith	len = 4 + roundup(len, 4);
16038451Smsmith
16138451Smsmith	cc = rpc_call(d, RPCPROG_MNT, RPCMNT_VER1, RPCMNT_MOUNT,
16238451Smsmith	    args, len, repl, sizeof(*repl));
16338451Smsmith	if (cc == -1) {
16438451Smsmith		/* errno was set by rpc_call */
16538451Smsmith		return (errno);
16638451Smsmith	}
16738451Smsmith	if (cc < 4)
16838451Smsmith		return (EBADRPC);
16938451Smsmith	if (repl->errno)
17038451Smsmith		return (ntohl(repl->errno));
17138451Smsmith	bcopy(repl->fh, fhp, sizeof(repl->fh));
17238451Smsmith	return (0);
17338451Smsmith}
17438451Smsmith
17538451Smsmith/*
17638451Smsmith * Lookup a file.  Store handle and attributes.
17738451Smsmith * Return zero or error number.
17838451Smsmith */
17938451Smsmithint
18038451Smsmithnfs_lookupfh(d, name, newfd)
18138451Smsmith	struct nfs_iodesc *d;
18239468Smsmith	const char *name;
18338451Smsmith	struct nfs_iodesc *newfd;
18438451Smsmith{
18538451Smsmith	register int len, rlen;
18638451Smsmith	struct args {
18738451Smsmith		u_char	fh[NFS_FHSIZE];
18838451Smsmith		n_long	len;
18938451Smsmith		char	name[FNAME_SIZE];
19038451Smsmith	} *args;
19138451Smsmith	struct repl {
19238451Smsmith		n_long	errno;
19338451Smsmith		u_char	fh[NFS_FHSIZE];
19438451Smsmith		struct	nfsv2_fattrs fa;
19538451Smsmith	} *repl;
19638451Smsmith	struct {
19738451Smsmith		n_long	h[RPC_HEADER_WORDS];
19838451Smsmith		struct args d;
19938451Smsmith	} sdata;
20038451Smsmith	struct {
20138451Smsmith		n_long	h[RPC_HEADER_WORDS];
20238451Smsmith		struct repl d;
20338451Smsmith	} rdata;
20438451Smsmith	ssize_t cc;
20538451Smsmith
20638451Smsmith#ifdef NFS_DEBUG
20738451Smsmith	if (debug)
20838451Smsmith		printf("lookupfh: called\n");
20938451Smsmith#endif
21038451Smsmith
21138451Smsmith	args = &sdata.d;
21238451Smsmith	repl = &rdata.d;
21338451Smsmith
21438451Smsmith	bzero(args, sizeof(*args));
21538451Smsmith	bcopy(d->fh, args->fh, sizeof(args->fh));
21638451Smsmith	len = strlen(name);
21738451Smsmith	if (len > sizeof(args->name))
21838451Smsmith		len = sizeof(args->name);
21938451Smsmith	bcopy(name, args->name, len);
22038451Smsmith	args->len = htonl(len);
22138451Smsmith	len = 4 + roundup(len, 4);
22238451Smsmith	len += NFS_FHSIZE;
22338451Smsmith
22438451Smsmith	rlen = sizeof(*repl);
22538451Smsmith
22638451Smsmith	cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER2, NFSPROC_LOOKUP,
22738451Smsmith	    args, len, repl, rlen);
22838451Smsmith	if (cc == -1)
22938451Smsmith		return (errno);		/* XXX - from rpc_call */
23038451Smsmith	if (cc < 4)
23138451Smsmith		return (EIO);
23238451Smsmith	if (repl->errno) {
23338451Smsmith		/* saerrno.h now matches NFS error numbers. */
23438451Smsmith		return (ntohl(repl->errno));
23538451Smsmith	}
23638451Smsmith	bcopy( repl->fh, &newfd->fh, sizeof(newfd->fh));
23738451Smsmith	bcopy(&repl->fa, &newfd->fa, sizeof(newfd->fa));
23838451Smsmith	return (0);
23938451Smsmith}
24038451Smsmith
24138451Smsmith#ifndef NFS_NOSYMLINK
24238451Smsmith/*
24338451Smsmith * Get the destination of a symbolic link.
24438451Smsmith */
24538451Smsmithint
24638451Smsmithnfs_readlink(d, buf)
24738451Smsmith	struct nfs_iodesc *d;
24838451Smsmith	char *buf;
24938451Smsmith{
25038451Smsmith	struct {
25138451Smsmith		n_long	h[RPC_HEADER_WORDS];
25238451Smsmith		u_char fh[NFS_FHSIZE];
25338451Smsmith	} sdata;
25438451Smsmith	struct {
25538451Smsmith		n_long	h[RPC_HEADER_WORDS];
25638451Smsmith		struct nfs_readlnk_repl d;
25738451Smsmith	} rdata;
25838451Smsmith	ssize_t cc;
25938451Smsmith
26038451Smsmith#ifdef NFS_DEBUG
26138451Smsmith	if (debug)
26238451Smsmith		printf("readlink: called\n");
26338451Smsmith#endif
26438451Smsmith
26538451Smsmith	bcopy(d->fh, sdata.fh, NFS_FHSIZE);
26638451Smsmith	cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER2, NFSPROC_READLINK,
26738451Smsmith		      sdata.fh, NFS_FHSIZE,
26838451Smsmith		      &rdata.d, sizeof(rdata.d));
26938451Smsmith	if (cc == -1)
27038451Smsmith		return (errno);
27138451Smsmith
27238451Smsmith	if (cc < 4)
27338451Smsmith		return (EIO);
27438451Smsmith
27538451Smsmith	if (rdata.d.errno)
27638451Smsmith		return (ntohl(rdata.d.errno));
27738451Smsmith
27838451Smsmith	rdata.d.len = ntohl(rdata.d.len);
27938451Smsmith	if (rdata.d.len > NFS_MAXPATHLEN)
28038451Smsmith		return (ENAMETOOLONG);
28138451Smsmith
28238451Smsmith	bcopy(rdata.d.path, buf, rdata.d.len);
28338451Smsmith	buf[rdata.d.len] = 0;
28438451Smsmith	return (0);
28538451Smsmith}
28638451Smsmith#endif
28738451Smsmith
28838451Smsmith/*
28938451Smsmith * Read data from a file.
29038451Smsmith * Return transfer count or -1 (and set errno)
29138451Smsmith */
29238451Smsmithssize_t
29338451Smsmithnfs_readdata(d, off, addr, len)
29438451Smsmith	struct nfs_iodesc *d;
29538451Smsmith	off_t off;
29638451Smsmith	void *addr;
29738451Smsmith	size_t len;
29838451Smsmith{
29938451Smsmith	struct nfs_read_args *args;
30038451Smsmith	struct nfs_read_repl *repl;
30138451Smsmith	struct {
30238451Smsmith		n_long	h[RPC_HEADER_WORDS];
30338451Smsmith		struct nfs_read_args d;
30438451Smsmith	} sdata;
30538451Smsmith	struct {
30638451Smsmith		n_long	h[RPC_HEADER_WORDS];
30738451Smsmith		struct nfs_read_repl d;
30838451Smsmith	} rdata;
30938451Smsmith	size_t cc;
31038451Smsmith	long x;
31138451Smsmith	int hlen, rlen;
31238451Smsmith
31338451Smsmith	args = &sdata.d;
31438451Smsmith	repl = &rdata.d;
31538451Smsmith
31638451Smsmith	bcopy(d->fh, args->fh, NFS_FHSIZE);
31738451Smsmith	args->off = htonl((n_long)off);
31838451Smsmith	if (len > NFSREAD_SIZE)
31938451Smsmith		len = NFSREAD_SIZE;
32038451Smsmith	args->len = htonl((n_long)len);
32138451Smsmith	args->xxx = htonl((n_long)0);
32238451Smsmith	hlen = sizeof(*repl) - NFSREAD_SIZE;
32338451Smsmith
32438451Smsmith	cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER2, NFSPROC_READ,
32538451Smsmith	    args, sizeof(*args),
32638451Smsmith	    repl, sizeof(*repl));
32738451Smsmith	if (cc == -1) {
32838451Smsmith		/* errno was already set by rpc_call */
32938451Smsmith		return (-1);
33038451Smsmith	}
33138451Smsmith	if (cc < hlen) {
33238451Smsmith		errno = EBADRPC;
33338451Smsmith		return (-1);
33438451Smsmith	}
33538451Smsmith	if (repl->errno) {
33638451Smsmith		errno = ntohl(repl->errno);
33738451Smsmith		return (-1);
33838451Smsmith	}
33938451Smsmith	rlen = cc - hlen;
34038451Smsmith	x = ntohl(repl->count);
34138451Smsmith	if (rlen < x) {
34238451Smsmith		printf("nfsread: short packet, %d < %ld\n", rlen, x);
34338451Smsmith		errno = EBADRPC;
34438451Smsmith		return(-1);
34538451Smsmith	}
34638451Smsmith	bcopy(repl->data, addr, x);
34738451Smsmith	return (x);
34838451Smsmith}
34938451Smsmith
35038451Smsmith/*
35138451Smsmith * Open a file.
35238451Smsmith * return zero or error number
35338451Smsmith */
35438451Smsmithint
35539468Smsmithnfs_open(upath, f)
35639468Smsmith	const char *upath;
35738451Smsmith	struct open_file *f;
35838451Smsmith{
35938451Smsmith	static struct nfs_iodesc nfs_root_node;
36038451Smsmith	struct iodesc *desc;
36138451Smsmith	struct nfs_iodesc *currfd;
36238451Smsmith#ifndef NFS_NOSYMLINK
36338451Smsmith	struct nfs_iodesc *newfd;
36438451Smsmith	struct nfsv2_fattrs *fa;
36538451Smsmith	register char *cp, *ncp;
36638451Smsmith	register int c;
36738451Smsmith	char namebuf[NFS_MAXPATHLEN + 1];
36838451Smsmith	char linkbuf[NFS_MAXPATHLEN + 1];
36938451Smsmith	int nlinks = 0;
37038451Smsmith#endif
37138451Smsmith	int error;
37239468Smsmith	char *path;
37338451Smsmith
37438451Smsmith#ifdef NFS_DEBUG
37538451Smsmith 	if (debug)
37638451Smsmith 	    printf("nfs_open: %s (rootpath=%s)\n", path, rootpath);
37738451Smsmith#endif
37838451Smsmith	if (!rootpath[0]) {
37938451Smsmith		printf("no rootpath, no nfs\n");
38038451Smsmith		return (ENXIO);
38138451Smsmith	}
38238451Smsmith
38338451Smsmith	if (!(desc = socktodesc(*(int *)(f->f_devdata))))
38438451Smsmith		return(EINVAL);
38538451Smsmith
38638451Smsmith	/* Bind to a reserved port. */
38738451Smsmith	desc->myport = htons(--rpc_port);
38838451Smsmith	desc->destip = rootip;
38938451Smsmith	if ((error = nfs_getrootfh(desc, rootpath, nfs_root_node.fh)))
39038451Smsmith		return (error);
39138451Smsmith	nfs_root_node.iodesc = desc;
39238451Smsmith
39338451Smsmith#ifndef NFS_NOSYMLINK
39438451Smsmith	/* Fake up attributes for the root dir. */
39538451Smsmith	fa = &nfs_root_node.fa;
39638451Smsmith	fa->fa_type  = htonl(NFDIR);
39738451Smsmith	fa->fa_mode  = htonl(0755);
39838451Smsmith	fa->fa_nlink = htonl(2);
39938451Smsmith
40038451Smsmith	currfd = &nfs_root_node;
40138451Smsmith	newfd = 0;
40238451Smsmith
40339468Smsmith	cp = path = strdup(upath);
40439468Smsmith	if (path == NULL) {
40539468Smsmith	    error = ENOMEM;
40639468Smsmith	    goto out;
40739468Smsmith	}
40838451Smsmith	while (*cp) {
40938451Smsmith		/*
41038451Smsmith		 * Remove extra separators
41138451Smsmith		 */
41238451Smsmith		while (*cp == '/')
41338451Smsmith			cp++;
41438451Smsmith
41538451Smsmith		if (*cp == '\0')
41638451Smsmith			break;
41738451Smsmith		/*
41838451Smsmith		 * Check that current node is a directory.
41938451Smsmith		 */
42038451Smsmith		if (currfd->fa.fa_type != htonl(NFDIR)) {
42138451Smsmith			error = ENOTDIR;
42238451Smsmith			goto out;
42338451Smsmith		}
42438451Smsmith
42538451Smsmith		/* allocate file system specific data structure */
42638451Smsmith		newfd = malloc(sizeof(*newfd));
42738451Smsmith		newfd->iodesc = currfd->iodesc;
42838451Smsmith		newfd->off = 0;
42938451Smsmith
43038451Smsmith		/*
43138451Smsmith		 * Get next component of path name.
43238451Smsmith		 */
43338451Smsmith		{
43438451Smsmith			register int len = 0;
43538451Smsmith
43638451Smsmith			ncp = cp;
43738451Smsmith			while ((c = *cp) != '\0' && c != '/') {
43838451Smsmith				if (++len > NFS_MAXNAMLEN) {
43938451Smsmith					error = ENOENT;
44038451Smsmith					goto out;
44138451Smsmith				}
44238451Smsmith				cp++;
44338451Smsmith			}
44438451Smsmith			*cp = '\0';
44538451Smsmith		}
44638451Smsmith
44738451Smsmith		/* lookup a file handle */
44838451Smsmith		error = nfs_lookupfh(currfd, ncp, newfd);
44938451Smsmith		*cp = c;
45038451Smsmith		if (error)
45138451Smsmith			goto out;
45238451Smsmith
45338451Smsmith		/*
45438451Smsmith		 * Check for symbolic link
45538451Smsmith		 */
45638451Smsmith		if (newfd->fa.fa_type == htonl(NFLNK)) {
45738451Smsmith			int link_len, len;
45838451Smsmith
45938451Smsmith			error = nfs_readlink(newfd, linkbuf);
46038451Smsmith			if (error)
46138451Smsmith				goto out;
46238451Smsmith
46338451Smsmith			link_len = strlen(linkbuf);
46438451Smsmith			len = strlen(cp);
46538451Smsmith
46638451Smsmith			if (link_len + len > MAXPATHLEN
46738451Smsmith			    || ++nlinks > MAXSYMLINKS) {
46838451Smsmith				error = ENOENT;
46938451Smsmith				goto out;
47038451Smsmith			}
47138451Smsmith
47238451Smsmith			bcopy(cp, &namebuf[link_len], len + 1);
47338451Smsmith			bcopy(linkbuf, namebuf, link_len);
47438451Smsmith
47538451Smsmith			/*
47638451Smsmith			 * If absolute pathname, restart at root.
47738451Smsmith			 * If relative pathname, restart at parent directory.
47838451Smsmith			 */
47938451Smsmith			cp = namebuf;
48038451Smsmith			if (*cp == '/') {
48138451Smsmith				if (currfd != &nfs_root_node)
48238451Smsmith					free(currfd);
48338451Smsmith				currfd = &nfs_root_node;
48438451Smsmith			}
48538451Smsmith
48638451Smsmith			free(newfd);
48738451Smsmith			newfd = 0;
48838451Smsmith
48938451Smsmith			continue;
49038451Smsmith		}
49138451Smsmith
49238451Smsmith		if (currfd != &nfs_root_node)
49338451Smsmith			free(currfd);
49438451Smsmith		currfd = newfd;
49538451Smsmith		newfd = 0;
49638451Smsmith	}
49738451Smsmith
49838451Smsmith	error = 0;
49938451Smsmith
50038451Smsmithout:
50138451Smsmith	if (newfd)
50238451Smsmith		free(newfd);
50339468Smsmith	if (path)
50439468Smsmith		free(path);
50538451Smsmith#else
50638451Smsmith        /* allocate file system specific data structure */
50738451Smsmith        currfd = malloc(sizeof(*currfd));
50838451Smsmith        currfd->iodesc = desc;
50938451Smsmith        currfd->off = 0;
51038451Smsmith
51139468Smsmith        error = nfs_lookupfh(&nfs_root_node, upath, currfd);
51238451Smsmith#endif
51338451Smsmith	if (!error) {
51438451Smsmith		f->f_fsdata = (void *)currfd;
51538451Smsmith		return (0);
51638451Smsmith	}
51738451Smsmith
51838451Smsmith#ifdef NFS_DEBUG
51938451Smsmith	if (debug)
52038451Smsmith		printf("nfs_open: %s lookupfh failed: %s\n",
52138451Smsmith		    path, strerror(error));
52238451Smsmith#endif
52338451Smsmith#ifndef NFS_NOSYMLINK
52438451Smsmith	if (currfd != &nfs_root_node)
52538451Smsmith#endif
52638451Smsmith		free(currfd);
52738451Smsmith
52838451Smsmith	return (error);
52938451Smsmith}
53038451Smsmith
53138451Smsmithint
53238451Smsmithnfs_close(f)
53338451Smsmith	struct open_file *f;
53438451Smsmith{
53538451Smsmith	register struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
53638451Smsmith
53738451Smsmith#ifdef NFS_DEBUG
53838451Smsmith	if (debug)
53938451Smsmith		printf("nfs_close: fp=0x%lx\n", (u_long)fp);
54038451Smsmith#endif
54138451Smsmith
54238451Smsmith	if (fp)
54338451Smsmith		free(fp);
54438451Smsmith	f->f_fsdata = (void *)0;
54538451Smsmith
54638451Smsmith	return (0);
54738451Smsmith}
54838451Smsmith
54938451Smsmith/*
55038451Smsmith * read a portion of a file
55138451Smsmith */
55238451Smsmithint
55338451Smsmithnfs_read(f, buf, size, resid)
55438451Smsmith	struct open_file *f;
55538451Smsmith	void *buf;
55638451Smsmith	size_t size;
55738451Smsmith	size_t *resid;	/* out */
55838451Smsmith{
55938451Smsmith	register struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
56038451Smsmith	register ssize_t cc;
56138451Smsmith	register char *addr = buf;
56238451Smsmith
56338451Smsmith#ifdef NFS_DEBUG
56438451Smsmith	if (debug)
56538451Smsmith		printf("nfs_read: size=%lu off=%d\n", (u_long)size,
56638451Smsmith		       (int)fp->off);
56738451Smsmith#endif
56838451Smsmith	while ((int)size > 0) {
56938451Smsmith		twiddle();
57038451Smsmith		cc = nfs_readdata(fp, fp->off, (void *)addr, size);
57138451Smsmith		/* XXX maybe should retry on certain errors */
57238451Smsmith		if (cc == -1) {
57338451Smsmith#ifdef NFS_DEBUG
57438451Smsmith			if (debug)
57538451Smsmith				printf("nfs_read: read: %s", strerror(errno));
57638451Smsmith#endif
57738451Smsmith			return (errno);	/* XXX - from nfs_readdata */
57838451Smsmith		}
57938451Smsmith		if (cc == 0) {
58038451Smsmith#ifdef NFS_DEBUG
58138451Smsmith			if (debug)
58238451Smsmith				printf("nfs_read: hit EOF unexpectantly");
58338451Smsmith#endif
58438451Smsmith			goto ret;
58538451Smsmith		}
58638451Smsmith		fp->off += cc;
58738451Smsmith		addr += cc;
58838451Smsmith		size -= cc;
58938451Smsmith	}
59038451Smsmithret:
59138451Smsmith	if (resid)
59238451Smsmith		*resid = size;
59338451Smsmith
59438451Smsmith	return (0);
59538451Smsmith}
59638451Smsmith
59738451Smsmith/*
59838451Smsmith * Not implemented.
59938451Smsmith */
60038451Smsmithint
60138451Smsmithnfs_write(f, buf, size, resid)
60238451Smsmith	struct open_file *f;
60338451Smsmith	void *buf;
60438451Smsmith	size_t size;
60538451Smsmith	size_t *resid;	/* out */
60638451Smsmith{
60738451Smsmith	return (EROFS);
60838451Smsmith}
60938451Smsmith
61038451Smsmithoff_t
61138451Smsmithnfs_seek(f, offset, where)
61238451Smsmith	struct open_file *f;
61338451Smsmith	off_t offset;
61438451Smsmith	int where;
61538451Smsmith{
61638451Smsmith	register struct nfs_iodesc *d = (struct nfs_iodesc *)f->f_fsdata;
61738451Smsmith	n_long size = ntohl(d->fa.fa_size);
61838451Smsmith
61938451Smsmith	switch (where) {
62038451Smsmith	case SEEK_SET:
62138451Smsmith		d->off = offset;
62238451Smsmith		break;
62338451Smsmith	case SEEK_CUR:
62438451Smsmith		d->off += offset;
62538451Smsmith		break;
62638451Smsmith	case SEEK_END:
62738451Smsmith		d->off = size - offset;
62838451Smsmith		break;
62938451Smsmith	default:
63038451Smsmith		return (-1);
63138451Smsmith	}
63238451Smsmith
63338451Smsmith	return (d->off);
63438451Smsmith}
63538451Smsmith
63638451Smsmith/* NFNON=0, NFREG=1, NFDIR=2, NFBLK=3, NFCHR=4, NFLNK=5 */
63738451Smsmithint nfs_stat_types[8] = {
63838451Smsmith	0, S_IFREG, S_IFDIR, S_IFBLK, S_IFCHR, S_IFLNK, 0 };
63938451Smsmith
64038451Smsmithint
64138451Smsmithnfs_stat(f, sb)
64238451Smsmith	struct open_file *f;
64338451Smsmith	struct stat *sb;
64438451Smsmith{
64538451Smsmith	struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
64638451Smsmith	register n_long ftype, mode;
64738451Smsmith
64838451Smsmith	ftype = ntohl(fp->fa.fa_type);
64938451Smsmith	mode  = ntohl(fp->fa.fa_mode);
65038451Smsmith	mode |= nfs_stat_types[ftype & 7];
65138451Smsmith
65238451Smsmith	sb->st_mode  = mode;
65338451Smsmith	sb->st_nlink = ntohl(fp->fa.fa_nlink);
65438451Smsmith	sb->st_uid   = ntohl(fp->fa.fa_uid);
65538451Smsmith	sb->st_gid   = ntohl(fp->fa.fa_gid);
65638451Smsmith	sb->st_size  = ntohl(fp->fa.fa_size);
65738451Smsmith
65838451Smsmith	return (0);
65938451Smsmith}
660