nfs.c revision 65496
138774Snsouch/* $FreeBSD: head/lib/libstand/nfs.c 65496 2000-09-05 22:11:41Z msmith $ */ 293023Snsouch/* $NetBSD: nfs.c,v 1.2 1998/01/24 12:43:09 drochner Exp $ */ 338774Snsouch 438774Snsouch/*- 538774Snsouch * Copyright (c) 1993 John Brezak 638774Snsouch * All rights reserved. 738774Snsouch * 838774Snsouch * Redistribution and use in source and binary forms, with or without 938774Snsouch * modification, are permitted provided that the following conditions 1038774Snsouch * are met: 1138774Snsouch * 1. Redistributions of source code must retain the above copyright 1238774Snsouch * notice, this list of conditions and the following disclaimer. 1338774Snsouch * 2. Redistributions in binary form must reproduce the above copyright 1438774Snsouch * notice, this list of conditions and the following disclaimer in the 1538774Snsouch * documentation and/or other materials provided with the distribution. 1638774Snsouch * 3. The name of the author may not be used to endorse or promote products 1738774Snsouch * derived from this software without specific prior written permission. 1838774Snsouch * 1938774Snsouch * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR 2038774Snsouch * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 2138774Snsouch * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 2238774Snsouch * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 2338774Snsouch * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 2438774Snsouch * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 2538774Snsouch * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2638774Snsouch * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 27119418Sobrien * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 28119418Sobrien * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29119418Sobrien * POSSIBILITY OF SUCH DAMAGE. 3038774Snsouch */ 3138774Snsouch 3238774Snsouch#include <sys/param.h> 3338774Snsouch#include <sys/time.h> 3438774Snsouch#include <sys/socket.h> 3538774Snsouch#include <sys/stat.h> 3638774Snsouch#include <string.h> 37181304Sjhb 38167856Simp#include <netinet/in.h> 3938774Snsouch#include <netinet/in_systm.h> 40181304Sjhb 4138774Snsouch#include "rpcv2.h" 4238774Snsouch#include "nfsv2.h" 4338774Snsouch 4438774Snsouch#include "stand.h" 4538774Snsouch#include "net.h" 4638774Snsouch#include "netif.h" 4738774Snsouch#include "rpc.h" 48129152Sjoerg 49129152Sjoerg#define NFS_DEBUGxx 50129152Sjoerg 5140782Snsouch/* Define our own NFS attributes without NQNFS stuff. */ 5240782Snsouchstruct nfsv2_fattrs { 5340782Snsouch n_long fa_type; 54160372Simp n_long fa_mode; 5542442Snsouch n_long fa_nlink; 56186833Snwhitehorn n_long fa_uid; 57186833Snwhitehorn n_long fa_gid; 58187457Snwhitehorn n_long fa_size; 5940782Snsouch n_long fa_blocksize; 6040782Snsouch n_long fa_rdev; 61129152Sjoerg n_long fa_blocks; 6240782Snsouch n_long fa_fsid; 6340782Snsouch n_long fa_fileid; 6440782Snsouch struct nfsv2_time fa_atime; 6540782Snsouch struct nfsv2_time fa_mtime; 6640782Snsouch struct nfsv2_time fa_ctime; 6740782Snsouch}; 6840782Snsouch 6940782Snsouch 7040782Snsouchstruct nfs_read_args { 7140782Snsouch u_char fh[NFS_FHSIZE]; 7240782Snsouch n_long off; 7340782Snsouch n_long len; 7440782Snsouch n_long xxx; /* XXX what's this for? */ 7540782Snsouch}; 7640782Snsouch 7740782Snsouch/* Data part of nfs rpc reply (also the largest thing we receive) */ 7840782Snsouch#define NFSREAD_SIZE 1024 7940782Snsouchstruct nfs_read_repl { 8040782Snsouch n_long errno; 8140782Snsouch struct nfsv2_fattrs fa; 8242442Snsouch n_long count; 8340782Snsouch u_char data[NFSREAD_SIZE]; 8438774Snsouch}; 8540782Snsouch 8640782Snsouch#ifndef NFS_NOSYMLINK 8738774Snsouchstruct nfs_readlnk_repl { 8838774Snsouch n_long errno; 8940782Snsouch n_long len; 9038774Snsouch char path[NFS_MAXPATHLEN]; 91129152Sjoerg}; 92129152Sjoerg#endif 93129152Sjoerg 94167856Simpstruct nfs_readdir_args { 95129152Sjoerg u_char fh[NFS_FHSIZE]; 96167856Simp n_long cookie; 97181304Sjhb n_long count; 9840782Snsouch}; 9938774Snsouch 10042442Snsouchstruct nfs_readdir_data { 10142442Snsouch n_long fileid; 10242442Snsouch n_long len; 10342442Snsouch char name[0]; 10442442Snsouch}; 105129152Sjoerg 10640782Snsouchstruct nfs_readdir_off { 10738774Snsouch n_long cookie; 10840782Snsouch n_long follows; 109129152Sjoerg}; 11040782Snsouch 11140782Snsouchstruct nfs_iodesc { 11240782Snsouch struct iodesc *iodesc; 11340782Snsouch off_t off; 11440782Snsouch u_char fh[NFS_FHSIZE]; 11542442Snsouch struct nfsv2_fattrs fa; /* all in network order */ 116181304Sjhb}; 117167856Simp 11838774Snsouch/* 11938774Snsouch * XXX interactions with tftp? See nfswrapper.c for a confusing 12038774Snsouch * issue. 12193023Snsouch */ 12293023Snsouchint nfs_open(const char *path, struct open_file *f); 12393023Snsouchstatic int nfs_close(struct open_file *f); 12493023Snsouchstatic int nfs_read(struct open_file *f, void *buf, size_t size, size_t *resid); 125181304Sjhbstatic int nfs_write(struct open_file *f, void *buf, size_t size, size_t *resid); 126160372Simpstatic off_t nfs_seek(struct open_file *f, off_t offset, int where); 12793023Snsouchstatic int nfs_stat(struct open_file *f, struct stat *sb); 12893023Snsouchstatic int nfs_readdir(struct open_file *f, struct dirent *d); 129181304Sjhb 13093023Snsouchstruct nfs_iodesc nfs_root_node; 13193023Snsouch 13293023Snsouchstruct fs_ops nfs_fsops = { 13393023Snsouch "nfs", 134167856Simp nfs_open, 13593023Snsouch nfs_close, 136167856Simp nfs_read, 137167856Simp nfs_write, 138160372Simp nfs_seek, 139167856Simp nfs_stat, 140167856Simp nfs_readdir 141167856Simp}; 142167856Simp 143167856Simp/* 144167856Simp * Fetch the root file handle (call mount daemon) 145167856Simp * Return zero or error number. 146167856Simp */ 147167856Simpint 148167856Simpnfs_getrootfh(d, path, fhp) 149167856Simp register struct iodesc *d; 150167856Simp char *path; 151167856Simp u_char *fhp; 152167856Simp{ 153167856Simp register int len; 154167856Simp struct args { 155167856Simp n_long len; 156167856Simp char path[FNAME_SIZE]; 157167856Simp } *args; 158167856Simp struct repl { 159167856Simp n_long errno; 160167856Simp u_char fh[NFS_FHSIZE]; 161167856Simp } *repl; 162167856Simp struct { 163167856Simp n_long h[RPC_HEADER_WORDS]; 16493023Snsouch struct args d; 16593023Snsouch } sdata; 16693023Snsouch struct { 167167856Simp n_long h[RPC_HEADER_WORDS]; 168167856Simp struct repl d; 169167856Simp } rdata; 170167856Simp size_t cc; 171167856Simp 172167856Simp#ifdef NFS_DEBUG 173167856Simp if (debug) 174167856Simp printf("nfs_getrootfh: %s\n", path); 175167856Simp#endif 176188461Simp 177167856Simp args = &sdata.d; 178167856Simp repl = &rdata.d; 179167856Simp 180167856Simp bzero(args, sizeof(*args)); 181167856Simp len = strlen(path); 182167856Simp if (len > sizeof(args->path)) 183167856Simp len = sizeof(args->path); 184167856Simp args->len = htonl(len); 185167856Simp bcopy(path, args->path, len); 186167856Simp len = 4 + roundup(len, 4); 187167856Simp 188167856Simp cc = rpc_call(d, RPCPROG_MNT, RPCMNT_VER1, RPCMNT_MOUNT, 189167856Simp args, len, repl, sizeof(*repl)); 190167856Simp if (cc == -1) { 191167856Simp /* errno was set by rpc_call */ 192167856Simp return (errno); 193167856Simp } 194167856Simp if (cc < 4) 195167856Simp return (EBADRPC); 196167856Simp if (repl->errno) 197167856Simp return (ntohl(repl->errno)); 198167856Simp bcopy(repl->fh, fhp, sizeof(repl->fh)); 199167856Simp return (0); 200167856Simp} 201167856Simp 202167856Simp/* 203167856Simp * Lookup a file. Store handle and attributes. 204167856Simp * Return zero or error number. 205167856Simp */ 206167856Simpint 207167856Simpnfs_lookupfh(d, name, newfd) 208167856Simp struct nfs_iodesc *d; 209167856Simp const char *name; 210167856Simp struct nfs_iodesc *newfd; 211167856Simp{ 212167856Simp register int len, rlen; 213167856Simp struct args { 214167856Simp u_char fh[NFS_FHSIZE]; 215167856Simp n_long len; 216167856Simp char name[FNAME_SIZE]; 217167856Simp } *args; 218167856Simp struct repl { 21938774Snsouch n_long errno; 22038774Snsouch u_char fh[NFS_FHSIZE]; 22138774Snsouch struct nfsv2_fattrs fa; 222160372Simp } *repl; 22338774Snsouch struct { 22438774Snsouch n_long h[RPC_HEADER_WORDS]; 22538774Snsouch struct args d; 22640782Snsouch } sdata; 22740782Snsouch struct { 22840782Snsouch n_long h[RPC_HEADER_WORDS]; 229160372Simp struct repl d; 23040782Snsouch } rdata; 23140782Snsouch ssize_t cc; 23240782Snsouch 23340782Snsouch#ifdef NFS_DEBUG 23440782Snsouch if (debug) 23540782Snsouch printf("lookupfh: called\n"); 236160372Simp#endif 23740782Snsouch 23840782Snsouch args = &sdata.d; 23940782Snsouch repl = &rdata.d; 240167856Simp 241167856Simp bzero(args, sizeof(*args)); 242167856Simp bcopy(d->fh, args->fh, sizeof(args->fh)); 243167856Simp len = strlen(name); 244167856Simp if (len > sizeof(args->name)) 245167856Simp len = sizeof(args->name); 246167856Simp bcopy(name, args->name, len); 247167856Simp args->len = htonl(len); 248167856Simp len = 4 + roundup(len, 4); 249167856Simp len += NFS_FHSIZE; 250167856Simp 251167856Simp rlen = sizeof(*repl); 252167856Simp 253167856Simp cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER2, NFSPROC_LOOKUP, 254167856Simp args, len, repl, rlen); 255167856Simp if (cc == -1) 256167856Simp return (errno); /* XXX - from rpc_call */ 257167856Simp if (cc < 4) 258167856Simp return (EIO); 259167856Simp if (repl->errno) { 260167856Simp /* saerrno.h now matches NFS error numbers. */ 261167856Simp return (ntohl(repl->errno)); 262167856Simp } 263167856Simp bcopy( repl->fh, &newfd->fh, sizeof(newfd->fh)); 264167856Simp bcopy(&repl->fa, &newfd->fa, sizeof(newfd->fa)); 265167856Simp return (0); 266167856Simp} 267167856Simp 268167856Simp#ifndef NFS_NOSYMLINK 269167856Simp/* 27093023Snsouch * Get the destination of a symbolic link. 271187261Snwhitehorn */ 272187261Snwhitehornint 273nfs_readlink(d, buf) 274 struct nfs_iodesc *d; 275 char *buf; 276{ 277 struct { 278 n_long h[RPC_HEADER_WORDS]; 279 u_char fh[NFS_FHSIZE]; 280 } sdata; 281 struct { 282 n_long h[RPC_HEADER_WORDS]; 283 struct nfs_readlnk_repl d; 284 } rdata; 285 ssize_t cc; 286 287#ifdef NFS_DEBUG 288 if (debug) 289 printf("readlink: called\n"); 290#endif 291 292 bcopy(d->fh, sdata.fh, NFS_FHSIZE); 293 cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER2, NFSPROC_READLINK, 294 sdata.fh, NFS_FHSIZE, 295 &rdata.d, sizeof(rdata.d)); 296 if (cc == -1) 297 return (errno); 298 299 if (cc < 4) 300 return (EIO); 301 302 if (rdata.d.errno) 303 return (ntohl(rdata.d.errno)); 304 305 rdata.d.len = ntohl(rdata.d.len); 306 if (rdata.d.len > NFS_MAXPATHLEN) 307 return (ENAMETOOLONG); 308 309 bcopy(rdata.d.path, buf, rdata.d.len); 310 buf[rdata.d.len] = 0; 311 return (0); 312} 313#endif 314 315/* 316 * Read data from a file. 317 * Return transfer count or -1 (and set errno) 318 */ 319ssize_t 320nfs_readdata(d, off, addr, len) 321 struct nfs_iodesc *d; 322 off_t off; 323 void *addr; 324 size_t len; 325{ 326 struct nfs_read_args *args; 327 struct nfs_read_repl *repl; 328 struct { 329 n_long h[RPC_HEADER_WORDS]; 330 struct nfs_read_args d; 331 } sdata; 332 struct { 333 n_long h[RPC_HEADER_WORDS]; 334 struct nfs_read_repl d; 335 } rdata; 336 size_t cc; 337 long x; 338 int hlen, rlen; 339 340 args = &sdata.d; 341 repl = &rdata.d; 342 343 bcopy(d->fh, args->fh, NFS_FHSIZE); 344 args->off = htonl((n_long)off); 345 if (len > NFSREAD_SIZE) 346 len = NFSREAD_SIZE; 347 args->len = htonl((n_long)len); 348 args->xxx = htonl((n_long)0); 349 hlen = sizeof(*repl) - NFSREAD_SIZE; 350 351 cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER2, NFSPROC_READ, 352 args, sizeof(*args), 353 repl, sizeof(*repl)); 354 if (cc == -1) { 355 /* errno was already set by rpc_call */ 356 return (-1); 357 } 358 if (cc < hlen) { 359 errno = EBADRPC; 360 return (-1); 361 } 362 if (repl->errno) { 363 errno = ntohl(repl->errno); 364 return (-1); 365 } 366 rlen = cc - hlen; 367 x = ntohl(repl->count); 368 if (rlen < x) { 369 printf("nfsread: short packet, %d < %ld\n", rlen, x); 370 errno = EBADRPC; 371 return(-1); 372 } 373 bcopy(repl->data, addr, x); 374 return (x); 375} 376 377/* 378 * Open a file. 379 * return zero or error number 380 */ 381int 382nfs_open(upath, f) 383 const char *upath; 384 struct open_file *f; 385{ 386 struct iodesc *desc; 387 struct nfs_iodesc *currfd; 388#ifndef NFS_NOSYMLINK 389 struct nfs_iodesc *newfd; 390 struct nfsv2_fattrs *fa; 391 register char *cp, *ncp; 392 register int c; 393 char namebuf[NFS_MAXPATHLEN + 1]; 394 char linkbuf[NFS_MAXPATHLEN + 1]; 395 int nlinks = 0; 396#endif 397 int error; 398 char *path; 399 400#ifdef NFS_DEBUG 401 if (debug) 402 printf("nfs_open: %s (rootpath=%s)\n", path, rootpath); 403#endif 404 if (!rootpath[0]) { 405 printf("no rootpath, no nfs\n"); 406 return (ENXIO); 407 } 408 409 if (!(desc = socktodesc(*(int *)(f->f_devdata)))) 410 return(EINVAL); 411 412 /* Bind to a reserved port. */ 413 desc->myport = htons(--rpc_port); 414 desc->destip = rootip; 415 if ((error = nfs_getrootfh(desc, rootpath, nfs_root_node.fh))) 416 return (error); 417 nfs_root_node.iodesc = desc; 418 419#ifndef NFS_NOSYMLINK 420 /* Fake up attributes for the root dir. */ 421 fa = &nfs_root_node.fa; 422 fa->fa_type = htonl(NFDIR); 423 fa->fa_mode = htonl(0755); 424 fa->fa_nlink = htonl(2); 425 426 currfd = &nfs_root_node; 427 newfd = 0; 428 429 cp = path = strdup(upath); 430 if (path == NULL) { 431 error = ENOMEM; 432 goto out; 433 } 434 while (*cp) { 435 /* 436 * Remove extra separators 437 */ 438 while (*cp == '/') 439 cp++; 440 441 if (*cp == '\0') 442 break; 443 /* 444 * Check that current node is a directory. 445 */ 446 if (currfd->fa.fa_type != htonl(NFDIR)) { 447 error = ENOTDIR; 448 goto out; 449 } 450 451 /* allocate file system specific data structure */ 452 newfd = malloc(sizeof(*newfd)); 453 newfd->iodesc = currfd->iodesc; 454 newfd->off = 0; 455 456 /* 457 * Get next component of path name. 458 */ 459 { 460 register int len = 0; 461 462 ncp = cp; 463 while ((c = *cp) != '\0' && c != '/') { 464 if (++len > NFS_MAXNAMLEN) { 465 error = ENOENT; 466 goto out; 467 } 468 cp++; 469 } 470 *cp = '\0'; 471 } 472 473 /* lookup a file handle */ 474 error = nfs_lookupfh(currfd, ncp, newfd); 475 *cp = c; 476 if (error) 477 goto out; 478 479 /* 480 * Check for symbolic link 481 */ 482 if (newfd->fa.fa_type == htonl(NFLNK)) { 483 int link_len, len; 484 485 error = nfs_readlink(newfd, linkbuf); 486 if (error) 487 goto out; 488 489 link_len = strlen(linkbuf); 490 len = strlen(cp); 491 492 if (link_len + len > MAXPATHLEN 493 || ++nlinks > MAXSYMLINKS) { 494 error = ENOENT; 495 goto out; 496 } 497 498 bcopy(cp, &namebuf[link_len], len + 1); 499 bcopy(linkbuf, namebuf, link_len); 500 501 /* 502 * If absolute pathname, restart at root. 503 * If relative pathname, restart at parent directory. 504 */ 505 cp = namebuf; 506 if (*cp == '/') { 507 if (currfd != &nfs_root_node) 508 free(currfd); 509 currfd = &nfs_root_node; 510 } 511 512 free(newfd); 513 newfd = 0; 514 515 continue; 516 } 517 518 if (currfd != &nfs_root_node) 519 free(currfd); 520 currfd = newfd; 521 newfd = 0; 522 } 523 524 error = 0; 525 526out: 527 if (newfd) 528 free(newfd); 529 if (path) 530 free(path); 531#else 532 /* allocate file system specific data structure */ 533 currfd = malloc(sizeof(*currfd)); 534 currfd->iodesc = desc; 535 currfd->off = 0; 536 537 error = nfs_lookupfh(&nfs_root_node, upath, currfd); 538#endif 539 if (!error) { 540 f->f_fsdata = (void *)currfd; 541 return (0); 542 } 543 544#ifdef NFS_DEBUG 545 if (debug) 546 printf("nfs_open: %s lookupfh failed: %s\n", 547 path, strerror(error)); 548#endif 549#ifndef NFS_NOSYMLINK 550 if (currfd != &nfs_root_node) 551#endif 552 free(currfd); 553 554 return (error); 555} 556 557int 558nfs_close(f) 559 struct open_file *f; 560{ 561 register struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; 562 563#ifdef NFS_DEBUG 564 if (debug) 565 printf("nfs_close: fp=0x%lx\n", (u_long)fp); 566#endif 567 568 if (fp != &nfs_root_node && fp) 569 free(fp); 570 f->f_fsdata = (void *)0; 571 572 return (0); 573} 574 575/* 576 * read a portion of a file 577 */ 578int 579nfs_read(f, buf, size, resid) 580 struct open_file *f; 581 void *buf; 582 size_t size; 583 size_t *resid; /* out */ 584{ 585 register struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; 586 register ssize_t cc; 587 register char *addr = buf; 588 589#ifdef NFS_DEBUG 590 if (debug) 591 printf("nfs_read: size=%lu off=%d\n", (u_long)size, 592 (int)fp->off); 593#endif 594 while ((int)size > 0) { 595 twiddle(); 596 cc = nfs_readdata(fp, fp->off, (void *)addr, size); 597 /* XXX maybe should retry on certain errors */ 598 if (cc == -1) { 599#ifdef NFS_DEBUG 600 if (debug) 601 printf("nfs_read: read: %s", strerror(errno)); 602#endif 603 return (errno); /* XXX - from nfs_readdata */ 604 } 605 if (cc == 0) { 606#ifdef NFS_DEBUG 607 if (debug) 608 printf("nfs_read: hit EOF unexpectantly"); 609#endif 610 goto ret; 611 } 612 fp->off += cc; 613 addr += cc; 614 size -= cc; 615 } 616ret: 617 if (resid) 618 *resid = size; 619 620 return (0); 621} 622 623/* 624 * Not implemented. 625 */ 626int 627nfs_write(f, buf, size, resid) 628 struct open_file *f; 629 void *buf; 630 size_t size; 631 size_t *resid; /* out */ 632{ 633 return (EROFS); 634} 635 636off_t 637nfs_seek(f, offset, where) 638 struct open_file *f; 639 off_t offset; 640 int where; 641{ 642 register struct nfs_iodesc *d = (struct nfs_iodesc *)f->f_fsdata; 643 n_long size = ntohl(d->fa.fa_size); 644 645 switch (where) { 646 case SEEK_SET: 647 d->off = offset; 648 break; 649 case SEEK_CUR: 650 d->off += offset; 651 break; 652 case SEEK_END: 653 d->off = size - offset; 654 break; 655 default: 656 return (-1); 657 } 658 659 return (d->off); 660} 661 662/* NFNON=0, NFREG=1, NFDIR=2, NFBLK=3, NFCHR=4, NFLNK=5 */ 663int nfs_stat_types[8] = { 664 0, S_IFREG, S_IFDIR, S_IFBLK, S_IFCHR, S_IFLNK, 0 }; 665 666int 667nfs_stat(f, sb) 668 struct open_file *f; 669 struct stat *sb; 670{ 671 struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; 672 register n_long ftype, mode; 673 674 ftype = ntohl(fp->fa.fa_type); 675 mode = ntohl(fp->fa.fa_mode); 676 mode |= nfs_stat_types[ftype & 7]; 677 678 sb->st_mode = mode; 679 sb->st_nlink = ntohl(fp->fa.fa_nlink); 680 sb->st_uid = ntohl(fp->fa.fa_uid); 681 sb->st_gid = ntohl(fp->fa.fa_gid); 682 sb->st_size = ntohl(fp->fa.fa_size); 683 684 return (0); 685} 686 687static int 688nfs_readdir(struct open_file *f, struct dirent *d) 689{ 690 register struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; 691 struct nfs_readdir_args *args; 692 struct nfs_readdir_data *rd; 693 struct nfs_readdir_off *roff = NULL; 694 static char *buf; 695 static n_long cookie = 0; 696 size_t cc; 697 n_long eof; 698 699 struct { 700 n_long h[RPC_HEADER_WORDS]; 701 struct nfs_readdir_args d; 702 } sdata; 703 static struct { 704 n_long h[RPC_HEADER_WORDS]; 705 u_char d[NFS_READDIRSIZE]; 706 } rdata; 707 708 if (cookie == 0) { 709 refill: 710 args = &sdata.d; 711 bzero(args, sizeof(*args)); 712 713 bcopy(fp->fh, args->fh, NFS_FHSIZE); 714 args->cookie = htonl(cookie); 715 args->count = htonl(NFS_READDIRSIZE); 716 717 cc = rpc_call(fp->iodesc, NFS_PROG, NFS_VER2, NFSPROC_READDIR, 718 args, sizeof(*args), 719 rdata.d, sizeof(rdata.d)); 720 buf = rdata.d; 721 roff = (struct nfs_readdir_off *)buf; 722 if (ntohl(roff->cookie) != 0) 723 return 1; 724 } 725 roff = (struct nfs_readdir_off *)buf; 726 727 if (ntohl(roff->follows) == 0) { 728 eof = ntohl((roff+1)->cookie); 729 if (eof) { 730 cookie = 0; 731 return 1; 732 } 733 goto refill; 734 } 735 736 buf += sizeof(struct nfs_readdir_off); 737 rd = (struct nfs_readdir_data *)buf; 738 d->d_namlen = ntohl(rd->len); 739 bcopy(rd->name, d->d_name, d->d_namlen); 740 d->d_name[d->d_namlen] = '\0'; 741 742 buf += (sizeof(struct nfs_readdir_data) + roundup(htonl(rd->len),4)); 743 roff = (struct nfs_readdir_off *)buf; 744 cookie = ntohl(roff->cookie); 745 return 0; 746} 747