linux/fs/xfs/linux-2.6/xfs_xattr.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2008 Christoph Hellwig.
   3 * Portions Copyright (C) 2000-2008 Silicon Graphics, Inc.
   4 *
   5 * This program is free software; you can redistribute it and/or
   6 * modify it under the terms of the GNU General Public License as
   7 * published by the Free Software Foundation.
   8 *
   9 * This program is distributed in the hope that it would be useful,
  10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12 * GNU General Public License for more details.
  13 *
  14 * You should have received a copy of the GNU General Public License
  15 * along with this program; if not, write the Free Software Foundation,
  16 * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  17 */
  18
  19#include "xfs.h"
  20#include "xfs_da_btree.h"
  21#include "xfs_bmap_btree.h"
  22#include "xfs_inode.h"
  23#include "xfs_attr.h"
  24#include "xfs_attr_leaf.h"
  25#include "xfs_acl.h"
  26#include "xfs_vnodeops.h"
  27
  28#include <linux/posix_acl_xattr.h>
  29#include <linux/xattr.h>
  30
  31
  32static int
  33xfs_xattr_get(struct dentry *dentry, const char *name,
  34                void *value, size_t size, int xflags)
  35{
  36        struct xfs_inode *ip = XFS_I(dentry->d_inode);
  37        int error, asize = size;
  38
  39        if (strcmp(name, "") == 0)
  40                return -EINVAL;
  41
  42        /* Convert Linux syscall to XFS internal ATTR flags */
  43        if (!size) {
  44                xflags |= ATTR_KERNOVAL;
  45                value = NULL;
  46        }
  47
  48        error = -xfs_attr_get(ip, (unsigned char *)name, value, &asize, xflags);
  49        if (error)
  50                return error;
  51        return asize;
  52}
  53
  54static int
  55xfs_xattr_set(struct dentry *dentry, const char *name, const void *value,
  56                size_t size, int flags, int xflags)
  57{
  58        struct xfs_inode *ip = XFS_I(dentry->d_inode);
  59
  60        if (strcmp(name, "") == 0)
  61                return -EINVAL;
  62
  63        /* Convert Linux syscall to XFS internal ATTR flags */
  64        if (flags & XATTR_CREATE)
  65                xflags |= ATTR_CREATE;
  66        if (flags & XATTR_REPLACE)
  67                xflags |= ATTR_REPLACE;
  68
  69        if (!value)
  70                return -xfs_attr_remove(ip, (unsigned char *)name, xflags);
  71        return -xfs_attr_set(ip, (unsigned char *)name,
  72                                (void *)value, size, xflags);
  73}
  74
  75static const struct xattr_handler xfs_xattr_user_handler = {
  76        .prefix = XATTR_USER_PREFIX,
  77        .flags  = 0, /* no flags implies user namespace */
  78        .get    = xfs_xattr_get,
  79        .set    = xfs_xattr_set,
  80};
  81
  82static const struct xattr_handler xfs_xattr_trusted_handler = {
  83        .prefix = XATTR_TRUSTED_PREFIX,
  84        .flags  = ATTR_ROOT,
  85        .get    = xfs_xattr_get,
  86        .set    = xfs_xattr_set,
  87};
  88
  89static const struct xattr_handler xfs_xattr_security_handler = {
  90        .prefix = XATTR_SECURITY_PREFIX,
  91        .flags  = ATTR_SECURE,
  92        .get    = xfs_xattr_get,
  93        .set    = xfs_xattr_set,
  94};
  95
  96const struct xattr_handler *xfs_xattr_handlers[] = {
  97        &xfs_xattr_user_handler,
  98        &xfs_xattr_trusted_handler,
  99        &xfs_xattr_security_handler,
 100#ifdef CONFIG_XFS_POSIX_ACL
 101        &xfs_xattr_acl_access_handler,
 102        &xfs_xattr_acl_default_handler,
 103#endif
 104        NULL
 105};
 106
 107static unsigned int xfs_xattr_prefix_len(int flags)
 108{
 109        if (flags & XFS_ATTR_SECURE)
 110                return sizeof("security");
 111        else if (flags & XFS_ATTR_ROOT)
 112                return sizeof("trusted");
 113        else
 114                return sizeof("user");
 115}
 116
 117static const char *xfs_xattr_prefix(int flags)
 118{
 119        if (flags & XFS_ATTR_SECURE)
 120                return xfs_xattr_security_handler.prefix;
 121        else if (flags & XFS_ATTR_ROOT)
 122                return xfs_xattr_trusted_handler.prefix;
 123        else
 124                return xfs_xattr_user_handler.prefix;
 125}
 126
 127static int
 128xfs_xattr_put_listent(
 129        struct xfs_attr_list_context *context,
 130        int             flags,
 131        unsigned char   *name,
 132        int             namelen,
 133        int             valuelen,
 134        unsigned char   *value)
 135{
 136        unsigned int prefix_len = xfs_xattr_prefix_len(flags);
 137        char *offset;
 138        int arraytop;
 139
 140        ASSERT(context->count >= 0);
 141
 142        /*
 143         * Only show root namespace entries if we are actually allowed to
 144         * see them.
 145         */
 146        if ((flags & XFS_ATTR_ROOT) && !capable(CAP_SYS_ADMIN))
 147                return 0;
 148
 149        arraytop = context->count + prefix_len + namelen + 1;
 150        if (arraytop > context->firstu) {
 151                context->count = -1;    /* insufficient space */
 152                return 1;
 153        }
 154        offset = (char *)context->alist + context->count;
 155        strncpy(offset, xfs_xattr_prefix(flags), prefix_len);
 156        offset += prefix_len;
 157        strncpy(offset, (char *)name, namelen);                 /* real name */
 158        offset += namelen;
 159        *offset = '\0';
 160        context->count += prefix_len + namelen + 1;
 161        return 0;
 162}
 163
 164static int
 165xfs_xattr_put_listent_sizes(
 166        struct xfs_attr_list_context *context,
 167        int             flags,
 168        unsigned char   *name,
 169        int             namelen,
 170        int             valuelen,
 171        unsigned char   *value)
 172{
 173        context->count += xfs_xattr_prefix_len(flags) + namelen + 1;
 174        return 0;
 175}
 176
 177static int
 178list_one_attr(const char *name, const size_t len, void *data,
 179                size_t size, ssize_t *result)
 180{
 181        char *p = data + *result;
 182
 183        *result += len;
 184        if (!size)
 185                return 0;
 186        if (*result > size)
 187                return -ERANGE;
 188
 189        strcpy(p, name);
 190        return 0;
 191}
 192
 193ssize_t
 194xfs_vn_listxattr(struct dentry *dentry, char *data, size_t size)
 195{
 196        struct xfs_attr_list_context context;
 197        struct attrlist_cursor_kern cursor = { 0 };
 198        struct inode            *inode = dentry->d_inode;
 199        int                     error;
 200
 201        /*
 202         * First read the regular on-disk attributes.
 203         */
 204        memset(&context, 0, sizeof(context));
 205        context.dp = XFS_I(inode);
 206        context.cursor = &cursor;
 207        context.resynch = 1;
 208        context.alist = data;
 209        context.bufsize = size;
 210        context.firstu = context.bufsize;
 211
 212        if (size)
 213                context.put_listent = xfs_xattr_put_listent;
 214        else
 215                context.put_listent = xfs_xattr_put_listent_sizes;
 216
 217        xfs_attr_list_int(&context);
 218        if (context.count < 0)
 219                return -ERANGE;
 220
 221        /*
 222         * Then add the two synthetic ACL attributes.
 223         */
 224        if (posix_acl_access_exists(inode)) {
 225                error = list_one_attr(POSIX_ACL_XATTR_ACCESS,
 226                                strlen(POSIX_ACL_XATTR_ACCESS) + 1,
 227                                data, size, &context.count);
 228                if (error)
 229                        return error;
 230        }
 231
 232        if (posix_acl_default_exists(inode)) {
 233                error = list_one_attr(POSIX_ACL_XATTR_DEFAULT,
 234                                strlen(POSIX_ACL_XATTR_DEFAULT) + 1,
 235                                data, size, &context.count);
 236                if (error)
 237                        return error;
 238        }
 239
 240        return context.count;
 241}
 242