ntfsundelete.c revision 9663:ace9a2ac3683
1/**
2 * ntfsundelete - Part of the Linux-NTFS project.
3 *
4 * Copyright (c) 2002-2005 Richard Russon
5 * Copyright (c) 2004-2005 Holger Ohmacht
6 * Copyright (c) 2005      Anton Altaparmakov
7 * Copyright (c) 2007      Yura Pakhuchiy
8 *
9 * This utility will recover deleted files from an NTFS volume.
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program (in the main directory of the Linux-NTFS
23 * distribution in the file COPYING); if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
25 */
26
27#include "config.h"
28
29#ifdef HAVE_FEATURES_H
30#include <features.h>
31#endif
32#ifdef HAVE_STDIO_H
33#include <stdio.h>
34#endif
35#ifdef HAVE_STDLIB_H
36#include <stdlib.h>
37#endif
38#ifdef HAVE_STRING_H
39#include <string.h>
40#endif
41#ifdef HAVE_ERRNO_H
42#include <errno.h>
43#endif
44#ifdef HAVE_SYS_TYPES_H
45#include <sys/types.h>
46#endif
47#ifdef HAVE_SYS_STAT_H
48#include <sys/stat.h>
49#endif
50#ifdef HAVE_UNISTD_H
51#include <unistd.h>
52#endif
53#ifdef HAVE_FCNTL_H
54#include <fcntl.h>
55#endif
56#ifdef HAVE_GETOPT_H
57#include <getopt.h>
58#endif
59#ifdef HAVE_TIME_H
60#include <time.h>
61#endif
62#ifdef HAVE_LIMITS_H
63#include <limits.h>
64#endif
65#ifdef HAVE_STDARG_H
66#include <stdarg.h>
67#endif
68#ifdef HAVE_UTIME_H
69#include <utime.h>
70#endif
71#include <regex.h>
72
73#if !defined(REG_NOERROR) || (REG_NOERROR != 0)
74#define REG_NOERROR 0
75#endif
76
77#include "ntfsundelete.h"
78#include "bootsect.h"
79#include "mft.h"
80#include "attrib.h"
81#include "layout.h"
82#include "inode.h"
83#include "device.h"
84#include "utils.h"
85#include "debug.h"
86#include "ntfstime.h"
87#include "version.h"
88#include "logging.h"
89
90static const char *EXEC_NAME = "ntfsundelete";
91static const char *MFTFILE   = "mft";
92static const char *UNNAMED   = "<unnamed>";
93static const char *NONE      = "<none>";
94static const char *UNKNOWN   = "unknown";
95static struct options opts;
96
97typedef struct
98{
99	u32 begin;
100	u32 end;
101} range;
102
103static short	with_regex;			/* Flag  Regular expression available */
104static short	avoid_duplicate_printing;	/* Flag  No duplicate printing of file infos */
105static range	*ranges;			/* Array containing all Inode-Ranges for undelete */
106static long	nr_entries;			/* Number of range entries */
107
108/**
109 * parse_inode_arg - parses the inode expression
110 *
111 * Parses the optarg after parameter -u for valid ranges
112 *
113 * Return: Number of correct inode specifications or -1 for error
114 */
115static int parse_inode_arg(void)
116{
117	int p;
118	u32 imax;
119	u32 range_begin;
120	u32 range_end;
121	u32 range_temp;
122	u32 inode;
123	char *opt_arg_ptr;
124	char *opt_arg_temp;
125	char *opt_arg_end1;
126	char *opt_arg_end2;
127
128	/* Check whether optarg is available or not */
129	nr_entries = 0;
130	if (optarg == NULL)
131		return (0);	/* bailout if no optarg */
132
133	/* init variables */
134	p = strlen(optarg);
135	imax = p;
136	opt_arg_ptr = optarg;
137	opt_arg_end1 = optarg;
138	opt_arg_end2 = &(optarg[p]);
139
140	/* alloc mem for range table */
141	ranges = (range *) malloc((p + 1) * sizeof(range));
142	if (ranges == NULL) {
143		ntfs_log_error("ERROR: Couldn't alloc mem for parsing inodes!\n");
144		return (-1);
145	}
146
147	/* loop */
148	while ((opt_arg_end1 != opt_arg_end2) && (p > 0)) {
149		/* Try to get inode */
150		inode = strtoul(opt_arg_ptr, &opt_arg_end1, 0);
151		p--;
152
153		/* invalid char at begin */
154		if ((opt_arg_ptr == opt_arg_end1) || (opt_arg_ptr == opt_arg_end2)) {
155			ntfs_log_error("ERROR: Invalid Number: %s\n", opt_arg_ptr);
156			return (-1);
157		}
158
159		/* RANGE - Check for range */
160		if (opt_arg_end1[0] == '-') {
161			/* get range end */
162			opt_arg_temp = opt_arg_end1;
163			opt_arg_end1 = & (opt_arg_temp[1]);
164			if (opt_arg_temp >= opt_arg_end2) {
165				ntfs_log_error("ERROR: Missing range end!\n");
166				return (-1);
167			}
168			range_begin = inode;
169
170			/* get count */
171			range_end = strtoul(opt_arg_end1, &opt_arg_temp, 0);
172			if (opt_arg_temp == opt_arg_end1) {
173				ntfs_log_error("ERROR: Invalid Number: %s\n", opt_arg_temp);
174				return (-1);
175			}
176
177			/* check for correct values */
178			if (range_begin > range_end) {
179				range_temp = range_end;
180				range_end = range_begin;
181				range_begin = range_temp;
182			}
183
184			/* put into struct */
185			ranges[nr_entries].begin = range_begin;
186			ranges[nr_entries].end = range_end;
187			nr_entries++;
188
189			/* Last check */
190			opt_arg_ptr = & (opt_arg_temp[1]);
191			if (opt_arg_ptr >= opt_arg_end2)
192				break;
193		} else if (opt_arg_end1[0] == ',') {
194			/* SINGLE VALUE, BUT CONTINUING */
195			/* put inode into range list */
196			ranges[nr_entries].begin = inode;
197			ranges[nr_entries].end = inode;
198			nr_entries++;
199
200			/* Next inode */
201			opt_arg_ptr = & (opt_arg_end1[1]);
202			if (opt_arg_ptr >= opt_arg_end2) {
203				ntfs_log_error("ERROR: Missing new value at end of input!\n");
204				return (-1);
205			}
206			continue;
207		} else { /* SINGLE VALUE, END */
208			ranges[nr_entries].begin = inode;
209			ranges[nr_entries].end = inode;
210			nr_entries++;
211		}
212	}
213	return (nr_entries);
214}
215
216/**
217 * version - Print version information about the program
218 *
219 * Print a copyright statement and a brief description of the program.
220 *
221 * Return:  none
222 */
223static void version(void)
224{
225	ntfs_log_info("\n%s v%s (libntfs %s) - Recover deleted files from an "
226			"NTFS Volume.\n\n", EXEC_NAME, VERSION,
227			ntfs_libntfs_version());
228	ntfs_log_info("Copyright (c) 2002-2005 Richard Russon\n"
229			"Copyright (c) 2004-2005 Holger Ohmacht\n"
230			"Copyright (c) 2005      Anton Altaparmakov\n"
231			"Copyright (c) 2007      Yura Pakhuchiy\n");
232	ntfs_log_info("\n%s\n%s%s\n", ntfs_gpl, ntfs_bugs, ntfs_home);
233}
234
235/**
236 * usage - Print a list of the parameters to the program
237 *
238 * Print a list of the parameters and options for the program.
239 *
240 * Return:  none
241 */
242static void usage(void)
243{
244	ntfs_log_info("\nUsage: %s [options] device\n"
245		"    -s, --scan             Scan for files (default)\n"
246		"    -p, --percentage NUM   Minimum percentage recoverable\n"
247		"    -m, --match PATTERN    Only work on files with matching names\n"
248		"    -C, --case             Case sensitive matching\n"
249		"    -S, --size RANGE       Match files of this size\n"
250		"    -t, --time SINCE       Last referenced since this time\n"
251		"\n"
252		"    -u, --undelete         Undelete mode\n"
253		"    -i, --inodes RANGE     Recover these inodes\n"
254		//"    -I, --interactive      Interactive mode\n"
255		"    -o, --output FILE      Save with this filename\n"
256		"    -O, --optimistic       Undelete in-use clusters as well\n"
257		"    -d, --destination DIR  Destination directory\n"
258		"    -b, --byte NUM         Fill missing parts with this byte\n"
259		"    -T, --truncate         Truncate 100%% recoverable file to exact size.\n"
260		"    -P, --parent           Show parent directory\n"
261		"\n"
262		"    -c, --copy RANGE       Write a range of MFT records to a file\n"
263		"\n"
264		"    -f, --force            Use less caution\n"
265		"    -q, --quiet            Less output\n"
266		"    -v, --verbose          More output\n"
267		"    -V, --version          Display version information\n"
268		"    -h, --help             Display this help\n\n",
269		EXEC_NAME);
270	ntfs_log_info("%s%s\n", ntfs_bugs, ntfs_home);
271}
272
273/**
274 * transform - Convert a shell style pattern to a regex
275 * @pattern:  String to be converted
276 * @regex:    Resulting regular expression is put here
277 *
278 * This will transform patterns, such as "*.doc" to true regular expressions.
279 * The function will also place '^' and '$' around the expression to make it
280 * behave as the user would expect
281 *
282 * Before  After
283 *   .       \.
284 *   *       .*
285 *   ?       .
286 *
287 * Notes:
288 *     The returned string must be freed by the caller.
289 *     If transform fails, @regex will not be changed.
290 *
291 * Return:  1, Success, the string was transformed
292 *	    0, An error occurred
293 */
294static int transform(const char *pattern, char **regex)
295{
296	char *result;
297	int length, i, j;
298
299	if (!pattern || !regex)
300		return 0;
301
302	length = strlen(pattern);
303	if (length < 1) {
304		ntfs_log_error("Pattern to transform is empty\n");
305		return 0;
306	}
307
308	for (i = 0; pattern[i]; i++) {
309		if ((pattern[i] == '*') || (pattern[i] == '.'))
310			length++;
311	}
312
313	result = malloc(length + 3);
314	if (!result) {
315		ntfs_log_error("Couldn't allocate memory in transform()\n");
316		return 0;
317	}
318
319	result[0] = '^';
320
321	for (i = 0, j = 1; pattern[i]; i++, j++) {
322		if (pattern[i] == '*') {
323			result[j] = '.';
324			j++;
325			result[j] = '*';
326		} else if (pattern[i] == '.') {
327			result[j] = '\\';
328			j++;
329			result[j] = '.';
330		} else if (pattern[i] == '?') {
331			result[j] = '.';
332		} else {
333			result[j] = pattern[i];
334		}
335	}
336
337	result[j]   = '$';
338	result[j+1] = 0;
339	ntfs_log_debug("Pattern '%s' replaced with regex '%s'.\n", pattern,
340			result);
341
342	*regex = result;
343	return 1;
344}
345
346/**
347 * parse_time - Convert a time abbreviation to seconds
348 * @string:  The string to be converted
349 * @since:   The absolute time referred to
350 *
351 * Strings representing times will be converted into a time_t.  The numbers will
352 * be regarded as seconds unless suffixed.
353 *
354 * Suffix  Description
355 *  [yY]      Year
356 *  [mM]      Month
357 *  [wW]      Week
358 *  [dD]      Day
359 *  [sS]      Second
360 *
361 * Therefore, passing "1W" will return the time_t representing 1 week ago.
362 *
363 * Notes:
364 *     Only the first character of the suffix is read.
365 *     If parse_time fails, @since will not be changed
366 *
367 * Return:  1  Success
368 *	    0  Error, the string was malformed
369 */
370static int parse_time(const char *value, time_t *since)
371{
372	long long result;
373	time_t now;
374	char *suffix = NULL;
375
376	if (!value || !since)
377		return -1;
378
379	ntfs_log_trace("Parsing time '%s' ago.\n", value);
380
381	result = strtoll(value, &suffix, 10);
382	if (result < 0 || errno == ERANGE) {
383		ntfs_log_error("Invalid time '%s'.\n", value);
384		return 0;
385	}
386
387	if (!suffix) {
388		ntfs_log_error("Internal error, strtoll didn't return a suffix.\n");
389		return 0;
390	}
391
392	if (strlen(suffix) > 1) {
393		ntfs_log_error("Invalid time suffix '%s'.  Use Y, M, W, D or H.\n", suffix);
394		return 0;
395	}
396
397	switch (suffix[0]) {
398		case 'y': case 'Y': result *=   12;
399		case 'm': case 'M': result *=    4;
400		case 'w': case 'W': result *=    7;
401		case 'd': case 'D': result *=   24;
402		case 'h': case 'H': result *= 3600;
403		case 0:
404		    break;
405
406		default:
407			ntfs_log_error("Invalid time suffix '%s'.  Use Y, M, W, D or H.\n", suffix);
408			return 0;
409	}
410
411	now = time(NULL);
412
413	ntfs_log_debug("Time now = %lld, Time then = %lld.\n", (long long) now,
414			(long long) result);
415	*since = now - result;
416	return 1;
417}
418
419/**
420 * parse_options - Read and validate the programs command line
421 *
422 * Read the command line, verify the syntax and parse the options.
423 * This function is very long, but quite simple.
424 *
425 * Return:  1 Success
426 *	    0 Error, one or more problems
427 */
428static int parse_options(int argc, char *argv[])
429{
430	static const char *sopt = "-b:Cc:d:fh?i:m:o:OPp:sS:t:TuqvV";
431	static const struct option lopt[] = {
432		{ "byte",	 required_argument,	NULL, 'b' },
433		{ "case",	 no_argument,		NULL, 'C' },
434		{ "copy",	 required_argument,	NULL, 'c' },
435		{ "destination", required_argument,	NULL, 'd' },
436		{ "force",	 no_argument,		NULL, 'f' },
437		{ "help",	 no_argument,		NULL, 'h' },
438		{ "inodes",	 required_argument,	NULL, 'i' },
439		//{ "interactive", no_argument,		NULL, 'I' },
440		{ "match",	 required_argument,	NULL, 'm' },
441		{ "optimistic",  no_argument,		NULL, 'O' },
442		{ "output",	 required_argument,	NULL, 'o' },
443		{ "parent",	 no_argument,		NULL, 'P' },
444		{ "percentage",  required_argument,	NULL, 'p' },
445		{ "quiet",	 no_argument,		NULL, 'q' },
446		{ "scan",	 no_argument,		NULL, 's' },
447		{ "size",	 required_argument,	NULL, 'S' },
448		{ "time",	 required_argument,	NULL, 't' },
449		{ "truncate",	 no_argument,		NULL, 'T' },
450		{ "undelete",	 no_argument,		NULL, 'u' },
451		{ "verbose",	 no_argument,		NULL, 'v' },
452		{ "version",	 no_argument,		NULL, 'V' },
453		{ NULL, 0, NULL, 0 }
454	};
455
456	int c = -1;
457	char *end = NULL;
458	int err  = 0;
459	int ver  = 0;
460	int help = 0;
461	int levels = 0;
462
463	opterr = 0; /* We'll handle the errors, thank you. */
464
465	opts.mode     = MODE_NONE;
466	opts.uinode   = -1;
467	opts.percent  = -1;
468	opts.fillbyte = -1;
469	while ((c = getopt_long(argc, argv, sopt, lopt, NULL)) != -1) {
470		switch (c) {
471		case 1:	/* A non-option argument */
472			if (!opts.device) {
473				opts.device = argv[optind-1];
474			} else {
475				opts.device = NULL;
476				err++;
477			}
478			break;
479		case 'b':
480			if (opts.fillbyte == (char)-1) {
481				end = NULL;
482				opts.fillbyte = strtol(optarg, &end, 0);
483				if (end && *end)
484					err++;
485			} else {
486				err++;
487			}
488			break;
489		case 'C':
490			opts.match_case++;
491			break;
492		case 'c':
493			if (opts.mode == MODE_NONE) {
494				if (!utils_parse_range(optarg,
495				    &opts.mft_begin, &opts.mft_end, TRUE))
496					err++;
497				opts.mode = MODE_COPY;
498			} else {
499				opts.mode = MODE_ERROR;
500			}
501			break;
502		case 'd':
503			if (!opts.dest)
504				opts.dest = optarg;
505			else
506				err++;
507			break;
508		case 'f':
509			opts.force++;
510			break;
511		case 'h':
512		case '?':
513			if (ntfs_log_parse_option (argv[optind-1]))
514				break;
515			help++;
516			break;
517		case 'i':
518			end = NULL;
519			/* parse inodes */
520			if (parse_inode_arg() == -1)
521				err++;
522			if (end && *end)
523				err++;
524			break;
525		case 'm':
526			if (!opts.match) {
527				if (!transform(optarg, &opts.match)) {
528					err++;
529				} else {
530					/* set regex-flag on true ;) */
531					with_regex= 1;
532				}
533			} else {
534				err++;
535			}
536			break;
537		case 'o':
538			if (!opts.output) {
539				opts.output = optarg;
540			} else {
541				err++;
542			}
543			break;
544		case 'O':
545			if (!opts.optimistic) {
546				opts.optimistic++;
547			} else {
548				err++;
549			}
550			break;
551		case 'P':
552			if (!opts.parent) {
553				opts.parent++;
554			} else {
555				err++;
556			}
557			break;
558		case 'p':
559			if (opts.percent == -1) {
560				end = NULL;
561				opts.percent = strtol(optarg, &end, 0);
562				if (end && ((*end != '%') && (*end != 0)))
563					err++;
564			} else {
565				err++;
566			}
567			break;
568		case 'q':
569			opts.quiet++;
570			ntfs_log_clear_levels(NTFS_LOG_LEVEL_QUIET);
571			break;
572		case 's':
573			if (opts.mode == MODE_NONE)
574				opts.mode = MODE_SCAN;
575			else
576				opts.mode = MODE_ERROR;
577			break;
578		case 'S':
579			if ((opts.size_begin > 0) || (opts.size_end > 0) ||
580			    !utils_parse_range(optarg, &opts.size_begin,
581			     &opts.size_end, TRUE)) {
582			    err++;
583			}
584			break;
585		case 't':
586			if (opts.since == 0) {
587				if (!parse_time(optarg, &opts.since))
588					err++;
589			} else {
590			    err++;
591			}
592			break;
593		case 'T':
594			opts.truncate++;
595			break;
596		case 'u':
597			if (opts.mode == MODE_NONE) {
598				opts.mode = MODE_UNDELETE;
599			} else {
600				opts.mode = MODE_ERROR;
601			}
602			break;
603		case 'v':
604			opts.verbose++;
605			ntfs_log_set_levels(NTFS_LOG_LEVEL_VERBOSE);
606			break;
607		case 'V':
608			ver++;
609			break;
610		default:
611			if (((optopt == 'b') || (optopt == 'c') ||
612			     (optopt == 'd') || (optopt == 'm') ||
613			     (optopt == 'o') || (optopt == 'p') ||
614			     (optopt == 'S') || (optopt == 't') ||
615			     (optopt == 'u')) && (!optarg)) {
616				ntfs_log_error("Option '%s' requires an argument.\n", argv[optind-1]);
617			} else {
618				ntfs_log_error("Unknown option '%s'.\n", argv[optind-1]);
619			}
620			err++;
621			break;
622		}
623	}
624
625	/* Make sure we're in sync with the log levels */
626	levels = ntfs_log_get_levels();
627	if (levels & NTFS_LOG_LEVEL_VERBOSE)
628		opts.verbose++;
629	if (!(levels & NTFS_LOG_LEVEL_QUIET))
630		opts.quiet++;
631
632	if (help || ver) {
633		opts.quiet = 0;
634	} else {
635		if (opts.device == NULL) {
636			if (argc > 1)
637				ntfs_log_error("You must specify exactly one device.\n");
638			err++;
639		}
640
641		if (opts.mode == MODE_NONE) {
642			opts.mode = MODE_SCAN;
643		}
644
645		switch (opts.mode) {
646		case MODE_SCAN:
647			if (opts.output || opts.dest || opts.truncate ||
648					(opts.fillbyte != (char)-1)) {
649				ntfs_log_error("Scan can only be used with --percent, "
650					"--match, --ignore-case, --size and --time.\n");
651				err++;
652			}
653			if (opts.match_case && !opts.match) {
654				ntfs_log_error("The --case option doesn't make sense without the --match option\n");
655				err++;
656			}
657			break;
658
659		case MODE_UNDELETE:
660			/*if ((opts.percent != -1) || (opts.size_begin > 0) || (opts.size_end > 0)) {
661				ntfs_log_error("Undelete can only be used with "
662					"--output, --destination, --byte and --truncate.\n");
663				err++;
664			}*/
665			break;
666		case MODE_COPY:
667			if ((opts.fillbyte != (char)-1) || opts.truncate ||
668			    (opts.percent != -1) ||
669			    opts.match || opts.match_case ||
670			    (opts.size_begin > 0) ||
671			    (opts.size_end > 0)) {
672				ntfs_log_error("Copy can only be used with --output and --destination.\n");
673				err++;
674			}
675			break;
676		default:
677			ntfs_log_error("You can only select one of Scan, Undelete or Copy.\n");
678			err++;
679		}
680
681		if ((opts.percent < -1) || (opts.percent > 100)) {
682			ntfs_log_error("Percentage value must be in the range 0 - 100.\n");
683			err++;
684		}
685
686		if (opts.quiet) {
687			if (opts.verbose) {
688				ntfs_log_error("You may not use --quiet and --verbose at the same time.\n");
689				err++;
690			} else if (opts.mode == MODE_SCAN) {
691				ntfs_log_error("You may not use --quiet when scanning a volume.\n");
692				err++;
693			}
694		}
695
696		if (opts.parent && !opts.verbose) {
697			ntfs_log_error("To use --parent, you must also use --verbose.\n");
698			err++;
699		}
700	}
701
702	if (opts.fillbyte == (char)-1)
703		opts.fillbyte = 0;
704
705	if (ver)
706		version();
707	if (help || err)
708		usage();
709
710	return (!err && !help && !ver);
711}
712
713/**
714 * free_file - Release the resources used by a file object
715 * @file:  The unwanted file object
716 *
717 * This will free up the memory used by a file object and iterate through the
718 * object's children, freeing their resources too.
719 *
720 * Return:  none
721 */
722static void free_file(struct ufile *file)
723{
724	struct list_head *item, *tmp;
725
726	if (!file)
727		return;
728
729	list_for_each_safe(item, tmp, &file->name) { /* List of filenames */
730		struct filename *f = list_entry(item, struct filename, list);
731		ntfs_log_debug("freeing filename '%s'", f->name ? f->name :
732				NONE);
733		if (f->name)
734			free(f->name);
735		if (f->parent_name) {
736			ntfs_log_debug(" and parent filename '%s'",
737					f->parent_name);
738			free(f->parent_name);
739		}
740		ntfs_log_debug(".\n");
741		free(f);
742	}
743
744	list_for_each_safe(item, tmp, &file->data) { /* List of data streams */
745		struct data *d = list_entry(item, struct data, list);
746		ntfs_log_debug("Freeing data stream '%s'.\n", d->name ?
747				d->name : UNNAMED);
748		if (d->name)
749			free(d->name);
750		if (d->runlist)
751			free(d->runlist);
752		free(d);
753	}
754
755	free(file->mft);
756	free(file);
757}
758
759/**
760 * verify_parent - confirm a record is parent of a file
761 * @name:	a filename of the file
762 * @rec:	the mft record of the possible parent
763 *
764 * Check that @rec is the parent of the file represented by @name.
765 * If @rec is a directory, but it is created after @name, then we
766 * can't determine whether @rec is really @name's parent.
767 *
768 * Return:	@rec's filename, either same name space as @name or lowest space.
769 *		NULL if can't determine parenthood or on error.
770 */
771static FILE_NAME_ATTR* verify_parent(struct filename* name, MFT_RECORD* rec)
772{
773	ATTR_RECORD *attr30;
774	FILE_NAME_ATTR *filename_attr = NULL, *lowest_space_name = NULL;
775	ntfs_attr_search_ctx *ctx;
776	int found_same_space = 1;
777
778	if (!name || !rec)
779		return NULL;
780
781	if (!(rec->flags & MFT_RECORD_IS_DIRECTORY)) {
782		return NULL;
783	}
784
785	ctx = ntfs_attr_get_search_ctx(NULL, rec);
786	if (!ctx) {
787		ntfs_log_error("ERROR: Couldn't create a search context.\n");
788		return NULL;
789	}
790
791	attr30 = find_attribute(AT_FILE_NAME, ctx);
792	if (!attr30) {
793		return NULL;
794	}
795
796	filename_attr = (FILE_NAME_ATTR*)((char*)attr30 + le16_to_cpu(attr30->u.res.value_offset));
797	/* if name is older than this dir -> can't determine */
798	if (ntfs2utc(filename_attr->creation_time) > name->date_c) {
799		return NULL;
800	}
801
802	if (filename_attr->file_name_type != name->name_space) {
803		found_same_space = 0;
804		lowest_space_name = filename_attr;
805
806		while (!found_same_space && (attr30 = find_attribute(AT_FILE_NAME, ctx))) {
807			filename_attr = (FILE_NAME_ATTR*)((char*)attr30 + le16_to_cpu(attr30->u.res.value_offset));
808
809			if (filename_attr->file_name_type == name->name_space) {
810				found_same_space = 1;
811			} else {
812				if (filename_attr->file_name_type < lowest_space_name->file_name_type) {
813					lowest_space_name = filename_attr;
814				}
815			}
816		}
817	}
818
819	ntfs_attr_put_search_ctx(ctx);
820
821	return (found_same_space ? filename_attr : lowest_space_name);
822}
823
824/**
825 * get_parent_name - Find the name of a file's parent.
826 * @name:	the filename whose parent's name to find
827 */
828static void get_parent_name(struct filename* name, ntfs_volume* vol)
829{
830	ntfs_attr* mft_data;
831	MFT_RECORD* rec;
832	FILE_NAME_ATTR* filename_attr;
833	long long inode_num;
834
835	if (!name || !vol)
836		return;
837
838	rec = calloc(1, vol->mft_record_size);
839	if (!rec) {
840		ntfs_log_error("ERROR: Couldn't allocate memory in "
841				"get_parent_name()\n");
842		return;
843	}
844
845	mft_data = ntfs_attr_open(vol->mft_ni, AT_DATA, AT_UNNAMED, 0);
846	if (!mft_data) {
847		ntfs_log_perror("ERROR: Couldn't open $MFT/$DATA");
848	} else {
849		inode_num = MREF_LE(name->parent_mref);
850
851		if (ntfs_attr_pread(mft_data, vol->mft_record_size * inode_num,
852					vol->mft_record_size, rec) < 1) {
853			ntfs_log_error("ERROR: Couldn't read MFT Record %lld"
854					".\n", inode_num);
855		} else if ((filename_attr = verify_parent(name, rec))) {
856			if (ntfs_ucstombs(filename_attr->file_name,
857					filename_attr->file_name_length,
858					&name->parent_name, 0) < 0) {
859				ntfs_log_debug("ERROR: Couldn't translate "
860						"filename to current "
861						"locale.\n");
862				name->parent_name = NULL;
863			}
864		}
865	}
866
867	if (mft_data) {
868		ntfs_attr_close(mft_data);
869	}
870
871	if (rec) {
872		free(rec);
873	}
874
875	return;
876}
877
878/**
879 * get_filenames - Read an MFT Record's $FILENAME attributes
880 * @file:  The file object to work with
881 *
882 * A single file may have more than one filename.  This is quite common.
883 * Windows creates a short DOS name for each long name, e.g. LONGFI~1.XYZ,
884 * LongFiLeName.xyZ.
885 *
886 * The filenames that are found are put in filename objects and added to a
887 * linked list of filenames in the file object.  For convenience, the unicode
888 * filename is converted into the current locale and stored in the filename
889 * object.
890 *
891 * One of the filenames is picked (the one with the lowest numbered namespace)
892 * and its locale friendly name is put in pref_name.
893 *
894 * Return:  n  The number of $FILENAME attributes found
895 *	   -1  Error
896 */
897static int get_filenames(struct ufile *file, ntfs_volume* vol)
898{
899	ATTR_RECORD *rec;
900	FILE_NAME_ATTR *attr;
901	ntfs_attr_search_ctx *ctx;
902	struct filename *name;
903	int count = 0;
904	int space = 4;
905
906	if (!file)
907		return -1;
908
909	ctx = ntfs_attr_get_search_ctx(NULL, file->mft);
910	if (!ctx)
911		return -1;
912
913	while ((rec = find_attribute(AT_FILE_NAME, ctx))) {
914		/* We know this will always be resident. */
915		attr = (FILE_NAME_ATTR *)((char *)rec +
916				le16_to_cpu(rec->u.res.value_offset));
917
918		name = calloc(1, sizeof(*name));
919		if (!name) {
920			ntfs_log_error("ERROR: Couldn't allocate memory in "
921					"get_filenames().\n");
922			count = -1;
923			break;
924		}
925
926		name->uname      = attr->file_name;
927		name->uname_len  = attr->file_name_length;
928		name->name_space = attr->file_name_type;
929		name->size_alloc = sle64_to_cpu(attr->allocated_size);
930		name->size_data  = sle64_to_cpu(attr->data_size);
931		name->flags      = attr->file_attributes;
932
933		name->date_c     = ntfs2utc(attr->creation_time);
934		name->date_a     = ntfs2utc(attr->last_data_change_time);
935		name->date_m     = ntfs2utc(attr->last_mft_change_time);
936		name->date_r     = ntfs2utc(attr->last_access_time);
937
938		if (ntfs_ucstombs(name->uname, name->uname_len, &name->name,
939				0) < 0) {
940			ntfs_log_debug("ERROR: Couldn't translate filename to "
941					"current locale.\n");
942		}
943
944		name->parent_name = NULL;
945
946		if (opts.parent) {
947			name->parent_mref = attr->parent_directory;
948			get_parent_name(name, vol);
949		}
950
951		if (name->name_space < space) {
952			file->pref_name = name->name;
953			file->pref_pname = name->parent_name;
954			space = name->name_space;
955		}
956
957		file->max_size = max(file->max_size, name->size_alloc);
958		file->max_size = max(file->max_size, name->size_data);
959
960		list_add_tail(&name->list, &file->name);
961		count++;
962	}
963
964	ntfs_attr_put_search_ctx(ctx);
965	ntfs_log_debug("File has %d names.\n", count);
966	return count;
967}
968
969/**
970 * get_data - Read an MFT Record's $DATA attributes
971 * @file:  The file object to work with
972 * @vol:  An ntfs volume obtained from ntfs_mount
973 *
974 * A file may have more than one data stream.  All files will have an unnamed
975 * data stream which contains the file's data.  Some Windows applications store
976 * extra information in a separate stream.
977 *
978 * The streams that are found are put in data objects and added to a linked
979 * list of data streams in the file object.
980 *
981 * Return:  n  The number of $FILENAME attributes found
982 *	   -1  Error
983 */
984static int get_data(struct ufile *file, ntfs_volume *vol)
985{
986	ATTR_RECORD *rec;
987	ntfs_attr_search_ctx *ctx;
988	int count = 0;
989	struct data *data;
990
991	if (!file)
992		return -1;
993
994	ctx = ntfs_attr_get_search_ctx(NULL, file->mft);
995	if (!ctx)
996		return -1;
997
998	while ((rec = find_attribute(AT_DATA, ctx))) {
999		data = calloc(1, sizeof(*data));
1000		if (!data) {
1001			ntfs_log_error("ERROR: Couldn't allocate memory in "
1002					"get_data().\n");
1003			count = -1;
1004			break;
1005		}
1006
1007		data->resident   = !rec->non_resident;
1008		data->compressed = (rec->flags & ATTR_IS_COMPRESSED) ? 1 : 0;
1009		data->encrypted  = (rec->flags & ATTR_IS_ENCRYPTED) ? 1 : 0;
1010
1011		if (rec->name_length) {
1012			data->uname = (ntfschar *)((char *)rec +
1013					le16_to_cpu(rec->name_offset));
1014			data->uname_len = rec->name_length;
1015
1016			if (ntfs_ucstombs(data->uname, data->uname_len,
1017						&data->name, 0) < 0) {
1018				ntfs_log_error("ERROR: Cannot translate name "
1019						"into current locale.\n");
1020			}
1021		}
1022
1023		if (data->resident) {
1024			data->size_data = le32_to_cpu(rec->u.res.value_length);
1025			data->data = (char*)rec +
1026				le16_to_cpu(rec->u.res.value_offset);
1027		} else {
1028			data->size_alloc = sle64_to_cpu(rec->u.nonres.allocated_size);
1029			data->size_data  = sle64_to_cpu(rec->u.nonres.data_size);
1030			data->size_init  = sle64_to_cpu(rec->u.nonres.initialized_size);
1031			data->size_vcn   = sle64_to_cpu(rec->u.nonres.highest_vcn) + 1;
1032		}
1033
1034		data->runlist = ntfs_mapping_pairs_decompress(vol, rec, NULL);
1035		if (!data->runlist) {
1036			ntfs_log_debug("Couldn't decompress the data runs.\n");
1037		}
1038
1039		file->max_size = max(file->max_size, data->size_data);
1040		file->max_size = max(file->max_size, data->size_init);
1041
1042		list_add_tail(&data->list, &file->data);
1043		count++;
1044	}
1045
1046	ntfs_attr_put_search_ctx(ctx);
1047	ntfs_log_debug("File has %d data streams.\n", count);
1048	return count;
1049}
1050
1051/**
1052 * read_record - Read an MFT record into memory
1053 * @vol:     An ntfs volume obtained from ntfs_mount
1054 * @record:  The record number to read
1055 *
1056 * Read the specified MFT record and gather as much information about it as
1057 * possible.
1058 *
1059 * Return:  Pointer  A ufile object containing the results
1060 *	    NULL     Error
1061 */
1062static struct ufile * read_record(ntfs_volume *vol, long long record)
1063{
1064	ATTR_RECORD *attr10, *attr20, *attr90;
1065	struct ufile *file;
1066	ntfs_attr *mft;
1067
1068	if (!vol)
1069		return NULL;
1070
1071	file = calloc(1, sizeof(*file));
1072	if (!file) {
1073		ntfs_log_error("ERROR: Couldn't allocate memory in read_record()\n");
1074		return NULL;
1075	}
1076
1077	INIT_LIST_HEAD(&file->name);
1078	INIT_LIST_HEAD(&file->data);
1079	file->inode = record;
1080
1081	file->mft = malloc(vol->mft_record_size);
1082	if (!file->mft) {
1083		ntfs_log_error("ERROR: Couldn't allocate memory in read_record()\n");
1084		free_file(file);
1085		return NULL;
1086	}
1087
1088	mft = ntfs_attr_open(vol->mft_ni, AT_DATA, AT_UNNAMED, 0);
1089	if (!mft) {
1090		ntfs_log_perror("ERROR: Couldn't open $MFT/$DATA");
1091		free_file(file);
1092		return NULL;
1093	}
1094
1095	if (ntfs_attr_mst_pread(mft, vol->mft_record_size * record, 1, vol->mft_record_size, file->mft) < 1) {
1096		ntfs_log_error("ERROR: Couldn't read MFT Record %lld.\n", record);
1097		ntfs_attr_close(mft);
1098		free_file(file);
1099		return NULL;
1100	}
1101
1102	ntfs_attr_close(mft);
1103	mft = NULL;
1104
1105	attr10 = find_first_attribute(AT_STANDARD_INFORMATION,	file->mft);
1106	attr20 = find_first_attribute(AT_ATTRIBUTE_LIST,	file->mft);
1107	attr90 = find_first_attribute(AT_INDEX_ROOT,		file->mft);
1108
1109	ntfs_log_debug("Attributes present: %s %s %s.\n", attr10?"0x10":"",
1110			attr20?"0x20":"", attr90?"0x90":"");
1111
1112	if (attr10) {
1113		STANDARD_INFORMATION *si;
1114		si = (STANDARD_INFORMATION *) ((char *) attr10 + le16_to_cpu(attr10->u.res.value_offset));
1115		file->date = ntfs2utc(si->last_data_change_time);
1116	}
1117
1118	if (attr20 || !attr10)
1119		file->attr_list = 1;
1120	if (attr90)
1121		file->directory = 1;
1122
1123	if (get_filenames(file, vol) < 0) {
1124		ntfs_log_error("ERROR: Couldn't get filenames.\n");
1125	}
1126	if (get_data(file, vol) < 0) {
1127		ntfs_log_error("ERROR: Couldn't get data streams.\n");
1128	}
1129
1130	return file;
1131}
1132
1133/**
1134 * calc_percentage - Calculate how much of the file is recoverable
1135 * @file:  The file object to work with
1136 * @vol:   An ntfs volume obtained from ntfs_mount
1137 *
1138 * Read through all the $DATA streams and determine if each cluster in each
1139 * stream is still free disk space.  This is just measuring the potential for
1140 * recovery.  The data may have still been overwritten by a another file which
1141 * was then deleted.
1142 *
1143 * Files with a resident $DATA stream will have a 100% potential.
1144 *
1145 * N.B.  If $DATA attribute spans more than one MFT record (i.e. badly
1146 *       fragmented) then only the data in this segment will be used for the
1147 *       calculation.
1148 *
1149 * N.B.  Currently, compressed and encrypted files cannot be recovered, so they
1150 *       will return 0%.
1151 *
1152 * Return:  n  The percentage of the file that _could_ be recovered
1153 *	   -1  Error
1154 */
1155static int calc_percentage(struct ufile *file, ntfs_volume *vol)
1156{
1157	runlist_element *rl = NULL;
1158	struct list_head *pos;
1159	struct data *data;
1160	long long i, j;
1161	long long start, end;
1162	int clusters_inuse, clusters_free;
1163	int percent = 0;
1164
1165	if (!file || !vol)
1166		return -1;
1167
1168	if (file->directory) {
1169		ntfs_log_debug("Found a directory: not recoverable.\n");
1170		return 0;
1171	}
1172
1173	if (list_empty(&file->data)) {
1174		ntfs_log_verbose("File has no data streams.\n");
1175		return 0;
1176	}
1177
1178	list_for_each(pos, &file->data) {
1179		data  = list_entry(pos, struct data, list);
1180		clusters_inuse = 0;
1181		clusters_free  = 0;
1182
1183		if (data->encrypted) {
1184			ntfs_log_verbose("File is encrypted, recovery is "
1185					"impossible.\n");
1186			continue;
1187		}
1188
1189		if (data->compressed) {
1190			ntfs_log_verbose("File is compressed, recovery not yet "
1191					"implemented.\n");
1192			continue;
1193		}
1194
1195		if (data->resident) {
1196			ntfs_log_verbose("File is resident, therefore "
1197					"recoverable.\n");
1198			percent = 100;
1199			data->percent = 100;
1200			continue;
1201		}
1202
1203		rl = data->runlist;
1204		if (!rl) {
1205			ntfs_log_verbose("File has no runlist, hence no data."
1206					"\n");
1207			continue;
1208		}
1209
1210		if (rl[0].length <= 0) {
1211			ntfs_log_verbose("File has an empty runlist, hence no "
1212					"data.\n");
1213			continue;
1214		}
1215
1216		if (rl[0].lcn == LCN_RL_NOT_MAPPED) { /* extended mft record */
1217			ntfs_log_verbose("Missing segment at beginning, %lld "
1218					"clusters\n", (long long)rl[0].length);
1219			clusters_inuse += rl[0].length;
1220			rl++;
1221		}
1222
1223		for (i = 0; rl[i].length > 0; i++) {
1224			if (rl[i].lcn == LCN_RL_NOT_MAPPED) {
1225				ntfs_log_verbose("Missing segment at end, %lld "
1226						"clusters\n",
1227						(long long)rl[i].length);
1228				clusters_inuse += rl[i].length;
1229				continue;
1230			}
1231
1232			if (rl[i].lcn == LCN_HOLE) {
1233				clusters_free += rl[i].length;
1234				continue;
1235			}
1236
1237			start = rl[i].lcn;
1238			end   = rl[i].lcn + rl[i].length;
1239
1240			for (j = start; j < end; j++) {
1241				if (utils_cluster_in_use(vol, j))
1242					clusters_inuse++;
1243				else
1244					clusters_free++;
1245			}
1246		}
1247
1248		if ((clusters_inuse + clusters_free) == 0) {
1249			ntfs_log_error("ERROR: Unexpected error whilst "
1250				"calculating percentage for inode %lld\n",
1251				file->inode);
1252			continue;
1253		}
1254
1255		data->percent = (clusters_free * 100) /
1256				(clusters_inuse + clusters_free);
1257
1258		percent = max(percent, data->percent);
1259	}
1260
1261	ntfs_log_verbose("File is %d%% recoverable\n", percent);
1262	return percent;
1263}
1264
1265/**
1266 * dump_record - Print everything we know about an MFT record
1267 * @file:  The file to work with
1268 *
1269 * Output the contents of the file object.  This will print everything that has
1270 * been read from the MFT record, or implied by various means.
1271 *
1272 * Because of the redundant nature of NTFS, there will be some duplication of
1273 * information, though it will have been read from different sources.
1274 *
1275 * N.B.  If the filename is missing, or couldn't be converted to the current
1276 *       locale, "<none>" will be displayed.
1277 *
1278 * Return:  none
1279 */
1280static void dump_record(struct ufile *file)
1281{
1282	char buffer[20];
1283	const char *name;
1284	struct list_head *item;
1285	int i;
1286
1287	if (!file)
1288		return;
1289
1290	ntfs_log_quiet("MFT Record %lld\n", file->inode);
1291	ntfs_log_quiet("Type: %s\n", (file->directory) ? "Directory" : "File");
1292	strftime(buffer, sizeof(buffer), "%F %R", localtime(&file->date));
1293	ntfs_log_quiet("Date: %s\n", buffer);
1294
1295	if (file->attr_list)
1296		ntfs_log_quiet("Metadata may span more than one MFT record\n");
1297
1298	list_for_each(item, &file->name) {
1299		struct filename *f = list_entry(item, struct filename, list);
1300
1301		if (f->name)
1302			name = f->name;
1303		else
1304			name = NONE;
1305
1306		ntfs_log_quiet("Filename: (%d) %s\n", f->name_space, f->name);
1307		ntfs_log_quiet("File Flags: ");
1308		if (f->flags & FILE_ATTR_SYSTEM)
1309			ntfs_log_quiet("System ");
1310		if (f->flags & FILE_ATTR_DIRECTORY)
1311			ntfs_log_quiet("Directory ");
1312		if (f->flags & FILE_ATTR_SPARSE_FILE)
1313			ntfs_log_quiet("Sparse ");
1314		if (f->flags & FILE_ATTR_REPARSE_POINT)
1315			ntfs_log_quiet("Reparse ");
1316		if (f->flags & FILE_ATTR_COMPRESSED)
1317			ntfs_log_quiet("Compressed ");
1318		if (f->flags & FILE_ATTR_ENCRYPTED)
1319			ntfs_log_quiet("Encrypted ");
1320		if (!(f->flags & (FILE_ATTR_SYSTEM | FILE_ATTR_DIRECTORY |
1321		    FILE_ATTR_SPARSE_FILE | FILE_ATTR_REPARSE_POINT |
1322		    FILE_ATTR_COMPRESSED | FILE_ATTR_ENCRYPTED))) {
1323			ntfs_log_quiet("%s", NONE);
1324		}
1325
1326		ntfs_log_quiet("\n");
1327
1328		if (opts.parent) {
1329			ntfs_log_quiet("Parent: %s\n", f->parent_name ?
1330				f->parent_name : "<non-determined>");
1331		}
1332
1333		ntfs_log_quiet("Size alloc: %lld\n", f->size_alloc);
1334		ntfs_log_quiet("Size data: %lld\n", f->size_data);
1335
1336		strftime(buffer, sizeof(buffer), "%F %R",
1337				localtime(&f->date_c));
1338		ntfs_log_quiet("Date C: %s\n", buffer);
1339		strftime(buffer, sizeof(buffer), "%F %R",
1340				localtime(&f->date_a));
1341		ntfs_log_quiet("Date A: %s\n", buffer);
1342		strftime(buffer, sizeof(buffer), "%F %R",
1343				localtime(&f->date_m));
1344		ntfs_log_quiet("Date M: %s\n", buffer);
1345		strftime(buffer, sizeof(buffer), "%F %R",
1346				localtime(&f->date_r));
1347		ntfs_log_quiet("Date R: %s\n", buffer);
1348	}
1349
1350	ntfs_log_quiet("Data Streams:\n");
1351	list_for_each(item, &file->data) {
1352		struct data *d = list_entry(item, struct data, list);
1353		ntfs_log_quiet("Name: %s\n", (d->name) ? d->name : UNNAMED);
1354		ntfs_log_quiet("Flags: ");
1355		if (d->resident)   ntfs_log_quiet("Resident\n");
1356		if (d->compressed) ntfs_log_quiet("Compressed\n");
1357		if (d->encrypted)  ntfs_log_quiet("Encrypted\n");
1358		if (!d->resident && !d->compressed && !d->encrypted)
1359			ntfs_log_quiet("None\n");
1360		else
1361			ntfs_log_quiet("\n");
1362
1363		ntfs_log_quiet("Size alloc: %lld\n", d->size_alloc);
1364		ntfs_log_quiet("Size data: %lld\n", d->size_data);
1365		ntfs_log_quiet("Size init: %lld\n", d->size_init);
1366		ntfs_log_quiet("Size vcn: %lld\n", d->size_vcn);
1367
1368		ntfs_log_quiet("Data runs:\n");
1369		if ((!d->runlist) || (d->runlist[0].length <= 0)) {
1370			ntfs_log_quiet("    None\n");
1371		} else {
1372			for (i = 0; d->runlist[i].length > 0; i++) {
1373				ntfs_log_quiet("    %lld @ %lld\n",
1374						(long long)d->runlist[i].length,
1375						(long long)d->runlist[i].lcn);
1376			}
1377		}
1378
1379		ntfs_log_quiet("Amount potentially recoverable %d%%\n",
1380				d->percent);
1381	}
1382
1383	ntfs_log_quiet("________________________________________\n\n");
1384}
1385
1386/**
1387 * list_record - Print a one line summary of the file
1388 * @file:  The file to work with
1389 *
1390 * Print a one line description of a file.
1391 *
1392 *   Inode    Flags  %age  Date            Size  Filename
1393 *
1394 * The output will contain the file's inode number (MFT Record), some flags,
1395 * the percentage of the file that is recoverable, the last modification date,
1396 * the size and the filename.
1397 *
1398 * The flags are F/D = File/Directory, N/R = Data is (Non-)Resident,
1399 * C = Compressed, E = Encrypted, ! = Metadata may span multiple records.
1400 *
1401 * N.B.  The file size is stored in many forms in several attributes.   This
1402 *       display the largest it finds.
1403 *
1404 * N.B.  If the filename is missing, or couldn't be converted to the current
1405 *       locale, "<none>" will be displayed.
1406 *
1407 * Return:  none
1408 */
1409static void list_record(struct ufile *file)
1410{
1411	char buffer[20];
1412	struct list_head *item;
1413	const char *name = NULL;
1414	long long size = 0;
1415	int percent = 0;
1416
1417	char flagd = '.', flagr = '.', flagc = '.', flagx = '.';
1418
1419	strftime(buffer, sizeof(buffer), "%F", localtime(&file->date));
1420
1421	if (file->attr_list)
1422		flagx = '!';
1423
1424	if (file->directory)
1425		flagd = 'D';
1426	else
1427		flagd = 'F';
1428
1429	list_for_each(item, &file->data) {
1430		struct data *d = list_entry(item, struct data, list);
1431
1432		if (!d->name) {
1433			if (d->resident)
1434				flagr = 'R';
1435			else
1436				flagr = 'N';
1437			if (d->compressed)
1438				flagc = 'C';
1439			if (d->encrypted)
1440				flagc = 'E';
1441
1442			percent = max(percent, d->percent);
1443		}
1444
1445		size = max(size, d->size_data);
1446		size = max(size, d->size_init);
1447	}
1448
1449	if (file->pref_name)
1450		name = file->pref_name;
1451	else
1452		name = NONE;
1453
1454	ntfs_log_quiet("%-8lld %c%c%c%c   %3d%%  %s %9lld  %s\n",
1455		file->inode, flagd, flagr, flagc, flagx,
1456		percent, buffer, size, name);
1457
1458}
1459
1460/**
1461 * name_match - Does a file have a name matching a regex
1462 * @re:    The regular expression object
1463 * @file:  The file to be tested
1464 *
1465 * Iterate through the file's $FILENAME attributes and compare them against the
1466 * regular expression, created with regcomp.
1467 *
1468 * Return:  1  There is a matching filename.
1469 *	    0  There is no match.
1470 */
1471static int name_match(regex_t *re, struct ufile *file)
1472{
1473	struct list_head *item;
1474	int result;
1475
1476	if (!re || !file)
1477		return 0;
1478
1479	list_for_each(item, &file->name) {
1480		struct filename *f = list_entry(item, struct filename, list);
1481
1482		if (!f->name)
1483			continue;
1484		result = regexec(re, f->name, 0, NULL, 0);
1485		if (result < 0) {
1486			ntfs_log_perror("Couldn't compare filename with regex");
1487			return 0;
1488		} else if (result == REG_NOERROR) {
1489			ntfs_log_debug("Found a matching filename.\n");
1490			return 1;
1491		}
1492	}
1493
1494	ntfs_log_debug("Filename '%s' doesn't match regex.\n", file->pref_name);
1495	return 0;
1496}
1497
1498/**
1499 * write_data - Write out a block of data
1500 * @fd:       File descriptor to write to
1501 * @buffer:   Data to write
1502 * @bufsize:  Amount of data to write
1503 *
1504 * Write a block of data to a file descriptor.
1505 *
1506 * Return:  -1  Error, something went wrong
1507 *	     0  Success, all the data was written
1508 */
1509static unsigned int write_data(int fd, const char *buffer,
1510	unsigned int bufsize)
1511{
1512	ssize_t result1, result2;
1513
1514	if (!buffer) {
1515		errno = EINVAL;
1516		return -1;
1517	}
1518
1519	result1 = write(fd, buffer, bufsize);
1520	if ((result1 == (ssize_t) bufsize) || (result1 < 0))
1521		return result1;
1522
1523	/* Try again with the rest of the buffer */
1524	buffer  += result1;
1525	bufsize -= result1;
1526
1527	result2 = write(fd, buffer, bufsize);
1528	if (result2 < 0)
1529		return result1;
1530
1531	return result1 + result2;
1532}
1533
1534/**
1535 * create_pathname - Create a path/file from some components
1536 * @dir:      Directory in which to create the file (optional)
1537 * @name:     Filename to give the file (optional)
1538 * @stream:   Name of the stream (optional)
1539 * @buffer:   Store the result here
1540 * @bufsize:  Size of buffer
1541 *
1542 * Create a filename from various pieces.  The output will be of the form:
1543 *	dir/file
1544 *	dir/file:stream
1545 *	file
1546 *	file:stream
1547 *
1548 * All the components are optional.  If the name is missing, "unknown" will be
1549 * used.  If the directory is missing the file will be created in the current
1550 * directory.  If the stream name is present it will be appended to the
1551 * filename, delimited by a colon.
1552 *
1553 * N.B. If the buffer isn't large enough the name will be truncated.
1554 *
1555 * Return:  n  Length of the allocated name
1556 */
1557static int create_pathname(const char *dir, const char *name,
1558	const char *stream, char *buffer, int bufsize)
1559{
1560	if (!name)
1561		name = UNKNOWN;
1562
1563	if (dir)
1564		if (stream)
1565			snprintf(buffer, bufsize, "%s/%s:%s", dir, name, stream);
1566		else
1567			snprintf(buffer, bufsize, "%s/%s", dir, name);
1568	else
1569		if (stream)
1570			snprintf(buffer, bufsize, "%s:%s", name, stream);
1571		else
1572			snprintf(buffer, bufsize, "%s", name);
1573
1574	return strlen(buffer);
1575}
1576
1577/**
1578 * open_file - Open a file to write to
1579 * @pathname:  Path, name and stream of the file to open
1580 *
1581 * Create a file and return the file descriptor.
1582 *
1583 * N.B.  If option force is given and existing file will be overwritten.
1584 *
1585 * Return:  -1  Error, failed to create the file
1586 *	     n  Success, this is the file descriptor
1587 */
1588static int open_file(const char *pathname)
1589{
1590	int flags;
1591
1592	ntfs_log_verbose("Creating file: %s\n", pathname);
1593
1594	if (opts.force)
1595		flags = O_RDWR | O_CREAT | O_TRUNC;
1596	else
1597		flags = O_RDWR | O_CREAT | O_EXCL;
1598
1599	return open(pathname, flags, S_IRUSR | S_IWUSR);
1600}
1601
1602/**
1603 * set_date - Set the file's date and time
1604 * @pathname:  Path and name of the file to alter
1605 * @date:      Date and time to set
1606 *
1607 * Give a file a particular date and time.
1608 *
1609 * Return:  1  Success, set the file's date and time
1610 *	    0  Error, failed to change the file's date and time
1611 */
1612static int set_date(const char *pathname, time_t date)
1613{
1614	struct utimbuf ut;
1615
1616	if (!pathname)
1617		return 0;
1618
1619	ut.actime  = date;
1620	ut.modtime = date;
1621	if (utime(pathname, &ut)) {
1622		ntfs_log_error("ERROR: Couldn't set the file's date and time\n");
1623		return 0;
1624	}
1625	return 1;
1626}
1627
1628/**
1629 * undelete_file - Recover a deleted file from an NTFS volume
1630 * @vol:    An ntfs volume obtained from ntfs_mount
1631 * @inode:  MFT Record number to be recovered
1632 *
1633 * Read an MFT Record and try an recover any data associated with it.  Some of
1634 * the clusters may be in use; these will be filled with zeros or the fill byte
1635 * supplied in the options.
1636 *
1637 * Each data stream will be recovered and saved to a file.  The file's name will
1638 * be the original filename and it will be written to the current directory.
1639 * Any named data stream will be saved as filename:streamname.
1640 *
1641 * The output file's name and location can be altered by using the command line
1642 * options.
1643 *
1644 * N.B.  We cannot tell if someone has overwritten some of the data since the
1645 *       file was deleted.
1646 *
1647 * Return:  0  Error, something went wrong
1648 *	    1  Success, the data was recovered
1649 */
1650static int undelete_file(ntfs_volume *vol, long long inode)
1651{
1652	char pathname[256];
1653	char *buffer = NULL;
1654	unsigned int bufsize;
1655	struct ufile *file;
1656	int i, j;
1657	long long start, end;
1658	runlist_element *rl;
1659	struct list_head *item;
1660	int fd = -1;
1661	long long k;
1662	int result = 0;
1663	char *name;
1664	long long cluster_count;	/* I'll need this variable (see below). +mabs */
1665
1666	if (!vol)
1667		return 0;
1668
1669	/* try to get record */
1670	file = read_record(vol, inode);
1671	if (!file || !file->mft) {
1672		ntfs_log_error("Can't read info from mft record %lld.\n", inode);
1673		return 0;
1674	}
1675
1676	/* if flag was not set, print file informations */
1677	if (avoid_duplicate_printing == 0) {
1678		if (opts.verbose) {
1679			dump_record(file);
1680		} else {
1681			list_record(file);
1682			//ntfs_log_quiet("\n");
1683		}
1684	}
1685
1686	bufsize = vol->cluster_size;
1687	buffer = malloc(bufsize);
1688	if (!buffer)
1689		goto free;
1690
1691	/* calc_percentage() must be called before dump_record() or
1692	 * list_record(). Otherwise, when undeleting, a file will always be
1693	 * listed as 0% recoverable even if successfully undeleted. +mabs
1694	 */
1695	if (file->mft->flags & MFT_RECORD_IN_USE) {
1696		ntfs_log_error("Record is in use by the mft\n");
1697		if (!opts.force) {
1698			free(buffer);
1699			free_file(file);
1700			return 0;
1701		}
1702		ntfs_log_verbose("Forced to continue.\n");
1703	}
1704
1705	if (calc_percentage(file, vol) == 0) {
1706		ntfs_log_quiet("File has no recoverable data.\n");
1707		goto free;
1708	}
1709
1710	if (list_empty(&file->data)) {
1711		ntfs_log_quiet("File has no data.  There is nothing to recover.\n");
1712		goto free;
1713	}
1714
1715	list_for_each(item, &file->data) {
1716		struct data *d = list_entry(item, struct data, list);
1717
1718		if (opts.output)
1719				name = opts.output;
1720		else
1721				name = file->pref_name;
1722
1723		create_pathname(opts.dest, name, d->name, pathname, sizeof(pathname));
1724		if (d->resident) {
1725			fd = open_file(pathname);
1726			if (fd < 0) {
1727				ntfs_log_perror("Couldn't create file");
1728				goto free;
1729			}
1730
1731			ntfs_log_verbose("File has resident data.\n");
1732			if (write_data(fd, d->data, d->size_data) < d->size_data) {
1733				ntfs_log_perror("Write failed");
1734				close(fd);
1735				goto free;
1736			}
1737
1738			if (close(fd) < 0) {
1739				ntfs_log_perror("Close failed");
1740			}
1741			fd = -1;
1742		} else {
1743			rl = d->runlist;
1744			if (!rl) {
1745				ntfs_log_verbose("File has no runlist, hence no data.\n");
1746				continue;
1747			}
1748
1749			if (rl[0].length <= 0) {
1750				ntfs_log_verbose("File has an empty runlist, hence no data.\n");
1751				continue;
1752			}
1753
1754			fd = open_file(pathname);
1755			if (fd < 0) {
1756				ntfs_log_perror("Couldn't create output file");
1757				goto free;
1758			}
1759
1760			if (rl[0].lcn == LCN_RL_NOT_MAPPED) {	/* extended mft record */
1761				ntfs_log_verbose("Missing segment at beginning, %lld "
1762						"clusters.\n",
1763						(long long)rl[0].length);
1764				memset(buffer, opts.fillbyte, bufsize);
1765				for (k = 0; k < rl[0].length * vol->cluster_size; k += bufsize) {
1766					if (write_data(fd, buffer, bufsize) < bufsize) {
1767						ntfs_log_perror("Write failed");
1768						close(fd);
1769						goto free;
1770					}
1771				}
1772			}
1773
1774			cluster_count = 0LL;
1775			for (i = 0; rl[i].length > 0; i++) {
1776
1777				if (rl[i].lcn == LCN_RL_NOT_MAPPED) {
1778					ntfs_log_verbose("Missing segment at end, "
1779							"%lld clusters.\n",
1780							(long long)rl[i].length);
1781					memset(buffer, opts.fillbyte, bufsize);
1782					for (k = 0; k < rl[k].length * vol->cluster_size; k += bufsize) {
1783						if (write_data(fd, buffer, bufsize) < bufsize) {
1784							ntfs_log_perror("Write failed");
1785							close(fd);
1786							goto free;
1787						}
1788						cluster_count++;
1789					}
1790					continue;
1791				}
1792
1793				if (rl[i].lcn == LCN_HOLE) {
1794					ntfs_log_verbose("File has a sparse section.\n");
1795					memset(buffer, 0, bufsize);
1796					for (k = 0; k < rl[k].length * vol->cluster_size; k += bufsize) {
1797						if (write_data(fd, buffer, bufsize) < bufsize) {
1798							ntfs_log_perror("Write failed");
1799							close(fd);
1800							goto free;
1801						}
1802					}
1803					continue;
1804				}
1805
1806				start = rl[i].lcn;
1807				end   = rl[i].lcn + rl[i].length;
1808
1809				for (j = start; j < end; j++) {
1810					if (utils_cluster_in_use(vol, j) && !opts.optimistic) {
1811						memset(buffer, opts.fillbyte, bufsize);
1812						if (write_data(fd, buffer, bufsize) < bufsize) {
1813							ntfs_log_perror("Write failed");
1814							close(fd);
1815							goto free;
1816						}
1817					} else {
1818						if (ntfs_cluster_read(vol, j, 1, buffer) < 1) {
1819							ntfs_log_perror("Read failed");
1820							close(fd);
1821							goto free;
1822						}
1823						if (write_data(fd, buffer, bufsize) < bufsize) {
1824							ntfs_log_perror("Write failed");
1825							close(fd);
1826							goto free;
1827						}
1828						cluster_count++;
1829					}
1830				}
1831			}
1832			ntfs_log_quiet("\n");
1833
1834			/*
1835			 * The following block of code implements the --truncate option.
1836			 * Its semantics are as follows:
1837			 * IF opts.truncate is set AND data stream currently being recovered is
1838			 * non-resident AND data stream has no holes (100% recoverability) AND
1839			 * 0 <= (data->size_alloc - data->size_data) <= vol->cluster_size AND
1840			 * cluster_count * vol->cluster_size == data->size_alloc THEN file
1841			 * currently being written is truncated to data->size_data bytes before
1842			 * it's closed.
1843			 * This multiple checks try to ensure that only files with consistent
1844			 * values of size/occupied clusters are eligible for truncation. Note
1845			 * that resident streams need not be truncated, since the original code
1846			 * already recovers their exact length.                           +mabs
1847			 */
1848			if (opts.truncate) {
1849				if (d->percent == 100 && d->size_alloc >= d->size_data &&
1850					(d->size_alloc - d->size_data) <= (long long)vol->cluster_size &&
1851					cluster_count * (long long)vol->cluster_size == d->size_alloc) {
1852					if (ftruncate(fd, (off_t)d->size_data))
1853						ntfs_log_perror("Truncation failed");
1854				} else ntfs_log_quiet("Truncation not performed because file has an "
1855					"inconsistent $MFT record.\n");
1856			}
1857
1858			if (close(fd) < 0) {
1859				ntfs_log_perror("Close failed");
1860			}
1861			fd = -1;
1862
1863		}
1864		set_date(pathname, file->date);
1865		if (d->name)
1866			ntfs_log_quiet("Undeleted '%s:%s' successfully.\n", file->pref_name, d->name);
1867		else
1868			ntfs_log_quiet("Undeleted '%s' successfully.\n", file->pref_name);
1869	}
1870	result = 1;
1871free:
1872	if (buffer)
1873		free(buffer);
1874	free_file(file);
1875	return result;
1876}
1877
1878/**
1879 * scan_disk - Search an NTFS volume for files that could be undeleted
1880 * @vol:  An ntfs volume obtained from ntfs_mount
1881 *
1882 * Read through all the MFT entries looking for deleted files.  For each one
1883 * determine how much of the data lies in unused disk space.
1884 *
1885 * The list can be filtered by name, size and date, using command line options.
1886 *
1887 * Return:  -1  Error, something went wrong
1888 *	     n  Success, the number of recoverable files
1889 */
1890static int scan_disk(ntfs_volume *vol)
1891{
1892	s64 nr_mft_records;
1893	const int BUFSIZE = 8192;
1894	char *buffer = NULL;
1895	int results = 0;
1896	ntfs_attr *attr;
1897	long long size;
1898	long long bmpsize;
1899	int i, j, k, b;
1900	int percent;
1901	struct ufile *file;
1902	regex_t re;
1903
1904	if (!vol)
1905		return -1;
1906
1907	attr = ntfs_attr_open(vol->mft_ni, AT_BITMAP, AT_UNNAMED, 0);
1908	if (!attr) {
1909		ntfs_log_perror("ERROR: Couldn't open $MFT/$BITMAP");
1910		return -1;
1911	}
1912	bmpsize = attr->initialized_size;
1913
1914	buffer = malloc(BUFSIZE);
1915	if (!buffer) {
1916		ntfs_log_error("ERROR: Couldn't allocate memory in scan_disk()\n");
1917		results = -1;
1918		goto out;
1919	}
1920
1921	if (opts.match) {
1922		int flags = REG_NOSUB;
1923
1924		if (!opts.match_case)
1925			flags |= REG_ICASE;
1926		if (regcomp(&re, opts.match, flags)) {
1927			ntfs_log_error("ERROR: Couldn't create a regex.\n");
1928			goto out;
1929		}
1930	}
1931
1932	nr_mft_records = vol->mft_na->initialized_size >>
1933			vol->mft_record_size_bits;
1934
1935	ntfs_log_quiet("Inode    Flags  %%age  Date           Size  Filename\n");
1936	ntfs_log_quiet("---------------------------------------------------------------\n");
1937	for (i = 0; i < bmpsize; i += BUFSIZE) {
1938		long long read_count = min((bmpsize - i), BUFSIZE);
1939		size = ntfs_attr_pread(attr, i, read_count, buffer);
1940		if (size < 0)
1941			break;
1942
1943		for (j = 0; j < size; j++) {
1944			b = buffer[j];
1945			for (k = 0; k < 8; k++, b>>=1) {
1946				if (((i+j)*8+k) >= nr_mft_records)
1947					goto done;
1948				if (b & 1)
1949					continue;
1950				file = read_record(vol, (i+j)*8+k);
1951				if (!file) {
1952					ntfs_log_error("Couldn't read MFT Record %d.\n", (i+j)*8+k);
1953					continue;
1954				}
1955
1956				if ((opts.since > 0) && (file->date <= opts.since))
1957					goto skip;
1958				if (opts.match && !name_match(&re, file))
1959					goto skip;
1960				if (opts.size_begin && (opts.size_begin > file->max_size))
1961					goto skip;
1962				if (opts.size_end && (opts.size_end < file->max_size))
1963					goto skip;
1964
1965				percent = calc_percentage(file, vol);
1966				if ((opts.percent == -1) || (percent >= opts.percent)) {
1967					if (opts.verbose)
1968						dump_record(file);
1969					else
1970						list_record(file);
1971
1972					/* Was -u specified with no inode
1973					   so undelete file by regex */
1974					if (opts.mode == MODE_UNDELETE) {
1975						if  (!undelete_file(vol, file->inode))
1976							ntfs_log_verbose("ERROR: Failed to undelete "
1977								  "inode %lli\n!",
1978								  file->inode);
1979						ntfs_log_info("\n");
1980					}
1981				}
1982				if (((opts.percent == -1) && (percent > 0)) ||
1983				    ((opts.percent > 0)  && (percent >= opts.percent))) {
1984					results++;
1985				}
1986skip:
1987				free_file(file);
1988			}
1989		}
1990	}
1991done:
1992	ntfs_log_quiet("\nFiles with potentially recoverable content: %d\n",
1993		results);
1994out:
1995	if (opts.match)
1996		regfree(&re);
1997	free(buffer);
1998	if (attr)
1999		ntfs_attr_close(attr);
2000	return results;
2001}
2002
2003/**
2004 * copy_mft - Write a range of MFT Records to a file
2005 * @vol:	An ntfs volume obtained from ntfs_mount
2006 * @mft_begin:	First MFT Record to save
2007 * @mft_end:	Last MFT Record to save
2008 *
2009 * Read a number of MFT Records and write them to a file.
2010 *
2011 * Return:  0  Success, all the records were written
2012 *	    1  Error, something went wrong
2013 */
2014static int copy_mft(ntfs_volume *vol, long long mft_begin, long long mft_end)
2015{
2016	s64 nr_mft_records;
2017	char pathname[256];
2018	ntfs_attr *mft;
2019	char *buffer;
2020	const char *name;
2021	long long i;
2022	int result = 1;
2023	int fd;
2024
2025	if (!vol)
2026		return 1;
2027
2028	if (mft_end < mft_begin) {
2029		ntfs_log_error("Range to copy is backwards.\n");
2030		return 1;
2031	}
2032
2033	buffer = malloc(vol->mft_record_size);
2034	if (!buffer) {
2035		ntfs_log_error("Couldn't allocate memory in copy_mft()\n");
2036		return 1;
2037	}
2038
2039	mft = ntfs_attr_open(vol->mft_ni, AT_DATA, AT_UNNAMED, 0);
2040	if (!mft) {
2041		ntfs_log_perror("Couldn't open $MFT/$DATA");
2042		goto free;
2043	}
2044
2045	name = opts.output;
2046	if (!name) {
2047		name = MFTFILE;
2048		ntfs_log_debug("No output filename, defaulting to '%s'.\n",
2049				name);
2050	}
2051
2052	create_pathname(opts.dest, name, NULL, pathname, sizeof(pathname));
2053	fd = open_file(pathname);
2054	if (fd < 0) {
2055		ntfs_log_perror("Couldn't open output file '%s'", name);
2056		goto attr;
2057	}
2058
2059	nr_mft_records = vol->mft_na->initialized_size >>
2060			vol->mft_record_size_bits;
2061
2062	mft_end = min(mft_end, nr_mft_records - 1);
2063
2064	ntfs_log_debug("MFT records:\n");
2065	ntfs_log_debug("\tTotal: %8lld\n", nr_mft_records);
2066	ntfs_log_debug("\tBegin: %8lld\n", mft_begin);
2067	ntfs_log_debug("\tEnd:   %8lld\n", mft_end);
2068
2069	for (i = mft_begin; i <= mft_end; i++) {
2070		if (ntfs_attr_pread(mft, vol->mft_record_size * i,
2071		    vol->mft_record_size, buffer) < vol->mft_record_size) {
2072			ntfs_log_perror("Couldn't read MFT Record %lld", i);
2073			goto close;
2074		}
2075
2076		if (write_data(fd, buffer, vol->mft_record_size) < vol->mft_record_size) {
2077			ntfs_log_perror("Write failed");
2078			goto close;
2079		}
2080	}
2081
2082	ntfs_log_verbose("Read %lld MFT Records\n", mft_end - mft_begin + 1);
2083	result = 0;
2084close:
2085	close(fd);
2086attr:
2087	ntfs_attr_close(mft);
2088free:
2089	free(buffer);
2090	return result;
2091}
2092
2093/**
2094 * handle_undelete
2095 *
2096 * Handles the undelete
2097 */
2098static int handle_undelete(ntfs_volume *vol)
2099{
2100	int result = 1;
2101	int i;
2102	unsigned long long	inode;
2103
2104	/* Check whether (an) inode(s) was specified or at least a regex! */
2105	if (nr_entries == 0) {
2106		if (with_regex == 0) {
2107			ntfs_log_error("ERROR: NO inode(s) AND NO match-regex "
2108				"specified!\n");
2109		} else {
2110			avoid_duplicate_printing= 1;
2111			result = !scan_disk(vol);
2112			if (result)
2113				ntfs_log_verbose("ERROR: Failed to scan device "
2114					"'%s'.\n", opts.device);
2115		}
2116	} else {
2117		/* Normal undelete by specifying inode(s) */
2118		ntfs_log_quiet("Inode    Flags  %%age  Date            Size  Filename\n");
2119		ntfs_log_quiet("---------------------------------------------------------------\n");
2120
2121		/* loop all given inodes */
2122		for (i = 0; i < nr_entries; i++) {
2123			for (inode = ranges[i].begin; inode <= ranges[i].end; inode ++) {
2124				/* Now undelete file */
2125				result = !undelete_file(vol, inode);
2126				if (result)
2127					ntfs_log_verbose("ERROR: Failed to "
2128						"undelete inode %lli\n!", inode);
2129			}
2130		}
2131	}
2132	return (result);
2133}
2134
2135/**
2136 * main - Begin here
2137 *
2138 * Start from here.
2139 *
2140 * Return:  0  Success, the program worked
2141 *	    1  Error, something went wrong
2142 */
2143int main(int argc, char *argv[])
2144{
2145	ntfs_volume *vol;
2146	int result = 1;
2147
2148	ntfs_log_set_handler(ntfs_log_handler_outerr);
2149
2150	with_regex = 0;
2151	avoid_duplicate_printing = 0;
2152
2153	if (!parse_options(argc, argv))
2154		goto free;
2155
2156	utils_set_locale();
2157
2158	vol = utils_mount_volume(opts.device, NTFS_MNT_RDONLY |
2159			(opts.force ? NTFS_MNT_FORCE : 0));
2160	if (!vol)
2161		return 1;
2162
2163	/* handling of the different modes */
2164	switch (opts.mode) {
2165	/* Scanning */
2166	case MODE_SCAN:
2167		result = !scan_disk(vol);
2168		if (result)
2169			ntfs_log_verbose("ERROR: Failed to scan device '%s'.\n",
2170				opts.device);
2171		break;
2172
2173	/* Undelete-handling */
2174	case MODE_UNDELETE:
2175		result= handle_undelete(vol);
2176		break;
2177
2178	/* Handling of copy mft */
2179	case MODE_COPY:
2180		result = !copy_mft(vol, opts.mft_begin, opts.mft_end);
2181		if (result)
2182			ntfs_log_verbose("ERROR: Failed to read MFT blocks "
2183				"%lld-%lld.\n", opts.mft_begin,
2184				min((vol->mft_na->initialized_size >>
2185				vol->mft_record_size_bits) , opts.mft_end));
2186		break;
2187	default:
2188		; /* Cannot happen */
2189	}
2190
2191	ntfs_umount(vol, FALSE);
2192free:
2193	if (opts.match)
2194		free(opts.match);
2195
2196	return result;
2197}
2198
2199