Module Name: src Committed By: dholland Date: Sun Sep 27 17:23:54 UTC 2009
Modified Files: src/share/man/man9: namei.9 src/sys/kern: vfs_lookup.c src/sys/nfs: nfs_srvsubs.c src/sys/sys: namei.src Log Message: Move a big wodge of symlink-following code from nfsd to inside lookup_for_nfsd(). This code is, or at least should be, the same as the regular symlink-following code plus an extra flag nfsd needs. The two lots of code can/will be merged in the future. To generate a diff of this commit: cvs rdiff -u -r1.22 -r1.23 src/share/man/man9/namei.9 cvs rdiff -u -r1.119 -r1.120 src/sys/kern/vfs_lookup.c cvs rdiff -u -r1.4 -r1.5 src/sys/nfs/nfs_srvsubs.c cvs rdiff -u -r1.12 -r1.13 src/sys/sys/namei.src Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/share/man/man9/namei.9 diff -u src/share/man/man9/namei.9:1.22 src/share/man/man9/namei.9:1.23 --- src/share/man/man9/namei.9:1.22 Sun Sep 27 17:19:07 2009 +++ src/share/man/man9/namei.9 Sun Sep 27 17:23:53 2009 @@ -1,4 +1,4 @@ -.\" $NetBSD: namei.9,v 1.22 2009/09/27 17:19:07 dholland Exp $ +.\" $NetBSD: namei.9,v 1.23 2009/09/27 17:23:53 dholland Exp $ .\" .\" Copyright (c) 2001, 2005, 2006 The NetBSD Foundation, Inc. .\" All rights reserved. @@ -46,7 +46,8 @@ .Ft int .Fn namei "struct nameidata *ndp" .Ft int -.Fn lookup_for_nfsd "struct nameidata *ndp" +.Fn lookup_for_nfsd "struct nameidata *ndp" "struct vnode *startdir" \ +"int neverfollow" .Ft int .Fn lookup_for_nfsd_index "struct nameidata *ndp" .Ft int @@ -288,11 +289,19 @@ is comparable to the historic .Fn lookup but this code is slated for refactoring. -.It Fn lookup_for_nfsd "ndp" +.It Fn lookup_for_nfsd "ndp" "startdir" "neverfollow" This is a private entry point into .Nm used by the NFS server code. -Its semantics are similar to the historic +It looks up a path starting from +.Fa startdir . +If +.Fa neverfollow +is set, +.Em any +symbolic link (not just at the end of the path) will cause an error. +Otherwise, it follows symlinks normally. +Its semantics are similar to a symlink-following loop around the historic .Fn lookup function described above. It should not be used by new code. @@ -304,9 +313,6 @@ .Fn lookup function described above. It should not be used by new code. -(For now it differs from the preceding private entry point in that it -has a different call site with a different context and different -custom initialization of what ought to be private namei state.) .It Fn relookup "dvp" "vpp" "cnp" Reacquire a path name component is a directory. This is a quicker way to lookup a pathname component when the parent Index: src/sys/kern/vfs_lookup.c diff -u src/sys/kern/vfs_lookup.c:1.119 src/sys/kern/vfs_lookup.c:1.120 --- src/sys/kern/vfs_lookup.c:1.119 Sun Sep 27 17:19:07 2009 +++ src/sys/kern/vfs_lookup.c Sun Sep 27 17:23:54 2009 @@ -1,4 +1,4 @@ -/* $NetBSD: vfs_lookup.c,v 1.119 2009/09/27 17:19:07 dholland Exp $ */ +/* $NetBSD: vfs_lookup.c,v 1.120 2009/09/27 17:23:54 dholland Exp $ */ /* * Copyright (c) 1982, 1986, 1989, 1993 @@ -37,7 +37,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: vfs_lookup.c,v 1.119 2009/09/27 17:19:07 dholland Exp $"); +__KERNEL_RCSID(0, "$NetBSD: vfs_lookup.c,v 1.120 2009/09/27 17:23:54 dholland Exp $"); #include "opt_magiclinks.h" @@ -1158,14 +1158,144 @@ */ int -lookup_for_nfsd(struct nameidata *ndp) +lookup_for_nfsd(struct nameidata *ndp, struct vnode *dp, int neverfollow) { struct namei_state state; int error; + struct iovec aiov; + struct uio auio; + int linklen; + char *cp; + /* For now at least we don't have to frob the state */ namei_init(&state, ndp); + + /* + * BEGIN wodge of code from nfsd + */ + + VREF(dp); + vn_lock(dp, LK_EXCLUSIVE | LK_RETRY); + + for (;;) { + + state.cnp->cn_nameptr = state.cnp->cn_pnbuf; + state.ndp->ni_startdir = dp; + + /* + * END wodge of code from nfsd + */ + error = do_lookup(&state); + if (error) { + /* BEGIN from nfsd */ + if (ndp->ni_dvp) { + vput(ndp->ni_dvp); + } + PNBUF_PUT(state.cnp->cn_pnbuf); + /* END from nfsd */ + namei_cleanup(&state); + return error; + } + + /* + * BEGIN wodge of code from nfsd + */ + + /* + * Check for encountering a symbolic link + */ + if ((state.cnp->cn_flags & ISSYMLINK) == 0) { + if ((state.cnp->cn_flags & LOCKPARENT) == 0 && state.ndp->ni_dvp) { + if (state.ndp->ni_dvp == state.ndp->ni_vp) { + vrele(state.ndp->ni_dvp); + } else { + vput(state.ndp->ni_dvp); + } + } + if (state.cnp->cn_flags & (SAVENAME | SAVESTART)) { + state.cnp->cn_flags |= HASBUF; + } else { + PNBUF_PUT(state.cnp->cn_pnbuf); +#if defined(DIAGNOSTIC) + state.cnp->cn_pnbuf = NULL; +#endif /* defined(DIAGNOSTIC) */ + } + return (0); + } else { + if (neverfollow) { + error = EINVAL; + goto out; + } + if (state.ndp->ni_loopcnt++ >= MAXSYMLINKS) { + error = ELOOP; + goto out; + } + if (state.ndp->ni_vp->v_mount->mnt_flag & MNT_SYMPERM) { + error = VOP_ACCESS(ndp->ni_vp, VEXEC, state.cnp->cn_cred); + if (error != 0) + goto out; + } + if (state.ndp->ni_pathlen > 1) + cp = PNBUF_GET(); + else + cp = state.cnp->cn_pnbuf; + aiov.iov_base = cp; + aiov.iov_len = MAXPATHLEN; + auio.uio_iov = &aiov; + auio.uio_iovcnt = 1; + auio.uio_offset = 0; + auio.uio_rw = UIO_READ; + auio.uio_resid = MAXPATHLEN; + UIO_SETUP_SYSSPACE(&auio); + error = VOP_READLINK(ndp->ni_vp, &auio, state.cnp->cn_cred); + if (error) { +badlink: + if (ndp->ni_pathlen > 1) + PNBUF_PUT(cp); + goto out; + } + linklen = MAXPATHLEN - auio.uio_resid; + if (linklen == 0) { + error = ENOENT; + goto badlink; + } + if (linklen + ndp->ni_pathlen >= MAXPATHLEN) { + error = ENAMETOOLONG; + goto badlink; + } + if (ndp->ni_pathlen > 1) { + memcpy(cp + linklen, ndp->ni_next, ndp->ni_pathlen); + PNBUF_PUT(state.cnp->cn_pnbuf); + state.cnp->cn_pnbuf = cp; + } else + state.cnp->cn_pnbuf[linklen] = '\0'; + state.ndp->ni_pathlen += linklen; + vput(state.ndp->ni_vp); + dp = state.ndp->ni_dvp; + + /* + * Check if root directory should replace current directory. + */ + if (state.cnp->cn_pnbuf[0] == '/') { + vput(dp); + dp = ndp->ni_rootdir; + VREF(dp); + vn_lock(dp, LK_EXCLUSIVE | LK_RETRY); + } + } + + } + out: + vput(state.ndp->ni_vp); + vput(state.ndp->ni_dvp); + state.ndp->ni_vp = NULL; + PNBUF_PUT(state.cnp->cn_pnbuf); + + /* + * END wodge of code from nfsd + */ namei_cleanup(&state); return error; Index: src/sys/nfs/nfs_srvsubs.c diff -u src/sys/nfs/nfs_srvsubs.c:1.4 src/sys/nfs/nfs_srvsubs.c:1.5 --- src/sys/nfs/nfs_srvsubs.c:1.4 Sun Sep 27 17:19:07 2009 +++ src/sys/nfs/nfs_srvsubs.c Sun Sep 27 17:23:54 2009 @@ -1,4 +1,4 @@ -/* $NetBSD: nfs_srvsubs.c,v 1.4 2009/09/27 17:19:07 dholland Exp $ */ +/* $NetBSD: nfs_srvsubs.c,v 1.5 2009/09/27 17:23:54 dholland Exp $ */ /* * Copyright (c) 1989, 1993 @@ -70,7 +70,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: nfs_srvsubs.c,v 1.4 2009/09/27 17:19:07 dholland Exp $"); +__KERNEL_RCSID(0, "$NetBSD: nfs_srvsubs.c,v 1.5 2009/09/27 17:23:54 dholland Exp $"); #include <sys/param.h> #include <sys/proc.h> @@ -121,10 +121,9 @@ int i, rem; struct mbuf *md; char *fromcp, *tocp, *cp; - struct iovec aiov; - struct uio auio; struct vnode *dp; - int error, rdonly, linklen; + int error, rdonly; + int neverfollow; struct componentname *cnp = &ndp->ni_cnd; *retdirp = NULL; @@ -254,111 +253,17 @@ cnp->cn_flags |= NOCROSSMOUNT; } - VREF(dp); - vn_lock(dp, LK_EXCLUSIVE | LK_RETRY); - - for (;;) { - cnp->cn_nameptr = cnp->cn_pnbuf; - ndp->ni_startdir = dp; + neverfollow = !pubflag; /* * And call lookup() to do the real work */ - error = lookup_for_nfsd(ndp); + error = lookup_for_nfsd(ndp, dp, neverfollow); if (error) { - if (ndp->ni_dvp) { - vput(ndp->ni_dvp); - } - PNBUF_PUT(cnp->cn_pnbuf); return (error); } + return 0; - /* - * Check for encountering a symbolic link - */ - if ((cnp->cn_flags & ISSYMLINK) == 0) { - if ((cnp->cn_flags & LOCKPARENT) == 0 && ndp->ni_dvp) { - if (ndp->ni_dvp == ndp->ni_vp) { - vrele(ndp->ni_dvp); - } else { - vput(ndp->ni_dvp); - } - } - if (cnp->cn_flags & (SAVENAME | SAVESTART)) { - cnp->cn_flags |= HASBUF; - } else { - PNBUF_PUT(cnp->cn_pnbuf); -#if defined(DIAGNOSTIC) - cnp->cn_pnbuf = NULL; -#endif /* defined(DIAGNOSTIC) */ - } - return (0); - } else { - if (!pubflag) { - error = EINVAL; - break; - } - if (ndp->ni_loopcnt++ >= MAXSYMLINKS) { - error = ELOOP; - break; - } - if (ndp->ni_vp->v_mount->mnt_flag & MNT_SYMPERM) { - error = VOP_ACCESS(ndp->ni_vp, VEXEC, cnp->cn_cred); - if (error != 0) - break; - } - if (ndp->ni_pathlen > 1) - cp = PNBUF_GET(); - else - cp = cnp->cn_pnbuf; - aiov.iov_base = cp; - aiov.iov_len = MAXPATHLEN; - auio.uio_iov = &aiov; - auio.uio_iovcnt = 1; - auio.uio_offset = 0; - auio.uio_rw = UIO_READ; - auio.uio_resid = MAXPATHLEN; - UIO_SETUP_SYSSPACE(&auio); - error = VOP_READLINK(ndp->ni_vp, &auio, cnp->cn_cred); - if (error) { -badlink: - if (ndp->ni_pathlen > 1) - PNBUF_PUT(cp); - break; - } - linklen = MAXPATHLEN - auio.uio_resid; - if (linklen == 0) { - error = ENOENT; - goto badlink; - } - if (linklen + ndp->ni_pathlen >= MAXPATHLEN) { - error = ENAMETOOLONG; - goto badlink; - } - if (ndp->ni_pathlen > 1) { - memcpy(cp + linklen, ndp->ni_next, ndp->ni_pathlen); - PNBUF_PUT(cnp->cn_pnbuf); - cnp->cn_pnbuf = cp; - } else - cnp->cn_pnbuf[linklen] = '\0'; - ndp->ni_pathlen += linklen; - vput(ndp->ni_vp); - dp = ndp->ni_dvp; - - /* - * Check if root directory should replace current directory. - */ - if (cnp->cn_pnbuf[0] == '/') { - vput(dp); - dp = ndp->ni_rootdir; - VREF(dp); - vn_lock(dp, LK_EXCLUSIVE | LK_RETRY); - } - } - } - vput(ndp->ni_dvp); - vput(ndp->ni_vp); - ndp->ni_vp = NULL; out: PNBUF_PUT(cnp->cn_pnbuf); return (error); Index: src/sys/sys/namei.src diff -u src/sys/sys/namei.src:1.12 src/sys/sys/namei.src:1.13 --- src/sys/sys/namei.src:1.12 Sun Sep 27 17:19:07 2009 +++ src/sys/sys/namei.src Sun Sep 27 17:23:54 2009 @@ -1,4 +1,4 @@ -/* $NetBSD: namei.src,v 1.12 2009/09/27 17:19:07 dholland Exp $ */ +/* $NetBSD: namei.src,v 1.13 2009/09/27 17:23:54 dholland Exp $ */ /* * Copyright (c) 1985, 1989, 1991, 1993 @@ -228,7 +228,7 @@ int namei(struct nameidata *); uint32_t namei_hash(const char *, const char **); -int lookup_for_nfsd(struct nameidata *); +int lookup_for_nfsd(struct nameidata *, struct vnode *, int neverfollow); int lookup_for_nfsd_index(struct nameidata *); int relookup(struct vnode *, struct vnode **, struct componentname *); void cache_purge1(struct vnode *, const struct componentname *, int);