ntfs-3g/libntfs/tree.c

2367 lines
53 KiB
C

/**
* tree.c - Directory tree handling code. Part of the Linux-NTFS project.
*
* Copyright (c) 2004-2005 Richard Russon
*
* This program/include file is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as published
* by the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program/include file is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program (in the main directory of the Linux-NTFS
* distribution in the file COPYING); if not, write to the Free Software
* Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifdef NTFS_RICH
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#ifdef HAVE_STRING_H
#include <string.h>
#endif
#include "volume.h"
#include "dir.h"
#include "tree.h"
#include "bitmap.h"
#include "index.h"
#include "inode.h"
#include "logging.h"
#include "rich.h"
/**
* ntfs_dt_free -
* @dt:
*
* Description...
*
* Returns:
*/
void ntfs_dt_free(struct ntfs_dt *dt)
{
int i;
if (!dt)
return;
ntfs_log_trace ("dt %p, children %d, dir %lld\n", dt, dt->child_count, MREF(dt->dir->mft_num));
for (i = 0; i < dt->child_count; i++) {
ntfs_dt_free(dt->sub_nodes[i]);
ntfs_inode_close2(dt->inodes[i]);
}
free(dt->sub_nodes);
free(dt->children);
free(dt->inodes);
free(dt->data); // XXX is this always ours?
free(dt);
}
/**
* ntfs_dt_rollback -
* @dt:
*
* Description...
*
* Returns:
*/
int ntfs_dt_rollback(struct ntfs_dt *dt)
{
int i;
if (!dt)
return 0;
if (dt->child_count == 0) // No children or nothing mapped
return 0;
ntfs_log_trace ("dt %p, children %d, dir %lld\n", dt, dt->child_count, MREF(dt->dir->mft_num));
if (dt->changed) {
// We can't trust anything below us in the tree
for (i = 0; i < dt->child_count; i++) {
ntfs_dt_free(dt->sub_nodes[i]);
ntfs_inode_close2(dt->inodes[i]);
}
dt->child_count = 0;
free(dt->data);
free(dt->children);
free(dt->sub_nodes);
free(dt->inodes);
dt->data = NULL;
dt->children = NULL;
dt->sub_nodes = NULL;
dt->inodes = NULL;
} else {
// This node is OK, check the su-nodes
for (i = 0; i < dt->child_count; i++) {
if (ntfs_dt_rollback(dt->sub_nodes[i])) {
ntfs_inode_close2(dt->inodes[i]);
// Child was changed so unmap it
dt->sub_nodes[i] = NULL;
dt->inodes[i] = NULL;
}
}
}
return (dt->child_count == 0);
}
/**
* ntfs_dt_commit -
* @dt:
*
* Description...
*
* Returns:
*/
int ntfs_dt_commit(struct ntfs_dt *dt)
{
ntfs_volume *vol;
ntfs_attr *attr;
struct ntfs_dir *dir;
int i;
int size;
if (!dt)
return 0;
ntfs_log_trace ("dt %p, children %d, dir %lld\n", dt, dt->child_count, MREF(dt->dir->mft_num));
dir = dt->dir;
if (!dir)
return -1;
vol = dir->vol; // cluster size
if (dt->changed) {
if (dt->parent) {
ntfs_log_debug("commit dt (alloc)\n");
attr = dt->dir->ialloc;
size = dt->dir->index_size;
//utils_dump_mem(dt->data, 0, size, DM_DEFAULTS);
ntfs_attr_mst_pwrite(attr, dt->vcn * vol->cluster_size, 1, size, dt->data); // XXX retval
} else {
ntfs_log_debug("commit dt (root)\n");
attr = dt->dir->iroot;
size = dt->data_len;
//utils_dump_mem(dt->data, 0, size, DM_DEFAULTS);
ntfs_attr_pwrite(attr, 0, size, dt->data); // XXX retval
}
ntfs_log_warning("\tntfs_attr_pwrite(vcn %lld)\n", dt->vcn);
dt->changed = FALSE;
} else {
//ntfs_log_debug("\tdt is clean\n");
}
for (i = 0; i < dt->child_count; i++) {
if ((dt->inodes[i]) && (NInoDirty(dt->inodes[i]))) {
//utils_dump_mem(dt->inodes[i]->mrec, 0, vol->mft_record_size, DM_DEFAULTS);
ntfs_inode_sync(dt->inodes[i]);
ntfs_log_warning("\tntfs_inode_sync %llu\n", dt->inodes[i]->mft_no);
}
if (ntfs_dt_commit(dt->sub_nodes[i]) < 0)
return -1;
}
return 0;
}
/**
* ntfs_dt_create_children2 -
* @dt:
* @count:
*
* Description...
*
* Returns:
*/
BOOL ntfs_dt_create_children2(struct ntfs_dt *dt, int count)
{
// XXX calculate for 2K and 4K indexes max and min filenames (inc/exc VCN)
int old = (dt->child_count + 0x1e) & ~0x1f;
int new = (count + 0x1f) & ~0x1f;
if (old == new)
return TRUE;
ntfs_log_trace ("\n");
dt->children = realloc(dt->children, new * sizeof(*dt->children));
dt->sub_nodes = realloc(dt->sub_nodes, new * sizeof(*dt->sub_nodes));
dt->inodes = realloc(dt->inodes, new * sizeof(*dt->inodes));
if (!dt->children || !dt->sub_nodes || !dt->inodes)
return FALSE; // dt->child_count = -1 ?
memset((u8*)dt->children + old, 0, (new - old) * sizeof(*dt->children));
memset((u8*)dt->sub_nodes + old, 0, (new - old) * sizeof(*dt->sub_nodes));
memset((u8*)dt->inodes + old, 0, (new - old) * sizeof(*dt->inodes));
return TRUE;
}
/**
* ntfs_dt_resize_children3 -
* @dt:
* @new:
*
* Description...
*
* Returns:
*/
BOOL ntfs_dt_resize_children3(struct ntfs_dt *dt, int new)
{
int old;
// XXX calculate for 2K and 4K indexes max and min filenames (inc/exc VCN)
// XXX assumption: sizeof(*dt->children) == sizeof(*dt->sub_nodes) == sizeof(*dt->inodes)
// XXX put back blocking factor
if (!dt)
return FALSE;
old = dt->child_count;
if (old == new)
return TRUE;
ntfs_log_trace ("dt %p, mft %lld, old %d, new %d\n", dt, MREF(dt->dir->mft_num), old, new);
dt->child_count = new;
old *= sizeof(*dt->children);
new *= sizeof(*dt->children);
dt->children = realloc(dt->children, new);
dt->sub_nodes = realloc(dt->sub_nodes, new);
dt->inodes = realloc(dt->inodes, new);
if (!dt->children || !dt->sub_nodes || !dt->inodes)
return FALSE;
if (new > old) {
memset((u8*)dt->children + old, 0, (new - old));
memset((u8*)dt->sub_nodes + old, 0, (new - old));
memset((u8*)dt->inodes + old, 0, (new - old));
}
return TRUE;
}
/**
* ntfs_dt_root_count -
* @dt:
*
* Description...
*
* Returns:
*/
int ntfs_dt_root_count(struct ntfs_dt *dt)
{
u8 *buffer = NULL;
u8 *ptr = NULL;
VCN vcn;
s64 size = 0;
char *name = NULL;
INDEX_ROOT *root;
INDEX_HEADER *header;
INDEX_ENTRY *entry;
if (!dt)
return -1;
ntfs_log_trace ("\n");
buffer = dt->data;
size = dt->data_len;
//utils_dump_mem(buffer, 0, size, DM_DEFAULTS);
root = (INDEX_ROOT*) buffer;
if (root->type != AT_FILE_NAME)
return -1;
header = (INDEX_HEADER*) (buffer + 0x10);
if (header->index_length > size)
return -1;
dt->child_count = 0;
ptr = buffer + header->entries_offset + 0x10;
while (ptr < (buffer + size)) {
entry = (INDEX_ENTRY*) ptr;
ntfs_dt_resize_children3(dt, dt->child_count + 1); // XXX retval
if (entry->flags & INDEX_ENTRY_NODE) {
vcn = ntfs_ie_get_vcn((INDEX_ENTRY*) ptr);
//ntfs_log_debug("VCN %lld\n", vcn);
}
if (!(entry->flags & INDEX_ENTRY_END)) {
ntfs_ucstombs(entry->key.file_name.file_name, entry->key.file_name.file_name_length, &name, 0);
//ntfs_log_debug("\tinode %8lld %s\n", MREF(entry->indexed_file), name);
free(name);
name = NULL;
}
//ntfs_log_debug("CC[%d] = %p\n", dt->child_count-1, entry);
dt->children[dt->child_count-1] = entry;
ptr += entry->length;
}
//ntfs_log_debug("count = %d\n\n", dt->child_count);
return dt->child_count;
}
/**
* ntfs_dt_alloc_count -
* @dt:
*
* Description...
*
* Returns:
*/
int ntfs_dt_alloc_count(struct ntfs_dt *dt)
{
u8 *buffer = NULL;
u8 *ptr = NULL;
VCN vcn;
s64 size = 0;
char *name = NULL;
INDEX_BLOCK *block;
INDEX_ENTRY *entry;
if (!dt)
return -1;
ntfs_log_trace ("\n");
buffer = dt->data;
size = dt->data_len;
//utils_dump_mem(buffer, 0, 128, DM_DEFAULTS);
block = (INDEX_BLOCK*) buffer;
//ntfs_log_debug("INDX %lld\n", block->index_block_vcn);
ptr = buffer + 0x18 + block->index.entries_offset;
//ntfs_log_debug("block size %d\n", block->index.index_length);
dt->child_count = 0;
//ntfs_log_debug("start = 0x%02X, end = 0x%02X\n", 0x18 + block->index.entries_offset, 0x18 + block->index.index_length);
while (ptr < (buffer + 0x18 + block->index.index_length)) {
entry = (INDEX_ENTRY*) ptr;
ntfs_dt_resize_children3(dt, dt->child_count + 1); // XXX retval
if (entry->flags & INDEX_ENTRY_NODE) {
vcn = ntfs_ie_get_vcn((INDEX_ENTRY*) ptr);
//ntfs_log_debug("\tVCN %lld\n", vcn);
}
dt->children[dt->child_count-1] = entry;
if (entry->flags & INDEX_ENTRY_END) {
break;
} else {
ntfs_ucstombs(entry->key.file_name.file_name, entry->key.file_name.file_name_length, &name, 0);
//ntfs_log_debug("\tinode %8lld %s\n", MREF(entry->indexed_file), name);
free(name);
name = NULL;
}
ptr += entry->length;
}
//ntfs_log_debug("count = %d\n", dt->child_count);
return dt->child_count;
}
/**
* ntfs_dt_initialise2 -
* @vol:
* @dt:
*
* Description...
*
* Returns:
*/
int ntfs_dt_initialise2(ntfs_volume *vol, struct ntfs_dt *dt)
{
INDEX_ALLOCATION *alloc;
INDEX_ENTRY *entry;
if (!vol)
return 1;
if (!dt)
return 1;
ntfs_log_trace ("\n");
memset(dt->data, 0, dt->data_len);
alloc = (INDEX_ALLOCATION*) dt->data;
alloc->magic = magic_INDX;
alloc->usa_ofs = 0x28;
alloc->usa_count = (dt->data_len >> vol->sector_size_bits) + 1;
alloc->lsn = 0;
alloc->index_block_vcn = 0;
alloc->index.entries_offset = 0x28;
alloc->index.index_length = 0x10 + 0x28;
alloc->index.allocated_size = dt->data_len - 0x18;
alloc->index.flags = 0;
entry = (INDEX_ENTRY*) (dt->data + 0x40);
entry->indexed_file = 0;
entry->length = 0x10;
entry->key_length = 0;
entry->flags = INDEX_ENTRY_END;
ntfs_dt_resize_children3(dt, 1); // XXX retval
dt->children[0] = entry;
return 0;
}
/**
* ntfs_dt_create -
* @dir:
* @parent:
* @vcn:
*
* Description...
*
* Returns:
*/
struct ntfs_dt * ntfs_dt_create(struct ntfs_dir *dir, struct ntfs_dt *parent, VCN vcn)
{
struct ntfs_dt *dt = NULL;
//int i;
if (!dir)
return NULL;
dt = calloc(1, sizeof(*dt));
if (!dt)
return NULL;
ntfs_log_trace ("\n");
dt->dir = dir;
dt->parent = parent;
dt->child_count = 0;
dt->children = NULL;
dt->sub_nodes = NULL;
dt->inodes = NULL;
dt->vcn = vcn;
dt->changed = FALSE;
if (parent) {
//ntfs_log_debug("alloc a = %lld\n", dir->ialloc->allocated_size);
//ntfs_log_debug("alloc d = %lld\n", dir->ialloc->data_size);
//ntfs_log_debug("alloc i = %lld\n", dir->ialloc->initialized_size);
//ntfs_log_debug("vcn = %lld\n", vcn);
dt->data_len = dt->dir->index_size;
//ntfs_log_debug("parent size = %d\n", dt->data_len);
dt->data = malloc(dt->data_len);
if (vcn >= 0) {
//ntfs_log_debug("%lld\n", ntfs_attr_mst_pread(dir->ialloc, vcn*512, 1, dt->data_len, dt->data));
ntfs_attr_mst_pread(dir->ialloc, vcn*512, 1, dt->data_len, dt->data);
} else {
ntfs_dt_initialise2(dir->vol, dt);
}
//utils_dump_mem(dt->data, 0, dt->data_len, DM_DEFAULTS);
//ntfs_log_debug("\n");
ntfs_dt_alloc_count(dt);
dt->header = &((INDEX_BLOCK*)dt->data)->index;
//ntfs_log_debug("USA = %d\n", ((INDEX_BLOCK*)dt->data)->usa_count);
#if 0
for (i = 0; i < dt->child_count; i++) {
INDEX_ENTRY *ie = dt->children[i];
ntfs_log_debug("%d\n", ((u8*)ie) - dt->data);
if (ie->flags & INDEX_ENTRY_END)
ntfs_log_debug("IE (%d)\n", ie->length);
else
ntfs_log_debug("IE %lld (%d)\n", MREF(ie->key.file_name.parent_directory), ie->length);
utils_dump_mem(ie, 0, ie->length, DM_DEFAULTS);
ntfs_log_debug("\n");
}
#endif
} else {
//ntfs_log_debug("root a = %lld\n", dir->iroot->allocated_size);
//ntfs_log_debug("root d = %lld\n", dir->iroot->data_size);
//ntfs_log_debug("root i = %lld\n", dir->iroot->initialized_size);
dt->data_len = dir->iroot->allocated_size;
dt->data = malloc(dt->data_len);
//ntfs_log_debug("%lld\n", ntfs_attr_pread(dir->iroot, 0, dt->data_len, dt->data));
ntfs_attr_pread(dir->iroot, 0, dt->data_len, dt->data);
//utils_dump_mem(dt->data, 0, dt->data_len, DM_DEFAULTS);
//ntfs_log_debug("\n");
ntfs_dt_root_count(dt);
dt->header = &((INDEX_ROOT*)dt->data)->index;
//dt->data_len = ((INDEX_ROOT*)dt->data)->index_block_size;
//ntfs_log_debug("IBS = %d\n", ((INDEX_ROOT*)dt->data)->index_block_size);
#if 0
for (i = 0; i < dt->child_count; i++) {
INDEX_ENTRY *ie = dt->children[i];
ntfs_log_debug("%d\n", ((u8*)ie) - dt->data);
if (ie->flags & INDEX_ENTRY_END)
ntfs_log_debug("IE (%d)\n", ie->length);
else
ntfs_log_debug("IE %lld (%d)\n", MREF(ie->key.file_name.parent_directory), ie->length);
utils_dump_mem(ie, 0, ie->length, DM_DEFAULTS);
ntfs_log_debug("\n");
}
#endif
}
//ntfs_log_debug("index_header (%d,%d)\n", dt->header->index_length, dt->header->allocated_size);
return dt;
}
/**
* ntfs_dt_find -
* @dt:
* @name:
* @name_len:
*
* find dt by name, return MFT_REF
* maps dt's as necessary
*/
MFT_REF ntfs_dt_find(struct ntfs_dt *dt, ntfschar *name, int name_len)
{
MFT_REF res = -1;
INDEX_ENTRY *ie;
struct ntfs_dt *sub;
VCN vcn;
int i;
int r;
if (!dt || !name)
return -1;
ntfs_log_trace ("\n");
/*
* State Children Action
* -------------------------------------------
* collates after - keep searching
* match name - return MREF
* collates before no return -1
* collates before yes map & recurse
* end marker no return -1
* end marker yes map & recurse
*/
//ntfs_log_debug("child_count = %d\n", dt->child_count);
for (i = 0; i < dt->child_count; i++) {
ie = dt->children[i];
if (ie->flags & INDEX_ENTRY_END) {
r = -1;
} else {
//ntfs_log_debug("\t"); ntfs_name_print(ie->key.file_name.file_name, ie->key.file_name.file_name_length); ntfs_log_debug("\n");
r = ntfs_names_collate(name, name_len,
ie->key.file_name.file_name,
ie->key.file_name.file_name_length,
2, IGNORE_CASE,
dt->dir->vol->upcase,
dt->dir->vol->upcase_len);
}
//ntfs_log_debug("%d, %d\n", i, r);
if (r == 1) {
//ntfs_log_debug("keep searching\n");
continue;
} else if (r == 0) {
res = MREF(ie->indexed_file);
//ntfs_log_debug("match %lld\n", res);
} else if (r == -1) {
if (ie->flags & INDEX_ENTRY_NODE) {
//ntfs_log_debug("map & recurse\n");
//ntfs_log_debug("sub %p\n", dt->sub_nodes);
if (!dt->sub_nodes[i]) {
vcn = ntfs_ie_get_vcn(ie);
//ntfs_log_debug("vcn = %lld\n", vcn);
sub = ntfs_dt_create(dt->dir, dt, vcn);
dt->sub_nodes[i] = sub;
}
res = ntfs_dt_find(dt->sub_nodes[i], name, name_len);
} else {
//ntfs_log_debug("ENOENT\n");
}
} else {
ntfs_log_debug("error collating name\n");
}
break;
}
return res;
}
/**
* ntfs_dt_find2 -
* @dt:
* @name:
* @name_len:
* @index_num:
*
* find dt by name, returns dt and index
* maps dt's as necessary
*/
struct ntfs_dt * ntfs_dt_find2(struct ntfs_dt *dt, ntfschar *name, int name_len, int *index_num)
{
struct ntfs_dt *res = NULL;
INDEX_ENTRY *ie;
VCN vcn;
int i;
int r;
if (!dt || !name)
return NULL;
ntfs_log_trace ("dt %p, mft %llu, name %p%d\n", dt, MREF(dt->dir->mft_num), name, name_len);
//ntfs_log_debug("searching for: "); ntfs_name_print(name, name_len); ntfs_log_debug("\n");
//utils_dump_mem(dt->data, 0, 256, DM_DEFAULTS);
// XXX default index_num to -1
/*
* State Children Action
* -------------------------------------------
* collates after - keep searching
* match name - return MREF
* collates before no return -1
* collates before yes map & recurse
* end marker no return -1
* end marker yes map & recurse
*/
//ntfs_log_debug("child_count = %d\n", dt->child_count);
for (i = 0; i < dt->child_count; i++) {
ie = dt->children[i];
if (ie->flags & INDEX_ENTRY_END) {
r = -1;
} else {
//ntfs_log_debug("\t"); ntfs_name_print(ie->key.file_name.file_name, ie->key.file_name.file_name_length); ntfs_log_debug("\n");
//utils_dump_mem(name, 0, name_len * 2, DM_DEFAULTS);
//utils_dump_mem(ie->key.file_name.file_name, 0, ie->key.file_name.file_name_length * 2, DM_DEFAULTS);
r = ntfs_names_collate(name, name_len,
ie->key.file_name.file_name,
ie->key.file_name.file_name_length,
2, IGNORE_CASE,
dt->dir->vol->upcase,
dt->dir->vol->upcase_len);
}
//ntfs_log_debug("%d, %d\n", i, r);
if (r == 1) {
//ntfs_log_debug("keep searching\n");
continue;
} else if (r == 0) {
res = dt;
//ntfs_log_debug("match %p\n", res);
if (index_num)
*index_num = i;
} else if ((r == -1) && (ie->flags & INDEX_ENTRY_NODE)) {
//ntfs_log_debug("recurse\n");
if (!dt->sub_nodes[i]) {
vcn = ntfs_ie_get_vcn(ie);
//ntfs_log_debug("vcn = %lld\n", vcn);
dt->sub_nodes[i] = ntfs_dt_create(dt->dir, dt, vcn);
}
res = ntfs_dt_find2(dt->sub_nodes[i], name, name_len, index_num);
} else {
//ntfs_log_debug("error collating name\n");
}
break;
}
return res;
}
/**
* ntfs_dt_find3 -
* @dt:
* @name:
* @name_len:
* @index_num:
*
* find dt by name, returns dt and index
* does not map new dt's
*/
struct ntfs_dt * ntfs_dt_find3(struct ntfs_dt *dt, ntfschar *name, int name_len, int *index_num)
{
struct ntfs_dt *res = NULL;
INDEX_ENTRY *ie;
int i;
int r;
if (!dt || !name)
return NULL;
ntfs_log_trace ("\n");
//ntfs_log_debug("child_count = %d\n", dt->child_count);
for (i = 0; i < dt->child_count; i++) {
ie = dt->children[i];
if (ie->flags & INDEX_ENTRY_END) {
r = -1;
} else {
//ntfs_log_debug("\t"); ntfs_name_print(ie->key.file_name.file_name, ie->key.file_name.file_name_length); ntfs_log_debug("\n");
r = ntfs_names_collate(name, name_len,
ie->key.file_name.file_name,
ie->key.file_name.file_name_length,
2, IGNORE_CASE,
dt->dir->vol->upcase,
dt->dir->vol->upcase_len);
}
//ntfs_log_debug("%d, %d\n", i, r);
if (r == 1) {
//ntfs_log_debug("keep searching\n");
continue;
} else if (r == 0) {
res = dt;
//ntfs_log_debug("match %p\n", res);
if (index_num)
*index_num = i;
} else if (r == -1) {
if (ie->flags & INDEX_ENTRY_NODE) {
//ntfs_log_debug("recurse\n");
res = ntfs_dt_find3(dt->sub_nodes[i], name, name_len, index_num);
} else {
//ntfs_log_debug("no match\n");
res = dt;
if (index_num)
*index_num = i;
}
} else {
ntfs_log_debug("error collating name\n");
}
break;
}
return res;
}
/**
* ntfs_dt_find4 -
* @dt:
* @name:
* @name_len:
* @index_num:
*
* find successor to specified name, returns dt and index
* maps dt's as necessary
*/
struct ntfs_dt * ntfs_dt_find4(struct ntfs_dt *dt, ntfschar *name, int name_len, int *index_num)
{
struct ntfs_dt *res = NULL;
struct ntfs_dt *sub = NULL;
INDEX_ENTRY *ie;
VCN vcn;
int i;
int r;
if (!dt || !name)
return NULL;
ntfs_log_trace ("\n");
//ntfs_log_debug("child_count = %d\n", dt->child_count);
for (i = 0; i < dt->child_count; i++) {
ie = dt->children[i];
//ntfs_log_debug("ie->flags = %d\n", ie->flags);
if (ie->flags & INDEX_ENTRY_END) {
r = -1;
} else {
//ntfs_log_debug("\t"); ntfs_name_print(ie->key.file_name.file_name, ie->key.file_name.file_name_length); ntfs_log_debug("\n");
r = ntfs_names_collate(name, name_len,
ie->key.file_name.file_name,
ie->key.file_name.file_name_length,
2, IGNORE_CASE,
dt->dir->vol->upcase,
dt->dir->vol->upcase_len);
}
//ntfs_log_debug("%d, %d\n", i, r);
if (r == 1) {
//ntfs_log_debug("keep searching\n");
} else if (r == 0) {
//res = dt;
//ntfs_log_debug("match\n");
// ignore
} else if (r == -1) {
if (ie->flags & INDEX_ENTRY_NODE) {
//ntfs_log_debug("recurse\n");
if (!dt->sub_nodes[i]) {
vcn = ntfs_ie_get_vcn(ie);
//ntfs_log_debug("vcn = %lld\n", vcn);
sub = ntfs_dt_create(dt->dir, dt, vcn);
dt->sub_nodes[i] = sub;
}
res = ntfs_dt_find4(dt->sub_nodes[i], name, name_len, index_num);
} else {
//ntfs_log_debug("no match\n");
res = dt;
if (index_num)
*index_num = i;
}
break;
} else {
ntfs_log_debug("error collating name\n");
}
//break;
}
return res;
}
/**
* ntfs_dt_find_all -
* @dt:
*
* maps all dt's into memory
*/
void ntfs_dt_find_all(struct ntfs_dt *dt)
{
INDEX_ENTRY *ie;
VCN vcn;
int i;
if (!dt)
return;
ntfs_log_trace ("\n");
for (i = 0; i < dt->child_count; i++) {
ie = dt->children[i];
if (ie->flags & INDEX_ENTRY_NODE) {
if (!dt->sub_nodes[i]) {
vcn = ntfs_ie_get_vcn(ie);
dt->sub_nodes[i] = ntfs_dt_create(dt->dir, dt, vcn);
}
ntfs_dt_find_all(dt->sub_nodes[i]);
}
}
}
/**
* ntfs_dt_find_parent -
* @dt:
*
* Description...
*
* Returns:
*/
int ntfs_dt_find_parent(struct ntfs_dt *dt)
{
int i;
struct ntfs_dt *parent;
if (!dt)
return -1;
ntfs_log_trace ("\n");
parent = dt->parent;
if (!parent)
return -1;
for (i = 0; i < parent->child_count; i++)
if (parent->sub_nodes[i] == dt)
return i;
return -1;
}
/**
* ntfs_dt_isroot -
* @dt:
*
* Description...
*
* Returns:
*/
BOOL ntfs_dt_isroot(struct ntfs_dt *dt)
{
if (!dt)
return FALSE;
ntfs_log_trace ("\n");
return (dt->parent == NULL);
}
/**
* ntfs_dt_root_freespace -
* @dt:
*
* Description...
*
* Returns:
*/
int ntfs_dt_root_freespace(struct ntfs_dt *dt)
{
int recsize;
int inuse;
MFT_RECORD *mrec;
if (!dt)
return -1;
ntfs_log_trace ("\n");
recsize = dt->dir->inode->vol->mft_record_size;
mrec = (MFT_RECORD*) dt->dir->inode->mrec;
inuse = mrec->bytes_in_use;
return recsize - inuse;
}
/**
* ntfs_dt_alloc_freespace -
* @dt:
*
* Description...
*
* Returns:
*/
int ntfs_dt_alloc_freespace(struct ntfs_dt *dt)
{
int recsize;
int inuse;
INDEX_BLOCK *block;
if (!dt)
return -1;
ntfs_log_trace ("\n");
recsize = dt->dir->index_size;
block = (INDEX_BLOCK*) dt->data;
inuse = block->index.index_length + 24;
return recsize - inuse;
}
/**
* ntfs_dt_transfer -
* @old:
* @new:
* @start:
* @count:
*
* Description...
*
* Returns:
*/
int ntfs_dt_transfer(struct ntfs_dt *old, struct ntfs_dt *new, int start, int count)
{
int i;
int need;
int space;
INDEX_ENTRY *mov_ie;
u8 *src;
u8 *dst;
int len;
int insert;
//FILE_NAME_ATTR *file;
ntfs_log_trace ("\n");
//XXX check len > 0
if (!old || !new)
return -1;
if ((start < 0) || ((start+count) >= old->child_count))
return -1;
//ntfs_log_debug("\n");
ntfs_log_debug("Transferring children\n");
need = 0;
for (i = start; i < (start+count+1); i++) {
mov_ie = old->children[i];
need += mov_ie->length;
//file = &mov_ie->key.file_name; ntfs_log_debug("\ttrn name: "); ntfs_name_print(file->file_name, file->file_name_length); ntfs_log_debug("\n");
}
if (ntfs_dt_isroot(new))
space = ntfs_dt_root_freespace(new);
else
space = ntfs_dt_alloc_freespace(new);
// XXX if this is an index root, it'll go badly wrong
// restrict to allocs only?
ntfs_log_debug("\tneed = %d\n", need);
ntfs_log_debug("\tspace = %d\n", space);
if (space < need)
return -1;
if (new->child_count == 1) {
i = -1;
} else {
ntfschar *n1, *n2;
int l1, l2;
n1 = new->children[0]->key.file_name.file_name;
l1 = new->children[0]->key.file_name.file_name_length;
n2 = old->children[start]->key.file_name.file_name;
l2 = old->children[start]->key.file_name.file_name_length;
i = ntfs_names_collate(n1, l1, n2, l2,
2, IGNORE_CASE,
old->dir->vol->upcase,
old->dir->vol->upcase_len);
}
if ((i == 0) || (i == 2))
return -1;
// determine the insertion point
if (i == 1)
insert = 0;
else
insert = new->child_count-1;
src = (u8*) new->children[insert];
dst = src + need;
len = (u8*) new->children[new->child_count-1] + new->children[new->child_count-1]->length - src;
//ntfs_log_debug("src = %d, dst = %d, len = %d\n", src - new->data, dst - new->data, len);
memmove(dst, src, len);
dst = src;
src = (u8*) old->children[start];
len = need;
memcpy(dst, src, len);
src = (u8*) old->children[start+count-1];
dst = (u8*) old->children[start];
len = (u8*) old->children[old->child_count-1] + old->children[old->child_count-1]->length - src;
//ntfs_log_debug("src = %d, dst = %d, len = %d\n", src - old->data, dst - old->data, len);
memmove(dst, src, len);
dst += len;
len = old->data + old->dir->index_size - dst;
//ntfs_log_debug("dst = %d, len = %d\n", dst - old->data, len);
memset(dst, 0, len);
if (!ntfs_dt_resize_children3(new, new->child_count + count))
return -1;
src = (u8*) &old->sub_nodes[start+count-1];
dst = (u8*) &old->sub_nodes[start];
len = (old->child_count - start - count + 1) * sizeof(struct ntfs_dt*);
memmove(dst, src, len);
src = (u8*) &new->sub_nodes[insert];
dst = (u8*) &new->sub_nodes[insert+count-1];
len = (new->child_count - insert - count + 1) * sizeof(struct ntfs_dt*);
memmove(dst, src, len);
if (!ntfs_dt_resize_children3(old, old->child_count - count))
return -1;
src = (u8*) new->children[0];
for (i = 0; i < new->child_count; i++) {
new->children[i] = (INDEX_ENTRY*) src;
src += new->children[i]->length;
}
src = (u8*) old->children[0];
for (i = 0; i < old->child_count; i++) {
old->children[i] = (INDEX_ENTRY*) src;
src += old->children[i]->length;
}
old->header->index_length -= need;
new->header->index_length += need;
// resize children and sub_nodes
// memmove keys in new
// memcpy old to new
// memmove keys in old
// rebuild old/new children/sub_nodes without destroying tree
// update old/new headers
old->changed = TRUE;
new->changed = TRUE;
ntfs_log_debug("Modified: inode %lld, $INDEX_ALLOCATION vcn %lld-%lld\n", old->dir->inode->mft_no, old->vcn, old->vcn + (old->dir->index_size>>9) - 1);
ntfs_log_debug("Modified: inode %lld, $INDEX_ALLOCATION vcn %lld-%lld\n", new->dir->inode->mft_no, new->vcn, new->vcn + (new->dir->index_size>>9) - 1);
return 0;
}
/**
* ntfs_dt_alloc_insert -
* @dt:
* @first:
* @count:
*
* Description...
*
* Returns:
*/
int ntfs_dt_alloc_insert(struct ntfs_dt *dt, INDEX_ENTRY *first, int count)
{
// XXX don't bother measuring, just subtract the children pointers
int i;
int need;
INDEX_ENTRY *ie;
INDEX_ALLOCATION *alloc;
u8 *src;
u8 *dst;
int len;
if (!dt)
return 1;
if (!first)
return 1;
ntfs_log_trace ("\n");
need = 0;
ie = first;
for (i = 0; i < count; i++) {
need += ie->length;
ie = (INDEX_ENTRY*) ((u8*)ie + ie->length);
}
ntfs_log_debug("alloc insert %d bytes\n", need);
alloc = (INDEX_ALLOCATION*) dt->data;
ntfs_log_debug("entries_offset = %d\n", alloc->index.entries_offset);
ntfs_log_debug("index_length = %d\n", alloc->index.index_length);
ntfs_log_debug("allocated_size = %d\n", alloc->index.allocated_size);
ntfs_log_debug("insert has %d children\n", dt->child_count);
ntfs_log_debug("children = %p\n", dt->children);
//utils_dump_mem(dt->data, 0, 128, DM_DEFAULTS);
ie = dt->children[dt->child_count-1];
ntfs_log_debug("last child = %p (%ld)\n", ie, (long)ie - (long)dt->data);
ntfs_log_debug("size = %d\n", ie->length);
src = (u8*) ie;
dst = src + need;
len = ie->length;
memmove(dst, src, len);
src = (u8*) first;
dst = (u8*) ie;
len = need;
memcpy(dst, src, len);
// use create children
// measure need and update children list
// adjust headers
//utils_dump_mem(dt->data, 0, 256, DM_DEFAULTS);
return 0;
}
/**
* ntfs_dt_alloc_insert2 -
* @dt:
* @before:
* @count:
* @bytes:
*
* Description...
*
* Returns:
*/
INDEX_ENTRY * ntfs_dt_alloc_insert2(struct ntfs_dt *dt, int before, int count, int bytes)
{
int space;
u8 *src;
u8 *dst;
int len;
// XXX don't bother measuring, just subtract the children pointers
if (!dt)
return NULL;
if (before < 0)
return NULL;
if (count < 1)
return NULL;
if (bytes < 1)
return NULL;
ntfs_log_trace ("\n");
// check alloc has enough space
space = ntfs_dt_alloc_freespace(dt);
if (bytes > space)
return NULL;
// move data
src = (u8*) dt->children[before];
dst = src + bytes;
len = dt->header->index_length - ((int)dt->children[before] - (int)dt->data) + 24;
//ntfs_log_debug("%d, %d, %d\n", (int)src - (int)dt->data, (int)dst - (int)dt->data, len);
memmove(dst, src, len);
memset(dst, 0, bytes);
// resize arrays
ntfs_dt_resize_children3(dt, dt->child_count + count);
// move keys (children)
src = (u8*) (dt->children + before);
dst = src + (count * sizeof(u8*));
len = (dt->child_count - count - before) * sizeof(u8*);
memmove(dst, src, len);
memset(src, 0, count * sizeof(u8*));
// move keys (inodes)
src = (u8*) (dt->inodes + before);
dst = src + (count * sizeof(u8*));
len = (dt->child_count - count - before) * sizeof(u8*);
memmove(dst, src, len);
memset(src, 0, count * sizeof(u8*));
// move keys (sub_nodes)
src = (u8*) (dt->sub_nodes + before);
dst = src + (count * sizeof(u8*));
len = (dt->child_count - count - before) * sizeof(u8*);
memmove(dst, src, len);
memset(src, 0, count * sizeof(u8*));
return NULL;
}
/**
* ntfs_dt_root_insert -
* @dt:
* @first:
* @count:
*
* Description...
*
* Returns:
*/
int ntfs_dt_root_insert(struct ntfs_dt *dt, INDEX_ENTRY *first, int count)
{
if (!dt)
return 1;
if (!first)
return 1;
ntfs_log_trace ("\n");
return count;
}
/**
* ntfs_dt_alloc_remove2 -
* @dt:
* @start:
* @count:
*
* Description...
*
* Returns:
*/
int ntfs_dt_alloc_remove2(struct ntfs_dt *dt, int start, int count)
{
int i;
int size;
if (!dt)
return 1;
ntfs_log_trace ("\n");
size = 0;
for (i = start; i < (start+count); i++) {
size += dt->children[i]->length;
}
return start + count;
}
/**
* ntfs_dt_root_remove2 -
* @dt:
* @start:
* @count:
*
* Description...
*
* Returns:
*/
int ntfs_dt_root_remove2(struct ntfs_dt *dt, int start, int count)
{
int i;
int size;
if (!dt)
return -1;
if ((start < 0) || (start >= dt->child_count))
return -1;
if ((count < 1) || ((start + count - 1) >= dt->child_count))
return -1;
ntfs_log_trace ("\n");
ntfs_log_debug("s c/t %d %d/%d\n", start, count, dt->child_count);
size = 0;
for (i = start; i < (start + count); i++)
size += dt->children[i]->length;
ntfs_log_debug("size1 = %d\n", size);
size = (int) dt->children[start+count] - (int) dt->children[start];
ntfs_log_debug("size2 = %d\n", size);
size = (int) dt->children[start+count-1] - (int) dt->children[start] + dt->children[start+count-1]->length;
ntfs_log_debug("size3 = %d\n", size);
// XXX what shall we do with the inodes?
// transfer them to the dir (commit them for now)
// are they _our_ responsibility? probably not
// rearrange arrays
// shrink attribute
ntfs_dt_resize_children3(dt, dt->child_count - count);
ntfs_log_debug("ntfs_dt_root_remove2\n");
return dt->child_count;
}
/**
* ntfs_dt_transfer2 -
* @old:
* @new:
* @start:
* @count:
*
* Description...
*
* Returns:
*/
int ntfs_dt_transfer2(struct ntfs_dt *old, struct ntfs_dt *new, int start, int count)
{
int i;
int need;
int space;
INDEX_ENTRY *mov_ie;
u8 *src;
u8 *dst;
int len;
int insert;
//FILE_NAME_ATTR *file;
if (!old || !new)
return -1;
if ((start < 0) || (count < 0))
return -1;
if ((start + count) >= old->child_count)
return -1;
ntfs_log_trace ("\n");
//ntfs_log_debug("\n");
ntfs_log_debug("Transferring children\n");
need = 0;
for (i = start; i < (start+count); i++) {
mov_ie = old->children[i];
need += mov_ie->length;
//file = &mov_ie->key.file_name; ntfs_log_debug("\ttrn name: "); ntfs_name_print(file->file_name, file->file_name_length); ntfs_log_debug("\n");
}
if (ntfs_dt_isroot(new))
space = ntfs_dt_root_freespace(new);
else
space = ntfs_dt_alloc_freespace(new);
ntfs_log_debug("\tneed = %d\n", need);
ntfs_log_debug("\tspace = %d\n", space);
if (need > space)
return -1;
if (ntfs_dt_isroot(new))
ntfs_dt_root_insert(new, old->children[0], count);
else
ntfs_dt_alloc_insert2(new, 0, count, need);
if (ntfs_dt_isroot(old))
ntfs_dt_root_remove2(old, 0, count);
else
ntfs_dt_alloc_remove2(old, 0, count);
if (1) return -1;
if (0) ntfs_dt_alloc_insert(NULL, NULL, 0);
if (new->child_count == 1) {
i = -1;
} else {
ntfschar *n1, *n2;
int l1, l2;
n1 = new->children[0]->key.file_name.file_name;
l1 = new->children[0]->key.file_name.file_name_length;
n2 = old->children[start]->key.file_name.file_name;
l2 = old->children[start]->key.file_name.file_name_length;
i = ntfs_names_collate(n1, l1, n2, l2,
2, IGNORE_CASE,
old->dir->vol->upcase,
old->dir->vol->upcase_len);
}
if ((i == 0) || (i == 2))
return -1;
// determine the insertion point
if (i == 1)
insert = 0;
else
insert = new->child_count-1;
src = (u8*) new->children[insert];
dst = src + need;
len = (u8*) new->children[new->child_count-1] + new->children[new->child_count-1]->length - src;
//ntfs_log_debug("src = %d, dst = %d, len = %d\n", src - new->data, dst - new->data, len);
memmove(dst, src, len);
dst = src;
src = (u8*) old->children[start];
len = need;
memcpy(dst, src, len);
src = (u8*) old->children[start+count-1];
dst = (u8*) old->children[start];
len = (u8*) old->children[old->child_count-1] + old->children[old->child_count-1]->length - src;
//ntfs_log_debug("src = %d, dst = %d, len = %d\n", src - old->data, dst - old->data, len);
memmove(dst, src, len);
dst += len;
len = old->data + old->dir->index_size - dst;
//ntfs_log_debug("dst = %d, len = %d\n", dst - old->data, len);
memset(dst, 0, len);
if (!ntfs_dt_resize_children3(new, new->child_count + count))
return -1;
src = (u8*) &old->sub_nodes[start+count-1];
dst = (u8*) &old->sub_nodes[start];
len = (old->child_count - start - count + 1) * sizeof(struct ntfs_dt*);
memmove(dst, src, len);
src = (u8*) &new->sub_nodes[insert];
dst = (u8*) &new->sub_nodes[insert+count-1];
len = (new->child_count - insert - count + 1) * sizeof(struct ntfs_dt*);
memmove(dst, src, len);
if (!ntfs_dt_resize_children3(old, old->child_count - count))
return -1;
src = (u8*) new->children[0];
for (i = 0; i < new->child_count; i++) {
new->children[i] = (INDEX_ENTRY*) src;
src += new->children[i]->length;
}
src = (u8*) old->children[0];
for (i = 0; i < old->child_count; i++) {
old->children[i] = (INDEX_ENTRY*) src;
src += old->children[i]->length;
}
old->header->index_length -= need;
new->header->index_length += need;
// resize children and sub_nodes
// memmove keys in new
// memcpy old to new
// memmove keys in old
// rebuild old/new children/sub_nodes without destroying tree
// update old/new headers
old->changed = TRUE;
new->changed = TRUE;
ntfs_log_debug("Modified: inode %lld, $INDEX_ALLOCATION vcn %lld-%lld\n", old->dir->inode->mft_no, old->vcn, old->vcn + (old->dir->index_size>>9) - 1);
ntfs_log_debug("Modified: inode %lld, $INDEX_ALLOCATION vcn %lld-%lld\n", new->dir->inode->mft_no, new->vcn, new->vcn + (new->dir->index_size>>9) - 1);
return 0;
}
/**
* ntfs_dt_root_replace -
* @del:
* @del_num:
* @del_ie:
* @suc_ie:
*
* Description...
*
* Returns:
*/
int ntfs_dt_root_replace(struct ntfs_dt *del, int del_num, INDEX_ENTRY *del_ie, INDEX_ENTRY *suc_ie)
{
u8 *src;
u8 *dst;
u8 *attr;
int len;
int i;
if (!del || !del_ie || !suc_ie)
return FALSE;
ntfs_log_trace ("\n");
//utils_dump_mem(del->data, 0, del->data_len, DM_DEFAULTS);
//ntfs_log_debug("\n");
attr = malloc(del->data_len + suc_ie->length - del_ie->length);
dst = attr;
src = del->data;
len = (u8*) del_ie - del->data;
memcpy(dst, src, len);
dst += len;
src = (u8*) suc_ie;
len = suc_ie->length;
memcpy(dst, src, len);
dst += len;
src = (u8*) del_ie + del_ie->length;
len = del->data_len + (del->data - (u8*) del_ie) - del_ie->length;
memcpy(dst, src, len);
src = (u8*) del->data;
dst = attr;
len = suc_ie->length - del_ie->length;
free(del->data);
del->data = attr;
del->data_len += len;
del->header = (INDEX_HEADER*) (del->data + 0x10);
del->header->index_length += len;
del->header->allocated_size += len;
ntfs_mft_resize_resident(del->dir->inode, AT_INDEX_ROOT, NTFS_INDEX_I30, 4, del->data, del->data_len);
//utils_dump_mem(attr, 0, del->data_len, DM_DEFAULTS);
//ntfs_log_debug("\n");
//ntfs_log_debug("Adjust children\n");
//for (i = 0; i < del->child_count; i++)
// ntfs_log_debug("\tChild %d %p %d\n", i, del->children[i], del->children[i]->flags);
//ntfs_log_debug("\n");
//ntfs_log_debug("src = %p, dst = %p, len = %d\n", src, dst, len); fflush (stdout);
for (i = 0; i < del->child_count; i++)
del->children[i] = (INDEX_ENTRY*) (dst + ((u8*) del->children[i] - src));
for (i = del_num+1; i < del->child_count; i++)
del->children[i] = (INDEX_ENTRY*) ((u8*) del->children[i] + len);
//for (i = 0; i < del->child_count; i++)
// ntfs_log_debug("\tChild %d %p %d\n", i, del->children[i], del->children[i]->flags);
//ntfs_log_debug("\n");
//utils_dump_mem(del->data, 0, del->data_len, DM_DEFAULTS);
//ntfs_log_debug("\n");
del->changed = TRUE;
ntfs_log_debug("Modified: inode %lld, $INDEX_ROOT\n", del->dir->inode->mft_no);
return TRUE;
}
/**
* ntfs_dt_alloc_replace -
* @del:
* @del_num:
* @del_ie:
* @suc_ie:
*
* Description...
*
* Returns:
*/
BOOL ntfs_dt_alloc_replace(struct ntfs_dt *del, int del_num, INDEX_ENTRY *del_ie, INDEX_ENTRY *suc_ie)
{
u8 *src;
u8 *dst;
int len;
int i;
if (!del || !del_ie || !suc_ie)
return FALSE;
ntfs_log_trace ("\n");
//utils_dump_mem(del->data, 0, del->data_len, DM_DEFAULTS);
src = (u8*) del_ie + del_ie->length;
dst = (u8*) del_ie + suc_ie->length;
len = del->header->index_length + 24 + (del->data - src);
//ntfs_log_debug("src = %d\n", src - del->data);
//ntfs_log_debug("dst = %d\n", dst - del->data);
//ntfs_log_debug("len = %d\n", len);
if (src != dst)
memmove(dst, src, len);
src = (u8*) suc_ie;
dst = (u8*) del_ie;
len = suc_ie->length;
memcpy(dst, src, len);
//utils_dump_mem(del->data, 0, del->data_len, DM_DEFAULTS);
del->header->index_length += suc_ie->length - del_ie->length;
dst = del->data + del->header->index_length + 24;
len = del->data_len - del->header->index_length - 24;
memset(dst, 0, len);
//for (i = 0; i < del->child_count; i++)
// ntfs_log_debug("Child %d %p\n", i, del->children[i]);
//ntfs_log_debug("\n");
len = suc_ie->length - del_ie->length;
//ntfs_log_debug("len = %d\n", len);
for (i = del_num+1; i < del->child_count; i++)
del->children[i] = (INDEX_ENTRY*) ((u8*) del->children[i] + len);
//for (i = 0; i < del->child_count; i++)
// ntfs_log_debug("Child %d %p\n", i, del->children[i]);
//ntfs_log_debug("\n");
//utils_dump_mem(del->data, 0, del->data_len, DM_DEFAULTS);
del->changed = TRUE;
ntfs_log_debug("Modified: inode %lld, $INDEX_ALLOCATION vcn %lld-%lld\n", del->dir->inode->mft_no, del->vcn, del->vcn + (del->dir->index_size>>9) - 1);
return TRUE;
}
/**
* ntfs_dt_root_remove -
* @del:
* @del_num:
*
* Description...
*
* Returns:
*/
BOOL ntfs_dt_root_remove(struct ntfs_dt *del, int del_num)
{
INDEX_ENTRY *del_ie = NULL;
u8 *src;
u8 *dst;
u8 *old;
int len;
int del_len;
int i;
//int off;
if (!del)
return FALSE;
ntfs_log_trace ("\n");
//utils_dump_mem(del->data, 0, del->header->index_length+16, DM_RED);
//ntfs_log_debug("\n");
#if 0
off = (u8*) del->children[0] - del->data;
for (i = 0; i < del->child_count; i++) {
del_ie = del->children[i];
ntfs_log_debug("%2d %4d ", i+1, off);
off += del_ie->length;
if (del_ie->flags & INDEX_ENTRY_END) {
ntfs_log_debug("END (%d)\n", del_ie->length);
break;
}
ntfs_name_print(del_ie->key.file_name.file_name, del_ie->key.file_name.file_name_length);
ntfs_log_debug(" (%d)\n", del_ie->length);
}
ntfs_log_debug("total = %d\n", off);
#endif
del_ie = del->children[del_num];
del_len = del_ie->length;
src = (u8*) del_ie + del_len;
dst = (u8*) del_ie;
len = del->header->index_length + 16 - (src - del->data);
//ntfs_log_debug("src = %d\n", src - del->data);
//ntfs_log_debug("dst = %d\n", dst - del->data);
//ntfs_log_debug("len = %d\n", len);
memmove(dst, src, len);
del->data_len -= del_len;
del->child_count--;
del->header->index_length = del->data_len - 16;
del->header->allocated_size = del->data_len - 16;
ntfs_mft_resize_resident(del->dir->inode, AT_INDEX_ROOT, NTFS_INDEX_I30, 4, del->data, del->data_len);
old = del->data;
del->data = realloc(del->data, del->data_len);
del->header = (INDEX_HEADER*) (del->data + 0x10);
//utils_dump_mem(del->data, 0, del->data_len, DM_GREEN | DM_RED);
src = (u8*) (&del->children[del_num+1]);
dst = (u8*) (&del->children[del_num]);
len = (del->child_count - del_num) * sizeof(INDEX_ENTRY*);
//ntfs_log_debug("src = %d\n", src - (u8*) del->children);
//ntfs_log_debug("dst = %d\n", dst - (u8*) del->children);
//ntfs_log_debug("len = %d\n", len);
memmove(dst, src, len);
src = (u8*) (&del->sub_nodes[del_num+1]);
dst = (u8*) (&del->sub_nodes[del_num]);
len = (del->child_count - del_num) * sizeof(struct ntfs_dt*);
//ntfs_log_debug("src = %d\n", src - (u8*) del->children);
//ntfs_log_debug("dst = %d\n", dst - (u8*) del->children);
//ntfs_log_debug("len = %d\n", len);
memmove(dst, src, len);
//ntfs_log_debug("del_num = %d\n", del_num);
for (i = 0; i < del->child_count; i++)
del->children[i] = (INDEX_ENTRY*) ((u8*) del->children[i] - old + del->data);
for (i = del_num; i < del->child_count; i++)
del->children[i] = (INDEX_ENTRY*) ((u8*) del->children[i] - del_len);
if (!ntfs_dt_create_children2(del, del->child_count))
return FALSE;
#if 0
off = (u8*) del->children[0] - del->data;
for (i = 0; i < del->child_count; i++) {
del_ie = del->children[i];
ntfs_log_debug("%2d %4d ", i+1, off);
off += del_len;
if (del_ie->flags & INDEX_ENTRY_END) {
ntfs_log_debug("END (%d)\n", del_len);
break;
}
ntfs_name_print(del_ie->key.file_name.file_name, del_ie->key.file_name.file_name_length);
ntfs_log_debug(" (%d)\n", del_len);
}
ntfs_log_debug("total = %d\n", off);
#endif
//utils_dump_mem(del->data, 0, del->header->index_length+16, DM_DEFAULTS);
del->changed = TRUE;
ntfs_log_debug("Modified: inode %lld, $INDEX_ROOT\n", del->dir->inode->mft_no);
return TRUE;
}
/**
* ntfs_dt_alloc_remove -
* @del:
* @del_num:
*
* Description...
*
* Returns:
*/
BOOL ntfs_dt_alloc_remove(struct ntfs_dt *del, int del_num)
{
INDEX_ENTRY *del_ie = NULL;
u8 *dst;
u8 *src;
int len;
int i;
//int off;
if (!del)
return FALSE;
ntfs_log_trace ("\n");
#if 0
off = (u8*)del->children[0] - del->data;
for (i = 0; i < del->child_count; i++) {
del_ie = del->children[i];
ntfs_log_debug("%2d %4d ", i, off);
off += del_ie->length;
if (del_ie->flags & INDEX_ENTRY_END) {
ntfs_log_debug("END (%d)\n", del_ie->length);
break;
}
ntfs_name_print(del_ie->key.file_name.file_name, del_ie->key.file_name.file_name_length);
ntfs_log_debug(" (%d)\n", del_ie->length);
}
ntfs_log_debug("total = %d\n", off);
ntfs_log_debug("\n");
#endif
//utils_dump_mem(del->data, 0, del->data_len, DM_DEFAULTS);
//ntfs_log_debug("\n");
del_ie = del->children[del_num];
src = (u8*) del_ie + del_ie->length;
dst = (u8*) del_ie;
len = del->header->index_length + 24 - (src - del->data);
//ntfs_log_debug("src = %d\n", src - del->data);
//ntfs_log_debug("dst = %d\n", dst - del->data);
//ntfs_log_debug("len = %d\n", len);
memmove(dst, src, len);
del->header->index_length -= src - dst;
del->child_count--;
dst += len;
len = del->data_len - del->header->index_length - 24;
//ntfs_log_debug("dst = %d\n", dst - del->data);
//ntfs_log_debug("len = %d\n", len);
memset(dst, 0, len);
src = (u8*) (&del->children[del_num+1]);
dst = (u8*) (&del->children[del_num]);
len = (del->child_count - del_num) * sizeof(INDEX_ENTRY*);
//ntfs_log_debug("src = %d\n", src - (u8*) del->children);
//ntfs_log_debug("dst = %d\n", dst - (u8*) del->children);
//ntfs_log_debug("len = %d\n", len);
memmove(dst, src, len);
src = (u8*) (&del->sub_nodes[del_num+1]);
dst = (u8*) (&del->sub_nodes[del_num]);
len = (del->child_count - del_num) * sizeof(struct ntfs_dt*);
//ntfs_log_debug("src = %d\n", src - (u8*) del->children);
//ntfs_log_debug("dst = %d\n", dst - (u8*) del->children);
//ntfs_log_debug("len = %d\n", len);
memmove(dst, src, len);
//ntfs_log_debug("del_num = %d\n", del_num);
for (i = del_num; i < del->child_count; i++)
del->children[i] = (INDEX_ENTRY*) ((u8*) del->children[i] - del_ie->length);
if (!ntfs_dt_create_children2(del, del->child_count))
return FALSE;
//utils_dump_mem(del->data, 0, del->data_len, DM_DEFAULTS);
#if 0
off = (u8*)del->children[0] - del->data;
for (i = 0; i < del->child_count; i++) {
del_ie = del->children[i];
ntfs_log_debug("%2d %4d ", i, off);
off += del_ie->length;
if (del_ie->flags & INDEX_ENTRY_END) {
ntfs_log_debug("END (%d)\n", del_ie->length);
break;
}
ntfs_name_print(del_ie->key.file_name.file_name, del_ie->key.file_name.file_name_length);
ntfs_log_debug(" (%d)\n", del_ie->length);
}
ntfs_log_debug("total = %d\n", off);
ntfs_log_debug("\n");
#endif
del->changed = TRUE;
ntfs_log_debug("Modified: inode %lld, $INDEX_ALLOCATION vcn %lld-%lld\n", del->dir->inode->mft_no, del->vcn, del->vcn + (del->dir->index_size>>9) - 1);
if (del->child_count < 2) {
ntfs_log_debug("indx is empty\n");
ntfs_bmp_set_range(del->dir->bitmap, del->vcn, 1, 0);
}
return TRUE;
}
/**
* ntfs_dt_alloc_add -
* @parent:
* @index_num:
* @ie:
* @child:
*
* Description...
*
* Returns:
*/
int ntfs_dt_alloc_add(struct ntfs_dt *parent, int index_num, INDEX_ENTRY *ie, struct ntfs_dt *child)
{
INDEX_BLOCK *block;
INDEX_ENTRY *entry;
int need;
int space;
u8 *src;
u8 *dst;
int len;
if (!parent || !ie)
return 0;
ntfs_log_trace ("\n");
block = (INDEX_BLOCK*) parent->data;
need = ie->length;
space = parent->data_len - block->index.index_length - 24;
ntfs_log_debug("need %d, have %d\n", need, space);
if (need > space) {
ntfs_log_debug("no room");
return 0;
}
//utils_dump_mem(parent->data, 0, parent->data_len, DM_DEFAULTS);
//ntfs_log_debug("\n");
src = (u8*) parent->children[index_num];
dst = src + need;
len = parent->data + parent->data_len - src - space;
//ntfs_log_debug("src = %d\n", src - parent->data);
//ntfs_log_debug("dst = %d\n", dst - parent->data);
//ntfs_log_debug("len = %d\n", len);
memmove(dst, src, len);
dst = src;
src = (u8*) ie;
len = need;
memcpy(dst, src, len);
block->index.index_length += len;
dst = parent->data + block->index.index_length + 24;
len = parent->data_len - block->index.index_length - 24;
memset(dst, 0, len);
//realloc children, sub_nodes
ntfs_dt_create_children2(parent, parent->child_count + 1);
// regen children pointers
parent->child_count = 0;
src = parent->data + 0x18 + parent->header->entries_offset;
len = parent->data_len - 0x18 - parent->header->entries_offset;
while (src < (parent->data + parent->data_len)) {
entry = (INDEX_ENTRY*) src;
parent->children[parent->child_count] = entry;
parent->child_count++;
if (entry->flags & INDEX_ENTRY_END)
break;
src += entry->length;
}
ntfs_log_debug("count = %d\n", parent->child_count);
src = (u8*) &parent->sub_nodes[index_num+parent->child_count-1];
dst = (u8*) &parent->sub_nodes[index_num];
len = (parent->child_count - index_num - 1) * sizeof(struct ntfs_dt*);
memmove(dst, src, len);
//insert sub_node pointer
parent->sub_nodes[index_num] = child;
//utils_dump_mem(parent->data, 0, parent->data_len, DM_DEFAULTS);
//ntfs_log_debug("\n");
return 0;
}
/**
* ntfs_dt_root_add -
* @parent:
* @index_num:
* @ie:
* @child:
*
* Description...
*
* Returns:
*/
int ntfs_dt_root_add(struct ntfs_dt *parent, int index_num, INDEX_ENTRY *ie, struct ntfs_dt *child)
{
INDEX_ROOT *root;
INDEX_ENTRY *entry;
int need;
int space;
u8 *attr;
u8 *src;
u8 *dst;
int len;
if (!parent || !ie)
return -1;
ntfs_log_trace ("\n");
root = (INDEX_ROOT*) parent->data;
//utils_dump_mem(parent->data, 0, parent->data_len, DM_DEFAULTS);
//ntfs_log_debug("\n");
need = ie->length;
space = ntfs_mft_free_space(parent->dir);
ntfs_log_debug("need %d, have %d\n", need, space);
if (need > space) {
ntfs_log_debug("no room");
return -1;
}
attr = malloc(parent->data_len + need);
src = parent->data;
dst = attr;
len = root->index.entries_offset + 16;
memcpy(dst, src, len);
dst += len;
src = (u8*) ie;
len = ie->length;
memcpy(dst, src, len);
dst += len;
src = (u8*) parent->children[index_num];
len = parent->data + parent->data_len - src;
memcpy(dst, src, len);
free(parent->data);
parent->data = attr;
parent->data_len += need;
ntfs_log_debug("parent data len = %d\n", parent->data_len);
root = (INDEX_ROOT*) parent->data;
root->index.index_length = parent->data_len - 16;
root->index.allocated_size = parent->data_len - 16;
//utils_dump_mem(parent->data, 0, parent->data_len, DM_DEFAULTS);
//ntfs_log_debug("\n");
ntfs_mft_resize_resident(parent->dir->inode, AT_INDEX_ROOT, NTFS_INDEX_I30, 4, parent->data, parent->data_len);
parent->changed = TRUE;
//realloc children, sub_nodes
ntfs_dt_create_children2(parent, parent->child_count + 1);
// regen children pointers
parent->child_count = 0;
src = parent->data + 0x18 + parent->header->entries_offset;
len = parent->data_len - 0x18 - parent->header->entries_offset;
// XXX can we rebase the children more simply? (in alloc_add too)
while (src < (parent->data + parent->data_len)) {
entry = (INDEX_ENTRY*) src;
parent->children[parent->child_count] = entry;
parent->child_count++;
if (entry->flags & INDEX_ENTRY_END)
break;
src += entry->length;
}
ntfs_log_debug("count = %d\n", parent->child_count);
src = (u8*) &parent->sub_nodes[index_num+parent->child_count-1];
dst = (u8*) &parent->sub_nodes[index_num];
len = (parent->child_count - index_num - 1) * sizeof(struct ntfs_dt*);
memmove(dst, src, len);
//insert sub_node pointer
parent->sub_nodes[index_num] = child;
return 0;
}
/**
* ntfs_dt_add2 -
* @ie:
* @suc:
* @suc_num:
* @ded:
*
* Description...
*
* Returns:
*/
int ntfs_dt_add2(INDEX_ENTRY *ie, struct ntfs_dt *suc, int suc_num, struct ntfs_dt *ded)
{
int need;
int space;
int median;
struct ntfs_dt *new = NULL;
struct ntfs_dt *chl;
INDEX_ENTRY *med_ie = NULL;
//FILE_NAME_ATTR *file;
VCN vcn = 0;
//int i;
if (!ie || !suc)
return -1;
ntfs_log_trace ("\n");
ntfs_log_debug("Add key to leaf\n");
//utils_dump_mem(suc->data, 0, suc->data_len, DM_DEFAULTS);
chl = NULL;
ascend:
//XXX replace with while/break?
#if 0
for (; ded; ded = ded->sub_nodes[0]) {
ntfs_log_debug("\tded vcn = %lld\n", ded->vcn);
}
#endif
/*
* ADD
* room in current node?
* yes, add, done
* no, split, ascend
*/
need = ie->length;
if (ntfs_dt_isroot(suc))
space = ntfs_dt_root_freespace(suc);
else
space = ntfs_dt_alloc_freespace(suc);
ntfs_log_debug("\tneed %d\n", need);
ntfs_log_debug("\tspace %d\n", space);
if (space >= need) {
//ntfs_log_critical("index = %d\n", suc_num);
//ntfs_log_debug("prev inode = %p\n", suc->inodes[suc_num-1]);
//ntfs_log_debug("curr inode = %p\n", suc->inodes[suc_num]);
ntfs_log_debug("count = %d\n", suc->child_count);
if (ntfs_dt_isroot(suc))
ntfs_dt_root_add(suc, suc_num, ie, chl);
else
ntfs_dt_alloc_add(suc, suc_num, ie, chl);
ntfs_log_debug("count = %d\n", suc->child_count);
//goto done;
return suc_num; //XXX this is probably off-by-one
}
/*
* SPLIT
* any dead?
* yes reuse
* no alloc
*/
if (ded) {
new = ded;
vcn = ded->vcn;
ded = ded->sub_nodes[0];
ntfs_log_debug("\treusing vcn %lld\n", new->vcn);
} else {
ntfs_mft_add_index(suc->dir);
/*
* ALLOC
* any unused records?
* yes, enable first
* no, extend
*/
/*
* ENABLE
* modify bitmap
* init indx record
*/
/*
* EXTEND
* room in bitmap
* yes, do nothing
* no, extend bitmap
* extend alloc
*/
/*
* EXTEND BITMAP
* extend bitmap
* init bitmap
*/
}
//ntfs_log_debug("\tnode has %d children\n", suc->child_count);
// initialise new node
// XXX ntfs_dt_initialise(new, vcn);
goto done;
// find median key
median = (suc->child_count+1) / 2;
med_ie = ntfs_ie_copy(suc->children[median]);
//file = &med_ie->key.file_name; ntfs_log_debug("\tmed name: "); ntfs_name_print(file->file_name, file->file_name_length); ntfs_log_debug("\n");
ntfs_ie_free(med_ie);
med_ie = NULL;
//ntfs_log_debug("suc key count = %d\n", suc->child_count);
//ntfs_log_debug("new key count = %d\n", new->child_count);
//ntfs_log_debug("median's child = %p\n", suc->sub_nodes[median]);
// need to pass the child when ascending
chl = suc->sub_nodes[median];
// transfer keys
if (ntfs_dt_transfer(suc, new, 0, median-1) < 0)
goto done;
//ntfs_log_debug("suc key count = %d\n", suc->child_count);
//ntfs_log_debug("new key count = %d\n", new->child_count);
//file = &suc->children[0]->key.file_name; ntfs_log_debug("\tmed name: "); ntfs_name_print(file->file_name, file->file_name_length); ntfs_log_debug("\n");
// can this be a root node?
if (ntfs_dt_isroot(suc))
ntfs_dt_root_remove(suc, 0);
else
ntfs_dt_alloc_remove(suc, 0);
//file = &suc->children[0]->key.file_name; ntfs_log_debug("\tmed name: "); ntfs_name_print(file->file_name, file->file_name_length); ntfs_log_debug("\n");
//ntfs_log_debug("suc key count = %d\n", suc->child_count);
//ntfs_log_debug("new key count = %d\n", new->child_count);
// remove the median key
// split when median has children
// median child given to new !
// median child is new
// ascend
med_ie = ntfs_ie_set_vcn(med_ie, new->vcn);
if (!med_ie)
goto done;
//ntfs_log_debug("median child = %lld\n", ntfs_ie_get_vcn(med_ie));
//ntfs_log_debug("new's vcn = %lld\n", new->vcn);
// adjust parents
// attach new to median
// escape clause for root node?
// goto ascend
// ie = insert
// child = child
// suc = successor
// suc_num = insert point
ie = med_ie;
suc = suc->parent;
suc_num = 0;
//ntfs_log_debug("\n");
ntfs_log_debug("Ascend\n");
goto ascend;
done:
return 0;
}
#endif /* NTFS_RICH */