Skip to content
Navigation Menu
Toggle navigation
Sign in
In this repository
All GitHub Enterprise
↵
Jump to
↵
No suggested jump to results
In this repository
All GitHub Enterprise
↵
Jump to
↵
In this organization
All GitHub Enterprise
↵
Jump to
↵
In this repository
All GitHub Enterprise
↵
Jump to
↵
Sign in
Reseting focus
You signed in with another tab or window.
Reload
to refresh your session.
You signed out in another tab or window.
Reload
to refresh your session.
You switched accounts on another tab or window.
Reload
to refresh your session.
Dismiss alert
{{ message }}
mariux64
/
linux
Public
Notifications
You must be signed in to change notification settings
Fork
0
Star
0
Code
Issues
2
Pull requests
0
Actions
Projects
0
Wiki
Security
Insights
Additional navigation options
Code
Issues
Pull requests
Actions
Projects
Wiki
Security
Insights
Files
7df336e
Documentation
arch
block
crypto
drivers
firmware
fs
9p
adfs
affs
afs
autofs
autofs4
befs
bfs
btrfs
Kconfig
Makefile
acl.c
async-thread.c
async-thread.h
btrfs_inode.h
compat.h
compression.c
compression.h
ctree.c
ctree.h
delayed-ref.c
delayed-ref.h
dir-item.c
disk-io.c
disk-io.h
export.c
export.h
extent-tree.c
extent_io.c
extent_io.h
extent_map.c
extent_map.h
file-item.c
file.c
free-space-cache.c
free-space-cache.h
hash.h
inode-item.c
inode-map.c
inode.c
ioctl.c
ioctl.h
locking.c
locking.h
ordered-data.c
ordered-data.h
orphan.c
print-tree.c
print-tree.h
ref-cache.c
ref-cache.h
relocation.c
root-tree.c
struct-funcs.c
super.c
sysfs.c
transaction.c
transaction.h
tree-defrag.c
tree-log.c
tree-log.h
version.h
version.sh
volumes.c
volumes.h
xattr.c
xattr.h
zlib.c
cachefiles
cifs
coda
configfs
cramfs
debugfs
devpts
dlm
ecryptfs
efs
exofs
exportfs
ext2
ext3
ext4
fat
freevxfs
fscache
fuse
gfs2
hfs
hfsplus
hostfs
hpfs
hppfs
hugetlbfs
isofs
jbd
jbd2
jffs2
jfs
lockd
minix
ncpfs
nfs
nfs_common
nfsd
nilfs2
nls
notify
ntfs
ocfs2
omfs
openpromfs
partitions
proc
qnx4
quota
ramfs
reiserfs
romfs
smbfs
squashfs
sysfs
sysv
ubifs
udf
ufs
xfs
Kconfig
Kconfig.binfmt
Makefile
aio.c
anon_inodes.c
attr.c
bad_inode.c
binfmt_aout.c
binfmt_elf.c
binfmt_elf_fdpic.c
binfmt_em86.c
binfmt_flat.c
binfmt_misc.c
binfmt_script.c
binfmt_som.c
bio-integrity.c
bio.c
block_dev.c
buffer.c
char_dev.c
compat.c
compat_binfmt_elf.c
compat_ioctl.c
dcache.c
dcookies.c
direct-io.c
drop_caches.c
eventfd.c
eventpoll.c
exec.c
fcntl.c
fifo.c
file.c
file_table.c
filesystems.c
fs-writeback.c
fs_struct.c
generic_acl.c
inode.c
internal.h
ioctl.c
ioprio.c
libfs.c
locks.c
mbcache.c
mpage.c
namei.c
namespace.c
nfsctl.c
no-block.c
open.c
pipe.c
pnode.c
pnode.h
posix_acl.c
read_write.c
read_write.h
readdir.c
select.c
seq_file.c
signalfd.c
splice.c
stack.c
stat.c
super.c
sync.c
timerfd.c
utimes.c
xattr.c
xattr_acl.c
include
init
ipc
kernel
lib
mm
net
samples
scripts
security
sound
usr
virt
.gitignore
.mailmap
COPYING
CREDITS
Kbuild
MAINTAINERS
Makefile
README
REPORTING-BUGS
Breadcrumbs
linux
/
fs
/
btrfs
/
acl.c
Blame
Blame
Latest commit
History
History
354 lines (294 loc) · 7.53 KB
Breadcrumbs
linux
/
fs
/
btrfs
/
acl.c
Top
File metadata and controls
Code
Blame
354 lines (294 loc) · 7.53 KB
Raw
/* * Copyright (C) 2007 Red Hat. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License v2 as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 021110-1307, USA. */ #include <linux/fs.h> #include <linux/string.h> #include <linux/xattr.h> #include <linux/posix_acl_xattr.h> #include <linux/posix_acl.h> #include <linux/sched.h> #include "ctree.h" #include "btrfs_inode.h" #include "xattr.h" #ifdef CONFIG_FS_POSIX_ACL static void btrfs_update_cached_acl(struct inode *inode, struct posix_acl **p_acl, struct posix_acl *acl) { spin_lock(&inode->i_lock); if (*p_acl && *p_acl != BTRFS_ACL_NOT_CACHED) posix_acl_release(*p_acl); *p_acl = posix_acl_dup(acl); spin_unlock(&inode->i_lock); } static struct posix_acl *btrfs_get_acl(struct inode *inode, int type) { int size; const char *name; char *value = NULL; struct posix_acl *acl = NULL, **p_acl; switch (type) { case ACL_TYPE_ACCESS: name = POSIX_ACL_XATTR_ACCESS; p_acl = &BTRFS_I(inode)->i_acl; break; case ACL_TYPE_DEFAULT: name = POSIX_ACL_XATTR_DEFAULT; p_acl = &BTRFS_I(inode)->i_default_acl; break; default: return ERR_PTR(-EINVAL); } /* Handle the cached NULL acl case without locking */ acl = ACCESS_ONCE(*p_acl); if (!acl) return acl; spin_lock(&inode->i_lock); acl = *p_acl; if (acl != BTRFS_ACL_NOT_CACHED) acl = posix_acl_dup(acl); spin_unlock(&inode->i_lock); if (acl != BTRFS_ACL_NOT_CACHED) return acl; size = __btrfs_getxattr(inode, name, "", 0); if (size > 0) { value = kzalloc(size, GFP_NOFS); if (!value) return ERR_PTR(-ENOMEM); size = __btrfs_getxattr(inode, name, value, size); if (size > 0) { acl = posix_acl_from_xattr(value, size); btrfs_update_cached_acl(inode, p_acl, acl); } kfree(value); } else if (size == -ENOENT || size == -ENODATA || size == 0) { /* FIXME, who returns -ENOENT? I think nobody */ acl = NULL; btrfs_update_cached_acl(inode, p_acl, acl); } else { acl = ERR_PTR(-EIO); } return acl; } static int btrfs_xattr_get_acl(struct inode *inode, int type, void *value, size_t size) { struct posix_acl *acl; int ret = 0; acl = btrfs_get_acl(inode, type); if (IS_ERR(acl)) return PTR_ERR(acl); if (acl == NULL) return -ENODATA; ret = posix_acl_to_xattr(acl, value, size); posix_acl_release(acl); return ret; } /* * Needs to be called with fs_mutex held */ static int btrfs_set_acl(struct inode *inode, struct posix_acl *acl, int type) { int ret, size = 0; const char *name; struct posix_acl **p_acl; char *value = NULL; mode_t mode; if (acl) { ret = posix_acl_valid(acl); if (ret < 0) return ret; ret = 0; } switch (type) { case ACL_TYPE_ACCESS: mode = inode->i_mode; ret = posix_acl_equiv_mode(acl, &mode); if (ret < 0) return ret; ret = 0; inode->i_mode = mode; name = POSIX_ACL_XATTR_ACCESS; p_acl = &BTRFS_I(inode)->i_acl; break; case ACL_TYPE_DEFAULT: if (!S_ISDIR(inode->i_mode)) return acl ? -EINVAL : 0; name = POSIX_ACL_XATTR_DEFAULT; p_acl = &BTRFS_I(inode)->i_default_acl; break; default: return -EINVAL; } if (acl) { size = posix_acl_xattr_size(acl->a_count); value = kmalloc(size, GFP_NOFS); if (!value) { ret = -ENOMEM; goto out; } ret = posix_acl_to_xattr(acl, value, size); if (ret < 0) goto out; } ret = __btrfs_setxattr(inode, name, value, size, 0); out: kfree(value); if (!ret) btrfs_update_cached_acl(inode, p_acl, acl); return ret; } static int btrfs_xattr_set_acl(struct inode *inode, int type, const void *value, size_t size) { int ret = 0; struct posix_acl *acl = NULL; if (value) { acl = posix_acl_from_xattr(value, size); if (acl == NULL) { value = NULL; size = 0; } else if (IS_ERR(acl)) { return PTR_ERR(acl); } } ret = btrfs_set_acl(inode, acl, type); posix_acl_release(acl); return ret; } static int btrfs_xattr_acl_access_get(struct inode *inode, const char *name, void *value, size_t size) { return btrfs_xattr_get_acl(inode, ACL_TYPE_ACCESS, value, size); } static int btrfs_xattr_acl_access_set(struct inode *inode, const char *name, const void *value, size_t size, int flags) { return btrfs_xattr_set_acl(inode, ACL_TYPE_ACCESS, value, size); } static int btrfs_xattr_acl_default_get(struct inode *inode, const char *name, void *value, size_t size) { return btrfs_xattr_get_acl(inode, ACL_TYPE_DEFAULT, value, size); } static int btrfs_xattr_acl_default_set(struct inode *inode, const char *name, const void *value, size_t size, int flags) { return btrfs_xattr_set_acl(inode, ACL_TYPE_DEFAULT, value, size); } int btrfs_check_acl(struct inode *inode, int mask) { struct posix_acl *acl; int error = -EAGAIN; acl = btrfs_get_acl(inode, ACL_TYPE_ACCESS); if (IS_ERR(acl)) return PTR_ERR(acl); if (acl) { error = posix_acl_permission(inode, acl, mask); posix_acl_release(acl); } return error; } /* * btrfs_init_acl is already generally called under fs_mutex, so the locking * stuff has been fixed to work with that. If the locking stuff changes, we * need to re-evaluate the acl locking stuff. */ int btrfs_init_acl(struct inode *inode, struct inode *dir) { struct posix_acl *acl = NULL; int ret = 0; /* this happens with subvols */ if (!dir) return 0; if (!S_ISLNK(inode->i_mode)) { if (IS_POSIXACL(dir)) { acl = btrfs_get_acl(dir, ACL_TYPE_DEFAULT); if (IS_ERR(acl)) return PTR_ERR(acl); } if (!acl) inode->i_mode &= ~current_umask(); } if (IS_POSIXACL(dir) && acl) { struct posix_acl *clone; mode_t mode; if (S_ISDIR(inode->i_mode)) { ret = btrfs_set_acl(inode, acl, ACL_TYPE_DEFAULT); if (ret) goto failed; } clone = posix_acl_clone(acl, GFP_NOFS); ret = -ENOMEM; if (!clone) goto failed; mode = inode->i_mode; ret = posix_acl_create_masq(clone, &mode); if (ret >= 0) { inode->i_mode = mode; if (ret > 0) { /* we need an acl */ ret = btrfs_set_acl(inode, clone, ACL_TYPE_ACCESS); } } } failed: posix_acl_release(acl); return ret; } int btrfs_acl_chmod(struct inode *inode) { struct posix_acl *acl, *clone; int ret = 0; if (S_ISLNK(inode->i_mode)) return -EOPNOTSUPP; if (!IS_POSIXACL(inode)) return 0; acl = btrfs_get_acl(inode, ACL_TYPE_ACCESS); if (IS_ERR(acl) || !acl) return PTR_ERR(acl); clone = posix_acl_clone(acl, GFP_KERNEL); posix_acl_release(acl); if (!clone) return -ENOMEM; ret = posix_acl_chmod_masq(clone, inode->i_mode); if (!ret) ret = btrfs_set_acl(inode, clone, ACL_TYPE_ACCESS); posix_acl_release(clone); return ret; } struct xattr_handler btrfs_xattr_acl_default_handler = { .prefix = POSIX_ACL_XATTR_DEFAULT, .get = btrfs_xattr_acl_default_get, .set = btrfs_xattr_acl_default_set, }; struct xattr_handler btrfs_xattr_acl_access_handler = { .prefix = POSIX_ACL_XATTR_ACCESS, .get = btrfs_xattr_acl_access_get, .set = btrfs_xattr_acl_access_set, }; #else /* CONFIG_FS_POSIX_ACL */ int btrfs_acl_chmod(struct inode *inode) { return 0; } int btrfs_init_acl(struct inode *inode, struct inode *dir) { return 0; } #endif /* CONFIG_FS_POSIX_ACL */
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
You can’t perform that action at this time.