diff options
Diffstat (limited to 'fs/open.c')
| -rw-r--r-- | fs/open.c | 63 | 
1 files changed, 37 insertions, 26 deletions
diff --git a/fs/open.c b/fs/open.c index 8c741002f947..fca72c4d3f17 100644 --- a/fs/open.c +++ b/fs/open.c @@ -840,11 +840,15 @@ static inline int build_open_flags(int flags, umode_t mode, struct open_flags *o  	if (flags & __O_SYNC)  		flags |= O_DSYNC; -	/* -	 * If we have O_PATH in the open flag. Then we -	 * cannot have anything other than the below set of flags -	 */ -	if (flags & O_PATH) { +	if (flags & O_TMPFILE) { +		if (!(flags & O_CREAT)) +			return -EINVAL; +		acc_mode = MAY_OPEN | ACC_MODE(flags); +	} else if (flags & O_PATH) { +		/* +		 * If we have O_PATH in the open flag. Then we +		 * cannot have anything other than the below set of flags +		 */  		flags &= O_DIRECTORY | O_NOFOLLOW | O_PATH;  		acc_mode = 0;  	} else { @@ -876,7 +880,8 @@ static inline int build_open_flags(int flags, umode_t mode, struct open_flags *o  		lookup_flags |= LOOKUP_DIRECTORY;  	if (!(flags & O_NOFOLLOW))  		lookup_flags |= LOOKUP_FOLLOW; -	return lookup_flags; +	op->lookup_flags = lookup_flags; +	return 0;  }  /** @@ -893,8 +898,8 @@ static inline int build_open_flags(int flags, umode_t mode, struct open_flags *o  struct file *file_open_name(struct filename *name, int flags, umode_t mode)  {  	struct open_flags op; -	int lookup = build_open_flags(flags, mode, &op); -	return do_filp_open(AT_FDCWD, name, &op, lookup); +	int err = build_open_flags(flags, mode, &op); +	return err ? ERR_PTR(err) : do_filp_open(AT_FDCWD, name, &op);  }  /** @@ -919,37 +924,43 @@ struct file *file_open_root(struct dentry *dentry, struct vfsmount *mnt,  			    const char *filename, int flags)  {  	struct open_flags op; -	int lookup = build_open_flags(flags, 0, &op); +	int err = build_open_flags(flags, 0, &op); +	if (err) +		return ERR_PTR(err);  	if (flags & O_CREAT)  		return ERR_PTR(-EINVAL);  	if (!filename && (flags & O_DIRECTORY))  		if (!dentry->d_inode->i_op->lookup)  			return ERR_PTR(-ENOTDIR); -	return do_file_open_root(dentry, mnt, filename, &op, lookup); +	return do_file_open_root(dentry, mnt, filename, &op);  }  EXPORT_SYMBOL(file_open_root);  long do_sys_open(int dfd, const char __user *filename, int flags, umode_t mode)  {  	struct open_flags op; -	int lookup = build_open_flags(flags, mode, &op); -	struct filename *tmp = getname(filename); -	int fd = PTR_ERR(tmp); - -	if (!IS_ERR(tmp)) { -		fd = get_unused_fd_flags(flags); -		if (fd >= 0) { -			struct file *f = do_filp_open(dfd, tmp, &op, lookup); -			if (IS_ERR(f)) { -				put_unused_fd(fd); -				fd = PTR_ERR(f); -			} else { -				fsnotify_open(f); -				fd_install(fd, f); -			} +	int fd = build_open_flags(flags, mode, &op); +	struct filename *tmp; + +	if (fd) +		return fd; + +	tmp = getname(filename); +	if (IS_ERR(tmp)) +		return PTR_ERR(tmp); + +	fd = get_unused_fd_flags(flags); +	if (fd >= 0) { +		struct file *f = do_filp_open(dfd, tmp, &op); +		if (IS_ERR(f)) { +			put_unused_fd(fd); +			fd = PTR_ERR(f); +		} else { +			fsnotify_open(f); +			fd_install(fd, f);  		} -		putname(tmp);  	} +	putname(tmp);  	return fd;  }  | 

