sched: Fix broken assertion
[sfrench/cifs-2.6.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 static int
33 __xfs_xattr_get(struct inode *inode, const char *name,
34                 void *value, size_t size, int xflags)
35 {
36         struct xfs_inode *ip = XFS_I(inode);
37         int error, asize = size;
38
39         if (strcmp(name, "") == 0)
40                 return -EINVAL;
41
42         /* Convert Linux syscall to XFS internal ATTR flags */
43         if (!size) {
44                 xflags |= ATTR_KERNOVAL;
45                 value = NULL;
46         }
47
48         error = -xfs_attr_get(ip, name, value, &asize, xflags);
49         if (error)
50                 return error;
51         return asize;
52 }
53
54 static int
55 __xfs_xattr_set(struct inode *inode, const char *name, const void *value,
56                 size_t size, int flags, int xflags)
57 {
58         struct xfs_inode *ip = XFS_I(inode);
59
60         if (strcmp(name, "") == 0)
61                 return -EINVAL;
62
63         /* Convert Linux syscall to XFS internal ATTR flags */
64         if (flags & XATTR_CREATE)
65                 xflags |= ATTR_CREATE;
66         if (flags & XATTR_REPLACE)
67                 xflags |= ATTR_REPLACE;
68
69         if (!value)
70                 return -xfs_attr_remove(ip, name, xflags);
71         return -xfs_attr_set(ip, name, (void *)value, size, xflags);
72 }
73
74 static int
75 xfs_xattr_user_get(struct inode *inode, const char *name,
76                 void *value, size_t size)
77 {
78         return __xfs_xattr_get(inode, name, value, size, 0);
79 }
80
81 static int
82 xfs_xattr_user_set(struct inode *inode, const char *name,
83                 const void *value, size_t size, int flags)
84 {
85         return __xfs_xattr_set(inode, name, value, size, flags, 0);
86 }
87
88 static struct xattr_handler xfs_xattr_user_handler = {
89         .prefix = XATTR_USER_PREFIX,
90         .get    = xfs_xattr_user_get,
91         .set    = xfs_xattr_user_set,
92 };
93
94
95 static int
96 xfs_xattr_trusted_get(struct inode *inode, const char *name,
97                 void *value, size_t size)
98 {
99         return __xfs_xattr_get(inode, name, value, size, ATTR_ROOT);
100 }
101
102 static int
103 xfs_xattr_trusted_set(struct inode *inode, const char *name,
104                 const void *value, size_t size, int flags)
105 {
106         return __xfs_xattr_set(inode, name, value, size, flags, ATTR_ROOT);
107 }
108
109 static struct xattr_handler xfs_xattr_trusted_handler = {
110         .prefix = XATTR_TRUSTED_PREFIX,
111         .get    = xfs_xattr_trusted_get,
112         .set    = xfs_xattr_trusted_set,
113 };
114
115
116 static int
117 xfs_xattr_secure_get(struct inode *inode, const char *name,
118                 void *value, size_t size)
119 {
120         return __xfs_xattr_get(inode, name, value, size, ATTR_SECURE);
121 }
122
123 static int
124 xfs_xattr_secure_set(struct inode *inode, const char *name,
125                 const void *value, size_t size, int flags)
126 {
127         return __xfs_xattr_set(inode, name, value, size, flags, ATTR_SECURE);
128 }
129
130 static struct xattr_handler xfs_xattr_security_handler = {
131         .prefix = XATTR_SECURITY_PREFIX,
132         .get    = xfs_xattr_secure_get,
133         .set    = xfs_xattr_secure_set,
134 };
135
136
137 struct xattr_handler *xfs_xattr_handlers[] = {
138         &xfs_xattr_user_handler,
139         &xfs_xattr_trusted_handler,
140         &xfs_xattr_security_handler,
141 #ifdef CONFIG_XFS_POSIX_ACL
142         &xfs_xattr_system_handler,
143 #endif
144         NULL
145 };
146
147 static unsigned int xfs_xattr_prefix_len(int flags)
148 {
149         if (flags & XFS_ATTR_SECURE)
150                 return sizeof("security");
151         else if (flags & XFS_ATTR_ROOT)
152                 return sizeof("trusted");
153         else
154                 return sizeof("user");
155 }
156
157 static const char *xfs_xattr_prefix(int flags)
158 {
159         if (flags & XFS_ATTR_SECURE)
160                 return xfs_xattr_security_handler.prefix;
161         else if (flags & XFS_ATTR_ROOT)
162                 return xfs_xattr_trusted_handler.prefix;
163         else
164                 return xfs_xattr_user_handler.prefix;
165 }
166
167 static int
168 xfs_xattr_put_listent(struct xfs_attr_list_context *context, int flags,
169                 char *name, int namelen, int valuelen, char *value)
170 {
171         unsigned int prefix_len = xfs_xattr_prefix_len(flags);
172         char *offset;
173         int arraytop;
174
175         ASSERT(context->count >= 0);
176
177         /*
178          * Only show root namespace entries if we are actually allowed to
179          * see them.
180          */
181         if ((flags & XFS_ATTR_ROOT) && !capable(CAP_SYS_ADMIN))
182                 return 0;
183
184         arraytop = context->count + prefix_len + namelen + 1;
185         if (arraytop > context->firstu) {
186                 context->count = -1;    /* insufficient space */
187                 return 1;
188         }
189         offset = (char *)context->alist + context->count;
190         strncpy(offset, xfs_xattr_prefix(flags), prefix_len);
191         offset += prefix_len;
192         strncpy(offset, name, namelen);                 /* real name */
193         offset += namelen;
194         *offset = '\0';
195         context->count += prefix_len + namelen + 1;
196         return 0;
197 }
198
199 static int
200 xfs_xattr_put_listent_sizes(struct xfs_attr_list_context *context, int flags,
201                 char *name, int namelen, int valuelen, char *value)
202 {
203         context->count += xfs_xattr_prefix_len(flags) + namelen + 1;
204         return 0;
205 }
206
207 static int
208 list_one_attr(const char *name, const size_t len, void *data,
209                 size_t size, ssize_t *result)
210 {
211         char *p = data + *result;
212
213         *result += len;
214         if (!size)
215                 return 0;
216         if (*result > size)
217                 return -ERANGE;
218
219         strcpy(p, name);
220         return 0;
221 }
222
223 ssize_t
224 xfs_vn_listxattr(struct dentry *dentry, char *data, size_t size)
225 {
226         struct xfs_attr_list_context context;
227         struct attrlist_cursor_kern cursor = { 0 };
228         struct inode            *inode = dentry->d_inode;
229         int                     error;
230
231         /*
232          * First read the regular on-disk attributes.
233          */
234         memset(&context, 0, sizeof(context));
235         context.dp = XFS_I(inode);
236         context.cursor = &cursor;
237         context.resynch = 1;
238         context.alist = data;
239         context.bufsize = size;
240         context.firstu = context.bufsize;
241
242         if (size)
243                 context.put_listent = xfs_xattr_put_listent;
244         else
245                 context.put_listent = xfs_xattr_put_listent_sizes;
246
247         xfs_attr_list_int(&context);
248         if (context.count < 0)
249                 return -ERANGE;
250
251         /*
252          * Then add the two synthetic ACL attributes.
253          */
254         if (posix_acl_access_exists(inode)) {
255                 error = list_one_attr(POSIX_ACL_XATTR_ACCESS,
256                                 strlen(POSIX_ACL_XATTR_ACCESS) + 1,
257                                 data, size, &context.count);
258                 if (error)
259                         return error;
260         }
261
262         if (posix_acl_default_exists(inode)) {
263                 error = list_one_attr(POSIX_ACL_XATTR_DEFAULT,
264                                 strlen(POSIX_ACL_XATTR_DEFAULT) + 1,
265                                 data, size, &context.count);
266                 if (error)
267                         return error;
268         }
269
270         return context.count;
271 }