1 1.53 rin /* $NetBSD: nfs.c,v 1.53 2024/06/29 07:49:36 rin Exp $ */ 2 1.4 cgd 3 1.1 brezak /*- 4 1.1 brezak * Copyright (c) 1993 John Brezak 5 1.1 brezak * All rights reserved. 6 1.37 perry * 7 1.1 brezak * Redistribution and use in source and binary forms, with or without 8 1.1 brezak * modification, are permitted provided that the following conditions 9 1.1 brezak * are met: 10 1.1 brezak * 1. Redistributions of source code must retain the above copyright 11 1.1 brezak * notice, this list of conditions and the following disclaimer. 12 1.1 brezak * 2. Redistributions in binary form must reproduce the above copyright 13 1.1 brezak * notice, this list of conditions and the following disclaimer in the 14 1.1 brezak * documentation and/or other materials provided with the distribution. 15 1.1 brezak * 3. The name of the author may not be used to endorse or promote products 16 1.1 brezak * derived from this software without specific prior written permission. 17 1.37 perry * 18 1.1 brezak * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR 19 1.1 brezak * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 20 1.1 brezak * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 1.1 brezak * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 22 1.1 brezak * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 23 1.1 brezak * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 1.1 brezak * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 1.1 brezak * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 26 1.1 brezak * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 27 1.1 brezak * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 1.1 brezak * POSSIBILITY OF SUCH DAMAGE. 29 1.1 brezak */ 30 1.1 brezak 31 1.25 cgd /* 32 1.25 cgd * XXX Does not currently implement: 33 1.25 cgd * XXX 34 1.25 cgd * XXX LIBSA_NO_FS_CLOSE 35 1.25 cgd * XXX LIBSA_NO_FS_SEEK 36 1.25 cgd * XXX LIBSA_NO_FS_WRITE 37 1.25 cgd * XXX LIBSA_NO_FS_SYMLINK (does this even make sense?) 38 1.25 cgd * XXX LIBSA_FS_SINGLECOMPONENT (does this even make sense?) 39 1.25 cgd */ 40 1.25 cgd 41 1.1 brezak #include <sys/param.h> 42 1.1 brezak #include <sys/time.h> 43 1.1 brezak #include <sys/socket.h> 44 1.1 brezak #include <sys/stat.h> 45 1.27 thorpej #ifdef _STANDALONE 46 1.27 thorpej #include <lib/libkern/libkern.h> 47 1.27 thorpej #else 48 1.27 thorpej #include <string.h> 49 1.27 thorpej #endif 50 1.1 brezak 51 1.1 brezak #include <netinet/in.h> 52 1.1 brezak #include <netinet/in_systm.h> 53 1.1 brezak 54 1.14 gwr #include "rpcv2.h" 55 1.13 scottr #include "nfsv2.h" 56 1.51 mlelstv #include "nfsv3.h" 57 1.1 brezak 58 1.1 brezak #include "stand.h" 59 1.1 brezak #include "net.h" 60 1.1 brezak #include "nfs.h" 61 1.1 brezak #include "rpc.h" 62 1.1 brezak 63 1.51 mlelstv /* Storage for any filehandle (including length for V3) */ 64 1.51 mlelstv #define NFS_FHSTORE (NFS_FHSIZE < NFS_V3FHSIZE ? NFS_V3FHSIZE + 4: NFS_FHSIZE) 65 1.1 brezak 66 1.1 brezak /* Data part of nfs rpc reply (also the largest thing we receive) */ 67 1.7 gwr #define NFSREAD_SIZE 1024 68 1.1 brezak 69 1.21 drochner #ifndef NFS_NOSYMLINK 70 1.16 ws struct nfs_readlnk_repl { 71 1.16 ws n_long errno; 72 1.16 ws n_long len; 73 1.16 ws char path[NFS_MAXPATHLEN]; 74 1.16 ws }; 75 1.21 drochner #endif 76 1.16 ws 77 1.51 mlelstv static inline uint64_t 78 1.51 mlelstv getnquad(n_long x[2]) { 79 1.51 mlelstv return (uint64_t)ntohl(x[0]) << 32 | ntohl(x[1]); 80 1.51 mlelstv } 81 1.51 mlelstv 82 1.51 mlelstv static inline void 83 1.51 mlelstv setnquad(n_long x[2], uint64_t v) 84 1.51 mlelstv { 85 1.51 mlelstv x[0] = htonl((n_long)(v >> 32)); 86 1.51 mlelstv x[1] = htonl((n_long)(v & 0xffffffff)); 87 1.51 mlelstv } 88 1.51 mlelstv 89 1.1 brezak struct nfs_iodesc { 90 1.7 gwr struct iodesc *iodesc; 91 1.1 brezak off_t off; 92 1.51 mlelstv int version; 93 1.51 mlelstv u_char fh[NFS_FHSTORE]; 94 1.51 mlelstv union { 95 1.51 mlelstv /* all in network order */ 96 1.51 mlelstv struct nfsv2_fattr v2; 97 1.51 mlelstv struct nfsv3_fattr v3; 98 1.51 mlelstv } u_fa; 99 1.7 gwr }; 100 1.7 gwr 101 1.51 mlelstv static inline size_t 102 1.51 mlelstv fhstore(int version, u_char *fh) 103 1.51 mlelstv { 104 1.51 mlelstv size_t len; 105 1.51 mlelstv 106 1.51 mlelstv switch (version) { 107 1.51 mlelstv case NFS_VER2: 108 1.51 mlelstv len = NFS_FHSIZE; 109 1.51 mlelstv break; 110 1.51 mlelstv case NFS_VER3: 111 1.51 mlelstv len = fh[0] << 24 | fh[1] << 16 | fh[2] << 8 | fh[3]; 112 1.51 mlelstv if (len > NFS_V3FHSIZE) 113 1.51 mlelstv len = NFS_V3FHSIZE; 114 1.51 mlelstv len = 4 + roundup(len, 4); 115 1.51 mlelstv break; 116 1.51 mlelstv default: 117 1.51 mlelstv len = 0; 118 1.51 mlelstv break; 119 1.51 mlelstv } 120 1.51 mlelstv 121 1.51 mlelstv return len; 122 1.51 mlelstv } 123 1.51 mlelstv 124 1.51 mlelstv static inline size_t 125 1.51 mlelstv fhcopy(int version, u_char *src, u_char *dst) 126 1.51 mlelstv { 127 1.51 mlelstv size_t len = fhstore(version, src); 128 1.51 mlelstv memcpy(dst, src, len); 129 1.51 mlelstv return len; 130 1.51 mlelstv } 131 1.51 mlelstv 132 1.51 mlelstv #define setfh(d, s) fhcopy((d)->version, (s), (d)->fh) 133 1.51 mlelstv #define getfh(d, s) fhcopy((d)->version, (d)->fh, (s)) 134 1.51 mlelstv 135 1.51 mlelstv 136 1.8 gwr struct nfs_iodesc nfs_root_node; 137 1.1 brezak 138 1.51 mlelstv int nfs_getrootfh(struct iodesc *, char *, u_char *, int *); 139 1.45 tsutsui int nfs_lookupfh(struct nfs_iodesc *, const char *, int, 140 1.45 tsutsui struct nfs_iodesc *); 141 1.45 tsutsui int nfs_readlink(struct nfs_iodesc *, char *); 142 1.45 tsutsui ssize_t nfs_readdata(struct nfs_iodesc *, off_t, void *, size_t); 143 1.7 gwr 144 1.12 gwr /* 145 1.12 gwr * Fetch the root file handle (call mount daemon) 146 1.12 gwr * On error, return non-zero and set errno. 147 1.12 gwr */ 148 1.7 gwr int 149 1.51 mlelstv nfs_getrootfh(struct iodesc *d, char *path, u_char *fhp, int *versionp) 150 1.1 brezak { 151 1.29 augustss int len; 152 1.7 gwr struct args { 153 1.7 gwr n_long len; 154 1.7 gwr char path[FNAME_SIZE]; 155 1.7 gwr } *args; 156 1.7 gwr struct repl { 157 1.7 gwr n_long errno; 158 1.51 mlelstv u_char fh[NFS_FHSTORE]; 159 1.7 gwr } *repl; 160 1.1 brezak struct { 161 1.7 gwr n_long h[RPC_HEADER_WORDS]; 162 1.7 gwr struct args d; 163 1.7 gwr } sdata; 164 1.1 brezak struct { 165 1.7 gwr n_long h[RPC_HEADER_WORDS]; 166 1.7 gwr struct repl d; 167 1.7 gwr } rdata; 168 1.33 fvdl ssize_t cc; 169 1.37 perry 170 1.1 brezak #ifdef NFS_DEBUG 171 1.1 brezak if (debug) 172 1.49 christos printf("%s: %s\n", __func__, path); 173 1.1 brezak #endif 174 1.6 mycroft 175 1.7 gwr args = &sdata.d; 176 1.7 gwr repl = &rdata.d; 177 1.7 gwr 178 1.43 christos (void)memset(args, 0, sizeof(*args)); 179 1.1 brezak len = strlen(path); 180 1.33 fvdl if ((size_t)len > sizeof(args->path)) 181 1.7 gwr len = sizeof(args->path); 182 1.7 gwr args->len = htonl(len); 183 1.43 christos (void)memcpy(args->path, path, len); 184 1.7 gwr len = 4 + roundup(len, 4); 185 1.7 gwr 186 1.51 mlelstv *versionp = NFS_VER3; 187 1.51 mlelstv cc = rpc_call(d, RPCPROG_MNT, RPCMNT_VER3, RPCMNT_MOUNT, 188 1.7 gwr args, len, repl, sizeof(*repl)); 189 1.51 mlelstv if (cc == -1 || cc < 4 || repl->errno) { 190 1.51 mlelstv *versionp = NFS_VER2; 191 1.51 mlelstv cc = rpc_call(d, RPCPROG_MNT, RPCMNT_VER1, RPCMNT_MOUNT, 192 1.51 mlelstv args, len, repl, sizeof(*repl)); 193 1.51 mlelstv } 194 1.12 gwr if (cc == -1) { 195 1.12 gwr /* errno was set by rpc_call */ 196 1.42 isaki return -1; 197 1.12 gwr } 198 1.12 gwr if (cc < 4) { 199 1.12 gwr errno = EBADRPC; 200 1.42 isaki return -1; 201 1.12 gwr } 202 1.7 gwr if (repl->errno) { 203 1.7 gwr errno = ntohl(repl->errno); 204 1.42 isaki return -1; 205 1.1 brezak } 206 1.51 mlelstv fhcopy(*versionp, repl->fh, fhp); 207 1.42 isaki return 0; 208 1.1 brezak } 209 1.1 brezak 210 1.12 gwr /* 211 1.12 gwr * Lookup a file. Store handle and attributes. 212 1.12 gwr * Return zero or error number. 213 1.12 gwr */ 214 1.7 gwr int 215 1.42 isaki nfs_lookupfh(struct nfs_iodesc *d, const char *name, int len, 216 1.42 isaki struct nfs_iodesc *newfd) 217 1.1 brezak { 218 1.51 mlelstv struct argsv2 { 219 1.1 brezak u_char fh[NFS_FHSIZE]; 220 1.7 gwr n_long len; 221 1.1 brezak char name[FNAME_SIZE]; 222 1.51 mlelstv } *argsv2; 223 1.51 mlelstv struct argsv3 { 224 1.51 mlelstv u_char fh[NFS_FHSTORE]; 225 1.51 mlelstv n_long len; 226 1.51 mlelstv char name[FNAME_SIZE]; 227 1.51 mlelstv } *argsv3; 228 1.51 mlelstv struct replv2 { 229 1.7 gwr n_long errno; 230 1.7 gwr u_char fh[NFS_FHSIZE]; 231 1.51 mlelstv struct nfsv2_fattr fa; 232 1.51 mlelstv } *replv2; 233 1.51 mlelstv struct replv3 { 234 1.51 mlelstv n_long errno; 235 1.51 mlelstv u_char fh[NFS_FHSTORE]; 236 1.51 mlelstv n_long fattrflag; 237 1.51 mlelstv struct nfsv3_fattr fa; 238 1.51 mlelstv n_long dattrflag; 239 1.51 mlelstv struct nfsv3_fattr da; 240 1.51 mlelstv } *replv3; 241 1.7 gwr struct { 242 1.7 gwr n_long h[RPC_HEADER_WORDS]; 243 1.51 mlelstv union { 244 1.51 mlelstv struct argsv2 v2; 245 1.51 mlelstv struct argsv3 v3; 246 1.51 mlelstv } u_d; 247 1.7 gwr } sdata; 248 1.1 brezak struct { 249 1.7 gwr n_long h[RPC_HEADER_WORDS]; 250 1.51 mlelstv union { 251 1.51 mlelstv struct replv2 v2; 252 1.51 mlelstv struct replv3 v3; 253 1.51 mlelstv } u_d; 254 1.7 gwr } rdata; 255 1.9 pk ssize_t cc; 256 1.51 mlelstv size_t alen; 257 1.37 perry 258 1.1 brezak #ifdef NFS_DEBUG 259 1.1 brezak if (debug) 260 1.49 christos printf("%s: called\n", __func__); 261 1.1 brezak #endif 262 1.1 brezak 263 1.51 mlelstv argsv2 = &sdata.u_d.v2; 264 1.51 mlelstv argsv3 = &sdata.u_d.v3; 265 1.51 mlelstv replv2 = &rdata.u_d.v2; 266 1.51 mlelstv replv3 = &rdata.u_d.v3; 267 1.51 mlelstv 268 1.51 mlelstv switch (d->version) { 269 1.51 mlelstv case NFS_VER2: 270 1.51 mlelstv (void)memset(argsv2, 0, sizeof(*argsv2)); 271 1.51 mlelstv getfh(d, argsv2->fh); 272 1.51 mlelstv if ((size_t)len > sizeof(argsv2->name)) 273 1.51 mlelstv len = sizeof(argsv2->name); 274 1.51 mlelstv (void)memcpy(argsv2->name, name, len); 275 1.51 mlelstv argsv2->len = htonl(len); 276 1.51 mlelstv 277 1.51 mlelstv /* padded name, name length */ 278 1.51 mlelstv len = roundup(len, 4) + 4; 279 1.51 mlelstv /* filehandle size */ 280 1.51 mlelstv alen = fhstore(d->version, argsv2->fh); 281 1.51 mlelstv 282 1.51 mlelstv cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER2, NFSPROC_LOOKUP, 283 1.51 mlelstv argsv2, alen+len, replv2, sizeof(*replv2)); 284 1.51 mlelstv break; 285 1.51 mlelstv case NFS_VER3: 286 1.51 mlelstv (void)memset(argsv3, 0, sizeof(*argsv3)); 287 1.51 mlelstv getfh(d, argsv3->fh); 288 1.51 mlelstv if ((size_t)len > sizeof(argsv3->name)) 289 1.51 mlelstv len = sizeof(argsv3->name); 290 1.51 mlelstv (void)memcpy(argsv3->name, name, len); 291 1.51 mlelstv argsv3->len = htonl(len); 292 1.51 mlelstv 293 1.51 mlelstv /* padded name, name length */ 294 1.51 mlelstv len = roundup(len, 4) + 4; 295 1.51 mlelstv /* filehandle size */ 296 1.51 mlelstv alen = fhstore(d->version, argsv3->fh); 297 1.7 gwr 298 1.51 mlelstv /* adjust for variable sized file handle */ 299 1.51 mlelstv memmove(argsv3->fh + alen, &argsv3->len, len); 300 1.7 gwr 301 1.51 mlelstv cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER3, NFSV3PROC_LOOKUP, 302 1.51 mlelstv argsv3, alen+len, replv3, sizeof(*replv3)); 303 1.51 mlelstv break; 304 1.51 mlelstv default: 305 1.51 mlelstv return ENOSYS; 306 1.51 mlelstv } 307 1.7 gwr 308 1.12 gwr if (cc == -1) 309 1.42 isaki return errno; /* XXX - from rpc_call */ 310 1.7 gwr if (cc < 4) 311 1.42 isaki return EIO; 312 1.51 mlelstv 313 1.51 mlelstv switch (d->version) { 314 1.51 mlelstv case NFS_VER2: 315 1.51 mlelstv if (replv2->errno) { 316 1.51 mlelstv /* saerrno.h now matches NFS error numbers. */ 317 1.51 mlelstv return ntohl(replv2->errno); 318 1.51 mlelstv } 319 1.51 mlelstv 320 1.51 mlelstv setfh(newfd, replv2->fh); 321 1.51 mlelstv (void)memcpy(&newfd->u_fa.v2, &replv2->fa, 322 1.51 mlelstv sizeof(newfd->u_fa.v2)); 323 1.51 mlelstv break; 324 1.51 mlelstv case NFS_VER3: 325 1.51 mlelstv if (replv3->errno) { 326 1.51 mlelstv /* saerrno.h now matches NFS error numbers. */ 327 1.51 mlelstv return ntohl(replv3->errno); 328 1.51 mlelstv } 329 1.51 mlelstv 330 1.51 mlelstv setfh(newfd, replv3->fh); 331 1.51 mlelstv 332 1.51 mlelstv if (replv3->fattrflag) { 333 1.51 mlelstv (void)memcpy(&newfd->u_fa.v3, &replv3->fa, 334 1.51 mlelstv sizeof(newfd->u_fa.v3)); 335 1.51 mlelstv } 336 1.51 mlelstv break; 337 1.1 brezak } 338 1.42 isaki return 0; 339 1.1 brezak } 340 1.1 brezak 341 1.21 drochner #ifndef NFS_NOSYMLINK 342 1.12 gwr /* 343 1.16 ws * Get the destination of a symbolic link. 344 1.16 ws */ 345 1.16 ws int 346 1.42 isaki nfs_readlink(struct nfs_iodesc *d, char *buf) 347 1.16 ws { 348 1.16 ws struct { 349 1.16 ws n_long h[RPC_HEADER_WORDS]; 350 1.51 mlelstv u_char fh[NFS_FHSTORE]; 351 1.16 ws } sdata; 352 1.16 ws struct { 353 1.16 ws n_long h[RPC_HEADER_WORDS]; 354 1.16 ws struct nfs_readlnk_repl d; 355 1.16 ws } rdata; 356 1.16 ws ssize_t cc; 357 1.16 ws 358 1.16 ws #ifdef NFS_DEBUG 359 1.16 ws if (debug) 360 1.49 christos printf("%s: called\n", __func__); 361 1.16 ws #endif 362 1.16 ws 363 1.51 mlelstv getfh(d, sdata.fh); 364 1.51 mlelstv cc = rpc_call(d->iodesc, NFS_PROG, d->version, NFSPROC_READLINK, 365 1.51 mlelstv sdata.fh, fhstore(d->version, sdata.fh), 366 1.51 mlelstv &rdata.d, sizeof(rdata.d)); 367 1.16 ws if (cc == -1) 368 1.42 isaki return errno; 369 1.16 ws 370 1.16 ws if (cc < 4) 371 1.42 isaki return EIO; 372 1.37 perry 373 1.16 ws if (rdata.d.errno) 374 1.42 isaki return ntohl(rdata.d.errno); 375 1.17 cgd 376 1.17 cgd rdata.d.len = ntohl(rdata.d.len); 377 1.16 ws if (rdata.d.len > NFS_MAXPATHLEN) 378 1.42 isaki return ENAMETOOLONG; 379 1.16 ws 380 1.43 christos (void)memcpy(buf, rdata.d.path, rdata.d.len); 381 1.16 ws buf[rdata.d.len] = 0; 382 1.42 isaki return 0; 383 1.16 ws } 384 1.21 drochner #endif 385 1.16 ws 386 1.16 ws /* 387 1.12 gwr * Read data from a file. 388 1.12 gwr * Return transfer count or -1 (and set errno) 389 1.12 gwr */ 390 1.9 pk ssize_t 391 1.42 isaki nfs_readdata(struct nfs_iodesc *d, off_t off, void *addr, size_t len) 392 1.1 brezak { 393 1.51 mlelstv struct argsv2 { 394 1.51 mlelstv u_char fh[NFS_FHSIZE]; 395 1.51 mlelstv n_long off; 396 1.51 mlelstv n_long len; 397 1.51 mlelstv n_long xxx; /* XXX what's this for? */ 398 1.51 mlelstv } *argsv2; 399 1.51 mlelstv struct argsv3 { 400 1.51 mlelstv u_char fh[NFS_FHSTORE]; 401 1.51 mlelstv n_long off[2]; 402 1.51 mlelstv n_long len; 403 1.51 mlelstv } *argsv3; 404 1.51 mlelstv struct replv2 { 405 1.51 mlelstv n_long errno; 406 1.51 mlelstv struct nfsv2_fattr fa; 407 1.51 mlelstv n_long count; 408 1.51 mlelstv u_char data[NFSREAD_SIZE]; 409 1.51 mlelstv } *replv2; 410 1.51 mlelstv struct replv3 { 411 1.51 mlelstv n_long errno; 412 1.51 mlelstv n_long attrflag; 413 1.51 mlelstv struct nfsv3_fattr fa; 414 1.51 mlelstv n_long count; 415 1.51 mlelstv n_long eof; 416 1.51 mlelstv n_long length; 417 1.51 mlelstv u_char data[NFSREAD_SIZE]; 418 1.51 mlelstv } *replv3; 419 1.51 mlelstv struct replv3_noattr { 420 1.51 mlelstv n_long errno; 421 1.51 mlelstv n_long attrflag; 422 1.51 mlelstv n_long count; 423 1.51 mlelstv n_long eof; 424 1.51 mlelstv n_long length; 425 1.51 mlelstv u_char data[NFSREAD_SIZE]; 426 1.51 mlelstv } *replv3no; 427 1.7 gwr struct { 428 1.7 gwr n_long h[RPC_HEADER_WORDS]; 429 1.51 mlelstv union { 430 1.51 mlelstv struct argsv2 v2; 431 1.51 mlelstv struct argsv3 v3; 432 1.51 mlelstv } u_d; 433 1.7 gwr } sdata; 434 1.7 gwr struct { 435 1.7 gwr n_long h[RPC_HEADER_WORDS]; 436 1.51 mlelstv union { 437 1.51 mlelstv struct replv2 v2; 438 1.51 mlelstv struct replv3 v3; 439 1.51 mlelstv } u_d; 440 1.7 gwr } rdata; 441 1.33 fvdl ssize_t cc; 442 1.9 pk long x; 443 1.51 mlelstv size_t hlen, rlen, alen; 444 1.51 mlelstv u_char *data; 445 1.7 gwr 446 1.51 mlelstv argsv2 = &sdata.u_d.v2; 447 1.51 mlelstv argsv3 = &sdata.u_d.v3; 448 1.51 mlelstv replv2 = &rdata.u_d.v2; 449 1.51 mlelstv replv3 = &rdata.u_d.v3; 450 1.6 mycroft 451 1.6 mycroft if (len > NFSREAD_SIZE) 452 1.6 mycroft len = NFSREAD_SIZE; 453 1.51 mlelstv 454 1.51 mlelstv switch (d->version) { 455 1.51 mlelstv case NFS_VER2: 456 1.51 mlelstv getfh(d, argsv2->fh); 457 1.51 mlelstv argsv2->off = htonl((n_long)off); 458 1.51 mlelstv argsv2->len = htonl((n_long)len); 459 1.51 mlelstv argsv2->xxx = htonl((n_long)0); 460 1.51 mlelstv hlen = sizeof(*replv2) - NFSREAD_SIZE; 461 1.51 mlelstv cc = rpc_call(d->iodesc, NFS_PROG, d->version, NFSPROC_READ, 462 1.51 mlelstv argsv2, sizeof(*argsv2), 463 1.51 mlelstv replv2, sizeof(*replv2)); 464 1.51 mlelstv break; 465 1.51 mlelstv case NFS_VER3: 466 1.51 mlelstv getfh(d, argsv3->fh); 467 1.51 mlelstv setnquad(argsv3->off, (uint64_t)off); 468 1.51 mlelstv argsv3->len = htonl((n_long)len); 469 1.51 mlelstv hlen = sizeof(*replv3) - NFSREAD_SIZE; 470 1.51 mlelstv 471 1.51 mlelstv /* adjust for variable sized file handle */ 472 1.51 mlelstv alen = sizeof(*argsv3) - offsetof(struct argsv3, off); 473 1.51 mlelstv memmove(argsv3->fh + fhstore(d->version, argsv3->fh), 474 1.51 mlelstv &argsv3->off, alen); 475 1.51 mlelstv alen += fhstore(d->version, argsv3->fh); 476 1.51 mlelstv 477 1.51 mlelstv cc = rpc_call(d->iodesc, NFS_PROG, d->version, NFSPROC_READ, 478 1.51 mlelstv argsv3, alen, 479 1.51 mlelstv replv3, sizeof(*replv3)); 480 1.51 mlelstv break; 481 1.51 mlelstv default: 482 1.51 mlelstv errno = ENOSYS; 483 1.51 mlelstv return -1; 484 1.51 mlelstv } 485 1.51 mlelstv 486 1.12 gwr if (cc == -1) { 487 1.12 gwr /* errno was already set by rpc_call */ 488 1.42 isaki return -1; 489 1.12 gwr } 490 1.33 fvdl if (cc < (ssize_t)hlen) { 491 1.12 gwr errno = EBADRPC; 492 1.42 isaki return -1; 493 1.9 pk } 494 1.51 mlelstv 495 1.51 mlelstv switch (d->version) { 496 1.51 mlelstv case NFS_VER2: 497 1.51 mlelstv if (replv2->errno) { 498 1.51 mlelstv errno = ntohl(replv2->errno); 499 1.51 mlelstv return -1; 500 1.51 mlelstv } 501 1.51 mlelstv x = ntohl(replv2->count); 502 1.51 mlelstv data = replv2->data; 503 1.51 mlelstv break; 504 1.51 mlelstv case NFS_VER3: 505 1.51 mlelstv if (replv3->errno) { 506 1.51 mlelstv errno = ntohl(replv3->errno); 507 1.51 mlelstv return -1; 508 1.51 mlelstv } 509 1.51 mlelstv 510 1.51 mlelstv /* adjust for optional attributes */ 511 1.51 mlelstv if (replv3->attrflag) { 512 1.51 mlelstv x = ntohl(replv3->length); 513 1.51 mlelstv data = replv3->data; 514 1.51 mlelstv } else { 515 1.51 mlelstv replv3no = (struct replv3_noattr *)replv3; 516 1.51 mlelstv x = ntohl(replv3no->length); 517 1.51 mlelstv data = replv3no->data; 518 1.51 mlelstv } 519 1.51 mlelstv break; 520 1.51 mlelstv default: 521 1.51 mlelstv errno = ENOSYS; 522 1.42 isaki return -1; 523 1.7 gwr } 524 1.51 mlelstv 525 1.7 gwr rlen = cc - hlen; 526 1.33 fvdl if (rlen < (size_t)x) { 527 1.49 christos printf("%s: short packet, %zu < %ld\n", __func__, rlen, x); 528 1.9 pk errno = EBADRPC; 529 1.42 isaki return -1; 530 1.7 gwr } 531 1.51 mlelstv (void)memcpy(addr, data, x); 532 1.42 isaki return x; 533 1.1 brezak } 534 1.1 brezak 535 1.1 brezak /* 536 1.1 brezak * nfs_mount - mount this nfs filesystem to a host 537 1.12 gwr * On error, return non-zero and set errno. 538 1.1 brezak */ 539 1.1 brezak int 540 1.42 isaki nfs_mount(int sock, struct in_addr ip, char *path) 541 1.1 brezak { 542 1.1 brezak struct iodesc *desc; 543 1.51 mlelstv struct nfsv2_fattr *fa2; 544 1.51 mlelstv struct nfsv3_fattr *fa3; 545 1.7 gwr 546 1.1 brezak if (!(desc = socktodesc(sock))) { 547 1.1 brezak errno = EINVAL; 548 1.42 isaki return -1; 549 1.1 brezak } 550 1.7 gwr 551 1.7 gwr /* Bind to a reserved port. */ 552 1.7 gwr desc->myport = htons(--rpc_port); 553 1.1 brezak desc->destip = ip; 554 1.51 mlelstv if (nfs_getrootfh(desc, path, nfs_root_node.fh, &nfs_root_node.version)) 555 1.42 isaki return -1; 556 1.7 gwr nfs_root_node.iodesc = desc; 557 1.8 gwr /* Fake up attributes for the root dir. */ 558 1.51 mlelstv switch (nfs_root_node.version) { 559 1.51 mlelstv case NFS_VER2: 560 1.51 mlelstv fa2 = &nfs_root_node.u_fa.v2; 561 1.51 mlelstv fa2->fa_type = htonl(NFDIR); 562 1.51 mlelstv fa2->fa_mode = htonl(0755); 563 1.51 mlelstv fa2->fa_nlink = htonl(2); 564 1.51 mlelstv break; 565 1.51 mlelstv case NFS_VER3: 566 1.51 mlelstv fa3 = &nfs_root_node.u_fa.v3; 567 1.51 mlelstv fa3->fa_type = htonl(NFDIR); 568 1.51 mlelstv fa3->fa_mode = htonl(0755); 569 1.51 mlelstv fa3->fa_nlink = htonl(2); 570 1.51 mlelstv break; 571 1.51 mlelstv default: 572 1.51 mlelstv errno = ENOSYS; 573 1.51 mlelstv return -1; 574 1.51 mlelstv } 575 1.1 brezak 576 1.1 brezak #ifdef NFS_DEBUG 577 1.1 brezak if (debug) 578 1.49 christos printf("%s: got fh for %s\n", __func__, path); 579 1.1 brezak #endif 580 1.1 brezak 581 1.42 isaki return 0; 582 1.1 brezak } 583 1.1 brezak 584 1.1 brezak /* 585 1.1 brezak * Open a file. 586 1.12 gwr * return zero or error number 587 1.1 brezak */ 588 1.46 joerg __compactcall int 589 1.42 isaki nfs_open(const char *path, struct open_file *f) 590 1.1 brezak { 591 1.16 ws struct nfs_iodesc *newfd, *currfd; 592 1.32 dsl const char *cp; 593 1.21 drochner #ifndef NFS_NOSYMLINK 594 1.32 dsl const char *ncp; 595 1.29 augustss int c; 596 1.16 ws char namebuf[NFS_MAXPATHLEN + 1]; 597 1.16 ws char linkbuf[NFS_MAXPATHLEN + 1]; 598 1.16 ws int nlinks = 0; 599 1.52 rin n_long fa_type; 600 1.21 drochner #endif 601 1.12 gwr int error = 0; 602 1.1 brezak 603 1.1 brezak #ifdef NFS_DEBUG 604 1.1 brezak if (debug) 605 1.49 christos printf("%s: %s\n", __func__, path); 606 1.1 brezak #endif 607 1.51 mlelstv 608 1.53 rin #ifdef LIBSA_NFS_IMPLICIT_MOUNT 609 1.53 rin if (nfs_mount(*((int *)(f->f_devdata)), rootip, rootpath)) 610 1.53 rin return errno; 611 1.53 rin #endif 612 1.53 rin 613 1.7 gwr if (nfs_root_node.iodesc == NULL) { 614 1.49 christos printf("%s: must mount first.\n", __func__); 615 1.42 isaki return ENXIO; 616 1.1 brezak } 617 1.1 brezak 618 1.16 ws currfd = &nfs_root_node; 619 1.16 ws newfd = 0; 620 1.21 drochner 621 1.21 drochner #ifndef NFS_NOSYMLINK 622 1.16 ws cp = path; 623 1.16 ws while (*cp) { 624 1.16 ws /* 625 1.16 ws * Remove extra separators 626 1.16 ws */ 627 1.16 ws while (*cp == '/') 628 1.16 ws cp++; 629 1.16 ws 630 1.16 ws if (*cp == '\0') 631 1.16 ws break; 632 1.16 ws /* 633 1.16 ws * Check that current node is a directory. 634 1.16 ws */ 635 1.51 mlelstv switch (currfd->version) { 636 1.51 mlelstv case NFS_VER2: 637 1.51 mlelstv fa_type = currfd->u_fa.v2.fa_type; 638 1.51 mlelstv break; 639 1.51 mlelstv case NFS_VER3: 640 1.51 mlelstv fa_type = currfd->u_fa.v3.fa_type; 641 1.51 mlelstv break; 642 1.51 mlelstv default: 643 1.51 mlelstv fa_type = htonl(NFNON); 644 1.51 mlelstv break; 645 1.51 mlelstv } 646 1.51 mlelstv if (fa_type != htonl(NFDIR)) { 647 1.16 ws error = ENOTDIR; 648 1.16 ws goto out; 649 1.16 ws } 650 1.37 perry 651 1.16 ws /* allocate file system specific data structure */ 652 1.16 ws newfd = alloc(sizeof(*newfd)); 653 1.16 ws newfd->iodesc = currfd->iodesc; 654 1.16 ws newfd->off = 0; 655 1.51 mlelstv newfd->version = currfd->version; 656 1.37 perry 657 1.16 ws /* 658 1.16 ws * Get next component of path name. 659 1.16 ws */ 660 1.16 ws { 661 1.29 augustss int len = 0; 662 1.37 perry 663 1.16 ws ncp = cp; 664 1.16 ws while ((c = *cp) != '\0' && c != '/') { 665 1.16 ws if (++len > NFS_MAXNAMLEN) { 666 1.16 ws error = ENOENT; 667 1.16 ws goto out; 668 1.16 ws } 669 1.16 ws cp++; 670 1.16 ws } 671 1.16 ws } 672 1.37 perry 673 1.16 ws /* lookup a file handle */ 674 1.32 dsl error = nfs_lookupfh(currfd, ncp, cp - ncp, newfd); 675 1.16 ws if (error) 676 1.16 ws goto out; 677 1.37 perry 678 1.16 ws /* 679 1.16 ws * Check for symbolic link 680 1.16 ws */ 681 1.51 mlelstv switch (newfd->version) { 682 1.51 mlelstv case NFS_VER2: 683 1.51 mlelstv fa_type = newfd->u_fa.v2.fa_type; 684 1.51 mlelstv break; 685 1.51 mlelstv case NFS_VER3: 686 1.51 mlelstv fa_type = newfd->u_fa.v3.fa_type; 687 1.51 mlelstv break; 688 1.51 mlelstv default: 689 1.51 mlelstv fa_type = htonl(NFNON); 690 1.51 mlelstv break; 691 1.51 mlelstv } 692 1.51 mlelstv if (fa_type == htonl(NFLNK)) { 693 1.16 ws int link_len, len; 694 1.37 perry 695 1.16 ws error = nfs_readlink(newfd, linkbuf); 696 1.16 ws if (error) 697 1.16 ws goto out; 698 1.16 ws 699 1.16 ws link_len = strlen(linkbuf); 700 1.16 ws len = strlen(cp); 701 1.16 ws 702 1.16 ws if (link_len + len > MAXPATHLEN 703 1.16 ws || ++nlinks > MAXSYMLINKS) { 704 1.16 ws error = ENOENT; 705 1.16 ws goto out; 706 1.16 ws } 707 1.16 ws 708 1.43 christos (void)memcpy(&namebuf[link_len], cp, len + 1); 709 1.43 christos (void)memcpy(namebuf, linkbuf, link_len); 710 1.37 perry 711 1.16 ws /* 712 1.16 ws * If absolute pathname, restart at root. 713 1.16 ws * If relative pathname, restart at parent directory. 714 1.16 ws */ 715 1.16 ws cp = namebuf; 716 1.16 ws if (*cp == '/') { 717 1.16 ws if (currfd != &nfs_root_node) 718 1.39 christos dealloc(currfd, sizeof(*currfd)); 719 1.16 ws currfd = &nfs_root_node; 720 1.16 ws } 721 1.16 ws 722 1.39 christos dealloc(newfd, sizeof(*newfd)); 723 1.16 ws newfd = 0; 724 1.37 perry 725 1.16 ws continue; 726 1.16 ws } 727 1.37 perry 728 1.16 ws if (currfd != &nfs_root_node) 729 1.39 christos dealloc(currfd, sizeof(*currfd)); 730 1.16 ws currfd = newfd; 731 1.16 ws newfd = 0; 732 1.16 ws } 733 1.16 ws 734 1.16 ws error = 0; 735 1.1 brezak 736 1.16 ws out: 737 1.21 drochner #else 738 1.28 simonb /* allocate file system specific data structure */ 739 1.28 simonb currfd = alloc(sizeof(*currfd)); 740 1.28 simonb currfd->iodesc = nfs_root_node.iodesc; 741 1.28 simonb currfd->off = 0; 742 1.51 mlelstv currfd->version = nfs_root_node.version; 743 1.21 drochner 744 1.28 simonb cp = path; 745 1.28 simonb /* 746 1.28 simonb * Remove extra separators 747 1.28 simonb */ 748 1.28 simonb while (*cp == '/') 749 1.28 simonb cp++; 750 1.28 simonb 751 1.28 simonb /* XXX: Check for empty path here? */ 752 1.28 simonb 753 1.32 dsl error = nfs_lookupfh(&nfs_root_node, cp, strlen(cp), currfd); 754 1.21 drochner #endif 755 1.12 gwr if (!error) { 756 1.16 ws f->f_fsdata = (void *)currfd; 757 1.44 ad fsmod = "nfs"; 758 1.42 isaki return 0; 759 1.1 brezak } 760 1.37 perry 761 1.1 brezak #ifdef NFS_DEBUG 762 1.1 brezak if (debug) 763 1.49 christos printf("%s: %s lookupfh failed: %s\n", __func__, 764 1.18 christos path, strerror(error)); 765 1.1 brezak #endif 766 1.16 ws if (currfd != &nfs_root_node) 767 1.39 christos dealloc(currfd, sizeof(*currfd)); 768 1.16 ws if (newfd) 769 1.39 christos dealloc(newfd, sizeof(*newfd)); 770 1.16 ws 771 1.42 isaki return error; 772 1.1 brezak } 773 1.1 brezak 774 1.46 joerg __compactcall int 775 1.42 isaki nfs_close(struct open_file *f) 776 1.1 brezak { 777 1.29 augustss struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; 778 1.1 brezak 779 1.1 brezak #ifdef NFS_DEBUG 780 1.1 brezak if (debug) 781 1.49 christos printf("%s: fp=%p\n", __func__, fp); 782 1.1 brezak #endif 783 1.7 gwr 784 1.7 gwr if (fp) 785 1.39 christos dealloc(fp, sizeof(struct nfs_iodesc)); 786 1.1 brezak f->f_fsdata = (void *)0; 787 1.37 perry 788 1.42 isaki return 0; 789 1.1 brezak } 790 1.1 brezak 791 1.1 brezak /* 792 1.1 brezak * read a portion of a file 793 1.1 brezak */ 794 1.46 joerg __compactcall int 795 1.42 isaki nfs_read(struct open_file *f, void *buf, size_t size, size_t *resid) 796 1.1 brezak { 797 1.29 augustss struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; 798 1.29 augustss ssize_t cc; 799 1.29 augustss char *addr = buf; 800 1.37 perry 801 1.1 brezak #ifdef NFS_DEBUG 802 1.1 brezak if (debug) 803 1.50 skrll printf("%s: size=%zu off=%" PRIx64 "\n", __func__, size, fp->off); 804 1.1 brezak #endif 805 1.9 pk while ((int)size > 0) { 806 1.25 cgd #if !defined(LIBSA_NO_TWIDDLE) 807 1.7 gwr twiddle(); 808 1.25 cgd #endif 809 1.7 gwr cc = nfs_readdata(fp, fp->off, (void *)addr, size); 810 1.6 mycroft /* XXX maybe should retry on certain errors */ 811 1.6 mycroft if (cc == -1) { 812 1.6 mycroft #ifdef NFS_DEBUG 813 1.6 mycroft if (debug) 814 1.49 christos printf("%s: read: %s\n", __func__, 815 1.49 christos strerror(errno)); 816 1.1 brezak #endif 817 1.42 isaki return errno; /* XXX - from nfs_readdata */ 818 1.6 mycroft } 819 1.6 mycroft if (cc == 0) { 820 1.20 pk #ifdef NFS_DEBUG 821 1.1 brezak if (debug) 822 1.49 christos printf("%s: hit EOF unexpectedly\n", __func__); 823 1.20 pk #endif 824 1.1 brezak goto ret; 825 1.1 brezak } 826 1.1 brezak fp->off += cc; 827 1.1 brezak addr += cc; 828 1.1 brezak size -= cc; 829 1.1 brezak } 830 1.1 brezak ret: 831 1.1 brezak if (resid) 832 1.1 brezak *resid = size; 833 1.1 brezak 834 1.42 isaki return 0; 835 1.1 brezak } 836 1.1 brezak 837 1.1 brezak /* 838 1.1 brezak * Not implemented. 839 1.1 brezak */ 840 1.46 joerg __compactcall int 841 1.42 isaki nfs_write(struct open_file *f, void *buf, size_t size, size_t *resid) 842 1.1 brezak { 843 1.42 isaki return EROFS; 844 1.1 brezak } 845 1.1 brezak 846 1.46 joerg __compactcall off_t 847 1.42 isaki nfs_seek(struct open_file *f, off_t offset, int where) 848 1.1 brezak { 849 1.29 augustss struct nfs_iodesc *d = (struct nfs_iodesc *)f->f_fsdata; 850 1.51 mlelstv off_t size; 851 1.51 mlelstv 852 1.51 mlelstv switch (d->version) { 853 1.51 mlelstv case NFS_VER2: 854 1.51 mlelstv size = ntohl(d->u_fa.v2.fa_size); 855 1.51 mlelstv break; 856 1.51 mlelstv case NFS_VER3: 857 1.51 mlelstv size = getnquad(d->u_fa.v3.fa_size); 858 1.51 mlelstv break; 859 1.51 mlelstv default: 860 1.51 mlelstv return -1; 861 1.51 mlelstv } 862 1.1 brezak 863 1.1 brezak switch (where) { 864 1.1 brezak case SEEK_SET: 865 1.7 gwr d->off = offset; 866 1.1 brezak break; 867 1.1 brezak case SEEK_CUR: 868 1.7 gwr d->off += offset; 869 1.1 brezak break; 870 1.1 brezak case SEEK_END: 871 1.7 gwr d->off = size - offset; 872 1.1 brezak break; 873 1.1 brezak default: 874 1.42 isaki return -1; 875 1.1 brezak } 876 1.7 gwr 877 1.42 isaki return d->off; 878 1.1 brezak } 879 1.1 brezak 880 1.7 gwr /* NFNON=0, NFREG=1, NFDIR=2, NFBLK=3, NFCHR=4, NFLNK=5 */ 881 1.31 mycroft const int nfs_stat_types[8] = { 882 1.7 gwr 0, S_IFREG, S_IFDIR, S_IFBLK, S_IFCHR, S_IFLNK, 0 }; 883 1.7 gwr 884 1.46 joerg __compactcall int 885 1.42 isaki nfs_stat(struct open_file *f, struct stat *sb) 886 1.1 brezak { 887 1.7 gwr struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; 888 1.29 augustss n_long ftype, mode; 889 1.1 brezak 890 1.51 mlelstv switch (fp->version) { 891 1.51 mlelstv case NFS_VER2: 892 1.51 mlelstv ftype = ntohl(fp->u_fa.v2.fa_type); 893 1.51 mlelstv mode = ntohl(fp->u_fa.v2.fa_mode); 894 1.51 mlelstv sb->st_nlink = ntohl(fp->u_fa.v2.fa_nlink); 895 1.51 mlelstv sb->st_uid = ntohl(fp->u_fa.v2.fa_uid); 896 1.51 mlelstv sb->st_gid = ntohl(fp->u_fa.v2.fa_gid); 897 1.51 mlelstv sb->st_size = ntohl(fp->u_fa.v2.fa_size); 898 1.51 mlelstv break; 899 1.51 mlelstv case NFS_VER3: 900 1.51 mlelstv ftype = ntohl(fp->u_fa.v3.fa_type); 901 1.51 mlelstv mode = ntohl(fp->u_fa.v3.fa_mode); 902 1.51 mlelstv sb->st_nlink = ntohl(fp->u_fa.v3.fa_nlink); 903 1.51 mlelstv sb->st_uid = ntohl(fp->u_fa.v3.fa_uid); 904 1.51 mlelstv sb->st_gid = ntohl(fp->u_fa.v3.fa_gid); 905 1.51 mlelstv sb->st_size = getnquad(fp->u_fa.v3.fa_size); 906 1.51 mlelstv break; 907 1.51 mlelstv default: 908 1.51 mlelstv return -1; 909 1.51 mlelstv } 910 1.51 mlelstv 911 1.7 gwr mode |= nfs_stat_types[ftype & 7]; 912 1.7 gwr sb->st_mode = mode; 913 1.1 brezak 914 1.42 isaki return 0; 915 1.1 brezak } 916 1.47 tsutsui 917 1.47 tsutsui #if defined(LIBSA_ENABLE_LS_OP) 918 1.48 christos #include "ls.h" 919 1.47 tsutsui __compactcall void 920 1.47 tsutsui nfs_ls(struct open_file *f, const char *pattern) 921 1.47 tsutsui { 922 1.48 christos lsunsup("nfs"); 923 1.47 tsutsui } 924 1.47 tsutsui #endif 925