nfs.c revision 124811
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 3184221Sdillon#include <sys/cdefs.h> 3284221Sdillon__FBSDID("$FreeBSD: head/lib/libstand/nfs.c 124811 2004-01-21 20:12:23Z jhb $"); 3384221Sdillon 3438451Smsmith#include <sys/param.h> 3538451Smsmith#include <sys/time.h> 3638451Smsmith#include <sys/socket.h> 3738451Smsmith#include <sys/stat.h> 3838451Smsmith#include <string.h> 3938451Smsmith 4038451Smsmith#include <netinet/in.h> 4138451Smsmith#include <netinet/in_systm.h> 4238451Smsmith 4338451Smsmith#include "rpcv2.h" 4438451Smsmith#include "nfsv2.h" 4538451Smsmith 4638451Smsmith#include "stand.h" 4738451Smsmith#include "net.h" 4838451Smsmith#include "netif.h" 4938451Smsmith#include "rpc.h" 5038451Smsmith 5138451Smsmith#define NFS_DEBUGxx 5238451Smsmith 5338451Smsmith/* Define our own NFS attributes without NQNFS stuff. */ 5438451Smsmithstruct nfsv2_fattrs { 5538451Smsmith n_long fa_type; 5638451Smsmith n_long fa_mode; 5738451Smsmith n_long fa_nlink; 5838451Smsmith n_long fa_uid; 5938451Smsmith n_long fa_gid; 6038451Smsmith n_long fa_size; 6138451Smsmith n_long fa_blocksize; 6238451Smsmith n_long fa_rdev; 6338451Smsmith n_long fa_blocks; 6438451Smsmith n_long fa_fsid; 6538451Smsmith n_long fa_fileid; 6638451Smsmith struct nfsv2_time fa_atime; 6738451Smsmith struct nfsv2_time fa_mtime; 6838451Smsmith struct nfsv2_time fa_ctime; 6938451Smsmith}; 7038451Smsmith 7138451Smsmith 7238451Smsmithstruct nfs_read_args { 7338451Smsmith u_char fh[NFS_FHSIZE]; 7438451Smsmith n_long off; 7538451Smsmith n_long len; 7638451Smsmith n_long xxx; /* XXX what's this for? */ 7738451Smsmith}; 7838451Smsmith 7938451Smsmith/* Data part of nfs rpc reply (also the largest thing we receive) */ 8038451Smsmith#define NFSREAD_SIZE 1024 8138451Smsmithstruct nfs_read_repl { 8238451Smsmith n_long errno; 8338451Smsmith struct nfsv2_fattrs fa; 8438451Smsmith n_long count; 8538451Smsmith u_char data[NFSREAD_SIZE]; 8638451Smsmith}; 8738451Smsmith 8838451Smsmith#ifndef NFS_NOSYMLINK 8938451Smsmithstruct nfs_readlnk_repl { 9038451Smsmith n_long errno; 9138451Smsmith n_long len; 9238451Smsmith char path[NFS_MAXPATHLEN]; 9338451Smsmith}; 9438451Smsmith#endif 9538451Smsmith 9659853Spsstruct nfs_readdir_args { 9759853Sps u_char fh[NFS_FHSIZE]; 9859853Sps n_long cookie; 9959853Sps n_long count; 10059853Sps}; 10159853Sps 10259853Spsstruct nfs_readdir_data { 10359853Sps n_long fileid; 10459853Sps n_long len; 10559853Sps char name[0]; 10659853Sps}; 10759853Sps 10859853Spsstruct nfs_readdir_off { 10959853Sps n_long cookie; 11059853Sps n_long follows; 11159853Sps}; 11259853Sps 11338451Smsmithstruct nfs_iodesc { 11438451Smsmith struct iodesc *iodesc; 11538451Smsmith off_t off; 11638451Smsmith u_char fh[NFS_FHSIZE]; 11738451Smsmith struct nfsv2_fattrs fa; /* all in network order */ 11838451Smsmith}; 11938451Smsmith 12038451Smsmith/* 12138451Smsmith * XXX interactions with tftp? See nfswrapper.c for a confusing 12238451Smsmith * issue. 12338451Smsmith */ 12439468Smsmithint nfs_open(const char *path, struct open_file *f); 12538451Smsmithstatic int nfs_close(struct open_file *f); 12638451Smsmithstatic int nfs_read(struct open_file *f, void *buf, size_t size, size_t *resid); 12738451Smsmithstatic int nfs_write(struct open_file *f, void *buf, size_t size, size_t *resid); 12838451Smsmithstatic off_t nfs_seek(struct open_file *f, off_t offset, int where); 12938451Smsmithstatic int nfs_stat(struct open_file *f, struct stat *sb); 13059853Spsstatic int nfs_readdir(struct open_file *f, struct dirent *d); 13138451Smsmith 13265496Smsmithstruct nfs_iodesc nfs_root_node; 13359824Sps 13438451Smsmithstruct fs_ops nfs_fsops = { 13559766Sjlemon "nfs", 13659766Sjlemon nfs_open, 13759766Sjlemon nfs_close, 13859766Sjlemon nfs_read, 13959766Sjlemon nfs_write, 14059766Sjlemon nfs_seek, 14159766Sjlemon nfs_stat, 14259853Sps nfs_readdir 14338451Smsmith}; 14438451Smsmith 14538451Smsmith/* 14638451Smsmith * Fetch the root file handle (call mount daemon) 14738451Smsmith * Return zero or error number. 14838451Smsmith */ 14938451Smsmithint 15038451Smsmithnfs_getrootfh(d, path, fhp) 15192913Sobrien struct iodesc *d; 15238451Smsmith char *path; 15338451Smsmith u_char *fhp; 15438451Smsmith{ 15592913Sobrien int len; 15638451Smsmith struct args { 15738451Smsmith n_long len; 15838451Smsmith char path[FNAME_SIZE]; 15938451Smsmith } *args; 16038451Smsmith struct repl { 16138451Smsmith n_long errno; 16238451Smsmith u_char fh[NFS_FHSIZE]; 16338451Smsmith } *repl; 16438451Smsmith struct { 16538451Smsmith n_long h[RPC_HEADER_WORDS]; 16638451Smsmith struct args d; 16738451Smsmith } sdata; 16838451Smsmith struct { 16938451Smsmith n_long h[RPC_HEADER_WORDS]; 17038451Smsmith struct repl d; 17138451Smsmith } rdata; 17238451Smsmith size_t cc; 17338451Smsmith 17438451Smsmith#ifdef NFS_DEBUG 17538451Smsmith if (debug) 17638451Smsmith printf("nfs_getrootfh: %s\n", path); 17738451Smsmith#endif 17838451Smsmith 17938451Smsmith args = &sdata.d; 18038451Smsmith repl = &rdata.d; 18138451Smsmith 18238451Smsmith bzero(args, sizeof(*args)); 18338451Smsmith len = strlen(path); 18438451Smsmith if (len > sizeof(args->path)) 18538451Smsmith len = sizeof(args->path); 18638451Smsmith args->len = htonl(len); 18738451Smsmith bcopy(path, args->path, len); 18838451Smsmith len = 4 + roundup(len, 4); 18938451Smsmith 19038451Smsmith cc = rpc_call(d, RPCPROG_MNT, RPCMNT_VER1, RPCMNT_MOUNT, 19138451Smsmith args, len, repl, sizeof(*repl)); 19238451Smsmith if (cc == -1) { 19338451Smsmith /* errno was set by rpc_call */ 19438451Smsmith return (errno); 19538451Smsmith } 19638451Smsmith if (cc < 4) 19738451Smsmith return (EBADRPC); 19838451Smsmith if (repl->errno) 19938451Smsmith return (ntohl(repl->errno)); 20038451Smsmith bcopy(repl->fh, fhp, sizeof(repl->fh)); 20138451Smsmith return (0); 20238451Smsmith} 20338451Smsmith 20438451Smsmith/* 20538451Smsmith * Lookup a file. Store handle and attributes. 20638451Smsmith * Return zero or error number. 20738451Smsmith */ 20838451Smsmithint 20938451Smsmithnfs_lookupfh(d, name, newfd) 21038451Smsmith struct nfs_iodesc *d; 21139468Smsmith const char *name; 21238451Smsmith struct nfs_iodesc *newfd; 21338451Smsmith{ 21492913Sobrien int len, rlen; 21538451Smsmith struct args { 21638451Smsmith u_char fh[NFS_FHSIZE]; 21738451Smsmith n_long len; 21838451Smsmith char name[FNAME_SIZE]; 21938451Smsmith } *args; 22038451Smsmith struct repl { 22138451Smsmith n_long errno; 22238451Smsmith u_char fh[NFS_FHSIZE]; 22338451Smsmith struct nfsv2_fattrs fa; 22438451Smsmith } *repl; 22538451Smsmith struct { 22638451Smsmith n_long h[RPC_HEADER_WORDS]; 22738451Smsmith struct args d; 22838451Smsmith } sdata; 22938451Smsmith struct { 23038451Smsmith n_long h[RPC_HEADER_WORDS]; 23138451Smsmith struct repl d; 23238451Smsmith } rdata; 23338451Smsmith ssize_t cc; 23438451Smsmith 23538451Smsmith#ifdef NFS_DEBUG 23638451Smsmith if (debug) 23738451Smsmith printf("lookupfh: called\n"); 23838451Smsmith#endif 23938451Smsmith 24038451Smsmith args = &sdata.d; 24138451Smsmith repl = &rdata.d; 24238451Smsmith 24338451Smsmith bzero(args, sizeof(*args)); 24438451Smsmith bcopy(d->fh, args->fh, sizeof(args->fh)); 24538451Smsmith len = strlen(name); 24638451Smsmith if (len > sizeof(args->name)) 24738451Smsmith len = sizeof(args->name); 24838451Smsmith bcopy(name, args->name, len); 24938451Smsmith args->len = htonl(len); 25038451Smsmith len = 4 + roundup(len, 4); 25138451Smsmith len += NFS_FHSIZE; 25238451Smsmith 25338451Smsmith rlen = sizeof(*repl); 25438451Smsmith 25538451Smsmith cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER2, NFSPROC_LOOKUP, 25638451Smsmith args, len, repl, rlen); 25738451Smsmith if (cc == -1) 25838451Smsmith return (errno); /* XXX - from rpc_call */ 25938451Smsmith if (cc < 4) 26038451Smsmith return (EIO); 26138451Smsmith if (repl->errno) { 26238451Smsmith /* saerrno.h now matches NFS error numbers. */ 26338451Smsmith return (ntohl(repl->errno)); 26438451Smsmith } 26538451Smsmith bcopy( repl->fh, &newfd->fh, sizeof(newfd->fh)); 26638451Smsmith bcopy(&repl->fa, &newfd->fa, sizeof(newfd->fa)); 26738451Smsmith return (0); 26838451Smsmith} 26938451Smsmith 27038451Smsmith#ifndef NFS_NOSYMLINK 27138451Smsmith/* 27238451Smsmith * Get the destination of a symbolic link. 27338451Smsmith */ 27438451Smsmithint 27538451Smsmithnfs_readlink(d, buf) 27638451Smsmith struct nfs_iodesc *d; 27738451Smsmith char *buf; 27838451Smsmith{ 27938451Smsmith struct { 28038451Smsmith n_long h[RPC_HEADER_WORDS]; 28138451Smsmith u_char fh[NFS_FHSIZE]; 28238451Smsmith } sdata; 28338451Smsmith struct { 28438451Smsmith n_long h[RPC_HEADER_WORDS]; 28538451Smsmith struct nfs_readlnk_repl d; 28638451Smsmith } rdata; 28738451Smsmith ssize_t cc; 28838451Smsmith 28938451Smsmith#ifdef NFS_DEBUG 29038451Smsmith if (debug) 29138451Smsmith printf("readlink: called\n"); 29238451Smsmith#endif 29338451Smsmith 29438451Smsmith bcopy(d->fh, sdata.fh, NFS_FHSIZE); 29538451Smsmith cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER2, NFSPROC_READLINK, 29638451Smsmith sdata.fh, NFS_FHSIZE, 29738451Smsmith &rdata.d, sizeof(rdata.d)); 29838451Smsmith if (cc == -1) 29938451Smsmith return (errno); 30038451Smsmith 30138451Smsmith if (cc < 4) 30238451Smsmith return (EIO); 30338451Smsmith 30438451Smsmith if (rdata.d.errno) 30538451Smsmith return (ntohl(rdata.d.errno)); 30638451Smsmith 30738451Smsmith rdata.d.len = ntohl(rdata.d.len); 30838451Smsmith if (rdata.d.len > NFS_MAXPATHLEN) 30938451Smsmith return (ENAMETOOLONG); 31038451Smsmith 31138451Smsmith bcopy(rdata.d.path, buf, rdata.d.len); 31238451Smsmith buf[rdata.d.len] = 0; 31338451Smsmith return (0); 31438451Smsmith} 31538451Smsmith#endif 31638451Smsmith 31738451Smsmith/* 31838451Smsmith * Read data from a file. 31938451Smsmith * Return transfer count or -1 (and set errno) 32038451Smsmith */ 32138451Smsmithssize_t 32238451Smsmithnfs_readdata(d, off, addr, len) 32338451Smsmith struct nfs_iodesc *d; 32438451Smsmith off_t off; 32538451Smsmith void *addr; 32638451Smsmith size_t len; 32738451Smsmith{ 32838451Smsmith struct nfs_read_args *args; 32938451Smsmith struct nfs_read_repl *repl; 33038451Smsmith struct { 33138451Smsmith n_long h[RPC_HEADER_WORDS]; 33238451Smsmith struct nfs_read_args d; 33338451Smsmith } sdata; 33438451Smsmith struct { 33538451Smsmith n_long h[RPC_HEADER_WORDS]; 33638451Smsmith struct nfs_read_repl d; 33738451Smsmith } rdata; 33838451Smsmith size_t cc; 33938451Smsmith long x; 34038451Smsmith int hlen, rlen; 34138451Smsmith 34238451Smsmith args = &sdata.d; 34338451Smsmith repl = &rdata.d; 34438451Smsmith 34538451Smsmith bcopy(d->fh, args->fh, NFS_FHSIZE); 34638451Smsmith args->off = htonl((n_long)off); 34738451Smsmith if (len > NFSREAD_SIZE) 34838451Smsmith len = NFSREAD_SIZE; 34938451Smsmith args->len = htonl((n_long)len); 35038451Smsmith args->xxx = htonl((n_long)0); 35138451Smsmith hlen = sizeof(*repl) - NFSREAD_SIZE; 35238451Smsmith 35338451Smsmith cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER2, NFSPROC_READ, 35438451Smsmith args, sizeof(*args), 35538451Smsmith repl, sizeof(*repl)); 35638451Smsmith if (cc == -1) { 35738451Smsmith /* errno was already set by rpc_call */ 35838451Smsmith return (-1); 35938451Smsmith } 36038451Smsmith if (cc < hlen) { 36138451Smsmith errno = EBADRPC; 36238451Smsmith return (-1); 36338451Smsmith } 36438451Smsmith if (repl->errno) { 36538451Smsmith errno = ntohl(repl->errno); 36638451Smsmith return (-1); 36738451Smsmith } 36838451Smsmith rlen = cc - hlen; 36938451Smsmith x = ntohl(repl->count); 37038451Smsmith if (rlen < x) { 37138451Smsmith printf("nfsread: short packet, %d < %ld\n", rlen, x); 37238451Smsmith errno = EBADRPC; 37338451Smsmith return(-1); 37438451Smsmith } 37538451Smsmith bcopy(repl->data, addr, x); 37638451Smsmith return (x); 37738451Smsmith} 37838451Smsmith 37938451Smsmith/* 38038451Smsmith * Open a file. 38138451Smsmith * return zero or error number 38238451Smsmith */ 38338451Smsmithint 38439468Smsmithnfs_open(upath, f) 38539468Smsmith const char *upath; 38638451Smsmith struct open_file *f; 38738451Smsmith{ 38838451Smsmith struct iodesc *desc; 38938451Smsmith struct nfs_iodesc *currfd; 390101112Sjake char buf[2 * NFS_FHSIZE + 3]; 391101112Sjake u_char *fh; 392101112Sjake char *cp; 393101112Sjake int i; 39438451Smsmith#ifndef NFS_NOSYMLINK 39538451Smsmith struct nfs_iodesc *newfd; 39638451Smsmith struct nfsv2_fattrs *fa; 397101112Sjake char *ncp; 39892913Sobrien int c; 39938451Smsmith char namebuf[NFS_MAXPATHLEN + 1]; 40038451Smsmith char linkbuf[NFS_MAXPATHLEN + 1]; 40138451Smsmith int nlinks = 0; 40238451Smsmith#endif 40338451Smsmith int error; 40439468Smsmith char *path; 40538451Smsmith 40638451Smsmith#ifdef NFS_DEBUG 40738451Smsmith if (debug) 40838451Smsmith printf("nfs_open: %s (rootpath=%s)\n", path, rootpath); 40938451Smsmith#endif 41038451Smsmith if (!rootpath[0]) { 41138451Smsmith printf("no rootpath, no nfs\n"); 41238451Smsmith return (ENXIO); 41338451Smsmith } 41438451Smsmith 415111776Smarcel#ifndef __i386__ 41699558Sjake if (strcmp(f->f_dev->dv_name, "net") != 0) 41799558Sjake return(EINVAL); 41899558Sjake#endif 419111776Smarcel 42038451Smsmith if (!(desc = socktodesc(*(int *)(f->f_devdata)))) 42138451Smsmith return(EINVAL); 42238451Smsmith 42338451Smsmith /* Bind to a reserved port. */ 42438451Smsmith desc->myport = htons(--rpc_port); 42538451Smsmith desc->destip = rootip; 42638451Smsmith if ((error = nfs_getrootfh(desc, rootpath, nfs_root_node.fh))) 42738451Smsmith return (error); 42838451Smsmith nfs_root_node.iodesc = desc; 42938451Smsmith 430101112Sjake fh = &nfs_root_node.fh[0]; 431101112Sjake buf[0] = 'X'; 432101112Sjake cp = &buf[1]; 433101112Sjake for (i = 0; i < NFS_FHSIZE; i++, cp += 2) 434101112Sjake sprintf(cp, "%02x", fh[i]); 435101112Sjake sprintf(cp, "X"); 436101112Sjake setenv("boot.nfsroot.server", inet_ntoa(rootip), 1); 437101112Sjake setenv("boot.nfsroot.path", rootpath, 1); 438101112Sjake setenv("boot.nfsroot.nfshandle", buf, 1); 439101112Sjake 44038451Smsmith#ifndef NFS_NOSYMLINK 44138451Smsmith /* Fake up attributes for the root dir. */ 44238451Smsmith fa = &nfs_root_node.fa; 44338451Smsmith fa->fa_type = htonl(NFDIR); 44438451Smsmith fa->fa_mode = htonl(0755); 44538451Smsmith fa->fa_nlink = htonl(2); 44638451Smsmith 44738451Smsmith currfd = &nfs_root_node; 44838451Smsmith newfd = 0; 44938451Smsmith 45039468Smsmith cp = path = strdup(upath); 45139468Smsmith if (path == NULL) { 45239468Smsmith error = ENOMEM; 45339468Smsmith goto out; 45439468Smsmith } 45538451Smsmith while (*cp) { 45638451Smsmith /* 45738451Smsmith * Remove extra separators 45838451Smsmith */ 45938451Smsmith while (*cp == '/') 46038451Smsmith cp++; 46138451Smsmith 46238451Smsmith if (*cp == '\0') 46338451Smsmith break; 46438451Smsmith /* 46538451Smsmith * Check that current node is a directory. 46638451Smsmith */ 46738451Smsmith if (currfd->fa.fa_type != htonl(NFDIR)) { 46838451Smsmith error = ENOTDIR; 46938451Smsmith goto out; 47038451Smsmith } 47138451Smsmith 47238451Smsmith /* allocate file system specific data structure */ 47338451Smsmith newfd = malloc(sizeof(*newfd)); 47438451Smsmith newfd->iodesc = currfd->iodesc; 47538451Smsmith newfd->off = 0; 47638451Smsmith 47738451Smsmith /* 47838451Smsmith * Get next component of path name. 47938451Smsmith */ 48038451Smsmith { 48192913Sobrien int len = 0; 48238451Smsmith 48338451Smsmith ncp = cp; 48438451Smsmith while ((c = *cp) != '\0' && c != '/') { 48538451Smsmith if (++len > NFS_MAXNAMLEN) { 48638451Smsmith error = ENOENT; 48738451Smsmith goto out; 48838451Smsmith } 48938451Smsmith cp++; 49038451Smsmith } 49138451Smsmith *cp = '\0'; 49238451Smsmith } 49338451Smsmith 49438451Smsmith /* lookup a file handle */ 49538451Smsmith error = nfs_lookupfh(currfd, ncp, newfd); 49638451Smsmith *cp = c; 49738451Smsmith if (error) 49838451Smsmith goto out; 49938451Smsmith 50038451Smsmith /* 50138451Smsmith * Check for symbolic link 50238451Smsmith */ 50338451Smsmith if (newfd->fa.fa_type == htonl(NFLNK)) { 50438451Smsmith int link_len, len; 50538451Smsmith 50638451Smsmith error = nfs_readlink(newfd, linkbuf); 50738451Smsmith if (error) 50838451Smsmith goto out; 50938451Smsmith 51038451Smsmith link_len = strlen(linkbuf); 51138451Smsmith len = strlen(cp); 51238451Smsmith 51338451Smsmith if (link_len + len > MAXPATHLEN 51438451Smsmith || ++nlinks > MAXSYMLINKS) { 51538451Smsmith error = ENOENT; 51638451Smsmith goto out; 51738451Smsmith } 51838451Smsmith 51938451Smsmith bcopy(cp, &namebuf[link_len], len + 1); 52038451Smsmith bcopy(linkbuf, namebuf, link_len); 52138451Smsmith 52238451Smsmith /* 52338451Smsmith * If absolute pathname, restart at root. 52438451Smsmith * If relative pathname, restart at parent directory. 52538451Smsmith */ 52638451Smsmith cp = namebuf; 52738451Smsmith if (*cp == '/') { 52838451Smsmith if (currfd != &nfs_root_node) 52938451Smsmith free(currfd); 53038451Smsmith currfd = &nfs_root_node; 53138451Smsmith } 53238451Smsmith 53338451Smsmith free(newfd); 53438451Smsmith newfd = 0; 53538451Smsmith 53638451Smsmith continue; 53738451Smsmith } 53838451Smsmith 53938451Smsmith if (currfd != &nfs_root_node) 54038451Smsmith free(currfd); 54138451Smsmith currfd = newfd; 54238451Smsmith newfd = 0; 54338451Smsmith } 54438451Smsmith 54538451Smsmith error = 0; 54638451Smsmith 54738451Smsmithout: 54838451Smsmith if (newfd) 54938451Smsmith free(newfd); 55039468Smsmith if (path) 55139468Smsmith free(path); 55238451Smsmith#else 55338451Smsmith /* allocate file system specific data structure */ 55438451Smsmith currfd = malloc(sizeof(*currfd)); 55538451Smsmith currfd->iodesc = desc; 55638451Smsmith currfd->off = 0; 55738451Smsmith 55839468Smsmith error = nfs_lookupfh(&nfs_root_node, upath, currfd); 55938451Smsmith#endif 56038451Smsmith if (!error) { 56138451Smsmith f->f_fsdata = (void *)currfd; 56238451Smsmith return (0); 56338451Smsmith } 56438451Smsmith 56538451Smsmith#ifdef NFS_DEBUG 56638451Smsmith if (debug) 56738451Smsmith printf("nfs_open: %s lookupfh failed: %s\n", 56838451Smsmith path, strerror(error)); 56938451Smsmith#endif 57038451Smsmith#ifndef NFS_NOSYMLINK 57138451Smsmith if (currfd != &nfs_root_node) 57238451Smsmith#endif 57338451Smsmith free(currfd); 57438451Smsmith 57538451Smsmith return (error); 57638451Smsmith} 57738451Smsmith 57838451Smsmithint 57938451Smsmithnfs_close(f) 58038451Smsmith struct open_file *f; 58138451Smsmith{ 58292913Sobrien struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; 58338451Smsmith 58438451Smsmith#ifdef NFS_DEBUG 58538451Smsmith if (debug) 58638451Smsmith printf("nfs_close: fp=0x%lx\n", (u_long)fp); 58738451Smsmith#endif 58838451Smsmith 58959824Sps if (fp != &nfs_root_node && fp) 59038451Smsmith free(fp); 59138451Smsmith f->f_fsdata = (void *)0; 59238451Smsmith 59338451Smsmith return (0); 59438451Smsmith} 59538451Smsmith 59638451Smsmith/* 59738451Smsmith * read a portion of a file 59838451Smsmith */ 59938451Smsmithint 60038451Smsmithnfs_read(f, buf, size, resid) 60138451Smsmith struct open_file *f; 60238451Smsmith void *buf; 60338451Smsmith size_t size; 60438451Smsmith size_t *resid; /* out */ 60538451Smsmith{ 60692913Sobrien struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; 60792913Sobrien ssize_t cc; 60892913Sobrien char *addr = buf; 60938451Smsmith 61038451Smsmith#ifdef NFS_DEBUG 61138451Smsmith if (debug) 61238451Smsmith printf("nfs_read: size=%lu off=%d\n", (u_long)size, 61338451Smsmith (int)fp->off); 61438451Smsmith#endif 61538451Smsmith while ((int)size > 0) { 61638451Smsmith twiddle(); 61738451Smsmith cc = nfs_readdata(fp, fp->off, (void *)addr, size); 61838451Smsmith /* XXX maybe should retry on certain errors */ 61938451Smsmith if (cc == -1) { 62038451Smsmith#ifdef NFS_DEBUG 62138451Smsmith if (debug) 62238451Smsmith printf("nfs_read: read: %s", strerror(errno)); 62338451Smsmith#endif 62438451Smsmith return (errno); /* XXX - from nfs_readdata */ 62538451Smsmith } 62638451Smsmith if (cc == 0) { 62738451Smsmith#ifdef NFS_DEBUG 62838451Smsmith if (debug) 62938451Smsmith printf("nfs_read: hit EOF unexpectantly"); 63038451Smsmith#endif 63138451Smsmith goto ret; 63238451Smsmith } 63338451Smsmith fp->off += cc; 63438451Smsmith addr += cc; 63538451Smsmith size -= cc; 63638451Smsmith } 63738451Smsmithret: 63838451Smsmith if (resid) 63938451Smsmith *resid = size; 64038451Smsmith 64138451Smsmith return (0); 64238451Smsmith} 64338451Smsmith 64438451Smsmith/* 64538451Smsmith * Not implemented. 64638451Smsmith */ 64738451Smsmithint 64838451Smsmithnfs_write(f, buf, size, resid) 64938451Smsmith struct open_file *f; 65038451Smsmith void *buf; 65138451Smsmith size_t size; 65238451Smsmith size_t *resid; /* out */ 65338451Smsmith{ 65438451Smsmith return (EROFS); 65538451Smsmith} 65638451Smsmith 65738451Smsmithoff_t 65838451Smsmithnfs_seek(f, offset, where) 65938451Smsmith struct open_file *f; 66038451Smsmith off_t offset; 66138451Smsmith int where; 66238451Smsmith{ 66392913Sobrien struct nfs_iodesc *d = (struct nfs_iodesc *)f->f_fsdata; 66438451Smsmith n_long size = ntohl(d->fa.fa_size); 66538451Smsmith 66638451Smsmith switch (where) { 66738451Smsmith case SEEK_SET: 66838451Smsmith d->off = offset; 66938451Smsmith break; 67038451Smsmith case SEEK_CUR: 67138451Smsmith d->off += offset; 67238451Smsmith break; 67338451Smsmith case SEEK_END: 67438451Smsmith d->off = size - offset; 67538451Smsmith break; 67638451Smsmith default: 677124811Sjhb errno = EINVAL; 67838451Smsmith return (-1); 67938451Smsmith } 68038451Smsmith 68138451Smsmith return (d->off); 68238451Smsmith} 68338451Smsmith 68438451Smsmith/* NFNON=0, NFREG=1, NFDIR=2, NFBLK=3, NFCHR=4, NFLNK=5 */ 68538451Smsmithint nfs_stat_types[8] = { 68638451Smsmith 0, S_IFREG, S_IFDIR, S_IFBLK, S_IFCHR, S_IFLNK, 0 }; 68738451Smsmith 68838451Smsmithint 68938451Smsmithnfs_stat(f, sb) 69038451Smsmith struct open_file *f; 69138451Smsmith struct stat *sb; 69238451Smsmith{ 69338451Smsmith struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; 69492913Sobrien n_long ftype, mode; 69538451Smsmith 69638451Smsmith ftype = ntohl(fp->fa.fa_type); 69738451Smsmith mode = ntohl(fp->fa.fa_mode); 69838451Smsmith mode |= nfs_stat_types[ftype & 7]; 69938451Smsmith 70038451Smsmith sb->st_mode = mode; 70138451Smsmith sb->st_nlink = ntohl(fp->fa.fa_nlink); 70238451Smsmith sb->st_uid = ntohl(fp->fa.fa_uid); 70338451Smsmith sb->st_gid = ntohl(fp->fa.fa_gid); 70438451Smsmith sb->st_size = ntohl(fp->fa.fa_size); 70538451Smsmith 70638451Smsmith return (0); 70738451Smsmith} 70859853Sps 70959853Spsstatic int 71059853Spsnfs_readdir(struct open_file *f, struct dirent *d) 71159853Sps{ 71292913Sobrien struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; 71359853Sps struct nfs_readdir_args *args; 71459853Sps struct nfs_readdir_data *rd; 71559853Sps struct nfs_readdir_off *roff = NULL; 71659853Sps static char *buf; 71759853Sps static n_long cookie = 0; 71859853Sps size_t cc; 71959853Sps n_long eof; 72059853Sps 72159853Sps struct { 72259853Sps n_long h[RPC_HEADER_WORDS]; 72359853Sps struct nfs_readdir_args d; 72459853Sps } sdata; 72559853Sps static struct { 72659853Sps n_long h[RPC_HEADER_WORDS]; 72759853Sps u_char d[NFS_READDIRSIZE]; 72859853Sps } rdata; 72959853Sps 73059853Sps if (cookie == 0) { 73159853Sps refill: 73259853Sps args = &sdata.d; 73359853Sps bzero(args, sizeof(*args)); 73459853Sps 73559853Sps bcopy(fp->fh, args->fh, NFS_FHSIZE); 73659853Sps args->cookie = htonl(cookie); 73759853Sps args->count = htonl(NFS_READDIRSIZE); 73859853Sps 73959853Sps cc = rpc_call(fp->iodesc, NFS_PROG, NFS_VER2, NFSPROC_READDIR, 74059853Sps args, sizeof(*args), 74159853Sps rdata.d, sizeof(rdata.d)); 74259853Sps buf = rdata.d; 74359853Sps roff = (struct nfs_readdir_off *)buf; 74459853Sps if (ntohl(roff->cookie) != 0) 745124811Sjhb return EIO; 74659853Sps } 74759853Sps roff = (struct nfs_readdir_off *)buf; 74859853Sps 74959853Sps if (ntohl(roff->follows) == 0) { 75059853Sps eof = ntohl((roff+1)->cookie); 75159853Sps if (eof) { 75259853Sps cookie = 0; 753124811Sjhb return ENOENT; 75459853Sps } 75559853Sps goto refill; 75659853Sps } 75759853Sps 75859853Sps buf += sizeof(struct nfs_readdir_off); 75959853Sps rd = (struct nfs_readdir_data *)buf; 76059853Sps d->d_namlen = ntohl(rd->len); 76159853Sps bcopy(rd->name, d->d_name, d->d_namlen); 76259853Sps d->d_name[d->d_namlen] = '\0'; 76359853Sps 76459853Sps buf += (sizeof(struct nfs_readdir_data) + roundup(htonl(rd->len),4)); 76559853Sps roff = (struct nfs_readdir_off *)buf; 76659853Sps cookie = ntohl(roff->cookie); 76759853Sps return 0; 76859853Sps} 769