Changes by: flatcap
Update of /cvsroot/linux-ntfs/linux-ntfs/ntfstools
In directory usw-pr-cvs1:/tmp/cvs-serv11841
Modified Files:
ntfsundelete.8.in ntfsundelete.c ntfsundelete.h
Log Message:
more tidying, more comments
Index: ntfsundelete.8.in
===================================================================
RCS file: /cvsroot/linux-ntfs/linux-ntfs/ntfstools/ntfsundelete.8.in,v
retrieving revision 1.2
retrieving revision 1.3
diff -U2 -r1.2 -r1.3
--- ntfsundelete.8.in 15 Jul 2002 02:57:21 -0000 1.2
+++ ntfsundelete.8.in 15 Jul 2002 16:30:41 -0000 1.3
@@ -1,7 +1,6 @@
-.\" -*- nroff -*-
.\" Copyright (c) 2002 Richard Russon. All Rights Reserved.
.\" This file may be copied under the terms of the GNU Public License.
.\"
-.TH NTFSUNDELETE 8 "June 2002" "Linux-NTFS version @VERSION@"
+.TH NTFSUNDELETE 8 "June 2002" "Linux\-NTFS version @VERSION@"
.SH NAME
ntfsundelete \- recover a deleted file from an NTFS volume.
@@ -13,9 +12,4 @@
.B device
.SH DESCRIPTION
-In the simplest case,
-.B ntfsundelete
-scans an NTFS volume for files that have been deleted and prints
-a list of them.
-.PP
.B ntfsundelete
has three modes of operation:
@@ -24,4 +18,24 @@
and
.I copy.
+
+
+
+
+In the simplest case,
+.B ntfsundelete
+scans an NTFS volume for files that have been deleted and prints
+a list of them.
+.PP
+
+
+.PP
+.B Note:
+.B ntfsundelete
+only ever
+.B reads
+from the NTFS Volume.
+.B ntfsundelete
+will never change the volume.
+
.SH OPTIONS
Below is a summary of all the options that
@@ -57,6 +71,6 @@
an NTFS volume, any filename matching (using the
.I \-\-match
-option) is case-insensitive. This option makes the maching
-case-sensitive.
+option) is case\-insensitive. This option makes the maching
+case\-sensitive.
.TP
.BI "\-\-copy " range
@@ -70,7 +84,7 @@
which will be created in the current directory. This option can
be combined with the
-.B --output
+.B \-\-output
and
-.B --destination
+.B \-\-destination
options.
.TP
@@ -110,5 +124,5 @@
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
+characters. By default the matching is case\-insensitive. To make the search
case sensitive, use the
.B \-\-case
@@ -121,7 +135,7 @@
.BI "\-\-output " file
Use this option to set name of output file that
-.B --undelete
+.B \-\-undelete
or
-.B --copy
+.B \-\-copy
will create.
.TP
@@ -146,9 +160,9 @@
This list can be filtered by filename, size, percentage recoverable or last
modification time, using the
-.B --match,
-.B --size,
-.B --percent
+.B \-\-match,
+.B \-\-size,
+.B \-\-percent
and
-.B --time
+.B \-\-time
options, respectively.
.TP
@@ -161,13 +175,13 @@
.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
+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
+.BI "\-t " since
.br
.ns
.TP
-.BI "\-\-time " time
+.BI "\-\-time " since
Filter the output of the
.B \-\-scan
@@ -182,8 +196,8 @@
.BI "\-\-undelete " num
Recover the file with this inode number. This option can be combined with
-.B --output,
-.B --destination,
+.B \-\-output,
+.B \-\-destination,
and
-.B --byte.
+.B \-\-byte.
.TP
.B \-v
@@ -205,4 +219,6 @@
.SH EXAMPLES
.SH CAVEATS
+.SS Miracles
+.SS Extended MFT Records
.B ntfsundelete
cannot perform miracles.
@@ -210,4 +226,7 @@
guarantee that the file hasn't been partially overwritten.
read only
+locale
+extended mft records != file framentation
+if you find this tool useful
potential, no guarantee
.SH BUGS
@@ -217,5 +236,5 @@
.SH AVAILABILITY
.B ntfsundelete
-is part of the linux-ntfs package and is available from
+is part of the linux\-ntfs package and is available from
.br
.nh
Index: ntfsundelete.c
===================================================================
RCS file: /cvsroot/linux-ntfs/linux-ntfs/ntfstools/ntfsundelete.c,v
retrieving revision 1.11
retrieving revision 1.12
diff -U2 -r1.11 -r1.12
--- ntfsundelete.c 15 Jul 2002 02:57:21 -0000 1.11
+++ ntfsundelete.c 15 Jul 2002 16:30:41 -0000 1.12
@@ -51,4 +51,7 @@
static const char *AUTHOR = "Richard Russon (FlatCap)";
static const char *EXEC_NAME = "ntfsundelete";
+static const char *MFTFILE = "mft";
+static char *UNKNOWN = "unknown";
+static char *NONAME = "<none>";
static struct options opts;
@@ -89,5 +92,5 @@
" -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"
+ " -t since --time since Last referenced since this time\n"
"\n"
" -u num --undelete num Undelete inode\n"
@@ -106,5 +109,4 @@
}
-
/**
* transform - Convert a shell style pattern to a regex
@@ -338,5 +340,4 @@
}
-
/**
* parse_options - Read and validate the programs command line
@@ -350,21 +351,21 @@
int parse_options (int argc, char *argv[])
{
- static const char *sopt = "-sp:m:CS:t:u:o:d:b:c:fvVh";
+ static const char *sopt = "-b:Cc:d:fhm:o:p:sS:t:u:vV";
static const struct option lopt[] = {
- { "scan", no_argument, NULL, 's' },
- { "percentage", required_argument, NULL, 'p' },
- { "match", required_argument, NULL, 'm' },
+ { "byte", required_argument, NULL, 'b' },
{ "case", no_argument, NULL, 'C' },
+ { "copy", required_argument, NULL, 'c' },
+ { "destination", required_argument, NULL, 'd' },
+ { "force", no_argument, NULL, 'f' },
+ { "help", no_argument, NULL, 'h' },
+ { "match", required_argument, NULL, 'm' },
+ { "output", required_argument, NULL, 'o' },
+ { "percentage", required_argument, NULL, 'p' },
+ { "scan", no_argument, NULL, 's' },
{ "size", required_argument, NULL, 'S' },
{ "time", required_argument, NULL, 't' },
{ "undelete", required_argument, NULL, 'u' },
- { "output", required_argument, NULL, 'o' },
- { "destination", required_argument, NULL, 'd' },
- { "byte", required_argument, NULL, 'b' },
- { "copy", required_argument, NULL, 'c' },
- { "force", no_argument, NULL, 'f' },
{ "verbose", no_argument, NULL, 'v' },
{ "version", no_argument, NULL, 'V' },
- { "help", no_argument, NULL, 'h' },
{ NULL }
};
@@ -393,20 +394,16 @@
}
break;
- case 's':
- if (opts.mode == MODE_NONE)
- opts.mode = MODE_SCAN;
- else
- opts.mode = MODE_ERROR;
- break;
- case 'u':
- if (opts.mode == MODE_NONE) {
- opts.mode = MODE_UNDELETE;
- opts.uinode = strtol (optarg, &end, 0);
+ case 'b':
+ if (opts.fillbyte == -1) {
+ opts.fillbyte = strtol (optarg, &end, 0);
if (end && *end)
err++;
} else {
- opts.mode = MODE_ERROR;
+ err++;
}
break;
+ case 'C':
+ opts.match_case++;
+ break;
case 'c':
if (opts.mode == MODE_NONE) {
@@ -418,34 +415,15 @@
}
break;
- case 'S':
- if ((opts.size_begin > 0) || (opts.size_end > 0) ||
- !parse_range (argv[optind-1], &opts.size_begin,
- &opts.size_end)) {
- err++;
- }
- break;
- case 't':
- if (opts.since == 0) {
- if (!parse_time (argv[optind-1], &opts.since))
- err++;
- } else {
- err++;
- }
- break;
- case 'o':
- if (!opts.output) {
- opts.output = argv[optind-1];
- } else {
+ case 'd':
+ if (!opts.dest)
+ opts.dest = argv[optind-1];
+ else
err++;
- }
break;
- case 'b':
- if (opts.fillbyte == -1) {
- opts.fillbyte = strtol (optarg, &end, 0);
- if (end && *end)
- err++;
- } else {
- err++;
- }
+ case 'f':
+ opts.force++;
+ break;
+ case 'h':
+ help++;
break;
case 'm':
@@ -455,4 +433,11 @@
err++;
break;
+ case 'o':
+ if (!opts.output) {
+ opts.output = argv[optind-1];
+ } else {
+ err++;
+ }
+ break;
case 'p':
if (opts.percent == -1) {
@@ -464,15 +449,34 @@
}
break;
- case 'd':
- if (!opts.dest)
- opts.dest = argv[optind-1];
+ case 's':
+ if (opts.mode == MODE_NONE)
+ opts.mode = MODE_SCAN;
else
- err++;
+ opts.mode = MODE_ERROR;
break;
- case 'C':
- opts.match_case++;
+ case 'S':
+ if ((opts.size_begin > 0) || (opts.size_end > 0) ||
+ !parse_range (argv[optind-1], &opts.size_begin,
+ &opts.size_end)) {
+ err++;
+ }
break;
- case 'f':
- opts.force++;
+ case 't':
+ if (opts.since == 0) {
+ if (!parse_time (argv[optind-1], &opts.since))
+ err++;
+ } else {
+ err++;
+ }
+ break;
+ case 'u':
+ if (opts.mode == MODE_NONE) {
+ opts.mode = MODE_UNDELETE;
+ opts.uinode = strtol (optarg, &end, 0);
+ if (end && *end)
+ err++;
+ } else {
+ opts.mode = MODE_ERROR;
+ }
break;
case 'v':
@@ -482,13 +486,10 @@
ver++;
break;
- case 'h':
- help++;
- break;
default:
- if (((optopt == 'u') || (optopt == 'o') ||
- (optopt == 'd') || (optopt == 'p') ||
- (optopt == 'b') || (optopt == 'c') ||
- (optopt == 'm') || (optopt == 'S') ||
- (optopt == 't')) && (!optarg)) {
+ if (((optopt == 'b') || (optopt == 'c') ||
+ (optopt == 'd') || (optopt == 'm') ||
+ (optopt == 'o') || (optopt == 'p') ||
+ (optopt == 'S') || (optopt == 't') ||
+ (optopt == 'u')) && (!optarg)) {
printf ("Option '%s' requires an "
"argument.\n", argv[optind-1]);
@@ -519,5 +520,5 @@
err++;
}
- if (opts.case && !opts.match) {
+ if (opts.match_case && !opts.match) {
printf ("The --case option doesn't make sense without the --match option\n");
err++;
@@ -560,5 +561,4 @@
}
-
/**
* ntfs2utc - Convert an NTFS time to Unix time
@@ -583,5 +583,6 @@
* given attribute type.
*
- * XXX it won't overflow the buffer as long as the context doesn't include an inode.
+ * N.B. This will return a pointer into @mft. As long as the search context
+ * has been created without an inode, it won't overflow the buffer.
*
* Return: Pointer Success, an attribute was found
@@ -607,4 +608,7 @@
* The return value is a pointer into the MFT record that was supplied.
*
+ * N.B. This will return a pointer into @mft. The pointer won't stray outside
+ * the buffer, since we created the search context without an inode.
+ *
* Return: Pointer Success, an attribute was found
* NULL Error, no matching attributes were found
@@ -658,5 +662,4 @@
}
-
/**
* cluster_in_use - Determine if a cluster is in use
@@ -715,5 +718,5 @@
/**
- * get_filenames - Read the MFT Record's $FILENAME attributes
+ * get_filenames - Read an MFT Record's $FILENAME attributes
* @file: The file object to work with
*
@@ -727,4 +730,6 @@
* object.
*
+ * XXX pref_name
+ *
* Return: n The number of $FILENAME attributes found
* -1 Error
@@ -735,6 +740,7 @@
FILE_NAME_ATTR *attr;
ntfs_attr_search_ctx *ctx;
- int count = 0;
struct filename *name;
+ int count = 0;
+ int space = 4;
if (!file)
@@ -776,4 +782,9 @@
}
+ if (attr->file_name_type < space) {
+ file->pref_name = name->name;
+ space = attr->file_name_type;
+ }
+
list_add_tail (&name->list, &file->name);
count++;
@@ -785,5 +796,5 @@
/**
- * get_data - Read the MFT Record's $DATA attributes
+ * get_data - Read an MFT Record's $DATA attributes
* @file: The file object to work with
* @vol: An ntfs volume obtained from ntfs_mount
@@ -858,5 +869,4 @@
}
-
/**
* read_record - Read an MFT record into memory
@@ -1176,5 +1186,4 @@
struct list_head *item;
char *name = NULL;
- int space = 4;
long long size = 0;
int percent = 0;
@@ -1192,16 +1201,4 @@
flagd = 'F';
- list_for_each (item, &file->name) {
- struct filename *f = list_entry (item, struct filename, list);
-
- if (f->name_space < space) {
- name = f->name;
- space = f->name_space;
- }
-
- //size = max (size, f->size_alloc);
- //size = max (size, f->size_data);
- }
-
list_for_each (item, &file->data) {
struct data *d = list_entry (item, struct data, list);
@@ -1221,6 +1218,8 @@
}
- if (!name)
- name = "<none>";
+ if (file->pref_name)
+ name = file->pref_name;
+ else
+ name = NONAME;
printf ("%-8lld %c%c%c%c%c %3d%% %s %9lld %s\n",
@@ -1229,5 +1228,4 @@
}
-
/**
* name_match - Does a file have a name matching a regex
@@ -1266,7 +1264,15 @@
}
-
/**
- * scan_disk
+ * scan_disk - Search an NTFS volume for files that could be undeleted
+ * @vol: An ntfs volume obtained from ntfs_mount
+ *
+ * Read through all the MFT entries looking for deleted files. For each one
+ * determine how much of the data lies in unused disk space.
+ *
+ * The list can be filtered by name, size and date, using command line options.
+ *
+ * Return: -1 Error, something went wrong
+ * n Success, the number of recoverable files
*/
int scan_disk (ntfs_volume *vol)
@@ -1360,7 +1366,14 @@
}
-
/**
- * write_data
+ * write_data - Write out a block of data
+ * @fd: File descriptor to write to
+ * @buffer: Data to write
+ * @bufsize: Amount of data to write
+ *
+ * Write a block of data to a file descriptor.
+ *
+ * Return: -1 Error, something went wrong
+ * 0 Success, all the data was written
*/
int write_data (int fd, const char *buffer, int bufsize)
@@ -1383,48 +1396,67 @@
result2 = write (fd, buffer, bufsize);
if (result2 < 0)
- return result2;
+ return result1;
return result1 + result2;
}
-
/**
- * open_file
+ * open_file - Create a file based on the dir, name and stream supplied
+ * @dir: Directory in which to create the file (optional)
+ * @name: Filename to give the file (optional)
+ * @stream: Name of the stream (optional)
+ *
+ * Create a file and return the file descriptor. All the components are
+ * optional. If the name is missing, "unknown" will be used. If the directory
+ * is missing the file will be created in the current directory. If the stream
+ * name is present it will be appended to the filename, delimited by a colon.
+ *
+ * Return: -1 Error, failed to create the file
+ * n Success, this is the file descriptor
*/
-int open_file (struct ufile *file, char *dest)
+int open_file (const char *dir, const char *name, const char *stream)
{
- char buffer[256];
- struct list_head *item;
- char *name = NULL;
- int space = 4;
-
- if (!file)
- return -1;
-
- list_for_each (item, &file->name) {
- struct filename *f = list_entry (item, struct filename, list);
-
- if (f->name_space >= space)
- continue;
-
- name = f->name;
- space = f->name_space;
- }
+ char buf[256];
if (!name)
- name = "unknown";
+ name = UNKNOWN;
- if (dest)
- snprintf (buffer, sizeof (buffer), "%s/%s", dest, name);
+ if (dir)
+ if (stream)
+ snprintf (buf, sizeof (buf), "%s/%s:%s", dir, name, stream);
+ else
+ snprintf (buf, sizeof (buf), "%s/%s", dir, name);
else
- snprintf (buffer, sizeof (buffer), "%s", name);
+ if (stream)
+ snprintf (buf, sizeof (buf), "%s:%s", name, stream);
+ else
+ snprintf (buf, sizeof (buf), "%s", name);
- printf ("Creating file: %s\n", buffer);
+ printf ("Creating file: %s\n", buf);
- return open (buffer, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR);
+ return open (buf, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR);
}
/**
- * undelete_file
+ * undelete_file - Recover a deleted file from an NTFS volume
+ * @vol: An ntfs volume obtained from ntfs_mount
+ * @inode: MFT Record number to be recovered
+ *
+ * Read an MFT Record and try an recover any data associated with it. Some of
+ * the clusters may be in use; these will be filled with zeros or the fill byte
+ * supplied in the options.
+ *
+ * Each data stream will be recovered and saved to a file. The file's name will
+ * be the original filename and it will be written to the current directory.
+ * Any named data stream will be saved as filename:streamname.
+ *
+ * The output file's name and location can be altered by using the command line
+ * options.
+ *
+ * N.B. We cannot tell if someone has overwritten some of the data since the
+ * file was deleted.
+ *
+ * Return: 0 Error, something went wrong
+ * 1 Success, the data was recovered
*/
int undelete_file (ntfs_volume *vol, long long inode)
@@ -1472,11 +1504,13 @@
struct data *d = list_entry (item, struct data, list);
+ /*
if (d->name) {
printf ("skipping named stream\n");
continue;
}
+ **/
if (d->resident) {
- fd = open_file (file, opts.dest);
+ fd = open_file (opts.dest, file->pref_name, d->name);
if (fd < 0) {
printf ("couldn't create file\n");
@@ -1507,5 +1541,5 @@
}
- fd = open_file (file, opts.dest);
+ fd = open_file (opts.dest, file->pref_name, d->name);
if (fd < 0) {
printf ("couldn't create file\n");
@@ -1591,12 +1625,20 @@
}
-
/**
- * copy_mft
+ * copy_mft - Write a range of MFT Records to a file
+ * @vol: An ntfs volume obtained from ntfs_mount
+ * @mft_begin: First MFT Record to save
+ * @mft_end: Last MFT Record to save
+ *
+ * Read a number of MFT Records and write them to a file.
+ *
+ * Return: 0 Success, all the records were written
+ * 1 Error, something went wrong
*/
int copy_mft (ntfs_volume *vol, long long mft_begin, long long mft_end)
{
ntfs_attr *mft;
- char *buffer = NULL;
+ char *buffer;
+ const char *name;
long long i;
int result = 1;
@@ -1606,4 +1648,7 @@
return 1;
+ if (mft_end < mft_begin)
+ return 1;
+
buffer = malloc (vol->mft_record_size);
if (!buffer)
@@ -1615,7 +1660,13 @@
}
- fd = open ("mft", O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
- if (fd < 0)
+ name = opts.output;
+ if (!name)
+ name = MFTFILE;
+
+ fd = open_file (opts.dest, MFTFILE, NULL);
+ if (fd < 0) {
+ printf ("error\n");
goto attr;
+ }
//printf ("MFT records\n");
@@ -1627,5 +1678,5 @@
for (i = mft_begin; i <= mft_end; i++) {
- printf ("for i = %lld\n", 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");
@@ -1649,7 +1700,14 @@
}
-
/**
- * valid_device
+ * valid_device - Perform some safety checks on the device, before we start
+ * @name: Full pathname of the device/file to work with
+ * @force: Continue regardless of problems
+ *
+ * Check that the name refers to a device and that is isn't already mounted.
+ * These checks can be overridden by using the force option.
+ *
+ * Return: 0 Error, we cannot use this device
+ * 1 Success, we can continue
*/
int valid_device (const char *name, int force)
@@ -1695,5 +1753,10 @@
/**
- * main
+ * main - Begin here
+ *
+ * Start from here.
+ *
+ * Return: 0 Success, the program worked
+ * 1 Error, something went wrong
*/
int main (int argc, char *argv[])
Index: ntfsundelete.h
===================================================================
RCS file: /cvsroot/linux-ntfs/linux-ntfs/ntfstools/ntfsundelete.h,v
retrieving revision 1.7
retrieving revision 1.8
diff -U2 -r1.7 -r1.8
--- ntfsundelete.h 14 Jul 2002 15:53:03 -0000 1.7
+++ ntfsundelete.h 15 Jul 2002 16:30:41 -0000 1.8
@@ -93,4 +93,5 @@
struct list_head name; /* A list of filenames */
struct list_head data; /* A list of data streams */
+ char *pref_name; /* The preferred filename */
int attr_list; /* MFT record may be one of many */
int directory; /* MFT record represents a directory */
|