]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blob - fs/xfs/linux-2.6/xfs_xattr.c
b4acb68fc9f793d3b54bab869425b26d6106cdcb
[linux-2.6-omap-h63xx.git] / fs / xfs / linux-2.6 / xfs_xattr.c
1 /*
2  * Copyright (C) 2008 Christoph Hellwig.
3  * Portions Copyright (C) 2000-2008 Silicon Graphics, Inc.
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License as
7  * published by the Free Software Foundation.
8  *
9  * This program is distributed in the hope that it would be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write the Free Software Foundation,
16  * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
17  */
18
19 #include "xfs.h"
20 #include "xfs_da_btree.h"
21 #include "xfs_bmap_btree.h"
22 #include "xfs_inode.h"
23 #include "xfs_attr.h"
24 #include "xfs_attr_leaf.h"
25 #include "xfs_acl.h"
26 #include "xfs_vnodeops.h"
27
28 #include <linux/posix_acl_xattr.h>
29 #include <linux/xattr.h>
30
31
32 /*
33  * ACL handling.  Should eventually be moved into xfs_acl.c
34  */
35
36 static int
37 xfs_decode_acl(const char *name)
38 {
39         if (strcmp(name, "posix_acl_access") == 0)
40                 return _ACL_TYPE_ACCESS;
41         else if (strcmp(name, "posix_acl_default") == 0)
42                 return _ACL_TYPE_DEFAULT;
43         return -EINVAL;
44 }
45
46 /*
47  * Get system extended attributes which at the moment only
48  * includes Posix ACLs.
49  */
50 static int
51 xfs_xattr_system_get(struct inode *inode, const char *name,
52                 void *buffer, size_t size)
53 {
54         int acl;
55
56         acl = xfs_decode_acl(name);
57         if (acl < 0)
58                 return acl;
59
60         return xfs_acl_vget(inode, buffer, size, acl);
61 }
62
63 static int
64 xfs_xattr_system_set(struct inode *inode, const char *name,
65                 const void *value, size_t size, int flags)
66 {
67         int error, acl;
68
69         acl = xfs_decode_acl(name);
70         if (acl < 0)
71                 return acl;
72         if (flags & XATTR_CREATE)
73                 return -EINVAL;
74
75         if (!value)
76                 return xfs_acl_vremove(inode, acl);
77
78         error = xfs_acl_vset(inode, (void *)value, size, acl);
79         if (!error)
80                 vn_revalidate(inode);
81         return error;
82 }
83
84 static struct xattr_handler xfs_xattr_system_handler = {
85         .prefix = XATTR_SYSTEM_PREFIX,
86         .get    = xfs_xattr_system_get,
87         .set    = xfs_xattr_system_set,
88 };
89
90
91 /*
92  * Real xattr handling.  The only difference between the namespaces is
93  * a flag passed to the low-level attr code.
94  */
95
96 static int
97 __xfs_xattr_get(struct inode *inode, const char *name,
98                 void *value, size_t size, int xflags)
99 {
100         struct xfs_inode *ip = XFS_I(inode);
101         int error, asize = size;
102
103         if (strcmp(name, "") == 0)
104                 return -EINVAL;
105
106         /* Convert Linux syscall to XFS internal ATTR flags */
107         if (!size) {
108                 xflags |= ATTR_KERNOVAL;
109                 value = NULL;
110         }
111
112         error = -xfs_attr_get(ip, name, value, &asize, xflags);
113         if (error)
114                 return error;
115         return asize;
116 }
117
118 static int
119 __xfs_xattr_set(struct inode *inode, const char *name, const void *value,
120                 size_t size, int flags, int xflags)
121 {
122         struct xfs_inode *ip = XFS_I(inode);
123
124         if (strcmp(name, "") == 0)
125                 return -EINVAL;
126
127         /* Convert Linux syscall to XFS internal ATTR flags */
128         if (flags & XATTR_CREATE)
129                 xflags |= ATTR_CREATE;
130         if (flags & XATTR_REPLACE)
131                 xflags |= ATTR_REPLACE;
132
133         if (!value)
134                 return -xfs_attr_remove(ip, name, xflags);
135         return -xfs_attr_set(ip, name, (void *)value, size, xflags);
136 }
137
138 static int
139 xfs_xattr_user_get(struct inode *inode, const char *name,
140                 void *value, size_t size)
141 {
142         return __xfs_xattr_get(inode, name, value, size, 0);
143 }
144
145 static int
146 xfs_xattr_user_set(struct inode *inode, const char *name,
147                 const void *value, size_t size, int flags)
148 {
149         return __xfs_xattr_set(inode, name, value, size, flags, 0);
150 }
151
152 static struct xattr_handler xfs_xattr_user_handler = {
153         .prefix = XATTR_USER_PREFIX,
154         .get    = xfs_xattr_user_get,
155         .set    = xfs_xattr_user_set,
156 };
157
158
159 static int
160 xfs_xattr_trusted_get(struct inode *inode, const char *name,
161                 void *value, size_t size)
162 {
163         return __xfs_xattr_get(inode, name, value, size, ATTR_ROOT);
164 }
165
166 static int
167 xfs_xattr_trusted_set(struct inode *inode, const char *name,
168                 const void *value, size_t size, int flags)
169 {
170         return __xfs_xattr_set(inode, name, value, size, flags, ATTR_ROOT);
171 }
172
173 static struct xattr_handler xfs_xattr_trusted_handler = {
174         .prefix = XATTR_TRUSTED_PREFIX,
175         .get    = xfs_xattr_trusted_get,
176         .set    = xfs_xattr_trusted_set,
177 };
178
179
180 static int
181 xfs_xattr_secure_get(struct inode *inode, const char *name,
182                 void *value, size_t size)
183 {
184         return __xfs_xattr_get(inode, name, value, size, ATTR_SECURE);
185 }
186
187 static int
188 xfs_xattr_secure_set(struct inode *inode, const char *name,
189                 const void *value, size_t size, int flags)
190 {
191         return __xfs_xattr_set(inode, name, value, size, flags, ATTR_SECURE);
192 }
193
194 static struct xattr_handler xfs_xattr_security_handler = {
195         .prefix = XATTR_SECURITY_PREFIX,
196         .get    = xfs_xattr_secure_get,
197         .set    = xfs_xattr_secure_set,
198 };
199
200
201 struct xattr_handler *xfs_xattr_handlers[] = {
202         &xfs_xattr_user_handler,
203         &xfs_xattr_trusted_handler,
204         &xfs_xattr_security_handler,
205         &xfs_xattr_system_handler,
206         NULL
207 };
208
209 static unsigned int xfs_xattr_prefix_len(int flags)
210 {
211         if (flags & XFS_ATTR_SECURE)
212                 return sizeof("security");
213         else if (flags & XFS_ATTR_ROOT)
214                 return sizeof("trusted");
215         else
216                 return sizeof("user");
217 }
218
219 static const char *xfs_xattr_prefix(int flags)
220 {
221         if (flags & XFS_ATTR_SECURE)
222                 return xfs_xattr_security_handler.prefix;
223         else if (flags & XFS_ATTR_ROOT)
224                 return xfs_xattr_trusted_handler.prefix;
225         else
226                 return xfs_xattr_user_handler.prefix;
227 }
228
229 static int
230 xfs_xattr_put_listent(struct xfs_attr_list_context *context, int flags,
231                 char *name, int namelen, int valuelen, char *value)
232 {
233         unsigned int prefix_len = xfs_xattr_prefix_len(flags);
234         char *offset;
235         int arraytop;
236
237         ASSERT(context->count >= 0);
238
239         /*
240          * Only show root namespace entries if we are actually allowed to
241          * see them.
242          */
243         if ((flags & XFS_ATTR_ROOT) && !capable(CAP_SYS_ADMIN))
244                 return 0;
245
246         arraytop = context->count + prefix_len + namelen + 1;
247         if (arraytop > context->firstu) {
248                 context->count = -1;    /* insufficient space */
249                 return 1;
250         }
251         offset = (char *)context->alist + context->count;
252         strncpy(offset, xfs_xattr_prefix(flags), prefix_len);
253         offset += prefix_len;
254         strncpy(offset, name, namelen);                 /* real name */
255         offset += namelen;
256         *offset = '\0';
257         context->count += prefix_len + namelen + 1;
258         return 0;
259 }
260
261 static int
262 xfs_xattr_put_listent_sizes(struct xfs_attr_list_context *context, int flags,
263                 char *name, int namelen, int valuelen, char *value)
264 {
265         context->count += xfs_xattr_prefix_len(flags) + namelen + 1;
266         return 0;
267 }
268
269 static int
270 list_one_attr(const char *name, const size_t len, void *data,
271                 size_t size, ssize_t *result)
272 {
273         char *p = data + *result;
274
275         *result += len;
276         if (!size)
277                 return 0;
278         if (*result > size)
279                 return -ERANGE;
280
281         strcpy(p, name);
282         return 0;
283 }
284
285 ssize_t
286 xfs_vn_listxattr(struct dentry *dentry, char *data, size_t size)
287 {
288         struct xfs_attr_list_context context;
289         struct attrlist_cursor_kern cursor = { 0 };
290         struct inode            *inode = dentry->d_inode;
291         int                     error;
292
293         /*
294          * First read the regular on-disk attributes.
295          */
296         memset(&context, 0, sizeof(context));
297         context.dp = XFS_I(inode);
298         context.cursor = &cursor;
299         context.resynch = 1;
300         context.alist = data;
301         context.bufsize = size;
302         context.firstu = context.bufsize;
303
304         if (size)
305                 context.put_listent = xfs_xattr_put_listent;
306         else
307                 context.put_listent = xfs_xattr_put_listent_sizes;
308
309         xfs_attr_list_int(&context);
310         if (context.count < 0)
311                 return -ERANGE;
312
313         /*
314          * Then add the two synthetic ACL attributes.
315          */
316         if (xfs_acl_vhasacl_access(inode)) {
317                 error = list_one_attr(POSIX_ACL_XATTR_ACCESS,
318                                 strlen(POSIX_ACL_XATTR_ACCESS) + 1,
319                                 data, size, &context.count);
320                 if (error)
321                         return error;
322         }
323
324         if (xfs_acl_vhasacl_default(inode)) {
325                 error = list_one_attr(POSIX_ACL_XATTR_DEFAULT,
326                                 strlen(POSIX_ACL_XATTR_DEFAULT) + 1,
327                                 data, size, &context.count);
328                 if (error)
329                         return error;
330         }
331
332         return context.count;
333 }