Changes by: flatcap
Update of /cvsroot/linux-ntfs/linux-ntfs/ntfstools
In directory usw-pr-cvs1:/tmp/cvs-serv11411
Modified Files:
ntfsundelete.8.in ntfsundelete.c
Log Message:
start tidying up and documenting
Index: ntfsundelete.8.in
===================================================================
RCS file: /cvsroot/linux-ntfs/linux-ntfs/ntfstools/ntfsundelete.8.in,v
retrieving revision 1.1
retrieving revision 1.2
diff -U2 -r1.1 -r1.2
--- ntfsundelete.8.in 30 Jun 2002 22:46:51 -0000 1.1
+++ ntfsundelete.8.in 15 Jul 2002 02:57:21 -0000 1.2
@@ -1,4 +1,4 @@
.\" -*- nroff -*-
-.\" Copyright (c) 2002 Anton Altaparmakov. All Rights Reserved.
+.\" Copyright (c) 2002 Richard Russon. All Rights Reserved.
.\" This file may be copied under the terms of the GNU Public License.
.\"
@@ -8,9 +8,208 @@
.SH SYNOPSIS
.B ntfsundelete
-.I [options]
-.I device
+[
+.I options
+]
+.B device
.SH DESCRIPTION
+In the simplest case,
.B ntfsundelete
-will try to recover a deleted file from an NTFS volume.
+scans an NTFS volume for files that have been deleted and prints
+a list of them.
+.PP
+.B ntfsundelete
+has three modes of operation:
+.I scan,
+.I undelete
+and
+.I copy.
+.SH OPTIONS
+Below is a summary of all the options that
+.B ntfsundelete
+accepts. All options have two equivalent names. The short name
+is preceded by
+.BR \-
+and the long name is preceded by
+.BR \-\- .
+Any single letter options, that don't take an argument, can be
+combined into a single command, e.g.
+.BR \-fv
+is equivalent to
+.BR "\-f \-v".
+Long named options can be abbreviated to any unique prefix of
+their name.
+.TP
+.BI "\-b " num
+.br
+.ns
+.TP
+.BI "\-\-byte " num
+If any clusters of the file cannot be recovered, the missing
+parts will be filled with this byte. The default is zeros.
+.TP
+.B \-C
+.br
+.ns
+.TP
+.B \-\-case
+When
+.I scanning
+an NTFS volume, any filename matching (using the
+.I \-\-match
+option) is case-insensitive. This option makes the maching
+case-sensitive.
+.TP
+.BI "\-\-copy " range
+.br
+.ns
+.TP
+.BI "\-c " range
+This wizard's option will write a block of MFT FILE records to
+a file. The default file is
+.I mft
+which will be created in the current directory. This option can
+be combined with the
+.B --output
+and
+.B --destination
+options.
+.TP
+.BI "\-d " dir
+.br
+.ns
+.TP
+.BI "\-\-destination " dir
+This option controls where to put the output file of the
+.B \-\-undelete
+and
+.B \-\-copy
+options.
+.TP
+.B \-f
+.br
+.ns
+.TP
+.B \-\-force
+This will override some sensible defaults, such as not overwriting an existing
+file. Use this option with caution.
+.TP
+.B \-h
+.br
+.ns
+.TP
+.B \-\-help
+Show a list of options with a brief description of each one.
+.TP
+.BI "\-m " pattern
+.br
+.ns
+.TP
+.BI "\-\-match " pattern
+Filter the output of the
+.B \-\-scan
+option, by only looking for matching filenames. The pattern can include the
+wildcards '?', match exactly one character or '*', match zero or more
+characters. By default the matching is case-insensitive. To make the search
+case sensitive, use the
+.B \-\-case
+option.
+.TP
+.BI "\-o " file
+.br
+.ns
+.TP
+.BI "\-\-output " file
+Use this option to set name of output file that
+.B --undelete
+or
+.B --copy
+will create.
+.TP
+.BI "\-p " num
+.br
+.ns
+.TP
+.BI "\-\-percentage " num
+Filter the output of the
+.B \-\-scan
+option, by only matching files with a certain amount of recoverable content.
+.B Please read the caveats section for more details.
+.TP
+.B \-s
+.br
+.ns
+.TP
+.B \-\-scan
+Search through an NTFS volume and print a list of files that could be recovered.
+This is the default action of
+.B ntfsundelete.
+This list can be filtered by filename, size, percentage recoverable or last
+modification time, using the
+.B --match,
+.B --size,
+.B --percent
+and
+.B --time
+options, respectively.
+.TP
+.BI "\-S " range
+.br
+.ns
+.TP
+.BI "\-\-size " range
+Filter the output of the
+.B \-\-scan
+option, by looking for a particular range of file sizes. The range may be
+specified as two numbers separated by a '-'. The sizes may be abbreviated
+using the suffixes k, m, g, t, for kilobytes, megabytes, gigabytes and terabytes
+respectively.
+.TP
+.BI "\-t " time
+.br
+.ns
+.TP
+.BI "\-\-time " time
+Filter the output of the
+.B \-\-scan
+option. Only match files that have been altered since this time. The time must
+be given as number using a suffix of d, w, m, y for days, weeks, months or years
+ago.
+.TP
+.BI "\-u " num
+.br
+.ns
+.TP
+.BI "\-\-undelete " num
+Recover the file with this inode number. This option can be combined with
+.B --output,
+.B --destination,
+and
+.B --byte.
+.TP
+.B \-v
+.br
+.ns
+.TP
+.B \-\-verbose
+Increase the amount of output that
+.B ntfsundelete
+prints.
+.TP
+.B \-V
+.br
+.ns
+.TP
+.B \-\-version
+Show the version number, copyright and license
+.B ntfsundelete.
+.SH EXAMPLES
+.SH CAVEATS
+.B ntfsundelete
+cannot perform miracles.
+Even if a file is entirely within unused portions of the disk, it does not
+guarantee that the file hasn't been partially overwritten.
+read only
+potential, no guarantee
+.SH BUGS
.SH AUTHOR
.B ntfsundelete
@@ -19,5 +218,14 @@
.B ntfsundelete
is part of the linux-ntfs package and is available from
-http://linux-ntfs.sourceforge.net/.
-
-
+.br
+.nh
+http://linux\-ntfs.sourceforge.net/downloads.html
+.hy
+This manual page is available online at:
+.br
+.nh
+http://linux\-ntfs.sourceforge.net/tools/ntfsundelete.html
+.hy
+.SH SEE ALSO
+.BR ntfsinfo(8)
+.br
Index: ntfsundelete.c
===================================================================
RCS file: /cvsroot/linux-ntfs/linux-ntfs/ntfstools/ntfsundelete.c,v
retrieving revision 1.10
retrieving revision 1.11
diff -U2 -r1.10 -r1.11
--- ntfsundelete.c 14 Jul 2002 15:53:03 -0000 1.10
+++ ntfsundelete.c 15 Jul 2002 02:57:21 -0000 1.11
@@ -84,22 +84,22 @@
{
printf ("Usage: %s [options] device\n"
- " -s --scan Scan for files (default)\n"
- " -p num --percentage num Minimum percentage recoverable\n"
- " -m regex --match regex Only work on files with matching names\n"
- " -C --case Case sensitive matching\n"
- " -S range --size range Match files of this size\n"
- " -t time --time time Last referenced since this time\n"
+ " -s --scan Scan for files (default)\n"
+ " -p num --percentage num Minimum percentage recoverable\n"
+ " -m pattern --match pattern Only work on files with matching names\n"
+ " -C --case Case sensitive matching\n"
+ " -S range --size range Match files of this size\n"
+ " -t time --time time Last referenced since this time\n"
"\n"
- " -u num --undelete num Undelete inode\n"
- " -o file --output file Save with this filename\n"
- " -d dir --destination dir Destination directory\n"
- " -b num --byte num Fill missing parts with this byte\n"
+ " -u num --undelete num Undelete inode\n"
+ " -o file --output file Save with this filename\n"
+ " -d dir --destination dir Destination directory\n"
+ " -b num --byte num Fill missing parts with this byte\n"
"\n"
- " -c range --copy range Write a range of MFT records to a file\n"
+ " -c range --copy range Write a range of MFT records to a file\n"
"\n"
- " -f --force Use less caution\n"
- " -v --verbose More output\n"
- " -V --version Version information\n"
- " -h --help Print this help\n\n",
+ " -f --force Use less caution\n"
+ " -v --verbose More output\n"
+ " -V --version Version information\n"
+ " -h --help Print this help\n\n",
EXEC_NAME);
@@ -108,5 +108,20 @@
/**
- * transform
+ * transform - Convert a shell style pattern to a regex
+ * @pattern: The string to be converted
+ *
+ * This will transform patterns, such as "*.doc" to true regular expressions.
+ * The function will also place '^' and '$' around the expression to make it
+ * behave as the user would expect
+ *
+ * Before After
+ * . \.
+ * * .*
+ * ? .
+ *
+ * N.B. The returned string must be freed by the caller.
+ *
+ * Return: Pointer, A newly allocated string for the regex
+ * NULL An error occurred
*/
char * transform (const char *pattern)
@@ -159,5 +174,24 @@
/**
- * parse_time
+ * parse_time - Convert a time abbreviation to seconds
+ * @string: The string to be converted
+ * @since: The absolute time referred to
+ *
+ * Strings representing times will be converted into a time_t. The numbers will
+ * be regarded as seconds unless suffixed.
+ *
+ * Suffix Description
+ * [yY] Year
+ * [mM] Month
+ * [wW] Week
+ * [dD] Day
+ * [sS] Second
+ *
+ * Therefore, passing "1W" will return the time_t representing 1 week ago.
+ *
+ * N.B. Only the first character of the suffix is read.
+ *
+ * Return: 1 Success
+ * 0 Error, the string was malformed
*/
int parse_time (const char *string, time_t *since)
@@ -187,5 +221,4 @@
case 'd': case 'D': result *= 24;
case 'h': case 'H': result *= 3600;
- case 's': case 'S':
case 0:
break;
@@ -202,5 +235,20 @@
/**
- * parse_size
+ * parse_size - Convert a string representing a size
+ * @value: The string to be parsed
+ *
+ * Read a string and convert it to a number. Strings may be suffixed to scale
+ * them. Any number without a suffix is assumed to be in bytes.
+ *
+ * Suffix Description Multiple
+ * [tT] Terabytes 10^12
+ * [gG] Gigabytes 10^9
+ * [mM] Megabytes 10^6
+ * [kK] Kilobytes 10^3
+ *
+ * N.B. The multipliers are decimal thousands, not binary: 1000, not 1024.
+ *
+ * Return: n The parsed valued
+ * -1 An error occurred
*/
long long parse_size (const char *value)
@@ -229,4 +277,9 @@
case 'm': case 'M': result *= 1000;
case 'k': case 'K': result *= 1000;
+ case '-': case 0:
+ break;
+ default:
+ printf ("bad suffix\n");
+ return -1;
}
@@ -235,5 +288,15 @@
/**
- * parse_range
+ * parse_range - Convert a string representing a range of numbers
+ * @string: The string to be parsed
+ * @start: The beginning of the range will be stored here
+ * @finish: The end of the range will be stored here
+ *
+ * Read a string of the form n-m. If the lower end is missing, zero will be
+ * substituted. If the upper end is missing LONG_MAX will be used. If the
+ * string cannot be parsed correctly, @start and @finish will not be changed.
+ *
+ * Return: 1 Success, a valid string was found
+ * 0 Error, the string was not a valid range
*/
int parse_range (const char *string, long long *start, long long *finish)
@@ -246,9 +309,4 @@
middle = strchr (string, '-');
- if (!middle) {
- //printf ("strchr\n");
- return 0;
- }
-
if (string == middle) {
//printf ("no start\n");
@@ -260,19 +318,25 @@
}
- if (middle[1] == 0) {
- //printf ("no stop\n");
- b = LONG_MAX;
+ if (middle) {
+ if (middle[1] == 0) {
+ //printf ("no stop\n");
+ b = LONG_MAX;
+ } else {
+ b = parse_size (middle+1);
+ if (b < 0)
+ return 0;
+ }
} else {
- b = parse_size (middle+1);
- if (b < 0)
- return 0;
+ b = a;
}
*start = a;
*finish = b;
+ printf ("range = %lld - %lld\n", a, b);
return 1;
}
+
/**
* parse_options - Read and validate the programs command line
@@ -343,12 +407,14 @@
} else {
opts.mode = MODE_ERROR;
- err++;
}
break;
case 'c':
- if (opts.mode == MODE_NONE)
+ if (opts.mode == MODE_NONE) {
+ if (!parse_range (argv[optind-1], &opts.mft_begin, &opts.mft_end))
+ err++;
opts.mode = MODE_COPY;
- else
+ } else {
opts.mode = MODE_ERROR;
+ }
break;
case 'S':
@@ -423,6 +489,6 @@
(optopt == 'd') || (optopt == 'p') ||
(optopt == 'b') || (optopt == 'c') ||
- (optopt == 'm') || (optopt == 'S')) &&
- (!optarg)) {
+ (optopt == 'm') || (optopt == 'S') ||
+ (optopt == 't')) && (!optarg)) {
printf ("Option '%s' requires an "
"argument.\n", argv[optind-1]);
@@ -450,5 +516,9 @@
if (opts.output || opts.dest || (opts.fillbyte != -1)) {
printf ("Scan can only be used with --percent, "
- "--match, --ignore-case or --size.\n");
+ "--match, --ignore-case, --size and --time.\n");
+ err++;
+ }
+ if (opts.case && !opts.match) {
+ printf ("The --case option doesn't make sense without the --match option\n");
err++;
}
@@ -458,5 +528,5 @@
(opts.size_begin > 0) || (opts.size_end > 0)) {
printf ("Undelete can only be used with "
- "--output, --destination or --byte.\n");
+ "--output, --destination and --byte.\n");
err++;
}
@@ -467,5 +537,5 @@
opts.match_case || (opts.size_begin > 0) ||
(opts.size_end > 0)) {
- printf ("Copy can only be used with --output\n");
+ printf ("Copy can only be used with --output and --destination.\n");
err++;
}
@@ -487,5 +557,5 @@
usage();
- return (err == 0);
+ return ((err == 0) && !help && !ver);
}
@@ -1161,5 +1231,13 @@
/**
- * name_match
+ * name_match - Does a file have a name matching a regex
+ * @re: The regular expression object
+ * @file: The file to be tested
+ *
+ * Iterate through the file's $FILENAME attributes and compare them against the
+ * regular expression, created with regcomp.
+ *
+ * Return: 1 There is a matching filename.
+ * 0 There is no match.
*/
int name_match (regex_t *re, struct ufile *file)
@@ -1188,4 +1266,5 @@
}
+
/**
* scan_disk
@@ -1516,7 +1595,56 @@
* copy_mft
*/
-int copy_mft (ntfs_volume *vol)
+int copy_mft (ntfs_volume *vol, long long mft_begin, long long mft_end)
{
- return 0;
+ ntfs_attr *mft;
+ char *buffer = NULL;
+ long long i;
+ int result = 1;
+ int fd;
+
+ if (!vol)
+ return 1;
+
+ buffer = malloc (vol->mft_record_size);
+ if (!buffer)
+ return 1;
+
+ mft = ntfs_attr_open (vol->mft_ni, AT_DATA, NULL, 0);
+ if (!mft) {
+ goto free;
+ }
+
+ fd = open ("mft", O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
+ if (fd < 0)
+ goto attr;
+
+ //printf ("MFT records\n");
+ //printf (" Total: %8lld\n", vol->nr_mft_records);
+ //printf (" Begin: %8lld\n", mft_begin);
+ //printf (" End: %8lld\n", mft_end);
+
+ mft_end = min (mft_end, vol->nr_mft_records - 1);
+
+ for (i = mft_begin; i <= mft_end; i++) {
+ printf ("for i = %lld\n", i);
+ if (ntfs_attr_pread (mft, vol->mft_record_size * i, vol->mft_record_size, buffer) < vol->mft_record_size) {
+ printf ("ntfs_attr_pread failed\n");
+ goto close;
+ }
+
+ if (write_data (fd, buffer, vol->mft_record_size) < vol->mft_record_size) {
+ printf ("write_data failed\n");
+ goto close;
+ }
+ }
+
+ result = 0;
+close:
+ close (fd);
+attr:
+ ntfs_attr_close (mft);
+free:
+ free (buffer);
+ return result;
}
@@ -1604,5 +1732,5 @@
break;
case MODE_COPY:
- result = copy_mft (vol);
+ result = copy_mft (vol, opts.mft_begin, opts.mft_end);
break;
default:
|