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