How do I convert a Linux disk image into a sparse file?
First of all, sparse files are only handled transparently if you seek, not if you write zeroes.
To make it more clear, the example from Wikipedia
dd if=/dev/zero of=sparse-file bs=1k count=0 seek=5120
does not write any zeroes, it will open the output file, seek (jump over) 5MB and then write zero zeroes (i. e. nothing at all). This command (not from Wikipedia)
dd if=/dev/zero of=sparse-file bs=1k count=5120
will write 5MB of zeroes and will not create a sparse file!
As a consequence, a file that is already non-sparse will not magically become sparse later.
Second, to make a file with lots of zeroes sparse, you have to cp it
cp --sparse=always original sparsefile
or you can use tar's or rsync's --sparse option as well.
Perhaps the easiest way to sparsify a file in place would be to use fallocate
utility as follows:
fallocate -v --dig-holes {file_name}
fallocate(1) is provided by util-linux package on Debian.
Editing my answer for completeness:
- Balloon empty FS space with zeroes (WARNING: this changes your disk image):
losetup --partscan --find --show disk.img
Assume it gives /dev/loop1 as the disk and there is only one partition, otherwise we need to repeat this for every partition with mountable FS in it (ignore swap partition etc.).
mkdir -p /mnt/tmp
mount /dev/loop1p1 /mnt/tmp
dd if=/dev/zero of=/mnt/tmp/tempfile
Let it finish to failure with ENOSPC.
/bin/rm -f /mnt/tmp/tempfile
umount /mnt/tmp
losetup -d /dev/loop1
- Copy into a sparse image:
'dd' has an option to convert a file with zeroes to a sparse file:
dd if=disk.img of=disk-sparse.img conv=sparse