18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * index.c - NTFS kernel index handling. Part of the Linux-NTFS project. 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (c) 2004-2005 Anton Altaparmakov 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include <linux/slab.h> 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include "aops.h" 118c2ecf20Sopenharmony_ci#include "collate.h" 128c2ecf20Sopenharmony_ci#include "debug.h" 138c2ecf20Sopenharmony_ci#include "index.h" 148c2ecf20Sopenharmony_ci#include "ntfs.h" 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci/** 178c2ecf20Sopenharmony_ci * ntfs_index_ctx_get - allocate and initialize a new index context 188c2ecf20Sopenharmony_ci * @idx_ni: ntfs index inode with which to initialize the context 198c2ecf20Sopenharmony_ci * 208c2ecf20Sopenharmony_ci * Allocate a new index context, initialize it with @idx_ni and return it. 218c2ecf20Sopenharmony_ci * Return NULL if allocation failed. 228c2ecf20Sopenharmony_ci * 238c2ecf20Sopenharmony_ci * Locking: Caller must hold i_mutex on the index inode. 248c2ecf20Sopenharmony_ci */ 258c2ecf20Sopenharmony_cintfs_index_context *ntfs_index_ctx_get(ntfs_inode *idx_ni) 268c2ecf20Sopenharmony_ci{ 278c2ecf20Sopenharmony_ci ntfs_index_context *ictx; 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci ictx = kmem_cache_alloc(ntfs_index_ctx_cache, GFP_NOFS); 308c2ecf20Sopenharmony_ci if (ictx) 318c2ecf20Sopenharmony_ci *ictx = (ntfs_index_context){ .idx_ni = idx_ni }; 328c2ecf20Sopenharmony_ci return ictx; 338c2ecf20Sopenharmony_ci} 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci/** 368c2ecf20Sopenharmony_ci * ntfs_index_ctx_put - release an index context 378c2ecf20Sopenharmony_ci * @ictx: index context to free 388c2ecf20Sopenharmony_ci * 398c2ecf20Sopenharmony_ci * Release the index context @ictx, releasing all associated resources. 408c2ecf20Sopenharmony_ci * 418c2ecf20Sopenharmony_ci * Locking: Caller must hold i_mutex on the index inode. 428c2ecf20Sopenharmony_ci */ 438c2ecf20Sopenharmony_civoid ntfs_index_ctx_put(ntfs_index_context *ictx) 448c2ecf20Sopenharmony_ci{ 458c2ecf20Sopenharmony_ci if (ictx->entry) { 468c2ecf20Sopenharmony_ci if (ictx->is_in_root) { 478c2ecf20Sopenharmony_ci if (ictx->actx) 488c2ecf20Sopenharmony_ci ntfs_attr_put_search_ctx(ictx->actx); 498c2ecf20Sopenharmony_ci if (ictx->base_ni) 508c2ecf20Sopenharmony_ci unmap_mft_record(ictx->base_ni); 518c2ecf20Sopenharmony_ci } else { 528c2ecf20Sopenharmony_ci struct page *page = ictx->page; 538c2ecf20Sopenharmony_ci if (page) { 548c2ecf20Sopenharmony_ci BUG_ON(!PageLocked(page)); 558c2ecf20Sopenharmony_ci unlock_page(page); 568c2ecf20Sopenharmony_ci ntfs_unmap_page(page); 578c2ecf20Sopenharmony_ci } 588c2ecf20Sopenharmony_ci } 598c2ecf20Sopenharmony_ci } 608c2ecf20Sopenharmony_ci kmem_cache_free(ntfs_index_ctx_cache, ictx); 618c2ecf20Sopenharmony_ci return; 628c2ecf20Sopenharmony_ci} 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci/** 658c2ecf20Sopenharmony_ci * ntfs_index_lookup - find a key in an index and return its index entry 668c2ecf20Sopenharmony_ci * @key: [IN] key for which to search in the index 678c2ecf20Sopenharmony_ci * @key_len: [IN] length of @key in bytes 688c2ecf20Sopenharmony_ci * @ictx: [IN/OUT] context describing the index and the returned entry 698c2ecf20Sopenharmony_ci * 708c2ecf20Sopenharmony_ci * Before calling ntfs_index_lookup(), @ictx must have been obtained from a 718c2ecf20Sopenharmony_ci * call to ntfs_index_ctx_get(). 728c2ecf20Sopenharmony_ci * 738c2ecf20Sopenharmony_ci * Look for the @key in the index specified by the index lookup context @ictx. 748c2ecf20Sopenharmony_ci * ntfs_index_lookup() walks the contents of the index looking for the @key. 758c2ecf20Sopenharmony_ci * 768c2ecf20Sopenharmony_ci * If the @key is found in the index, 0 is returned and @ictx is setup to 778c2ecf20Sopenharmony_ci * describe the index entry containing the matching @key. @ictx->entry is the 788c2ecf20Sopenharmony_ci * index entry and @ictx->data and @ictx->data_len are the index entry data and 798c2ecf20Sopenharmony_ci * its length in bytes, respectively. 808c2ecf20Sopenharmony_ci * 818c2ecf20Sopenharmony_ci * If the @key is not found in the index, -ENOENT is returned and @ictx is 828c2ecf20Sopenharmony_ci * setup to describe the index entry whose key collates immediately after the 838c2ecf20Sopenharmony_ci * search @key, i.e. this is the position in the index at which an index entry 848c2ecf20Sopenharmony_ci * with a key of @key would need to be inserted. 858c2ecf20Sopenharmony_ci * 868c2ecf20Sopenharmony_ci * If an error occurs return the negative error code and @ictx is left 878c2ecf20Sopenharmony_ci * untouched. 888c2ecf20Sopenharmony_ci * 898c2ecf20Sopenharmony_ci * When finished with the entry and its data, call ntfs_index_ctx_put() to free 908c2ecf20Sopenharmony_ci * the context and other associated resources. 918c2ecf20Sopenharmony_ci * 928c2ecf20Sopenharmony_ci * If the index entry was modified, call flush_dcache_index_entry_page() 938c2ecf20Sopenharmony_ci * immediately after the modification and either ntfs_index_entry_mark_dirty() 948c2ecf20Sopenharmony_ci * or ntfs_index_entry_write() before the call to ntfs_index_ctx_put() to 958c2ecf20Sopenharmony_ci * ensure that the changes are written to disk. 968c2ecf20Sopenharmony_ci * 978c2ecf20Sopenharmony_ci * Locking: - Caller must hold i_mutex on the index inode. 988c2ecf20Sopenharmony_ci * - Each page cache page in the index allocation mapping must be 998c2ecf20Sopenharmony_ci * locked whilst being accessed otherwise we may find a corrupt 1008c2ecf20Sopenharmony_ci * page due to it being under ->writepage at the moment which 1018c2ecf20Sopenharmony_ci * applies the mst protection fixups before writing out and then 1028c2ecf20Sopenharmony_ci * removes them again after the write is complete after which it 1038c2ecf20Sopenharmony_ci * unlocks the page. 1048c2ecf20Sopenharmony_ci */ 1058c2ecf20Sopenharmony_ciint ntfs_index_lookup(const void *key, const int key_len, 1068c2ecf20Sopenharmony_ci ntfs_index_context *ictx) 1078c2ecf20Sopenharmony_ci{ 1088c2ecf20Sopenharmony_ci VCN vcn, old_vcn; 1098c2ecf20Sopenharmony_ci ntfs_inode *idx_ni = ictx->idx_ni; 1108c2ecf20Sopenharmony_ci ntfs_volume *vol = idx_ni->vol; 1118c2ecf20Sopenharmony_ci struct super_block *sb = vol->sb; 1128c2ecf20Sopenharmony_ci ntfs_inode *base_ni = idx_ni->ext.base_ntfs_ino; 1138c2ecf20Sopenharmony_ci MFT_RECORD *m; 1148c2ecf20Sopenharmony_ci INDEX_ROOT *ir; 1158c2ecf20Sopenharmony_ci INDEX_ENTRY *ie; 1168c2ecf20Sopenharmony_ci INDEX_ALLOCATION *ia; 1178c2ecf20Sopenharmony_ci u8 *index_end, *kaddr; 1188c2ecf20Sopenharmony_ci ntfs_attr_search_ctx *actx; 1198c2ecf20Sopenharmony_ci struct address_space *ia_mapping; 1208c2ecf20Sopenharmony_ci struct page *page; 1218c2ecf20Sopenharmony_ci int rc, err = 0; 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci ntfs_debug("Entering."); 1248c2ecf20Sopenharmony_ci BUG_ON(!NInoAttr(idx_ni)); 1258c2ecf20Sopenharmony_ci BUG_ON(idx_ni->type != AT_INDEX_ALLOCATION); 1268c2ecf20Sopenharmony_ci BUG_ON(idx_ni->nr_extents != -1); 1278c2ecf20Sopenharmony_ci BUG_ON(!base_ni); 1288c2ecf20Sopenharmony_ci BUG_ON(!key); 1298c2ecf20Sopenharmony_ci BUG_ON(key_len <= 0); 1308c2ecf20Sopenharmony_ci if (!ntfs_is_collation_rule_supported( 1318c2ecf20Sopenharmony_ci idx_ni->itype.index.collation_rule)) { 1328c2ecf20Sopenharmony_ci ntfs_error(sb, "Index uses unsupported collation rule 0x%x. " 1338c2ecf20Sopenharmony_ci "Aborting lookup.", le32_to_cpu( 1348c2ecf20Sopenharmony_ci idx_ni->itype.index.collation_rule)); 1358c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 1368c2ecf20Sopenharmony_ci } 1378c2ecf20Sopenharmony_ci /* Get hold of the mft record for the index inode. */ 1388c2ecf20Sopenharmony_ci m = map_mft_record(base_ni); 1398c2ecf20Sopenharmony_ci if (IS_ERR(m)) { 1408c2ecf20Sopenharmony_ci ntfs_error(sb, "map_mft_record() failed with error code %ld.", 1418c2ecf20Sopenharmony_ci -PTR_ERR(m)); 1428c2ecf20Sopenharmony_ci return PTR_ERR(m); 1438c2ecf20Sopenharmony_ci } 1448c2ecf20Sopenharmony_ci actx = ntfs_attr_get_search_ctx(base_ni, m); 1458c2ecf20Sopenharmony_ci if (unlikely(!actx)) { 1468c2ecf20Sopenharmony_ci err = -ENOMEM; 1478c2ecf20Sopenharmony_ci goto err_out; 1488c2ecf20Sopenharmony_ci } 1498c2ecf20Sopenharmony_ci /* Find the index root attribute in the mft record. */ 1508c2ecf20Sopenharmony_ci err = ntfs_attr_lookup(AT_INDEX_ROOT, idx_ni->name, idx_ni->name_len, 1518c2ecf20Sopenharmony_ci CASE_SENSITIVE, 0, NULL, 0, actx); 1528c2ecf20Sopenharmony_ci if (unlikely(err)) { 1538c2ecf20Sopenharmony_ci if (err == -ENOENT) { 1548c2ecf20Sopenharmony_ci ntfs_error(sb, "Index root attribute missing in inode " 1558c2ecf20Sopenharmony_ci "0x%lx.", idx_ni->mft_no); 1568c2ecf20Sopenharmony_ci err = -EIO; 1578c2ecf20Sopenharmony_ci } 1588c2ecf20Sopenharmony_ci goto err_out; 1598c2ecf20Sopenharmony_ci } 1608c2ecf20Sopenharmony_ci /* Get to the index root value (it has been verified in read_inode). */ 1618c2ecf20Sopenharmony_ci ir = (INDEX_ROOT*)((u8*)actx->attr + 1628c2ecf20Sopenharmony_ci le16_to_cpu(actx->attr->data.resident.value_offset)); 1638c2ecf20Sopenharmony_ci index_end = (u8*)&ir->index + le32_to_cpu(ir->index.index_length); 1648c2ecf20Sopenharmony_ci /* The first index entry. */ 1658c2ecf20Sopenharmony_ci ie = (INDEX_ENTRY*)((u8*)&ir->index + 1668c2ecf20Sopenharmony_ci le32_to_cpu(ir->index.entries_offset)); 1678c2ecf20Sopenharmony_ci /* 1688c2ecf20Sopenharmony_ci * Loop until we exceed valid memory (corruption case) or until we 1698c2ecf20Sopenharmony_ci * reach the last entry. 1708c2ecf20Sopenharmony_ci */ 1718c2ecf20Sopenharmony_ci for (;; ie = (INDEX_ENTRY*)((u8*)ie + le16_to_cpu(ie->length))) { 1728c2ecf20Sopenharmony_ci /* Bounds checks. */ 1738c2ecf20Sopenharmony_ci if ((u8*)ie < (u8*)actx->mrec || (u8*)ie + 1748c2ecf20Sopenharmony_ci sizeof(INDEX_ENTRY_HEADER) > index_end || 1758c2ecf20Sopenharmony_ci (u8*)ie + le16_to_cpu(ie->length) > index_end) 1768c2ecf20Sopenharmony_ci goto idx_err_out; 1778c2ecf20Sopenharmony_ci /* 1788c2ecf20Sopenharmony_ci * The last entry cannot contain a key. It can however contain 1798c2ecf20Sopenharmony_ci * a pointer to a child node in the B+tree so we just break out. 1808c2ecf20Sopenharmony_ci */ 1818c2ecf20Sopenharmony_ci if (ie->flags & INDEX_ENTRY_END) 1828c2ecf20Sopenharmony_ci break; 1838c2ecf20Sopenharmony_ci /* Further bounds checks. */ 1848c2ecf20Sopenharmony_ci if ((u32)sizeof(INDEX_ENTRY_HEADER) + 1858c2ecf20Sopenharmony_ci le16_to_cpu(ie->key_length) > 1868c2ecf20Sopenharmony_ci le16_to_cpu(ie->data.vi.data_offset) || 1878c2ecf20Sopenharmony_ci (u32)le16_to_cpu(ie->data.vi.data_offset) + 1888c2ecf20Sopenharmony_ci le16_to_cpu(ie->data.vi.data_length) > 1898c2ecf20Sopenharmony_ci le16_to_cpu(ie->length)) 1908c2ecf20Sopenharmony_ci goto idx_err_out; 1918c2ecf20Sopenharmony_ci /* If the keys match perfectly, we setup @ictx and return 0. */ 1928c2ecf20Sopenharmony_ci if ((key_len == le16_to_cpu(ie->key_length)) && !memcmp(key, 1938c2ecf20Sopenharmony_ci &ie->key, key_len)) { 1948c2ecf20Sopenharmony_ciir_done: 1958c2ecf20Sopenharmony_ci ictx->is_in_root = true; 1968c2ecf20Sopenharmony_ci ictx->ir = ir; 1978c2ecf20Sopenharmony_ci ictx->actx = actx; 1988c2ecf20Sopenharmony_ci ictx->base_ni = base_ni; 1998c2ecf20Sopenharmony_ci ictx->ia = NULL; 2008c2ecf20Sopenharmony_ci ictx->page = NULL; 2018c2ecf20Sopenharmony_cidone: 2028c2ecf20Sopenharmony_ci ictx->entry = ie; 2038c2ecf20Sopenharmony_ci ictx->data = (u8*)ie + 2048c2ecf20Sopenharmony_ci le16_to_cpu(ie->data.vi.data_offset); 2058c2ecf20Sopenharmony_ci ictx->data_len = le16_to_cpu(ie->data.vi.data_length); 2068c2ecf20Sopenharmony_ci ntfs_debug("Done."); 2078c2ecf20Sopenharmony_ci return err; 2088c2ecf20Sopenharmony_ci } 2098c2ecf20Sopenharmony_ci /* 2108c2ecf20Sopenharmony_ci * Not a perfect match, need to do full blown collation so we 2118c2ecf20Sopenharmony_ci * know which way in the B+tree we have to go. 2128c2ecf20Sopenharmony_ci */ 2138c2ecf20Sopenharmony_ci rc = ntfs_collate(vol, idx_ni->itype.index.collation_rule, key, 2148c2ecf20Sopenharmony_ci key_len, &ie->key, le16_to_cpu(ie->key_length)); 2158c2ecf20Sopenharmony_ci /* 2168c2ecf20Sopenharmony_ci * If @key collates before the key of the current entry, there 2178c2ecf20Sopenharmony_ci * is definitely no such key in this index but we might need to 2188c2ecf20Sopenharmony_ci * descend into the B+tree so we just break out of the loop. 2198c2ecf20Sopenharmony_ci */ 2208c2ecf20Sopenharmony_ci if (rc == -1) 2218c2ecf20Sopenharmony_ci break; 2228c2ecf20Sopenharmony_ci /* 2238c2ecf20Sopenharmony_ci * A match should never happen as the memcmp() call should have 2248c2ecf20Sopenharmony_ci * cought it, but we still treat it correctly. 2258c2ecf20Sopenharmony_ci */ 2268c2ecf20Sopenharmony_ci if (!rc) 2278c2ecf20Sopenharmony_ci goto ir_done; 2288c2ecf20Sopenharmony_ci /* The keys are not equal, continue the search. */ 2298c2ecf20Sopenharmony_ci } 2308c2ecf20Sopenharmony_ci /* 2318c2ecf20Sopenharmony_ci * We have finished with this index without success. Check for the 2328c2ecf20Sopenharmony_ci * presence of a child node and if not present setup @ictx and return 2338c2ecf20Sopenharmony_ci * -ENOENT. 2348c2ecf20Sopenharmony_ci */ 2358c2ecf20Sopenharmony_ci if (!(ie->flags & INDEX_ENTRY_NODE)) { 2368c2ecf20Sopenharmony_ci ntfs_debug("Entry not found."); 2378c2ecf20Sopenharmony_ci err = -ENOENT; 2388c2ecf20Sopenharmony_ci goto ir_done; 2398c2ecf20Sopenharmony_ci } /* Child node present, descend into it. */ 2408c2ecf20Sopenharmony_ci /* Consistency check: Verify that an index allocation exists. */ 2418c2ecf20Sopenharmony_ci if (!NInoIndexAllocPresent(idx_ni)) { 2428c2ecf20Sopenharmony_ci ntfs_error(sb, "No index allocation attribute but index entry " 2438c2ecf20Sopenharmony_ci "requires one. Inode 0x%lx is corrupt or " 2448c2ecf20Sopenharmony_ci "driver bug.", idx_ni->mft_no); 2458c2ecf20Sopenharmony_ci goto err_out; 2468c2ecf20Sopenharmony_ci } 2478c2ecf20Sopenharmony_ci /* Get the starting vcn of the index_block holding the child node. */ 2488c2ecf20Sopenharmony_ci vcn = sle64_to_cpup((sle64*)((u8*)ie + le16_to_cpu(ie->length) - 8)); 2498c2ecf20Sopenharmony_ci ia_mapping = VFS_I(idx_ni)->i_mapping; 2508c2ecf20Sopenharmony_ci /* 2518c2ecf20Sopenharmony_ci * We are done with the index root and the mft record. Release them, 2528c2ecf20Sopenharmony_ci * otherwise we deadlock with ntfs_map_page(). 2538c2ecf20Sopenharmony_ci */ 2548c2ecf20Sopenharmony_ci ntfs_attr_put_search_ctx(actx); 2558c2ecf20Sopenharmony_ci unmap_mft_record(base_ni); 2568c2ecf20Sopenharmony_ci m = NULL; 2578c2ecf20Sopenharmony_ci actx = NULL; 2588c2ecf20Sopenharmony_cidescend_into_child_node: 2598c2ecf20Sopenharmony_ci /* 2608c2ecf20Sopenharmony_ci * Convert vcn to index into the index allocation attribute in units 2618c2ecf20Sopenharmony_ci * of PAGE_SIZE and map the page cache page, reading it from 2628c2ecf20Sopenharmony_ci * disk if necessary. 2638c2ecf20Sopenharmony_ci */ 2648c2ecf20Sopenharmony_ci page = ntfs_map_page(ia_mapping, vcn << 2658c2ecf20Sopenharmony_ci idx_ni->itype.index.vcn_size_bits >> PAGE_SHIFT); 2668c2ecf20Sopenharmony_ci if (IS_ERR(page)) { 2678c2ecf20Sopenharmony_ci ntfs_error(sb, "Failed to map index page, error %ld.", 2688c2ecf20Sopenharmony_ci -PTR_ERR(page)); 2698c2ecf20Sopenharmony_ci err = PTR_ERR(page); 2708c2ecf20Sopenharmony_ci goto err_out; 2718c2ecf20Sopenharmony_ci } 2728c2ecf20Sopenharmony_ci lock_page(page); 2738c2ecf20Sopenharmony_ci kaddr = (u8*)page_address(page); 2748c2ecf20Sopenharmony_cifast_descend_into_child_node: 2758c2ecf20Sopenharmony_ci /* Get to the index allocation block. */ 2768c2ecf20Sopenharmony_ci ia = (INDEX_ALLOCATION*)(kaddr + ((vcn << 2778c2ecf20Sopenharmony_ci idx_ni->itype.index.vcn_size_bits) & ~PAGE_MASK)); 2788c2ecf20Sopenharmony_ci /* Bounds checks. */ 2798c2ecf20Sopenharmony_ci if ((u8*)ia < kaddr || (u8*)ia > kaddr + PAGE_SIZE) { 2808c2ecf20Sopenharmony_ci ntfs_error(sb, "Out of bounds check failed. Corrupt inode " 2818c2ecf20Sopenharmony_ci "0x%lx or driver bug.", idx_ni->mft_no); 2828c2ecf20Sopenharmony_ci goto unm_err_out; 2838c2ecf20Sopenharmony_ci } 2848c2ecf20Sopenharmony_ci /* Catch multi sector transfer fixup errors. */ 2858c2ecf20Sopenharmony_ci if (unlikely(!ntfs_is_indx_record(ia->magic))) { 2868c2ecf20Sopenharmony_ci ntfs_error(sb, "Index record with vcn 0x%llx is corrupt. " 2878c2ecf20Sopenharmony_ci "Corrupt inode 0x%lx. Run chkdsk.", 2888c2ecf20Sopenharmony_ci (long long)vcn, idx_ni->mft_no); 2898c2ecf20Sopenharmony_ci goto unm_err_out; 2908c2ecf20Sopenharmony_ci } 2918c2ecf20Sopenharmony_ci if (sle64_to_cpu(ia->index_block_vcn) != vcn) { 2928c2ecf20Sopenharmony_ci ntfs_error(sb, "Actual VCN (0x%llx) of index buffer is " 2938c2ecf20Sopenharmony_ci "different from expected VCN (0x%llx). Inode " 2948c2ecf20Sopenharmony_ci "0x%lx is corrupt or driver bug.", 2958c2ecf20Sopenharmony_ci (unsigned long long) 2968c2ecf20Sopenharmony_ci sle64_to_cpu(ia->index_block_vcn), 2978c2ecf20Sopenharmony_ci (unsigned long long)vcn, idx_ni->mft_no); 2988c2ecf20Sopenharmony_ci goto unm_err_out; 2998c2ecf20Sopenharmony_ci } 3008c2ecf20Sopenharmony_ci if (le32_to_cpu(ia->index.allocated_size) + 0x18 != 3018c2ecf20Sopenharmony_ci idx_ni->itype.index.block_size) { 3028c2ecf20Sopenharmony_ci ntfs_error(sb, "Index buffer (VCN 0x%llx) of inode 0x%lx has " 3038c2ecf20Sopenharmony_ci "a size (%u) differing from the index " 3048c2ecf20Sopenharmony_ci "specified size (%u). Inode is corrupt or " 3058c2ecf20Sopenharmony_ci "driver bug.", (unsigned long long)vcn, 3068c2ecf20Sopenharmony_ci idx_ni->mft_no, 3078c2ecf20Sopenharmony_ci le32_to_cpu(ia->index.allocated_size) + 0x18, 3088c2ecf20Sopenharmony_ci idx_ni->itype.index.block_size); 3098c2ecf20Sopenharmony_ci goto unm_err_out; 3108c2ecf20Sopenharmony_ci } 3118c2ecf20Sopenharmony_ci index_end = (u8*)ia + idx_ni->itype.index.block_size; 3128c2ecf20Sopenharmony_ci if (index_end > kaddr + PAGE_SIZE) { 3138c2ecf20Sopenharmony_ci ntfs_error(sb, "Index buffer (VCN 0x%llx) of inode 0x%lx " 3148c2ecf20Sopenharmony_ci "crosses page boundary. Impossible! Cannot " 3158c2ecf20Sopenharmony_ci "access! This is probably a bug in the " 3168c2ecf20Sopenharmony_ci "driver.", (unsigned long long)vcn, 3178c2ecf20Sopenharmony_ci idx_ni->mft_no); 3188c2ecf20Sopenharmony_ci goto unm_err_out; 3198c2ecf20Sopenharmony_ci } 3208c2ecf20Sopenharmony_ci index_end = (u8*)&ia->index + le32_to_cpu(ia->index.index_length); 3218c2ecf20Sopenharmony_ci if (index_end > (u8*)ia + idx_ni->itype.index.block_size) { 3228c2ecf20Sopenharmony_ci ntfs_error(sb, "Size of index buffer (VCN 0x%llx) of inode " 3238c2ecf20Sopenharmony_ci "0x%lx exceeds maximum size.", 3248c2ecf20Sopenharmony_ci (unsigned long long)vcn, idx_ni->mft_no); 3258c2ecf20Sopenharmony_ci goto unm_err_out; 3268c2ecf20Sopenharmony_ci } 3278c2ecf20Sopenharmony_ci /* The first index entry. */ 3288c2ecf20Sopenharmony_ci ie = (INDEX_ENTRY*)((u8*)&ia->index + 3298c2ecf20Sopenharmony_ci le32_to_cpu(ia->index.entries_offset)); 3308c2ecf20Sopenharmony_ci /* 3318c2ecf20Sopenharmony_ci * Iterate similar to above big loop but applied to index buffer, thus 3328c2ecf20Sopenharmony_ci * loop until we exceed valid memory (corruption case) or until we 3338c2ecf20Sopenharmony_ci * reach the last entry. 3348c2ecf20Sopenharmony_ci */ 3358c2ecf20Sopenharmony_ci for (;; ie = (INDEX_ENTRY*)((u8*)ie + le16_to_cpu(ie->length))) { 3368c2ecf20Sopenharmony_ci /* Bounds checks. */ 3378c2ecf20Sopenharmony_ci if ((u8*)ie < (u8*)ia || (u8*)ie + 3388c2ecf20Sopenharmony_ci sizeof(INDEX_ENTRY_HEADER) > index_end || 3398c2ecf20Sopenharmony_ci (u8*)ie + le16_to_cpu(ie->length) > index_end) { 3408c2ecf20Sopenharmony_ci ntfs_error(sb, "Index entry out of bounds in inode " 3418c2ecf20Sopenharmony_ci "0x%lx.", idx_ni->mft_no); 3428c2ecf20Sopenharmony_ci goto unm_err_out; 3438c2ecf20Sopenharmony_ci } 3448c2ecf20Sopenharmony_ci /* 3458c2ecf20Sopenharmony_ci * The last entry cannot contain a key. It can however contain 3468c2ecf20Sopenharmony_ci * a pointer to a child node in the B+tree so we just break out. 3478c2ecf20Sopenharmony_ci */ 3488c2ecf20Sopenharmony_ci if (ie->flags & INDEX_ENTRY_END) 3498c2ecf20Sopenharmony_ci break; 3508c2ecf20Sopenharmony_ci /* Further bounds checks. */ 3518c2ecf20Sopenharmony_ci if ((u32)sizeof(INDEX_ENTRY_HEADER) + 3528c2ecf20Sopenharmony_ci le16_to_cpu(ie->key_length) > 3538c2ecf20Sopenharmony_ci le16_to_cpu(ie->data.vi.data_offset) || 3548c2ecf20Sopenharmony_ci (u32)le16_to_cpu(ie->data.vi.data_offset) + 3558c2ecf20Sopenharmony_ci le16_to_cpu(ie->data.vi.data_length) > 3568c2ecf20Sopenharmony_ci le16_to_cpu(ie->length)) { 3578c2ecf20Sopenharmony_ci ntfs_error(sb, "Index entry out of bounds in inode " 3588c2ecf20Sopenharmony_ci "0x%lx.", idx_ni->mft_no); 3598c2ecf20Sopenharmony_ci goto unm_err_out; 3608c2ecf20Sopenharmony_ci } 3618c2ecf20Sopenharmony_ci /* If the keys match perfectly, we setup @ictx and return 0. */ 3628c2ecf20Sopenharmony_ci if ((key_len == le16_to_cpu(ie->key_length)) && !memcmp(key, 3638c2ecf20Sopenharmony_ci &ie->key, key_len)) { 3648c2ecf20Sopenharmony_ciia_done: 3658c2ecf20Sopenharmony_ci ictx->is_in_root = false; 3668c2ecf20Sopenharmony_ci ictx->actx = NULL; 3678c2ecf20Sopenharmony_ci ictx->base_ni = NULL; 3688c2ecf20Sopenharmony_ci ictx->ia = ia; 3698c2ecf20Sopenharmony_ci ictx->page = page; 3708c2ecf20Sopenharmony_ci goto done; 3718c2ecf20Sopenharmony_ci } 3728c2ecf20Sopenharmony_ci /* 3738c2ecf20Sopenharmony_ci * Not a perfect match, need to do full blown collation so we 3748c2ecf20Sopenharmony_ci * know which way in the B+tree we have to go. 3758c2ecf20Sopenharmony_ci */ 3768c2ecf20Sopenharmony_ci rc = ntfs_collate(vol, idx_ni->itype.index.collation_rule, key, 3778c2ecf20Sopenharmony_ci key_len, &ie->key, le16_to_cpu(ie->key_length)); 3788c2ecf20Sopenharmony_ci /* 3798c2ecf20Sopenharmony_ci * If @key collates before the key of the current entry, there 3808c2ecf20Sopenharmony_ci * is definitely no such key in this index but we might need to 3818c2ecf20Sopenharmony_ci * descend into the B+tree so we just break out of the loop. 3828c2ecf20Sopenharmony_ci */ 3838c2ecf20Sopenharmony_ci if (rc == -1) 3848c2ecf20Sopenharmony_ci break; 3858c2ecf20Sopenharmony_ci /* 3868c2ecf20Sopenharmony_ci * A match should never happen as the memcmp() call should have 3878c2ecf20Sopenharmony_ci * cought it, but we still treat it correctly. 3888c2ecf20Sopenharmony_ci */ 3898c2ecf20Sopenharmony_ci if (!rc) 3908c2ecf20Sopenharmony_ci goto ia_done; 3918c2ecf20Sopenharmony_ci /* The keys are not equal, continue the search. */ 3928c2ecf20Sopenharmony_ci } 3938c2ecf20Sopenharmony_ci /* 3948c2ecf20Sopenharmony_ci * We have finished with this index buffer without success. Check for 3958c2ecf20Sopenharmony_ci * the presence of a child node and if not present return -ENOENT. 3968c2ecf20Sopenharmony_ci */ 3978c2ecf20Sopenharmony_ci if (!(ie->flags & INDEX_ENTRY_NODE)) { 3988c2ecf20Sopenharmony_ci ntfs_debug("Entry not found."); 3998c2ecf20Sopenharmony_ci err = -ENOENT; 4008c2ecf20Sopenharmony_ci goto ia_done; 4018c2ecf20Sopenharmony_ci } 4028c2ecf20Sopenharmony_ci if ((ia->index.flags & NODE_MASK) == LEAF_NODE) { 4038c2ecf20Sopenharmony_ci ntfs_error(sb, "Index entry with child node found in a leaf " 4048c2ecf20Sopenharmony_ci "node in inode 0x%lx.", idx_ni->mft_no); 4058c2ecf20Sopenharmony_ci goto unm_err_out; 4068c2ecf20Sopenharmony_ci } 4078c2ecf20Sopenharmony_ci /* Child node present, descend into it. */ 4088c2ecf20Sopenharmony_ci old_vcn = vcn; 4098c2ecf20Sopenharmony_ci vcn = sle64_to_cpup((sle64*)((u8*)ie + le16_to_cpu(ie->length) - 8)); 4108c2ecf20Sopenharmony_ci if (vcn >= 0) { 4118c2ecf20Sopenharmony_ci /* 4128c2ecf20Sopenharmony_ci * If vcn is in the same page cache page as old_vcn we recycle 4138c2ecf20Sopenharmony_ci * the mapped page. 4148c2ecf20Sopenharmony_ci */ 4158c2ecf20Sopenharmony_ci if (old_vcn << vol->cluster_size_bits >> 4168c2ecf20Sopenharmony_ci PAGE_SHIFT == vcn << 4178c2ecf20Sopenharmony_ci vol->cluster_size_bits >> 4188c2ecf20Sopenharmony_ci PAGE_SHIFT) 4198c2ecf20Sopenharmony_ci goto fast_descend_into_child_node; 4208c2ecf20Sopenharmony_ci unlock_page(page); 4218c2ecf20Sopenharmony_ci ntfs_unmap_page(page); 4228c2ecf20Sopenharmony_ci goto descend_into_child_node; 4238c2ecf20Sopenharmony_ci } 4248c2ecf20Sopenharmony_ci ntfs_error(sb, "Negative child node vcn in inode 0x%lx.", 4258c2ecf20Sopenharmony_ci idx_ni->mft_no); 4268c2ecf20Sopenharmony_ciunm_err_out: 4278c2ecf20Sopenharmony_ci unlock_page(page); 4288c2ecf20Sopenharmony_ci ntfs_unmap_page(page); 4298c2ecf20Sopenharmony_cierr_out: 4308c2ecf20Sopenharmony_ci if (!err) 4318c2ecf20Sopenharmony_ci err = -EIO; 4328c2ecf20Sopenharmony_ci if (actx) 4338c2ecf20Sopenharmony_ci ntfs_attr_put_search_ctx(actx); 4348c2ecf20Sopenharmony_ci if (m) 4358c2ecf20Sopenharmony_ci unmap_mft_record(base_ni); 4368c2ecf20Sopenharmony_ci return err; 4378c2ecf20Sopenharmony_ciidx_err_out: 4388c2ecf20Sopenharmony_ci ntfs_error(sb, "Corrupt index. Aborting lookup."); 4398c2ecf20Sopenharmony_ci goto err_out; 4408c2ecf20Sopenharmony_ci} 441