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