ntfs-3g/ntfsprogs/ntfsrm.c

3631 lines
81 KiB
C
Raw Blame History

This file contains invisible Unicode characters!

This file contains invisible Unicode characters that may be processed differently from what appears below. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to reveal hidden characters.

/**
* ntfsrm - Part of the Linux-NTFS project.
*
* Copyright (c) 2004 Richard Russon
*
* This utility will delete files from an NTFS volume.
*
* This program 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 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
*/
#include "config.h"
#include <stdio.h>
#include <getopt.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "utils.h"
#include "ntfsrm.h"
#include "debug.h"
#include "dir.h"
#include "lcnalloc.h"
#include "mft.h"
static const char *EXEC_NAME = "ntfsrm";
static struct options opts;
static const char *space = " ";
GEN_PRINTF (Eprintf, stderr, NULL, FALSE)
GEN_PRINTF (Vprintf, stdout, &opts.verbose, TRUE)
GEN_PRINTF (Qprintf, stdout, &opts.quiet, FALSE)
/**
* version - Print version information about the program
*
* Print a copyright statement and a brief description of the program.
*
* Return: none
*/
static void version (void)
{
printf ("\n%s v%s - Delete files from an NTFS volume.\n\n",
EXEC_NAME, VERSION);
printf ("Copyright (c) 2004 Richard Russon\n");
printf ("\n%s\n%s%s\n", ntfs_gpl, ntfs_bugs, ntfs_home);
}
/**
* usage - Print a list of the parameters to the program
*
* Print a list of the parameters and options for the program.
*
* Return: none
*/
static void usage (void)
{
printf ("\nUsage: %s [options] device file\n"
"\n"
" -r --recursive Delete files in subdirectories\n"
" -i --interactive Ask before deleting files\n"
//" -I num --inode num Delete the file with this inode number\n"
//" -U --unlink Unlink the file, deleting all references \n"
"\n"
" -D --no-dirty Do not mark volume dirty (require chkdsk)\n"
" -n --no-action Do not write to disk\n"
" -f --force Use less caution\n"
" -h --help Print this help\n"
" -q --quiet Less output\n"
" -V --version Version information\n"
" -v --verbose More output\n\n",
EXEC_NAME);
printf ("%s%s\n", ntfs_bugs, ntfs_home);
}
/**
* parse_options - Read and validate the programs command line
*
* Read the command line, verify the syntax and parse the options.
* This function is very long, but quite simple.
*
* Return: 1 Success
* 0 Error, one or more problems
*/
static int parse_options (int argc, char **argv)
{
static const char *sopt = "-Dfh?inqRrVv"; //"-Dfh?I:inqRrUVv";
static const struct option lopt[] = {
{ "force", no_argument, NULL, 'f' },
{ "help", no_argument, NULL, 'h' },
//{ "inode", required_argument, NULL, 'I' },
{ "interactive", no_argument, NULL, 'i' },
{ "no-action", no_argument, NULL, 'n' },
{ "no-dirty", no_argument, NULL, 'D' },
{ "quiet", no_argument, NULL, 'q' },
{ "recursive", no_argument, NULL, 'r' },
//{ "unlink", no_argument, NULL, 'U' },
{ "verbose", no_argument, NULL, 'v' },
{ "version", no_argument, NULL, 'V' },
{ NULL, 0, NULL, 0 }
};
char c = -1;
int err = 0;
int ver = 0;
int help = 0;
opterr = 0; /* We'll handle the errors, thank you. */
while ((c = getopt_long (argc, argv, sopt, lopt, NULL)) != -1) {
switch (c) {
case 1: /* A non-option argument */
if (!opts.device) {
opts.device = argv[optind-1];
} else if (!opts.file) {
opts.file = argv[optind-1];
} else {
opts.device = NULL;
opts.file = NULL;
err++;
}
break;
case 'D':
opts.nodirty++;
break;
case 'f':
opts.force++;
break;
case 'h':
case '?':
help++;
break;
case 'i':
opts.interactive++;
break;
case 'n':
opts.noaction++;
break;
case 'q':
opts.quiet++;
break;
case 'R':
case 'r':
opts.recursive++;
break;
case 'V':
ver++;
break;
case 'v':
opts.verbose++;
break;
default:
Eprintf ("Unknown option '%s'.\n", argv[optind-1]);
err++;
break;
}
}
if (help || ver) {
opts.quiet = 0;
} else {
if ((opts.device == NULL) ||
(opts.file == NULL)) {
if (argc > 1)
Eprintf ("You must specify one device and one file.\n");
err++;
}
if (opts.quiet && opts.verbose) {
Eprintf("You may not use --quiet and --verbose at the "
"same time.\n");
err++;
}
}
if (ver)
version();
if (help || err)
usage();
return (!err && !help && !ver);
}
struct ntfs_dir;
static void ntfs_ie_dump (INDEX_ENTRY *ie);
static VCN ntfs_ie_get_vcn (INDEX_ENTRY *ie);
static INDEX_ENTRY * ntfs_ie_set_name (INDEX_ENTRY *ie, ntfschar *name, int namelen, FILE_NAME_TYPE_FLAGS nametype);
#define RED ""
#define GREEN ""
#define YELLOW ""
#define BLUE ""
#define MAGENTA ""
#define CYAN ""
#define BOLD ""
#define END ""
#define ROUND_UP(num,bound) (((num)+((bound)-1)) & ~((bound)-1))
#define ATTR_SIZE(s) ROUND_UP(s,8)
/**
* struct ntfs_bmp
* a cache for either dir/$BITMAP, $MFT/$BITMAP or $Bitmap/$DATA
*/
struct ntfs_bmp {
ntfs_attr *attr;
u8 **data;
VCN *data_vcn;
int count;
//int cluster_size;
};
/**
* struct ntfs_dt
*/
struct ntfs_dt {
struct ntfs_dir *dir;
struct ntfs_dt *parent;
u8 *data;
int data_len;
int child_count;
INDEX_ENTRY **children;
struct ntfs_dt **sub_nodes;
INDEX_HEADER *header;
VCN vcn;
};
/**
* struct ntfs_dir
*/
struct ntfs_dir {
ntfs_volume *vol;
struct ntfs_dir *parent;
ntfschar *name;
int name_len;
struct ntfs_dt *index;
struct ntfs_dir **children;
int child_count;
MFT_REF mft_num;
struct mft_bitmap *bitmap;
ntfs_inode *inode;
ntfs_attr *iroot;
ntfs_attr *ialloc;
ntfs_attr *ibmp;
int index_size;
};
/**
* ntfs_name_print
*/
static void ntfs_name_print (ntfschar *name, int name_len)
{
char *buffer = NULL;
if (name_len) {
ntfs_ucstombs (name, name_len, (char**) &buffer, 0);
printf ("%s", buffer);
free (buffer);
} else {
printf ("!");
}
}
/**
* ntfs_dir_print
*/
static void ntfs_dir_print (struct ntfs_dir *dir, int indent)
{
int i;
if (!dir)
return;
printf ("%.*s%p ", indent, space, dir);
ntfs_name_print (dir->name, dir->name_len);
printf ("\n");
for (i = 0; i < dir->child_count; i++) {
ntfs_dir_print (dir->children[i], indent + 4);
}
}
/**
* ntfs_dt_print
*/
static void ntfs_dt_print (struct ntfs_dt *dt, int indent)
{
int i;
if (!dt)
return;
printf ("%.*s%p (%d)\n", indent, space, dt, dt->child_count);
for (i = 0; i < dt->child_count; i++) {
ntfs_dt_print (dt->sub_nodes[i], indent + 4);
}
}
/**
* ntfs_bmp_free
*/
static void ntfs_bmp_free (struct ntfs_bmp *bmp)
{
int i;
if (!bmp)
return;
for (i = 0; i < bmp->count; i++)
free (bmp->data[i]);
ntfs_attr_close (bmp->attr);
free (bmp->data);
free (bmp->data_vcn);
free (bmp);
}
/**
* ntfs_bmp_alloc
*/
static struct ntfs_bmp * ntfs_bmp_alloc (ntfs_inode *inode, ATTR_TYPES type, ntfschar *name, int name_len)
{
struct ntfs_bmp *bmp;
ntfs_attr *attr;
if (!inode)
return NULL;
attr = ntfs_attr_open (inode, type, name, name_len);
if (!attr)
return NULL;
bmp = calloc (1, sizeof (*bmp));
if (!bmp)
return NULL;
bmp->attr = attr;
bmp->data = calloc (16, sizeof (*bmp->data));
bmp->data_vcn = calloc (16, sizeof (*bmp->data_vcn));
bmp->count = 0;
if (!bmp->data || !bmp->data_vcn) {
ntfs_bmp_free (bmp);
return NULL;
}
return bmp;
}
/**
* ntfs_bmp_add_data
*/
static int ntfs_bmp_add_data (struct ntfs_bmp *bmp, VCN vcn, u8 *data)
{
int i = 0;
int old;
int new;
if (!bmp || !data)
return -1;
old = ((bmp->count + 15) & ~15);
bmp->count++;
new = ((bmp->count + 15) & ~15);
if (old != new) {
bmp->data = realloc (bmp->data, new * sizeof (*bmp->data));
bmp->data_vcn = realloc (bmp->data_vcn , new * sizeof (*bmp->data_vcn));
}
for (i = 0; i < bmp->count-1; i++)
if (bmp->data_vcn[i] > vcn)
break;
if ((bmp->count-i) > 0) {
memmove (&bmp->data[i+1], &bmp->data[i], (bmp->count-i) * sizeof (*bmp->data));
memmove (&bmp->data_vcn[i+1], &bmp->data_vcn[i], (bmp->count-i) * sizeof (*bmp->data_vcn));
}
bmp->data[i] = data;
bmp->data_vcn[i] = vcn;
return bmp->count;
}
/**
* ntfs_bmp_get_data
*/
static u8 * ntfs_bmp_get_data (struct ntfs_bmp *bmp, VCN vcn)
{
u8 *buffer;
int i;
VCN begin;
VCN end;
if (!bmp)
return NULL;
for (i = 0; i < bmp->count; i++) {
begin = (bmp->data_vcn[i] >> 3) & (~(512-1));
end = begin + (512 << 3);
if ((vcn >= begin) && (vcn < end)) {
//printf ("%lld, %lld, %lld\n", begin, vcn, end);
return bmp->data[i];
}
}
buffer = malloc (512);
if (!buffer)
return NULL;
begin = (vcn>>3) & (~(512-1));
//printf ("loading from offset %lld\n", begin);
if (ntfs_attr_pread (bmp->attr, begin, 512, buffer) < 0) {
free (buffer);
return NULL;
}
ntfs_bmp_add_data (bmp, vcn, buffer);
return buffer;
}
/**
* ntfs_bmp_set_range
*/
static int ntfs_bmp_set_range (struct ntfs_bmp *bmp, VCN vcn, u64 length, int value)
{
u64 i;
u8 *buffer;
VCN begin;
VCN end;
int start;
int finish;
u8 sta_part;
u8 fin_part;
if (!bmp)
return -1;
//printf ("\n");
//printf ("set range: %lld - %lld\n", vcn, vcn+length-1);
for (i = vcn; i < (vcn+length); i += 4096) {
buffer = ntfs_bmp_get_data (bmp, i);
if (!buffer)
return -1;
#if 0
memset (buffer, 0xFF, 512);
value = 0;
memset (buffer, 0x00, 512);
value = 1;
#endif
//utils_dump_mem (buffer, 0, 32, DM_DEFAULTS);
//printf ("\n");
begin = i & ~4095;
end = begin + 4095;
//printf ("begin = %lld, vcn = %lld,%lld end = %lld\n", begin, vcn, vcn+length-1, end);
if ((vcn > begin) && (vcn < end)) {
//printf ("1\n");
start = ((vcn+8) >> 3) & 511;
sta_part = 0xff << (vcn&7);
} else {
//printf ("2\n");
start = 0;
}
if (((vcn+length-1) >= begin) && ((vcn+length-1) <= end)) {
//printf ("3\n");
finish = ((vcn+length-1) >> 3) & 511;
fin_part = 0xff >> (7-((vcn+length-1)&7));
} else {
//printf ("4\n");
finish = 511;
}
#if 0
//printf ("\n");
printf ("%lld) ", i>>12);
if (start > 0) {
printf ("(%02x) ", sta_part);
} else {
printf (" ");
}
printf ("%d - %d", start, finish);
if (finish < 511) {
printf (" (%02x)\n", fin_part);
} else {
printf (" \n");
}
#endif
if (value) {
if (start != 0)
buffer[start-1] |= sta_part;
if ((finish - start) > 0)
memset (buffer+start, 0xff, finish-start);
buffer[finish] |= fin_part;
} else {
if (start != 0)
buffer[start-1] &= ~sta_part;
if ((finish - start) > 0)
memset (buffer+start, 0x00, finish-start);
buffer[finish] &= ~fin_part;
}
//utils_dump_mem (buffer, 0, 16, DM_DEFAULTS);
}
printf (GREEN "Modified: inode %lld, " END, bmp->attr->ni->mft_no);
switch (bmp->attr->type) {
case AT_BITMAP: printf ("$BITMAP"); break;
case AT_DATA: printf ("$DATA"); break;
}
printf (" vcn %lld-%lld\n", vcn>>12, (vcn+length)>>12);
return 1;
}
/**
* ntfs_bmp_commit
*/
static int ntfs_bmp_commit (struct ntfs_bmp *bmp)
{
if (!bmp)
return -1;
return 0;
}
/**
* ntfs_bmp_rollback
*/
static int ntfs_bmp_rollback (struct ntfs_bmp *bmp)
{
if (!bmp)
return -1;
return 0;
}
/**
* ntfs_dt_alloc_children
*/
static INDEX_ENTRY ** ntfs_dt_alloc_children (INDEX_ENTRY **children, int count)
{
// XXX calculate for 2K and 4K indexes max and min filenames (inc/exc VCN)
int old = (count + 0x1e) & ~0x1f;
int new = (count + 0x1f) & ~0x1f;
if (old == new)
return children;
return realloc (children, new * sizeof (INDEX_ENTRY*));
}
/**
* ntfs_dt_alloc_children2
*/
static BOOL ntfs_dt_alloc_children2 (struct ntfs_dt *dt, int count)
{
// XXX calculate for 2K and 4K indexes max and min filenames (inc/exc VCN)
int old = (count + 0x1e) & ~0x1f;
int new = (count + 0x1f) & ~0x1f;
if (old == new)
return TRUE;
dt->children = realloc (dt->children, new * sizeof (*dt->children));
dt->sub_nodes = realloc (dt->sub_nodes, new * sizeof (*dt->sub_nodes));
return (dt->children && dt->sub_nodes);
}
/**
* ntfs_dt_count_root
*/
static int ntfs_dt_count_root (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;
buffer = dt->data;
size = dt->data_len;
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;
dt->child_count++;
dt->children = ntfs_dt_alloc_children (dt->children, dt->child_count);
if (entry->flags & INDEX_ENTRY_NODE) {
vcn = ntfs_ie_get_vcn ((INDEX_ENTRY*) ptr);
//printf ("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, entry->key.file_name.file_name_length);
//printf ("\tinode %8lld %s\n", MREF (entry->indexed_file), name);
free (name);
name = NULL;
}
//printf ("CC[%d] = %p\n", dt->child_count-1, entry);
dt->children[dt->child_count-1] = entry;
ptr += entry->length;
}
//printf ("count = %d\n\n", dt->child_count);
if (dt->child_count > 0) {
//printf ("%d subnodes\n", dt->child_count);
dt->sub_nodes = calloc (dt->child_count, sizeof (struct ntfs_dt *));
}
return dt->child_count;
}
/**
* ntfs_dt_count_alloc
*/
static int ntfs_dt_count_alloc (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;
buffer = dt->data;
size = dt->data_len;
//utils_dump_mem (buffer, 0, 128, DM_DEFAULTS);
block = (INDEX_BLOCK*) buffer;
//printf ("INDX %lld\n", block->index_block_vcn);
ptr = buffer + 0x18 + block->index.entries_offset;
//printf ("block size %d\n", block->index.index_length);
dt->child_count = 0;
while (ptr < (buffer + 0x18 + block->index.index_length)) {
entry = (INDEX_ENTRY*) ptr;
dt->child_count++;
dt->children = ntfs_dt_alloc_children (dt->children, dt->child_count);
if (entry->flags & INDEX_ENTRY_NODE) {
vcn = ntfs_ie_get_vcn ((INDEX_ENTRY*) ptr);
//printf ("\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, entry->key.file_name.file_name_length);
//printf ("\tinode %8lld %s\n", MREF (entry->indexed_file), name);
free (name);
name = NULL;
}
ptr += entry->length;
}
//printf ("count = %d\n", dt->child_count);
if (dt->child_count > 0) {
//printf ("%d subnodes\n", dt->child_count);
dt->sub_nodes = calloc (dt->child_count, sizeof (struct ntfs_dt *));
}
return dt->child_count;
}
/**
* ntfs_dt_alloc
*/
static struct ntfs_dt * ntfs_dt_alloc (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;
dt->dir = dir;
dt->parent = parent;
dt->children = NULL;
dt->child_count = 0;
dt->sub_nodes = NULL;
dt->vcn = vcn;
if (parent) {
//printf ("alloc a = %lld\n", dir->ialloc->allocated_size);
//printf ("alloc d = %lld\n", dir->ialloc->data_size);
//printf ("alloc i = %lld\n", dir->ialloc->initialized_size);
//printf ("vcn = %lld\n", vcn);
dt->data_len = dt->dir->index_size;
//printf ("parent size = %d\n", dt->data_len);
dt->data = malloc (dt->data_len);
//printf ("%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);
//utils_dump_mem (dt->data, 0, dt->data_len, DM_DEFAULTS);
//printf ("\n");
ntfs_dt_count_alloc (dt);
dt->header = &((INDEX_BLOCK*)dt->data)->index;
//printf ("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];
printf ("%d\n", ((u8*)ie) - dt->data);
if (ie->flags & INDEX_ENTRY_END)
printf ("IE (%d)\n", ie->length);
else
printf ("IE %lld (%d)\n", MREF (ie->key.file_name.parent_directory), ie->length);
utils_dump_mem ((u8*)ie, 0, ie->length, DM_DEFAULTS);
printf ("\n");
}
#endif
} else {
//printf ("root a = %lld\n", dir->iroot->allocated_size);
//printf ("root d = %lld\n", dir->iroot->data_size);
//printf ("root i = %lld\n", dir->iroot->initialized_size);
dt->data_len = dir->iroot->allocated_size;
dt->data = malloc (dt->data_len);
//printf ("%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_dt_count_root (dt);
dt->header = &((INDEX_ROOT*)dt->data)->index;
//dt->data_len = ((INDEX_ROOT*)dt->data)->index_block_size;
//printf ("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];
printf ("%d\n", ((u8*)ie) - dt->data);
if (ie->flags & INDEX_ENTRY_END)
printf ("IE (%d)\n", ie->length);
else
printf ("IE %lld (%d)\n", MREF (ie->key.file_name.parent_directory), ie->length);
utils_dump_mem ((u8*)ie, 0, ie->length, DM_DEFAULTS);
printf ("\n");
}
#endif
}
//printf ("index_header (%d,%d)\n", dt->header.index_length, dt->header.allocated_size);
return dt;
}
/**
* ntfs_dt_free
*/
static void ntfs_dt_free (struct ntfs_dt *dt)
{
int i;
if (!dt)
return;
for (i = 0; i < dt->child_count; i++)
ntfs_dt_free (dt->sub_nodes[i]);
free (dt->sub_nodes);
free (dt->children);
free (dt->data);
free (dt);
}
/**
* ntfs_dt_find
* find dt by name, return MFT_REF
* maps dt's as necessary
*/
static 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;
/*
* 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
*/
//printf ("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 {
//printf ("\t"); ntfs_name_print (ie->key.file_name.file_name, ie->key.file_name.file_name_length); printf ("\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);
}
//printf ("%d, %d\n", i, r);
if (r == 1) {
//printf ("keep searching\n");
continue;
} else if (r == 0) {
res = MREF (ie->indexed_file);
//printf ("match %lld\n", res);
} else if (r == -1) {
if (ie->flags & INDEX_ENTRY_NODE) {
//printf ("map & recurse\n");
//printf ("sub %p\n", dt->sub_nodes);
if (!dt->sub_nodes[i]) {
vcn = ntfs_ie_get_vcn (ie);
//printf ("vcn = %lld\n", vcn);
sub = ntfs_dt_alloc (dt->dir, dt, vcn);
dt->sub_nodes[i] = sub;
}
res = ntfs_dt_find (dt->sub_nodes[i], name, name_len);
} else {
//printf ("ENOENT\n");
}
} else {
printf ("error collating name\n");
}
break;
}
return res;
}
/**
* ntfs_dt_find2
* find dt by name, returns dt and index
* maps dt's as necessary
*/
static 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;
int i;
int r;
if (!dt || !name)
return NULL;
/*
* 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
*/
//printf ("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 {
//printf ("\t"); ntfs_name_print (ie->key.file_name.file_name, ie->key.file_name.file_name_length); printf ("\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);
}
//printf ("%d, %d\n", i, r);
if (r == 1) {
//printf ("keep searching\n");
continue;
} else if (r == 0) {
res = dt;
//printf ("match %p\n", res);
if (index_num)
*index_num = i;
} else if (r == -1) {
//printf ("recurse\n");
res = ntfs_dt_find2 (dt->sub_nodes[i], name, name_len, index_num);
} else {
printf ("error collating name\n");
}
break;
}
return res;
}
/**
* ntfs_dt_find3
* find dt by name, returns dt and index
* does not map new dt's
*/
static 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;
//printf ("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 {
//printf ("\t"); ntfs_name_print (ie->key.file_name.file_name, ie->key.file_name.file_name_length); printf ("\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);
}
//printf ("%d, %d\n", i, r);
if (r == 1) {
//printf ("keep searching\n");
continue;
} else if (r == 0) {
res = dt;
//printf ("match %p\n", res);
if (index_num)
*index_num = i;
} else if (r == -1) {
if (ie->flags & INDEX_ENTRY_NODE) {
//printf ("recurse\n");
res = ntfs_dt_find3 (dt->sub_nodes[i], name, name_len, index_num);
} else {
//printf ("no match\n");
res = dt;
if (index_num)
*index_num = i;
}
} else {
printf ("error collating name\n");
}
break;
}
return res;
}
/**
* ntfs_dt_find4
* find successor to specified name, returns dt and index
* maps dt's as necessary
*/
static 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;
//printf ("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 {
//printf ("\t"); ntfs_name_print (ie->key.file_name.file_name, ie->key.file_name.file_name_length); printf ("\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);
}
//printf ("%d, %d\n", i, r);
if (r == 1) {
//printf ("keep searching\n");
} else if (r == 0) {
//res = dt;
//printf ("match\n");
// ignore
} else if (r == -1) {
if (ie->flags & INDEX_ENTRY_NODE) {
//printf ("recurse\n");
if (!dt->sub_nodes[i]) {
vcn = ntfs_ie_get_vcn (ie);
//printf ("vcn = %lld\n", vcn);
sub = ntfs_dt_alloc (dt->dir, dt, vcn);
dt->sub_nodes[i] = sub;
}
res = ntfs_dt_find4 (dt->sub_nodes[i], name, name_len, index_num);
} else {
//printf ("no match\n");
res = dt;
if (index_num)
*index_num = i;
}
break;
} else {
printf ("error collating name\n");
}
//break;
}
return res;
}
/**
* ntfs_dt_commit
*/
static int ntfs_dt_commit (struct ntfs_dt *dt)
{
if (!dt)
return -1;
return 0;
}
/**
* ntfs_dt_rollback
*/
static int ntfs_dt_rollback (struct ntfs_dt *dt)
{
if (!dt)
return -1;
return 0;
}
/**
* ntfs_dt_find_parent
*/
static int ntfs_dt_find_parent (struct ntfs_dt *dt)
{
int i;
struct ntfs_dt *parent;
if (!dt)
return -1;
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_root
*/
static BOOL ntfs_dt_root (struct ntfs_dt *dt)
{
if (!dt)
return FALSE;
return (dt->parent == NULL);
}
/**
* ntfs_dir_alloc
*/
static struct ntfs_dir * ntfs_dir_alloc (ntfs_volume *vol, MFT_REF mft_num)
{
struct ntfs_dir *dir = NULL;
ntfs_inode *inode = NULL;
ATTR_RECORD *rec = NULL;
INDEX_ROOT *ir = NULL;
if (!vol)
return NULL;
inode = ntfs_inode_open (vol, mft_num);
if (!inode)
return NULL;
dir = calloc (1, sizeof (*dir));
if (!dir) {
ntfs_inode_close (inode);
return NULL;
}
dir->inode = inode;
dir->iroot = ntfs_attr_open (inode, AT_INDEX_ROOT, I30, 4);
dir->ialloc = ntfs_attr_open (inode, AT_INDEX_ALLOCATION, I30, 4);
dir->ibmp = ntfs_attr_open (inode, AT_BITMAP, I30, 4);
dir->vol = vol;
dir->parent = NULL;
dir->name = NULL;
dir->name_len = 0;
dir->index = NULL;
dir->children = NULL;
dir->child_count = 0;
dir->mft_num = mft_num;
dir->bitmap = NULL;
if (dir->ialloc) {
rec = find_first_attribute (AT_INDEX_ROOT, inode->mrec);
ir = (INDEX_ROOT*) ((u8*)rec + rec->value_offset);
dir->index_size = ir->index_block_size;
} else {
dir->index_size = 0;
}
if (!dir->iroot) {
free (dir);
return NULL;
}
return dir;
}
/**
* ntfs_dir_free
*/
static void ntfs_dir_free (struct ntfs_dir *dir)
{
struct ntfs_dir *parent;
int i;
if (!dir)
return;
parent = dir->parent;
if (parent) {
for (i = 0; i < parent->child_count; i++) {
if (parent->children[i] == dir) {
parent->children[i] = NULL;
}
}
}
ntfs_attr_close (dir->iroot);
ntfs_attr_close (dir->ialloc);
ntfs_attr_close (dir->ibmp);
ntfs_inode_close (dir->inode);
for (i = 0; i < dir->child_count; i++)
ntfs_dir_free (dir->children[i]);
free (dir->children);
ntfs_dt_free (dir->index);
free (dir);
}
/**
* ntfs_dir_find
*/
static MFT_REF ntfs_dir_find (struct ntfs_dir *dir, char *name)
{
MFT_REF mft_num;
ntfschar *uname = NULL;
int len;
if (!dir || !name)
return -1;
len = ntfs_mbstoucs (name, &uname, 0);
if (len < 0)
return -1;
if (!dir->index)
dir->index = ntfs_dt_alloc (dir, NULL, -1);
//printf ("dir->index = %p\n", dir->index);
//printf ("dir->child_count = %d\n", dir->child_count);
//printf ("uname = %p\n", uname);
mft_num = ntfs_dt_find (dir->index, uname, len);
free (uname);
return mft_num;
}
/**
* ntfs_dir_add
*/
static void ntfs_dir_add (struct ntfs_dir *parent, struct ntfs_dir *child)
{
if (!parent || !child)
return;
parent->child_count++;
//printf ("child count = %d\n", parent->child_count);
parent->children = realloc (parent->children, parent->child_count * sizeof (struct ntfs_dir*));
child->parent = parent;
parent->children[parent->child_count-1] = child;
}
/**
* ntfs_dir_commit
*/
static int ntfs_dir_commit (struct ntfs_dir *dir)
{
if (!dir)
return -1;
if (0) ntfs_dt_commit (NULL);
if (0) ntfs_bmp_commit (NULL);
return 0;
}
/**
* ntfs_dir_rollback
*/
static int ntfs_dir_rollback (struct ntfs_dir *dir)
{
if (!dir)
return -1;
if (0) ntfs_dt_rollback (NULL);
if (0) ntfs_bmp_rollback (NULL);
return 0;
}
/**
* utils_pathname_to_mftref
*/
static MFT_REF utils_pathname_to_mftref (ntfs_volume *vol, struct ntfs_dir *parent, const char *pathname, struct ntfs_dir **finddir)
{
MFT_REF mft_num;
MFT_REF result = -1;
char *p, *q;
char *ascii = NULL;
struct ntfs_dir *dir = NULL;
if (!vol || !parent || !pathname) {
errno = EINVAL;
return -1;
}
ascii = strdup (pathname); // Work with a r/w copy
if (!ascii) {
Eprintf ("Out of memory.\n");
goto close;
}
p = ascii;
while (p && *p && *p == PATH_SEP) // Remove leading /'s
p++;
while (p && *p) {
q = strchr (p, PATH_SEP); // Find the end of the first token
if (q != NULL) {
*q = '\0';
q++;
}
//printf ("looking for %s in %p\n", p, parent);
mft_num = ntfs_dir_find (parent, p);
if (mft_num == (u64)-1) {
Eprintf ("Couldn't find name '%s' in pathname '%s'.\n", p, pathname);
goto close;
}
if (q) {
dir = ntfs_dir_alloc (vol, mft_num);
if (!dir) {
Eprintf ("Couldn't allocate a new directory (%lld).\n", mft_num);
goto close;
}
ntfs_dir_add (parent, dir);
parent = dir;
} else {
//printf ("file %s\n", p);
result = mft_num;
if (finddir)
*finddir = dir ? dir : parent;
break;
}
p = q;
while (p && *p && *p == PATH_SEP)
p++;
}
close:
free (ascii);
return result;
}
/**
* utils_mftrec_mark_free
*/
static int utils_mftrec_mark_free (ntfs_volume *vol, MFT_REF mref)
{
static u8 buffer[512];
static s64 bmpmref = -sizeof (buffer) - 1; /* Which bit of $BITMAP is in the buffer */
int byte, bit;
if (!vol) {
errno = EINVAL;
return -1;
}
mref = MREF (mref);
//printf ("mref = %lld\n", mref);
/* Does mref lie in the section of $Bitmap we already have cached? */
if (((s64)mref < bmpmref) || ((s64)mref >= (bmpmref +
(sizeof (buffer) << 3)))) {
Dprintf ("Bit lies outside cache.\n");
/* Mark the buffer as not in use, in case the read is shorter. */
memset (buffer, 0, sizeof (buffer));
bmpmref = mref & (~((sizeof (buffer) << 3) - 1));
if (ntfs_attr_pread (vol->mftbmp_na, (bmpmref>>3), sizeof (buffer), buffer) < 0) {
Eprintf ("Couldn't read $MFT/$BITMAP: %s\n", strerror (errno));
return -1;
}
Dprintf ("Reloaded bitmap buffer.\n");
}
bit = 1 << (mref & 7);
byte = (mref >> 3) & (sizeof (buffer) - 1);
Dprintf ("cluster = %lld, bmpmref = %lld, byte = %d, bit = %d, in use %d\n",
mref, bmpmref, byte, bit, buffer[byte] & bit);
if ((buffer[byte] & bit) == 0) {
Eprintf ("MFT record isn't in use (1).\n");
return -1;
}
//utils_dump_mem (buffer, byte, 1, DM_NO_ASCII);
buffer[byte] &= ~bit;
//utils_dump_mem (buffer, byte, 1, DM_NO_ASCII);
if (ntfs_attr_pwrite (vol->mftbmp_na, (bmpmref>>3), sizeof (buffer), buffer) < 0) {
Eprintf ("Couldn't write $MFT/$BITMAP: %s\n", strerror (errno));
return -1;
}
return (buffer[byte] & bit);
}
/**
* utils_mftrec_mark_free2
*/
static int utils_mftrec_mark_free2 (ntfs_volume *vol, MFT_REF mref)
{
u8 buffer[1024];
s64 res;
MFT_RECORD *rec;
if (!vol)
return -1;
mref = MREF (mref);
rec = (MFT_RECORD*) buffer;
res = ntfs_mft_record_read (vol, mref, rec);
printf ("res = %lld\n", res);
if ((rec->flags & MFT_RECORD_IN_USE) == 0) {
Eprintf ("MFT record isn't in use (2).\n");
return -1;
}
rec->flags &= ~MFT_RECORD_IN_USE;
//printf ("\n");
//utils_dump_mem (buffer, 0, 1024, DM_DEFAULTS);
res = ntfs_mft_record_write (vol, mref, rec);
printf ("res = %lld\n", res);
return 0;
}
/**
* utils_mftrec_mark_free3
*/
static int utils_mftrec_mark_free3 (struct ntfs_bmp *bmp, MFT_REF mref)
{
return ntfs_bmp_set_range (bmp, (VCN) MREF (mref), 1, 0);
}
/**
* utils_mftrec_mark_free4
*/
static int utils_mftrec_mark_free4 (ntfs_inode *inode)
{
MFT_RECORD *rec;
if (!inode)
return -1;
rec = (MFT_RECORD*) inode->mrec;
if ((rec->flags & MFT_RECORD_IN_USE) == 0) {
Eprintf ("MFT record isn't in use (2).\n");
return -1;
}
rec->flags &= ~MFT_RECORD_IN_USE;
//printf ("\n");
//utils_dump_mem (buffer, 0, 1024, DM_DEFAULTS);
printf (GREEN "Modified: inode %lld MFT_RECORD header\n" END, inode->mft_no);
return 0;
}
/**
* utils_free_non_residents
*/
static int utils_free_non_residents (ntfs_inode *inode)
{
// XXX need to do this in memory
ntfs_attr_search_ctx *ctx;
ntfs_attr *na;
ATTR_RECORD *arec;
if (!inode)
return -1;
ctx = ntfs_attr_get_search_ctx (NULL, inode->mrec);
if (!ctx) {
printf ("can't create a search context\n");
return -1;
}
while (ntfs_attr_lookup(AT_UNUSED, NULL, 0, 0, 0, NULL, 0, ctx) == 0) {
arec = ctx->attr;
if (arec->non_resident) {
na = ntfs_attr_open (inode, arec->type, NULL, 0);
if (na) {
runlist_element *rl;
LCN size;
LCN count;
ntfs_attr_map_whole_runlist (na);
rl = na->rl;
size = na->allocated_size >> inode->vol->cluster_size_bits;
for (count = 0; count < size; count += rl->length, rl++) {
//printf ("rl(%llu,%llu,%lld)\n", rl->vcn, rl->lcn, rl->length);
//printf ("freed %d\n", ntfs_cluster_free (inode->vol, na, rl->vcn, rl->length));
ntfs_cluster_free (inode->vol, na, rl->vcn, rl->length);
}
ntfs_attr_close (na);
}
}
}
ntfs_attr_put_search_ctx (ctx);
return 0;
}
/**
* utils_free_non_residents2
*/
static int utils_free_non_residents2 (ntfs_inode *inode, struct ntfs_bmp *bmp)
{
ntfs_attr_search_ctx *ctx;
ntfs_attr *na;
ATTR_RECORD *arec;
if (!inode)
return -1;
ctx = ntfs_attr_get_search_ctx (NULL, inode->mrec);
if (!ctx) {
printf ("can't create a search context\n");
return -1;
}
while (ntfs_attr_lookup(AT_UNUSED, NULL, 0, 0, 0, NULL, 0, ctx) == 0) {
arec = ctx->attr;
if (arec->non_resident) {
na = ntfs_attr_open (inode, arec->type, NULL, 0);
if (na) {
runlist_element *rl;
LCN size;
LCN count;
ntfs_attr_map_whole_runlist (na);
rl = na->rl;
size = na->allocated_size >> inode->vol->cluster_size_bits;
for (count = 0; count < size; count += rl->length, rl++) {
ntfs_bmp_set_range (bmp, rl->lcn, rl->length, 0);
}
ntfs_attr_close (na);
}
}
}
ntfs_attr_put_search_ctx (ctx);
return 0;
}
/**
* ntfs_mft_resize_resident
*/
static int ntfs_mft_resize_resident (ntfs_inode *inode, ATTR_TYPES type, ntfschar *name, int name_len, u8 *data, int data_len)
{
int mft_size;
int mft_usage;
int mft_free;
int attr_orig;
int attr_new;
u8 *src;
u8 *dst;
u8 *end;
int len;
ntfs_attr_search_ctx *ctx = NULL;
ATTR_RECORD *arec = NULL;
MFT_RECORD *mrec = NULL;
int res = -1;
if ((!inode) || (!inode->mrec))
return -1;
if ((!data) || (data_len < 0))
return -1;
mrec = inode->mrec;
mft_size = mrec->bytes_allocated;
mft_usage = mrec->bytes_in_use;
mft_free = mft_size - mft_usage;
//printf ("mft_size = %d\n", mft_size);
//printf ("mft_usage = %d\n", mft_usage);
//printf ("mft_free = %d\n", mft_free);
//printf ("\n");
ctx = ntfs_attr_get_search_ctx (NULL, mrec);
if (!ctx)
goto done;
if (ntfs_attr_lookup(type, name, name_len, CASE_SENSITIVE, 0, NULL, 0, ctx) != 0)
goto done;
arec = ctx->attr;
if (arec->non_resident) {
printf ("attribute isn't resident\n");
goto done;
}
attr_orig = arec->value_length;
attr_new = data_len;
//printf ("attr orig = %d\n", attr_orig);
//printf ("attr new = %d\n", attr_new);
//printf ("\n");
if ((attr_new - attr_orig + mft_usage) > mft_size) {
printf ("attribute won't fit into mft record\n");
goto done;
}
//printf ("new free space = %d\n", mft_size - (attr_new - attr_orig + mft_usage));
src = (u8*)arec + arec->length;
dst = src + (attr_new - attr_orig);
end = (u8*)mrec + mft_usage;
len = end - src;
//printf ("src = %d\n", src - (u8*)mrec);
//printf ("dst = %d\n", dst - (u8*)mrec);
//printf ("end = %d\n", end - (u8*)mrec);
//printf ("len = %d\n", len);
if (src != dst)
memmove (dst, src, len);
memcpy ((u8*)arec + arec->value_offset, data, data_len);
mrec->bytes_in_use += (attr_new - attr_orig);
arec->length += (attr_new - attr_orig);
arec->value_length += (attr_new - attr_orig);
memset ((u8*)mrec + mrec->bytes_in_use, 0, mft_size - mrec->bytes_in_use);
mft_usage += (attr_new - attr_orig);
//utils_dump_mem ((u8*) mrec, 0, mft_size, DM_DEFAULTS);
res = 0;
done:
ntfs_attr_put_search_ctx (ctx);
return res;
}
/**
* ntfs_mft_free_space
*/
static int ntfs_mft_free_space (struct ntfs_dir *dir)
{
int res = 0;
MFT_RECORD *mft;
if ((!dir) || (!dir->inode))
return -1;
mft = (MFT_RECORD*) dir->inode->mrec;
res = mft->bytes_allocated - mft->bytes_in_use;
return res;
}
/**
* ntfs_dt_add_alloc
*/
static int ntfs_dt_add_alloc (struct ntfs_dt *parent, int index_num, INDEX_ENTRY *ie)
{
INDEX_BLOCK *block;
int need;
int space;
u8 *src;
u8 *dst;
int len;
if (!parent || !ie)
return 0;
block = (INDEX_BLOCK*) parent->data;
need = ie->length;
space = parent->data_len - block->index.index_length - 24;
printf ("need %d, have %d\n", need, space);
if (need > space) {
printf ("no room");
return 0;
}
//utils_dump_mem (parent->data, 0, parent->data_len, DM_DEFAULTS);
//printf ("\n");
src = (u8*) parent->children[index_num];
dst = src + need;
len = parent->data + parent->data_len - src - space;
//printf ("src = %d\n", src - parent->data);
//printf ("dst = %d\n", dst - parent->data);
//printf ("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);
//utils_dump_mem (parent->data, 0, parent->data_len, DM_DEFAULTS);
//printf ("\n");
return 0;
}
/**
* ntfs_dt_add_root
*/
static int ntfs_dt_add_root (struct ntfs_dt *parent, int index_num, INDEX_ENTRY *ie)
{
INDEX_ROOT *root;
int need;
int space;
u8 *attr;
u8 *src;
u8 *dst;
int len;
if (!parent || !ie)
return 0;
root = (INDEX_ROOT*) parent->data;
utils_dump_mem (parent->data, 0, parent->data_len, DM_DEFAULTS);
printf ("\n");
need = ie->length;
space = ntfs_mft_free_space (parent->dir);
printf ("need %d, have %d\n", need, space);
if (need > space) {
printf ("no room");
return 0;
}
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;
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);
printf ("\n");
ntfs_mft_resize_resident (parent->dir->inode, AT_INDEX_ROOT, I30, 4, parent->data, parent->data_len);
return 0;
}
/**
* ntfs_dt_add
*/
static int ntfs_dt_add (struct ntfs_dt *parent, INDEX_ENTRY *ie)
{
FILE_NAME_ATTR *file;
struct ntfs_dt *dt;
int index_num = -1;
if (!ie)
return 0;
file = &ie->key.file_name;
dt = ntfs_dt_find3 (parent, file->file_name, file->file_name_length, &index_num);
if (!dt)
return 0;
//printf ("dt = %p, index = %d\n", dt, index_num);
//ntfs_ie_dump (dt->children[index_num]);
//utils_dump_mem ((u8*)dt->children[index_num], 0, dt->children[index_num]->length, DM_DEFAULTS);
//printf ("\n");
if (0) ntfs_dt_add_alloc (dt, index_num, ie);
if (0) ntfs_dt_add_root (dt->dir->index, 0, ie);
return 0;
}
/**
* ntfs_dt_add2
*/
static int ntfs_dt_add2 (INDEX_ENTRY *ie, struct ntfs_dt *suc, int suc_num, struct ntfs_dt *ded)
{
if (!ie || !suc)
return -1;
if (ntfs_dt_root (suc))
ntfs_dt_add_root (suc, suc_num, ie);
else
ntfs_dt_add_alloc (suc, suc_num, ie);
return 0;
}
/**
* ntfs_dt_remove_alloc
*/
static int ntfs_dt_remove_alloc (struct ntfs_dt *dt, int index_num)
{
INDEX_ENTRY *ie = NULL;
int i;
u8 *dst;
u8 *src;
u8 *end;
int off;
int len;
s64 res;
//printf ("removing entry %d of %d\n", index_num+1, dt->child_count);
//printf ("index size = %d\n", dt->data_len);
//printf ("index use = %d\n", dt->header->index_length);
//utils_dump_mem (dt->data, 0, dt->data_len, DM_DEFAULTS);
off = (u8*)dt->children[0] - dt->data;
for (i = 0; i < dt->child_count; i++) {
ie = dt->children[i];
//printf ("%2d %4d ", i, off);
off += ie->length;
if (ie->flags & INDEX_ENTRY_END) {
//printf ("END (%d)\n", ie->length);
break;
}
//ntfs_name_print (ie->key.file_name.file_name, ie->key.file_name.file_name_length);
//printf (" (%d)\n", ie->length);
}
//printf ("total = %d\n", off);
ie = dt->children[index_num];
dst = (u8*)ie;
src = dst + ie->length;
ie = dt->children[dt->child_count-1];
end = (u8*)ie + ie->length;
len = end - src;
//printf ("move %d bytes\n", len);
//printf ("%d, %d, %d\n", dst - dt->data, src - dt->data, len);
memmove (dst, src, len);
//printf ("clear %d bytes\n", dt->data_len - (dst - dt->data) - len);
//printf ("%d, %d, %d\n", dst - dt->data + len, 0, dt->data_len - (dst - dt->data) - len);
//ntfs_dt_print (dt->dir->index, 0);
memset (dst + len, 0, dt->data_len - (dst - dt->data) - len);
for (i = 0; i < dt->child_count; i++) {
if (dt->sub_nodes[i]) {
printf ("this shouldn't happen %p\n", dt->sub_nodes[i]);
ntfs_dt_free (dt->sub_nodes[i]); // shouldn't be any, yet
}
}
free (dt->sub_nodes);
dt->sub_nodes = NULL;
free (dt->children);
dt->children = NULL;
dt->child_count = 0;
//printf ("before = %d\n", dt->header->index_length + 24);
dt->header->index_length -= src - dst;
//printf ("after = %d\n", dt->header->index_length + 24);
ntfs_dt_count_alloc (dt);
//utils_dump_mem (dt->data, 0, dt->data_len, DM_DEFAULTS);
#if 0
//printf ("\n");
//printf ("index size = %d\n", dt->data_len);
//printf ("index use = %d\n", dt->header.index_length);
off = (u8*)dt->children[0] - dt->data;
for (i = 0; i < dt->child_count; i++) {
ie = dt->children[i];
printf ("%2d %4d ", i, off);
off += ie->length;
if (ie->flags & INDEX_ENTRY_END) {
printf ("END (%d)\n", ie->length);
break;
}
ntfs_name_print (ie->key.file_name.file_name,
ie->key.file_name.file_name_length);
printf (" (%d)\n", ie->length);
}
#endif
//utils_dump_mem (dt->data, 0, dt->data_len, DM_DEFAULTS);
res = ntfs_attr_mst_pwrite (dt->dir->ialloc, dt->vcn*512, 1, dt->data_len, dt->data);
printf ("res = %lld\n", res);
return 0;
}
/**
* ntfs_dt_remove_root
*/
static int ntfs_dt_remove_root (struct ntfs_dt *dt, int index_num)
{
INDEX_ENTRY *ie = NULL;
INDEX_ROOT *ir = NULL;
int i;
u8 *dst;
u8 *src;
u8 *end;
int off;
int len;
s64 res;
//printf ("removing entry %d of %d\n", index_num+1, dt->child_count);
//printf ("index size = %d\n", dt->data_len);
//printf ("index use = %d\n", dt->header->index_length);
//utils_dump_mem (dt->data, 0, dt->data_len, DM_DEFAULTS);
off = (u8*)dt->children[0] - dt->data;
for (i = 0; i < dt->child_count; i++) {
ie = dt->children[i];
//printf ("%2d %4d ", i+1, off);
off += ie->length;
if (ie->flags & INDEX_ENTRY_END) {
//printf ("END (%d)\n", ie->length);
break;
}
//ntfs_name_print (ie->key.file_name.file_name, ie->key.file_name.file_name_length);
//printf (" (%d)\n", ie->length);
}
//printf ("total = %d\n", off);
ie = dt->children[index_num];
dst = (u8*)ie;
src = dst + ie->length;
ie = dt->children[dt->child_count-1];
end = (u8*)ie + ie->length;
len = end - src;
//printf ("move %d bytes\n", len);
//printf ("%d, %d, %d\n", dst - dt->data, src - dt->data, len);
memmove (dst, src, len);
dt->data_len -= (src - dt->data - sizeof (INDEX_ROOT));
dt->child_count--;
ir = (INDEX_ROOT*) dt->data;
ir->index.index_length = dt->data_len - 16;
ir->index.allocated_size = dt->data_len - 16;
ntfs_mft_resize_resident (dt->dir->inode, AT_INDEX_ROOT, I30, 4, dt->data, dt->data_len);
dt->data = realloc (dt->data, dt->data_len);
//printf ("ih->index_length = %d\n", ir->index.index_length);
//printf ("ih->allocated_size = %d\n", ir->index.allocated_size);
//printf ("dt->data_len = %d\n", dt->data_len);
//utils_dump_mem (dt->data, 0, dt->data_len, DM_DEFAULTS);
//ntfs_dt_print (dt->dir->index, 0);
#if 1
for (i = 0; i < dt->child_count; i++) {
if (dt->sub_nodes[i]) {
printf ("this shouldn't happen %p\n", dt->sub_nodes[i]);
ntfs_dt_free (dt->sub_nodes[i]); // shouldn't be any, yet
}
}
free (dt->sub_nodes);
dt->sub_nodes = NULL;
free (dt->children);
dt->children = NULL;
dt->child_count = 0;
//printf ("before = %d\n", dt->header->index_length + 24);
dt->header->index_length -= src - dst;
//printf ("after = %d\n", dt->header->index_length + 24);
ntfs_dt_count_root (dt);
#endif
//utils_dump_mem (dt->data, 0, dt->data_len, DM_DEFAULTS);
#if 0
//printf ("\n");
//printf ("index size = %d\n", dt->data_len);
//printf ("index use = %d\n", dt->header.index_length);
off = (u8*)dt->children[0] - dt->data;
for (i = 0; i < dt->child_count; i++) {
ie = dt->children[i];
printf ("%2d %4d ", i, off);
off += ie->length;
if (ie->flags & INDEX_ENTRY_END) {
printf ("END (%d)\n", ie->length);
break;
}
ntfs_name_print (ie->key.file_name.file_name,
ie->key.file_name.file_name_length);
printf (" (%d)\n", ie->length);
}
#endif
//utils_dump_mem (dt->data, 0, dt->data_len, DM_DEFAULTS);
res = ntfs_mft_record_write (dt->dir->inode->vol, dt->dir->inode->mft_no, dt->dir->inode->mrec);
printf ("res = %lld\n", res);
return 0;
}
/**
* ntfs_dt_remove
*/
static int ntfs_dt_remove (struct ntfs_dt *dt, int index_num)
{
if (!dt)
return 1;
if ((index_num < 0) || (index_num >= dt->child_count))
return 1;
if (ntfs_dt_root (dt))
return ntfs_dt_remove_root (dt, index_num);
else
return ntfs_dt_remove_alloc (dt, index_num);
}
/**
* ntfs_dt_del_child
*/
static int ntfs_dt_del_child (struct ntfs_dt *dt, ntfschar *uname, int len)
{
struct ntfs_dt *del;
INDEX_ENTRY *ie;
ntfs_inode *ichild = NULL;
ntfs_inode *iparent = NULL;
ntfs_attr *attr = NULL;
ntfs_attr_search_ctx *ctx = NULL;
int index_num = 0;
int res = 1;
ATTR_RECORD *arec = NULL;
MFT_REF mft_num = -1;
FILE_NAME_ATTR *file;
int filenames = 0;
// compressed & encrypted files?
del = ntfs_dt_find2 (dt, uname, len, &index_num);
if (!del) {
printf ("can't find item to delete\n");
goto close;
}
if ((index_num < 0) || (index_num >= del->child_count)) {
printf ("error in dt_find\n");
goto close;
}
if (del->header->flags & INDEX_NODE) {
printf ("can only delete leaf nodes\n");
goto close;
}
/*
if (!del->parent) {
printf ("has 0xA0, but isn't in use\n");
goto close;
}
*/
ie = del->children[index_num];
if (ie->key.file_name.file_attributes & FILE_ATTR_DIRECTORY) {
printf ("can't delete directories\n");
goto close;
}
if (ie->key.file_name.file_attributes & FILE_ATTR_SYSTEM) {
printf ("can't delete system files\n");
goto close;
}
ichild = ntfs_inode_open (dt->dir->vol, MREF (ie->indexed_file));
if (!ichild) {
printf ("can't open inode\n");
goto close;
}
ctx = ntfs_attr_get_search_ctx (NULL, ichild->mrec);
if (!ctx) {
printf ("can't create a search context\n");
goto close;
}
while (ntfs_attr_lookup(AT_UNUSED, NULL, 0, 0, 0, NULL, 0, ctx) == 0) {
arec = ctx->attr;
if (arec->type == AT_ATTRIBUTE_LIST) {
printf ("can't delete files with an attribute list\n");
goto close;
}
if (arec->type == AT_INDEX_ROOT) {
printf ("can't delete directories\n");
goto close;
}
if (arec->type == AT_FILE_NAME) {
filenames++;
file = (FILE_NAME_ATTR*) ((u8*) arec + arec->value_offset);
mft_num = MREF (file->parent_directory);
}
}
if (filenames != 1) {
printf ("file has more than one name\n");
goto close;
}
iparent = ntfs_inode_open (dt->dir->vol, mft_num);
if (!iparent) {
printf ("can't open parent directory\n");
goto close;
}
/*
attr = ntfs_attr_open (iparent, AT_INDEX_ALLOCATION, I30, 4);
if (!attr) {
printf ("parent doesn't have 0xA0\n");
goto close;
}
*/
//printf ("deleting file\n");
//ntfs_dt_print (del->dir->index, 0);
if (1) res = utils_free_non_residents (ichild);
if (1) res = utils_mftrec_mark_free (dt->dir->vol, del->children[index_num]->indexed_file);
if (1) res = utils_mftrec_mark_free2 (dt->dir->vol, del->children[index_num]->indexed_file);
if (1) res = ntfs_dt_remove (del, index_num);
close:
ntfs_attr_put_search_ctx (ctx);
ntfs_attr_close (attr);
ntfs_inode_close (iparent);
ntfs_inode_close (ichild);
return res;
}
/**
* ntfsrm
*/
static int ntfsrm (ntfs_volume *vol, char *name)
{
struct ntfs_dir *dir = NULL;
struct ntfs_dir *finddir = NULL;
MFT_REF mft_num;
ntfschar *uname = NULL;
int len;
dir = ntfs_dir_alloc (vol, FILE_root);
if (!dir)
return 1;
//mft_num = ntfs_dir_find (dir, name);
//printf ("%s = %lld\n", name, mft_num);
mft_num = utils_pathname_to_mftref (vol, dir, name, &finddir);
//printf ("mft_num = %lld\n", mft_num);
//ntfs_dir_print (finddir, 0);
if (!finddir) {
printf ("Couldn't find the index entry for %s\n", name);
return 1;
}
if (rindex (name, PATH_SEP))
name = rindex (name, PATH_SEP) + 1;
len = ntfs_mbstoucs (name, &uname, 0);
if (len < 0)
return 1;
ntfs_dt_del_child (finddir->index, uname, len);
ntfs_dir_free (dir);
free (uname);
return 0;
}
/**
* ntfsinfo_time_to_str() -
* @sle_ntfs_clock: on disk time format in 100ns units since 1st jan 1601
* in little-endian format
*
* Return char* in a format 'Thu Jan 1 00:00:00 1970'.
* No need to free the returned memory.
*
* Example of usage:
* char *time_str = ntfsinfo_time_to_str(
* sle64_to_cpu(standard_attr->creation_time));
* printf("\tFile Creation Time:\t %s", time_str);
*/
static const char *ntfsinfo_time_to_str(const s64 sle_ntfs_clock)
{
time_t unix_clock = ntfs2utc(sle64_to_cpu(sle_ntfs_clock));
if (sle_ntfs_clock == 0)
return "none\n";
else
return ctime(&unix_clock);
}
/**
* ntfs_ie_dump
*/
static void ntfs_ie_dump (INDEX_ENTRY *ie)
{
if (!ie)
return;
printf ("________________________________________________");
printf ("\n");
utils_dump_mem ((u8*)ie, 0, ie->length, DM_DEFAULTS);
printf ("MFT Ref: 0x%llx\n", ie->indexed_file);
printf ("length: %d\n", ie->length);
printf ("keylen: %d\n", ie->key_length);
printf ("flags: ");
if (ie->flags & INDEX_ENTRY_NODE) printf ("NODE ");
if (ie->flags & INDEX_ENTRY_END) printf ("END");
if (!(ie->flags & (INDEX_ENTRY_NODE | INDEX_ENTRY_END))) printf ("none");
printf ("\n");
printf ("reserved 0x%04x\n", ie->reserved);
if (ie->key_length > 0) {
printf ("mft parent: 0x%llx\n", ie->key.file_name.parent_directory);
printf ("ctime: %s", ntfsinfo_time_to_str(ie->key.file_name.creation_time));
printf ("dtime: %s", ntfsinfo_time_to_str(ie->key.file_name.last_data_change_time));
printf ("mtime: %s", ntfsinfo_time_to_str(ie->key.file_name.last_mft_change_time));
printf ("atime: %s", ntfsinfo_time_to_str(ie->key.file_name.last_access_time));
printf ("alloc size: %lld\n", ie->key.file_name.allocated_size);
printf ("data size: %lld\n", ie->key.file_name.data_size);
printf ("file flags: 0x%04x\n", ie->key.file_name.file_attributes);
printf ("reserved: 0x%04x\n", ie->key.file_name.reserved); printf ("name len: %d\n", ie->key.file_name.file_name_length);
if (ie->key.file_name.file_name_length > 0) {
int i, r;
printf ("name type: %d\n", ie->key.file_name.file_name_type);
printf ("name: ");
ntfs_name_print (ie->key.file_name.file_name, ie->key.file_name.file_name_length);
printf ("\n");
r = ATTR_SIZE (2 * (ie->key.file_name.file_name_length+1)) - (2 * (ie->key.file_name.file_name_length+1));
if (r > 0) {
u8 *ptr;
printf ("padding: ");
ptr = (u8*) (ie->key.file_name.file_name + ie->key.file_name.file_name_length);
for (i = 0; i < r; i++, ptr++)
printf ("0x%02x ", *ptr);
printf ("\n");
}
}
}
if (ie->flags == INDEX_ENTRY_NODE) {
printf ("child vcn = %lld\n", ntfs_ie_get_vcn (ie));
}
}
/**
* ntfs_ie_create
*/
static INDEX_ENTRY * ntfs_ie_create (void)
{
int length;
INDEX_ENTRY *ie;
length = 16;
ie = malloc (length);
if (!ie)
return NULL;
ie->indexed_file = 0;
ie->length = length;
ie->key_length = 0;
ie->flags = INDEX_ENTRY_END;
ie->reserved = 0;
return ie;
}
/**
* ntfs_ie_copy
*/
static INDEX_ENTRY * ntfs_ie_copy (INDEX_ENTRY *ie)
{
INDEX_ENTRY *copy = NULL;
if (!ie)
return NULL;
copy = malloc (ie->length);
if (!copy)
return NULL;
memcpy (copy, ie, ie->length);
return copy;
}
/**
* ntfs_ie_set_vcn
*/
static INDEX_ENTRY * ntfs_ie_set_vcn (INDEX_ENTRY *ie, VCN vcn)
{
if (!ie)
return 0;
if (!(ie->flags & INDEX_ENTRY_NODE)) {
ie->length += 8;
ie = realloc (ie, ie->length);
if (!ie)
return NULL;
ie->flags |= INDEX_ENTRY_NODE;
}
*((VCN*) ((u8*) ie + ie->length - 8)) = vcn;
return ie;
}
/**
* ntfs_ie_remove_vcn
*/
static INDEX_ENTRY * ntfs_ie_remove_vcn (INDEX_ENTRY *ie)
{
if (!ie)
return NULL;
if (!(ie->flags & INDEX_ENTRY_NODE))
return ie;
ie->length -= 8;
ie->flags &= ~INDEX_ENTRY_NODE;
ie = realloc (ie, ie->length);
return ie;
}
/**
* ntfs_ie_set_name
*/
static INDEX_ENTRY * ntfs_ie_set_name (INDEX_ENTRY *ie, ntfschar *name, int namelen, FILE_NAME_TYPE_FLAGS nametype)
{
FILE_NAME_ATTR *file;
int klen;
int need;
VCN vcn = 0;
if (!ie || !name)
return NULL;
/*
* INDEX_ENTRY
* MFT_REF indexed_file;
* u16 length;
* u16 key_length;
* INDEX_ENTRY_FLAGS flags;
* u16 reserved;
*
* FILENAME
* MFT_REF parent_directory;
* s64 creation_time;
* s64 last_data_change_time;
* s64 last_mft_change_time;
* s64 last_access_time;
* s64 allocated_size;
* s64 data_size;
* FILE_ATTR_FLAGS file_attributes;
* u32 reserved;
* u8 file_name_length;
* FILE_NAME_TYPE_FLAGS file_name_type;
* ntfschar file_name[l];
* u8 reserved[n]
*
* VCN vcn;
*/
file = &ie->key.file_name;
klen = ATTR_SIZE (ie->key_length);
need = ATTR_SIZE (sizeof (FILE_NAME_ATTR) + (namelen * sizeof (ntfschar)));
//printf ("ilen = %d\n", ie->length);
//printf ("klen = %d\n", klen);
//printf ("need = %d\n", need);
if (ie->flags & INDEX_ENTRY_NODE)
vcn = ntfs_ie_get_vcn (ie);
ie->length = 16 + need;
ie->key_length = sizeof (FILE_NAME_ATTR) + (namelen * sizeof (ntfschar));
ie = realloc (ie, ie->length + ie->key_length);
if (!ie)
return NULL;
memcpy (ie->key.file_name.file_name, name, namelen * 2);
if (ie->flags & INDEX_ENTRY_NODE)
ie = ntfs_ie_set_vcn (ie, vcn);
ie->key.file_name.file_name_length = namelen;
ie->key.file_name.file_name_type = nametype;
ie->flags &= ~INDEX_ENTRY_END;
return ie;
}
/**
* ntfs_ie_remove_name
*/
static INDEX_ENTRY * ntfs_ie_remove_name (INDEX_ENTRY *ie)
{
VCN vcn;
if (!ie)
return NULL;
if (ie->key_length == 0)
return ie;
if (ie->flags & INDEX_ENTRY_NODE)
vcn = ntfs_ie_get_vcn (ie);
ie->length -= ATTR_SIZE (ie->key_length);
ie->key_length = 0;
ie->flags |= INDEX_ENTRY_END;
ie = realloc (ie, ie->length);
if (!ie)
return NULL;
if (ie->flags & INDEX_ENTRY_NODE)
ie = ntfs_ie_set_vcn (ie, vcn);
return ie;
}
/**
* ntfs_ie_test
*/
static int ntfs_ie_test (void)
{
INDEX_ENTRY *ie1 = NULL;
INDEX_ENTRY *ie2 = NULL;
int namelen = 0;
ntfschar *name = NULL;
if (1) {
ie1 = ntfs_ie_create();
//ntfs_ie_dump (ie1);
}
if (0) {
ie2 = ntfs_ie_copy (ie1);
ntfs_ie_dump (ie2);
}
if (1) {
namelen = ntfs_mbstoucs("richard", &name, 0);
ie1 = ntfs_ie_set_name (ie1, name, namelen, FILE_NAME_WIN32);
free (name);
name = NULL;
ntfs_ie_dump (ie1);
}
if (1) {
namelen = ntfs_mbstoucs("richard2", &name, 0);
ie1 = ntfs_ie_set_name (ie1, name, namelen, FILE_NAME_WIN32);
free (name);
name = NULL;
ntfs_ie_dump (ie1);
}
if (1) {
ie1 = ntfs_ie_remove_name (ie1);
ntfs_ie_dump (ie1);
}
if (1) {
ie1 = ntfs_ie_set_vcn (ie1, 1234);
ntfs_ie_dump (ie1);
}
if (1) {
ie1 = ntfs_ie_remove_vcn (ie1);
ntfs_ie_dump (ie1);
}
ie1->indexed_file = 1234;
ie1->key.file_name.parent_directory = 5;
ie1->key.file_name.creation_time = utc2ntfs (time(NULL));
ie1->key.file_name.last_data_change_time = utc2ntfs (time(NULL));
ie1->key.file_name.last_mft_change_time = utc2ntfs (time(NULL));
ie1->key.file_name.last_access_time = utc2ntfs (time(NULL));
ie1->key.file_name.allocated_size = 4096;
ie1->key.file_name.data_size = 3973;
//ntfs_ie_dump (ie1);
free (name);
free (ie1);
free (ie2);
return 0;
}
/**
* ntfs_ie_get_vcn
*/
static VCN ntfs_ie_get_vcn (INDEX_ENTRY *ie)
{
if (!ie)
return -1;
return *((VCN*) ((u8*) ie + ie->length - 8));
}
/**
* ntfs_index_dump_alloc
*/
static int ntfs_index_dump_alloc (ntfs_attr *attr, VCN vcn, int indent)
{
u8 buffer[4096];
INDEX_BLOCK *block;
INDEX_ENTRY *entry;
u8 *ptr;
int size;
VCN *newvcn;
ntfs_attr_mst_pread (attr, vcn*512, 1, sizeof (buffer), buffer);
block = (INDEX_BLOCK*) buffer;
size = block->index.allocated_size;
for (ptr = buffer + 64; ptr < (buffer + size); ptr += entry->length) {
entry = (INDEX_ENTRY*) ptr;
if (entry->flags & INDEX_ENTRY_NODE) {
newvcn = (VCN*) (ptr + ((entry->key_length + 0x17) & ~7));
ntfs_index_dump_alloc (attr, *newvcn, indent+4);
}
printf ("%.*s", indent, space);
if (entry->flags & INDEX_ENTRY_END) {
printf ("[END]");
} else {
ntfs_name_print (entry->key.file_name.file_name, entry->key.file_name.file_name_length);
}
if (entry->flags & INDEX_ENTRY_NODE) {
printf (" (%lld)\n", *newvcn);
} else {
printf ("\n");
}
if (entry->flags & INDEX_ENTRY_END)
break;
}
printf ("%.*s", indent, space);
printf ("fill = %d/%d\n", block->index.index_length, block->index.allocated_size);
return 0;
}
/**
* ntfs_index_dump
*/
static int ntfs_index_dump (ntfs_inode *inode)
{
u8 buffer[1024];
ntfs_attr *iroot;
ntfs_attr *ialloc;
INDEX_ROOT *root;
INDEX_ENTRY *entry;
u8 *ptr;
int size;
VCN *vcn;
if (!inode)
return 0;
iroot = ntfs_attr_open (inode, AT_INDEX_ROOT, I30, 4);
ialloc = ntfs_attr_open (inode, AT_INDEX_ALLOCATION, I30, 4);
size = (int) ntfs_attr_pread (iroot, 0, sizeof (buffer), buffer);
root = (INDEX_ROOT*) buffer;
ptr = buffer + root->index.entries_offset + 0x10;
while (ptr < (buffer + size)) {
entry = (INDEX_ENTRY*) ptr;
if (entry->flags & INDEX_ENTRY_NODE) {
vcn = (VCN*) (ptr + ((entry->key_length + 0x17) & ~7));
ntfs_index_dump_alloc (ialloc, *vcn, 4);
}
if (entry->flags & INDEX_ENTRY_END) {
printf ("[END]");
} else {
ntfs_name_print (entry->key.file_name.file_name, entry->key.file_name.file_name_length);
}
if (entry->flags & INDEX_ENTRY_NODE) {
printf (" (%lld)", *vcn);
}
printf ("\n");
ptr += entry->length;
}
printf ("fill = %d\n", ptr - buffer);
return 0;
}
/**
* ntfs_dt_root_replace
*/
static 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;
//utils_dump_mem (del->data, 0, del->data_len, DM_DEFAULTS);
//printf ("\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 = del->data_len + suc_ie->length - del_ie->length;
free (del->data);
del->data = attr;
del->data_len = len;
ntfs_mft_resize_resident (del->dir->inode, AT_INDEX_ROOT, I30, 4, del->data, del->data_len);
//utils_dump_mem (attr, 0, del->data_len, DM_DEFAULTS);
//printf ("\n");
//printf (BOLD YELLOW "Adjust children\n" END);
//for (i = 0; i < del->child_count; i++)
// printf ("\tChild %d %p %d\n", i, del->children[i], del->children[i]->flags);
//printf ("\n");
len = suc_ie->length - del_ie->length;
//printf ("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++)
// printf ("\tChild %d %p %d\n", i, del->children[i], del->children[i]->flags);
//printf ("\n");
//utils_dump_mem (del->data, 0, del->data_len, DM_DEFAULTS);
//printf ("\n");
printf (GREEN "Modified: inode %lld, $INDEX_ROOT\n" END, del->dir->inode->mft_no);
return TRUE;
}
/**
* ntfs_dt_alloc_replace
*/
static 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;
//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);
//printf ("src = %d\n", src - del->data);
//printf ("dst = %d\n", dst - del->data);
//printf ("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++)
// printf ("Child %d %p\n", i, del->children[i]);
//printf ("\n");
len = suc_ie->length - del_ie->length;
//printf ("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++)
// printf ("Child %d %p\n", i, del->children[i]);
//printf ("\n");
//utils_dump_mem (del->data, 0, del->data_len, DM_DEFAULTS);
printf (GREEN "Modified: inode %lld, $INDEX_ALLOCATION vcn %lld-%lld\n" END, del->dir->inode->mft_no, del->vcn, del->vcn + 4);
return TRUE;
}
/**
* ntfs_dt_root_remove
*/
static BOOL ntfs_dt_root_remove (struct ntfs_dt *del, int del_num)
{
INDEX_ENTRY *del_ie = NULL;
u8 *src;
u8 *dst;
int len;
int i;
//int off;
if (!del)
return FALSE;
//utils_dump_mem (del->data, 0, del->data_len, DM_RED);
//printf ("\n");
#if 0
off = (u8*) del->children[0] - del->data;
for (i = 0; i < del->child_count; i++) {
del_ie = del->children[i];
printf ("%2d %4d ", i+1, off);
off += del_ie->length;
if (del_ie->flags & INDEX_ENTRY_END) {
printf ("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);
printf (" (%d)\n", del_ie->length);
}
printf ("total = %d\n", off);
#endif
del_ie = del->children[del_num];
src = (u8*) del_ie + del_ie->length;
dst = (u8*) del_ie;
len = del->header->index_length + 16 - (src - del->data);
//printf ("src = %d\n", src - del->data);
//printf ("dst = %d\n", dst - del->data);
//printf ("len = %d\n", len);
memmove (dst, src, len);
del->data_len -= del_ie->length;
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, I30, 4, del->data, del->data_len);
del->data = realloc (del->data, del->data_len);
//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*);
//printf ("src = %d\n", src - (u8*) del->children);
//printf ("dst = %d\n", dst - (u8*) del->children);
//printf ("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*);
//printf ("src = %d\n", src - (u8*) del->children);
//printf ("dst = %d\n", dst - (u8*) del->children);
//printf ("len = %d\n", len);
memmove (dst, src, len);
//printf ("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_alloc_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];
printf ("%2d %4d ", i+1, off);
off += del_ie->length;
if (del_ie->flags & INDEX_ENTRY_END) {
printf ("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);
printf (" (%d)\n", del_ie->length);
}
printf ("total = %d\n", off);
#endif
//utils_dump_mem (del->data, 0, del->data_len, DM_DEFAULTS);
printf (GREEN "Modified: inode %lld, $INDEX_ROOT\n" END, del->dir->inode->mft_no);
return TRUE;
}
/**
* ntfs_dt_alloc_remove
*/
static 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;
#if 0
off = (u8*)del->children[0] - del->data;
for (i = 0; i < del->child_count; i++) {
del_ie = del->children[i];
printf ("%2d %4d ", i, off);
off += del_ie->length;
if (del_ie->flags & INDEX_ENTRY_END) {
printf ("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);
printf (" (%d)\n", del_ie->length);
}
printf ("total = %d\n", off);
printf ("\n");
#endif
//utils_dump_mem (del->data, 0, del->data_len, DM_DEFAULTS);
//printf ("\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);
//printf ("src = %d\n", src - del->data);
//printf ("dst = %d\n", dst - del->data);
//printf ("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;
//printf ("dst = %d\n", dst - del->data);
//printf ("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*);
//printf ("src = %d\n", src - (u8*) del->children);
//printf ("dst = %d\n", dst - (u8*) del->children);
//printf ("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*);
//printf ("src = %d\n", src - (u8*) del->children);
//printf ("dst = %d\n", dst - (u8*) del->children);
//printf ("len = %d\n", len);
memmove (dst, src, len);
//printf ("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_alloc_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];
printf ("%2d %4d ", i, off);
off += del_ie->length;
if (del_ie->flags & INDEX_ENTRY_END) {
printf ("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);
printf (" (%d)\n", del_ie->length);
}
printf ("total = %d\n", off);
printf ("\n");
#endif
printf (GREEN "Modified: inode %lld, $INDEX_ALLOCATION vcn %lld-%lld\n" END, del->dir->inode->mft_no, del->vcn, del->vcn + 4);
return TRUE;
}
/**
* ntfs_dt_root_add
*/
static int ntfs_dt_root_add (struct ntfs_dt *add, INDEX_ENTRY *add_ie)
{
FILE_NAME_ATTR *file;
struct ntfs_dt *suc;
int suc_num;
int need;
int space;
u8 *attr;
u8 *src;
u8 *dst;
int len;
if (!add || !add_ie)
return 0;
//utils_dump_mem (add->data, 0, add->data_len, DM_DEFAULTS);
//printf ("\n");
need = add_ie->length;
space = ntfs_mft_free_space (add->dir);
file = &add_ie->key.file_name;
suc = ntfs_dt_find3 (add, file->file_name, file->file_name_length, &suc_num);
if (!suc)
return 0;
// hmm, suc == add
printf ("need %d, have %d\n", need, space);
if (need > space) {
printf ("no room");
return 0;
}
attr = malloc (add->data_len + need);
src = add->data;
dst = attr;
len = add->header->entries_offset + 16;
memcpy (dst, src, len);
dst += len;
src = (u8*) add_ie;
len = add_ie->length;
memcpy (dst, src, len);
dst += len;
src = (u8*) suc->children[suc_num];
len = add->data + add->data_len - src;
memcpy (dst, src, len);
free (add->data);
add->data = attr;
add->data_len += need;
add->header->index_length = add->data_len - 16;
add->header->allocated_size = add->data_len - 16;
ntfs_mft_resize_resident (add->dir->inode, AT_INDEX_ROOT, I30, 4, add->data, add->data_len);
//utils_dump_mem (add->data, 0, add->data_len, DM_DEFAULTS);
//printf ("\n");
printf (GREEN "Modified: inode %lld, $INDEX_ROOT\n" END, add->dir->inode->mft_no);
return 0;
}
/**
* ntfs_dt_alloc_add
*/
static int ntfs_dt_alloc_add (struct ntfs_dt *add, INDEX_ENTRY *add_ie)
{
FILE_NAME_ATTR *file;
struct ntfs_dt *suc_dt;
int suc_num;
int need;
int space;
u8 *src;
u8 *dst;
int len;
if (!add || !add_ie)
return 0;
need = add_ie->length;
space = add->data_len - add->header->index_length - 24;
file = &add_ie->key.file_name;
suc_dt = ntfs_dt_find3 (add, file->file_name, file->file_name_length, &suc_num);
if (!suc_dt)
return 0;
// hmm, suc_dt == add
printf ("need %d, have %d\n", need, space);
if (need > space) {
printf ("no room");
return 0;
}
//utils_dump_mem (add->data, 0, add->data_len, DM_DEFAULTS);
//printf ("\n");
src = (u8*) suc_dt->children[suc_num];
dst = src + need;
len = add->data + add->data_len - src - space;
//printf ("src = %d\n", src - add->data);
//printf ("dst = %d\n", dst - add->data);
//printf ("len = %d\n", len);
memmove (dst, src, len);
dst = src;
src = (u8*) add_ie;
len = need;
memcpy (dst, src, len);
add->header->index_length += len;
dst = add->data + add->header->index_length + 24;
len = add->data_len - add->header->index_length - 24;
memset (dst, 0, len);
//utils_dump_mem (add->data, 0, add->data_len, DM_DEFAULTS);
//printf ("\n");
printf (GREEN "Modified: inode %lld, $INDEX_ALLOCATION vcn %lld-%lld\n" END, add->dir->inode->mft_no, add->vcn, add->vcn + 4);
return 0;
}
/**
* ntfs_file_add
*/
static int ntfs_file_add (ntfs_volume *vol, char *name)
{
struct ntfs_dir *dir = NULL;
struct ntfs_dir *finddir = NULL;
struct ntfs_dt *del = NULL;
INDEX_ENTRY *ie = NULL;
MFT_REF mft_num;
ntfschar *uname = NULL;
int len;
int index_num = 0;
dir = ntfs_dir_alloc (vol, FILE_root);
if (!dir)
return 1;
mft_num = utils_pathname_to_mftref (vol, dir, name, &finddir);
//printf ("mft_num = %lld\n", mft_num);
//ntfs_dir_print (finddir, 0);
if (!finddir) {
printf ("Couldn't find the index entry for %s\n", name);
return 1;
}
if (rindex (name, PATH_SEP))
name = rindex (name, PATH_SEP) + 1;
len = ntfs_mbstoucs (name, &uname, 0);
if (len < 0)
return 1;
del = ntfs_dt_find2 (finddir->index, uname, len, &index_num);
if (!del) {
printf ("can't find item to delete\n");
goto done;
}
ie = ntfs_ie_copy (del->children[index_num]);
if (!ie)
goto done;
free (uname);
uname = NULL;
len = ntfs_mbstoucs ("file26a", &uname, 0);
if (len < 0)
goto done;
ie = ntfs_ie_set_name (ie, uname, len, FILE_NAME_WIN32);
if (!ie)
goto done;
//utils_dump_mem ((u8*)ie, 0, ie->length, DM_DEFAULTS);
//printf ("\n");
//printf ("ie = %lld\n", MREF (ie->indexed_file));
//ntfs_dt_del_child (finddir->index, uname, len);
//ntfs_dt_print (finddir->index, 0);
ntfs_dt_add (finddir->index, ie);
// test
if (0) ntfs_dt_alloc_add (del, ie);
if (0) ntfs_dt_root_add (del, ie);
// test
done:
ntfs_dir_free (dir);
free (uname);
free (ie);
return 0;
}
/**
* ntfs_file_remove
*/
static int ntfs_file_remove (ntfs_volume *vol, char *name)
{
// XXX work with inode - lookup name outside?
// how do I do the inode -> dt lookup?
struct ntfs_dir *root_dir = NULL;
struct ntfs_dir *find_dir = NULL;
struct ntfs_dt *del = NULL;
struct ntfs_dt *suc = NULL;
struct ntfs_dt *old = NULL;
struct ntfs_dt *par = NULL;
struct ntfs_dt *ded = NULL;
MFT_REF mft_num;
ntfschar *uname = NULL;
int name_len;
int del_num = 0;
int suc_num = 0;
int par_num = -1;
INDEX_ENTRY *del_ie = NULL;
INDEX_ENTRY *suc_ie = NULL;
INDEX_ENTRY *par_ie = NULL;
INDEX_ENTRY *add_ie = NULL;
int res;
VCN vcn;
FILE_NAME_ATTR *file = NULL;
//int i;
root_dir = ntfs_dir_alloc (vol, FILE_root);
if (!root_dir)
return 1;
mft_num = utils_pathname_to_mftref (vol, root_dir, name, &find_dir);
if (!find_dir) {
printf ("Couldn't find the index entry for %s\n", name);
goto done;
}
if (rindex (name, PATH_SEP))
name = rindex (name, PATH_SEP) + 1;
name_len = ntfs_mbstoucs (name, &uname, 0);
if (name_len < 0)
goto done;
del = ntfs_dt_find2 (find_dir->index, uname, name_len, &del_num);
if (!del) {
printf ("can't find item to delete\n");
goto done;
}
del_ie = del->children[del_num];
//utils_dump_mem ((u8*)del_ie, 0, del_ie->length, DM_DEFAULTS);
//printf ("\n");
/*
* If the key is not in a leaf node, then replace it with its successor.
* Continue the delete as if the successor had been deleted.
*/
if (del->header->flags & INDEX_NODE) {
printf (BOLD YELLOW "Replace key with its successor:\n" END);
vcn = ntfs_ie_get_vcn (del_ie);
//printf ("vcn = %lld\n", vcn);
suc = ntfs_dt_find4 (find_dir->index, uname, name_len, &suc_num);
//printf ("succ = %p, index = %d\n", suc, suc_num);
//printf ("\n");
suc_ie = ntfs_ie_copy (suc->children[suc_num]);
//utils_dump_mem ((u8*)suc_ie, 0, suc_ie->length, DM_BLUE|DM_GREEN|DM_INDENT);
//printf ("\n");
suc_ie = ntfs_ie_set_vcn (suc_ie, vcn);
//utils_dump_mem ((u8*)suc_ie, 0, suc_ie->length, DM_BLUE|DM_GREEN|DM_INDENT);
//printf ("\n");
file = &del_ie->key.file_name; printf ("\trep name: "); ntfs_name_print (file->file_name, file->file_name_length); printf ("\n");
file = &suc_ie->key.file_name; printf ("\tsuc name: "); ntfs_name_print (file->file_name, file->file_name_length); printf ("\n");
//utils_dump_mem (del->data, 0, del->data_len, DM_BLUE|DM_GREEN|DM_INDENT);
if (ntfs_dt_root (del))
res = ntfs_dt_root_replace (del, del_num, del_ie, suc_ie);
else
res = ntfs_dt_alloc_replace (del, del_num, del_ie, suc_ie);
//printf ("\n");
//utils_dump_mem (del->data, 0, del->data_len, DM_BLUE|DM_GREEN|DM_INDENT);
free (suc_ie);
if (res == FALSE)
goto done;
del = suc; // Continue delete with the successor
del_num = suc_num;
del_ie = suc->children[suc_num];
}
/*
* Now we have the simpler case of deleting from a leaf node.
* If this step creates an empty node, we have more to do.
*/
printf ("\n");
printf (BOLD YELLOW "Delete key:\n" END);
file = &del->children[del_num]->key.file_name; printf ("\tdel name: "); ntfs_name_print (file->file_name, file->file_name_length); printf ("\n");
//utils_dump_mem (del->data, 0, del->header->index_length+24, DM_BLUE|DM_GREEN|DM_INDENT);
// XXX if del->child_count == 2, we could skip this step
// no, if we combine with another node, we'll have to remember
if (ntfs_dt_root (del))
ntfs_dt_root_remove (del, del_num);
else
ntfs_dt_alloc_remove (del, del_num);
//printf ("\n");
//utils_dump_mem (del->data, 0, del->header->index_length+24, DM_BLUE|DM_GREEN|DM_INDENT);
if (del->child_count > 1) // XXX ntfs_dt_empty (dt), ntfs_dt_full (dt, new)
goto commit;
/*
* Ascend the tree until we find a node that is not empty. Take the
* ancestor key and unhook it. This will free up some space in the
* index allocation. Finally add the ancestor to the node of its
* successor.
*/
// find the key nearest the root which has no descendents
printf ("\n");
printf (BOLD YELLOW "Find childless parent:\n" END);
for (par = del->parent, old = par; par; old = par, par = par->parent) {
if (par->child_count > 1)
break;
par_num = ntfs_dt_find_parent (par);
}
//utils_dump_mem (par->data, 0, par->data_len, DM_BLUE|DM_GREEN|DM_INDENT);
file = &par->children[par_num]->key.file_name; printf ("\tpar name: "); ntfs_name_print (file->file_name, file->file_name_length); printf ("\n");
if (par == NULL) {
// unhook everything
printf ("whole dir is empty\n");
goto freedts;
}
printf ("\n");
//utils_dump_mem (par->data, 0, par->data_len, DM_BLUE|DM_GREEN|DM_INDENT);
//printf ("\n");
// find if parent has left siblings
if (par->children[par_num]->flags & INDEX_ENTRY_END) {
printf (BOLD YELLOW "Swap the children of the parent and its left sibling\n" END);
par_ie = par->children[par_num];
vcn = ntfs_ie_get_vcn (par_ie);
//printf ("\toffset = %d\n", (u8*)par_ie - par->data); printf ("\tflags = %d\n", par_ie->flags); printf ("\tvcn = %lld\n", vcn); printf ("\tlength = %d\n", par_ie->length);
//utils_dump_mem ((u8*)par_ie, 0, par_ie->length, DM_DEFAULTS);
//printf ("\n");
//printf ("\toffset = %d\n", (u8*)par_ie - par->data); printf ("\tflags = %d\n", par_ie->flags); printf ("\tvcn = %lld\n", vcn); printf ("\tlength = %d\n", par_ie->length);
//utils_dump_mem ((u8*)par_ie, 0, par_ie->length, DM_DEFAULTS);
//printf ("\n");
file = &par->children[par_num] ->key.file_name; printf ("\tpar name: "); ntfs_name_print (file->file_name, file->file_name_length); printf ("\n");
file = &par->children[par_num-1]->key.file_name; printf ("\tsib name: "); ntfs_name_print (file->file_name, file->file_name_length); printf ("\n");
old = par->sub_nodes[par_num];
par->sub_nodes[par_num] = par->sub_nodes[par_num-1];
par->sub_nodes[par_num-1] = old;
par_ie = par->children[par_num-1];
vcn = ntfs_ie_get_vcn (par_ie);
par_ie = par->children[par_num];
ntfs_ie_set_vcn (par_ie, vcn);
par_num--;
if (ntfs_dt_root (par))
printf (GREEN "Modified: inode %lld, $INDEX_ROOT\n" END, par->dir->inode->mft_no);
else
printf (GREEN "Modified: inode %lld, $INDEX_ALLOCATION vcn %lld-%lld\n" END, par->dir->inode->mft_no, par->vcn, par->vcn + 4);
}
//printf ("\n");
//utils_dump_mem (par->data, 0, par->data_len, DM_DEFAULTS);
// unhook and hold onto the ded dt's
printf ("\n");
printf (BOLD YELLOW "Remove parent\n" END);
file = &par->children[par_num]->key.file_name; printf ("\tpar name: "); ntfs_name_print (file->file_name, file->file_name_length); printf ("\n");
add_ie = ntfs_ie_copy (par->children[par_num]);
add_ie = ntfs_ie_remove_vcn (add_ie);
if (!add_ie)
goto done;
//printf ("\n");
//utils_dump_mem ((u8*)add_ie, 0, add_ie->length, DM_BLUE|DM_GREEN|DM_INDENT);
ded = par->sub_nodes[par_num];
par->sub_nodes[par_num] = NULL;
//ntfs_dt_print (ded, 8);
if (ntfs_dt_root (par))
ntfs_dt_root_remove (par, par_num);
else
ntfs_dt_alloc_remove (par, par_num);
printf ("\n");
file = &add_ie->key.file_name;
suc = NULL;
suc_num = -1;
suc = ntfs_dt_find4 (find_dir->index, file->file_name, file->file_name_length, &suc_num);
printf ("%p, %d\n", suc, suc_num);
if (!suc)
goto done;
file = &suc->children[suc_num]->key.file_name; printf ("\tsuc name: "); ntfs_name_print (file->file_name, file->file_name_length); printf ("\n");
// insert key into successor
// if any new nodes are needed, reuse the preserved nodes
if (!ntfs_dt_add2 (del_ie, suc, suc_num, ded))
goto done;
// remove any unused nodes
// XXX mark dts, dirs and inodes dirty
// XXX attach bmp to dir and volume
// XXX attach root dir to volume
// XXX add freed dts to a list for immediate reuse (attach to dir?)
// XXX commit will free list of spare dts
// XXX reduce size of alloc
if (0) ntfs_dt_add2 (del_ie, suc, suc_num, ded);
if (0) ntfs_dir_commit (find_dir);
if (0) ntfs_dir_rollback (find_dir);
printf ("empty\n");
goto done;
freedts:
commit:
printf ("commit\n");
done:
ntfs_dir_free (root_dir);
free (uname);
return 0;
}
/**
* ntfs_test_bmp
*/
static int ntfs_test_bmp (ntfs_volume *vol, ntfs_inode *inode)
{
ntfs_inode *volbmp;
struct ntfs_bmp *bmp;
struct ntfs_bmp *bmp2;
//u8 *buffer;
//int i;
volbmp = ntfs_inode_open (vol, FILE_Bitmap);
if (!volbmp)
return 1;
bmp = ntfs_bmp_alloc (volbmp, AT_DATA, NULL, 0);
if (!bmp)
return 1;
bmp2 = ntfs_bmp_alloc (vol->mft_ni, AT_BITMAP, NULL, 0);
if (!bmp2)
return 1;
if (0) ntfs_bmp_set_range (bmp, 0, 9, 1);
if (0) utils_free_non_residents2 (inode, bmp);
if (0) utils_mftrec_mark_free3 (bmp2, inode->mft_no);
if (0) utils_mftrec_mark_free4 (inode);
ntfs_bmp_free (bmp);
return 0;
}
/**
* main - Begin here
*
* Start from here.
*
* Return: 0 Success, the program worked
* 1 Error, something went wrong
*/
int main (int argc, char *argv[])
{
ntfs_volume *vol = NULL;
ntfs_inode *inode = NULL;
int flags = 0;
int result = 1;
if (!parse_options (argc, argv))
goto done;
utils_set_locale();
#if 0
printf ("sizeof (ntfs_bmp) = %d\n", sizeof (struct ntfs_bmp));
printf ("sizeof (ntfs_dt) = %d\n", sizeof (struct ntfs_dt));
printf ("sizeof (ntfs_dir) = %d\n", sizeof (struct ntfs_dir));
printf ("\n");
#endif
if (opts.noaction)
flags |= MS_RDONLY;
vol = utils_mount_volume (opts.device, flags, opts.force);
if (!vol) {
printf ("!vol\n");
goto done;
}
inode = utils_pathname_to_inode (vol, NULL, opts.file);
if (!inode) {
printf ("!inode\n");
goto done;
}
if (0) result = ntfs_index_dump (inode);
if (0) result = ntfsrm (vol, opts.file);
if (0) result = ntfs_ie_test();
if (0) result = ntfs_file_add (vol, opts.file);
if (0) result = ntfs_file_remove (vol, opts.file);
if (0) result = ntfs_test_bmp (vol, inode);
done:
ntfs_inode_close (inode);
ntfs_umount (vol, FALSE);
return result;
}