diff options
Diffstat (limited to 'fs/hfsplus/btree.c')
| -rw-r--r-- | fs/hfsplus/btree.c | 67 |
1 files changed, 52 insertions, 15 deletions
diff --git a/fs/hfsplus/btree.c b/fs/hfsplus/btree.c index e49fcee1e293..22e4d4e32999 100644 --- a/fs/hfsplus/btree.c +++ b/fs/hfsplus/btree.c | |||
| @@ -30,7 +30,7 @@ struct hfs_btree *hfs_btree_open(struct super_block *sb, u32 id) | |||
| 30 | if (!tree) | 30 | if (!tree) |
| 31 | return NULL; | 31 | return NULL; |
| 32 | 32 | ||
| 33 | init_MUTEX(&tree->tree_lock); | 33 | mutex_init(&tree->tree_lock); |
| 34 | spin_lock_init(&tree->hash_lock); | 34 | spin_lock_init(&tree->hash_lock); |
| 35 | tree->sb = sb; | 35 | tree->sb = sb; |
| 36 | tree->cnid = id; | 36 | tree->cnid = id; |
| @@ -39,10 +39,16 @@ struct hfs_btree *hfs_btree_open(struct super_block *sb, u32 id) | |||
| 39 | goto free_tree; | 39 | goto free_tree; |
| 40 | tree->inode = inode; | 40 | tree->inode = inode; |
| 41 | 41 | ||
| 42 | if (!HFSPLUS_I(tree->inode)->first_blocks) { | ||
| 43 | printk(KERN_ERR | ||
| 44 | "hfs: invalid btree extent records (0 size).\n"); | ||
| 45 | goto free_inode; | ||
| 46 | } | ||
| 47 | |||
| 42 | mapping = tree->inode->i_mapping; | 48 | mapping = tree->inode->i_mapping; |
| 43 | page = read_mapping_page(mapping, 0, NULL); | 49 | page = read_mapping_page(mapping, 0, NULL); |
| 44 | if (IS_ERR(page)) | 50 | if (IS_ERR(page)) |
| 45 | goto free_tree; | 51 | goto free_inode; |
| 46 | 52 | ||
| 47 | /* Load the header */ | 53 | /* Load the header */ |
| 48 | head = (struct hfs_btree_header_rec *)(kmap(page) + sizeof(struct hfs_bnode_desc)); | 54 | head = (struct hfs_btree_header_rec *)(kmap(page) + sizeof(struct hfs_bnode_desc)); |
| @@ -57,27 +63,56 @@ struct hfs_btree *hfs_btree_open(struct super_block *sb, u32 id) | |||
| 57 | tree->max_key_len = be16_to_cpu(head->max_key_len); | 63 | tree->max_key_len = be16_to_cpu(head->max_key_len); |
| 58 | tree->depth = be16_to_cpu(head->depth); | 64 | tree->depth = be16_to_cpu(head->depth); |
| 59 | 65 | ||
| 60 | /* Set the correct compare function */ | 66 | /* Verify the tree and set the correct compare function */ |
| 61 | if (id == HFSPLUS_EXT_CNID) { | 67 | switch (id) { |
| 68 | case HFSPLUS_EXT_CNID: | ||
| 69 | if (tree->max_key_len != HFSPLUS_EXT_KEYLEN - sizeof(u16)) { | ||
| 70 | printk(KERN_ERR "hfs: invalid extent max_key_len %d\n", | ||
| 71 | tree->max_key_len); | ||
| 72 | goto fail_page; | ||
| 73 | } | ||
| 74 | if (tree->attributes & HFS_TREE_VARIDXKEYS) { | ||
| 75 | printk(KERN_ERR "hfs: invalid extent btree flag\n"); | ||
| 76 | goto fail_page; | ||
| 77 | } | ||
| 78 | |||
| 62 | tree->keycmp = hfsplus_ext_cmp_key; | 79 | tree->keycmp = hfsplus_ext_cmp_key; |
| 63 | } else if (id == HFSPLUS_CAT_CNID) { | 80 | break; |
| 64 | if ((HFSPLUS_SB(sb).flags & HFSPLUS_SB_HFSX) && | 81 | case HFSPLUS_CAT_CNID: |
| 82 | if (tree->max_key_len != HFSPLUS_CAT_KEYLEN - sizeof(u16)) { | ||
| 83 | printk(KERN_ERR "hfs: invalid catalog max_key_len %d\n", | ||
| 84 | tree->max_key_len); | ||
| 85 | goto fail_page; | ||
| 86 | } | ||
| 87 | if (!(tree->attributes & HFS_TREE_VARIDXKEYS)) { | ||
| 88 | printk(KERN_ERR "hfs: invalid catalog btree flag\n"); | ||
| 89 | goto fail_page; | ||
| 90 | } | ||
| 91 | |||
| 92 | if (test_bit(HFSPLUS_SB_HFSX, &HFSPLUS_SB(sb)->flags) && | ||
| 65 | (head->key_type == HFSPLUS_KEY_BINARY)) | 93 | (head->key_type == HFSPLUS_KEY_BINARY)) |
| 66 | tree->keycmp = hfsplus_cat_bin_cmp_key; | 94 | tree->keycmp = hfsplus_cat_bin_cmp_key; |
| 67 | else { | 95 | else { |
| 68 | tree->keycmp = hfsplus_cat_case_cmp_key; | 96 | tree->keycmp = hfsplus_cat_case_cmp_key; |
| 69 | HFSPLUS_SB(sb).flags |= HFSPLUS_SB_CASEFOLD; | 97 | set_bit(HFSPLUS_SB_CASEFOLD, &HFSPLUS_SB(sb)->flags); |
| 70 | } | 98 | } |
| 71 | } else { | 99 | break; |
| 100 | default: | ||
| 72 | printk(KERN_ERR "hfs: unknown B*Tree requested\n"); | 101 | printk(KERN_ERR "hfs: unknown B*Tree requested\n"); |
| 73 | goto fail_page; | 102 | goto fail_page; |
| 74 | } | 103 | } |
| 75 | 104 | ||
| 105 | if (!(tree->attributes & HFS_TREE_BIGKEYS)) { | ||
| 106 | printk(KERN_ERR "hfs: invalid btree flag\n"); | ||
| 107 | goto fail_page; | ||
| 108 | } | ||
| 109 | |||
| 76 | size = tree->node_size; | 110 | size = tree->node_size; |
| 77 | if (!is_power_of_2(size)) | 111 | if (!is_power_of_2(size)) |
| 78 | goto fail_page; | 112 | goto fail_page; |
| 79 | if (!tree->node_count) | 113 | if (!tree->node_count) |
| 80 | goto fail_page; | 114 | goto fail_page; |
| 115 | |||
| 81 | tree->node_size_shift = ffs(size) - 1; | 116 | tree->node_size_shift = ffs(size) - 1; |
| 82 | 117 | ||
| 83 | tree->pages_per_bnode = (tree->node_size + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT; | 118 | tree->pages_per_bnode = (tree->node_size + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT; |
| @@ -87,10 +122,11 @@ struct hfs_btree *hfs_btree_open(struct super_block *sb, u32 id) | |||
| 87 | return tree; | 122 | return tree; |
| 88 | 123 | ||
| 89 | fail_page: | 124 | fail_page: |
| 90 | tree->inode->i_mapping->a_ops = &hfsplus_aops; | ||
| 91 | page_cache_release(page); | 125 | page_cache_release(page); |
| 92 | free_tree: | 126 | free_inode: |
| 127 | tree->inode->i_mapping->a_ops = &hfsplus_aops; | ||
| 93 | iput(tree->inode); | 128 | iput(tree->inode); |
| 129 | free_tree: | ||
| 94 | kfree(tree); | 130 | kfree(tree); |
| 95 | return NULL; | 131 | return NULL; |
| 96 | } | 132 | } |
| @@ -192,17 +228,18 @@ struct hfs_bnode *hfs_bmap_alloc(struct hfs_btree *tree) | |||
| 192 | 228 | ||
| 193 | while (!tree->free_nodes) { | 229 | while (!tree->free_nodes) { |
| 194 | struct inode *inode = tree->inode; | 230 | struct inode *inode = tree->inode; |
| 231 | struct hfsplus_inode_info *hip = HFSPLUS_I(inode); | ||
| 195 | u32 count; | 232 | u32 count; |
| 196 | int res; | 233 | int res; |
| 197 | 234 | ||
| 198 | res = hfsplus_file_extend(inode); | 235 | res = hfsplus_file_extend(inode); |
| 199 | if (res) | 236 | if (res) |
| 200 | return ERR_PTR(res); | 237 | return ERR_PTR(res); |
| 201 | HFSPLUS_I(inode).phys_size = inode->i_size = | 238 | hip->phys_size = inode->i_size = |
| 202 | (loff_t)HFSPLUS_I(inode).alloc_blocks << | 239 | (loff_t)hip->alloc_blocks << |
| 203 | HFSPLUS_SB(tree->sb).alloc_blksz_shift; | 240 | HFSPLUS_SB(tree->sb)->alloc_blksz_shift; |
| 204 | HFSPLUS_I(inode).fs_blocks = HFSPLUS_I(inode).alloc_blocks << | 241 | hip->fs_blocks = |
| 205 | HFSPLUS_SB(tree->sb).fs_shift; | 242 | hip->alloc_blocks << HFSPLUS_SB(tree->sb)->fs_shift; |
| 206 | inode_set_bytes(inode, inode->i_size); | 243 | inode_set_bytes(inode, inode->i_size); |
| 207 | count = inode->i_size >> tree->node_size_shift; | 244 | count = inode->i_size >> tree->node_size_shift; |
| 208 | tree->free_nodes = count - tree->node_count; | 245 | tree->free_nodes = count - tree->node_count; |
