Skip to content

Commit e0a43dd

Browse files
author
Miklos Szeredi
committed
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é <[email protected]> Signed-off-by: Miklos Szeredi <[email protected]>
1 parent 201fa69 commit e0a43dd

File tree

4 files changed

+46
-6
lines changed

4 files changed

+46
-6
lines changed

fs/fuse/dir.c

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -375,7 +375,7 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry, int mode,
375375
struct fuse_conn *fc = get_fuse_conn(dir);
376376
struct fuse_req *req;
377377
struct fuse_req *forget_req;
378-
struct fuse_open_in inarg;
378+
struct fuse_create_in inarg;
379379
struct fuse_open_out outopen;
380380
struct fuse_entry_out outentry;
381381
struct fuse_file *ff;
@@ -399,15 +399,20 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry, int mode,
399399
if (!ff)
400400
goto out_put_request;
401401

402+
if (!fc->dont_mask)
403+
mode &= ~current_umask();
404+
402405
flags &= ~O_NOCTTY;
403406
memset(&inarg, 0, sizeof(inarg));
404407
memset(&outentry, 0, sizeof(outentry));
405408
inarg.flags = flags;
406409
inarg.mode = mode;
410+
inarg.umask = current_umask();
407411
req->in.h.opcode = FUSE_CREATE;
408412
req->in.h.nodeid = get_node_id(dir);
409413
req->in.numargs = 2;
410-
req->in.args[0].size = sizeof(inarg);
414+
req->in.args[0].size = fc->minor < 12 ? sizeof(struct fuse_open_in) :
415+
sizeof(inarg);
411416
req->in.args[0].value = &inarg;
412417
req->in.args[1].size = entry->d_name.len + 1;
413418
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,
546551
if (IS_ERR(req))
547552
return PTR_ERR(req);
548553

554+
if (!fc->dont_mask)
555+
mode &= ~current_umask();
556+
549557
memset(&inarg, 0, sizeof(inarg));
550558
inarg.mode = mode;
551559
inarg.rdev = new_encode_dev(rdev);
560+
inarg.umask = current_umask();
552561
req->in.h.opcode = FUSE_MKNOD;
553562
req->in.numargs = 2;
554-
req->in.args[0].size = sizeof(inarg);
563+
req->in.args[0].size = fc->minor < 12 ? FUSE_COMPAT_MKNOD_IN_SIZE :
564+
sizeof(inarg);
555565
req->in.args[0].value = &inarg;
556566
req->in.args[1].size = entry->d_name.len + 1;
557567
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)
578588
if (IS_ERR(req))
579589
return PTR_ERR(req);
580590

591+
if (!fc->dont_mask)
592+
mode &= ~current_umask();
593+
581594
memset(&inarg, 0, sizeof(inarg));
582595
inarg.mode = mode;
596+
inarg.umask = current_umask();
583597
req->in.h.opcode = FUSE_MKDIR;
584598
req->in.numargs = 2;
585599
req->in.args[0].size = sizeof(inarg);

fs/fuse/fuse_i.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -446,6 +446,9 @@ struct fuse_conn {
446446
/** Do multi-page cached writes */
447447
unsigned big_writes:1;
448448

449+
/** Don't apply umask to creation modes */
450+
unsigned dont_mask:1;
451+
449452
/** The number of requests waiting for completion */
450453
atomic_t num_waiting;
451454

fs/fuse/inode.c

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -725,6 +725,8 @@ static void process_init_reply(struct fuse_conn *fc, struct fuse_req *req)
725725
}
726726
if (arg->flags & FUSE_BIG_WRITES)
727727
fc->big_writes = 1;
728+
if (arg->flags & FUSE_DONT_MASK)
729+
fc->dont_mask = 1;
728730
} else {
729731
ra_pages = fc->max_read / PAGE_CACHE_SIZE;
730732
fc->no_lock = 1;
@@ -748,7 +750,7 @@ static void fuse_send_init(struct fuse_conn *fc, struct fuse_req *req)
748750
arg->minor = FUSE_KERNEL_MINOR_VERSION;
749751
arg->max_readahead = fc->bdi.ra_pages * PAGE_CACHE_SIZE;
750752
arg->flags |= FUSE_ASYNC_READ | FUSE_POSIX_LOCKS | FUSE_ATOMIC_O_TRUNC |
751-
FUSE_EXPORT_SUPPORT | FUSE_BIG_WRITES;
753+
FUSE_EXPORT_SUPPORT | FUSE_BIG_WRITES | FUSE_DONT_MASK;
752754
req->in.h.opcode = FUSE_INIT;
753755
req->in.numargs = 1;
754756
req->in.args[0].size = sizeof(*arg);
@@ -864,6 +866,11 @@ static int fuse_fill_super(struct super_block *sb, void *data, int silent)
864866
if (err)
865867
goto err_put_conn;
866868

869+
/* Handle umasking inside the fuse code */
870+
if (sb->s_flags & MS_POSIXACL)
871+
fc->dont_mask = 1;
872+
sb->s_flags |= MS_POSIXACL;
873+
867874
fc->release = fuse_free_conn;
868875
fc->flags = d.flags;
869876
fc->user_id = d.user_id;

include/linux/fuse.h

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,9 @@
2525
* - add IOCTL message
2626
* - add unsolicited notification support
2727
* - add POLL message and NOTIFY_POLL notification
28+
*
29+
* 7.12
30+
* - add umask flag to input argument of open, mknod and mkdir
2831
*/
2932

3033
#ifndef _LINUX_FUSE_H
@@ -36,7 +39,7 @@
3639
#define FUSE_KERNEL_VERSION 7
3740

3841
/** Minor version number of this interface */
39-
#define FUSE_KERNEL_MINOR_VERSION 11
42+
#define FUSE_KERNEL_MINOR_VERSION 12
4043

4144
/** The node ID of the root inode */
4245
#define FUSE_ROOT_ID 1
@@ -112,13 +115,15 @@ struct fuse_file_lock {
112115
* INIT request/reply flags
113116
*
114117
* FUSE_EXPORT_SUPPORT: filesystem handles lookups of "." and ".."
118+
* FUSE_DONT_MASK: don't apply umask to file mode on create operations
115119
*/
116120
#define FUSE_ASYNC_READ (1 << 0)
117121
#define FUSE_POSIX_LOCKS (1 << 1)
118122
#define FUSE_FILE_OPS (1 << 2)
119123
#define FUSE_ATOMIC_O_TRUNC (1 << 3)
120124
#define FUSE_EXPORT_SUPPORT (1 << 4)
121125
#define FUSE_BIG_WRITES (1 << 5)
126+
#define FUSE_DONT_MASK (1 << 6)
122127

123128
/**
124129
* CUSE INIT request/reply flags
@@ -262,14 +267,18 @@ struct fuse_attr_out {
262267
struct fuse_attr attr;
263268
};
264269

270+
#define FUSE_COMPAT_MKNOD_IN_SIZE 8
271+
265272
struct fuse_mknod_in {
266273
__u32 mode;
267274
__u32 rdev;
275+
__u32 umask;
276+
__u32 padding;
268277
};
269278

270279
struct fuse_mkdir_in {
271280
__u32 mode;
272-
__u32 padding;
281+
__u32 umask;
273282
};
274283

275284
struct fuse_rename_in {
@@ -300,8 +309,15 @@ struct fuse_setattr_in {
300309
};
301310

302311
struct fuse_open_in {
312+
__u32 flags;
313+
__u32 unused;
314+
};
315+
316+
struct fuse_create_in {
303317
__u32 flags;
304318
__u32 mode;
319+
__u32 umask;
320+
__u32 padding;
305321
};
306322

307323
struct fuse_open_out {

0 commit comments

Comments
 (0)