/** * ntfs_index_ctx_reinit - reinitialize an index context * @icx: index context to reinitialize * * Reinitialize the index context @icx so it can be used for ntfs_index_lookup. */ void ntfs_index_ctx_reinit(ntfs_index_context *icx) { ntfs_log_trace("Entering\n"); ntfs_index_ctx_free(icx); *icx = (ntfs_index_context) { .ni = icx->ni, .name = icx->name, .name_len = icx->name_len, }; } static VCN *ntfs_ie_get_vcn_addr(INDEX_ENTRY *ie) { return (VCN *)((u8 *)ie + le16_to_cpu(ie->length) - sizeof(VCN)); } /** * Get the subnode vcn to which the index entry refers. */ VCN ntfs_ie_get_vcn(INDEX_ENTRY *ie) { return sle64_to_cpup(ntfs_ie_get_vcn_addr(ie)); } static INDEX_ENTRY *ntfs_ie_get_first(INDEX_HEADER *ih) { return (INDEX_ENTRY *)((u8 *)ih + le32_to_cpu(ih->entries_offset)); } static INDEX_ENTRY *ntfs_ie_get_next(INDEX_ENTRY *ie) { return (INDEX_ENTRY *)((char *)ie + le16_to_cpu(ie->length)); } static u8 *ntfs_ie_get_end(INDEX_HEADER *ih) { /* FIXME: check if it isn't overflowing the index block size */ return (u8 *)ih + le32_to_cpu(ih->index_length); } static int ntfs_ie_end(INDEX_ENTRY *ie) { return ie->ie_flags & INDEX_ENTRY_END || !ie->length; } /** * Find the last entry in the index block */ static INDEX_ENTRY *ntfs_ie_get_last(INDEX_ENTRY *ie, char *ies_end) { ntfs_log_trace("Entering\n"); while ((char *)ie < ies_end && !ntfs_ie_end(ie)) ie = ntfs_ie_get_next(ie); return ie; }
void ntfs_ih_filename_dump(INDEX_HEADER *ih) { INDEX_ENTRY *ie; ntfs_log_trace("Entering\n"); ie = ntfs_ie_get_first(ih); while (!ntfs_ie_end(ie)) { ntfs_ie_filename_dump(ie); ie = ntfs_ie_get_next(ie); } }
static int ntfs_index_rm_leaf(ntfs_index_context *icx) { INDEX_BLOCK *ib = NULL; INDEX_HEADER *parent_ih; INDEX_ENTRY *ie; int ret = STATUS_ERROR; ntfs_log_trace("pindex: %d\n", icx->pindex); if (ntfs_icx_parent_dec(icx)) return STATUS_ERROR; if (ntfs_ibm_clear(icx, icx->parent_vcn[icx->pindex + 1])) return STATUS_ERROR; if (ntfs_icx_parent_vcn(icx) == VCN_INDEX_ROOT_PARENT) parent_ih = &icx->ir->index; else { ib = ntfs_malloc(icx->block_size); if (!ib) return STATUS_ERROR; if (ntfs_ib_read(icx, ntfs_icx_parent_vcn(icx), ib)) goto out; parent_ih = &ib->index; } ie = ntfs_ie_get_by_pos(parent_ih, ntfs_icx_parent_pos(icx)); if (!ntfs_ie_end(ie)) { ret = ntfs_ih_takeout(icx, parent_ih, ie, ib); goto out; } if (ntfs_ih_zero_entry(parent_ih)) { if (ntfs_icx_parent_vcn(icx) == VCN_INDEX_ROOT_PARENT) { ntfs_ir_leafify(icx, parent_ih); goto ok; } ret = ntfs_index_rm_leaf(icx); goto out; } if (ntfs_ih_reparent_end(icx, parent_ih, ib)) goto out; ok: ret = STATUS_OK; out: free(ib); return ret; }
static int ntfs_ih_numof_entries(INDEX_HEADER *ih) { int n; INDEX_ENTRY *ie; u8 *end; ntfs_log_trace("Entering\n"); end = ntfs_ie_get_end(ih); ie = ntfs_ie_get_first(ih); for (n = 0; !ntfs_ie_end(ie) && (u8 *)ie < end; n++) ie = ntfs_ie_get_next(ie); return n; }
/*static JPA*/ int ntfs_index_rm(ntfs_index_context *icx) { INDEX_HEADER *ih = NULL; int err, ret = STATUS_OK; ntfs_log_trace("Entering\n"); if (!icx || (!icx->ib && !icx->ir) || ntfs_ie_end(icx->entry)) { ntfs_log_error("Invalid arguments.\n"); errno = EINVAL; goto err_out; } if (icx->is_in_root) ih = &icx->ir->index; else ih = &icx->ib->index; if(NULL == ih) { errno = EINVAL; goto err_out; } if (icx->entry->ie_flags & INDEX_ENTRY_NODE) { ret = ntfs_index_rm_node(icx); } else if (icx->is_in_root || !ntfs_ih_one_entry(ih)) { ntfs_ie_delete(ih, icx->entry); if (icx->is_in_root) { err = ntfs_ir_truncate(icx, le32_to_cpu(ih->index_length)); if (err != STATUS_OK) goto err_out; } else if (ntfs_icx_ib_write(icx)) goto err_out; } else { if (ntfs_index_rm_leaf(icx)) goto err_out; } out: return ret; err_out: ret = STATUS_ERROR; goto out; }
/** * Find a key in the index block. * * Return values: * STATUS_OK with errno set to ESUCCESS if we know for sure that the * entry exists and @ie_out points to this entry. * STATUS_NOT_FOUND with errno set to ENOENT if we know for sure the * entry doesn't exist and @ie_out is the insertion point. * STATUS_KEEP_SEARCHING if we can't answer the above question and * @vcn will contain the node index block. * STATUS_ERROR with errno set if on unexpected error during lookup. */ static int ntfs_ie_lookup(const void *key, const int key_len, ntfs_index_context *icx, INDEX_HEADER *ih, VCN *vcn, INDEX_ENTRY **ie_out) { INDEX_ENTRY *ie; u8 *index_end; int rc, item = 0; ntfs_log_trace("Entering\n"); index_end = ntfs_ie_get_end(ih); /* * Loop until we exceed valid memory (corruption case) or until we * reach the last entry. */ for (ie = ntfs_ie_get_first(ih); ; ie = ntfs_ie_get_next(ie)) { /* Bounds checks. */ if ((u8 *)ie + sizeof(INDEX_ENTRY_HEADER) > index_end || (u8 *)ie + le16_to_cpu(ie->length) > index_end) { errno = ERANGE; ntfs_log_error("Index entry out of bounds in inode " "%llu.\n", (unsigned long long)icx->ni->mft_no); return STATUS_ERROR; } /* * The last entry cannot contain a key. It can however contain * a pointer to a child node in the B+tree so we just break out. */ if (ntfs_ie_end(ie)) break; /* * Not a perfect match, need to do full blown collation so we * know which way in the B+tree we have to go. */ if (!icx->collate) { ntfs_log_error("Collation function not defined\n"); errno = EOPNOTSUPP; return STATUS_ERROR; } rc = icx->collate(icx->ni->vol, key, key_len, &ie->key, le16_to_cpu(ie->key_length)); if (rc == NTFS_COLLATION_ERROR) { ntfs_log_error("Collation error. Perhaps a filename " "contains invalid characters?\n"); errno = ERANGE; return STATUS_ERROR; } /* * If @key collates before the key of the current entry, there * is definitely no such key in this index but we might need to * descend into the B+tree so we just break out of the loop. */ if (rc == -1) break; if (!rc) { *ie_out = ie; errno = 0; icx->parent_pos[icx->pindex] = item; return STATUS_OK; } item++; } /* * We have finished with this index block without success. Check for the * presence of a child node and if not present return with errno ENOENT, * otherwise we will keep searching in another index block. */ if (!(ie->ie_flags & INDEX_ENTRY_NODE)) { ntfs_log_debug("Index entry wasn't found.\n"); *ie_out = ie; errno = ENOENT; return STATUS_NOT_FOUND; } /* Get the starting vcn of the index_block holding the child node. */ *vcn = ntfs_ie_get_vcn(ie); if (*vcn < 0) { errno = EINVAL; ntfs_log_perror("Negative vcn in inode %llu", (unsigned long long)icx->ni->mft_no); return STATUS_ERROR; } ntfs_log_trace("Parent entry number %d\n", item); icx->parent_pos[icx->pindex] = item; return STATUS_KEEP_SEARCHING; }