This commit was manufactured by cvs2svn to create branch
[linux-2.6.git] / fs / xattr.c
1 /*
2   File: fs/xattr.c
3
4   Extended attribute handling.
5
6   Copyright (C) 2001 by Andreas Gruenbacher <a.gruenbacher@computer.org>
7   Copyright (C) 2001 SGI - Silicon Graphics, Inc <linux-xfs@oss.sgi.com>
8   Copyright (c) 2004 Red Hat, Inc., James Morris <jmorris@redhat.com>
9  */
10 #include <linux/fs.h>
11 #include <linux/slab.h>
12 #include <linux/smp_lock.h>
13 #include <linux/file.h>
14 #include <linux/xattr.h>
15 #include <linux/namei.h>
16 #include <linux/security.h>
17 #include <linux/syscalls.h>
18 #include <linux/module.h>
19 #include <asm/uaccess.h>
20
21 /*
22  * Extended attribute SET operations
23  */
24 static long
25 setxattr(struct dentry *d, char __user *name, void __user *value,
26          size_t size, int flags, struct vfsmount *mnt)
27 {
28         int error;
29         void *kvalue = NULL;
30         char kname[XATTR_NAME_MAX + 1];
31
32         if (flags & ~(XATTR_CREATE|XATTR_REPLACE))
33                 return -EINVAL;
34
35         error = strncpy_from_user(kname, name, sizeof(kname));
36         if (error == 0 || error == sizeof(kname))
37                 error = -ERANGE;
38         if (error < 0)
39                 return error;
40
41         if (size) {
42                 if (size > XATTR_SIZE_MAX)
43                         return -E2BIG;
44                 kvalue = kmalloc(size, GFP_KERNEL);
45                 if (!kvalue)
46                         return -ENOMEM;
47                 if (copy_from_user(kvalue, value, size)) {
48                         kfree(kvalue);
49                         return -EFAULT;
50                 }
51         }
52
53         error = -EOPNOTSUPP;
54         if (d->d_inode->i_op && d->d_inode->i_op->setxattr) {
55                 down(&d->d_inode->i_sem);
56                 error = security_inode_setxattr(d, kname, kvalue, size, flags);
57                 if (error)
58                         goto out;
59                 error = -EROFS;
60                 if (MNT_IS_RDONLY(mnt))
61                         goto out;
62                 error = d->d_inode->i_op->setxattr(d, kname, kvalue, size, flags);
63                 if (!error)
64                         security_inode_post_setxattr(d, kname, kvalue, size, flags);
65 out:
66                 up(&d->d_inode->i_sem);
67         }
68         if (kvalue)
69                 kfree(kvalue);
70         return error;
71 }
72
73 asmlinkage long
74 sys_setxattr(char __user *path, char __user *name, void __user *value,
75              size_t size, int flags)
76 {
77         struct nameidata nd;
78         int error;
79
80         error = user_path_walk(path, &nd);
81         if (error)
82                 return error;
83         error = setxattr(nd.dentry, name, value, size, flags, nd.mnt);
84         path_release(&nd);
85         return error;
86 }
87
88 asmlinkage long
89 sys_lsetxattr(char __user *path, char __user *name, void __user *value,
90               size_t size, int flags)
91 {
92         struct nameidata nd;
93         int error;
94
95         error = user_path_walk_link(path, &nd);
96         if (error)
97                 return error;
98         error = setxattr(nd.dentry, name, value, size, flags, nd.mnt);
99         path_release(&nd);
100         return error;
101 }
102
103 asmlinkage long
104 sys_fsetxattr(int fd, char __user *name, void __user *value,
105               size_t size, int flags)
106 {
107         struct file *f;
108         int error = -EBADF;
109
110         f = fget(fd);
111         if (!f)
112                 return error;
113         error = setxattr(f->f_dentry, name, value, size, flags, f->f_vfsmnt);
114         fput(f);
115         return error;
116 }
117
118 /*
119  * Extended attribute GET operations
120  */
121 static ssize_t
122 getxattr(struct dentry *d, char __user *name, void __user *value, size_t size)
123 {
124         ssize_t error;
125         void *kvalue = NULL;
126         char kname[XATTR_NAME_MAX + 1];
127
128         error = strncpy_from_user(kname, name, sizeof(kname));
129         if (error == 0 || error == sizeof(kname))
130                 error = -ERANGE;
131         if (error < 0)
132                 return error;
133
134         if (size) {
135                 if (size > XATTR_SIZE_MAX)
136                         size = XATTR_SIZE_MAX;
137                 kvalue = kmalloc(size, GFP_KERNEL);
138                 if (!kvalue)
139                         return -ENOMEM;
140         }
141
142         error = -EOPNOTSUPP;
143         if (d->d_inode->i_op && d->d_inode->i_op->getxattr) {
144                 error = security_inode_getxattr(d, kname);
145                 if (error)
146                         goto out;
147                 error = d->d_inode->i_op->getxattr(d, kname, kvalue, size);
148                 if (error > 0) {
149                         if (size && copy_to_user(value, kvalue, error))
150                                 error = -EFAULT;
151                 } else if (error == -ERANGE && size >= XATTR_SIZE_MAX) {
152                         /* The file system tried to returned a value bigger
153                            than XATTR_SIZE_MAX bytes. Not possible. */
154                         error = -E2BIG;
155                 }
156         }
157 out:
158         if (kvalue)
159                 kfree(kvalue);
160         return error;
161 }
162
163 asmlinkage ssize_t
164 sys_getxattr(char __user *path, char __user *name, void __user *value,
165              size_t size)
166 {
167         struct nameidata nd;
168         ssize_t error;
169
170         error = user_path_walk(path, &nd);
171         if (error)
172                 return error;
173         error = getxattr(nd.dentry, name, value, size);
174         path_release(&nd);
175         return error;
176 }
177
178 asmlinkage ssize_t
179 sys_lgetxattr(char __user *path, char __user *name, void __user *value,
180               size_t size)
181 {
182         struct nameidata nd;
183         ssize_t error;
184
185         error = user_path_walk_link(path, &nd);
186         if (error)
187                 return error;
188         error = getxattr(nd.dentry, name, value, size);
189         path_release(&nd);
190         return error;
191 }
192
193 asmlinkage ssize_t
194 sys_fgetxattr(int fd, char __user *name, void __user *value, size_t size)
195 {
196         struct file *f;
197         ssize_t error = -EBADF;
198
199         f = fget(fd);
200         if (!f)
201                 return error;
202         error = getxattr(f->f_dentry, name, value, size);
203         fput(f);
204         return error;
205 }
206
207 /*
208  * Extended attribute LIST operations
209  */
210 static ssize_t
211 listxattr(struct dentry *d, char __user *list, size_t size)
212 {
213         ssize_t error;
214         char *klist = NULL;
215
216         if (size) {
217                 if (size > XATTR_LIST_MAX)
218                         size = XATTR_LIST_MAX;
219                 klist = kmalloc(size, GFP_KERNEL);
220                 if (!klist)
221                         return -ENOMEM;
222         }
223
224         error = -EOPNOTSUPP;
225         if (d->d_inode->i_op && d->d_inode->i_op->listxattr) {
226                 error = security_inode_listxattr(d);
227                 if (error)
228                         goto out;
229                 error = d->d_inode->i_op->listxattr(d, klist, size);
230                 if (error > 0) {
231                         if (size && copy_to_user(list, klist, error))
232                                 error = -EFAULT;
233                 } else if (error == -ERANGE && size >= XATTR_LIST_MAX) {
234                         /* The file system tried to returned a list bigger
235                            than XATTR_LIST_MAX bytes. Not possible. */
236                         error = -E2BIG;
237                 }
238         }
239 out:
240         if (klist)
241                 kfree(klist);
242         return error;
243 }
244
245 asmlinkage ssize_t
246 sys_listxattr(char __user *path, char __user *list, size_t size)
247 {
248         struct nameidata nd;
249         ssize_t error;
250
251         error = user_path_walk(path, &nd);
252         if (error)
253                 return error;
254         error = listxattr(nd.dentry, list, size);
255         path_release(&nd);
256         return error;
257 }
258
259 asmlinkage ssize_t
260 sys_llistxattr(char __user *path, char __user *list, size_t size)
261 {
262         struct nameidata nd;
263         ssize_t error;
264
265         error = user_path_walk_link(path, &nd);
266         if (error)
267                 return error;
268         error = listxattr(nd.dentry, list, size);
269         path_release(&nd);
270         return error;
271 }
272
273 asmlinkage ssize_t
274 sys_flistxattr(int fd, char __user *list, size_t size)
275 {
276         struct file *f;
277         ssize_t error = -EBADF;
278
279         f = fget(fd);
280         if (!f)
281                 return error;
282         error = listxattr(f->f_dentry, list, size);
283         fput(f);
284         return error;
285 }
286
287 /*
288  * Extended attribute REMOVE operations
289  */
290 static long
291 removexattr(struct dentry *d, char __user *name, struct vfsmount *mnt)
292 {
293         int error;
294         char kname[XATTR_NAME_MAX + 1];
295
296         error = strncpy_from_user(kname, name, sizeof(kname));
297         if (error == 0 || error == sizeof(kname))
298                 error = -ERANGE;
299         if (error < 0)
300                 return error;
301
302         error = -EOPNOTSUPP;
303         if (d->d_inode->i_op && d->d_inode->i_op->removexattr) {
304                 error = security_inode_removexattr(d, kname);
305                 if (error)
306                         goto out;
307                 error = -EROFS;
308                 if (MNT_IS_RDONLY(mnt))
309                         goto out;
310                 down(&d->d_inode->i_sem);
311                 error = d->d_inode->i_op->removexattr(d, kname);
312                 up(&d->d_inode->i_sem);
313         }
314 out:
315         return error;
316 }
317
318 asmlinkage long
319 sys_removexattr(char __user *path, char __user *name)
320 {
321         struct nameidata nd;
322         int error;
323
324         error = user_path_walk(path, &nd);
325         if (error)
326                 return error;
327         error = removexattr(nd.dentry, name, nd.mnt);
328         path_release(&nd);
329         return error;
330 }
331
332 asmlinkage long
333 sys_lremovexattr(char __user *path, char __user *name)
334 {
335         struct nameidata nd;
336         int error;
337
338         error = user_path_walk_link(path, &nd);
339         if (error)
340                 return error;
341         error = removexattr(nd.dentry, name, nd.mnt);
342         path_release(&nd);
343         return error;
344 }
345
346 asmlinkage long
347 sys_fremovexattr(int fd, char __user *name)
348 {
349         struct file *f;
350         int error = -EBADF;
351
352         f = fget(fd);
353         if (!f)
354                 return error;
355         error = removexattr(f->f_dentry, name, f->f_vfsmnt);
356         fput(f);
357         return error;
358 }
359
360
361 static const char *
362 strcmp_prefix(const char *a, const char *a_prefix)
363 {
364         while (*a_prefix && *a == *a_prefix) {
365                 a++;
366                 a_prefix++;
367         }
368         return *a_prefix ? NULL : a;
369 }
370
371 /*
372  * In order to implement different sets of xattr operations for each xattr
373  * prefix with the generic xattr API, a filesystem should create a
374  * null-terminated array of struct xattr_handler (one for each prefix) and
375  * hang a pointer to it off of the s_xattr field of the superblock.
376  *
377  * The generic_fooxattr() functions will use this list to dispatch xattr
378  * operations to the correct xattr_handler.
379  */
380 #define for_each_xattr_handler(handlers, handler)               \
381                 for ((handler) = *(handlers)++;                 \
382                         (handler) != NULL;                      \
383                         (handler) = *(handlers)++)
384
385 /*
386  * Find the xattr_handler with the matching prefix.
387  */
388 static struct xattr_handler *
389 xattr_resolve_name(struct xattr_handler **handlers, const char **name)
390 {
391         struct xattr_handler *handler;
392
393         if (!*name)
394                 return NULL;
395
396         for_each_xattr_handler(handlers, handler) {
397                 const char *n = strcmp_prefix(*name, handler->prefix);
398                 if (n) {
399                         *name = n;
400                         break;
401                 }
402         }
403         return handler;
404 }
405
406 /*
407  * Find the handler for the prefix and dispatch its get() operation.
408  */
409 ssize_t
410 generic_getxattr(struct dentry *dentry, const char *name, void *buffer, size_t size)
411 {
412         struct xattr_handler *handler;
413         struct inode *inode = dentry->d_inode;
414
415         handler = xattr_resolve_name(inode->i_sb->s_xattr, &name);
416         if (!handler)
417                 return -EOPNOTSUPP;
418         return handler->get(inode, name, buffer, size);
419 }
420
421 /*
422  * Combine the results of the list() operation from every xattr_handler in the
423  * list.
424  */
425 ssize_t
426 generic_listxattr(struct dentry *dentry, char *buffer, size_t buffer_size)
427 {
428         struct inode *inode = dentry->d_inode;
429         struct xattr_handler *handler, **handlers = inode->i_sb->s_xattr;
430         unsigned int size = 0;
431
432         if (!buffer) {
433                 for_each_xattr_handler(handlers, handler)
434                         size += handler->list(inode, NULL, 0, NULL, 0);
435         } else {
436                 char *buf = buffer;
437
438                 for_each_xattr_handler(handlers, handler) {
439                         size = handler->list(inode, buf, buffer_size, NULL, 0);
440                         if (size > buffer_size)
441                                 return -ERANGE;
442                         buf += size;
443                         buffer_size -= size;
444                 }
445                 size = buf - buffer;
446         }
447         return size;
448 }
449
450 /*
451  * Find the handler for the prefix and dispatch its set() operation.
452  */
453 int
454 generic_setxattr(struct dentry *dentry, const char *name, const void *value, size_t size, int flags)
455 {
456         struct xattr_handler *handler;
457         struct inode *inode = dentry->d_inode;
458
459         if (size == 0)
460                 value = "";  /* empty EA, do not remove */
461         handler = xattr_resolve_name(inode->i_sb->s_xattr, &name);
462         if (!handler)
463                 return -EOPNOTSUPP;
464         return handler->set(inode, name, value, size, flags);
465 }
466
467 /*
468  * Find the handler for the prefix and dispatch its set() operation to remove
469  * any associated extended attribute.
470  */
471 int
472 generic_removexattr(struct dentry *dentry, const char *name)
473 {
474         struct xattr_handler *handler;
475         struct inode *inode = dentry->d_inode;
476
477         handler = xattr_resolve_name(inode->i_sb->s_xattr, &name);
478         if (!handler)
479                 return -EOPNOTSUPP;
480         return handler->set(inode, name, NULL, 0, XATTR_REPLACE);
481 }
482
483 EXPORT_SYMBOL(generic_getxattr);
484 EXPORT_SYMBOL(generic_listxattr);
485 EXPORT_SYMBOL(generic_setxattr);
486 EXPORT_SYMBOL(generic_removexattr);