CTC++ Coverage Report - Execution Profile    #901/1532

Files Summary | Functions Summary | Execution Profile | Index | No Index
First | Previous | Next | Last


File: fs/ext3/acl.c
Instrumentation mode: function-decision-multicondition
TER: 9 % ( 26/303)

Start/ End/    
True False - Line Source

  1 /*
  2  * linux/fs/ext3/acl.c
  3  *
  4  * Copyright (C) 2001-2003 Andreas Gruenbacher, <agruen@suse.de>
  5  */
  6 
  7 #include <linux/init.h>
  8 #include <linux/sched.h>
  9 #include <linux/slab.h>
  10 #include <linux/capability.h>
  11 #include <linux/fs.h>
  12 #include <linux/ext3_jbd.h>
  13 #include <linux/ext3_fs.h>
  14 #include "xattr.h"
  15 #include "acl.h"
  16 
  17 /*
  18  * Convert from filesystem to in-memory representation.
  19  */
  20 static struct posix_acl *
 
- 21 ext3_acl_from_disk(const void *value, size_t size)
  22 {
  23    const char *end = (char *)value + size;
  24    int n, count;
  25    struct posix_acl *acl;
  26 
- 27    if (!value)
 - 28       return NULL;
- 29    if (size < sizeof(ext3_acl_header))
 - 30        return ERR_PTR(-EINVAL);
  31    if (((ext3_acl_header *)value)->a_version !=
- 32        cpu_to_le32(EXT3_ACL_VERSION))
 - 33       return ERR_PTR(-EINVAL);
  34    value = (char *)value + sizeof(ext3_acl_header);
  35    count = ext3_acl_count(size);
- 36    if (count < 0)
 - 37       return ERR_PTR(-EINVAL);
- 38    if (count == 0)
 - 39       return NULL;
  40    acl = posix_acl_alloc(count, GFP_KERNEL);
- 41    if (!acl)
 - 42       return ERR_PTR(-ENOMEM);
- 43    for (n=0; n < count; n++) {
  44       ext3_acl_entry *entry =
  45          (ext3_acl_entry *)value;
- 46       if ((char *)value + sizeof(ext3_acl_entry_short) > end)
 - 47          goto fail;
  48       acl->a_entries[n].e_tag  = le16_to_cpu(entry->e_tag);
  49       acl->a_entries[n].e_perm = le16_to_cpu(entry->e_perm);
    50       switch(acl->a_entries[n].e_tag) {
 - 51          case ACL_USER_OBJ:
 - 52          case ACL_GROUP_OBJ:
 - 53          case ACL_MASK:
 - 54          case ACL_OTHER:
  55             value = (char *)value +
  56                sizeof(ext3_acl_entry_short);
  57             acl->a_entries[n].e_id = ACL_UNDEFINED_ID;
 - 58             break;
  59 
 - 60          case ACL_USER:
 - 61          case ACL_GROUP:
  62             value = (char *)value + sizeof(ext3_acl_entry);
- 63             if ((char *)value > end)
 - 64                goto fail;
  65             acl->a_entries[n].e_id =
  66                le32_to_cpu(entry->e_id);
 - 67             break;
  68 
 - 69          default:
 - 70             goto fail;
  71       }
  72    }
- 73    if (value != end)
 - 74       goto fail;
 - 75    return acl;
  76 
  77 fail:
  78    posix_acl_release(acl);
 - 79    return ERR_PTR(-EINVAL);
  80 }
  81 
  82 /*
  83  * Convert from in-memory to filesystem representation.
  84  */
  85 static void *
 
- 86 ext3_acl_to_disk(const struct posix_acl *acl, size_t *size)
  87 {
  88    ext3_acl_header *ext_acl;
  89    char *e;
  90    size_t n;
  91 
  92    *size = ext3_acl_size(acl->a_count);
  93    ext_acl = (ext3_acl_header *)kmalloc(sizeof(ext3_acl_header) +
  94       acl->a_count * sizeof(ext3_acl_entry), GFP_KERNEL);
- 95    if (!ext_acl)
 - 96       return ERR_PTR(-ENOMEM);
  97    ext_acl->a_version = cpu_to_le32(EXT3_ACL_VERSION);
  98    e = (char *)ext_acl + sizeof(ext3_acl_header);
- 99    for (n=0; n < acl->a_count; n++) {
  100       ext3_acl_entry *entry = (ext3_acl_entry *)e;
  101       entry->e_tag  = cpu_to_le16(acl->a_entries[n].e_tag);
  102       entry->e_perm = cpu_to_le16(acl->a_entries[n].e_perm);
    103       switch(acl->a_entries[n].e_tag) {
 - 104          case ACL_USER:
 - 105          case ACL_GROUP:
  106             entry->e_id =
  107                cpu_to_le32(acl->a_entries[n].e_id);
  108             e += sizeof(ext3_acl_entry);
 - 109             break;
  110 
 - 111          case ACL_USER_OBJ:
 - 112          case ACL_GROUP_OBJ:
 - 113          case ACL_MASK:
 - 114          case ACL_OTHER:
  115             e += sizeof(ext3_acl_entry_short);
 - 116             break;
  117 
 - 118          default:
 - 119             goto fail;
  120       }
  121    }
 - 122    return (char *)ext_acl;
  123 
  124 fail:
  125    kfree(ext_acl);
 - 126    return ERR_PTR(-EINVAL);
  127 }
  128 
  129 static inline struct posix_acl *
 
- 130 ext3_iget_acl(struct inode *inode, struct posix_acl **i_acl)
  131 {
  132    struct posix_acl *acl = EXT3_ACL_NOT_CACHED;
  133 
    134    spin_lock(&inode->i_lock);
    134   do
- 134   do-while (0)
- 134 do-while (0)
- 135    if (*i_acl != EXT3_ACL_NOT_CACHED)
  136       acl = posix_acl_dup(*i_acl);
    137    spin_unlock(&inode->i_lock);
    137   do
- 137   do-while (0)
- 137 do-while (0)
  138 
 - 139    return acl;
  140 }
  141 
  142 static inline void
 
- 143 ext3_iset_acl(struct inode *inode, struct posix_acl **i_acl,
  144                   struct posix_acl *acl)
  145 {
    146    spin_lock(&inode->i_lock);
    146   do
- 146   do-while (0)
- 146 do-while (0)
- 147    if (*i_acl != EXT3_ACL_NOT_CACHED)
  148       posix_acl_release(*i_acl);
  149    *i_acl = posix_acl_dup(acl);
    150    spin_unlock(&inode->i_lock);
    150   do
- 150   do-while (0)
- 150 do-while (0)
  151 }
  152 
  153 /*
  154  * Inode operation get_posix_acl().
  155  *
  156  * inode->i_mutex: don't care
  157  */
  158 static struct posix_acl *
 
- 159 ext3_get_acl(struct inode *inode, int type)
  160 {
  161    struct ext3_inode_info *ei = EXT3_I(inode);
  162    int name_index;
  163    char *value = NULL;
  164    struct posix_acl *acl;
  165    int retval;
  166 
- 167    if (!test_opt(inode->i_sb, POSIX_ACL))
 - 168       return NULL;
  169 
    170    switch(type) {
 - 171       case ACL_TYPE_ACCESS:
  172          acl = ext3_iget_acl(inode, &ei->i_acl);
- 173          if (acl != EXT3_ACL_NOT_CACHED)
 - 174             return acl;
  175          name_index = EXT3_XATTR_INDEX_POSIX_ACL_ACCESS;
 - 176          break;
  177 
 - 178       case ACL_TYPE_DEFAULT:
  179          acl = ext3_iget_acl(inode, &ei->i_default_acl);
- 180          if (acl != EXT3_ACL_NOT_CACHED)
 - 181             return acl;
  182          name_index = EXT3_XATTR_INDEX_POSIX_ACL_DEFAULT;
 - 183          break;
  184 
 - 185       default:
 - 186          return ERR_PTR(-EINVAL);
  187    }
  188    retval = ext3_xattr_get(inode, name_index, "", NULL, 0);
- 189    if (retval > 0) {
  190       value = kmalloc(retval, GFP_KERNEL);
- 191       if (!value)
 - 192          return ERR_PTR(-ENOMEM);
  193       retval = ext3_xattr_get(inode, name_index, "", value, retval);
  194    }
- 195    if (retval > 0)
  196       acl = ext3_acl_from_disk(value, retval);
- 197    else if (retval == -ENODATA || retval == -ENOSYS)
 - 197   T || _
 - 197   F || T
 - 197   F || F
  198       acl = NULL;
    199    else
  200       acl = ERR_PTR(retval);
  201    kfree(value);
  202 
- 203    if (!IS_ERR(acl)) {
    204       switch(type) {
 - 205          case ACL_TYPE_ACCESS:
  206             ext3_iset_acl(inode, &ei->i_acl, acl);
 - 207             break;
  208 
 - 209          case ACL_TYPE_DEFAULT:
  210             ext3_iset_acl(inode, &ei->i_default_acl, acl);
 - 211             break;
  212       }
  213    }
 - 214    return acl;
  215 }
  216 
  217 /*
  218  * Set the access or default ACL of an inode.
  219  *
  220  * inode->i_mutex: down unless called from ext3_new_inode
  221  */
  222 static int
 
- 223 ext3_set_acl(handle_t *handle, struct inode *inode, int type,
  224         struct posix_acl *acl)
  225 {
  226    struct ext3_inode_info *ei = EXT3_I(inode);
  227    int name_index;
  228    void *value = NULL;
  229    size_t size = 0;
  230    int error;
  231 
- 232    if (S_ISLNK(inode->i_mode))
 - 233       return -EOPNOTSUPP;
  234 
    235    switch(type) {
 - 236       case ACL_TYPE_ACCESS:
  237          name_index = EXT3_XATTR_INDEX_POSIX_ACL_ACCESS;
- 238          if (acl) {
  239             mode_t mode = inode->i_mode;
  240             error = posix_acl_equiv_mode(acl, &mode);
- 241             if (error < 0)
 - 242                return error;
    243             else {
  244                inode->i_mode = mode;
  245                ext3_mark_inode_dirty(handle, inode);
- 246                if (error == 0)
  247                   acl = NULL;
  248             }
  249          }
 - 250          break;
  251 
 - 252       case ACL_TYPE_DEFAULT:
  253          name_index = EXT3_XATTR_INDEX_POSIX_ACL_DEFAULT;
- 254          if (!S_ISDIR(inode->i_mode))
    255             return acl ? -EACCES : 0;
- 255     ternary-?: acl
 - 255     return acl ? - 13 : 0
 - 256          break;
  257 
 - 258       default:
 - 259          return -EINVAL;
  260    }
- 261     if (acl) {
  262       value = ext3_acl_to_disk(acl, &size);
- 263       if (IS_ERR(value))
 - 264          return (int)PTR_ERR(value);
  265    }
  266 
  267    error = ext3_xattr_set_handle(handle, inode, name_index, "",
  268                   value, size, 0);
  269 
  270    kfree(value);
- 271    if (!error) {
    272       switch(type) {
 - 273          case ACL_TYPE_ACCESS:
  274             ext3_iset_acl(inode, &ei->i_acl, acl);
 - 275             break;
  276 
 - 277          case ACL_TYPE_DEFAULT:
  278             ext3_iset_acl(inode, &ei->i_default_acl, acl);
 - 279             break;
  280       }
  281    }
 - 282    return error;
  283 }
  284 
  285 static int
 
- 286 ext3_check_acl(struct inode *inode, int mask)
  287 {
  288    struct posix_acl *acl = ext3_get_acl(inode, ACL_TYPE_ACCESS);
  289 
- 290    if (IS_ERR(acl))
 - 291       return PTR_ERR(acl);
- 292    if (acl) {
  293       int error = posix_acl_permission(inode, acl, mask);
  294       posix_acl_release(acl);
 - 295       return error;
  296    }
  297 
 - 298    return -EAGAIN;
  299 }
  300 
  301 int
 
8492E4   302 ext3_permission(struct inode *inode, int mask, struct nameidata *nd)
  303 {
8492E4    304    return generic_permission(inode, mask, ext3_check_acl);
  305 }
  306 
  307 /*
  308  * Initialize the ACLs of a new inode. Called from ext3_new_inode.
  309  *
  310  * dir->i_mutex: down
  311  * inode->i_mutex: up (access to inode is still exclusive)
  312  */
  313 int
 
641597   314 ext3_init_acl(handle_t *handle, struct inode *inode, struct inode *dir)
  315 {
  316    struct posix_acl *acl = NULL;
  317    int error = 0;
  318 
640664 933   319    if (!S_ISLNK(inode->i_mode)) {
640664 - 320       if (test_opt(dir->i_sb, POSIX_ACL)) {
  321          acl = ext3_get_acl(dir, ACL_TYPE_DEFAULT);
- 322          if (IS_ERR(acl))
 - 323             return PTR_ERR(acl);
  324       }
640664 - 325       if (!acl)
  326          inode->i_mode &= ~current->fs->umask;
  327    }
641597 - 328    if (test_opt(inode->i_sb, POSIX_ACL) && acl) {
 - 328   (T) && T
 - 328   (T) && F
 641597   328   (F) && _
  329       struct posix_acl *clone;
  330       mode_t mode;
  331 
- 332       if (S_ISDIR(inode->i_mode)) {
  333          error = ext3_set_acl(handle, inode,
  334                     ACL_TYPE_DEFAULT, acl);
- 335          if (error)
 - 336             goto cleanup;
  337       }
  338       clone = posix_acl_clone(acl, GFP_KERNEL);
  339       error = -ENOMEM;
- 340       if (!clone)
 - 341          goto cleanup;
  342 
  343       mode = inode->i_mode;
  344       error = posix_acl_create_masq(clone, &mode);
- 345       if (error >= 0) {
  346          inode->i_mode = mode;
- 347          if (error > 0) {
  348             /* This is an extended ACL */
  349             error = ext3_set_acl(handle, inode,
  350                        ACL_TYPE_ACCESS, clone);
  351          }
  352       }
  353       posix_acl_release(clone);
  354    }
  355 cleanup:
  356    posix_acl_release(acl);
641597    357    return error;
  358 }
  359 
  360 /*
  361  * Does chmod for an inode that may have an Access Control List. The
  362  * inode->i_mode field must be updated to the desired value by the caller
  363  * before calling this function.
  364  * Returns 0 on success, or a negative error number.
  365  *
  366  * We change the ACL rather than storing some ACL entries in the file
  367  * mode permission bits (which would be more efficient), because that
  368  * would break once additional permissions (like  ACL_APPEND, ACL_DELETE
  369  * for directories) are added. There are no more bits available in the
  370  * file mode.
  371  *
  372  * inode->i_mutex: down
  373  */
  374 int
 
17657   375 ext3_acl_chmod(struct inode *inode)
  376 {
  377    struct posix_acl *acl, *clone;
  378         int error;
  379 
17657 - 380    if (S_ISLNK(inode->i_mode))
 - 381       return -EOPNOTSUPP;
17657 - 382    if (!test_opt(inode->i_sb, POSIX_ACL))
17657    383       return 0;
  384    acl = ext3_get_acl(inode, ACL_TYPE_ACCESS);
- 385    if (IS_ERR(acl) || !acl)
 - 385   T || _
 - 385   F || T
 - 385   F || F
 - 386       return PTR_ERR(acl);
  387    clone = posix_acl_clone(acl, GFP_KERNEL);
  388    posix_acl_release(acl);
- 389    if (!clone)
 - 390       return -ENOMEM;
  391    error = posix_acl_chmod_masq(clone, inode->i_mode);
- 392    if (!error) {
  393       handle_t *handle;
  394       int retries = 0;
  395 
  396    retry:
  397       handle = ext3_journal_start(inode,
  398             EXT3_DATA_TRANS_BLOCKS(inode->i_sb));
- 399       if (IS_ERR(handle)) {
  400          error = PTR_ERR(handle);
    401          ext3_std_error(inode->i_sb, error);
- 401       if (( error ))
- 401     do-while (0)
 - 402          goto out;
  403       }
  404       error = ext3_set_acl(handle, inode, ACL_TYPE_ACCESS, clone);
  405       ext3_journal_stop(handle);
  406       if (error == -ENOSPC &&
- 407           ext3_should_retry_alloc(inode->i_sb, &retries))
 - 407     T && T
 - 407     T && F
 - 407     F && _
 - 408          goto retry;
  409    }
  410 out:
  411    posix_acl_release(clone);
 - 412    return error;
  413 }
  414 
  415 /*
  416  * Extended attribute handlers
  417  */
  418 static size_t
 
- 419 ext3_xattr_list_acl_access(struct inode *inode, char *list, size_t list_len,
  420             const char *name, size_t name_len)
  421 {
  422    const size_t size = sizeof(POSIX_ACL_XATTR_ACCESS);
  423 
- 424    if (!test_opt(inode->i_sb, POSIX_ACL))
 - 425       return 0;
- 426    if (list && size <= list_len)
 - 426   T && T
 - 426   T && F
 - 426   F && _
  427       memcpy(list, POSIX_ACL_XATTR_ACCESS, size);
 - 428    return size;
  429 }
  430 
  431 static size_t
 
- 432 ext3_xattr_list_acl_default(struct inode *inode, char *list, size_t list_len,
  433              const char *name, size_t name_len)
  434 {
  435    const size_t size = sizeof(POSIX_ACL_XATTR_DEFAULT);
  436 
- 437    if (!test_opt(inode->i_sb, POSIX_ACL))
 - 438       return 0;
- 439    if (list && size <= list_len)
 - 439   T && T
 - 439   T && F
 - 439   F && _
  440       memcpy(list, POSIX_ACL_XATTR_DEFAULT, size);
 - 441    return size;
  442 }
  443 
  444 static int
 
73826   445 ext3_xattr_get_acl(struct inode *inode, int type, void *buffer, size_t size)
  446 {
  447    struct posix_acl *acl;
  448    int error;
  449 
73826 - 450    if (!test_opt(inode->i_sb, POSIX_ACL))
73826    451       return -EOPNOTSUPP;
  452 
  453    acl = ext3_get_acl(inode, type);
- 454    if (IS_ERR(acl))
 - 455       return PTR_ERR(acl);
- 456    if (acl == NULL)
 - 457       return -ENODATA;
  458    error = posix_acl_to_xattr(acl, buffer, size);
  459    posix_acl_release(acl);
  460 
 - 461    return error;
  462 }