I was trying to make a copy of a bootable USB stick. In spite of both sticks (source and destination) being allegedly the same size, the destination stick was in fact slightly smaller than the source stick, so a simple blockwise copy using dd did not work – “no space left on device”.
A blockwise copy just copies all the blocks of the source drive sequentially on to the destination drive. Any structure on the source drive – like partitions and what-have-you – will end up recreated on the destination drive.
If the source drive is smaller than the destination drive, there will be unused space on the destination after the last partition, but it can be recovered using (say) gparted to extend the partition into the leftover space.
If the destination is smaller than the source, however, the last few blocks of the source device will not be copied, and the partition table on the destination device will be incorrect. The file system index will also be incorrect – it will reference blocks that do not exist. If the missing blocks actually contained data, then the files those blocks were part of will be corrupt on the destination drive. The resulting copy will probably work fine in spite of all these issues, especially if the missing blocks were empty, and as long as the file system does not get too full. On the whole though, the resulting drive is probably not good enough for real work.
So how to do this copy properly?
In my case the source drive contained just one partition, occupying all available space, and a lot of the partition was empty. I used gparted to resize the partition down to a size that would fit on the destination device. This step makes sure that the partition table and any file system indexes in the partition will be correct.
The I used the “Information” option on the resized partition to see what the last block number occupied by the partition was.
Then I used dd again, but this time used the “count” option to copy only the blocks up to and including the last block of the source partition. The result: A working, bootable USB stick that was an exact (enough) copy of the source.
In summary, to copy a larger USB drive to a smaller one, do this:
- use gparted to compact the source drive down to a size that will fit on the destination.
- use gparted or fdisk to view the partition table; work out how many blocks actually need to be copied. The number you want is the offset of the last block of the last partition, plus one.
- make sure neither drive is mounted
- use dd to copy only that many blocks from the source to the destination. Assuming the source is mounted as /dev/sdb, the destination is mounted as /dev/sdc, the source block size is 512 bytes and X is the number of blocks to copy, the command would look like this:
sudo dd if=/dev/sdb of=/dev/sdc bs=512 count=X
Be very, very careful using dd! If you mix up “of” and “if”, or if you specify the wrong devices, you can lose lots of data.
If you need multiple copies, you can write the data to an image file, then write the image file to multiple USB drives:
sudo dd if=/dev/sdb of=/path/to/image/file bs=512 count=X sudo dd if=/path/to/image/file of=/dev/sdc bs=512
You can use larger block sizes; just make sure you do copy only the data you need. 512 is generally safest, though slow. There is no need to specify a block count when the source is an image file.
Note: Devices, like disk drives or partitions, are generally specified using “/dev/…”. Files, however, are specified using their normal path in the file system. Following the above example, I might put the image file in my home directory and copy it from there onto another USB stick like so:
sudo dd if=/dev/sdb of=/home/kauer/myimage.dat bs=512 count=3000 sudo dd if=/home/kauer/myimage.dat of=/dev/sdc bs=512