ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[linux-2.6.git] / fs / devpts / xattr.c
1 /*
2   File: fs/devpts/xattr.c
3  
4   Derived from fs/ext3/xattr.c, changed in the following ways:
5       drop everything related to persistent storage of EAs
6       pass dentry rather than inode to internal methods
7       only presently define a handler for security modules
8 */
9
10 #include <linux/init.h>
11 #include <linux/fs.h>
12 #include <linux/slab.h>
13 #include <linux/string.h>
14 #include <asm/semaphore.h>
15 #include "xattr.h"
16
17 static struct devpts_xattr_handler *devpts_xattr_handlers[DEVPTS_XATTR_INDEX_MAX];
18 static rwlock_t devpts_handler_lock = RW_LOCK_UNLOCKED;
19
20 int
21 devpts_xattr_register(int name_index, struct devpts_xattr_handler *handler)
22 {
23         int error = -EINVAL;
24
25         if (name_index > 0 && name_index <= DEVPTS_XATTR_INDEX_MAX) {
26                 write_lock(&devpts_handler_lock);
27                 if (!devpts_xattr_handlers[name_index-1]) {
28                         devpts_xattr_handlers[name_index-1] = handler;
29                         error = 0;
30                 }
31                 write_unlock(&devpts_handler_lock);
32         }
33         return error;
34 }
35
36 void
37 devpts_xattr_unregister(int name_index, struct devpts_xattr_handler *handler)
38 {
39         if (name_index > 0 || name_index <= DEVPTS_XATTR_INDEX_MAX) {
40                 write_lock(&devpts_handler_lock);
41                 devpts_xattr_handlers[name_index-1] = NULL;
42                 write_unlock(&devpts_handler_lock);
43         }
44 }
45
46 static inline const char *
47 strcmp_prefix(const char *a, const char *a_prefix)
48 {
49         while (*a_prefix && *a == *a_prefix) {
50                 a++;
51                 a_prefix++;
52         }
53         return *a_prefix ? NULL : a;
54 }
55
56 /*
57  * Decode the extended attribute name, and translate it into
58  * the name_index and name suffix.
59  */
60 static inline struct devpts_xattr_handler *
61 devpts_xattr_resolve_name(const char **name)
62 {
63         struct devpts_xattr_handler *handler = NULL;
64         int i;
65
66         if (!*name)
67                 return NULL;
68         read_lock(&devpts_handler_lock);
69         for (i=0; i<DEVPTS_XATTR_INDEX_MAX; i++) {
70                 if (devpts_xattr_handlers[i]) {
71                         const char *n = strcmp_prefix(*name,
72                                 devpts_xattr_handlers[i]->prefix);
73                         if (n) {
74                                 handler = devpts_xattr_handlers[i];
75                                 *name = n;
76                                 break;
77                         }
78                 }
79         }
80         read_unlock(&devpts_handler_lock);
81         return handler;
82 }
83
84 static inline struct devpts_xattr_handler *
85 devpts_xattr_handler(int name_index)
86 {
87         struct devpts_xattr_handler *handler = NULL;
88         if (name_index > 0 && name_index <= DEVPTS_XATTR_INDEX_MAX) {
89                 read_lock(&devpts_handler_lock);
90                 handler = devpts_xattr_handlers[name_index-1];
91                 read_unlock(&devpts_handler_lock);
92         }
93         return handler;
94 }
95
96 /*
97  * Inode operation getxattr()
98  *
99  * dentry->d_inode->i_sem down
100  */
101 ssize_t
102 devpts_getxattr(struct dentry *dentry, const char *name,
103               void *buffer, size_t size)
104 {
105         struct devpts_xattr_handler *handler;
106
107         handler = devpts_xattr_resolve_name(&name);
108         if (!handler)
109                 return -EOPNOTSUPP;
110         return handler->get(dentry, name, buffer, size);
111 }
112
113 /*
114  * Inode operation listxattr()
115  *
116  * dentry->d_inode->i_sem down
117  */
118 ssize_t
119 devpts_listxattr(struct dentry *dentry, char *buffer, size_t buffer_size)
120 {
121         struct devpts_xattr_handler *handler = NULL;
122         int i, error = 0;
123         unsigned int size = 0;
124         char *buf;
125
126         read_lock(&devpts_handler_lock);
127
128         for (i=0; i<DEVPTS_XATTR_INDEX_MAX; i++) {
129                 handler = devpts_xattr_handlers[i];
130                 if (handler)
131                         size += handler->list(dentry, NULL);
132         }
133
134         if (!buffer) {
135                 error = size;
136                 goto out;
137         } else {
138                 error = -ERANGE;
139                 if (size > buffer_size)
140                         goto out;
141         }
142
143         buf = buffer;
144         for (i=0; i<DEVPTS_XATTR_INDEX_MAX; i++) {
145                 handler = devpts_xattr_handlers[i];
146                 if (handler)
147                         buf += handler->list(dentry, buf);
148         }
149         error = size;
150
151 out:
152         read_unlock(&devpts_handler_lock);
153         return size;
154 }
155
156 /*
157  * Inode operation setxattr()
158  *
159  * dentry->d_inode->i_sem down
160  */
161 int
162 devpts_setxattr(struct dentry *dentry, const char *name,
163               const void *value, size_t size, int flags)
164 {
165         struct devpts_xattr_handler *handler;
166
167         if (size == 0)
168                 value = "";  /* empty EA, do not remove */
169         handler = devpts_xattr_resolve_name(&name);
170         if (!handler)
171                 return -EOPNOTSUPP;
172         return handler->set(dentry, name, value, size, flags);
173 }
174
175 /*
176  * Inode operation removexattr()
177  *
178  * dentry->d_inode->i_sem down
179  */
180 int
181 devpts_removexattr(struct dentry *dentry, const char *name)
182 {
183         struct devpts_xattr_handler *handler;
184
185         handler = devpts_xattr_resolve_name(&name);
186         if (!handler)
187                 return -EOPNOTSUPP;
188         return handler->set(dentry, name, NULL, 0, XATTR_REPLACE);
189 }
190
191 int __init
192 init_devpts_xattr(void)
193 {
194 #ifdef CONFIG_DEVPTS_FS_SECURITY        
195         int     err;
196
197         err = devpts_xattr_register(DEVPTS_XATTR_INDEX_SECURITY,
198                                     &devpts_xattr_security_handler);
199         if (err)
200                 return err;
201 #endif
202
203         return 0;
204 }
205
206 void
207 exit_devpts_xattr(void)
208 {
209 #ifdef CONFIG_DEVPTS_FS_SECURITY        
210         devpts_xattr_unregister(DEVPTS_XATTR_INDEX_SECURITY,
211                                 &devpts_xattr_security_handler);
212 #endif
213
214 }