GFS: ea and acl
Subsystems (2)
PATCH 8/16 GFS: ea and acl
Code that handles extended attributes and ACL's.
Signed-off-by Ken Preslan <[email protected]>
Signed-off-by David Teigland <[email protected]>
---
fs/gfs2/acl.c | 312 ++++++++++ fs/gfs2/acl.h | 37 + fs/gfs2/eaops.c | 185 ++++++ fs/gfs2/eaops.h | 30 + fs/gfs2/eattr.c | 1620 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ fs/gfs2/eattr.h | 91 +++ 6 files changed, 2275 insertions(+)
fs/gfs2/acl.c +312 -0
@@ -0,0 +1,312 @@ +/* +* Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. +* Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. +* +* This copyrighted material is made available to anyone wishing to use, +* modify, copy, or redistribute it subject to the terms and conditions +* of the GNU General Public License v.2. +*/ + +#include <linux/sched.h> +#include <linux/slab.h> +#include <linux/spinlock.h> +#include <linux/completion.h> +#include <linux/buffer_head.h> +#include <linux/posix_acl.h> +#include <linux/posix_acl_xattr.h> +#include <asm/semaphore.h> + +#include "gfs2.h" +#include "acl.h" +#include "eaops.h" +#include "eattr.h" +#include "glock.h" +#include "inode.h" +#include "meta_io.h" +#include "trans.h" + +#define ACL_ACCESS 1 +#define ACL_DEFAULT 0 + +int gfs2_acl_validate_set (struct gfs2_inode *ip,int access, +struct gfs2_ea_request *er, +int *remove,mode_t *mode) +{ +struct posix_acl *acl; +int error; + + error =gfs2_acl_validate_remove (ip, access); +if (error) +return error; + +if (!er->er_data) +return -EINVAL ; + + acl =posix_acl_from_xattr (er->er_data, er->er_data_len); +if (IS_ERR (acl)) +return PTR_ERR (acl); +if (!acl) { + *remove =1 ; +return 0 ; + } + + error =posix_acl_valid (acl); +if (error) + goto out; + +if (access) { + error =posix_acl_equiv_mode (acl, mode); +if (!error) + *remove =1 ; +else if (error >0 ) + error =0 ; + } + + out: +posix_acl_release (acl); + +return error; +} + +int gfs2_acl_validate_remove (struct gfs2_inode *ip,int access) +{ +if (!ip->i_sbd->sd_args.ar_posix_acl) +return -EOPNOTSUPP ; +if (current->fsuid != ip->i_di.di_uid && !capable (CAP_FOWNER )) +return -EPERM ; +if (S_ISLNK (ip->i_di.di_mode)) +return -EOPNOTSUPP ; +if (!access && !S_ISDIR (ip->i_di.di_mode)) +return -EACCES ; + +return 0 ; +} + +static int acl_get (struct gfs2_inode *ip,int access,struct posix_acl **acl, +struct gfs2_ea_location *el,char **data,unsigned int *len) +{ +struct gfs2_ea_request er; +struct gfs2_ea_location el_this; +int error; + +if (!ip->i_di.di_eattr) +return 0 ; + +memset (&er,0 ,sizeof (struct gfs2_ea_request )); +if (access) { + er.er_name =GFS2_POSIX_ACL_ACCESS ; + er.er_name_len =GFS2_POSIX_ACL_ACCESS_LEN ; + }else { + er.er_name =GFS2_POSIX_ACL_DEFAULT ; + er.er_name_len =GFS2_POSIX_ACL_DEFAULT_LEN ; + } + er.er_type =GFS2_EATYPE_SYS ; + +if (!el) + el = &el_this; + + error =gfs2_ea_find (ip, &er, el); +if (error) +return error; +if (!el->el_ea) +return 0 ; +if (!GFS2_EA_DATA_LEN (el->el_ea)) + goto out; + + er.er_data_len =GFS2_EA_DATA_LEN (el->el_ea); + er.er_data =kmalloc (er.er_data_len,GFP_KERNEL ); + error = -ENOMEM ; +if (!er.er_data) + goto out; + + error =gfs2_ea_get_copy (ip, el, er.er_data); +if (error) + goto out_kfree; + +if (acl) { + *acl =posix_acl_from_xattr (er.er_data, er.er_data_len); +if (IS_ERR (*acl)) + error =PTR_ERR (*acl); + } + + out_kfree: +if (error || !data) +kfree (er.er_data); +else { + *data = er.er_data; + *len = er.er_data_len; + } + + out: +if (error || el == &el_this) +brelse (el->el_bh); + +return error; +} + +/** +* gfs2_check_acl_locked - Check an ACL to see if we're allowed to do something +* @inode: the file we want to do something to +* @mask: what we want to do +* +* Returns: errno +*/ + +int gfs2_check_acl_locked (struct inode *inode,int mask) +{ +struct posix_acl *acl =NULL ; +int error; + + error =acl_get (get_v2ip (inode),ACL_ACCESS , &acl,NULL ,NULL ,NULL ); +if (error) +return error; + +if (acl) { + error =posix_acl_permission (inode, acl, mask); +posix_acl_release (acl); +return error; + } + +return -EAGAIN ; +} + +int gfs2_check_acl (struct inode *inode,int mask) +{ +struct gfs2_inode *ip =get_v2ip (inode); +struct gfs2_holder i_gh; +int error; + + error =gfs2_glock_nq_init (ip->i_gl, +LM_ST_SHARED ,LM_FLAG_ANY , + &i_gh); +if (!error) { + error =gfs2_check_acl_locked (inode, mask); +gfs2_glock_dq_uninit (&i_gh); + } + +return error; +} + +static int munge_mode (struct gfs2_inode *ip,mode_t mode) +{ +struct gfs2_sbd *sdp = ip->i_sbd; +struct buffer_head *dibh; +int error; + + error =gfs2_trans_begin (sdp,RES_DINODE ,0 ); +if (error) +return error; + + error =gfs2_meta_inode_buffer (ip, &dibh); +if (!error) { +gfs2_assert_withdraw (sdp, + (ip->i_di.di_mode &S_IFMT ) == (mode &S_IFMT )); + ip->i_di.di_mode = mode; +gfs2_trans_add_bh (ip->i_gl, dibh); +gfs2_dinode_out (&ip->i_di, dibh->b_data); +brelse (dibh); + } + +gfs2_trans_end (sdp); + +return 0 ; +} + +int gfs2_acl_create (struct gfs2_inode *dip,struct gfs2_inode *ip) +{ +struct gfs2_sbd *sdp = dip->i_sbd; +struct posix_acl *acl =NULL , *clone; +struct gfs2_ea_request er; +mode_t mode = ip->i_di.di_mode; +int error; + +if (!sdp->sd_args.ar_posix_acl) +return 0 ; +if (S_ISLNK (ip->i_di.di_mode)) +return 0 ; + +memset (&er,0 ,sizeof (struct gfs2_ea_request )); + er.er_type =GFS2_EATYPE_SYS ; + + error =acl_get (dip,ACL_DEFAULT , &acl,NULL , + &er.er_data, &er.er_data_len); +if (error) +return error; +if (!acl) { + mode &= ~current->fs->umask; +if (mode != ip->i_di.di_mode) + error =munge_mode (ip, mode); +return error; + } + + clone =posix_acl_clone (acl,GFP_KERNEL ); + error = -ENOMEM ; +if (!clone) + goto out; +posix_acl_release (acl); + acl = clone; + +if (S_ISDIR (ip->i_di.di_mode)) { + er.er_name =GFS2_POSIX_ACL_DEFAULT ; + er.er_name_len =GFS2_POSIX_ACL_DEFAULT_LEN ; + error = gfs2_system_eaops.eo_set (ip, &er); +if (error) + goto out; + } + + error =posix_acl_create_masq (acl, &mode); +if (error <0 ) + goto out; +if (error >0 ) { + er.er_name =GFS2_POSIX_ACL_ACCESS ; + er.er_name_len =GFS2_POSIX_ACL_ACCESS_LEN ; +posix_acl_to_xattr (acl, er.er_data, er.er_data_len); + er.er_mode = mode; + er.er_flags =GFS2_ERF_MODE ; + error = gfs2_system_eaops.eo_set (ip, &er); +if (error) + goto out; + }else +munge_mode (ip, mode); + + out: +posix_acl_release (acl); +kfree (er.er_data); +return error; +} + +int gfs2_acl_chmod (struct gfs2_inode *ip,struct iattr *attr) +{ +struct posix_acl *acl =NULL , *clone; +struct gfs2_ea_location el; +char *data; +unsigned int len; +int error; + + error =acl_get (ip,ACL_ACCESS , &acl, &el, &data, &len); +if (error) +return error; +if (!acl) +return gfs2_setattr_simple (ip, attr); + + clone =posix_acl_clone (acl,GFP_KERNEL ); + error = -ENOMEM ; +if (!clone) + goto out; +posix_acl_release (acl); + acl = clone; + + error =posix_acl_chmod_masq (acl, attr->ia_mode); +if (!error) { +posix_acl_to_xattr (acl, data, len); + error =gfs2_ea_acl_chmod (ip, &el, attr, data); + } + + out: +posix_acl_release (acl); +brelse (el.el_bh); +kfree (data); + +return error; +} +
fs/gfs2/acl.h +37 -0
@@ -0,0 +1,37 @@ +/* +* Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. +* Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. +* +* This copyrighted material is made available to anyone wishing to use, +* modify, copy, or redistribute it subject to the terms and conditions +* of the GNU General Public License v.2. +*/ + +#ifndef __ACL_DOT_H__ +#define __ACL_DOT_H__ + +#define GFS2_POSIX_ACL_ACCESS "posix_acl_access" +#define GFS2_POSIX_ACL_ACCESS_LEN 16 +#define GFS2_POSIX_ACL_DEFAULT "posix_acl_default" +#define GFS2_POSIX_ACL_DEFAULT_LEN 17 + +#define GFS2_ACL_IS_ACCESS (name, len) \ + ((len) == GFS2_POSIX_ACL_ACCESS_LEN && \ + !memcmp(GFS2_POSIX_ACL_ACCESS, (name), (len))) + +#define GFS2_ACL_IS_DEFAULT (name, len) \ + ((len) == GFS2_POSIX_ACL_DEFAULT_LEN && \ + !memcmp(GFS2_POSIX_ACL_DEFAULT, (name), (len))) + +struct gfs2_ea_request ; + +int gfs2_acl_validate_set (struct gfs2_inode *ip,int access, +struct gfs2_ea_request *er, +int *remove,mode_t *mode); +int gfs2_acl_validate_remove (struct gfs2_inode *ip,int access); +int gfs2_check_acl_locked (struct inode *inode,int mask); +int gfs2_check_acl (struct inode *inode,int mask); +int gfs2_acl_create (struct gfs2_inode *dip,struct gfs2_inode *ip); +int gfs2_acl_chmod (struct gfs2_inode *ip,struct iattr *attr); + +#endif /* __ACL_DOT_H__ */
fs/gfs2/eattr.c +1620 -0
1,620 lines not on this page · raw message
fs/gfs2/eattr.h +91 -0
91 lines not on this page · raw message
fs/gfs2/eaops.c +185 -0
185 lines not on this page · raw message
fs/gfs2/eaops.h +30 -0
@@ -0,0 +1,30 @@ +/* +* Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. +* Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. +* +* This copyrighted material is made available to anyone wishing to use, +* modify, copy, or redistribute it subject to the terms and conditions +* of the GNU General Public License v.2. +*/ + +#ifndef __EAOPS_DOT_H__ +#define __EAOPS_DOT_H__ + +struct gfs2_ea_request ; + +struct gfs2_eattr_operations { +int (*eo_get) (struct gfs2_inode *ip,struct gfs2_ea_request *er); +int (*eo_set) (struct gfs2_inode *ip,struct gfs2_ea_request *er); +int (*eo_remove) (struct gfs2_inode *ip,struct gfs2_ea_request *er); +char *eo_name; +}; + +unsigned int gfs2_ea_name2type (const char *name,char **truncated_name); + +extern struct gfs2_eattr_operations gfs2_user_eaops; +extern struct gfs2_eattr_operations gfs2_system_eaops; + +extern struct gfs2_eattr_operations *gfs2_ea_ops[]; + +#endif /* __EAOPS_DOT_H__ */ +