Copying Windows to a New Hard Drive Using Linux24 Feb 2010
When replacing the hard disk in a computer, it's convenient to be able to copy the existing installed operating system to the new disk, rather than performing a new install. This guide describes a method of doing this using the dd copy tool under Linux to move a working Microsoft Windows installation to a new disk. The main details concern dealing with different disk sizes and CHS geometries, together with different partition locations.
This guide originates from a recovering a Windows XP installation with a faulty hard disk. The faulty drive would intermittently freeze the system and issue various clunking sounds. I took the drive out of the system, mounted it in a USB enclosure, and attached it to my Ubuntu Linux system. I successfully copied the an image of the disk to my hard disk using GNU ddrescue, and then attached the new drive, formatted it, imaged it, and fixed up a number of aspects as described below.
Warning: The techniques used here are inherently risky for the data concened, and small errors can easily destroy the data on any of the disks currently connected to the computer. It describes my experience, but if you follow any instructions here, you do so at your own risk. Always ensure you first have good backups of all data currently accessible to the computer.
Under modern Linux installations, the first hard disk device is /dev/sda, the second /dev/sdb, and so on. Within each of those disks there can be a number of partitions. These are referred to as /dev/sda1. /dev/sda2 etc. For two identical disks one can simply copy the entire disk, with a command like,
dd if=/dev/sdb of=/dev/sdc bs=64k
to copy the contents of the second disk to the third disk. (Avoid trying to copy a currently mounted disk as the resulting copy is likely to be inconsistent)
However, when the two disks have different geometries, or if the partition layout is to change, then it's necessary to deal with the partitions individually, as the remainder of this guide describes.
These are some other guides that perform similar tasks:
- Copying Windows to a new drive, using linux - How-to/Guide. This is a good clear how-to of the general ideas, but doesn't deal with the case of different geometries/partition layouts.
- HOWTO: Move/Copy Windows XP to another Partition. If I'd found this before doing it, it'd have saved some time.
- Forking a XP-installation
- Move an entire Windows installation
Adjusting the Windows Registry and Boot Files
If the partition layout is going to change on the new drive, it's necessary to first change the windows registry to match it, otherwise it will hang sometime before or after the login prompt is reached. One way is before shutting down the system to simply use regedit under windows to delete all the registry entries in HKEY_LOCAL_MACHINE\SYSTEM\MountedDevices. It will then re-create them to match the new system after the next boot.
This can alternatively be done in Linux after doing the copy procedure with the chntpw utility by first mounting the partition (or image thereof) and executing:
chntpw -e WINDOWS/system32/config/system cd MountedDevices delallv q
As of Ubuntu 9.10, the packaged version of chntpw does not work on 64-bit systems. To overcome this, you can download the upstream source archive, and it contains a statically linked binary that works.
If the partition number or drive order has changed, it will also be necssary to edit the boot.ini file in the root of the NTFS partition to reflect this.
Partition the Target Drive
The target drive can be partitioned as normal into the desired partition layout. The main constraint is that the the target partition be at least as large as on the source disk. If not, the filesystem will need to be shrunk before the copy occurs. It doesn't need to be exactly the same size, and quite likely will vary a bit if the new disk has a different geometry, as partitions are generally lined up with cylinder boundaries. If you are wanting to increase the size of the partition, simply make it the desired final size, as the filesystem can be resized to fill it after the copy operation.
Make sure that the partition type is set correctly (For windows, probably 7 for NTFS), and the bootable flag set.
Copy the MBR
The Master Boot Record is the first sector (512 bytes) of the hard disk. (There is typically then a further 62 sectors following it before the end of the first track that are used by some bootloaders, like GRUB.) The first part of the MBR sector consists mainly of the boot loader code, and at the end there is the partition table. We just want to copy the boot loader section, which is the first 446 bytes. To do that:
dd if=/dev/sdb of=/dev/sdc bs=446 count=1
That's for sdb as the input and sdc as the output. Make sure you are sure of which is the correct device name before issuing these commands - they do what you say, and aren't forgiving.
Alternatives: Alternatively this can be done in two stages, copying to an intermediate image file on the disk:
dd if=/dev/sdb of=mbrloader.img bs=446 count=1 dd if=mbrloader.img of=/dev/sdc
Or if you also wish to copy the sectors following the MBR (sometimes containing GRUB stage 1.5 or other bootloaders), first copy the section before the partition table, then the remainder. This version copies the complete first track of 63 sectors into a file, and then copies the pieces to the target disk.
dd if=/dev/sdb of=mbr.img bs=512 count=63 dd if=mbr.img of=/dev/sdc bs=446 count=1 dd if=mbr.img of=/dev/sdc bs=512 skip=1 seek=1
Copy the Partition
The partitions are copied simply by copying the partition devices. For example
dd if=/dev/sdb1 of=/dev/sdc1 bs=64k
Alternatives: Again, these can also be copied to an intermediate image file on another disk as above. In cases where the device is giving read errors, GNU ddrescue or ddrescue can give better results. I was recovering a disk that was giving read faults, and used the following:
ddrescue /dev/sdb1 /dev/sdc1 logsdb1
The 3rd parameter is the filename of a log file that GNU ddrescue uses to continue on if the copy is interrupted. If copying the partition to an intermediate image file, the 2nd parameter can be the filname for that image.
After copying, the filesystem can be resized to fill the partition with ntfsresize. I'd suggest booting the new system and running chkdsk in windows first though.
Fix up the Partition Geometry
This section is aimed mainly at copying Windows XP/2000/NT installs, but also will relate to other operating systems to varying degrees. It is only necessary when the head or sector geometry has changed between the disks, or the partiton has changed location. Many modern disks have a 255 head/63 sector configuration. If both disks are like this, and the boot is the first partition in both cases, then it should not be necessary to make the changes in this section.
The NTFS bootloader is located in the first 16 sectors of the boot partition (the one just copied). The MBR code loads the first of those sectors, and code in that sector loads the rest of the boot loader. That 16 sector boot loader can read the NTFS filesystem to the point of loading the NTLDR file, which loads the rest of the operating system.
The initial boot stages rely on the BIOS calls to read the disk, and the sectors on the disk are located with the aid of information in the BIOS parameter block at the start of the first sector of the partition. The MBR code loads the first sector of the booted partition. In the case of NTFS, that NTFS boot sector will then load the first 16 sectors of that partition into memory (including the first sector that is already loaded and runnning).
More information on the NTFS Boot sectors can be found here:
Relevant to us are the following fields:
- 0x18 (2 bytes) Sectors per Track (often 63)
- 0x1A (2 bytes) Number of Heads (often 255)
- 0x1C (4 bytes) Hidden Sectors (starting sector of partition)
If any of these have changed in going from one disk to the other, its necessary to change these values in the first sector of the partition. (The first 2 are actually ignored if the partition is past the first 8GB of the disk, but its safer to have them right anyhow). To find the correct values you can use fdisk or similar. In this example we're looking at /dev/sdc2 as the target partition.
# fdisk /dev/sdc Command (m for help): u Changing display/entry units to sectors Command (m for help): p Disk /dev/sdc: 160.0 GB, 160000000000 bytes 255 heads, 63 sectors/track, 19452 cylinders, total 312500000 sectors Units = sectors of 1 * 512 = 512 bytes Disk identifier: 0x4c95ac34 Device Boot Start End Blocks Id System /dev/sdc1 63 96389 48163+ de Dell Utility /dev/sdc2 * 96390 234484739 117194175 7 HPFS/NTFS /dev/sdc3 234484740 312496379 39005820 5 Extended /dev/sdc5 234484803 309203054 37359126 83 Linux /dev/sdc6 309203118 312496379 1646631 82 Linux swap / Solaris
The important pieces of information from this disk is that there are
- 255 logical heads
- 63 sectors per track
- partition starts at sector 96390
We convert these to hexadecimal, and will then load them into the boot sector of the partition. The hex conversion can be done at the shell prompt with
# printf "%08x\n" 96390 00017886
The data from this example gives:
- Sectors: 63 = 0x003F
- Heads: 255 = 0x00FF
- Offset: 96390 = 0x00017886
That translates into the following string of bytes starting at addres 0x18. Note that it is little endian format, which means that the low order bytes go first (so the 3F goes before the 00 in Sectors).
3F 00 FF 00 86 78 01 00
63 Sectors and 255 Heads is very common for modern disks. The first partition of the disk is also placed after the first group of 63 Sectors, and hence the normal byte pattern for the first partition on a drive is:
3F 00 FF 00 3F 00 00 00
To edit this boot sector, we first load the sector into a file, here bootsector.img. Then edit the image file with a hex editor, such as ghex or hexedit, and finally write the file back to disk (sdc2 must be substituted for the target partition)
dd if=/dev/sdc2 of=bootsector.img bs=512 count=1 ghex2 bootsector.img dd if=bootsector.img of=/dev/sdc2
In the hex editor, offset hexadecimal 18 (should be on the 2nd line, halfway along) is set to 3F, offset 19 to 00, and so on through the list for sequential bytes. In a hex editor, the start of the file be as shown below. The second half of the second row is the modified area corresponding to starting address 0x18.
00000000 EB 52 90 4E 54 46 53 20 20 20 20 00 02 08 00 00 .R.NTFS ..... 00000010 00 00 00 00 00 F8 00 00 3F 00 FF 00 86 78 01 00 ........?....x.. 00000020 00 00 00 00 80 00 80 00 E0 AD 58 06 00 00 00 00 ..........X.....
With these changes made, the new disk should be ready to boot.