162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * index.c - NTFS kernel index handling. Part of the Linux-NTFS project. 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (c) 2004-2005 Anton Altaparmakov 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <linux/slab.h> 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include "aops.h" 1162306a36Sopenharmony_ci#include "collate.h" 1262306a36Sopenharmony_ci#include "debug.h" 1362306a36Sopenharmony_ci#include "index.h" 1462306a36Sopenharmony_ci#include "ntfs.h" 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci/** 1762306a36Sopenharmony_ci * ntfs_index_ctx_get - allocate and initialize a new index context 1862306a36Sopenharmony_ci * @idx_ni: ntfs index inode with which to initialize the context 1962306a36Sopenharmony_ci * 2062306a36Sopenharmony_ci * Allocate a new index context, initialize it with @idx_ni and return it. 2162306a36Sopenharmony_ci * Return NULL if allocation failed. 2262306a36Sopenharmony_ci * 2362306a36Sopenharmony_ci * Locking: Caller must hold i_mutex on the index inode. 2462306a36Sopenharmony_ci */ 2562306a36Sopenharmony_cintfs_index_context *ntfs_index_ctx_get(ntfs_inode *idx_ni) 2662306a36Sopenharmony_ci{ 2762306a36Sopenharmony_ci ntfs_index_context *ictx; 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci ictx = kmem_cache_alloc(ntfs_index_ctx_cache, GFP_NOFS); 3062306a36Sopenharmony_ci if (ictx) 3162306a36Sopenharmony_ci *ictx = (ntfs_index_context){ .idx_ni = idx_ni }; 3262306a36Sopenharmony_ci return ictx; 3362306a36Sopenharmony_ci} 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci/** 3662306a36Sopenharmony_ci * ntfs_index_ctx_put - release an index context 3762306a36Sopenharmony_ci * @ictx: index context to free 3862306a36Sopenharmony_ci * 3962306a36Sopenharmony_ci * Release the index context @ictx, releasing all associated resources. 4062306a36Sopenharmony_ci * 4162306a36Sopenharmony_ci * Locking: Caller must hold i_mutex on the index inode. 4262306a36Sopenharmony_ci */ 4362306a36Sopenharmony_civoid ntfs_index_ctx_put(ntfs_index_context *ictx) 4462306a36Sopenharmony_ci{ 4562306a36Sopenharmony_ci if (ictx->entry) { 4662306a36Sopenharmony_ci if (ictx->is_in_root) { 4762306a36Sopenharmony_ci if (ictx->actx) 4862306a36Sopenharmony_ci ntfs_attr_put_search_ctx(ictx->actx); 4962306a36Sopenharmony_ci if (ictx->base_ni) 5062306a36Sopenharmony_ci unmap_mft_record(ictx->base_ni); 5162306a36Sopenharmony_ci } else { 5262306a36Sopenharmony_ci struct page *page = ictx->page; 5362306a36Sopenharmony_ci if (page) { 5462306a36Sopenharmony_ci BUG_ON(!PageLocked(page)); 5562306a36Sopenharmony_ci unlock_page(page); 5662306a36Sopenharmony_ci ntfs_unmap_page(page); 5762306a36Sopenharmony_ci } 5862306a36Sopenharmony_ci } 5962306a36Sopenharmony_ci } 6062306a36Sopenharmony_ci kmem_cache_free(ntfs_index_ctx_cache, ictx); 6162306a36Sopenharmony_ci return; 6262306a36Sopenharmony_ci} 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci/** 6562306a36Sopenharmony_ci * ntfs_index_lookup - find a key in an index and return its index entry 6662306a36Sopenharmony_ci * @key: [IN] key for which to search in the index 6762306a36Sopenharmony_ci * @key_len: [IN] length of @key in bytes 6862306a36Sopenharmony_ci * @ictx: [IN/OUT] context describing the index and the returned entry 6962306a36Sopenharmony_ci * 7062306a36Sopenharmony_ci * Before calling ntfs_index_lookup(), @ictx must have been obtained from a 7162306a36Sopenharmony_ci * call to ntfs_index_ctx_get(). 7262306a36Sopenharmony_ci * 7362306a36Sopenharmony_ci * Look for the @key in the index specified by the index lookup context @ictx. 7462306a36Sopenharmony_ci * ntfs_index_lookup() walks the contents of the index looking for the @key. 7562306a36Sopenharmony_ci * 7662306a36Sopenharmony_ci * If the @key is found in the index, 0 is returned and @ictx is setup to 7762306a36Sopenharmony_ci * describe the index entry containing the matching @key. @ictx->entry is the 7862306a36Sopenharmony_ci * index entry and @ictx->data and @ictx->data_len are the index entry data and 7962306a36Sopenharmony_ci * its length in bytes, respectively. 8062306a36Sopenharmony_ci * 8162306a36Sopenharmony_ci * If the @key is not found in the index, -ENOENT is returned and @ictx is 8262306a36Sopenharmony_ci * setup to describe the index entry whose key collates immediately after the 8362306a36Sopenharmony_ci * search @key, i.e. this is the position in the index at which an index entry 8462306a36Sopenharmony_ci * with a key of @key would need to be inserted. 8562306a36Sopenharmony_ci * 8662306a36Sopenharmony_ci * If an error occurs return the negative error code and @ictx is left 8762306a36Sopenharmony_ci * untouched. 8862306a36Sopenharmony_ci * 8962306a36Sopenharmony_ci * When finished with the entry and its data, call ntfs_index_ctx_put() to free 9062306a36Sopenharmony_ci * the context and other associated resources. 9162306a36Sopenharmony_ci * 9262306a36Sopenharmony_ci * If the index entry was modified, call flush_dcache_index_entry_page() 9362306a36Sopenharmony_ci * immediately after the modification and either ntfs_index_entry_mark_dirty() 9462306a36Sopenharmony_ci * or ntfs_index_entry_write() before the call to ntfs_index_ctx_put() to 9562306a36Sopenharmony_ci * ensure that the changes are written to disk. 9662306a36Sopenharmony_ci * 9762306a36Sopenharmony_ci * Locking: - Caller must hold i_mutex on the index inode. 9862306a36Sopenharmony_ci * - Each page cache page in the index allocation mapping must be 9962306a36Sopenharmony_ci * locked whilst being accessed otherwise we may find a corrupt 10062306a36Sopenharmony_ci * page due to it being under ->writepage at the moment which 10162306a36Sopenharmony_ci * applies the mst protection fixups before writing out and then 10262306a36Sopenharmony_ci * removes them again after the write is complete after which it 10362306a36Sopenharmony_ci * unlocks the page. 10462306a36Sopenharmony_ci */ 10562306a36Sopenharmony_ciint ntfs_index_lookup(const void *key, const int key_len, 10662306a36Sopenharmony_ci ntfs_index_context *ictx) 10762306a36Sopenharmony_ci{ 10862306a36Sopenharmony_ci VCN vcn, old_vcn; 10962306a36Sopenharmony_ci ntfs_inode *idx_ni = ictx->idx_ni; 11062306a36Sopenharmony_ci ntfs_volume *vol = idx_ni->vol; 11162306a36Sopenharmony_ci struct super_block *sb = vol->sb; 11262306a36Sopenharmony_ci ntfs_inode *base_ni = idx_ni->ext.base_ntfs_ino; 11362306a36Sopenharmony_ci MFT_RECORD *m; 11462306a36Sopenharmony_ci INDEX_ROOT *ir; 11562306a36Sopenharmony_ci INDEX_ENTRY *ie; 11662306a36Sopenharmony_ci INDEX_ALLOCATION *ia; 11762306a36Sopenharmony_ci u8 *index_end, *kaddr; 11862306a36Sopenharmony_ci ntfs_attr_search_ctx *actx; 11962306a36Sopenharmony_ci struct address_space *ia_mapping; 12062306a36Sopenharmony_ci struct page *page; 12162306a36Sopenharmony_ci int rc, err = 0; 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci ntfs_debug("Entering."); 12462306a36Sopenharmony_ci BUG_ON(!NInoAttr(idx_ni)); 12562306a36Sopenharmony_ci BUG_ON(idx_ni->type != AT_INDEX_ALLOCATION); 12662306a36Sopenharmony_ci BUG_ON(idx_ni->nr_extents != -1); 12762306a36Sopenharmony_ci BUG_ON(!base_ni); 12862306a36Sopenharmony_ci BUG_ON(!key); 12962306a36Sopenharmony_ci BUG_ON(key_len <= 0); 13062306a36Sopenharmony_ci if (!ntfs_is_collation_rule_supported( 13162306a36Sopenharmony_ci idx_ni->itype.index.collation_rule)) { 13262306a36Sopenharmony_ci ntfs_error(sb, "Index uses unsupported collation rule 0x%x. " 13362306a36Sopenharmony_ci "Aborting lookup.", le32_to_cpu( 13462306a36Sopenharmony_ci idx_ni->itype.index.collation_rule)); 13562306a36Sopenharmony_ci return -EOPNOTSUPP; 13662306a36Sopenharmony_ci } 13762306a36Sopenharmony_ci /* Get hold of the mft record for the index inode. */ 13862306a36Sopenharmony_ci m = map_mft_record(base_ni); 13962306a36Sopenharmony_ci if (IS_ERR(m)) { 14062306a36Sopenharmony_ci ntfs_error(sb, "map_mft_record() failed with error code %ld.", 14162306a36Sopenharmony_ci -PTR_ERR(m)); 14262306a36Sopenharmony_ci return PTR_ERR(m); 14362306a36Sopenharmony_ci } 14462306a36Sopenharmony_ci actx = ntfs_attr_get_search_ctx(base_ni, m); 14562306a36Sopenharmony_ci if (unlikely(!actx)) { 14662306a36Sopenharmony_ci err = -ENOMEM; 14762306a36Sopenharmony_ci goto err_out; 14862306a36Sopenharmony_ci } 14962306a36Sopenharmony_ci /* Find the index root attribute in the mft record. */ 15062306a36Sopenharmony_ci err = ntfs_attr_lookup(AT_INDEX_ROOT, idx_ni->name, idx_ni->name_len, 15162306a36Sopenharmony_ci CASE_SENSITIVE, 0, NULL, 0, actx); 15262306a36Sopenharmony_ci if (unlikely(err)) { 15362306a36Sopenharmony_ci if (err == -ENOENT) { 15462306a36Sopenharmony_ci ntfs_error(sb, "Index root attribute missing in inode " 15562306a36Sopenharmony_ci "0x%lx.", idx_ni->mft_no); 15662306a36Sopenharmony_ci err = -EIO; 15762306a36Sopenharmony_ci } 15862306a36Sopenharmony_ci goto err_out; 15962306a36Sopenharmony_ci } 16062306a36Sopenharmony_ci /* Get to the index root value (it has been verified in read_inode). */ 16162306a36Sopenharmony_ci ir = (INDEX_ROOT*)((u8*)actx->attr + 16262306a36Sopenharmony_ci le16_to_cpu(actx->attr->data.resident.value_offset)); 16362306a36Sopenharmony_ci index_end = (u8*)&ir->index + le32_to_cpu(ir->index.index_length); 16462306a36Sopenharmony_ci /* The first index entry. */ 16562306a36Sopenharmony_ci ie = (INDEX_ENTRY*)((u8*)&ir->index + 16662306a36Sopenharmony_ci le32_to_cpu(ir->index.entries_offset)); 16762306a36Sopenharmony_ci /* 16862306a36Sopenharmony_ci * Loop until we exceed valid memory (corruption case) or until we 16962306a36Sopenharmony_ci * reach the last entry. 17062306a36Sopenharmony_ci */ 17162306a36Sopenharmony_ci for (;; ie = (INDEX_ENTRY*)((u8*)ie + le16_to_cpu(ie->length))) { 17262306a36Sopenharmony_ci /* Bounds checks. */ 17362306a36Sopenharmony_ci if ((u8*)ie < (u8*)actx->mrec || (u8*)ie + 17462306a36Sopenharmony_ci sizeof(INDEX_ENTRY_HEADER) > index_end || 17562306a36Sopenharmony_ci (u8*)ie + le16_to_cpu(ie->length) > index_end) 17662306a36Sopenharmony_ci goto idx_err_out; 17762306a36Sopenharmony_ci /* 17862306a36Sopenharmony_ci * The last entry cannot contain a key. It can however contain 17962306a36Sopenharmony_ci * a pointer to a child node in the B+tree so we just break out. 18062306a36Sopenharmony_ci */ 18162306a36Sopenharmony_ci if (ie->flags & INDEX_ENTRY_END) 18262306a36Sopenharmony_ci break; 18362306a36Sopenharmony_ci /* Further bounds checks. */ 18462306a36Sopenharmony_ci if ((u32)sizeof(INDEX_ENTRY_HEADER) + 18562306a36Sopenharmony_ci le16_to_cpu(ie->key_length) > 18662306a36Sopenharmony_ci le16_to_cpu(ie->data.vi.data_offset) || 18762306a36Sopenharmony_ci (u32)le16_to_cpu(ie->data.vi.data_offset) + 18862306a36Sopenharmony_ci le16_to_cpu(ie->data.vi.data_length) > 18962306a36Sopenharmony_ci le16_to_cpu(ie->length)) 19062306a36Sopenharmony_ci goto idx_err_out; 19162306a36Sopenharmony_ci /* If the keys match perfectly, we setup @ictx and return 0. */ 19262306a36Sopenharmony_ci if ((key_len == le16_to_cpu(ie->key_length)) && !memcmp(key, 19362306a36Sopenharmony_ci &ie->key, key_len)) { 19462306a36Sopenharmony_ciir_done: 19562306a36Sopenharmony_ci ictx->is_in_root = true; 19662306a36Sopenharmony_ci ictx->ir = ir; 19762306a36Sopenharmony_ci ictx->actx = actx; 19862306a36Sopenharmony_ci ictx->base_ni = base_ni; 19962306a36Sopenharmony_ci ictx->ia = NULL; 20062306a36Sopenharmony_ci ictx->page = NULL; 20162306a36Sopenharmony_cidone: 20262306a36Sopenharmony_ci ictx->entry = ie; 20362306a36Sopenharmony_ci ictx->data = (u8*)ie + 20462306a36Sopenharmony_ci le16_to_cpu(ie->data.vi.data_offset); 20562306a36Sopenharmony_ci ictx->data_len = le16_to_cpu(ie->data.vi.data_length); 20662306a36Sopenharmony_ci ntfs_debug("Done."); 20762306a36Sopenharmony_ci return err; 20862306a36Sopenharmony_ci } 20962306a36Sopenharmony_ci /* 21062306a36Sopenharmony_ci * Not a perfect match, need to do full blown collation so we 21162306a36Sopenharmony_ci * know which way in the B+tree we have to go. 21262306a36Sopenharmony_ci */ 21362306a36Sopenharmony_ci rc = ntfs_collate(vol, idx_ni->itype.index.collation_rule, key, 21462306a36Sopenharmony_ci key_len, &ie->key, le16_to_cpu(ie->key_length)); 21562306a36Sopenharmony_ci /* 21662306a36Sopenharmony_ci * If @key collates before the key of the current entry, there 21762306a36Sopenharmony_ci * is definitely no such key in this index but we might need to 21862306a36Sopenharmony_ci * descend into the B+tree so we just break out of the loop. 21962306a36Sopenharmony_ci */ 22062306a36Sopenharmony_ci if (rc == -1) 22162306a36Sopenharmony_ci break; 22262306a36Sopenharmony_ci /* 22362306a36Sopenharmony_ci * A match should never happen as the memcmp() call should have 22462306a36Sopenharmony_ci * cought it, but we still treat it correctly. 22562306a36Sopenharmony_ci */ 22662306a36Sopenharmony_ci if (!rc) 22762306a36Sopenharmony_ci goto ir_done; 22862306a36Sopenharmony_ci /* The keys are not equal, continue the search. */ 22962306a36Sopenharmony_ci } 23062306a36Sopenharmony_ci /* 23162306a36Sopenharmony_ci * We have finished with this index without success. Check for the 23262306a36Sopenharmony_ci * presence of a child node and if not present setup @ictx and return 23362306a36Sopenharmony_ci * -ENOENT. 23462306a36Sopenharmony_ci */ 23562306a36Sopenharmony_ci if (!(ie->flags & INDEX_ENTRY_NODE)) { 23662306a36Sopenharmony_ci ntfs_debug("Entry not found."); 23762306a36Sopenharmony_ci err = -ENOENT; 23862306a36Sopenharmony_ci goto ir_done; 23962306a36Sopenharmony_ci } /* Child node present, descend into it. */ 24062306a36Sopenharmony_ci /* Consistency check: Verify that an index allocation exists. */ 24162306a36Sopenharmony_ci if (!NInoIndexAllocPresent(idx_ni)) { 24262306a36Sopenharmony_ci ntfs_error(sb, "No index allocation attribute but index entry " 24362306a36Sopenharmony_ci "requires one. Inode 0x%lx is corrupt or " 24462306a36Sopenharmony_ci "driver bug.", idx_ni->mft_no); 24562306a36Sopenharmony_ci goto err_out; 24662306a36Sopenharmony_ci } 24762306a36Sopenharmony_ci /* Get the starting vcn of the index_block holding the child node. */ 24862306a36Sopenharmony_ci vcn = sle64_to_cpup((sle64*)((u8*)ie + le16_to_cpu(ie->length) - 8)); 24962306a36Sopenharmony_ci ia_mapping = VFS_I(idx_ni)->i_mapping; 25062306a36Sopenharmony_ci /* 25162306a36Sopenharmony_ci * We are done with the index root and the mft record. Release them, 25262306a36Sopenharmony_ci * otherwise we deadlock with ntfs_map_page(). 25362306a36Sopenharmony_ci */ 25462306a36Sopenharmony_ci ntfs_attr_put_search_ctx(actx); 25562306a36Sopenharmony_ci unmap_mft_record(base_ni); 25662306a36Sopenharmony_ci m = NULL; 25762306a36Sopenharmony_ci actx = NULL; 25862306a36Sopenharmony_cidescend_into_child_node: 25962306a36Sopenharmony_ci /* 26062306a36Sopenharmony_ci * Convert vcn to index into the index allocation attribute in units 26162306a36Sopenharmony_ci * of PAGE_SIZE and map the page cache page, reading it from 26262306a36Sopenharmony_ci * disk if necessary. 26362306a36Sopenharmony_ci */ 26462306a36Sopenharmony_ci page = ntfs_map_page(ia_mapping, vcn << 26562306a36Sopenharmony_ci idx_ni->itype.index.vcn_size_bits >> PAGE_SHIFT); 26662306a36Sopenharmony_ci if (IS_ERR(page)) { 26762306a36Sopenharmony_ci ntfs_error(sb, "Failed to map index page, error %ld.", 26862306a36Sopenharmony_ci -PTR_ERR(page)); 26962306a36Sopenharmony_ci err = PTR_ERR(page); 27062306a36Sopenharmony_ci goto err_out; 27162306a36Sopenharmony_ci } 27262306a36Sopenharmony_ci lock_page(page); 27362306a36Sopenharmony_ci kaddr = (u8*)page_address(page); 27462306a36Sopenharmony_cifast_descend_into_child_node: 27562306a36Sopenharmony_ci /* Get to the index allocation block. */ 27662306a36Sopenharmony_ci ia = (INDEX_ALLOCATION*)(kaddr + ((vcn << 27762306a36Sopenharmony_ci idx_ni->itype.index.vcn_size_bits) & ~PAGE_MASK)); 27862306a36Sopenharmony_ci /* Bounds checks. */ 27962306a36Sopenharmony_ci if ((u8*)ia < kaddr || (u8*)ia > kaddr + PAGE_SIZE) { 28062306a36Sopenharmony_ci ntfs_error(sb, "Out of bounds check failed. Corrupt inode " 28162306a36Sopenharmony_ci "0x%lx or driver bug.", idx_ni->mft_no); 28262306a36Sopenharmony_ci goto unm_err_out; 28362306a36Sopenharmony_ci } 28462306a36Sopenharmony_ci /* Catch multi sector transfer fixup errors. */ 28562306a36Sopenharmony_ci if (unlikely(!ntfs_is_indx_record(ia->magic))) { 28662306a36Sopenharmony_ci ntfs_error(sb, "Index record with vcn 0x%llx is corrupt. " 28762306a36Sopenharmony_ci "Corrupt inode 0x%lx. Run chkdsk.", 28862306a36Sopenharmony_ci (long long)vcn, idx_ni->mft_no); 28962306a36Sopenharmony_ci goto unm_err_out; 29062306a36Sopenharmony_ci } 29162306a36Sopenharmony_ci if (sle64_to_cpu(ia->index_block_vcn) != vcn) { 29262306a36Sopenharmony_ci ntfs_error(sb, "Actual VCN (0x%llx) of index buffer is " 29362306a36Sopenharmony_ci "different from expected VCN (0x%llx). Inode " 29462306a36Sopenharmony_ci "0x%lx is corrupt or driver bug.", 29562306a36Sopenharmony_ci (unsigned long long) 29662306a36Sopenharmony_ci sle64_to_cpu(ia->index_block_vcn), 29762306a36Sopenharmony_ci (unsigned long long)vcn, idx_ni->mft_no); 29862306a36Sopenharmony_ci goto unm_err_out; 29962306a36Sopenharmony_ci } 30062306a36Sopenharmony_ci if (le32_to_cpu(ia->index.allocated_size) + 0x18 != 30162306a36Sopenharmony_ci idx_ni->itype.index.block_size) { 30262306a36Sopenharmony_ci ntfs_error(sb, "Index buffer (VCN 0x%llx) of inode 0x%lx has " 30362306a36Sopenharmony_ci "a size (%u) differing from the index " 30462306a36Sopenharmony_ci "specified size (%u). Inode is corrupt or " 30562306a36Sopenharmony_ci "driver bug.", (unsigned long long)vcn, 30662306a36Sopenharmony_ci idx_ni->mft_no, 30762306a36Sopenharmony_ci le32_to_cpu(ia->index.allocated_size) + 0x18, 30862306a36Sopenharmony_ci idx_ni->itype.index.block_size); 30962306a36Sopenharmony_ci goto unm_err_out; 31062306a36Sopenharmony_ci } 31162306a36Sopenharmony_ci index_end = (u8*)ia + idx_ni->itype.index.block_size; 31262306a36Sopenharmony_ci if (index_end > kaddr + PAGE_SIZE) { 31362306a36Sopenharmony_ci ntfs_error(sb, "Index buffer (VCN 0x%llx) of inode 0x%lx " 31462306a36Sopenharmony_ci "crosses page boundary. Impossible! Cannot " 31562306a36Sopenharmony_ci "access! This is probably a bug in the " 31662306a36Sopenharmony_ci "driver.", (unsigned long long)vcn, 31762306a36Sopenharmony_ci idx_ni->mft_no); 31862306a36Sopenharmony_ci goto unm_err_out; 31962306a36Sopenharmony_ci } 32062306a36Sopenharmony_ci index_end = (u8*)&ia->index + le32_to_cpu(ia->index.index_length); 32162306a36Sopenharmony_ci if (index_end > (u8*)ia + idx_ni->itype.index.block_size) { 32262306a36Sopenharmony_ci ntfs_error(sb, "Size of index buffer (VCN 0x%llx) of inode " 32362306a36Sopenharmony_ci "0x%lx exceeds maximum size.", 32462306a36Sopenharmony_ci (unsigned long long)vcn, idx_ni->mft_no); 32562306a36Sopenharmony_ci goto unm_err_out; 32662306a36Sopenharmony_ci } 32762306a36Sopenharmony_ci /* The first index entry. */ 32862306a36Sopenharmony_ci ie = (INDEX_ENTRY*)((u8*)&ia->index + 32962306a36Sopenharmony_ci le32_to_cpu(ia->index.entries_offset)); 33062306a36Sopenharmony_ci /* 33162306a36Sopenharmony_ci * Iterate similar to above big loop but applied to index buffer, thus 33262306a36Sopenharmony_ci * loop until we exceed valid memory (corruption case) or until we 33362306a36Sopenharmony_ci * reach the last entry. 33462306a36Sopenharmony_ci */ 33562306a36Sopenharmony_ci for (;; ie = (INDEX_ENTRY*)((u8*)ie + le16_to_cpu(ie->length))) { 33662306a36Sopenharmony_ci /* Bounds checks. */ 33762306a36Sopenharmony_ci if ((u8*)ie < (u8*)ia || (u8*)ie + 33862306a36Sopenharmony_ci sizeof(INDEX_ENTRY_HEADER) > index_end || 33962306a36Sopenharmony_ci (u8*)ie + le16_to_cpu(ie->length) > index_end) { 34062306a36Sopenharmony_ci ntfs_error(sb, "Index entry out of bounds in inode " 34162306a36Sopenharmony_ci "0x%lx.", idx_ni->mft_no); 34262306a36Sopenharmony_ci goto unm_err_out; 34362306a36Sopenharmony_ci } 34462306a36Sopenharmony_ci /* 34562306a36Sopenharmony_ci * The last entry cannot contain a key. It can however contain 34662306a36Sopenharmony_ci * a pointer to a child node in the B+tree so we just break out. 34762306a36Sopenharmony_ci */ 34862306a36Sopenharmony_ci if (ie->flags & INDEX_ENTRY_END) 34962306a36Sopenharmony_ci break; 35062306a36Sopenharmony_ci /* Further bounds checks. */ 35162306a36Sopenharmony_ci if ((u32)sizeof(INDEX_ENTRY_HEADER) + 35262306a36Sopenharmony_ci le16_to_cpu(ie->key_length) > 35362306a36Sopenharmony_ci le16_to_cpu(ie->data.vi.data_offset) || 35462306a36Sopenharmony_ci (u32)le16_to_cpu(ie->data.vi.data_offset) + 35562306a36Sopenharmony_ci le16_to_cpu(ie->data.vi.data_length) > 35662306a36Sopenharmony_ci le16_to_cpu(ie->length)) { 35762306a36Sopenharmony_ci ntfs_error(sb, "Index entry out of bounds in inode " 35862306a36Sopenharmony_ci "0x%lx.", idx_ni->mft_no); 35962306a36Sopenharmony_ci goto unm_err_out; 36062306a36Sopenharmony_ci } 36162306a36Sopenharmony_ci /* If the keys match perfectly, we setup @ictx and return 0. */ 36262306a36Sopenharmony_ci if ((key_len == le16_to_cpu(ie->key_length)) && !memcmp(key, 36362306a36Sopenharmony_ci &ie->key, key_len)) { 36462306a36Sopenharmony_ciia_done: 36562306a36Sopenharmony_ci ictx->is_in_root = false; 36662306a36Sopenharmony_ci ictx->actx = NULL; 36762306a36Sopenharmony_ci ictx->base_ni = NULL; 36862306a36Sopenharmony_ci ictx->ia = ia; 36962306a36Sopenharmony_ci ictx->page = page; 37062306a36Sopenharmony_ci goto done; 37162306a36Sopenharmony_ci } 37262306a36Sopenharmony_ci /* 37362306a36Sopenharmony_ci * Not a perfect match, need to do full blown collation so we 37462306a36Sopenharmony_ci * know which way in the B+tree we have to go. 37562306a36Sopenharmony_ci */ 37662306a36Sopenharmony_ci rc = ntfs_collate(vol, idx_ni->itype.index.collation_rule, key, 37762306a36Sopenharmony_ci key_len, &ie->key, le16_to_cpu(ie->key_length)); 37862306a36Sopenharmony_ci /* 37962306a36Sopenharmony_ci * If @key collates before the key of the current entry, there 38062306a36Sopenharmony_ci * is definitely no such key in this index but we might need to 38162306a36Sopenharmony_ci * descend into the B+tree so we just break out of the loop. 38262306a36Sopenharmony_ci */ 38362306a36Sopenharmony_ci if (rc == -1) 38462306a36Sopenharmony_ci break; 38562306a36Sopenharmony_ci /* 38662306a36Sopenharmony_ci * A match should never happen as the memcmp() call should have 38762306a36Sopenharmony_ci * cought it, but we still treat it correctly. 38862306a36Sopenharmony_ci */ 38962306a36Sopenharmony_ci if (!rc) 39062306a36Sopenharmony_ci goto ia_done; 39162306a36Sopenharmony_ci /* The keys are not equal, continue the search. */ 39262306a36Sopenharmony_ci } 39362306a36Sopenharmony_ci /* 39462306a36Sopenharmony_ci * We have finished with this index buffer without success. Check for 39562306a36Sopenharmony_ci * the presence of a child node and if not present return -ENOENT. 39662306a36Sopenharmony_ci */ 39762306a36Sopenharmony_ci if (!(ie->flags & INDEX_ENTRY_NODE)) { 39862306a36Sopenharmony_ci ntfs_debug("Entry not found."); 39962306a36Sopenharmony_ci err = -ENOENT; 40062306a36Sopenharmony_ci goto ia_done; 40162306a36Sopenharmony_ci } 40262306a36Sopenharmony_ci if ((ia->index.flags & NODE_MASK) == LEAF_NODE) { 40362306a36Sopenharmony_ci ntfs_error(sb, "Index entry with child node found in a leaf " 40462306a36Sopenharmony_ci "node in inode 0x%lx.", idx_ni->mft_no); 40562306a36Sopenharmony_ci goto unm_err_out; 40662306a36Sopenharmony_ci } 40762306a36Sopenharmony_ci /* Child node present, descend into it. */ 40862306a36Sopenharmony_ci old_vcn = vcn; 40962306a36Sopenharmony_ci vcn = sle64_to_cpup((sle64*)((u8*)ie + le16_to_cpu(ie->length) - 8)); 41062306a36Sopenharmony_ci if (vcn >= 0) { 41162306a36Sopenharmony_ci /* 41262306a36Sopenharmony_ci * If vcn is in the same page cache page as old_vcn we recycle 41362306a36Sopenharmony_ci * the mapped page. 41462306a36Sopenharmony_ci */ 41562306a36Sopenharmony_ci if (old_vcn << vol->cluster_size_bits >> 41662306a36Sopenharmony_ci PAGE_SHIFT == vcn << 41762306a36Sopenharmony_ci vol->cluster_size_bits >> 41862306a36Sopenharmony_ci PAGE_SHIFT) 41962306a36Sopenharmony_ci goto fast_descend_into_child_node; 42062306a36Sopenharmony_ci unlock_page(page); 42162306a36Sopenharmony_ci ntfs_unmap_page(page); 42262306a36Sopenharmony_ci goto descend_into_child_node; 42362306a36Sopenharmony_ci } 42462306a36Sopenharmony_ci ntfs_error(sb, "Negative child node vcn in inode 0x%lx.", 42562306a36Sopenharmony_ci idx_ni->mft_no); 42662306a36Sopenharmony_ciunm_err_out: 42762306a36Sopenharmony_ci unlock_page(page); 42862306a36Sopenharmony_ci ntfs_unmap_page(page); 42962306a36Sopenharmony_cierr_out: 43062306a36Sopenharmony_ci if (!err) 43162306a36Sopenharmony_ci err = -EIO; 43262306a36Sopenharmony_ci if (actx) 43362306a36Sopenharmony_ci ntfs_attr_put_search_ctx(actx); 43462306a36Sopenharmony_ci if (m) 43562306a36Sopenharmony_ci unmap_mft_record(base_ni); 43662306a36Sopenharmony_ci return err; 43762306a36Sopenharmony_ciidx_err_out: 43862306a36Sopenharmony_ci ntfs_error(sb, "Corrupt index. Aborting lookup."); 43962306a36Sopenharmony_ci goto err_out; 44062306a36Sopenharmony_ci} 441