[PATCH] new (local) helper: user_path_parent()

Preparation to untangling intents mess: reduce the number of do_path_lookup()
callers.

Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
This commit is contained in:
Al Viro 2008-07-21 09:32:51 -04:00
parent 2d8f30380a
commit 2ad94ae654
1 changed files with 57 additions and 80 deletions

View File

@ -1352,6 +1352,24 @@ int user_path_at(int dfd, const char __user *name, unsigned flags,
return err; return err;
} }
static int user_path_parent(int dfd, const char __user *path,
struct nameidata *nd, char **name)
{
char *s = getname(path);
int error;
if (IS_ERR(s))
return PTR_ERR(s);
error = do_path_lookup(dfd, s, LOOKUP_PARENT, nd);
if (error)
putname(s);
else
*name = s;
return error;
}
/* /*
* It's inline, so penalty for filesystems that don't use sticky bit is * It's inline, so penalty for filesystems that don't use sticky bit is
* minimal. * minimal.
@ -1989,20 +2007,18 @@ static int may_mknod(mode_t mode)
asmlinkage long sys_mknodat(int dfd, const char __user *filename, int mode, asmlinkage long sys_mknodat(int dfd, const char __user *filename, int mode,
unsigned dev) unsigned dev)
{ {
int error = 0; int error;
char * tmp; char *tmp;
struct dentry * dentry; struct dentry *dentry;
struct nameidata nd; struct nameidata nd;
if (S_ISDIR(mode)) if (S_ISDIR(mode))
return -EPERM; return -EPERM;
tmp = getname(filename);
if (IS_ERR(tmp))
return PTR_ERR(tmp);
error = do_path_lookup(dfd, tmp, LOOKUP_PARENT, &nd); error = user_path_parent(dfd, filename, &nd, &tmp);
if (error) if (error)
goto out; return error;
dentry = lookup_create(&nd, 0); dentry = lookup_create(&nd, 0);
if (IS_ERR(dentry)) { if (IS_ERR(dentry)) {
error = PTR_ERR(dentry); error = PTR_ERR(dentry);
@ -2034,7 +2050,6 @@ out_dput:
out_unlock: out_unlock:
mutex_unlock(&nd.path.dentry->d_inode->i_mutex); mutex_unlock(&nd.path.dentry->d_inode->i_mutex);
path_put(&nd.path); path_put(&nd.path);
out:
putname(tmp); putname(tmp);
return error; return error;
@ -2074,14 +2089,10 @@ asmlinkage long sys_mkdirat(int dfd, const char __user *pathname, int mode)
struct dentry *dentry; struct dentry *dentry;
struct nameidata nd; struct nameidata nd;
tmp = getname(pathname); error = user_path_parent(dfd, pathname, &nd, &tmp);
error = PTR_ERR(tmp); if (error)
if (IS_ERR(tmp))
goto out_err; goto out_err;
error = do_path_lookup(dfd, tmp, LOOKUP_PARENT, &nd);
if (error)
goto out;
dentry = lookup_create(&nd, 1); dentry = lookup_create(&nd, 1);
error = PTR_ERR(dentry); error = PTR_ERR(dentry);
if (IS_ERR(dentry)) if (IS_ERR(dentry))
@ -2099,7 +2110,6 @@ out_dput:
out_unlock: out_unlock:
mutex_unlock(&nd.path.dentry->d_inode->i_mutex); mutex_unlock(&nd.path.dentry->d_inode->i_mutex);
path_put(&nd.path); path_put(&nd.path);
out:
putname(tmp); putname(tmp);
out_err: out_err:
return error; return error;
@ -2177,13 +2187,9 @@ static long do_rmdir(int dfd, const char __user *pathname)
struct dentry *dentry; struct dentry *dentry;
struct nameidata nd; struct nameidata nd;
name = getname(pathname); error = user_path_parent(dfd, pathname, &nd, &name);
if(IS_ERR(name))
return PTR_ERR(name);
error = do_path_lookup(dfd, name, LOOKUP_PARENT, &nd);
if (error) if (error)
goto exit; return error;
switch(nd.last_type) { switch(nd.last_type) {
case LAST_DOTDOT: case LAST_DOTDOT:
@ -2212,7 +2218,6 @@ exit2:
mutex_unlock(&nd.path.dentry->d_inode->i_mutex); mutex_unlock(&nd.path.dentry->d_inode->i_mutex);
exit1: exit1:
path_put(&nd.path); path_put(&nd.path);
exit:
putname(name); putname(name);
return error; return error;
} }
@ -2261,19 +2266,16 @@ int vfs_unlink(struct inode *dir, struct dentry *dentry)
*/ */
static long do_unlinkat(int dfd, const char __user *pathname) static long do_unlinkat(int dfd, const char __user *pathname)
{ {
int error = 0; int error;
char * name; char *name;
struct dentry *dentry; struct dentry *dentry;
struct nameidata nd; struct nameidata nd;
struct inode *inode = NULL; struct inode *inode = NULL;
name = getname(pathname); error = user_path_parent(dfd, pathname, &nd, &name);
if(IS_ERR(name))
return PTR_ERR(name);
error = do_path_lookup(dfd, name, LOOKUP_PARENT, &nd);
if (error) if (error)
goto exit; return error;
error = -EISDIR; error = -EISDIR;
if (nd.last_type != LAST_NORM) if (nd.last_type != LAST_NORM)
goto exit1; goto exit1;
@ -2300,7 +2302,6 @@ static long do_unlinkat(int dfd, const char __user *pathname)
iput(inode); /* truncate the inode here */ iput(inode); /* truncate the inode here */
exit1: exit1:
path_put(&nd.path); path_put(&nd.path);
exit:
putname(name); putname(name);
return error; return error;
@ -2350,23 +2351,20 @@ int vfs_symlink(struct inode *dir, struct dentry *dentry, const char *oldname)
asmlinkage long sys_symlinkat(const char __user *oldname, asmlinkage long sys_symlinkat(const char __user *oldname,
int newdfd, const char __user *newname) int newdfd, const char __user *newname)
{ {
int error = 0; int error;
char * from; char *from;
char * to; char *to;
struct dentry *dentry; struct dentry *dentry;
struct nameidata nd; struct nameidata nd;
from = getname(oldname); from = getname(oldname);
if(IS_ERR(from)) if (IS_ERR(from))
return PTR_ERR(from); return PTR_ERR(from);
to = getname(newname);
error = PTR_ERR(to); error = user_path_parent(newdfd, newname, &nd, &to);
if (IS_ERR(to)) if (error)
goto out_putname; goto out_putname;
error = do_path_lookup(newdfd, to, LOOKUP_PARENT, &nd);
if (error)
goto out;
dentry = lookup_create(&nd, 0); dentry = lookup_create(&nd, 0);
error = PTR_ERR(dentry); error = PTR_ERR(dentry);
if (IS_ERR(dentry)) if (IS_ERR(dentry))
@ -2382,7 +2380,6 @@ out_dput:
out_unlock: out_unlock:
mutex_unlock(&nd.path.dentry->d_inode->i_mutex); mutex_unlock(&nd.path.dentry->d_inode->i_mutex);
path_put(&nd.path); path_put(&nd.path);
out:
putname(to); putname(to);
out_putname: out_putname:
putname(from); putname(from);
@ -2449,21 +2446,18 @@ asmlinkage long sys_linkat(int olddfd, const char __user *oldname,
struct nameidata nd; struct nameidata nd;
struct path old_path; struct path old_path;
int error; int error;
char * to; char *to;
if ((flags & ~AT_SYMLINK_FOLLOW) != 0) if ((flags & ~AT_SYMLINK_FOLLOW) != 0)
return -EINVAL; return -EINVAL;
to = getname(newname);
if (IS_ERR(to))
return PTR_ERR(to);
error = user_path_at(olddfd, oldname, error = user_path_at(olddfd, oldname,
flags & AT_SYMLINK_FOLLOW ? LOOKUP_FOLLOW : 0, flags & AT_SYMLINK_FOLLOW ? LOOKUP_FOLLOW : 0,
&old_path); &old_path);
if (error) if (error)
goto exit; return error;
error = do_path_lookup(newdfd, to, LOOKUP_PARENT, &nd);
error = user_path_parent(newdfd, newname, &nd, &to);
if (error) if (error)
goto out; goto out;
error = -EXDEV; error = -EXDEV;
@ -2484,10 +2478,9 @@ out_unlock:
mutex_unlock(&nd.path.dentry->d_inode->i_mutex); mutex_unlock(&nd.path.dentry->d_inode->i_mutex);
out_release: out_release:
path_put(&nd.path); path_put(&nd.path);
putname(to);
out: out:
path_put(&old_path); path_put(&old_path);
exit:
putname(to);
return error; return error;
} }
@ -2643,20 +2636,22 @@ int vfs_rename(struct inode *old_dir, struct dentry *old_dentry,
return error; return error;
} }
static int do_rename(int olddfd, const char *oldname, asmlinkage long sys_renameat(int olddfd, const char __user *oldname,
int newdfd, const char *newname) int newdfd, const char __user *newname)
{ {
int error = 0; struct dentry *old_dir, *new_dir;
struct dentry * old_dir, * new_dir; struct dentry *old_dentry, *new_dentry;
struct dentry * old_dentry, *new_dentry; struct dentry *trap;
struct dentry * trap;
struct nameidata oldnd, newnd; struct nameidata oldnd, newnd;
char *from;
char *to;
int error;
error = do_path_lookup(olddfd, oldname, LOOKUP_PARENT, &oldnd); error = user_path_parent(olddfd, oldname, &oldnd, &from);
if (error) if (error)
goto exit; goto exit;
error = do_path_lookup(newdfd, newname, LOOKUP_PARENT, &newnd); error = user_path_parent(newdfd, newname, &newnd, &to);
if (error) if (error)
goto exit1; goto exit1;
@ -2718,29 +2713,11 @@ exit3:
unlock_rename(new_dir, old_dir); unlock_rename(new_dir, old_dir);
exit2: exit2:
path_put(&newnd.path); path_put(&newnd.path);
putname(to);
exit1: exit1:
path_put(&oldnd.path); path_put(&oldnd.path);
exit:
return error;
}
asmlinkage long sys_renameat(int olddfd, const char __user *oldname,
int newdfd, const char __user *newname)
{
int error;
char * from;
char * to;
from = getname(oldname);
if(IS_ERR(from))
return PTR_ERR(from);
to = getname(newname);
error = PTR_ERR(to);
if (!IS_ERR(to)) {
error = do_rename(olddfd, from, newdfd, to);
putname(to);
}
putname(from); putname(from);
exit:
return error; return error;
} }