Added a new option for testing the consistency of an ntfsclone image

This patch adds a new option -n to ntfsclone for simulating a restore
without writing anything. This is useful for checking the consistency
of an image without destroying the original partition.
edge.strict_endians
Jean-Pierre André 2013-02-09 11:29:21 +01:00
parent 44fbf02a97
commit 7c83060553
2 changed files with 43 additions and 16 deletions

View File

@ -203,6 +203,12 @@ argument. If the
.I SOURCE
is '\-' then the image is read from the standard input.
.TP
\fB\-n\fR, \fB\-\-no\-action\fR
Test the consistency of a saved image by simulating its restoring without
writing anything. The NTFS data contained in the image is not tested.
The option \fB\-\-restore\-image\fR must also be present, and the options
\fB\-\-output\fR and \fB\-\-overwrite\fR must be omitted.
.TP
\fB\-\-rescue\fR
Ignore disk read errors so disks having bad sectors, e.g. dying disks, can be
rescued the most efficiently way, with minimal stress on them. Ntfsclone works

View File

@ -123,6 +123,7 @@ static struct {
int std_out;
int blkdev_out; /* output file is block device */
int metadata; /* metadata only cloning */
int no_action; /* do not really restore */
int ignore_fs_check;
int rescue;
int save_image;
@ -324,6 +325,7 @@ static void usage(void)
" -r, --restore-image Restore from the special image format\n"
" --rescue Continue after disk read errors\n"
" -m, --metadata Clone *only* metadata (for NTFS experts)\n"
" -n, --no-action Test restoring, without outputting anything\n"
" --ignore-fs-check Ignore the filesystem check result\n"
" --new-serial Set a new serial number\n"
" --new-half-serial Set a partial new serial number\n"
@ -344,7 +346,7 @@ static void usage(void)
static void parse_options(int argc, char **argv)
{
static const char *sopt = "-dfhmo:O:qrst";
static const char *sopt = "-dfhmno:O:qrst";
static const struct option lopt[] = {
#ifdef DEBUG
{ "debug", no_argument, NULL, 'd' },
@ -353,6 +355,7 @@ static void parse_options(int argc, char **argv)
{ "force", no_argument, NULL, 'f' },
{ "help", no_argument, NULL, 'h' },
{ "metadata", no_argument, NULL, 'm' },
{ "no-action", no_argument, NULL, 'n' },
{ "output", required_argument, NULL, 'o' },
{ "overwrite", required_argument, NULL, 'O' },
{ "restore-image", no_argument, NULL, 'r' },
@ -397,6 +400,9 @@ static void parse_options(int argc, char **argv)
case 'm':
opt.metadata++;
break;
case 'n':
opt.no_action++;
break;
case 'O':
opt.overwrite++;
case 'o':
@ -425,12 +431,12 @@ static void parse_options(int argc, char **argv)
}
}
if (opt.output == NULL) {
if (!opt.no_action && (opt.output == NULL)) {
err_printf("You must specify an output file.\n");
usage();
}
if (strcmp(opt.output, "-") == 0)
if (!opt.no_action && (strcmp(opt.output, "-") == 0))
opt.std_out++;
if (opt.volume == NULL) {
@ -458,7 +464,13 @@ static void parse_options(int argc, char **argv)
err_exit("Saving and restoring an image at the same time "
"is not supported!\n");
if (!opt.std_out) {
if (opt.no_action && !opt.restore_image)
err_exit("A restoring test requires the restore option!\n");
if (opt.no_action && opt.output)
err_exit("A restoring test requires not defining any output!\n");
if (!opt.no_action && !opt.std_out) {
struct stat st;
if (stat(opt.output, &st) == -1) {
@ -590,10 +602,14 @@ static int io_all(void *fd, void *buf, int count, int do_write)
while (count > 0) {
if (do_write) {
if (opt.save_image || opt.metadata_image)
i = fwrite(buf, 1, count, stream_out);
else
i = write(*(int *)fd, buf, count);
if (opt.no_action) {
i = count;
} else {
if (opt.save_image || opt.metadata_image)
i = fwrite(buf, 1, count, stream_out);
else
i = write(*(int *)fd, buf, count);
}
} else if (opt.restore_image)
i = read(*(int *)fd, buf, count);
else
@ -618,7 +634,8 @@ static void rescue_sector(void *fd, off_t pos, void *buff)
struct ntfs_device *dev = fd;
if (opt.restore_image) {
if (lseek(*(int *)fd, pos, SEEK_SET) == (off_t)-1)
if (!opt.no_action
&& (lseek(*(int *)fd, pos, SEEK_SET) == (off_t)-1))
perr_exit("lseek");
} else {
if (vol->dev->d_ops->seek(dev, pos, SEEK_SET) == (off_t)-1)
@ -947,8 +964,9 @@ static void restore_image(void)
> sle64_to_cpu(image_hdr.nr_clusters)))
err_exit("restore_image: corrupt image\n");
else
if (lseek(fd_out, count * csize,
SEEK_CUR) == (off_t)-1)
if (!opt.no_action
&& (lseek(fd_out, count * csize,
SEEK_CUR) == (off_t)-1))
perr_exit("restore_image: lseek");
}
pos += count;
@ -2105,7 +2123,7 @@ static void set_filesize(s64 filesize)
"operation will be very inefficient and may fail!\n");
#endif
if (ftruncate(fd_out, filesize) == -1) {
if (!opt.no_action && (ftruncate(fd_out, filesize) == -1)) {
int err = errno;
perr_printf("ftruncate failed for file '%s'", opt.output);
#ifndef NO_STATFS
@ -2414,6 +2432,7 @@ int main(int argc, char **argv)
/* device_size_get() might need to read() */
int flags = O_RDWR;
fd_out = 0;
if (!opt.blkdev_out) {
flags |= O_CREAT | O_TRUNC;
if (!opt.overwrite)
@ -2427,19 +2446,21 @@ int main(int argc, char **argv)
opt.output);
fd_out = fileno(stream_out);
} else
if ((fd_out = open(opt.output, flags,
S_IRUSR | S_IWUSR)) == -1)
if (!opt.no_action
&& ((fd_out = open(opt.output, flags,
S_IRUSR | S_IWUSR)) == -1))
perr_exit("Opening file '%s' failed",
opt.output);
if (!opt.save_image && !opt.metadata_image)
if (!opt.save_image && !opt.metadata_image && !opt.no_action)
check_output_device(ntfs_size);
}
if (opt.restore_image) {
print_image_info();
restore_image();
fsync_clone(fd_out);
if (!opt.no_action)
fsync_clone(fd_out);
exit(0);
}