linux/fs/reiserfs/xattr_acl.c
<<
>>
Prefs
   1#include <linux/capability.h>
   2#include <linux/fs.h>
   3#include <linux/posix_acl.h>
   4#include <linux/reiserfs_fs.h>
   5#include <linux/errno.h>
   6#include <linux/pagemap.h>
   7#include <linux/xattr.h>
   8#include <linux/posix_acl_xattr.h>
   9#include <linux/reiserfs_xattr.h>
  10#include <linux/reiserfs_acl.h>
  11#include <asm/uaccess.h>
  12
  13static int reiserfs_set_acl(struct reiserfs_transaction_handle *th,
  14                            struct inode *inode, int type,
  15                            struct posix_acl *acl);
  16
  17static int
  18xattr_set_acl(struct inode *inode, int type, const void *value, size_t size)
  19{
  20        struct posix_acl *acl;
  21        int error, error2;
  22        struct reiserfs_transaction_handle th;
  23        size_t jcreate_blocks;
  24        if (!reiserfs_posixacl(inode->i_sb))
  25                return -EOPNOTSUPP;
  26        if (!is_owner_or_cap(inode))
  27                return -EPERM;
  28
  29        if (value) {
  30                acl = posix_acl_from_xattr(value, size);
  31                if (IS_ERR(acl)) {
  32                        return PTR_ERR(acl);
  33                } else if (acl) {
  34                        error = posix_acl_valid(acl);
  35                        if (error)
  36                                goto release_and_out;
  37                }
  38        } else
  39                acl = NULL;
  40
  41        /* Pessimism: We can't assume that anything from the xattr root up
  42         * has been created. */
  43
  44        jcreate_blocks = reiserfs_xattr_jcreate_nblocks(inode) +
  45                         reiserfs_xattr_nblocks(inode, size) * 2;
  46
  47        reiserfs_write_lock(inode->i_sb);
  48        error = journal_begin(&th, inode->i_sb, jcreate_blocks);
  49        if (error == 0) {
  50                error = reiserfs_set_acl(&th, inode, type, acl);
  51                error2 = journal_end(&th, inode->i_sb, jcreate_blocks);
  52                if (error2)
  53                        error = error2;
  54        }
  55        reiserfs_write_unlock(inode->i_sb);
  56
  57      release_and_out:
  58        posix_acl_release(acl);
  59        return error;
  60}
  61
  62static int
  63xattr_get_acl(struct inode *inode, int type, void *buffer, size_t size)
  64{
  65        struct posix_acl *acl;
  66        int error;
  67
  68        if (!reiserfs_posixacl(inode->i_sb))
  69                return -EOPNOTSUPP;
  70
  71        acl = reiserfs_get_acl(inode, type);
  72        if (IS_ERR(acl))
  73                return PTR_ERR(acl);
  74        if (acl == NULL)
  75                return -ENODATA;
  76        error = posix_acl_to_xattr(acl, buffer, size);
  77        posix_acl_release(acl);
  78
  79        return error;
  80}
  81
  82/*
  83 * Convert from filesystem to in-memory representation.
  84 */
  85static struct posix_acl *posix_acl_from_disk(const void *value, size_t size)
  86{
  87        const char *end = (char *)value + size;
  88        int n, count;
  89        struct posix_acl *acl;
  90
  91        if (!value)
  92                return NULL;
  93        if (size < sizeof(reiserfs_acl_header))
  94                return ERR_PTR(-EINVAL);
  95        if (((reiserfs_acl_header *) value)->a_version !=
  96            cpu_to_le32(REISERFS_ACL_VERSION))
  97                return ERR_PTR(-EINVAL);
  98        value = (char *)value + sizeof(reiserfs_acl_header);
  99        count = reiserfs_acl_count(size);
 100        if (count < 0)
 101                return ERR_PTR(-EINVAL);
 102        if (count == 0)
 103                return NULL;
 104        acl = posix_acl_alloc(count, GFP_NOFS);
 105        if (!acl)
 106                return ERR_PTR(-ENOMEM);
 107        for (n = 0; n < count; n++) {
 108                reiserfs_acl_entry *entry = (reiserfs_acl_entry *) value;
 109                if ((char *)value + sizeof(reiserfs_acl_entry_short) > end)
 110                        goto fail;
 111                acl->a_entries[n].e_tag = le16_to_cpu(entry->e_tag);
 112                acl->a_entries[n].e_perm = le16_to_cpu(entry->e_perm);
 113                switch (acl->a_entries[n].e_tag) {
 114                case ACL_USER_OBJ:
 115                case ACL_GROUP_OBJ:
 116                case ACL_MASK:
 117                case ACL_OTHER:
 118                        value = (char *)value +
 119                            sizeof(reiserfs_acl_entry_short);
 120                        acl->a_entries[n].e_id = ACL_UNDEFINED_ID;
 121                        break;
 122
 123                case ACL_USER:
 124                case ACL_GROUP:
 125                        value = (char *)value + sizeof(reiserfs_acl_entry);
 126                        if ((char *)value > end)
 127                                goto fail;
 128                        acl->a_entries[n].e_id = le32_to_cpu(entry->e_id);
 129                        break;
 130
 131                default:
 132                        goto fail;
 133                }
 134        }
 135        if (value != end)
 136                goto fail;
 137        return acl;
 138
 139      fail:
 140        posix_acl_release(acl);
 141        return ERR_PTR(-EINVAL);
 142}
 143
 144/*
 145 * Convert from in-memory to filesystem representation.
 146 */
 147static void *posix_acl_to_disk(const struct posix_acl *acl, size_t * size)
 148{
 149        reiserfs_acl_header *ext_acl;
 150        char *e;
 151        int n;
 152
 153        *size = reiserfs_acl_size(acl->a_count);
 154        ext_acl = kmalloc(sizeof(reiserfs_acl_header) +
 155                                                  acl->a_count *
 156                                                  sizeof(reiserfs_acl_entry),
 157                                                  GFP_NOFS);
 158        if (!ext_acl)
 159                return ERR_PTR(-ENOMEM);
 160        ext_acl->a_version = cpu_to_le32(REISERFS_ACL_VERSION);
 161        e = (char *)ext_acl + sizeof(reiserfs_acl_header);
 162        for (n = 0; n < acl->a_count; n++) {
 163                reiserfs_acl_entry *entry = (reiserfs_acl_entry *) e;
 164                entry->e_tag = cpu_to_le16(acl->a_entries[n].e_tag);
 165                entry->e_perm = cpu_to_le16(acl->a_entries[n].e_perm);
 166                switch (acl->a_entries[n].e_tag) {
 167                case ACL_USER:
 168                case ACL_GROUP:
 169                        entry->e_id = cpu_to_le32(acl->a_entries[n].e_id);
 170                        e += sizeof(reiserfs_acl_entry);
 171                        break;
 172
 173                case ACL_USER_OBJ:
 174                case ACL_GROUP_OBJ:
 175                case ACL_MASK:
 176                case ACL_OTHER:
 177                        e += sizeof(reiserfs_acl_entry_short);
 178                        break;
 179
 180                default:
 181                        goto fail;
 182                }
 183        }
 184        return (char *)ext_acl;
 185
 186      fail:
 187        kfree(ext_acl);
 188        return ERR_PTR(-EINVAL);
 189}
 190
 191/*
 192 * Inode operation get_posix_acl().
 193 *
 194 * inode->i_mutex: down
 195 * BKL held [before 2.5.x]
 196 */
 197struct posix_acl *reiserfs_get_acl(struct inode *inode, int type)
 198{
 199        char *name, *value;
 200        struct posix_acl *acl;
 201        int size;
 202        int retval;
 203
 204        acl = get_cached_acl(inode, type);
 205        if (acl != ACL_NOT_CACHED)
 206                return acl;
 207
 208        switch (type) {
 209        case ACL_TYPE_ACCESS:
 210                name = POSIX_ACL_XATTR_ACCESS;
 211                break;
 212        case ACL_TYPE_DEFAULT:
 213                name = POSIX_ACL_XATTR_DEFAULT;
 214                break;
 215        default:
 216                BUG();
 217        }
 218
 219        size = reiserfs_xattr_get(inode, name, NULL, 0);
 220        if (size < 0) {
 221                if (size == -ENODATA || size == -ENOSYS) {
 222                        set_cached_acl(inode, type, NULL);
 223                        return NULL;
 224                }
 225                return ERR_PTR(size);
 226        }
 227
 228        value = kmalloc(size, GFP_NOFS);
 229        if (!value)
 230                return ERR_PTR(-ENOMEM);
 231
 232        retval = reiserfs_xattr_get(inode, name, value, size);
 233        if (retval == -ENODATA || retval == -ENOSYS) {
 234                /* This shouldn't actually happen as it should have
 235                   been caught above.. but just in case */
 236                acl = NULL;
 237        } else if (retval < 0) {
 238                acl = ERR_PTR(retval);
 239        } else {
 240                acl = posix_acl_from_disk(value, retval);
 241        }
 242        if (!IS_ERR(acl))
 243                set_cached_acl(inode, type, acl);
 244
 245        kfree(value);
 246        return acl;
 247}
 248
 249/*
 250 * Inode operation set_posix_acl().
 251 *
 252 * inode->i_mutex: down
 253 * BKL held [before 2.5.x]
 254 */
 255static int
 256reiserfs_set_acl(struct reiserfs_transaction_handle *th, struct inode *inode,
 257                 int type, struct posix_acl *acl)
 258{
 259        char *name;
 260        void *value = NULL;
 261        size_t size = 0;
 262        int error;
 263
 264        if (S_ISLNK(inode->i_mode))
 265                return -EOPNOTSUPP;
 266
 267        switch (type) {
 268        case ACL_TYPE_ACCESS:
 269                name = POSIX_ACL_XATTR_ACCESS;
 270                if (acl) {
 271                        mode_t mode = inode->i_mode;
 272                        error = posix_acl_equiv_mode(acl, &mode);
 273                        if (error < 0)
 274                                return error;
 275                        else {
 276                                inode->i_mode = mode;
 277                                if (error == 0)
 278                                        acl = NULL;
 279                        }
 280                }
 281                break;
 282        case ACL_TYPE_DEFAULT:
 283                name = POSIX_ACL_XATTR_DEFAULT;
 284                if (!S_ISDIR(inode->i_mode))
 285                        return acl ? -EACCES : 0;
 286                break;
 287        default:
 288                return -EINVAL;
 289        }
 290
 291        if (acl) {
 292                value = posix_acl_to_disk(acl, &size);
 293                if (IS_ERR(value))
 294                        return (int)PTR_ERR(value);
 295        }
 296
 297        error = reiserfs_xattr_set_handle(th, inode, name, value, size, 0);
 298
 299        /*
 300         * Ensure that the inode gets dirtied if we're only using
 301         * the mode bits and an old ACL didn't exist. We don't need
 302         * to check if the inode is hashed here since we won't get
 303         * called by reiserfs_inherit_default_acl().
 304         */
 305        if (error == -ENODATA) {
 306                error = 0;
 307                if (type == ACL_TYPE_ACCESS) {
 308                        inode->i_ctime = CURRENT_TIME_SEC;
 309                        mark_inode_dirty(inode);
 310                }
 311        }
 312
 313        kfree(value);
 314
 315        if (!error)
 316                set_cached_acl(inode, type, acl);
 317
 318        return error;
 319}
 320
 321/* dir->i_mutex: locked,
 322 * inode is new and not released into the wild yet */
 323int
 324reiserfs_inherit_default_acl(struct reiserfs_transaction_handle *th,
 325                             struct inode *dir, struct dentry *dentry,
 326                             struct inode *inode)
 327{
 328        struct posix_acl *acl;
 329        int err = 0;
 330
 331        /* ACLs only get applied to files and directories */
 332        if (S_ISLNK(inode->i_mode))
 333                return 0;
 334
 335        /* ACLs can only be used on "new" objects, so if it's an old object
 336         * there is nothing to inherit from */
 337        if (get_inode_sd_version(dir) == STAT_DATA_V1)
 338                goto apply_umask;
 339
 340        /* Don't apply ACLs to objects in the .reiserfs_priv tree.. This
 341         * would be useless since permissions are ignored, and a pain because
 342         * it introduces locking cycles */
 343        if (IS_PRIVATE(dir)) {
 344                inode->i_flags |= S_PRIVATE;
 345                goto apply_umask;
 346        }
 347
 348        acl = reiserfs_get_acl(dir, ACL_TYPE_DEFAULT);
 349        if (IS_ERR(acl))
 350                return PTR_ERR(acl);
 351
 352        if (acl) {
 353                struct posix_acl *acl_copy;
 354                mode_t mode = inode->i_mode;
 355                int need_acl;
 356
 357                /* Copy the default ACL to the default ACL of a new directory */
 358                if (S_ISDIR(inode->i_mode)) {
 359                        err = reiserfs_set_acl(th, inode, ACL_TYPE_DEFAULT,
 360                                               acl);
 361                        if (err)
 362                                goto cleanup;
 363                }
 364
 365                /* Now we reconcile the new ACL and the mode,
 366                   potentially modifying both */
 367                acl_copy = posix_acl_clone(acl, GFP_NOFS);
 368                if (!acl_copy) {
 369                        err = -ENOMEM;
 370                        goto cleanup;
 371                }
 372
 373                need_acl = posix_acl_create_masq(acl_copy, &mode);
 374                if (need_acl >= 0) {
 375                        if (mode != inode->i_mode) {
 376                                inode->i_mode = mode;
 377                        }
 378
 379                        /* If we need an ACL.. */
 380                        if (need_acl > 0) {
 381                                err = reiserfs_set_acl(th, inode,
 382                                                       ACL_TYPE_ACCESS,
 383                                                       acl_copy);
 384                                if (err)
 385                                        goto cleanup_copy;
 386                        }
 387                }
 388              cleanup_copy:
 389                posix_acl_release(acl_copy);
 390              cleanup:
 391                posix_acl_release(acl);
 392        } else {
 393              apply_umask:
 394                /* no ACL, apply umask */
 395                inode->i_mode &= ~current_umask();
 396        }
 397
 398        return err;
 399}
 400
 401/* This is used to cache the default acl before a new object is created.
 402 * The biggest reason for this is to get an idea of how many blocks will
 403 * actually be required for the create operation if we must inherit an ACL.
 404 * An ACL write can add up to 3 object creations and an additional file write
 405 * so we'd prefer not to reserve that many blocks in the journal if we can.
 406 * It also has the advantage of not loading the ACL with a transaction open,
 407 * this may seem silly, but if the owner of the directory is doing the
 408 * creation, the ACL may not be loaded since the permissions wouldn't require
 409 * it.
 410 * We return the number of blocks required for the transaction.
 411 */
 412int reiserfs_cache_default_acl(struct inode *inode)
 413{
 414        struct posix_acl *acl;
 415        int nblocks = 0;
 416
 417        if (IS_PRIVATE(inode))
 418                return 0;
 419
 420        acl = reiserfs_get_acl(inode, ACL_TYPE_DEFAULT);
 421
 422        if (acl && !IS_ERR(acl)) {
 423                int size = reiserfs_acl_size(acl->a_count);
 424
 425                /* Other xattrs can be created during inode creation. We don't
 426                 * want to claim too many blocks, so we check to see if we
 427                 * we need to create the tree to the xattrs, and then we
 428                 * just want two files. */
 429                nblocks = reiserfs_xattr_jcreate_nblocks(inode);
 430                nblocks += JOURNAL_BLOCKS_PER_OBJECT(inode->i_sb);
 431
 432                REISERFS_I(inode)->i_flags |= i_has_xattr_dir;
 433
 434                /* We need to account for writes + bitmaps for two files */
 435                nblocks += reiserfs_xattr_nblocks(inode, size) * 4;
 436                posix_acl_release(acl);
 437        }
 438
 439        return nblocks;
 440}
 441
 442int reiserfs_acl_chmod(struct inode *inode)
 443{
 444        struct posix_acl *acl, *clone;
 445        int error;
 446
 447        if (S_ISLNK(inode->i_mode))
 448                return -EOPNOTSUPP;
 449
 450        if (get_inode_sd_version(inode) == STAT_DATA_V1 ||
 451            !reiserfs_posixacl(inode->i_sb)) {
 452                return 0;
 453        }
 454
 455        acl = reiserfs_get_acl(inode, ACL_TYPE_ACCESS);
 456        if (!acl)
 457                return 0;
 458        if (IS_ERR(acl))
 459                return PTR_ERR(acl);
 460        clone = posix_acl_clone(acl, GFP_NOFS);
 461        posix_acl_release(acl);
 462        if (!clone)
 463                return -ENOMEM;
 464        error = posix_acl_chmod_masq(clone, inode->i_mode);
 465        if (!error) {
 466                struct reiserfs_transaction_handle th;
 467                size_t size = reiserfs_xattr_nblocks(inode,
 468                                             reiserfs_acl_size(clone->a_count));
 469                reiserfs_write_lock(inode->i_sb);
 470                error = journal_begin(&th, inode->i_sb, size * 2);
 471                if (!error) {
 472                        int error2;
 473                        error = reiserfs_set_acl(&th, inode, ACL_TYPE_ACCESS,
 474                                                 clone);
 475                        error2 = journal_end(&th, inode->i_sb, size * 2);
 476                        if (error2)
 477                                error = error2;
 478                }
 479                reiserfs_write_unlock(inode->i_sb);
 480        }
 481        posix_acl_release(clone);
 482        return error;
 483}
 484
 485static int
 486posix_acl_access_get(struct inode *inode, const char *name,
 487                     void *buffer, size_t size)
 488{
 489        if (strlen(name) != sizeof(POSIX_ACL_XATTR_ACCESS) - 1)
 490                return -EINVAL;
 491        return xattr_get_acl(inode, ACL_TYPE_ACCESS, buffer, size);
 492}
 493
 494static int
 495posix_acl_access_set(struct inode *inode, const char *name,
 496                     const void *value, size_t size, int flags)
 497{
 498        if (strlen(name) != sizeof(POSIX_ACL_XATTR_ACCESS) - 1)
 499                return -EINVAL;
 500        return xattr_set_acl(inode, ACL_TYPE_ACCESS, value, size);
 501}
 502
 503static size_t posix_acl_access_list(struct inode *inode, char *list,
 504                                    size_t list_size, const char *name,
 505                                    size_t name_len)
 506{
 507        const size_t size = sizeof(POSIX_ACL_XATTR_ACCESS);
 508        if (!reiserfs_posixacl(inode->i_sb))
 509                return 0;
 510        if (list && size <= list_size)
 511                memcpy(list, POSIX_ACL_XATTR_ACCESS, size);
 512        return size;
 513}
 514
 515struct xattr_handler reiserfs_posix_acl_access_handler = {
 516        .prefix = POSIX_ACL_XATTR_ACCESS,
 517        .get = posix_acl_access_get,
 518        .set = posix_acl_access_set,
 519        .list = posix_acl_access_list,
 520};
 521
 522static int
 523posix_acl_default_get(struct inode *inode, const char *name,
 524                      void *buffer, size_t size)
 525{
 526        if (strlen(name) != sizeof(POSIX_ACL_XATTR_DEFAULT) - 1)
 527                return -EINVAL;
 528        return xattr_get_acl(inode, ACL_TYPE_DEFAULT, buffer, size);
 529}
 530
 531static int
 532posix_acl_default_set(struct inode *inode, const char *name,
 533                      const void *value, size_t size, int flags)
 534{
 535        if (strlen(name) != sizeof(POSIX_ACL_XATTR_DEFAULT) - 1)
 536                return -EINVAL;
 537        return xattr_set_acl(inode, ACL_TYPE_DEFAULT, value, size);
 538}
 539
 540static size_t posix_acl_default_list(struct inode *inode, char *list,
 541                                     size_t list_size, const char *name,
 542                                     size_t name_len)
 543{
 544        const size_t size = sizeof(POSIX_ACL_XATTR_DEFAULT);
 545        if (!reiserfs_posixacl(inode->i_sb))
 546                return 0;
 547        if (list && size <= list_size)
 548                memcpy(list, POSIX_ACL_XATTR_DEFAULT, size);
 549        return size;
 550}
 551
 552struct xattr_handler reiserfs_posix_acl_default_handler = {
 553        .prefix = POSIX_ACL_XATTR_DEFAULT,
 554        .get = posix_acl_default_get,
 555        .set = posix_acl_default_set,
 556        .list = posix_acl_default_list,
 557};
 558