2 * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
3 * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
5 * This copyrighted material is made available to anyone wishing to use,
6 * modify, copy, or redistribute it subject to the terms and conditions
7 * of the GNU General Public License version 2.
10 #include <linux/sched.h>
11 #include <linux/slab.h>
12 #include <linux/spinlock.h>
13 #include <linux/completion.h>
14 #include <linux/buffer_head.h>
15 #include <linux/posix_acl.h>
16 #include <linux/posix_acl_xattr.h>
17 #include <linux/gfs2_ondisk.h>
32 int gfs2_acl_validate_set(struct gfs2_inode
*ip
, int access
,
33 struct gfs2_ea_request
*er
, int *remove
, mode_t
*mode
)
35 struct posix_acl
*acl
;
38 error
= gfs2_acl_validate_remove(ip
, access
);
45 acl
= posix_acl_from_xattr(er
->er_data
, er
->er_data_len
);
53 error
= posix_acl_valid(acl
);
58 error
= posix_acl_equiv_mode(acl
, mode
);
66 posix_acl_release(acl
);
70 int gfs2_acl_validate_remove(struct gfs2_inode
*ip
, int access
)
72 if (!GFS2_SB(&ip
->i_inode
)->sd_args
.ar_posix_acl
)
74 if (!is_owner_or_cap(&ip
->i_inode
))
76 if (S_ISLNK(ip
->i_inode
.i_mode
))
78 if (!access
&& !S_ISDIR(ip
->i_inode
.i_mode
))
84 static int acl_get(struct gfs2_inode
*ip
, const char *name
,
85 struct posix_acl
**acl
, struct gfs2_ea_location
*el
,
86 char **datap
, unsigned int *lenp
)
97 error
= gfs2_ea_find(ip
, GFS2_EATYPE_SYS
, name
, el
);
102 if (!GFS2_EA_DATA_LEN(el
->el_ea
))
105 len
= GFS2_EA_DATA_LEN(el
->el_ea
);
106 data
= kmalloc(len
, GFP_NOFS
);
111 error
= gfs2_ea_get_copy(ip
, el
, data
, len
);
117 *acl
= posix_acl_from_xattr(data
, len
);
119 error
= PTR_ERR(*acl
);
123 if (error
|| !datap
) {
134 * gfs2_check_acl - Check an ACL to see if we're allowed to do something
135 * @inode: the file we want to do something to
136 * @mask: what we want to do
141 int gfs2_check_acl(struct inode
*inode
, int mask
)
143 struct gfs2_ea_location el
;
144 struct posix_acl
*acl
= NULL
;
147 error
= acl_get(GFS2_I(inode
), GFS2_POSIX_ACL_ACCESS
, &acl
, &el
, NULL
, NULL
);
153 error
= posix_acl_permission(inode
, acl
, mask
);
154 posix_acl_release(acl
);
161 static int munge_mode(struct gfs2_inode
*ip
, mode_t mode
)
163 struct gfs2_sbd
*sdp
= GFS2_SB(&ip
->i_inode
);
164 struct buffer_head
*dibh
;
167 error
= gfs2_trans_begin(sdp
, RES_DINODE
, 0);
171 error
= gfs2_meta_inode_buffer(ip
, &dibh
);
173 gfs2_assert_withdraw(sdp
,
174 (ip
->i_inode
.i_mode
& S_IFMT
) == (mode
& S_IFMT
));
175 ip
->i_inode
.i_mode
= mode
;
176 gfs2_trans_add_bh(ip
->i_gl
, dibh
, 1);
177 gfs2_dinode_out(ip
, dibh
->b_data
);
186 int gfs2_acl_create(struct gfs2_inode
*dip
, struct gfs2_inode
*ip
)
188 struct gfs2_ea_location el
;
189 struct gfs2_sbd
*sdp
= GFS2_SB(&dip
->i_inode
);
190 struct posix_acl
*acl
= NULL
, *clone
;
191 mode_t mode
= ip
->i_inode
.i_mode
;
196 if (!sdp
->sd_args
.ar_posix_acl
)
198 if (S_ISLNK(ip
->i_inode
.i_mode
))
201 error
= acl_get(dip
, GFS2_POSIX_ACL_DEFAULT
, &acl
, &el
, &data
, &len
);
206 mode
&= ~current_umask();
207 if (mode
!= ip
->i_inode
.i_mode
)
208 error
= munge_mode(ip
, mode
);
212 clone
= posix_acl_clone(acl
, GFP_NOFS
);
216 posix_acl_release(acl
);
219 if (S_ISDIR(ip
->i_inode
.i_mode
)) {
220 error
= gfs2_xattr_set(&ip
->i_inode
, GFS2_EATYPE_SYS
,
221 GFS2_POSIX_ACL_DEFAULT
, data
, len
, 0);
226 error
= posix_acl_create_masq(acl
, &mode
);
232 posix_acl_to_xattr(acl
, data
, len
);
233 error
= gfs2_xattr_set(&ip
->i_inode
, GFS2_EATYPE_SYS
,
234 GFS2_POSIX_ACL_ACCESS
, data
, len
, 0);
238 error
= munge_mode(ip
, mode
);
240 posix_acl_release(acl
);
245 int gfs2_acl_chmod(struct gfs2_inode
*ip
, struct iattr
*attr
)
247 struct posix_acl
*acl
= NULL
, *clone
;
248 struct gfs2_ea_location el
;
253 error
= acl_get(ip
, GFS2_POSIX_ACL_ACCESS
, &acl
, &el
, &data
, &len
);
257 return gfs2_setattr_simple(ip
, attr
);
259 clone
= posix_acl_clone(acl
, GFP_NOFS
);
263 posix_acl_release(acl
);
266 error
= posix_acl_chmod_masq(acl
, attr
->ia_mode
);
268 posix_acl_to_xattr(acl
, data
, len
);
269 error
= gfs2_ea_acl_chmod(ip
, &el
, attr
, data
);
273 posix_acl_release(acl
);