6df3c606853d928b52c5ab41abf3a5d99249bd12
[ntfsprogs.git] / ntfsprogs / ntfsundelete.c
1 /**
2  * ntfsundelete - Part of the Linux-NTFS project.
3  *
4  * Copyright (c) 2002-2003 Richard Russon
5  *
6  * This utility will recover deleted files from an NTFS volume.
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program (in the main directory of the Linux-NTFS
20  * distribution in the file COPYING); if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
22  */
23
24 #include "config.h"
25
26 #include <features.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <errno.h>
31 #include <sys/types.h>
32 #include <sys/stat.h>
33 #include <unistd.h>
34 #include <fcntl.h>
35 #include <getopt.h>
36 #include <time.h>
37 #include <limits.h>
38 #include <regex.h>
39 #include <time.h>
40 #include <stdarg.h>
41 #include <utime.h>
42
43 #include "ntfsundelete.h"
44 #include "bootsect.h"
45 #include "mft.h"
46 #include "attrib.h"
47 #include "layout.h"
48 #include "inode.h"
49 #include "disk_io.h"
50 #include "utils.h"
51 #include "debug.h"
52
53 static const char *EXEC_NAME = "ntfsundelete";
54 static const char *MFTFILE   = "mft";
55 static const char *UNNAMED   = "<unnamed>";
56 static       char *NONE      = "<none>";
57 static       char *UNKNOWN   = "unknown";
58 static struct options opts;
59
60 GEN_PRINTF (Eprintf, stderr, NULL,          FALSE)
61 GEN_PRINTF (Vprintf, stdout, &opts.verbose, TRUE)
62 GEN_PRINTF (Qprintf, stdout, &opts.quiet,   FALSE)
63
64 #define _(S)    gettext(S)
65
66 /**
67  * version - Print version information about the program
68  *
69  * Print a copyright statement and a brief description of the program.
70  *
71  * Return:  none
72  */
73 void version (void)
74 {
75         printf ("\n%s v%s - Recover deleted files from an NTFS Volume.\n\n",
76                 EXEC_NAME, VERSION);
77         printf ("Copyright (c)\n");
78         printf ("    2002-2003 Richard Russon\n");
79         printf ("\n%s\n%s%s\n", ntfs_gpl, ntfs_bugs, ntfs_home);
80 }
81
82 /**
83  * usage - Print a list of the parameters to the program
84  *
85  * Print a list of the parameters and options for the program.
86  *
87  * Return:  none
88  */
89 void usage (void)
90 {
91         printf ("\nUsage: %s [options] device\n"
92                 "    -s          --scan             Scan for files (default)\n"
93                 "    -p num      --percentage num   Minimum percentage recoverable\n"
94                 "    -m pattern  --match pattern    Only work on files with matching names\n"
95                 "    -C          --case             Case sensitive matching\n"
96                 "    -S range    --size range       Match files of this size\n"
97                 "    -t since    --time since       Last referenced since this time\n"
98                 "\n"
99                 "    -u num      --undelete num     Undelete inode\n"
100                 "    -o file     --output file      Save with this filename\n"
101                 "    -d dir      --destination dir  Destination directory\n"
102                 "    -b num      --byte num         Fill missing parts with this byte\n"
103                 "\n"
104                 "    -c range    --copy range       Write a range of MFT records to a file\n"
105                 "\n"
106                 "    -f          --force            Use less caution\n"
107                 "    -q          --quiet            Less output\n"
108                 "    -v          --verbose          More output\n"
109                 "    -V          --version          Display version information\n"
110                 "    -h          --help             Display this help\n\n",
111                 EXEC_NAME);
112         printf ("%s%s\n", ntfs_bugs, ntfs_home);
113 }
114
115 /**
116  * transform - Convert a shell style pattern to a regex
117  * @pattern:  String to be converted
118  * @regex:    Resulting regular expression is put here
119  *
120  * This will transform patterns, such as "*.doc" to true regular expressions.
121  * The function will also place '^' and '$' around the expression to make it
122  * behave as the user would expect
123  *
124  * Before  After
125  *   .       \.
126  *   *       .*
127  *   ?       .
128  *
129  * Notes:
130  *     The returned string must be freed by the caller.
131  *     If transform fails, @regex will not be changed.
132  *
133  * Return:  1, Success, the string was transformed
134  *          0, An error occurred
135  */
136 int transform (const char *pattern, char **regex)
137 {
138         char *result;
139         int length, i, j;
140
141         if (!pattern || !regex)
142                 return 0;
143
144         length = strlen (pattern);
145         if (length < 1) {
146                 Eprintf ("Pattern to transform is empty\n");
147                 return 0;
148         }
149
150         for (i = 0; pattern[i]; i++) {
151                 if ((pattern[i] == '*') || (pattern[i] == '.'))
152                         length++;
153         }
154
155         result = malloc (length + 3);
156         if (!result) {
157                 Eprintf ("Couldn't allocate memory in transform()\n");
158                 return 0;
159         }
160
161         result[0] = '^';
162
163         for (i = 0, j = 1; pattern[i]; i++, j++) {
164                 if (pattern[i] == '*') {
165                         result[j] = '.';
166                         j++;
167                         result[j] = '*';
168                 } else if (pattern[i] == '.') {
169                         result[j] = '\\';
170                         j++;
171                         result[j] = '.';
172                 } else if (pattern[i] == '?') {
173                         result[j] = '.';
174                 } else {
175                         result[j] = pattern[i];
176                 }
177         }
178
179         result[j]   = '$';
180         result[j+1] = 0;
181         Dprintf ("Pattern '%s' replaced with regex '%s'\n", pattern, result);
182
183         *regex = result;
184         return 1;
185 }
186
187 /**
188  * parse_time - Convert a time abbreviation to seconds
189  * @string:  The string to be converted
190  * @since:   The absolute time referred to
191  *
192  * Strings representing times will be converted into a time_t.  The numbers will
193  * be regarded as seconds unless suffixed.
194  *
195  * Suffix  Description
196  *  [yY]      Year
197  *  [mM]      Month
198  *  [wW]      Week
199  *  [dD]      Day
200  *  [sS]      Second
201  *
202  * Therefore, passing "1W" will return the time_t representing 1 week ago.
203  *
204  * Notes:
205  *     Only the first character of the suffix is read.
206  *     If parse_time fails, @since will not be changed
207  *
208  * Return:  1  Success
209  *          0  Error, the string was malformed
210  */
211 int parse_time (const char *value, time_t *since)
212 {
213         time_t result, now;
214         char *suffix = NULL;
215
216         if (!value || !since)
217                 return -1;
218
219         Dprintf ("parsing time '%s' ago\n", value);
220
221         result = strtoll (value, &suffix, 10);
222         if (result < 0 || errno == ERANGE) {
223                 Eprintf ("Invalid time '%s'.\n", value);
224                 return 0;
225         }
226
227         if (!suffix) {
228                 Eprintf ("Internal error, strtoll didn't return a suffix.\n");
229                 return 0;
230         }
231
232         if (strlen (suffix) > 1) {
233                 Eprintf ("Invalid time suffix '%s'.  Use Y, M, W, D or H.\n", suffix);
234                 return 0;
235         }
236
237         switch (suffix[0]) {
238                 case 'y': case 'Y': result *=   12;
239                 case 'm': case 'M': result *=    4;
240                 case 'w': case 'W': result *=    7;
241                 case 'd': case 'D': result *=   24;
242                 case 'h': case 'H': result *= 3600;
243                 case 0:
244                     break;
245
246                 default:
247                         Eprintf ("Invalid time suffix '%s'.  Use Y, M, W, D or H.\n", suffix);
248                         return 0;
249         }
250
251         now = time (NULL);
252
253         Dprintf ("Time now = %lld, Time then = %lld.\n", (long long) now, (long long) result);
254         *since = now - result;
255         return 1;
256 }
257
258 /**
259  * parse_options - Read and validate the programs command line
260  *
261  * Read the command line, verify the syntax and parse the options.
262  * This function is very long, but quite simple.
263  *
264  * Return:  1 Success
265  *          0 Error, one or more problems
266  */
267 int parse_options (int argc, char *argv[])
268 {
269         static const char *sopt = "-b:Cc:d:fh?m:o:p:sS:t:u:qvV";
270         static const struct option lopt[] = {
271                 { "byte",        required_argument,     NULL, 'b' },
272                 { "case",        no_argument,           NULL, 'C' },
273                 { "copy",        required_argument,     NULL, 'c' },
274                 { "destination", required_argument,     NULL, 'd' },
275                 { "force",       no_argument,           NULL, 'f' },
276                 { "help",        no_argument,           NULL, 'h' },
277                 { "match",       required_argument,     NULL, 'm' },
278                 { "output",      required_argument,     NULL, 'o' },
279                 { "percentage",  required_argument,     NULL, 'p' },
280                 { "scan",        no_argument,           NULL, 's' },
281                 { "size",        required_argument,     NULL, 'S' },
282                 { "time",        required_argument,     NULL, 't' },
283                 { "undelete",    required_argument,     NULL, 'u' },
284                 { "quiet",       no_argument,           NULL, 'q' },
285                 { "verbose",     no_argument,           NULL, 'v' },
286                 { "version",     no_argument,           NULL, 'V' },
287                 { NULL, 0, NULL, 0 }
288         };
289
290         char c = -1;
291         char *end = NULL;
292         int err  = 0;
293         int ver  = 0;
294         int help = 0;
295
296         opterr = 0; /* We'll handle the errors, thank you. */
297
298         opts.mode     = MODE_NONE;
299         opts.uinode   = -1;
300         opts.percent  = -1;
301         opts.fillbyte = -1;
302
303         while ((c = getopt_long (argc, argv, sopt, lopt, NULL)) != -1) {
304                 switch (c) {
305                 case 1: /* A non-option argument */
306                         if (!opts.device) {
307                                 opts.device = argv[optind-1];
308                         } else {
309                                 opts.device = NULL;
310                                 err++;
311                         }
312                         break;
313                 case 'b':
314                         if (opts.fillbyte == -1) {
315                                 end = NULL;
316                                 opts.fillbyte = strtol (optarg, &end, 0);
317                                 if (end && *end)
318                                         err++;
319                         } else {
320                                 err++;
321                         }
322                         break;
323                 case 'C':
324                         opts.match_case++;
325                         break;
326                 case 'c':
327                         if (opts.mode == MODE_NONE) {
328                                 if (!utils_parse_range (argv[optind-1],
329                                     &opts.mft_begin, &opts.mft_end, TRUE))
330                                         err++;
331                                 opts.mode = MODE_COPY;
332                         } else {
333                                 opts.mode = MODE_ERROR;
334                         }
335                         break;
336                 case 'd':
337                         if (!opts.dest)
338                                 opts.dest = argv[optind-1];
339                         else
340                                 err++;
341                         break;
342                 case 'f':
343                         opts.force++;
344                         break;
345                 case 'h':
346                 case '?':
347                         help++;
348                         break;
349                 case 'm':
350                         if (!opts.match) {
351                                 if (!transform (argv[optind-1], &opts.match))
352                                         err++;
353                         } else {
354                                 err++;
355                         }
356                         break;
357                 case 'o':
358                         if (!opts.output) {
359                                 opts.output = argv[optind-1];
360                         } else {
361                                 err++;
362                         }
363                         break;
364                 case 'p':
365                         if (opts.percent == -1) {
366                                 end = NULL;
367                                 opts.percent = strtol (optarg, &end, 0);
368                                 if (end && ((*end != '%') && (*end != 0)))
369                                         err++;
370                         } else {
371                                 err++;
372                         }
373                         break;
374                 case 'q':
375                         opts.quiet++;
376                         break;
377                 case 's':
378                         if (opts.mode == MODE_NONE)
379                                 opts.mode = MODE_SCAN;
380                         else
381                                 opts.mode = MODE_ERROR;
382                         break;
383                 case 'S':
384                         if ((opts.size_begin > 0) || (opts.size_end > 0) ||
385                             !utils_parse_range (argv[optind-1], &opts.size_begin,
386                              &opts.size_end, TRUE)) {
387                             err++;
388                         }
389                         break;
390                 case 't':
391                         if (opts.since == 0) {
392                                 if (!parse_time (argv[optind-1], &opts.since))
393                                         err++;
394                         } else {
395                             err++;
396                         }
397                         break;
398                 case 'u':
399                         if (opts.mode == MODE_NONE) {
400                                 end = NULL;
401                                 opts.mode = MODE_UNDELETE;
402                                 opts.uinode = strtol (optarg, &end, 0);
403                                 if (end && *end)
404                                         err++;
405                         } else {
406                                 opts.mode = MODE_ERROR;
407                         }
408                         break;
409                 case 'v':
410                         opts.verbose++;
411                         break;
412                 case 'V':
413                         ver++;
414                         break;
415                 default:
416                         if (((optopt == 'b') || (optopt == 'c') ||
417                              (optopt == 'd') || (optopt == 'm') ||
418                              (optopt == 'o') || (optopt == 'p') ||
419                              (optopt == 'S') || (optopt == 't') ||
420                              (optopt == 'u')) && (!optarg)) {
421                                 Eprintf ("Option '%s' requires an argument.\n", argv[optind-1]);
422                         } else {
423                                 Eprintf ("Unknown option '%s'.\n", argv[optind-1]);
424                         }
425                         err++;
426                         break;
427                 }
428         }
429
430         if (help || ver) {
431                 opts.quiet = 0;
432         } else {
433                 if (opts.device == NULL) {
434                         if (argc > 1)
435                                 Eprintf ("You must specify exactly one device.\n");
436                         err++;
437                 }
438
439                 if (opts.mode == MODE_NONE) {
440                         opts.mode = MODE_SCAN;
441                 }
442
443                 switch (opts.mode) {
444                 case MODE_SCAN:
445                         if (opts.output || opts.dest || (opts.fillbyte != -1)) {
446                                 Eprintf ("Scan can only be used with --percent, "
447                                         "--match, --ignore-case, --size and --time.\n");
448                                 err++;
449                         }
450                         if (opts.match_case && !opts.match) {
451                                 Eprintf ("The --case option doesn't make sense without the --match option\n");
452                                 err++;
453                         }
454                         break;
455                 case MODE_UNDELETE:
456                         if ((opts.percent != -1) || opts.match || opts.match_case ||
457                             (opts.size_begin > 0) || (opts.size_end > 0)) {
458                                 Eprintf ("Undelete can only be used with "
459                                         "--output, --destination and --byte.\n");
460                                 err++;
461                         }
462                         break;
463                 case MODE_COPY:
464                         if ((opts.fillbyte != -1) || (opts.percent != -1) ||
465                             opts.match || opts.match_case ||
466                             (opts.size_begin > 0) || (opts.size_end > 0)) {
467                                 Eprintf ("Copy can only be used with --output and --destination.\n");
468                                 err++;
469                         }
470                         break;
471                 default:
472                         Eprintf ("You can only select one of Scan, Undelete or Copy.\n");
473                         err++;
474                 }
475
476                 if ((opts.percent < -1) || (opts.percent > 100)) {
477                         Eprintf ("Percentage value must be in the range 0 - 100.\n");
478                         err++;
479                 }
480
481                 if (opts.quiet) {
482                         if (opts.verbose) {
483                                 Eprintf ("You may not use --quiet and --verbose at the same time.\n");
484                                 err++;
485                         } else if (opts.mode == MODE_SCAN) {
486                                 Eprintf ("You may not use --quiet when scanning a volume.\n");
487                                 err++;
488                         }
489                 }
490         }
491
492         if (ver)
493                 version();
494         if (help || err)
495                 usage();
496
497         return (!err && !help && !ver);
498 }
499
500
501 /**
502  * free_file - Release the resources used by a file object
503  * @file:  The unwanted file object
504  *
505  * This will free up the memory used by a file object and iterate through the
506  * object's children, freeing their resources too.
507  *
508  * Return:  none
509  */
510 void free_file (struct ufile *file)
511 {
512         struct list_head *item, *tmp;
513
514         if (!file)
515                 return;
516
517         list_for_each_safe (item, tmp, &file->name) { /* List of filenames */
518                 struct filename *f = list_entry (item, struct filename, list);
519                 Dprintf ("freeing filename '%s'\n", f->name ? f->name : NONE);
520                 if (f->name)
521                         free (f->name);
522                 free (f);
523         }
524
525         list_for_each_safe (item, tmp, &file->data) { /* List of data streams */
526                 struct data *d = list_entry (item, struct data, list);
527                 Dprintf ("freeing data stream '%s'\n", d->name ? d->name : UNNAMED);
528                 if (d->name)
529                         free (d->name);
530                 if (d->runlist)
531                         free (d->runlist);
532                 free (d);
533         }
534
535         free (file->mft);
536         free (file);
537 }
538
539 /**
540  * get_filenames - Read an MFT Record's $FILENAME attributes
541  * @file:  The file object to work with
542  *
543  * A single file may have more than one filename.  This is quite common.
544  * Windows creates a short DOS name for each long name, e.g. LONGFI~1.XYZ,
545  * LongFiLeName.xyZ.
546  *
547  * The filenames that are found are put in filename objects and added to a
548  * linked list of filenames in the file object.  For convenience, the unicode
549  * filename is converted into the current locale and stored in the filename
550  * object.
551  *
552  * One of the filenames is picked (the one with the lowest numbered namespace)
553  * and its locale friendly name is put in pref_name.
554  *
555  * Return:  n  The number of $FILENAME attributes found
556  *         -1  Error
557  */
558 int get_filenames (struct ufile *file)
559 {
560         ATTR_RECORD *rec;
561         FILE_NAME_ATTR *attr;
562         ntfs_attr_search_ctx *ctx;
563         struct filename *name;
564         int count = 0;
565         int space = 4;
566
567         if (!file)
568                 return -1;
569
570         ctx = ntfs_attr_get_search_ctx (NULL, file->mft);
571         if (!ctx)
572                 return -1;
573
574         while ((rec = find_attribute (AT_FILE_NAME, ctx))) {
575                 /* We know this will always be resident. */
576                 attr = (FILE_NAME_ATTR *) ((char *) rec + le16_to_cpu (rec->value_offset));
577
578                 name = calloc (1, sizeof (*name));
579                 if (!name) {
580                         Eprintf ("Couldn't allocate memory in get_filenames().\n");
581                         count = -1;
582                         break;
583                 }
584
585                 name->uname      = attr->file_name;
586                 name->uname_len  = attr->file_name_length;
587                 name->name_space = attr->file_name_type;
588                 name->size_alloc = sle64_to_cpu (attr->allocated_size);
589                 name->size_data  = sle64_to_cpu (attr->data_size);
590                 name->flags      = attr->file_attributes;
591
592                 name->date_c     = ntfs2utc (sle64_to_cpu (attr->creation_time));
593                 name->date_a     = ntfs2utc (sle64_to_cpu (attr->last_data_change_time));
594                 name->date_m     = ntfs2utc (sle64_to_cpu (attr->last_mft_change_time));
595                 name->date_r     = ntfs2utc (sle64_to_cpu (attr->last_access_time));
596
597                 if (ntfs_ucstombs (name->uname, name->uname_len, &name->name,
598                     name->uname_len) < 0) {
599                         Dprintf ("Couldn't translate filename to current locale.\n");
600                 }
601
602                 if (name->name_space < space) {
603                         file->pref_name = name->name;
604                         space = name->name_space;
605                 }
606
607                 file->max_size = max (file->max_size, name->size_alloc);
608                 file->max_size = max (file->max_size, name->size_data);
609
610                 list_add_tail (&name->list, &file->name);
611                 count++;
612         }
613
614         ntfs_attr_put_search_ctx(ctx);
615         Dprintf ("File has %d names.\n", count);
616         return count;
617 }
618
619 /**
620  * get_data - Read an MFT Record's $DATA attributes
621  * @file:  The file object to work with
622  * @vol:  An ntfs volume obtained from ntfs_mount
623  *
624  * A file may have more than one data stream.  All files will have an unnamed
625  * data stream which contains the file's data.  Some Windows applications store
626  * extra information in a separate stream.
627  *
628  * The streams that are found are put in data objects and added to a linked
629  * list of data streams in the file object.
630  *
631  * Return:  n  The number of $FILENAME attributes found
632  *         -1  Error
633  */
634 int get_data (struct ufile *file, ntfs_volume *vol)
635 {
636         ATTR_RECORD *rec;
637         ntfs_attr_search_ctx *ctx;
638         int count = 0;
639         struct data *data;
640
641         if (!file)
642                 return -1;
643
644         ctx = ntfs_attr_get_search_ctx (NULL, file->mft);
645         if (!ctx)
646                 return -1;
647
648         while ((rec = find_attribute (AT_DATA, ctx))) {
649                 data = calloc (1, sizeof (*data));
650                 if (!data) {
651                         Eprintf ("Couldn't allocate memory in get_data().\n");
652                         count = -1;
653                         break;
654                 }
655
656                 data->resident   = !rec->non_resident;
657                 data->compressed = rec->flags & ATTR_IS_COMPRESSED;
658                 data->encrypted  = rec->flags & ATTR_IS_ENCRYPTED;
659
660                 if (rec->name_length) {
661                         data->uname     = (uchar_t *) ((char *) rec + le16_to_cpu (rec->name_offset));
662                         data->uname_len = rec->name_length;
663
664                         if (ntfs_ucstombs (data->uname, data->uname_len, &data->name,
665                             data->uname_len) < 0) {
666                                 Eprintf ("Cannot translate name into current locale.\n");
667                         }
668                 }
669
670                 if (data->resident) {
671                         data->size_data  = le32_to_cpu (rec->value_length);
672                         data->data       = ((char*) (rec)) + le16_to_cpu (rec->value_offset);
673                 } else {
674                         data->size_alloc = sle64_to_cpu (rec->allocated_size);
675                         data->size_data  = sle64_to_cpu (rec->data_size);
676                         data->size_init  = sle64_to_cpu (rec->initialized_size);
677                         data->size_vcn   = sle64_to_cpu (rec->highest_vcn) + 1;
678                 }
679
680                 data->runlist = ntfs_mapping_pairs_decompress(vol, rec, NULL);
681                 if (!data->runlist) {
682                         Dprintf ("Couldn't decompress the data runs\n");
683                 }
684
685                 file->max_size = max (file->max_size, data->size_data);
686                 file->max_size = max (file->max_size, data->size_init);
687
688                 list_add_tail (&data->list, &file->data);
689                 count++;
690         }
691
692         ntfs_attr_put_search_ctx(ctx);
693         Dprintf ("File has %d data streams.\n", count);
694         return count;
695 }
696
697 /**
698  * read_record - Read an MFT record into memory
699  * @vol:     An ntfs volume obtained from ntfs_mount
700  * @record:  The record number to read
701  *
702  * Read the specified MFT record and gather as much information about it as
703  * possible.
704  *
705  * Return:  Pointer  A ufile object containing the results
706  *          NULL     Error
707  */
708 struct ufile * read_record (ntfs_volume *vol, long long record)
709 {
710         ATTR_RECORD *attr10, *attr20, *attr90;
711         struct ufile *file;
712         ntfs_attr *mft;
713
714         if (!vol)
715                 return NULL;
716
717         file = calloc (1, sizeof (*file));
718         if (!file) {
719                 Eprintf ("Couldn't allocate memory in read_record()\n");
720                 return NULL;
721         }
722
723         INIT_LIST_HEAD (&file->name);
724         INIT_LIST_HEAD (&file->data);
725         file->inode = record;
726
727         file->mft = malloc (vol->mft_record_size);
728         if (!file->mft) {
729                 Eprintf ("Couldn't allocate memory in read_record()\n");
730                 free_file (file);
731                 return NULL;
732         }
733
734         mft = ntfs_attr_open (vol->mft_ni, AT_DATA, NULL, 0);
735         if (!mft) {
736                 Eprintf ("Couldn't open $MFT/$DATA: %s\n", strerror (errno));
737                 free_file (file);
738                 return NULL;
739         }
740
741         if (ntfs_attr_mst_pread (mft, vol->mft_record_size * record, 1, vol->mft_record_size, file->mft) < 1) {
742                 Eprintf ("Couldn't read MFT Record %lld.\n", record);
743                 ntfs_attr_close (mft);
744                 free_file (file);
745                 return NULL;
746         }
747
748         ntfs_attr_close (mft);
749         mft = NULL;
750
751         attr10 = find_first_attribute (AT_STANDARD_INFORMATION, file->mft);
752         attr20 = find_first_attribute (AT_ATTRIBUTE_LIST,       file->mft);
753         attr90 = find_first_attribute (AT_INDEX_ROOT,           file->mft);
754
755         Dprintf ("Attributes present: %s %s %s\n", attr10?"0x10":"", attr20?"0x20":"", attr90?"0x90":"");
756
757         if (attr10)
758         {
759                 STANDARD_INFORMATION *si;
760                 si = (STANDARD_INFORMATION *) ((char *) attr10 + le16_to_cpu (attr10->value_offset));
761                 file->date = ntfs2utc (sle64_to_cpu (si->last_data_change_time));
762         }
763
764         if (attr20 || !attr10)
765                 file->attr_list = 1;
766         if (attr90)
767                 file->directory = 1;
768
769         if (get_filenames (file) < 0) {
770                 Eprintf ("Couldn't get filenames.\n");
771         }
772         if (get_data (file, vol) < 0) {
773                 Eprintf ("Couldn't get data streams.\n");
774         }
775
776         return file;
777 }
778
779
780 /**
781  * calc_percentage - Calculate how much of the file is recoverable
782  * @file:  The file object to work with
783  * @vol:   An ntfs volume obtained from ntfs_mount
784  *
785  * Read through all the $DATA streams and determine if each cluster in each
786  * stream is still free disk space.  This is just measuring the potential for
787  * recovery.  The data may have still been overwritten by a another file which
788  * was then deleted.
789  *
790  * Files with a resident $DATA stream will have a 100% potential.
791  *
792  * N.B.  If $DATA attribute spans more than one MFT record (i.e. badly
793  *       fragmented) then only the data in this segment will be used for the
794  *       calculation.
795  *
796  * N.B.  Currently, compressed and encrypted files cannot be recovered, so they
797  *       will return 0%.
798  *
799  * Return:  n  The percentage of the file that _could_ be recovered
800  *         -1  Error
801  */
802 int calc_percentage (struct ufile *file, ntfs_volume *vol)
803 {
804         runlist_element *rl = NULL;
805         struct list_head *pos;
806         struct data *data;
807         long long i, j;
808         long long start, end;
809         int inuse, free;
810         int percent = 0;
811
812         if (!file || !vol)
813                 return -1;
814
815         if (file->directory) {
816                 Dprintf ("Found a directory: not recoverable.\n");
817                 return 0;
818         }
819
820         if (list_empty (&file->data)) {
821                 Vprintf ("File has no data streams.\n");
822                 return 0;
823         }
824
825         list_for_each (pos, &file->data) {
826                 data  = list_entry (pos, struct data, list);
827                 inuse = 0;
828                 free  = 0;
829
830                 if (data->encrypted) {
831                         Vprintf ("File is encrypted, recovery is impossible.\n");
832                         continue;
833                 }
834
835                 if (data->compressed) {
836                         Vprintf ("File is compressed, recovery not yet implemented.\n");
837                         continue;
838                 }
839
840                 if (data->resident) {
841                         Vprintf ("File is resident, therefore recoverable.\n");
842                         percent = 100;
843                         data->percent = 100;
844                         continue;
845                 }
846
847                 rl = data->runlist;
848                 if (!rl) {
849                         Vprintf ("File has no runlist, hence no data.\n");
850                         continue;
851                 }
852
853                 if (rl[0].length <= 0) {
854                         Vprintf ("File has an empty runlist, hence no data.\n");
855                         continue;
856                 }
857
858                 if (rl[0].lcn == LCN_RL_NOT_MAPPED) {   /* extended mft record */
859                         Vprintf ("Missing segment at beginning, %lld clusters\n", rl[0].length);
860                         inuse += rl[0].length;
861                         rl++;
862                 }
863
864                 for (i = 0; rl[i].length > 0; i++) {
865                         if (rl[i].lcn == LCN_RL_NOT_MAPPED) {
866                                 Vprintf ("Missing segment at end, %lld clusters\n", rl[i].length);
867                                 inuse += rl[i].length;
868                                 continue;
869                         }
870
871                         if (rl[i].lcn == LCN_HOLE) {
872                                 free += rl[i].length;
873                                 continue;
874                         }
875
876                         start = rl[i].lcn;
877                         end   = rl[i].lcn + rl[i].length;
878
879                         for (j = start; j < end; j++) {
880                                 if (utils_cluster_in_use (vol, j))
881                                         inuse++;
882                                 else
883                                         free++;
884                         }
885                 }
886
887                 if ((inuse + free) == 0) {
888                         Eprintf ("Unexpected error whilst calculating percentage for inode %lld\n", file->inode);
889                         continue;
890                 }
891
892                 data->percent = (free * 100) / (inuse + free);
893
894                 percent = max (percent, data->percent);
895         }
896
897         Vprintf ("File is %d%% recoverable\n", percent);
898         return percent;
899 }
900
901 /**
902  * dump_record - Print everything we know about an MFT record
903  * @file:  The file to work with
904  *
905  * Output the contents of the file object.  This will print everything that has
906  * been read from the MFT record, or implied by various means.
907  *
908  * Because of the redundant nature of NTFS, there will be some duplication of
909  * information, though it will have been read from different sources.
910  *
911  * N.B.  If the filename is missing, or couldn't be converted to the current
912  *       locale, "<none>" will be displayed.
913  *
914  * Return:  none
915  */
916 void dump_record (struct ufile *file)
917 {
918         char buffer[20];
919         char *name;
920         struct list_head *item;
921         int i;
922
923         if (!file)
924                 return;
925
926         Qprintf ("MFT Record %lld\n", file->inode);
927         Qprintf ("Type: %s\n", (file->directory) ? "Directory" : "File");
928         strftime (buffer, sizeof (buffer), "%F %R", localtime (&file->date));
929         Qprintf ("Date: %s\n", buffer);
930
931         if (file->attr_list)
932                 Qprintf ("Metadata may span more than one MFT record\n");
933
934         list_for_each (item, &file->name) {
935                 struct filename *f = list_entry (item, struct filename, list);
936
937                 if (f->name)
938                         name = f->name;
939                 else
940                         name = NONE;
941
942                 Qprintf ("Filename: (%d) %s\n", f->name_space, f->name);
943                 Qprintf ("File Flags: ");
944                 if (f->flags & FILE_ATTR_SYSTEM)        Qprintf ("System ");
945                 if (f->flags & FILE_ATTR_DIRECTORY)     Qprintf ("Directory ");
946                 if (f->flags & FILE_ATTR_SPARSE_FILE)   Qprintf ("Sparse ");
947                 if (f->flags & FILE_ATTR_REPARSE_POINT) Qprintf ("Reparse ");
948                 if (f->flags & FILE_ATTR_COMPRESSED)    Qprintf ("Compressed ");
949                 if (f->flags & FILE_ATTR_ENCRYPTED)     Qprintf ("Encrypted ");
950                 if (!(f->flags & (FILE_ATTR_SYSTEM || FILE_ATTR_DIRECTORY ||
951                     FILE_ATTR_SPARSE_FILE || FILE_ATTR_REPARSE_POINT ||
952                     FILE_ATTR_COMPRESSED || FILE_ATTR_ENCRYPTED))) {
953                         Qprintf (NONE);
954                 }
955                 Qprintf ("\n");
956                 Qprintf ("Size alloc: %lld\n", f->size_alloc);
957                 Qprintf ("Size data: %lld\n", f->size_data);
958
959                 strftime (buffer, sizeof (buffer), "%F %R", localtime (&f->date_c));
960                 Qprintf ("Date C: %s\n", buffer);
961                 strftime (buffer, sizeof (buffer), "%F %R", localtime (&f->date_a));
962                 Qprintf ("Date A: %s\n", buffer);
963                 strftime (buffer, sizeof (buffer), "%F %R", localtime (&f->date_m));
964                 Qprintf ("Date M: %s\n", buffer);
965                 strftime (buffer, sizeof (buffer), "%F %R", localtime (&f->date_r));
966                 Qprintf ("Date R: %s\n", buffer);
967         }
968
969         Qprintf ("Data Streams:\n");
970         list_for_each (item, &file->data) {
971                 struct data *d = list_entry (item, struct data, list);
972                 Qprintf ("Name: %s\n", (d->name) ? d->name : "<unnamed>");
973                 Qprintf ("Flags: ");
974                 if (d->resident)   Qprintf ("Resident\n");
975                 if (d->compressed) Qprintf ("Compressed\n");
976                 if (d->encrypted)  Qprintf ("Encrypted\n");
977                 if (!d->resident && !d->compressed && !d->encrypted)
978                         Qprintf ("None\n");
979                 else
980                         Qprintf ("\n");
981
982                 Qprintf ("Size alloc: %lld\n", d->size_alloc);
983                 Qprintf ("Size data: %lld\n", d->size_data);
984                 Qprintf ("Size init: %lld\n", d->size_init);
985                 Qprintf ("Size vcn: %lld\n", d->size_vcn);
986
987                 Qprintf ("Data runs:\n");
988                 if ((!d->runlist) || (d->runlist[0].length <= 0)) {
989                         Qprintf ("    None\n");
990                 } else {
991                         for (i = 0; d->runlist[i].length > 0; i++) {
992                                 Qprintf ("    %lld @ %lld\n", d->runlist[i].length, d->runlist[i].lcn);
993                         }
994                 }
995
996                 Qprintf ("Amount potentially recoverable %d%%\n", d->percent);
997         }
998
999         Qprintf ("________________________________________\n\n");
1000 }
1001
1002 /**
1003  * list_record - Print a one line summary of the file
1004  * @file:  The file to work with
1005  *
1006  * Print a one line description of a file.
1007  *
1008  *   Inode    Flags  %age  Date            Size  Filename
1009  *
1010  * The output will contain the file's inode number (MFT Record), some flags,
1011  * the percentage of the file that is recoverable, the last modification date,
1012  * the size and the filename.
1013  *
1014  * The flags are F/D = File/Directory, N/R = Data is (Non-)Resident,
1015  * C = Compressed, E = Encrypted, ! = Metadata may span multiple records.
1016  *
1017  * N.B.  The file size is stored in many forms in several attributes.   This
1018  *       display the largest it finds.
1019  *
1020  * N.B.  If the filename is missing, or couldn't be converted to the current
1021  *       locale, "<none>" will be displayed.
1022  *
1023  * Return:  none
1024  */
1025 void list_record (struct ufile *file)
1026 {
1027         char buffer[20];
1028         struct list_head *item;
1029         char *name = NULL;
1030         long long size = 0;
1031         int percent = 0;
1032
1033         char flagd = '.', flagr = '.', flagc = '.', flagx = '.';
1034
1035         strftime (buffer, sizeof (buffer), "%F", localtime (&file->date));
1036
1037         if (file->attr_list)
1038                 flagx = '!';
1039
1040         if (file->directory)
1041                 flagd = 'D';
1042         else
1043                 flagd = 'F';
1044
1045         list_for_each (item, &file->data) {
1046                 struct data *d = list_entry (item, struct data, list);
1047
1048                 if (!d->name) {
1049                         if (d->resident)   flagr = 'R';
1050                         else               flagr = 'N';
1051                         if (d->compressed) flagc = 'C'; /* These two are mutually exclusive */
1052                         if (d->encrypted)  flagc = 'E';
1053
1054                         percent = max (percent, d->percent);
1055                 }
1056
1057                 size = max (size, d->size_data);
1058                 size = max (size, d->size_init);
1059         }
1060
1061         if (file->pref_name)
1062                 name = file->pref_name;
1063         else
1064                 name = NONE;
1065
1066         Qprintf ("%-8lld %c%c%c%c   %3d%%  %s %9lld  %s\n",
1067                 file->inode, flagd, flagr, flagc, flagx,
1068                 percent, buffer, size, name);
1069 }
1070
1071 /**
1072  * name_match - Does a file have a name matching a regex
1073  * @re:    The regular expression object
1074  * @file:  The file to be tested
1075  *
1076  * Iterate through the file's $FILENAME attributes and compare them against the
1077  * regular expression, created with regcomp.
1078  *
1079  * Return:  1  There is a matching filename.
1080  *          0  There is no match.
1081  */
1082 int name_match (regex_t *re, struct ufile *file)
1083 {
1084         struct list_head *item;
1085         int result;
1086
1087         if (!re || !file)
1088                 return 0;
1089
1090         list_for_each (item, &file->name) {
1091                 struct filename *f = list_entry (item, struct filename, list);
1092
1093                 if (!f->name)
1094                         continue;
1095                 result = regexec (re, f->name, 0, NULL, 0);
1096                 if (result < 0) {
1097                         Eprintf ("Couldn't compare filename with regex: %s\n", strerror (errno));
1098                         return 0;
1099                 } else if (result == REG_NOERROR) {
1100                         Dprintf ("Found a matching filename.\n");
1101                         return 1;
1102                 }
1103         }
1104
1105         Dprintf ("Filename '%s' doesn't match regex.\n", file->pref_name);
1106         return 0;
1107 }
1108
1109 /**
1110  * write_data - Write out a block of data
1111  * @fd:       File descriptor to write to
1112  * @buffer:   Data to write
1113  * @bufsize:  Amount of data to write
1114  *
1115  * Write a block of data to a file descriptor.
1116  *
1117  * Return:  -1  Error, something went wrong
1118  *           0  Success, all the data was written
1119  */
1120 unsigned int write_data (int fd, const char *buffer, unsigned int bufsize)
1121 {
1122         ssize_t result1, result2;
1123
1124         if (!buffer) {
1125                 errno = EINVAL;
1126                 return -1;
1127         }
1128
1129         result1 = write (fd, buffer, bufsize);
1130         if ((result1 == (ssize_t) bufsize) || (result1 < 0))
1131                 return result1;
1132
1133         /* Try again with the rest of the buffer */
1134         buffer  += result1;
1135         bufsize -= result1;
1136
1137         result2 = write (fd, buffer, bufsize);
1138         if (result2 < 0)
1139                 return result1;
1140
1141         return result1 + result2;
1142 }
1143
1144 /**
1145  * create_pathname - Create a path/file from some components
1146  * @dir:      Directory in which to create the file (optional)
1147  * @name:     Filename to give the file (optional)
1148  * @stream:   Name of the stream (optional)
1149  * @buffer:   Store the result here
1150  * @bufsize:  Size of buffer
1151  *
1152  * Create a filename from various pieces.  The output will be of the form:
1153  *      dir/file
1154  *      dir/file:stream
1155  *      file
1156  *      file:stream
1157  *
1158  * All the components are optional.  If the name is missing, "unknown" will be
1159  * used.  If the directory is missing the file will be created in the current
1160  * directory.  If the stream name is present it will be appended to the
1161  * filename, delimited by a colon.
1162  *
1163  * N.B. If the buffer isn't large enough the name will be truncated.
1164  *
1165  * Return:  n  Length of the allocated name
1166  */
1167 int create_pathname (const char *dir, const char *name, const char *stream,
1168                      char *buffer, int bufsize)
1169 {
1170         if (!name)
1171                 name = UNKNOWN;
1172
1173         if (dir)
1174                 if (stream)
1175                         snprintf (buffer, bufsize, "%s/%s:%s", dir, name, stream);
1176                 else
1177                         snprintf (buffer, bufsize, "%s/%s", dir, name);
1178         else
1179                 if (stream)
1180                         snprintf (buffer, bufsize, "%s:%s", name, stream);
1181                 else
1182                         snprintf (buffer, bufsize, "%s", name);
1183
1184         return strlen (buffer);
1185 }
1186
1187 /**
1188  * open_file - Open a file to write to
1189  * @pathname:  Path, name and stream of the file to open
1190  *
1191  * Create a file and return the file descriptor.
1192  *
1193  * N.B.  If option force is given and existing file will be overwritten.
1194  *
1195  * Return:  -1  Error, failed to create the file
1196  *           n  Success, this is the file descriptor
1197  */
1198 int open_file (const char *pathname)
1199 {
1200         int flags;
1201
1202         Vprintf ("Creating file: %s\n", pathname);
1203
1204         if (opts.force)
1205                 flags = O_RDWR | O_CREAT | O_TRUNC;
1206         else
1207                 flags = O_RDWR | O_CREAT | O_EXCL;
1208
1209         return open (pathname, flags, S_IRUSR | S_IWUSR);
1210 }
1211
1212 /**
1213  * set_date - Set the file's date and time
1214  * @pathname:  Path and name of the file to alter
1215  * @date:      Date and time to set
1216  *
1217  * Give a file a particular date and time.
1218  *
1219  * Return:  1  Success, set the file's date and time
1220  *          0  Error, failed to change the file's date and time
1221  */
1222 int set_date (const char *pathname, time_t date)
1223 {
1224         struct utimbuf ut;
1225
1226         if (!pathname)
1227                 return 0;
1228
1229         ut.actime  = date;
1230         ut.modtime = date;
1231         if (utime (pathname, &ut)) {
1232                 Eprintf ("Couldn't set the file's date and time\n");
1233                 return 0;
1234         }
1235         return 1;
1236 }
1237
1238 /**
1239  * scan_disk - Search an NTFS volume for files that could be undeleted
1240  * @vol:  An ntfs volume obtained from ntfs_mount
1241  *
1242  * Read through all the MFT entries looking for deleted files.  For each one
1243  * determine how much of the data lies in unused disk space.
1244  *
1245  * The list can be filtered by name, size and date, using command line options.
1246  *
1247  * Return:  -1  Error, something went wrong
1248  *           n  Success, the number of recoverable files
1249  */
1250 int scan_disk (ntfs_volume *vol)
1251 {
1252         const int BUFSIZE = 8192;
1253         char *buffer = NULL;
1254         int results = 0;
1255         ntfs_attr *attr;
1256         long long size;
1257         long long read;
1258         long long bmpsize;
1259         int i, j, k, b;
1260         int percent;
1261         struct ufile *file;
1262         regex_t re;
1263
1264         if (!vol)
1265                 return -1;
1266
1267         attr = ntfs_attr_open (vol->mft_ni, AT_BITMAP, AT_UNNAMED, 0);
1268         if (!attr) {
1269                 Eprintf ("Couldn't open $MFT/$BITMAP: %s\n", strerror (errno));
1270                 return -1;
1271         }
1272         bmpsize = attr->initialized_size;
1273
1274         buffer = malloc (BUFSIZE);
1275         if (!buffer) {
1276                 Eprintf ("Couldn't allocate memory in scan_disk()\n");
1277                 results = -1;
1278                 goto out;
1279         }
1280
1281         if (opts.match) {
1282                 int flags = REG_NOSUB;
1283
1284                 if (!opts.match_case)
1285                         flags |= REG_ICASE;
1286                 if (regcomp (&re, opts.match, flags)) {
1287                         Eprintf ("Couldn't create a regex.\n");
1288                         goto out;
1289                 }
1290         }
1291
1292         Qprintf ("Inode    Flags  %%age  Date            Size  Filename\n");
1293         Qprintf ("---------------------------------------------------------------\n");
1294         for (i = 0; i < bmpsize; i += BUFSIZE) {
1295                 read = min ((bmpsize - i), BUFSIZE);
1296                 size = ntfs_attr_pread (attr, i, read, buffer);
1297                 if (size < 0)
1298                         break;
1299
1300                 for (j = 0; j < size; j++) {
1301                         b = buffer[j];
1302                         for (k = 0; k < 8; k++, b>>=1) {
1303                                 if (((i+j)*8+k) >= vol->nr_mft_records)
1304                                         goto done;
1305                                 if (b & 1)
1306                                         continue;
1307                                 file = read_record (vol, (i+j)*8+k);
1308                                 if (!file) {
1309                                         Eprintf ("Couldn't read MFT Record %d.\n", (i+j)*8+k);
1310                                         continue;
1311                                 }
1312
1313                                 if ((opts.since > 0) && (file->date <= opts.since))
1314                                         goto skip;
1315                                 if (opts.match && !name_match (&re, file))
1316                                         goto skip;
1317                                 if (opts.size_begin && (opts.size_begin > file->max_size))
1318                                         goto skip;
1319                                 if (opts.size_end && (opts.size_end < file->max_size))
1320                                         goto skip;
1321
1322                                 percent = calc_percentage (file, vol);
1323
1324                                 if ((opts.percent == -1) || (percent >= opts.percent)) {
1325                                         if (opts.verbose)
1326                                                 dump_record (file);
1327                                         else
1328                                                 list_record (file);
1329                                 }
1330
1331                                 if (((opts.percent == -1) && (percent > 0)) ||
1332                                     ((opts.percent > 0)  && (percent >= opts.percent))) {
1333                                         results++;
1334                                 }
1335 skip:
1336                                 free_file (file);
1337                         }
1338                 }
1339         }
1340 done:
1341         Qprintf ("\nFiles with potentially recoverable content: %d\n", results);
1342 out:
1343         if (opts.match)
1344                 regfree (&re);
1345         free (buffer);
1346         if (attr)
1347                 ntfs_attr_close (attr);
1348         return results;
1349 }
1350
1351 /**
1352  * undelete_file - Recover a deleted file from an NTFS volume
1353  * @vol:    An ntfs volume obtained from ntfs_mount
1354  * @inode:  MFT Record number to be recovered
1355  *
1356  * Read an MFT Record and try an recover any data associated with it.  Some of
1357  * the clusters may be in use; these will be filled with zeros or the fill byte
1358  * supplied in the options.
1359  *
1360  * Each data stream will be recovered and saved to a file.  The file's name will
1361  * be the original filename and it will be written to the current directory.
1362  * Any named data stream will be saved as filename:streamname.
1363  *
1364  * The output file's name and location can be altered by using the command line
1365  * options.
1366  *
1367  * N.B.  We cannot tell if someone has overwritten some of the data since the
1368  *       file was deleted.
1369  *
1370  * Return:  0  Error, something went wrong
1371  *          1  Success, the data was recovered
1372  */
1373 int undelete_file (ntfs_volume *vol, long long inode)
1374 {
1375         char pathname[256];
1376         char *buffer = NULL;
1377         unsigned int bufsize;
1378         struct ufile *file;
1379         int i, j;
1380         long long start, end;
1381         runlist_element *rl;
1382         struct list_head *item;
1383         int fd = -1;
1384         long long k;
1385         int result = 0;
1386
1387         if (!vol)
1388                 return 0;
1389
1390         file = read_record (vol, inode);
1391         if (!file || !file->mft) {
1392                 Eprintf ("Can't read info from mft record %lld.\n", inode);
1393                 return 0;
1394         }
1395
1396         bufsize = vol->cluster_size;
1397         buffer = malloc (bufsize);
1398         if (!buffer)
1399                 goto free;
1400
1401         if (opts.verbose) {
1402                 dump_record (file);
1403         } else {
1404                 Qprintf ("Inode    Flags  %%age  Date            Size  Filename\n");
1405                 Qprintf ("---------------------------------------------------------------\n");
1406                 list_record (file);
1407                 Qprintf ("\n");
1408         }
1409
1410         if (file->mft->flags & MFT_RECORD_IN_USE) {
1411                 Eprintf ("Record is in use by the mft\n");
1412                 if (!opts.force) {
1413                         free_file (file);
1414                         return 0;
1415                 }
1416                 Vprintf ("Forced to continue.\n");
1417         }
1418
1419         if (calc_percentage (file, vol) == 0) {
1420                 Qprintf ("File has no recoverable data.\n");
1421                 goto free;
1422         }
1423
1424         if (list_empty (&file->data)) {
1425                 Qprintf ("File has no data.  There is nothing to recover.\n");
1426                 goto free;
1427         }
1428
1429         list_for_each (item, &file->data) {
1430                 struct data *d = list_entry (item, struct data, list);
1431
1432                 create_pathname (opts.dest, file->pref_name, d->name, pathname, sizeof (pathname));
1433                 if (d->resident) {
1434                         fd = open_file (pathname);
1435                         if (fd < 0) {
1436                                 Eprintf ("Couldn't create file: %s\n", strerror (errno));
1437                                 goto free;
1438                         }
1439
1440                         Vprintf ("File has resident data.\n");
1441                         if (write_data (fd, d->data, d->size_data) < d->size_data) {
1442                                 Eprintf ("Write failed: %s\n", strerror (errno));
1443                                 close (fd);
1444                                 goto free;
1445                         }
1446
1447                         if (close (fd) < 0) {
1448                                 Eprintf ("Close failed: %s\n", strerror (errno));
1449                         }
1450                         fd = -1;
1451                 } else {
1452                         rl = d->runlist;
1453                         if (!rl) {
1454                                 Vprintf ("File has no runlist, hence no data.\n");
1455                                 continue;
1456                         }
1457
1458                         if (rl[0].length <= 0) {
1459                                 Vprintf ("File has an empty runlist, hence no data.\n");
1460                                 continue;
1461                         }
1462
1463                         fd = open_file (pathname);
1464                         if (fd < 0) {
1465                                 Eprintf ("Couldn't create output file: %s\n", strerror (errno));
1466                                 goto free;
1467                         }
1468
1469                         if (rl[0].lcn == LCN_RL_NOT_MAPPED) {   /* extended mft record */
1470                                 Vprintf ("Missing segment at beginning, %lld clusters.\n", rl[0].length);
1471                                 memset (buffer, opts.fillbyte, bufsize);
1472                                 for (k = 0; k < rl[0].length * vol->cluster_size; k += bufsize) {
1473                                         if (write_data (fd, buffer, bufsize) < bufsize) {
1474                                                 Eprintf ("Write failed: %s\n", strerror (errno));
1475                                                 close (fd);
1476                                                 goto free;
1477                                         }
1478                                 }
1479                         }
1480
1481                         for (i = 0; rl[i].length > 0; i++) {
1482
1483                                 if (rl[i].lcn == LCN_RL_NOT_MAPPED) {
1484                                         Vprintf ("Missing segment at end, %lld clusters.\n", rl[i].length);
1485                                         memset (buffer, opts.fillbyte, bufsize);
1486                                         for (k = 0; k < rl[k].length * vol->cluster_size; k += bufsize) {
1487                                                 if (write_data (fd, buffer, bufsize) < bufsize) {
1488                                                         Eprintf ("Write failed: %s\n", strerror (errno));
1489                                                         close (fd);
1490                                                         goto free;
1491                                                 }
1492                                         }
1493                                         continue;
1494                                 }
1495
1496                                 if (rl[i].lcn == LCN_HOLE) {
1497                                         Vprintf ("File has a sparse section.\n");
1498                                         memset (buffer, 0, bufsize);
1499                                         for (k = 0; k < rl[k].length * vol->cluster_size; k += bufsize) {
1500                                                 if (write_data (fd, buffer, bufsize) < bufsize) {
1501                                                         Eprintf ("Write failed: %s\n", strerror (errno));
1502                                                         close (fd);
1503                                                         goto free;
1504                                                 }
1505                                         }
1506                                         continue;
1507                                 }
1508
1509                                 start = rl[i].lcn;
1510                                 end   = rl[i].lcn + rl[i].length;
1511
1512                                 for (j = start; j < end; j++) {
1513                                         if (utils_cluster_in_use (vol, j)) {
1514                                                 memset (buffer, opts.fillbyte, bufsize);
1515                                                 if (write_data (fd, buffer, bufsize) < bufsize) {
1516                                                         Eprintf ("Write failed: %s\n", strerror (errno));
1517                                                         close (fd);
1518                                                         goto free;
1519                                                 }
1520                                         } else {
1521                                                 if (ntfs_cluster_read(vol, j, 1, buffer) < 1) {
1522                                                         Eprintf ("Read failed: %s\n", strerror (errno));
1523                                                         close (fd);
1524                                                         goto free;
1525                                                 }
1526                                                 if (write_data (fd, buffer, bufsize) < bufsize) {
1527                                                         Eprintf ("Write failed: %s\n", strerror (errno));
1528                                                         close (fd);
1529                                                         goto free;
1530                                                 }
1531                                         }
1532                                 }
1533                         }
1534                         Qprintf ("\n");
1535                         if (close (fd) < 0) {
1536                                 Eprintf ("Close failed: %s\n", strerror (errno));
1537                         }
1538                         fd = -1;
1539
1540                 }
1541                 set_date (pathname, file->date);
1542                 if (d->name)
1543                         Qprintf ("Undeleted '%s:%s' successfully.\n", file->pref_name, d->name);
1544                 else
1545                         Qprintf ("Undeleted '%s' successfully.\n", file->pref_name);
1546         }
1547         result = 1;
1548 free:
1549         if (buffer)
1550                 free (buffer);
1551         free_file (file);
1552         return result;
1553 }
1554
1555 /**
1556  * copy_mft - Write a range of MFT Records to a file
1557  * @vol:        An ntfs volume obtained from ntfs_mount
1558  * @mft_begin:  First MFT Record to save
1559  * @mft_end:    Last MFT Record to save
1560  *
1561  * Read a number of MFT Records and write them to a file.
1562  *
1563  * Return:  0  Success, all the records were written
1564  *          1  Error, something went wrong
1565  */
1566 int copy_mft (ntfs_volume *vol, long long mft_begin, long long mft_end)
1567 {
1568         char pathname[256];
1569         ntfs_attr *mft;
1570         char *buffer;
1571         const char *name;
1572         long long i;
1573         int result = 1;
1574         int fd;
1575
1576         if (!vol)
1577                 return 1;
1578
1579         if (mft_end < mft_begin) {
1580                 Eprintf ("Range to copy is backwards.\n");
1581                 return 1;
1582         }
1583
1584         buffer = malloc (vol->mft_record_size);
1585         if (!buffer) {
1586                 Eprintf ("Couldn't allocate memory in copy_mft()\n");
1587                 return 1;
1588         }
1589
1590         mft = ntfs_attr_open (vol->mft_ni, AT_DATA, NULL, 0);
1591         if (!mft) {
1592                 Eprintf ("Couldn't open $MFT/$DATA: %s\n", strerror (errno));
1593                 goto free;
1594         }
1595
1596         name = opts.output;
1597         if (!name) {
1598                 name = MFTFILE;
1599                 Dprintf ("No output filename, defaulting to '%s'.\n", name);
1600         }
1601
1602         create_pathname (opts.dest, name, NULL, pathname, sizeof (pathname));
1603         fd = open_file (pathname);
1604         if (fd < 0) {
1605                 Eprintf ("Couldn't open output file '%s': %s\n", name, strerror (errno));
1606                 goto attr;
1607         }
1608
1609         mft_end = min (mft_end, vol->nr_mft_records - 1);
1610
1611         Dprintf ("MFT records\n");
1612         Dprintf ("    Total: %8lld\n", vol->nr_mft_records);
1613         Dprintf ("    Begin: %8lld\n", mft_begin);
1614         Dprintf ("    End:   %8lld\n", mft_end);
1615
1616         for (i = mft_begin; i <= mft_end; i++) {
1617                 if (ntfs_attr_pread (mft, vol->mft_record_size * i, vol->mft_record_size, buffer) < vol->mft_record_size) {
1618                         Eprintf ("Couldn't read MFT Record %lld: %s.\n", i, strerror (errno));
1619                         goto close;
1620                 }
1621
1622                 if (write_data (fd, buffer, vol->mft_record_size) < vol->mft_record_size) {
1623                         Eprintf ("Write failed: %s\n", strerror (errno));
1624                         goto close;
1625                 }
1626         }
1627
1628         Vprintf ("Read %lld MFT Records\n", mft_end - mft_begin + 1);
1629         result = 0;
1630 close:
1631         close (fd);
1632 attr:
1633         ntfs_attr_close (mft);
1634 free:
1635         free (buffer);
1636         return result;
1637 }
1638
1639 /**
1640  * main - Begin here
1641  *
1642  * Start from here.
1643  *
1644  * Return:  0  Success, the program worked
1645  *          1  Error, something went wrong
1646  */
1647 int main (int argc, char *argv[])
1648 {
1649         ntfs_volume *vol;
1650         int result = 1;
1651
1652         if (!parse_options (argc, argv))
1653                 goto free;
1654
1655         utils_set_locale();
1656
1657         vol = utils_mount_volume (opts.device, MS_RDONLY, opts.force);
1658         if (!vol)
1659                 return 1;
1660
1661         switch (opts.mode) {
1662         case MODE_SCAN:
1663                 result = !scan_disk (vol);
1664                 if (result)
1665                         Vprintf ("Failed to scan device '%s'.\n", opts.device);
1666                 break;
1667         case MODE_UNDELETE:
1668                 result = !undelete_file (vol, opts.uinode);
1669                 if (result)
1670                         Vprintf ("Failed to undelete inode %d.\n", opts.uinode);
1671                 break;
1672         case MODE_COPY:
1673                 result = !copy_mft (vol, opts.mft_begin, opts.mft_end);
1674                 if (result)
1675                         Vprintf ("Failed to read MFT blocks %lld-%lld.\n",
1676                                 opts.mft_begin, min (vol->nr_mft_records, opts.mft_end));
1677                 break;
1678         default:
1679                 ; /* Cannot happen */
1680         }
1681
1682         ntfs_umount (vol, FALSE);
1683 free:
1684         if (opts.match)
1685                 free (opts.match);
1686
1687         return result;
1688 }
1689