]> CyberLeo.Net >> Repos - FreeBSD/releng/10.2.git/blob - lib/libstand/nfs.c
- Copy stable/10@285827 to releng/10.2 in preparation for 10.2-RC1
[FreeBSD/releng/10.2.git] / lib / libstand / nfs.c
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
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
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
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
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
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
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
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
697 nfs_write(struct open_file *f, void *buf, size_t size, size_t *resid)
698 {
699         return (EROFS);
700 }
701
702 off_t
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
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
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
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
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
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
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
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
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
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
1346 nfs_write(struct open_file *f, void *buf, size_t size, size_t *resid)
1347 {
1348         return (EROFS);
1349 }
1350
1351 off_t
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
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
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 */