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

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


File: fs/ext2/acl.c
Instrumentation mode: function-decision-multicondition
TER: 0 % ( 0/284)

Start/ End/    
True False - Line Source

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