qcow2 — QCOW2 v2/v3 codec
github.com/go-diskimages/qcow2 (Go package image_qcow2) is a pure-Go
codec for the QCOW2 disk-image format. Standard library only,
CGO_ENABLED=0, no qemu-img. All on-disk structures — the 72-byte header,
the L1/L2 cluster tables, the refcount table/blocks, and compressed-cluster
descriptors — are read and written big-endian, matching the QCOW2 wire
format. The magic bytes are 0x514649fb (QFI\xfb).
Package functions
// Create writes a new empty QCOW2 v2 image (no allocated data clusters;
// reads from the equivalent raw image return zeros). cluster_bits = 16
// (64 KiB clusters). A 4-cluster file holds header, L1 table, refcount
// table, and refcount block.
func Create(path string, sizeBytes int64) error
// IsQCOW2File reports whether path begins with the QCOW2 magic bytes.
func IsQCOW2File(path string) bool
// ConvertToRaw reads a QCOW2 v2/v3 image and writes the equivalent raw
// disk image to dst, emitting "N%\n" progress lines to w.
// Supported: deflate-compressed clusters (compression type 0).
// Unsupported: encryption, and ZSTD compression (v3 compression_type=1).
func ConvertToRaw(src, dst string, w io.Writer) error
Format
Format{} satisfies the interface Format contract
structurally (no import needed):
type Format struct{}
func (Format) Name() string // "qcow2"
func (Format) Create(path string, sizeBytes int64) error // → Create
func (Format) Detect(path string) (bool, error) // → IsQCOW2File
func (Format) ToRaw(src, dst string, w io.Writer) error // → ConvertToRaw
func (Format) Resize(path string, newSizeBytes int64) error // grow only
Resize grows the image in place: it writes the new virtual size into the
header and extends the L1 table with zero (unallocated) entries when the new
size needs more L1 capacity. Shrinking is rejected — a smaller size could
silently discard allocated data.
Device — lazy copy-on-write block access
OpenDevice opens a QCOW2 image as a read-write block device:
dev, err := image_qcow2.OpenDevice("disk.qcow2")
if err != nil { log.Fatal(err) }
defer dev.Close()
buf := make([]byte, 4096)
dev.ReadAt(buf, 0) // unallocated clusters read as zeros
dev.WriteAt(buf, 0) // first write to a virtual cluster allocates it (COW append)
- Unallocated virtual clusters are allocated lazily on first write, appended to the end of the file (copy-on-write append), and the in-memory L1/L2 tables are updated.
- Compressed clusters are readable; writing to a compressed cluster returns an error (re-compression is not implemented).
- Supported versions are QCOW2 v2 and v3; encrypted images are rejected.
- Access is guarded by a
sync.RWMutex.