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: stable/9/lib/libstand/nfs.c 252701 2013-07-04 15:21:27Z mav $");
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 if (newfd)
610 free(newfd);
611 if (path)
612 free(path);
613 #else
614 currfd->iodesc = desc;
615
616 error = nfs_lookupfh(&nfs_root_node, upath, currfd);
617 #endif
618 if (!error) {
619 currfd->off = 0;
620 f->f_fsdata = (void *)currfd;
621 return (0);
622 }
623
624 #ifdef NFS_DEBUG
625 if (debug)
626 printf("nfs_open: %s lookupfh failed: %s\n",
627 path, strerror(error));
628 #endif
629 free(currfd);
630
631 return (error);
632 }
633
634 int
nfs_close(struct open_file * f)635 nfs_close(struct open_file *f)
636 {
637 struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
638
639 #ifdef NFS_DEBUG
640 if (debug)
641 printf("nfs_close: fp=0x%lx\n", (u_long)fp);
642 #endif
643
644 if (fp)
645 free(fp);
646 f->f_fsdata = (void *)0;
647
648 return (0);
649 }
650
651 /*
652 * read a portion of a file
653 */
654 int
nfs_read(struct open_file * f,void * buf,size_t size,size_t * resid)655 nfs_read(struct open_file *f, void *buf, size_t size, size_t *resid)
656 {
657 struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
658 ssize_t cc;
659 char *addr = buf;
660
661 #ifdef NFS_DEBUG
662 if (debug)
663 printf("nfs_read: size=%lu off=%d\n", (u_long)size,
664 (int)fp->off);
665 #endif
666 while ((int)size > 0) {
667 twiddle();
668 cc = nfs_readdata(fp, fp->off, (void *)addr, size);
669 /* XXX maybe should retry on certain errors */
670 if (cc == -1) {
671 #ifdef NFS_DEBUG
672 if (debug)
673 printf("nfs_read: read: %s", strerror(errno));
674 #endif
675 return (errno); /* XXX - from nfs_readdata */
676 }
677 if (cc == 0) {
678 #ifdef NFS_DEBUG
679 if (debug)
680 printf("nfs_read: hit EOF unexpectantly");
681 #endif
682 goto ret;
683 }
684 fp->off += cc;
685 addr += cc;
686 size -= cc;
687 }
688 ret:
689 if (resid)
690 *resid = size;
691
692 return (0);
693 }
694
695 /*
696 * Not implemented.
697 */
698 int
nfs_write(struct open_file * f,void * buf,size_t size,size_t * resid)699 nfs_write(struct open_file *f, void *buf, size_t size, size_t *resid)
700 {
701 return (EROFS);
702 }
703
704 off_t
nfs_seek(struct open_file * f,off_t offset,int where)705 nfs_seek(struct open_file *f, off_t offset, int where)
706 {
707 struct nfs_iodesc *d = (struct nfs_iodesc *)f->f_fsdata;
708 n_long size = ntohl(d->fa.fa_size);
709
710 switch (where) {
711 case SEEK_SET:
712 d->off = offset;
713 break;
714 case SEEK_CUR:
715 d->off += offset;
716 break;
717 case SEEK_END:
718 d->off = size - offset;
719 break;
720 default:
721 errno = EINVAL;
722 return (-1);
723 }
724
725 return (d->off);
726 }
727
728 /* NFNON=0, NFREG=1, NFDIR=2, NFBLK=3, NFCHR=4, NFLNK=5 */
729 int nfs_stat_types[8] = {
730 0, S_IFREG, S_IFDIR, S_IFBLK, S_IFCHR, S_IFLNK, 0 };
731
732 int
nfs_stat(struct open_file * f,struct stat * sb)733 nfs_stat(struct open_file *f, struct stat *sb)
734 {
735 struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
736 n_long ftype, mode;
737
738 ftype = ntohl(fp->fa.fa_type);
739 mode = ntohl(fp->fa.fa_mode);
740 mode |= nfs_stat_types[ftype & 7];
741
742 sb->st_mode = mode;
743 sb->st_nlink = ntohl(fp->fa.fa_nlink);
744 sb->st_uid = ntohl(fp->fa.fa_uid);
745 sb->st_gid = ntohl(fp->fa.fa_gid);
746 sb->st_size = ntohl(fp->fa.fa_size);
747
748 return (0);
749 }
750
751 static int
nfs_readdir(struct open_file * f,struct dirent * d)752 nfs_readdir(struct open_file *f, struct dirent *d)
753 {
754 struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
755 struct nfs_readdir_args *args;
756 struct nfs_readdir_data *rd;
757 struct nfs_readdir_off *roff = NULL;
758 static char *buf;
759 static struct nfs_iodesc *pfp = NULL;
760 static n_long cookie = 0;
761 size_t cc;
762 n_long eof;
763
764 struct {
765 n_long h[RPC_HEADER_WORDS];
766 struct nfs_readdir_args d;
767 } sdata;
768 static struct {
769 n_long h[RPC_HEADER_WORDS];
770 u_char d[NFS_READDIRSIZE];
771 } rdata;
772
773 if (fp != pfp || fp->off != cookie) {
774 pfp = NULL;
775 refill:
776 args = &sdata.d;
777 bzero(args, sizeof(*args));
778
779 bcopy(fp->fh, args->fh, NFS_FHSIZE);
780 args->cookie = htonl(fp->off);
781 args->count = htonl(NFS_READDIRSIZE);
782
783 cc = rpc_call(fp->iodesc, NFS_PROG, NFS_VER2, NFSPROC_READDIR,
784 args, sizeof(*args),
785 rdata.d, sizeof(rdata.d));
786 buf = rdata.d;
787 roff = (struct nfs_readdir_off *)buf;
788 if (ntohl(roff->cookie) != 0)
789 return EIO;
790 pfp = fp;
791 cookie = fp->off;
792 }
793 roff = (struct nfs_readdir_off *)buf;
794
795 if (ntohl(roff->follows) == 0) {
796 eof = ntohl((roff+1)->cookie);
797 if (eof) {
798 cookie = 0;
799 return ENOENT;
800 }
801 goto refill;
802 }
803
804 buf += sizeof(struct nfs_readdir_off);
805 rd = (struct nfs_readdir_data *)buf;
806 d->d_namlen = ntohl(rd->len);
807 bcopy(rd->name, d->d_name, d->d_namlen);
808 d->d_name[d->d_namlen] = '\0';
809
810 buf += (sizeof(struct nfs_readdir_data) + roundup(htonl(rd->len),4));
811 roff = (struct nfs_readdir_off *)buf;
812 fp->off = cookie = ntohl(roff->cookie);
813 return 0;
814 }
815 #else /* !OLD_NFSV2 */
816 /*
817 * Fetch the root file handle (call mount daemon)
818 * Return zero or error number.
819 */
820 int
nfs_getrootfh(struct iodesc * d,char * path,uint32_t * fhlenp,u_char * fhp)821 nfs_getrootfh(struct iodesc *d, char *path, uint32_t *fhlenp, u_char *fhp)
822 {
823 int len;
824 struct args {
825 uint32_t len;
826 char path[FNAME_SIZE];
827 } *args;
828 struct repl {
829 uint32_t errno;
830 uint32_t fhsize;
831 u_char fh[NFS_V3MAXFHSIZE];
832 uint32_t authcnt;
833 uint32_t auth[7];
834 } *repl;
835 struct {
836 uint32_t h[RPC_HEADER_WORDS];
837 struct args d;
838 } sdata;
839 struct {
840 uint32_t h[RPC_HEADER_WORDS];
841 struct repl d;
842 } rdata;
843 size_t cc;
844
845 #ifdef NFS_DEBUG
846 if (debug)
847 printf("nfs_getrootfh: %s\n", path);
848 #endif
849
850 args = &sdata.d;
851 repl = &rdata.d;
852
853 bzero(args, sizeof(*args));
854 len = strlen(path);
855 if (len > sizeof(args->path))
856 len = sizeof(args->path);
857 args->len = htonl(len);
858 bcopy(path, args->path, len);
859 len = sizeof(uint32_t) + roundup(len, sizeof(uint32_t));
860
861 cc = rpc_call(d, RPCPROG_MNT, RPCMNT_VER3, RPCMNT_MOUNT,
862 args, len, repl, sizeof(*repl));
863 if (cc == -1)
864 /* errno was set by rpc_call */
865 return (errno);
866 if (cc < 2 * sizeof (uint32_t))
867 return (EBADRPC);
868 if (repl->errno != 0)
869 return (ntohl(repl->errno));
870 *fhlenp = ntohl(repl->fhsize);
871 bcopy(repl->fh, fhp, *fhlenp);
872 return (0);
873 }
874
875 /*
876 * Lookup a file. Store handle and attributes.
877 * Return zero or error number.
878 */
879 int
nfs_lookupfh(struct nfs_iodesc * d,const char * name,struct nfs_iodesc * newfd)880 nfs_lookupfh(struct nfs_iodesc *d, const char *name, struct nfs_iodesc *newfd)
881 {
882 int len, rlen, pos;
883 struct args {
884 uint32_t fhsize;
885 uint32_t fhplusname[1 +
886 (NFS_V3MAXFHSIZE + FNAME_SIZE) / sizeof(uint32_t)];
887 } *args;
888 struct repl {
889 uint32_t errno;
890 uint32_t fhsize;
891 uint32_t fhplusattr[(NFS_V3MAXFHSIZE +
892 2 * (sizeof(uint32_t) +
893 sizeof(struct nfsv3_fattrs))) / sizeof(uint32_t)];
894 } *repl;
895 struct {
896 uint32_t h[RPC_HEADER_WORDS];
897 struct args d;
898 } sdata;
899 struct {
900 uint32_t h[RPC_HEADER_WORDS];
901 struct repl d;
902 } rdata;
903 ssize_t cc;
904
905 #ifdef NFS_DEBUG
906 if (debug)
907 printf("lookupfh: called\n");
908 #endif
909
910 args = &sdata.d;
911 repl = &rdata.d;
912
913 bzero(args, sizeof(*args));
914 args->fhsize = htonl(d->fhsize);
915 bcopy(d->fh, args->fhplusname, d->fhsize);
916 len = strlen(name);
917 if (len > FNAME_SIZE)
918 len = FNAME_SIZE;
919 pos = roundup(d->fhsize, sizeof(uint32_t)) / sizeof(uint32_t);
920 args->fhplusname[pos++] = htonl(len);
921 bcopy(name, &args->fhplusname[pos], len);
922 len = sizeof(uint32_t) + pos * sizeof(uint32_t) +
923 roundup(len, sizeof(uint32_t));
924
925 rlen = sizeof(*repl);
926
927 cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER3, NFSPROCV3_LOOKUP,
928 args, len, repl, rlen);
929 if (cc == -1)
930 return (errno); /* XXX - from rpc_call */
931 if (cc < 2 * sizeof(uint32_t))
932 return (EIO);
933 if (repl->errno != 0)
934 /* saerrno.h now matches NFS error numbers. */
935 return (ntohl(repl->errno));
936 newfd->fhsize = ntohl(repl->fhsize);
937 bcopy(repl->fhplusattr, &newfd->fh, newfd->fhsize);
938 pos = roundup(newfd->fhsize, sizeof(uint32_t)) / sizeof(uint32_t);
939 if (repl->fhplusattr[pos++] == 0)
940 return (EIO);
941 bcopy(&repl->fhplusattr[pos], &newfd->fa, sizeof(newfd->fa));
942 return (0);
943 }
944
945 #ifndef NFS_NOSYMLINK
946 /*
947 * Get the destination of a symbolic link.
948 */
949 int
nfs_readlink(struct nfs_iodesc * d,char * buf)950 nfs_readlink(struct nfs_iodesc *d, char *buf)
951 {
952 struct args {
953 uint32_t fhsize;
954 u_char fh[NFS_V3MAXFHSIZE];
955 } *args;
956 struct repl {
957 uint32_t errno;
958 uint32_t ok;
959 struct nfsv3_fattrs fa;
960 uint32_t len;
961 u_char path[NFS_MAXPATHLEN];
962 } *repl;
963 struct {
964 uint32_t h[RPC_HEADER_WORDS];
965 struct args d;
966 } sdata;
967 struct {
968 uint32_t h[RPC_HEADER_WORDS];
969 struct repl d;
970 } rdata;
971 ssize_t cc;
972
973 #ifdef NFS_DEBUG
974 if (debug)
975 printf("readlink: called\n");
976 #endif
977
978 args = &sdata.d;
979 repl = &rdata.d;
980
981 bzero(args, sizeof(*args));
982 args->fhsize = htonl(d->fhsize);
983 bcopy(d->fh, args->fh, d->fhsize);
984 cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER3, NFSPROCV3_READLINK,
985 args, sizeof(uint32_t) + roundup(d->fhsize, sizeof(uint32_t)),
986 repl, sizeof(*repl));
987 if (cc == -1)
988 return (errno);
989
990 if (cc < 2 * sizeof(uint32_t))
991 return (EIO);
992
993 if (repl->errno != 0)
994 return (ntohl(repl->errno));
995
996 if (repl->ok == 0)
997 return (EIO);
998
999 repl->len = ntohl(repl->len);
1000 if (repl->len > NFS_MAXPATHLEN)
1001 return (ENAMETOOLONG);
1002
1003 bcopy(repl->path, buf, repl->len);
1004 buf[repl->len] = 0;
1005 return (0);
1006 }
1007 #endif
1008
1009 /*
1010 * Read data from a file.
1011 * Return transfer count or -1 (and set errno)
1012 */
1013 ssize_t
nfs_readdata(struct nfs_iodesc * d,off_t off,void * addr,size_t len)1014 nfs_readdata(struct nfs_iodesc *d, off_t off, void *addr, size_t len)
1015 {
1016 struct args {
1017 uint32_t fhsize;
1018 uint32_t fhoffcnt[NFS_V3MAXFHSIZE / sizeof(uint32_t) + 3];
1019 } *args;
1020 struct repl {
1021 uint32_t errno;
1022 uint32_t ok;
1023 struct nfsv3_fattrs fa;
1024 uint32_t count;
1025 uint32_t eof;
1026 uint32_t len;
1027 u_char data[NFSREAD_SIZE];
1028 } *repl;
1029 struct {
1030 uint32_t h[RPC_HEADER_WORDS];
1031 struct args d;
1032 } sdata;
1033 struct {
1034 uint32_t h[RPC_HEADER_WORDS];
1035 struct repl d;
1036 } rdata;
1037 size_t cc;
1038 long x;
1039 int hlen, rlen, pos;
1040
1041 args = &sdata.d;
1042 repl = &rdata.d;
1043
1044 bzero(args, sizeof(*args));
1045 args->fhsize = htonl(d->fhsize);
1046 bcopy(d->fh, args->fhoffcnt, d->fhsize);
1047 pos = roundup(d->fhsize, sizeof(uint32_t)) / sizeof(uint32_t);
1048 args->fhoffcnt[pos++] = 0;
1049 args->fhoffcnt[pos++] = htonl((uint32_t)off);
1050 if (len > NFSREAD_SIZE)
1051 len = NFSREAD_SIZE;
1052 args->fhoffcnt[pos] = htonl((uint32_t)len);
1053 hlen = sizeof(*repl) - NFSREAD_SIZE;
1054
1055 cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER3, NFSPROCV3_READ,
1056 args, 4 * sizeof(uint32_t) + roundup(d->fhsize, sizeof(uint32_t)),
1057 repl, sizeof(*repl));
1058 if (cc == -1)
1059 /* errno was already set by rpc_call */
1060 return (-1);
1061 if (cc < hlen) {
1062 errno = EBADRPC;
1063 return (-1);
1064 }
1065 if (repl->errno != 0) {
1066 errno = ntohl(repl->errno);
1067 return (-1);
1068 }
1069 rlen = cc - hlen;
1070 x = ntohl(repl->count);
1071 if (rlen < x) {
1072 printf("nfsread: short packet, %d < %ld\n", rlen, x);
1073 errno = EBADRPC;
1074 return (-1);
1075 }
1076 bcopy(repl->data, addr, x);
1077 return (x);
1078 }
1079
1080 /*
1081 * Open a file.
1082 * return zero or error number
1083 */
1084 int
nfs_open(const char * upath,struct open_file * f)1085 nfs_open(const char *upath, struct open_file *f)
1086 {
1087 struct iodesc *desc;
1088 struct nfs_iodesc *currfd;
1089 char buf[2 * NFS_V3MAXFHSIZE + 3];
1090 u_char *fh;
1091 char *cp;
1092 int i;
1093 #ifndef NFS_NOSYMLINK
1094 struct nfs_iodesc *newfd;
1095 struct nfsv3_fattrs *fa;
1096 char *ncp;
1097 int c;
1098 char namebuf[NFS_MAXPATHLEN + 1];
1099 char linkbuf[NFS_MAXPATHLEN + 1];
1100 int nlinks = 0;
1101 #endif
1102 int error;
1103 char *path;
1104
1105 #ifdef NFS_DEBUG
1106 if (debug)
1107 printf("nfs_open: %s (rootpath=%s)\n", upath, rootpath);
1108 #endif
1109 if (!rootpath[0]) {
1110 printf("no rootpath, no nfs\n");
1111 return (ENXIO);
1112 }
1113
1114 /*
1115 * This is silly - we should look at dv_type but that value is
1116 * arch dependant and we can't use it here.
1117 */
1118 #ifndef __i386__
1119 if (strcmp(f->f_dev->dv_name, "net") != 0)
1120 return (EINVAL);
1121 #else
1122 if (strcmp(f->f_dev->dv_name, "pxe") != 0)
1123 return (EINVAL);
1124 #endif
1125
1126 if (!(desc = socktodesc(*(int *)(f->f_devdata))))
1127 return (EINVAL);
1128
1129 /* Bind to a reserved port. */
1130 desc->myport = htons(--rpc_port);
1131 desc->destip = rootip;
1132 if ((error = nfs_getrootfh(desc, rootpath, &nfs_root_node.fhsize,
1133 nfs_root_node.fh)))
1134 return (error);
1135 nfs_root_node.fa.fa_type = htonl(NFDIR);
1136 nfs_root_node.fa.fa_mode = htonl(0755);
1137 nfs_root_node.fa.fa_nlink = htonl(2);
1138 nfs_root_node.iodesc = desc;
1139
1140 fh = &nfs_root_node.fh[0];
1141 buf[0] = 'X';
1142 cp = &buf[1];
1143 for (i = 0; i < nfs_root_node.fhsize; i++, cp += 2)
1144 sprintf(cp, "%02x", fh[i]);
1145 sprintf(cp, "X");
1146 setenv("boot.nfsroot.server", inet_ntoa(rootip), 1);
1147 setenv("boot.nfsroot.path", rootpath, 1);
1148 setenv("boot.nfsroot.nfshandle", buf, 1);
1149 sprintf(buf, "%d", nfs_root_node.fhsize);
1150 setenv("boot.nfsroot.nfshandlelen", buf, 1);
1151
1152 /* Allocate file system specific data structure */
1153 currfd = malloc(sizeof(*newfd));
1154 if (currfd == NULL) {
1155 error = ENOMEM;
1156 goto out;
1157 }
1158 #ifndef NFS_NOSYMLINK
1159 bcopy(&nfs_root_node, currfd, sizeof(*currfd));
1160 newfd = 0;
1161
1162 cp = path = strdup(upath);
1163 if (path == NULL) {
1164 error = ENOMEM;
1165 goto out;
1166 }
1167 while (*cp) {
1168 /*
1169 * Remove extra separators
1170 */
1171 while (*cp == '/')
1172 cp++;
1173
1174 if (*cp == '\0')
1175 break;
1176 /*
1177 * Check that current node is a directory.
1178 */
1179 if (currfd->fa.fa_type != htonl(NFDIR)) {
1180 error = ENOTDIR;
1181 goto out;
1182 }
1183
1184 /* allocate file system specific data structure */
1185 newfd = malloc(sizeof(*newfd));
1186 if (newfd == NULL) {
1187 error = ENOMEM;
1188 goto out;
1189 }
1190 newfd->iodesc = currfd->iodesc;
1191
1192 /*
1193 * Get next component of path name.
1194 */
1195 {
1196 int len = 0;
1197
1198 ncp = cp;
1199 while ((c = *cp) != '\0' && c != '/') {
1200 if (++len > NFS_MAXNAMLEN) {
1201 error = ENOENT;
1202 goto out;
1203 }
1204 cp++;
1205 }
1206 *cp = '\0';
1207 }
1208
1209 /* lookup a file handle */
1210 error = nfs_lookupfh(currfd, ncp, newfd);
1211 *cp = c;
1212 if (error)
1213 goto out;
1214
1215 /*
1216 * Check for symbolic link
1217 */
1218 if (newfd->fa.fa_type == htonl(NFLNK)) {
1219 int link_len, len;
1220
1221 error = nfs_readlink(newfd, linkbuf);
1222 if (error)
1223 goto out;
1224
1225 link_len = strlen(linkbuf);
1226 len = strlen(cp);
1227
1228 if (link_len + len > MAXPATHLEN
1229 || ++nlinks > MAXSYMLINKS) {
1230 error = ENOENT;
1231 goto out;
1232 }
1233
1234 bcopy(cp, &namebuf[link_len], len + 1);
1235 bcopy(linkbuf, namebuf, link_len);
1236
1237 /*
1238 * If absolute pathname, restart at root.
1239 * If relative pathname, restart at parent directory.
1240 */
1241 cp = namebuf;
1242 if (*cp == '/')
1243 bcopy(&nfs_root_node, currfd, sizeof(*currfd));
1244
1245 free(newfd);
1246 newfd = 0;
1247
1248 continue;
1249 }
1250
1251 free(currfd);
1252 currfd = newfd;
1253 newfd = 0;
1254 }
1255
1256 error = 0;
1257
1258 out:
1259 free(newfd);
1260 free(path);
1261 #else
1262 currfd->iodesc = desc;
1263
1264 error = nfs_lookupfh(&nfs_root_node, upath, currfd);
1265 #endif
1266 if (!error) {
1267 currfd->off = 0;
1268 currfd->cookie = 0;
1269 f->f_fsdata = (void *)currfd;
1270 return (0);
1271 }
1272
1273 #ifdef NFS_DEBUG
1274 if (debug)
1275 printf("nfs_open: %s lookupfh failed: %s\n",
1276 path, strerror(error));
1277 #endif
1278 free(currfd);
1279
1280 return (error);
1281 }
1282
1283 int
nfs_close(struct open_file * f)1284 nfs_close(struct open_file *f)
1285 {
1286 struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
1287
1288 #ifdef NFS_DEBUG
1289 if (debug)
1290 printf("nfs_close: fp=0x%lx\n", (u_long)fp);
1291 #endif
1292
1293 if (fp)
1294 free(fp);
1295 f->f_fsdata = (void *)0;
1296
1297 return (0);
1298 }
1299
1300 /*
1301 * read a portion of a file
1302 */
1303 int
nfs_read(struct open_file * f,void * buf,size_t size,size_t * resid)1304 nfs_read(struct open_file *f, void *buf, size_t size, size_t *resid)
1305 {
1306 struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
1307 ssize_t cc;
1308 char *addr = buf;
1309
1310 #ifdef NFS_DEBUG
1311 if (debug)
1312 printf("nfs_read: size=%lu off=%d\n", (u_long)size,
1313 (int)fp->off);
1314 #endif
1315 while ((int)size > 0) {
1316 twiddle();
1317 cc = nfs_readdata(fp, fp->off, (void *)addr, size);
1318 /* XXX maybe should retry on certain errors */
1319 if (cc == -1) {
1320 #ifdef NFS_DEBUG
1321 if (debug)
1322 printf("nfs_read: read: %s", strerror(errno));
1323 #endif
1324 return (errno); /* XXX - from nfs_readdata */
1325 }
1326 if (cc == 0) {
1327 #ifdef NFS_DEBUG
1328 if (debug)
1329 printf("nfs_read: hit EOF unexpectantly");
1330 #endif
1331 goto ret;
1332 }
1333 fp->off += cc;
1334 addr += cc;
1335 size -= cc;
1336 }
1337 ret:
1338 if (resid)
1339 *resid = size;
1340
1341 return (0);
1342 }
1343
1344 /*
1345 * Not implemented.
1346 */
1347 int
nfs_write(struct open_file * f,void * buf,size_t size,size_t * resid)1348 nfs_write(struct open_file *f, void *buf, size_t size, size_t *resid)
1349 {
1350 return (EROFS);
1351 }
1352
1353 off_t
nfs_seek(struct open_file * f,off_t offset,int where)1354 nfs_seek(struct open_file *f, off_t offset, int where)
1355 {
1356 struct nfs_iodesc *d = (struct nfs_iodesc *)f->f_fsdata;
1357 uint32_t size = ntohl(d->fa.fa_size.val[1]);
1358
1359 switch (where) {
1360 case SEEK_SET:
1361 d->off = offset;
1362 break;
1363 case SEEK_CUR:
1364 d->off += offset;
1365 break;
1366 case SEEK_END:
1367 d->off = size - offset;
1368 break;
1369 default:
1370 errno = EINVAL;
1371 return (-1);
1372 }
1373
1374 return (d->off);
1375 }
1376
1377 /* NFNON=0, NFREG=1, NFDIR=2, NFBLK=3, NFCHR=4, NFLNK=5, NFSOCK=6, NFFIFO=7 */
1378 int nfs_stat_types[9] = {
1379 0, S_IFREG, S_IFDIR, S_IFBLK, S_IFCHR, S_IFLNK, S_IFSOCK, S_IFIFO, 0 };
1380
1381 int
nfs_stat(struct open_file * f,struct stat * sb)1382 nfs_stat(struct open_file *f, struct stat *sb)
1383 {
1384 struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
1385 uint32_t ftype, mode;
1386
1387 ftype = ntohl(fp->fa.fa_type);
1388 mode = ntohl(fp->fa.fa_mode);
1389 mode |= nfs_stat_types[ftype & 7];
1390
1391 sb->st_mode = mode;
1392 sb->st_nlink = ntohl(fp->fa.fa_nlink);
1393 sb->st_uid = ntohl(fp->fa.fa_uid);
1394 sb->st_gid = ntohl(fp->fa.fa_gid);
1395 sb->st_size = ntohl(fp->fa.fa_size.val[1]);
1396
1397 return (0);
1398 }
1399
1400 static int
nfs_readdir(struct open_file * f,struct dirent * d)1401 nfs_readdir(struct open_file *f, struct dirent *d)
1402 {
1403 struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
1404 struct nfsv3_readdir_repl *repl;
1405 struct nfsv3_readdir_entry *rent;
1406 static char *buf;
1407 static struct nfs_iodesc *pfp = NULL;
1408 static uint64_t cookie = 0;
1409 size_t cc;
1410 int pos;
1411
1412 struct args {
1413 uint32_t fhsize;
1414 uint32_t fhpluscookie[5 + NFS_V3MAXFHSIZE];
1415 } *args;
1416 struct {
1417 uint32_t h[RPC_HEADER_WORDS];
1418 struct args d;
1419 } sdata;
1420 static struct {
1421 uint32_t h[RPC_HEADER_WORDS];
1422 u_char d[NFS_READDIRSIZE];
1423 } rdata;
1424
1425 if (fp != pfp || fp->off != cookie) {
1426 pfp = NULL;
1427 refill:
1428 args = &sdata.d;
1429 bzero(args, sizeof(*args));
1430
1431 args->fhsize = htonl(fp->fhsize);
1432 bcopy(fp->fh, args->fhpluscookie, fp->fhsize);
1433 pos = roundup(fp->fhsize, sizeof(uint32_t)) / sizeof(uint32_t);
1434 args->fhpluscookie[pos++] = htonl(fp->off >> 32);
1435 args->fhpluscookie[pos++] = htonl(fp->off);
1436 args->fhpluscookie[pos++] = htonl(fp->cookie >> 32);
1437 args->fhpluscookie[pos++] = htonl(fp->cookie);
1438 args->fhpluscookie[pos] = htonl(NFS_READDIRSIZE);
1439
1440 cc = rpc_call(fp->iodesc, NFS_PROG, NFS_VER3, NFSPROCV3_READDIR,
1441 args, 6 * sizeof(uint32_t) +
1442 roundup(fp->fhsize, sizeof(uint32_t)),
1443 rdata.d, sizeof(rdata.d));
1444 buf = rdata.d;
1445 repl = (struct nfsv3_readdir_repl *)buf;
1446 if (repl->errno != 0)
1447 return (ntohl(repl->errno));
1448 pfp = fp;
1449 cookie = fp->off;
1450 fp->cookie = ((uint64_t)ntohl(repl->cookiev0) << 32) |
1451 ntohl(repl->cookiev1);
1452 buf += sizeof (struct nfsv3_readdir_repl);
1453 }
1454 rent = (struct nfsv3_readdir_entry *)buf;
1455
1456 if (rent->follows == 0) {
1457 /* fid0 is actually eof */
1458 if (rent->fid0 != 0) {
1459 cookie = 0;
1460 return (ENOENT);
1461 }
1462 goto refill;
1463 }
1464
1465 d->d_namlen = ntohl(rent->len);
1466 bcopy(rent->nameplus, d->d_name, d->d_namlen);
1467 d->d_name[d->d_namlen] = '\0';
1468
1469 pos = roundup(d->d_namlen, sizeof(uint32_t)) / sizeof(uint32_t);
1470 fp->off = cookie = ((uint64_t)ntohl(rent->nameplus[pos]) << 32) |
1471 ntohl(rent->nameplus[pos + 1]);
1472 pos += 2;
1473 buf = (u_char *)&rent->nameplus[pos];
1474 return (0);
1475 }
1476 #endif /* OLD_NFSV2 */
1477