]> git.kernelconcepts.de Git - karo-tx-linux.git/blob - fs/xfs/xfs_xattr.c
Merge branch 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jack/linux-fs
[karo-tx-linux.git] / fs / xfs / 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_format.h"
21 #include "xfs_log_format.h"
22 #include "xfs_trans_resv.h"
23 #include "xfs_sb.h"
24 #include "xfs_ag.h"
25 #include "xfs_mount.h"
26 #include "xfs_da_format.h"
27 #include "xfs_inode.h"
28 #include "xfs_attr.h"
29 #include "xfs_attr_leaf.h"
30 #include "xfs_acl.h"
31
32 #include <linux/posix_acl_xattr.h>
33 #include <linux/xattr.h>
34
35
36 static int
37 xfs_xattr_get(struct dentry *dentry, const char *name,
38                 void *value, size_t size, int xflags)
39 {
40         struct xfs_inode *ip = XFS_I(dentry->d_inode);
41         int error, asize = size;
42
43         if (strcmp(name, "") == 0)
44                 return -EINVAL;
45
46         /* Convert Linux syscall to XFS internal ATTR flags */
47         if (!size) {
48                 xflags |= ATTR_KERNOVAL;
49                 value = NULL;
50         }
51
52         error = -xfs_attr_get(ip, (unsigned char *)name, value, &asize, xflags);
53         if (error)
54                 return error;
55         return asize;
56 }
57
58 static int
59 xfs_xattr_set(struct dentry *dentry, const char *name, const void *value,
60                 size_t size, int flags, int xflags)
61 {
62         struct xfs_inode *ip = XFS_I(dentry->d_inode);
63
64         if (strcmp(name, "") == 0)
65                 return -EINVAL;
66
67         /* Convert Linux syscall to XFS internal ATTR flags */
68         if (flags & XATTR_CREATE)
69                 xflags |= ATTR_CREATE;
70         if (flags & XATTR_REPLACE)
71                 xflags |= ATTR_REPLACE;
72
73         if (!value)
74                 return -xfs_attr_remove(ip, (unsigned char *)name, xflags);
75         return -xfs_attr_set(ip, (unsigned char *)name,
76                                 (void *)value, size, xflags);
77 }
78
79 static const struct xattr_handler xfs_xattr_user_handler = {
80         .prefix = XATTR_USER_PREFIX,
81         .flags  = 0, /* no flags implies user namespace */
82         .get    = xfs_xattr_get,
83         .set    = xfs_xattr_set,
84 };
85
86 static const struct xattr_handler xfs_xattr_trusted_handler = {
87         .prefix = XATTR_TRUSTED_PREFIX,
88         .flags  = ATTR_ROOT,
89         .get    = xfs_xattr_get,
90         .set    = xfs_xattr_set,
91 };
92
93 static const struct xattr_handler xfs_xattr_security_handler = {
94         .prefix = XATTR_SECURITY_PREFIX,
95         .flags  = ATTR_SECURE,
96         .get    = xfs_xattr_get,
97         .set    = xfs_xattr_set,
98 };
99
100 const struct xattr_handler *xfs_xattr_handlers[] = {
101         &xfs_xattr_user_handler,
102         &xfs_xattr_trusted_handler,
103         &xfs_xattr_security_handler,
104 #ifdef CONFIG_XFS_POSIX_ACL
105         &posix_acl_access_xattr_handler,
106         &posix_acl_default_xattr_handler,
107 #endif
108         NULL
109 };
110
111 static unsigned int xfs_xattr_prefix_len(int flags)
112 {
113         if (flags & XFS_ATTR_SECURE)
114                 return sizeof("security");
115         else if (flags & XFS_ATTR_ROOT)
116                 return sizeof("trusted");
117         else
118                 return sizeof("user");
119 }
120
121 static const char *xfs_xattr_prefix(int flags)
122 {
123         if (flags & XFS_ATTR_SECURE)
124                 return xfs_xattr_security_handler.prefix;
125         else if (flags & XFS_ATTR_ROOT)
126                 return xfs_xattr_trusted_handler.prefix;
127         else
128                 return xfs_xattr_user_handler.prefix;
129 }
130
131 static int
132 xfs_xattr_put_listent(
133         struct xfs_attr_list_context *context,
134         int             flags,
135         unsigned char   *name,
136         int             namelen,
137         int             valuelen,
138         unsigned char   *value)
139 {
140         unsigned int prefix_len = xfs_xattr_prefix_len(flags);
141         char *offset;
142         int arraytop;
143
144         ASSERT(context->count >= 0);
145
146         /*
147          * Only show root namespace entries if we are actually allowed to
148          * see them.
149          */
150         if ((flags & XFS_ATTR_ROOT) && !capable(CAP_SYS_ADMIN))
151                 return 0;
152
153         arraytop = context->count + prefix_len + namelen + 1;
154         if (arraytop > context->firstu) {
155                 context->count = -1;    /* insufficient space */
156                 return 1;
157         }
158         offset = (char *)context->alist + context->count;
159         strncpy(offset, xfs_xattr_prefix(flags), prefix_len);
160         offset += prefix_len;
161         strncpy(offset, (char *)name, namelen);                 /* real name */
162         offset += namelen;
163         *offset = '\0';
164         context->count += prefix_len + namelen + 1;
165         return 0;
166 }
167
168 static int
169 xfs_xattr_put_listent_sizes(
170         struct xfs_attr_list_context *context,
171         int             flags,
172         unsigned char   *name,
173         int             namelen,
174         int             valuelen,
175         unsigned char   *value)
176 {
177         context->count += xfs_xattr_prefix_len(flags) + namelen + 1;
178         return 0;
179 }
180
181 static int
182 list_one_attr(const char *name, const size_t len, void *data,
183                 size_t size, ssize_t *result)
184 {
185         char *p = data + *result;
186
187         *result += len;
188         if (!size)
189                 return 0;
190         if (*result > size)
191                 return -ERANGE;
192
193         strcpy(p, name);
194         return 0;
195 }
196
197 ssize_t
198 xfs_vn_listxattr(struct dentry *dentry, char *data, size_t size)
199 {
200         struct xfs_attr_list_context context;
201         struct attrlist_cursor_kern cursor = { 0 };
202         struct inode            *inode = dentry->d_inode;
203         int                     error;
204
205         /*
206          * First read the regular on-disk attributes.
207          */
208         memset(&context, 0, sizeof(context));
209         context.dp = XFS_I(inode);
210         context.cursor = &cursor;
211         context.resynch = 1;
212         context.alist = data;
213         context.bufsize = size;
214         context.firstu = context.bufsize;
215
216         if (size)
217                 context.put_listent = xfs_xattr_put_listent;
218         else
219                 context.put_listent = xfs_xattr_put_listent_sizes;
220
221         xfs_attr_list_int(&context);
222         if (context.count < 0)
223                 return -ERANGE;
224
225         /*
226          * Then add the two synthetic ACL attributes.
227          */
228         if (posix_acl_access_exists(inode)) {
229                 error = list_one_attr(POSIX_ACL_XATTR_ACCESS,
230                                 strlen(POSIX_ACL_XATTR_ACCESS) + 1,
231                                 data, size, &context.count);
232                 if (error)
233                         return error;
234         }
235
236         if (posix_acl_default_exists(inode)) {
237                 error = list_one_attr(POSIX_ACL_XATTR_DEFAULT,
238                                 strlen(POSIX_ACL_XATTR_DEFAULT) + 1,
239                                 data, size, &context.count);
240                 if (error)
241                         return error;
242         }
243
244         return context.count;
245 }