Commit 574dd596 authored by Andrew Morton's avatar Andrew Morton Committed by Linus Torvalds

[PATCH] xattr: cleanups

From: From: Andreas Gruenbacher <agruen@suse.de>

* Various minor cleanups and simplifications in the extended attributes
  and acl code.

* Use a smarter shortcut rule in ext[23]_permission(): If the mask
  contains permissions that are not also contained in the group
  file mode permission bits, those permissions can never be granted by
  an acl. (The previous shortcut rule was more coarse.)
parent c3087712
/* /*
* linux/fs/ext2/acl.c * linux/fs/ext2/acl.c
* *
* Copyright (C) 2001 by Andreas Gruenbacher, <a.gruenbacher@computer.org> * Copyright (C) 2001-2003 Andreas Gruenbacher, <agruen@suse.de>
*/ */
#include <linux/init.h> #include <linux/init.h>
...@@ -19,7 +19,7 @@ static struct posix_acl * ...@@ -19,7 +19,7 @@ static struct posix_acl *
ext2_acl_from_disk(const void *value, size_t size) ext2_acl_from_disk(const void *value, size_t size)
{ {
const char *end = (char *)value + size; const char *end = (char *)value + size;
int n, count; size_t n, count;
struct posix_acl *acl; struct posix_acl *acl;
if (!value) if (!value)
...@@ -85,7 +85,7 @@ ext2_acl_to_disk(const struct posix_acl *acl, size_t *size) ...@@ -85,7 +85,7 @@ ext2_acl_to_disk(const struct posix_acl *acl, size_t *size)
{ {
ext2_acl_header *ext_acl; ext2_acl_header *ext_acl;
char *e; char *e;
int n; size_t n;
*size = ext2_acl_size(acl->a_count); *size = ext2_acl_size(acl->a_count);
ext_acl = (ext2_acl_header *)kmalloc(sizeof(ext2_acl_header) + ext_acl = (ext2_acl_header *)kmalloc(sizeof(ext2_acl_header) +
...@@ -130,10 +130,11 @@ ext2_acl_to_disk(const struct posix_acl *acl, size_t *size) ...@@ -130,10 +130,11 @@ ext2_acl_to_disk(const struct posix_acl *acl, size_t *size)
static struct posix_acl * static struct posix_acl *
ext2_get_acl(struct inode *inode, int type) ext2_get_acl(struct inode *inode, int type)
{ {
const size_t max_size = ext2_acl_size(EXT2_ACL_MAX_ENTRIES);
struct ext2_inode_inode *ei = EXT2_I(inode);
int name_index; int name_index;
char *value; char *value;
struct posix_acl *acl, **p_acl; struct posix_acl *acl;
const size_t size = ext2_acl_size(EXT2_ACL_MAX_ENTRIES);
int retval; int retval;
if (!test_opt(inode->i_sb, POSIX_ACL)) if (!test_opt(inode->i_sb, POSIX_ACL))
...@@ -141,36 +142,43 @@ ext2_get_acl(struct inode *inode, int type) ...@@ -141,36 +142,43 @@ ext2_get_acl(struct inode *inode, int type)
switch(type) { switch(type) {
case ACL_TYPE_ACCESS: case ACL_TYPE_ACCESS:
p_acl = &EXT2_I(inode)->i_acl; if (ei->i_acl != EXT2_ACL_NOT_CACHED)
return posix_acl_dup(ei->i_acl);
name_index = EXT2_XATTR_INDEX_POSIX_ACL_ACCESS; name_index = EXT2_XATTR_INDEX_POSIX_ACL_ACCESS;
break; break;
case ACL_TYPE_DEFAULT: case ACL_TYPE_DEFAULT:
p_acl = &EXT2_I(inode)->i_default_acl; if (ei->i_default_acl != EXT2_ACL_NOT_CACHED)
return posix_acl_dup(ei->i_default_acl);
name_index = EXT2_XATTR_INDEX_POSIX_ACL_DEFAULT; name_index = EXT2_XATTR_INDEX_POSIX_ACL_DEFAULT;
break; break;
default: default:
return ERR_PTR(-EINVAL); return ERR_PTR(-EINVAL);
} }
if (*p_acl != EXT2_ACL_NOT_CACHED) value = kmalloc(max_size, GFP_KERNEL);
return posix_acl_dup(*p_acl);
value = kmalloc(size, GFP_KERNEL);
if (!value) if (!value)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
retval = ext2_xattr_get(inode, name_index, "", value, size); retval = ext2_xattr_get(inode, name_index, "", value, max_size);
acl = ERR_PTR(retval);
if (retval == -ENODATA || retval == -ENOSYS) if (retval >= 0)
*p_acl = acl = NULL;
else if (retval < 0)
acl = ERR_PTR(retval);
else {
acl = ext2_acl_from_disk(value, retval); acl = ext2_acl_from_disk(value, retval);
if (!IS_ERR(acl)) else if (retval == -ENODATA || retval == -ENOSYS)
*p_acl = posix_acl_dup(acl); acl = NULL;
}
kfree(value); kfree(value);
if (!IS_ERR(acl)) {
switch(type) {
case ACL_TYPE_ACCESS:
ei->i_acl = posix_acl_dup(acl);
break;
case ACL_TYPE_DEFAULT:
ei->i_default_acl = posix_acl_dup(acl);
break;
}
}
return acl; return acl;
} }
...@@ -180,9 +188,9 @@ ext2_get_acl(struct inode *inode, int type) ...@@ -180,9 +188,9 @@ ext2_get_acl(struct inode *inode, int type)
static int static int
ext2_set_acl(struct inode *inode, int type, struct posix_acl *acl) ext2_set_acl(struct inode *inode, int type, struct posix_acl *acl)
{ {
struct ext2_inode_info *ei = EXT2_I(inode);
int name_index; int name_index;
void *value = NULL; void *value = NULL;
struct posix_acl **p_acl;
size_t size; size_t size;
int error; int error;
...@@ -194,7 +202,6 @@ ext2_set_acl(struct inode *inode, int type, struct posix_acl *acl) ...@@ -194,7 +202,6 @@ ext2_set_acl(struct inode *inode, int type, struct posix_acl *acl)
switch(type) { switch(type) {
case ACL_TYPE_ACCESS: case ACL_TYPE_ACCESS:
name_index = EXT2_XATTR_INDEX_POSIX_ACL_ACCESS; name_index = EXT2_XATTR_INDEX_POSIX_ACL_ACCESS;
p_acl = &EXT2_I(inode)->i_acl;
if (acl) { if (acl) {
mode_t mode = inode->i_mode; mode_t mode = inode->i_mode;
error = posix_acl_equiv_mode(acl, &mode); error = posix_acl_equiv_mode(acl, &mode);
...@@ -211,7 +218,6 @@ ext2_set_acl(struct inode *inode, int type, struct posix_acl *acl) ...@@ -211,7 +218,6 @@ ext2_set_acl(struct inode *inode, int type, struct posix_acl *acl)
case ACL_TYPE_DEFAULT: case ACL_TYPE_DEFAULT:
name_index = EXT2_XATTR_INDEX_POSIX_ACL_DEFAULT; name_index = EXT2_XATTR_INDEX_POSIX_ACL_DEFAULT;
p_acl = &EXT2_I(inode)->i_default_acl;
if (!S_ISDIR(inode->i_mode)) if (!S_ISDIR(inode->i_mode))
return acl ? -EACCES : 0; return acl ? -EACCES : 0;
break; break;
...@@ -232,9 +238,19 @@ ext2_set_acl(struct inode *inode, int type, struct posix_acl *acl) ...@@ -232,9 +238,19 @@ ext2_set_acl(struct inode *inode, int type, struct posix_acl *acl)
if (value) if (value)
kfree(value); kfree(value);
if (!error) { if (!error) {
if (*p_acl && *p_acl != EXT2_ACL_NOT_CACHED) switch(type) {
posix_acl_release(*p_acl); case ACL_TYPE_ACCESS:
*p_acl = posix_acl_dup(acl); if (ei->i_acl != EXT2_ACL_NOT_CACHED)
posix_acl_release(ei->i_acl);
ei->i_acl = posix_acl_dup(acl);
break;
case ACL_TYPE_DEFAULT:
if (ei->i_default_acl != EXT2_ACL_NOT_CACHED)
posix_acl_release(ei->i_default_acl);
ei->i_default_acl = posix_acl_dup(acl);
break;
}
} }
return error; return error;
} }
...@@ -254,11 +270,13 @@ __ext2_permission(struct inode *inode, int mask, int lock) ...@@ -254,11 +270,13 @@ __ext2_permission(struct inode *inode, int mask, int lock)
if (current->fsuid == inode->i_uid) { if (current->fsuid == inode->i_uid) {
mode >>= 6; mode >>= 6;
} else if (test_opt(inode->i_sb, POSIX_ACL)) { } else if (test_opt(inode->i_sb, POSIX_ACL)) {
/* ACL can't contain additional permissions if struct ext2_inode_info *ei = EXT2_I(inode);
the ACL_MASK entry is 0 */
if (!(mode & S_IRWXG)) /* The access ACL cannot grant access if the group class
permission bits don't contain all requested permissions. */
if (((mode >> 3) & mask & S_IRWXO) != mask)
goto check_groups; goto check_groups;
if (EXT2_I(inode)->i_acl == EXT2_ACL_NOT_CACHED) { if (ei->i_acl == EXT2_ACL_NOT_CACHED) {
struct posix_acl *acl; struct posix_acl *acl;
if (lock) { if (lock) {
...@@ -271,12 +289,11 @@ __ext2_permission(struct inode *inode, int mask, int lock) ...@@ -271,12 +289,11 @@ __ext2_permission(struct inode *inode, int mask, int lock)
if (IS_ERR(acl)) if (IS_ERR(acl))
return PTR_ERR(acl); return PTR_ERR(acl);
posix_acl_release(acl); posix_acl_release(acl);
if (EXT2_I(inode)->i_acl == EXT2_ACL_NOT_CACHED) if (ei->i_acl == EXT2_ACL_NOT_CACHED)
return -EIO; return -EIO;
} }
if (EXT2_I(inode)->i_acl) { if (ei->i_acl) {
int error = posix_acl_permission(inode, int error = posix_acl_permission(inode, ei->i_acl,mask);
EXT2_I(inode)->i_acl, mask);
if (error == -EACCES) if (error == -EACCES)
goto check_capabilities; goto check_capabilities;
return error; return error;
......
/* /*
* linux/fs/ext2/xattr.c * linux/fs/ext2/xattr.c
* *
* Copyright (C) 2001 by Andreas Gruenbacher, <a.gruenbacher@computer.org> * Copyright (C) 2001-2003 Andreas Gruenbacher <agruen@suse.de>
* *
* Fix by Harrison Xing <harrison@mountainviewdata.com>. * Fix by Harrison Xing <harrison@mountainviewdata.com>.
* Extended attributes for symlinks and special files added per * Extended attributes for symlinks and special files added per
...@@ -83,8 +83,9 @@ EXPORT_SYMBOL(ext2_xattr_set); ...@@ -83,8 +83,9 @@ EXPORT_SYMBOL(ext2_xattr_set);
} while (0) } while (0)
# define ea_bdebug(bh, f...) do { \ # define ea_bdebug(bh, f...) do { \
char b[BDEVNAME_SIZE]; \ char b[BDEVNAME_SIZE]; \
printk(KERN_DEBUG "block %s:%ld: ", \ printk(KERN_DEBUG "block %s:%lu: ", \
bdevname(bh->b_bdev, b), bh->b_blocknr); \ bdevname(bh->b_bdev, b), \
(unsigned long) bh->b_blocknr); \
printk(f); \ printk(f); \
printk("\n"); \ printk("\n"); \
} while (0) } while (0)
...@@ -196,7 +197,6 @@ ext2_xattr_handler(int name_index) ...@@ -196,7 +197,6 @@ ext2_xattr_handler(int name_index)
* Inode operation getxattr() * Inode operation getxattr()
* *
* dentry->d_inode->i_sem down * dentry->d_inode->i_sem down
* BKL held [before 2.5.x]
*/ */
ssize_t ssize_t
ext2_getxattr(struct dentry *dentry, const char *name, ext2_getxattr(struct dentry *dentry, const char *name,
...@@ -215,7 +215,6 @@ ext2_getxattr(struct dentry *dentry, const char *name, ...@@ -215,7 +215,6 @@ ext2_getxattr(struct dentry *dentry, const char *name,
* Inode operation listxattr() * Inode operation listxattr()
* *
* dentry->d_inode->i_sem down * dentry->d_inode->i_sem down
* BKL held [before 2.5.x]
*/ */
ssize_t ssize_t
ext2_listxattr(struct dentry *dentry, char *buffer, size_t size) ext2_listxattr(struct dentry *dentry, char *buffer, size_t size)
...@@ -227,7 +226,6 @@ ext2_listxattr(struct dentry *dentry, char *buffer, size_t size) ...@@ -227,7 +226,6 @@ ext2_listxattr(struct dentry *dentry, char *buffer, size_t size)
* Inode operation setxattr() * Inode operation setxattr()
* *
* dentry->d_inode->i_sem down * dentry->d_inode->i_sem down
* BKL held [before 2.5.x]
*/ */
int int
ext2_setxattr(struct dentry *dentry, const char *name, ext2_setxattr(struct dentry *dentry, const char *name,
...@@ -248,7 +246,6 @@ ext2_setxattr(struct dentry *dentry, const char *name, ...@@ -248,7 +246,6 @@ ext2_setxattr(struct dentry *dentry, const char *name,
* Inode operation removexattr() * Inode operation removexattr()
* *
* dentry->d_inode->i_sem down * dentry->d_inode->i_sem down
* BKL held [before 2.5.x]
*/ */
int int
ext2_removexattr(struct dentry *dentry, const char *name) ext2_removexattr(struct dentry *dentry, const char *name)
...@@ -278,9 +275,9 @@ ext2_xattr_get(struct inode *inode, int name_index, const char *name, ...@@ -278,9 +275,9 @@ ext2_xattr_get(struct inode *inode, int name_index, const char *name,
{ {
struct buffer_head *bh = NULL; struct buffer_head *bh = NULL;
struct ext2_xattr_entry *entry; struct ext2_xattr_entry *entry;
unsigned int size; size_t name_len, size;
char *end; char *end;
int name_len, error; int error;
ea_idebug(inode, "name=%d.%s, buffer=%p, buffer_size=%ld", ea_idebug(inode, "name=%d.%s, buffer=%p, buffer_size=%ld",
name_index, name, buffer, (long)buffer_size); name_index, name, buffer, (long)buffer_size);
...@@ -376,7 +373,7 @@ ext2_xattr_list(struct inode *inode, char *buffer, size_t buffer_size) ...@@ -376,7 +373,7 @@ ext2_xattr_list(struct inode *inode, char *buffer, size_t buffer_size)
{ {
struct buffer_head *bh = NULL; struct buffer_head *bh = NULL;
struct ext2_xattr_entry *entry; struct ext2_xattr_entry *entry;
unsigned int size = 0; size_t size = 0;
char *buf, *end; char *buf, *end;
int error; int error;
...@@ -482,8 +479,8 @@ ext2_xattr_set(struct inode *inode, int name_index, const char *name, ...@@ -482,8 +479,8 @@ ext2_xattr_set(struct inode *inode, int name_index, const char *name,
struct buffer_head *bh = NULL; struct buffer_head *bh = NULL;
struct ext2_xattr_header *header = NULL; struct ext2_xattr_header *header = NULL;
struct ext2_xattr_entry *here, *last; struct ext2_xattr_entry *here, *last;
unsigned int name_len; size_t name_len, free, min_offs = sb->s_blocksize;
int min_offs = sb->s_blocksize, not_found = 1, free, error; int not_found = 1, error;
char *end; char *end;
/* /*
...@@ -540,7 +537,7 @@ bad_block: ext2_error(sb, "ext2_xattr_set", ...@@ -540,7 +537,7 @@ bad_block: ext2_error(sb, "ext2_xattr_set",
if ((char *)next >= end) if ((char *)next >= end)
goto bad_block; goto bad_block;
if (!here->e_value_block && here->e_value_size) { if (!here->e_value_block && here->e_value_size) {
int offs = le16_to_cpu(here->e_value_offs); size_t offs = le16_to_cpu(here->e_value_offs);
if (offs < min_offs) if (offs < min_offs)
min_offs = offs; min_offs = offs;
} }
...@@ -560,7 +557,7 @@ bad_block: ext2_error(sb, "ext2_xattr_set", ...@@ -560,7 +557,7 @@ bad_block: ext2_error(sb, "ext2_xattr_set",
if ((char *)next >= end) if ((char *)next >= end)
goto bad_block; goto bad_block;
if (!last->e_value_block && last->e_value_size) { if (!last->e_value_block && last->e_value_size) {
int offs = le16_to_cpu(last->e_value_offs); size_t offs = le16_to_cpu(last->e_value_offs);
if (offs < min_offs) if (offs < min_offs)
min_offs = offs; min_offs = offs;
} }
...@@ -584,25 +581,23 @@ bad_block: ext2_error(sb, "ext2_xattr_set", ...@@ -584,25 +581,23 @@ bad_block: ext2_error(sb, "ext2_xattr_set",
error = 0; error = 0;
if (value == NULL) if (value == NULL)
goto cleanup; goto cleanup;
else
free -= EXT2_XATTR_LEN(name_len);
} else { } else {
/* Request to create an existing attribute? */ /* Request to create an existing attribute? */
error = -EEXIST; error = -EEXIST;
if (flags & XATTR_CREATE) if (flags & XATTR_CREATE)
goto cleanup; goto cleanup;
if (!here->e_value_block && here->e_value_size) { if (!here->e_value_block && here->e_value_size) {
unsigned int size = le32_to_cpu(here->e_value_size); size_t size = le32_to_cpu(here->e_value_size);
if (le16_to_cpu(here->e_value_offs) + size > if (le16_to_cpu(here->e_value_offs) + size >
sb->s_blocksize || size > sb->s_blocksize) sb->s_blocksize || size > sb->s_blocksize)
goto bad_block; goto bad_block;
free += EXT2_XATTR_SIZE(size); free += EXT2_XATTR_SIZE(size);
} }
free += EXT2_XATTR_LEN(name_len);
} }
free -= EXT2_XATTR_SIZE(value_len);
error = -ENOSPC; error = -ENOSPC;
if (free < 0) if (free < EXT2_XATTR_LEN(name_len) + EXT2_XATTR_SIZE(value_len))
goto cleanup; goto cleanup;
/* Here we know that we can set the new attribute. */ /* Here we know that we can set the new attribute. */
...@@ -640,8 +635,8 @@ bad_block: ext2_error(sb, "ext2_xattr_set", ...@@ -640,8 +635,8 @@ bad_block: ext2_error(sb, "ext2_xattr_set",
if (not_found) { if (not_found) {
/* Insert the new name. */ /* Insert the new name. */
int size = EXT2_XATTR_LEN(name_len); size_t size = EXT2_XATTR_LEN(name_len);
int rest = (char *)last - (char *)here; size_t rest = (char *)last - (char *)here;
memmove((char *)here + size, here, rest); memmove((char *)here + size, here, rest);
memset(here, 0, size); memset(here, 0, size);
here->e_name_index = name_index; here->e_name_index = name_index;
...@@ -651,7 +646,7 @@ bad_block: ext2_error(sb, "ext2_xattr_set", ...@@ -651,7 +646,7 @@ bad_block: ext2_error(sb, "ext2_xattr_set",
/* Remove the old value. */ /* Remove the old value. */
if (!here->e_value_block && here->e_value_size) { if (!here->e_value_block && here->e_value_size) {
char *first_val = (char *)header + min_offs; char *first_val = (char *)header + min_offs;
int offs = le16_to_cpu(here->e_value_offs); size_t offs = le16_to_cpu(here->e_value_offs);
char *val = (char *)header + offs; char *val = (char *)header + offs;
size_t size = EXT2_XATTR_SIZE( size_t size = EXT2_XATTR_SIZE(
le32_to_cpu(here->e_value_size)); le32_to_cpu(here->e_value_size));
...@@ -663,7 +658,7 @@ bad_block: ext2_error(sb, "ext2_xattr_set", ...@@ -663,7 +658,7 @@ bad_block: ext2_error(sb, "ext2_xattr_set",
/* Adjust all value offsets. */ /* Adjust all value offsets. */
last = ENTRY(header+1); last = ENTRY(header+1);
while (!IS_LAST_ENTRY(last)) { while (!IS_LAST_ENTRY(last)) {
int o = le16_to_cpu(last->e_value_offs); size_t o = le16_to_cpu(last->e_value_offs);
if (!last->e_value_block && o < offs) if (!last->e_value_block && o < offs)
last->e_value_offs = last->e_value_offs =
cpu_to_le16(o + size); cpu_to_le16(o + size);
...@@ -678,7 +673,7 @@ bad_block: ext2_error(sb, "ext2_xattr_set", ...@@ -678,7 +673,7 @@ bad_block: ext2_error(sb, "ext2_xattr_set",
goto cleanup; goto cleanup;
} else { } else {
/* Remove the old name. */ /* Remove the old name. */
int size = EXT2_XATTR_LEN(name_len); size_t size = EXT2_XATTR_LEN(name_len);
last = ENTRY((char *)last - size); last = ENTRY((char *)last - size);
memmove(here, (char*)here + size, memmove(here, (char*)here + size,
(char*)last - (char*)here); (char*)last - (char*)here);
...@@ -732,9 +727,9 @@ ext2_xattr_set2(struct inode *inode, struct buffer_head *old_bh, ...@@ -732,9 +727,9 @@ ext2_xattr_set2(struct inode *inode, struct buffer_head *old_bh,
* The old block will be released after updating * The old block will be released after updating
* the inode. * the inode.
*/ */
ea_bdebug(new_bh, "%s block %ld", ea_bdebug(new_bh, "%s block %lu",
(old_bh == new_bh) ? "keeping" : "reusing", (old_bh == new_bh) ? "keeping" : "reusing",
new_bh->b_blocknr); (unsigned long) new_bh->b_blocknr);
error = -EDQUOT; error = -EDQUOT;
if (DQUOT_ALLOC_BLOCK(inode, 1)) if (DQUOT_ALLOC_BLOCK(inode, 1))
...@@ -751,8 +746,10 @@ ext2_xattr_set2(struct inode *inode, struct buffer_head *old_bh, ...@@ -751,8 +746,10 @@ ext2_xattr_set2(struct inode *inode, struct buffer_head *old_bh,
ext2_xattr_cache_insert(new_bh); ext2_xattr_cache_insert(new_bh);
} else { } else {
/* We need to allocate a new block */ /* We need to allocate a new block */
int goal = le32_to_cpu(EXT2_SB(sb)->s_es->s_first_data_block) + int goal = le32_to_cpu(EXT2_SB(sb)->s_es->
EXT2_I(inode)->i_block_group * EXT2_BLOCKS_PER_GROUP(sb); s_first_data_block) +
EXT2_I(inode)->i_block_group *
EXT2_BLOCKS_PER_GROUP(sb);
int block = ext2_new_block(inode, goal, 0, 0, &error); int block = ext2_new_block(inode, goal, 0, 0, &error);
if (error) if (error)
goto cleanup; goto cleanup;
...@@ -857,8 +854,8 @@ ext2_xattr_delete_inode(struct inode *inode) ...@@ -857,8 +854,8 @@ ext2_xattr_delete_inode(struct inode *inode)
if (HDR(bh)->h_refcount == cpu_to_le32(1)) { if (HDR(bh)->h_refcount == cpu_to_le32(1)) {
ext2_xattr_cache_remove(bh); ext2_xattr_cache_remove(bh);
ext2_free_blocks(inode, EXT2_I(inode)->i_file_acl, 1); ext2_free_blocks(inode, EXT2_I(inode)->i_file_acl, 1);
get_bh(bh);
bforget(bh); bforget(bh);
bh = NULL;
} else { } else {
HDR(bh)->h_refcount = cpu_to_le32( HDR(bh)->h_refcount = cpu_to_le32(
le32_to_cpu(HDR(bh)->h_refcount) - 1); le32_to_cpu(HDR(bh)->h_refcount) - 1);
......
/* /*
* linux/fs/ext3/acl.c * linux/fs/ext3/acl.c
* *
* Copyright (C) 2001 by Andreas Gruenbacher, <a.gruenbacher@computer.org> * Copyright (C) 2001-2003 Andreas Gruenbacher, <agruen@suse.de>
*/ */
#include <linux/init.h> #include <linux/init.h>
...@@ -20,7 +20,7 @@ static struct posix_acl * ...@@ -20,7 +20,7 @@ static struct posix_acl *
ext3_acl_from_disk(const void *value, size_t size) ext3_acl_from_disk(const void *value, size_t size)
{ {
const char *end = (char *)value + size; const char *end = (char *)value + size;
int n, count; size_t n, count;
struct posix_acl *acl; struct posix_acl *acl;
if (!value) if (!value)
...@@ -86,7 +86,7 @@ ext3_acl_to_disk(const struct posix_acl *acl, size_t *size) ...@@ -86,7 +86,7 @@ ext3_acl_to_disk(const struct posix_acl *acl, size_t *size)
{ {
ext3_acl_header *ext_acl; ext3_acl_header *ext_acl;
char *e; char *e;
int n; size_t n;
*size = ext3_acl_size(acl->a_count); *size = ext3_acl_size(acl->a_count);
ext_acl = (ext3_acl_header *)kmalloc(sizeof(ext3_acl_header) + ext_acl = (ext3_acl_header *)kmalloc(sizeof(ext3_acl_header) +
...@@ -133,10 +133,11 @@ ext3_acl_to_disk(const struct posix_acl *acl, size_t *size) ...@@ -133,10 +133,11 @@ ext3_acl_to_disk(const struct posix_acl *acl, size_t *size)
static struct posix_acl * static struct posix_acl *
ext3_get_acl(struct inode *inode, int type) ext3_get_acl(struct inode *inode, int type)
{ {
const size_t max_size = ext3_acl_size(EXT3_ACL_MAX_ENTRIES);
struct ext3_inode_info *ei = EXT3_I(inode);
int name_index; int name_index;
char *value; char *value;
struct posix_acl *acl, **p_acl; struct posix_acl *acl;
const size_t size = ext3_acl_size(EXT3_ACL_MAX_ENTRIES);
int retval; int retval;
if (!test_opt(inode->i_sb, POSIX_ACL)) if (!test_opt(inode->i_sb, POSIX_ACL))
...@@ -144,36 +145,43 @@ ext3_get_acl(struct inode *inode, int type) ...@@ -144,36 +145,43 @@ ext3_get_acl(struct inode *inode, int type)
switch(type) { switch(type) {
case ACL_TYPE_ACCESS: case ACL_TYPE_ACCESS:
p_acl = &EXT3_I(inode)->i_acl; if (ei->i_acl != EXT3_ACL_NOT_CACHED)
return posix_acl_dup(ei->i_acl);
name_index = EXT3_XATTR_INDEX_POSIX_ACL_ACCESS; name_index = EXT3_XATTR_INDEX_POSIX_ACL_ACCESS;
break; break;
case ACL_TYPE_DEFAULT: case ACL_TYPE_DEFAULT:
p_acl = &EXT3_I(inode)->i_default_acl; if (ei->i_default_acl != EXT3_ACL_NOT_CACHED)
return posix_acl_dup(ei->i_default_acl);
name_index = EXT3_XATTR_INDEX_POSIX_ACL_DEFAULT; name_index = EXT3_XATTR_INDEX_POSIX_ACL_DEFAULT;
break; break;
default: default:
return ERR_PTR(-EINVAL); return ERR_PTR(-EINVAL);
} }
if (*p_acl != EXT3_ACL_NOT_CACHED) value = kmalloc(max_size, GFP_KERNEL);
return posix_acl_dup(*p_acl);
value = kmalloc(size, GFP_KERNEL);
if (!value) if (!value)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
retval = ext3_xattr_get(inode, name_index, "", value, size); retval = ext3_xattr_get(inode, name_index, "", value, max_size);
acl = ERR_PTR(retval);
if (retval == -ENODATA || retval == -ENOSYS) if (retval > 0)
*p_acl = acl = NULL;
else if (retval < 0)
acl = ERR_PTR(retval);
else {
acl = ext3_acl_from_disk(value, retval); acl = ext3_acl_from_disk(value, retval);
if (!IS_ERR(acl)) else if (retval == -ENODATA || retval == -ENOSYS)
*p_acl = posix_acl_dup(acl); acl = NULL;
}
kfree(value); kfree(value);
if (!IS_ERR(acl)) {
switch(type) {
case ACL_TYPE_ACCESS:
ei->i_acl = posix_acl_dup(acl);
break;
case ACL_TYPE_DEFAULT:
ei->i_default_acl = posix_acl_dup(acl);
break;
}
}
return acl; return acl;
} }
...@@ -186,9 +194,9 @@ static int ...@@ -186,9 +194,9 @@ static int
ext3_set_acl(handle_t *handle, struct inode *inode, int type, ext3_set_acl(handle_t *handle, struct inode *inode, int type,
struct posix_acl *acl) struct posix_acl *acl)
{ {
struct ext3_inode_info *ei = EXT3_I(inode);
int name_index; int name_index;
void *value = NULL; void *value = NULL;
struct posix_acl **p_acl;
size_t size; size_t size;
int error; int error;
...@@ -198,7 +206,6 @@ ext3_set_acl(handle_t *handle, struct inode *inode, int type, ...@@ -198,7 +206,6 @@ ext3_set_acl(handle_t *handle, struct inode *inode, int type,
switch(type) { switch(type) {
case ACL_TYPE_ACCESS: case ACL_TYPE_ACCESS:
name_index = EXT3_XATTR_INDEX_POSIX_ACL_ACCESS; name_index = EXT3_XATTR_INDEX_POSIX_ACL_ACCESS;
p_acl = &EXT3_I(inode)->i_acl;
if (acl) { if (acl) {
mode_t mode = inode->i_mode; mode_t mode = inode->i_mode;
error = posix_acl_equiv_mode(acl, &mode); error = posix_acl_equiv_mode(acl, &mode);
...@@ -215,7 +222,6 @@ ext3_set_acl(handle_t *handle, struct inode *inode, int type, ...@@ -215,7 +222,6 @@ ext3_set_acl(handle_t *handle, struct inode *inode, int type,
case ACL_TYPE_DEFAULT: case ACL_TYPE_DEFAULT:
name_index = EXT3_XATTR_INDEX_POSIX_ACL_DEFAULT; name_index = EXT3_XATTR_INDEX_POSIX_ACL_DEFAULT;
p_acl = &EXT3_I(inode)->i_default_acl;
if (!S_ISDIR(inode->i_mode)) if (!S_ISDIR(inode->i_mode))
return acl ? -EACCES : 0; return acl ? -EACCES : 0;
break; break;
...@@ -231,14 +237,25 @@ ext3_set_acl(handle_t *handle, struct inode *inode, int type, ...@@ -231,14 +237,25 @@ ext3_set_acl(handle_t *handle, struct inode *inode, int type,
return (int)PTR_ERR(value); return (int)PTR_ERR(value);
} }
error = ext3_xattr_set_handle(handle, inode, name_index, "", value, size, 0); error = ext3_xattr_set_handle(handle, inode, name_index, "",
value, size, 0);
if (value) if (value)
kfree(value); kfree(value);
if (!error) { if (!error) {
if (*p_acl && *p_acl != EXT3_ACL_NOT_CACHED) switch(type) {
posix_acl_release(*p_acl); case ACL_TYPE_ACCESS:
*p_acl = posix_acl_dup(acl); if (ei->i_acl != EXT3_ACL_NOT_CACHED)
posix_acl_release(ei->i_acl);
ei->i_acl = posix_acl_dup(acl);
break;
case ACL_TYPE_DEFAULT:
if (ei->i_default_acl != EXT3_ACL_NOT_CACHED)
posix_acl_release(ei->i_default_acl);
ei->i_default_acl = posix_acl_dup(acl);
break;
}
} }
return error; return error;
} }
...@@ -258,11 +275,13 @@ __ext3_permission(struct inode *inode, int mask, int lock) ...@@ -258,11 +275,13 @@ __ext3_permission(struct inode *inode, int mask, int lock)
if (current->fsuid == inode->i_uid) { if (current->fsuid == inode->i_uid) {
mode >>= 6; mode >>= 6;
} else if (test_opt(inode->i_sb, POSIX_ACL)) { } else if (test_opt(inode->i_sb, POSIX_ACL)) {
/* ACL can't contain additional permissions if struct ext3_inode_info *ei = EXT3_I(inode);
the ACL_MASK entry is 0 */
if (!(mode & S_IRWXG)) /* The access ACL cannot grant access if the group class
permission bits don't contain all requested permissions. */
if (((mode >> 3) & mask & S_IRWXO) != mask)
goto check_groups; goto check_groups;
if (EXT3_I(inode)->i_acl == EXT3_ACL_NOT_CACHED) { if (ei->i_acl == EXT3_ACL_NOT_CACHED) {
struct posix_acl *acl; struct posix_acl *acl;
if (lock) { if (lock) {
...@@ -275,12 +294,11 @@ __ext3_permission(struct inode *inode, int mask, int lock) ...@@ -275,12 +294,11 @@ __ext3_permission(struct inode *inode, int mask, int lock)
if (IS_ERR(acl)) if (IS_ERR(acl))
return PTR_ERR(acl); return PTR_ERR(acl);
posix_acl_release(acl); posix_acl_release(acl);
if (EXT3_I(inode)->i_acl == EXT3_ACL_NOT_CACHED) if (ei->i_acl == EXT3_ACL_NOT_CACHED)
return -EIO; return -EIO;
} }
if (EXT3_I(inode)->i_acl) { if (ei->i_acl) {
int error = posix_acl_permission(inode, int error = posix_acl_permission(inode, ei->i_acl,mask);
EXT3_I(inode)->i_acl, mask);
if (error == -EACCES) if (error == -EACCES)
goto check_capabilities; goto check_capabilities;
return error; return error;
......
/* /*
* linux/fs/ext3/xattr.c * linux/fs/ext3/xattr.c
* *
* Copyright (C) 2001 by Andreas Gruenbacher, <a.gruenbacher@computer.org> * Copyright (C) 2001-2003 Andreas Gruenbacher, <agruen@suse.de>
* *
* Fix by Harrison Xing <harrison@mountainviewdata.com>. * Fix by Harrison Xing <harrison@mountainviewdata.com>.
* Ext3 code with a lot of help from Eric Jarman <ejarman@acm.org>. * Ext3 code with a lot of help from Eric Jarman <ejarman@acm.org>.
...@@ -63,8 +63,6 @@ ...@@ -63,8 +63,6 @@
#include "xattr.h" #include "xattr.h"
#include "acl.h" #include "acl.h"
#define EXT3_EA_USER "user."
#define HDR(bh) ((struct ext3_xattr_header *)((bh)->b_data)) #define HDR(bh) ((struct ext3_xattr_header *)((bh)->b_data))
#define ENTRY(ptr) ((struct ext3_xattr_entry *)(ptr)) #define ENTRY(ptr) ((struct ext3_xattr_entry *)(ptr))
#define FIRST_ENTRY(bh) ENTRY(HDR(bh)+1) #define FIRST_ENTRY(bh) ENTRY(HDR(bh)+1)
...@@ -79,8 +77,9 @@ ...@@ -79,8 +77,9 @@
} while (0) } while (0)
# define ea_bdebug(bh, f...) do { \ # define ea_bdebug(bh, f...) do { \
char b[BDEVNAME_SIZE]; \ char b[BDEVNAME_SIZE]; \
printk(KERN_DEBUG "block %s:%ld: ", \ printk(KERN_DEBUG "block %s:%lu: ", \
bdevname(bh->b_bdev, b), bh->b_blocknr); \ bdevname(bh->b_bdev, b), \
(unsigned long) bh->b_blocknr); \
printk(f); \ printk(f); \
printk("\n"); \ printk("\n"); \
} while (0) } while (0)
...@@ -271,9 +270,9 @@ ext3_xattr_get(struct inode *inode, int name_index, const char *name, ...@@ -271,9 +270,9 @@ ext3_xattr_get(struct inode *inode, int name_index, const char *name,
{ {
struct buffer_head *bh = NULL; struct buffer_head *bh = NULL;
struct ext3_xattr_entry *entry; struct ext3_xattr_entry *entry;
unsigned int size; size_t name_len, size;
char *end; char *end;
int name_len, error; int error;
ea_idebug(inode, "name=%d.%s, buffer=%p, buffer_size=%ld", ea_idebug(inode, "name=%d.%s, buffer=%p, buffer_size=%ld",
name_index, name, buffer, (long)buffer_size); name_index, name, buffer, (long)buffer_size);
...@@ -369,7 +368,7 @@ ext3_xattr_list(struct inode *inode, char *buffer, size_t buffer_size) ...@@ -369,7 +368,7 @@ ext3_xattr_list(struct inode *inode, char *buffer, size_t buffer_size)
{ {
struct buffer_head *bh = NULL; struct buffer_head *bh = NULL;
struct ext3_xattr_entry *entry; struct ext3_xattr_entry *entry;
unsigned int size = 0; size_t size = 0;
char *buf, *end; char *buf, *end;
int error; int error;
...@@ -478,8 +477,8 @@ ext3_xattr_set_handle(handle_t *handle, struct inode *inode, int name_index, ...@@ -478,8 +477,8 @@ ext3_xattr_set_handle(handle_t *handle, struct inode *inode, int name_index,
struct buffer_head *bh = NULL; struct buffer_head *bh = NULL;
struct ext3_xattr_header *header = NULL; struct ext3_xattr_header *header = NULL;
struct ext3_xattr_entry *here, *last; struct ext3_xattr_entry *here, *last;
unsigned int name_len; size_t name_len, free, min_offs = sb->s_blocksize;
int min_offs = sb->s_blocksize, not_found = 1, free, error; int not_found = 1, error;
char *end; char *end;
/* /*
...@@ -536,7 +535,7 @@ bad_block: ext3_error(sb, "ext3_xattr_set", ...@@ -536,7 +535,7 @@ bad_block: ext3_error(sb, "ext3_xattr_set",
if ((char *)next >= end) if ((char *)next >= end)
goto bad_block; goto bad_block;
if (!here->e_value_block && here->e_value_size) { if (!here->e_value_block && here->e_value_size) {
int offs = le16_to_cpu(here->e_value_offs); size_t offs = le16_to_cpu(here->e_value_offs);
if (offs < min_offs) if (offs < min_offs)
min_offs = offs; min_offs = offs;
} }
...@@ -556,7 +555,7 @@ bad_block: ext3_error(sb, "ext3_xattr_set", ...@@ -556,7 +555,7 @@ bad_block: ext3_error(sb, "ext3_xattr_set",
if ((char *)next >= end) if ((char *)next >= end)
goto bad_block; goto bad_block;
if (!last->e_value_block && last->e_value_size) { if (!last->e_value_block && last->e_value_size) {
int offs = le16_to_cpu(last->e_value_offs); size_t offs = le16_to_cpu(last->e_value_offs);
if (offs < min_offs) if (offs < min_offs)
min_offs = offs; min_offs = offs;
} }
...@@ -580,25 +579,23 @@ bad_block: ext3_error(sb, "ext3_xattr_set", ...@@ -580,25 +579,23 @@ bad_block: ext3_error(sb, "ext3_xattr_set",
error = 0; error = 0;
if (value == NULL) if (value == NULL)
goto cleanup; goto cleanup;
else
free -= EXT3_XATTR_LEN(name_len);
} else { } else {
/* Request to create an existing attribute? */ /* Request to create an existing attribute? */
error = -EEXIST; error = -EEXIST;
if (flags & XATTR_CREATE) if (flags & XATTR_CREATE)
goto cleanup; goto cleanup;
if (!here->e_value_block && here->e_value_size) { if (!here->e_value_block && here->e_value_size) {
unsigned int size = le32_to_cpu(here->e_value_size); size_t size = le32_to_cpu(here->e_value_size);
if (le16_to_cpu(here->e_value_offs) + size > if (le16_to_cpu(here->e_value_offs) + size >
sb->s_blocksize || size > sb->s_blocksize) sb->s_blocksize || size > sb->s_blocksize)
goto bad_block; goto bad_block;
free += EXT3_XATTR_SIZE(size); free += EXT3_XATTR_SIZE(size);
} }
free += EXT3_XATTR_LEN(name_len);
} }
free -= EXT3_XATTR_SIZE(value_len);
error = -ENOSPC; error = -ENOSPC;
if (free < 0) if (free < EXT3_XATTR_LEN(name_len) + EXT3_XATTR_SIZE(value_len))
goto cleanup; goto cleanup;
/* Here we know that we can set the new attribute. */ /* Here we know that we can set the new attribute. */
...@@ -639,8 +636,8 @@ bad_block: ext3_error(sb, "ext3_xattr_set", ...@@ -639,8 +636,8 @@ bad_block: ext3_error(sb, "ext3_xattr_set",
if (not_found) { if (not_found) {
/* Insert the new name. */ /* Insert the new name. */
int size = EXT3_XATTR_LEN(name_len); size_t size = EXT3_XATTR_LEN(name_len);
int rest = (char *)last - (char *)here; size_t rest = (char *)last - (char *)here;
memmove((char *)here + size, here, rest); memmove((char *)here + size, here, rest);
memset(here, 0, size); memset(here, 0, size);
here->e_name_index = name_index; here->e_name_index = name_index;
...@@ -650,7 +647,7 @@ bad_block: ext3_error(sb, "ext3_xattr_set", ...@@ -650,7 +647,7 @@ bad_block: ext3_error(sb, "ext3_xattr_set",
/* Remove the old value. */ /* Remove the old value. */
if (!here->e_value_block && here->e_value_size) { if (!here->e_value_block && here->e_value_size) {
char *first_val = (char *)header + min_offs; char *first_val = (char *)header + min_offs;
int offs = le16_to_cpu(here->e_value_offs); size_t offs = le16_to_cpu(here->e_value_offs);
char *val = (char *)header + offs; char *val = (char *)header + offs;
size_t size = EXT3_XATTR_SIZE( size_t size = EXT3_XATTR_SIZE(
le32_to_cpu(here->e_value_size)); le32_to_cpu(here->e_value_size));
...@@ -662,7 +659,7 @@ bad_block: ext3_error(sb, "ext3_xattr_set", ...@@ -662,7 +659,7 @@ bad_block: ext3_error(sb, "ext3_xattr_set",
/* Adjust all value offsets. */ /* Adjust all value offsets. */
last = ENTRY(header+1); last = ENTRY(header+1);
while (!IS_LAST_ENTRY(last)) { while (!IS_LAST_ENTRY(last)) {
int o = le16_to_cpu(last->e_value_offs); size_t o = le16_to_cpu(last->e_value_offs);
if (!last->e_value_block && o < offs) if (!last->e_value_block && o < offs)
last->e_value_offs = last->e_value_offs =
cpu_to_le16(o + size); cpu_to_le16(o + size);
...@@ -678,7 +675,7 @@ bad_block: ext3_error(sb, "ext3_xattr_set", ...@@ -678,7 +675,7 @@ bad_block: ext3_error(sb, "ext3_xattr_set",
goto cleanup; goto cleanup;
} else { } else {
/* Remove the old name. */ /* Remove the old name. */
int size = EXT3_XATTR_LEN(name_len); size_t size = EXT3_XATTR_LEN(name_len);
last = ENTRY((char *)last - size); last = ENTRY((char *)last - size);
memmove(here, (char*)here + size, memmove(here, (char*)here + size,
(char*)last - (char*)here); (char*)last - (char*)here);
...@@ -733,9 +730,9 @@ ext3_xattr_set_handle2(handle_t *handle, struct inode *inode, ...@@ -733,9 +730,9 @@ ext3_xattr_set_handle2(handle_t *handle, struct inode *inode,
* The old block will be released after updating * The old block will be released after updating
* the inode. * the inode.
*/ */
ea_bdebug(new_bh, "%s block %ld", ea_bdebug(new_bh, "%s block %lu",
(old_bh == new_bh) ? "keeping" : "reusing", (old_bh == new_bh) ? "keeping" : "reusing",
new_bh->b_blocknr); (unsigned long) new_bh->b_blocknr);
error = -EDQUOT; error = -EDQUOT;
if (DQUOT_ALLOC_BLOCK(inode, 1)) if (DQUOT_ALLOC_BLOCK(inode, 1))
...@@ -759,7 +756,7 @@ ext3_xattr_set_handle2(handle_t *handle, struct inode *inode, ...@@ -759,7 +756,7 @@ ext3_xattr_set_handle2(handle_t *handle, struct inode *inode,
EXT3_SB(sb)->s_es->s_first_data_block) + EXT3_SB(sb)->s_es->s_first_data_block) +
EXT3_I(inode)->i_block_group * EXT3_I(inode)->i_block_group *
EXT3_BLOCKS_PER_GROUP(sb); EXT3_BLOCKS_PER_GROUP(sb);
int block = ext3_new_block(handle, int block = ext3_new_block(handle,
inode, goal, 0, 0, &error); inode, goal, 0, 0, &error);
if (error) if (error)
goto cleanup; goto cleanup;
...@@ -895,8 +892,8 @@ ext3_xattr_delete_inode(handle_t *handle, struct inode *inode) ...@@ -895,8 +892,8 @@ ext3_xattr_delete_inode(handle_t *handle, struct inode *inode)
if (HDR(bh)->h_refcount == cpu_to_le32(1)) { if (HDR(bh)->h_refcount == cpu_to_le32(1)) {
ext3_xattr_cache_remove(bh); ext3_xattr_cache_remove(bh);
ext3_free_blocks(handle, inode, EXT3_I(inode)->i_file_acl, 1); ext3_free_blocks(handle, inode, EXT3_I(inode)->i_file_acl, 1);
get_bh(bh);
ext3_forget(handle, 1, inode, bh, EXT3_I(inode)->i_file_acl); ext3_forget(handle, 1, inode, bh, EXT3_I(inode)->i_file_acl);
bh = NULL;
} else { } else {
HDR(bh)->h_refcount = cpu_to_le32( HDR(bh)->h_refcount = cpu_to_le32(
le32_to_cpu(HDR(bh)->h_refcount) - 1); le32_to_cpu(HDR(bh)->h_refcount) - 1);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment