xref: /dragonfly/stand/lib/nfs.c (revision 655933d6)
1 /* $FreeBSD: src/lib/libstand/nfs.c,v 1.2.6.3 2000/09/10 01:33:25 ps Exp $ */
2 /*	$NetBSD: nfs.c,v 1.2 1998/01/24 12:43:09 drochner Exp $	*/
3 
4 /*-
5  *  Copyright (c) 1993 John Brezak
6  *  All rights reserved.
7  *
8  *  Redistribution and use in source and binary forms, with or without
9  *  modification, are permitted provided that the following conditions
10  *  are met:
11  *  1. Redistributions of source code must retain the above copyright
12  *     notice, this list of conditions and the following disclaimer.
13  *  2. Redistributions in binary form must reproduce the above copyright
14  *     notice, this list of conditions and the following disclaimer in the
15  *     documentation and/or other materials provided with the distribution.
16  *  3. The name of the author may not be used to endorse or promote products
17  *     derived from this software without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR
20  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
23  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
27  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
28  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 #include <sys/param.h>
33 #include <sys/time.h>
34 #include <sys/socket.h>
35 #include <sys/stat.h>
36 #include <string.h>
37 #include <stddef.h>
38 
39 #include <netinet/in.h>
40 #include <netinet/in_systm.h>
41 
42 #include "rpcv2.h"
43 #include "nfsv2.h"
44 
45 #include "stand.h"
46 #include "net.h"
47 #include "netif.h"
48 #include "rpc.h"
49 
50 #define NFS_DEBUGxx
51 
52 /* Define our own NFS attributes without NQNFS stuff. */
53 struct nfsv2_fattrs {
54 	n_long	fa_type;
55 	n_long	fa_mode;
56 	n_long	fa_nlink;
57 	n_long	fa_uid;
58 	n_long	fa_gid;
59 	n_long	fa_size;
60 	n_long	fa_blocksize;
61 	n_long	fa_rdev;
62 	n_long	fa_blocks;
63 	n_long	fa_fsid;
64 	n_long	fa_fileid;
65 	struct nfsv2_time fa_atime;
66 	struct nfsv2_time fa_mtime;
67 	struct nfsv2_time fa_ctime;
68 };
69 
70 
71 struct nfs_read_args {
72 	u_char	fh[NFS_FHSIZE];
73 	n_long	off;
74 	n_long	len;
75 	n_long	xxx;			/* XXX what's this for? */
76 };
77 
78 /*
79  * Data part of nfs rpc reply (also the largest thing we receive).
80  * Worry about the size of the structure declared on the stack.
81  */
82 
83 #define NFSREAD_MIN_SIZE 1024
84 #define NFSREAD_MAX_SIZE 4096
85 
86 struct nfs_read_repl {
87 	n_long	errno;
88 	struct	nfsv2_fattrs fa;
89 	n_long	count;
90 	u_char	data[NFSREAD_MAX_SIZE];
91 };
92 
93 #ifndef NFS_NOSYMLINK
94 struct nfs_readlnk_repl {
95 	n_long	errno;
96 	n_long	len;
97 	char	path[NFS_MAXPATHLEN];
98 };
99 #endif
100 
101 struct nfs_readdir_args {
102 	u_char	fh[NFS_FHSIZE];
103 	n_long	cookie;
104 	n_long	count;
105 };
106 
107 struct nfs_readdir_data {
108 	n_long	fileid;
109 	n_long	len;
110 	char	name[0];
111 };
112 
113 struct nfs_readdir_off {
114 	n_long	cookie;
115 	n_long	follows;
116 };
117 
118 struct nfs_iodesc {
119 	struct	iodesc	*iodesc;
120 	off_t	off;
121 	u_char	fh[NFS_FHSIZE];
122 	struct nfsv2_fattrs fa;	/* all in network order */
123 };
124 
125 /*
126  * XXX interactions with tftp? See nfswrapper.c for a confusing
127  *     issue.
128  */
129 int		nfs_open(const char *path, struct open_file *f);
130 static int	nfs_close(struct open_file *f);
131 static int	nfs_read(struct open_file *f, void *buf, size_t size, size_t *resid);
132 static int	nfs_write(struct open_file *f, void *buf, size_t size, size_t *resid);
133 static off_t	nfs_seek(struct open_file *f, off_t offset, int where);
134 static int	nfs_stat(struct open_file *f, struct stat *sb);
135 static int	nfs_readdir(struct open_file *f, struct dirent *d);
136 
137 struct	nfs_iodesc nfs_root_node;
138 
139 struct fs_ops nfs_fsops = {
140 	"nfs",
141 	nfs_open,
142 	nfs_close,
143 	nfs_read,
144 	nfs_write,
145 	nfs_seek,
146 	nfs_stat,
147 	nfs_readdir
148 };
149 
150 static int nfs_read_size = NFSREAD_MIN_SIZE;
151 
152 /*
153  * Fetch the root file handle (call mount daemon)
154  * Return zero or error number.
155  */
156 int
157 nfs_getrootfh(struct iodesc *d, char *path, u_char *fhp)
158 {
159 	int len;
160 	struct args {
161 		n_long	len;
162 		char	path[FNAME_SIZE];
163 	} *args;
164 	struct repl {
165 		n_long	errno;
166 		u_char	fh[NFS_FHSIZE];
167 	} *repl;
168 	struct {
169 		n_long	h[RPC_HEADER_WORDS];
170 		struct args d;
171 	} sdata;
172 	struct {
173 		n_long	h[RPC_HEADER_WORDS];
174 		struct repl d;
175 	} rdata;
176 	size_t cc;
177 
178 #ifdef NFS_DEBUG
179 	if (debug)
180 		printf("nfs_getrootfh: %s\n", path);
181 #endif
182 
183 	args = &sdata.d;
184 	repl = &rdata.d;
185 
186 	bzero(args, sizeof(*args));
187 	len = strlen(path);
188 	if (len > sizeof(args->path))
189 		len = sizeof(args->path);
190 	args->len = htonl(len);
191 	bcopy(path, args->path, len);
192 	len = 4 + roundup(len, 4);
193 
194 	cc = rpc_call(d, RPCPROG_MNT, RPCMNT_VER1, RPCMNT_MOUNT,
195 	    args, len, repl, sizeof(*repl));
196 	if (cc == -1) {
197 		/* errno was set by rpc_call */
198 		return (errno);
199 	}
200 	if (cc < 4)
201 		return (EBADRPC);
202 	if (repl->errno)
203 		return (ntohl(repl->errno));
204 	bcopy(repl->fh, fhp, sizeof(repl->fh));
205 
206 	/*
207 	 * Improve boot performance over NFS
208 	 */
209 	if (getenv("nfs.read_size") != NULL)
210 		nfs_read_size = strtol(getenv("nfs.read_size"), NULL, 0);
211 	if (nfs_read_size < NFSREAD_MIN_SIZE)
212 		nfs_read_size = NFSREAD_MIN_SIZE;
213 	if (nfs_read_size > NFSREAD_MAX_SIZE)
214 		nfs_read_size = NFSREAD_MAX_SIZE;
215 
216 	return (0);
217 }
218 
219 /*
220  * Lookup a file.  Store handle and attributes.
221  * Return zero or error number.
222  */
223 int
224 nfs_lookupfh(struct nfs_iodesc *d, const char *name, struct nfs_iodesc *newfd)
225 {
226 	int len, rlen;
227 	struct args {
228 		u_char	fh[NFS_FHSIZE];
229 		n_long	len;
230 		char	name[FNAME_SIZE];
231 	} *args;
232 	struct repl {
233 		n_long	errno;
234 		u_char	fh[NFS_FHSIZE];
235 		struct	nfsv2_fattrs fa;
236 	} *repl;
237 	struct {
238 		n_long	h[RPC_HEADER_WORDS];
239 		struct args d;
240 	} sdata;
241 	struct {
242 		n_long	h[RPC_HEADER_WORDS];
243 		struct repl d;
244 	} rdata;
245 	ssize_t cc;
246 
247 #ifdef NFS_DEBUG
248 	if (debug)
249 		printf("lookupfh: called\n");
250 #endif
251 
252 	args = &sdata.d;
253 	repl = &rdata.d;
254 
255 	bzero(args, sizeof(*args));
256 	bcopy(d->fh, args->fh, sizeof(args->fh));
257 	len = strlen(name);
258 	if (len > sizeof(args->name))
259 		len = sizeof(args->name);
260 	bcopy(name, args->name, len);
261 	args->len = htonl(len);
262 	len = 4 + roundup(len, 4);
263 	len += NFS_FHSIZE;
264 
265 	rlen = sizeof(*repl);
266 
267 	cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER2, NFSPROC_LOOKUP,
268 	    args, len, repl, rlen);
269 	if (cc == -1)
270 		return (errno);		/* XXX - from rpc_call */
271 	if (cc < 4)
272 		return (EIO);
273 	if (repl->errno) {
274 		/* saerrno.h now matches NFS error numbers. */
275 		return (ntohl(repl->errno));
276 	}
277 	bcopy( repl->fh, &newfd->fh, sizeof(newfd->fh));
278 	bcopy(&repl->fa, &newfd->fa, sizeof(newfd->fa));
279 	return (0);
280 }
281 
282 #ifndef NFS_NOSYMLINK
283 /*
284  * Get the destination of a symbolic link.
285  */
286 int
287 nfs_readlink(struct nfs_iodesc *d, char *buf)
288 {
289 	struct {
290 		n_long	h[RPC_HEADER_WORDS];
291 		u_char fh[NFS_FHSIZE];
292 	} sdata;
293 	struct {
294 		n_long	h[RPC_HEADER_WORDS];
295 		struct nfs_readlnk_repl d;
296 	} rdata;
297 	ssize_t cc;
298 
299 #ifdef NFS_DEBUG
300 	if (debug)
301 		printf("readlink: called\n");
302 #endif
303 
304 	bcopy(d->fh, sdata.fh, NFS_FHSIZE);
305 	cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER2, NFSPROC_READLINK,
306 		      sdata.fh, NFS_FHSIZE,
307 		      &rdata.d, sizeof(rdata.d));
308 	if (cc == -1)
309 		return (errno);
310 
311 	if (cc < 4)
312 		return (EIO);
313 
314 	if (rdata.d.errno)
315 		return (ntohl(rdata.d.errno));
316 
317 	rdata.d.len = ntohl(rdata.d.len);
318 	if (rdata.d.len > NFS_MAXPATHLEN)
319 		return (ENAMETOOLONG);
320 
321 	bcopy(rdata.d.path, buf, rdata.d.len);
322 	buf[rdata.d.len] = 0;
323 	return (0);
324 }
325 #endif
326 
327 /*
328  * Read data from a file.
329  * Return transfer count or -1 (and set errno)
330  */
331 ssize_t
332 nfs_readdata(struct nfs_iodesc *d, off_t off, void *addr, size_t len)
333 {
334 	struct nfs_read_args *args;
335 	struct nfs_read_repl *repl;
336 	struct {
337 		n_long	h[RPC_HEADER_WORDS];
338 		struct nfs_read_args d;
339 	} sdata;
340 	struct {
341 		n_long	h[RPC_HEADER_WORDS];
342 		struct nfs_read_repl d;
343 	} rdata;
344 	size_t cc;
345 	long x;
346 	int hlen, rlen;
347 
348 	args = &sdata.d;
349 	repl = &rdata.d;
350 
351 	bcopy(d->fh, args->fh, NFS_FHSIZE);
352 	args->off = htonl((n_long)off);
353 	if (len > nfs_read_size)
354 		len = nfs_read_size;
355 	args->len = htonl((n_long)len);
356 	args->xxx = htonl((n_long)0);
357 	hlen = offsetof(struct nfs_read_repl, data[0]);
358 
359 	cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER2, NFSPROC_READ,
360 	    args, sizeof(*args),
361 	    repl, sizeof(*repl));
362 	if (cc == -1) {
363 		/* errno was already set by rpc_call */
364 		return (-1);
365 	}
366 	if (cc < hlen) {
367 		errno = EBADRPC;
368 		return (-1);
369 	}
370 	if (repl->errno) {
371 		errno = ntohl(repl->errno);
372 		return (-1);
373 	}
374 	rlen = cc - hlen;
375 	x = ntohl(repl->count);
376 	if (rlen < x) {
377 		printf("nfsread: short packet, %d < %ld\n", rlen, x);
378 		errno = EBADRPC;
379 		return(-1);
380 	}
381 	bcopy(repl->data, addr, x);
382 	return (x);
383 }
384 
385 /*
386  * Open a file.
387  * return zero or error number
388  */
389 int
390 nfs_open(const char *upath, struct open_file *f)
391 {
392 	struct iodesc *desc;
393 	struct nfs_iodesc *currfd;
394 #ifndef NFS_NOSYMLINK
395 	struct nfs_iodesc *newfd;
396 	struct nfsv2_fattrs *fa;
397 	char *cp, *ncp;
398 	int c;
399 	char namebuf[NFS_MAXPATHLEN + 1];
400 	char linkbuf[NFS_MAXPATHLEN + 1];
401 	int nlinks = 0;
402 #endif
403 	int error;
404 	char *path;
405 
406 #ifdef NFS_DEBUG
407  	if (debug)
408  	    printf("nfs_open: %s (rootpath=%s)\n", path, rootpath);
409 #endif
410 	if (!rootpath[0]) {
411 		printf("no rootpath, no nfs\n");
412 		return (ENXIO);
413 	}
414 
415 	/* Avoid trying out nfs_open for disk devices in the EFI loader */
416 #ifndef __i386__
417 	if (strcmp(f->f_dev->dv_name, "net") != 0)
418 		return (EINVAL);
419 #endif
420 
421 	if (!(desc = socktodesc(*(int *)(f->f_devdata))))
422 		return(EINVAL);
423 
424 	/* Bind to a reserved port. */
425 	desc->myport = htons(rpc_newport());
426 	desc->destip = rootip;
427 	if ((error = nfs_getrootfh(desc, rootpath, nfs_root_node.fh)))
428 		return (error);
429 	nfs_root_node.iodesc = desc;
430 
431 #ifndef NFS_NOSYMLINK
432 	/* Fake up attributes for the root dir. */
433 	fa = &nfs_root_node.fa;
434 	fa->fa_type  = htonl(NFDIR);
435 	fa->fa_mode  = htonl(0755);
436 	fa->fa_nlink = htonl(2);
437 
438 	currfd = &nfs_root_node;
439 	newfd = NULL;
440 
441 	cp = path = strdup(upath);
442 	if (path == NULL) {
443 	    error = ENOMEM;
444 	    goto out;
445 	}
446 	while (*cp) {
447 		/*
448 		 * Remove extra separators
449 		 */
450 		while (*cp == '/')
451 			cp++;
452 
453 		if (*cp == '\0')
454 			break;
455 		/*
456 		 * Check that current node is a directory.
457 		 */
458 		if (currfd->fa.fa_type != htonl(NFDIR)) {
459 			error = ENOTDIR;
460 			goto out;
461 		}
462 
463 		/* allocate file system specific data structure */
464 		newfd = malloc(sizeof(*newfd));
465 		newfd->iodesc = currfd->iodesc;
466 		newfd->off = 0;
467 
468 		/*
469 		 * Get next component of path name.
470 		 */
471 		{
472 			int len = 0;
473 
474 			ncp = cp;
475 			while ((c = *cp) != '\0' && c != '/') {
476 				if (++len > NFS_MAXNAMLEN) {
477 					error = ENOENT;
478 					goto out;
479 				}
480 				cp++;
481 			}
482 			*cp = '\0';
483 		}
484 
485 		/* lookup a file handle */
486 		error = nfs_lookupfh(currfd, ncp, newfd);
487 		*cp = c;
488 		if (error)
489 			goto out;
490 
491 		/*
492 		 * Check for symbolic link
493 		 */
494 		if (newfd->fa.fa_type == htonl(NFLNK)) {
495 			int link_len, len;
496 
497 			error = nfs_readlink(newfd, linkbuf);
498 			if (error)
499 				goto out;
500 
501 			link_len = strlen(linkbuf);
502 			len = strlen(cp);
503 
504 			if (link_len + len > MAXPATHLEN
505 			    || ++nlinks > MAXSYMLINKS) {
506 				error = ENOENT;
507 				goto out;
508 			}
509 
510 			bcopy(cp, &namebuf[link_len], len + 1);
511 			bcopy(linkbuf, namebuf, link_len);
512 
513 			/*
514 			 * If absolute pathname, restart at root.
515 			 * If relative pathname, restart at parent directory.
516 			 */
517 			cp = namebuf;
518 			if (*cp == '/') {
519 				if (currfd != &nfs_root_node)
520 					free(currfd);
521 				currfd = &nfs_root_node;
522 			}
523 
524 			free(newfd);
525 			newfd = NULL;
526 
527 			continue;
528 		}
529 
530 		if (currfd != &nfs_root_node)
531 			free(currfd);
532 		currfd = newfd;
533 		newfd = NULL;
534 	}
535 
536 	error = 0;
537 
538 out:
539 	if (newfd)
540 		free(newfd);
541 	if (path)
542 		free(path);
543 #else
544         /* allocate file system specific data structure */
545         currfd = malloc(sizeof(*currfd));
546         currfd->iodesc = desc;
547         currfd->off = 0;
548 
549         error = nfs_lookupfh(&nfs_root_node, upath, currfd);
550 #endif
551 	if (!error) {
552 		f->f_fsdata = (void *)currfd;
553 		return (0);
554 	}
555 
556 #ifdef NFS_DEBUG
557 	if (debug)
558 		printf("nfs_open: %s lookupfh failed: %s\n",
559 		    path, strerror(error));
560 #endif
561 #ifndef NFS_NOSYMLINK
562 	if (currfd != &nfs_root_node)
563 #endif
564 		free(currfd);
565 
566 	return (error);
567 }
568 
569 int
570 nfs_close(struct open_file *f)
571 {
572 	struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
573 
574 #ifdef NFS_DEBUG
575 	if (debug)
576 		printf("nfs_close: fp=0x%lx\n", (u_long)fp);
577 #endif
578 
579 	f->f_fsdata = NULL;
580 	if (fp && fp != &nfs_root_node)
581 		free(fp);
582 
583 	return (0);
584 }
585 
586 /*
587  * read a portion of a file
588  *
589  * Parameters:
590  *	resid:	out
591  */
592 int
593 nfs_read(struct open_file *f, void *buf, size_t size, size_t *resid)
594 {
595 	struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
596 	ssize_t cc;
597 	static int tc;
598 	char *addr = buf;
599 
600 #ifdef NFS_DEBUG
601 	if (debug)
602 		printf("nfs_read: size=%lu off=%d\n", (u_long)size,
603 		       (int)fp->off);
604 #endif
605 	while ((int)size > 0) {
606 		if (!(tc++ % 256))
607 			twiddle();
608 		cc = nfs_readdata(fp, fp->off, addr, size);
609 		/* XXX maybe should retry on certain errors */
610 		if (cc == -1) {
611 #ifdef NFS_DEBUG
612 			if (debug)
613 				printf("nfs_read: read: %s", strerror(errno));
614 #endif
615 			return (errno);	/* XXX - from nfs_readdata */
616 		}
617 		if (cc == 0) {
618 #ifdef NFS_DEBUG
619 			if (debug)
620 				printf("nfs_read: hit EOF unexpectantly");
621 #endif
622 			goto ret;
623 		}
624 		fp->off += cc;
625 		addr += cc;
626 		size -= cc;
627 	}
628 ret:
629 	if (resid)
630 		*resid = size;
631 
632 	return (0);
633 }
634 
635 /*
636  * Not implemented.
637  *
638  * Parameters:
639  *	resid:	out
640  */
641 int
642 nfs_write(struct open_file *f, void *buf, size_t size, size_t *resid)
643 {
644 	return (EROFS);
645 }
646 
647 off_t
648 nfs_seek(struct open_file *f, off_t offset, int where)
649 {
650 	struct nfs_iodesc *d = (struct nfs_iodesc *)f->f_fsdata;
651 	n_long size = ntohl(d->fa.fa_size);
652 
653 	switch (where) {
654 	case SEEK_SET:
655 		d->off = offset;
656 		break;
657 	case SEEK_CUR:
658 		d->off += offset;
659 		break;
660 	case SEEK_END:
661 		d->off = size - offset;
662 		break;
663 	default:
664 		return (-1);
665 	}
666 
667 	return (d->off);
668 }
669 
670 /* NFNON=0, NFREG=1, NFDIR=2, NFBLK=3, NFCHR=4, NFLNK=5 */
671 int nfs_stat_types[8] = {
672 	0, S_IFREG, S_IFDIR, S_IFBLK, S_IFCHR, S_IFLNK, 0 };
673 
674 int
675 nfs_stat(struct open_file *f, struct stat *sb)
676 {
677 	struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
678 	n_long ftype, mode;
679 
680 	ftype = ntohl(fp->fa.fa_type);
681 	mode  = ntohl(fp->fa.fa_mode);
682 	mode |= nfs_stat_types[ftype & 7];
683 
684 	sb->st_mode  = mode;
685 	sb->st_nlink = ntohl(fp->fa.fa_nlink);
686 	sb->st_uid   = ntohl(fp->fa.fa_uid);
687 	sb->st_gid   = ntohl(fp->fa.fa_gid);
688 	sb->st_size  = ntohl(fp->fa.fa_size);
689 
690 	return (0);
691 }
692 
693 static int
694 nfs_readdir(struct open_file *f, struct dirent *d)
695 {
696 	struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
697 	struct nfs_readdir_args *args;
698 	struct nfs_readdir_data *rd;
699 	struct nfs_readdir_off  *roff = NULL;
700 	static char *buf;
701 	static n_long cookie = 0;
702 	size_t cc;
703 	n_long eof;
704 
705 	struct {
706 		n_long h[RPC_HEADER_WORDS];
707 		struct nfs_readdir_args d;
708 	} sdata;
709 	static struct {
710 		n_long h[RPC_HEADER_WORDS];
711 		u_char d[NFS_READDIRSIZE];
712 	} rdata;
713 
714 	if (cookie == 0) {
715 	refill:
716 		args = &sdata.d;
717 		bzero(args, sizeof(*args));
718 
719 		bcopy(fp->fh, args->fh, NFS_FHSIZE);
720 		args->cookie = htonl(cookie);
721 		args->count  = htonl(NFS_READDIRSIZE);
722 
723 		cc = rpc_call(fp->iodesc, NFS_PROG, NFS_VER2, NFSPROC_READDIR,
724 			      args, sizeof(*args),
725 			      rdata.d, sizeof(rdata.d));
726 		buf  = rdata.d;
727 		roff = (struct nfs_readdir_off *)buf;
728 		if (ntohl(roff->cookie) != 0)
729 			return 1;
730 	}
731 	roff = (struct nfs_readdir_off *)buf;
732 
733 	if (ntohl(roff->follows) == 0) {
734 		eof = ntohl((roff+1)->cookie);
735 		if (eof) {
736 			cookie = 0;
737 			return 1;
738 		}
739 		goto refill;
740 	}
741 
742 	buf += sizeof(struct nfs_readdir_off);
743 	rd = (struct nfs_readdir_data *)buf;
744 	d->d_namlen = ntohl(rd->len);
745 	bcopy(rd->name, d->d_name, d->d_namlen);
746 	d->d_name[d->d_namlen] = '\0';
747 
748 	buf += (sizeof(struct nfs_readdir_data) + roundup(htonl(rd->len),4));
749 	roff = (struct nfs_readdir_off *)buf;
750 	cookie = ntohl(roff->cookie);
751 	return 0;
752 }
753