|
@@ -166,6 +166,64 @@ out_noalloc:
|
|
|
}
|
|
|
EXPORT_SYMBOL_GPL(xattr_getsecurity);
|
|
|
|
|
|
+/*
|
|
|
+ * vfs_getxattr_alloc - allocate memory, if necessary, before calling getxattr
|
|
|
+ *
|
|
|
+ * Allocate memory, if not already allocated, or re-allocate correct size,
|
|
|
+ * before retrieving the extended attribute.
|
|
|
+ *
|
|
|
+ * Returns the result of alloc, if failed, or the getxattr operation.
|
|
|
+ */
|
|
|
+ssize_t
|
|
|
+vfs_getxattr_alloc(struct dentry *dentry, const char *name, char **xattr_value,
|
|
|
+ size_t xattr_size, gfp_t flags)
|
|
|
+{
|
|
|
+ struct inode *inode = dentry->d_inode;
|
|
|
+ char *value = *xattr_value;
|
|
|
+ int error;
|
|
|
+
|
|
|
+ error = xattr_permission(inode, name, MAY_READ);
|
|
|
+ if (error)
|
|
|
+ return error;
|
|
|
+
|
|
|
+ if (!inode->i_op->getxattr)
|
|
|
+ return -EOPNOTSUPP;
|
|
|
+
|
|
|
+ error = inode->i_op->getxattr(dentry, name, NULL, 0);
|
|
|
+ if (error < 0)
|
|
|
+ return error;
|
|
|
+
|
|
|
+ if (!value || (error > xattr_size)) {
|
|
|
+ value = krealloc(*xattr_value, error + 1, flags);
|
|
|
+ if (!value)
|
|
|
+ return -ENOMEM;
|
|
|
+ memset(value, 0, error + 1);
|
|
|
+ }
|
|
|
+
|
|
|
+ error = inode->i_op->getxattr(dentry, name, value, error);
|
|
|
+ *xattr_value = value;
|
|
|
+ return error;
|
|
|
+}
|
|
|
+
|
|
|
+/* Compare an extended attribute value with the given value */
|
|
|
+int vfs_xattr_cmp(struct dentry *dentry, const char *xattr_name,
|
|
|
+ const char *value, size_t size, gfp_t flags)
|
|
|
+{
|
|
|
+ char *xattr_value = NULL;
|
|
|
+ int rc;
|
|
|
+
|
|
|
+ rc = vfs_getxattr_alloc(dentry, xattr_name, &xattr_value, 0, flags);
|
|
|
+ if (rc < 0)
|
|
|
+ return rc;
|
|
|
+
|
|
|
+ if ((rc != size) || (memcmp(xattr_value, value, rc) != 0))
|
|
|
+ rc = -EINVAL;
|
|
|
+ else
|
|
|
+ rc = 0;
|
|
|
+ kfree(xattr_value);
|
|
|
+ return rc;
|
|
|
+}
|
|
|
+
|
|
|
ssize_t
|
|
|
vfs_getxattr(struct dentry *dentry, const char *name, void *value, size_t size)
|
|
|
{
|