upgrade to use new logging

change stderror messages to ntfs_log_perror
edge.strict_endians
flatcap 2005-10-28 18:15:24 +00:00
parent d5a925b3bf
commit 7960f45998
1 changed files with 183 additions and 161 deletions

View File

@ -84,6 +84,7 @@
#include "debug.h"
#include "ntfstime.h"
#include "version.h"
#include "logging.h"
static const char *EXEC_NAME = "ntfsundelete";
static const char *MFTFILE = "mft";
@ -100,13 +101,9 @@ typedef struct
static short with_regex; /* Flag Regular expression available */
static short avoid_duplicate_printing; /* Flag No duplicate printing of file infos */
static range *ranges; /* Array containing all Inode-Rages for undelete */
static range *ranges; /* Array containing all Inode-Ranges for undelete */
static long nr_entries; /* Number of range entries */
GEN_PRINTF(Eprintf, stderr, NULL, FALSE)
GEN_PRINTF(Vprintf, stdout, &opts.verbose, TRUE)
GEN_PRINTF(Qprintf, stdout, &opts.quiet, FALSE)
/**
* parse_inode_arg - parses the inode expression
*
@ -142,7 +139,7 @@ static int parse_inode_arg(void)
/* alloc mem for range table */
ranges = (range *) malloc((p + 1) * sizeof(range));
if (ranges == NULL) {
printf("ERROR: Couldn't alloc mem for parsing inodes!\n");
ntfs_log_error("ERROR: Couldn't alloc mem for parsing inodes!\n");
return (-1);
}
@ -154,7 +151,7 @@ static int parse_inode_arg(void)
/* invalid char at begin */
if ((opt_arg_ptr == opt_arg_end1) || (opt_arg_ptr == opt_arg_end2)) {
printf("ERROR: Invalid Number: %s\n", opt_arg_ptr);
ntfs_log_error("ERROR: Invalid Number: %s\n", opt_arg_ptr);
return (-1);
}
@ -164,7 +161,7 @@ static int parse_inode_arg(void)
opt_arg_temp = opt_arg_end1;
opt_arg_end1 = & (opt_arg_temp[1]);
if (opt_arg_temp >= opt_arg_end2) {
printf("ERROR: Missing range end!\n");
ntfs_log_error("ERROR: Missing range end!\n");
return (-1);
}
range_begin = inode;
@ -172,7 +169,7 @@ static int parse_inode_arg(void)
/* get count */
range_end = strtoul(opt_arg_end1, &opt_arg_temp, 0);
if (opt_arg_temp == opt_arg_end1) {
printf("ERROR: Invalid Number: %s\n", opt_arg_temp);
ntfs_log_error("ERROR: Invalid Number: %s\n", opt_arg_temp);
return (-1);
}
@ -202,7 +199,7 @@ static int parse_inode_arg(void)
/* Next inode */
opt_arg_ptr = & (opt_arg_end1[1]);
if (opt_arg_ptr >= opt_arg_end2) {
printf("ERROR: Missing new value at end of input!\n");
ntfs_log_error("ERROR: Missing new value at end of input!\n");
return (-1);
}
continue;
@ -224,12 +221,12 @@ static int parse_inode_arg(void)
*/
static void version(void)
{
printf("\n%s v%s (libntfs %s) - Recover deleted files from an NTFS "
ntfs_log_info("\n%s v%s (libntfs %s) - Recover deleted files from an NTFS "
"Volume.\n\n", EXEC_NAME, VERSION,
ntfs_libntfs_version());
printf("Copyright (c) 2002-2005 Richard Russon\n"
ntfs_log_info("Copyright (c) 2002-2005 Richard Russon\n"
"Copyright (c) 2004-2005 Holger Ohmacht\n");
printf("\n%s\n%s%s\n", ntfs_gpl, ntfs_bugs, ntfs_home);
ntfs_log_info("\n%s\n%s%s\n", ntfs_gpl, ntfs_bugs, ntfs_home);
}
/**
@ -241,7 +238,7 @@ static void version(void)
*/
static void usage(void)
{
printf("\nUsage: %s [options] device\n"
ntfs_log_info("\nUsage: %s [options] device\n"
" -s --scan Scan for files (default)\n"
" -p num --percentage num Minimum percentage recoverable\n"
" -m pattern --match pattern Only work on files with matching names\n"
@ -266,7 +263,7 @@ static void usage(void)
" -V --version Display version information\n"
" -h --help Display this help\n\n",
EXEC_NAME);
printf("%s%s\n", ntfs_bugs, ntfs_home);
ntfs_log_info("%s%s\n", ntfs_bugs, ntfs_home);
}
/**
@ -300,7 +297,7 @@ static int transform(const char *pattern, char **regex)
length = strlen(pattern);
if (length < 1) {
Eprintf("Pattern to transform is empty\n");
ntfs_log_error("Pattern to transform is empty\n");
return 0;
}
@ -311,7 +308,7 @@ static int transform(const char *pattern, char **regex)
result = malloc(length + 3);
if (!result) {
Eprintf("Couldn't allocate memory in transform()\n");
ntfs_log_error("Couldn't allocate memory in transform()\n");
return 0;
}
@ -379,17 +376,17 @@ static int parse_time(const char *value, time_t *since)
result = strtoll(value, &suffix, 10);
if (result < 0 || errno == ERANGE) {
Eprintf("Invalid time '%s'.\n", value);
ntfs_log_error("Invalid time '%s'.\n", value);
return 0;
}
if (!suffix) {
Eprintf("Internal error, strtoll didn't return a suffix.\n");
ntfs_log_error("Internal error, strtoll didn't return a suffix.\n");
return 0;
}
if (strlen(suffix) > 1) {
Eprintf("Invalid time suffix '%s'. Use Y, M, W, D or H.\n", suffix);
ntfs_log_error("Invalid time suffix '%s'. Use Y, M, W, D or H.\n", suffix);
return 0;
}
@ -403,7 +400,7 @@ static int parse_time(const char *value, time_t *since)
break;
default:
Eprintf("Invalid time suffix '%s'. Use Y, M, W, D or H.\n", suffix);
ntfs_log_error("Invalid time suffix '%s'. Use Y, M, W, D or H.\n", suffix);
return 0;
}
@ -456,6 +453,7 @@ static int parse_options(int argc, char *argv[])
int err = 0;
int ver = 0;
int help = 0;
int levels = 0;
opterr = 0; /* We'll handle the errors, thank you. */
@ -507,6 +505,11 @@ static int parse_options(int argc, char *argv[])
break;
case 'h':
case '?':
if (strncmp (argv[optind-1], "--log-", 6) == 0) {
if (!ntfs_log_parse_option (argv[optind-1]))
err++;
break;
}
help++;
break;
case 'm':
@ -554,6 +557,7 @@ static int parse_options(int argc, char *argv[])
break;
case 'q':
opts.quiet++;
ntfs_log_clear_levels(NTFS_LOG_LEVEL_QUIET);
break;
case 's':
if (opts.mode == MODE_NONE)
@ -594,6 +598,7 @@ static int parse_options(int argc, char *argv[])
break;
case 'v':
opts.verbose++;
ntfs_log_set_levels(NTFS_LOG_LEVEL_VERBOSE);
break;
case 'V':
ver++;
@ -604,21 +609,28 @@ static int parse_options(int argc, char *argv[])
(optopt == 'o') || (optopt == 'p') ||
(optopt == 'S') || (optopt == 't') ||
(optopt == 'u')) && (!optarg)) {
Eprintf("Option '%s' requires an argument.\n", argv[optind-1]);
ntfs_log_error("Option '%s' requires an argument.\n", argv[optind-1]);
} else {
Eprintf("Unknown option '%s'.\n", argv[optind-1]);
ntfs_log_error("Unknown option '%s'.\n", argv[optind-1]);
}
err++;
break;
}
}
/* Make sure we're in sync with the log levels */
levels = ntfs_log_get_levels();
if (levels & NTFS_LOG_LEVEL_VERBOSE)
opts.verbose++;
if (!(levels & NTFS_LOG_LEVEL_QUIET))
opts.quiet++;
if (help || ver) {
opts.quiet = 0;
} else {
if (opts.device == NULL) {
if (argc > 1)
Eprintf("You must specify exactly one device.\n");
ntfs_log_error("You must specify exactly one device.\n");
err++;
}
@ -630,19 +642,19 @@ static int parse_options(int argc, char *argv[])
case MODE_SCAN:
if (opts.output || opts.dest || opts.truncate ||
(opts.fillbyte != (char)-1)) {
Eprintf("Scan can only be used with --percent, "
ntfs_log_error("Scan can only be used with --percent, "
"--match, --ignore-case, --size and --time.\n");
err++;
}
if (opts.match_case && !opts.match) {
Eprintf("The --case option doesn't make sense without the --match option\n");
ntfs_log_error("The --case option doesn't make sense without the --match option\n");
err++;
}
break;
case MODE_UNDELETE:
/*if ((opts.percent != -1) || (opts.size_begin > 0) || (opts.size_end > 0)) {
Eprintf("Undelete can only be used with "
ntfs_log_error("Undelete can only be used with "
"--output, --destination, --byte and --truncate.\n");
err++;
}*/
@ -653,32 +665,32 @@ static int parse_options(int argc, char *argv[])
opts.match || opts.match_case ||
(opts.size_begin > 0) ||
(opts.size_end > 0)) {
Eprintf("Copy can only be used with --output and --destination.\n");
ntfs_log_error("Copy can only be used with --output and --destination.\n");
err++;
}
break;
default:
Eprintf("You can only select one of Scan, Undelete or Copy.\n");
ntfs_log_error("You can only select one of Scan, Undelete or Copy.\n");
err++;
}
if ((opts.percent < -1) || (opts.percent > 100)) {
Eprintf("Percentage value must be in the range 0 - 100.\n");
ntfs_log_error("Percentage value must be in the range 0 - 100.\n");
err++;
}
if (opts.quiet) {
if (opts.verbose) {
Eprintf("You may not use --quiet and --verbose at the same time.\n");
ntfs_log_error("You may not use --quiet and --verbose at the same time.\n");
err++;
} else if (opts.mode == MODE_SCAN) {
Eprintf("You may not use --quiet when scanning a volume.\n");
ntfs_log_error("You may not use --quiet when scanning a volume.\n");
err++;
}
}
if (opts.parent && !opts.verbose) {
Eprintf("To use --parent, you must also use --verbose.\n");
ntfs_log_error("To use --parent, you must also use --verbose.\n");
err++;
}
}
@ -694,7 +706,6 @@ static int parse_options(int argc, char *argv[])
return (!err && !help && !ver);
}
/**
* free_file - Release the resources used by a file object
* @file: The unwanted file object
@ -769,7 +780,7 @@ static FILE_NAME_ATTR* verify_parent(struct filename* name, MFT_RECORD* rec)
ctx = ntfs_attr_get_search_ctx(NULL, rec);
if (!ctx) {
Eprintf("ERROR: Couldn't create a search context.\n");
ntfs_log_error("ERROR: Couldn't create a search context.\n");
return NULL;
}
@ -822,18 +833,18 @@ static void get_parent_name(struct filename* name, ntfs_volume* vol)
rec = calloc(1, vol->mft_record_size);
if (!rec) {
Eprintf("ERROR: Couldn't allocate memory in get_parent_name()\n");
ntfs_log_error("ERROR: Couldn't allocate memory in get_parent_name()\n");
return;
}
mft_data = ntfs_attr_open(vol->mft_ni, AT_DATA, AT_UNNAMED, 0);
if (!mft_data) {
Eprintf("ERROR: Couldn't open $MFT/$DATA: %s\n", strerror(errno));
ntfs_log_perror("ERROR: Couldn't open $MFT/$DATA");
} 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("ERROR: Couldn't read MFT Record %lld.\n", inode_num);
ntfs_log_error("ERROR: 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,
@ -898,7 +909,7 @@ static int get_filenames(struct ufile *file, ntfs_volume* vol)
name = calloc(1, sizeof(*name));
if (!name) {
Eprintf("ERROR: Couldn't allocate memory in get_filenames().\n");
ntfs_log_error("ERROR: Couldn't allocate memory in get_filenames().\n");
count = -1;
break;
}
@ -978,7 +989,7 @@ static int get_data(struct ufile *file, ntfs_volume *vol)
while ((rec = find_attribute(AT_DATA, ctx))) {
data = calloc(1, sizeof(*data));
if (!data) {
Eprintf("ERROR: Couldn't allocate memory in get_data().\n");
ntfs_log_error("ERROR: Couldn't allocate memory in get_data().\n");
count = -1;
break;
}
@ -993,7 +1004,7 @@ static int get_data(struct ufile *file, ntfs_volume *vol)
if (ntfs_ucstombs(data->uname, data->uname_len, &data->name,
0) < 0) {
Eprintf("ERROR: Cannot translate name into current locale.\n");
ntfs_log_error("ERROR: Cannot translate name into current locale.\n");
}
}
@ -1046,7 +1057,7 @@ static struct ufile * read_record(ntfs_volume *vol, long long record)
file = calloc(1, sizeof(*file));
if (!file) {
Eprintf("ERROR: Couldn't allocate memory in read_record()\n");
ntfs_log_error("ERROR: Couldn't allocate memory in read_record()\n");
return NULL;
}
@ -1056,20 +1067,20 @@ static struct ufile * read_record(ntfs_volume *vol, long long record)
file->mft = malloc(vol->mft_record_size);
if (!file->mft) {
Eprintf("ERROR: Couldn't allocate memory in read_record()\n");
ntfs_log_error("ERROR: Couldn't allocate memory in read_record()\n");
free_file(file);
return NULL;
}
mft = ntfs_attr_open(vol->mft_ni, AT_DATA, AT_UNNAMED, 0);
if (!mft) {
Eprintf("ERROR: Couldn't open $MFT/$DATA: %s\n", strerror(errno));
ntfs_log_perror("ERROR: Couldn't open $MFT/$DATA");
free_file(file);
return NULL;
}
if (ntfs_attr_mst_pread(mft, vol->mft_record_size * record, 1, vol->mft_record_size, file->mft) < 1) {
Eprintf("ERROR: Couldn't read MFT Record %lld.\n", record);
ntfs_log_error("ERROR: Couldn't read MFT Record %lld.\n", record);
ntfs_attr_close(mft);
free_file(file);
return NULL;
@ -1097,16 +1108,15 @@ static struct ufile * read_record(ntfs_volume *vol, long long record)
file->directory = 1;
if (get_filenames(file, vol) < 0) {
Eprintf("ERROR: Couldn't get filenames.\n");
ntfs_log_error("ERROR: Couldn't get filenames.\n");
}
if (get_data(file, vol) < 0) {
Eprintf("ERROR: Couldn't get data streams.\n");
ntfs_log_error("ERROR: Couldn't get data streams.\n");
}
return file;
}
/**
* calc_percentage - Calculate how much of the file is recoverable
* @file: The file object to work with
@ -1148,7 +1158,7 @@ static int calc_percentage(struct ufile *file, ntfs_volume *vol)
}
if (list_empty(&file->data)) {
Vprintf("File has no data streams.\n");
ntfs_log_verbose("File has no data streams.\n");
return 0;
}
@ -1158,17 +1168,17 @@ static int calc_percentage(struct ufile *file, ntfs_volume *vol)
clusters_free = 0;
if (data->encrypted) {
Vprintf("File is encrypted, recovery is impossible.\n");
ntfs_log_verbose("File is encrypted, recovery is impossible.\n");
continue;
}
if (data->compressed) {
Vprintf("File is compressed, recovery not yet implemented.\n");
ntfs_log_verbose("File is compressed, recovery not yet implemented.\n");
continue;
}
if (data->resident) {
Vprintf("File is resident, therefore recoverable.\n");
ntfs_log_verbose("File is resident, therefore recoverable.\n");
percent = 100;
data->percent = 100;
continue;
@ -1176,17 +1186,17 @@ static int calc_percentage(struct ufile *file, ntfs_volume *vol)
rl = data->runlist;
if (!rl) {
Vprintf("File has no runlist, hence no data.\n");
ntfs_log_verbose("File has no runlist, hence no data.\n");
continue;
}
if (rl[0].length <= 0) {
Vprintf("File has an empty runlist, hence no data.\n");
ntfs_log_verbose("File has an empty runlist, hence no data.\n");
continue;
}
if (rl[0].lcn == LCN_RL_NOT_MAPPED) { /* extended mft record */
Vprintf("Missing segment at beginning, %lld "
ntfs_log_verbose("Missing segment at beginning, %lld "
"clusters\n", (long long)rl[0].length);
clusters_inuse += rl[0].length;
rl++;
@ -1194,7 +1204,7 @@ static int calc_percentage(struct ufile *file, ntfs_volume *vol)
for (i = 0; rl[i].length > 0; i++) {
if (rl[i].lcn == LCN_RL_NOT_MAPPED) {
Vprintf("Missing segment at end, %lld "
ntfs_log_verbose("Missing segment at end, %lld "
"clusters\n",
(long long)rl[i].length);
clusters_inuse += rl[i].length;
@ -1218,7 +1228,9 @@ static int calc_percentage(struct ufile *file, ntfs_volume *vol)
}
if ((clusters_inuse + clusters_free) == 0) {
Eprintf("ERROR: Unexpected error whilst calculating percentage for inode %lld\n", file->inode);
ntfs_log_error("ERROR: Unexpected error whilst "
"calculating percentage for inode %lld\n",
file->inode);
continue;
}
@ -1228,7 +1240,7 @@ static int calc_percentage(struct ufile *file, ntfs_volume *vol)
percent = max(percent, data->percent);
}
Vprintf("File is %d%% recoverable\n", percent);
ntfs_log_verbose("File is %d%% recoverable\n", percent);
return percent;
}
@ -1257,13 +1269,13 @@ static void dump_record(struct ufile *file)
if (!file)
return;
Qprintf("MFT Record %lld\n", file->inode);
Qprintf("Type: %s\n", (file->directory) ? "Directory" : "File");
ntfs_log_quiet("MFT Record %lld\n", file->inode);
ntfs_log_quiet("Type: %s\n", (file->directory) ? "Directory" : "File");
strftime(buffer, sizeof(buffer), "%F %R", localtime(&file->date));
Qprintf("Date: %s\n", buffer);
ntfs_log_quiet("Date: %s\n", buffer);
if (file->attr_list)
Qprintf("Metadata may span more than one MFT record\n");
ntfs_log_quiet("Metadata may span more than one MFT record\n");
list_for_each(item, &file->name) {
struct filename *f = list_entry(item, struct filename, list);
@ -1273,72 +1285,73 @@ static void dump_record(struct ufile *file)
else
name = NONE;
Qprintf("Filename: (%d) %s\n", f->name_space, f->name);
Qprintf("File Flags: ");
if (f->flags & FILE_ATTR_SYSTEM) Qprintf("System ");
if (f->flags & FILE_ATTR_DIRECTORY) Qprintf("Directory ");
if (f->flags & FILE_ATTR_SPARSE_FILE) Qprintf("Sparse ");
if (f->flags & FILE_ATTR_REPARSE_POINT) Qprintf("Reparse ");
if (f->flags & FILE_ATTR_COMPRESSED) Qprintf("Compressed ");
if (f->flags & FILE_ATTR_ENCRYPTED) Qprintf("Encrypted ");
ntfs_log_quiet("Filename: (%d) %s\n", f->name_space, f->name);
ntfs_log_quiet("File Flags: ");
if (f->flags & FILE_ATTR_SYSTEM) ntfs_log_quiet("System ");
if (f->flags & FILE_ATTR_DIRECTORY) ntfs_log_quiet("Directory ");
if (f->flags & FILE_ATTR_SPARSE_FILE) ntfs_log_quiet("Sparse ");
if (f->flags & FILE_ATTR_REPARSE_POINT) ntfs_log_quiet("Reparse ");
if (f->flags & FILE_ATTR_COMPRESSED) ntfs_log_quiet("Compressed ");
if (f->flags & FILE_ATTR_ENCRYPTED) ntfs_log_quiet("Encrypted ");
if (!(f->flags & (FILE_ATTR_SYSTEM | FILE_ATTR_DIRECTORY |
FILE_ATTR_SPARSE_FILE | FILE_ATTR_REPARSE_POINT |
FILE_ATTR_COMPRESSED | FILE_ATTR_ENCRYPTED))) {
Qprintf("%s", NONE);
ntfs_log_quiet("%s", NONE);
}
Qprintf("\n");
ntfs_log_quiet("\n");
if (opts.parent) {
Qprintf("Parent: %s\n", f->parent_name ? f->parent_name : "<non-determined>");
ntfs_log_quiet("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);
ntfs_log_quiet("Size alloc: %lld\n", f->size_alloc);
ntfs_log_quiet("Size data: %lld\n", f->size_data);
strftime(buffer, sizeof(buffer), "%F %R", localtime(&f->date_c));
Qprintf("Date C: %s\n", buffer);
ntfs_log_quiet("Date C: %s\n", buffer);
strftime(buffer, sizeof(buffer), "%F %R", localtime(&f->date_a));
Qprintf("Date A: %s\n", buffer);
ntfs_log_quiet("Date A: %s\n", buffer);
strftime(buffer, sizeof(buffer), "%F %R", localtime(&f->date_m));
Qprintf("Date M: %s\n", buffer);
ntfs_log_quiet("Date M: %s\n", buffer);
strftime(buffer, sizeof(buffer), "%F %R", localtime(&f->date_r));
Qprintf("Date R: %s\n", buffer);
ntfs_log_quiet("Date R: %s\n", buffer);
}
Qprintf("Data Streams:\n");
ntfs_log_quiet("Data Streams:\n");
list_for_each(item, &file->data) {
struct data *d = list_entry(item, struct data, list);
Qprintf("Name: %s\n", (d->name) ? d->name : UNNAMED);
Qprintf("Flags: ");
if (d->resident) Qprintf("Resident\n");
if (d->compressed) Qprintf("Compressed\n");
if (d->encrypted) Qprintf("Encrypted\n");
ntfs_log_quiet("Name: %s\n", (d->name) ? d->name : UNNAMED);
ntfs_log_quiet("Flags: ");
if (d->resident) ntfs_log_quiet("Resident\n");
if (d->compressed) ntfs_log_quiet("Compressed\n");
if (d->encrypted) ntfs_log_quiet("Encrypted\n");
if (!d->resident && !d->compressed && !d->encrypted)
Qprintf("None\n");
ntfs_log_quiet("None\n");
else
Qprintf("\n");
ntfs_log_quiet("\n");
Qprintf("Size alloc: %lld\n", d->size_alloc);
Qprintf("Size data: %lld\n", d->size_data);
Qprintf("Size init: %lld\n", d->size_init);
Qprintf("Size vcn: %lld\n", d->size_vcn);
ntfs_log_quiet("Size alloc: %lld\n", d->size_alloc);
ntfs_log_quiet("Size data: %lld\n", d->size_data);
ntfs_log_quiet("Size init: %lld\n", d->size_init);
ntfs_log_quiet("Size vcn: %lld\n", d->size_vcn);
Qprintf("Data runs:\n");
ntfs_log_quiet("Data runs:\n");
if ((!d->runlist) || (d->runlist[0].length <= 0)) {
Qprintf(" None\n");
ntfs_log_quiet(" None\n");
} else {
for (i = 0; d->runlist[i].length > 0; i++) {
Qprintf(" %lld @ %lld\n",
ntfs_log_quiet(" %lld @ %lld\n",
(long long)d->runlist[i].length,
(long long)d->runlist[i].lcn);
}
}
Qprintf("Amount potentially recoverable %d%%\n", d->percent);
ntfs_log_quiet("Amount potentially recoverable %d%%\n", d->percent);
}
Qprintf("________________________________________\n\n");
ntfs_log_quiet("________________________________________\n\n");
}
/**
@ -1405,7 +1418,7 @@ static void list_record(struct ufile *file)
else
name = NONE;
Qprintf("%-8lld %c%c%c%c %3d%% %s %9lld %s\n",
ntfs_log_quiet("%-8lld %c%c%c%c %3d%% %s %9lld %s\n",
file->inode, flagd, flagr, flagc, flagx,
percent, buffer, size, name);
@ -1437,7 +1450,7 @@ static int name_match(regex_t *re, struct ufile *file)
continue;
result = regexec(re, f->name, 0, NULL, 0);
if (result < 0) {
Eprintf("Couldn't compare filename with regex: %s\n", strerror(errno));
ntfs_log_perror("Couldn't compare filename with regex");
return 0;
} else if (result == REG_NOERROR) {
ntfs_log_debug("Found a matching filename.\n");
@ -1543,7 +1556,7 @@ static int open_file(const char *pathname)
{
int flags;
Vprintf("Creating file: %s\n", pathname);
ntfs_log_verbose("Creating file: %s\n", pathname);
if (opts.force)
flags = O_RDWR | O_CREAT | O_TRUNC;
@ -1573,7 +1586,7 @@ static int set_date(const char *pathname, time_t date)
ut.actime = date;
ut.modtime = date;
if (utime(pathname, &ut)) {
Eprintf("ERROR: Couldn't set the file's date and time\n");
ntfs_log_error("ERROR: Couldn't set the file's date and time\n");
return 0;
}
return 1;
@ -1623,7 +1636,7 @@ static int undelete_file(ntfs_volume *vol, long long inode)
/* try to get record */
file = read_record(vol, inode);
if (!file || !file->mft) {
Eprintf("Can't read info from mft record %lld.\n", inode);
ntfs_log_error("Can't read info from mft record %lld.\n", inode);
return 0;
}
@ -1633,7 +1646,7 @@ static int undelete_file(ntfs_volume *vol, long long inode)
dump_record(file);
} else {
list_record(file);
//Qprintf("\n");
//ntfs_log_quiet("\n");
}
}
@ -1642,23 +1655,27 @@ static int undelete_file(ntfs_volume *vol, long long inode)
if (!buffer)
goto free;
if (file->mft->flags & MFT_RECORD_IN_USE) { /* These two statement blocks were */
Eprintf("Record is in use by the mft\n"); /* relocated from below because */
if (!opts.force) { /* calc_percentage() must be called */
/* calc_percentage() must be called before dump_record() or
* list_record(). Otherwise, when undeleting, a file will always be
* listed as 0% recoverable even if successfully undeleted. +mabs
*/
if (file->mft->flags & MFT_RECORD_IN_USE) {
ntfs_log_error("Record is in use by the mft\n");
if (!opts.force) {
free(buffer);
free_file(file); /* before dump_record() or list_record(). */
return 0; /* Otherwise, when undeleting, a file */
} /* will always be listed as 0% recoverable */
Vprintf("Forced to continue.\n"); /* even if successfully undeleted. +mabs */
free_file(file);
return 0;
}
ntfs_log_verbose("Forced to continue.\n");
}
if (calc_percentage(file, vol) == 0) {
Qprintf("File has no recoverable data.\n");
ntfs_log_quiet("File has no recoverable data.\n");
goto free;
}
if (list_empty(&file->data)) {
Qprintf("File has no data. There is nothing to recover.\n");
ntfs_log_quiet("File has no data. There is nothing to recover.\n");
goto free;
}
@ -1674,47 +1691,47 @@ static int undelete_file(ntfs_volume *vol, long long inode)
if (d->resident) {
fd = open_file(pathname);
if (fd < 0) {
Eprintf("Couldn't create file: %s\n", strerror(errno));
ntfs_log_perror("Couldn't create file");
goto free;
}
Vprintf("File has resident data.\n");
ntfs_log_verbose("File has resident data.\n");
if (write_data(fd, d->data, d->size_data) < d->size_data) {
Eprintf("Write failed: %s\n", strerror(errno));
ntfs_log_perror("Write failed");
close(fd);
goto free;
}
if (close(fd) < 0) {
Eprintf("Close failed: %s\n", strerror(errno));
ntfs_log_perror("Close failed");
}
fd = -1;
} else {
rl = d->runlist;
if (!rl) {
Vprintf("File has no runlist, hence no data.\n");
ntfs_log_verbose("File has no runlist, hence no data.\n");
continue;
}
if (rl[0].length <= 0) {
Vprintf("File has an empty runlist, hence no data.\n");
ntfs_log_verbose("File has an empty runlist, hence no data.\n");
continue;
}
fd = open_file(pathname);
if (fd < 0) {
Eprintf("Couldn't create output file: %s\n", strerror(errno));
ntfs_log_perror("Couldn't create output file");
goto free;
}
if (rl[0].lcn == LCN_RL_NOT_MAPPED) { /* extended mft record */
Vprintf("Missing segment at beginning, %lld "
ntfs_log_verbose("Missing segment at beginning, %lld "
"clusters.\n",
(long long)rl[0].length);
memset(buffer, opts.fillbyte, bufsize);
for (k = 0; k < rl[0].length * vol->cluster_size; k += bufsize) {
if (write_data(fd, buffer, bufsize) < bufsize) {
Eprintf("Write failed: %s\n", strerror(errno));
ntfs_log_perror("Write failed");
close(fd);
goto free;
}
@ -1725,13 +1742,13 @@ static int undelete_file(ntfs_volume *vol, long long inode)
for (i = 0; rl[i].length > 0; i++) {
if (rl[i].lcn == LCN_RL_NOT_MAPPED) {
Vprintf("Missing segment at end, "
ntfs_log_verbose("Missing segment at end, "
"%lld clusters.\n",
(long long)rl[i].length);
memset(buffer, opts.fillbyte, bufsize);
for (k = 0; k < rl[k].length * vol->cluster_size; k += bufsize) {
if (write_data(fd, buffer, bufsize) < bufsize) {
Eprintf("Write failed: %s\n", strerror(errno));
ntfs_log_perror("Write failed");
close(fd);
goto free;
}
@ -1741,11 +1758,11 @@ static int undelete_file(ntfs_volume *vol, long long inode)
}
if (rl[i].lcn == LCN_HOLE) {
Vprintf("File has a sparse section.\n");
ntfs_log_verbose("File has a sparse section.\n");
memset(buffer, 0, bufsize);
for (k = 0; k < rl[k].length * vol->cluster_size; k += bufsize) {
if (write_data(fd, buffer, bufsize) < bufsize) {
Eprintf("Write failed: %s\n", strerror(errno));
ntfs_log_perror("Write failed");
close(fd);
goto free;
}
@ -1760,18 +1777,18 @@ static int undelete_file(ntfs_volume *vol, long long inode)
if (utils_cluster_in_use(vol, j) && !opts.optimistic) {
memset(buffer, opts.fillbyte, bufsize);
if (write_data(fd, buffer, bufsize) < bufsize) {
Eprintf("Write failed: %s\n", strerror(errno));
ntfs_log_perror("Write failed");
close(fd);
goto free;
}
} else {
if (ntfs_cluster_read(vol, j, 1, buffer) < 1) {
Eprintf("Read failed: %s\n", strerror(errno));
ntfs_log_perror("Read failed");
close(fd);
goto free;
}
if (write_data(fd, buffer, bufsize) < bufsize) {
Eprintf("Write failed: %s\n", strerror(errno));
ntfs_log_perror("Write failed");
close(fd);
goto free;
}
@ -1779,7 +1796,7 @@ static int undelete_file(ntfs_volume *vol, long long inode)
}
}
}
Qprintf("\n");
ntfs_log_quiet("\n");
/*
* The following block of code implements the --truncate option.
@ -1795,28 +1812,27 @@ static int undelete_file(ntfs_volume *vol, long long inode)
* that resident streams need not be truncated, since the original code
* already recovers their exact length. +mabs
*/
if (opts.truncate) {
if (d->percent == 100 && d->size_alloc >= d->size_data &&
(d->size_alloc - d->size_data) <= (long long)vol->cluster_size &&
cluster_count * (long long)vol->cluster_size == d->size_alloc) {
if (ftruncate(fd, (off_t)d->size_data))
Eprintf("Truncation failed: %s\n", strerror(errno));
} else Qprintf("Truncation not performed because file has an "
ntfs_log_perror("Truncation failed");
} else ntfs_log_quiet("Truncation not performed because file has an "
"inconsistent $MFT record.\n");
}
if (close(fd) < 0) {
Eprintf("Close failed: %s\n", strerror(errno));
ntfs_log_perror("Close failed");
}
fd = -1;
}
set_date(pathname, file->date);
if (d->name)
Qprintf("Undeleted '%s:%s' successfully.\n", file->pref_name, d->name);
ntfs_log_quiet("Undeleted '%s:%s' successfully.\n", file->pref_name, d->name);
else
Qprintf("Undeleted '%s' successfully.\n", file->pref_name);
ntfs_log_quiet("Undeleted '%s' successfully.\n", file->pref_name);
}
result = 1;
free:
@ -1857,14 +1873,14 @@ static int scan_disk(ntfs_volume *vol)
attr = ntfs_attr_open(vol->mft_ni, AT_BITMAP, AT_UNNAMED, 0);
if (!attr) {
Eprintf("ERROR: Couldn't open $MFT/$BITMAP: %s\n", strerror(errno));
ntfs_log_perror("ERROR: Couldn't open $MFT/$BITMAP");
return -1;
}
bmpsize = attr->initialized_size;
buffer = malloc(BUFSIZE);
if (!buffer) {
Eprintf("ERROR: Couldn't allocate memory in scan_disk()\n");
ntfs_log_error("ERROR: Couldn't allocate memory in scan_disk()\n");
results = -1;
goto out;
}
@ -1875,7 +1891,7 @@ static int scan_disk(ntfs_volume *vol)
if (!opts.match_case)
flags |= REG_ICASE;
if (regcomp(&re, opts.match, flags)) {
Eprintf("ERROR: Couldn't create a regex.\n");
ntfs_log_error("ERROR: Couldn't create a regex.\n");
goto out;
}
}
@ -1883,8 +1899,8 @@ static int scan_disk(ntfs_volume *vol)
nr_mft_records = vol->mft_na->initialized_size >>
vol->mft_record_size_bits;
Qprintf("Inode Flags %%age Date Size Filename\n");
Qprintf("---------------------------------------------------------------\n");
ntfs_log_quiet("Inode Flags %%age Date Size Filename\n");
ntfs_log_quiet("---------------------------------------------------------------\n");
for (i = 0; i < bmpsize; i += BUFSIZE) {
long long read_count = min((bmpsize - i), BUFSIZE);
size = ntfs_attr_pread(attr, i, read_count, buffer);
@ -1900,7 +1916,7 @@ static int scan_disk(ntfs_volume *vol)
continue;
file = read_record(vol, (i+j)*8+k);
if (!file) {
Eprintf("Couldn't read MFT Record %d.\n", (i+j)*8+k);
ntfs_log_error("Couldn't read MFT Record %d.\n", (i+j)*8+k);
continue;
}
@ -1924,10 +1940,10 @@ static int scan_disk(ntfs_volume *vol)
so undelete file by regex */
if (opts.mode == MODE_UNDELETE) {
if (!undelete_file(vol, file->inode))
Vprintf("ERROR: Failed to undelete "
ntfs_log_verbose("ERROR: Failed to undelete "
"inode %lli\n!",
file->inode);
printf("\n");
ntfs_log_info("\n");
}
}
if (((opts.percent == -1) && (percent > 0)) ||
@ -1940,7 +1956,8 @@ skip:
}
}
done:
Qprintf("\nFiles with potentially recoverable content: %d\n", results);
ntfs_log_quiet("\nFiles with potentially recoverable content: %d\n",
results);
out:
if (opts.match)
regfree(&re);
@ -1976,19 +1993,19 @@ static int copy_mft(ntfs_volume *vol, long long mft_begin, long long mft_end)
return 1;
if (mft_end < mft_begin) {
Eprintf("Range to copy is backwards.\n");
ntfs_log_error("Range to copy is backwards.\n");
return 1;
}
buffer = malloc(vol->mft_record_size);
if (!buffer) {
Eprintf("Couldn't allocate memory in copy_mft()\n");
ntfs_log_error("Couldn't allocate memory in copy_mft()\n");
return 1;
}
mft = ntfs_attr_open(vol->mft_ni, AT_DATA, AT_UNNAMED, 0);
if (!mft) {
Eprintf("Couldn't open $MFT/$DATA: %s\n", strerror(errno));
ntfs_log_perror("Couldn't open $MFT/$DATA");
goto free;
}
@ -2002,7 +2019,7 @@ static int copy_mft(ntfs_volume *vol, long long mft_begin, long long mft_end)
create_pathname(opts.dest, name, NULL, pathname, sizeof(pathname));
fd = open_file(pathname);
if (fd < 0) {
Eprintf("Couldn't open output file '%s': %s\n", name, strerror(errno));
ntfs_log_perror("Couldn't open output file '%s'", name);
goto attr;
}
@ -2017,18 +2034,19 @@ static int copy_mft(ntfs_volume *vol, long long mft_begin, long long mft_end)
ntfs_log_debug("\tEnd: %8lld\n", mft_end);
for (i = mft_begin; i <= mft_end; i++) {
if (ntfs_attr_pread(mft, vol->mft_record_size * i, vol->mft_record_size, buffer) < vol->mft_record_size) {
Eprintf("Couldn't read MFT Record %lld: %s.\n", i, strerror(errno));
if (ntfs_attr_pread(mft, vol->mft_record_size * i,
vol->mft_record_size, buffer) < vol->mft_record_size) {
ntfs_log_perror("Couldn't read MFT Record %lld", i);
goto close;
}
if (write_data(fd, buffer, vol->mft_record_size) < vol->mft_record_size) {
Eprintf("Write failed: %s\n", strerror(errno));
ntfs_log_perror("Write failed");
goto close;
}
}
Vprintf("Read %lld MFT Records\n", mft_end - mft_begin + 1);
ntfs_log_verbose("Read %lld MFT Records\n", mft_end - mft_begin + 1);
result = 0;
close:
close(fd);
@ -2053,17 +2071,19 @@ static int handle_undelete(ntfs_volume *vol)
/* Check whether (an) inode(s) was specified or at least a regex! */
if (nr_entries == 0) {
if (with_regex == 0) {
printf("ERROR: NO inode(s) AND NO match-regex specified!\n");
ntfs_log_error("ERROR: NO inode(s) AND NO match-regex "
"specified!\n");
} else {
avoid_duplicate_printing= 1;
result = !scan_disk(vol);
if (result)
Vprintf("ERROR: Failed to scan device '%s'.\n", opts.device);
ntfs_log_verbose("ERROR: Failed to scan device "
"'%s'.\n", opts.device);
}
} else {
/* Normal undelete by specifying inode(s) */
Qprintf("Inode Flags %%age Date Size Filename\n");
Qprintf("---------------------------------------------------------------\n");
ntfs_log_quiet("Inode Flags %%age Date Size Filename\n");
ntfs_log_quiet("---------------------------------------------------------------\n");
/* loop all given inodes */
for (i = 0; i < nr_entries; i++) {
@ -2071,9 +2091,8 @@ static int handle_undelete(ntfs_volume *vol)
/* Now undelete file */
result = !undelete_file(vol, inode);
if (result)
Vprintf("ERROR: Failed to undelete "
"inode %lli\n!",
inode);
ntfs_log_verbose("ERROR: Failed to "
"undelete inode %lli\n!", inode);
}
}
}
@ -2093,6 +2112,8 @@ int main(int argc, char *argv[])
ntfs_volume *vol;
int result = 1;
ntfs_log_set_handler(ntfs_log_handler_outerr);
with_regex = 0;
avoid_duplicate_printing = 0;
@ -2111,7 +2132,8 @@ int main(int argc, char *argv[])
case MODE_SCAN:
result = !scan_disk(vol);
if (result)
Vprintf("ERROR: Failed to scan device '%s'.\n", opts.device);
ntfs_log_verbose("ERROR: Failed to scan device '%s'.\n",
opts.device);
break;
/* Undelete-handling */
@ -2123,8 +2145,8 @@ int main(int argc, char *argv[])
case MODE_COPY:
result = !copy_mft(vol, opts.mft_begin, opts.mft_end);
if (result)
Vprintf("ERROR: Failed to read MFT blocks %lld-%lld.\n",
opts.mft_begin,
ntfs_log_verbose("ERROR: Failed to read MFT blocks "
"%lld-%lld.\n", opts.mft_begin,
min((vol->mft_na->initialized_size >>
vol->mft_record_size_bits) , opts.mft_end));
break;