2 * ntfsundelete - Part of the Linux-NTFS project.
4 * Copyright (c) 2002-2003 Richard Russon
6 * This utility will recover deleted files from an NTFS volume.
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program (in the main directory of the Linux-NTFS
20 * distribution in the file COPYING); if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
31 #include <sys/types.h>
43 #include "ntfsundelete.h"
53 static const char *EXEC_NAME = "ntfsundelete";
54 static const char *MFTFILE = "mft";
55 static const char *UNNAMED = "<unnamed>";
56 static char *NONE = "<none>";
57 static char *UNKNOWN = "unknown";
58 static struct options opts;
60 GEN_PRINTF (Eprintf, stderr, NULL, FALSE)
61 GEN_PRINTF (Vprintf, stdout, &opts.verbose, TRUE)
62 GEN_PRINTF (Qprintf, stdout, &opts.quiet, FALSE)
64 #define _(S) gettext(S)
67 * version - Print version information about the program
69 * Print a copyright statement and a brief description of the program.
75 printf ("\n%s v%s - Recover deleted files from an NTFS Volume.\n\n",
77 printf ("Copyright (c)\n");
78 printf (" 2002-2003 Richard Russon\n");
79 printf ("\n%s\n%s%s\n", ntfs_gpl, ntfs_bugs, ntfs_home);
83 * usage - Print a list of the parameters to the program
85 * Print a list of the parameters and options for the program.
91 printf ("\nUsage: %s [options] device\n"
92 " -s --scan Scan for files (default)\n"
93 " -p num --percentage num Minimum percentage recoverable\n"
94 " -m pattern --match pattern Only work on files with matching names\n"
95 " -C --case Case sensitive matching\n"
96 " -S range --size range Match files of this size\n"
97 " -t since --time since Last referenced since this time\n"
99 " -u num --undelete num Undelete inode\n"
100 " -o file --output file Save with this filename\n"
101 " -d dir --destination dir Destination directory\n"
102 " -b num --byte num Fill missing parts with this byte\n"
104 " -c range --copy range Write a range of MFT records to a file\n"
106 " -f --force Use less caution\n"
107 " -q --quiet Less output\n"
108 " -v --verbose More output\n"
109 " -V --version Display version information\n"
110 " -h --help Display this help\n\n",
112 printf ("%s%s\n", ntfs_bugs, ntfs_home);
116 * transform - Convert a shell style pattern to a regex
117 * @pattern: String to be converted
118 * @regex: Resulting regular expression is put here
120 * This will transform patterns, such as "*.doc" to true regular expressions.
121 * The function will also place '^' and '$' around the expression to make it
122 * behave as the user would expect
130 * The returned string must be freed by the caller.
131 * If transform fails, @regex will not be changed.
133 * Return: 1, Success, the string was transformed
134 * 0, An error occurred
136 int transform (const char *pattern, char **regex)
141 if (!pattern || !regex)
144 length = strlen (pattern);
146 Eprintf ("Pattern to transform is empty\n");
150 for (i = 0; pattern[i]; i++) {
151 if ((pattern[i] == '*') || (pattern[i] == '.'))
155 result = malloc (length + 3);
157 Eprintf ("Couldn't allocate memory in transform()\n");
163 for (i = 0, j = 1; pattern[i]; i++, j++) {
164 if (pattern[i] == '*') {
168 } else if (pattern[i] == '.') {
172 } else if (pattern[i] == '?') {
175 result[j] = pattern[i];
181 Dprintf ("Pattern '%s' replaced with regex '%s'\n", pattern, result);
188 * parse_time - Convert a time abbreviation to seconds
189 * @string: The string to be converted
190 * @since: The absolute time referred to
192 * Strings representing times will be converted into a time_t. The numbers will
193 * be regarded as seconds unless suffixed.
202 * Therefore, passing "1W" will return the time_t representing 1 week ago.
205 * Only the first character of the suffix is read.
206 * If parse_time fails, @since will not be changed
209 * 0 Error, the string was malformed
211 int parse_time (const char *value, time_t *since)
216 if (!value || !since)
219 Dprintf ("parsing time '%s' ago\n", value);
221 result = strtoll (value, &suffix, 10);
222 if (result < 0 || errno == ERANGE) {
223 Eprintf ("Invalid time '%s'.\n", value);
228 Eprintf ("Internal error, strtoll didn't return a suffix.\n");
232 if (strlen (suffix) > 1) {
233 Eprintf ("Invalid time suffix '%s'. Use Y, M, W, D or H.\n", suffix);
238 case 'y': case 'Y': result *= 12;
239 case 'm': case 'M': result *= 4;
240 case 'w': case 'W': result *= 7;
241 case 'd': case 'D': result *= 24;
242 case 'h': case 'H': result *= 3600;
247 Eprintf ("Invalid time suffix '%s'. Use Y, M, W, D or H.\n", suffix);
253 Dprintf ("Time now = %lld, Time then = %lld.\n", (long long) now, (long long) result);
254 *since = now - result;
259 * parse_options - Read and validate the programs command line
261 * Read the command line, verify the syntax and parse the options.
262 * This function is very long, but quite simple.
265 * 0 Error, one or more problems
267 int parse_options (int argc, char *argv[])
269 static const char *sopt = "-b:Cc:d:fh?m:o:p:sS:t:u:qvV";
270 static const struct option lopt[] = {
271 { "byte", required_argument, NULL, 'b' },
272 { "case", no_argument, NULL, 'C' },
273 { "copy", required_argument, NULL, 'c' },
274 { "destination", required_argument, NULL, 'd' },
275 { "force", no_argument, NULL, 'f' },
276 { "help", no_argument, NULL, 'h' },
277 { "match", required_argument, NULL, 'm' },
278 { "output", required_argument, NULL, 'o' },
279 { "percentage", required_argument, NULL, 'p' },
280 { "scan", no_argument, NULL, 's' },
281 { "size", required_argument, NULL, 'S' },
282 { "time", required_argument, NULL, 't' },
283 { "undelete", required_argument, NULL, 'u' },
284 { "quiet", no_argument, NULL, 'q' },
285 { "verbose", no_argument, NULL, 'v' },
286 { "version", no_argument, NULL, 'V' },
296 opterr = 0; /* We'll handle the errors, thank you. */
298 opts.mode = MODE_NONE;
303 while ((c = getopt_long (argc, argv, sopt, lopt, NULL)) != -1) {
305 case 1: /* A non-option argument */
307 opts.device = argv[optind-1];
314 if (opts.fillbyte == -1) {
316 opts.fillbyte = strtol (optarg, &end, 0);
327 if (opts.mode == MODE_NONE) {
328 if (!utils_parse_range (argv[optind-1],
329 &opts.mft_begin, &opts.mft_end, TRUE))
331 opts.mode = MODE_COPY;
333 opts.mode = MODE_ERROR;
338 opts.dest = argv[optind-1];
351 if (!transform (argv[optind-1], &opts.match))
359 opts.output = argv[optind-1];
365 if (opts.percent == -1) {
367 opts.percent = strtol (optarg, &end, 0);
368 if (end && ((*end != '%') && (*end != 0)))
378 if (opts.mode == MODE_NONE)
379 opts.mode = MODE_SCAN;
381 opts.mode = MODE_ERROR;
384 if ((opts.size_begin > 0) || (opts.size_end > 0) ||
385 !utils_parse_range (argv[optind-1], &opts.size_begin,
386 &opts.size_end, TRUE)) {
391 if (opts.since == 0) {
392 if (!parse_time (argv[optind-1], &opts.since))
399 if (opts.mode == MODE_NONE) {
401 opts.mode = MODE_UNDELETE;
402 opts.uinode = strtol (optarg, &end, 0);
406 opts.mode = MODE_ERROR;
416 if (((optopt == 'b') || (optopt == 'c') ||
417 (optopt == 'd') || (optopt == 'm') ||
418 (optopt == 'o') || (optopt == 'p') ||
419 (optopt == 'S') || (optopt == 't') ||
420 (optopt == 'u')) && (!optarg)) {
421 Eprintf ("Option '%s' requires an argument.\n", argv[optind-1]);
423 Eprintf ("Unknown option '%s'.\n", argv[optind-1]);
433 if (opts.device == NULL) {
435 Eprintf ("You must specify exactly one device.\n");
439 if (opts.mode == MODE_NONE) {
440 opts.mode = MODE_SCAN;
445 if (opts.output || opts.dest || (opts.fillbyte != -1)) {
446 Eprintf ("Scan can only be used with --percent, "
447 "--match, --ignore-case, --size and --time.\n");
450 if (opts.match_case && !opts.match) {
451 Eprintf ("The --case option doesn't make sense without the --match option\n");
456 if ((opts.percent != -1) || opts.match || opts.match_case ||
457 (opts.size_begin > 0) || (opts.size_end > 0)) {
458 Eprintf ("Undelete can only be used with "
459 "--output, --destination and --byte.\n");
464 if ((opts.fillbyte != -1) || (opts.percent != -1) ||
465 opts.match || opts.match_case ||
466 (opts.size_begin > 0) || (opts.size_end > 0)) {
467 Eprintf ("Copy can only be used with --output and --destination.\n");
472 Eprintf ("You can only select one of Scan, Undelete or Copy.\n");
476 if ((opts.percent < -1) || (opts.percent > 100)) {
477 Eprintf ("Percentage value must be in the range 0 - 100.\n");
483 Eprintf ("You may not use --quiet and --verbose at the same time.\n");
485 } else if (opts.mode == MODE_SCAN) {
486 Eprintf ("You may not use --quiet when scanning a volume.\n");
492 if (opts.fillbyte == -1)
500 return (!err && !help && !ver);
505 * free_file - Release the resources used by a file object
506 * @file: The unwanted file object
508 * This will free up the memory used by a file object and iterate through the
509 * object's children, freeing their resources too.
513 void free_file (struct ufile *file)
515 struct list_head *item, *tmp;
520 list_for_each_safe (item, tmp, &file->name) { /* List of filenames */
521 struct filename *f = list_entry (item, struct filename, list);
522 Dprintf ("freeing filename '%s'\n", f->name ? f->name : NONE);
528 list_for_each_safe (item, tmp, &file->data) { /* List of data streams */
529 struct data *d = list_entry (item, struct data, list);
530 Dprintf ("freeing data stream '%s'\n", d->name ? d->name : UNNAMED);
543 * get_filenames - Read an MFT Record's $FILENAME attributes
544 * @file: The file object to work with
546 * A single file may have more than one filename. This is quite common.
547 * Windows creates a short DOS name for each long name, e.g. LONGFI~1.XYZ,
550 * The filenames that are found are put in filename objects and added to a
551 * linked list of filenames in the file object. For convenience, the unicode
552 * filename is converted into the current locale and stored in the filename
555 * One of the filenames is picked (the one with the lowest numbered namespace)
556 * and its locale friendly name is put in pref_name.
558 * Return: n The number of $FILENAME attributes found
561 int get_filenames (struct ufile *file)
564 FILE_NAME_ATTR *attr;
565 ntfs_attr_search_ctx *ctx;
566 struct filename *name;
573 ctx = ntfs_attr_get_search_ctx (NULL, file->mft);
577 while ((rec = find_attribute (AT_FILE_NAME, ctx))) {
578 /* We know this will always be resident. */
579 attr = (FILE_NAME_ATTR *) ((char *) rec + le16_to_cpu (rec->value_offset));
581 name = calloc (1, sizeof (*name));
583 Eprintf ("Couldn't allocate memory in get_filenames().\n");
588 name->uname = attr->file_name;
589 name->uname_len = attr->file_name_length;
590 name->name_space = attr->file_name_type;
591 name->size_alloc = sle64_to_cpu (attr->allocated_size);
592 name->size_data = sle64_to_cpu (attr->data_size);
593 name->flags = attr->file_attributes;
595 name->date_c = ntfs2utc (sle64_to_cpu (attr->creation_time));
596 name->date_a = ntfs2utc (sle64_to_cpu (attr->last_data_change_time));
597 name->date_m = ntfs2utc (sle64_to_cpu (attr->last_mft_change_time));
598 name->date_r = ntfs2utc (sle64_to_cpu (attr->last_access_time));
600 if (ntfs_ucstombs (name->uname, name->uname_len, &name->name,
601 name->uname_len) < 0) {
602 Dprintf ("Couldn't translate filename to current locale.\n");
605 if (name->name_space < space) {
606 file->pref_name = name->name;
607 space = name->name_space;
610 file->max_size = max (file->max_size, name->size_alloc);
611 file->max_size = max (file->max_size, name->size_data);
613 list_add_tail (&name->list, &file->name);
617 ntfs_attr_put_search_ctx(ctx);
618 Dprintf ("File has %d names.\n", count);
623 * get_data - Read an MFT Record's $DATA attributes
624 * @file: The file object to work with
625 * @vol: An ntfs volume obtained from ntfs_mount
627 * A file may have more than one data stream. All files will have an unnamed
628 * data stream which contains the file's data. Some Windows applications store
629 * extra information in a separate stream.
631 * The streams that are found are put in data objects and added to a linked
632 * list of data streams in the file object.
634 * Return: n The number of $FILENAME attributes found
637 int get_data (struct ufile *file, ntfs_volume *vol)
640 ntfs_attr_search_ctx *ctx;
647 ctx = ntfs_attr_get_search_ctx (NULL, file->mft);
651 while ((rec = find_attribute (AT_DATA, ctx))) {
652 data = calloc (1, sizeof (*data));
654 Eprintf ("Couldn't allocate memory in get_data().\n");
659 data->resident = !rec->non_resident;
660 data->compressed = rec->flags & ATTR_IS_COMPRESSED;
661 data->encrypted = rec->flags & ATTR_IS_ENCRYPTED;
663 if (rec->name_length) {
664 data->uname = (uchar_t *) ((char *) rec + le16_to_cpu (rec->name_offset));
665 data->uname_len = rec->name_length;
667 if (ntfs_ucstombs (data->uname, data->uname_len, &data->name,
668 data->uname_len) < 0) {
669 Eprintf ("Cannot translate name into current locale.\n");
673 if (data->resident) {
674 data->size_data = le32_to_cpu (rec->value_length);
675 data->data = ((char*) (rec)) + le16_to_cpu (rec->value_offset);
677 data->size_alloc = sle64_to_cpu (rec->allocated_size);
678 data->size_data = sle64_to_cpu (rec->data_size);
679 data->size_init = sle64_to_cpu (rec->initialized_size);
680 data->size_vcn = sle64_to_cpu (rec->highest_vcn) + 1;
683 data->runlist = ntfs_mapping_pairs_decompress(vol, rec, NULL);
684 if (!data->runlist) {
685 Dprintf ("Couldn't decompress the data runs\n");
688 file->max_size = max (file->max_size, data->size_data);
689 file->max_size = max (file->max_size, data->size_init);
691 list_add_tail (&data->list, &file->data);
695 ntfs_attr_put_search_ctx(ctx);
696 Dprintf ("File has %d data streams.\n", count);
701 * read_record - Read an MFT record into memory
702 * @vol: An ntfs volume obtained from ntfs_mount
703 * @record: The record number to read
705 * Read the specified MFT record and gather as much information about it as
708 * Return: Pointer A ufile object containing the results
711 struct ufile * read_record (ntfs_volume *vol, long long record)
713 ATTR_RECORD *attr10, *attr20, *attr90;
720 file = calloc (1, sizeof (*file));
722 Eprintf ("Couldn't allocate memory in read_record()\n");
726 INIT_LIST_HEAD (&file->name);
727 INIT_LIST_HEAD (&file->data);
728 file->inode = record;
730 file->mft = malloc (vol->mft_record_size);
732 Eprintf ("Couldn't allocate memory in read_record()\n");
737 mft = ntfs_attr_open (vol->mft_ni, AT_DATA, NULL, 0);
739 Eprintf ("Couldn't open $MFT/$DATA: %s\n", strerror (errno));
744 if (ntfs_attr_mst_pread (mft, vol->mft_record_size * record, 1, vol->mft_record_size, file->mft) < 1) {
745 Eprintf ("Couldn't read MFT Record %lld.\n", record);
746 ntfs_attr_close (mft);
751 ntfs_attr_close (mft);
754 attr10 = find_first_attribute (AT_STANDARD_INFORMATION, file->mft);
755 attr20 = find_first_attribute (AT_ATTRIBUTE_LIST, file->mft);
756 attr90 = find_first_attribute (AT_INDEX_ROOT, file->mft);
758 Dprintf ("Attributes present: %s %s %s\n", attr10?"0x10":"", attr20?"0x20":"", attr90?"0x90":"");
762 STANDARD_INFORMATION *si;
763 si = (STANDARD_INFORMATION *) ((char *) attr10 + le16_to_cpu (attr10->value_offset));
764 file->date = ntfs2utc (sle64_to_cpu (si->last_data_change_time));
767 if (attr20 || !attr10)
772 if (get_filenames (file) < 0) {
773 Eprintf ("Couldn't get filenames.\n");
775 if (get_data (file, vol) < 0) {
776 Eprintf ("Couldn't get data streams.\n");
784 * calc_percentage - Calculate how much of the file is recoverable
785 * @file: The file object to work with
786 * @vol: An ntfs volume obtained from ntfs_mount
788 * Read through all the $DATA streams and determine if each cluster in each
789 * stream is still free disk space. This is just measuring the potential for
790 * recovery. The data may have still been overwritten by a another file which
793 * Files with a resident $DATA stream will have a 100% potential.
795 * N.B. If $DATA attribute spans more than one MFT record (i.e. badly
796 * fragmented) then only the data in this segment will be used for the
799 * N.B. Currently, compressed and encrypted files cannot be recovered, so they
802 * Return: n The percentage of the file that _could_ be recovered
805 int calc_percentage (struct ufile *file, ntfs_volume *vol)
807 runlist_element *rl = NULL;
808 struct list_head *pos;
811 long long start, end;
818 if (file->directory) {
819 Dprintf ("Found a directory: not recoverable.\n");
823 if (list_empty (&file->data)) {
824 Vprintf ("File has no data streams.\n");
828 list_for_each (pos, &file->data) {
829 data = list_entry (pos, struct data, list);
833 if (data->encrypted) {
834 Vprintf ("File is encrypted, recovery is impossible.\n");
838 if (data->compressed) {
839 Vprintf ("File is compressed, recovery not yet implemented.\n");
843 if (data->resident) {
844 Vprintf ("File is resident, therefore recoverable.\n");
852 Vprintf ("File has no runlist, hence no data.\n");
856 if (rl[0].length <= 0) {
857 Vprintf ("File has an empty runlist, hence no data.\n");
861 if (rl[0].lcn == LCN_RL_NOT_MAPPED) { /* extended mft record */
862 Vprintf ("Missing segment at beginning, %lld clusters\n", rl[0].length);
863 inuse += rl[0].length;
867 for (i = 0; rl[i].length > 0; i++) {
868 if (rl[i].lcn == LCN_RL_NOT_MAPPED) {
869 Vprintf ("Missing segment at end, %lld clusters\n", rl[i].length);
870 inuse += rl[i].length;
874 if (rl[i].lcn == LCN_HOLE) {
875 free += rl[i].length;
880 end = rl[i].lcn + rl[i].length;
882 for (j = start; j < end; j++) {
883 if (utils_cluster_in_use (vol, j))
890 if ((inuse + free) == 0) {
891 Eprintf ("Unexpected error whilst calculating percentage for inode %lld\n", file->inode);
895 data->percent = (free * 100) / (inuse + free);
897 percent = max (percent, data->percent);
900 Vprintf ("File is %d%% recoverable\n", percent);
905 * dump_record - Print everything we know about an MFT record
906 * @file: The file to work with
908 * Output the contents of the file object. This will print everything that has
909 * been read from the MFT record, or implied by various means.
911 * Because of the redundant nature of NTFS, there will be some duplication of
912 * information, though it will have been read from different sources.
914 * N.B. If the filename is missing, or couldn't be converted to the current
915 * locale, "<none>" will be displayed.
919 void dump_record (struct ufile *file)
923 struct list_head *item;
929 Qprintf ("MFT Record %lld\n", file->inode);
930 Qprintf ("Type: %s\n", (file->directory) ? "Directory" : "File");
931 strftime (buffer, sizeof (buffer), "%F %R", localtime (&file->date));
932 Qprintf ("Date: %s\n", buffer);
935 Qprintf ("Metadata may span more than one MFT record\n");
937 list_for_each (item, &file->name) {
938 struct filename *f = list_entry (item, struct filename, list);
945 Qprintf ("Filename: (%d) %s\n", f->name_space, f->name);
946 Qprintf ("File Flags: ");
947 if (f->flags & FILE_ATTR_SYSTEM) Qprintf ("System ");
948 if (f->flags & FILE_ATTR_DIRECTORY) Qprintf ("Directory ");
949 if (f->flags & FILE_ATTR_SPARSE_FILE) Qprintf ("Sparse ");
950 if (f->flags & FILE_ATTR_REPARSE_POINT) Qprintf ("Reparse ");
951 if (f->flags & FILE_ATTR_COMPRESSED) Qprintf ("Compressed ");
952 if (f->flags & FILE_ATTR_ENCRYPTED) Qprintf ("Encrypted ");
953 if (!(f->flags & (FILE_ATTR_SYSTEM | FILE_ATTR_DIRECTORY |
954 FILE_ATTR_SPARSE_FILE | FILE_ATTR_REPARSE_POINT |
955 FILE_ATTR_COMPRESSED | FILE_ATTR_ENCRYPTED))) {
959 Qprintf ("Size alloc: %lld\n", f->size_alloc);
960 Qprintf ("Size data: %lld\n", f->size_data);
962 strftime (buffer, sizeof (buffer), "%F %R", localtime (&f->date_c));
963 Qprintf ("Date C: %s\n", buffer);
964 strftime (buffer, sizeof (buffer), "%F %R", localtime (&f->date_a));
965 Qprintf ("Date A: %s\n", buffer);
966 strftime (buffer, sizeof (buffer), "%F %R", localtime (&f->date_m));
967 Qprintf ("Date M: %s\n", buffer);
968 strftime (buffer, sizeof (buffer), "%F %R", localtime (&f->date_r));
969 Qprintf ("Date R: %s\n", buffer);
972 Qprintf ("Data Streams:\n");
973 list_for_each (item, &file->data) {
974 struct data *d = list_entry (item, struct data, list);
975 Qprintf ("Name: %s\n", (d->name) ? d->name : "<unnamed>");
977 if (d->resident) Qprintf ("Resident\n");
978 if (d->compressed) Qprintf ("Compressed\n");
979 if (d->encrypted) Qprintf ("Encrypted\n");
980 if (!d->resident && !d->compressed && !d->encrypted)
985 Qprintf ("Size alloc: %lld\n", d->size_alloc);
986 Qprintf ("Size data: %lld\n", d->size_data);
987 Qprintf ("Size init: %lld\n", d->size_init);
988 Qprintf ("Size vcn: %lld\n", d->size_vcn);
990 Qprintf ("Data runs:\n");
991 if ((!d->runlist) || (d->runlist[0].length <= 0)) {
994 for (i = 0; d->runlist[i].length > 0; i++) {
995 Qprintf (" %lld @ %lld\n", d->runlist[i].length, d->runlist[i].lcn);
999 Qprintf ("Amount potentially recoverable %d%%\n", d->percent);
1002 Qprintf ("________________________________________\n\n");
1006 * list_record - Print a one line summary of the file
1007 * @file: The file to work with
1009 * Print a one line description of a file.
1011 * Inode Flags %age Date Size Filename
1013 * The output will contain the file's inode number (MFT Record), some flags,
1014 * the percentage of the file that is recoverable, the last modification date,
1015 * the size and the filename.
1017 * The flags are F/D = File/Directory, N/R = Data is (Non-)Resident,
1018 * C = Compressed, E = Encrypted, ! = Metadata may span multiple records.
1020 * N.B. The file size is stored in many forms in several attributes. This
1021 * display the largest it finds.
1023 * N.B. If the filename is missing, or couldn't be converted to the current
1024 * locale, "<none>" will be displayed.
1028 void list_record (struct ufile *file)
1031 struct list_head *item;
1036 char flagd = '.', flagr = '.', flagc = '.', flagx = '.';
1038 strftime (buffer, sizeof (buffer), "%F", localtime (&file->date));
1040 if (file->attr_list)
1043 if (file->directory)
1048 list_for_each (item, &file->data) {
1049 struct data *d = list_entry (item, struct data, list);
1052 if (d->resident) flagr = 'R';
1054 if (d->compressed) flagc = 'C'; /* These two are mutually exclusive */
1055 if (d->encrypted) flagc = 'E';
1057 percent = max (percent, d->percent);
1060 size = max (size, d->size_data);
1061 size = max (size, d->size_init);
1064 if (file->pref_name)
1065 name = file->pref_name;
1069 Qprintf ("%-8lld %c%c%c%c %3d%% %s %9lld %s\n",
1070 file->inode, flagd, flagr, flagc, flagx,
1071 percent, buffer, size, name);
1075 * name_match - Does a file have a name matching a regex
1076 * @re: The regular expression object
1077 * @file: The file to be tested
1079 * Iterate through the file's $FILENAME attributes and compare them against the
1080 * regular expression, created with regcomp.
1082 * Return: 1 There is a matching filename.
1083 * 0 There is no match.
1085 int name_match (regex_t *re, struct ufile *file)
1087 struct list_head *item;
1093 list_for_each (item, &file->name) {
1094 struct filename *f = list_entry (item, struct filename, list);
1098 result = regexec (re, f->name, 0, NULL, 0);
1100 Eprintf ("Couldn't compare filename with regex: %s\n", strerror (errno));
1102 } else if (result == REG_NOERROR) {
1103 Dprintf ("Found a matching filename.\n");
1108 Dprintf ("Filename '%s' doesn't match regex.\n", file->pref_name);
1113 * write_data - Write out a block of data
1114 * @fd: File descriptor to write to
1115 * @buffer: Data to write
1116 * @bufsize: Amount of data to write
1118 * Write a block of data to a file descriptor.
1120 * Return: -1 Error, something went wrong
1121 * 0 Success, all the data was written
1123 unsigned int write_data (int fd, const char *buffer, unsigned int bufsize)
1125 ssize_t result1, result2;
1132 result1 = write (fd, buffer, bufsize);
1133 if ((result1 == (ssize_t) bufsize) || (result1 < 0))
1136 /* Try again with the rest of the buffer */
1140 result2 = write (fd, buffer, bufsize);
1144 return result1 + result2;
1148 * create_pathname - Create a path/file from some components
1149 * @dir: Directory in which to create the file (optional)
1150 * @name: Filename to give the file (optional)
1151 * @stream: Name of the stream (optional)
1152 * @buffer: Store the result here
1153 * @bufsize: Size of buffer
1155 * Create a filename from various pieces. The output will be of the form:
1161 * All the components are optional. If the name is missing, "unknown" will be
1162 * used. If the directory is missing the file will be created in the current
1163 * directory. If the stream name is present it will be appended to the
1164 * filename, delimited by a colon.
1166 * N.B. If the buffer isn't large enough the name will be truncated.
1168 * Return: n Length of the allocated name
1170 int create_pathname (const char *dir, const char *name, const char *stream,
1171 char *buffer, int bufsize)
1178 snprintf (buffer, bufsize, "%s/%s:%s", dir, name, stream);
1180 snprintf (buffer, bufsize, "%s/%s", dir, name);
1183 snprintf (buffer, bufsize, "%s:%s", name, stream);
1185 snprintf (buffer, bufsize, "%s", name);
1187 return strlen (buffer);
1191 * open_file - Open a file to write to
1192 * @pathname: Path, name and stream of the file to open
1194 * Create a file and return the file descriptor.
1196 * N.B. If option force is given and existing file will be overwritten.
1198 * Return: -1 Error, failed to create the file
1199 * n Success, this is the file descriptor
1201 int open_file (const char *pathname)
1205 Vprintf ("Creating file: %s\n", pathname);
1208 flags = O_RDWR | O_CREAT | O_TRUNC;
1210 flags = O_RDWR | O_CREAT | O_EXCL;
1212 return open (pathname, flags, S_IRUSR | S_IWUSR);
1216 * set_date - Set the file's date and time
1217 * @pathname: Path and name of the file to alter
1218 * @date: Date and time to set
1220 * Give a file a particular date and time.
1222 * Return: 1 Success, set the file's date and time
1223 * 0 Error, failed to change the file's date and time
1225 int set_date (const char *pathname, time_t date)
1234 if (utime (pathname, &ut)) {
1235 Eprintf ("Couldn't set the file's date and time\n");
1242 * scan_disk - Search an NTFS volume for files that could be undeleted
1243 * @vol: An ntfs volume obtained from ntfs_mount
1245 * Read through all the MFT entries looking for deleted files. For each one
1246 * determine how much of the data lies in unused disk space.
1248 * The list can be filtered by name, size and date, using command line options.
1250 * Return: -1 Error, something went wrong
1251 * n Success, the number of recoverable files
1253 int scan_disk (ntfs_volume *vol)
1255 const int BUFSIZE = 8192;
1256 char *buffer = NULL;
1270 attr = ntfs_attr_open (vol->mft_ni, AT_BITMAP, AT_UNNAMED, 0);
1272 Eprintf ("Couldn't open $MFT/$BITMAP: %s\n", strerror (errno));
1275 bmpsize = attr->initialized_size;
1277 buffer = malloc (BUFSIZE);
1279 Eprintf ("Couldn't allocate memory in scan_disk()\n");
1285 int flags = REG_NOSUB;
1287 if (!opts.match_case)
1289 if (regcomp (&re, opts.match, flags)) {
1290 Eprintf ("Couldn't create a regex.\n");
1295 Qprintf ("Inode Flags %%age Date Size Filename\n");
1296 Qprintf ("---------------------------------------------------------------\n");
1297 for (i = 0; i < bmpsize; i += BUFSIZE) {
1298 read = min ((bmpsize - i), BUFSIZE);
1299 size = ntfs_attr_pread (attr, i, read, buffer);
1303 for (j = 0; j < size; j++) {
1305 for (k = 0; k < 8; k++, b>>=1) {
1306 if (((i+j)*8+k) >= vol->nr_mft_records)
1310 file = read_record (vol, (i+j)*8+k);
1312 Eprintf ("Couldn't read MFT Record %d.\n", (i+j)*8+k);
1316 if ((opts.since > 0) && (file->date <= opts.since))
1318 if (opts.match && !name_match (&re, file))
1320 if (opts.size_begin && (opts.size_begin > file->max_size))
1322 if (opts.size_end && (opts.size_end < file->max_size))
1325 percent = calc_percentage (file, vol);
1327 if ((opts.percent == -1) || (percent >= opts.percent)) {
1334 if (((opts.percent == -1) && (percent > 0)) ||
1335 ((opts.percent > 0) && (percent >= opts.percent))) {
1344 Qprintf ("\nFiles with potentially recoverable content: %d\n", results);
1350 ntfs_attr_close (attr);
1355 * undelete_file - Recover a deleted file from an NTFS volume
1356 * @vol: An ntfs volume obtained from ntfs_mount
1357 * @inode: MFT Record number to be recovered
1359 * Read an MFT Record and try an recover any data associated with it. Some of
1360 * the clusters may be in use; these will be filled with zeros or the fill byte
1361 * supplied in the options.
1363 * Each data stream will be recovered and saved to a file. The file's name will
1364 * be the original filename and it will be written to the current directory.
1365 * Any named data stream will be saved as filename:streamname.
1367 * The output file's name and location can be altered by using the command line
1370 * N.B. We cannot tell if someone has overwritten some of the data since the
1373 * Return: 0 Error, something went wrong
1374 * 1 Success, the data was recovered
1376 int undelete_file (ntfs_volume *vol, long long inode)
1379 char *buffer = NULL;
1380 unsigned int bufsize;
1383 long long start, end;
1384 runlist_element *rl;
1385 struct list_head *item;
1393 file = read_record (vol, inode);
1394 if (!file || !file->mft) {
1395 Eprintf ("Can't read info from mft record %lld.\n", inode);
1399 bufsize = vol->cluster_size;
1400 buffer = malloc (bufsize);
1407 Qprintf ("Inode Flags %%age Date Size Filename\n");
1408 Qprintf ("---------------------------------------------------------------\n");
1413 if (file->mft->flags & MFT_RECORD_IN_USE) {
1414 Eprintf ("Record is in use by the mft\n");
1419 Vprintf ("Forced to continue.\n");
1422 if (calc_percentage (file, vol) == 0) {
1423 Qprintf ("File has no recoverable data.\n");
1427 if (list_empty (&file->data)) {
1428 Qprintf ("File has no data. There is nothing to recover.\n");
1432 list_for_each (item, &file->data) {
1433 struct data *d = list_entry (item, struct data, list);
1435 create_pathname (opts.dest, file->pref_name, d->name, pathname, sizeof (pathname));
1437 fd = open_file (pathname);
1439 Eprintf ("Couldn't create file: %s\n", strerror (errno));
1443 Vprintf ("File has resident data.\n");
1444 if (write_data (fd, d->data, d->size_data) < d->size_data) {
1445 Eprintf ("Write failed: %s\n", strerror (errno));
1450 if (close (fd) < 0) {
1451 Eprintf ("Close failed: %s\n", strerror (errno));
1457 Vprintf ("File has no runlist, hence no data.\n");
1461 if (rl[0].length <= 0) {
1462 Vprintf ("File has an empty runlist, hence no data.\n");
1466 fd = open_file (pathname);
1468 Eprintf ("Couldn't create output file: %s\n", strerror (errno));
1472 if (rl[0].lcn == LCN_RL_NOT_MAPPED) { /* extended mft record */
1473 Vprintf ("Missing segment at beginning, %lld clusters.\n", rl[0].length);
1474 memset (buffer, opts.fillbyte, bufsize);
1475 for (k = 0; k < rl[0].length * vol->cluster_size; k += bufsize) {
1476 if (write_data (fd, buffer, bufsize) < bufsize) {
1477 Eprintf ("Write failed: %s\n", strerror (errno));
1484 for (i = 0; rl[i].length > 0; i++) {
1486 if (rl[i].lcn == LCN_RL_NOT_MAPPED) {
1487 Vprintf ("Missing segment at end, %lld clusters.\n", rl[i].length);
1488 memset (buffer, opts.fillbyte, bufsize);
1489 for (k = 0; k < rl[k].length * vol->cluster_size; k += bufsize) {
1490 if (write_data (fd, buffer, bufsize) < bufsize) {
1491 Eprintf ("Write failed: %s\n", strerror (errno));
1499 if (rl[i].lcn == LCN_HOLE) {
1500 Vprintf ("File has a sparse section.\n");
1501 memset (buffer, 0, bufsize);
1502 for (k = 0; k < rl[k].length * vol->cluster_size; k += bufsize) {
1503 if (write_data (fd, buffer, bufsize) < bufsize) {
1504 Eprintf ("Write failed: %s\n", strerror (errno));
1513 end = rl[i].lcn + rl[i].length;
1515 for (j = start; j < end; j++) {
1516 if (utils_cluster_in_use (vol, j)) {
1517 memset (buffer, opts.fillbyte, bufsize);
1518 if (write_data (fd, buffer, bufsize) < bufsize) {
1519 Eprintf ("Write failed: %s\n", strerror (errno));
1524 if (ntfs_cluster_read(vol, j, 1, buffer) < 1) {
1525 Eprintf ("Read failed: %s\n", strerror (errno));
1529 if (write_data (fd, buffer, bufsize) < bufsize) {
1530 Eprintf ("Write failed: %s\n", strerror (errno));
1538 if (close (fd) < 0) {
1539 Eprintf ("Close failed: %s\n", strerror (errno));
1544 set_date (pathname, file->date);
1546 Qprintf ("Undeleted '%s:%s' successfully.\n", file->pref_name, d->name);
1548 Qprintf ("Undeleted '%s' successfully.\n", file->pref_name);
1559 * copy_mft - Write a range of MFT Records to a file
1560 * @vol: An ntfs volume obtained from ntfs_mount
1561 * @mft_begin: First MFT Record to save
1562 * @mft_end: Last MFT Record to save
1564 * Read a number of MFT Records and write them to a file.
1566 * Return: 0 Success, all the records were written
1567 * 1 Error, something went wrong
1569 int copy_mft (ntfs_volume *vol, long long mft_begin, long long mft_end)
1582 if (mft_end < mft_begin) {
1583 Eprintf ("Range to copy is backwards.\n");
1587 buffer = malloc (vol->mft_record_size);
1589 Eprintf ("Couldn't allocate memory in copy_mft()\n");
1593 mft = ntfs_attr_open (vol->mft_ni, AT_DATA, NULL, 0);
1595 Eprintf ("Couldn't open $MFT/$DATA: %s\n", strerror (errno));
1602 Dprintf ("No output filename, defaulting to '%s'.\n", name);
1605 create_pathname (opts.dest, name, NULL, pathname, sizeof (pathname));
1606 fd = open_file (pathname);
1608 Eprintf ("Couldn't open output file '%s': %s\n", name, strerror (errno));
1612 mft_end = min (mft_end, vol->nr_mft_records - 1);
1614 Dprintf ("MFT records\n");
1615 Dprintf (" Total: %8lld\n", vol->nr_mft_records);
1616 Dprintf (" Begin: %8lld\n", mft_begin);
1617 Dprintf (" End: %8lld\n", mft_end);
1619 for (i = mft_begin; i <= mft_end; i++) {
1620 if (ntfs_attr_pread (mft, vol->mft_record_size * i, vol->mft_record_size, buffer) < vol->mft_record_size) {
1621 Eprintf ("Couldn't read MFT Record %lld: %s.\n", i, strerror (errno));
1625 if (write_data (fd, buffer, vol->mft_record_size) < vol->mft_record_size) {
1626 Eprintf ("Write failed: %s\n", strerror (errno));
1631 Vprintf ("Read %lld MFT Records\n", mft_end - mft_begin + 1);
1636 ntfs_attr_close (mft);
1647 * Return: 0 Success, the program worked
1648 * 1 Error, something went wrong
1650 int main (int argc, char *argv[])
1655 if (!parse_options (argc, argv))
1660 vol = utils_mount_volume (opts.device, MS_RDONLY, opts.force);
1664 switch (opts.mode) {
1666 result = !scan_disk (vol);
1668 Vprintf ("Failed to scan device '%s'.\n", opts.device);
1671 result = !undelete_file (vol, opts.uinode);
1673 Vprintf ("Failed to undelete inode %d.\n", opts.uinode);
1676 result = !copy_mft (vol, opts.mft_begin, opts.mft_end);
1678 Vprintf ("Failed to read MFT blocks %lld-%lld.\n",
1679 opts.mft_begin, min (vol->nr_mft_records, opts.mft_end));
1682 ; /* Cannot happen */
1685 ntfs_umount (vol, FALSE);