diff options
-rw-r--r-- | fs/xattr.c | 58 | ||||
-rw-r--r-- | include/linux/xattr.h | 5 |
2 files changed, 62 insertions, 1 deletions
diff --git a/fs/xattr.c b/fs/xattr.c index f060663ab70c..851808c92b30 100644 --- a/fs/xattr.c +++ b/fs/xattr.c | |||
@@ -166,6 +166,64 @@ out_noalloc: | |||
166 | } | 166 | } |
167 | EXPORT_SYMBOL_GPL(xattr_getsecurity); | 167 | EXPORT_SYMBOL_GPL(xattr_getsecurity); |
168 | 168 | ||
169 | /* | ||
170 | * vfs_getxattr_alloc - allocate memory, if necessary, before calling getxattr | ||
171 | * | ||
172 | * Allocate memory, if not already allocated, or re-allocate correct size, | ||
173 | * before retrieving the extended attribute. | ||
174 | * | ||
175 | * Returns the result of alloc, if failed, or the getxattr operation. | ||
176 | */ | ||
177 | ssize_t | ||
178 | vfs_getxattr_alloc(struct dentry *dentry, const char *name, char **xattr_value, | ||
179 | size_t xattr_size, gfp_t flags) | ||
180 | { | ||
181 | struct inode *inode = dentry->d_inode; | ||
182 | char *value = *xattr_value; | ||
183 | int error; | ||
184 | |||
185 | error = xattr_permission(inode, name, MAY_READ); | ||
186 | if (error) | ||
187 | return error; | ||
188 | |||
189 | if (!inode->i_op->getxattr) | ||
190 | return -EOPNOTSUPP; | ||
191 | |||
192 | error = inode->i_op->getxattr(dentry, name, NULL, 0); | ||
193 | if (error < 0) | ||
194 | return error; | ||
195 | |||
196 | if (!value || (error > xattr_size)) { | ||
197 | value = krealloc(*xattr_value, error + 1, flags); | ||
198 | if (!value) | ||
199 | return -ENOMEM; | ||
200 | memset(value, 0, error + 1); | ||
201 | } | ||
202 | |||
203 | error = inode->i_op->getxattr(dentry, name, value, error); | ||
204 | *xattr_value = value; | ||
205 | return error; | ||
206 | } | ||
207 | |||
208 | /* Compare an extended attribute value with the given value */ | ||
209 | int vfs_xattr_cmp(struct dentry *dentry, const char *xattr_name, | ||
210 | const char *value, size_t size, gfp_t flags) | ||
211 | { | ||
212 | char *xattr_value = NULL; | ||
213 | int rc; | ||
214 | |||
215 | rc = vfs_getxattr_alloc(dentry, xattr_name, &xattr_value, 0, flags); | ||
216 | if (rc < 0) | ||
217 | return rc; | ||
218 | |||
219 | if ((rc != size) || (memcmp(xattr_value, value, rc) != 0)) | ||
220 | rc = -EINVAL; | ||
221 | else | ||
222 | rc = 0; | ||
223 | kfree(xattr_value); | ||
224 | return rc; | ||
225 | } | ||
226 | |||
169 | ssize_t | 227 | ssize_t |
170 | vfs_getxattr(struct dentry *dentry, const char *name, void *value, size_t size) | 228 | vfs_getxattr(struct dentry *dentry, const char *name, void *value, size_t size) |
171 | { | 229 | { |
diff --git a/include/linux/xattr.h b/include/linux/xattr.h index 7a378662ddff..4703f6bd1f53 100644 --- a/include/linux/xattr.h +++ b/include/linux/xattr.h | |||
@@ -84,7 +84,10 @@ ssize_t generic_getxattr(struct dentry *dentry, const char *name, void *buffer, | |||
84 | ssize_t generic_listxattr(struct dentry *dentry, char *buffer, size_t buffer_size); | 84 | ssize_t generic_listxattr(struct dentry *dentry, char *buffer, size_t buffer_size); |
85 | int generic_setxattr(struct dentry *dentry, const char *name, const void *value, size_t size, int flags); | 85 | int generic_setxattr(struct dentry *dentry, const char *name, const void *value, size_t size, int flags); |
86 | int generic_removexattr(struct dentry *dentry, const char *name); | 86 | int generic_removexattr(struct dentry *dentry, const char *name); |
87 | 87 | ssize_t vfs_getxattr_alloc(struct dentry *dentry, const char *name, | |
88 | char **xattr_value, size_t size, gfp_t flags); | ||
89 | int vfs_xattr_cmp(struct dentry *dentry, const char *xattr_name, | ||
90 | const char *value, size_t size, gfp_t flags); | ||
88 | #endif /* __KERNEL__ */ | 91 | #endif /* __KERNEL__ */ |
89 | 92 | ||
90 | #endif /* _LINUX_XATTR_H */ | 93 | #endif /* _LINUX_XATTR_H */ |