diff options
author | 1996-12-08 15:15:44 +0000 | |
---|---|---|
committer | 1996-12-08 15:15:44 +0000 | |
commit | 79dbd5ceb790c1a6e35c11a8bfd3df05746466e4 (patch) | |
tree | cdd73304c6efb8b8c0a428ff7146d6f83a604d24 /sys/lib/libsa/nfs.c | |
parent | install -> ${INSTALL}, -c -> ${COPY} (diff) | |
download | wireguard-openbsd-79dbd5ceb790c1a6e35c11a8bfd3df05746466e4.tar.xz wireguard-openbsd-79dbd5ceb790c1a6e35c11a8bfd3df05746466e4.zip |
Merge to NetBSD 961207
Diffstat (limited to 'sys/lib/libsa/nfs.c')
-rw-r--r-- | sys/lib/libsa/nfs.c | 180 |
1 files changed, 165 insertions, 15 deletions
diff --git a/sys/lib/libsa/nfs.c b/sys/lib/libsa/nfs.c index b31ecc8da50..a09d4698d0a 100644 --- a/sys/lib/libsa/nfs.c +++ b/sys/lib/libsa/nfs.c @@ -1,5 +1,5 @@ -/* $OpenBSD: nfs.c,v 1.5 1996/10/15 09:58:34 mickey Exp $ */ -/* $NetBSD: nfs.c,v 1.15 1996/05/14 10:28:26 leo Exp $ */ +/* $OpenBSD: nfs.c,v 1.6 1996/12/08 15:15:52 niklas Exp $ */ +/* $NetBSD: nfs.c,v 1.19 1996/10/13 02:29:04 christos Exp $ */ /*- * Copyright (c) 1993 John Brezak @@ -38,8 +38,8 @@ #include <netinet/in.h> #include <netinet/in_systm.h> -#include <nfs/rpcv2.h> -#include <nfs/nfsv2.h> +#include "rpcv2.h" +#include "nfsv2.h" #include "stand.h" #include "net.h" @@ -82,6 +82,12 @@ struct nfs_read_repl { u_char data[NFSREAD_SIZE]; }; +struct nfs_readlnk_repl { + n_long errno; + n_long len; + char path[NFS_MAXPATHLEN]; +}; + struct nfs_iodesc { struct iodesc *iodesc; off_t off; @@ -222,6 +228,51 @@ nfs_lookupfh(d, name, newfd) } /* + * Get the destination of a symbolic link. + */ +int +nfs_readlink(d, buf) + struct nfs_iodesc *d; + char *buf; +{ + struct { + n_long h[RPC_HEADER_WORDS]; + u_char fh[NFS_FHSIZE]; + } sdata; + struct { + n_long h[RPC_HEADER_WORDS]; + struct nfs_readlnk_repl d; + } rdata; + ssize_t cc; + +#ifdef NFS_DEBUG + if (debug) + printf("readlink: called\n"); +#endif + + bcopy(d->fh, sdata.fh, NFS_FHSIZE); + cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER2, NFSPROC_READLINK, + sdata.fh, NFS_FHSIZE, + &rdata.d, sizeof(rdata.d)); + if (cc == -1) + return (errno); + + if (cc < 4) + return (EIO); + + if (rdata.d.errno) + return (ntohl(rdata.d.errno)); + + rdata.d.len = ntohl(rdata.d.len); + if (rdata.d.len > NFS_MAXPATHLEN) + return (ENAMETOOLONG); + + bcopy(rdata.d.path, buf, rdata.d.len); + buf[rdata.d.len] = 0; + return (0); +} + +/* * Read data from a file. * Return transfer count or -1 (and set errno) */ @@ -330,7 +381,12 @@ nfs_open(path, f) char *path; struct open_file *f; { - struct nfs_iodesc *newfd; + struct nfs_iodesc *newfd, *currfd; + register char *cp, *ncp; + register int c; + char namebuf[NFS_MAXPATHLEN + 1]; + char linkbuf[NFS_MAXPATHLEN + 1]; + int nlinks = 0; int error = 0; #ifdef NFS_DEBUG @@ -342,24 +398,118 @@ nfs_open(path, f) return (ENXIO); } - /* allocate file system specific data structure */ - newfd = alloc(sizeof(*newfd)); - newfd->iodesc = nfs_root_node.iodesc; - newfd->off = 0; + currfd = &nfs_root_node; + newfd = 0; + + cp = path; + while (*cp) { + /* + * Remove extra separators + */ + while (*cp == '/') + cp++; + + if (*cp == '\0') + break; + /* + * Check that current node is a directory. + */ + if (currfd->fa.fa_type != htonl(NFDIR)) { + error = ENOTDIR; + goto out; + } + + /* allocate file system specific data structure */ + newfd = alloc(sizeof(*newfd)); + newfd->iodesc = currfd->iodesc; + newfd->off = 0; + + /* + * Get next component of path name. + */ + { + register int len = 0; + + ncp = cp; + while ((c = *cp) != '\0' && c != '/') { + if (++len > NFS_MAXNAMLEN) { + error = ENOENT; + goto out; + } + cp++; + } + *cp = '\0'; + } + + /* lookup a file handle */ + error = nfs_lookupfh(currfd, ncp, newfd); + *cp = c; + if (error) + goto out; + + /* + * Check for symbolic link + */ + if (newfd->fa.fa_type == htonl(NFLNK)) { + int link_len, len; + + error = nfs_readlink(newfd, linkbuf); + if (error) + goto out; + + link_len = strlen(linkbuf); + len = strlen(cp); + + if (link_len + len > MAXPATHLEN + || ++nlinks > MAXSYMLINKS) { + error = ENOENT; + goto out; + } + + bcopy(cp, &namebuf[link_len], len + 1); + bcopy(linkbuf, namebuf, link_len); + + /* + * If absolute pathname, restart at root. + * If relative pathname, restart at parent directory. + */ + cp = namebuf; + if (*cp == '/') { + if (currfd != &nfs_root_node) + free(currfd, sizeof(*currfd)); + currfd = &nfs_root_node; + } + + free(newfd, sizeof(*newfd)); + newfd = 0; + + continue; + } + + if (currfd != &nfs_root_node) + free(currfd, sizeof(*currfd)); + currfd = newfd; + newfd = 0; + } + + error = 0; - /* lookup a file handle */ - error = nfs_lookupfh(&nfs_root_node, path, newfd); +out: if (!error) { - f->f_fsdata = (void *)newfd; + f->f_fsdata = (void *)currfd; return (0); } - + #ifdef NFS_DEBUG if (debug) printf("nfs_open: %s lookupfh failed: %s\n", - path, strerror(error)); + path, strerror(error)); #endif - free(newfd, sizeof(*newfd)); + if (currfd != &nfs_root_node) + free(currfd, sizeof(*currfd)); + if (newfd) + free(newfd, sizeof(*newfd)); + return (error); } |