Skip to content

diskimage — toolkit + CLI

github.com/go-diskimages/diskimage is the unified toolkit (library + CLI) for creating, converting, resizing, and reading/writing files inside VM disk images (raw / DMG-UDIF, plus QCOW2 via the CLI), across ext4/fat32/btrfs/xfs/zfs/exfat/apfs and MBR/GPT partition tables, with optional LUKS and APFS FileVault encryption. It is used to prepare images for Apple Virtualization.framework VMs. It also ships a cmd/diskimage CLI (renamed from the older diskimagec).

github.com/go-diskimages/diskimage

It composes the qcow2 and dmg codecs, the go-filesystems drivers, and go-fde (APFS/LUKS encryption) into one CLI + library — see its go.mod for exact versions. GRUB-config patching lives in the sibling go-bootloaders/grub package; OCI/Tart image extraction lives in the sibling tart-oci package.

Block device dispatcher

OpenBlockDevice opens a raw, QCOW2, or UDIF-UDRW DMG image behind one uniform BlockDevice (ReadAt / WriteAt / Size / Close):

dev, err := diskimage.OpenBlockDevice("disk.qcow2")
if err != nil { log.Fatal(err) }
defer dev.Close()

buf := make([]byte, 512)
dev.ReadAt(buf, 0)

Format is auto-detected: QCOW2 by its magic bytes, UDIF DMG by the koly trailer, everything else as a raw file.

UDIF is UDRW-only and in place

Read/Write are bounded to the data fork (the sector area at file offset 0). Close refreshes the koly trailer's dataForkChecksum + masterChecksum when anything was written, so the next open passes master-checksum verification. Compressed subformats (UDRO / UDZO / UDBZ / UDSP) are rejected with a pointer to dmg.UnpackToTemp + PackFromTemp for the explicit unpack-edit-repack path.

LUKS

OpenLUKSBlockDevice layers LUKS decryption on top of a raw or QCOW2 backing:

dev, err := diskimage.OpenLUKSBlockDevice("disk.luks.qcow2", []byte("pass"))
if err != nil { log.Fatal(err) }
defer dev.Close()              // closes LUKS and the underlying device

buf := make([]byte, 4096)
dev.ReadAt(buf, 0)             // reads the decrypted LUKS payload
dev.WriteAt(buf, 0)            // encrypts and writes back

Backing is raw (fallback) or QCOW2 (magic QFI\xfb). Size() returns the decrypted payload length — 0 for LUKS1 (its header does not encode the payload length), the configured length for LUKS2.

Image creation, growing, resizing, converting

func Create(opts CreateOptions) error
func Grow(path string, sizeBytes int64) error
func ResizeImage(path string, newSizeBytes int64) error
func ConvertImageFormat(path, dstFormat string) error

CreateOptions selects the container format (FormatRaw/FormatDmg), partition scheme (PartNone/PartMBR/PartGPT), filesystem (FSNone, FSExt4, FSFat32, FSBtrfs, FSXfs, FSZfs, FSExFAT, FSNTFS, FSApfs), volume label, and — for DMG images — the UDIF sub-format and an optional FileVault passphrase. ResizeImage/ConvertImageFormat are pure Go (via the dmg codec) and cross-platform. QCOW2 creation is exposed by the CLI (diskimage create qcow2) directly through the sibling qcow2 package.

In-image file operations

func ReadFile(opts FileOptions) ([]byte, error)
func WriteFile(opts FileOptions, data []byte, perm os.FileMode) error
func Stat(opts FileOptions) (filesystem.Stat, error)
func Rename(opts FileOptions, newPath string) error
func DeleteFile(opts FileOptions) error
func DeleteDir(opts FileOptions) error
func MkDir(opts FileOptions, perm os.FileMode) error
func List(opts ListOptions) ([]ListEntry, error)
func DetectFilesystem(imagePath string, partIndex int) (FilesystemType, error)

ext4 volume label

func SetExt4Label(imagePath string, partIndex int, label string) error
func Ext4Label(imagePath string, partIndex int) (string, error)

Reads or writes the ext4 s_volume_name of the partition at partIndex, working on raw, QCOW2, and UDIF-UDRW DMG inputs via OpenBlockDevice and an in-package ext4 adapter. The label is capped at 16 bytes; the metadata-csum is refreshed with the kernel-canonical CRC-32C convention (crc32c(~0, sb[:0x3FC]), no final XOR). Use it offline — concurrent writers may produce a torn superblock.

Filesystem detection

OpenBlockDevice plus the package's detect.go recognise the filesystem inside a backing image:

Filesystem How detected
APFS NX SuperBlock magic "NXSB" at offset 32 of block 0
ext4 superblock magic 0xEF53 at offset 0x438
FAT32 OEM "MSWIN4.1" / FAT32 BPB signature in the boot sector
NTFS OEM "NTFSIMG1" (test) or "NTFS " (real NTFS)
exFAT OEM "EXFAT " at bytes 3–10 of the boot sector
btrfs superblock magic _BHRfS_M at offset 0x10040
XFS superblock magic XFSB at offset 0
ZFS vdev label magic across blocks 0 / 256K / end

Build requirements

Pure Go (CGO_ENABLED=0), cross-platform, all six supported 64-bit architectures. A handful of darwin-only integration tests additionally cross-check the pure-Go UDIF codec against real hdiutil output and the go-bootloaders/grub patch helpers against real GRUB behavior on macOS; they are not part of the public API and are not required to build or use the library on any platform.

Debugging

The integration stress test's iteration count is configurable via the DISKIMAGE_STRESS_ITERS environment variable.