aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorChristoph Hellwig <hch@lst.de>2009-11-03 10:44:44 -0500
committerAl Viro <viro@zeniv.linux.org.uk>2009-12-16 12:16:49 -0500
commit1c7c474c31aea6d5cb2fb35f31d9e9e91ae466b1 (patch)
tree89a5fd1146be1744ce3ac94789542841512315b8 /fs
parent431547b3c4533b8c7fd150ab36980b9a3147797b (diff)
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 <hch@lst.de> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'fs')
-rw-r--r--fs/generic_acl.c158
1 files changed, 89 insertions, 69 deletions
diff --git a/fs/generic_acl.c b/fs/generic_acl.c
index e0b53aa7bbec..55458031e501 100644
--- a/fs/generic_acl.c
+++ b/fs/generic_acl.c
@@ -1,62 +1,58 @@
1/* 1/*
2 * fs/generic_acl.c
3 *
4 * (C) 2005 Andreas Gruenbacher <agruen@suse.de> 2 * (C) 2005 Andreas Gruenbacher <agruen@suse.de>
5 * 3 *
6 * This file is released under the GPL. 4 * This file is released under the GPL.
5 *
6 * Generic ACL support for in-memory filesystems.
7 */ 7 */
8 8
9#include <linux/sched.h> 9#include <linux/sched.h>
10#include <linux/fs.h> 10#include <linux/fs.h>
11#include <linux/generic_acl.h> 11#include <linux/generic_acl.h>
12#include <linux/posix_acl.h>
13#include <linux/posix_acl_xattr.h>
12 14
13/** 15
14 * generic_acl_list - Generic xattr_handler->list() operation 16static size_t
15 * @ops: Filesystem specific getacl and setacl callbacks 17generic_acl_list(struct dentry *dentry, char *list, size_t list_size,
16 */ 18 const char *name, size_t name_len, int type)
17size_t
18generic_acl_list(struct inode *inode, struct generic_acl_operations *ops,
19 int type, char *list, size_t list_size)
20{ 19{
21 struct posix_acl *acl; 20 struct posix_acl *acl;
22 const char *name; 21 const char *xname;
23 size_t size; 22 size_t size;
24 23
25 acl = ops->getacl(inode, type); 24 acl = get_cached_acl(dentry->d_inode, type);
26 if (!acl) 25 if (!acl)
27 return 0; 26 return 0;
28 posix_acl_release(acl); 27 posix_acl_release(acl);
29 28
30 switch(type) { 29 switch (type) {
31 case ACL_TYPE_ACCESS: 30 case ACL_TYPE_ACCESS:
32 name = POSIX_ACL_XATTR_ACCESS; 31 xname = POSIX_ACL_XATTR_ACCESS;
33 break; 32 break;
34 33 case ACL_TYPE_DEFAULT:
35 case ACL_TYPE_DEFAULT: 34 xname = POSIX_ACL_XATTR_DEFAULT;
36 name = POSIX_ACL_XATTR_DEFAULT; 35 break;
37 break; 36 default:
38 37 return 0;
39 default:
40 return 0;
41 } 38 }
42 size = strlen(name) + 1; 39 size = strlen(xname) + 1;
43 if (list && size <= list_size) 40 if (list && size <= list_size)
44 memcpy(list, name, size); 41 memcpy(list, xname, size);
45 return size; 42 return size;
46} 43}
47 44
48/** 45static int
49 * generic_acl_get - Generic xattr_handler->get() operation 46generic_acl_get(struct dentry *dentry, const char *name, void *buffer,
50 * @ops: Filesystem specific getacl and setacl callbacks 47 size_t size, int type)
51 */
52int
53generic_acl_get(struct inode *inode, struct generic_acl_operations *ops,
54 int type, void *buffer, size_t size)
55{ 48{
56 struct posix_acl *acl; 49 struct posix_acl *acl;
57 int error; 50 int error;
58 51
59 acl = ops->getacl(inode, type); 52 if (strcmp(name, "") != 0)
53 return -EINVAL;
54
55 acl = get_cached_acl(dentry->d_inode, type);
60 if (!acl) 56 if (!acl)
61 return -ENODATA; 57 return -ENODATA;
62 error = posix_acl_to_xattr(acl, buffer, size); 58 error = posix_acl_to_xattr(acl, buffer, size);
@@ -65,17 +61,16 @@ generic_acl_get(struct inode *inode, struct generic_acl_operations *ops,
65 return error; 61 return error;
66} 62}
67 63
68/** 64static int
69 * generic_acl_set - Generic xattr_handler->set() operation 65generic_acl_set(struct dentry *dentry, const char *name, const void *value,
70 * @ops: Filesystem specific getacl and setacl callbacks 66 size_t size, int flags, int type)
71 */
72int
73generic_acl_set(struct inode *inode, struct generic_acl_operations *ops,
74 int type, const void *value, size_t size)
75{ 67{
68 struct inode *inode = dentry->d_inode;
76 struct posix_acl *acl = NULL; 69 struct posix_acl *acl = NULL;
77 int error; 70 int error;
78 71
72 if (strcmp(name, "") != 0)
73 return -EINVAL;
79 if (S_ISLNK(inode->i_mode)) 74 if (S_ISLNK(inode->i_mode))
80 return -EOPNOTSUPP; 75 return -EOPNOTSUPP;
81 if (!is_owner_or_cap(inode)) 76 if (!is_owner_or_cap(inode))
@@ -91,28 +86,27 @@ generic_acl_set(struct inode *inode, struct generic_acl_operations *ops,
91 error = posix_acl_valid(acl); 86 error = posix_acl_valid(acl);
92 if (error) 87 if (error)
93 goto failed; 88 goto failed;
94 switch(type) { 89 switch (type) {
95 case ACL_TYPE_ACCESS: 90 case ACL_TYPE_ACCESS:
96 mode = inode->i_mode; 91 mode = inode->i_mode;
97 error = posix_acl_equiv_mode(acl, &mode); 92 error = posix_acl_equiv_mode(acl, &mode);
98 if (error < 0) 93 if (error < 0)
99 goto failed; 94 goto failed;
100 inode->i_mode = mode; 95 inode->i_mode = mode;
101 if (error == 0) { 96 if (error == 0) {
102 posix_acl_release(acl); 97 posix_acl_release(acl);
103 acl = NULL; 98 acl = NULL;
104 } 99 }
105 break; 100 break;
106 101 case ACL_TYPE_DEFAULT:
107 case ACL_TYPE_DEFAULT: 102 if (!S_ISDIR(inode->i_mode)) {
108 if (!S_ISDIR(inode->i_mode)) { 103 error = -EINVAL;
109 error = -EINVAL; 104 goto failed;
110 goto failed; 105 }
111 } 106 break;
112 break;
113 } 107 }
114 } 108 }
115 ops->setacl(inode, type, acl); 109 set_cached_acl(inode, type, acl);
116 error = 0; 110 error = 0;
117failed: 111failed:
118 posix_acl_release(acl); 112 posix_acl_release(acl);
@@ -121,14 +115,12 @@ failed:
121 115
122/** 116/**
123 * generic_acl_init - Take care of acl inheritance at @inode create time 117 * generic_acl_init - Take care of acl inheritance at @inode create time
124 * @ops: Filesystem specific getacl and setacl callbacks
125 * 118 *
126 * Files created inside a directory with a default ACL inherit the 119 * Files created inside a directory with a default ACL inherit the
127 * directory's default ACL. 120 * directory's default ACL.
128 */ 121 */
129int 122int
130generic_acl_init(struct inode *inode, struct inode *dir, 123generic_acl_init(struct inode *inode, struct inode *dir)
131 struct generic_acl_operations *ops)
132{ 124{
133 struct posix_acl *acl = NULL; 125 struct posix_acl *acl = NULL;
134 mode_t mode = inode->i_mode; 126 mode_t mode = inode->i_mode;
@@ -136,7 +128,7 @@ generic_acl_init(struct inode *inode, struct inode *dir,
136 128
137 inode->i_mode = mode & ~current_umask(); 129 inode->i_mode = mode & ~current_umask();
138 if (!S_ISLNK(inode->i_mode)) 130 if (!S_ISLNK(inode->i_mode))
139 acl = ops->getacl(dir, ACL_TYPE_DEFAULT); 131 acl = get_cached_acl(dir, ACL_TYPE_DEFAULT);
140 if (acl) { 132 if (acl) {
141 struct posix_acl *clone; 133 struct posix_acl *clone;
142 134
@@ -145,7 +137,7 @@ generic_acl_init(struct inode *inode, struct inode *dir,
145 error = -ENOMEM; 137 error = -ENOMEM;
146 if (!clone) 138 if (!clone)
147 goto cleanup; 139 goto cleanup;
148 ops->setacl(inode, ACL_TYPE_DEFAULT, clone); 140 set_cached_acl(inode, ACL_TYPE_DEFAULT, clone);
149 posix_acl_release(clone); 141 posix_acl_release(clone);
150 } 142 }
151 clone = posix_acl_clone(acl, GFP_KERNEL); 143 clone = posix_acl_clone(acl, GFP_KERNEL);
@@ -156,7 +148,7 @@ generic_acl_init(struct inode *inode, struct inode *dir,
156 if (error >= 0) { 148 if (error >= 0) {
157 inode->i_mode = mode; 149 inode->i_mode = mode;
158 if (error > 0) 150 if (error > 0)
159 ops->setacl(inode, ACL_TYPE_ACCESS, clone); 151 set_cached_acl(inode, ACL_TYPE_ACCESS, clone);
160 } 152 }
161 posix_acl_release(clone); 153 posix_acl_release(clone);
162 } 154 }
@@ -169,20 +161,19 @@ cleanup:
169 161
170/** 162/**
171 * generic_acl_chmod - change the access acl of @inode upon chmod() 163 * generic_acl_chmod - change the access acl of @inode upon chmod()
172 * @ops: FIlesystem specific getacl and setacl callbacks
173 * 164 *
174 * A chmod also changes the permissions of the owner, group/mask, and 165 * A chmod also changes the permissions of the owner, group/mask, and
175 * other ACL entries. 166 * other ACL entries.
176 */ 167 */
177int 168int
178generic_acl_chmod(struct inode *inode, struct generic_acl_operations *ops) 169generic_acl_chmod(struct inode *inode)
179{ 170{
180 struct posix_acl *acl, *clone; 171 struct posix_acl *acl, *clone;
181 int error = 0; 172 int error = 0;
182 173
183 if (S_ISLNK(inode->i_mode)) 174 if (S_ISLNK(inode->i_mode))
184 return -EOPNOTSUPP; 175 return -EOPNOTSUPP;
185 acl = ops->getacl(inode, ACL_TYPE_ACCESS); 176 acl = get_cached_acl(inode, ACL_TYPE_ACCESS);
186 if (acl) { 177 if (acl) {
187 clone = posix_acl_clone(acl, GFP_KERNEL); 178 clone = posix_acl_clone(acl, GFP_KERNEL);
188 posix_acl_release(acl); 179 posix_acl_release(acl);
@@ -190,8 +181,37 @@ generic_acl_chmod(struct inode *inode, struct generic_acl_operations *ops)
190 return -ENOMEM; 181 return -ENOMEM;
191 error = posix_acl_chmod_masq(clone, inode->i_mode); 182 error = posix_acl_chmod_masq(clone, inode->i_mode);
192 if (!error) 183 if (!error)
193 ops->setacl(inode, ACL_TYPE_ACCESS, clone); 184 set_cached_acl(inode, ACL_TYPE_ACCESS, clone);
194 posix_acl_release(clone); 185 posix_acl_release(clone);
195 } 186 }
196 return error; 187 return error;
197} 188}
189
190int
191generic_check_acl(struct inode *inode, int mask)
192{
193 struct posix_acl *acl = get_cached_acl(inode, ACL_TYPE_ACCESS);
194
195 if (acl) {
196 int error = posix_acl_permission(inode, acl, mask);
197 posix_acl_release(acl);
198 return error;
199 }
200 return -EAGAIN;
201}
202
203struct xattr_handler generic_acl_access_handler = {
204 .prefix = POSIX_ACL_XATTR_ACCESS,
205 .flags = ACL_TYPE_ACCESS,
206 .list = generic_acl_list,
207 .get = generic_acl_get,
208 .set = generic_acl_set,
209};
210
211struct xattr_handler generic_acl_default_handler = {
212 .prefix = POSIX_ACL_XATTR_DEFAULT,
213 .flags = ACL_TYPE_DEFAULT,
214 .list = generic_acl_list,
215 .get = generic_acl_get,
216 .set = generic_acl_set,
217};