1 /* $NetBSD: nfs.c,v 1.2 1998/01/24 12:43:09 drochner 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 #include <sys/cdefs.h> 32 __FBSDID("$FreeBSD$"); 33 34 #include <sys/param.h> 35 #include <sys/time.h> 36 #include <sys/socket.h> 37 #include <sys/stat.h> 38 #include <string.h> 39 #include <stddef.h> 40 41 #include <netinet/in.h> 42 #include <netinet/in_systm.h> 43 44 #include "rpcv2.h" 45 #include "nfsv2.h" 46 47 #include "stand.h" 48 #include "net.h" 49 #include "netif.h" 50 #include "rpc.h" 51 52 #define NFS_DEBUGxx 53 54 #define NFSREAD_MIN_SIZE 1024 55 #define NFSREAD_MAX_SIZE 16384 56 57 /* NFSv3 definitions */ 58 #define NFS_V3MAXFHSIZE 64 59 #define NFS_VER3 3 60 #define RPCMNT_VER3 3 61 #define NFSPROCV3_LOOKUP 3 62 #define NFSPROCV3_READLINK 5 63 #define NFSPROCV3_READ 6 64 #define NFSPROCV3_READDIR 16 65 66 typedef struct { 67 uint32_t val[2]; 68 } n_quad; 69 70 struct nfsv3_time { 71 uint32_t nfs_sec; 72 uint32_t nfs_nsec; 73 }; 74 75 struct nfsv3_fattrs { 76 uint32_t fa_type; 77 uint32_t fa_mode; 78 uint32_t fa_nlink; 79 uint32_t fa_uid; 80 uint32_t fa_gid; 81 n_quad fa_size; 82 n_quad fa_used; 83 n_quad fa_rdev; 84 n_quad fa_fsid; 85 n_quad fa_fileid; 86 struct nfsv3_time fa_atime; 87 struct nfsv3_time fa_mtime; 88 struct nfsv3_time fa_ctime; 89 }; 90 91 /* 92 * For NFSv3, the file handle is variable in size, so most fixed sized 93 * structures for arguments won't work. For most cases, a structure 94 * that starts with any fixed size section is followed by an array 95 * that covers the maximum size required. 96 */ 97 struct nfsv3_readdir_repl { 98 uint32_t errno; 99 uint32_t ok; 100 struct nfsv3_fattrs fa; 101 uint32_t cookiev0; 102 uint32_t cookiev1; 103 }; 104 105 struct nfsv3_readdir_entry { 106 uint32_t follows; 107 uint32_t fid0; 108 uint32_t fid1; 109 uint32_t len; 110 uint32_t nameplus[0]; 111 }; 112 113 struct nfs_iodesc { 114 struct iodesc *iodesc; 115 off_t off; 116 uint32_t fhsize; 117 u_char fh[NFS_V3MAXFHSIZE]; 118 struct nfsv3_fattrs fa; /* all in network order */ 119 uint64_t cookie; 120 }; 121 122 /* 123 * XXX interactions with tftp? See nfswrapper.c for a confusing 124 * issue. 125 */ 126 int nfs_open(const char *path, struct open_file *f); 127 static int nfs_close(struct open_file *f); 128 static int nfs_read(struct open_file *f, void *buf, size_t size, size_t *resid); 129 static int nfs_write(struct open_file *f, void *buf, size_t size, size_t *resid); 130 static off_t nfs_seek(struct open_file *f, off_t offset, int where); 131 static int nfs_stat(struct open_file *f, struct stat *sb); 132 static int nfs_readdir(struct open_file *f, struct dirent *d); 133 134 struct nfs_iodesc nfs_root_node; 135 136 struct fs_ops nfs_fsops = { 137 "nfs", 138 nfs_open, 139 nfs_close, 140 nfs_read, 141 nfs_write, 142 nfs_seek, 143 nfs_stat, 144 nfs_readdir 145 }; 146 147 static int nfs_read_size = NFSREAD_MIN_SIZE; 148 149 /* 150 * Improve boot performance over NFS 151 */ 152 static void 153 set_nfs_read_size(void) 154 { 155 char *env, *end; 156 char buf[10]; 157 158 if ((env = getenv("nfs.read_size")) != NULL) { 159 errno = 0; 160 nfs_read_size = (int)strtol(env, &end, 0); 161 if (errno != 0 || *env == '\0' || *end != '\0') { 162 printf("%s: bad value: \"%s\", defaulting to %d\n", 163 "nfs.read_size", env, NFSREAD_MIN_SIZE); 164 nfs_read_size = NFSREAD_MIN_SIZE; 165 } 166 } 167 if (nfs_read_size < NFSREAD_MIN_SIZE) { 168 printf("%s: bad value: \"%d\", defaulting to %d\n", 169 "nfs.read_size", nfs_read_size, NFSREAD_MIN_SIZE); 170 nfs_read_size = NFSREAD_MIN_SIZE; 171 } 172 if (nfs_read_size > NFSREAD_MAX_SIZE) { 173 printf("%s: bad value: \"%d\", defaulting to %d\n", 174 "nfs.read_size", nfs_read_size, NFSREAD_MIN_SIZE); 175 nfs_read_size = NFSREAD_MAX_SIZE; 176 } 177 snprintf(buf, sizeof (buf), "%d", nfs_read_size); 178 setenv("nfs.read_size", buf, 1); 179 } 180 181 /* 182 * Fetch the root file handle (call mount daemon) 183 * Return zero or error number. 184 */ 185 int 186 nfs_getrootfh(struct iodesc *d, char *path, uint32_t *fhlenp, u_char *fhp) 187 { 188 void *pkt = NULL; 189 int len; 190 struct args { 191 uint32_t len; 192 char path[FNAME_SIZE]; 193 } *args; 194 struct repl { 195 uint32_t errno; 196 uint32_t fhsize; 197 u_char fh[NFS_V3MAXFHSIZE]; 198 uint32_t authcnt; 199 uint32_t auth[7]; 200 } *repl; 201 struct { 202 uint32_t h[RPC_HEADER_WORDS]; 203 struct args d; 204 } sdata; 205 size_t cc; 206 207 #ifdef NFS_DEBUG 208 if (debug) 209 printf("nfs_getrootfh: %s\n", path); 210 #endif 211 212 args = &sdata.d; 213 214 bzero(args, sizeof(*args)); 215 len = strlen(path); 216 if (len > sizeof(args->path)) 217 len = sizeof(args->path); 218 args->len = htonl(len); 219 bcopy(path, args->path, len); 220 len = sizeof(uint32_t) + roundup(len, sizeof(uint32_t)); 221 222 cc = rpc_call(d, RPCPROG_MNT, RPCMNT_VER3, RPCMNT_MOUNT, 223 args, len, (void **)&repl, &pkt); 224 if (cc == -1) { 225 free(pkt); 226 /* errno was set by rpc_call */ 227 return (errno); 228 } 229 if (cc < 2 * sizeof (uint32_t)) { 230 free(pkt); 231 return (EBADRPC); 232 } 233 if (repl->errno != 0) { 234 free(pkt); 235 return (ntohl(repl->errno)); 236 } 237 *fhlenp = ntohl(repl->fhsize); 238 bcopy(repl->fh, fhp, *fhlenp); 239 240 set_nfs_read_size(); 241 free(pkt); 242 return (0); 243 } 244 245 /* 246 * Lookup a file. Store handle and attributes. 247 * Return zero or error number. 248 */ 249 int 250 nfs_lookupfh(struct nfs_iodesc *d, const char *name, struct nfs_iodesc *newfd) 251 { 252 void *pkt = NULL; 253 int len, rlen, pos; 254 struct args { 255 uint32_t fhsize; 256 uint32_t fhplusname[1 + 257 (NFS_V3MAXFHSIZE + FNAME_SIZE) / sizeof(uint32_t)]; 258 } *args; 259 struct repl { 260 uint32_t errno; 261 uint32_t fhsize; 262 uint32_t fhplusattr[(NFS_V3MAXFHSIZE + 263 2 * (sizeof(uint32_t) + 264 sizeof(struct nfsv3_fattrs))) / sizeof(uint32_t)]; 265 } *repl; 266 struct { 267 uint32_t h[RPC_HEADER_WORDS]; 268 struct args d; 269 } sdata; 270 ssize_t cc; 271 272 #ifdef NFS_DEBUG 273 if (debug) 274 printf("lookupfh: called\n"); 275 #endif 276 277 args = &sdata.d; 278 279 bzero(args, sizeof(*args)); 280 args->fhsize = htonl(d->fhsize); 281 bcopy(d->fh, args->fhplusname, d->fhsize); 282 len = strlen(name); 283 if (len > FNAME_SIZE) 284 len = FNAME_SIZE; 285 pos = roundup(d->fhsize, sizeof(uint32_t)) / sizeof(uint32_t); 286 args->fhplusname[pos++] = htonl(len); 287 bcopy(name, &args->fhplusname[pos], len); 288 len = sizeof(uint32_t) + pos * sizeof(uint32_t) + 289 roundup(len, sizeof(uint32_t)); 290 291 cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER3, NFSPROCV3_LOOKUP, 292 args, len, (void **)&repl, &pkt); 293 if (cc == -1) { 294 free(pkt); 295 return (errno); /* XXX - from rpc_call */ 296 } 297 if (cc < 2 * sizeof(uint32_t)) { 298 free(pkt); 299 return (EIO); 300 } 301 if (repl->errno != 0) { 302 free(pkt); 303 /* saerrno.h now matches NFS error numbers. */ 304 return (ntohl(repl->errno)); 305 } 306 newfd->fhsize = ntohl(repl->fhsize); 307 bcopy(repl->fhplusattr, &newfd->fh, newfd->fhsize); 308 pos = roundup(newfd->fhsize, sizeof(uint32_t)) / sizeof(uint32_t); 309 if (repl->fhplusattr[pos++] == 0) { 310 free(pkt); 311 return (EIO); 312 } 313 bcopy(&repl->fhplusattr[pos], &newfd->fa, sizeof(newfd->fa)); 314 free(pkt); 315 return (0); 316 } 317 318 #ifndef NFS_NOSYMLINK 319 /* 320 * Get the destination of a symbolic link. 321 */ 322 int 323 nfs_readlink(struct nfs_iodesc *d, char *buf) 324 { 325 void *pkt = NULL; 326 struct args { 327 uint32_t fhsize; 328 u_char fh[NFS_V3MAXFHSIZE]; 329 } *args; 330 struct repl { 331 uint32_t errno; 332 uint32_t ok; 333 struct nfsv3_fattrs fa; 334 uint32_t len; 335 u_char path[NFS_MAXPATHLEN]; 336 } *repl; 337 struct { 338 uint32_t h[RPC_HEADER_WORDS]; 339 struct args d; 340 } sdata; 341 ssize_t cc; 342 int rc = 0; 343 344 #ifdef NFS_DEBUG 345 if (debug) 346 printf("readlink: called\n"); 347 #endif 348 349 args = &sdata.d; 350 351 bzero(args, sizeof(*args)); 352 args->fhsize = htonl(d->fhsize); 353 bcopy(d->fh, args->fh, d->fhsize); 354 cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER3, NFSPROCV3_READLINK, 355 args, sizeof(uint32_t) + roundup(d->fhsize, sizeof(uint32_t)), 356 (void **)&repl, &pkt); 357 if (cc == -1) 358 return (errno); 359 360 if (cc < 2 * sizeof(uint32_t)) { 361 rc = EIO; 362 goto done; 363 } 364 365 if (repl->errno != 0) { 366 rc = ntohl(repl->errno); 367 goto done; 368 } 369 370 if (repl->ok == 0) { 371 rc = EIO; 372 goto done; 373 } 374 375 repl->len = ntohl(repl->len); 376 if (repl->len > NFS_MAXPATHLEN) { 377 rc = ENAMETOOLONG; 378 goto done; 379 } 380 381 bcopy(repl->path, buf, repl->len); 382 buf[repl->len] = 0; 383 done: 384 free(pkt); 385 return (rc); 386 } 387 #endif 388 389 /* 390 * Read data from a file. 391 * Return transfer count or -1 (and set errno) 392 */ 393 ssize_t 394 nfs_readdata(struct nfs_iodesc *d, off_t off, void *addr, size_t len) 395 { 396 void *pkt = NULL; 397 struct args { 398 uint32_t fhsize; 399 uint32_t fhoffcnt[NFS_V3MAXFHSIZE / sizeof(uint32_t) + 3]; 400 } *args; 401 struct repl { 402 uint32_t errno; 403 uint32_t ok; 404 struct nfsv3_fattrs fa; 405 uint32_t count; 406 uint32_t eof; 407 uint32_t len; 408 u_char data[NFSREAD_MAX_SIZE]; 409 } *repl; 410 struct { 411 uint32_t h[RPC_HEADER_WORDS]; 412 struct args d; 413 } sdata; 414 size_t cc; 415 long x; 416 int hlen, rlen, pos; 417 418 args = &sdata.d; 419 420 bzero(args, sizeof(*args)); 421 args->fhsize = htonl(d->fhsize); 422 bcopy(d->fh, args->fhoffcnt, d->fhsize); 423 pos = roundup(d->fhsize, sizeof(uint32_t)) / sizeof(uint32_t); 424 args->fhoffcnt[pos++] = 0; 425 args->fhoffcnt[pos++] = htonl((uint32_t)off); 426 if (len > nfs_read_size) 427 len = nfs_read_size; 428 args->fhoffcnt[pos] = htonl((uint32_t)len); 429 hlen = offsetof(struct repl, data[0]); 430 431 cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER3, NFSPROCV3_READ, 432 args, 4 * sizeof(uint32_t) + roundup(d->fhsize, sizeof(uint32_t)), 433 (void **)&repl, &pkt); 434 if (cc == -1) { 435 /* errno was already set by rpc_call */ 436 return (-1); 437 } 438 if (cc < hlen) { 439 errno = EBADRPC; 440 free(pkt); 441 return (-1); 442 } 443 if (repl->errno != 0) { 444 errno = ntohl(repl->errno); 445 free(pkt); 446 return (-1); 447 } 448 rlen = cc - hlen; 449 x = ntohl(repl->count); 450 if (rlen < x) { 451 printf("nfsread: short packet, %d < %ld\n", rlen, x); 452 errno = EBADRPC; 453 free(pkt); 454 return (-1); 455 } 456 bcopy(repl->data, addr, x); 457 free(pkt); 458 return (x); 459 } 460 461 /* 462 * Open a file. 463 * return zero or error number 464 */ 465 int 466 nfs_open(const char *upath, struct open_file *f) 467 { 468 struct iodesc *desc; 469 struct nfs_iodesc *currfd; 470 char buf[2 * NFS_V3MAXFHSIZE + 3]; 471 u_char *fh; 472 char *cp; 473 int i; 474 #ifndef NFS_NOSYMLINK 475 struct nfs_iodesc *newfd; 476 struct nfsv3_fattrs *fa; 477 char *ncp; 478 int c; 479 char namebuf[NFS_MAXPATHLEN + 1]; 480 char linkbuf[NFS_MAXPATHLEN + 1]; 481 int nlinks = 0; 482 #endif 483 int error; 484 char *path; 485 486 if (netproto != NET_NFS) 487 return (EINVAL); 488 489 #ifdef NFS_DEBUG 490 if (debug) 491 printf("nfs_open: %s (rootpath=%s)\n", upath, rootpath); 492 #endif 493 if (!rootpath[0]) { 494 printf("no rootpath, no nfs\n"); 495 return (ENXIO); 496 } 497 498 if (f->f_dev->dv_type != DEVT_NET) 499 return (EINVAL); 500 501 if (!(desc = socktodesc(*(int *)(f->f_devdata)))) 502 return (EINVAL); 503 504 /* Bind to a reserved port. */ 505 desc->myport = htons(--rpc_port); 506 desc->destip = rootip; 507 if ((error = nfs_getrootfh(desc, rootpath, &nfs_root_node.fhsize, 508 nfs_root_node.fh))) 509 return (error); 510 nfs_root_node.fa.fa_type = htonl(NFDIR); 511 nfs_root_node.fa.fa_mode = htonl(0755); 512 nfs_root_node.fa.fa_nlink = htonl(2); 513 nfs_root_node.iodesc = desc; 514 515 fh = &nfs_root_node.fh[0]; 516 buf[0] = 'X'; 517 cp = &buf[1]; 518 for (i = 0; i < nfs_root_node.fhsize; i++, cp += 2) 519 sprintf(cp, "%02x", fh[i]); 520 sprintf(cp, "X"); 521 setenv("boot.nfsroot.server", inet_ntoa(rootip), 1); 522 setenv("boot.nfsroot.path", rootpath, 1); 523 setenv("boot.nfsroot.nfshandle", buf, 1); 524 sprintf(buf, "%d", nfs_root_node.fhsize); 525 setenv("boot.nfsroot.nfshandlelen", buf, 1); 526 527 /* Allocate file system specific data structure */ 528 currfd = malloc(sizeof(*newfd)); 529 if (currfd == NULL) { 530 error = ENOMEM; 531 goto out; 532 } 533 #ifndef NFS_NOSYMLINK 534 bcopy(&nfs_root_node, currfd, sizeof(*currfd)); 535 newfd = NULL; 536 537 cp = path = strdup(upath); 538 if (path == NULL) { 539 error = ENOMEM; 540 goto out; 541 } 542 while (*cp) { 543 /* 544 * Remove extra separators 545 */ 546 while (*cp == '/') 547 cp++; 548 549 if (*cp == '\0') 550 break; 551 /* 552 * Check that current node is a directory. 553 */ 554 if (currfd->fa.fa_type != htonl(NFDIR)) { 555 error = ENOTDIR; 556 goto out; 557 } 558 559 /* allocate file system specific data structure */ 560 newfd = malloc(sizeof(*newfd)); 561 if (newfd == NULL) { 562 error = ENOMEM; 563 goto out; 564 } 565 newfd->iodesc = currfd->iodesc; 566 567 /* 568 * Get next component of path name. 569 */ 570 { 571 int len = 0; 572 573 ncp = cp; 574 while ((c = *cp) != '\0' && c != '/') { 575 if (++len > NFS_MAXNAMLEN) { 576 error = ENOENT; 577 goto out; 578 } 579 cp++; 580 } 581 *cp = '\0'; 582 } 583 584 /* lookup a file handle */ 585 error = nfs_lookupfh(currfd, ncp, newfd); 586 *cp = c; 587 if (error) 588 goto out; 589 590 /* 591 * Check for symbolic link 592 */ 593 if (newfd->fa.fa_type == htonl(NFLNK)) { 594 int link_len, len; 595 596 error = nfs_readlink(newfd, linkbuf); 597 if (error) 598 goto out; 599 600 link_len = strlen(linkbuf); 601 len = strlen(cp); 602 603 if (link_len + len > MAXPATHLEN 604 || ++nlinks > MAXSYMLINKS) { 605 error = ENOENT; 606 goto out; 607 } 608 609 bcopy(cp, &namebuf[link_len], len + 1); 610 bcopy(linkbuf, namebuf, link_len); 611 612 /* 613 * If absolute pathname, restart at root. 614 * If relative pathname, restart at parent directory. 615 */ 616 cp = namebuf; 617 if (*cp == '/') 618 bcopy(&nfs_root_node, currfd, sizeof(*currfd)); 619 620 free(newfd); 621 newfd = NULL; 622 623 continue; 624 } 625 626 free(currfd); 627 currfd = newfd; 628 newfd = NULL; 629 } 630 631 error = 0; 632 633 out: 634 free(newfd); 635 free(path); 636 #else 637 currfd->iodesc = desc; 638 639 error = nfs_lookupfh(&nfs_root_node, upath, currfd); 640 #endif 641 if (!error) { 642 currfd->off = 0; 643 currfd->cookie = 0; 644 f->f_fsdata = (void *)currfd; 645 return (0); 646 } 647 648 #ifdef NFS_DEBUG 649 if (debug) 650 printf("nfs_open: %s lookupfh failed: %s\n", 651 path, strerror(error)); 652 #endif 653 free(currfd); 654 655 return (error); 656 } 657 658 int 659 nfs_close(struct open_file *f) 660 { 661 struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; 662 663 #ifdef NFS_DEBUG 664 if (debug) 665 printf("nfs_close: fp=0x%lx\n", (u_long)fp); 666 #endif 667 668 free(fp); 669 f->f_fsdata = NULL; 670 671 return (0); 672 } 673 674 /* 675 * read a portion of a file 676 */ 677 int 678 nfs_read(struct open_file *f, void *buf, size_t size, size_t *resid) 679 { 680 struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; 681 ssize_t cc; 682 char *addr = buf; 683 684 #ifdef NFS_DEBUG 685 if (debug) 686 printf("nfs_read: size=%lu off=%d\n", (u_long)size, 687 (int)fp->off); 688 #endif 689 while ((int)size > 0) { 690 twiddle(16); 691 cc = nfs_readdata(fp, fp->off, (void *)addr, size); 692 /* XXX maybe should retry on certain errors */ 693 if (cc == -1) { 694 #ifdef NFS_DEBUG 695 if (debug) 696 printf("nfs_read: read: %s", strerror(errno)); 697 #endif 698 return (errno); /* XXX - from nfs_readdata */ 699 } 700 if (cc == 0) { 701 #ifdef NFS_DEBUG 702 if (debug) 703 printf("nfs_read: hit EOF unexpectantly"); 704 #endif 705 goto ret; 706 } 707 fp->off += cc; 708 addr += cc; 709 size -= cc; 710 } 711 ret: 712 if (resid) 713 *resid = size; 714 715 return (0); 716 } 717 718 /* 719 * Not implemented. 720 */ 721 int 722 nfs_write(struct open_file *f, void *buf, size_t size, size_t *resid) 723 { 724 return (EROFS); 725 } 726 727 off_t 728 nfs_seek(struct open_file *f, off_t offset, int where) 729 { 730 struct nfs_iodesc *d = (struct nfs_iodesc *)f->f_fsdata; 731 uint32_t size = ntohl(d->fa.fa_size.val[1]); 732 733 switch (where) { 734 case SEEK_SET: 735 d->off = offset; 736 break; 737 case SEEK_CUR: 738 d->off += offset; 739 break; 740 case SEEK_END: 741 d->off = size - offset; 742 break; 743 default: 744 errno = EINVAL; 745 return (-1); 746 } 747 748 return (d->off); 749 } 750 751 /* NFNON=0, NFREG=1, NFDIR=2, NFBLK=3, NFCHR=4, NFLNK=5, NFSOCK=6, NFFIFO=7 */ 752 int nfs_stat_types[9] = { 753 0, S_IFREG, S_IFDIR, S_IFBLK, S_IFCHR, S_IFLNK, S_IFSOCK, S_IFIFO, 0 }; 754 755 int 756 nfs_stat(struct open_file *f, struct stat *sb) 757 { 758 struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; 759 uint32_t ftype, mode; 760 761 ftype = ntohl(fp->fa.fa_type); 762 mode = ntohl(fp->fa.fa_mode); 763 mode |= nfs_stat_types[ftype & 7]; 764 765 sb->st_mode = mode; 766 sb->st_nlink = ntohl(fp->fa.fa_nlink); 767 sb->st_uid = ntohl(fp->fa.fa_uid); 768 sb->st_gid = ntohl(fp->fa.fa_gid); 769 sb->st_size = ntohl(fp->fa.fa_size.val[1]); 770 771 return (0); 772 } 773 774 static int 775 nfs_readdir(struct open_file *f, struct dirent *d) 776 { 777 struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; 778 struct nfsv3_readdir_repl *repl; 779 struct nfsv3_readdir_entry *rent; 780 static void *pkt = NULL; 781 static char *buf; 782 static struct nfs_iodesc *pfp = NULL; 783 static uint64_t cookie = 0; 784 size_t cc; 785 int pos, rc; 786 787 struct args { 788 uint32_t fhsize; 789 uint32_t fhpluscookie[5 + NFS_V3MAXFHSIZE]; 790 } *args; 791 struct { 792 uint32_t h[RPC_HEADER_WORDS]; 793 struct args d; 794 } sdata; 795 796 if (fp != pfp || fp->off != cookie) { 797 pfp = NULL; 798 refill: 799 free(pkt); 800 pkt = NULL; 801 args = &sdata.d; 802 bzero(args, sizeof(*args)); 803 804 args->fhsize = htonl(fp->fhsize); 805 bcopy(fp->fh, args->fhpluscookie, fp->fhsize); 806 pos = roundup(fp->fhsize, sizeof(uint32_t)) / sizeof(uint32_t); 807 args->fhpluscookie[pos++] = htonl(fp->off >> 32); 808 args->fhpluscookie[pos++] = htonl(fp->off); 809 args->fhpluscookie[pos++] = htonl(fp->cookie >> 32); 810 args->fhpluscookie[pos++] = htonl(fp->cookie); 811 args->fhpluscookie[pos] = htonl(NFS_READDIRSIZE); 812 813 cc = rpc_call(fp->iodesc, NFS_PROG, NFS_VER3, NFSPROCV3_READDIR, 814 args, 6 * sizeof(uint32_t) + 815 roundup(fp->fhsize, sizeof(uint32_t)), 816 (void **)&buf, &pkt); 817 if (cc == -1) { 818 rc = errno; 819 goto err; 820 } 821 repl = (struct nfsv3_readdir_repl *)buf; 822 if (repl->errno != 0) { 823 rc = ntohl(repl->errno); 824 goto err; 825 } 826 pfp = fp; 827 cookie = fp->off; 828 fp->cookie = ((uint64_t)ntohl(repl->cookiev0) << 32) | 829 ntohl(repl->cookiev1); 830 buf += sizeof (struct nfsv3_readdir_repl); 831 } 832 rent = (struct nfsv3_readdir_entry *)buf; 833 834 if (rent->follows == 0) { 835 /* fid0 is actually eof */ 836 if (rent->fid0 != 0) { 837 rc = ENOENT; 838 goto err; 839 } 840 goto refill; 841 } 842 843 d->d_namlen = ntohl(rent->len); 844 bcopy(rent->nameplus, d->d_name, d->d_namlen); 845 d->d_name[d->d_namlen] = '\0'; 846 847 pos = roundup(d->d_namlen, sizeof(uint32_t)) / sizeof(uint32_t); 848 fp->off = cookie = ((uint64_t)ntohl(rent->nameplus[pos]) << 32) | 849 ntohl(rent->nameplus[pos + 1]); 850 pos += 2; 851 buf = (u_char *)&rent->nameplus[pos]; 852 return (0); 853 854 err: 855 free(pkt); 856 pkt = NULL; 857 pfp = NULL; 858 cookie = 0; 859 return (rc); 860 } 861