1*0a6a1f1dSLionel Sambuc /* $NetBSD: nfs.c,v 1.48 2014/03/20 03:13:18 christos Exp $ */
258a2b000SEvgeniy Ivanov
358a2b000SEvgeniy Ivanov /*-
458a2b000SEvgeniy Ivanov * Copyright (c) 1993 John Brezak
558a2b000SEvgeniy Ivanov * All rights reserved.
658a2b000SEvgeniy Ivanov *
758a2b000SEvgeniy Ivanov * Redistribution and use in source and binary forms, with or without
858a2b000SEvgeniy Ivanov * modification, are permitted provided that the following conditions
958a2b000SEvgeniy Ivanov * are met:
1058a2b000SEvgeniy Ivanov * 1. Redistributions of source code must retain the above copyright
1158a2b000SEvgeniy Ivanov * notice, this list of conditions and the following disclaimer.
1258a2b000SEvgeniy Ivanov * 2. Redistributions in binary form must reproduce the above copyright
1358a2b000SEvgeniy Ivanov * notice, this list of conditions and the following disclaimer in the
1458a2b000SEvgeniy Ivanov * documentation and/or other materials provided with the distribution.
1558a2b000SEvgeniy Ivanov * 3. The name of the author may not be used to endorse or promote products
1658a2b000SEvgeniy Ivanov * derived from this software without specific prior written permission.
1758a2b000SEvgeniy Ivanov *
1858a2b000SEvgeniy Ivanov * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR
1958a2b000SEvgeniy Ivanov * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
2058a2b000SEvgeniy Ivanov * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
2158a2b000SEvgeniy Ivanov * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
2258a2b000SEvgeniy Ivanov * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
2358a2b000SEvgeniy Ivanov * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
2458a2b000SEvgeniy Ivanov * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2558a2b000SEvgeniy Ivanov * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
2658a2b000SEvgeniy Ivanov * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
2758a2b000SEvgeniy Ivanov * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
2858a2b000SEvgeniy Ivanov * POSSIBILITY OF SUCH DAMAGE.
2958a2b000SEvgeniy Ivanov */
3058a2b000SEvgeniy Ivanov
3158a2b000SEvgeniy Ivanov /*
3258a2b000SEvgeniy Ivanov * XXX Does not currently implement:
3358a2b000SEvgeniy Ivanov * XXX
3458a2b000SEvgeniy Ivanov * XXX LIBSA_NO_FS_CLOSE
3558a2b000SEvgeniy Ivanov * XXX LIBSA_NO_FS_SEEK
3658a2b000SEvgeniy Ivanov * XXX LIBSA_NO_FS_WRITE
3758a2b000SEvgeniy Ivanov * XXX LIBSA_NO_FS_SYMLINK (does this even make sense?)
3858a2b000SEvgeniy Ivanov * XXX LIBSA_FS_SINGLECOMPONENT (does this even make sense?)
3958a2b000SEvgeniy Ivanov */
4058a2b000SEvgeniy Ivanov
4158a2b000SEvgeniy Ivanov #include <sys/param.h>
4258a2b000SEvgeniy Ivanov #include <sys/time.h>
4358a2b000SEvgeniy Ivanov #include <sys/socket.h>
4458a2b000SEvgeniy Ivanov #include <sys/stat.h>
4558a2b000SEvgeniy Ivanov #ifdef _STANDALONE
4658a2b000SEvgeniy Ivanov #include <lib/libkern/libkern.h>
4758a2b000SEvgeniy Ivanov #else
4858a2b000SEvgeniy Ivanov #include <string.h>
4958a2b000SEvgeniy Ivanov #endif
5058a2b000SEvgeniy Ivanov
5158a2b000SEvgeniy Ivanov #include <netinet/in.h>
5258a2b000SEvgeniy Ivanov #include <netinet/in_systm.h>
5358a2b000SEvgeniy Ivanov
5458a2b000SEvgeniy Ivanov #include "rpcv2.h"
5558a2b000SEvgeniy Ivanov #include "nfsv2.h"
5658a2b000SEvgeniy Ivanov
5758a2b000SEvgeniy Ivanov #include "stand.h"
5858a2b000SEvgeniy Ivanov #include "net.h"
5958a2b000SEvgeniy Ivanov #include "nfs.h"
6058a2b000SEvgeniy Ivanov #include "rpc.h"
6158a2b000SEvgeniy Ivanov
6258a2b000SEvgeniy Ivanov /* Define our own NFS attributes */
6358a2b000SEvgeniy Ivanov struct nfsv2_fattrs {
6458a2b000SEvgeniy Ivanov n_long fa_type;
6558a2b000SEvgeniy Ivanov n_long fa_mode;
6658a2b000SEvgeniy Ivanov n_long fa_nlink;
6758a2b000SEvgeniy Ivanov n_long fa_uid;
6858a2b000SEvgeniy Ivanov n_long fa_gid;
6958a2b000SEvgeniy Ivanov n_long fa_size;
7058a2b000SEvgeniy Ivanov n_long fa_blocksize;
7158a2b000SEvgeniy Ivanov n_long fa_rdev;
7258a2b000SEvgeniy Ivanov n_long fa_blocks;
7358a2b000SEvgeniy Ivanov n_long fa_fsid;
7458a2b000SEvgeniy Ivanov n_long fa_fileid;
7558a2b000SEvgeniy Ivanov struct nfsv2_time fa_atime;
7658a2b000SEvgeniy Ivanov struct nfsv2_time fa_mtime;
7758a2b000SEvgeniy Ivanov struct nfsv2_time fa_ctime;
7858a2b000SEvgeniy Ivanov };
7958a2b000SEvgeniy Ivanov
8058a2b000SEvgeniy Ivanov
8158a2b000SEvgeniy Ivanov struct nfs_read_args {
8258a2b000SEvgeniy Ivanov u_char fh[NFS_FHSIZE];
8358a2b000SEvgeniy Ivanov n_long off;
8458a2b000SEvgeniy Ivanov n_long len;
8558a2b000SEvgeniy Ivanov n_long xxx; /* XXX what's this for? */
8658a2b000SEvgeniy Ivanov };
8758a2b000SEvgeniy Ivanov
8858a2b000SEvgeniy Ivanov /* Data part of nfs rpc reply (also the largest thing we receive) */
8958a2b000SEvgeniy Ivanov #define NFSREAD_SIZE 1024
9058a2b000SEvgeniy Ivanov struct nfs_read_repl {
9158a2b000SEvgeniy Ivanov n_long errno;
9258a2b000SEvgeniy Ivanov struct nfsv2_fattrs fa;
9358a2b000SEvgeniy Ivanov n_long count;
9458a2b000SEvgeniy Ivanov u_char data[NFSREAD_SIZE];
9558a2b000SEvgeniy Ivanov };
9658a2b000SEvgeniy Ivanov
9758a2b000SEvgeniy Ivanov #ifndef NFS_NOSYMLINK
9858a2b000SEvgeniy Ivanov struct nfs_readlnk_repl {
9958a2b000SEvgeniy Ivanov n_long errno;
10058a2b000SEvgeniy Ivanov n_long len;
10158a2b000SEvgeniy Ivanov char path[NFS_MAXPATHLEN];
10258a2b000SEvgeniy Ivanov };
10358a2b000SEvgeniy Ivanov #endif
10458a2b000SEvgeniy Ivanov
10558a2b000SEvgeniy Ivanov struct nfs_iodesc {
10658a2b000SEvgeniy Ivanov struct iodesc *iodesc;
10758a2b000SEvgeniy Ivanov off_t off;
10858a2b000SEvgeniy Ivanov u_char fh[NFS_FHSIZE];
10958a2b000SEvgeniy Ivanov struct nfsv2_fattrs fa; /* all in network order */
11058a2b000SEvgeniy Ivanov };
11158a2b000SEvgeniy Ivanov
11258a2b000SEvgeniy Ivanov struct nfs_iodesc nfs_root_node;
11358a2b000SEvgeniy Ivanov
11458a2b000SEvgeniy Ivanov int nfs_getrootfh(struct iodesc *, char *, u_char *);
11558a2b000SEvgeniy Ivanov int nfs_lookupfh(struct nfs_iodesc *, const char *, int,
11658a2b000SEvgeniy Ivanov struct nfs_iodesc *);
11758a2b000SEvgeniy Ivanov int nfs_readlink(struct nfs_iodesc *, char *);
11858a2b000SEvgeniy Ivanov ssize_t nfs_readdata(struct nfs_iodesc *, off_t, void *, size_t);
11958a2b000SEvgeniy Ivanov
12058a2b000SEvgeniy Ivanov /*
12158a2b000SEvgeniy Ivanov * Fetch the root file handle (call mount daemon)
12258a2b000SEvgeniy Ivanov * On error, return non-zero and set errno.
12358a2b000SEvgeniy Ivanov */
12458a2b000SEvgeniy Ivanov int
nfs_getrootfh(struct iodesc * d,char * path,u_char * fhp)12558a2b000SEvgeniy Ivanov nfs_getrootfh(struct iodesc *d, char *path, u_char *fhp)
12658a2b000SEvgeniy Ivanov {
12758a2b000SEvgeniy Ivanov int len;
12858a2b000SEvgeniy Ivanov struct args {
12958a2b000SEvgeniy Ivanov n_long len;
13058a2b000SEvgeniy Ivanov char path[FNAME_SIZE];
13158a2b000SEvgeniy Ivanov } *args;
13258a2b000SEvgeniy Ivanov struct repl {
13358a2b000SEvgeniy Ivanov n_long errno;
13458a2b000SEvgeniy Ivanov u_char fh[NFS_FHSIZE];
13558a2b000SEvgeniy Ivanov } *repl;
13658a2b000SEvgeniy Ivanov struct {
13758a2b000SEvgeniy Ivanov n_long h[RPC_HEADER_WORDS];
13858a2b000SEvgeniy Ivanov struct args d;
13958a2b000SEvgeniy Ivanov } sdata;
14058a2b000SEvgeniy Ivanov struct {
14158a2b000SEvgeniy Ivanov n_long h[RPC_HEADER_WORDS];
14258a2b000SEvgeniy Ivanov struct repl d;
14358a2b000SEvgeniy Ivanov } rdata;
14458a2b000SEvgeniy Ivanov ssize_t cc;
14558a2b000SEvgeniy Ivanov
14658a2b000SEvgeniy Ivanov #ifdef NFS_DEBUG
14758a2b000SEvgeniy Ivanov if (debug)
14858a2b000SEvgeniy Ivanov printf("nfs_getrootfh: %s\n", path);
14958a2b000SEvgeniy Ivanov #endif
15058a2b000SEvgeniy Ivanov
15158a2b000SEvgeniy Ivanov args = &sdata.d;
15258a2b000SEvgeniy Ivanov repl = &rdata.d;
15358a2b000SEvgeniy Ivanov
15458a2b000SEvgeniy Ivanov (void)memset(args, 0, sizeof(*args));
15558a2b000SEvgeniy Ivanov len = strlen(path);
15658a2b000SEvgeniy Ivanov if ((size_t)len > sizeof(args->path))
15758a2b000SEvgeniy Ivanov len = sizeof(args->path);
15858a2b000SEvgeniy Ivanov args->len = htonl(len);
15958a2b000SEvgeniy Ivanov (void)memcpy(args->path, path, len);
16058a2b000SEvgeniy Ivanov len = 4 + roundup(len, 4);
16158a2b000SEvgeniy Ivanov
16258a2b000SEvgeniy Ivanov cc = rpc_call(d, RPCPROG_MNT, RPCMNT_VER1, RPCMNT_MOUNT,
16358a2b000SEvgeniy Ivanov args, len, repl, sizeof(*repl));
16458a2b000SEvgeniy Ivanov if (cc == -1) {
16558a2b000SEvgeniy Ivanov /* errno was set by rpc_call */
16658a2b000SEvgeniy Ivanov return -1;
16758a2b000SEvgeniy Ivanov }
16858a2b000SEvgeniy Ivanov if (cc < 4) {
16958a2b000SEvgeniy Ivanov errno = EBADRPC;
17058a2b000SEvgeniy Ivanov return -1;
17158a2b000SEvgeniy Ivanov }
17258a2b000SEvgeniy Ivanov if (repl->errno) {
17358a2b000SEvgeniy Ivanov errno = ntohl(repl->errno);
17458a2b000SEvgeniy Ivanov return -1;
17558a2b000SEvgeniy Ivanov }
17658a2b000SEvgeniy Ivanov (void)memcpy(fhp, repl->fh, sizeof(repl->fh));
17758a2b000SEvgeniy Ivanov return 0;
17858a2b000SEvgeniy Ivanov }
17958a2b000SEvgeniy Ivanov
18058a2b000SEvgeniy Ivanov /*
18158a2b000SEvgeniy Ivanov * Lookup a file. Store handle and attributes.
18258a2b000SEvgeniy Ivanov * Return zero or error number.
18358a2b000SEvgeniy Ivanov */
18458a2b000SEvgeniy Ivanov int
nfs_lookupfh(struct nfs_iodesc * d,const char * name,int len,struct nfs_iodesc * newfd)18558a2b000SEvgeniy Ivanov nfs_lookupfh(struct nfs_iodesc *d, const char *name, int len,
18658a2b000SEvgeniy Ivanov struct nfs_iodesc *newfd)
18758a2b000SEvgeniy Ivanov {
18858a2b000SEvgeniy Ivanov int rlen;
18958a2b000SEvgeniy Ivanov struct args {
19058a2b000SEvgeniy Ivanov u_char fh[NFS_FHSIZE];
19158a2b000SEvgeniy Ivanov n_long len;
19258a2b000SEvgeniy Ivanov char name[FNAME_SIZE];
19358a2b000SEvgeniy Ivanov } *args;
19458a2b000SEvgeniy Ivanov struct repl {
19558a2b000SEvgeniy Ivanov n_long errno;
19658a2b000SEvgeniy Ivanov u_char fh[NFS_FHSIZE];
19758a2b000SEvgeniy Ivanov struct nfsv2_fattrs fa;
19858a2b000SEvgeniy Ivanov } *repl;
19958a2b000SEvgeniy Ivanov struct {
20058a2b000SEvgeniy Ivanov n_long h[RPC_HEADER_WORDS];
20158a2b000SEvgeniy Ivanov struct args d;
20258a2b000SEvgeniy Ivanov } sdata;
20358a2b000SEvgeniy Ivanov struct {
20458a2b000SEvgeniy Ivanov n_long h[RPC_HEADER_WORDS];
20558a2b000SEvgeniy Ivanov struct repl d;
20658a2b000SEvgeniy Ivanov } rdata;
20758a2b000SEvgeniy Ivanov ssize_t cc;
20858a2b000SEvgeniy Ivanov
20958a2b000SEvgeniy Ivanov #ifdef NFS_DEBUG
21058a2b000SEvgeniy Ivanov if (debug)
21158a2b000SEvgeniy Ivanov printf("lookupfh: called\n");
21258a2b000SEvgeniy Ivanov #endif
21358a2b000SEvgeniy Ivanov
21458a2b000SEvgeniy Ivanov args = &sdata.d;
21558a2b000SEvgeniy Ivanov repl = &rdata.d;
21658a2b000SEvgeniy Ivanov
21758a2b000SEvgeniy Ivanov (void)memset(args, 0, sizeof(*args));
21858a2b000SEvgeniy Ivanov (void)memcpy(args->fh, d->fh, sizeof(args->fh));
21958a2b000SEvgeniy Ivanov if ((size_t)len > sizeof(args->name))
22058a2b000SEvgeniy Ivanov len = sizeof(args->name);
22158a2b000SEvgeniy Ivanov (void)memcpy(args->name, name, len);
22258a2b000SEvgeniy Ivanov args->len = htonl(len);
22358a2b000SEvgeniy Ivanov len = 4 + roundup(len, 4);
22458a2b000SEvgeniy Ivanov len += NFS_FHSIZE;
22558a2b000SEvgeniy Ivanov
22658a2b000SEvgeniy Ivanov rlen = sizeof(*repl);
22758a2b000SEvgeniy Ivanov
22858a2b000SEvgeniy Ivanov cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER2, NFSPROC_LOOKUP,
22958a2b000SEvgeniy Ivanov args, len, repl, rlen);
23058a2b000SEvgeniy Ivanov if (cc == -1)
23158a2b000SEvgeniy Ivanov return errno; /* XXX - from rpc_call */
23258a2b000SEvgeniy Ivanov if (cc < 4)
23358a2b000SEvgeniy Ivanov return EIO;
23458a2b000SEvgeniy Ivanov if (repl->errno) {
23558a2b000SEvgeniy Ivanov /* saerrno.h now matches NFS error numbers. */
23658a2b000SEvgeniy Ivanov return ntohl(repl->errno);
23758a2b000SEvgeniy Ivanov }
23858a2b000SEvgeniy Ivanov (void)memcpy(&newfd->fh, repl->fh, sizeof(newfd->fh));
23958a2b000SEvgeniy Ivanov (void)memcpy(&newfd->fa, &repl->fa, sizeof(newfd->fa));
24058a2b000SEvgeniy Ivanov return 0;
24158a2b000SEvgeniy Ivanov }
24258a2b000SEvgeniy Ivanov
24358a2b000SEvgeniy Ivanov #ifndef NFS_NOSYMLINK
24458a2b000SEvgeniy Ivanov /*
24558a2b000SEvgeniy Ivanov * Get the destination of a symbolic link.
24658a2b000SEvgeniy Ivanov */
24758a2b000SEvgeniy Ivanov int
nfs_readlink(struct nfs_iodesc * d,char * buf)24858a2b000SEvgeniy Ivanov nfs_readlink(struct nfs_iodesc *d, char *buf)
24958a2b000SEvgeniy Ivanov {
25058a2b000SEvgeniy Ivanov struct {
25158a2b000SEvgeniy Ivanov n_long h[RPC_HEADER_WORDS];
25258a2b000SEvgeniy Ivanov u_char fh[NFS_FHSIZE];
25358a2b000SEvgeniy Ivanov } sdata;
25458a2b000SEvgeniy Ivanov struct {
25558a2b000SEvgeniy Ivanov n_long h[RPC_HEADER_WORDS];
25658a2b000SEvgeniy Ivanov struct nfs_readlnk_repl d;
25758a2b000SEvgeniy Ivanov } rdata;
25858a2b000SEvgeniy Ivanov ssize_t cc;
25958a2b000SEvgeniy Ivanov
26058a2b000SEvgeniy Ivanov #ifdef NFS_DEBUG
26158a2b000SEvgeniy Ivanov if (debug)
26258a2b000SEvgeniy Ivanov printf("readlink: called\n");
26358a2b000SEvgeniy Ivanov #endif
26458a2b000SEvgeniy Ivanov
26558a2b000SEvgeniy Ivanov (void)memcpy(sdata.fh, d->fh, NFS_FHSIZE);
26658a2b000SEvgeniy Ivanov cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER2, NFSPROC_READLINK,
26758a2b000SEvgeniy Ivanov sdata.fh, NFS_FHSIZE,
26858a2b000SEvgeniy Ivanov &rdata.d, sizeof(rdata.d));
26958a2b000SEvgeniy Ivanov if (cc == -1)
27058a2b000SEvgeniy Ivanov return errno;
27158a2b000SEvgeniy Ivanov
27258a2b000SEvgeniy Ivanov if (cc < 4)
27358a2b000SEvgeniy Ivanov return EIO;
27458a2b000SEvgeniy Ivanov
27558a2b000SEvgeniy Ivanov if (rdata.d.errno)
27658a2b000SEvgeniy Ivanov return ntohl(rdata.d.errno);
27758a2b000SEvgeniy Ivanov
27858a2b000SEvgeniy Ivanov rdata.d.len = ntohl(rdata.d.len);
27958a2b000SEvgeniy Ivanov if (rdata.d.len > NFS_MAXPATHLEN)
28058a2b000SEvgeniy Ivanov return ENAMETOOLONG;
28158a2b000SEvgeniy Ivanov
28258a2b000SEvgeniy Ivanov (void)memcpy(buf, rdata.d.path, rdata.d.len);
28358a2b000SEvgeniy Ivanov buf[rdata.d.len] = 0;
28458a2b000SEvgeniy Ivanov return 0;
28558a2b000SEvgeniy Ivanov }
28658a2b000SEvgeniy Ivanov #endif
28758a2b000SEvgeniy Ivanov
28858a2b000SEvgeniy Ivanov /*
28958a2b000SEvgeniy Ivanov * Read data from a file.
29058a2b000SEvgeniy Ivanov * Return transfer count or -1 (and set errno)
29158a2b000SEvgeniy Ivanov */
29258a2b000SEvgeniy Ivanov ssize_t
nfs_readdata(struct nfs_iodesc * d,off_t off,void * addr,size_t len)29358a2b000SEvgeniy Ivanov nfs_readdata(struct nfs_iodesc *d, off_t off, void *addr, size_t len)
29458a2b000SEvgeniy Ivanov {
29558a2b000SEvgeniy Ivanov struct nfs_read_args *args;
29658a2b000SEvgeniy Ivanov struct nfs_read_repl *repl;
29758a2b000SEvgeniy Ivanov struct {
29858a2b000SEvgeniy Ivanov n_long h[RPC_HEADER_WORDS];
29958a2b000SEvgeniy Ivanov struct nfs_read_args d;
30058a2b000SEvgeniy Ivanov } sdata;
30158a2b000SEvgeniy Ivanov struct {
30258a2b000SEvgeniy Ivanov n_long h[RPC_HEADER_WORDS];
30358a2b000SEvgeniy Ivanov struct nfs_read_repl d;
30458a2b000SEvgeniy Ivanov } rdata;
30558a2b000SEvgeniy Ivanov ssize_t cc;
30658a2b000SEvgeniy Ivanov long x;
30758a2b000SEvgeniy Ivanov size_t hlen, rlen;
30858a2b000SEvgeniy Ivanov
30958a2b000SEvgeniy Ivanov args = &sdata.d;
31058a2b000SEvgeniy Ivanov repl = &rdata.d;
31158a2b000SEvgeniy Ivanov
31258a2b000SEvgeniy Ivanov (void)memcpy(args->fh, d->fh, NFS_FHSIZE);
31358a2b000SEvgeniy Ivanov args->off = htonl((n_long)off);
31458a2b000SEvgeniy Ivanov if (len > NFSREAD_SIZE)
31558a2b000SEvgeniy Ivanov len = NFSREAD_SIZE;
31658a2b000SEvgeniy Ivanov args->len = htonl((n_long)len);
31758a2b000SEvgeniy Ivanov args->xxx = htonl((n_long)0);
31858a2b000SEvgeniy Ivanov hlen = sizeof(*repl) - NFSREAD_SIZE;
31958a2b000SEvgeniy Ivanov
32058a2b000SEvgeniy Ivanov cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER2, NFSPROC_READ,
32158a2b000SEvgeniy Ivanov args, sizeof(*args),
32258a2b000SEvgeniy Ivanov repl, sizeof(*repl));
32358a2b000SEvgeniy Ivanov if (cc == -1) {
32458a2b000SEvgeniy Ivanov /* errno was already set by rpc_call */
32558a2b000SEvgeniy Ivanov return -1;
32658a2b000SEvgeniy Ivanov }
32758a2b000SEvgeniy Ivanov if (cc < (ssize_t)hlen) {
32858a2b000SEvgeniy Ivanov errno = EBADRPC;
32958a2b000SEvgeniy Ivanov return -1;
33058a2b000SEvgeniy Ivanov }
33158a2b000SEvgeniy Ivanov if (repl->errno) {
33258a2b000SEvgeniy Ivanov errno = ntohl(repl->errno);
33358a2b000SEvgeniy Ivanov return -1;
33458a2b000SEvgeniy Ivanov }
33558a2b000SEvgeniy Ivanov rlen = cc - hlen;
33658a2b000SEvgeniy Ivanov x = ntohl(repl->count);
33758a2b000SEvgeniy Ivanov if (rlen < (size_t)x) {
33858a2b000SEvgeniy Ivanov printf("nfsread: short packet, %lu < %ld\n", (u_long) rlen, x);
33958a2b000SEvgeniy Ivanov errno = EBADRPC;
34058a2b000SEvgeniy Ivanov return -1;
34158a2b000SEvgeniy Ivanov }
34258a2b000SEvgeniy Ivanov (void)memcpy(addr, repl->data, x);
34358a2b000SEvgeniy Ivanov return x;
34458a2b000SEvgeniy Ivanov }
34558a2b000SEvgeniy Ivanov
34658a2b000SEvgeniy Ivanov /*
34758a2b000SEvgeniy Ivanov * nfs_mount - mount this nfs filesystem to a host
34858a2b000SEvgeniy Ivanov * On error, return non-zero and set errno.
34958a2b000SEvgeniy Ivanov */
35058a2b000SEvgeniy Ivanov int
nfs_mount(int sock,struct in_addr ip,char * path)35158a2b000SEvgeniy Ivanov nfs_mount(int sock, struct in_addr ip, char *path)
35258a2b000SEvgeniy Ivanov {
35358a2b000SEvgeniy Ivanov struct iodesc *desc;
35458a2b000SEvgeniy Ivanov struct nfsv2_fattrs *fa;
35558a2b000SEvgeniy Ivanov
35658a2b000SEvgeniy Ivanov if (!(desc = socktodesc(sock))) {
35758a2b000SEvgeniy Ivanov errno = EINVAL;
35858a2b000SEvgeniy Ivanov return -1;
35958a2b000SEvgeniy Ivanov }
36058a2b000SEvgeniy Ivanov
36158a2b000SEvgeniy Ivanov /* Bind to a reserved port. */
36258a2b000SEvgeniy Ivanov desc->myport = htons(--rpc_port);
36358a2b000SEvgeniy Ivanov desc->destip = ip;
36458a2b000SEvgeniy Ivanov if (nfs_getrootfh(desc, path, nfs_root_node.fh))
36558a2b000SEvgeniy Ivanov return -1;
36658a2b000SEvgeniy Ivanov nfs_root_node.iodesc = desc;
36758a2b000SEvgeniy Ivanov /* Fake up attributes for the root dir. */
36858a2b000SEvgeniy Ivanov fa = &nfs_root_node.fa;
36958a2b000SEvgeniy Ivanov fa->fa_type = htonl(NFDIR);
37058a2b000SEvgeniy Ivanov fa->fa_mode = htonl(0755);
37158a2b000SEvgeniy Ivanov fa->fa_nlink = htonl(2);
37258a2b000SEvgeniy Ivanov
37358a2b000SEvgeniy Ivanov #ifdef NFS_DEBUG
37458a2b000SEvgeniy Ivanov if (debug)
37558a2b000SEvgeniy Ivanov printf("nfs_mount: got fh for %s\n", path);
37658a2b000SEvgeniy Ivanov #endif
37758a2b000SEvgeniy Ivanov
37858a2b000SEvgeniy Ivanov return 0;
37958a2b000SEvgeniy Ivanov }
38058a2b000SEvgeniy Ivanov
38158a2b000SEvgeniy Ivanov /*
38258a2b000SEvgeniy Ivanov * Open a file.
38358a2b000SEvgeniy Ivanov * return zero or error number
38458a2b000SEvgeniy Ivanov */
38558a2b000SEvgeniy Ivanov __compactcall int
nfs_open(const char * path,struct open_file * f)38658a2b000SEvgeniy Ivanov nfs_open(const char *path, struct open_file *f)
38758a2b000SEvgeniy Ivanov {
38858a2b000SEvgeniy Ivanov struct nfs_iodesc *newfd, *currfd;
38958a2b000SEvgeniy Ivanov const char *cp;
39058a2b000SEvgeniy Ivanov #ifndef NFS_NOSYMLINK
39158a2b000SEvgeniy Ivanov const char *ncp;
39258a2b000SEvgeniy Ivanov int c;
39358a2b000SEvgeniy Ivanov char namebuf[NFS_MAXPATHLEN + 1];
39458a2b000SEvgeniy Ivanov char linkbuf[NFS_MAXPATHLEN + 1];
39558a2b000SEvgeniy Ivanov int nlinks = 0;
39658a2b000SEvgeniy Ivanov #endif
39758a2b000SEvgeniy Ivanov int error = 0;
39858a2b000SEvgeniy Ivanov
39958a2b000SEvgeniy Ivanov #ifdef NFS_DEBUG
40058a2b000SEvgeniy Ivanov if (debug)
40158a2b000SEvgeniy Ivanov printf("nfs_open: %s\n", path);
40258a2b000SEvgeniy Ivanov #endif
40358a2b000SEvgeniy Ivanov if (nfs_root_node.iodesc == NULL) {
40458a2b000SEvgeniy Ivanov printf("nfs_open: must mount first.\n");
40558a2b000SEvgeniy Ivanov return ENXIO;
40658a2b000SEvgeniy Ivanov }
40758a2b000SEvgeniy Ivanov
40858a2b000SEvgeniy Ivanov currfd = &nfs_root_node;
40958a2b000SEvgeniy Ivanov newfd = 0;
41058a2b000SEvgeniy Ivanov
41158a2b000SEvgeniy Ivanov #ifndef NFS_NOSYMLINK
41258a2b000SEvgeniy Ivanov cp = path;
41358a2b000SEvgeniy Ivanov while (*cp) {
41458a2b000SEvgeniy Ivanov /*
41558a2b000SEvgeniy Ivanov * Remove extra separators
41658a2b000SEvgeniy Ivanov */
41758a2b000SEvgeniy Ivanov while (*cp == '/')
41858a2b000SEvgeniy Ivanov cp++;
41958a2b000SEvgeniy Ivanov
42058a2b000SEvgeniy Ivanov if (*cp == '\0')
42158a2b000SEvgeniy Ivanov break;
42258a2b000SEvgeniy Ivanov /*
42358a2b000SEvgeniy Ivanov * Check that current node is a directory.
42458a2b000SEvgeniy Ivanov */
42558a2b000SEvgeniy Ivanov if (currfd->fa.fa_type != htonl(NFDIR)) {
42658a2b000SEvgeniy Ivanov error = ENOTDIR;
42758a2b000SEvgeniy Ivanov goto out;
42858a2b000SEvgeniy Ivanov }
42958a2b000SEvgeniy Ivanov
43058a2b000SEvgeniy Ivanov /* allocate file system specific data structure */
43158a2b000SEvgeniy Ivanov newfd = alloc(sizeof(*newfd));
43258a2b000SEvgeniy Ivanov newfd->iodesc = currfd->iodesc;
43358a2b000SEvgeniy Ivanov newfd->off = 0;
43458a2b000SEvgeniy Ivanov
43558a2b000SEvgeniy Ivanov /*
43658a2b000SEvgeniy Ivanov * Get next component of path name.
43758a2b000SEvgeniy Ivanov */
43858a2b000SEvgeniy Ivanov {
43958a2b000SEvgeniy Ivanov int len = 0;
44058a2b000SEvgeniy Ivanov
44158a2b000SEvgeniy Ivanov ncp = cp;
44258a2b000SEvgeniy Ivanov while ((c = *cp) != '\0' && c != '/') {
44358a2b000SEvgeniy Ivanov if (++len > NFS_MAXNAMLEN) {
44458a2b000SEvgeniy Ivanov error = ENOENT;
44558a2b000SEvgeniy Ivanov goto out;
44658a2b000SEvgeniy Ivanov }
44758a2b000SEvgeniy Ivanov cp++;
44858a2b000SEvgeniy Ivanov }
44958a2b000SEvgeniy Ivanov }
45058a2b000SEvgeniy Ivanov
45158a2b000SEvgeniy Ivanov /* lookup a file handle */
45258a2b000SEvgeniy Ivanov error = nfs_lookupfh(currfd, ncp, cp - ncp, newfd);
45358a2b000SEvgeniy Ivanov if (error)
45458a2b000SEvgeniy Ivanov goto out;
45558a2b000SEvgeniy Ivanov
45658a2b000SEvgeniy Ivanov /*
45758a2b000SEvgeniy Ivanov * Check for symbolic link
45858a2b000SEvgeniy Ivanov */
45958a2b000SEvgeniy Ivanov if (newfd->fa.fa_type == htonl(NFLNK)) {
46058a2b000SEvgeniy Ivanov int link_len, len;
46158a2b000SEvgeniy Ivanov
46258a2b000SEvgeniy Ivanov error = nfs_readlink(newfd, linkbuf);
46358a2b000SEvgeniy Ivanov if (error)
46458a2b000SEvgeniy Ivanov goto out;
46558a2b000SEvgeniy Ivanov
46658a2b000SEvgeniy Ivanov link_len = strlen(linkbuf);
46758a2b000SEvgeniy Ivanov len = strlen(cp);
46858a2b000SEvgeniy Ivanov
46958a2b000SEvgeniy Ivanov if (link_len + len > MAXPATHLEN
47058a2b000SEvgeniy Ivanov || ++nlinks > MAXSYMLINKS) {
47158a2b000SEvgeniy Ivanov error = ENOENT;
47258a2b000SEvgeniy Ivanov goto out;
47358a2b000SEvgeniy Ivanov }
47458a2b000SEvgeniy Ivanov
47558a2b000SEvgeniy Ivanov (void)memcpy(&namebuf[link_len], cp, len + 1);
47658a2b000SEvgeniy Ivanov (void)memcpy(namebuf, linkbuf, link_len);
47758a2b000SEvgeniy Ivanov
47858a2b000SEvgeniy Ivanov /*
47958a2b000SEvgeniy Ivanov * If absolute pathname, restart at root.
48058a2b000SEvgeniy Ivanov * If relative pathname, restart at parent directory.
48158a2b000SEvgeniy Ivanov */
48258a2b000SEvgeniy Ivanov cp = namebuf;
48358a2b000SEvgeniy Ivanov if (*cp == '/') {
48458a2b000SEvgeniy Ivanov if (currfd != &nfs_root_node)
48558a2b000SEvgeniy Ivanov dealloc(currfd, sizeof(*currfd));
48658a2b000SEvgeniy Ivanov currfd = &nfs_root_node;
48758a2b000SEvgeniy Ivanov }
48858a2b000SEvgeniy Ivanov
48958a2b000SEvgeniy Ivanov dealloc(newfd, sizeof(*newfd));
49058a2b000SEvgeniy Ivanov newfd = 0;
49158a2b000SEvgeniy Ivanov
49258a2b000SEvgeniy Ivanov continue;
49358a2b000SEvgeniy Ivanov }
49458a2b000SEvgeniy Ivanov
49558a2b000SEvgeniy Ivanov if (currfd != &nfs_root_node)
49658a2b000SEvgeniy Ivanov dealloc(currfd, sizeof(*currfd));
49758a2b000SEvgeniy Ivanov currfd = newfd;
49858a2b000SEvgeniy Ivanov newfd = 0;
49958a2b000SEvgeniy Ivanov }
50058a2b000SEvgeniy Ivanov
50158a2b000SEvgeniy Ivanov error = 0;
50258a2b000SEvgeniy Ivanov
50358a2b000SEvgeniy Ivanov out:
50458a2b000SEvgeniy Ivanov #else
50558a2b000SEvgeniy Ivanov /* allocate file system specific data structure */
50658a2b000SEvgeniy Ivanov currfd = alloc(sizeof(*currfd));
50758a2b000SEvgeniy Ivanov currfd->iodesc = nfs_root_node.iodesc;
50858a2b000SEvgeniy Ivanov currfd->off = 0;
50958a2b000SEvgeniy Ivanov
51058a2b000SEvgeniy Ivanov cp = path;
51158a2b000SEvgeniy Ivanov /*
51258a2b000SEvgeniy Ivanov * Remove extra separators
51358a2b000SEvgeniy Ivanov */
51458a2b000SEvgeniy Ivanov while (*cp == '/')
51558a2b000SEvgeniy Ivanov cp++;
51658a2b000SEvgeniy Ivanov
51758a2b000SEvgeniy Ivanov /* XXX: Check for empty path here? */
51858a2b000SEvgeniy Ivanov
51958a2b000SEvgeniy Ivanov error = nfs_lookupfh(&nfs_root_node, cp, strlen(cp), currfd);
52058a2b000SEvgeniy Ivanov #endif
52158a2b000SEvgeniy Ivanov if (!error) {
52258a2b000SEvgeniy Ivanov f->f_fsdata = (void *)currfd;
52358a2b000SEvgeniy Ivanov fsmod = "nfs";
52458a2b000SEvgeniy Ivanov return 0;
52558a2b000SEvgeniy Ivanov }
52658a2b000SEvgeniy Ivanov
52758a2b000SEvgeniy Ivanov #ifdef NFS_DEBUG
52858a2b000SEvgeniy Ivanov if (debug)
52958a2b000SEvgeniy Ivanov printf("nfs_open: %s lookupfh failed: %s\n",
53058a2b000SEvgeniy Ivanov path, strerror(error));
53158a2b000SEvgeniy Ivanov #endif
53258a2b000SEvgeniy Ivanov if (currfd != &nfs_root_node)
53358a2b000SEvgeniy Ivanov dealloc(currfd, sizeof(*currfd));
53458a2b000SEvgeniy Ivanov if (newfd)
53558a2b000SEvgeniy Ivanov dealloc(newfd, sizeof(*newfd));
53658a2b000SEvgeniy Ivanov
53758a2b000SEvgeniy Ivanov return error;
53858a2b000SEvgeniy Ivanov }
53958a2b000SEvgeniy Ivanov
54058a2b000SEvgeniy Ivanov __compactcall int
nfs_close(struct open_file * f)54158a2b000SEvgeniy Ivanov nfs_close(struct open_file *f)
54258a2b000SEvgeniy Ivanov {
54358a2b000SEvgeniy Ivanov struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
54458a2b000SEvgeniy Ivanov
54558a2b000SEvgeniy Ivanov #ifdef NFS_DEBUG
54658a2b000SEvgeniy Ivanov if (debug)
54758a2b000SEvgeniy Ivanov printf("nfs_close: fp=0x%lx\n", (u_long)fp);
54858a2b000SEvgeniy Ivanov #endif
54958a2b000SEvgeniy Ivanov
55058a2b000SEvgeniy Ivanov if (fp)
55158a2b000SEvgeniy Ivanov dealloc(fp, sizeof(struct nfs_iodesc));
55258a2b000SEvgeniy Ivanov f->f_fsdata = (void *)0;
55358a2b000SEvgeniy Ivanov
55458a2b000SEvgeniy Ivanov return 0;
55558a2b000SEvgeniy Ivanov }
55658a2b000SEvgeniy Ivanov
55758a2b000SEvgeniy Ivanov /*
55858a2b000SEvgeniy Ivanov * read a portion of a file
55958a2b000SEvgeniy Ivanov */
56058a2b000SEvgeniy Ivanov __compactcall int
nfs_read(struct open_file * f,void * buf,size_t size,size_t * resid)56158a2b000SEvgeniy Ivanov nfs_read(struct open_file *f, void *buf, size_t size, size_t *resid)
56258a2b000SEvgeniy Ivanov {
56358a2b000SEvgeniy Ivanov struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
56458a2b000SEvgeniy Ivanov ssize_t cc;
56558a2b000SEvgeniy Ivanov char *addr = buf;
56658a2b000SEvgeniy Ivanov
56758a2b000SEvgeniy Ivanov #ifdef NFS_DEBUG
56858a2b000SEvgeniy Ivanov if (debug)
56958a2b000SEvgeniy Ivanov printf("nfs_read: size=%lu off=%d\n", (u_long)size,
57058a2b000SEvgeniy Ivanov (int)fp->off);
57158a2b000SEvgeniy Ivanov #endif
57258a2b000SEvgeniy Ivanov while ((int)size > 0) {
57358a2b000SEvgeniy Ivanov #if !defined(LIBSA_NO_TWIDDLE)
57458a2b000SEvgeniy Ivanov twiddle();
57558a2b000SEvgeniy Ivanov #endif
57658a2b000SEvgeniy Ivanov cc = nfs_readdata(fp, fp->off, (void *)addr, size);
57758a2b000SEvgeniy Ivanov /* XXX maybe should retry on certain errors */
57858a2b000SEvgeniy Ivanov if (cc == -1) {
57958a2b000SEvgeniy Ivanov #ifdef NFS_DEBUG
58058a2b000SEvgeniy Ivanov if (debug)
58158a2b000SEvgeniy Ivanov printf("nfs_read: read: %s\n",
58258a2b000SEvgeniy Ivanov strerror(errno));
58358a2b000SEvgeniy Ivanov #endif
58458a2b000SEvgeniy Ivanov return errno; /* XXX - from nfs_readdata */
58558a2b000SEvgeniy Ivanov }
58658a2b000SEvgeniy Ivanov if (cc == 0) {
58758a2b000SEvgeniy Ivanov #ifdef NFS_DEBUG
58858a2b000SEvgeniy Ivanov if (debug)
58958a2b000SEvgeniy Ivanov printf("nfs_read: hit EOF unexpectantly\n");
59058a2b000SEvgeniy Ivanov #endif
59158a2b000SEvgeniy Ivanov goto ret;
59258a2b000SEvgeniy Ivanov }
59358a2b000SEvgeniy Ivanov fp->off += cc;
59458a2b000SEvgeniy Ivanov addr += cc;
59558a2b000SEvgeniy Ivanov size -= cc;
59658a2b000SEvgeniy Ivanov }
59758a2b000SEvgeniy Ivanov ret:
59858a2b000SEvgeniy Ivanov if (resid)
59958a2b000SEvgeniy Ivanov *resid = size;
60058a2b000SEvgeniy Ivanov
60158a2b000SEvgeniy Ivanov return 0;
60258a2b000SEvgeniy Ivanov }
60358a2b000SEvgeniy Ivanov
60458a2b000SEvgeniy Ivanov /*
60558a2b000SEvgeniy Ivanov * Not implemented.
60658a2b000SEvgeniy Ivanov */
60758a2b000SEvgeniy Ivanov __compactcall int
nfs_write(struct open_file * f,void * buf,size_t size,size_t * resid)60858a2b000SEvgeniy Ivanov nfs_write(struct open_file *f, void *buf, size_t size, size_t *resid)
60958a2b000SEvgeniy Ivanov {
61058a2b000SEvgeniy Ivanov return EROFS;
61158a2b000SEvgeniy Ivanov }
61258a2b000SEvgeniy Ivanov
61358a2b000SEvgeniy Ivanov __compactcall off_t
nfs_seek(struct open_file * f,off_t offset,int where)61458a2b000SEvgeniy Ivanov nfs_seek(struct open_file *f, off_t offset, int where)
61558a2b000SEvgeniy Ivanov {
61658a2b000SEvgeniy Ivanov struct nfs_iodesc *d = (struct nfs_iodesc *)f->f_fsdata;
61758a2b000SEvgeniy Ivanov n_long size = ntohl(d->fa.fa_size);
61858a2b000SEvgeniy Ivanov
61958a2b000SEvgeniy Ivanov switch (where) {
62058a2b000SEvgeniy Ivanov case SEEK_SET:
62158a2b000SEvgeniy Ivanov d->off = offset;
62258a2b000SEvgeniy Ivanov break;
62358a2b000SEvgeniy Ivanov case SEEK_CUR:
62458a2b000SEvgeniy Ivanov d->off += offset;
62558a2b000SEvgeniy Ivanov break;
62658a2b000SEvgeniy Ivanov case SEEK_END:
62758a2b000SEvgeniy Ivanov d->off = size - offset;
62858a2b000SEvgeniy Ivanov break;
62958a2b000SEvgeniy Ivanov default:
63058a2b000SEvgeniy Ivanov return -1;
63158a2b000SEvgeniy Ivanov }
63258a2b000SEvgeniy Ivanov
63358a2b000SEvgeniy Ivanov return d->off;
63458a2b000SEvgeniy Ivanov }
63558a2b000SEvgeniy Ivanov
63658a2b000SEvgeniy Ivanov /* NFNON=0, NFREG=1, NFDIR=2, NFBLK=3, NFCHR=4, NFLNK=5 */
63758a2b000SEvgeniy Ivanov const int nfs_stat_types[8] = {
63858a2b000SEvgeniy Ivanov 0, S_IFREG, S_IFDIR, S_IFBLK, S_IFCHR, S_IFLNK, 0 };
63958a2b000SEvgeniy Ivanov
64058a2b000SEvgeniy Ivanov __compactcall int
nfs_stat(struct open_file * f,struct stat * sb)64158a2b000SEvgeniy Ivanov nfs_stat(struct open_file *f, struct stat *sb)
64258a2b000SEvgeniy Ivanov {
64358a2b000SEvgeniy Ivanov struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
64458a2b000SEvgeniy Ivanov n_long ftype, mode;
64558a2b000SEvgeniy Ivanov
64658a2b000SEvgeniy Ivanov ftype = ntohl(fp->fa.fa_type);
64758a2b000SEvgeniy Ivanov mode = ntohl(fp->fa.fa_mode);
64858a2b000SEvgeniy Ivanov mode |= nfs_stat_types[ftype & 7];
64958a2b000SEvgeniy Ivanov
65058a2b000SEvgeniy Ivanov sb->st_mode = mode;
65158a2b000SEvgeniy Ivanov sb->st_nlink = ntohl(fp->fa.fa_nlink);
65258a2b000SEvgeniy Ivanov sb->st_uid = ntohl(fp->fa.fa_uid);
65358a2b000SEvgeniy Ivanov sb->st_gid = ntohl(fp->fa.fa_gid);
65458a2b000SEvgeniy Ivanov sb->st_size = ntohl(fp->fa.fa_size);
65558a2b000SEvgeniy Ivanov
65658a2b000SEvgeniy Ivanov return 0;
65758a2b000SEvgeniy Ivanov }
65858a2b000SEvgeniy Ivanov
65958a2b000SEvgeniy Ivanov #if defined(LIBSA_ENABLE_LS_OP)
660*0a6a1f1dSLionel Sambuc #include "ls.h"
66158a2b000SEvgeniy Ivanov __compactcall void
nfs_ls(struct open_file * f,const char * pattern)662*0a6a1f1dSLionel Sambuc nfs_ls(struct open_file *f, const char *pattern)
66358a2b000SEvgeniy Ivanov {
664*0a6a1f1dSLionel Sambuc lsunsup("nfs");
66558a2b000SEvgeniy Ivanov }
66658a2b000SEvgeniy Ivanov #endif
667