When working with USB drives in Linux, you'll often encounter situations where not all disk space is allocated to partitions. The fdisk -l
output shows a typical case:
Disk /dev/sdb: 8462 MB, 8462008320 bytes
255 heads, 63 sectors/track, 1028 cylinders
Units = cylinders of 16065 * 512 = 8225280 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
Device Boot Start End Blocks Id System
/dev/sdb1 * 1 9 72261 e W95 FAT16 (LBA)
/dev/sdb2 10 103 755055 83 Linux
The conventional dd
approach captures all sectors, including unallocated space:
dd if=/dev/sdb of=myimage.img bs=1M
This creates an 8GB file when we only need about 1GB for the actual partitions.
Here are three practical methods to create space-efficient images:
Method 1: Partition-Level Imaging
Create separate images for each partition:
dd if=/dev/sdb1 of=fat_partition.img bs=1M
dd if=/dev/sdb2 of=linux_partition.img bs=1M
Method 2: Using partclone
The partclone
tool is specifically designed for this purpose:
partclone.ext2 -c -s /dev/sdb2 -o linux_partition.pcl
partclone.fat -c -s /dev/sdb1 -o fat_partition.pcl
Method 3: Combined Approach with sfdisk
First backup the partition table:
sfdisk -d /dev/sdb > partitions.sfdisk
Then create compressed images of each partition:
partclone.ext2 -c -s /dev/sdb2 | gzip > linux_partition.img.gz
partclone.fat -c -s /dev/sdb1 | gzip > fat_partition.img.gz
To restore to a new USB drive:
sfdisk /dev/sdX < partitions.sfdisk
partclone.ext2 -r -s linux_partition.pcl -o /dev/sdX2
partclone.fat -r -s fat_partition.pcl -o /dev/sdX1
For even more space savings, consider sparse files:
dd if=/dev/sdb of=sparse.img bs=1M conv=sparse
This creates a file that only stores non-zero blocks, appearing as 8GB but consuming less actual disk space.
While partclone is generally faster for partition imaging, dd offers more control over block sizes. For best results with partclone:
partclone.ext2 -c -s /dev/sdb2 -o linux_partition.pcl -b -q
The -b
enables buffering and -q
reduces output verbosity.
When working with USB drives containing unallocated space, the standard dd
approach creates unnecessarily large image files. Consider this common scenario:
[root@host]# fdisk -l /dev/sdb
Disk /dev/sdb: 8462 MB, 8462008320 bytes
255 heads, 63 sectors/track, 1028 cylinders
Units = cylinders of 16065 * 512 = 8225280 bytes
/dev/sdb1 * 1 9 72261 e W95 FAT16 (LBA)
/dev/sdb2 10 103 755055 83 Linux
Running dd if=/dev/sdb of=myimage.img bs=1M
would produce an 8GB file, while only about 1GB contains actual data.
The most straightforward solution is to image only the allocated partitions:
# Image the FAT partition
dd if=/dev/sdb1 of=fat_partition.img bs=1M
# Image the Linux partition
dd if=/dev/sdb2 of=linux_partition.img bs=1M
This creates separate image files totaling approximately 827MB (72MB + 755MB).
For tools requiring a single image file, we can use these approaches:
Method 1: Using sfdisk and dd
# Save partition table
sfdisk -d /dev/sdb > partitions.sfdisk
# Calculate total used blocks
END_SECTOR=$(sfdisk -l -o End /dev/sdb | tail -1)
BLOCK_SIZE=512
IMAGE_SIZE=$(( (END_SECTOR + 1) * BLOCK_SIZE ))
# Create optimized image
dd if=/dev/sdb of=optimized.img bs=1M count=$((IMAGE_SIZE/1048576 + 1))
Method 2: Using parted for Precision
# Get last sector of last partition
LAST_SECTOR=$(parted /dev/sdb unit s print | grep -A2 "Number" | tail -1 | awk '{print $3}' | tr -d 's')
# Calculate image size
dd if=/dev/sdb of=compact.img bs=512 count=$((LAST_SECTOR + 1))
For even better space management:
dd if=/dev/sdb of=sparse.img bs=1M conv=sparse
This creates a sparse file that only occupies actual data blocks on disk while appearing as a full-size image to applications.
When working with emulators like QEMU:
# Create qcow2 image (dynamically allocated)
qemu-img convert -f raw -O qcow2 optimized.img bootable.qcow2
This creates a compressed, efficient image file that only grows as data is written.
Always verify your images:
# Check file sizes
ls -lh *.img
# Verify partition structure
fdisk -l optimized.img
# Test bootability
qemu-system-x86_64 -hda optimized.img