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