version 1.133, 2011/04/11 01:33:04 |
version 1.134, 2011/04/11 01:35:00 |
Line 591 namei_ktrace(struct namei_state *state) |
|
Line 591 namei_ktrace(struct namei_state *state) |
|
* appropriate. |
* appropriate. |
*/ |
*/ |
static int |
static int |
namei_start(struct namei_state *state, int isnfsd, struct vnode *forcecwd) |
namei_start(struct namei_state *state, struct vnode *forcecwd) |
{ |
{ |
struct nameidata *ndp = state->ndp; |
struct nameidata *ndp = state->ndp; |
|
|
Line 609 namei_start(struct namei_state *state, i |
|
Line 609 namei_start(struct namei_state *state, i |
|
ndp->ni_loopcnt = 0; |
ndp->ni_loopcnt = 0; |
|
|
/* Get starting directory, set up root, and ktrace. */ |
/* Get starting directory, set up root, and ktrace. */ |
if (isnfsd) { |
if (forcecwd != NULL) { |
state->namei_startdir = namei_getstartdir_for_nfsd(state, |
state->namei_startdir = namei_getstartdir_for_nfsd(state, |
forcecwd); |
forcecwd); |
/* no ktrace */ |
/* no ktrace */ |
Line 645 namei_atsymlink(struct namei_state *stat |
|
Line 645 namei_atsymlink(struct namei_state *stat |
|
* Follow a symlink. |
* Follow a symlink. |
*/ |
*/ |
static inline int |
static inline int |
namei_follow(struct namei_state *state) |
namei_follow(struct namei_state *state, int inhibitmagic) |
{ |
{ |
struct nameidata *ndp = state->ndp; |
struct nameidata *ndp = state->ndp; |
struct componentname *cnp = state->cnp; |
struct componentname *cnp = state->cnp; |
Line 690 namei_follow(struct namei_state *state) |
|
Line 690 namei_follow(struct namei_state *state) |
|
/* |
/* |
* Do symlink substitution, if appropriate, and |
* Do symlink substitution, if appropriate, and |
* check length for potential overflow. |
* check length for potential overflow. |
|
* |
|
* Inhibit symlink substitution for nfsd. |
|
* XXX: This is how it was before; is that a bug or a feature? |
*/ |
*/ |
if ((vfs_magiclinks && |
if ((!inhibitmagic && vfs_magiclinks && |
symlink_magic(self->l_proc, cp, &linklen)) || |
symlink_magic(self->l_proc, cp, &linklen)) || |
(linklen + ndp->ni_pathlen >= MAXPATHLEN)) { |
(linklen + ndp->ni_pathlen >= MAXPATHLEN)) { |
PNBUF_PUT(cp); |
PNBUF_PUT(cp); |
|
|
////////////////////////////// |
////////////////////////////// |
|
|
static int |
static int |
do_namei(struct namei_state *state) |
do_namei(struct namei_state *state, struct vnode *forcecwd, |
|
int neverfollow, int inhibitmagic) |
{ |
{ |
int error; |
int error; |
|
|
Line 1253 do_namei(struct namei_state *state) |
|
Line 1257 do_namei(struct namei_state *state) |
|
savepath = NULL; |
savepath = NULL; |
} |
} |
|
|
error = namei_start(state, 0/*not nfsd*/, NULL); |
error = namei_start(state, forcecwd); |
if (error) { |
if (error) { |
if (savepath != NULL) { |
if (savepath != NULL) { |
pathbuf_stringcopy_put(ndp->ni_pathbuf, savepath); |
pathbuf_stringcopy_put(ndp->ni_pathbuf, savepath); |
Line 1302 do_namei(struct namei_state *state) |
|
Line 1306 do_namei(struct namei_state *state) |
|
* aren't supposed to. |
* aren't supposed to. |
*/ |
*/ |
if (namei_atsymlink(state)) { |
if (namei_atsymlink(state)) { |
error = namei_follow(state); |
if (neverfollow) { |
|
error = EINVAL; |
|
} else { |
|
error = namei_follow(state, inhibitmagic); |
|
} |
if (error) { |
if (error) { |
KASSERT(ndp->ni_dvp != ndp->ni_vp); |
KASSERT(ndp->ni_dvp != ndp->ni_vp); |
vput(ndp->ni_dvp); |
vput(ndp->ni_dvp); |
Line 1349 namei(struct nameidata *ndp) |
|
Line 1357 namei(struct nameidata *ndp) |
|
int error; |
int error; |
|
|
namei_init(&state, ndp); |
namei_init(&state, ndp); |
error = do_namei(&state); |
error = do_namei(&state, NULL, 0/*!neverfollow*/, 0/*!inhibitmagic*/); |
namei_cleanup(&state); |
namei_cleanup(&state); |
|
|
return error; |
return error; |
Line 1366 namei(struct nameidata *ndp) |
|
Line 1374 namei(struct nameidata *ndp) |
|
* affecting the other. |
* affecting the other. |
*/ |
*/ |
|
|
int |
static int |
lookup_for_nfsd(struct nameidata *ndp, struct vnode *dp, int neverfollow) |
do_lookup_for_nfsd(struct namei_state *state, struct vnode *forcecwd, |
|
int neverfollow, int inhibitmagic) |
{ |
{ |
struct namei_state state; |
|
int error; |
int error; |
|
|
struct iovec aiov; |
struct nameidata *ndp = state->ndp; |
struct uio auio; |
//struct componentname *cnp = state->cnp; |
int linklen; |
|
char *cp; |
|
|
|
namei_init(&state, ndp); |
|
|
|
namei_start(&state, 1/*nfsd*/, dp); |
error = namei_start(state, forcecwd); |
|
if (error) { |
|
return error; |
|
} |
|
|
for (;;) { |
for (;;) { |
|
|
error = do_lookup(&state, dp); |
error = do_lookup(state, state->namei_startdir); |
|
|
if (error) { |
if (error) { |
/* BEGIN from nfsd */ |
|
if (ndp->ni_dvp) { |
if (ndp->ni_dvp) { |
vput(ndp->ni_dvp); |
vput(ndp->ni_dvp); |
} |
} |
/* END from nfsd */ |
|
namei_cleanup(&state); |
|
return error; |
return error; |
} |
} |
|
|
/* |
/* |
* BEGIN wodge of code from nfsd |
|
*/ |
|
|
|
/* |
|
* Check for encountering a symbolic link |
* Check for encountering a symbolic link |
*/ |
*/ |
if ((state.cnp->cn_flags & ISSYMLINK) == 0) { |
if (namei_atsymlink(state)) { |
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); |
|
} |
|
} |
|
return (0); |
|
} else { |
|
if (neverfollow) { |
if (neverfollow) { |
error = EINVAL; |
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; |
|
} |
|
cp = PNBUF_GET(); |
|
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) { |
|
PNBUF_PUT(cp); |
|
goto out; |
|
} |
|
linklen = MAXPATHLEN - auio.uio_resid; |
|
if (linklen == 0) { |
|
PNBUF_PUT(cp); |
|
error = ENOENT; |
|
goto out; |
|
} |
|
if (linklen + ndp->ni_pathlen >= MAXPATHLEN) { |
|
PNBUF_PUT(cp); |
|
error = ENAMETOOLONG; |
|
goto out; |
|
} |
|
if (ndp->ni_pathlen > 1) { |
|
/* includes a null-terminator */ |
|
memcpy(cp + linklen, ndp->ni_next, ndp->ni_pathlen); |
|
} else { |
} else { |
cp[linklen] = '\0'; |
error = namei_follow(state, inhibitmagic); |
} |
} |
state.ndp->ni_pathlen += linklen; |
if (error) { |
memcpy(state.ndp->ni_pnbuf, cp, state.ndp->ni_pathlen); |
KASSERT(ndp->ni_dvp != ndp->ni_vp); |
PNBUF_PUT(cp); |
vput(state->ndp->ni_vp); |
vput(state.ndp->ni_vp); |
vput(state->ndp->ni_dvp); |
dp = state.ndp->ni_dvp; |
state->ndp->ni_vp = NULL; |
|
return error; |
/* |
|
* Check if root directory should replace current directory. |
|
*/ |
|
if (state.ndp->ni_pnbuf[0] == '/') { |
|
vput(dp); |
|
dp = ndp->ni_rootdir; |
|
vref(dp); |
|
vn_lock(dp, LK_EXCLUSIVE | LK_RETRY); |
|
} |
} |
|
} else { |
|
break; |
} |
} |
|
} |
|
|
|
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); |
|
} |
} |
} |
out: |
return (0); |
vput(state.ndp->ni_vp); |
} |
vput(state.ndp->ni_dvp); |
|
state.ndp->ni_vp = NULL; |
|
|
|
/* |
int |
* END wodge of code from nfsd |
lookup_for_nfsd(struct nameidata *ndp, struct vnode *dp, int neverfollow) |
*/ |
{ |
|
struct namei_state state; |
|
int error; |
|
|
|
namei_init(&state, ndp); |
|
error = do_lookup_for_nfsd(&state, dp, neverfollow, 1/*inhibitmagic*/); |
namei_cleanup(&state); |
namei_cleanup(&state); |
|
|
return error; |
return error; |