With VirtualBox, in order to compact sparse images effectively, unused blocks need to be set to zero. The traditional

cat /dev/zero >fillerup

Doesn’t seem to give good results. Here’s what worked better for me.

This info comes from the virtualbox forums but seems to have absolutely no google-juice, so I’m reposting it here in hopes of making it easier to find.

The end result still isn’t spectacular, but on my image that should occupy 2.1G if the disk image were perfectly sparse, it resulted in a 2.8G image. Copying from /dev/zero prior to compacting resulted in a 3.6G image. That makes the difference between wanting to compress the image when I burn it to a DVD and being happy to leave it alone.

From the guest:

  1. Download and build zerofree from here.
  2. Find out the device node for the filesystem in question using df. For me, it’s /dev/sda1 mounted at /.
  3. Drop to single user mode using init 1
  4. Remount the filesystem read-only without journaling:
    mount -n -o remount,ro -t ext2 /dev/sda1 /
    
  5. Check the filesystem (fsck.ext2 -f /devicenode)
  6. Run zerofree, pointed at the device node
  7. Recheck the filesystem
  8. Remount read-write with journaling:
    mount -o remount,rw -t ext3 /dev/sda1 /
    
  9. shutdown -h now
  10. Then from the host, use vboxmanage to compact the disk image:

    VBoxManage modifyvdi /full/path/to/vdifile compact