xfs: Change how listxattr generates synthetic attributes
authorAndreas Gruenbacher <agruenba@redhat.com>
Wed, 2 Dec 2015 13:44:40 +0000 (14:44 +0100)
committerAl Viro <viro@zeniv.linux.org.uk>
Mon, 7 Dec 2015 02:34:16 +0000 (21:34 -0500)
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>
fs/xfs/xfs_acl.c
fs/xfs/xfs_acl.h
fs/xfs/xfs_xattr.c

index 6bb470fbb8e8ff3567abfb23b774607c7eab2dda..2d5df1f23bbcbe47cebc087023d04126230cbe6c 100644 (file)
@@ -252,29 +252,6 @@ xfs_set_mode(struct inode *inode, umode_t mode)
        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
 xfs_set_acl(struct inode *inode, struct posix_acl *acl, int type)
 {
index 52f8255d6bdfe0c511bd9d29fb76b89a5b05efdf..286fa89217f5cbeda44bed3f28698690e1efe06e 100644 (file)
@@ -24,16 +24,12 @@ struct posix_acl;
 #ifdef CONFIG_XFS_POSIX_ACL
 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 posix_acl_access_exists(struct inode *inode);
-extern int posix_acl_default_exists(struct inode *inode);
 #else
 static inline struct posix_acl *xfs_get_acl(struct inode *inode, int type)
 {
        return 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 */
 
 extern void xfs_forget_acl(struct inode *inode, const char *name, int xflags);
index 36a43851aac0dd2d583d85a1d58c983d42b377f4..110f1d7d86b0b4ab5a0fa72d8f752d5b29ea9e5f 100644 (file)
@@ -129,47 +129,19 @@ const struct xattr_handler *xfs_xattr_handlers[] = {
        NULL
 };
 
-static unsigned int xfs_xattr_prefix_len(int flags)
-{
-       if (flags & XFS_ATTR_SECURE)
-               return sizeof("security");
-       else if (flags & XFS_ATTR_ROOT)
-               return sizeof("trusted");
-       else
-               return sizeof("user");
-}
-
-static const char *xfs_xattr_prefix(int flags)
-{
-       if (flags & XFS_ATTR_SECURE)
-               return xfs_xattr_security_handler.prefix;
-       else if (flags & XFS_ATTR_ROOT)
-               return xfs_xattr_trusted_handler.prefix;
-       else
-               return xfs_xattr_user_handler.prefix;
-}
-
 static int
-xfs_xattr_put_listent(
+__xfs_xattr_put_listent(
        struct xfs_attr_list_context *context,
-       int             flags,
-       unsigned char   *name,
-       int             namelen,
-       int             valuelen,
-       unsigned char   *value)
+       char *prefix,
+       int prefix_len,
+       unsigned char *name,
+       int namelen)
 {
-       unsigned int prefix_len = xfs_xattr_prefix_len(flags);
        char *offset;
        int arraytop;
 
-       ASSERT(context->count >= 0);
-
-       /*
-        * Only show root namespace entries if we are actually allowed to
-        * see them.
-        */
-       if ((flags & XFS_ATTR_ROOT) && !capable(CAP_SYS_ADMIN))
-               return 0;
+       if (!context->alist)
+               goto compute_size;
 
        arraytop = context->count + prefix_len + namelen + 1;
        if (arraytop > context->firstu) {
@@ -177,17 +149,19 @@ xfs_xattr_put_listent(
                return 1;
        }
        offset = (char *)context->alist + context->count;
-       strncpy(offset, xfs_xattr_prefix(flags), prefix_len);
+       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
-xfs_xattr_put_listent_sizes(
+xfs_xattr_put_listent(
        struct xfs_attr_list_context *context,
        int             flags,
        unsigned char   *name,
@@ -195,24 +169,55 @@ xfs_xattr_put_listent_sizes(
        int             valuelen,
        unsigned char   *value)
 {
-       context->count += xfs_xattr_prefix_len(flags) + namelen + 1;
-       return 0;
-}
+       char *prefix;
+       int prefix_len;
 
-static int
-list_one_attr(const char *name, const size_t len, void *data,
-               size_t size, ssize_t *result)
-{
-       char *p = data + *result;
+       ASSERT(context->count >= 0);
 
-       *result += len;
-       if (!size)
-               return 0;
-       if (*result > size)
-               return -ERANGE;
+       if (flags & XFS_ATTR_ROOT) {
+#ifdef CONFIG_XFS_POSIX_ACL
+               if (namelen == SGI_ACL_FILE_SIZE &&
+                   strncmp(name, SGI_ACL_FILE,
+                           SGI_ACL_FILE_SIZE) == 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
 
-       strcpy(p, name);
-       return 0;
+               /*
+                * Only show root namespace entries if we are actually allowed to
+                * see them.
+                */
+               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;
+       }
+
+       return __xfs_xattr_put_listent(context, prefix, prefix_len, name,
+                                      namelen);
 }
 
 ssize_t
@@ -221,7 +226,6 @@ xfs_vn_listxattr(struct dentry *dentry, char *data, size_t size)
        struct xfs_attr_list_context context;
        struct attrlist_cursor_kern cursor = { 0 };
        struct inode            *inode = d_inode(dentry);
-       int                     error;
 
        /*
         * 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.cursor = &cursor;
        context.resynch = 1;
-       context.alist = data;
+       context.alist = size ? data : NULL;
        context.bufsize = size;
        context.firstu = context.bufsize;
-
-       if (size)
-               context.put_listent = xfs_xattr_put_listent;
-       else
-               context.put_listent = xfs_xattr_put_listent_sizes;
+       context.put_listent = xfs_xattr_put_listent;
 
        xfs_attr_list_int(&context);
        if (context.count < 0)
                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;
 }