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 /* Define our own NFS attributes without NQNFS stuff. */ 57 #ifdef OLD_NFSV2 58 struct nfsv2_fattrs { 59 n_long fa_type; 60 n_long fa_mode; 61 n_long fa_nlink; 62 n_long fa_uid; 63 n_long fa_gid; 64 n_long fa_size; 65 n_long fa_blocksize; 66 n_long fa_rdev; 67 n_long fa_blocks; 68 n_long fa_fsid; 69 n_long fa_fileid; 70 struct nfsv2_time fa_atime; 71 struct nfsv2_time fa_mtime; 72 struct nfsv2_time fa_ctime; 73 }; 74 75 struct nfs_read_args { 76 u_char fh[NFS_FHSIZE]; 77 n_long off; 78 n_long len; 79 n_long xxx; /* XXX what's this for? */ 80 }; 81 82 /* Data part of nfs rpc reply (also the largest thing we receive) */ 83 struct nfs_read_repl { 84 n_long errno; 85 struct nfsv2_fattrs fa; 86 n_long count; 87 u_char data[NFSREAD_MAX_SIZE]; 88 }; 89 90 #ifndef NFS_NOSYMLINK 91 struct nfs_readlnk_repl { 92 n_long errno; 93 n_long len; 94 char path[NFS_MAXPATHLEN]; 95 }; 96 #endif 97 98 struct nfs_readdir_args { 99 u_char fh[NFS_FHSIZE]; 100 n_long cookie; 101 n_long count; 102 }; 103 104 struct nfs_readdir_data { 105 n_long fileid; 106 n_long len; 107 char name[0]; 108 }; 109 110 struct nfs_readdir_off { 111 n_long cookie; 112 n_long follows; 113 }; 114 115 struct nfs_iodesc { 116 struct iodesc *iodesc; 117 off_t off; 118 u_char fh[NFS_FHSIZE]; 119 struct nfsv2_fattrs fa; /* all in network order */ 120 }; 121 #else /* !OLD_NFSV2 */ 122 123 /* NFSv3 definitions */ 124 #define NFS_V3MAXFHSIZE 64 125 #define NFS_VER3 3 126 #define RPCMNT_VER3 3 127 #define NFSPROCV3_LOOKUP 3 128 #define NFSPROCV3_READLINK 5 129 #define NFSPROCV3_READ 6 130 #define NFSPROCV3_READDIR 16 131 132 typedef struct { 133 uint32_t val[2]; 134 } n_quad; 135 136 struct nfsv3_time { 137 uint32_t nfs_sec; 138 uint32_t nfs_nsec; 139 }; 140 141 struct nfsv3_fattrs { 142 uint32_t fa_type; 143 uint32_t fa_mode; 144 uint32_t fa_nlink; 145 uint32_t fa_uid; 146 uint32_t fa_gid; 147 n_quad fa_size; 148 n_quad fa_used; 149 n_quad fa_rdev; 150 n_quad fa_fsid; 151 n_quad fa_fileid; 152 struct nfsv3_time fa_atime; 153 struct nfsv3_time fa_mtime; 154 struct nfsv3_time fa_ctime; 155 }; 156 157 /* 158 * For NFSv3, the file handle is variable in size, so most fixed sized 159 * structures for arguments won't work. For most cases, a structure 160 * that starts with any fixed size section is followed by an array 161 * that covers the maximum size required. 162 */ 163 struct nfsv3_readdir_repl { 164 uint32_t errno; 165 uint32_t ok; 166 struct nfsv3_fattrs fa; 167 uint32_t cookiev0; 168 uint32_t cookiev1; 169 }; 170 171 struct nfsv3_readdir_entry { 172 uint32_t follows; 173 uint32_t fid0; 174 uint32_t fid1; 175 uint32_t len; 176 uint32_t nameplus[0]; 177 }; 178 179 struct nfs_iodesc { 180 struct iodesc *iodesc; 181 off_t off; 182 uint32_t fhsize; 183 u_char fh[NFS_V3MAXFHSIZE]; 184 struct nfsv3_fattrs fa; /* all in network order */ 185 uint64_t cookie; 186 }; 187 #endif /* OLD_NFSV2 */ 188 189 /* 190 * XXX interactions with tftp? See nfswrapper.c for a confusing 191 * issue. 192 */ 193 int nfs_open(const char *path, struct open_file *f); 194 static int nfs_close(struct open_file *f); 195 static int nfs_read(struct open_file *f, void *buf, size_t size, size_t *resid); 196 static int nfs_write(struct open_file *f, void *buf, size_t size, size_t *resid); 197 static off_t nfs_seek(struct open_file *f, off_t offset, int where); 198 static int nfs_stat(struct open_file *f, struct stat *sb); 199 static int nfs_readdir(struct open_file *f, struct dirent *d); 200 201 struct nfs_iodesc nfs_root_node; 202 203 struct fs_ops nfs_fsops = { 204 "nfs", 205 nfs_open, 206 nfs_close, 207 nfs_read, 208 nfs_write, 209 nfs_seek, 210 nfs_stat, 211 nfs_readdir 212 }; 213 214 static int nfs_read_size = NFSREAD_MIN_SIZE; 215 216 /* 217 * Improve boot performance over NFS 218 */ 219 static void 220 set_nfs_read_size(void) 221 { 222 char *env, *end; 223 char buf[10]; 224 225 if ((env = getenv("nfs.read_size")) != NULL) { 226 errno = 0; 227 nfs_read_size = strtol(env, &end, 0); 228 if (errno != 0 || *env == '\0' || *end != '\0') { 229 printf("%s: bad value: \"%s\", defaulting to %d\n", 230 "nfs.read_size", env, NFSREAD_MIN_SIZE); 231 nfs_read_size = NFSREAD_MIN_SIZE; 232 } 233 } 234 if (nfs_read_size < NFSREAD_MIN_SIZE) { 235 printf("%s: bad value: \"%d\", defaulting to %d\n", 236 "nfs.read_size", nfs_read_size, NFSREAD_MIN_SIZE); 237 nfs_read_size = NFSREAD_MIN_SIZE; 238 } 239 if (nfs_read_size > NFSREAD_MAX_SIZE) { 240 printf("%s: bad value: \"%d\", defaulting to %d\n", 241 "nfs.read_size", nfs_read_size, NFSREAD_MIN_SIZE); 242 nfs_read_size = NFSREAD_MAX_SIZE; 243 } 244 snprintf(buf, sizeof (buf), "%d", nfs_read_size); 245 setenv("nfs.read_size", buf, 1); 246 } 247 248 #ifdef OLD_NFSV2 249 /* 250 * Fetch the root file handle (call mount daemon) 251 * Return zero or error number. 252 */ 253 int 254 nfs_getrootfh(struct iodesc *d, char *path, u_char *fhp) 255 { 256 int len; 257 struct args { 258 n_long len; 259 char path[FNAME_SIZE]; 260 } *args; 261 struct repl { 262 n_long errno; 263 u_char fh[NFS_FHSIZE]; 264 } *repl; 265 struct { 266 n_long h[RPC_HEADER_WORDS]; 267 struct args d; 268 } sdata; 269 struct { 270 n_long h[RPC_HEADER_WORDS]; 271 struct repl d; 272 } rdata; 273 size_t cc; 274 275 #ifdef NFS_DEBUG 276 if (debug) 277 printf("nfs_getrootfh: %s\n", path); 278 #endif 279 280 args = &sdata.d; 281 repl = &rdata.d; 282 283 bzero(args, sizeof(*args)); 284 len = strlen(path); 285 if (len > sizeof(args->path)) 286 len = sizeof(args->path); 287 args->len = htonl(len); 288 bcopy(path, args->path, len); 289 len = 4 + roundup(len, 4); 290 291 cc = rpc_call(d, RPCPROG_MNT, RPCMNT_VER1, RPCMNT_MOUNT, 292 args, len, repl, sizeof(*repl)); 293 if (cc == -1) { 294 /* errno was set by rpc_call */ 295 return (errno); 296 } 297 if (cc < 4) 298 return (EBADRPC); 299 if (repl->errno) 300 return (ntohl(repl->errno)); 301 bcopy(repl->fh, fhp, sizeof(repl->fh)); 302 303 set_nfs_read_size(); 304 return (0); 305 } 306 307 /* 308 * Lookup a file. Store handle and attributes. 309 * Return zero or error number. 310 */ 311 int 312 nfs_lookupfh(struct nfs_iodesc *d, const char *name, struct nfs_iodesc *newfd) 313 { 314 int len, rlen; 315 struct args { 316 u_char fh[NFS_FHSIZE]; 317 n_long len; 318 char name[FNAME_SIZE]; 319 } *args; 320 struct repl { 321 n_long errno; 322 u_char fh[NFS_FHSIZE]; 323 struct nfsv2_fattrs fa; 324 } *repl; 325 struct { 326 n_long h[RPC_HEADER_WORDS]; 327 struct args d; 328 } sdata; 329 struct { 330 n_long h[RPC_HEADER_WORDS]; 331 struct repl d; 332 } rdata; 333 ssize_t cc; 334 335 #ifdef NFS_DEBUG 336 if (debug) 337 printf("lookupfh: called\n"); 338 #endif 339 340 args = &sdata.d; 341 repl = &rdata.d; 342 343 bzero(args, sizeof(*args)); 344 bcopy(d->fh, args->fh, sizeof(args->fh)); 345 len = strlen(name); 346 if (len > sizeof(args->name)) 347 len = sizeof(args->name); 348 bcopy(name, args->name, len); 349 args->len = htonl(len); 350 len = 4 + roundup(len, 4); 351 len += NFS_FHSIZE; 352 353 rlen = sizeof(*repl); 354 355 cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER2, NFSPROC_LOOKUP, 356 args, len, repl, rlen); 357 if (cc == -1) 358 return (errno); /* XXX - from rpc_call */ 359 if (cc < 4) 360 return (EIO); 361 if (repl->errno) { 362 /* saerrno.h now matches NFS error numbers. */ 363 return (ntohl(repl->errno)); 364 } 365 bcopy( repl->fh, &newfd->fh, sizeof(newfd->fh)); 366 bcopy(&repl->fa, &newfd->fa, sizeof(newfd->fa)); 367 return (0); 368 } 369 370 #ifndef NFS_NOSYMLINK 371 /* 372 * Get the destination of a symbolic link. 373 */ 374 int 375 nfs_readlink(struct nfs_iodesc *d, char *buf) 376 { 377 struct { 378 n_long h[RPC_HEADER_WORDS]; 379 u_char fh[NFS_FHSIZE]; 380 } sdata; 381 struct { 382 n_long h[RPC_HEADER_WORDS]; 383 struct nfs_readlnk_repl d; 384 } rdata; 385 ssize_t cc; 386 387 #ifdef NFS_DEBUG 388 if (debug) 389 printf("readlink: called\n"); 390 #endif 391 392 bcopy(d->fh, sdata.fh, NFS_FHSIZE); 393 cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER2, NFSPROC_READLINK, 394 sdata.fh, NFS_FHSIZE, 395 &rdata.d, sizeof(rdata.d)); 396 if (cc == -1) 397 return (errno); 398 399 if (cc < 4) 400 return (EIO); 401 402 if (rdata.d.errno) 403 return (ntohl(rdata.d.errno)); 404 405 rdata.d.len = ntohl(rdata.d.len); 406 if (rdata.d.len > NFS_MAXPATHLEN) 407 return (ENAMETOOLONG); 408 409 bcopy(rdata.d.path, buf, rdata.d.len); 410 buf[rdata.d.len] = 0; 411 return (0); 412 } 413 #endif 414 415 /* 416 * Read data from a file. 417 * Return transfer count or -1 (and set errno) 418 */ 419 ssize_t 420 nfs_readdata(struct nfs_iodesc *d, off_t off, void *addr, size_t len) 421 { 422 struct nfs_read_args *args; 423 struct nfs_read_repl *repl; 424 struct { 425 n_long h[RPC_HEADER_WORDS]; 426 struct nfs_read_args d; 427 } sdata; 428 struct { 429 n_long h[RPC_HEADER_WORDS]; 430 struct nfs_read_repl d; 431 } rdata; 432 size_t cc; 433 long x; 434 int hlen, rlen; 435 436 args = &sdata.d; 437 repl = &rdata.d; 438 439 bcopy(d->fh, args->fh, NFS_FHSIZE); 440 args->off = htonl((n_long)off); 441 if (len > nfs_read_size) 442 len = nfs_read_size; 443 args->len = htonl((n_long)len); 444 args->xxx = htonl((n_long)0); 445 hlen = offsetof(struct nfs_read_rpl, data[0]); 446 447 cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER2, NFSPROC_READ, 448 args, sizeof(*args), 449 repl, sizeof(*repl)); 450 if (cc == -1) { 451 /* errno was already set by rpc_call */ 452 return (-1); 453 } 454 if (cc < hlen) { 455 errno = EBADRPC; 456 return (-1); 457 } 458 if (repl->errno) { 459 errno = ntohl(repl->errno); 460 return (-1); 461 } 462 rlen = cc - hlen; 463 x = ntohl(repl->count); 464 if (rlen < x) { 465 printf("nfsread: short packet, %d < %ld\n", rlen, x); 466 errno = EBADRPC; 467 return(-1); 468 } 469 bcopy(repl->data, addr, x); 470 return (x); 471 } 472 473 /* 474 * Open a file. 475 * return zero or error number 476 */ 477 int 478 nfs_open(const char *upath, struct open_file *f) 479 { 480 struct iodesc *desc; 481 struct nfs_iodesc *currfd; 482 char buf[2 * NFS_FHSIZE + 3]; 483 u_char *fh; 484 char *cp; 485 int i; 486 #ifndef NFS_NOSYMLINK 487 struct nfs_iodesc *newfd; 488 struct nfsv2_fattrs *fa; 489 char *ncp; 490 int c; 491 char namebuf[NFS_MAXPATHLEN + 1]; 492 char linkbuf[NFS_MAXPATHLEN + 1]; 493 int nlinks = 0; 494 #endif 495 int error; 496 char *path; 497 498 if (netproto != NET_NFS) 499 return (EINVAL); 500 501 #ifdef NFS_DEBUG 502 if (debug) 503 printf("nfs_open: %s (rootpath=%s)\n", upath, rootpath); 504 #endif 505 if (!rootpath[0]) { 506 printf("no rootpath, no nfs\n"); 507 return (ENXIO); 508 } 509 510 /* 511 * This is silly - we should look at dv_type but that value is 512 * arch dependant and we can't use it here. 513 */ 514 #ifndef __i386__ 515 if (strcmp(f->f_dev->dv_name, "net") != 0) 516 return(EINVAL); 517 #else 518 if (strcmp(f->f_dev->dv_name, "pxe") != 0) 519 return(EINVAL); 520 #endif 521 522 if (!(desc = socktodesc(*(int *)(f->f_devdata)))) 523 return(EINVAL); 524 525 /* Bind to a reserved port. */ 526 desc->myport = htons(--rpc_port); 527 desc->destip = rootip; 528 if ((error = nfs_getrootfh(desc, rootpath, nfs_root_node.fh))) 529 return (error); 530 nfs_root_node.fa.fa_type = htonl(NFDIR); 531 nfs_root_node.fa.fa_mode = htonl(0755); 532 nfs_root_node.fa.fa_nlink = htonl(2); 533 nfs_root_node.iodesc = desc; 534 535 fh = &nfs_root_node.fh[0]; 536 buf[0] = 'X'; 537 cp = &buf[1]; 538 for (i = 0; i < NFS_FHSIZE; i++, cp += 2) 539 sprintf(cp, "%02x", fh[i]); 540 sprintf(cp, "X"); 541 setenv("boot.nfsroot.server", inet_ntoa(rootip), 1); 542 setenv("boot.nfsroot.path", rootpath, 1); 543 setenv("boot.nfsroot.nfshandle", buf, 1); 544 545 /* Allocate file system specific data structure */ 546 currfd = malloc(sizeof(*newfd)); 547 if (currfd == NULL) { 548 error = ENOMEM; 549 goto out; 550 } 551 552 #ifndef NFS_NOSYMLINK 553 bcopy(&nfs_root_node, currfd, sizeof(*currfd)); 554 newfd = NULL; 555 556 cp = path = strdup(upath); 557 if (path == NULL) { 558 error = ENOMEM; 559 goto out; 560 } 561 while (*cp) { 562 /* 563 * Remove extra separators 564 */ 565 while (*cp == '/') 566 cp++; 567 568 if (*cp == '\0') 569 break; 570 /* 571 * Check that current node is a directory. 572 */ 573 if (currfd->fa.fa_type != htonl(NFDIR)) { 574 error = ENOTDIR; 575 goto out; 576 } 577 578 /* allocate file system specific data structure */ 579 newfd = malloc(sizeof(*newfd)); 580 newfd->iodesc = currfd->iodesc; 581 582 /* 583 * Get next component of path name. 584 */ 585 { 586 int len = 0; 587 588 ncp = cp; 589 while ((c = *cp) != '\0' && c != '/') { 590 if (++len > NFS_MAXNAMLEN) { 591 error = ENOENT; 592 goto out; 593 } 594 cp++; 595 } 596 *cp = '\0'; 597 } 598 599 /* lookup a file handle */ 600 error = nfs_lookupfh(currfd, ncp, newfd); 601 *cp = c; 602 if (error) 603 goto out; 604 605 /* 606 * Check for symbolic link 607 */ 608 if (newfd->fa.fa_type == htonl(NFLNK)) { 609 int link_len, len; 610 611 error = nfs_readlink(newfd, linkbuf); 612 if (error) 613 goto out; 614 615 link_len = strlen(linkbuf); 616 len = strlen(cp); 617 618 if (link_len + len > MAXPATHLEN 619 || ++nlinks > MAXSYMLINKS) { 620 error = ENOENT; 621 goto out; 622 } 623 624 bcopy(cp, &namebuf[link_len], len + 1); 625 bcopy(linkbuf, namebuf, link_len); 626 627 /* 628 * If absolute pathname, restart at root. 629 * If relative pathname, restart at parent directory. 630 */ 631 cp = namebuf; 632 if (*cp == '/') 633 bcopy(&nfs_root_node, currfd, sizeof(*currfd)); 634 635 free(newfd); 636 newfd = NULL; 637 638 continue; 639 } 640 641 free(currfd); 642 currfd = newfd; 643 newfd = NULL; 644 } 645 646 error = 0; 647 648 out: 649 free(newfd); 650 free(path); 651 #else 652 currfd->iodesc = desc; 653 654 error = nfs_lookupfh(&nfs_root_node, upath, currfd); 655 #endif 656 if (!error) { 657 currfd->off = 0; 658 f->f_fsdata = (void *)currfd; 659 return (0); 660 } 661 662 #ifdef NFS_DEBUG 663 if (debug) 664 printf("nfs_open: %s lookupfh failed: %s\n", 665 path, strerror(error)); 666 #endif 667 free(currfd); 668 669 return (error); 670 } 671 672 int 673 nfs_close(struct open_file *f) 674 { 675 struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; 676 677 #ifdef NFS_DEBUG 678 if (debug) 679 printf("nfs_close: fp=0x%lx\n", (u_long)fp); 680 #endif 681 682 if (fp) 683 free(fp); 684 f->f_fsdata = (void *)0; 685 686 return (0); 687 } 688 689 /* 690 * read a portion of a file 691 */ 692 int 693 nfs_read(struct open_file *f, void *buf, size_t size, size_t *resid) 694 { 695 struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; 696 ssize_t cc; 697 char *addr = buf; 698 699 #ifdef NFS_DEBUG 700 if (debug) 701 printf("nfs_read: size=%lu off=%d\n", (u_long)size, 702 (int)fp->off); 703 #endif 704 while ((int)size > 0) { 705 twiddle(16); 706 cc = nfs_readdata(fp, fp->off, (void *)addr, size); 707 /* XXX maybe should retry on certain errors */ 708 if (cc == -1) { 709 #ifdef NFS_DEBUG 710 if (debug) 711 printf("nfs_read: read: %s", strerror(errno)); 712 #endif 713 return (errno); /* XXX - from nfs_readdata */ 714 } 715 if (cc == 0) { 716 #ifdef NFS_DEBUG 717 if (debug) 718 printf("nfs_read: hit EOF unexpectantly"); 719 #endif 720 goto ret; 721 } 722 fp->off += cc; 723 addr += cc; 724 size -= cc; 725 } 726 ret: 727 if (resid) 728 *resid = size; 729 730 return (0); 731 } 732 733 /* 734 * Not implemented. 735 */ 736 int 737 nfs_write(struct open_file *f, void *buf, size_t size, size_t *resid) 738 { 739 return (EROFS); 740 } 741 742 off_t 743 nfs_seek(struct open_file *f, off_t offset, int where) 744 { 745 struct nfs_iodesc *d = (struct nfs_iodesc *)f->f_fsdata; 746 n_long size = ntohl(d->fa.fa_size); 747 748 switch (where) { 749 case SEEK_SET: 750 d->off = offset; 751 break; 752 case SEEK_CUR: 753 d->off += offset; 754 break; 755 case SEEK_END: 756 d->off = size - offset; 757 break; 758 default: 759 errno = EINVAL; 760 return (-1); 761 } 762 763 return (d->off); 764 } 765 766 /* NFNON=0, NFREG=1, NFDIR=2, NFBLK=3, NFCHR=4, NFLNK=5 */ 767 int nfs_stat_types[8] = { 768 0, S_IFREG, S_IFDIR, S_IFBLK, S_IFCHR, S_IFLNK, 0 }; 769 770 int 771 nfs_stat(struct open_file *f, struct stat *sb) 772 { 773 struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; 774 n_long ftype, mode; 775 776 ftype = ntohl(fp->fa.fa_type); 777 mode = ntohl(fp->fa.fa_mode); 778 mode |= nfs_stat_types[ftype & 7]; 779 780 sb->st_mode = mode; 781 sb->st_nlink = ntohl(fp->fa.fa_nlink); 782 sb->st_uid = ntohl(fp->fa.fa_uid); 783 sb->st_gid = ntohl(fp->fa.fa_gid); 784 sb->st_size = ntohl(fp->fa.fa_size); 785 786 return (0); 787 } 788 789 static int 790 nfs_readdir(struct open_file *f, struct dirent *d) 791 { 792 struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; 793 struct nfs_readdir_args *args; 794 struct nfs_readdir_data *rd; 795 struct nfs_readdir_off *roff = NULL; 796 static char *buf; 797 static struct nfs_iodesc *pfp = NULL; 798 static n_long cookie = 0; 799 size_t cc; 800 n_long eof; 801 802 struct { 803 n_long h[RPC_HEADER_WORDS]; 804 struct nfs_readdir_args d; 805 } sdata; 806 static struct { 807 n_long h[RPC_HEADER_WORDS]; 808 u_char d[NFS_READDIRSIZE]; 809 } rdata; 810 811 if (fp != pfp || fp->off != cookie) { 812 pfp = NULL; 813 refill: 814 args = &sdata.d; 815 bzero(args, sizeof(*args)); 816 817 bcopy(fp->fh, args->fh, NFS_FHSIZE); 818 args->cookie = htonl(fp->off); 819 args->count = htonl(NFS_READDIRSIZE); 820 821 cc = rpc_call(fp->iodesc, NFS_PROG, NFS_VER2, NFSPROC_READDIR, 822 args, sizeof(*args), 823 rdata.d, sizeof(rdata.d)); 824 buf = rdata.d; 825 roff = (struct nfs_readdir_off *)buf; 826 if (ntohl(roff->cookie) != 0) 827 return EIO; 828 pfp = fp; 829 cookie = fp->off; 830 } 831 roff = (struct nfs_readdir_off *)buf; 832 833 if (ntohl(roff->follows) == 0) { 834 eof = ntohl((roff+1)->cookie); 835 if (eof) { 836 cookie = 0; 837 return ENOENT; 838 } 839 goto refill; 840 } 841 842 buf += sizeof(struct nfs_readdir_off); 843 rd = (struct nfs_readdir_data *)buf; 844 d->d_namlen = ntohl(rd->len); 845 bcopy(rd->name, d->d_name, d->d_namlen); 846 d->d_name[d->d_namlen] = '\0'; 847 848 buf += (sizeof(struct nfs_readdir_data) + roundup(htonl(rd->len),4)); 849 roff = (struct nfs_readdir_off *)buf; 850 fp->off = cookie = ntohl(roff->cookie); 851 return 0; 852 } 853 #else /* !OLD_NFSV2 */ 854 /* 855 * Fetch the root file handle (call mount daemon) 856 * Return zero or error number. 857 */ 858 int 859 nfs_getrootfh(struct iodesc *d, char *path, uint32_t *fhlenp, u_char *fhp) 860 { 861 int len; 862 struct args { 863 uint32_t len; 864 char path[FNAME_SIZE]; 865 } *args; 866 struct repl { 867 uint32_t errno; 868 uint32_t fhsize; 869 u_char fh[NFS_V3MAXFHSIZE]; 870 uint32_t authcnt; 871 uint32_t auth[7]; 872 } *repl; 873 struct { 874 uint32_t h[RPC_HEADER_WORDS]; 875 struct args d; 876 } sdata; 877 struct { 878 uint32_t h[RPC_HEADER_WORDS]; 879 struct repl d; 880 } rdata; 881 size_t cc; 882 883 #ifdef NFS_DEBUG 884 if (debug) 885 printf("nfs_getrootfh: %s\n", path); 886 #endif 887 888 args = &sdata.d; 889 repl = &rdata.d; 890 891 bzero(args, sizeof(*args)); 892 len = strlen(path); 893 if (len > sizeof(args->path)) 894 len = sizeof(args->path); 895 args->len = htonl(len); 896 bcopy(path, args->path, len); 897 len = sizeof(uint32_t) + roundup(len, sizeof(uint32_t)); 898 899 cc = rpc_call(d, RPCPROG_MNT, RPCMNT_VER3, RPCMNT_MOUNT, 900 args, len, repl, sizeof(*repl)); 901 if (cc == -1) 902 /* errno was set by rpc_call */ 903 return (errno); 904 if (cc < 2 * sizeof (uint32_t)) 905 return (EBADRPC); 906 if (repl->errno != 0) 907 return (ntohl(repl->errno)); 908 *fhlenp = ntohl(repl->fhsize); 909 bcopy(repl->fh, fhp, *fhlenp); 910 911 set_nfs_read_size(); 912 return (0); 913 } 914 915 /* 916 * Lookup a file. Store handle and attributes. 917 * Return zero or error number. 918 */ 919 int 920 nfs_lookupfh(struct nfs_iodesc *d, const char *name, struct nfs_iodesc *newfd) 921 { 922 int len, rlen, pos; 923 struct args { 924 uint32_t fhsize; 925 uint32_t fhplusname[1 + 926 (NFS_V3MAXFHSIZE + FNAME_SIZE) / sizeof(uint32_t)]; 927 } *args; 928 struct repl { 929 uint32_t errno; 930 uint32_t fhsize; 931 uint32_t fhplusattr[(NFS_V3MAXFHSIZE + 932 2 * (sizeof(uint32_t) + 933 sizeof(struct nfsv3_fattrs))) / sizeof(uint32_t)]; 934 } *repl; 935 struct { 936 uint32_t h[RPC_HEADER_WORDS]; 937 struct args d; 938 } sdata; 939 struct { 940 uint32_t h[RPC_HEADER_WORDS]; 941 struct repl d; 942 } rdata; 943 ssize_t cc; 944 945 #ifdef NFS_DEBUG 946 if (debug) 947 printf("lookupfh: called\n"); 948 #endif 949 950 args = &sdata.d; 951 repl = &rdata.d; 952 953 bzero(args, sizeof(*args)); 954 args->fhsize = htonl(d->fhsize); 955 bcopy(d->fh, args->fhplusname, d->fhsize); 956 len = strlen(name); 957 if (len > FNAME_SIZE) 958 len = FNAME_SIZE; 959 pos = roundup(d->fhsize, sizeof(uint32_t)) / sizeof(uint32_t); 960 args->fhplusname[pos++] = htonl(len); 961 bcopy(name, &args->fhplusname[pos], len); 962 len = sizeof(uint32_t) + pos * sizeof(uint32_t) + 963 roundup(len, sizeof(uint32_t)); 964 965 rlen = sizeof(*repl); 966 967 cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER3, NFSPROCV3_LOOKUP, 968 args, len, repl, rlen); 969 if (cc == -1) 970 return (errno); /* XXX - from rpc_call */ 971 if (cc < 2 * sizeof(uint32_t)) 972 return (EIO); 973 if (repl->errno != 0) 974 /* saerrno.h now matches NFS error numbers. */ 975 return (ntohl(repl->errno)); 976 newfd->fhsize = ntohl(repl->fhsize); 977 bcopy(repl->fhplusattr, &newfd->fh, newfd->fhsize); 978 pos = roundup(newfd->fhsize, sizeof(uint32_t)) / sizeof(uint32_t); 979 if (repl->fhplusattr[pos++] == 0) 980 return (EIO); 981 bcopy(&repl->fhplusattr[pos], &newfd->fa, sizeof(newfd->fa)); 982 return (0); 983 } 984 985 #ifndef NFS_NOSYMLINK 986 /* 987 * Get the destination of a symbolic link. 988 */ 989 int 990 nfs_readlink(struct nfs_iodesc *d, char *buf) 991 { 992 struct args { 993 uint32_t fhsize; 994 u_char fh[NFS_V3MAXFHSIZE]; 995 } *args; 996 struct repl { 997 uint32_t errno; 998 uint32_t ok; 999 struct nfsv3_fattrs fa; 1000 uint32_t len; 1001 u_char path[NFS_MAXPATHLEN]; 1002 } *repl; 1003 struct { 1004 uint32_t h[RPC_HEADER_WORDS]; 1005 struct args d; 1006 } sdata; 1007 struct { 1008 uint32_t h[RPC_HEADER_WORDS]; 1009 struct repl d; 1010 } rdata; 1011 ssize_t cc; 1012 1013 #ifdef NFS_DEBUG 1014 if (debug) 1015 printf("readlink: called\n"); 1016 #endif 1017 1018 args = &sdata.d; 1019 repl = &rdata.d; 1020 1021 bzero(args, sizeof(*args)); 1022 args->fhsize = htonl(d->fhsize); 1023 bcopy(d->fh, args->fh, d->fhsize); 1024 cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER3, NFSPROCV3_READLINK, 1025 args, sizeof(uint32_t) + roundup(d->fhsize, sizeof(uint32_t)), 1026 repl, sizeof(*repl)); 1027 if (cc == -1) 1028 return (errno); 1029 1030 if (cc < 2 * sizeof(uint32_t)) 1031 return (EIO); 1032 1033 if (repl->errno != 0) 1034 return (ntohl(repl->errno)); 1035 1036 if (repl->ok == 0) 1037 return (EIO); 1038 1039 repl->len = ntohl(repl->len); 1040 if (repl->len > NFS_MAXPATHLEN) 1041 return (ENAMETOOLONG); 1042 1043 bcopy(repl->path, buf, repl->len); 1044 buf[repl->len] = 0; 1045 return (0); 1046 } 1047 #endif 1048 1049 /* 1050 * Read data from a file. 1051 * Return transfer count or -1 (and set errno) 1052 */ 1053 ssize_t 1054 nfs_readdata(struct nfs_iodesc *d, off_t off, void *addr, size_t len) 1055 { 1056 struct args { 1057 uint32_t fhsize; 1058 uint32_t fhoffcnt[NFS_V3MAXFHSIZE / sizeof(uint32_t) + 3]; 1059 } *args; 1060 struct repl { 1061 uint32_t errno; 1062 uint32_t ok; 1063 struct nfsv3_fattrs fa; 1064 uint32_t count; 1065 uint32_t eof; 1066 uint32_t len; 1067 u_char data[NFSREAD_MAX_SIZE]; 1068 } *repl; 1069 struct { 1070 uint32_t h[RPC_HEADER_WORDS]; 1071 struct args d; 1072 } sdata; 1073 struct { 1074 uint32_t h[RPC_HEADER_WORDS]; 1075 struct repl d; 1076 } rdata; 1077 size_t cc; 1078 long x; 1079 int hlen, rlen, pos; 1080 1081 args = &sdata.d; 1082 repl = &rdata.d; 1083 1084 bzero(args, sizeof(*args)); 1085 args->fhsize = htonl(d->fhsize); 1086 bcopy(d->fh, args->fhoffcnt, d->fhsize); 1087 pos = roundup(d->fhsize, sizeof(uint32_t)) / sizeof(uint32_t); 1088 args->fhoffcnt[pos++] = 0; 1089 args->fhoffcnt[pos++] = htonl((uint32_t)off); 1090 if (len > nfs_read_size) 1091 len = nfs_read_size; 1092 args->fhoffcnt[pos] = htonl((uint32_t)len); 1093 hlen = offsetof(struct repl, data[0]); 1094 1095 cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER3, NFSPROCV3_READ, 1096 args, 4 * sizeof(uint32_t) + roundup(d->fhsize, sizeof(uint32_t)), 1097 repl, sizeof(*repl)); 1098 if (cc == -1) 1099 /* errno was already set by rpc_call */ 1100 return (-1); 1101 if (cc < hlen) { 1102 errno = EBADRPC; 1103 return (-1); 1104 } 1105 if (repl->errno != 0) { 1106 errno = ntohl(repl->errno); 1107 return (-1); 1108 } 1109 rlen = cc - hlen; 1110 x = ntohl(repl->count); 1111 if (rlen < x) { 1112 printf("nfsread: short packet, %d < %ld\n", rlen, x); 1113 errno = EBADRPC; 1114 return (-1); 1115 } 1116 bcopy(repl->data, addr, x); 1117 return (x); 1118 } 1119 1120 /* 1121 * Open a file. 1122 * return zero or error number 1123 */ 1124 int 1125 nfs_open(const char *upath, struct open_file *f) 1126 { 1127 struct iodesc *desc; 1128 struct nfs_iodesc *currfd; 1129 char buf[2 * NFS_V3MAXFHSIZE + 3]; 1130 u_char *fh; 1131 char *cp; 1132 int i; 1133 #ifndef NFS_NOSYMLINK 1134 struct nfs_iodesc *newfd; 1135 struct nfsv3_fattrs *fa; 1136 char *ncp; 1137 int c; 1138 char namebuf[NFS_MAXPATHLEN + 1]; 1139 char linkbuf[NFS_MAXPATHLEN + 1]; 1140 int nlinks = 0; 1141 #endif 1142 int error; 1143 char *path; 1144 1145 if (netproto != NET_NFS) 1146 return (EINVAL); 1147 1148 #ifdef NFS_DEBUG 1149 if (debug) 1150 printf("nfs_open: %s (rootpath=%s)\n", upath, rootpath); 1151 #endif 1152 if (!rootpath[0]) { 1153 printf("no rootpath, no nfs\n"); 1154 return (ENXIO); 1155 } 1156 1157 /* 1158 * This is silly - we should look at dv_type but that value is 1159 * arch dependant and we can't use it here. 1160 */ 1161 #ifndef __i386__ 1162 if (strcmp(f->f_dev->dv_name, "net") != 0) 1163 return (EINVAL); 1164 #else 1165 if (strcmp(f->f_dev->dv_name, "pxe") != 0) 1166 return (EINVAL); 1167 #endif 1168 1169 if (!(desc = socktodesc(*(int *)(f->f_devdata)))) 1170 return (EINVAL); 1171 1172 /* Bind to a reserved port. */ 1173 desc->myport = htons(--rpc_port); 1174 desc->destip = rootip; 1175 if ((error = nfs_getrootfh(desc, rootpath, &nfs_root_node.fhsize, 1176 nfs_root_node.fh))) 1177 return (error); 1178 nfs_root_node.fa.fa_type = htonl(NFDIR); 1179 nfs_root_node.fa.fa_mode = htonl(0755); 1180 nfs_root_node.fa.fa_nlink = htonl(2); 1181 nfs_root_node.iodesc = desc; 1182 1183 fh = &nfs_root_node.fh[0]; 1184 buf[0] = 'X'; 1185 cp = &buf[1]; 1186 for (i = 0; i < nfs_root_node.fhsize; i++, cp += 2) 1187 sprintf(cp, "%02x", fh[i]); 1188 sprintf(cp, "X"); 1189 setenv("boot.nfsroot.server", inet_ntoa(rootip), 1); 1190 setenv("boot.nfsroot.path", rootpath, 1); 1191 setenv("boot.nfsroot.nfshandle", buf, 1); 1192 sprintf(buf, "%d", nfs_root_node.fhsize); 1193 setenv("boot.nfsroot.nfshandlelen", buf, 1); 1194 1195 /* Allocate file system specific data structure */ 1196 currfd = malloc(sizeof(*newfd)); 1197 if (currfd == NULL) { 1198 error = ENOMEM; 1199 goto out; 1200 } 1201 #ifndef NFS_NOSYMLINK 1202 bcopy(&nfs_root_node, currfd, sizeof(*currfd)); 1203 newfd = NULL; 1204 1205 cp = path = strdup(upath); 1206 if (path == NULL) { 1207 error = ENOMEM; 1208 goto out; 1209 } 1210 while (*cp) { 1211 /* 1212 * Remove extra separators 1213 */ 1214 while (*cp == '/') 1215 cp++; 1216 1217 if (*cp == '\0') 1218 break; 1219 /* 1220 * Check that current node is a directory. 1221 */ 1222 if (currfd->fa.fa_type != htonl(NFDIR)) { 1223 error = ENOTDIR; 1224 goto out; 1225 } 1226 1227 /* allocate file system specific data structure */ 1228 newfd = malloc(sizeof(*newfd)); 1229 if (newfd == NULL) { 1230 error = ENOMEM; 1231 goto out; 1232 } 1233 newfd->iodesc = currfd->iodesc; 1234 1235 /* 1236 * Get next component of path name. 1237 */ 1238 { 1239 int len = 0; 1240 1241 ncp = cp; 1242 while ((c = *cp) != '\0' && c != '/') { 1243 if (++len > NFS_MAXNAMLEN) { 1244 error = ENOENT; 1245 goto out; 1246 } 1247 cp++; 1248 } 1249 *cp = '\0'; 1250 } 1251 1252 /* lookup a file handle */ 1253 error = nfs_lookupfh(currfd, ncp, newfd); 1254 *cp = c; 1255 if (error) 1256 goto out; 1257 1258 /* 1259 * Check for symbolic link 1260 */ 1261 if (newfd->fa.fa_type == htonl(NFLNK)) { 1262 int link_len, len; 1263 1264 error = nfs_readlink(newfd, linkbuf); 1265 if (error) 1266 goto out; 1267 1268 link_len = strlen(linkbuf); 1269 len = strlen(cp); 1270 1271 if (link_len + len > MAXPATHLEN 1272 || ++nlinks > MAXSYMLINKS) { 1273 error = ENOENT; 1274 goto out; 1275 } 1276 1277 bcopy(cp, &namebuf[link_len], len + 1); 1278 bcopy(linkbuf, namebuf, link_len); 1279 1280 /* 1281 * If absolute pathname, restart at root. 1282 * If relative pathname, restart at parent directory. 1283 */ 1284 cp = namebuf; 1285 if (*cp == '/') 1286 bcopy(&nfs_root_node, currfd, sizeof(*currfd)); 1287 1288 free(newfd); 1289 newfd = NULL; 1290 1291 continue; 1292 } 1293 1294 free(currfd); 1295 currfd = newfd; 1296 newfd = NULL; 1297 } 1298 1299 error = 0; 1300 1301 out: 1302 free(newfd); 1303 free(path); 1304 #else 1305 currfd->iodesc = desc; 1306 1307 error = nfs_lookupfh(&nfs_root_node, upath, currfd); 1308 #endif 1309 if (!error) { 1310 currfd->off = 0; 1311 currfd->cookie = 0; 1312 f->f_fsdata = (void *)currfd; 1313 return (0); 1314 } 1315 1316 #ifdef NFS_DEBUG 1317 if (debug) 1318 printf("nfs_open: %s lookupfh failed: %s\n", 1319 path, strerror(error)); 1320 #endif 1321 free(currfd); 1322 1323 return (error); 1324 } 1325 1326 int 1327 nfs_close(struct open_file *f) 1328 { 1329 struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; 1330 1331 #ifdef NFS_DEBUG 1332 if (debug) 1333 printf("nfs_close: fp=0x%lx\n", (u_long)fp); 1334 #endif 1335 1336 if (fp) 1337 free(fp); 1338 f->f_fsdata = (void *)0; 1339 1340 return (0); 1341 } 1342 1343 /* 1344 * read a portion of a file 1345 */ 1346 int 1347 nfs_read(struct open_file *f, void *buf, size_t size, size_t *resid) 1348 { 1349 struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; 1350 ssize_t cc; 1351 char *addr = buf; 1352 1353 #ifdef NFS_DEBUG 1354 if (debug) 1355 printf("nfs_read: size=%lu off=%d\n", (u_long)size, 1356 (int)fp->off); 1357 #endif 1358 while ((int)size > 0) { 1359 twiddle(16); 1360 cc = nfs_readdata(fp, fp->off, (void *)addr, size); 1361 /* XXX maybe should retry on certain errors */ 1362 if (cc == -1) { 1363 #ifdef NFS_DEBUG 1364 if (debug) 1365 printf("nfs_read: read: %s", strerror(errno)); 1366 #endif 1367 return (errno); /* XXX - from nfs_readdata */ 1368 } 1369 if (cc == 0) { 1370 #ifdef NFS_DEBUG 1371 if (debug) 1372 printf("nfs_read: hit EOF unexpectantly"); 1373 #endif 1374 goto ret; 1375 } 1376 fp->off += cc; 1377 addr += cc; 1378 size -= cc; 1379 } 1380 ret: 1381 if (resid) 1382 *resid = size; 1383 1384 return (0); 1385 } 1386 1387 /* 1388 * Not implemented. 1389 */ 1390 int 1391 nfs_write(struct open_file *f, void *buf, size_t size, size_t *resid) 1392 { 1393 return (EROFS); 1394 } 1395 1396 off_t 1397 nfs_seek(struct open_file *f, off_t offset, int where) 1398 { 1399 struct nfs_iodesc *d = (struct nfs_iodesc *)f->f_fsdata; 1400 uint32_t size = ntohl(d->fa.fa_size.val[1]); 1401 1402 switch (where) { 1403 case SEEK_SET: 1404 d->off = offset; 1405 break; 1406 case SEEK_CUR: 1407 d->off += offset; 1408 break; 1409 case SEEK_END: 1410 d->off = size - offset; 1411 break; 1412 default: 1413 errno = EINVAL; 1414 return (-1); 1415 } 1416 1417 return (d->off); 1418 } 1419 1420 /* NFNON=0, NFREG=1, NFDIR=2, NFBLK=3, NFCHR=4, NFLNK=5, NFSOCK=6, NFFIFO=7 */ 1421 int nfs_stat_types[9] = { 1422 0, S_IFREG, S_IFDIR, S_IFBLK, S_IFCHR, S_IFLNK, S_IFSOCK, S_IFIFO, 0 }; 1423 1424 int 1425 nfs_stat(struct open_file *f, struct stat *sb) 1426 { 1427 struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; 1428 uint32_t ftype, mode; 1429 1430 ftype = ntohl(fp->fa.fa_type); 1431 mode = ntohl(fp->fa.fa_mode); 1432 mode |= nfs_stat_types[ftype & 7]; 1433 1434 sb->st_mode = mode; 1435 sb->st_nlink = ntohl(fp->fa.fa_nlink); 1436 sb->st_uid = ntohl(fp->fa.fa_uid); 1437 sb->st_gid = ntohl(fp->fa.fa_gid); 1438 sb->st_size = ntohl(fp->fa.fa_size.val[1]); 1439 1440 return (0); 1441 } 1442 1443 static int 1444 nfs_readdir(struct open_file *f, struct dirent *d) 1445 { 1446 struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; 1447 struct nfsv3_readdir_repl *repl; 1448 struct nfsv3_readdir_entry *rent; 1449 static char *buf; 1450 static struct nfs_iodesc *pfp = NULL; 1451 static uint64_t cookie = 0; 1452 size_t cc; 1453 int pos; 1454 1455 struct args { 1456 uint32_t fhsize; 1457 uint32_t fhpluscookie[5 + NFS_V3MAXFHSIZE]; 1458 } *args; 1459 struct { 1460 uint32_t h[RPC_HEADER_WORDS]; 1461 struct args d; 1462 } sdata; 1463 static struct { 1464 uint32_t h[RPC_HEADER_WORDS]; 1465 u_char d[NFS_READDIRSIZE]; 1466 } rdata; 1467 1468 if (fp != pfp || fp->off != cookie) { 1469 pfp = NULL; 1470 refill: 1471 args = &sdata.d; 1472 bzero(args, sizeof(*args)); 1473 1474 args->fhsize = htonl(fp->fhsize); 1475 bcopy(fp->fh, args->fhpluscookie, fp->fhsize); 1476 pos = roundup(fp->fhsize, sizeof(uint32_t)) / sizeof(uint32_t); 1477 args->fhpluscookie[pos++] = htonl(fp->off >> 32); 1478 args->fhpluscookie[pos++] = htonl(fp->off); 1479 args->fhpluscookie[pos++] = htonl(fp->cookie >> 32); 1480 args->fhpluscookie[pos++] = htonl(fp->cookie); 1481 args->fhpluscookie[pos] = htonl(NFS_READDIRSIZE); 1482 1483 cc = rpc_call(fp->iodesc, NFS_PROG, NFS_VER3, NFSPROCV3_READDIR, 1484 args, 6 * sizeof(uint32_t) + 1485 roundup(fp->fhsize, sizeof(uint32_t)), 1486 rdata.d, sizeof(rdata.d)); 1487 buf = rdata.d; 1488 repl = (struct nfsv3_readdir_repl *)buf; 1489 if (repl->errno != 0) 1490 return (ntohl(repl->errno)); 1491 pfp = fp; 1492 cookie = fp->off; 1493 fp->cookie = ((uint64_t)ntohl(repl->cookiev0) << 32) | 1494 ntohl(repl->cookiev1); 1495 buf += sizeof (struct nfsv3_readdir_repl); 1496 } 1497 rent = (struct nfsv3_readdir_entry *)buf; 1498 1499 if (rent->follows == 0) { 1500 /* fid0 is actually eof */ 1501 if (rent->fid0 != 0) { 1502 cookie = 0; 1503 return (ENOENT); 1504 } 1505 goto refill; 1506 } 1507 1508 d->d_namlen = ntohl(rent->len); 1509 bcopy(rent->nameplus, d->d_name, d->d_namlen); 1510 d->d_name[d->d_namlen] = '\0'; 1511 1512 pos = roundup(d->d_namlen, sizeof(uint32_t)) / sizeof(uint32_t); 1513 fp->off = cookie = ((uint64_t)ntohl(rent->nameplus[pos]) << 32) | 1514 ntohl(rent->nameplus[pos + 1]); 1515 pos += 2; 1516 buf = (u_char *)&rent->nameplus[pos]; 1517 return (0); 1518 } 1519 #endif /* OLD_NFSV2 */ 1520