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