Changes by: flatcap
Update of /cvsroot/linux-ntfs/linux-ntfs/ntfstools
In directory usw-pr-cvs1:/tmp/cvs-serv5862
Modified Files:
ntfsundelete.c ntfsundelete.h
Log Message:
start to fill in the options
Index: ntfsundelete.c
===================================================================
RCS file: /cvsroot/linux-ntfs/linux-ntfs/ntfstools/ntfsundelete.c,v
retrieving revision 1.6
retrieving revision 1.7
diff -U2 -r1.6 -r1.7
--- ntfsundelete.c 11 Jul 2002 13:18:11 -0000 1.6
+++ ntfsundelete.c 13 Jul 2002 16:33:00 -0000 1.7
@@ -36,4 +36,7 @@
#include <getopt.h>
#include <time.h>
+#include <limits.h>
+#include <regex.h>
+#include <libintl.h>
#include "ntfsundelete.h"
@@ -49,4 +52,6 @@
static struct options opts;
+#define _(S) gettext(S)
+
/**
* version - Print version information about the program
@@ -78,32 +83,201 @@
{
printf ("Usage: %s [options] device\n"
- " -s --scan Scan for files (default)\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"
+ " -i --ignore-case Case insensive matching\n"
+ " -S range --size range Match files of this size\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"
"\n"
- " -u num --undelete num Undelete inode\n"
- // " -n stream --name stream Undelete the named stream\n"
- // " -a --all Undelete all files\n"
- " -d dir --destination dir Destination directory\n"
- // " -o file --output file Save with this filename\n"
- " -p num --percentage num Minimum percentage recoverable\n"
- // " -b file --byte num Fill missing parts with this byte\n"
+ " -c range --copy range Write a range of MFT records to a file\n"
"\n"
- // " -m regex --match regex Only work on files with matching names\n"
- // " -i --ignore-case Case insensive matching\n"
- // " -S range --size range Match files of this size\n"
- // "\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);
}
+
+#if 0
+/**
+ * create_regex
+ */
+int create_regex (const char *pattern, int case, regex_t *re)
+{
+ int result;
+ int retval = 1;
+ char *arg1, *arg2;
+
+ arg1 = create_regex (argv[1]);
+ arg2 = argv[2];
+ if (!arg1) {
+ printf ("create_regex\n");
+ goto free;
+ }
+
+ //printf ("match '%s' = regex '%s'\n", argv[1], arg1);
+
+ if (regcomp (&re, arg1, REG_NOSUB)) {
+ printf ("regcomp\n");
+ goto out;
+ }
+
+ result = regexec (&re, arg2, 0, NULL, 0);
+ if (result < 0) {
+ printf ("regexec\n");
+ goto rfree;
+ }
+
+ if (result == REG_NOMATCH) {
+ printf ("no match\n");
+ goto rfree;
+ }
+
+ printf ("match\n");
+ retval = 0;
+
+rfree:
+ regfree (&re);
+free:
+ free (arg1);
+out:
+ return retval;
+}
+
+#endif
+
+/**
+ * transform
+ */
+char * transform (const char *pattern)
+{
+ char *result;
+ int length, i, j;
+
+ if (!pattern) {
+ errno = EINVAL;
+ return NULL;
+ }
+
+ length = strlen (pattern);
+ if (length < 1) {
+ errno = EINVAL;
+ return NULL;
+ }
+
+ for (i = 0; pattern[i]; i++) {
+ if ((pattern[i] == '*') || (pattern[i] == '.'))
+ length++;
+ }
+
+ result = malloc (length + 1);
+ if (!result)
+ return NULL;
+
+ for (i = 0, j = 0; pattern[i]; i++, j++) {
+ if (pattern[i] == '*') {
+ result[j] = '.';
+ j++;
+ result[j] = '*';
+ } else if (pattern[i] == '.') {
+ result[j] = '\\';
+ j++;
+ result[j] = '.';
+ } else if (pattern[i] == '?') {
+ result[j] = '.';
+ } else {
+ result[j] = pattern[i];
+ }
+ }
+
+ return result;
+}
+
+/**
+ * parse_size
+ */
+long long parse_size (const char *value)
+{
+ unsigned long long result;
+ char mult = 0;
+
+ if (!value) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ for (result = 0; *value; value++) {
+ if ((*value >= '0') && (*value <= '9')) {
+ result *= 10;
+ result += *value - '0';
+ } else {
+ mult = *value;
+ break;
+ }
+ }
+
+ switch (mult) {
+ case 't': case 'T': result *= 1000;
+ case 'g': case 'G': result *= 1000;
+ case 'm': case 'M': result *= 1000;
+ case 'k': case 'K': result *= 1000;
+ }
+
+ return result;
+}
+
+/**
+ * parse_range
+ */
+int parse_range (const char *string, long long *start, long long *finish)
+{
+ long long a, b;
+ char *middle;
+
+ if (!start || !finish)
+ return 0;
+
+ middle = strchr (string, '-');
+ if (!middle) {
+ //printf ("strchr\n");
+ return 0;
+ }
+
+ if (string == middle) {
+ //printf ("no start\n");
+ a = 0;
+ } else {
+ a = parse_size (string);
+ if (a < 0)
+ return 0;
+ }
+
+ if (middle[1] == 0) {
+ //printf ("no stop\n");
+ b = LONG_MAX;
+ } else {
+ b = parse_size (middle+1);
+ if (b < 0)
+ return 0;
+ }
+
+ *start = a;
+ *finish = b;
+
+ return 1;
+}
+
+
/**
* parse_options - Read and validate the programs command line
*
* Read the command line, verify the syntax and parse the options.
+ * This function is very long, but quite simple.
*
* Return: 0 Success
@@ -112,19 +286,17 @@
int parse_options (int argc, char *argv[])
{
- const char *sopt = "-su:p:d:vVh"; // "-su:n:ad:o:p:b:m:iS:c:fvVh";
- const struct option lopt[] = {
+ static const char *sopt = "-sp:m:iS:u:o:d:b:c:fvVh";
+ static const struct option lopt[] = {
{ "scan", no_argument, NULL, 's' },
+ { "percentage", required_argument, NULL, 'p' },
+ { "match", required_argument, NULL, 'm' },
+ { "ignore-case", no_argument, NULL, 'i' },
+ { "size", required_argument, NULL, 'S' },
{ "undelete", required_argument, NULL, 'u' },
- // { "name", required_argument, NULL, 'n' },
- // { "all", no_argument, NULL, 'a' },
+ { "output", required_argument, NULL, 'o' },
{ "destination", required_argument, NULL, 'd' },
- // { "output", required_argument, NULL, 'o' },
- { "percentage", required_argument, NULL, 'p' },
- // { "byte", required_argument, NULL, 'b' },
- // { "match", required_argument, NULL, 'm' },
- // { "ignore-case", no_argument, NULL, 'i' },
- // { "size", required_argument, NULL, 'S' },
- // { "copy", required_argument, NULL, 'c' },
- // { "force", no_argument, NULL, 'f' },
+ { "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' },
@@ -141,72 +313,159 @@
opterr = 0; /* We'll handle the errors, thank you. */
- opts.uinode = -1;
+ opts.mode = MODE_NONE;
+ opts.uinode = -1;
+ opts.percent = -1;
+ opts.fillbyte = -1;
while ((c = getopt_long (argc, argv, sopt, lopt, NULL)) != -1) {
switch (c) {
- case 1: /* A non-option argument */
- if (!opts.device)
- opts.device = argv[optind-1];
- else
- err++;
- break;
- case 's':
- opts.scan++;
- break;
- case 'u':
- if (opts.uinode < 0) {
- opts.uinode = strtol (optarg, &end, 0);
- if (end && *end)
- err++;
- } else {
+ case 1: /* A non-option argument */
+ if (!opts.device) {
+ opts.device = argv[optind-1];
+ } else {
+ opts.device = NULL;
+ err++;
+ }
+ 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);
+ if (end && *end)
err++;
- }
- break;
- case 'p':
- if (opts.percent == 0) {
- opts.percent = strtol (optarg, &end, 0);
- if (end && *end)
- err++;
- } else {
+ } else {
+ opts.mode = MODE_ERROR;
+ err++;
+ }
+ break;
+ case 'c':
+ if (opts.mode == MODE_NONE)
+ opts.mode = MODE_COPY;
+ else
+ opts.mode = MODE_ERROR;
+ 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 'o':
+ if (!opts.output) {
+ opts.output = argv[optind-1];
+ } else {
+ err++;
+ }
+ break;
+ case 'b':
+ if (opts.fillbyte == -1) {
+ opts.fillbyte = strtol (optarg, &end, 0);
+ if (end && *end)
err++;
- }
- break;
- case 'd':
- if (!opts.dest)
- opts.dest = argv[optind-1];
- else
+ } else {
+ err++;
+ }
+ break;
+ case 'm':
+ if (!opts.match)
+ opts.match = transform (argv[optind-1]);
+ else
+ err++;
+ break;
+ case 'p':
+ if (opts.percent == -1) {
+ opts.percent = strtol (optarg, &end, 0);
+ if (end && *end)
err++;
- break;
- case 'v':
- opts.verbose++;
- break;
- case 'V':
- ver++;
- break;
- case 'h':
- help++;
- break;
- case '?':
- default:
- if (((optopt == 'u') || (optopt == 'd') || (optopt == 'p')) && !optarg) {
- printf ("Option '%s' requires an argument.\n", argv[optind-1]);
- } else {
- printf ("Unknown option '%s'.\n", argv[optind-1]);
- }
+ } else {
+ err++;
+ }
+ break;
+ case 'd':
+ if (!opts.dest)
+ opts.dest = argv[optind-1];
+ else
err++;
- break;
+ break;
+ case 'i':
+ opts.ignore_case++;
+ break;
+ case 'f':
+ opts.force++;
+ break;
+ case 'v':
+ opts.verbose++;
+ break;
+ case 'V':
+ ver++;
+ break;
+ case 'h':
+ help++;
+ break;
+ default:
+ if (((optopt == 'u') || (optopt == 'o') ||
+ (optopt == 'd') || (optopt == 'p') ||
+ (optopt == 'b') || (optopt == 'c') ||
+ (optopt == 'm') || (optopt == 'S')) &&
+ (!optarg)) {
+ printf ("Option '%s' requires an "
+ "argument.\n", argv[optind-1]);
+ } else {
+ printf ("Unknown option '%s'.\n",
+ argv[optind-1]);
+ }
+ err++;
+ break;
}
}
if (!help && !ver) {
- if (!opts.device) {
- printf ("No device has been specified.\n");
+ if (opts.device == NULL) {
+ printf ("You must specify exactly one device.\n");
err++;
}
- if ((opts.uinode > -1) && ((opts.percent > 0) || opts.scan)) {
- printf ("Scan and percentage options cannot be combined with undelete.\n");
+
+ if (opts.mode == MODE_NONE) {
+ opts.mode = MODE_SCAN;
+ }
+
+ switch (opts.mode) {
+ case MODE_SCAN:
+ if (opts.output || opts.dest || (opts.fillbyte != -1)) {
+ printf ("Scan can only be used with --percent, "
+ "--match, --ignore-case or --size.\n");
+ err++;
+ }
+ break;
+ case MODE_UNDELETE:
+ if ((opts.percent != -1) || opts.match || opts.ignore_case ||
+ (opts.size_begin > 0) || (opts.size_end > 0)) {
+ printf ("Undelete can only be used with "
+ "--output, --destination or --byte.\n");
+ err++;
+ }
+ break;
+ case MODE_COPY:
+ if (opts.dest || (opts.fillbyte != -1) ||
+ (opts.percent != -1) || opts.match ||
+ opts.ignore_case || (opts.size_begin > 0) ||
+ (opts.size_end > 0)) {
+ printf ("Copy can only be used with --output\n");
+ err++;
+ }
+ break;
+ default:
+ printf ("You can only select one of Scan, Undelete or Copy.\n");
err++;
}
- if ((opts.percent < 0) || (opts.percent > 100)) {
+
+ if ((opts.percent < -1) || (opts.percent > 100)) {
printf ("Percentage value must be in the range 0 - 100.\n");
err++;
@@ -792,8 +1051,8 @@
/**
- * list_record - Print a one-line summary of the file
+ * list_record - Print a one line summary of the file
* @file: The file to work with
*
- * Print a one-line description of a file.
+ * Print a one line description of a file.
*
* Inode Flags %age Date Size Filename
@@ -921,5 +1180,5 @@
percent = calc_percentage (file, vol);
- if ((opts.percent == 0) || (percent >= opts.percent)) {
+ if ((opts.percent == -1) || (percent >= opts.percent)) {
if (opts.verbose)
dump_record (file);
@@ -928,5 +1187,5 @@
}
- if (((opts.percent == 0) && (percent > 0)) ||
+ if (((opts.percent == -1) && (percent > 0)) ||
((opts.percent > 0) && (percent >= opts.percent))) {
results++;
@@ -946,4 +1205,32 @@
/**
+ * write_data
+ */
+int write_data (int fd, const char *buffer, int bufsize)
+{
+ ssize_t result1, result2;
+
+ if (!buffer) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ result1 = write (fd, buffer, bufsize);
+ if ((result1 == bufsize) || (result1 < 0))
+ return result1;
+
+ /* Try again with the rest of the buffer */
+ buffer += result1;
+ bufsize -= result1;
+
+ result2 = write (fd, buffer, bufsize);
+ if (result2 < 0)
+ return result2;
+
+ return result1 + result2;
+}
+
+
+/**
* open_file
*/
@@ -1041,5 +1328,5 @@
printf ("resident data\n");
- if (write (fd, d->data, d->size_data) < d->size_data) {
+ if (write_data (fd, d->data, d->size_data) < d->size_data) {
printf ("write failed\n");
close (fd);
@@ -1073,5 +1360,5 @@
memset (buffer, 'R', sizeof (buffer));
for (k = 0; k < rl[0].length * vol->cluster_size; k += sizeof (buffer)) {
- if (write (fd, buffer, sizeof (buffer)) < sizeof (buffer)) {
+ if (write_data (fd, buffer, sizeof (buffer)) < sizeof (buffer)) {
printf ("write failed\n");
close (fd);
@@ -1087,5 +1374,5 @@
memset (buffer, 'S', sizeof (buffer));
for (k = 0; k < rl[k].length * vol->cluster_size; k += sizeof (buffer)) {
- if (write (fd, buffer, sizeof (buffer)) < sizeof (buffer)) {
+ if (write_data (fd, buffer, sizeof (buffer)) < sizeof (buffer)) {
printf ("write failed\n");
close (fd);
@@ -1100,5 +1387,5 @@
memset (buffer, 'H', sizeof (buffer));
for (k = 0; k < rl[k].length * vol->cluster_size; k += sizeof (buffer)) {
- if (write (fd, buffer, sizeof (buffer)) < sizeof (buffer)) {
+ if (write_data (fd, buffer, sizeof (buffer)) < sizeof (buffer)) {
printf ("write failed\n");
close (fd);
@@ -1115,5 +1402,5 @@
if (cluster_in_use (vol, j)) {
memset (buffer, 'X', sizeof (buffer));
- if (write (fd, buffer, sizeof (buffer)) < sizeof (buffer)) {
+ if (write_data (fd, buffer, sizeof (buffer)) < sizeof (buffer)) {
printf ("write failed\n");
close (fd);
@@ -1126,5 +1413,5 @@
return 0;
}
- if (write (fd, buffer, sizeof (buffer)) < sizeof (buffer)) {
+ if (write_data (fd, buffer, sizeof (buffer)) < sizeof (buffer)) {
printf ("write failed\n");
close (fd);
Index: ntfsundelete.h
===================================================================
RCS file: /cvsroot/linux-ntfs/linux-ntfs/ntfstools/ntfsundelete.h,v
retrieving revision 1.3
retrieving revision 1.4
diff -U2 -r1.3 -r1.4
--- ntfsundelete.h 11 Jul 2002 13:18:12 -0000 1.3
+++ ntfsundelete.h 13 Jul 2002 16:33:00 -0000 1.4
@@ -1,6 +1,3 @@
-#ifndef _NTFSUNDELETE_H_
-#define _NTFSUNDELETE_H_
-
-/**
+/*
* ntfsundelete - Part of the Linux-NTFS project.
*
@@ -25,15 +22,36 @@
*/
+#ifndef _NTFSUNDELETE_H_
+#define _NTFSUNDELETE_H_
+
#include "types.h"
#include "list.h"
#include "runlist.h"
+enum optmode {
+ MODE_NONE = 0,
+ MODE_SCAN,
+ MODE_UNDELETE,
+ MODE_COPY,
+ MODE_ERROR
+};
+
+
struct options {
char *device; /* Device/File to work with */
- int scan; /* Scan the disk */
+ enum optmode mode; /* Scan / Undelete / Copy */
int percent; /* Minimum recoverability */
- int verbose; /* Extra output */
int uinode; /* Undelete this inode */
char *dest; /* Save file to this directory */
+ char *output; /* With this filename */
+ char fillbyte; /* Use for unrecoverable sections */
+ char *match; /* Regex for filename matching */
+ int ignore_case; /* Case insensitive matching */
+ int verbose; /* Extra output */
+ int force; /* Override common sense */
+ long long size_begin; /* Range for file size */
+ long long size_end;
+ long long mft_begin; /* Range for mft copy */
+ long long mft_end;
};
|