aboutsummaryrefslogtreecommitdiffstats
path: root/fs/gfs2/acl.c
diff options
context:
space:
mode:
authorSteven Whitehouse <swhiteho@redhat.com>2009-10-02 06:50:54 -0400
committerSteven Whitehouse <swhiteho@redhat.com>2009-12-03 06:43:05 -0500
commit2646a1f61a3b5525914757f10fa12b5b94713648 (patch)
tree9f6b7bdad5fb85963cbf05d2215f960b7ac3beaa /fs/gfs2/acl.c
parentf55073ff1eaf99f6b3bc62134a456638bca043a3 (diff)
GFS2: Fix up system xattrs
This code has been shamelessly stolen from XFS at the suggestion of Christoph Hellwig. I've not added support for cached ACLs so far... watch for that in a later patch, although this is designed in such a way that they should be easy to add. Signed-off-by: Steven Whitehouse <swhiteho@redhat.com> Cc: Christoph Hellwig <hch@infradead.org>
Diffstat (limited to 'fs/gfs2/acl.c')
-rw-r--r--fs/gfs2/acl.c170
1 files changed, 115 insertions, 55 deletions
diff --git a/fs/gfs2/acl.c b/fs/gfs2/acl.c
index 3fc4e3ac7d84..2168da121647 100644
--- a/fs/gfs2/acl.c
+++ b/fs/gfs2/acl.c
@@ -12,6 +12,7 @@
12#include <linux/spinlock.h> 12#include <linux/spinlock.h>
13#include <linux/completion.h> 13#include <linux/completion.h>
14#include <linux/buffer_head.h> 14#include <linux/buffer_head.h>
15#include <linux/xattr.h>
15#include <linux/posix_acl.h> 16#include <linux/posix_acl.h>
16#include <linux/posix_acl_xattr.h> 17#include <linux/posix_acl_xattr.h>
17#include <linux/gfs2_ondisk.h> 18#include <linux/gfs2_ondisk.h>
@@ -26,61 +27,6 @@
26#include "trans.h" 27#include "trans.h"
27#include "util.h" 28#include "util.h"
28 29
29#define ACL_ACCESS 1
30#define ACL_DEFAULT 0
31
32int gfs2_acl_validate_set(struct gfs2_inode *ip, int access,
33 struct gfs2_ea_request *er, int *remove, mode_t *mode)
34{
35 struct posix_acl *acl;
36 int error;
37
38 error = gfs2_acl_validate_remove(ip, access);
39 if (error)
40 return error;
41
42 if (!er->er_data)
43 return -EINVAL;
44
45 acl = posix_acl_from_xattr(er->er_data, er->er_data_len);
46 if (IS_ERR(acl))
47 return PTR_ERR(acl);
48 if (!acl) {
49 *remove = 1;
50 return 0;
51 }
52
53 error = posix_acl_valid(acl);
54 if (error)
55 goto out;
56
57 if (access) {
58 error = posix_acl_equiv_mode(acl, mode);
59 if (!error)
60 *remove = 1;
61 else if (error > 0)
62 error = 0;
63 }
64
65out:
66 posix_acl_release(acl);
67 return error;
68}
69
70int gfs2_acl_validate_remove(struct gfs2_inode *ip, int access)
71{
72 if (!GFS2_SB(&ip->i_inode)->sd_args.ar_posix_acl)
73 return -EOPNOTSUPP;
74 if (!is_owner_or_cap(&ip->i_inode))
75 return -EPERM;
76 if (S_ISLNK(ip->i_inode.i_mode))
77 return -EOPNOTSUPP;
78 if (!access && !S_ISDIR(ip->i_inode.i_mode))
79 return -EACCES;
80
81 return 0;
82}
83
84static int acl_get(struct gfs2_inode *ip, const char *name, 30static int acl_get(struct gfs2_inode *ip, const char *name,
85 struct posix_acl **acl, struct gfs2_ea_location *el, 31 struct posix_acl **acl, struct gfs2_ea_location *el,
86 char **datap, unsigned int *lenp) 32 char **datap, unsigned int *lenp)
@@ -277,3 +223,117 @@ out_brelse:
277 return error; 223 return error;
278} 224}
279 225
226static int gfs2_acl_type(const char *name)
227{
228 if (strcmp(name, GFS2_POSIX_ACL_ACCESS) == 0)
229 return ACL_TYPE_ACCESS;
230 if (strcmp(name, GFS2_POSIX_ACL_DEFAULT) == 0)
231 return ACL_TYPE_DEFAULT;
232 return -EINVAL;
233}
234
235static int gfs2_xattr_system_get(struct inode *inode, const char *name,
236 void *buffer, size_t size)
237{
238 int type;
239
240 type = gfs2_acl_type(name);
241 if (type < 0)
242 return type;
243
244 return gfs2_xattr_get(inode, GFS2_EATYPE_SYS, name, buffer, size);
245}
246
247static int gfs2_set_mode(struct inode *inode, mode_t mode)
248{
249 int error = 0;
250
251 if (mode != inode->i_mode) {
252 struct iattr iattr;
253
254 iattr.ia_valid = ATTR_MODE;
255 iattr.ia_mode = mode;
256
257 error = gfs2_setattr_simple(GFS2_I(inode), &iattr);
258 }
259
260 return error;
261}
262
263static int gfs2_xattr_system_set(struct inode *inode, const char *name,
264 const void *value, size_t size, int flags)
265{
266 struct gfs2_sbd *sdp = GFS2_SB(inode);
267 struct posix_acl *acl = NULL;
268 int error = 0, type;
269
270 if (!sdp->sd_args.ar_posix_acl)
271 return -EOPNOTSUPP;
272
273 type = gfs2_acl_type(name);
274 if (type < 0)
275 return type;
276 if (flags & XATTR_CREATE)
277 return -EINVAL;
278 if (type == ACL_TYPE_DEFAULT && !S_ISDIR(inode->i_mode))
279 return value ? -EACCES : 0;
280 if ((current_fsuid() != inode->i_uid) && !capable(CAP_FOWNER))
281 return -EPERM;
282 if (S_ISLNK(inode->i_mode))
283 return -EOPNOTSUPP;
284
285 if (!value)
286 goto set_acl;
287
288 acl = posix_acl_from_xattr(value, size);
289 if (!acl) {
290 /*
291 * acl_set_file(3) may request that we set default ACLs with
292 * zero length -- defend (gracefully) against that here.
293 */
294 goto out;
295 }
296 if (IS_ERR(acl)) {
297 error = PTR_ERR(acl);
298 goto out;
299 }
300
301 error = posix_acl_valid(acl);
302 if (error)
303 goto out_release;
304
305 error = -EINVAL;
306 if (acl->a_count > GFS2_ACL_MAX_ENTRIES)
307 goto out_release;
308
309 if (type == ACL_TYPE_ACCESS) {
310 mode_t mode = inode->i_mode;
311 error = posix_acl_equiv_mode(acl, &mode);
312
313 if (error <= 0) {
314 posix_acl_release(acl);
315 acl = NULL;
316
317 if (error < 0)
318 return error;
319 }
320
321 error = gfs2_set_mode(inode, mode);
322 if (error)
323 goto out_release;
324 }
325
326set_acl:
327 error = gfs2_xattr_set(inode, GFS2_EATYPE_SYS, name, value, size, 0);
328out_release:
329 posix_acl_release(acl);
330out:
331 return error;
332}
333
334struct xattr_handler gfs2_xattr_system_handler = {
335 .prefix = XATTR_SYSTEM_PREFIX,
336 .get = gfs2_xattr_system_get,
337 .set = gfs2_xattr_system_set,
338};
339