From 14cd02ffc1d2086633ecf7856311ef6a367b16a8 Mon Sep 17 00:00:00 2001 From: "flatcap.org!ntfs" Date: Wed, 23 Mar 2005 13:01:27 +0000 Subject: [PATCH] Updates from Holger for regex undelete Fix up code formatting (Logical change 1.693) --- ntfsprogs/ntfsundelete.c | 245 +++++++++++++++++++++++---------------- 1 file changed, 143 insertions(+), 102 deletions(-) diff --git a/ntfsprogs/ntfsundelete.c b/ntfsprogs/ntfsundelete.c index 586207b9..990a5b06 100644 --- a/ntfsprogs/ntfsundelete.c +++ b/ntfsprogs/ntfsundelete.c @@ -1,8 +1,8 @@ /** * ntfsundelete - Part of the Linux-NTFS project. * - * Copyright (c) 2002-2004 Richard Russon - * Copyright (c) 2004 Holger Ohmacht + * Copyright (c) 2002-2005 Richard Russon + * Copyright (c) 2004-2005 Holger Ohmacht * * This utility will recover deleted files from an NTFS volume. * @@ -68,13 +68,17 @@ typedef struct u32 end; } range; -static range *ranges; -static long nr_entries; +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 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) +static int undelete_file (ntfs_volume *vol, long long inode); + #define _(S) gettext(S) /** @@ -97,43 +101,43 @@ static int parse_inode_arg (void) char *opt_arg_end1; char *opt_arg_end2; + /* Check whether optarg is available or not */ + nr_entries = 0; + if (optarg == NULL) + return (0); /* bailout if no optarg */ + /* init variables */ p = strlen (optarg); imax = p; opt_arg_ptr = optarg; opt_arg_end1 = optarg; opt_arg_end2 = &(optarg[p]); - nr_entries = 0; /* alloc mem for range table */ ranges = (range *) malloc ((p + 1) * sizeof (range)); - if (ranges == NULL) - { + if (ranges == NULL) { printf ("ERROR: Couldn't alloc mem for parsing inodes!\n"); return (-1); } /* loop */ - while ((opt_arg_end1 != opt_arg_end2) && (p > 0)) - { + while ((opt_arg_end1 != opt_arg_end2) && (p > 0)) { + /* Try to get inode */ inode = strtoul (opt_arg_ptr, &opt_arg_end1, 0); p--; /* invalid char at begin */ - if ((opt_arg_ptr == opt_arg_end1) || (opt_arg_ptr == opt_arg_end2)) - { + if ((opt_arg_ptr == opt_arg_end1) || (opt_arg_ptr == opt_arg_end2)) { printf ("ERROR: Invalid Number: %s\n", opt_arg_ptr); return (-1); } /* RANGE - Check for range */ - if (opt_arg_end1[0] == '-') - { + if (opt_arg_end1[0] == '-') { /* get range end */ opt_arg_temp = opt_arg_end1; opt_arg_end1 = & (opt_arg_temp[1]); - if (opt_arg_temp >= opt_arg_end2) - { + if (opt_arg_temp >= opt_arg_end2) { printf ("ERROR: Missing range end!\n"); return (-1); } @@ -141,15 +145,13 @@ 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) - { + if (opt_arg_temp == opt_arg_end1) { printf ("ERROR: Invalid Number: %s\n", opt_arg_temp); return (-1); } /* check for correct values */ - if (range_begin > range_end) - { + if (range_begin > range_end) { range_temp = range_end; range_end = range_begin; range_begin = range_temp; @@ -173,8 +175,7 @@ static int parse_inode_arg (void) /* Next inode */ opt_arg_ptr = & (opt_arg_end1[1]); - if (opt_arg_ptr >= opt_arg_end2) - { + if (opt_arg_ptr >= opt_arg_end2) { printf ("ERROR: Missing new value at end of input!\n"); return (-1); } @@ -199,8 +200,8 @@ static void version (void) { printf ("\n%s v%s - Recover deleted files from an NTFS Volume.\n\n", EXEC_NAME, VERSION); - printf ("Copyright (c)\n"); - printf (" 2002-2003 Richard Russon\n"); + printf ("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); } @@ -221,7 +222,8 @@ static void usage (void) " -S range --size range Match files of this size\n" " -t since --time since Last referenced since this time\n" "\n" - " -u nums --undelete nums Undelete inodes\n" + " -i --interactive Interactive mode\n" + " -u [nums] --undelete [nums] Undelete mode: if specified, so undelete these\n" " -o file --output file Save with this filename\n" " -O --optimistic Undelete in-use clusters as well\n" " -d dir --destination dir Destination directory\n" @@ -395,13 +397,14 @@ 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:OPp:sS:t:Tu:qvV"; + static const char *sopt = "-b:Cc:d:fhi?m:o:OPp:sS:t:Tu::qvV"; static const struct option lopt[] = { { "byte", required_argument, NULL, 'b' }, { "case", no_argument, NULL, 'C' }, { "copy", required_argument, NULL, 'c' }, { "destination", required_argument, NULL, 'd' }, { "force", no_argument, NULL, 'f' }, + { "interactive", no_argument, NULL, 'i' }, { "help", no_argument, NULL, 'h' }, { "match", required_argument, NULL, 'm' }, { "output", required_argument, NULL, 'o' }, @@ -412,7 +415,7 @@ static int parse_options (int argc, char *argv[]) { "parent", no_argument, NULL, 'P' }, { "time", required_argument, NULL, 't' }, { "truncate", no_argument, NULL, 'T' }, - { "undelete", required_argument, NULL, 'u' }, + { "undelete", optional_argument, NULL, 'u' }, { "quiet", no_argument, NULL, 'q' }, { "verbose", no_argument, NULL, 'v' }, { "version", no_argument, NULL, 'V' }, @@ -431,8 +434,7 @@ static int parse_options (int argc, char *argv[]) opts.uinode = -1; opts.percent = -1; opts.fillbyte = -1; - - while ((c = getopt_long (argc, argv, sopt, lopt, NULL)) != (char)-1) { + while ((c = getopt_long (argc, argv, sopt, lopt, NULL)) != (char)-1) { switch (c) { case 1: /* A non-option argument */ if (!opts.device) { @@ -480,8 +482,12 @@ static int parse_options (int argc, char *argv[]) break; case 'm': if (!opts.match) { - if (!transform (optarg, &opts.match)) + if (!transform (optarg, &opts.match)) { err++; + } else { + /* set regex-flag on true ;) */ + with_regex= 1; + } } else { err++; } @@ -545,8 +551,7 @@ static int parse_options (int argc, char *argv[]) opts.truncate++; break; case 'u': - if (opts.mode == MODE_NONE) - { + if (opts.mode == MODE_NONE) { end = NULL; opts.mode = MODE_UNDELETE; /* parse inodes */ @@ -605,13 +610,13 @@ static int parse_options (int argc, char *argv[]) err++; } break; + case MODE_UNDELETE: - if ((opts.percent != -1) || opts.match || opts.match_case || - (opts.size_begin > 0) || (opts.size_end > 0)) { + /*if ((opts.percent != -1) || (opts.size_begin > 0) || (opts.size_end > 0)) { Eprintf ("Undelete can only be used with " "--output, --destination, --byte and --truncate.\n"); err++; - } + }*/ break; case MODE_COPY: if ((opts.fillbyte != (char)-1) || opts.truncate || @@ -730,7 +735,7 @@ static FILE_NAME_ATTR* verify_parent(struct filename* name, MFT_RECORD* rec) { ctx = ntfs_attr_get_search_ctx(NULL, rec); if (!ctx) { - Eprintf ("Couldn't create a search context.\n"); + Eprintf ("ERROR: Couldn't create a search context.\n"); return NULL; } @@ -754,15 +759,14 @@ static FILE_NAME_ATTR* verify_parent(struct filename* name, MFT_RECORD* rec) { if (filename_attr->file_name_type == name->name_space) { found_same_space = 1; - } - else { + } 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); @@ -771,9 +775,9 @@ static FILE_NAME_ATTR* verify_parent(struct filename* name, MFT_RECORD* rec) { /** * 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) { +static void get_parent_name (struct filename* name, ntfs_volume* vol) +{ ntfs_attr* mft_data; MFT_RECORD* rec; FILE_NAME_ATTR* filename_attr; @@ -784,21 +788,19 @@ static void get_parent_name(struct filename* name, ntfs_volume* vol) { rec = calloc(1, vol->mft_record_size); if (!rec) { - Eprintf ("Couldn't allocate memory in get_parent_name()\n"); + Eprintf ("ERROR: 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 { + Eprintf ("ERROR: 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 { + Eprintf ("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, &name->parent_name, 0) < 0) { Dprintf ("Couldn't translate filename to current locale.\n"); @@ -860,7 +862,7 @@ static int get_filenames (struct ufile *file, ntfs_volume* vol) name = calloc (1, sizeof (*name)); if (!name) { - Eprintf ("Couldn't allocate memory in get_filenames().\n"); + Eprintf ("ERROR: Couldn't allocate memory in get_filenames().\n"); count = -1; break; } @@ -879,7 +881,7 @@ static int get_filenames (struct ufile *file, ntfs_volume* vol) if (ntfs_ucstombs (name->uname, name->uname_len, &name->name, name->uname_len) < 0) { - Dprintf ("Couldn't translate filename to current locale.\n"); + Dprintf ("ERROR: Couldn't translate filename to current locale.\n"); } name->parent_name = NULL; @@ -939,7 +941,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 ("Couldn't allocate memory in get_data().\n"); + Eprintf ("ERROR: Couldn't allocate memory in get_data().\n"); count = -1; break; } @@ -954,7 +956,7 @@ static int get_data (struct ufile *file, ntfs_volume *vol) if (ntfs_ucstombs (data->uname, data->uname_len, &data->name, data->uname_len) < 0) { - Eprintf ("Cannot translate name into current locale.\n"); + Eprintf ("ERROR: Cannot translate name into current locale.\n"); } } @@ -1007,7 +1009,7 @@ static struct ufile * read_record (ntfs_volume *vol, long long record) file = calloc (1, sizeof (*file)); if (!file) { - Eprintf ("Couldn't allocate memory in read_record()\n"); + Eprintf ("ERROR: Couldn't allocate memory in read_record()\n"); return NULL; } @@ -1017,20 +1019,20 @@ static struct ufile * read_record (ntfs_volume *vol, long long record) file->mft = malloc (vol->mft_record_size); if (!file->mft) { - Eprintf ("Couldn't allocate memory in read_record()\n"); + Eprintf ("ERROR: Couldn't allocate memory in read_record()\n"); free_file (file); return NULL; } mft = ntfs_attr_open (vol->mft_ni, AT_DATA, NULL, 0); if (!mft) { - Eprintf ("Couldn't open $MFT/$DATA: %s\n", strerror (errno)); + Eprintf ("ERROR: Couldn't open $MFT/$DATA: %s\n", strerror (errno)); 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 ("Couldn't read MFT Record %lld.\n", record); + Eprintf ("ERROR: Couldn't read MFT Record %lld.\n", record); ntfs_attr_close (mft); free_file (file); return NULL; @@ -1045,8 +1047,7 @@ static struct ufile * read_record (ntfs_volume *vol, long long record) Dprintf ("Attributes present: %s %s %s\n", attr10?"0x10":"", attr20?"0x20":"", attr90?"0x90":""); - if (attr10) - { + if (attr10) { STANDARD_INFORMATION *si; si = (STANDARD_INFORMATION *) ((char *) attr10 + le16_to_cpu (attr10->value_offset)); file->date = ntfs2utc (sle64_to_cpu (si->last_data_change_time)); @@ -1058,10 +1059,10 @@ static struct ufile * read_record (ntfs_volume *vol, long long record) file->directory = 1; if (get_filenames (file, vol) < 0) { - Eprintf ("Couldn't get filenames.\n"); + Eprintf ("ERROR: Couldn't get filenames.\n"); } if (get_data (file, vol) < 0) { - Eprintf ("Couldn't get data streams.\n"); + Eprintf ("ERROR: Couldn't get data streams.\n"); } return file; @@ -1179,7 +1180,7 @@ static int calc_percentage (struct ufile *file, ntfs_volume *vol) } if ((clusters_inuse + clusters_free) == 0) { - Eprintf ("Unexpected error whilst calculating percentage for inode %lld\n", file->inode); + Eprintf ("ERROR: Unexpected error whilst calculating percentage for inode %lld\n", file->inode); continue; } @@ -1369,6 +1370,7 @@ static void list_record (struct ufile *file) Qprintf ("%-8lld %c%c%c%c %3d%% %s %9lld %s\n", file->inode, flagd, flagr, flagc, flagx, percent, buffer, size, name); + } /** @@ -1533,7 +1535,7 @@ static int set_date (const char *pathname, time_t date) ut.actime = date; ut.modtime = date; if (utime (pathname, &ut)) { - Eprintf ("Couldn't set the file's date and time\n"); + Eprintf ("ERROR: Couldn't set the file's date and time\n"); return 0; } return 1; @@ -1570,14 +1572,14 @@ static int scan_disk (ntfs_volume *vol) attr = ntfs_attr_open (vol->mft_ni, AT_BITMAP, AT_UNNAMED, 0); if (!attr) { - Eprintf ("Couldn't open $MFT/$BITMAP: %s\n", strerror (errno)); + Eprintf ("ERROR: Couldn't open $MFT/$BITMAP: %s\n", strerror (errno)); return -1; } bmpsize = attr->initialized_size; buffer = malloc (BUFSIZE); if (!buffer) { - Eprintf ("Couldn't allocate memory in scan_disk()\n"); + Eprintf ("ERROR: Couldn't allocate memory in scan_disk()\n"); results = -1; goto out; } @@ -1588,7 +1590,7 @@ static int scan_disk (ntfs_volume *vol) if (!opts.match_case) flags |= REG_ICASE; if (regcomp (&re, opts.match, flags)) { - Eprintf ("Couldn't create a regex.\n"); + Eprintf ("ERROR: Couldn't create a regex.\n"); goto out; } } @@ -1596,7 +1598,7 @@ 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 ("Inode Flags %%age Date Size Filename\n"); Qprintf ("---------------------------------------------------------------\n"); for (i = 0; i < bmpsize; i += BUFSIZE) { long long read_count = min ((bmpsize - i), BUFSIZE); @@ -1627,14 +1629,22 @@ static int scan_disk (ntfs_volume *vol) goto skip; percent = calc_percentage (file, vol); - if ((opts.percent == -1) || (percent >= opts.percent)) { if (opts.verbose) dump_record (file); else list_record (file); - } + /* Was -u specified with no inode + so undelete file by regex */ + if (opts.mode == MODE_UNDELETE) { + if (!undelete_file (vol, file->inode)) + Vprintf ("ERROR: Failed to undelete " + "inode %lli\n!", + file->inode); + printf ("\n"); + } + } if (((opts.percent == -1) && (percent > 0)) || ((opts.percent > 0) && (percent >= opts.percent))) { results++; @@ -1696,12 +1706,23 @@ static int undelete_file (ntfs_volume *vol, long long inode) if (!vol) return 0; + /* try to get record */ file = read_record (vol, inode); if (!file || !file->mft) { Eprintf ("Can't read info from mft record %lld.\n", inode); return 0; } + /* if flag was not set, print file informations */ + if (avoid_duplicate_printing == 0) { + if (opts.verbose) { + dump_record (file); + } else { + list_record (file); + //Qprintf ("\n"); + } + } + bufsize = vol->cluster_size; buffer = malloc (bufsize); if (!buffer) @@ -1722,15 +1743,6 @@ static int undelete_file (ntfs_volume *vol, long long inode) goto free; } - if (opts.verbose) { - dump_record (file); - } else { - Qprintf ("Inode Flags %%age Date Size Filename\n"); - Qprintf ("---------------------------------------------------------------\n"); - list_record (file); - Qprintf ("\n"); - } - if (list_empty (&file->data)) { Qprintf ("File has no data. There is nothing to recover.\n"); goto free; @@ -1986,6 +1998,46 @@ free: return result; } +/** + * handle_undelete + * Handles the undelete + */ +int handle_undelete (ntfs_volume *vol) +{ + int result = 1; + int i; + unsigned long long inode; + + /* 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"); + } else { + avoid_duplicate_printing= 1; + result = !scan_disk (vol); + if (result) + Vprintf ("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"); + + /* loop all given inodes */ + for (i = 0; i < nr_entries; i++) { + for (inode = ranges[i].begin; inode <= ranges[i].end; inode ++) { + /* Now undelete file */ + result = !undelete_file (vol, inode); + if (result) + Vprintf ("ERROR: Failed to undelete " + "inode %lli\n!", + inode); + } + } + } + return (result); +} + /** * main - Begin here * @@ -1996,11 +2048,11 @@ free: */ int main (int argc, char *argv[]) { - s64 nr_mft_records; ntfs_volume *vol; int result = 1; - int i; - u32 inode; + + with_regex = 0; + avoid_duplicate_printing = 0; if (!parse_options (argc, argv)) goto free; @@ -2011,39 +2063,28 @@ int main (int argc, char *argv[]) if (!vol) return 1; + /* handling of the different modes */ switch (opts.mode) { + /* Scanning */ case MODE_SCAN: result = !scan_disk (vol); if (result) - Vprintf ("Failed to scan device '%s'.\n", opts.device); + Vprintf ("ERROR: Failed to scan device '%s'.\n", opts.device); break; + + /* Undelete-handling */ case MODE_UNDELETE: - if (nr_entries == 0) - { - printf ("ERROR: No inode(s) specified!\n"); - break; - } - - for (i = 0; i < nr_entries; i++) - { - for (inode = ranges[i].begin; inode <= ranges[i].end; inode ++) - { - result = !undelete_file (vol, inode); - if (result) - Vprintf ("ERROR: Failed to undelete " - "inode %u\n!", - (unsigned int)inode); - } - } + result= handle_undelete (vol); break; - case MODE_COPY: - nr_mft_records = vol->mft_na->initialized_size >> - vol->mft_record_size_bits; + /* Handling of copy mft */ + case MODE_COPY: result = !copy_mft (vol, opts.mft_begin, opts.mft_end); if (result) - Vprintf ("Failed to read MFT blocks %lld-%lld.\n", - opts.mft_begin, min(nr_mft_records, opts.mft_end)); + Vprintf ("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; default: ; /* Cannot happen */