forked from torvalds/linux
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
make generic_acl slightly more generic
Now that we cache the ACL pointers in the generic inode all the generic_acl cruft can go away and generic_acl.c can directly implement xattr handlers dealing with the full Posix ACL semantics for in-memory filesystems. Signed-off-by: Christoph Hellwig <[email protected]> Signed-off-by: Al Viro <[email protected]>
- Loading branch information
Christoph Hellwig
authored and
Al Viro
committed
Dec 16, 2009
1 parent
431547b
commit 1c7c474
Showing
6 changed files
with
109 additions
and
257 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,62 +1,58 @@ | ||
/* | ||
* fs/generic_acl.c | ||
* | ||
* (C) 2005 Andreas Gruenbacher <[email protected]> | ||
* | ||
* This file is released under the GPL. | ||
* | ||
* Generic ACL support for in-memory filesystems. | ||
*/ | ||
|
||
#include <linux/sched.h> | ||
#include <linux/fs.h> | ||
#include <linux/generic_acl.h> | ||
#include <linux/posix_acl.h> | ||
#include <linux/posix_acl_xattr.h> | ||
|
||
/** | ||
* generic_acl_list - Generic xattr_handler->list() operation | ||
* @ops: Filesystem specific getacl and setacl callbacks | ||
*/ | ||
size_t | ||
generic_acl_list(struct inode *inode, struct generic_acl_operations *ops, | ||
int type, char *list, size_t list_size) | ||
|
||
static size_t | ||
generic_acl_list(struct dentry *dentry, char *list, size_t list_size, | ||
const char *name, size_t name_len, int type) | ||
{ | ||
struct posix_acl *acl; | ||
const char *name; | ||
const char *xname; | ||
size_t size; | ||
|
||
acl = ops->getacl(inode, type); | ||
acl = get_cached_acl(dentry->d_inode, type); | ||
if (!acl) | ||
return 0; | ||
posix_acl_release(acl); | ||
|
||
switch(type) { | ||
case ACL_TYPE_ACCESS: | ||
name = POSIX_ACL_XATTR_ACCESS; | ||
break; | ||
|
||
case ACL_TYPE_DEFAULT: | ||
name = POSIX_ACL_XATTR_DEFAULT; | ||
break; | ||
|
||
default: | ||
return 0; | ||
switch (type) { | ||
case ACL_TYPE_ACCESS: | ||
xname = POSIX_ACL_XATTR_ACCESS; | ||
break; | ||
case ACL_TYPE_DEFAULT: | ||
xname = POSIX_ACL_XATTR_DEFAULT; | ||
break; | ||
default: | ||
return 0; | ||
} | ||
size = strlen(name) + 1; | ||
size = strlen(xname) + 1; | ||
if (list && size <= list_size) | ||
memcpy(list, name, size); | ||
memcpy(list, xname, size); | ||
return size; | ||
} | ||
|
||
/** | ||
* generic_acl_get - Generic xattr_handler->get() operation | ||
* @ops: Filesystem specific getacl and setacl callbacks | ||
*/ | ||
int | ||
generic_acl_get(struct inode *inode, struct generic_acl_operations *ops, | ||
int type, void *buffer, size_t size) | ||
static int | ||
generic_acl_get(struct dentry *dentry, const char *name, void *buffer, | ||
size_t size, int type) | ||
{ | ||
struct posix_acl *acl; | ||
int error; | ||
|
||
acl = ops->getacl(inode, type); | ||
if (strcmp(name, "") != 0) | ||
return -EINVAL; | ||
|
||
acl = get_cached_acl(dentry->d_inode, type); | ||
if (!acl) | ||
return -ENODATA; | ||
error = posix_acl_to_xattr(acl, buffer, size); | ||
|
@@ -65,17 +61,16 @@ generic_acl_get(struct inode *inode, struct generic_acl_operations *ops, | |
return error; | ||
} | ||
|
||
/** | ||
* generic_acl_set - Generic xattr_handler->set() operation | ||
* @ops: Filesystem specific getacl and setacl callbacks | ||
*/ | ||
int | ||
generic_acl_set(struct inode *inode, struct generic_acl_operations *ops, | ||
int type, const void *value, size_t size) | ||
static int | ||
generic_acl_set(struct dentry *dentry, const char *name, const void *value, | ||
size_t size, int flags, int type) | ||
{ | ||
struct inode *inode = dentry->d_inode; | ||
struct posix_acl *acl = NULL; | ||
int error; | ||
|
||
if (strcmp(name, "") != 0) | ||
return -EINVAL; | ||
if (S_ISLNK(inode->i_mode)) | ||
return -EOPNOTSUPP; | ||
if (!is_owner_or_cap(inode)) | ||
|
@@ -91,28 +86,27 @@ generic_acl_set(struct inode *inode, struct generic_acl_operations *ops, | |
error = posix_acl_valid(acl); | ||
if (error) | ||
goto failed; | ||
switch(type) { | ||
case ACL_TYPE_ACCESS: | ||
mode = inode->i_mode; | ||
error = posix_acl_equiv_mode(acl, &mode); | ||
if (error < 0) | ||
goto failed; | ||
inode->i_mode = mode; | ||
if (error == 0) { | ||
posix_acl_release(acl); | ||
acl = NULL; | ||
} | ||
break; | ||
|
||
case ACL_TYPE_DEFAULT: | ||
if (!S_ISDIR(inode->i_mode)) { | ||
error = -EINVAL; | ||
goto failed; | ||
} | ||
break; | ||
switch (type) { | ||
case ACL_TYPE_ACCESS: | ||
mode = inode->i_mode; | ||
error = posix_acl_equiv_mode(acl, &mode); | ||
if (error < 0) | ||
goto failed; | ||
inode->i_mode = mode; | ||
if (error == 0) { | ||
posix_acl_release(acl); | ||
acl = NULL; | ||
} | ||
break; | ||
case ACL_TYPE_DEFAULT: | ||
if (!S_ISDIR(inode->i_mode)) { | ||
error = -EINVAL; | ||
goto failed; | ||
} | ||
break; | ||
} | ||
} | ||
ops->setacl(inode, type, acl); | ||
set_cached_acl(inode, type, acl); | ||
error = 0; | ||
failed: | ||
posix_acl_release(acl); | ||
|
@@ -121,22 +115,20 @@ generic_acl_set(struct inode *inode, struct generic_acl_operations *ops, | |
|
||
/** | ||
* generic_acl_init - Take care of acl inheritance at @inode create time | ||
* @ops: Filesystem specific getacl and setacl callbacks | ||
* | ||
* Files created inside a directory with a default ACL inherit the | ||
* directory's default ACL. | ||
*/ | ||
int | ||
generic_acl_init(struct inode *inode, struct inode *dir, | ||
struct generic_acl_operations *ops) | ||
generic_acl_init(struct inode *inode, struct inode *dir) | ||
{ | ||
struct posix_acl *acl = NULL; | ||
mode_t mode = inode->i_mode; | ||
int error; | ||
|
||
inode->i_mode = mode & ~current_umask(); | ||
if (!S_ISLNK(inode->i_mode)) | ||
acl = ops->getacl(dir, ACL_TYPE_DEFAULT); | ||
acl = get_cached_acl(dir, ACL_TYPE_DEFAULT); | ||
if (acl) { | ||
struct posix_acl *clone; | ||
|
||
|
@@ -145,7 +137,7 @@ generic_acl_init(struct inode *inode, struct inode *dir, | |
error = -ENOMEM; | ||
if (!clone) | ||
goto cleanup; | ||
ops->setacl(inode, ACL_TYPE_DEFAULT, clone); | ||
set_cached_acl(inode, ACL_TYPE_DEFAULT, clone); | ||
posix_acl_release(clone); | ||
} | ||
clone = posix_acl_clone(acl, GFP_KERNEL); | ||
|
@@ -156,7 +148,7 @@ generic_acl_init(struct inode *inode, struct inode *dir, | |
if (error >= 0) { | ||
inode->i_mode = mode; | ||
if (error > 0) | ||
ops->setacl(inode, ACL_TYPE_ACCESS, clone); | ||
set_cached_acl(inode, ACL_TYPE_ACCESS, clone); | ||
} | ||
posix_acl_release(clone); | ||
} | ||
|
@@ -169,29 +161,57 @@ generic_acl_init(struct inode *inode, struct inode *dir, | |
|
||
/** | ||
* generic_acl_chmod - change the access acl of @inode upon chmod() | ||
* @ops: FIlesystem specific getacl and setacl callbacks | ||
* | ||
* A chmod also changes the permissions of the owner, group/mask, and | ||
* other ACL entries. | ||
*/ | ||
int | ||
generic_acl_chmod(struct inode *inode, struct generic_acl_operations *ops) | ||
generic_acl_chmod(struct inode *inode) | ||
{ | ||
struct posix_acl *acl, *clone; | ||
int error = 0; | ||
|
||
if (S_ISLNK(inode->i_mode)) | ||
return -EOPNOTSUPP; | ||
acl = ops->getacl(inode, ACL_TYPE_ACCESS); | ||
acl = get_cached_acl(inode, ACL_TYPE_ACCESS); | ||
if (acl) { | ||
clone = posix_acl_clone(acl, GFP_KERNEL); | ||
posix_acl_release(acl); | ||
if (!clone) | ||
return -ENOMEM; | ||
error = posix_acl_chmod_masq(clone, inode->i_mode); | ||
if (!error) | ||
ops->setacl(inode, ACL_TYPE_ACCESS, clone); | ||
set_cached_acl(inode, ACL_TYPE_ACCESS, clone); | ||
posix_acl_release(clone); | ||
} | ||
return error; | ||
} | ||
|
||
int | ||
generic_check_acl(struct inode *inode, int mask) | ||
{ | ||
struct posix_acl *acl = get_cached_acl(inode, ACL_TYPE_ACCESS); | ||
|
||
if (acl) { | ||
int error = posix_acl_permission(inode, acl, mask); | ||
posix_acl_release(acl); | ||
return error; | ||
} | ||
return -EAGAIN; | ||
} | ||
|
||
struct xattr_handler generic_acl_access_handler = { | ||
.prefix = POSIX_ACL_XATTR_ACCESS, | ||
.flags = ACL_TYPE_ACCESS, | ||
.list = generic_acl_list, | ||
.get = generic_acl_get, | ||
.set = generic_acl_set, | ||
}; | ||
|
||
struct xattr_handler generic_acl_default_handler = { | ||
.prefix = POSIX_ACL_XATTR_DEFAULT, | ||
.flags = ACL_TYPE_DEFAULT, | ||
.list = generic_acl_list, | ||
.get = generic_acl_get, | ||
.set = generic_acl_set, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,36 +1,15 @@ | ||
/* | ||
* include/linux/generic_acl.h | ||
* | ||
* (C) 2005 Andreas Gruenbacher <[email protected]> | ||
* | ||
* This file is released under the GPL. | ||
*/ | ||
#ifndef LINUX_GENERIC_ACL_H | ||
#define LINUX_GENERIC_ACL_H | ||
|
||
#ifndef GENERIC_ACL_H | ||
#define GENERIC_ACL_H | ||
#include <linux/xattr.h> | ||
|
||
#include <linux/posix_acl.h> | ||
#include <linux/posix_acl_xattr.h> | ||
struct inode; | ||
|
||
/** | ||
* struct generic_acl_operations - filesystem operations | ||
* | ||
* Filesystems must make these operations available to the generic | ||
* operations. | ||
*/ | ||
struct generic_acl_operations { | ||
struct posix_acl *(*getacl)(struct inode *, int); | ||
void (*setacl)(struct inode *, int, struct posix_acl *); | ||
}; | ||
extern struct xattr_handler generic_acl_access_handler; | ||
extern struct xattr_handler generic_acl_default_handler; | ||
|
||
size_t generic_acl_list(struct inode *, struct generic_acl_operations *, int, | ||
char *, size_t); | ||
int generic_acl_get(struct inode *, struct generic_acl_operations *, int, | ||
void *, size_t); | ||
int generic_acl_set(struct inode *, struct generic_acl_operations *, int, | ||
const void *, size_t); | ||
int generic_acl_init(struct inode *, struct inode *, | ||
struct generic_acl_operations *); | ||
int generic_acl_chmod(struct inode *, struct generic_acl_operations *); | ||
int generic_acl_init(struct inode *, struct inode *); | ||
int generic_acl_chmod(struct inode *); | ||
int generic_check_acl(struct inode *inode, int mask); | ||
|
||
#endif | ||
#endif /* LINUX_GENERIC_ACL_H */ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.