1 /* $NetBSD: nfs.c,v 1.2 1998/01/24 12:43:09 drochner Exp $ */
4 * Copyright (c) 1993 John Brezak
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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.
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.
31 #include <sys/cdefs.h>
32 __FBSDID("$FreeBSD$");
34 #include <sys/param.h>
36 #include <sys/socket.h>
40 #include <netinet/in.h>
41 #include <netinet/in_systm.h>
53 #define NFSREAD_SIZE 1024
55 /* Define our own NFS attributes without NQNFS stuff. */
69 struct nfsv2_time fa_atime;
70 struct nfsv2_time fa_mtime;
71 struct nfsv2_time fa_ctime;
74 struct nfs_read_args {
75 u_char fh[NFS_FHSIZE];
78 n_long xxx; /* XXX what's this for? */
81 /* Data part of nfs rpc reply (also the largest thing we receive) */
82 struct nfs_read_repl {
84 struct nfsv2_fattrs fa;
86 u_char data[NFSREAD_SIZE];
90 struct nfs_readlnk_repl {
93 char path[NFS_MAXPATHLEN];
97 struct nfs_readdir_args {
98 u_char fh[NFS_FHSIZE];
103 struct nfs_readdir_data {
109 struct nfs_readdir_off {
115 struct iodesc *iodesc;
117 u_char fh[NFS_FHSIZE];
118 struct nfsv2_fattrs fa; /* all in network order */
120 #else /* !OLD_NFSV2 */
122 /* NFSv3 definitions */
123 #define NFS_V3MAXFHSIZE 64
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
140 struct nfsv3_fattrs {
151 struct nfsv3_time fa_atime;
152 struct nfsv3_time fa_mtime;
153 struct nfsv3_time fa_ctime;
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.
162 struct nfsv3_readdir_repl {
165 struct nfsv3_fattrs fa;
170 struct nfsv3_readdir_entry {
175 uint32_t nameplus[0];
179 struct iodesc *iodesc;
182 u_char fh[NFS_V3MAXFHSIZE];
183 struct nfsv3_fattrs fa; /* all in network order */
186 #endif /* OLD_NFSV2 */
189 * XXX interactions with tftp? See nfswrapper.c for a confusing
192 int nfs_open(const char *path, struct open_file *f);
193 static int nfs_close(struct open_file *f);
194 static int nfs_read(struct open_file *f, void *buf, size_t size, size_t *resid);
195 static int nfs_write(struct open_file *f, void *buf, size_t size, size_t *resid);
196 static off_t nfs_seek(struct open_file *f, off_t offset, int where);
197 static int nfs_stat(struct open_file *f, struct stat *sb);
198 static int nfs_readdir(struct open_file *f, struct dirent *d);
200 struct nfs_iodesc nfs_root_node;
202 struct fs_ops nfs_fsops = {
215 * Fetch the root file handle (call mount daemon)
216 * Return zero or error number.
219 nfs_getrootfh(struct iodesc *d, char *path, u_char *fhp)
224 char path[FNAME_SIZE];
228 u_char fh[NFS_FHSIZE];
231 n_long h[RPC_HEADER_WORDS];
235 n_long h[RPC_HEADER_WORDS];
242 printf("nfs_getrootfh: %s\n", path);
248 bzero(args, sizeof(*args));
250 if (len > sizeof(args->path))
251 len = sizeof(args->path);
252 args->len = htonl(len);
253 bcopy(path, args->path, len);
254 len = 4 + roundup(len, 4);
256 cc = rpc_call(d, RPCPROG_MNT, RPCMNT_VER1, RPCMNT_MOUNT,
257 args, len, repl, sizeof(*repl));
259 /* errno was set by rpc_call */
265 return (ntohl(repl->errno));
266 bcopy(repl->fh, fhp, sizeof(repl->fh));
271 * Lookup a file. Store handle and attributes.
272 * Return zero or error number.
275 nfs_lookupfh(struct nfs_iodesc *d, const char *name, struct nfs_iodesc *newfd)
279 u_char fh[NFS_FHSIZE];
281 char name[FNAME_SIZE];
285 u_char fh[NFS_FHSIZE];
286 struct nfsv2_fattrs fa;
289 n_long h[RPC_HEADER_WORDS];
293 n_long h[RPC_HEADER_WORDS];
300 printf("lookupfh: called\n");
306 bzero(args, sizeof(*args));
307 bcopy(d->fh, args->fh, sizeof(args->fh));
309 if (len > sizeof(args->name))
310 len = sizeof(args->name);
311 bcopy(name, args->name, len);
312 args->len = htonl(len);
313 len = 4 + roundup(len, 4);
316 rlen = sizeof(*repl);
318 cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER2, NFSPROC_LOOKUP,
319 args, len, repl, rlen);
321 return (errno); /* XXX - from rpc_call */
325 /* saerrno.h now matches NFS error numbers. */
326 return (ntohl(repl->errno));
328 bcopy( repl->fh, &newfd->fh, sizeof(newfd->fh));
329 bcopy(&repl->fa, &newfd->fa, sizeof(newfd->fa));
333 #ifndef NFS_NOSYMLINK
335 * Get the destination of a symbolic link.
338 nfs_readlink(struct nfs_iodesc *d, char *buf)
341 n_long h[RPC_HEADER_WORDS];
342 u_char fh[NFS_FHSIZE];
345 n_long h[RPC_HEADER_WORDS];
346 struct nfs_readlnk_repl d;
352 printf("readlink: called\n");
355 bcopy(d->fh, sdata.fh, NFS_FHSIZE);
356 cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER2, NFSPROC_READLINK,
357 sdata.fh, NFS_FHSIZE,
358 &rdata.d, sizeof(rdata.d));
366 return (ntohl(rdata.d.errno));
368 rdata.d.len = ntohl(rdata.d.len);
369 if (rdata.d.len > NFS_MAXPATHLEN)
370 return (ENAMETOOLONG);
372 bcopy(rdata.d.path, buf, rdata.d.len);
373 buf[rdata.d.len] = 0;
379 * Read data from a file.
380 * Return transfer count or -1 (and set errno)
383 nfs_readdata(struct nfs_iodesc *d, off_t off, void *addr, size_t len)
385 struct nfs_read_args *args;
386 struct nfs_read_repl *repl;
388 n_long h[RPC_HEADER_WORDS];
389 struct nfs_read_args d;
392 n_long h[RPC_HEADER_WORDS];
393 struct nfs_read_repl d;
402 bcopy(d->fh, args->fh, NFS_FHSIZE);
403 args->off = htonl((n_long)off);
404 if (len > NFSREAD_SIZE)
406 args->len = htonl((n_long)len);
407 args->xxx = htonl((n_long)0);
408 hlen = sizeof(*repl) - NFSREAD_SIZE;
410 cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER2, NFSPROC_READ,
412 repl, sizeof(*repl));
414 /* errno was already set by rpc_call */
422 errno = ntohl(repl->errno);
426 x = ntohl(repl->count);
428 printf("nfsread: short packet, %d < %ld\n", rlen, x);
432 bcopy(repl->data, addr, x);
438 * return zero or error number
441 nfs_open(const char *upath, struct open_file *f)
444 struct nfs_iodesc *currfd;
445 char buf[2 * NFS_FHSIZE + 3];
449 #ifndef NFS_NOSYMLINK
450 struct nfs_iodesc *newfd;
451 struct nfsv2_fattrs *fa;
454 char namebuf[NFS_MAXPATHLEN + 1];
455 char linkbuf[NFS_MAXPATHLEN + 1];
463 printf("nfs_open: %s (rootpath=%s)\n", upath, rootpath);
466 printf("no rootpath, no nfs\n");
471 * This is silly - we should look at dv_type but that value is
472 * arch dependant and we can't use it here.
475 if (strcmp(f->f_dev->dv_name, "net") != 0)
478 if (strcmp(f->f_dev->dv_name, "pxe") != 0)
482 if (!(desc = socktodesc(*(int *)(f->f_devdata))))
485 /* Bind to a reserved port. */
486 desc->myport = htons(--rpc_port);
487 desc->destip = rootip;
488 if ((error = nfs_getrootfh(desc, rootpath, nfs_root_node.fh)))
490 nfs_root_node.fa.fa_type = htonl(NFDIR);
491 nfs_root_node.fa.fa_mode = htonl(0755);
492 nfs_root_node.fa.fa_nlink = htonl(2);
493 nfs_root_node.iodesc = desc;
495 fh = &nfs_root_node.fh[0];
498 for (i = 0; i < NFS_FHSIZE; i++, cp += 2)
499 sprintf(cp, "%02x", fh[i]);
501 setenv("boot.nfsroot.server", inet_ntoa(rootip), 1);
502 setenv("boot.nfsroot.path", rootpath, 1);
503 setenv("boot.nfsroot.nfshandle", buf, 1);
505 /* Allocate file system specific data structure */
506 currfd = malloc(sizeof(*newfd));
507 if (currfd == NULL) {
512 #ifndef NFS_NOSYMLINK
513 bcopy(&nfs_root_node, currfd, sizeof(*currfd));
516 cp = path = strdup(upath);
523 * Remove extra separators
531 * Check that current node is a directory.
533 if (currfd->fa.fa_type != htonl(NFDIR)) {
538 /* allocate file system specific data structure */
539 newfd = malloc(sizeof(*newfd));
540 newfd->iodesc = currfd->iodesc;
543 * Get next component of path name.
549 while ((c = *cp) != '\0' && c != '/') {
550 if (++len > NFS_MAXNAMLEN) {
559 /* lookup a file handle */
560 error = nfs_lookupfh(currfd, ncp, newfd);
566 * Check for symbolic link
568 if (newfd->fa.fa_type == htonl(NFLNK)) {
571 error = nfs_readlink(newfd, linkbuf);
575 link_len = strlen(linkbuf);
578 if (link_len + len > MAXPATHLEN
579 || ++nlinks > MAXSYMLINKS) {
584 bcopy(cp, &namebuf[link_len], len + 1);
585 bcopy(linkbuf, namebuf, link_len);
588 * If absolute pathname, restart at root.
589 * If relative pathname, restart at parent directory.
593 bcopy(&nfs_root_node, currfd, sizeof(*currfd));
614 currfd->iodesc = desc;
616 error = nfs_lookupfh(&nfs_root_node, upath, currfd);
620 f->f_fsdata = (void *)currfd;
626 printf("nfs_open: %s lookupfh failed: %s\n",
627 path, strerror(error));
635 nfs_close(struct open_file *f)
637 struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
641 printf("nfs_close: fp=0x%lx\n", (u_long)fp);
646 f->f_fsdata = (void *)0;
652 * read a portion of a file
655 nfs_read(struct open_file *f, void *buf, size_t size, size_t *resid)
657 struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
663 printf("nfs_read: size=%lu off=%d\n", (u_long)size,
666 while ((int)size > 0) {
668 cc = nfs_readdata(fp, fp->off, (void *)addr, size);
669 /* XXX maybe should retry on certain errors */
673 printf("nfs_read: read: %s", strerror(errno));
675 return (errno); /* XXX - from nfs_readdata */
680 printf("nfs_read: hit EOF unexpectantly");
699 nfs_write(struct open_file *f, void *buf, size_t size, size_t *resid)
705 nfs_seek(struct open_file *f, off_t offset, int where)
707 struct nfs_iodesc *d = (struct nfs_iodesc *)f->f_fsdata;
708 n_long size = ntohl(d->fa.fa_size);
718 d->off = size - offset;
728 /* NFNON=0, NFREG=1, NFDIR=2, NFBLK=3, NFCHR=4, NFLNK=5 */
729 int nfs_stat_types[8] = {
730 0, S_IFREG, S_IFDIR, S_IFBLK, S_IFCHR, S_IFLNK, 0 };
733 nfs_stat(struct open_file *f, struct stat *sb)
735 struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
738 ftype = ntohl(fp->fa.fa_type);
739 mode = ntohl(fp->fa.fa_mode);
740 mode |= nfs_stat_types[ftype & 7];
743 sb->st_nlink = ntohl(fp->fa.fa_nlink);
744 sb->st_uid = ntohl(fp->fa.fa_uid);
745 sb->st_gid = ntohl(fp->fa.fa_gid);
746 sb->st_size = ntohl(fp->fa.fa_size);
752 nfs_readdir(struct open_file *f, struct dirent *d)
754 struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
755 struct nfs_readdir_args *args;
756 struct nfs_readdir_data *rd;
757 struct nfs_readdir_off *roff = NULL;
759 static struct nfs_iodesc *pfp = NULL;
760 static n_long cookie = 0;
765 n_long h[RPC_HEADER_WORDS];
766 struct nfs_readdir_args d;
769 n_long h[RPC_HEADER_WORDS];
770 u_char d[NFS_READDIRSIZE];
773 if (fp != pfp || fp->off != cookie) {
777 bzero(args, sizeof(*args));
779 bcopy(fp->fh, args->fh, NFS_FHSIZE);
780 args->cookie = htonl(fp->off);
781 args->count = htonl(NFS_READDIRSIZE);
783 cc = rpc_call(fp->iodesc, NFS_PROG, NFS_VER2, NFSPROC_READDIR,
785 rdata.d, sizeof(rdata.d));
787 roff = (struct nfs_readdir_off *)buf;
788 if (ntohl(roff->cookie) != 0)
793 roff = (struct nfs_readdir_off *)buf;
795 if (ntohl(roff->follows) == 0) {
796 eof = ntohl((roff+1)->cookie);
804 buf += sizeof(struct nfs_readdir_off);
805 rd = (struct nfs_readdir_data *)buf;
806 d->d_namlen = ntohl(rd->len);
807 bcopy(rd->name, d->d_name, d->d_namlen);
808 d->d_name[d->d_namlen] = '\0';
810 buf += (sizeof(struct nfs_readdir_data) + roundup(htonl(rd->len),4));
811 roff = (struct nfs_readdir_off *)buf;
812 fp->off = cookie = ntohl(roff->cookie);
815 #else /* !OLD_NFSV2 */
817 * Fetch the root file handle (call mount daemon)
818 * Return zero or error number.
821 nfs_getrootfh(struct iodesc *d, char *path, uint32_t *fhlenp, u_char *fhp)
826 char path[FNAME_SIZE];
831 u_char fh[NFS_V3MAXFHSIZE];
836 uint32_t h[RPC_HEADER_WORDS];
840 uint32_t h[RPC_HEADER_WORDS];
847 printf("nfs_getrootfh: %s\n", path);
853 bzero(args, sizeof(*args));
855 if (len > sizeof(args->path))
856 len = sizeof(args->path);
857 args->len = htonl(len);
858 bcopy(path, args->path, len);
859 len = sizeof(uint32_t) + roundup(len, sizeof(uint32_t));
861 cc = rpc_call(d, RPCPROG_MNT, RPCMNT_VER3, RPCMNT_MOUNT,
862 args, len, repl, sizeof(*repl));
864 /* errno was set by rpc_call */
866 if (cc < 2 * sizeof (uint32_t))
868 if (repl->errno != 0)
869 return (ntohl(repl->errno));
870 *fhlenp = ntohl(repl->fhsize);
871 bcopy(repl->fh, fhp, *fhlenp);
876 * Lookup a file. Store handle and attributes.
877 * Return zero or error number.
880 nfs_lookupfh(struct nfs_iodesc *d, const char *name, struct nfs_iodesc *newfd)
885 uint32_t fhplusname[1 +
886 (NFS_V3MAXFHSIZE + FNAME_SIZE) / sizeof(uint32_t)];
891 uint32_t fhplusattr[(NFS_V3MAXFHSIZE +
892 2 * (sizeof(uint32_t) +
893 sizeof(struct nfsv3_fattrs))) / sizeof(uint32_t)];
896 uint32_t h[RPC_HEADER_WORDS];
900 uint32_t h[RPC_HEADER_WORDS];
907 printf("lookupfh: called\n");
913 bzero(args, sizeof(*args));
914 args->fhsize = htonl(d->fhsize);
915 bcopy(d->fh, args->fhplusname, d->fhsize);
917 if (len > FNAME_SIZE)
919 pos = roundup(d->fhsize, sizeof(uint32_t)) / sizeof(uint32_t);
920 args->fhplusname[pos++] = htonl(len);
921 bcopy(name, &args->fhplusname[pos], len);
922 len = sizeof(uint32_t) + pos * sizeof(uint32_t) +
923 roundup(len, sizeof(uint32_t));
925 rlen = sizeof(*repl);
927 cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER3, NFSPROCV3_LOOKUP,
928 args, len, repl, rlen);
930 return (errno); /* XXX - from rpc_call */
931 if (cc < 2 * sizeof(uint32_t))
933 if (repl->errno != 0)
934 /* saerrno.h now matches NFS error numbers. */
935 return (ntohl(repl->errno));
936 newfd->fhsize = ntohl(repl->fhsize);
937 bcopy(repl->fhplusattr, &newfd->fh, newfd->fhsize);
938 pos = roundup(newfd->fhsize, sizeof(uint32_t)) / sizeof(uint32_t);
939 if (repl->fhplusattr[pos++] == 0)
941 bcopy(&repl->fhplusattr[pos], &newfd->fa, sizeof(newfd->fa));
945 #ifndef NFS_NOSYMLINK
947 * Get the destination of a symbolic link.
950 nfs_readlink(struct nfs_iodesc *d, char *buf)
954 u_char fh[NFS_V3MAXFHSIZE];
959 struct nfsv3_fattrs fa;
961 u_char path[NFS_MAXPATHLEN];
964 uint32_t h[RPC_HEADER_WORDS];
968 uint32_t h[RPC_HEADER_WORDS];
975 printf("readlink: called\n");
981 bzero(args, sizeof(*args));
982 args->fhsize = htonl(d->fhsize);
983 bcopy(d->fh, args->fh, d->fhsize);
984 cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER3, NFSPROCV3_READLINK,
985 args, sizeof(uint32_t) + roundup(d->fhsize, sizeof(uint32_t)),
986 repl, sizeof(*repl));
990 if (cc < 2 * sizeof(uint32_t))
993 if (repl->errno != 0)
994 return (ntohl(repl->errno));
999 repl->len = ntohl(repl->len);
1000 if (repl->len > NFS_MAXPATHLEN)
1001 return (ENAMETOOLONG);
1003 bcopy(repl->path, buf, repl->len);
1010 * Read data from a file.
1011 * Return transfer count or -1 (and set errno)
1014 nfs_readdata(struct nfs_iodesc *d, off_t off, void *addr, size_t len)
1018 uint32_t fhoffcnt[NFS_V3MAXFHSIZE / sizeof(uint32_t) + 3];
1023 struct nfsv3_fattrs fa;
1027 u_char data[NFSREAD_SIZE];
1030 uint32_t h[RPC_HEADER_WORDS];
1034 uint32_t h[RPC_HEADER_WORDS];
1039 int hlen, rlen, pos;
1044 bzero(args, sizeof(*args));
1045 args->fhsize = htonl(d->fhsize);
1046 bcopy(d->fh, args->fhoffcnt, d->fhsize);
1047 pos = roundup(d->fhsize, sizeof(uint32_t)) / sizeof(uint32_t);
1048 args->fhoffcnt[pos++] = 0;
1049 args->fhoffcnt[pos++] = htonl((uint32_t)off);
1050 if (len > NFSREAD_SIZE)
1052 args->fhoffcnt[pos] = htonl((uint32_t)len);
1053 hlen = sizeof(*repl) - NFSREAD_SIZE;
1055 cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER3, NFSPROCV3_READ,
1056 args, 4 * sizeof(uint32_t) + roundup(d->fhsize, sizeof(uint32_t)),
1057 repl, sizeof(*repl));
1059 /* errno was already set by rpc_call */
1065 if (repl->errno != 0) {
1066 errno = ntohl(repl->errno);
1070 x = ntohl(repl->count);
1072 printf("nfsread: short packet, %d < %ld\n", rlen, x);
1076 bcopy(repl->data, addr, x);
1082 * return zero or error number
1085 nfs_open(const char *upath, struct open_file *f)
1087 struct iodesc *desc;
1088 struct nfs_iodesc *currfd;
1089 char buf[2 * NFS_V3MAXFHSIZE + 3];
1093 #ifndef NFS_NOSYMLINK
1094 struct nfs_iodesc *newfd;
1095 struct nfsv3_fattrs *fa;
1098 char namebuf[NFS_MAXPATHLEN + 1];
1099 char linkbuf[NFS_MAXPATHLEN + 1];
1107 printf("nfs_open: %s (rootpath=%s)\n", upath, rootpath);
1110 printf("no rootpath, no nfs\n");
1115 * This is silly - we should look at dv_type but that value is
1116 * arch dependant and we can't use it here.
1119 if (strcmp(f->f_dev->dv_name, "net") != 0)
1122 if (strcmp(f->f_dev->dv_name, "pxe") != 0)
1126 if (!(desc = socktodesc(*(int *)(f->f_devdata))))
1129 /* Bind to a reserved port. */
1130 desc->myport = htons(--rpc_port);
1131 desc->destip = rootip;
1132 if ((error = nfs_getrootfh(desc, rootpath, &nfs_root_node.fhsize,
1135 nfs_root_node.fa.fa_type = htonl(NFDIR);
1136 nfs_root_node.fa.fa_mode = htonl(0755);
1137 nfs_root_node.fa.fa_nlink = htonl(2);
1138 nfs_root_node.iodesc = desc;
1140 fh = &nfs_root_node.fh[0];
1143 for (i = 0; i < nfs_root_node.fhsize; i++, cp += 2)
1144 sprintf(cp, "%02x", fh[i]);
1146 setenv("boot.nfsroot.server", inet_ntoa(rootip), 1);
1147 setenv("boot.nfsroot.path", rootpath, 1);
1148 setenv("boot.nfsroot.nfshandle", buf, 1);
1149 sprintf(buf, "%d", nfs_root_node.fhsize);
1150 setenv("boot.nfsroot.nfshandlelen", buf, 1);
1152 /* Allocate file system specific data structure */
1153 currfd = malloc(sizeof(*newfd));
1154 if (currfd == NULL) {
1158 #ifndef NFS_NOSYMLINK
1159 bcopy(&nfs_root_node, currfd, sizeof(*currfd));
1162 cp = path = strdup(upath);
1169 * Remove extra separators
1177 * Check that current node is a directory.
1179 if (currfd->fa.fa_type != htonl(NFDIR)) {
1184 /* allocate file system specific data structure */
1185 newfd = malloc(sizeof(*newfd));
1186 if (newfd == NULL) {
1190 newfd->iodesc = currfd->iodesc;
1193 * Get next component of path name.
1199 while ((c = *cp) != '\0' && c != '/') {
1200 if (++len > NFS_MAXNAMLEN) {
1209 /* lookup a file handle */
1210 error = nfs_lookupfh(currfd, ncp, newfd);
1216 * Check for symbolic link
1218 if (newfd->fa.fa_type == htonl(NFLNK)) {
1221 error = nfs_readlink(newfd, linkbuf);
1225 link_len = strlen(linkbuf);
1228 if (link_len + len > MAXPATHLEN
1229 || ++nlinks > MAXSYMLINKS) {
1234 bcopy(cp, &namebuf[link_len], len + 1);
1235 bcopy(linkbuf, namebuf, link_len);
1238 * If absolute pathname, restart at root.
1239 * If relative pathname, restart at parent directory.
1243 bcopy(&nfs_root_node, currfd, sizeof(*currfd));
1262 currfd->iodesc = desc;
1264 error = nfs_lookupfh(&nfs_root_node, upath, currfd);
1269 f->f_fsdata = (void *)currfd;
1275 printf("nfs_open: %s lookupfh failed: %s\n",
1276 path, strerror(error));
1284 nfs_close(struct open_file *f)
1286 struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
1290 printf("nfs_close: fp=0x%lx\n", (u_long)fp);
1295 f->f_fsdata = (void *)0;
1301 * read a portion of a file
1304 nfs_read(struct open_file *f, void *buf, size_t size, size_t *resid)
1306 struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
1312 printf("nfs_read: size=%lu off=%d\n", (u_long)size,
1315 while ((int)size > 0) {
1317 cc = nfs_readdata(fp, fp->off, (void *)addr, size);
1318 /* XXX maybe should retry on certain errors */
1322 printf("nfs_read: read: %s", strerror(errno));
1324 return (errno); /* XXX - from nfs_readdata */
1329 printf("nfs_read: hit EOF unexpectantly");
1348 nfs_write(struct open_file *f, void *buf, size_t size, size_t *resid)
1354 nfs_seek(struct open_file *f, off_t offset, int where)
1356 struct nfs_iodesc *d = (struct nfs_iodesc *)f->f_fsdata;
1357 uint32_t size = ntohl(d->fa.fa_size.val[1]);
1367 d->off = size - offset;
1377 /* NFNON=0, NFREG=1, NFDIR=2, NFBLK=3, NFCHR=4, NFLNK=5, NFSOCK=6, NFFIFO=7 */
1378 int nfs_stat_types[9] = {
1379 0, S_IFREG, S_IFDIR, S_IFBLK, S_IFCHR, S_IFLNK, S_IFSOCK, S_IFIFO, 0 };
1382 nfs_stat(struct open_file *f, struct stat *sb)
1384 struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
1385 uint32_t ftype, mode;
1387 ftype = ntohl(fp->fa.fa_type);
1388 mode = ntohl(fp->fa.fa_mode);
1389 mode |= nfs_stat_types[ftype & 7];
1392 sb->st_nlink = ntohl(fp->fa.fa_nlink);
1393 sb->st_uid = ntohl(fp->fa.fa_uid);
1394 sb->st_gid = ntohl(fp->fa.fa_gid);
1395 sb->st_size = ntohl(fp->fa.fa_size.val[1]);
1401 nfs_readdir(struct open_file *f, struct dirent *d)
1403 struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
1404 struct nfsv3_readdir_repl *repl;
1405 struct nfsv3_readdir_entry *rent;
1407 static struct nfs_iodesc *pfp = NULL;
1408 static uint64_t cookie = 0;
1414 uint32_t fhpluscookie[5 + NFS_V3MAXFHSIZE];
1417 uint32_t h[RPC_HEADER_WORDS];
1421 uint32_t h[RPC_HEADER_WORDS];
1422 u_char d[NFS_READDIRSIZE];
1425 if (fp != pfp || fp->off != cookie) {
1429 bzero(args, sizeof(*args));
1431 args->fhsize = htonl(fp->fhsize);
1432 bcopy(fp->fh, args->fhpluscookie, fp->fhsize);
1433 pos = roundup(fp->fhsize, sizeof(uint32_t)) / sizeof(uint32_t);
1434 args->fhpluscookie[pos++] = htonl(fp->off >> 32);
1435 args->fhpluscookie[pos++] = htonl(fp->off);
1436 args->fhpluscookie[pos++] = htonl(fp->cookie >> 32);
1437 args->fhpluscookie[pos++] = htonl(fp->cookie);
1438 args->fhpluscookie[pos] = htonl(NFS_READDIRSIZE);
1440 cc = rpc_call(fp->iodesc, NFS_PROG, NFS_VER3, NFSPROCV3_READDIR,
1441 args, 6 * sizeof(uint32_t) +
1442 roundup(fp->fhsize, sizeof(uint32_t)),
1443 rdata.d, sizeof(rdata.d));
1445 repl = (struct nfsv3_readdir_repl *)buf;
1446 if (repl->errno != 0)
1447 return (ntohl(repl->errno));
1450 fp->cookie = ((uint64_t)ntohl(repl->cookiev0) << 32) |
1451 ntohl(repl->cookiev1);
1452 buf += sizeof (struct nfsv3_readdir_repl);
1454 rent = (struct nfsv3_readdir_entry *)buf;
1456 if (rent->follows == 0) {
1457 /* fid0 is actually eof */
1458 if (rent->fid0 != 0) {
1465 d->d_namlen = ntohl(rent->len);
1466 bcopy(rent->nameplus, d->d_name, d->d_namlen);
1467 d->d_name[d->d_namlen] = '\0';
1469 pos = roundup(d->d_namlen, sizeof(uint32_t)) / sizeof(uint32_t);
1470 fp->off = cookie = ((uint64_t)ntohl(rent->nameplus[pos]) << 32) |
1471 ntohl(rent->nameplus[pos + 1]);
1473 buf = (u_char *)&rent->nameplus[pos];
1476 #endif /* OLD_NFSV2 */