fuse: allow umask processing in userspace
This patch lets filesystems handle masking the file mode on creation. This is needed if filesystem is using ACLs. - The CREATE, MKDIR and MKNOD requests are extended with a "umask" parameter. - A new FUSE_DONT_MASK flag is added to the INIT request/reply. With this the filesystem may request that the create mode is not masked. CC: Jean-Pierre André <jean-pierre.andre@wanadoo.fr> Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
This commit is contained in:
parent
201fa69a28
commit
e0a43ddcc0
|
@ -375,7 +375,7 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry, int mode,
|
||||||
struct fuse_conn *fc = get_fuse_conn(dir);
|
struct fuse_conn *fc = get_fuse_conn(dir);
|
||||||
struct fuse_req *req;
|
struct fuse_req *req;
|
||||||
struct fuse_req *forget_req;
|
struct fuse_req *forget_req;
|
||||||
struct fuse_open_in inarg;
|
struct fuse_create_in inarg;
|
||||||
struct fuse_open_out outopen;
|
struct fuse_open_out outopen;
|
||||||
struct fuse_entry_out outentry;
|
struct fuse_entry_out outentry;
|
||||||
struct fuse_file *ff;
|
struct fuse_file *ff;
|
||||||
|
@ -399,15 +399,20 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry, int mode,
|
||||||
if (!ff)
|
if (!ff)
|
||||||
goto out_put_request;
|
goto out_put_request;
|
||||||
|
|
||||||
|
if (!fc->dont_mask)
|
||||||
|
mode &= ~current_umask();
|
||||||
|
|
||||||
flags &= ~O_NOCTTY;
|
flags &= ~O_NOCTTY;
|
||||||
memset(&inarg, 0, sizeof(inarg));
|
memset(&inarg, 0, sizeof(inarg));
|
||||||
memset(&outentry, 0, sizeof(outentry));
|
memset(&outentry, 0, sizeof(outentry));
|
||||||
inarg.flags = flags;
|
inarg.flags = flags;
|
||||||
inarg.mode = mode;
|
inarg.mode = mode;
|
||||||
|
inarg.umask = current_umask();
|
||||||
req->in.h.opcode = FUSE_CREATE;
|
req->in.h.opcode = FUSE_CREATE;
|
||||||
req->in.h.nodeid = get_node_id(dir);
|
req->in.h.nodeid = get_node_id(dir);
|
||||||
req->in.numargs = 2;
|
req->in.numargs = 2;
|
||||||
req->in.args[0].size = sizeof(inarg);
|
req->in.args[0].size = fc->minor < 12 ? sizeof(struct fuse_open_in) :
|
||||||
|
sizeof(inarg);
|
||||||
req->in.args[0].value = &inarg;
|
req->in.args[0].value = &inarg;
|
||||||
req->in.args[1].size = entry->d_name.len + 1;
|
req->in.args[1].size = entry->d_name.len + 1;
|
||||||
req->in.args[1].value = entry->d_name.name;
|
req->in.args[1].value = entry->d_name.name;
|
||||||
|
@ -546,12 +551,17 @@ static int fuse_mknod(struct inode *dir, struct dentry *entry, int mode,
|
||||||
if (IS_ERR(req))
|
if (IS_ERR(req))
|
||||||
return PTR_ERR(req);
|
return PTR_ERR(req);
|
||||||
|
|
||||||
|
if (!fc->dont_mask)
|
||||||
|
mode &= ~current_umask();
|
||||||
|
|
||||||
memset(&inarg, 0, sizeof(inarg));
|
memset(&inarg, 0, sizeof(inarg));
|
||||||
inarg.mode = mode;
|
inarg.mode = mode;
|
||||||
inarg.rdev = new_encode_dev(rdev);
|
inarg.rdev = new_encode_dev(rdev);
|
||||||
|
inarg.umask = current_umask();
|
||||||
req->in.h.opcode = FUSE_MKNOD;
|
req->in.h.opcode = FUSE_MKNOD;
|
||||||
req->in.numargs = 2;
|
req->in.numargs = 2;
|
||||||
req->in.args[0].size = sizeof(inarg);
|
req->in.args[0].size = fc->minor < 12 ? FUSE_COMPAT_MKNOD_IN_SIZE :
|
||||||
|
sizeof(inarg);
|
||||||
req->in.args[0].value = &inarg;
|
req->in.args[0].value = &inarg;
|
||||||
req->in.args[1].size = entry->d_name.len + 1;
|
req->in.args[1].size = entry->d_name.len + 1;
|
||||||
req->in.args[1].value = entry->d_name.name;
|
req->in.args[1].value = entry->d_name.name;
|
||||||
|
@ -578,8 +588,12 @@ static int fuse_mkdir(struct inode *dir, struct dentry *entry, int mode)
|
||||||
if (IS_ERR(req))
|
if (IS_ERR(req))
|
||||||
return PTR_ERR(req);
|
return PTR_ERR(req);
|
||||||
|
|
||||||
|
if (!fc->dont_mask)
|
||||||
|
mode &= ~current_umask();
|
||||||
|
|
||||||
memset(&inarg, 0, sizeof(inarg));
|
memset(&inarg, 0, sizeof(inarg));
|
||||||
inarg.mode = mode;
|
inarg.mode = mode;
|
||||||
|
inarg.umask = current_umask();
|
||||||
req->in.h.opcode = FUSE_MKDIR;
|
req->in.h.opcode = FUSE_MKDIR;
|
||||||
req->in.numargs = 2;
|
req->in.numargs = 2;
|
||||||
req->in.args[0].size = sizeof(inarg);
|
req->in.args[0].size = sizeof(inarg);
|
||||||
|
|
|
@ -446,6 +446,9 @@ struct fuse_conn {
|
||||||
/** Do multi-page cached writes */
|
/** Do multi-page cached writes */
|
||||||
unsigned big_writes:1;
|
unsigned big_writes:1;
|
||||||
|
|
||||||
|
/** Don't apply umask to creation modes */
|
||||||
|
unsigned dont_mask:1;
|
||||||
|
|
||||||
/** The number of requests waiting for completion */
|
/** The number of requests waiting for completion */
|
||||||
atomic_t num_waiting;
|
atomic_t num_waiting;
|
||||||
|
|
||||||
|
|
|
@ -725,6 +725,8 @@ static void process_init_reply(struct fuse_conn *fc, struct fuse_req *req)
|
||||||
}
|
}
|
||||||
if (arg->flags & FUSE_BIG_WRITES)
|
if (arg->flags & FUSE_BIG_WRITES)
|
||||||
fc->big_writes = 1;
|
fc->big_writes = 1;
|
||||||
|
if (arg->flags & FUSE_DONT_MASK)
|
||||||
|
fc->dont_mask = 1;
|
||||||
} else {
|
} else {
|
||||||
ra_pages = fc->max_read / PAGE_CACHE_SIZE;
|
ra_pages = fc->max_read / PAGE_CACHE_SIZE;
|
||||||
fc->no_lock = 1;
|
fc->no_lock = 1;
|
||||||
|
@ -748,7 +750,7 @@ static void fuse_send_init(struct fuse_conn *fc, struct fuse_req *req)
|
||||||
arg->minor = FUSE_KERNEL_MINOR_VERSION;
|
arg->minor = FUSE_KERNEL_MINOR_VERSION;
|
||||||
arg->max_readahead = fc->bdi.ra_pages * PAGE_CACHE_SIZE;
|
arg->max_readahead = fc->bdi.ra_pages * PAGE_CACHE_SIZE;
|
||||||
arg->flags |= FUSE_ASYNC_READ | FUSE_POSIX_LOCKS | FUSE_ATOMIC_O_TRUNC |
|
arg->flags |= FUSE_ASYNC_READ | FUSE_POSIX_LOCKS | FUSE_ATOMIC_O_TRUNC |
|
||||||
FUSE_EXPORT_SUPPORT | FUSE_BIG_WRITES;
|
FUSE_EXPORT_SUPPORT | FUSE_BIG_WRITES | FUSE_DONT_MASK;
|
||||||
req->in.h.opcode = FUSE_INIT;
|
req->in.h.opcode = FUSE_INIT;
|
||||||
req->in.numargs = 1;
|
req->in.numargs = 1;
|
||||||
req->in.args[0].size = sizeof(*arg);
|
req->in.args[0].size = sizeof(*arg);
|
||||||
|
@ -864,6 +866,11 @@ static int fuse_fill_super(struct super_block *sb, void *data, int silent)
|
||||||
if (err)
|
if (err)
|
||||||
goto err_put_conn;
|
goto err_put_conn;
|
||||||
|
|
||||||
|
/* Handle umasking inside the fuse code */
|
||||||
|
if (sb->s_flags & MS_POSIXACL)
|
||||||
|
fc->dont_mask = 1;
|
||||||
|
sb->s_flags |= MS_POSIXACL;
|
||||||
|
|
||||||
fc->release = fuse_free_conn;
|
fc->release = fuse_free_conn;
|
||||||
fc->flags = d.flags;
|
fc->flags = d.flags;
|
||||||
fc->user_id = d.user_id;
|
fc->user_id = d.user_id;
|
||||||
|
|
|
@ -25,6 +25,9 @@
|
||||||
* - add IOCTL message
|
* - add IOCTL message
|
||||||
* - add unsolicited notification support
|
* - add unsolicited notification support
|
||||||
* - add POLL message and NOTIFY_POLL notification
|
* - add POLL message and NOTIFY_POLL notification
|
||||||
|
*
|
||||||
|
* 7.12
|
||||||
|
* - add umask flag to input argument of open, mknod and mkdir
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef _LINUX_FUSE_H
|
#ifndef _LINUX_FUSE_H
|
||||||
|
@ -36,7 +39,7 @@
|
||||||
#define FUSE_KERNEL_VERSION 7
|
#define FUSE_KERNEL_VERSION 7
|
||||||
|
|
||||||
/** Minor version number of this interface */
|
/** Minor version number of this interface */
|
||||||
#define FUSE_KERNEL_MINOR_VERSION 11
|
#define FUSE_KERNEL_MINOR_VERSION 12
|
||||||
|
|
||||||
/** The node ID of the root inode */
|
/** The node ID of the root inode */
|
||||||
#define FUSE_ROOT_ID 1
|
#define FUSE_ROOT_ID 1
|
||||||
|
@ -112,6 +115,7 @@ struct fuse_file_lock {
|
||||||
* INIT request/reply flags
|
* INIT request/reply flags
|
||||||
*
|
*
|
||||||
* FUSE_EXPORT_SUPPORT: filesystem handles lookups of "." and ".."
|
* FUSE_EXPORT_SUPPORT: filesystem handles lookups of "." and ".."
|
||||||
|
* FUSE_DONT_MASK: don't apply umask to file mode on create operations
|
||||||
*/
|
*/
|
||||||
#define FUSE_ASYNC_READ (1 << 0)
|
#define FUSE_ASYNC_READ (1 << 0)
|
||||||
#define FUSE_POSIX_LOCKS (1 << 1)
|
#define FUSE_POSIX_LOCKS (1 << 1)
|
||||||
|
@ -119,6 +123,7 @@ struct fuse_file_lock {
|
||||||
#define FUSE_ATOMIC_O_TRUNC (1 << 3)
|
#define FUSE_ATOMIC_O_TRUNC (1 << 3)
|
||||||
#define FUSE_EXPORT_SUPPORT (1 << 4)
|
#define FUSE_EXPORT_SUPPORT (1 << 4)
|
||||||
#define FUSE_BIG_WRITES (1 << 5)
|
#define FUSE_BIG_WRITES (1 << 5)
|
||||||
|
#define FUSE_DONT_MASK (1 << 6)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* CUSE INIT request/reply flags
|
* CUSE INIT request/reply flags
|
||||||
|
@ -262,14 +267,18 @@ struct fuse_attr_out {
|
||||||
struct fuse_attr attr;
|
struct fuse_attr attr;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define FUSE_COMPAT_MKNOD_IN_SIZE 8
|
||||||
|
|
||||||
struct fuse_mknod_in {
|
struct fuse_mknod_in {
|
||||||
__u32 mode;
|
__u32 mode;
|
||||||
__u32 rdev;
|
__u32 rdev;
|
||||||
|
__u32 umask;
|
||||||
|
__u32 padding;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct fuse_mkdir_in {
|
struct fuse_mkdir_in {
|
||||||
__u32 mode;
|
__u32 mode;
|
||||||
__u32 padding;
|
__u32 umask;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct fuse_rename_in {
|
struct fuse_rename_in {
|
||||||
|
@ -300,8 +309,15 @@ struct fuse_setattr_in {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct fuse_open_in {
|
struct fuse_open_in {
|
||||||
|
__u32 flags;
|
||||||
|
__u32 unused;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct fuse_create_in {
|
||||||
__u32 flags;
|
__u32 flags;
|
||||||
__u32 mode;
|
__u32 mode;
|
||||||
|
__u32 umask;
|
||||||
|
__u32 padding;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct fuse_open_out {
|
struct fuse_open_out {
|
||||||
|
|
Loading…
Reference in New Issue