/* * Set the access or default ACL of an inode. * * inode->i_mutex: down unless called from ext3_new_inode */ static int ext3_set_acl(handle_t *handle, struct inode *inode, int type, struct posix_acl *acl) { struct ext3_inode_info *ei = EXT3_I(inode); int name_index; void *value = NULL; size_t size = 0; int error; if (S_ISLNK(inode->i_mode)) return -EOPNOTSUPP; switch(type) { case ACL_TYPE_ACCESS: name_index = EXT3_XATTR_INDEX_POSIX_ACL_ACCESS; if (acl) { mode_t mode = inode->i_mode; error = posix_acl_equiv_mode(acl, &mode); if (error < 0) return error; else { inode->i_mode = mode; inode->i_ctime = CURRENT_TIME_SEC; ext3_mark_inode_dirty(handle, inode); if (error == 0) acl = NULL; } } break; case ACL_TYPE_DEFAULT: name_index = EXT3_XATTR_INDEX_POSIX_ACL_DEFAULT; if (!S_ISDIR(inode->i_mode)) return acl ? -EACCES : 0; break; default: return -EINVAL; } if (acl) { value = ext3_acl_to_disk(acl, &size); if (IS_ERR(value)) return (int)PTR_ERR(value); } error = ext3_xattr_set_handle(handle, inode, name_index, "", value, size, 0); kfree(value); if (!error) { switch(type) { case ACL_TYPE_ACCESS: ext3_iset_acl(inode, &ei->i_acl, acl); break; case ACL_TYPE_DEFAULT: ext3_iset_acl(inode, &ei->i_default_acl, acl); break; } } return error; }
/* * inode->i_sem: down, or inode is just being initialized * BKL: held */ static int ext3_do_set_acl(handle_t *handle, struct inode *inode, int type, struct posix_acl *acl) { struct ext3_inode_info *ei = EXT3_I(inode); int name_index; void *value = NULL; size_t size; int error; if (S_ISLNK(inode->i_mode)) return -ENODATA; switch(type) { case ACL_TYPE_ACCESS: name_index = EXT3_XATTR_INDEX_POSIX_ACL_ACCESS; if (acl) { mode_t mode = inode->i_mode; error = posix_acl_equiv_mode(acl, &mode); if (error < 0) return error; else { inode->i_mode = mode; ext3_mark_inode_dirty(handle, inode); if (error == 0) acl = NULL; } } break; case ACL_TYPE_DEFAULT: name_index = EXT3_XATTR_INDEX_POSIX_ACL_DEFAULT; if (!S_ISDIR(inode->i_mode)) return acl ? -EACCES : 0; break; default: return -EINVAL; } if (acl) { if (acl->a_count > EXT3_ACL_MAX_ENTRIES) return -EINVAL; value = ext3_acl_to_disk(acl, &size); if (IS_ERR(value)) return (int)PTR_ERR(value); } error = ext3_xattr_set_handle(handle, inode, name_index, "", value, size, 0); if (value) kfree(value); if (!error) { switch(type) { case ACL_TYPE_ACCESS: if (ei->i_acl != EXT3_ACL_NOT_CACHED) posix_acl_release(ei->i_acl); ei->i_acl = posix_acl_dup(acl); break; case ACL_TYPE_DEFAULT: if (ei->i_default_acl != EXT3_ACL_NOT_CACHED) posix_acl_release(ei->i_default_acl); ei->i_default_acl = posix_acl_dup(acl); break; } } return error; }