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_equiv_mode(acl, &inode->i_mode);
212 inode->i_ctime = CURRENT_TIME_SEC;
213 ext3_mark_inode_dirty(handle, inode);
220 case ACL_TYPE_DEFAULT:
221 name_index = EXT3_XATTR_INDEX_POSIX_ACL_DEFAULT;
222 if (!S_ISDIR(inode->i_mode))
223 return acl ? -EACCES : 0;
230 value = ext3_acl_to_disk(acl, &size);
232 return (int)PTR_ERR(value);
235 error = ext3_xattr_set_handle(handle, inode, name_index, "",
241 set_cached_acl(inode, type, acl);
247 * Initialize the ACLs of a new inode. Called from ext3_new_inode.
250 * inode->i_mutex: up (access to inode is still exclusive)
253 ext3_init_acl(handle_t *handle, struct inode *inode, struct inode *dir)
255 struct posix_acl *acl = NULL;
258 if (!S_ISLNK(inode->i_mode)) {
259 if (test_opt(dir->i_sb, POSIX_ACL)) {
260 acl = ext3_get_acl(dir, ACL_TYPE_DEFAULT);
265 inode->i_mode &= ~current_umask();
267 if (test_opt(inode->i_sb, POSIX_ACL) && acl) {
268 if (S_ISDIR(inode->i_mode)) {
269 error = ext3_set_acl(handle, inode,
270 ACL_TYPE_DEFAULT, acl);
274 error = posix_acl_create(&acl, GFP_NOFS, &inode->i_mode);
279 /* This is an extended ACL */
280 error = ext3_set_acl(handle, inode, ACL_TYPE_ACCESS, acl);
284 posix_acl_release(acl);
289 * Does chmod for an inode that may have an Access Control List. The
290 * inode->i_mode field must be updated to the desired value by the caller
291 * before calling this function.
292 * Returns 0 on success, or a negative error number.
294 * We change the ACL rather than storing some ACL entries in the file
295 * mode permission bits (which would be more efficient), because that
296 * would break once additional permissions (like ACL_APPEND, ACL_DELETE
297 * for directories) are added. There are no more bits available in the
300 * inode->i_mutex: down
303 ext3_acl_chmod(struct inode *inode)
305 struct posix_acl *acl;
310 if (S_ISLNK(inode->i_mode))
312 if (!test_opt(inode->i_sb, POSIX_ACL))
314 acl = ext3_get_acl(inode, ACL_TYPE_ACCESS);
315 if (IS_ERR(acl) || !acl)
317 error = posix_acl_chmod(&acl, GFP_KERNEL, inode->i_mode);
321 handle = ext3_journal_start(inode,
322 EXT3_DATA_TRANS_BLOCKS(inode->i_sb));
323 if (IS_ERR(handle)) {
324 error = PTR_ERR(handle);
325 ext3_std_error(inode->i_sb, error);
328 error = ext3_set_acl(handle, inode, ACL_TYPE_ACCESS, acl);
329 ext3_journal_stop(handle);
330 if (error == -ENOSPC &&
331 ext3_should_retry_alloc(inode->i_sb, &retries))
334 posix_acl_release(acl);
339 * Extended attribute handlers
342 ext3_xattr_list_acl_access(struct dentry *dentry, char *list, size_t list_len,
343 const char *name, size_t name_len, int type)
345 const size_t size = sizeof(POSIX_ACL_XATTR_ACCESS);
347 if (!test_opt(dentry->d_sb, POSIX_ACL))
349 if (list && size <= list_len)
350 memcpy(list, POSIX_ACL_XATTR_ACCESS, size);
355 ext3_xattr_list_acl_default(struct dentry *dentry, char *list, size_t list_len,
356 const char *name, size_t name_len, int type)
358 const size_t size = sizeof(POSIX_ACL_XATTR_DEFAULT);
360 if (!test_opt(dentry->d_sb, POSIX_ACL))
362 if (list && size <= list_len)
363 memcpy(list, POSIX_ACL_XATTR_DEFAULT, size);
368 ext3_xattr_get_acl(struct dentry *dentry, const char *name, void *buffer,
369 size_t size, int type)
371 struct posix_acl *acl;
374 if (strcmp(name, "") != 0)
376 if (!test_opt(dentry->d_sb, POSIX_ACL))
379 acl = ext3_get_acl(dentry->d_inode, type);
384 error = posix_acl_to_xattr(&init_user_ns, acl, buffer, size);
385 posix_acl_release(acl);
391 ext3_xattr_set_acl(struct dentry *dentry, const char *name, const void *value,
392 size_t size, int flags, int type)
394 struct inode *inode = dentry->d_inode;
396 struct posix_acl *acl;
397 int error, retries = 0;
399 if (strcmp(name, "") != 0)
401 if (!test_opt(inode->i_sb, POSIX_ACL))
403 if (!inode_owner_or_capable(inode))
407 acl = posix_acl_from_xattr(&init_user_ns, value, size);
411 error = posix_acl_valid(acl);
413 goto release_and_out;
419 handle = ext3_journal_start(inode, EXT3_DATA_TRANS_BLOCKS(inode->i_sb));
421 return PTR_ERR(handle);
422 error = ext3_set_acl(handle, inode, type, acl);
423 ext3_journal_stop(handle);
424 if (error == -ENOSPC && ext3_should_retry_alloc(inode->i_sb, &retries))
428 posix_acl_release(acl);
432 const struct xattr_handler ext3_xattr_acl_access_handler = {
433 .prefix = POSIX_ACL_XATTR_ACCESS,
434 .flags = ACL_TYPE_ACCESS,
435 .list = ext3_xattr_list_acl_access,
436 .get = ext3_xattr_get_acl,
437 .set = ext3_xattr_set_acl,
440 const struct xattr_handler ext3_xattr_acl_default_handler = {
441 .prefix = POSIX_ACL_XATTR_DEFAULT,
442 .flags = ACL_TYPE_DEFAULT,
443 .list = ext3_xattr_list_acl_default,
444 .get = ext3_xattr_get_acl,
445 .set = ext3_xattr_set_acl,