linux/fs/btrfs/xattr.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2007 Red Hat.  All rights reserved.
   3 *
   4 * This program is free software; you can redistribute it and/or
   5 * modify it under the terms of the GNU General Public
   6 * License v2 as published by the Free Software Foundation.
   7 *
   8 * This program is distributed in the hope that it will be useful,
   9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  11 * General Public License for more details.
  12 *
  13 * You should have received a copy of the GNU General Public
  14 * License along with this program; if not, write to the
  15 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  16 * Boston, MA 021110-1307, USA.
  17 */
  18
  19#include <linux/init.h>
  20#include <linux/fs.h>
  21#include <linux/slab.h>
  22#include <linux/rwsem.h>
  23#include <linux/xattr.h>
  24#include <linux/security.h>
  25#include "ctree.h"
  26#include "btrfs_inode.h"
  27#include "transaction.h"
  28#include "xattr.h"
  29#include "disk-io.h"
  30
  31
  32ssize_t __btrfs_getxattr(struct inode *inode, const char *name,
  33                                void *buffer, size_t size)
  34{
  35        struct btrfs_dir_item *di;
  36        struct btrfs_root *root = BTRFS_I(inode)->root;
  37        struct btrfs_path *path;
  38        struct extent_buffer *leaf;
  39        int ret = 0;
  40        unsigned long data_ptr;
  41
  42        path = btrfs_alloc_path();
  43        if (!path)
  44                return -ENOMEM;
  45
  46        /* lookup the xattr by name */
  47        di = btrfs_lookup_xattr(NULL, root, path, btrfs_ino(inode), name,
  48                                strlen(name), 0);
  49        if (!di) {
  50                ret = -ENODATA;
  51                goto out;
  52        } else if (IS_ERR(di)) {
  53                ret = PTR_ERR(di);
  54                goto out;
  55        }
  56
  57        leaf = path->nodes[0];
  58        /* if size is 0, that means we want the size of the attr */
  59        if (!size) {
  60                ret = btrfs_dir_data_len(leaf, di);
  61                goto out;
  62        }
  63
  64        /* now get the data out of our dir_item */
  65        if (btrfs_dir_data_len(leaf, di) > size) {
  66                ret = -ERANGE;
  67                goto out;
  68        }
  69
  70        /*
  71         * The way things are packed into the leaf is like this
  72         * |struct btrfs_dir_item|name|data|
  73         * where name is the xattr name, so security.foo, and data is the
  74         * content of the xattr.  data_ptr points to the location in memory
  75         * where the data starts in the in memory leaf
  76         */
  77        data_ptr = (unsigned long)((char *)(di + 1) +
  78                                   btrfs_dir_name_len(leaf, di));
  79        read_extent_buffer(leaf, buffer, data_ptr,
  80                           btrfs_dir_data_len(leaf, di));
  81        ret = btrfs_dir_data_len(leaf, di);
  82
  83out:
  84        btrfs_free_path(path);
  85        return ret;
  86}
  87
  88static int do_setxattr(struct btrfs_trans_handle *trans,
  89                       struct inode *inode, const char *name,
  90                       const void *value, size_t size, int flags)
  91{
  92        struct btrfs_dir_item *di;
  93        struct btrfs_root *root = BTRFS_I(inode)->root;
  94        struct btrfs_path *path;
  95        size_t name_len = strlen(name);
  96        int ret = 0;
  97
  98        if (name_len + size > BTRFS_MAX_XATTR_SIZE(root))
  99                return -ENOSPC;
 100
 101        path = btrfs_alloc_path();
 102        if (!path)
 103                return -ENOMEM;
 104
 105        if (flags & XATTR_REPLACE) {
 106                di = btrfs_lookup_xattr(trans, root, path, btrfs_ino(inode), name,
 107                                        name_len, -1);
 108                if (IS_ERR(di)) {
 109                        ret = PTR_ERR(di);
 110                        goto out;
 111                } else if (!di) {
 112                        ret = -ENODATA;
 113                        goto out;
 114                }
 115                ret = btrfs_delete_one_dir_name(trans, root, path, di);
 116                if (ret)
 117                        goto out;
 118                btrfs_release_path(path);
 119
 120                /*
 121                 * remove the attribute
 122                 */
 123                if (!value)
 124                        goto out;
 125        }
 126
 127again:
 128        ret = btrfs_insert_xattr_item(trans, root, path, btrfs_ino(inode),
 129                                      name, name_len, value, size);
 130        /*
 131         * If we're setting an xattr to a new value but the new value is say
 132         * exactly BTRFS_MAX_XATTR_SIZE, we could end up with EOVERFLOW getting
 133         * back from split_leaf.  This is because it thinks we'll be extending
 134         * the existing item size, but we're asking for enough space to add the
 135         * item itself.  So if we get EOVERFLOW just set ret to EEXIST and let
 136         * the rest of the function figure it out.
 137         */
 138        if (ret == -EOVERFLOW)
 139                ret = -EEXIST;
 140
 141        if (ret == -EEXIST) {
 142                if (flags & XATTR_CREATE)
 143                        goto out;
 144                /*
 145                 * We can't use the path we already have since we won't have the
 146                 * proper locking for a delete, so release the path and
 147                 * re-lookup to delete the thing.
 148                 */
 149                btrfs_release_path(path);
 150                di = btrfs_lookup_xattr(trans, root, path, btrfs_ino(inode),
 151                                        name, name_len, -1);
 152                if (IS_ERR(di)) {
 153                        ret = PTR_ERR(di);
 154                        goto out;
 155                } else if (!di) {
 156                        /* Shouldn't happen but just in case... */
 157                        btrfs_release_path(path);
 158                        goto again;
 159                }
 160
 161                ret = btrfs_delete_one_dir_name(trans, root, path, di);
 162                if (ret)
 163                        goto out;
 164
 165                /*
 166                 * We have a value to set, so go back and try to insert it now.
 167                 */
 168                if (value) {
 169                        btrfs_release_path(path);
 170                        goto again;
 171                }
 172        }
 173out:
 174        btrfs_free_path(path);
 175        return ret;
 176}
 177
 178/*
 179 * @value: "" makes the attribute to empty, NULL removes it
 180 */
 181int __btrfs_setxattr(struct btrfs_trans_handle *trans,
 182                     struct inode *inode, const char *name,
 183                     const void *value, size_t size, int flags)
 184{
 185        struct btrfs_root *root = BTRFS_I(inode)->root;
 186        int ret;
 187
 188        if (trans)
 189                return do_setxattr(trans, inode, name, value, size, flags);
 190
 191        trans = btrfs_start_transaction(root, 2);
 192        if (IS_ERR(trans))
 193                return PTR_ERR(trans);
 194
 195        ret = do_setxattr(trans, inode, name, value, size, flags);
 196        if (ret)
 197                goto out;
 198
 199        inode_inc_iversion(inode);
 200        inode->i_ctime = CURRENT_TIME;
 201        ret = btrfs_update_inode(trans, root, inode);
 202        BUG_ON(ret);
 203out:
 204        btrfs_end_transaction(trans, root);
 205        return ret;
 206}
 207
 208ssize_t btrfs_listxattr(struct dentry *dentry, char *buffer, size_t size)
 209{
 210        struct btrfs_key key, found_key;
 211        struct inode *inode = dentry->d_inode;
 212        struct btrfs_root *root = BTRFS_I(inode)->root;
 213        struct btrfs_path *path;
 214        struct extent_buffer *leaf;
 215        struct btrfs_dir_item *di;
 216        int ret = 0, slot;
 217        size_t total_size = 0, size_left = size;
 218        unsigned long name_ptr;
 219        size_t name_len;
 220
 221        /*
 222         * ok we want all objects associated with this id.
 223         * NOTE: we set key.offset = 0; because we want to start with the
 224         * first xattr that we find and walk forward
 225         */
 226        key.objectid = btrfs_ino(inode);
 227        btrfs_set_key_type(&key, BTRFS_XATTR_ITEM_KEY);
 228        key.offset = 0;
 229
 230        path = btrfs_alloc_path();
 231        if (!path)
 232                return -ENOMEM;
 233        path->reada = 2;
 234
 235        /* search for our xattrs */
 236        ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
 237        if (ret < 0)
 238                goto err;
 239
 240        while (1) {
 241                leaf = path->nodes[0];
 242                slot = path->slots[0];
 243
 244                /* this is where we start walking through the path */
 245                if (slot >= btrfs_header_nritems(leaf)) {
 246                        /*
 247                         * if we've reached the last slot in this leaf we need
 248                         * to go to the next leaf and reset everything
 249                         */
 250                        ret = btrfs_next_leaf(root, path);
 251                        if (ret < 0)
 252                                goto err;
 253                        else if (ret > 0)
 254                                break;
 255                        continue;
 256                }
 257
 258                btrfs_item_key_to_cpu(leaf, &found_key, slot);
 259
 260                /* check to make sure this item is what we want */
 261                if (found_key.objectid != key.objectid)
 262                        break;
 263                if (btrfs_key_type(&found_key) != BTRFS_XATTR_ITEM_KEY)
 264                        break;
 265
 266                di = btrfs_item_ptr(leaf, slot, struct btrfs_dir_item);
 267                if (verify_dir_item(root, leaf, di))
 268                        continue;
 269
 270                name_len = btrfs_dir_name_len(leaf, di);
 271                total_size += name_len + 1;
 272
 273                /* we are just looking for how big our buffer needs to be */
 274                if (!size)
 275                        goto next;
 276
 277                if (!buffer || (name_len + 1) > size_left) {
 278                        ret = -ERANGE;
 279                        goto err;
 280                }
 281
 282                name_ptr = (unsigned long)(di + 1);
 283                read_extent_buffer(leaf, buffer, name_ptr, name_len);
 284                buffer[name_len] = '\0';
 285
 286                size_left -= name_len + 1;
 287                buffer += name_len + 1;
 288next:
 289                path->slots[0]++;
 290        }
 291        ret = total_size;
 292
 293err:
 294        btrfs_free_path(path);
 295
 296        return ret;
 297}
 298
 299/*
 300 * List of handlers for synthetic system.* attributes.  All real ondisk
 301 * attributes are handled directly.
 302 */
 303const struct xattr_handler *btrfs_xattr_handlers[] = {
 304#ifdef CONFIG_BTRFS_FS_POSIX_ACL
 305        &btrfs_xattr_acl_access_handler,
 306        &btrfs_xattr_acl_default_handler,
 307#endif
 308        NULL,
 309};
 310
 311/*
 312 * Check if the attribute is in a supported namespace.
 313 *
 314 * This applied after the check for the synthetic attributes in the system
 315 * namespace.
 316 */
 317static bool btrfs_is_valid_xattr(const char *name)
 318{
 319        return !strncmp(name, XATTR_SECURITY_PREFIX,
 320                        XATTR_SECURITY_PREFIX_LEN) ||
 321               !strncmp(name, XATTR_SYSTEM_PREFIX, XATTR_SYSTEM_PREFIX_LEN) ||
 322               !strncmp(name, XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN) ||
 323               !strncmp(name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN);
 324}
 325
 326ssize_t btrfs_getxattr(struct dentry *dentry, const char *name,
 327                       void *buffer, size_t size)
 328{
 329        /*
 330         * If this is a request for a synthetic attribute in the system.*
 331         * namespace use the generic infrastructure to resolve a handler
 332         * for it via sb->s_xattr.
 333         */
 334        if (!strncmp(name, XATTR_SYSTEM_PREFIX, XATTR_SYSTEM_PREFIX_LEN))
 335                return generic_getxattr(dentry, name, buffer, size);
 336
 337        if (!btrfs_is_valid_xattr(name))
 338                return -EOPNOTSUPP;
 339        return __btrfs_getxattr(dentry->d_inode, name, buffer, size);
 340}
 341
 342int btrfs_setxattr(struct dentry *dentry, const char *name, const void *value,
 343                   size_t size, int flags)
 344{
 345        struct btrfs_root *root = BTRFS_I(dentry->d_inode)->root;
 346
 347        /*
 348         * The permission on security.* and system.* is not checked
 349         * in permission().
 350         */
 351        if (btrfs_root_readonly(root))
 352                return -EROFS;
 353
 354        /*
 355         * If this is a request for a synthetic attribute in the system.*
 356         * namespace use the generic infrastructure to resolve a handler
 357         * for it via sb->s_xattr.
 358         */
 359        if (!strncmp(name, XATTR_SYSTEM_PREFIX, XATTR_SYSTEM_PREFIX_LEN))
 360                return generic_setxattr(dentry, name, value, size, flags);
 361
 362        if (!btrfs_is_valid_xattr(name))
 363                return -EOPNOTSUPP;
 364
 365        if (size == 0)
 366                value = "";  /* empty EA, do not remove */
 367
 368        return __btrfs_setxattr(NULL, dentry->d_inode, name, value, size,
 369                                flags);
 370}
 371
 372int btrfs_removexattr(struct dentry *dentry, const char *name)
 373{
 374        struct btrfs_root *root = BTRFS_I(dentry->d_inode)->root;
 375
 376        /*
 377         * The permission on security.* and system.* is not checked
 378         * in permission().
 379         */
 380        if (btrfs_root_readonly(root))
 381                return -EROFS;
 382
 383        /*
 384         * If this is a request for a synthetic attribute in the system.*
 385         * namespace use the generic infrastructure to resolve a handler
 386         * for it via sb->s_xattr.
 387         */
 388        if (!strncmp(name, XATTR_SYSTEM_PREFIX, XATTR_SYSTEM_PREFIX_LEN))
 389                return generic_removexattr(dentry, name);
 390
 391        if (!btrfs_is_valid_xattr(name))
 392                return -EOPNOTSUPP;
 393
 394        return __btrfs_setxattr(NULL, dentry->d_inode, name, NULL, 0,
 395                                XATTR_REPLACE);
 396}
 397
 398int btrfs_initxattrs(struct inode *inode, const struct xattr *xattr_array,
 399                     void *fs_info)
 400{
 401        const struct xattr *xattr;
 402        struct btrfs_trans_handle *trans = fs_info;
 403        char *name;
 404        int err = 0;
 405
 406        for (xattr = xattr_array; xattr->name != NULL; xattr++) {
 407                name = kmalloc(XATTR_SECURITY_PREFIX_LEN +
 408                               strlen(xattr->name) + 1, GFP_NOFS);
 409                if (!name) {
 410                        err = -ENOMEM;
 411                        break;
 412                }
 413                strcpy(name, XATTR_SECURITY_PREFIX);
 414                strcpy(name + XATTR_SECURITY_PREFIX_LEN, xattr->name);
 415                err = __btrfs_setxattr(trans, inode, name,
 416                                       xattr->value, xattr->value_len, 0);
 417                kfree(name);
 418                if (err < 0)
 419                        break;
 420        }
 421        return err;
 422}
 423
 424int btrfs_xattr_security_init(struct btrfs_trans_handle *trans,
 425                              struct inode *inode, struct inode *dir,
 426                              const struct qstr *qstr)
 427{
 428        return security_inode_init_security(inode, dir, qstr,
 429                                            &btrfs_initxattrs, trans);
 430}
 431
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.