1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | * Copyright (C) International Business Machines Corp., 2002-2004 |
4 | * Copyright (C) Andreas Gruenbacher, 2001 |
5 | * Copyright (C) Linus Torvalds, 1991, 1992 |
6 | */ |
7 | |
8 | #include <linux/sched.h> |
9 | #include <linux/slab.h> |
10 | #include <linux/fs.h> |
11 | #include <linux/posix_acl_xattr.h> |
12 | #include "jfs_incore.h" |
13 | #include "jfs_txnmgr.h" |
14 | #include "jfs_xattr.h" |
15 | #include "jfs_acl.h" |
16 | |
17 | struct posix_acl *jfs_get_acl(struct inode *inode, int type, bool rcu) |
18 | { |
19 | struct posix_acl *acl; |
20 | char *ea_name; |
21 | int size; |
22 | char *value = NULL; |
23 | |
24 | if (rcu) |
25 | return ERR_PTR(error: -ECHILD); |
26 | |
27 | switch(type) { |
28 | case ACL_TYPE_ACCESS: |
29 | ea_name = XATTR_NAME_POSIX_ACL_ACCESS; |
30 | break; |
31 | case ACL_TYPE_DEFAULT: |
32 | ea_name = XATTR_NAME_POSIX_ACL_DEFAULT; |
33 | break; |
34 | default: |
35 | return ERR_PTR(error: -EINVAL); |
36 | } |
37 | |
38 | size = __jfs_getxattr(inode, ea_name, NULL, 0); |
39 | |
40 | if (size > 0) { |
41 | value = kmalloc(size, GFP_KERNEL); |
42 | if (!value) |
43 | return ERR_PTR(error: -ENOMEM); |
44 | size = __jfs_getxattr(inode, ea_name, value, size); |
45 | } |
46 | |
47 | if (size < 0) { |
48 | if (size == -ENODATA) |
49 | acl = NULL; |
50 | else |
51 | acl = ERR_PTR(error: size); |
52 | } else { |
53 | acl = posix_acl_from_xattr(user_ns: &init_user_ns, value, size); |
54 | } |
55 | kfree(objp: value); |
56 | return acl; |
57 | } |
58 | |
59 | static int __jfs_set_acl(tid_t tid, struct inode *inode, int type, |
60 | struct posix_acl *acl) |
61 | { |
62 | char *ea_name; |
63 | int rc; |
64 | int size = 0; |
65 | char *value = NULL; |
66 | |
67 | switch (type) { |
68 | case ACL_TYPE_ACCESS: |
69 | ea_name = XATTR_NAME_POSIX_ACL_ACCESS; |
70 | break; |
71 | case ACL_TYPE_DEFAULT: |
72 | ea_name = XATTR_NAME_POSIX_ACL_DEFAULT; |
73 | break; |
74 | default: |
75 | return -EINVAL; |
76 | } |
77 | |
78 | if (acl) { |
79 | size = posix_acl_xattr_size(count: acl->a_count); |
80 | value = kmalloc(size, GFP_KERNEL); |
81 | if (!value) |
82 | return -ENOMEM; |
83 | rc = posix_acl_to_xattr(user_ns: &init_user_ns, acl, buffer: value, size); |
84 | if (rc < 0) |
85 | goto out; |
86 | } |
87 | rc = __jfs_setxattr(tid, inode, ea_name, value, size, 0); |
88 | out: |
89 | kfree(objp: value); |
90 | |
91 | if (!rc) |
92 | set_cached_acl(inode, type, acl); |
93 | |
94 | return rc; |
95 | } |
96 | |
97 | int jfs_set_acl(struct mnt_idmap *idmap, struct dentry *dentry, |
98 | struct posix_acl *acl, int type) |
99 | { |
100 | int rc; |
101 | tid_t tid; |
102 | int update_mode = 0; |
103 | struct inode *inode = d_inode(dentry); |
104 | umode_t mode = inode->i_mode; |
105 | |
106 | tid = txBegin(inode->i_sb, 0); |
107 | mutex_lock(&JFS_IP(inode)->commit_mutex); |
108 | if (type == ACL_TYPE_ACCESS && acl) { |
109 | rc = posix_acl_update_mode(&nop_mnt_idmap, inode, &mode, &acl); |
110 | if (rc) |
111 | goto end_tx; |
112 | if (mode != inode->i_mode) |
113 | update_mode = 1; |
114 | } |
115 | rc = __jfs_set_acl(tid, inode, type, acl); |
116 | if (!rc) { |
117 | if (update_mode) { |
118 | inode->i_mode = mode; |
119 | inode_set_ctime_current(inode); |
120 | mark_inode_dirty(inode); |
121 | } |
122 | rc = txCommit(tid, 1, &inode, 0); |
123 | } |
124 | end_tx: |
125 | txEnd(tid); |
126 | mutex_unlock(lock: &JFS_IP(inode)->commit_mutex); |
127 | return rc; |
128 | } |
129 | |
130 | int jfs_init_acl(tid_t tid, struct inode *inode, struct inode *dir) |
131 | { |
132 | struct posix_acl *default_acl, *acl; |
133 | int rc = 0; |
134 | |
135 | rc = posix_acl_create(dir, &inode->i_mode, &default_acl, &acl); |
136 | if (rc) |
137 | return rc; |
138 | |
139 | if (default_acl) { |
140 | rc = __jfs_set_acl(tid, inode, ACL_TYPE_DEFAULT, acl: default_acl); |
141 | posix_acl_release(acl: default_acl); |
142 | } else { |
143 | inode->i_default_acl = NULL; |
144 | } |
145 | |
146 | if (acl) { |
147 | if (!rc) |
148 | rc = __jfs_set_acl(tid, inode, ACL_TYPE_ACCESS, acl); |
149 | posix_acl_release(acl); |
150 | } else { |
151 | inode->i_acl = NULL; |
152 | } |
153 | |
154 | JFS_IP(inode)->mode2 = (JFS_IP(inode)->mode2 & 0xffff0000) | |
155 | inode->i_mode; |
156 | |
157 | return rc; |
158 | } |
159 | |