import of upstream 2.4.34.4 from kernel.org
[linux-2.4.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                 down(&d->d_inode->i_sem);
88                 lock_kernel();
89                 error = d->d_inode->i_op->setxattr(d, kname, kvalue, size, flags);
90                 unlock_kernel();
91                 up(&d->d_inode->i_sem);
92         }
93
94         xattr_free(kvalue, size);
95         return error;
96 }
97
98 asmlinkage long
99 sys_setxattr(char *path, char *name, void *value, size_t size, int flags)
100 {
101         struct nameidata nd;
102         int error;
103
104         error = user_path_walk(path, &nd);
105         if (error)
106                 return error;
107         error = setxattr(nd.dentry, name, value, size, flags);
108         path_release(&nd);
109         return error;
110 }
111
112 asmlinkage long
113 sys_lsetxattr(char *path, char *name, void *value, size_t size, int flags)
114 {
115         struct nameidata nd;
116         int error;
117
118         error = user_path_walk_link(path, &nd);
119         if (error)
120                 return error;
121         error = setxattr(nd.dentry, name, value, size, flags);
122         path_release(&nd);
123         return error;
124 }
125
126 asmlinkage long
127 sys_fsetxattr(int fd, char *name, void *value, size_t size, int flags)
128 {
129         struct file *f;
130         int error = -EBADF;
131
132         f = fget(fd);
133         if (!f)
134                 return error;
135         error = setxattr(f->f_dentry, name, value, size, flags);
136         fput(f);
137         return error;
138 }
139
140 /*
141  * Extended attribute GET operations
142  */
143 static ssize_t
144 getxattr(struct dentry *d, char *name, void *value, size_t size)
145 {
146         ssize_t error;
147         void *kvalue;
148         char kname[XATTR_NAME_MAX + 1];
149
150         error = strncpy_from_user(kname, name, sizeof(kname));
151         if (error == 0 || error == sizeof(kname))
152                 error = -ERANGE;
153         if (error < 0)
154                 return error;
155
156         kvalue = xattr_alloc(size, XATTR_SIZE_MAX);
157         if (IS_ERR(kvalue))
158                 return PTR_ERR(kvalue);
159
160         error = -EOPNOTSUPP;
161         if (d->d_inode->i_op && d->d_inode->i_op->getxattr) {
162                 down(&d->d_inode->i_sem);
163                 lock_kernel();
164                 error = d->d_inode->i_op->getxattr(d, kname, kvalue, size);
165                 unlock_kernel();
166                 up(&d->d_inode->i_sem);
167         }
168
169         if (kvalue && error > 0)
170                 if (copy_to_user(value, kvalue, error))
171                         error = -EFAULT;
172         xattr_free(kvalue, size);
173         return error;
174 }
175
176 asmlinkage ssize_t
177 sys_getxattr(char *path, char *name, void *value, size_t size)
178 {
179         struct nameidata nd;
180         ssize_t error;
181
182         error = user_path_walk(path, &nd);
183         if (error)
184                 return error;
185         error = getxattr(nd.dentry, name, value, size);
186         path_release(&nd);
187         return error;
188 }
189
190 asmlinkage ssize_t
191 sys_lgetxattr(char *path, char *name, void *value, size_t size)
192 {
193         struct nameidata nd;
194         ssize_t error;
195
196         error = user_path_walk_link(path, &nd);
197         if (error)
198                 return error;
199         error = getxattr(nd.dentry, name, value, size);
200         path_release(&nd);
201         return error;
202 }
203
204 asmlinkage ssize_t
205 sys_fgetxattr(int fd, char *name, void *value, size_t size)
206 {
207         struct file *f;
208         ssize_t error = -EBADF;
209
210         f = fget(fd);
211         if (!f)
212                 return error;
213         error = getxattr(f->f_dentry, name, value, size);
214         fput(f);
215         return error;
216 }
217
218 /*
219  * Extended attribute LIST operations
220  */
221 static ssize_t
222 listxattr(struct dentry *d, char *list, size_t size)
223 {
224         ssize_t error;
225         char *klist;
226
227         klist = (char *)xattr_alloc(size, XATTR_LIST_MAX);
228         if (IS_ERR(klist))
229                 return PTR_ERR(klist);
230
231         error = -EOPNOTSUPP;
232         if (d->d_inode->i_op && d->d_inode->i_op->listxattr) {
233                 down(&d->d_inode->i_sem);
234                 lock_kernel();
235                 error = d->d_inode->i_op->listxattr(d, klist, size);
236                 unlock_kernel();
237                 up(&d->d_inode->i_sem);
238         }
239
240         if (klist && error > 0)
241                 if (copy_to_user(list, klist, error))
242                         error = -EFAULT;
243         xattr_free(klist, size);
244         return error;
245 }
246
247 asmlinkage ssize_t
248 sys_listxattr(char *path, char *list, size_t size)
249 {
250         struct nameidata nd;
251         ssize_t error;
252
253         error = user_path_walk(path, &nd);
254         if (error)
255                 return error;
256         error = listxattr(nd.dentry, list, size);
257         path_release(&nd);
258         return error;
259 }
260
261 asmlinkage ssize_t
262 sys_llistxattr(char *path, char *list, size_t size)
263 {
264         struct nameidata nd;
265         ssize_t error;
266
267         error = user_path_walk_link(path, &nd);
268         if (error)
269                 return error;
270         error = listxattr(nd.dentry, list, size);
271         path_release(&nd);
272         return error;
273 }
274
275 asmlinkage ssize_t
276 sys_flistxattr(int fd, char *list, size_t size)
277 {
278         struct file *f;
279         ssize_t error = -EBADF;
280
281         f = fget(fd);
282         if (!f)
283                 return error;
284         error = listxattr(f->f_dentry, list, size);
285         fput(f);
286         return error;
287 }
288
289 /*
290  * Extended attribute REMOVE operations
291  */
292 static long
293 removexattr(struct dentry *d, char *name)
294 {
295         int error;
296         char kname[XATTR_NAME_MAX + 1];
297
298         error = strncpy_from_user(kname, name, sizeof(kname));
299         if (error == 0 || error == sizeof(kname))
300                 error = -ERANGE;
301         if (error < 0)
302                 return error;
303
304         error = -EOPNOTSUPP;
305         if (d->d_inode->i_op && d->d_inode->i_op->removexattr) {
306                 down(&d->d_inode->i_sem);
307                 lock_kernel();
308                 error = d->d_inode->i_op->removexattr(d, kname);
309                 unlock_kernel();
310                 up(&d->d_inode->i_sem);
311         }
312         return error;
313 }
314
315 asmlinkage long
316 sys_removexattr(char *path, char *name)
317 {
318         struct nameidata nd;
319         int error;
320
321         error = user_path_walk(path, &nd);
322         if (error)
323                 return error;
324         error = removexattr(nd.dentry, name);
325         path_release(&nd);
326         return error;
327 }
328
329 asmlinkage long
330 sys_lremovexattr(char *path, char *name)
331 {
332         struct nameidata nd;
333         int error;
334
335         error = user_path_walk_link(path, &nd);
336         if (error)
337                 return error;
338         error = removexattr(nd.dentry, name);
339         path_release(&nd);
340         return error;
341 }
342
343 asmlinkage long
344 sys_fremovexattr(int fd, char *name)
345 {
346         struct file *f;
347         int error = -EBADF;
348
349         f = fget(fd);
350         if (!f)
351                 return error;
352         error = removexattr(f->f_dentry, name);
353         fput(f);
354         return error;
355 }