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.
edge.strict_endians
Jean-Pierre André 2012-01-23 18:19:17 +01:00
parent e7bfd31de4
commit 54f96e4af1
2 changed files with 99 additions and 2 deletions

View File

@ -228,6 +228,26 @@ inconsistency are saved too.
Do not wipe the timestamps, to be used only with the
.B \-\-metadata
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
\fB\-f\fR, \fB\-\-force\fR
Forces ntfsclone to proceed if the filesystem is marked

View File

@ -3,7 +3,7 @@
*
* Copyright (c) 2003-2006 Szabolcs Szakacsits
* 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
*
* Clone NTFS data and/or metadata to a sparse file, image, device or stdout.
@ -31,6 +31,9 @@
#ifdef HAVE_SYS_STAT_H
#include <sys/stat.h>
#endif
#ifdef HAVE_TIME_H
#include <time.h>
#endif
#ifdef HAVE_SYS_IOCTL_H
#include <sys/ioctl.h>
#endif
@ -55,6 +58,9 @@
#ifdef HAVE_GETOPT_H
#include <getopt.h>
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
/*
* FIXME: ntfsclone do bad things about endians handling. Fix it and remove
@ -119,6 +125,7 @@ static struct {
int ignore_fs_check;
int rescue;
int save_image;
int new_serial;
int metadata_image;
int preserve_timestamps;
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_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 BOOL image_is_host_endian = FALSE;
@ -316,6 +324,8 @@ static void usage(void)
" --rescue Continue after disk read errors\n"
" -m, --metadata Clone *only* metadata (for NTFS experts)\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"
" -q, --quiet Do not display any progress bars\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' },
{ "ignore-fs-check", no_argument, NULL, 'C' },
{ "rescue", no_argument, NULL, 'R' },
{ "new-serial", no_argument, NULL, 'I' },
{ "new-half-serial", no_argument, NULL, 'i' },
{ "save-image", no_argument, NULL, 's' },
{ "preserve-timestamps", no_argument, NULL, 't' },
{ NULL, 0, NULL, 0 }
@ -375,6 +387,12 @@ static void parse_options(int argc, char **argv)
case 'h':
case '?':
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':
opt.metadata++;
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)
{
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 */
/* vol is NULL if opt.restore_image is set */
s32 csize = le32_to_cpu(image_hdr.cluster_size);
BOOL backup_bootsector;
void *fd = (void *)&fd_in;
off_t rescue_pos;
NTFS_BOOT_SECTOR *bs;
le64 mask;
static u16 bytes_per_sector;
if (!opt.restore_image) {
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);
/* 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;
if (csize < 0) {
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)) {
char cmd = 1;
if (write_all(&fd_out, &cmd, sizeof(cmd)) == -1)
@ -760,6 +831,9 @@ static void clone_ntfs(u64 nr_clusters)
else
Printf("Cloning NTFS ...\n");
if (opt.new_serial)
generate_serial_number();
buf = ntfs_calloc(csize);
if (!buf)
perr_exit("clone_ntfs");
@ -829,6 +903,9 @@ static void restore_image(void)
sle64_to_cpu(image_hdr.inuse) + 1,
100);
if (opt.new_serial)
generate_serial_number();
/* Restore up to the alternate boot sector */
while (pos <= sle64_to_cpu(image_hdr.nr_clusters)) {
if (read_all(&fd_in, &cmd, sizeof(cmd)) == -1) {