1*58a2b000SEvgeniy Ivanov /* $NetBSD: nfs.c,v 1.47 2011/12/25 06:09:08 tsutsui Exp $ */ 2*58a2b000SEvgeniy Ivanov 3*58a2b000SEvgeniy Ivanov /*- 4*58a2b000SEvgeniy Ivanov * Copyright (c) 1993 John Brezak 5*58a2b000SEvgeniy Ivanov * All rights reserved. 6*58a2b000SEvgeniy Ivanov * 7*58a2b000SEvgeniy Ivanov * Redistribution and use in source and binary forms, with or without 8*58a2b000SEvgeniy Ivanov * modification, are permitted provided that the following conditions 9*58a2b000SEvgeniy Ivanov * are met: 10*58a2b000SEvgeniy Ivanov * 1. Redistributions of source code must retain the above copyright 11*58a2b000SEvgeniy Ivanov * notice, this list of conditions and the following disclaimer. 12*58a2b000SEvgeniy Ivanov * 2. Redistributions in binary form must reproduce the above copyright 13*58a2b000SEvgeniy Ivanov * notice, this list of conditions and the following disclaimer in the 14*58a2b000SEvgeniy Ivanov * documentation and/or other materials provided with the distribution. 15*58a2b000SEvgeniy Ivanov * 3. The name of the author may not be used to endorse or promote products 16*58a2b000SEvgeniy Ivanov * derived from this software without specific prior written permission. 17*58a2b000SEvgeniy Ivanov * 18*58a2b000SEvgeniy Ivanov * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR 19*58a2b000SEvgeniy Ivanov * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 20*58a2b000SEvgeniy Ivanov * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21*58a2b000SEvgeniy Ivanov * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 22*58a2b000SEvgeniy Ivanov * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 23*58a2b000SEvgeniy Ivanov * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24*58a2b000SEvgeniy Ivanov * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25*58a2b000SEvgeniy Ivanov * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 26*58a2b000SEvgeniy Ivanov * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 27*58a2b000SEvgeniy Ivanov * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28*58a2b000SEvgeniy Ivanov * POSSIBILITY OF SUCH DAMAGE. 29*58a2b000SEvgeniy Ivanov */ 30*58a2b000SEvgeniy Ivanov 31*58a2b000SEvgeniy Ivanov /* 32*58a2b000SEvgeniy Ivanov * XXX Does not currently implement: 33*58a2b000SEvgeniy Ivanov * XXX 34*58a2b000SEvgeniy Ivanov * XXX LIBSA_NO_FS_CLOSE 35*58a2b000SEvgeniy Ivanov * XXX LIBSA_NO_FS_SEEK 36*58a2b000SEvgeniy Ivanov * XXX LIBSA_NO_FS_WRITE 37*58a2b000SEvgeniy Ivanov * XXX LIBSA_NO_FS_SYMLINK (does this even make sense?) 38*58a2b000SEvgeniy Ivanov * XXX LIBSA_FS_SINGLECOMPONENT (does this even make sense?) 39*58a2b000SEvgeniy Ivanov */ 40*58a2b000SEvgeniy Ivanov 41*58a2b000SEvgeniy Ivanov #include <sys/param.h> 42*58a2b000SEvgeniy Ivanov #include <sys/time.h> 43*58a2b000SEvgeniy Ivanov #include <sys/socket.h> 44*58a2b000SEvgeniy Ivanov #include <sys/stat.h> 45*58a2b000SEvgeniy Ivanov #ifdef _STANDALONE 46*58a2b000SEvgeniy Ivanov #include <lib/libkern/libkern.h> 47*58a2b000SEvgeniy Ivanov #else 48*58a2b000SEvgeniy Ivanov #include <string.h> 49*58a2b000SEvgeniy Ivanov #endif 50*58a2b000SEvgeniy Ivanov 51*58a2b000SEvgeniy Ivanov #include <netinet/in.h> 52*58a2b000SEvgeniy Ivanov #include <netinet/in_systm.h> 53*58a2b000SEvgeniy Ivanov 54*58a2b000SEvgeniy Ivanov #include "rpcv2.h" 55*58a2b000SEvgeniy Ivanov #include "nfsv2.h" 56*58a2b000SEvgeniy Ivanov 57*58a2b000SEvgeniy Ivanov #include "stand.h" 58*58a2b000SEvgeniy Ivanov #include "net.h" 59*58a2b000SEvgeniy Ivanov #include "nfs.h" 60*58a2b000SEvgeniy Ivanov #include "rpc.h" 61*58a2b000SEvgeniy Ivanov 62*58a2b000SEvgeniy Ivanov /* Define our own NFS attributes */ 63*58a2b000SEvgeniy Ivanov struct nfsv2_fattrs { 64*58a2b000SEvgeniy Ivanov n_long fa_type; 65*58a2b000SEvgeniy Ivanov n_long fa_mode; 66*58a2b000SEvgeniy Ivanov n_long fa_nlink; 67*58a2b000SEvgeniy Ivanov n_long fa_uid; 68*58a2b000SEvgeniy Ivanov n_long fa_gid; 69*58a2b000SEvgeniy Ivanov n_long fa_size; 70*58a2b000SEvgeniy Ivanov n_long fa_blocksize; 71*58a2b000SEvgeniy Ivanov n_long fa_rdev; 72*58a2b000SEvgeniy Ivanov n_long fa_blocks; 73*58a2b000SEvgeniy Ivanov n_long fa_fsid; 74*58a2b000SEvgeniy Ivanov n_long fa_fileid; 75*58a2b000SEvgeniy Ivanov struct nfsv2_time fa_atime; 76*58a2b000SEvgeniy Ivanov struct nfsv2_time fa_mtime; 77*58a2b000SEvgeniy Ivanov struct nfsv2_time fa_ctime; 78*58a2b000SEvgeniy Ivanov }; 79*58a2b000SEvgeniy Ivanov 80*58a2b000SEvgeniy Ivanov 81*58a2b000SEvgeniy Ivanov struct nfs_read_args { 82*58a2b000SEvgeniy Ivanov u_char fh[NFS_FHSIZE]; 83*58a2b000SEvgeniy Ivanov n_long off; 84*58a2b000SEvgeniy Ivanov n_long len; 85*58a2b000SEvgeniy Ivanov n_long xxx; /* XXX what's this for? */ 86*58a2b000SEvgeniy Ivanov }; 87*58a2b000SEvgeniy Ivanov 88*58a2b000SEvgeniy Ivanov /* Data part of nfs rpc reply (also the largest thing we receive) */ 89*58a2b000SEvgeniy Ivanov #define NFSREAD_SIZE 1024 90*58a2b000SEvgeniy Ivanov struct nfs_read_repl { 91*58a2b000SEvgeniy Ivanov n_long errno; 92*58a2b000SEvgeniy Ivanov struct nfsv2_fattrs fa; 93*58a2b000SEvgeniy Ivanov n_long count; 94*58a2b000SEvgeniy Ivanov u_char data[NFSREAD_SIZE]; 95*58a2b000SEvgeniy Ivanov }; 96*58a2b000SEvgeniy Ivanov 97*58a2b000SEvgeniy Ivanov #ifndef NFS_NOSYMLINK 98*58a2b000SEvgeniy Ivanov struct nfs_readlnk_repl { 99*58a2b000SEvgeniy Ivanov n_long errno; 100*58a2b000SEvgeniy Ivanov n_long len; 101*58a2b000SEvgeniy Ivanov char path[NFS_MAXPATHLEN]; 102*58a2b000SEvgeniy Ivanov }; 103*58a2b000SEvgeniy Ivanov #endif 104*58a2b000SEvgeniy Ivanov 105*58a2b000SEvgeniy Ivanov struct nfs_iodesc { 106*58a2b000SEvgeniy Ivanov struct iodesc *iodesc; 107*58a2b000SEvgeniy Ivanov off_t off; 108*58a2b000SEvgeniy Ivanov u_char fh[NFS_FHSIZE]; 109*58a2b000SEvgeniy Ivanov struct nfsv2_fattrs fa; /* all in network order */ 110*58a2b000SEvgeniy Ivanov }; 111*58a2b000SEvgeniy Ivanov 112*58a2b000SEvgeniy Ivanov struct nfs_iodesc nfs_root_node; 113*58a2b000SEvgeniy Ivanov 114*58a2b000SEvgeniy Ivanov int nfs_getrootfh(struct iodesc *, char *, u_char *); 115*58a2b000SEvgeniy Ivanov int nfs_lookupfh(struct nfs_iodesc *, const char *, int, 116*58a2b000SEvgeniy Ivanov struct nfs_iodesc *); 117*58a2b000SEvgeniy Ivanov int nfs_readlink(struct nfs_iodesc *, char *); 118*58a2b000SEvgeniy Ivanov ssize_t nfs_readdata(struct nfs_iodesc *, off_t, void *, size_t); 119*58a2b000SEvgeniy Ivanov 120*58a2b000SEvgeniy Ivanov /* 121*58a2b000SEvgeniy Ivanov * Fetch the root file handle (call mount daemon) 122*58a2b000SEvgeniy Ivanov * On error, return non-zero and set errno. 123*58a2b000SEvgeniy Ivanov */ 124*58a2b000SEvgeniy Ivanov int 125*58a2b000SEvgeniy Ivanov nfs_getrootfh(struct iodesc *d, char *path, u_char *fhp) 126*58a2b000SEvgeniy Ivanov { 127*58a2b000SEvgeniy Ivanov int len; 128*58a2b000SEvgeniy Ivanov struct args { 129*58a2b000SEvgeniy Ivanov n_long len; 130*58a2b000SEvgeniy Ivanov char path[FNAME_SIZE]; 131*58a2b000SEvgeniy Ivanov } *args; 132*58a2b000SEvgeniy Ivanov struct repl { 133*58a2b000SEvgeniy Ivanov n_long errno; 134*58a2b000SEvgeniy Ivanov u_char fh[NFS_FHSIZE]; 135*58a2b000SEvgeniy Ivanov } *repl; 136*58a2b000SEvgeniy Ivanov struct { 137*58a2b000SEvgeniy Ivanov n_long h[RPC_HEADER_WORDS]; 138*58a2b000SEvgeniy Ivanov struct args d; 139*58a2b000SEvgeniy Ivanov } sdata; 140*58a2b000SEvgeniy Ivanov struct { 141*58a2b000SEvgeniy Ivanov n_long h[RPC_HEADER_WORDS]; 142*58a2b000SEvgeniy Ivanov struct repl d; 143*58a2b000SEvgeniy Ivanov } rdata; 144*58a2b000SEvgeniy Ivanov ssize_t cc; 145*58a2b000SEvgeniy Ivanov 146*58a2b000SEvgeniy Ivanov #ifdef NFS_DEBUG 147*58a2b000SEvgeniy Ivanov if (debug) 148*58a2b000SEvgeniy Ivanov printf("nfs_getrootfh: %s\n", path); 149*58a2b000SEvgeniy Ivanov #endif 150*58a2b000SEvgeniy Ivanov 151*58a2b000SEvgeniy Ivanov args = &sdata.d; 152*58a2b000SEvgeniy Ivanov repl = &rdata.d; 153*58a2b000SEvgeniy Ivanov 154*58a2b000SEvgeniy Ivanov (void)memset(args, 0, sizeof(*args)); 155*58a2b000SEvgeniy Ivanov len = strlen(path); 156*58a2b000SEvgeniy Ivanov if ((size_t)len > sizeof(args->path)) 157*58a2b000SEvgeniy Ivanov len = sizeof(args->path); 158*58a2b000SEvgeniy Ivanov args->len = htonl(len); 159*58a2b000SEvgeniy Ivanov (void)memcpy(args->path, path, len); 160*58a2b000SEvgeniy Ivanov len = 4 + roundup(len, 4); 161*58a2b000SEvgeniy Ivanov 162*58a2b000SEvgeniy Ivanov cc = rpc_call(d, RPCPROG_MNT, RPCMNT_VER1, RPCMNT_MOUNT, 163*58a2b000SEvgeniy Ivanov args, len, repl, sizeof(*repl)); 164*58a2b000SEvgeniy Ivanov if (cc == -1) { 165*58a2b000SEvgeniy Ivanov /* errno was set by rpc_call */ 166*58a2b000SEvgeniy Ivanov return -1; 167*58a2b000SEvgeniy Ivanov } 168*58a2b000SEvgeniy Ivanov if (cc < 4) { 169*58a2b000SEvgeniy Ivanov errno = EBADRPC; 170*58a2b000SEvgeniy Ivanov return -1; 171*58a2b000SEvgeniy Ivanov } 172*58a2b000SEvgeniy Ivanov if (repl->errno) { 173*58a2b000SEvgeniy Ivanov errno = ntohl(repl->errno); 174*58a2b000SEvgeniy Ivanov return -1; 175*58a2b000SEvgeniy Ivanov } 176*58a2b000SEvgeniy Ivanov (void)memcpy(fhp, repl->fh, sizeof(repl->fh)); 177*58a2b000SEvgeniy Ivanov return 0; 178*58a2b000SEvgeniy Ivanov } 179*58a2b000SEvgeniy Ivanov 180*58a2b000SEvgeniy Ivanov /* 181*58a2b000SEvgeniy Ivanov * Lookup a file. Store handle and attributes. 182*58a2b000SEvgeniy Ivanov * Return zero or error number. 183*58a2b000SEvgeniy Ivanov */ 184*58a2b000SEvgeniy Ivanov int 185*58a2b000SEvgeniy Ivanov nfs_lookupfh(struct nfs_iodesc *d, const char *name, int len, 186*58a2b000SEvgeniy Ivanov struct nfs_iodesc *newfd) 187*58a2b000SEvgeniy Ivanov { 188*58a2b000SEvgeniy Ivanov int rlen; 189*58a2b000SEvgeniy Ivanov struct args { 190*58a2b000SEvgeniy Ivanov u_char fh[NFS_FHSIZE]; 191*58a2b000SEvgeniy Ivanov n_long len; 192*58a2b000SEvgeniy Ivanov char name[FNAME_SIZE]; 193*58a2b000SEvgeniy Ivanov } *args; 194*58a2b000SEvgeniy Ivanov struct repl { 195*58a2b000SEvgeniy Ivanov n_long errno; 196*58a2b000SEvgeniy Ivanov u_char fh[NFS_FHSIZE]; 197*58a2b000SEvgeniy Ivanov struct nfsv2_fattrs fa; 198*58a2b000SEvgeniy Ivanov } *repl; 199*58a2b000SEvgeniy Ivanov struct { 200*58a2b000SEvgeniy Ivanov n_long h[RPC_HEADER_WORDS]; 201*58a2b000SEvgeniy Ivanov struct args d; 202*58a2b000SEvgeniy Ivanov } sdata; 203*58a2b000SEvgeniy Ivanov struct { 204*58a2b000SEvgeniy Ivanov n_long h[RPC_HEADER_WORDS]; 205*58a2b000SEvgeniy Ivanov struct repl d; 206*58a2b000SEvgeniy Ivanov } rdata; 207*58a2b000SEvgeniy Ivanov ssize_t cc; 208*58a2b000SEvgeniy Ivanov 209*58a2b000SEvgeniy Ivanov #ifdef NFS_DEBUG 210*58a2b000SEvgeniy Ivanov if (debug) 211*58a2b000SEvgeniy Ivanov printf("lookupfh: called\n"); 212*58a2b000SEvgeniy Ivanov #endif 213*58a2b000SEvgeniy Ivanov 214*58a2b000SEvgeniy Ivanov args = &sdata.d; 215*58a2b000SEvgeniy Ivanov repl = &rdata.d; 216*58a2b000SEvgeniy Ivanov 217*58a2b000SEvgeniy Ivanov (void)memset(args, 0, sizeof(*args)); 218*58a2b000SEvgeniy Ivanov (void)memcpy(args->fh, d->fh, sizeof(args->fh)); 219*58a2b000SEvgeniy Ivanov if ((size_t)len > sizeof(args->name)) 220*58a2b000SEvgeniy Ivanov len = sizeof(args->name); 221*58a2b000SEvgeniy Ivanov (void)memcpy(args->name, name, len); 222*58a2b000SEvgeniy Ivanov args->len = htonl(len); 223*58a2b000SEvgeniy Ivanov len = 4 + roundup(len, 4); 224*58a2b000SEvgeniy Ivanov len += NFS_FHSIZE; 225*58a2b000SEvgeniy Ivanov 226*58a2b000SEvgeniy Ivanov rlen = sizeof(*repl); 227*58a2b000SEvgeniy Ivanov 228*58a2b000SEvgeniy Ivanov cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER2, NFSPROC_LOOKUP, 229*58a2b000SEvgeniy Ivanov args, len, repl, rlen); 230*58a2b000SEvgeniy Ivanov if (cc == -1) 231*58a2b000SEvgeniy Ivanov return errno; /* XXX - from rpc_call */ 232*58a2b000SEvgeniy Ivanov if (cc < 4) 233*58a2b000SEvgeniy Ivanov return EIO; 234*58a2b000SEvgeniy Ivanov if (repl->errno) { 235*58a2b000SEvgeniy Ivanov /* saerrno.h now matches NFS error numbers. */ 236*58a2b000SEvgeniy Ivanov return ntohl(repl->errno); 237*58a2b000SEvgeniy Ivanov } 238*58a2b000SEvgeniy Ivanov (void)memcpy(&newfd->fh, repl->fh, sizeof(newfd->fh)); 239*58a2b000SEvgeniy Ivanov (void)memcpy(&newfd->fa, &repl->fa, sizeof(newfd->fa)); 240*58a2b000SEvgeniy Ivanov return 0; 241*58a2b000SEvgeniy Ivanov } 242*58a2b000SEvgeniy Ivanov 243*58a2b000SEvgeniy Ivanov #ifndef NFS_NOSYMLINK 244*58a2b000SEvgeniy Ivanov /* 245*58a2b000SEvgeniy Ivanov * Get the destination of a symbolic link. 246*58a2b000SEvgeniy Ivanov */ 247*58a2b000SEvgeniy Ivanov int 248*58a2b000SEvgeniy Ivanov nfs_readlink(struct nfs_iodesc *d, char *buf) 249*58a2b000SEvgeniy Ivanov { 250*58a2b000SEvgeniy Ivanov struct { 251*58a2b000SEvgeniy Ivanov n_long h[RPC_HEADER_WORDS]; 252*58a2b000SEvgeniy Ivanov u_char fh[NFS_FHSIZE]; 253*58a2b000SEvgeniy Ivanov } sdata; 254*58a2b000SEvgeniy Ivanov struct { 255*58a2b000SEvgeniy Ivanov n_long h[RPC_HEADER_WORDS]; 256*58a2b000SEvgeniy Ivanov struct nfs_readlnk_repl d; 257*58a2b000SEvgeniy Ivanov } rdata; 258*58a2b000SEvgeniy Ivanov ssize_t cc; 259*58a2b000SEvgeniy Ivanov 260*58a2b000SEvgeniy Ivanov #ifdef NFS_DEBUG 261*58a2b000SEvgeniy Ivanov if (debug) 262*58a2b000SEvgeniy Ivanov printf("readlink: called\n"); 263*58a2b000SEvgeniy Ivanov #endif 264*58a2b000SEvgeniy Ivanov 265*58a2b000SEvgeniy Ivanov (void)memcpy(sdata.fh, d->fh, NFS_FHSIZE); 266*58a2b000SEvgeniy Ivanov cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER2, NFSPROC_READLINK, 267*58a2b000SEvgeniy Ivanov sdata.fh, NFS_FHSIZE, 268*58a2b000SEvgeniy Ivanov &rdata.d, sizeof(rdata.d)); 269*58a2b000SEvgeniy Ivanov if (cc == -1) 270*58a2b000SEvgeniy Ivanov return errno; 271*58a2b000SEvgeniy Ivanov 272*58a2b000SEvgeniy Ivanov if (cc < 4) 273*58a2b000SEvgeniy Ivanov return EIO; 274*58a2b000SEvgeniy Ivanov 275*58a2b000SEvgeniy Ivanov if (rdata.d.errno) 276*58a2b000SEvgeniy Ivanov return ntohl(rdata.d.errno); 277*58a2b000SEvgeniy Ivanov 278*58a2b000SEvgeniy Ivanov rdata.d.len = ntohl(rdata.d.len); 279*58a2b000SEvgeniy Ivanov if (rdata.d.len > NFS_MAXPATHLEN) 280*58a2b000SEvgeniy Ivanov return ENAMETOOLONG; 281*58a2b000SEvgeniy Ivanov 282*58a2b000SEvgeniy Ivanov (void)memcpy(buf, rdata.d.path, rdata.d.len); 283*58a2b000SEvgeniy Ivanov buf[rdata.d.len] = 0; 284*58a2b000SEvgeniy Ivanov return 0; 285*58a2b000SEvgeniy Ivanov } 286*58a2b000SEvgeniy Ivanov #endif 287*58a2b000SEvgeniy Ivanov 288*58a2b000SEvgeniy Ivanov /* 289*58a2b000SEvgeniy Ivanov * Read data from a file. 290*58a2b000SEvgeniy Ivanov * Return transfer count or -1 (and set errno) 291*58a2b000SEvgeniy Ivanov */ 292*58a2b000SEvgeniy Ivanov ssize_t 293*58a2b000SEvgeniy Ivanov nfs_readdata(struct nfs_iodesc *d, off_t off, void *addr, size_t len) 294*58a2b000SEvgeniy Ivanov { 295*58a2b000SEvgeniy Ivanov struct nfs_read_args *args; 296*58a2b000SEvgeniy Ivanov struct nfs_read_repl *repl; 297*58a2b000SEvgeniy Ivanov struct { 298*58a2b000SEvgeniy Ivanov n_long h[RPC_HEADER_WORDS]; 299*58a2b000SEvgeniy Ivanov struct nfs_read_args d; 300*58a2b000SEvgeniy Ivanov } sdata; 301*58a2b000SEvgeniy Ivanov struct { 302*58a2b000SEvgeniy Ivanov n_long h[RPC_HEADER_WORDS]; 303*58a2b000SEvgeniy Ivanov struct nfs_read_repl d; 304*58a2b000SEvgeniy Ivanov } rdata; 305*58a2b000SEvgeniy Ivanov ssize_t cc; 306*58a2b000SEvgeniy Ivanov long x; 307*58a2b000SEvgeniy Ivanov size_t hlen, rlen; 308*58a2b000SEvgeniy Ivanov 309*58a2b000SEvgeniy Ivanov args = &sdata.d; 310*58a2b000SEvgeniy Ivanov repl = &rdata.d; 311*58a2b000SEvgeniy Ivanov 312*58a2b000SEvgeniy Ivanov (void)memcpy(args->fh, d->fh, NFS_FHSIZE); 313*58a2b000SEvgeniy Ivanov args->off = htonl((n_long)off); 314*58a2b000SEvgeniy Ivanov if (len > NFSREAD_SIZE) 315*58a2b000SEvgeniy Ivanov len = NFSREAD_SIZE; 316*58a2b000SEvgeniy Ivanov args->len = htonl((n_long)len); 317*58a2b000SEvgeniy Ivanov args->xxx = htonl((n_long)0); 318*58a2b000SEvgeniy Ivanov hlen = sizeof(*repl) - NFSREAD_SIZE; 319*58a2b000SEvgeniy Ivanov 320*58a2b000SEvgeniy Ivanov cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER2, NFSPROC_READ, 321*58a2b000SEvgeniy Ivanov args, sizeof(*args), 322*58a2b000SEvgeniy Ivanov repl, sizeof(*repl)); 323*58a2b000SEvgeniy Ivanov if (cc == -1) { 324*58a2b000SEvgeniy Ivanov /* errno was already set by rpc_call */ 325*58a2b000SEvgeniy Ivanov return -1; 326*58a2b000SEvgeniy Ivanov } 327*58a2b000SEvgeniy Ivanov if (cc < (ssize_t)hlen) { 328*58a2b000SEvgeniy Ivanov errno = EBADRPC; 329*58a2b000SEvgeniy Ivanov return -1; 330*58a2b000SEvgeniy Ivanov } 331*58a2b000SEvgeniy Ivanov if (repl->errno) { 332*58a2b000SEvgeniy Ivanov errno = ntohl(repl->errno); 333*58a2b000SEvgeniy Ivanov return -1; 334*58a2b000SEvgeniy Ivanov } 335*58a2b000SEvgeniy Ivanov rlen = cc - hlen; 336*58a2b000SEvgeniy Ivanov x = ntohl(repl->count); 337*58a2b000SEvgeniy Ivanov if (rlen < (size_t)x) { 338*58a2b000SEvgeniy Ivanov printf("nfsread: short packet, %lu < %ld\n", (u_long) rlen, x); 339*58a2b000SEvgeniy Ivanov errno = EBADRPC; 340*58a2b000SEvgeniy Ivanov return -1; 341*58a2b000SEvgeniy Ivanov } 342*58a2b000SEvgeniy Ivanov (void)memcpy(addr, repl->data, x); 343*58a2b000SEvgeniy Ivanov return x; 344*58a2b000SEvgeniy Ivanov } 345*58a2b000SEvgeniy Ivanov 346*58a2b000SEvgeniy Ivanov /* 347*58a2b000SEvgeniy Ivanov * nfs_mount - mount this nfs filesystem to a host 348*58a2b000SEvgeniy Ivanov * On error, return non-zero and set errno. 349*58a2b000SEvgeniy Ivanov */ 350*58a2b000SEvgeniy Ivanov int 351*58a2b000SEvgeniy Ivanov nfs_mount(int sock, struct in_addr ip, char *path) 352*58a2b000SEvgeniy Ivanov { 353*58a2b000SEvgeniy Ivanov struct iodesc *desc; 354*58a2b000SEvgeniy Ivanov struct nfsv2_fattrs *fa; 355*58a2b000SEvgeniy Ivanov 356*58a2b000SEvgeniy Ivanov if (!(desc = socktodesc(sock))) { 357*58a2b000SEvgeniy Ivanov errno = EINVAL; 358*58a2b000SEvgeniy Ivanov return -1; 359*58a2b000SEvgeniy Ivanov } 360*58a2b000SEvgeniy Ivanov 361*58a2b000SEvgeniy Ivanov /* Bind to a reserved port. */ 362*58a2b000SEvgeniy Ivanov desc->myport = htons(--rpc_port); 363*58a2b000SEvgeniy Ivanov desc->destip = ip; 364*58a2b000SEvgeniy Ivanov if (nfs_getrootfh(desc, path, nfs_root_node.fh)) 365*58a2b000SEvgeniy Ivanov return -1; 366*58a2b000SEvgeniy Ivanov nfs_root_node.iodesc = desc; 367*58a2b000SEvgeniy Ivanov /* Fake up attributes for the root dir. */ 368*58a2b000SEvgeniy Ivanov fa = &nfs_root_node.fa; 369*58a2b000SEvgeniy Ivanov fa->fa_type = htonl(NFDIR); 370*58a2b000SEvgeniy Ivanov fa->fa_mode = htonl(0755); 371*58a2b000SEvgeniy Ivanov fa->fa_nlink = htonl(2); 372*58a2b000SEvgeniy Ivanov 373*58a2b000SEvgeniy Ivanov #ifdef NFS_DEBUG 374*58a2b000SEvgeniy Ivanov if (debug) 375*58a2b000SEvgeniy Ivanov printf("nfs_mount: got fh for %s\n", path); 376*58a2b000SEvgeniy Ivanov #endif 377*58a2b000SEvgeniy Ivanov 378*58a2b000SEvgeniy Ivanov return 0; 379*58a2b000SEvgeniy Ivanov } 380*58a2b000SEvgeniy Ivanov 381*58a2b000SEvgeniy Ivanov /* 382*58a2b000SEvgeniy Ivanov * Open a file. 383*58a2b000SEvgeniy Ivanov * return zero or error number 384*58a2b000SEvgeniy Ivanov */ 385*58a2b000SEvgeniy Ivanov __compactcall int 386*58a2b000SEvgeniy Ivanov nfs_open(const char *path, struct open_file *f) 387*58a2b000SEvgeniy Ivanov { 388*58a2b000SEvgeniy Ivanov struct nfs_iodesc *newfd, *currfd; 389*58a2b000SEvgeniy Ivanov const char *cp; 390*58a2b000SEvgeniy Ivanov #ifndef NFS_NOSYMLINK 391*58a2b000SEvgeniy Ivanov const char *ncp; 392*58a2b000SEvgeniy Ivanov int c; 393*58a2b000SEvgeniy Ivanov char namebuf[NFS_MAXPATHLEN + 1]; 394*58a2b000SEvgeniy Ivanov char linkbuf[NFS_MAXPATHLEN + 1]; 395*58a2b000SEvgeniy Ivanov int nlinks = 0; 396*58a2b000SEvgeniy Ivanov #endif 397*58a2b000SEvgeniy Ivanov int error = 0; 398*58a2b000SEvgeniy Ivanov 399*58a2b000SEvgeniy Ivanov #ifdef NFS_DEBUG 400*58a2b000SEvgeniy Ivanov if (debug) 401*58a2b000SEvgeniy Ivanov printf("nfs_open: %s\n", path); 402*58a2b000SEvgeniy Ivanov #endif 403*58a2b000SEvgeniy Ivanov if (nfs_root_node.iodesc == NULL) { 404*58a2b000SEvgeniy Ivanov printf("nfs_open: must mount first.\n"); 405*58a2b000SEvgeniy Ivanov return ENXIO; 406*58a2b000SEvgeniy Ivanov } 407*58a2b000SEvgeniy Ivanov 408*58a2b000SEvgeniy Ivanov currfd = &nfs_root_node; 409*58a2b000SEvgeniy Ivanov newfd = 0; 410*58a2b000SEvgeniy Ivanov 411*58a2b000SEvgeniy Ivanov #ifndef NFS_NOSYMLINK 412*58a2b000SEvgeniy Ivanov cp = path; 413*58a2b000SEvgeniy Ivanov while (*cp) { 414*58a2b000SEvgeniy Ivanov /* 415*58a2b000SEvgeniy Ivanov * Remove extra separators 416*58a2b000SEvgeniy Ivanov */ 417*58a2b000SEvgeniy Ivanov while (*cp == '/') 418*58a2b000SEvgeniy Ivanov cp++; 419*58a2b000SEvgeniy Ivanov 420*58a2b000SEvgeniy Ivanov if (*cp == '\0') 421*58a2b000SEvgeniy Ivanov break; 422*58a2b000SEvgeniy Ivanov /* 423*58a2b000SEvgeniy Ivanov * Check that current node is a directory. 424*58a2b000SEvgeniy Ivanov */ 425*58a2b000SEvgeniy Ivanov if (currfd->fa.fa_type != htonl(NFDIR)) { 426*58a2b000SEvgeniy Ivanov error = ENOTDIR; 427*58a2b000SEvgeniy Ivanov goto out; 428*58a2b000SEvgeniy Ivanov } 429*58a2b000SEvgeniy Ivanov 430*58a2b000SEvgeniy Ivanov /* allocate file system specific data structure */ 431*58a2b000SEvgeniy Ivanov newfd = alloc(sizeof(*newfd)); 432*58a2b000SEvgeniy Ivanov newfd->iodesc = currfd->iodesc; 433*58a2b000SEvgeniy Ivanov newfd->off = 0; 434*58a2b000SEvgeniy Ivanov 435*58a2b000SEvgeniy Ivanov /* 436*58a2b000SEvgeniy Ivanov * Get next component of path name. 437*58a2b000SEvgeniy Ivanov */ 438*58a2b000SEvgeniy Ivanov { 439*58a2b000SEvgeniy Ivanov int len = 0; 440*58a2b000SEvgeniy Ivanov 441*58a2b000SEvgeniy Ivanov ncp = cp; 442*58a2b000SEvgeniy Ivanov while ((c = *cp) != '\0' && c != '/') { 443*58a2b000SEvgeniy Ivanov if (++len > NFS_MAXNAMLEN) { 444*58a2b000SEvgeniy Ivanov error = ENOENT; 445*58a2b000SEvgeniy Ivanov goto out; 446*58a2b000SEvgeniy Ivanov } 447*58a2b000SEvgeniy Ivanov cp++; 448*58a2b000SEvgeniy Ivanov } 449*58a2b000SEvgeniy Ivanov } 450*58a2b000SEvgeniy Ivanov 451*58a2b000SEvgeniy Ivanov /* lookup a file handle */ 452*58a2b000SEvgeniy Ivanov error = nfs_lookupfh(currfd, ncp, cp - ncp, newfd); 453*58a2b000SEvgeniy Ivanov if (error) 454*58a2b000SEvgeniy Ivanov goto out; 455*58a2b000SEvgeniy Ivanov 456*58a2b000SEvgeniy Ivanov /* 457*58a2b000SEvgeniy Ivanov * Check for symbolic link 458*58a2b000SEvgeniy Ivanov */ 459*58a2b000SEvgeniy Ivanov if (newfd->fa.fa_type == htonl(NFLNK)) { 460*58a2b000SEvgeniy Ivanov int link_len, len; 461*58a2b000SEvgeniy Ivanov 462*58a2b000SEvgeniy Ivanov error = nfs_readlink(newfd, linkbuf); 463*58a2b000SEvgeniy Ivanov if (error) 464*58a2b000SEvgeniy Ivanov goto out; 465*58a2b000SEvgeniy Ivanov 466*58a2b000SEvgeniy Ivanov link_len = strlen(linkbuf); 467*58a2b000SEvgeniy Ivanov len = strlen(cp); 468*58a2b000SEvgeniy Ivanov 469*58a2b000SEvgeniy Ivanov if (link_len + len > MAXPATHLEN 470*58a2b000SEvgeniy Ivanov || ++nlinks > MAXSYMLINKS) { 471*58a2b000SEvgeniy Ivanov error = ENOENT; 472*58a2b000SEvgeniy Ivanov goto out; 473*58a2b000SEvgeniy Ivanov } 474*58a2b000SEvgeniy Ivanov 475*58a2b000SEvgeniy Ivanov (void)memcpy(&namebuf[link_len], cp, len + 1); 476*58a2b000SEvgeniy Ivanov (void)memcpy(namebuf, linkbuf, link_len); 477*58a2b000SEvgeniy Ivanov 478*58a2b000SEvgeniy Ivanov /* 479*58a2b000SEvgeniy Ivanov * If absolute pathname, restart at root. 480*58a2b000SEvgeniy Ivanov * If relative pathname, restart at parent directory. 481*58a2b000SEvgeniy Ivanov */ 482*58a2b000SEvgeniy Ivanov cp = namebuf; 483*58a2b000SEvgeniy Ivanov if (*cp == '/') { 484*58a2b000SEvgeniy Ivanov if (currfd != &nfs_root_node) 485*58a2b000SEvgeniy Ivanov dealloc(currfd, sizeof(*currfd)); 486*58a2b000SEvgeniy Ivanov currfd = &nfs_root_node; 487*58a2b000SEvgeniy Ivanov } 488*58a2b000SEvgeniy Ivanov 489*58a2b000SEvgeniy Ivanov dealloc(newfd, sizeof(*newfd)); 490*58a2b000SEvgeniy Ivanov newfd = 0; 491*58a2b000SEvgeniy Ivanov 492*58a2b000SEvgeniy Ivanov continue; 493*58a2b000SEvgeniy Ivanov } 494*58a2b000SEvgeniy Ivanov 495*58a2b000SEvgeniy Ivanov if (currfd != &nfs_root_node) 496*58a2b000SEvgeniy Ivanov dealloc(currfd, sizeof(*currfd)); 497*58a2b000SEvgeniy Ivanov currfd = newfd; 498*58a2b000SEvgeniy Ivanov newfd = 0; 499*58a2b000SEvgeniy Ivanov } 500*58a2b000SEvgeniy Ivanov 501*58a2b000SEvgeniy Ivanov error = 0; 502*58a2b000SEvgeniy Ivanov 503*58a2b000SEvgeniy Ivanov out: 504*58a2b000SEvgeniy Ivanov #else 505*58a2b000SEvgeniy Ivanov /* allocate file system specific data structure */ 506*58a2b000SEvgeniy Ivanov currfd = alloc(sizeof(*currfd)); 507*58a2b000SEvgeniy Ivanov currfd->iodesc = nfs_root_node.iodesc; 508*58a2b000SEvgeniy Ivanov currfd->off = 0; 509*58a2b000SEvgeniy Ivanov 510*58a2b000SEvgeniy Ivanov cp = path; 511*58a2b000SEvgeniy Ivanov /* 512*58a2b000SEvgeniy Ivanov * Remove extra separators 513*58a2b000SEvgeniy Ivanov */ 514*58a2b000SEvgeniy Ivanov while (*cp == '/') 515*58a2b000SEvgeniy Ivanov cp++; 516*58a2b000SEvgeniy Ivanov 517*58a2b000SEvgeniy Ivanov /* XXX: Check for empty path here? */ 518*58a2b000SEvgeniy Ivanov 519*58a2b000SEvgeniy Ivanov error = nfs_lookupfh(&nfs_root_node, cp, strlen(cp), currfd); 520*58a2b000SEvgeniy Ivanov #endif 521*58a2b000SEvgeniy Ivanov if (!error) { 522*58a2b000SEvgeniy Ivanov f->f_fsdata = (void *)currfd; 523*58a2b000SEvgeniy Ivanov fsmod = "nfs"; 524*58a2b000SEvgeniy Ivanov return 0; 525*58a2b000SEvgeniy Ivanov } 526*58a2b000SEvgeniy Ivanov 527*58a2b000SEvgeniy Ivanov #ifdef NFS_DEBUG 528*58a2b000SEvgeniy Ivanov if (debug) 529*58a2b000SEvgeniy Ivanov printf("nfs_open: %s lookupfh failed: %s\n", 530*58a2b000SEvgeniy Ivanov path, strerror(error)); 531*58a2b000SEvgeniy Ivanov #endif 532*58a2b000SEvgeniy Ivanov if (currfd != &nfs_root_node) 533*58a2b000SEvgeniy Ivanov dealloc(currfd, sizeof(*currfd)); 534*58a2b000SEvgeniy Ivanov if (newfd) 535*58a2b000SEvgeniy Ivanov dealloc(newfd, sizeof(*newfd)); 536*58a2b000SEvgeniy Ivanov 537*58a2b000SEvgeniy Ivanov return error; 538*58a2b000SEvgeniy Ivanov } 539*58a2b000SEvgeniy Ivanov 540*58a2b000SEvgeniy Ivanov __compactcall int 541*58a2b000SEvgeniy Ivanov nfs_close(struct open_file *f) 542*58a2b000SEvgeniy Ivanov { 543*58a2b000SEvgeniy Ivanov struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; 544*58a2b000SEvgeniy Ivanov 545*58a2b000SEvgeniy Ivanov #ifdef NFS_DEBUG 546*58a2b000SEvgeniy Ivanov if (debug) 547*58a2b000SEvgeniy Ivanov printf("nfs_close: fp=0x%lx\n", (u_long)fp); 548*58a2b000SEvgeniy Ivanov #endif 549*58a2b000SEvgeniy Ivanov 550*58a2b000SEvgeniy Ivanov if (fp) 551*58a2b000SEvgeniy Ivanov dealloc(fp, sizeof(struct nfs_iodesc)); 552*58a2b000SEvgeniy Ivanov f->f_fsdata = (void *)0; 553*58a2b000SEvgeniy Ivanov 554*58a2b000SEvgeniy Ivanov return 0; 555*58a2b000SEvgeniy Ivanov } 556*58a2b000SEvgeniy Ivanov 557*58a2b000SEvgeniy Ivanov /* 558*58a2b000SEvgeniy Ivanov * read a portion of a file 559*58a2b000SEvgeniy Ivanov */ 560*58a2b000SEvgeniy Ivanov __compactcall int 561*58a2b000SEvgeniy Ivanov nfs_read(struct open_file *f, void *buf, size_t size, size_t *resid) 562*58a2b000SEvgeniy Ivanov { 563*58a2b000SEvgeniy Ivanov struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; 564*58a2b000SEvgeniy Ivanov ssize_t cc; 565*58a2b000SEvgeniy Ivanov char *addr = buf; 566*58a2b000SEvgeniy Ivanov 567*58a2b000SEvgeniy Ivanov #ifdef NFS_DEBUG 568*58a2b000SEvgeniy Ivanov if (debug) 569*58a2b000SEvgeniy Ivanov printf("nfs_read: size=%lu off=%d\n", (u_long)size, 570*58a2b000SEvgeniy Ivanov (int)fp->off); 571*58a2b000SEvgeniy Ivanov #endif 572*58a2b000SEvgeniy Ivanov while ((int)size > 0) { 573*58a2b000SEvgeniy Ivanov #if !defined(LIBSA_NO_TWIDDLE) 574*58a2b000SEvgeniy Ivanov twiddle(); 575*58a2b000SEvgeniy Ivanov #endif 576*58a2b000SEvgeniy Ivanov cc = nfs_readdata(fp, fp->off, (void *)addr, size); 577*58a2b000SEvgeniy Ivanov /* XXX maybe should retry on certain errors */ 578*58a2b000SEvgeniy Ivanov if (cc == -1) { 579*58a2b000SEvgeniy Ivanov #ifdef NFS_DEBUG 580*58a2b000SEvgeniy Ivanov if (debug) 581*58a2b000SEvgeniy Ivanov printf("nfs_read: read: %s\n", 582*58a2b000SEvgeniy Ivanov strerror(errno)); 583*58a2b000SEvgeniy Ivanov #endif 584*58a2b000SEvgeniy Ivanov return errno; /* XXX - from nfs_readdata */ 585*58a2b000SEvgeniy Ivanov } 586*58a2b000SEvgeniy Ivanov if (cc == 0) { 587*58a2b000SEvgeniy Ivanov #ifdef NFS_DEBUG 588*58a2b000SEvgeniy Ivanov if (debug) 589*58a2b000SEvgeniy Ivanov printf("nfs_read: hit EOF unexpectantly\n"); 590*58a2b000SEvgeniy Ivanov #endif 591*58a2b000SEvgeniy Ivanov goto ret; 592*58a2b000SEvgeniy Ivanov } 593*58a2b000SEvgeniy Ivanov fp->off += cc; 594*58a2b000SEvgeniy Ivanov addr += cc; 595*58a2b000SEvgeniy Ivanov size -= cc; 596*58a2b000SEvgeniy Ivanov } 597*58a2b000SEvgeniy Ivanov ret: 598*58a2b000SEvgeniy Ivanov if (resid) 599*58a2b000SEvgeniy Ivanov *resid = size; 600*58a2b000SEvgeniy Ivanov 601*58a2b000SEvgeniy Ivanov return 0; 602*58a2b000SEvgeniy Ivanov } 603*58a2b000SEvgeniy Ivanov 604*58a2b000SEvgeniy Ivanov /* 605*58a2b000SEvgeniy Ivanov * Not implemented. 606*58a2b000SEvgeniy Ivanov */ 607*58a2b000SEvgeniy Ivanov __compactcall int 608*58a2b000SEvgeniy Ivanov nfs_write(struct open_file *f, void *buf, size_t size, size_t *resid) 609*58a2b000SEvgeniy Ivanov { 610*58a2b000SEvgeniy Ivanov return EROFS; 611*58a2b000SEvgeniy Ivanov } 612*58a2b000SEvgeniy Ivanov 613*58a2b000SEvgeniy Ivanov __compactcall off_t 614*58a2b000SEvgeniy Ivanov nfs_seek(struct open_file *f, off_t offset, int where) 615*58a2b000SEvgeniy Ivanov { 616*58a2b000SEvgeniy Ivanov struct nfs_iodesc *d = (struct nfs_iodesc *)f->f_fsdata; 617*58a2b000SEvgeniy Ivanov n_long size = ntohl(d->fa.fa_size); 618*58a2b000SEvgeniy Ivanov 619*58a2b000SEvgeniy Ivanov switch (where) { 620*58a2b000SEvgeniy Ivanov case SEEK_SET: 621*58a2b000SEvgeniy Ivanov d->off = offset; 622*58a2b000SEvgeniy Ivanov break; 623*58a2b000SEvgeniy Ivanov case SEEK_CUR: 624*58a2b000SEvgeniy Ivanov d->off += offset; 625*58a2b000SEvgeniy Ivanov break; 626*58a2b000SEvgeniy Ivanov case SEEK_END: 627*58a2b000SEvgeniy Ivanov d->off = size - offset; 628*58a2b000SEvgeniy Ivanov break; 629*58a2b000SEvgeniy Ivanov default: 630*58a2b000SEvgeniy Ivanov return -1; 631*58a2b000SEvgeniy Ivanov } 632*58a2b000SEvgeniy Ivanov 633*58a2b000SEvgeniy Ivanov return d->off; 634*58a2b000SEvgeniy Ivanov } 635*58a2b000SEvgeniy Ivanov 636*58a2b000SEvgeniy Ivanov /* NFNON=0, NFREG=1, NFDIR=2, NFBLK=3, NFCHR=4, NFLNK=5 */ 637*58a2b000SEvgeniy Ivanov const int nfs_stat_types[8] = { 638*58a2b000SEvgeniy Ivanov 0, S_IFREG, S_IFDIR, S_IFBLK, S_IFCHR, S_IFLNK, 0 }; 639*58a2b000SEvgeniy Ivanov 640*58a2b000SEvgeniy Ivanov __compactcall int 641*58a2b000SEvgeniy Ivanov nfs_stat(struct open_file *f, struct stat *sb) 642*58a2b000SEvgeniy Ivanov { 643*58a2b000SEvgeniy Ivanov struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; 644*58a2b000SEvgeniy Ivanov n_long ftype, mode; 645*58a2b000SEvgeniy Ivanov 646*58a2b000SEvgeniy Ivanov ftype = ntohl(fp->fa.fa_type); 647*58a2b000SEvgeniy Ivanov mode = ntohl(fp->fa.fa_mode); 648*58a2b000SEvgeniy Ivanov mode |= nfs_stat_types[ftype & 7]; 649*58a2b000SEvgeniy Ivanov 650*58a2b000SEvgeniy Ivanov sb->st_mode = mode; 651*58a2b000SEvgeniy Ivanov sb->st_nlink = ntohl(fp->fa.fa_nlink); 652*58a2b000SEvgeniy Ivanov sb->st_uid = ntohl(fp->fa.fa_uid); 653*58a2b000SEvgeniy Ivanov sb->st_gid = ntohl(fp->fa.fa_gid); 654*58a2b000SEvgeniy Ivanov sb->st_size = ntohl(fp->fa.fa_size); 655*58a2b000SEvgeniy Ivanov 656*58a2b000SEvgeniy Ivanov return 0; 657*58a2b000SEvgeniy Ivanov } 658*58a2b000SEvgeniy Ivanov 659*58a2b000SEvgeniy Ivanov #if defined(LIBSA_ENABLE_LS_OP) 660*58a2b000SEvgeniy Ivanov __compactcall void 661*58a2b000SEvgeniy Ivanov nfs_ls(struct open_file *f, const char *pattern) 662*58a2b000SEvgeniy Ivanov { 663*58a2b000SEvgeniy Ivanov printf("Currently ls command is unsupported by nfs\n"); 664*58a2b000SEvgeniy Ivanov return; 665*58a2b000SEvgeniy Ivanov } 666*58a2b000SEvgeniy Ivanov #endif 667