Commit 764a5c6b authored by Andreas Gruenbacher's avatar Andreas Gruenbacher Committed by Al Viro

xattr handlers: Simplify list operation

Change the list operation to only return whether or not an attribute
should be listed.  Copying the attribute names into the buffer is moved
to the callers.

Since the result only depends on the dentry and not on the attribute
name, we do not pass the attribute name to list operations.
Signed-off-by: 's avatarAndreas Gruenbacher <agruenba@redhat.com>
Signed-off-by: 's avatarAl Viro <viro@zeniv.linux.org.uk>
parent 1046cb11
......@@ -292,16 +292,21 @@ bad_block: ext2_error(inode->i_sb, "ext2_xattr_list",
const struct xattr_handler *handler =
ext2_xattr_handler(entry->e_name_index);
if (handler) {
size_t size = handler->list(handler, dentry, buffer,
rest, entry->e_name,
entry->e_name_len);
if (handler && (!handler->list || handler->list(dentry))) {
const char *prefix = handler->prefix ?: handler->name;
size_t prefix_len = strlen(prefix);
size_t size = prefix_len + entry->e_name_len + 1;
if (buffer) {
if (size > rest) {
error = -ERANGE;
goto cleanup;
}
buffer += size;
memcpy(buffer, prefix, prefix_len);
buffer += prefix_len;
memcpy(buffer, entry->e_name, entry->e_name_len);
buffer += entry->e_name_len;
*buffer++ = 0;
}
rest -= size;
}
......
......@@ -7,22 +7,6 @@
#include <linux/security.h>
#include "xattr.h"
static size_t
ext2_xattr_security_list(const struct xattr_handler *handler,
struct dentry *dentry, char *list, size_t list_size,
const char *name, size_t name_len)
{
const int prefix_len = XATTR_SECURITY_PREFIX_LEN;
const size_t total_len = prefix_len + name_len + 1;
if (list && total_len <= list_size) {
memcpy(list, XATTR_SECURITY_PREFIX, prefix_len);
memcpy(list+prefix_len, name, name_len);
list[prefix_len + name_len] = '\0';
}
return total_len;
}
static int
ext2_xattr_security_get(const struct xattr_handler *handler,
struct dentry *dentry, const char *name,
......@@ -67,7 +51,6 @@ ext2_init_security(struct inode *inode, struct inode *dir,
const struct xattr_handler ext2_xattr_security_handler = {
.prefix = XATTR_SECURITY_PREFIX,
.list = ext2_xattr_security_list,
.get = ext2_xattr_security_get,
.set = ext2_xattr_security_set,
};
......@@ -8,23 +8,10 @@
#include "ext2.h"
#include "xattr.h"
static size_t
ext2_xattr_trusted_list(const struct xattr_handler *handler,
struct dentry *dentry, char *list, size_t list_size,
const char *name, size_t name_len)
static bool
ext2_xattr_trusted_list(struct dentry *dentry)
{
const int prefix_len = XATTR_TRUSTED_PREFIX_LEN;
const size_t total_len = prefix_len + name_len + 1;
if (!capable(CAP_SYS_ADMIN))
return 0;
if (list && total_len <= list_size) {
memcpy(list, XATTR_TRUSTED_PREFIX, prefix_len);
memcpy(list+prefix_len, name, name_len);
list[prefix_len + name_len] = '\0';
}
return total_len;
return capable(CAP_SYS_ADMIN);
}
static int
......
......@@ -10,23 +10,10 @@
#include "ext2.h"
#include "xattr.h"
static size_t
ext2_xattr_user_list(const struct xattr_handler *handler,
struct dentry *dentry, char *list, size_t list_size,
const char *name, size_t name_len)
static bool
ext2_xattr_user_list(struct dentry *dentry)
{
const size_t prefix_len = XATTR_USER_PREFIX_LEN;
const size_t total_len = prefix_len + name_len + 1;
if (!test_opt(dentry->d_sb, XATTR_USER))
return 0;
if (list && total_len <= list_size) {
memcpy(list, XATTR_USER_PREFIX, prefix_len);
memcpy(list+prefix_len, name, name_len);
list[prefix_len + name_len] = '\0';
}
return total_len;
return test_opt(dentry->d_sb, XATTR_USER);
}
static int
......
......@@ -404,19 +404,24 @@ ext4_xattr_list_entries(struct dentry *dentry, struct ext4_xattr_entry *entry,
const struct xattr_handler *handler =
ext4_xattr_handler(entry->e_name_index);
if (handler) {
size_t size = handler->list(handler, dentry, buffer,
rest, entry->e_name,
entry->e_name_len);
if (handler && (!handler->list || handler->list(dentry))) {
const char *prefix = handler->prefix ?: handler->name;
size_t prefix_len = strlen(prefix);
size_t size = prefix_len + entry->e_name_len + 1;
if (buffer) {
if (size > rest)
return -ERANGE;
buffer += size;
memcpy(buffer, prefix, prefix_len);
buffer += prefix_len;
memcpy(buffer, entry->e_name, entry->e_name_len);
buffer += entry->e_name_len;
*buffer++ = 0;
}
rest -= size;
}
}
return buffer_size - rest;
return buffer_size - rest; /* total size */
}
static int
......
......@@ -11,23 +11,6 @@
#include "ext4.h"
#include "xattr.h"
static size_t
ext4_xattr_security_list(const struct xattr_handler *handler,
struct dentry *dentry, char *list, size_t list_size,
const char *name, size_t name_len)
{
const size_t prefix_len = sizeof(XATTR_SECURITY_PREFIX)-1;
const size_t total_len = prefix_len + name_len + 1;
if (list && total_len <= list_size) {
memcpy(list, XATTR_SECURITY_PREFIX, prefix_len);
memcpy(list+prefix_len, name, name_len);
list[prefix_len + name_len] = '\0';
}
return total_len;
}
static int
ext4_xattr_security_get(const struct xattr_handler *handler,
struct dentry *dentry, const char *name,
......@@ -75,7 +58,6 @@ ext4_init_security(handle_t *handle, struct inode *inode, struct inode *dir,
const struct xattr_handler ext4_xattr_security_handler = {
.prefix = XATTR_SECURITY_PREFIX,
.list = ext4_xattr_security_list,
.get = ext4_xattr_security_get,
.set = ext4_xattr_security_set,
};
......@@ -12,23 +12,10 @@
#include "ext4.h"
#include "xattr.h"
static size_t
ext4_xattr_trusted_list(const struct xattr_handler *handler,
struct dentry *dentry, char *list, size_t list_size,
const char *name, size_t name_len)
static bool
ext4_xattr_trusted_list(struct dentry *dentry)
{
const size_t prefix_len = XATTR_TRUSTED_PREFIX_LEN;
const size_t total_len = prefix_len + name_len + 1;
if (!capable(CAP_SYS_ADMIN))
return 0;
if (list && total_len <= list_size) {
memcpy(list, XATTR_TRUSTED_PREFIX, prefix_len);
memcpy(list+prefix_len, name, name_len);
list[prefix_len + name_len] = '\0';
}
return total_len;
return capable(CAP_SYS_ADMIN);
}
static int
......
......@@ -11,23 +11,10 @@
#include "ext4.h"
#include "xattr.h"
static size_t
ext4_xattr_user_list(const struct xattr_handler *handler,
struct dentry *dentry, char *list, size_t list_size,
const char *name, size_t name_len)
static bool
ext4_xattr_user_list(struct dentry *dentry)
{
const size_t prefix_len = XATTR_USER_PREFIX_LEN;
const size_t total_len = prefix_len + name_len + 1;
if (!test_opt(dentry->d_sb, XATTR_USER))
return 0;
if (list && total_len <= list_size) {
memcpy(list, XATTR_USER_PREFIX, prefix_len);
memcpy(list+prefix_len, name, name_len);
list[prefix_len + name_len] = '\0';
}
return total_len;
return test_opt(dentry->d_sb, XATTR_USER);
}
static int
......
......@@ -25,40 +25,6 @@
#include "f2fs.h"
#include "xattr.h"
static size_t f2fs_xattr_generic_list(const struct xattr_handler *handler,
struct dentry *dentry, char *list, size_t list_size,
const char *name, size_t len)
{
struct f2fs_sb_info *sbi = F2FS_SB(dentry->d_sb);
const char *prefix;
int total_len, prefix_len;
switch (handler->flags) {
case F2FS_XATTR_INDEX_USER:
if (!test_opt(sbi, XATTR_USER))
return -EOPNOTSUPP;
break;
case F2FS_XATTR_INDEX_TRUSTED:
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
break;
case F2FS_XATTR_INDEX_SECURITY:
break;
default:
return -EINVAL;
}
prefix = xattr_prefix(handler);
prefix_len = strlen(prefix);
total_len = prefix_len + len + 1;
if (list && total_len <= list_size) {
memcpy(list, prefix, prefix_len);
memcpy(list + prefix_len, name, len);
list[prefix_len + len] = '\0';
}
return total_len;
}
static int f2fs_xattr_generic_get(const struct xattr_handler *handler,
struct dentry *dentry, const char *name, void *buffer,
size_t size)
......@@ -107,17 +73,16 @@ static int f2fs_xattr_generic_set(const struct xattr_handler *handler,
value, size, NULL, flags);
}
static size_t f2fs_xattr_advise_list(const struct xattr_handler *handler,
struct dentry *dentry, char *list, size_t list_size,
const char *name, size_t len)
static bool f2fs_xattr_user_list(struct dentry *dentry)
{
const char *xname = F2FS_SYSTEM_ADVISE_NAME;
size_t size;
struct f2fs_sb_info *sbi = F2FS_SB(dentry->d_sb);
return test_opt(sbi, XATTR_USER);
}
size = strlen(xname) + 1;
if (list && size <= list_size)
memcpy(list, xname, size);
return size;
static bool f2fs_xattr_trusted_list(struct dentry *dentry)
{
return capable(CAP_SYS_ADMIN);
}
static int f2fs_xattr_advise_get(const struct xattr_handler *handler,
......@@ -175,7 +140,7 @@ int f2fs_init_security(struct inode *inode, struct inode *dir,
const struct xattr_handler f2fs_xattr_user_handler = {
.prefix = XATTR_USER_PREFIX,
.flags = F2FS_XATTR_INDEX_USER,
.list = f2fs_xattr_generic_list,
.list = f2fs_xattr_user_list,
.get = f2fs_xattr_generic_get,
.set = f2fs_xattr_generic_set,
};
......@@ -183,7 +148,7 @@ const struct xattr_handler f2fs_xattr_user_handler = {
const struct xattr_handler f2fs_xattr_trusted_handler = {
.prefix = XATTR_TRUSTED_PREFIX,
.flags = F2FS_XATTR_INDEX_TRUSTED,
.list = f2fs_xattr_generic_list,
.list = f2fs_xattr_trusted_list,
.get = f2fs_xattr_generic_get,
.set = f2fs_xattr_generic_set,
};
......@@ -191,7 +156,6 @@ const struct xattr_handler f2fs_xattr_trusted_handler = {
const struct xattr_handler f2fs_xattr_advise_handler = {
.name = F2FS_SYSTEM_ADVISE_NAME,
.flags = F2FS_XATTR_INDEX_ADVISE,
.list = f2fs_xattr_advise_list,
.get = f2fs_xattr_advise_get,
.set = f2fs_xattr_advise_set,
};
......@@ -199,7 +163,6 @@ const struct xattr_handler f2fs_xattr_advise_handler = {
const struct xattr_handler f2fs_xattr_security_handler = {
.prefix = XATTR_SECURITY_PREFIX,
.flags = F2FS_XATTR_INDEX_SECURITY,
.list = f2fs_xattr_generic_list,
.get = f2fs_xattr_generic_get,
.set = f2fs_xattr_generic_set,
};
......@@ -447,20 +410,27 @@ ssize_t f2fs_listxattr(struct dentry *dentry, char *buffer, size_t buffer_size)
list_for_each_xattr(entry, base_addr) {
const struct xattr_handler *handler =
f2fs_xattr_handler(entry->e_name_index);
const char *prefix;
size_t prefix_len;
size_t size;
if (!handler)
if (!handler || (handler->list && !handler->list(dentry)))
continue;
size = handler->list(handler, dentry, buffer, rest,
entry->e_name, entry->e_name_len);
if (buffer && size > rest) {
error = -ERANGE;
goto cleanup;
prefix = handler->prefix ?: handler->name;
prefix_len = strlen(prefix);
size = prefix_len + entry->e_name_len + 1;
if (buffer) {
if (size > rest) {
error = -ERANGE;
goto cleanup;
}
memcpy(buffer, prefix, prefix_len);
buffer += prefix_len;
memcpy(buffer, entry->e_name, entry->e_name_len);
buffer += entry->e_name_len;
*buffer++ = 0;
}
if (buffer)
buffer += size;
rest -= size;
}
error = buffer_size - rest;
......
......@@ -64,24 +64,8 @@ static int jffs2_security_setxattr(const struct xattr_handler *handler,
name, buffer, size, flags);
}
static size_t jffs2_security_listxattr(const struct xattr_handler *handler,
struct dentry *dentry, char *list,
size_t list_size, const char *name,
size_t name_len)
{
size_t retlen = XATTR_SECURITY_PREFIX_LEN + name_len + 1;
if (list && retlen <= list_size) {
strcpy(list, XATTR_SECURITY_PREFIX);
strcpy(list + XATTR_SECURITY_PREFIX_LEN, name);
}
return retlen;
}
const struct xattr_handler jffs2_security_xattr_handler = {
.prefix = XATTR_SECURITY_PREFIX,
.list = jffs2_security_listxattr,
.set = jffs2_security_setxattr,
.get = jffs2_security_getxattr
};
......@@ -967,7 +967,8 @@ ssize_t jffs2_listxattr(struct dentry *dentry, char *buffer, size_t size)
struct jffs2_xattr_ref *ref, **pref;
struct jffs2_xattr_datum *xd;
const struct xattr_handler *xhandle;
ssize_t len, rc;
const char *prefix;
ssize_t prefix_len, len, rc;
int retry = 0;
rc = check_xattr_ref_inode(c, ic);
......@@ -998,18 +999,23 @@ ssize_t jffs2_listxattr(struct dentry *dentry, char *buffer, size_t size)
}
}
xhandle = xprefix_to_handler(xd->xprefix);
if (!xhandle)
if (!xhandle || (xhandle->list && !xhandle->list(dentry)))
continue;
prefix = xhandle->prefix ?: xhandle->name;
prefix_len = strlen(prefix);
rc = prefix_len + xd->name_len + 1;
if (buffer) {
rc = xhandle->list(xhandle, dentry, buffer + len,
size - len, xd->xname,
xd->name_len);
} else {
rc = xhandle->list(xhandle, dentry, NULL, 0,
xd->xname, xd->name_len);
if (rc > size - len) {
rc = -ERANGE;
goto out;
}
memcpy(buffer, prefix, prefix_len);
buffer += prefix_len;
memcpy(buffer, xd->xname, xd->name_len);
buffer += xd->name_len;
*buffer++ = 0;
}
if (rc < 0)
goto out;
len += rc;
}
rc = len;
......
......@@ -32,22 +32,9 @@ static int jffs2_trusted_setxattr(const struct xattr_handler *handler,
name, buffer, size, flags);
}
static size_t jffs2_trusted_listxattr(const struct xattr_handler *handler,
struct dentry *dentry, char *list,
size_t list_size, const char *name,
size_t name_len)
static bool jffs2_trusted_listxattr(struct dentry *dentry)
{
size_t retlen = XATTR_TRUSTED_PREFIX_LEN + name_len + 1;
if (!capable(CAP_SYS_ADMIN))
return 0;
if (list && retlen<=list_size) {
strcpy(list, XATTR_TRUSTED_PREFIX);
strcpy(list + XATTR_TRUSTED_PREFIX_LEN, name);
}
return retlen;
return capable(CAP_SYS_ADMIN);
}
const struct xattr_handler jffs2_trusted_xattr_handler = {
......
......@@ -32,24 +32,8 @@ static int jffs2_user_setxattr(const struct xattr_handler *handler,
name, buffer, size, flags);
}
static size_t jffs2_user_listxattr(const struct xattr_handler *handler,
struct dentry *dentry, char *list,
size_t list_size, const char *name,
size_t name_len)
{
size_t retlen = XATTR_USER_PREFIX_LEN + name_len + 1;
if (list && retlen <= list_size) {
strcpy(list, XATTR_USER_PREFIX);
strcpy(list + XATTR_USER_PREFIX_LEN, name);
}
return retlen;
}
const struct xattr_handler jffs2_user_xattr_handler = {
.prefix = XATTR_USER_PREFIX,
.list = jffs2_user_listxattr,
.set = jffs2_user_setxattr,
.get = jffs2_user_getxattr
};
......@@ -6263,19 +6263,9 @@ static int nfs4_xattr_get_nfs4_acl(const struct xattr_handler *handler,
return nfs4_proc_get_acl(d_inode(dentry), buf, buflen);
}
static size_t nfs4_xattr_list_nfs4_acl(const struct xattr_handler *handler,
struct dentry *dentry, char *list,
size_t list_len, const char *name,
size_t name_len)
static bool nfs4_xattr_list_nfs4_acl(struct dentry *dentry)
{
size_t len = sizeof(XATTR_NAME_NFSV4_ACL);
if (!nfs4_server_supports_acls(NFS_SERVER(d_inode(dentry))))
return 0;
if (list && len <= list_len)
memcpy(list, XATTR_NAME_NFSV4_ACL, len);
return len;
return nfs4_server_supports_acls(NFS_SERVER(d_inode(dentry)));
}
#ifdef CONFIG_NFS_V4_SECURITY_LABEL
......
......@@ -823,21 +823,10 @@ posix_acl_xattr_set(const struct xattr_handler *handler,
return ret;
}
static size_t
posix_acl_xattr_list(const struct xattr_handler *handler,
struct dentry *dentry, char *list, size_t list_size,
const char *name, size_t name_len)
static bool
posix_acl_xattr_list(struct dentry *dentry)
{
const char *xname = handler->name;
size_t size;
if (!IS_POSIXACL(d_backing_inode(dentry)))
return 0;
size = strlen(xname) + 1;
if (list && size <= list_size)
memcpy(list, xname, size);
return size;
return IS_POSIXACL(d_backing_inode(dentry));
}
const struct xattr_handler posix_acl_access_xattr_handler = {
......
......@@ -840,19 +840,16 @@ static int listxattr_filler(struct dir_context *ctx, const char *name,
handler = find_xattr_handler_prefix(b->dentry->d_sb->s_xattr,
name);
if (!handler) /* Unsupported xattr name */
if (!handler /* Unsupported xattr name */ ||
(handler->list && !handler->list(b->dentry)))
return 0;
size = namelen + 1;
if (b->buf) {
size = handler->list(handler, b->dentry,
b->buf + b->pos, b->size, name,
namelen);
if (size > b->size)
return -ERANGE;
} else {
size = handler->list(handler, b->dentry,
NULL, 0, name, namelen);
memcpy(b->buf + b->pos, name, namelen);
b->buf[b->pos + namelen] = 0;
}
b->pos += size;
}
return 0;
......
......@@ -34,21 +34,9 @@ security_set(const struct xattr_handler *handler, struct dentry *dentry,
return reiserfs_xattr_set(d_inode(dentry), name, buffer, size, flags);
}
static size_t security_list(const struct xattr_handler *handler,
struct dentry *dentry, char *list, size_t list_len,
const char *name, size_t namelen)
static bool security_list(struct dentry *dentry)
{
const size_t len = namelen + 1;
if (IS_PRIVATE(d_inode(dentry)))
return 0;
if (list && len <= list_len) {
memcpy(list, name, namelen);
list[namelen] = '\0';
}
return len;
return !IS_PRIVATE(d_inode(dentry));
}
/* Initializes the security context for a new inode and returns the number
......
......@@ -33,20 +33,9 @@ trusted_set(const struct xattr_handler *handler, struct dentry *dentry,
return reiserfs_xattr_set(d_inode(dentry), name, buffer, size, flags);
}
static size_t trusted_list(const struct xattr_handler *handler,
struct dentry *dentry, char *list, size_t list_size,
const char *name, size_t name_len)
static bool trusted_list(struct dentry *dentry)
{
const size_t len = name_len + 1;
if (!capable(CAP_SYS_ADMIN) || IS_PRIVATE(d_inode(dentry)))
return 0;
if (list && len <= list_size) {
memcpy(list, name, name_len);
list[name_len] = '\0';
}
return len;
return capable(CAP_SYS_ADMIN) && !IS_PRIVATE(d_inode(dentry));
}
const struct xattr_handler reiserfs_xattr_trusted_handler = {
......
......@@ -30,19 +30,9 @@ user_set(const struct xattr_handler *handler, struct dentry *dentry,
return reiserfs_xattr_set(d_inode(dentry), name, buffer, size, flags);
}
static size_t user_list(const struct xattr_handler *handler,
struct dentry *dentry, char *list, size_t list_size,
const char *name, size_t name_len)
static bool user_list(struct dentry *dentry)
{
const size_t len = name_len + 1;
if (!reiserfs_xattrs_user(dentry->d_sb))
return 0;
if (list && len <= list_size) {
memcpy(list, name, name_len);
list[name_len] = '\0';
}
return len;
return reiserfs_xattrs_user(dentry->d_sb);
}
const struct xattr_handler reiserfs_xattr_user_handler = {
......
......@@ -58,7 +58,7 @@ ssize_t squashfs_listxattr(struct dentry *d, char *buffer,
struct squashfs_xattr_entry entry;
struct squashfs_xattr_val val;
const struct xattr_handler *handler;
int name_size, prefix_size = 0;
int name_size;
err = squashfs_read_metadata(sb, &entry, &start, &offset,
sizeof(entry));
......@@ -67,15 +67,16 @@ ssize_t squashfs_listxattr(struct dentry *d, char *buffer,
name_size = le16_to_cpu(entry.size);
handler = squashfs_xattr_handler(le16_to_cpu(entry.type));
if (handler)
prefix_size = handler->list(handler, d, buffer, rest,
NULL, name_size);
if (prefix_size) {
if (handler && (!handler->list || handler->list(d))) {
const char *prefix = handler->prefix ?: handler->name;
size_t prefix_size = strlen(prefix);
if (buffer) {
if (prefix_size + name_size + 1 > rest) {
err = -ERANGE;
goto failed;
}
memcpy(buffer, prefix, prefix_size);
buffer += prefix_size;
}
err = squashfs_read_metadata(sb, buffer, &start,
......@@ -212,18 +213,6 @@ static int squashfs_xattr_get(struct inode *inode, int name_index,
}
static size_t squashfs_xattr_handler_list(const struct xattr_handler *handler,
struct dentry *d, char *list,
size_t list_size, const char *name,
size_t name_len)
{
int len = strlen(handler->prefix);
if (list && len <= list_size)
memcpy(list, handler->prefix, len);
return len;
}
static int squashfs_xattr_handler_get(const struct xattr_handler *handler,
struct dentry *d, const char *name,
void *buffer, size_t size)
......@@ -238,22 +227,15 @@ static int squashfs_xattr_handler_get(const struct xattr_handler *handler,
static const struct xattr_handler squashfs_xattr_user_handler = {
.prefix = XATTR_USER_PREFIX,
.flags = SQUASHFS_XATTR_USER,
.list = squashfs_xattr_handler_list,
.get = squashfs_xattr_handler_get
};
/*
* Trusted namespace support
*/
static size_t squashfs_trusted_xattr_handler_list(const struct xattr_handler *handler,
struct dentry *d, char *list,
size_t list_size, const char *name,
size_t name_len)
static bool squashfs_trusted_xattr_handler_list(struct dentry *d)
{
if (!capable(CAP_SYS_ADMIN))
return 0;
return squashfs_xattr_handler_list(handler, d, list, list_size, name,
name_len);
return capable(CAP_SYS_ADMIN);
}
static const struct xattr_handler squashfs_xattr_trusted_handler = {
......@@ -269,7 +251,6 @@ static const struct xattr_handler squashfs_xattr_trusted_handler = {
static const struct xattr_handler squashfs_xattr_security_handler = {
.prefix = XATTR_SECURITY_PREFIX,
.flags = SQUASHFS_XATTR_SECURITY,
.list = squashfs_xattr_handler_list,
.get = squashfs_xattr_handler_get
};
......
......@@ -723,23 +723,25 @@ generic_listxattr(struct dentry *dentry, char *buffer, size_t buffer_size)
if (!buffer) {
for_each_xattr_handler(handlers, handler) {
if (!handler->list)
if (!handler->name ||
(handler->list && !handler->list(dentry)))
continue;
size += handler->list(handler, dentry, NULL, 0,
NULL, 0);
size += strlen(handler->name) + 1;
}
} else {
char *buf = buffer;