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