]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - lib/libstand/nfs.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.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         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
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
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
699 nfs_write(struct open_file *f, void *buf, size_t size, size_t *resid)
700 {
701         return (EROFS);
702 }
703
704 off_t
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
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
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
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
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
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
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
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
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
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
1348 nfs_write(struct open_file *f, void *buf, size_t size, size_t *resid)
1349 {
1350         return (EROFS);
1351 }
1352
1353 off_t
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
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
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 */