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
  33__xfs_xattr_get(struct inode *inode, const char *name,
  34                void *value, size_t size, int xflags)
  35{
  36        struct xfs_inode *ip = XFS_I(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, name, value, &asize, xflags);
  49        if (error)
  50                return error;
  51        return asize;
  52}
  53
  54static int
  55__xfs_xattr_set(struct inode *inode, const char *name, const void *value,
  56                size_t size, int flags, int xflags)
  57{
  58        struct xfs_inode *ip = XFS_I(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, name, xflags);
  71        return -xfs_attr_set(ip, name, (void *)value, size, xflags);
  72}
  73
  74static int
  75xfs_xattr_user_get(struct inode *inode, const char *name,
  76                void *value, size_t size)
  77{
  78        return __xfs_xattr_get(inode, name, value, size, 0);
  79}
  80
  81static int
  82xfs_xattr_user_set(struct inode *inode, const char *name,
  83                const void *value, size_t size, int flags)
  84{
  85        return __xfs_xattr_set(inode, name, value, size, flags, 0);
  86}
  87
  88static struct xattr_handler xfs_xattr_user_handler = {
  89        .prefix = XATTR_USER_PREFIX,
  90        .get    = xfs_xattr_user_get,
  91        .set    = xfs_xattr_user_set,
  92};
  93
  94
  95static int
  96xfs_xattr_trusted_get(struct inode *inode, const char *name,
  97                void *value, size_t size)
  98{
  99        return __xfs_xattr_get(inode, name, value, size, ATTR_ROOT);
 100}
 101
 102static int
 103xfs_xattr_trusted_set(struct inode *inode, const char *name,
 104                const void *value, size_t size, int flags)
 105{
 106        return __xfs_xattr_set(inode, name, value, size, flags, ATTR_ROOT);
 107}
 108
 109static struct xattr_handler xfs_xattr_trusted_handler = {
 110        .prefix = XATTR_TRUSTED_PREFIX,
 111        .get    = xfs_xattr_trusted_get,
 112        .set    = xfs_xattr_trusted_set,
 113};
 114
 115
 116static int
 117xfs_xattr_secure_get(struct inode *inode, const char *name,
 118                void *value, size_t size)
 119{
 120        return __xfs_xattr_get(inode, name, value, size, ATTR_SECURE);
 121}
 122
 123static int
 124xfs_xattr_secure_set(struct inode *inode, const char *name,
 125                const void *value, size_t size, int flags)
 126{
 127        return __xfs_xattr_set(inode, name, value, size, flags, ATTR_SECURE);
 128}
 129
 130static struct xattr_handler xfs_xattr_security_handler = {
 131        .prefix = XATTR_SECURITY_PREFIX,
 132        .get    = xfs_xattr_secure_get,
 133        .set    = xfs_xattr_secure_set,
 134};
 135
 136
 137struct xattr_handler *xfs_xattr_handlers[] = {
 138        &xfs_xattr_user_handler,
 139        &xfs_xattr_trusted_handler,
 140        &xfs_xattr_security_handler,
 141#ifdef CONFIG_XFS_POSIX_ACL
 142        &xfs_xattr_system_handler,
 143#endif
 144        NULL
 145};
 146
 147static unsigned int xfs_xattr_prefix_len(int flags)
 148{
 149        if (flags & XFS_ATTR_SECURE)
 150                return sizeof("security");
 151        else if (flags & XFS_ATTR_ROOT)
 152                return sizeof("trusted");
 153        else
 154                return sizeof("user");
 155}
 156
 157static const char *xfs_xattr_prefix(int flags)
 158{
 159        if (flags & XFS_ATTR_SECURE)
 160                return xfs_xattr_security_handler.prefix;
 161        else if (flags & XFS_ATTR_ROOT)
 162                return xfs_xattr_trusted_handler.prefix;
 163        else
 164                return xfs_xattr_user_handler.prefix;
 165}
 166
 167static int
 168xfs_xattr_put_listent(struct xfs_attr_list_context *context, int flags,
 169                char *name, int namelen, int valuelen, char *value)
 170{
 171        unsigned int prefix_len = xfs_xattr_prefix_len(flags);
 172        char *offset;
 173        int arraytop;
 174
 175        ASSERT(context->count >= 0);
 176
 177        /*
 178         * Only show root namespace entries if we are actually allowed to
 179         * see them.
 180         */
 181        if ((flags & XFS_ATTR_ROOT) && !capable(CAP_SYS_ADMIN))
 182                return 0;
 183
 184        arraytop = context->count + prefix_len + namelen + 1;
 185        if (arraytop > context->firstu) {
 186                context->count = -1;    /* insufficient space */
 187                return 1;
 188        }
 189        offset = (char *)context->alist + context->count;
 190        strncpy(offset, xfs_xattr_prefix(flags), prefix_len);
 191        offset += prefix_len;
 192        strncpy(offset, name, namelen);                 /* real name */
 193        offset += namelen;
 194        *offset = '\0';
 195        context->count += prefix_len + namelen + 1;
 196        return 0;
 197}
 198
 199static int
 200xfs_xattr_put_listent_sizes(struct xfs_attr_list_context *context, int flags,
 201                char *name, int namelen, int valuelen, char *value)
 202{
 203        context->count += xfs_xattr_prefix_len(flags) + namelen + 1;
 204        return 0;
 205}
 206
 207static int
 208list_one_attr(const char *name, const size_t len, void *data,
 209                size_t size, ssize_t *result)
 210{
 211        char *p = data + *result;
 212
 213        *result += len;
 214        if (!size)
 215                return 0;
 216        if (*result > size)
 217                return -ERANGE;
 218
 219        strcpy(p, name);
 220        return 0;
 221}
 222
 223ssize_t
 224xfs_vn_listxattr(struct dentry *dentry, char *data, size_t size)
 225{
 226        struct xfs_attr_list_context context;
 227        struct attrlist_cursor_kern cursor = { 0 };
 228        struct inode            *inode = dentry->d_inode;
 229        int                     error;
 230
 231        /*
 232         * First read the regular on-disk attributes.
 233         */
 234        memset(&context, 0, sizeof(context));
 235        context.dp = XFS_I(inode);
 236        context.cursor = &cursor;
 237        context.resynch = 1;
 238        context.alist = data;
 239        context.bufsize = size;
 240        context.firstu = context.bufsize;
 241
 242        if (size)
 243                context.put_listent = xfs_xattr_put_listent;
 244        else
 245                context.put_listent = xfs_xattr_put_listent_sizes;
 246
 247        xfs_attr_list_int(&context);
 248        if (context.count < 0)
 249                return -ERANGE;
 250
 251        /*
 252         * Then add the two synthetic ACL attributes.
 253         */
 254        if (posix_acl_access_exists(inode)) {
 255                error = list_one_attr(POSIX_ACL_XATTR_ACCESS,
 256                                strlen(POSIX_ACL_XATTR_ACCESS) + 1,
 257                                data, size, &context.count);
 258                if (error)
 259                        return error;
 260        }
 261
 262        if (posix_acl_default_exists(inode)) {
 263                error = list_one_attr(POSIX_ACL_XATTR_DEFAULT,
 264                                strlen(POSIX_ACL_XATTR_DEFAULT) + 1,
 265                                data, size, &context.count);
 266                if (error)
 267                        return error;
 268        }
 269
 270        return context.count;
 271}
 272