aboutsummaryrefslogtreecommitdiffstats
path: root/fs/xfs/xfs_acl.c
diff options
context:
space:
mode:
authorChristoph Hellwig <hch@infradead.org>2011-08-12 17:21:35 -0400
committerAlex Elder <aelder@sgi.com>2011-08-12 17:21:35 -0400
commitc59d87c460767bc35dafd490139d3cfe78fb8da4 (patch)
tree2aad8261f86488e501d9645bd35d1398906da46d /fs/xfs/xfs_acl.c
parent06f8e2d6754dc631732415b741b5aa58a0f7133f (diff)
xfs: remove subdirectories
Use the move from Linux 2.6 to Linux 3.x as an excuse to kill the annoying subdirectories in the XFS source code. Besides the large amount of file rename the only changes are to the Makefile, a few files including headers with the subdirectory prefix, and the binary sysctl compat code that includes a header under fs/xfs/ from kernel/. Signed-off-by: Christoph Hellwig <hch@lst.de> Signed-off-by: Alex Elder <aelder@sgi.com>
Diffstat (limited to 'fs/xfs/xfs_acl.c')
-rw-r--r--fs/xfs/xfs_acl.c420
1 files changed, 420 insertions, 0 deletions
diff --git a/fs/xfs/xfs_acl.c b/fs/xfs/xfs_acl.c
new file mode 100644
index 000000000000..b6c4b3795c4a
--- /dev/null
+++ b/fs/xfs/xfs_acl.c
@@ -0,0 +1,420 @@
1/*
2 * Copyright (c) 2008, Christoph Hellwig
3 * All Rights Reserved.
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
7 * published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope that it would be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write the Free Software Foundation,
16 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17 */
18#include "xfs.h"
19#include "xfs_acl.h"
20#include "xfs_attr.h"
21#include "xfs_bmap_btree.h"
22#include "xfs_inode.h"
23#include "xfs_vnodeops.h"
24#include "xfs_trace.h"
25#include <linux/slab.h>
26#include <linux/xattr.h>
27#include <linux/posix_acl_xattr.h>
28
29
30/*
31 * Locking scheme:
32 * - all ACL updates are protected by inode->i_mutex, which is taken before
33 * calling into this file.
34 */
35
36STATIC struct posix_acl *
37xfs_acl_from_disk(struct xfs_acl *aclp)
38{
39 struct posix_acl_entry *acl_e;
40 struct posix_acl *acl;
41 struct xfs_acl_entry *ace;
42 int count, i;
43
44 count = be32_to_cpu(aclp->acl_cnt);
45
46 acl = posix_acl_alloc(count, GFP_KERNEL);
47 if (!acl)
48 return ERR_PTR(-ENOMEM);
49
50 for (i = 0; i < count; i++) {
51 acl_e = &acl->a_entries[i];
52 ace = &aclp->acl_entry[i];
53
54 /*
55 * The tag is 32 bits on disk and 16 bits in core.
56 *
57 * Because every access to it goes through the core
58 * format first this is not a problem.
59 */
60 acl_e->e_tag = be32_to_cpu(ace->ae_tag);
61 acl_e->e_perm = be16_to_cpu(ace->ae_perm);
62
63 switch (acl_e->e_tag) {
64 case ACL_USER:
65 case ACL_GROUP:
66 acl_e->e_id = be32_to_cpu(ace->ae_id);
67 break;
68 case ACL_USER_OBJ:
69 case ACL_GROUP_OBJ:
70 case ACL_MASK:
71 case ACL_OTHER:
72 acl_e->e_id = ACL_UNDEFINED_ID;
73 break;
74 default:
75 goto fail;
76 }
77 }
78 return acl;
79
80fail:
81 posix_acl_release(acl);
82 return ERR_PTR(-EINVAL);
83}
84
85STATIC void
86xfs_acl_to_disk(struct xfs_acl *aclp, const struct posix_acl *acl)
87{
88 const struct posix_acl_entry *acl_e;
89 struct xfs_acl_entry *ace;
90 int i;
91
92 aclp->acl_cnt = cpu_to_be32(acl->a_count);
93 for (i = 0; i < acl->a_count; i++) {
94 ace = &aclp->acl_entry[i];
95 acl_e = &acl->a_entries[i];
96
97 ace->ae_tag = cpu_to_be32(acl_e->e_tag);
98 ace->ae_id = cpu_to_be32(acl_e->e_id);
99 ace->ae_perm = cpu_to_be16(acl_e->e_perm);
100 }
101}
102
103struct posix_acl *
104xfs_get_acl(struct inode *inode, int type)
105{
106 struct xfs_inode *ip = XFS_I(inode);
107 struct posix_acl *acl;
108 struct xfs_acl *xfs_acl;
109 int len = sizeof(struct xfs_acl);
110 unsigned char *ea_name;
111 int error;
112
113 acl = get_cached_acl(inode, type);
114 if (acl != ACL_NOT_CACHED)
115 return acl;
116
117 trace_xfs_get_acl(ip);
118
119 switch (type) {
120 case ACL_TYPE_ACCESS:
121 ea_name = SGI_ACL_FILE;
122 break;
123 case ACL_TYPE_DEFAULT:
124 ea_name = SGI_ACL_DEFAULT;
125 break;
126 default:
127 BUG();
128 }
129
130 /*
131 * If we have a cached ACLs value just return it, not need to
132 * go out to the disk.
133 */
134
135 xfs_acl = kzalloc(sizeof(struct xfs_acl), GFP_KERNEL);
136 if (!xfs_acl)
137 return ERR_PTR(-ENOMEM);
138
139 error = -xfs_attr_get(ip, ea_name, (unsigned char *)xfs_acl,
140 &len, ATTR_ROOT);
141 if (error) {
142 /*
143 * If the attribute doesn't exist make sure we have a negative
144 * cache entry, for any other error assume it is transient and
145 * leave the cache entry as ACL_NOT_CACHED.
146 */
147 if (error == -ENOATTR) {
148 acl = NULL;
149 goto out_update_cache;
150 }
151 goto out;
152 }
153
154 acl = xfs_acl_from_disk(xfs_acl);
155 if (IS_ERR(acl))
156 goto out;
157
158 out_update_cache:
159 set_cached_acl(inode, type, acl);
160 out:
161 kfree(xfs_acl);
162 return acl;
163}
164
165STATIC int
166xfs_set_acl(struct inode *inode, int type, struct posix_acl *acl)
167{
168 struct xfs_inode *ip = XFS_I(inode);
169 unsigned char *ea_name;
170 int error;
171
172 if (S_ISLNK(inode->i_mode))
173 return -EOPNOTSUPP;
174
175 switch (type) {
176 case ACL_TYPE_ACCESS:
177 ea_name = SGI_ACL_FILE;
178 break;
179 case ACL_TYPE_DEFAULT:
180 if (!S_ISDIR(inode->i_mode))
181 return acl ? -EACCES : 0;
182 ea_name = SGI_ACL_DEFAULT;
183 break;
184 default:
185 return -EINVAL;
186 }
187
188 if (acl) {
189 struct xfs_acl *xfs_acl;
190 int len;
191
192 xfs_acl = kzalloc(sizeof(struct xfs_acl), GFP_KERNEL);
193 if (!xfs_acl)
194 return -ENOMEM;
195
196 xfs_acl_to_disk(xfs_acl, acl);
197 len = sizeof(struct xfs_acl) -
198 (sizeof(struct xfs_acl_entry) *
199 (XFS_ACL_MAX_ENTRIES - acl->a_count));
200
201 error = -xfs_attr_set(ip, ea_name, (unsigned char *)xfs_acl,
202 len, ATTR_ROOT);
203
204 kfree(xfs_acl);
205 } else {
206 /*
207 * A NULL ACL argument means we want to remove the ACL.
208 */
209 error = -xfs_attr_remove(ip, ea_name, ATTR_ROOT);
210
211 /*
212 * If the attribute didn't exist to start with that's fine.
213 */
214 if (error == -ENOATTR)
215 error = 0;
216 }
217
218 if (!error)
219 set_cached_acl(inode, type, acl);
220 return error;
221}
222
223static int
224xfs_set_mode(struct inode *inode, umode_t mode)
225{
226 int error = 0;
227
228 if (mode != inode->i_mode) {
229 struct iattr iattr;
230
231 iattr.ia_valid = ATTR_MODE | ATTR_CTIME;
232 iattr.ia_mode = mode;
233 iattr.ia_ctime = current_fs_time(inode->i_sb);
234
235 error = -xfs_setattr_nonsize(XFS_I(inode), &iattr, XFS_ATTR_NOACL);
236 }
237
238 return error;
239}
240
241static int
242xfs_acl_exists(struct inode *inode, unsigned char *name)
243{
244 int len = sizeof(struct xfs_acl);
245
246 return (xfs_attr_get(XFS_I(inode), name, NULL, &len,
247 ATTR_ROOT|ATTR_KERNOVAL) == 0);
248}
249
250int
251posix_acl_access_exists(struct inode *inode)
252{
253 return xfs_acl_exists(inode, SGI_ACL_FILE);
254}
255
256int
257posix_acl_default_exists(struct inode *inode)
258{
259 if (!S_ISDIR(inode->i_mode))
260 return 0;
261 return xfs_acl_exists(inode, SGI_ACL_DEFAULT);
262}
263
264/*
265 * No need for i_mutex because the inode is not yet exposed to the VFS.
266 */
267int
268xfs_inherit_acl(struct inode *inode, struct posix_acl *acl)
269{
270 umode_t mode = inode->i_mode;
271 int error = 0, inherit = 0;
272
273 if (S_ISDIR(inode->i_mode)) {
274 error = xfs_set_acl(inode, ACL_TYPE_DEFAULT, acl);
275 if (error)
276 goto out;
277 }
278
279 error = posix_acl_create(&acl, GFP_KERNEL, &mode);
280 if (error < 0)
281 return error;
282
283 /*
284 * If posix_acl_create returns a positive value we need to
285 * inherit a permission that can't be represented using the Unix
286 * mode bits and we actually need to set an ACL.
287 */
288 if (error > 0)
289 inherit = 1;
290
291 error = xfs_set_mode(inode, mode);
292 if (error)
293 goto out;
294
295 if (inherit)
296 error = xfs_set_acl(inode, ACL_TYPE_ACCESS, acl);
297
298out:
299 posix_acl_release(acl);
300 return error;
301}
302
303int
304xfs_acl_chmod(struct inode *inode)
305{
306 struct posix_acl *acl;
307 int error;
308
309 if (S_ISLNK(inode->i_mode))
310 return -EOPNOTSUPP;
311
312 acl = xfs_get_acl(inode, ACL_TYPE_ACCESS);
313 if (IS_ERR(acl) || !acl)
314 return PTR_ERR(acl);
315
316 error = posix_acl_chmod(&acl, GFP_KERNEL, inode->i_mode);
317 if (error)
318 return error;
319
320 error = xfs_set_acl(inode, ACL_TYPE_ACCESS, acl);
321 posix_acl_release(acl);
322 return error;
323}
324
325static int
326xfs_xattr_acl_get(struct dentry *dentry, const char *name,
327 void *value, size_t size, int type)
328{
329 struct posix_acl *acl;
330 int error;
331
332 acl = xfs_get_acl(dentry->d_inode, type);
333 if (IS_ERR(acl))
334 return PTR_ERR(acl);
335 if (acl == NULL)
336 return -ENODATA;
337
338 error = posix_acl_to_xattr(acl, value, size);
339 posix_acl_release(acl);
340
341 return error;
342}
343
344static int
345xfs_xattr_acl_set(struct dentry *dentry, const char *name,
346 const void *value, size_t size, int flags, int type)
347{
348 struct inode *inode = dentry->d_inode;
349 struct posix_acl *acl = NULL;
350 int error = 0;
351
352 if (flags & XATTR_CREATE)
353 return -EINVAL;
354 if (type == ACL_TYPE_DEFAULT && !S_ISDIR(inode->i_mode))
355 return value ? -EACCES : 0;
356 if ((current_fsuid() != inode->i_uid) && !capable(CAP_FOWNER))
357 return -EPERM;
358
359 if (!value)
360 goto set_acl;
361
362 acl = posix_acl_from_xattr(value, size);
363 if (!acl) {
364 /*
365 * acl_set_file(3) may request that we set default ACLs with
366 * zero length -- defend (gracefully) against that here.
367 */
368 goto out;
369 }
370 if (IS_ERR(acl)) {
371 error = PTR_ERR(acl);
372 goto out;
373 }
374
375 error = posix_acl_valid(acl);
376 if (error)
377 goto out_release;
378
379 error = -EINVAL;
380 if (acl->a_count > XFS_ACL_MAX_ENTRIES)
381 goto out_release;
382
383 if (type == ACL_TYPE_ACCESS) {
384 umode_t mode = inode->i_mode;
385 error = posix_acl_equiv_mode(acl, &mode);
386
387 if (error <= 0) {
388 posix_acl_release(acl);
389 acl = NULL;
390
391 if (error < 0)
392 return error;
393 }
394
395 error = xfs_set_mode(inode, mode);
396 if (error)
397 goto out_release;
398 }
399
400 set_acl:
401 error = xfs_set_acl(inode, type, acl);
402 out_release:
403 posix_acl_release(acl);
404 out:
405 return error;
406}
407
408const struct xattr_handler xfs_xattr_acl_access_handler = {
409 .prefix = POSIX_ACL_XATTR_ACCESS,
410 .flags = ACL_TYPE_ACCESS,
411 .get = xfs_xattr_acl_get,
412 .set = xfs_xattr_acl_set,
413};
414
415const struct xattr_handler xfs_xattr_acl_default_handler = {
416 .prefix = POSIX_ACL_XATTR_DEFAULT,
417 .flags = ACL_TYPE_DEFAULT,
418 .get = xfs_xattr_acl_get,
419 .set = xfs_xattr_acl_set,
420};