4 * Copyright (C) 2001-2003 Andreas Gruenbacher, <agruen@suse.de>
12 * Convert from filesystem to in-memory representation.
14 static struct posix_acl
*
15 ext3_acl_from_disk(const void *value
, size_t size
)
17 const char *end
= (char *)value
+ size
;
19 struct posix_acl
*acl
;
23 if (size
< sizeof(ext3_acl_header
))
24 return ERR_PTR(-EINVAL
);
25 if (((ext3_acl_header
*)value
)->a_version
!=
26 cpu_to_le32(EXT3_ACL_VERSION
))
27 return ERR_PTR(-EINVAL
);
28 value
= (char *)value
+ sizeof(ext3_acl_header
);
29 count
= ext3_acl_count(size
);
31 return ERR_PTR(-EINVAL
);
34 acl
= posix_acl_alloc(count
, GFP_NOFS
);
36 return ERR_PTR(-ENOMEM
);
37 for (n
=0; n
< count
; n
++) {
38 ext3_acl_entry
*entry
=
39 (ext3_acl_entry
*)value
;
40 if ((char *)value
+ sizeof(ext3_acl_entry_short
) > end
)
42 acl
->a_entries
[n
].e_tag
= le16_to_cpu(entry
->e_tag
);
43 acl
->a_entries
[n
].e_perm
= le16_to_cpu(entry
->e_perm
);
44 switch(acl
->a_entries
[n
].e_tag
) {
49 value
= (char *)value
+
50 sizeof(ext3_acl_entry_short
);
54 value
= (char *)value
+ sizeof(ext3_acl_entry
);
55 if ((char *)value
> end
)
57 acl
->a_entries
[n
].e_uid
=
58 make_kuid(&init_user_ns
,
59 le32_to_cpu(entry
->e_id
));
62 value
= (char *)value
+ sizeof(ext3_acl_entry
);
63 if ((char *)value
> end
)
65 acl
->a_entries
[n
].e_gid
=
66 make_kgid(&init_user_ns
,
67 le32_to_cpu(entry
->e_id
));
79 posix_acl_release(acl
);
80 return ERR_PTR(-EINVAL
);
84 * Convert from in-memory to filesystem representation.
87 ext3_acl_to_disk(const struct posix_acl
*acl
, size_t *size
)
89 ext3_acl_header
*ext_acl
;
93 *size
= ext3_acl_size(acl
->a_count
);
94 ext_acl
= kmalloc(sizeof(ext3_acl_header
) + acl
->a_count
*
95 sizeof(ext3_acl_entry
), GFP_NOFS
);
97 return ERR_PTR(-ENOMEM
);
98 ext_acl
->a_version
= cpu_to_le32(EXT3_ACL_VERSION
);
99 e
= (char *)ext_acl
+ sizeof(ext3_acl_header
);
100 for (n
=0; n
< acl
->a_count
; n
++) {
101 const struct posix_acl_entry
*acl_e
= &acl
->a_entries
[n
];
102 ext3_acl_entry
*entry
= (ext3_acl_entry
*)e
;
103 entry
->e_tag
= cpu_to_le16(acl_e
->e_tag
);
104 entry
->e_perm
= cpu_to_le16(acl_e
->e_perm
);
105 switch(acl_e
->e_tag
) {
107 entry
->e_id
= cpu_to_le32(
108 from_kuid(&init_user_ns
, acl_e
->e_uid
));
109 e
+= sizeof(ext3_acl_entry
);
112 entry
->e_id
= cpu_to_le32(
113 from_kgid(&init_user_ns
, acl_e
->e_gid
));
114 e
+= sizeof(ext3_acl_entry
);
121 e
+= sizeof(ext3_acl_entry_short
);
128 return (char *)ext_acl
;
132 return ERR_PTR(-EINVAL
);
136 * Inode operation get_posix_acl().
138 * inode->i_mutex: don't care
141 ext3_get_acl(struct inode
*inode
, int type
)
145 struct posix_acl
*acl
;
148 if (!test_opt(inode
->i_sb
, POSIX_ACL
))
151 acl
= get_cached_acl(inode
, type
);
152 if (acl
!= ACL_NOT_CACHED
)
156 case ACL_TYPE_ACCESS
:
157 name_index
= EXT3_XATTR_INDEX_POSIX_ACL_ACCESS
;
159 case ACL_TYPE_DEFAULT
:
160 name_index
= EXT3_XATTR_INDEX_POSIX_ACL_DEFAULT
;
166 retval
= ext3_xattr_get(inode
, name_index
, "", NULL
, 0);
168 value
= kmalloc(retval
, GFP_NOFS
);
170 return ERR_PTR(-ENOMEM
);
171 retval
= ext3_xattr_get(inode
, name_index
, "", value
, retval
);
174 acl
= ext3_acl_from_disk(value
, retval
);
175 else if (retval
== -ENODATA
|| retval
== -ENOSYS
)
178 acl
= ERR_PTR(retval
);
182 set_cached_acl(inode
, type
, acl
);
188 * Set the access or default ACL of an inode.
190 * inode->i_mutex: down unless called from ext3_new_inode
193 ext3_set_acl(handle_t
*handle
, struct inode
*inode
, int type
,
194 struct posix_acl
*acl
)
201 if (S_ISLNK(inode
->i_mode
))
205 case ACL_TYPE_ACCESS
:
206 name_index
= EXT3_XATTR_INDEX_POSIX_ACL_ACCESS
;
208 error
= posix_acl_update_mode(inode
, &inode
->i_mode
, &acl
);
211 inode
->i_ctime
= CURRENT_TIME_SEC
;
212 ext3_mark_inode_dirty(handle
, inode
);
216 case ACL_TYPE_DEFAULT
:
217 name_index
= EXT3_XATTR_INDEX_POSIX_ACL_DEFAULT
;
218 if (!S_ISDIR(inode
->i_mode
))
219 return acl
? -EACCES
: 0;
226 value
= ext3_acl_to_disk(acl
, &size
);
228 return (int)PTR_ERR(value
);
231 error
= ext3_xattr_set_handle(handle
, inode
, name_index
, "",
237 set_cached_acl(inode
, type
, acl
);
243 * Initialize the ACLs of a new inode. Called from ext3_new_inode.
246 * inode->i_mutex: up (access to inode is still exclusive)
249 ext3_init_acl(handle_t
*handle
, struct inode
*inode
, struct inode
*dir
)
251 struct posix_acl
*acl
= NULL
;
254 if (!S_ISLNK(inode
->i_mode
)) {
255 if (test_opt(dir
->i_sb
, POSIX_ACL
)) {
256 acl
= ext3_get_acl(dir
, ACL_TYPE_DEFAULT
);
261 inode
->i_mode
&= ~current_umask();
263 if (test_opt(inode
->i_sb
, POSIX_ACL
) && acl
) {
264 if (S_ISDIR(inode
->i_mode
)) {
265 error
= ext3_set_acl(handle
, inode
,
266 ACL_TYPE_DEFAULT
, acl
);
270 error
= posix_acl_create(&acl
, GFP_NOFS
, &inode
->i_mode
);
275 /* This is an extended ACL */
276 error
= ext3_set_acl(handle
, inode
, ACL_TYPE_ACCESS
, acl
);
280 posix_acl_release(acl
);
285 * Does chmod for an inode that may have an Access Control List. The
286 * inode->i_mode field must be updated to the desired value by the caller
287 * before calling this function.
288 * Returns 0 on success, or a negative error number.
290 * We change the ACL rather than storing some ACL entries in the file
291 * mode permission bits (which would be more efficient), because that
292 * would break once additional permissions (like ACL_APPEND, ACL_DELETE
293 * for directories) are added. There are no more bits available in the
296 * inode->i_mutex: down
299 ext3_acl_chmod(struct inode
*inode
)
301 struct posix_acl
*acl
;
306 if (S_ISLNK(inode
->i_mode
))
308 if (!test_opt(inode
->i_sb
, POSIX_ACL
))
310 acl
= ext3_get_acl(inode
, ACL_TYPE_ACCESS
);
311 if (IS_ERR(acl
) || !acl
)
313 error
= posix_acl_chmod(&acl
, GFP_KERNEL
, inode
->i_mode
);
317 handle
= ext3_journal_start(inode
,
318 EXT3_DATA_TRANS_BLOCKS(inode
->i_sb
));
319 if (IS_ERR(handle
)) {
320 error
= PTR_ERR(handle
);
321 ext3_std_error(inode
->i_sb
, error
);
324 error
= ext3_set_acl(handle
, inode
, ACL_TYPE_ACCESS
, acl
);
325 ext3_journal_stop(handle
);
326 if (error
== -ENOSPC
&&
327 ext3_should_retry_alloc(inode
->i_sb
, &retries
))
330 posix_acl_release(acl
);
335 * Extended attribute handlers
338 ext3_xattr_list_acl_access(struct dentry
*dentry
, char *list
, size_t list_len
,
339 const char *name
, size_t name_len
, int type
)
341 const size_t size
= sizeof(POSIX_ACL_XATTR_ACCESS
);
343 if (!test_opt(dentry
->d_sb
, POSIX_ACL
))
345 if (list
&& size
<= list_len
)
346 memcpy(list
, POSIX_ACL_XATTR_ACCESS
, size
);
351 ext3_xattr_list_acl_default(struct dentry
*dentry
, char *list
, size_t list_len
,
352 const char *name
, size_t name_len
, int type
)
354 const size_t size
= sizeof(POSIX_ACL_XATTR_DEFAULT
);
356 if (!test_opt(dentry
->d_sb
, POSIX_ACL
))
358 if (list
&& size
<= list_len
)
359 memcpy(list
, POSIX_ACL_XATTR_DEFAULT
, size
);
364 ext3_xattr_get_acl(struct dentry
*dentry
, const char *name
, void *buffer
,
365 size_t size
, int type
)
367 struct posix_acl
*acl
;
370 if (strcmp(name
, "") != 0)
372 if (!test_opt(dentry
->d_sb
, POSIX_ACL
))
375 acl
= ext3_get_acl(dentry
->d_inode
, type
);
380 error
= posix_acl_to_xattr(&init_user_ns
, acl
, buffer
, size
);
381 posix_acl_release(acl
);
387 ext3_xattr_set_acl(struct dentry
*dentry
, const char *name
, const void *value
,
388 size_t size
, int flags
, int type
)
390 struct inode
*inode
= dentry
->d_inode
;
392 struct posix_acl
*acl
;
393 int error
, retries
= 0;
395 if (strcmp(name
, "") != 0)
397 if (!test_opt(inode
->i_sb
, POSIX_ACL
))
399 if (!inode_owner_or_capable(inode
))
403 acl
= posix_acl_from_xattr(&init_user_ns
, value
, size
);
407 error
= posix_acl_valid(acl
);
409 goto release_and_out
;
415 handle
= ext3_journal_start(inode
, EXT3_DATA_TRANS_BLOCKS(inode
->i_sb
));
417 return PTR_ERR(handle
);
418 error
= ext3_set_acl(handle
, inode
, type
, acl
);
419 ext3_journal_stop(handle
);
420 if (error
== -ENOSPC
&& ext3_should_retry_alloc(inode
->i_sb
, &retries
))
424 posix_acl_release(acl
);
428 const struct xattr_handler ext3_xattr_acl_access_handler
= {
429 .prefix
= POSIX_ACL_XATTR_ACCESS
,
430 .flags
= ACL_TYPE_ACCESS
,
431 .list
= ext3_xattr_list_acl_access
,
432 .get
= ext3_xattr_get_acl
,
433 .set
= ext3_xattr_set_acl
,
436 const struct xattr_handler ext3_xattr_acl_default_handler
= {
437 .prefix
= POSIX_ACL_XATTR_DEFAULT
,
438 .flags
= ACL_TYPE_DEFAULT
,
439 .list
= ext3_xattr_list_acl_default
,
440 .get
= ext3_xattr_get_acl
,
441 .set
= ext3_xattr_set_acl
,