ntfs-3g/ntfsprogs/ntfsrm.c

1999 lines
45 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;
/**
* struct bmp_page
*/
struct bmp_page {
u8 *data;
VCN vcn;
};
/**
* struct mft_bitmap
*/
struct mft_bitmap {
ntfs_attr *bmp;
struct bmp_page **pages;
int count;
};
/**
* struct ntfs_dt
*/
struct ntfs_dt {
struct ntfs_dir *dir;
struct ntfs_dt *parent;
u8 *data;
int data_len;
struct ntfs_dt **sub_nodes;
int child_count;
INDEX_ENTRY **children;
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;
ntfs_ucstombs (name, name_len, (char**) &buffer, 0);
printf ("%s", buffer);
free (buffer);
}
/**
* 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_dt_alloc_children
*/
static INDEX_ENTRY ** ntfs_dt_alloc_children (INDEX_ENTRY **children, int count)
{
int old = (count + 0x1e) & ~0x1f;
int new = (count + 0x1f) & ~0x1f;
if (old == new)
return children;
return realloc (children, new * sizeof (INDEX_ENTRY*));
}
/**
* ntfs_dt_count_root
*/
static int ntfs_dt_count_root (struct ntfs_dt *dt)
{
u8 *buffer = NULL;
u8 *ptr = NULL;
VCN *vcn = NULL;
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 = (VCN *) (ptr + ((entry->key_length + 0x17) & ~7));
//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 = NULL;
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, TRUE);
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 = (VCN *) (ptr + ((entry->key_length + 0x17) & ~7));
//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, 1);
//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, 1);
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, 1);
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, 1);
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
*/
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 = *(VCN*)(((u8*)ie) + ie->length - sizeof (VCN));
//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
*/
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 %lld\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_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;
}
/**
* 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, 0);
buffer[byte] &= ~bit;
//utils_dump_mem (buffer, byte, 1, 0);
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, 1);
res = ntfs_mft_record_write (vol, mref, rec);
printf ("res = %lld\n", res);
return 0;
}
/**
* utils_free_non_residents
*/
static int utils_free_non_residents (ntfs_inode *inode)
{
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;
}
/**
* 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 ("attributes 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, 1);
res = 0;
done:
ntfs_attr_put_search_ctx (ctx);
return res;
}
/**
* ntfs_dt_remove_alloc
*/
static int ntfs_dt_remove_alloc (struct ntfs_dt *dt, int index_num)
{
INDEX_ENTRY *ie = NULL;
int i;
u8 *dest;
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, TRUE);
//write (2, dt->data, dt->data_len);
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];
dest = (u8*)ie;
src = dest + 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", dest - dt->data, src - dt->data, len);
memmove (dest, src, len);
//printf ("clear %d bytes\n", dt->data_len - (dest - dt->data) - len);
//printf ("%d, %d, %d\n", dest - dt->data + len, 0, dt->data_len - (dest - dt->data) - len);
//ntfs_dt_print (dt->dir->index, 0);
#if 1
memset (dest + len, 0, dt->data_len - (dest - 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 - dest;
//printf ("after = %d\n", dt->header->index_length + 24);
ntfs_dt_count_alloc (dt);
#endif
//utils_dump_mem (dt->data, 0, dt->data_len, TRUE);
//write (2, dt->data, dt->data_len);
#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, TRUE);
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 *dest;
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, TRUE);
//write (2, dt->data, dt->data_len);
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];
dest = (u8*)ie;
src = dest + 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", dest - dt->data, src - dt->data, len);
memmove (dest, 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, 1);
//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 - dest;
//printf ("after = %d\n", dt->header->index_length + 24);
ntfs_dt_count_root (dt);
#endif
//utils_dump_mem (dt->data, 0, dt->data_len, TRUE);
//write (2, dt->data, dt->data_len);
#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, TRUE);
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 (dt->parent)
return ntfs_dt_remove_alloc (dt, index_num);
else
return ntfs_dt_remove_root (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;
}
#define ATTR_SIZE(s) (((s)+7) & ~7)
/**
* 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, 1);
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) {
VCN *vcn = (VCN*) ((u8*) ie + ie->length - 8);
printf ("child vcn = %lld\n", *vcn);
}
}
/**
* 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_child
*/
static INDEX_ENTRY * ntfs_ie_set_child (INDEX_ENTRY *ie, VCN vcn)
{
if (!ie)
return 0;
if (ie->flags & INDEX_ENTRY_NODE) {
*((VCN*) ((u8*) ie + ie->length - 8)) = vcn;
return ie;
}
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 0;
}
/**
* ntfs_ie_remove_child
*/
static INDEX_ENTRY * ntfs_ie_remove_child (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 NULL;
}
/**
* 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 = *((VCN*) ((u8*) ie + ie->length - 8));
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)
*((VCN*) ((u8*) ie + ie->length - 8)) = 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 = *((VCN*) ((u8*) ie + ie->length - 8));
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)
*((VCN*) ((u8*) ie + ie->length - 8)) = 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;
printf ("\n\n\n\n\n\n----------------------------------------------------------------------------------\n\n");
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) {
ntfs_ie_set_child (ie1, 1234);
ntfs_ie_dump (ie1);
}
if (1) {
ntfs_ie_remove_child (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_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;
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;
}
/**
* 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 (bmp_page) = %d\n", sizeof (struct bmp_page));
printf ("sizeof (mft_bitmap) = %d\n", sizeof (struct mft_bitmap));
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();
done:
ntfs_inode_close (inode);
ntfs_umount (vol, FALSE);
return result;
}