diff options
author | Al Viro <viro@zeniv.linux.org.uk> | 2016-04-26 06:02:50 +0200 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2016-05-03 01:49:33 +0200 |
commit | 6ac087099edf09ca357e2f765e3e24677543897c (patch) | |
tree | 56dc485b6e28fba20710486a17b8025a690c876c /fs/namei.c | |
parent | simple local filesystems: switch to ->iterate_shared() (diff) | |
download | linux-6ac087099edf09ca357e2f765e3e24677543897c.tar.xz linux-6ac087099edf09ca357e2f765e3e24677543897c.zip |
path_openat(): take O_PATH handling out of do_last()
do_last() and lookup_open() simpler that way and so does O_PATH
itself. As it bloody well should: we find what the pathname
resolves to, same way as in stat() et.al. and associate it with
FMODE_PATH struct file.
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'fs/namei.c')
-rw-r--r-- | fs/namei.c | 31 |
1 files changed, 24 insertions, 7 deletions
diff --git a/fs/namei.c b/fs/namei.c index 8249852b5fc6..8145b415e257 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -3019,7 +3019,7 @@ static int lookup_open(struct nameidata *nd, struct path *path, goto out_no_open; } - if ((nd->flags & LOOKUP_OPEN) && dir_inode->i_op->atomic_open) { + if (dir_inode->i_op->atomic_open) { return atomic_open(nd, dentry, path, file, op, got_write, need_lookup, opened); } @@ -3219,7 +3219,7 @@ finish_open: return error; } audit_inode(nd->name, nd->path.dentry, 0); - if (unlikely(d_is_symlink(nd->path.dentry)) && !(open_flag & O_PATH)) { + if (unlikely(d_is_symlink(nd->path.dentry))) { error = -ELOOP; goto out; } @@ -3239,11 +3239,9 @@ finish_open: got_write = true; } finish_open_created: - if (likely(!(open_flag & O_PATH))) { - error = may_open(&nd->path, acc_mode, open_flag); - if (error) - goto out; - } + error = may_open(&nd->path, acc_mode, open_flag); + if (error) + goto out; BUG_ON(*opened & FILE_OPENED); /* once it's opened, it's opened */ error = vfs_open(&nd->path, file, current_cred()); if (!error) { @@ -3357,6 +3355,18 @@ out: return error; } +static int do_o_path(struct nameidata *nd, unsigned flags, struct file *file) +{ + struct path path; + int error = path_lookupat(nd, flags, &path); + if (!error) { + audit_inode(nd->name, path.dentry, 0); + error = vfs_open(&path, file, current_cred()); + path_put(&path); + } + return error; +} + static struct file *path_openat(struct nameidata *nd, const struct open_flags *op, unsigned flags) { @@ -3376,6 +3386,13 @@ static struct file *path_openat(struct nameidata *nd, goto out2; } + if (unlikely(file->f_flags & O_PATH)) { + error = do_o_path(nd, flags, file); + if (!error) + opened |= FILE_OPENED; + goto out2; + } + s = path_init(nd, flags); if (IS_ERR(s)) { put_filp(file); |