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));
612 currfd->iodesc = desc;
614 error = nfs_lookupfh(&nfs_root_node, upath, currfd);
618 f->f_fsdata = (void *)currfd;
624 printf("nfs_open: %s lookupfh failed: %s\n",
625 path, strerror(error));
633 nfs_close(struct open_file *f)
635 struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
639 printf("nfs_close: fp=0x%lx\n", (u_long)fp);
644 f->f_fsdata = (void *)0;
650 * read a portion of a file
653 nfs_read(struct open_file *f, void *buf, size_t size, size_t *resid)
655 struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
661 printf("nfs_read: size=%lu off=%d\n", (u_long)size,
664 while ((int)size > 0) {
666 cc = nfs_readdata(fp, fp->off, (void *)addr, size);
667 /* XXX maybe should retry on certain errors */
671 printf("nfs_read: read: %s", strerror(errno));
673 return (errno); /* XXX - from nfs_readdata */
678 printf("nfs_read: hit EOF unexpectantly");
697 nfs_write(struct open_file *f, void *buf, size_t size, size_t *resid)
703 nfs_seek(struct open_file *f, off_t offset, int where)
705 struct nfs_iodesc *d = (struct nfs_iodesc *)f->f_fsdata;
706 n_long size = ntohl(d->fa.fa_size);
716 d->off = size - offset;
726 /* NFNON=0, NFREG=1, NFDIR=2, NFBLK=3, NFCHR=4, NFLNK=5 */
727 int nfs_stat_types[8] = {
728 0, S_IFREG, S_IFDIR, S_IFBLK, S_IFCHR, S_IFLNK, 0 };
731 nfs_stat(struct open_file *f, struct stat *sb)
733 struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
736 ftype = ntohl(fp->fa.fa_type);
737 mode = ntohl(fp->fa.fa_mode);
738 mode |= nfs_stat_types[ftype & 7];
741 sb->st_nlink = ntohl(fp->fa.fa_nlink);
742 sb->st_uid = ntohl(fp->fa.fa_uid);
743 sb->st_gid = ntohl(fp->fa.fa_gid);
744 sb->st_size = ntohl(fp->fa.fa_size);
750 nfs_readdir(struct open_file *f, struct dirent *d)
752 struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
753 struct nfs_readdir_args *args;
754 struct nfs_readdir_data *rd;
755 struct nfs_readdir_off *roff = NULL;
757 static struct nfs_iodesc *pfp = NULL;
758 static n_long cookie = 0;
763 n_long h[RPC_HEADER_WORDS];
764 struct nfs_readdir_args d;
767 n_long h[RPC_HEADER_WORDS];
768 u_char d[NFS_READDIRSIZE];
771 if (fp != pfp || fp->off != cookie) {
775 bzero(args, sizeof(*args));
777 bcopy(fp->fh, args->fh, NFS_FHSIZE);
778 args->cookie = htonl(fp->off);
779 args->count = htonl(NFS_READDIRSIZE);
781 cc = rpc_call(fp->iodesc, NFS_PROG, NFS_VER2, NFSPROC_READDIR,
783 rdata.d, sizeof(rdata.d));
785 roff = (struct nfs_readdir_off *)buf;
786 if (ntohl(roff->cookie) != 0)
791 roff = (struct nfs_readdir_off *)buf;
793 if (ntohl(roff->follows) == 0) {
794 eof = ntohl((roff+1)->cookie);
802 buf += sizeof(struct nfs_readdir_off);
803 rd = (struct nfs_readdir_data *)buf;
804 d->d_namlen = ntohl(rd->len);
805 bcopy(rd->name, d->d_name, d->d_namlen);
806 d->d_name[d->d_namlen] = '\0';
808 buf += (sizeof(struct nfs_readdir_data) + roundup(htonl(rd->len),4));
809 roff = (struct nfs_readdir_off *)buf;
810 fp->off = cookie = ntohl(roff->cookie);
813 #else /* !OLD_NFSV2 */
815 * Fetch the root file handle (call mount daemon)
816 * Return zero or error number.
819 nfs_getrootfh(struct iodesc *d, char *path, uint32_t *fhlenp, u_char *fhp)
824 char path[FNAME_SIZE];
829 u_char fh[NFS_V3MAXFHSIZE];
834 uint32_t h[RPC_HEADER_WORDS];
838 uint32_t h[RPC_HEADER_WORDS];
845 printf("nfs_getrootfh: %s\n", path);
851 bzero(args, sizeof(*args));
853 if (len > sizeof(args->path))
854 len = sizeof(args->path);
855 args->len = htonl(len);
856 bcopy(path, args->path, len);
857 len = sizeof(uint32_t) + roundup(len, sizeof(uint32_t));
859 cc = rpc_call(d, RPCPROG_MNT, RPCMNT_VER3, RPCMNT_MOUNT,
860 args, len, repl, sizeof(*repl));
862 /* errno was set by rpc_call */
864 if (cc < 2 * sizeof (uint32_t))
866 if (repl->errno != 0)
867 return (ntohl(repl->errno));
868 *fhlenp = ntohl(repl->fhsize);
869 bcopy(repl->fh, fhp, *fhlenp);
874 * Lookup a file. Store handle and attributes.
875 * Return zero or error number.
878 nfs_lookupfh(struct nfs_iodesc *d, const char *name, struct nfs_iodesc *newfd)
883 uint32_t fhplusname[1 +
884 (NFS_V3MAXFHSIZE + FNAME_SIZE) / sizeof(uint32_t)];
889 uint32_t fhplusattr[(NFS_V3MAXFHSIZE +
890 2 * (sizeof(uint32_t) +
891 sizeof(struct nfsv3_fattrs))) / sizeof(uint32_t)];
894 uint32_t h[RPC_HEADER_WORDS];
898 uint32_t h[RPC_HEADER_WORDS];
905 printf("lookupfh: called\n");
911 bzero(args, sizeof(*args));
912 args->fhsize = htonl(d->fhsize);
913 bcopy(d->fh, args->fhplusname, d->fhsize);
915 if (len > FNAME_SIZE)
917 pos = roundup(d->fhsize, sizeof(uint32_t)) / sizeof(uint32_t);
918 args->fhplusname[pos++] = htonl(len);
919 bcopy(name, &args->fhplusname[pos], len);
920 len = sizeof(uint32_t) + pos * sizeof(uint32_t) +
921 roundup(len, sizeof(uint32_t));
923 rlen = sizeof(*repl);
925 cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER3, NFSPROCV3_LOOKUP,
926 args, len, repl, rlen);
928 return (errno); /* XXX - from rpc_call */
929 if (cc < 2 * sizeof(uint32_t))
931 if (repl->errno != 0)
932 /* saerrno.h now matches NFS error numbers. */
933 return (ntohl(repl->errno));
934 newfd->fhsize = ntohl(repl->fhsize);
935 bcopy(repl->fhplusattr, &newfd->fh, newfd->fhsize);
936 pos = roundup(newfd->fhsize, sizeof(uint32_t)) / sizeof(uint32_t);
937 if (repl->fhplusattr[pos++] == 0)
939 bcopy(&repl->fhplusattr[pos], &newfd->fa, sizeof(newfd->fa));
943 #ifndef NFS_NOSYMLINK
945 * Get the destination of a symbolic link.
948 nfs_readlink(struct nfs_iodesc *d, char *buf)
952 u_char fh[NFS_V3MAXFHSIZE];
957 struct nfsv3_fattrs fa;
959 u_char path[NFS_MAXPATHLEN];
962 uint32_t h[RPC_HEADER_WORDS];
966 uint32_t h[RPC_HEADER_WORDS];
973 printf("readlink: called\n");
979 bzero(args, sizeof(*args));
980 args->fhsize = htonl(d->fhsize);
981 bcopy(d->fh, args->fh, d->fhsize);
982 cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER3, NFSPROCV3_READLINK,
983 args, sizeof(uint32_t) + roundup(d->fhsize, sizeof(uint32_t)),
984 repl, sizeof(*repl));
988 if (cc < 2 * sizeof(uint32_t))
991 if (repl->errno != 0)
992 return (ntohl(repl->errno));
997 repl->len = ntohl(repl->len);
998 if (repl->len > NFS_MAXPATHLEN)
999 return (ENAMETOOLONG);
1001 bcopy(repl->path, buf, repl->len);
1008 * Read data from a file.
1009 * Return transfer count or -1 (and set errno)
1012 nfs_readdata(struct nfs_iodesc *d, off_t off, void *addr, size_t len)
1016 uint32_t fhoffcnt[NFS_V3MAXFHSIZE / sizeof(uint32_t) + 3];
1021 struct nfsv3_fattrs fa;
1025 u_char data[NFSREAD_SIZE];
1028 uint32_t h[RPC_HEADER_WORDS];
1032 uint32_t h[RPC_HEADER_WORDS];
1037 int hlen, rlen, pos;
1042 bzero(args, sizeof(*args));
1043 args->fhsize = htonl(d->fhsize);
1044 bcopy(d->fh, args->fhoffcnt, d->fhsize);
1045 pos = roundup(d->fhsize, sizeof(uint32_t)) / sizeof(uint32_t);
1046 args->fhoffcnt[pos++] = 0;
1047 args->fhoffcnt[pos++] = htonl((uint32_t)off);
1048 if (len > NFSREAD_SIZE)
1050 args->fhoffcnt[pos] = htonl((uint32_t)len);
1051 hlen = sizeof(*repl) - NFSREAD_SIZE;
1053 cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER3, NFSPROCV3_READ,
1054 args, 4 * sizeof(uint32_t) + roundup(d->fhsize, sizeof(uint32_t)),
1055 repl, sizeof(*repl));
1057 /* errno was already set by rpc_call */
1063 if (repl->errno != 0) {
1064 errno = ntohl(repl->errno);
1068 x = ntohl(repl->count);
1070 printf("nfsread: short packet, %d < %ld\n", rlen, x);
1074 bcopy(repl->data, addr, x);
1080 * return zero or error number
1083 nfs_open(const char *upath, struct open_file *f)
1085 struct iodesc *desc;
1086 struct nfs_iodesc *currfd;
1087 char buf[2 * NFS_V3MAXFHSIZE + 3];
1091 #ifndef NFS_NOSYMLINK
1092 struct nfs_iodesc *newfd;
1093 struct nfsv3_fattrs *fa;
1096 char namebuf[NFS_MAXPATHLEN + 1];
1097 char linkbuf[NFS_MAXPATHLEN + 1];
1105 printf("nfs_open: %s (rootpath=%s)\n", upath, rootpath);
1108 printf("no rootpath, no nfs\n");
1113 * This is silly - we should look at dv_type but that value is
1114 * arch dependant and we can't use it here.
1117 if (strcmp(f->f_dev->dv_name, "net") != 0)
1120 if (strcmp(f->f_dev->dv_name, "pxe") != 0)
1124 if (!(desc = socktodesc(*(int *)(f->f_devdata))))
1127 /* Bind to a reserved port. */
1128 desc->myport = htons(--rpc_port);
1129 desc->destip = rootip;
1130 if ((error = nfs_getrootfh(desc, rootpath, &nfs_root_node.fhsize,
1133 nfs_root_node.fa.fa_type = htonl(NFDIR);
1134 nfs_root_node.fa.fa_mode = htonl(0755);
1135 nfs_root_node.fa.fa_nlink = htonl(2);
1136 nfs_root_node.iodesc = desc;
1138 fh = &nfs_root_node.fh[0];
1141 for (i = 0; i < nfs_root_node.fhsize; i++, cp += 2)
1142 sprintf(cp, "%02x", fh[i]);
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);
1150 /* Allocate file system specific data structure */
1151 currfd = malloc(sizeof(*newfd));
1152 if (currfd == NULL) {
1156 #ifndef NFS_NOSYMLINK
1157 bcopy(&nfs_root_node, currfd, sizeof(*currfd));
1160 cp = path = strdup(upath);
1167 * Remove extra separators
1175 * Check that current node is a directory.
1177 if (currfd->fa.fa_type != htonl(NFDIR)) {
1182 /* allocate file system specific data structure */
1183 newfd = malloc(sizeof(*newfd));
1184 if (newfd == NULL) {
1188 newfd->iodesc = currfd->iodesc;
1191 * Get next component of path name.
1197 while ((c = *cp) != '\0' && c != '/') {
1198 if (++len > NFS_MAXNAMLEN) {
1207 /* lookup a file handle */
1208 error = nfs_lookupfh(currfd, ncp, newfd);
1214 * Check for symbolic link
1216 if (newfd->fa.fa_type == htonl(NFLNK)) {
1219 error = nfs_readlink(newfd, linkbuf);
1223 link_len = strlen(linkbuf);
1226 if (link_len + len > MAXPATHLEN
1227 || ++nlinks > MAXSYMLINKS) {
1232 bcopy(cp, &namebuf[link_len], len + 1);
1233 bcopy(linkbuf, namebuf, link_len);
1236 * If absolute pathname, restart at root.
1237 * If relative pathname, restart at parent directory.
1241 bcopy(&nfs_root_node, currfd, sizeof(*currfd));
1260 currfd->iodesc = desc;
1262 error = nfs_lookupfh(&nfs_root_node, upath, currfd);
1267 f->f_fsdata = (void *)currfd;
1273 printf("nfs_open: %s lookupfh failed: %s\n",
1274 path, strerror(error));
1282 nfs_close(struct open_file *f)
1284 struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
1288 printf("nfs_close: fp=0x%lx\n", (u_long)fp);
1293 f->f_fsdata = (void *)0;
1299 * read a portion of a file
1302 nfs_read(struct open_file *f, void *buf, size_t size, size_t *resid)
1304 struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
1310 printf("nfs_read: size=%lu off=%d\n", (u_long)size,
1313 while ((int)size > 0) {
1315 cc = nfs_readdata(fp, fp->off, (void *)addr, size);
1316 /* XXX maybe should retry on certain errors */
1320 printf("nfs_read: read: %s", strerror(errno));
1322 return (errno); /* XXX - from nfs_readdata */
1327 printf("nfs_read: hit EOF unexpectantly");
1346 nfs_write(struct open_file *f, void *buf, size_t size, size_t *resid)
1352 nfs_seek(struct open_file *f, off_t offset, int where)
1354 struct nfs_iodesc *d = (struct nfs_iodesc *)f->f_fsdata;
1355 uint32_t size = ntohl(d->fa.fa_size.val[1]);
1365 d->off = size - offset;
1375 /* NFNON=0, NFREG=1, NFDIR=2, NFBLK=3, NFCHR=4, NFLNK=5, NFSOCK=6, NFFIFO=7 */
1376 int nfs_stat_types[9] = {
1377 0, S_IFREG, S_IFDIR, S_IFBLK, S_IFCHR, S_IFLNK, S_IFSOCK, S_IFIFO, 0 };
1380 nfs_stat(struct open_file *f, struct stat *sb)
1382 struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
1383 uint32_t ftype, mode;
1385 ftype = ntohl(fp->fa.fa_type);
1386 mode = ntohl(fp->fa.fa_mode);
1387 mode |= nfs_stat_types[ftype & 7];
1390 sb->st_nlink = ntohl(fp->fa.fa_nlink);
1391 sb->st_uid = ntohl(fp->fa.fa_uid);
1392 sb->st_gid = ntohl(fp->fa.fa_gid);
1393 sb->st_size = ntohl(fp->fa.fa_size.val[1]);
1399 nfs_readdir(struct open_file *f, struct dirent *d)
1401 struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
1402 struct nfsv3_readdir_repl *repl;
1403 struct nfsv3_readdir_entry *rent;
1405 static struct nfs_iodesc *pfp = NULL;
1406 static uint64_t cookie = 0;
1412 uint32_t fhpluscookie[5 + NFS_V3MAXFHSIZE];
1415 uint32_t h[RPC_HEADER_WORDS];
1419 uint32_t h[RPC_HEADER_WORDS];
1420 u_char d[NFS_READDIRSIZE];
1423 if (fp != pfp || fp->off != cookie) {
1427 bzero(args, sizeof(*args));
1429 args->fhsize = htonl(fp->fhsize);
1430 bcopy(fp->fh, args->fhpluscookie, fp->fhsize);
1431 pos = roundup(fp->fhsize, sizeof(uint32_t)) / sizeof(uint32_t);
1432 args->fhpluscookie[pos++] = htonl(fp->off >> 32);
1433 args->fhpluscookie[pos++] = htonl(fp->off);
1434 args->fhpluscookie[pos++] = htonl(fp->cookie >> 32);
1435 args->fhpluscookie[pos++] = htonl(fp->cookie);
1436 args->fhpluscookie[pos] = htonl(NFS_READDIRSIZE);
1438 cc = rpc_call(fp->iodesc, NFS_PROG, NFS_VER3, NFSPROCV3_READDIR,
1439 args, 6 * sizeof(uint32_t) +
1440 roundup(fp->fhsize, sizeof(uint32_t)),
1441 rdata.d, sizeof(rdata.d));
1443 repl = (struct nfsv3_readdir_repl *)buf;
1444 if (repl->errno != 0)
1445 return (ntohl(repl->errno));
1448 fp->cookie = ((uint64_t)ntohl(repl->cookiev0) << 32) |
1449 ntohl(repl->cookiev1);
1450 buf += sizeof (struct nfsv3_readdir_repl);
1452 rent = (struct nfsv3_readdir_entry *)buf;
1454 if (rent->follows == 0) {
1455 /* fid0 is actually eof */
1456 if (rent->fid0 != 0) {
1463 d->d_namlen = ntohl(rent->len);
1464 bcopy(rent->nameplus, d->d_name, d->d_namlen);
1465 d->d_name[d->d_namlen] = '\0';
1467 pos = roundup(d->d_namlen, sizeof(uint32_t)) / sizeof(uint32_t);
1468 fp->off = cookie = ((uint64_t)ntohl(rent->nameplus[pos]) << 32) |
1469 ntohl(rent->nameplus[pos + 1]);
1471 buf = (u_char *)&rent->nameplus[pos];
1474 #endif /* OLD_NFSV2 */