📄 index.c
字号:
return STATUS_OK;}static int ntfs_ih_insert(INDEX_HEADER *ih, INDEX_ENTRY *orig_ie, VCN new_vcn, int pos){ INDEX_ENTRY *ie_node, *ie; int ret = STATUS_ERROR; VCN old_vcn; ntfs_log_trace("Entering\n"); ie = ntfs_ie_dup(orig_ie); if (!ie) return STATUS_ERROR; if (!(ie->ie_flags & INDEX_ENTRY_NODE)) if (ntfs_ie_add_vcn(&ie)) goto out; ie_node = ntfs_ie_get_by_pos(ih, pos); old_vcn = ntfs_ie_get_vcn(ie_node); ntfs_ie_set_vcn(ie_node, new_vcn); ntfs_ie_insert(ih, ie, ie_node); ntfs_ie_set_vcn(ie_node, old_vcn); ret = STATUS_OK;out: free(ie); return ret;}static VCN ntfs_icx_parent_vcn(ntfs_index_context *icx){ return icx->parent_vcn[icx->pindex];}static VCN ntfs_icx_parent_pos(ntfs_index_context *icx){ return icx->parent_pos[icx->pindex];}static int ntfs_ir_insert_median(ntfs_index_context *icx, INDEX_ENTRY *median, VCN new_vcn){ u32 new_size; int ret; ntfs_log_trace("Entering\n"); icx->ir = ntfs_ir_lookup2(icx->ni, icx->name, icx->name_len); if (!icx->ir) return STATUS_ERROR; new_size = le32_to_cpu(icx->ir->index.index_length) + le16_to_cpu(median->length); if (!(median->ie_flags & INDEX_ENTRY_NODE)) new_size += sizeof(VCN); ret = ntfs_ir_make_space(icx, new_size); if (ret != STATUS_OK) return ret; icx->ir = ntfs_ir_lookup2(icx->ni, icx->name, icx->name_len); if (!icx->ir) return STATUS_ERROR; return ntfs_ih_insert(&icx->ir->index, median, new_vcn, ntfs_icx_parent_pos(icx));}static int ntfs_ib_split(ntfs_index_context *icx, INDEX_BLOCK *ib);/** * On success return STATUS_OK or STATUS_KEEP_SEARCHING. * On error return STATUS_ERROR. */static int ntfs_ib_insert(ntfs_index_context *icx, INDEX_ENTRY *ie, VCN new_vcn){ INDEX_BLOCK *ib; u32 idx_size, allocated_size; int err = STATUS_ERROR; VCN old_vcn; ntfs_log_trace("Entering\n"); ib = ntfs_malloc(icx->block_size); if (!ib) return -1; old_vcn = ntfs_icx_parent_vcn(icx); if (ntfs_ib_read(icx, old_vcn, ib)) goto err_out; idx_size = le32_to_cpu(ib->index.index_length); allocated_size = le32_to_cpu(ib->index.allocated_size); /* FIXME: sizeof(VCN) should be included only if ie has no VCN */ if (idx_size + le16_to_cpu(ie->length) + sizeof(VCN) > allocated_size) { err = ntfs_ib_split(icx, ib); if (err == STATUS_OK) err = STATUS_KEEP_SEARCHING; goto err_out; } if (ntfs_ih_insert(&ib->index, ie, new_vcn, ntfs_icx_parent_pos(icx))) goto err_out; if (ntfs_ib_write(icx, ib)) goto err_out; err = STATUS_OK;err_out: free(ib); return err;}/** * ntfs_ib_split - Split an index block * * On success return STATUS_OK or STATUS_KEEP_SEARCHING. * On error return is STATUS_ERROR. */static int ntfs_ib_split(ntfs_index_context *icx, INDEX_BLOCK *ib){ INDEX_ENTRY *median; VCN new_vcn; int ret; ntfs_log_trace("Entering\n"); if (ntfs_icx_parent_dec(icx)) return STATUS_ERROR; median = ntfs_ie_get_median(&ib->index); new_vcn = ntfs_ibm_get_free(icx); if (new_vcn == -1) return STATUS_ERROR; if (ntfs_ib_copy_tail(icx, ib, median, new_vcn)) { ntfs_ibm_clear(icx, new_vcn); return STATUS_ERROR; } if (ntfs_icx_parent_vcn(icx) == VCN_INDEX_ROOT_PARENT) ret = ntfs_ir_insert_median(icx, median, new_vcn); else ret = ntfs_ib_insert(icx, median, new_vcn); if (ret != STATUS_OK) { ntfs_ibm_clear(icx, new_vcn); return ret; } ret = ntfs_ib_cut_tail(icx, ib, median); return ret;}static int ntfs_ie_add(ntfs_index_context *icx, INDEX_ENTRY *ie){ char *fn; INDEX_HEADER *ih; int allocated_size, new_size; int ret = STATUS_ERROR; fn = ntfs_ie_filename_get(ie); ntfs_log_trace("file: '%s'\n", fn); ntfs_attr_name_free(&fn); while (1) { if (!ntfs_index_lookup(&ie->key, le16_to_cpu(ie->key_length), icx)) { errno = EEXIST; ntfs_log_perror("Index already have such entry"); goto err_out; } if (errno != ENOENT) { ntfs_log_perror("Failed to find place for new entry"); goto err_out; } if (icx->is_in_root) ih = &icx->ir->index; else ih = &icx->ib->index; allocated_size = le32_to_cpu(ih->allocated_size); new_size = le32_to_cpu(ih->index_length) + le16_to_cpu(ie->length); if (new_size <= allocated_size) break; ntfs_log_trace("index block sizes: allocated: %d needed: %d\n", allocated_size, new_size); if (icx->is_in_root) { if (ntfs_ir_make_space(icx, new_size) == STATUS_ERROR) goto err_out; } else { if (ntfs_ib_split(icx, icx->ib) == STATUS_ERROR) goto err_out; } ntfs_inode_mark_dirty(icx->actx->ntfs_ino); ntfs_index_ctx_reinit(icx); } ntfs_ie_insert(ih, ie, icx->entry); ntfs_index_entry_mark_dirty(icx); ret = STATUS_OK;err_out: ntfs_log_trace("%s\n", ret ? "Failed" : "Done"); return ret;}/** * ntfs_index_add_filename - add filename to directory index * @ni: ntfs inode describing directory to which index add filename * @fn: FILE_NAME attribute to add * @mref: reference of the inode which @fn describes * * Return 0 on success or -1 on error with errno set to the error code. */int ntfs_index_add_filename(ntfs_inode *ni, FILE_NAME_ATTR *fn, MFT_REF mref){ INDEX_ENTRY *ie; ntfs_index_context *icx; int fn_size, ie_size, err, ret = -1; ntfs_log_trace("Entering\n"); if (!ni || !fn) { ntfs_log_error("Invalid arguments.\n"); errno = EINVAL; return -1; } fn_size = (fn->file_name_length * sizeof(ntfschar)) + sizeof(FILE_NAME_ATTR); ie_size = (sizeof(INDEX_ENTRY_HEADER) + fn_size + 7) & ~7; ie = ntfs_calloc(ie_size); if (!ie) return -1; ie->indexed_file = cpu_to_le64(mref); ie->length = cpu_to_le16(ie_size); ie->key_length = cpu_to_le16(fn_size); memcpy(&ie->key, fn, fn_size); icx = ntfs_index_ctx_get(ni, NTFS_INDEX_I30, 4); if (!icx) goto out; ret = ntfs_ie_add(icx, ie); err = errno; ntfs_index_ctx_put(icx); errno = err;out: free(ie); return ret;}static int ntfs_ih_takeout(ntfs_index_context *icx, INDEX_HEADER *ih, INDEX_ENTRY *ie, INDEX_BLOCK *ib){ INDEX_ENTRY *ie_roam; int ret = STATUS_ERROR; ntfs_log_trace("Entering\n"); ie_roam = ntfs_ie_dup_novcn(ie); if (!ie_roam) return STATUS_ERROR; ntfs_ie_delete(ih, ie); if (ntfs_icx_parent_vcn(icx) == VCN_INDEX_ROOT_PARENT) ntfs_inode_mark_dirty(icx->actx->ntfs_ino); else if (ntfs_ib_write(icx, ib)) goto out; ntfs_index_ctx_reinit(icx); ret = ntfs_ie_add(icx, ie_roam);out: free(ie_roam); return ret;}/** * Used if an empty index block to be deleted has END entry as the parent * in the INDEX_ROOT which is the only one there. */static void ntfs_ir_leafify(ntfs_index_context *icx, INDEX_HEADER *ih){ INDEX_ENTRY *ie; ntfs_log_trace("Entering\n"); ie = ntfs_ie_get_first(ih); ie->ie_flags &= ~INDEX_ENTRY_NODE; ie->length = cpu_to_le16(le16_to_cpu(ie->length) - sizeof(VCN)); ih->index_length = cpu_to_le32(le32_to_cpu(ih->index_length) - sizeof(VCN)); ih->ih_flags &= ~LARGE_INDEX; /* Not fatal error */ ntfs_ir_truncate(icx, le32_to_cpu(ih->index_length));}/** * Used if an empty index block to be deleted has END entry as the parent * in the INDEX_ROOT which is not the only one there. */static int ntfs_ih_reparent_end(ntfs_index_context *icx, INDEX_HEADER *ih, INDEX_BLOCK *ib){ INDEX_ENTRY *ie, *ie_prev; ntfs_log_trace("Entering\n"); ie = ntfs_ie_get_by_pos(ih, ntfs_icx_parent_pos(icx)); ie_prev = ntfs_ie_prev(ih, ie); ntfs_ie_set_vcn(ie, ntfs_ie_get_vcn(ie_prev)); return ntfs_ih_takeout(icx, ih, ie_prev, ib);}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_index_rm_node(ntfs_index_context *icx){ int entry_pos, pindex; VCN vcn; INDEX_BLOCK *ib = NULL; INDEX_ENTRY *ie_succ, *ie, *entry = icx->entry; INDEX_HEADER *ih; u32 new_size; int delta, ret = STATUS_ERROR; ntfs_log_trace("Entering\n"); if (!icx->ia_na) { icx->ia_na = ntfs_ia_open(icx, icx->ni); if (!icx->ia_na) return STATUS_ERROR; } ib = ntfs_malloc(icx->block_size); if (!ib) return STATUS_ERROR; ie_succ = ntfs_ie_get_next(icx->entry); entry_pos = icx->parent_pos[icx->pindex]++; pindex = icx->pindex;descend: vcn = ntfs_ie_get_vcn(ie_succ); if (ntfs_ib_read(icx, vcn, ib)) goto out; ie_succ = ntfs_ie_get_first(&ib->index); if (ntfs_icx_parent_inc(icx)) goto out; icx->parent_vcn[icx->pindex] = vcn; icx->parent_pos[icx->pindex] = 0; if ((ib->index.ih_flags & NODE_MASK) == INDEX_NODE) goto descend; if (ntfs_ih_zero_entry(&ib->index)) { errno = EIO; ntfs_log_perror("Empty index block"); goto out; } ie = ntfs_ie_dup(ie_succ); if (!ie) goto out; if (ntfs_ie_add_vcn(&ie)) goto out2; ntfs_ie_set_vcn(ie, ntfs_ie_get_vcn(icx->entry)); if (icx->is_in_root) ih = &icx->ir->index; else ih = &icx->ib->index; delta = le16_to_cpu(ie->length) - le16_to_cpu(icx->entry->length); new_size = le32_to_cpu(ih->index_length) + delta; if (delta > 0) { if (icx->is_in_root) { ret = ntfs_ir_make_space(icx, new_size); if (ret != STATUS_OK) goto out2; ih = &icx->ir->index; entry = ntfs_ie_get_by_pos(ih, entry_pos); } else if (new_size > le32_to_cpu(ih->allocated_size)) { icx->pindex = pindex; ret = ntfs_ib_split(icx, icx->ib); if (ret == STATUS_OK) ret = STATUS_KEEP_SEARCHING; goto out2; } } ntfs_ie_delete(ih, entry); ntfs_ie_insert(ih, ie, entry); if (icx->is_in_root) { if (ntfs_ir_truncate(icx, new_size)) goto out2; } else if (ntfs_icx_ib_write(icx)) goto out2; ntfs_ie_delete(&ib->index, ie_succ); if (ntfs_ih_zero_entry(&ib->index)) { if (ntfs_index_rm_leaf(icx)) goto out2; } else if (ntfs_ib_write(icx, ib)) goto out2; ret = STATUS_OK;out2: free(ie);out: free(ib); return ret;}/** * ntfs_index_rm - remove entry from the index * @icx: index context describing entry to delete * * Delete entry described by @icx from the index. Index context is always * reinitialized after use of this function, so it can be used for index * lookup once again. * * Return 0 on success or -1 on error with errno set to the error code. */static int ntfs_index_rm(ntfs_index_context *icx){ INDEX_HEADER *ih; 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 (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;}int ntfs_index_remove(ntfs_inode *ni, const void *key, const int keylen){ int ret = STATUS_ERROR; ntfs_index_context *icx; icx = ntfs_index_ctx_get(ni, NTFS_INDEX_I30, 4); if (!icx) return -1; while (1) { if (ntfs_index_lookup(key, keylen, icx)) goto err_out; if (((FILE_NAME_ATTR *)icx->data)->file_attributes & FILE_ATTR_REPARSE_POINT) { errno = EOPNOTSUPP; goto err_out; } ret = ntfs_index_rm(icx); if (ret == STATUS_ERROR) goto err_out; else if (ret == STATUS_OK) break; ntfs_inode_mark_dirty(icx->actx->ntfs_ino); ntfs_index_ctx_reinit(icx); } ntfs_inode_mark_dirty(icx->actx->ntfs_ino);out: ntfs_index_ctx_put(icx); return ret;err_out: ret = STATUS_ERROR; ntfs_log_perror("Delete failed"); goto out;}/** * ntfs_index_root_get - read the index root of an attribute * @ni: open ntfs inode in which the ntfs attribute resides * @attr: attribute for which we want its index root * * This function will read the related index root an ntfs attribute. * * On success a buffer is allocated with the content of the index root * and which needs to be freed when it's not needed anymore. * * On error NULL is returned with errno set to the error code. */INDEX_ROOT *ntfs_index_root_get(ntfs_inode *ni, ATTR_RECORD *attr){ ntfs_attr_search_ctx *ctx; ntfschar *name; INDEX_ROOT *root = NULL; name = (ntfschar *)((u8 *)attr + le16_to_cpu(attr->name_offset)); if (!ntfs_ir_lookup(ni, name, attr->name_length, &ctx)) return NULL; root = ntfs_malloc(sizeof(INDEX_ROOT)); if (!root) goto out; *root = *((INDEX_ROOT *)((u8 *)ctx->attr + le16_to_cpu(ctx->attr->value_offset)));out: ntfs_attr_put_search_ctx(ctx); return root;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -