identify the deleted file's parent

(Logical change 1.514)
edge.strict_endians
flatcap.org!ntfs 2004-08-23 22:54:51 +00:00
parent 60c6241ac8
commit 02745a21f1
1 changed files with 151 additions and 5 deletions

View File

@ -55,9 +55,7 @@
static const char *EXEC_NAME = "ntfsundelete";
static const char *MFTFILE = "mft";
#ifdef DEBUG
static const char *UNNAMED = "<unnamed>";
#endif
static const char *NONE = "<none>";
static const char *UNKNOWN = "unknown";
static struct options opts;
@ -227,6 +225,7 @@ static void usage (void)
" -d dir --destination dir Destination directory\n"
" -b num --byte num Fill missing parts with this byte\n"
" -T --truncate Truncate 100%% recoverable file to exact size.\n"
" -P --parent Show parent directory\n"
"\n"
" -c range --copy range Write a range of MFT records to a file\n"
"\n"
@ -394,7 +393,7 @@ static int parse_time (const char *value, time_t *since)
*/
static int parse_options (int argc, char *argv[])
{
static const char *sopt = "-b:Cc:d:fh?m:o:Op:sS:t:Tu:qvV";
static const char *sopt = "-b:Cc:d:fh?m:o:OPp:sS:t:Tu:qvV";
static const struct option lopt[] = {
{ "byte", required_argument, NULL, 'b' },
{ "case", no_argument, NULL, 'C' },
@ -408,6 +407,7 @@ static int parse_options (int argc, char *argv[])
{ "percentage", required_argument, NULL, 'p' },
{ "scan", no_argument, NULL, 's' },
{ "size", required_argument, NULL, 'S' },
{ "parent", no_argument, NULL, 'P' },
{ "time", required_argument, NULL, 't' },
{ "truncate", no_argument, NULL, 'T' },
{ "undelete", required_argument, NULL, 'u' },
@ -498,6 +498,13 @@ static int parse_options (int argc, char *argv[])
err++;
}
break;
case 'P':
if (!opts.parent) {
opts.parent++;
} else {
err++;
}
break;
case 'p':
if (opts.percent == -1) {
end = NULL;
@ -633,6 +640,11 @@ static int parse_options (int argc, char *argv[])
err++;
}
}
if (opts.parent && !opts.verbose) {
Eprintf ("To use --parent, you must also use --verbose.\n");
err++;
}
}
if (opts.fillbyte == (char)-1)
@ -668,6 +680,10 @@ static void free_file (struct ufile *file)
Dprintf ("freeing filename '%s'\n", f->name ? f->name : NONE);
if (f->name)
free (f->name);
if (f->parent_name) {
Dprintf ("\tand parent filename '%s'\n", f->parent_name ? f->parent_name : NONE);
free (f->parent_name);
}
free (f);
}
@ -685,6 +701,122 @@ static void free_file (struct ufile *file)
free (file);
}
/**
* verify_parent - confirm a record is parent of a file
* @name: a filename of the file
* @rec: the mft record of the possible parent
*
* Check that @rec is the parent of the file represented by @name.
* If @rec is a directory, but it is created after @name, then we
* can't determine wheter @rec is really @name's parent.
*
* Return: @rec's filename, either same name space as @name or lowest space.
* NULL if can't determine parenthood or on error.
*/
static FILE_NAME_ATTR* verify_parent(struct filename* name, MFT_RECORD* rec) {
ATTR_RECORD *attr30;
FILE_NAME_ATTR *filename_attr = NULL, *lowest_space_name = NULL;
ntfs_attr_search_ctx *ctx;
int found_same_space = 1;
if (!name || !rec)
return NULL;
if (!(rec->flags & MFT_RECORD_IS_DIRECTORY)) {
return NULL;
}
ctx = ntfs_attr_get_search_ctx(NULL, rec);
if (!ctx) {
Eprintf ("Couldn't create a search context.\n");
return NULL;
}
attr30 = find_attribute(AT_FILE_NAME, ctx);
if (!attr30) {
return NULL;
}
filename_attr = (FILE_NAME_ATTR*)((char*)attr30 + le16_to_cpu(attr30->value_offset));
/* if name is older than this dir -> can't determine */
if (ntfs2utc(filename_attr->creation_time) > name->date_c) {
return NULL;
}
if (filename_attr->file_name_type != name->name_space) {
found_same_space = 0;
lowest_space_name = filename_attr;
while (!found_same_space && (attr30 = find_attribute(AT_FILE_NAME, ctx))) {
filename_attr = (FILE_NAME_ATTR*)((char*)attr30 + le16_to_cpu(attr30->value_offset));
if (filename_attr->file_name_type == name->name_space) {
found_same_space = 1;
}
else {
if (filename_attr->file_name_type < lowest_space_name->file_name_type) {
lowest_space_name = filename_attr;
}
}
}
}
ntfs_attr_put_search_ctx(ctx);
return (found_same_space ? filename_attr : lowest_space_name);
}
/**
* get_parent_name - Find the name of a file's parent.
* @name: the filename whose parent's name to find
*
*/
static void get_parent_name(struct filename* name, ntfs_volume* vol) {
ntfs_attr* mft_data;
MFT_RECORD* rec;
FILE_NAME_ATTR* filename_attr;
long long inode_num;
if (!name || !vol)
return;
rec = calloc(1, vol->mft_record_size);
if (!rec) {
Eprintf ("Couldn't allocate memory in get_parent_name()\n");
return;
}
mft_data = ntfs_attr_open(vol->mft_ni, AT_DATA, NULL, 0);
if (!mft_data) {
Eprintf ("Couldn't open $MFT/$DATA: %s\n", strerror (errno));
}
else {
inode_num = MREF(name->parent_mref);
if (ntfs_attr_pread(mft_data, vol->mft_record_size * inode_num, vol->mft_record_size, rec) < 1) {
Eprintf ("Couldn't read MFT Record %lld.\n", inode_num);
}
else {
if ((filename_attr = verify_parent(name, rec))) {
if (ntfs_ucstombs(filename_attr->file_name, filename_attr->file_name_length, &name->parent_name, 0) < 0) {
Dprintf ("Couldn't translate filename to current locale.\n");
name->parent_name = NULL;
}
}
}
}
if (mft_data) {
ntfs_attr_close(mft_data);
}
if (rec) {
free(rec);
}
return;
}
/**
* get_filenames - Read an MFT Record's $FILENAME attributes
* @file: The file object to work with
@ -704,7 +836,7 @@ static void free_file (struct ufile *file)
* Return: n The number of $FILENAME attributes found
* -1 Error
*/
static int get_filenames (struct ufile *file)
static int get_filenames (struct ufile *file, ntfs_volume* vol)
{
ATTR_RECORD *rec;
FILE_NAME_ATTR *attr;
@ -748,8 +880,16 @@ static int get_filenames (struct ufile *file)
Dprintf ("Couldn't translate filename to current locale.\n");
}
name->parent_name = NULL;
if (opts.parent) {
name->parent_mref = attr->parent_directory;
get_parent_name(name, vol);
}
if (name->name_space < space) {
file->pref_name = name->name;
file->pref_pname = name->parent_name;
space = name->name_space;
}
@ -915,7 +1055,7 @@ static struct ufile * read_record (ntfs_volume *vol, long long record)
if (attr90)
file->directory = 1;
if (get_filenames (file) < 0) {
if (get_filenames (file, vol) < 0) {
Eprintf ("Couldn't get filenames.\n");
}
if (get_data (file, vol) < 0) {
@ -1105,7 +1245,13 @@ static void dump_record (struct ufile *file)
FILE_ATTR_COMPRESSED | FILE_ATTR_ENCRYPTED))) {
Qprintf (NONE);
}
Qprintf ("\n");
if (opts.parent) {
Qprintf ("Parent: %s\n", f->parent_name ? f->parent_name : "<non-determined>");
}
Qprintf ("Size alloc: %lld\n", f->size_alloc);
Qprintf ("Size data: %lld\n", f->size_data);