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