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