Implemented an option to set a new serial number in ntfsclone
Defined new options --new-serial and --new-half-serial to set a new random serial number when cloning or restoring a file system. Useful for mounting the original and the cloned file system at the same time.
This commit is contained in:
@@ -228,6 +228,26 @@ inconsistency are saved too.
|
|||||||
Do not wipe the timestamps, to be used only with the
|
Do not wipe the timestamps, to be used only with the
|
||||||
.B \-\-metadata
|
.B \-\-metadata
|
||||||
option.
|
option.
|
||||||
|
|
||||||
|
|
||||||
|
.TP
|
||||||
|
\fB\-\-new\-serial\fR, or
|
||||||
|
.TP
|
||||||
|
\fB\-\-new\-half\-serial\fR
|
||||||
|
Set a new random serial number to the clone. The serial number is a 64
|
||||||
|
bit number used to identify the device during the mounting process, so
|
||||||
|
it has to be changed to enable the original file system
|
||||||
|
and the clone to be mounted at the same time on the same computer.
|
||||||
|
|
||||||
|
The option \fB\-\-new\-half\-serial\fP only changes the upper part of the
|
||||||
|
serial number, keeping the lower part which is used by Windows unchanged.
|
||||||
|
|
||||||
|
The options \fB\-\-new\-serial\fP and \fB\-\-new\-half\-serial\fP can
|
||||||
|
only be used when cloning a file system of restoring from an image.
|
||||||
|
|
||||||
|
The serial number is not the volume UUID used by Windows
|
||||||
|
to locate files which have been moved to another volume.
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
\fB\-f\fR, \fB\-\-force\fR
|
\fB\-f\fR, \fB\-\-force\fR
|
||||||
Forces ntfsclone to proceed if the filesystem is marked
|
Forces ntfsclone to proceed if the filesystem is marked
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
*
|
*
|
||||||
* Copyright (c) 2003-2006 Szabolcs Szakacsits
|
* Copyright (c) 2003-2006 Szabolcs Szakacsits
|
||||||
* Copyright (c) 2004-2006 Anton Altaparmakov
|
* Copyright (c) 2004-2006 Anton Altaparmakov
|
||||||
* Copyright (c) 2010-2011 Jean-Pierre Andre
|
* Copyright (c) 2010-2012 Jean-Pierre Andre
|
||||||
* Special image format support copyright (c) 2004 Per Olofsson
|
* Special image format support copyright (c) 2004 Per Olofsson
|
||||||
*
|
*
|
||||||
* Clone NTFS data and/or metadata to a sparse file, image, device or stdout.
|
* Clone NTFS data and/or metadata to a sparse file, image, device or stdout.
|
||||||
@@ -31,6 +31,9 @@
|
|||||||
#ifdef HAVE_SYS_STAT_H
|
#ifdef HAVE_SYS_STAT_H
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef HAVE_TIME_H
|
||||||
|
#include <time.h>
|
||||||
|
#endif
|
||||||
#ifdef HAVE_SYS_IOCTL_H
|
#ifdef HAVE_SYS_IOCTL_H
|
||||||
#include <sys/ioctl.h>
|
#include <sys/ioctl.h>
|
||||||
#endif
|
#endif
|
||||||
@@ -55,6 +58,9 @@
|
|||||||
#ifdef HAVE_GETOPT_H
|
#ifdef HAVE_GETOPT_H
|
||||||
#include <getopt.h>
|
#include <getopt.h>
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef HAVE_UNISTD_H
|
||||||
|
#include <unistd.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* FIXME: ntfsclone do bad things about endians handling. Fix it and remove
|
* FIXME: ntfsclone do bad things about endians handling. Fix it and remove
|
||||||
@@ -119,6 +125,7 @@ static struct {
|
|||||||
int ignore_fs_check;
|
int ignore_fs_check;
|
||||||
int rescue;
|
int rescue;
|
||||||
int save_image;
|
int save_image;
|
||||||
|
int new_serial;
|
||||||
int metadata_image;
|
int metadata_image;
|
||||||
int preserve_timestamps;
|
int preserve_timestamps;
|
||||||
int restore_image;
|
int restore_image;
|
||||||
@@ -171,6 +178,7 @@ static unsigned int wiped_unused_mft = 0;
|
|||||||
static unsigned int wiped_resident_data = 0;
|
static unsigned int wiped_resident_data = 0;
|
||||||
static unsigned int wiped_timestamp_data = 0;
|
static unsigned int wiped_timestamp_data = 0;
|
||||||
|
|
||||||
|
static le64 volume_serial_number; /* new random serial number */
|
||||||
static u64 full_device_size; /* full size, including the backup boot sector */
|
static u64 full_device_size; /* full size, including the backup boot sector */
|
||||||
|
|
||||||
static BOOL image_is_host_endian = FALSE;
|
static BOOL image_is_host_endian = FALSE;
|
||||||
@@ -316,6 +324,8 @@ static void usage(void)
|
|||||||
" --rescue Continue after disk read errors\n"
|
" --rescue Continue after disk read errors\n"
|
||||||
" -m, --metadata Clone *only* metadata (for NTFS experts)\n"
|
" -m, --metadata Clone *only* metadata (for NTFS experts)\n"
|
||||||
" --ignore-fs-check Ignore the filesystem check result\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"
|
||||||
" -t, --preserve-timestamps Do not clear the timestamps\n"
|
" -t, --preserve-timestamps Do not clear the timestamps\n"
|
||||||
" -q, --quiet Do not display any progress bars\n"
|
" -q, --quiet Do not display any progress bars\n"
|
||||||
" -f, --force Force to progress (DANGEROUS)\n"
|
" -f, --force Force to progress (DANGEROUS)\n"
|
||||||
@@ -347,6 +357,8 @@ static void parse_options(int argc, char **argv)
|
|||||||
{ "restore-image", no_argument, NULL, 'r' },
|
{ "restore-image", no_argument, NULL, 'r' },
|
||||||
{ "ignore-fs-check", no_argument, NULL, 'C' },
|
{ "ignore-fs-check", no_argument, NULL, 'C' },
|
||||||
{ "rescue", no_argument, NULL, 'R' },
|
{ "rescue", no_argument, NULL, 'R' },
|
||||||
|
{ "new-serial", no_argument, NULL, 'I' },
|
||||||
|
{ "new-half-serial", no_argument, NULL, 'i' },
|
||||||
{ "save-image", no_argument, NULL, 's' },
|
{ "save-image", no_argument, NULL, 's' },
|
||||||
{ "preserve-timestamps", no_argument, NULL, 't' },
|
{ "preserve-timestamps", no_argument, NULL, 't' },
|
||||||
{ NULL, 0, NULL, 0 }
|
{ NULL, 0, NULL, 0 }
|
||||||
@@ -375,6 +387,12 @@ static void parse_options(int argc, char **argv)
|
|||||||
case 'h':
|
case 'h':
|
||||||
case '?':
|
case '?':
|
||||||
usage();
|
usage();
|
||||||
|
case 'i': /* not proposed as a short option */
|
||||||
|
opt.new_serial |= 1;
|
||||||
|
break;
|
||||||
|
case 'I': /* not proposed as a short option */
|
||||||
|
opt.new_serial |= 2;
|
||||||
|
break;
|
||||||
case 'm':
|
case 'm':
|
||||||
opt.metadata++;
|
opt.metadata++;
|
||||||
break;
|
break;
|
||||||
@@ -491,6 +509,20 @@ static void parse_options(int argc, char **argv)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initialize the random number generator with the current
|
||||||
|
* time, and generate a 64-bit random number for the serial
|
||||||
|
* number
|
||||||
|
*/
|
||||||
|
static void generate_serial_number(void) {
|
||||||
|
u64 sn;
|
||||||
|
|
||||||
|
/* different values for parallel processes */
|
||||||
|
srandom(time((time_t*)NULL) ^ (getpid() << 16));
|
||||||
|
sn = ((u64)random() << 32) | ((u64)random() & 0xffffffff);
|
||||||
|
volume_serial_number = cpu_to_le64(sn);
|
||||||
|
}
|
||||||
|
|
||||||
static void progress_init(struct progress_bar *p, u64 start, u64 stop, int res)
|
static void progress_init(struct progress_bar *p, u64 start, u64 stop, int res)
|
||||||
{
|
{
|
||||||
p->start = start;
|
p->start = start;
|
||||||
@@ -630,8 +662,12 @@ static void copy_cluster(int rescue, u64 rescue_lcn, u64 lcn)
|
|||||||
char buff[NTFS_MAX_CLUSTER_SIZE]; /* overflow checked at mount time */
|
char buff[NTFS_MAX_CLUSTER_SIZE]; /* overflow checked at mount time */
|
||||||
/* vol is NULL if opt.restore_image is set */
|
/* vol is NULL if opt.restore_image is set */
|
||||||
s32 csize = le32_to_cpu(image_hdr.cluster_size);
|
s32 csize = le32_to_cpu(image_hdr.cluster_size);
|
||||||
|
BOOL backup_bootsector;
|
||||||
void *fd = (void *)&fd_in;
|
void *fd = (void *)&fd_in;
|
||||||
off_t rescue_pos;
|
off_t rescue_pos;
|
||||||
|
NTFS_BOOT_SECTOR *bs;
|
||||||
|
le64 mask;
|
||||||
|
static u16 bytes_per_sector;
|
||||||
|
|
||||||
if (!opt.restore_image) {
|
if (!opt.restore_image) {
|
||||||
csize = vol->cluster_size;
|
csize = vol->cluster_size;
|
||||||
@@ -641,7 +677,8 @@ static void copy_cluster(int rescue, u64 rescue_lcn, u64 lcn)
|
|||||||
rescue_pos = (off_t)(rescue_lcn * csize);
|
rescue_pos = (off_t)(rescue_lcn * csize);
|
||||||
|
|
||||||
/* possible partial cluster holding the backup boot sector */
|
/* possible partial cluster holding the backup boot sector */
|
||||||
if ((lcn + 1)*csize > full_device_size) {
|
backup_bootsector = (lcn + 1)*csize >= full_device_size;
|
||||||
|
if (backup_bootsector) {
|
||||||
csize = full_device_size - lcn*csize;
|
csize = full_device_size - lcn*csize;
|
||||||
if (csize < 0) {
|
if (csize < 0) {
|
||||||
err_exit("Corrupted input, copy aborted");
|
err_exit("Corrupted input, copy aborted");
|
||||||
@@ -663,6 +700,40 @@ static void copy_cluster(int rescue, u64 rescue_lcn, u64 lcn)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Set the new serial number if requested */
|
||||||
|
if (opt.new_serial
|
||||||
|
&& !opt.save_image
|
||||||
|
&& (!lcn || backup_bootsector)) {
|
||||||
|
/*
|
||||||
|
* For updating the backup boot sector, we need to
|
||||||
|
* know the sector size, but this is not recorded
|
||||||
|
* in the image header, so we collect it on the fly
|
||||||
|
* while reading the first boot sector.
|
||||||
|
*/
|
||||||
|
if (!lcn) {
|
||||||
|
bs = (NTFS_BOOT_SECTOR*)buff;
|
||||||
|
bytes_per_sector = le16_to_cpu(bs->bpb.bytes_per_sector);
|
||||||
|
if ((bytes_per_sector > csize)
|
||||||
|
|| (bytes_per_sector < NTFS_SECTOR_SIZE))
|
||||||
|
bytes_per_sector = NTFS_SECTOR_SIZE;
|
||||||
|
} else
|
||||||
|
bs = (NTFS_BOOT_SECTOR*)(buff
|
||||||
|
+ csize - bytes_per_sector);
|
||||||
|
if (opt.new_serial & 2)
|
||||||
|
bs->volume_serial_number = volume_serial_number;
|
||||||
|
else {
|
||||||
|
mask = const_cpu_to_le64(~0x0ffffffffULL);
|
||||||
|
bs->volume_serial_number
|
||||||
|
= (volume_serial_number & mask)
|
||||||
|
| (bs->volume_serial_number & ~mask);
|
||||||
|
}
|
||||||
|
/* Show the new full serial after merging */
|
||||||
|
if (!lcn)
|
||||||
|
Printf("New serial number : 0x%llx\n",
|
||||||
|
(long long)le64_to_cpu(
|
||||||
|
bs->volume_serial_number));
|
||||||
|
}
|
||||||
|
|
||||||
if (opt.save_image || (opt.metadata_image && wipe)) {
|
if (opt.save_image || (opt.metadata_image && wipe)) {
|
||||||
char cmd = 1;
|
char cmd = 1;
|
||||||
if (write_all(&fd_out, &cmd, sizeof(cmd)) == -1)
|
if (write_all(&fd_out, &cmd, sizeof(cmd)) == -1)
|
||||||
@@ -760,6 +831,9 @@ static void clone_ntfs(u64 nr_clusters)
|
|||||||
else
|
else
|
||||||
Printf("Cloning NTFS ...\n");
|
Printf("Cloning NTFS ...\n");
|
||||||
|
|
||||||
|
if (opt.new_serial)
|
||||||
|
generate_serial_number();
|
||||||
|
|
||||||
buf = ntfs_calloc(csize);
|
buf = ntfs_calloc(csize);
|
||||||
if (!buf)
|
if (!buf)
|
||||||
perr_exit("clone_ntfs");
|
perr_exit("clone_ntfs");
|
||||||
@@ -829,6 +903,9 @@ static void restore_image(void)
|
|||||||
sle64_to_cpu(image_hdr.inuse) + 1,
|
sle64_to_cpu(image_hdr.inuse) + 1,
|
||||||
100);
|
100);
|
||||||
|
|
||||||
|
if (opt.new_serial)
|
||||||
|
generate_serial_number();
|
||||||
|
|
||||||
/* Restore up to the alternate boot sector */
|
/* Restore up to the alternate boot sector */
|
||||||
while (pos <= sle64_to_cpu(image_hdr.nr_clusters)) {
|
while (pos <= sle64_to_cpu(image_hdr.nr_clusters)) {
|
||||||
if (read_all(&fd_in, &cmd, sizeof(cmd)) == -1) {
|
if (read_all(&fd_in, &cmd, sizeof(cmd)) == -1) {
|
||||||
|
|||||||
Reference in New Issue
Block a user