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