diff options
| author | Al Viro <viro@zeniv.linux.org.uk> | 2013-06-11 00:23:01 -0400 |
|---|---|---|
| committer | Al Viro <viro@zeniv.linux.org.uk> | 2013-06-29 04:57:09 -0400 |
| commit | f9652e10c12b43d9bb957269745cf2fa5682fa92 (patch) | |
| tree | fd358891b9778f7bdd8764163aa2029d01efcf9c | |
| parent | 50cd2c577668a170750b15f9a88f022f681ce3c7 (diff) | |
allow build_open_flags() to return an error
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
| -rw-r--r-- | fs/exec.c | 10 | ||||
| -rw-r--r-- | fs/internal.h | 5 | ||||
| -rw-r--r-- | fs/namei.c | 8 | ||||
| -rw-r--r-- | fs/open.c | 49 |
4 files changed, 41 insertions, 31 deletions
| @@ -110,13 +110,14 @@ SYSCALL_DEFINE1(uselib, const char __user *, library) | |||
| 110 | static const struct open_flags uselib_flags = { | 110 | static const struct open_flags uselib_flags = { |
| 111 | .open_flag = O_LARGEFILE | O_RDONLY | __FMODE_EXEC, | 111 | .open_flag = O_LARGEFILE | O_RDONLY | __FMODE_EXEC, |
| 112 | .acc_mode = MAY_READ | MAY_EXEC | MAY_OPEN, | 112 | .acc_mode = MAY_READ | MAY_EXEC | MAY_OPEN, |
| 113 | .intent = LOOKUP_OPEN | 113 | .intent = LOOKUP_OPEN, |
| 114 | .lookup_flags = LOOKUP_FOLLOW, | ||
| 114 | }; | 115 | }; |
| 115 | 116 | ||
| 116 | if (IS_ERR(tmp)) | 117 | if (IS_ERR(tmp)) |
| 117 | goto out; | 118 | goto out; |
| 118 | 119 | ||
| 119 | file = do_filp_open(AT_FDCWD, tmp, &uselib_flags, LOOKUP_FOLLOW); | 120 | file = do_filp_open(AT_FDCWD, tmp, &uselib_flags); |
| 120 | putname(tmp); | 121 | putname(tmp); |
| 121 | error = PTR_ERR(file); | 122 | error = PTR_ERR(file); |
| 122 | if (IS_ERR(file)) | 123 | if (IS_ERR(file)) |
| @@ -756,10 +757,11 @@ struct file *open_exec(const char *name) | |||
| 756 | static const struct open_flags open_exec_flags = { | 757 | static const struct open_flags open_exec_flags = { |
| 757 | .open_flag = O_LARGEFILE | O_RDONLY | __FMODE_EXEC, | 758 | .open_flag = O_LARGEFILE | O_RDONLY | __FMODE_EXEC, |
| 758 | .acc_mode = MAY_EXEC | MAY_OPEN, | 759 | .acc_mode = MAY_EXEC | MAY_OPEN, |
| 759 | .intent = LOOKUP_OPEN | 760 | .intent = LOOKUP_OPEN, |
| 761 | .lookup_flags = LOOKUP_FOLLOW, | ||
| 760 | }; | 762 | }; |
| 761 | 763 | ||
| 762 | file = do_filp_open(AT_FDCWD, &tmp, &open_exec_flags, LOOKUP_FOLLOW); | 764 | file = do_filp_open(AT_FDCWD, &tmp, &open_exec_flags); |
| 763 | if (IS_ERR(file)) | 765 | if (IS_ERR(file)) |
| 764 | goto out; | 766 | goto out; |
| 765 | 767 | ||
diff --git a/fs/internal.h b/fs/internal.h index 68121584ae37..f6ad34362823 100644 --- a/fs/internal.h +++ b/fs/internal.h | |||
| @@ -96,11 +96,12 @@ struct open_flags { | |||
| 96 | umode_t mode; | 96 | umode_t mode; |
| 97 | int acc_mode; | 97 | int acc_mode; |
| 98 | int intent; | 98 | int intent; |
| 99 | int lookup_flags; | ||
| 99 | }; | 100 | }; |
| 100 | extern struct file *do_filp_open(int dfd, struct filename *pathname, | 101 | extern struct file *do_filp_open(int dfd, struct filename *pathname, |
| 101 | const struct open_flags *op, int flags); | 102 | const struct open_flags *op); |
| 102 | extern struct file *do_file_open_root(struct dentry *, struct vfsmount *, | 103 | extern struct file *do_file_open_root(struct dentry *, struct vfsmount *, |
| 103 | const char *, const struct open_flags *, int lookup_flags); | 104 | const char *, const struct open_flags *); |
| 104 | 105 | ||
| 105 | extern long do_handle_open(int mountdirfd, | 106 | extern long do_handle_open(int mountdirfd, |
| 106 | struct file_handle __user *ufh, int open_flag); | 107 | struct file_handle __user *ufh, int open_flag); |
diff --git a/fs/namei.c b/fs/namei.c index 1bc7b7582a66..402eda351d07 100644 --- a/fs/namei.c +++ b/fs/namei.c | |||
| @@ -2969,9 +2969,10 @@ out: | |||
| 2969 | } | 2969 | } |
| 2970 | 2970 | ||
| 2971 | struct file *do_filp_open(int dfd, struct filename *pathname, | 2971 | struct file *do_filp_open(int dfd, struct filename *pathname, |
| 2972 | const struct open_flags *op, int flags) | 2972 | const struct open_flags *op) |
| 2973 | { | 2973 | { |
| 2974 | struct nameidata nd; | 2974 | struct nameidata nd; |
| 2975 | int flags = op->lookup_flags; | ||
| 2975 | struct file *filp; | 2976 | struct file *filp; |
| 2976 | 2977 | ||
| 2977 | filp = path_openat(dfd, pathname, &nd, op, flags | LOOKUP_RCU); | 2978 | filp = path_openat(dfd, pathname, &nd, op, flags | LOOKUP_RCU); |
| @@ -2983,17 +2984,16 @@ struct file *do_filp_open(int dfd, struct filename *pathname, | |||
| 2983 | } | 2984 | } |
| 2984 | 2985 | ||
| 2985 | struct file *do_file_open_root(struct dentry *dentry, struct vfsmount *mnt, | 2986 | struct file *do_file_open_root(struct dentry *dentry, struct vfsmount *mnt, |
| 2986 | const char *name, const struct open_flags *op, int flags) | 2987 | const char *name, const struct open_flags *op) |
| 2987 | { | 2988 | { |
| 2988 | struct nameidata nd; | 2989 | struct nameidata nd; |
| 2989 | struct file *file; | 2990 | struct file *file; |
| 2990 | struct filename filename = { .name = name }; | 2991 | struct filename filename = { .name = name }; |
| 2992 | int flags = op->lookup_flags | LOOKUP_ROOT; | ||
| 2991 | 2993 | ||
| 2992 | nd.root.mnt = mnt; | 2994 | nd.root.mnt = mnt; |
| 2993 | nd.root.dentry = dentry; | 2995 | nd.root.dentry = dentry; |
| 2994 | 2996 | ||
| 2995 | flags |= LOOKUP_ROOT; | ||
| 2996 | |||
| 2997 | if (dentry->d_inode->i_op->follow_link && op->intent & LOOKUP_OPEN) | 2997 | if (dentry->d_inode->i_op->follow_link && op->intent & LOOKUP_OPEN) |
| 2998 | return ERR_PTR(-ELOOP); | 2998 | return ERR_PTR(-ELOOP); |
| 2999 | 2999 | ||
| @@ -876,7 +876,8 @@ static inline int build_open_flags(int flags, umode_t mode, struct open_flags *o | |||
| 876 | lookup_flags |= LOOKUP_DIRECTORY; | 876 | lookup_flags |= LOOKUP_DIRECTORY; |
| 877 | if (!(flags & O_NOFOLLOW)) | 877 | if (!(flags & O_NOFOLLOW)) |
| 878 | lookup_flags |= LOOKUP_FOLLOW; | 878 | lookup_flags |= LOOKUP_FOLLOW; |
| 879 | return lookup_flags; | 879 | op->lookup_flags = lookup_flags; |
| 880 | return 0; | ||
| 880 | } | 881 | } |
| 881 | 882 | ||
| 882 | /** | 883 | /** |
| @@ -893,8 +894,8 @@ static inline int build_open_flags(int flags, umode_t mode, struct open_flags *o | |||
| 893 | struct file *file_open_name(struct filename *name, int flags, umode_t mode) | 894 | struct file *file_open_name(struct filename *name, int flags, umode_t mode) |
| 894 | { | 895 | { |
| 895 | struct open_flags op; | 896 | struct open_flags op; |
| 896 | int lookup = build_open_flags(flags, mode, &op); | 897 | int err = build_open_flags(flags, mode, &op); |
| 897 | return do_filp_open(AT_FDCWD, name, &op, lookup); | 898 | return err ? ERR_PTR(err) : do_filp_open(AT_FDCWD, name, &op); |
| 898 | } | 899 | } |
| 899 | 900 | ||
| 900 | /** | 901 | /** |
| @@ -919,37 +920,43 @@ struct file *file_open_root(struct dentry *dentry, struct vfsmount *mnt, | |||
| 919 | const char *filename, int flags) | 920 | const char *filename, int flags) |
| 920 | { | 921 | { |
| 921 | struct open_flags op; | 922 | struct open_flags op; |
| 922 | int lookup = build_open_flags(flags, 0, &op); | 923 | int err = build_open_flags(flags, 0, &op); |
| 924 | if (err) | ||
| 925 | return ERR_PTR(err); | ||
| 923 | if (flags & O_CREAT) | 926 | if (flags & O_CREAT) |
| 924 | return ERR_PTR(-EINVAL); | 927 | return ERR_PTR(-EINVAL); |
| 925 | if (!filename && (flags & O_DIRECTORY)) | 928 | if (!filename && (flags & O_DIRECTORY)) |
| 926 | if (!dentry->d_inode->i_op->lookup) | 929 | if (!dentry->d_inode->i_op->lookup) |
| 927 | return ERR_PTR(-ENOTDIR); | 930 | return ERR_PTR(-ENOTDIR); |
| 928 | return do_file_open_root(dentry, mnt, filename, &op, lookup); | 931 | return do_file_open_root(dentry, mnt, filename, &op); |
| 929 | } | 932 | } |
| 930 | EXPORT_SYMBOL(file_open_root); | 933 | EXPORT_SYMBOL(file_open_root); |
| 931 | 934 | ||
| 932 | long do_sys_open(int dfd, const char __user *filename, int flags, umode_t mode) | 935 | long do_sys_open(int dfd, const char __user *filename, int flags, umode_t mode) |
| 933 | { | 936 | { |
| 934 | struct open_flags op; | 937 | struct open_flags op; |
| 935 | int lookup = build_open_flags(flags, mode, &op); | 938 | int fd = build_open_flags(flags, mode, &op); |
| 936 | struct filename *tmp = getname(filename); | 939 | struct filename *tmp; |
| 937 | int fd = PTR_ERR(tmp); | 940 | |
| 938 | 941 | if (fd) | |
| 939 | if (!IS_ERR(tmp)) { | 942 | return fd; |
| 940 | fd = get_unused_fd_flags(flags); | 943 | |
| 941 | if (fd >= 0) { | 944 | tmp = getname(filename); |
| 942 | struct file *f = do_filp_open(dfd, tmp, &op, lookup); | 945 | if (IS_ERR(tmp)) |
| 943 | if (IS_ERR(f)) { | 946 | return PTR_ERR(tmp); |
| 944 | put_unused_fd(fd); | 947 | |
| 945 | fd = PTR_ERR(f); | 948 | fd = get_unused_fd_flags(flags); |
| 946 | } else { | 949 | if (fd >= 0) { |
| 947 | fsnotify_open(f); | 950 | struct file *f = do_filp_open(dfd, tmp, &op); |
| 948 | fd_install(fd, f); | 951 | if (IS_ERR(f)) { |
| 949 | } | 952 | put_unused_fd(fd); |
| 953 | fd = PTR_ERR(f); | ||
| 954 | } else { | ||
| 955 | fsnotify_open(f); | ||
| 956 | fd_install(fd, f); | ||
| 950 | } | 957 | } |
| 951 | putname(tmp); | ||
| 952 | } | 958 | } |
| 959 | putname(tmp); | ||
| 953 | return fd; | 960 | return fd; |
| 954 | } | 961 | } |
| 955 | 962 | ||
