[PATCH] xattr updates (minor, 2/4)
[opensuse:kernel.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  */
9 #include <linux/fs.h>
10 #include <linux/slab.h>
11 #include <linux/vmalloc.h>
12 #include <linux/smp_lock.h>
13 #include <linux/file.h>
14 #include <linux/xattr.h>
15 #include <asm/uaccess.h>
16
17 /*
18  * Extended attribute memory allocation wrappers, originally
19  * based on the Intermezzo PRESTO_ALLOC/PRESTO_FREE macros.
20  * The vmalloc use here is very uncommon - extended attributes
21  * are supposed to be small chunks of metadata, and it is quite
22  * unusual to have very many extended attributes, so lists tend
23  * to be quite short as well.  The 64K upper limit is derived
24  * from the extended attribute size limit used by XFS.
25  * Intentionally allow zero @size for value/list size requests.
26  */
27 static void *
28 xattr_alloc(size_t size, size_t limit)
29 {
30         void *ptr;
31
32         if (size > limit)
33                 return ERR_PTR(-E2BIG);
34
35         if (!size)      /* size request, no buffer is needed */
36                 return NULL;
37         else if (size <= PAGE_SIZE)
38                 ptr = kmalloc((unsigned long) size, GFP_KERNEL);
39         else
40                 ptr = vmalloc((unsigned long) size);
41         if (!ptr)
42                 return ERR_PTR(-ENOMEM);
43         return ptr;
44 }
45
46 static void
47 xattr_free(void *ptr, size_t size)
48 {
49         if (!size)      /* size request, no buffer was needed */
50                 return;
51         else if (size <= PAGE_SIZE)
52                 kfree(ptr);
53         else
54                 vfree(ptr);
55 }
56
57 /*
58  * Extended attribute SET operations
59  */
60 static long
61 setxattr(struct dentry *d, char *name, void *value, size_t size, int flags)
62 {
63         int error;
64         void *kvalue;
65         char kname[XATTR_NAME_MAX + 1];
66
67         if (flags & ~(XATTR_CREATE|XATTR_REPLACE))
68                 return -EINVAL;
69
70         error = strncpy_from_user(kname, name, sizeof(kname));
71         if (error == 0 || error == sizeof(kname))
72                 error = -ERANGE;
73         if (error < 0)
74                 return error;
75
76         kvalue = xattr_alloc(size, XATTR_SIZE_MAX);
77         if (IS_ERR(kvalue))
78                 return PTR_ERR(kvalue);
79
80         if (size > 0 && copy_from_user(kvalue, value, size)) {
81                 xattr_free(kvalue, size);
82                 return -EFAULT;
83         }
84
85         error = -EOPNOTSUPP;
86         if (d->d_inode->i_op && d->d_inode->i_op->setxattr) {
87                 lock_kernel();
88                 error = d->d_inode->i_op->setxattr(d, kname, kvalue, size, flags);
89                 unlock_kernel();
90         }
91
92         xattr_free(kvalue, size);
93         return error;
94 }
95
96 asmlinkage long
97 sys_setxattr(char *path, char *name, void *value, size_t size, int flags)
98 {
99         struct nameidata nd;
100         int error;
101
102         error = user_path_walk(path, &nd);
103         if (error)
104                 return error;
105         error = setxattr(nd.dentry, name, value, size, flags);
106         path_release(&nd);
107         return error;
108 }
109
110 asmlinkage long
111 sys_lsetxattr(char *path, char *name, void *value, size_t size, int flags)
112 {
113         struct nameidata nd;
114         int error;
115
116         error = user_path_walk_link(path, &nd);
117         if (error)
118                 return error;
119         error = setxattr(nd.dentry, name, value, size, flags);
120         path_release(&nd);
121         return error;
122 }
123
124 asmlinkage long
125 sys_fsetxattr(int fd, char *name, void *value, size_t size, int flags)
126 {
127         struct file *f;
128         int error = -EBADF;
129
130         f = fget(fd);
131         if (!f)
132                 return error;
133         error = setxattr(f->f_dentry, name, value, size, flags);
134         fput(f);
135         return error;
136 }
137
138 /*
139  * Extended attribute GET operations
140  */
141 static long
142 getxattr(struct dentry *d, char *name, void *value, size_t size)
143 {
144         int error;
145         void *kvalue;
146         char kname[XATTR_NAME_MAX + 1];
147
148         error = strncpy_from_user(kname, name, sizeof(kname));
149         if (error == 0 || error == sizeof(kname))
150                 error = -ERANGE;
151         if (error < 0)
152                 return error;
153
154         kvalue = xattr_alloc(size, XATTR_SIZE_MAX);
155         if (IS_ERR(kvalue))
156                 return PTR_ERR(kvalue);
157
158         error = -EOPNOTSUPP;
159         if (d->d_inode->i_op && d->d_inode->i_op->getxattr) {
160                 lock_kernel();
161                 error = d->d_inode->i_op->getxattr(d, kname, kvalue, size);
162                 unlock_kernel();
163         }
164
165         if (kvalue && error > 0)
166                 if (copy_to_user(value, kvalue, error))
167                         error = -EFAULT;
168         xattr_free(kvalue, size);
169         return error;
170 }
171
172 asmlinkage long
173 sys_getxattr(char *path, char *name, void *value, size_t size)
174 {
175         struct nameidata nd;
176         int error;
177
178         error = user_path_walk(path, &nd);
179         if (error)
180                 return error;
181         error = getxattr(nd.dentry, name, value, size);
182         path_release(&nd);
183         return error;
184 }
185
186 asmlinkage long
187 sys_lgetxattr(char *path, char *name, void *value, size_t size)
188 {
189         struct nameidata nd;
190         int error;
191
192         error = user_path_walk_link(path, &nd);
193         if (error)
194                 return error;
195         error = getxattr(nd.dentry, name, value, size);
196         path_release(&nd);
197         return error;
198 }
199
200 asmlinkage long
201 sys_fgetxattr(int fd, char *name, void *value, size_t size)
202 {
203         struct file *f;
204         int error = -EBADF;
205
206         f = fget(fd);
207         if (!f)
208                 return error;
209         error = getxattr(f->f_dentry, name, value, size);
210         fput(f);
211         return error;
212 }
213
214 /*
215  * Extended attribute LIST operations
216  */
217 static long
218 listxattr(struct dentry *d, char *list, size_t size)
219 {
220         int error;
221         char *klist;
222
223         klist = (char *)xattr_alloc(size, XATTR_LIST_MAX);
224         if (IS_ERR(klist))
225                 return PTR_ERR(klist);
226
227         error = -EOPNOTSUPP;
228         if (d->d_inode->i_op && d->d_inode->i_op->listxattr) {
229                 lock_kernel();
230                 error = d->d_inode->i_op->listxattr(d, klist, size);
231                 unlock_kernel();
232         }
233
234         if (klist && error > 0)
235                 if (copy_to_user(list, klist, error))
236                         error = -EFAULT;
237         xattr_free(klist, size);
238         return error;
239 }
240
241 asmlinkage long
242 sys_listxattr(char *path, char *list, size_t size)
243 {
244         struct nameidata nd;
245         int error;
246
247         error = user_path_walk(path, &nd);
248         if (error)
249                 return error;
250         error = listxattr(nd.dentry, list, size);
251         path_release(&nd);
252         return error;
253 }
254
255 asmlinkage long
256 sys_llistxattr(char *path, char *list, size_t size)
257 {
258         struct nameidata nd;
259         int error;
260
261         error = user_path_walk_link(path, &nd);
262         if (error)
263                 return error;
264         error = listxattr(nd.dentry, list, size);
265         path_release(&nd);
266         return error;
267 }
268
269 asmlinkage long
270 sys_flistxattr(int fd, char *list, size_t size)
271 {
272         struct file *f;
273         int error = -EBADF;
274
275         f = fget(fd);
276         if (!f)
277                 return error;
278         error = listxattr(f->f_dentry, list, size);
279         fput(f);
280         return error;
281 }
282
283 /*
284  * Extended attribute REMOVE operations
285  */
286 static long
287 removexattr(struct dentry *d, char *name)
288 {
289         int error;
290         char kname[XATTR_NAME_MAX + 1];
291
292         error = strncpy_from_user(kname, name, sizeof(kname));
293         if (error == 0 || error == sizeof(kname))
294                 error = -ERANGE;
295         if (error < 0)
296                 return error;
297
298         error = -EOPNOTSUPP;
299         if (d->d_inode->i_op && d->d_inode->i_op->removexattr) {
300                 lock_kernel();
301                 error = d->d_inode->i_op->removexattr(d, kname);
302                 unlock_kernel();
303         }
304         return error;
305 }
306
307 asmlinkage long
308 sys_removexattr(char *path, char *name)
309 {
310         struct nameidata nd;
311         int error;
312
313         error = user_path_walk(path, &nd);
314         if (error)
315                 return error;
316         error = removexattr(nd.dentry, name);
317         path_release(&nd);
318         return error;
319 }
320
321 asmlinkage long
322 sys_lremovexattr(char *path, char *name)
323 {
324         struct nameidata nd;
325         int error;
326
327         error = user_path_walk_link(path, &nd);
328         if (error)
329                 return error;
330         error = removexattr(nd.dentry, name);
331         path_release(&nd);
332         return error;
333 }
334
335 asmlinkage long
336 sys_fremovexattr(int fd, char *name)
337 {
338         struct file *f;
339         int error = -EBADF;
340
341         f = fget(fd);
342         if (!f)
343                 return error;
344         error = removexattr(f->f_dentry, name);
345         fput(f);
346         return error;
347 }