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.
This commit is contained in:
parent
a3c0999baa
commit
8d36057243
@ -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 @@ As of this writing the internal function
|
||||
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 @@ Its semantics are similar to the historic
|
||||
.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
|
||||
|
@ -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 @@ bad:
|
||||
*/
|
||||
|
||||
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;
|
||||
|
@ -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 @@ nfs_namei(struct nameidata *ndp, nfsrvfh_t *nsfh, uint32_t len, struct nfssvc_so
|
||||
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 @@ nfs_namei(struct nameidata *ndp, nfsrvfh_t *nsfh, uint32_t len, struct nfssvc_so
|
||||
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);
|
||||
|
@ -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_simple_user(const char *, namei_simple_flags_t, struct vnode **);
|
||||
|
||||
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);
|
||||
|
Loading…
Reference in New Issue
Block a user