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/xattr.h>
16 #include <linux/posix_acl.h>
17 #include <linux/posix_acl_xattr.h>
18 #include <linux/gfs2_ondisk.h>
30 static int acl_get(struct gfs2_inode
*ip
, const char *name
,
31 struct posix_acl
**acl
, struct gfs2_ea_location
*el
,
32 char **datap
, unsigned int *lenp
)
43 error
= gfs2_ea_find(ip
, GFS2_EATYPE_SYS
, name
, el
);
48 if (!GFS2_EA_DATA_LEN(el
->el_ea
))
51 len
= GFS2_EA_DATA_LEN(el
->el_ea
);
52 data
= kmalloc(len
, GFP_NOFS
);
57 error
= gfs2_ea_get_copy(ip
, el
, data
, len
);
63 *acl
= posix_acl_from_xattr(data
, len
);
65 error
= PTR_ERR(*acl
);
69 if (error
|| !datap
) {
80 * gfs2_check_acl - Check an ACL to see if we're allowed to do something
81 * @inode: the file we want to do something to
82 * @mask: what we want to do
87 int gfs2_check_acl(struct inode
*inode
, int mask
)
89 struct gfs2_ea_location el
;
90 struct posix_acl
*acl
= NULL
;
93 error
= acl_get(GFS2_I(inode
), GFS2_POSIX_ACL_ACCESS
, &acl
, &el
, NULL
, NULL
);
99 error
= posix_acl_permission(inode
, acl
, mask
);
100 posix_acl_release(acl
);
107 static int munge_mode(struct gfs2_inode
*ip
, mode_t mode
)
109 struct gfs2_sbd
*sdp
= GFS2_SB(&ip
->i_inode
);
110 struct buffer_head
*dibh
;
113 error
= gfs2_trans_begin(sdp
, RES_DINODE
, 0);
117 error
= gfs2_meta_inode_buffer(ip
, &dibh
);
119 gfs2_assert_withdraw(sdp
,
120 (ip
->i_inode
.i_mode
& S_IFMT
) == (mode
& S_IFMT
));
121 ip
->i_inode
.i_mode
= mode
;
122 gfs2_trans_add_bh(ip
->i_gl
, dibh
, 1);
123 gfs2_dinode_out(ip
, dibh
->b_data
);
132 int gfs2_acl_create(struct gfs2_inode
*dip
, struct gfs2_inode
*ip
)
134 struct gfs2_ea_location el
;
135 struct gfs2_sbd
*sdp
= GFS2_SB(&dip
->i_inode
);
136 struct posix_acl
*acl
= NULL
, *clone
;
137 mode_t mode
= ip
->i_inode
.i_mode
;
142 if (!sdp
->sd_args
.ar_posix_acl
)
144 if (S_ISLNK(ip
->i_inode
.i_mode
))
147 error
= acl_get(dip
, GFS2_POSIX_ACL_DEFAULT
, &acl
, &el
, &data
, &len
);
152 mode
&= ~current_umask();
153 if (mode
!= ip
->i_inode
.i_mode
)
154 error
= munge_mode(ip
, mode
);
158 clone
= posix_acl_clone(acl
, GFP_NOFS
);
162 posix_acl_release(acl
);
165 if (S_ISDIR(ip
->i_inode
.i_mode
)) {
166 error
= gfs2_xattr_set(&ip
->i_inode
, GFS2_EATYPE_SYS
,
167 GFS2_POSIX_ACL_DEFAULT
, data
, len
, 0);
172 error
= posix_acl_create_masq(acl
, &mode
);
178 posix_acl_to_xattr(acl
, data
, len
);
179 error
= gfs2_xattr_set(&ip
->i_inode
, GFS2_EATYPE_SYS
,
180 GFS2_POSIX_ACL_ACCESS
, data
, len
, 0);
184 error
= munge_mode(ip
, mode
);
186 posix_acl_release(acl
);
191 int gfs2_acl_chmod(struct gfs2_inode
*ip
, struct iattr
*attr
)
193 struct posix_acl
*acl
= NULL
, *clone
;
194 struct gfs2_ea_location el
;
199 error
= acl_get(ip
, GFS2_POSIX_ACL_ACCESS
, &acl
, &el
, &data
, &len
);
203 return gfs2_setattr_simple(ip
, attr
);
205 clone
= posix_acl_clone(acl
, GFP_NOFS
);
209 posix_acl_release(acl
);
212 error
= posix_acl_chmod_masq(acl
, attr
->ia_mode
);
214 posix_acl_to_xattr(acl
, data
, len
);
215 error
= gfs2_ea_acl_chmod(ip
, &el
, attr
, data
);
219 posix_acl_release(acl
);
226 static int gfs2_acl_type(const char *name
)
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
;
235 static int gfs2_xattr_system_get(struct inode
*inode
, const char *name
,
236 void *buffer
, size_t size
)
240 type
= gfs2_acl_type(name
);
244 return gfs2_xattr_get(inode
, GFS2_EATYPE_SYS
, name
, buffer
, size
);
247 static int gfs2_set_mode(struct inode
*inode
, mode_t mode
)
251 if (mode
!= inode
->i_mode
) {
254 iattr
.ia_valid
= ATTR_MODE
;
255 iattr
.ia_mode
= mode
;
257 error
= gfs2_setattr_simple(GFS2_I(inode
), &iattr
);
263 static int gfs2_xattr_system_set(struct inode
*inode
, const char *name
,
264 const void *value
, size_t size
, int flags
)
266 struct gfs2_sbd
*sdp
= GFS2_SB(inode
);
267 struct posix_acl
*acl
= NULL
;
270 if (!sdp
->sd_args
.ar_posix_acl
)
273 type
= gfs2_acl_type(name
);
276 if (flags
& XATTR_CREATE
)
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
))
282 if (S_ISLNK(inode
->i_mode
))
288 acl
= posix_acl_from_xattr(value
, size
);
291 * acl_set_file(3) may request that we set default ACLs with
292 * zero length -- defend (gracefully) against that here.
297 error
= PTR_ERR(acl
);
301 error
= posix_acl_valid(acl
);
306 if (acl
->a_count
> GFS2_ACL_MAX_ENTRIES
)
309 if (type
== ACL_TYPE_ACCESS
) {
310 mode_t mode
= inode
->i_mode
;
311 error
= posix_acl_equiv_mode(acl
, &mode
);
314 posix_acl_release(acl
);
321 error
= gfs2_set_mode(inode
, mode
);
327 error
= gfs2_xattr_set(inode
, GFS2_EATYPE_SYS
, name
, value
, size
, 0);
329 posix_acl_release(acl
);
334 struct xattr_handler gfs2_xattr_system_handler
= {
335 .prefix
= XATTR_SYSTEM_PREFIX
,
336 .get
= gfs2_xattr_system_get
,
337 .set
= gfs2_xattr_system_set
,