A sparse extent (extent type SPARSE), used by Workstation, Fusion and
Player and in stream-optimized files, stores only the grains (blocks) of the disk that
have been written. It starts with a 512-byte header whose magic reads
KDMV. All numbers are little-endian and positions are in 512-byte
sectors.
Header
| Offset | Size | Type | Name | Description |
|---|---|---|---|---|
0 | 4 | uint32 | Magic | 0x564D444B, stored 4B 44 4D 56 (KDMV). |
4 | 4 | uint32 | Version | 1, 2 or 3. The redundant grain directory flag needs version 2 or later. |
8 | 4 | bits | Flags | See flags. |
12 | 8 | uint64 | Capacity | The extent’s size in sectors. |
20 | 8 | uint64 | Grain size | Sectors per grain, a power of two greater than 8; 128 (64 KiB) normally. |
28 | 8 | uint64 | Descriptor offset | Sector of the embedded descriptor; 0 if none. |
36 | 8 | uint64 | Descriptor size | Its size in sectors. |
44 | 4 | uint32 | Grain table entries | Entries per grain table: 512. |
48 | 8 | uint64 | Redundant grain directory offset | Sector of the second (backup) grain directory. |
56 | 8 | uint64 | Grain directory offset | Sector of the grain directory. 0xFFFFFFFFFFFFFFFF (GD_AT_END) in a stream-optimized file: the real value is in the footer. |
64 | 8 | uint64 | Overhead | Sectors before the first grain: header, descriptor and tables, rounded up to a whole grain. |
72 | 1 | uint8 | Unclean shutdown | 1 while the file is open for writing; 1 when found means it was not closed properly. |
73 | 4 | bytes | Newline check | 0A 20 0D 0A (LF, space, CR, LF): if a file transfer changed line endings these bytes change, and the file is known to be damaged. |
77 | 2 | uint16 | Compression | 0 none; 1 deflate. See compressed grains. |
79 | 433 | – | Padding | Zeros. |
Flags
| Bit | Meaning |
|---|---|
0x00000001 | The newline check bytes are valid. |
0x00000002 | The redundant grain directory is used. |
0x00000004 | Grain table entry 1 means a zeroed grain (see below). |
0x00010000 | Grains are compressed. |
0x00020000 | The file contains markers (stream-optimized). |
Grain directory and grain tables
A two-level map. The grain directory is an array of uint32 sector numbers, one per grain table; each grain table is an array of 512 uint32 entries, one per grain. One grain table therefore covers 512 × grain size sectors (32 MiB with 64 KiB grains), and the directory has capacity ÷ that many entries, rounded up.
| Grain table entry | Meaning |
|---|---|
| 0 | The grain is not allocated: it reads as zeros, or from the parent disk for a child. |
| 1 | With flag 0x4: a zeroed grain, which reads as zeros even in a child disk. |
| any other | The sector where the grain’s data starts. |
To read sector s: grain table = s ÷ (512 × grain size); entry in it = (s ÷ grain size) mod 512; then the data is at entry × 512 + (s mod grain size) × 512 bytes. The redundant directory and its tables are a full second copy.
Compressed grains
With compression 1, each stored grain is a small header and the compressed data, starting on a sector boundary:
| Offset | Size | Type | Name | Description |
|---|---|---|---|---|
0 | 8 | uint64 | LBA | The grain’s first sector on the virtual disk. |
8 | 4 | uint32 | Size | Bytes of compressed data. |
12 | size | bytes | Data | The grain, compressed with deflate in a zlib wrapper (RFC 1950), then padding to the next sector. libvmdk’s section on compressed grain data says “ZLIB compressed data (DEFLATE + ZLIB header)”, and QEMU’s block/vmdk.c uses zlib’s compress and uncompress; libvmdk’s header table names the method only as deflate (RFC 1951). |
Markers and stream-optimized files
A stream-optimized file is written front to back with no seeking, so the tables come after the grains they describe, each announced by a marker sector:
| Offset | Size | Type | Name | Description |
|---|---|---|---|---|
0 | 8 | uint64 | Value | For a table marker: the number of sectors of table that follow. |
8 | 4 | uint32 | Size | 0 for a marker. (A non-zero value here means the sector is a compressed grain, as above.) |
12 | 4 | uint32 | Type | 0 end of stream; 1 grain table follows; 2 grain directory follows; 3 footer follows. |
16 | 496 | – | Padding | Zeros, to the end of the sector. |
The usual order is: header, embedded descriptor, then compressed grains with a grain table marker and grain table after each run of 512 grains, then a grain directory marker and the grain directory, a footer marker and the footer (a copy of the header with the real grain directory offset), and an end-of-stream marker. The footer is the second-last sector, 1,024 bytes from the end of the file.
Example
The header of a 20 GiB monolithic sparse disk.
00000000 4B 44 4D 56 01 00 00 00 03 00 00 00 00 00 80 02 KDMV............
00000010 00 00 00 00 80 00 00 00 00 00 00 00 01 00 00 00 ................
00000020 00 00 00 00 14 00 00 00 00 00 00 00 00 02 00 00 ................
00000030 15 00 00 00 00 00 00 00 1A 0A 00 00 00 00 00 00 ................
00000040 80 14 00 00 00 00 00 00 00 0A 20 0D 0A 00 00 00 ......... ......
Reading it: KDMV, version 1; flags 3 (newline check, redundant
directory); capacity 0x2800000 sectors, 20 GiB; grains of 128 sectors;
descriptor at sector 1, 20 sectors long; 512 entries per grain table; redundant
directory at sector 21 and directory at sector 2,586; 5,248 sectors of overhead; clean;
the newline bytes; no compression. 640 grain tables cover the disk, so each directory
is 640 × 4 bytes, 5 sectors.