aboutsummaryrefslogtreecommitdiffstats
path: root/fs/open.c
diff options
context:
space:
mode:
authorAl Viro <viro@zeniv.linux.org.uk>2011-03-13 03:51:11 -0400
committerAl Viro <viro@zeniv.linux.org.uk>2011-03-15 02:21:45 -0400
commit1abf0c718f15a56a0a435588d1b104c7a37dc9bd (patch)
tree91a6fae3218686b9a945569a7fa7fad120f64e94 /fs/open.c
parentf2fa2ffc2046fdc35f96366d1ec8675f4d578522 (diff)
New kind of open files - "location only".
New flag for open(2) - O_PATH. Semantics: * pathname is resolved, but the file itself is _NOT_ opened as far as filesystem is concerned. * almost all operations on the resulting descriptors shall fail with -EBADF. Exceptions are: 1) operations on descriptors themselves (i.e. close(), dup(), dup2(), dup3(), fcntl(fd, F_DUPFD), fcntl(fd, F_DUPFD_CLOEXEC, ...), fcntl(fd, F_GETFD), fcntl(fd, F_SETFD, ...)) 2) fcntl(fd, F_GETFL), for a common non-destructive way to check if descriptor is open 3) "dfd" arguments of ...at(2) syscalls, i.e. the starting points of pathname resolution * closing such descriptor does *NOT* affect dnotify or posix locks. * permissions are checked as usual along the way to file; no permission checks are applied to the file itself. Of course, giving such thing to syscall will result in permission checks (at the moment it means checking that starting point of ....at() is a directory and caller has exec permissions on it). fget() and fget_light() return NULL on such descriptors; use of fget_raw() and fget_raw_light() is needed to get them. That protects existing code from dealing with those things. There are two things still missing (they come in the next commits): one is handling of symlinks (right now we refuse to open them that way; see the next commit for semantics related to those) and another is descriptor passing via SCM_RIGHTS datagrams. Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'fs/open.c')
-rw-r--r--fs/open.c35
1 files changed, 29 insertions, 6 deletions
diff --git a/fs/open.c b/fs/open.c
index 48afc5c139d2..14a51de01f54 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -669,11 +669,16 @@ static struct file *__dentry_open(struct dentry *dentry, struct vfsmount *mnt,
669 int (*open)(struct inode *, struct file *), 669 int (*open)(struct inode *, struct file *),
670 const struct cred *cred) 670 const struct cred *cred)
671{ 671{
672 static const struct file_operations empty_fops = {};
672 struct inode *inode; 673 struct inode *inode;
673 int error; 674 int error;
674 675
675 f->f_mode = OPEN_FMODE(f->f_flags) | FMODE_LSEEK | 676 f->f_mode = OPEN_FMODE(f->f_flags) | FMODE_LSEEK |
676 FMODE_PREAD | FMODE_PWRITE; 677 FMODE_PREAD | FMODE_PWRITE;
678
679 if (unlikely(f->f_flags & O_PATH))
680 f->f_mode = FMODE_PATH;
681
677 inode = dentry->d_inode; 682 inode = dentry->d_inode;
678 if (f->f_mode & FMODE_WRITE) { 683 if (f->f_mode & FMODE_WRITE) {
679 error = __get_file_write_access(inode, mnt); 684 error = __get_file_write_access(inode, mnt);
@@ -687,9 +692,15 @@ static struct file *__dentry_open(struct dentry *dentry, struct vfsmount *mnt,
687 f->f_path.dentry = dentry; 692 f->f_path.dentry = dentry;
688 f->f_path.mnt = mnt; 693 f->f_path.mnt = mnt;
689 f->f_pos = 0; 694 f->f_pos = 0;
690 f->f_op = fops_get(inode->i_fop);
691 file_sb_list_add(f, inode->i_sb); 695 file_sb_list_add(f, inode->i_sb);
692 696
697 if (unlikely(f->f_mode & FMODE_PATH)) {
698 f->f_op = &empty_fops;
699 return f;
700 }
701
702 f->f_op = fops_get(inode->i_fop);
703
693 error = security_dentry_open(f, cred); 704 error = security_dentry_open(f, cred);
694 if (error) 705 if (error)
695 goto cleanup_all; 706 goto cleanup_all;
@@ -911,9 +922,18 @@ static inline int build_open_flags(int flags, int mode, struct open_flags *op)
911 if (flags & __O_SYNC) 922 if (flags & __O_SYNC)
912 flags |= O_DSYNC; 923 flags |= O_DSYNC;
913 924
914 op->open_flag = flags; 925 /*
926 * If we have O_PATH in the open flag. Then we
927 * cannot have anything other than the below set of flags
928 */
929 if (flags & O_PATH) {
930 flags &= O_DIRECTORY | O_NOFOLLOW | O_PATH;
931 acc_mode = 0;
932 } else {
933 acc_mode = MAY_OPEN | ACC_MODE(flags);
934 }
915 935
916 acc_mode = MAY_OPEN | ACC_MODE(flags); 936 op->open_flag = flags;
917 937
918 /* O_TRUNC implies we need access checks for write permissions */ 938 /* O_TRUNC implies we need access checks for write permissions */
919 if (flags & O_TRUNC) 939 if (flags & O_TRUNC)
@@ -926,7 +946,8 @@ static inline int build_open_flags(int flags, int mode, struct open_flags *op)
926 946
927 op->acc_mode = acc_mode; 947 op->acc_mode = acc_mode;
928 948
929 op->intent = LOOKUP_OPEN; 949 op->intent = flags & O_PATH ? 0 : LOOKUP_OPEN;
950
930 if (flags & O_CREAT) { 951 if (flags & O_CREAT) {
931 op->intent |= LOOKUP_CREATE; 952 op->intent |= LOOKUP_CREATE;
932 if (flags & O_EXCL) 953 if (flags & O_EXCL)
@@ -1053,8 +1074,10 @@ int filp_close(struct file *filp, fl_owner_t id)
1053 if (filp->f_op && filp->f_op->flush) 1074 if (filp->f_op && filp->f_op->flush)
1054 retval = filp->f_op->flush(filp, id); 1075 retval = filp->f_op->flush(filp, id);
1055 1076
1056 dnotify_flush(filp, id); 1077 if (likely(!(filp->f_mode & FMODE_PATH))) {
1057 locks_remove_posix(filp, id); 1078 dnotify_flush(filp, id);
1079 locks_remove_posix(filp, id);
1080 }
1058 fput(filp); 1081 fput(filp);
1059 return retval; 1082 return retval;
1060} 1083}