xfs: Change how listxattr generates synthetic attributes
Instead of adding the synthesized POSIX ACL attribute names after listing all non-synthesized attributes, generate them immediately when listing the non-synthesized attributes. In addition, merge xfs_xattr_put_listent and xfs_xattr_put_listent_sizes to ensure that the list size is computed correctly; the split version was overestimating the list size for non-root users. Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com> Cc: Dave Chinner <david@fromorbit.com> Cc: xfs@oss.sgi.com Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
This commit is contained in:
parent
786534b92f
commit
5d92b75c75
|
@ -252,29 +252,6 @@ xfs_set_mode(struct inode *inode, umode_t mode)
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
|
||||||
xfs_acl_exists(struct inode *inode, unsigned char *name)
|
|
||||||
{
|
|
||||||
int len = XFS_ACL_MAX_SIZE(XFS_M(inode->i_sb));
|
|
||||||
|
|
||||||
return (xfs_attr_get(XFS_I(inode), name, NULL, &len,
|
|
||||||
ATTR_ROOT|ATTR_KERNOVAL) == 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
posix_acl_access_exists(struct inode *inode)
|
|
||||||
{
|
|
||||||
return xfs_acl_exists(inode, SGI_ACL_FILE);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
posix_acl_default_exists(struct inode *inode)
|
|
||||||
{
|
|
||||||
if (!S_ISDIR(inode->i_mode))
|
|
||||||
return 0;
|
|
||||||
return xfs_acl_exists(inode, SGI_ACL_DEFAULT);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
int
|
||||||
xfs_set_acl(struct inode *inode, struct posix_acl *acl, int type)
|
xfs_set_acl(struct inode *inode, struct posix_acl *acl, int type)
|
||||||
{
|
{
|
||||||
|
|
|
@ -24,16 +24,12 @@ struct posix_acl;
|
||||||
#ifdef CONFIG_XFS_POSIX_ACL
|
#ifdef CONFIG_XFS_POSIX_ACL
|
||||||
extern struct posix_acl *xfs_get_acl(struct inode *inode, int type);
|
extern struct posix_acl *xfs_get_acl(struct inode *inode, int type);
|
||||||
extern int xfs_set_acl(struct inode *inode, struct posix_acl *acl, int type);
|
extern int xfs_set_acl(struct inode *inode, struct posix_acl *acl, int type);
|
||||||
extern int posix_acl_access_exists(struct inode *inode);
|
|
||||||
extern int posix_acl_default_exists(struct inode *inode);
|
|
||||||
#else
|
#else
|
||||||
static inline struct posix_acl *xfs_get_acl(struct inode *inode, int type)
|
static inline struct posix_acl *xfs_get_acl(struct inode *inode, int type)
|
||||||
{
|
{
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
# define xfs_set_acl NULL
|
# define xfs_set_acl NULL
|
||||||
# define posix_acl_access_exists(inode) 0
|
|
||||||
# define posix_acl_default_exists(inode) 0
|
|
||||||
#endif /* CONFIG_XFS_POSIX_ACL */
|
#endif /* CONFIG_XFS_POSIX_ACL */
|
||||||
|
|
||||||
extern void xfs_forget_acl(struct inode *inode, const char *name, int xflags);
|
extern void xfs_forget_acl(struct inode *inode, const char *name, int xflags);
|
||||||
|
|
|
@ -129,24 +129,35 @@ const struct xattr_handler *xfs_xattr_handlers[] = {
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
static unsigned int xfs_xattr_prefix_len(int flags)
|
static int
|
||||||
|
__xfs_xattr_put_listent(
|
||||||
|
struct xfs_attr_list_context *context,
|
||||||
|
char *prefix,
|
||||||
|
int prefix_len,
|
||||||
|
unsigned char *name,
|
||||||
|
int namelen)
|
||||||
{
|
{
|
||||||
if (flags & XFS_ATTR_SECURE)
|
char *offset;
|
||||||
return sizeof("security");
|
int arraytop;
|
||||||
else if (flags & XFS_ATTR_ROOT)
|
|
||||||
return sizeof("trusted");
|
|
||||||
else
|
|
||||||
return sizeof("user");
|
|
||||||
}
|
|
||||||
|
|
||||||
static const char *xfs_xattr_prefix(int flags)
|
if (!context->alist)
|
||||||
{
|
goto compute_size;
|
||||||
if (flags & XFS_ATTR_SECURE)
|
|
||||||
return xfs_xattr_security_handler.prefix;
|
arraytop = context->count + prefix_len + namelen + 1;
|
||||||
else if (flags & XFS_ATTR_ROOT)
|
if (arraytop > context->firstu) {
|
||||||
return xfs_xattr_trusted_handler.prefix;
|
context->count = -1; /* insufficient space */
|
||||||
else
|
return 1;
|
||||||
return xfs_xattr_user_handler.prefix;
|
}
|
||||||
|
offset = (char *)context->alist + context->count;
|
||||||
|
strncpy(offset, prefix, prefix_len);
|
||||||
|
offset += prefix_len;
|
||||||
|
strncpy(offset, (char *)name, namelen); /* real name */
|
||||||
|
offset += namelen;
|
||||||
|
*offset = '\0';
|
||||||
|
|
||||||
|
compute_size:
|
||||||
|
context->count += prefix_len + namelen + 1;
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
|
@ -158,61 +169,55 @@ xfs_xattr_put_listent(
|
||||||
int valuelen,
|
int valuelen,
|
||||||
unsigned char *value)
|
unsigned char *value)
|
||||||
{
|
{
|
||||||
unsigned int prefix_len = xfs_xattr_prefix_len(flags);
|
char *prefix;
|
||||||
char *offset;
|
int prefix_len;
|
||||||
int arraytop;
|
|
||||||
|
|
||||||
ASSERT(context->count >= 0);
|
ASSERT(context->count >= 0);
|
||||||
|
|
||||||
/*
|
if (flags & XFS_ATTR_ROOT) {
|
||||||
* Only show root namespace entries if we are actually allowed to
|
#ifdef CONFIG_XFS_POSIX_ACL
|
||||||
* see them.
|
if (namelen == SGI_ACL_FILE_SIZE &&
|
||||||
*/
|
strncmp(name, SGI_ACL_FILE,
|
||||||
if ((flags & XFS_ATTR_ROOT) && !capable(CAP_SYS_ADMIN))
|
SGI_ACL_FILE_SIZE) == 0) {
|
||||||
return 0;
|
int ret = __xfs_xattr_put_listent(
|
||||||
|
context, XATTR_SYSTEM_PREFIX,
|
||||||
|
XATTR_SYSTEM_PREFIX_LEN,
|
||||||
|
XATTR_POSIX_ACL_ACCESS,
|
||||||
|
strlen(XATTR_POSIX_ACL_ACCESS));
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
} else if (namelen == SGI_ACL_DEFAULT_SIZE &&
|
||||||
|
strncmp(name, SGI_ACL_DEFAULT,
|
||||||
|
SGI_ACL_DEFAULT_SIZE) == 0) {
|
||||||
|
int ret = __xfs_xattr_put_listent(
|
||||||
|
context, XATTR_SYSTEM_PREFIX,
|
||||||
|
XATTR_SYSTEM_PREFIX_LEN,
|
||||||
|
XATTR_POSIX_ACL_DEFAULT,
|
||||||
|
strlen(XATTR_POSIX_ACL_DEFAULT));
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
arraytop = context->count + prefix_len + namelen + 1;
|
/*
|
||||||
if (arraytop > context->firstu) {
|
* Only show root namespace entries if we are actually allowed to
|
||||||
context->count = -1; /* insufficient space */
|
* see them.
|
||||||
return 1;
|
*/
|
||||||
|
if (!capable(CAP_SYS_ADMIN))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
prefix = XATTR_TRUSTED_PREFIX;
|
||||||
|
prefix_len = XATTR_TRUSTED_PREFIX_LEN;
|
||||||
|
} else if (flags & XFS_ATTR_SECURE) {
|
||||||
|
prefix = XATTR_SECURITY_PREFIX;
|
||||||
|
prefix_len = XATTR_SECURITY_PREFIX_LEN;
|
||||||
|
} else {
|
||||||
|
prefix = XATTR_USER_PREFIX;
|
||||||
|
prefix_len = XATTR_USER_PREFIX_LEN;
|
||||||
}
|
}
|
||||||
offset = (char *)context->alist + context->count;
|
|
||||||
strncpy(offset, xfs_xattr_prefix(flags), prefix_len);
|
|
||||||
offset += prefix_len;
|
|
||||||
strncpy(offset, (char *)name, namelen); /* real name */
|
|
||||||
offset += namelen;
|
|
||||||
*offset = '\0';
|
|
||||||
context->count += prefix_len + namelen + 1;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
return __xfs_xattr_put_listent(context, prefix, prefix_len, name,
|
||||||
xfs_xattr_put_listent_sizes(
|
namelen);
|
||||||
struct xfs_attr_list_context *context,
|
|
||||||
int flags,
|
|
||||||
unsigned char *name,
|
|
||||||
int namelen,
|
|
||||||
int valuelen,
|
|
||||||
unsigned char *value)
|
|
||||||
{
|
|
||||||
context->count += xfs_xattr_prefix_len(flags) + namelen + 1;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
list_one_attr(const char *name, const size_t len, void *data,
|
|
||||||
size_t size, ssize_t *result)
|
|
||||||
{
|
|
||||||
char *p = data + *result;
|
|
||||||
|
|
||||||
*result += len;
|
|
||||||
if (!size)
|
|
||||||
return 0;
|
|
||||||
if (*result > size)
|
|
||||||
return -ERANGE;
|
|
||||||
|
|
||||||
strcpy(p, name);
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ssize_t
|
ssize_t
|
||||||
|
@ -221,7 +226,6 @@ xfs_vn_listxattr(struct dentry *dentry, char *data, size_t size)
|
||||||
struct xfs_attr_list_context context;
|
struct xfs_attr_list_context context;
|
||||||
struct attrlist_cursor_kern cursor = { 0 };
|
struct attrlist_cursor_kern cursor = { 0 };
|
||||||
struct inode *inode = d_inode(dentry);
|
struct inode *inode = d_inode(dentry);
|
||||||
int error;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* First read the regular on-disk attributes.
|
* First read the regular on-disk attributes.
|
||||||
|
@ -230,37 +234,14 @@ xfs_vn_listxattr(struct dentry *dentry, char *data, size_t size)
|
||||||
context.dp = XFS_I(inode);
|
context.dp = XFS_I(inode);
|
||||||
context.cursor = &cursor;
|
context.cursor = &cursor;
|
||||||
context.resynch = 1;
|
context.resynch = 1;
|
||||||
context.alist = data;
|
context.alist = size ? data : NULL;
|
||||||
context.bufsize = size;
|
context.bufsize = size;
|
||||||
context.firstu = context.bufsize;
|
context.firstu = context.bufsize;
|
||||||
|
context.put_listent = xfs_xattr_put_listent;
|
||||||
if (size)
|
|
||||||
context.put_listent = xfs_xattr_put_listent;
|
|
||||||
else
|
|
||||||
context.put_listent = xfs_xattr_put_listent_sizes;
|
|
||||||
|
|
||||||
xfs_attr_list_int(&context);
|
xfs_attr_list_int(&context);
|
||||||
if (context.count < 0)
|
if (context.count < 0)
|
||||||
return -ERANGE;
|
return -ERANGE;
|
||||||
|
|
||||||
/*
|
|
||||||
* Then add the two synthetic ACL attributes.
|
|
||||||
*/
|
|
||||||
if (posix_acl_access_exists(inode)) {
|
|
||||||
error = list_one_attr(XATTR_NAME_POSIX_ACL_ACCESS,
|
|
||||||
strlen(XATTR_NAME_POSIX_ACL_ACCESS) + 1,
|
|
||||||
data, size, &context.count);
|
|
||||||
if (error)
|
|
||||||
return error;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (posix_acl_default_exists(inode)) {
|
|
||||||
error = list_one_attr(XATTR_NAME_POSIX_ACL_DEFAULT,
|
|
||||||
strlen(XATTR_NAME_POSIX_ACL_DEFAULT) + 1,
|
|
||||||
data, size, &context.count);
|
|
||||||
if (error)
|
|
||||||
return error;
|
|
||||||
}
|
|
||||||
|
|
||||||
return context.count;
|
return context.count;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue