What Is a VMDK File? The Virtual Machine Disk File, and How to Open, Convert and Check One
A VMDK file is the virtual hard disk of a virtual machine, and VMware made the format. Four readers opened 12 of our 15 test files, and the three main readers gave one answer on only 3 of 21 damaged copies. Jump to your question below, or work through it in order.
What Is a VMDK File? The hard disk of a virtual machine, and what the ending hides
Short answer
A VMDK file is the virtual hard disk of a virtual machine, and VMware made the format. It can be one file or a small text descriptor with data files beside it. All 15 of our test files end in .vmdk, and they are four kinds.
We tested 15 VMDK files with 4 readers. Twelve opened in all 4. We then damaged one file in 21 ways, and the 3 main readers gave one answer on only 3 copies.
To see inside one, use the open steps. To make a raw disk from one, use the convert steps. If your VMDK file will not open, begin with the causes.
A VMDK file is the virtual hard disk of a virtual machine, and VMware made the format. It can be one file or a small text descriptor with data files beside it. All 15 of our test files end in .vmdk, and they are four kinds.
Picture a folder named after a virtual machine. Inside it is a VMDK file, and that file is the hard disk of the machine. FileInfo names the type Virtual Machine Disk File and lists VMware as the developer.
Wikipedia says VMware made the format for its own products and opened it with revision 5.0 in 2011. QEMU, VirtualBox and Parallels Desktop support VMDK files too. It is one of the disk formats inside OVF packages.
The same article says some subformats keep metadata in an external descriptor file, and others embed it. Flat images take their space in advance, and sparse images grow as the machine writes data. An image can point to a parent and store only changes, which is how snapshots work.
Where our VMDK files come from
We studied 15 VMDK files. We made 14 of them with qemu-img 8.2.2 from one 16 MiB disk image. The image has a small file system with 7 files in it. The 15th is a public test file from the dissect.hypervisor project, and it starts with the bytes CAFEBABE.
We made no file with VMware or VirtualBox. So our results show how readers treat these files, and they do not show what VMware accepts. Our four readers are qemu-img, libvmdk 20260714 for Python, dissect.hypervisor 3.21 and 7-Zip 23.01.
We also damaged one sparse file in 21 ways and tested file sets that lost a piece. Our lab uses Linux and has no VMware product, so we opened no file in VMware.
VMDK file facts at a glance
| Property | Value |
|---|---|
| Meaning | A virtual disk image for a virtual machine, made by VMware. |
| Ending |
.vmdk. FileInfo names the type Virtual Machine Disk File.
|
| Maker | VMware, per FileInfo and Wikipedia. |
| Pieces | One file, or a text descriptor with data files. We tested both. |
| Signature |
KDMV at the start of a sparse file, and # Disk DescriptorFile at the start of a descriptor.
|
| Sector size | 512 bytes, per the libvmdk documentation. |
| Readers | qemu-img, libvmdk, dissect and 7-Zip, all tested. FileInfo names VMware Workstation, VirtualBox and more. |
| Our tests | 15 files, 21 damaged copies, 3 readers in the grid, a check script of 28 lines and a repair script of 19 lines. |
Is it a compressed archive and not a disk? The ZIP file overview covers the ZIP format.
Which Kind of VMDK File Is Yours? Four kinds, and the name does not decide
Four kinds of VMDK file showed up in our tests, and all of them end in .vmdk. A descriptor with its data files and a single sparse file opened in all 4 readers. 7-Zip refused the 2 stream files, and only dissect opened the SEsparse file.
Anyone can see the ending, and it does not name the kind. We sorted our 15 files by their first bytes and by the descriptor text. Follow the figure.
The kinds in detail
| Kind | Files and results |
|---|---|
| A descriptor and its extents | 5 of 15 files. A text file names one or more data files in extent lines. Ours are 2 flat files, 2 split sparse files and 1 split flat file. All 4 readers returned the original disk. |
| A sparse file in one piece | 7 of 15 files. The file starts with KDMV and has its own descriptor inside. All 4 readers returned the original disk, for every adapter and hardware option we set. |
| A stream file | 2 of 15 files. The grains are compressed, so the file is smaller. Ours is 403,456 bytes, and the same disk as a sparse file is 786,432 bytes. qemu-img, libvmdk and dissect returned the original disk, and 7-Zip refused both. |
| An SEsparse file | 1 of 15 files. The file starts with the bytes CAFEBABE. dissect opened it and reported 536,870,912 bytes. libvmdk and 7-Zip refused it. qemu-img refused it as VMDK, and with no format option it called the file raw. |
Look at the first bytes
Sparse VMDK files start with the four letters KDMV, and descriptors are text that you can print. Command one prints 48 bytes of a sparse file. Command two prints the start of a descriptor.
xxd -l 48 disk.vmdk
00000000: 4b44 4d56 0100 0000 0300 0000 0080 0000 KDMV............
00000010: 0000 0000 8000 0000 0000 0000 0100 0000 ................
00000020: 0000 0000 1400 0000 0000 0000 0002 0000 ................
Bytes 1 to 4 are KDMV. Bytes 5 to 8, 01000000, give version 1. Then come flags, 03000000, and capacity, 0080 0000 0000 0000. That is 32,768 sectors of 512 bytes, or 16 MiB.
head -n 8 flat.vmdk
# Disk DescriptorFile
version=1
CID=e150112
parentCID=ffffffff
createType="monolithicFlat"
# Extent description
RW 32768 FLAT "flat-flat.vmdk" 0
| Value | What we measured |
|---|---|
| Signature |
KDMV in 9 files. The 5 descriptor files start with the text # Disk DescriptorFile.
|
| Version | Version 1 in 6 sparse files, version 2 in 1 file made with the zeroed grain option and version 3 in the 2 stream files. |
| Flags |
0x3 in 6 files, 0x7 in the zeroed grain file and 0x30003 in the 2 stream files.
|
| Capacity and grain | 32,768 sectors and a grain of 128 sectors, which is 64 KiB, in all 9 files with a header. |
| Descriptor | At sector 1 and 20 sectors long in all 9 files with a header. |
| Compression | Method 0 in 7 files and method 1 in the 2 stream files. The libvmdk notes on compression name method 1 as deflate. |
Is it a Microsoft Office file and not a disk? The XLS file overview covers the Excel workbook format.
What Is Inside a VMDK File? A header, a descriptor and grains of data
A sparse VMDK file has 512 bytes of header, then an embedded descriptor, grain directory, tables and grains of data. Our example has 786,432 bytes and 11 grains. We found no checksum in the header, the tables or the grains.
We looked inside one sparse VMDK file, because its layout explains the results later on this page. It has 16 MiB of disk and 786,432 bytes of file. The two commands below show how qemu-img describes it and how 7-Zip lists the files inside the disk.
qemu-img info disk.vmdk
image: disk.vmdk
file format: vmdk
virtual size: 16 MiB (16777216 bytes)
disk size: 720 KiB
cid: 2255558497
parent cid: 4294967295
create type: monolithicSparse
extents:
[0]:
virtual size: 16777216
7z l disk.vmdk
D.... lost+found
..... 3400 4096 file1.txt
..... 6800 8192 file2.txt
..... 10200 12288 file3.txt
..... 13600 16384 file4.txt
..... 17000 20480 file5.txt
..... 20400 20480 file6.txt
..... 300000 303104 random.bin
..... 4194304 4194304 [SYS]/Journal
4565704 4579328 8 files,
7-Zip shows the file system of our disk, with 7 files and a journal. So disks contain file systems, and VMDK files are containers around them. Follow the figure for the layout.
The parts, one by one
Headers have signature, version, flags, capacity and grain size fields. After it comes the descriptor, a text block with disk type and extent line. In our file the descriptor starts at sector 1 and takes 20 sectors.
Grain directories point to grain tables, and tables point to grains. Our file has its directory at sector 26 and a copy at sector 21. Tables have 512 entries. Grains are 128 sectors, so one table covers 32 MiB of disk and is enough for our 16 MiB.
Data starts at sector 128. Grains have 64 KiB, so 16 MiB of disk has 256 grains. Our file has 11 of them, which take 704 KiB. We found no checksum or signature on grains.
What every part stores
| Part | What it stores |
|---|---|
| Header | The first 512 bytes. Copy A1 changes KDMV and A4 sets the capacity to 0. qemu-img and libvmdk refused both. Our repair script restores both. |
| Embedded descriptor | Text with CID, parentCID and createType. Copy C3 zeroes it, and all 3 readers refused the copy. Copy C2 misspells the type, and only libvmdk refused it. |
| Grain directory and tables | Pointers to the grains. Copy C4 zeroes the directory and C5 zeroes the first table. All 3 readers returned a disk of zeros and no error. |
| Line check bytes | Four bytes that show if a transfer changed line ends. Copy B1 changes one, and only libvmdk refused it. |
| Grains | The data. Copy C6 changes one byte in a grain, and all 3 readers returned the disk with that byte changed and no warning. |
| The file cut short | Copy C7 cuts the file at 100,000 bytes. libvmdk refused it, and qemu-img and dissect returned a different disk. |
What the public pages say about the layout
The libvmdk file format notes say a sector is 512 bytes and the header has the signature KDMV. It lists versions 1, 2 and 3 for the sparse header. It also lists a COWD sparse type for vmfsSparse, and we had no such file.
The VMDK article on Wikipedia says VMware opened the specification with revision 5.0 in 2011. We did not use the VMware specification. We took our values from the bytes of our files and from the libvmdk notes.
The structure is small. Our script checks headers only. It looks at signature, version, sizes and offsets. It never checks tables or grains, so it printed OK for 6 VMDK file copies that readers did not treat as the original.
What Did We Find in 15 Test VMDK Files? Four readers, and twelve files opened in all of them
We tested 15 VMDK files with 4 readers. Twelve opened in all 4 with the original disk. qemu-img and libvmdk opened 14 files, dissect opened all 15 and 7-Zip opened 12.
We called a result the same when the reader returned the same bytes as our source disk, by SHA-256. The public SEsparse file has no source disk, so we only note that a reader opened it. A descriptor needs its data files beside it, and we kept them together.
What the numbers show
| Finding | What we measured |
|---|---|
| The readers agree on files we made | Twelve of our 14 made files gave the original disk in all 4 readers. The options we set changed nothing for any reader. They are compat6, hardware 6, zeroed grain and three adapter types. |
| 7-Zip and the stream files | 7-Zip refused both stream files and said it cannot open them as VMDK. qemu-img, libvmdk and dissect returned the original disk. |
| The SEsparse file | Only dissect opened it, and it reported a disk of 536,870,912 bytes. libvmdk and 7-Zip refused it. qemu-img refuses it as VMDK, and it calls the same file raw when you give no format. |
| Split files need every piece | A descriptor with no data file beside it was refused by all 4 readers. Renaming both files broke the link too. After we edited the extent line to the new name, all 4 returned the original disk. |
| A snapshot child needs its parent | A child made from a parent opened in qemu-img, libvmdk and dissect when the parent was beside it, and 7-Zip refused it. Alone, all 4 refused it. Our libvmdk script had to open the parent and link it. |
| Size depends on the kind | Our stream file is 403,456 bytes and our sparse file for one disk is 786,432 bytes. Flat disks take 16,777,216 bytes plus a 512 byte descriptor. |
We do not know which reader VMware would agree with, because we used no VMware product. The 12 files that opened everywhere show that the readers agree on the bytes when they agree to open the file.
What this study cannot show you
Our disk is 16 MiB, and one tool made 14 of the 15 files. Disks from working virtual machines are much larger, and VMware or VirtualBox can store other values. Readers that pass here have shown that they open small samples from qemu-img.
We tested no encrypted disk, no vmfs disk, no delta file with a COWD header and no disk over 16 MiB. We compared full disks by SHA-256. We did not compare partitions or file names for the damaged copies.
What Happens When a VMDK File Is Damaged? 21 broken copies, and a blank disk that nobody flags
We damaged one VMDK file in 21 ways. The 3 main readers gave the original disk on only 3 copies. A zeroed grain directory gave a blank disk in all 3 readers with no error, and our script printed OK for it.
Our base VMDK file is the sparse file, with 786,432 bytes and 16 MiB of disk. We changed one thing at a time and saved 21 copies. Same means readers returned the bytes of the base disk, by SHA-256. Refused means an error and no disk. Differs means readers returned another disk with no error.
Differs is the result that worries us. A refusal shows a problem. Another disk shows none, and nobody would know. Follow the figure.
What the grid shows
| Copies | What happened |
|---|---|
| The signature and the version | Copy A1 changes KDMV. qemu-img and libvmdk refused it, and dissect returned another disk. Copy A2 sets the version to 0, and all 3 readers returned the original disk. Copy A3 sets it to 4, and only qemu-img refused it. |
| Capacity and grain size | Copy A4 sets the capacity to 0. qemu-img and libvmdk refused it, and dissect returned another disk. Copy A5 sets the grain size to 0, and all 3 refused it. Copy A6 sets it to 127. libvmdk refused it, and the other two returned another disk with no error. |
| The flags and the dirty byte | Copy A7 clears the flags, and C1 sets the dirty byte to 1. All 3 readers returned the original disk for both. |
| The line check byte | Copy B1 changes the first check byte. libvmdk refused it, and qemu-img and dissect returned the original disk. |
| The descriptor | Copy B2 sets the descriptor offset to 0, and libvmdk and dissect refused it. Copy B3 sets the size to 0, and only libvmdk refused it. Copy C2 misspells the disk type, and only libvmdk refused it. Copy C3 zeroes the descriptor, and all 3 refused it. |
| Tables and directories | Copy B4 sets table entries to 0, and all 3 readers refused it. Copies B5 and B6 point the directory to 0 and past the end. qemu-img returned another disk for both, and two readers refused. Copy B7 zeroes the offset of the directory copy, and only libvmdk refused it. |
| Zeroed tables and a changed grain | Copies C4 and C5 zero the directory and the first table, and C6 changes one byte in a grain. All 3 readers returned another disk with no error. For C4 and C5 the disk was 16 MiB of zeros. |
| A cut file | Copy C7 cuts the file at 100,000 bytes. libvmdk refused it, and qemu-img and dissect returned another disk with no error. |
The pattern has two sides. Most header damage got a refusal from libvmdk, which refused 14 of 21 copies. None of the 3 readers refused C4, C5 or C6, because nothing in the tables or the grains checks them.
The readers differ in how much they accept. qemu-img and dissect gave the original disk on 8 copies and refused 6. libvmdk gave it on 4 and refused 14.
The silent failures
Two results point to a risk, and we tested both at scale. First, we cut the file every 8,192 bytes, which made 95 cuts. libvmdk refused all 95. dissect returned another disk on 94 of them and qemu-img on 85, with no error. qemu-img returned the original disk on the last 3 cuts, which lose 8,192 to 24,576 bytes.
Second, we changed one byte at the start of every one of the 11 grains, one copy for every grain. All 3 readers opened all 11 and returned another disk. None refused a copy and none warned. So an open file is not proof that the data is right.
Our script cannot see changed grains, because the header is fine. Only comparing against known good copies shows them. So keep SHA-256 hashes of the raw disk from when the VMDK file was good.
Our script and the repairs
Our check script of 28 lines printed OK for 6 copies, WARN for 3 and FLAG for 12. All 6 OK copies differ from the original in at least one reader, because it checks headers and not tables. See the script.
It also printed WARN or FLAG on 3 copies that all 3 readers treated as the original. They are A2, A7 and C1. So a flag is a reason to look and not proof of damage.
The repair script of 19 lines restored 12 copies, A1, A3 to A6 and B1 to B7. All 3 readers then gave the original disk on those 12. It cannot restore cut files, zeroed tables or changed grains. For C3 it wrote a new descriptor, and libvmdk still refused the file. We did not test a repaired file in VMware.
What Does Our Expert Say About VMDK Files? A note from Neeraj Singh on trusting a disk that opens
We asked our expert what the grid means for someone who has a VMDK file and has to decide if the disk inside is right. He looked at the 21 copies and at the cuts.
Expert insight
Treat the VMDK file as a container, and keep a hash of the disk inside it. A zeroed grain directory gave a blank disk in all 3 readers with no error, so a file that opens is not proof that the data is there.
That advice fits our lab. Readers opened blank disks without a word, so quick opens prove little. Convert the disk to raw, list the files inside and compare hashes with known good copies.
How Do You Open a VMDK File? Four readers, with the commands we tested
To open a VMDK file without VMware, use qemu-img, libvmdk through Python, dissect or 7-Zip. All 4 opened 12 of our 15 files and left the files unchanged. We did not test VMware or VirtualBox. Copy the files first, and compare more than one reader.
VMware products are the usual route. FileInfo lists VMware Workstation, VMware Fusion and Oracle VirtualBox, and Wikipedia adds QEMU and Parallels Desktop. Our lab uses Linux and has no VMware product, so we tested 4 readers that need none.
Your options
Copy first, then look
Work on copies of the VMDK descriptor and of every data file, and keep their names. Our readers only looked at the files. SHA-256 hashes of disk.vmdk and of the flat set were the same before and after all 4 readers opened them. Copies cost nothing, and they keep originals safe from your own mistakes.
Look at the size of the disk
Start with disk size. Command one asks libvmdk for it, and command two asks dissect. Command three checks the VMDK file with qemu-img. All three agree on 16,777,216 bytes.
python3 -c "import pyvmdk; h = pyvmdk.handle(); h.open('disk.vmdk'); h.open_extent_data_files(); print(h.get_media_size())"
16777216
python3 -c "from dissect.hypervisor.disk.vmdk import VMDK; v = VMDK(open('disk.vmdk', 'rb')); print(v.size)"
16777216
qemu-img check disk.vmdk
No errors were found on the image.
The check looks at structure. It found no errors in copies C4 and C5, where the disk is blank, or in C6, where one byte changed. It did report an error for cut copy C7. So a good check is a start, and it does not prove data.
Is it a database and not a disk? The SQLITE file overview covers the SQLite format.
How Do You Convert a VMDK File to Another Disk Format? Five targets, tested on one disk
To convert VMDK files to raw disks, use qemu-img. Our example gave a raw file with the same SHA-256 as our source disk. QCOW2, VDI and VHDX gave the same bytes back, and VHD added 4,096 bytes of size. We tested no VMware or VirtualBox converter.
All conversions left the VMDK file unchanged in our tests. We checked every result by converting it back to raw and comparing SHA-256 hashes. A raw file is the disk as bytes, and it has the full size of the disk, 16,777,216 bytes for ours.
Convert it to raw
Command one converts the disk. Command two makes a hash, and it matches our source disk. Command three lists the files in the raw disk with debugfs, so you can see the data is there.
qemu-img convert -f vmdk -O raw disk.vmdk disk.raw
sha256sum disk.raw
df77962264738a5775e4ccf3b7b7c595cfcd9adbf4951cc3d835e4412cc59321 disk.raw
debugfs -R "ls -l" disk.raw
11 40700 (2) 0 0 16384 7-Nov-2026 00:56 lost+found
12 100644 (1) 0 0 3400 7-Nov-2026 00:56 file1.txt
Convert it to other formats
The same command makes other formats when you change the -O option. We converted our disk to QCOW2, VDI, VHDX and VHD, and then back to raw. We compared the raw files with the source.
| Target | Result |
|---|---|
| Raw | 16,777,216 bytes. The SHA-256 matches the source disk. |
| QCOW2 | The file has 1,048,576 bytes. The SHA-256 after a conversion back to raw matches. |
| VDI | The file has 3,146,752 bytes. The SHA-256 after a conversion back to raw matches. |
| VHDX | The file has 16,777,216 bytes. The SHA-256 after a conversion back to raw matches. |
| VHD |
The file has 4,197,888 bytes and the virtual size is 16,781,312 bytes, which is 4,096 more. The first 16 MiB match. The option force_size=on kept 16,777,216 bytes.
|
Make a VMDK file
The subformat option sets the kind. We made 3 kinds of VMDK file from the same raw disk. The sparse file has 786,432 bytes, the stream file has 403,456 bytes and the flat kind has a 512 byte descriptor and a 16,777,216 byte data file.
qemu-img convert -f raw -O vmdk -o subformat=streamOptimized disk.raw disk.vmdk
What we did not test. We converted one disk of 16 MiB. We did not test converters from VMware or VirtualBox, web converters, snapshot chains, encrypted disks or disks over 16 MiB. We did not start a virtual machine from any converted disk.
Is the disk image a ZIP of files? The ZIP file page covers archives.
How Do You Check a VMDK File? Six steps and a script of 28 lines
Check a VMDK file in six steps. Copy it first. Then print its first bytes, check the header, convert it to raw in two readers, list the files inside and compare hashes with a known good copy. Our script of 28 lines does the header step.
- Copy the VMDK file and every data file beside it, and keep their names. Keep the original.
-
Print the first bytes with
xxd -l 48 disk.vmdk. They must start withKDMVor with the text# Disk DescriptorFile. -
Check the header with
python3 vmdk_peek.py disk.vmdk. A good file prints OK. - Convert the copy to raw in two readers, and compare the SHA-256 of the two raw files.
- List the files inside the raw disk with 7-Zip or debugfs, and open a few.
- Keep a SHA-256 hash of the raw disk from a good time, and compare it with the disk you have now. Only comparing hashes finds silent changes.
The check in Python
Our script of 28 lines checks VMDK file headers with the standard library. It prints OK, WARN or FLAG with the problem it found. It checks signature, version, sizes, offsets, line check bytes and the dirty byte. It never looks inside tables or grains.
import sys, struct, os
FMT = '<4sIIQQQQIQQQBccccH'
def peek(p):
n = os.path.getsize(p); b = open(p, 'rb').read(65536)
if b[:4] != b'KDMV':
text = b[:4096].decode('latin1')
if text.startswith('# Disk DescriptorFile') and 'createType' in text: return 'OK', 'text descriptor'
return 'FLAG', 'no KDMV and no descriptor'
m, v, fl, cap, gs, do, ds, ngt, rgd, gd, oh, un, c1, c2, c3, c4, cm = struct.unpack(FMT, b[:79])
bad, warn = [], []
if v not in (1, 2, 3): bad.append('version %d' % v)
if cap == 0: bad.append('capacity 0')
if gs < 8 or gs & (gs - 1): bad.append('grain size %d' % gs)
if ngt == 0: bad.append('0 GTEs per table')
if (c1, c2, c3, c4) != (b'\n', b' ', b'\r', b'\n'): bad.append('line check bytes')
if (do == 0) != (ds == 0) or (do == 0 and fl & 0x20000 == 0 and v != 3): bad.append('no descriptor')
if gd == 0: bad.append('gd offset 0')
for name, off in (('gd', gd), ('rgd', rgd)):
if off != 2**64 - 1 and off * 512 >= n: bad.append('%s offset past end' % name)
if n < oh * 512: bad.append('file shorter than overhead')
if fl & 1 == 0: warn.append('flags bit 0 clear')
if un: warn.append('unclean shutdown flag')
desc = open(p, 'rb').read((do + ds) * 512)[do * 512:] if do else b''
if do and b'createType' not in desc: warn.append('descriptor has no createType')
if bad: return 'FLAG', '; '.join(bad)
return ('WARN', '; '.join(warn)) if warn else ('OK', 'header looks fine')
for p in sys.argv[1:]:
s, m = peek(p); print('%s %-5s %s' % (os.path.basename(p), s, m))
What the script prints
First come good sparse files and good descriptors. Next is copy A4, which has zero capacity. Then copy B6, which has its directory past the end. Then comes copy C4, with a zeroed directory. The script cannot see C4, and all 3 readers returned a blank disk.
python3 vmdk_peek.py disk.vmdk flat.vmdk A4.vmdk B6.vmdk C4.vmdk
disk.vmdk OK header looks fine
flat.vmdk OK text descriptor
A4.vmdk FLAG capacity 0
B6.vmdk FLAG gd offset past end
C4.vmdk OK header looks fine
The repair script
The repair script of 19 lines changes VMDK file headers and descriptors only. It restores KDMV, version, capacity, grain size, table entries and line check bytes. It moves a bad directory offset to its computed place and clears the dirty byte. It restored 12 of our 21 damaged copies.
It guesses 128 sectors per grain and 512 table entries when a field is bad. Those values fit our file, and files made with other values need other numbers.
python3 vmdk_fix.py B6.vmdk B6_fixed.vmdk
python3 vmdk_peek.py B6.vmdk B6_fixed.vmdk
B6.vmdk FLAG gd offset past end
B6_fixed.vmdk OK header looks fine
import sys, os, re, struct, math, shutil
FMT = '<4sIIQQQQIQQQBccccH'
src, dst = sys.argv[1:3]
shutil.copyfile(src, dst); f = open(dst, 'r+b'); b = f.read(65536)
m, v, fl, cap, gs, do, ds, ngt, rgd, gd, oh, un, c1, c2, c3, c4, cm = struct.unpack(FMT, b[:79])
if do == 0 or ds == 0: do, ds = 1, 20
text = b[do * 512:(do + ds) * 512].decode('latin1').strip('\0')
if cap == 0: cap = sum(int(x) for x in re.findall(r'^RW (\d+) SPARSE', text, re.M)) or cap
if v not in (1, 2, 3): v = 1
if gs < 8 or gs & (gs - 1): gs = 128
if ngt == 0: ngt = 512
if rgd == 0: rgd = do + ds
n = math.ceil(cap / (gs * ngt))
if gd == 0 or gd * 512 >= os.path.getsize(src):
gd = rgd + math.ceil(n * 4 / 512) + n * math.ceil(ngt * 4 / 512)
if not text:
new = '# Disk DescriptorFile\nversion=1\nCID=fffffffe\nparentCID=ffffffff\ncreateType="monolithicSparse"\n\nRW %d SPARSE "%s"\n' % (cap, os.path.basename(dst))
f.seek(do * 512); f.write(new.encode().ljust(ds * 512, b'\0'))
f.seek(0); f.write(struct.pack(FMT, b'KDMV', v, fl | 1, cap, gs, do, ds, ngt, rgd, gd, oh, 0, b'\n', b' ', b'\r', b'\n', cm)); f.close()
Copy B6 had its directory offset set past the end of the VMDK file. The script computes a place from the directory copy and table sizes. All 3 readers then gave the original disk, and that is the only proof we have. We did not test the repaired file in VMware.
Know the limits. The script printed OK for 6 copies where at least one reader did not give the original disk. It cannot see changed grains or zeroed tables. So an OK from one script is only a start, and comparing hashes with a known good copy is the test.
Is a VMDK File Safe to Open? The file is data, and the risk is the disk inside
Opening a VMDK file with a reader looks at bytes and starts nothing. The risk is the disk inside, because it can contain any file, program or private data. Our readers left every file unchanged. We started no virtual machine and scanned nothing for malware.
VMDK files are copies of disks. Anything on the disk is in the file, including documents, settings and programs. So treat an unknown VMDK file like a stranger's hard drive.
Our own disk has 7 files that we made. We did not scan any file with a security tool, and we did not start a virtual machine from any disk.
Five steps for a file you do not know
- Get the file from a source you trust, and keep the original.
-
Print the first bytes. A sparse file starts with
KDMV, and a descriptor starts with# Disk DescriptorFile. - Make a copy, and list the files inside the disk with a reader.
- Look at the file list before you open any file from the disk.
- Do not start a virtual machine from a disk you do not know.
What we did not test. We scanned no file for malware and started no machine from any disk. These steps lower the risk of surprises and do not remove it.
Why Will Your VMDK File Not Open? Seven causes, and what to do about every one
Seven causes stop VMDK files from opening or make disks look wrong, and the file causes only some of them. Start with the list of files beside it. All 4 readers refused descriptors with no data file, so a missing piece is the first thing to check.
Work down the list in order. Every cause comes from our 15 files, our 21 damaged copies or our file set tests, so every fix names copies or counts. If you still have the virtual machine, copy the disk again. New copies are the safest fix for damaged files.
sed -i "s/old-flat.vmdk/new-flat.vmdk/" new.vmdk did it for us.
parentFileNameHint line.
How Does a VMDK File Differ From Other Disk Files? Raw, QCOW2, VDI and VHD, measured on one disk
A VMDK file is one of several disk formats, and our readers converted it to the others with no change in the bytes. QCOW2, VDI and VHDX gave the same bytes back, and VHD added 4,096 bytes of size. We tested conversions only, and no virtual machine.
The table lists neighbors of the VMDK file. We made every file from one 16 MiB disk with qemu-img, so sizes show how one tool wrote the disk and do not rank formats.
| Format | What we measured |
|---|---|
| VMDK sparse | 786,432 bytes for our disk. All 4 readers returned the original bytes. |
| Raw | 16,777,216 bytes, the full size of the disk. debugfs listed the files in it with no other tool. |
| QCOW2 | 1,048,576 bytes. The bytes came back the same after a conversion to raw. |
| VDI | 3,146,752 bytes. The bytes came back the same after a conversion to raw. |
| VHD and VHDX | VHDX has 16,777,216 bytes and gave the same bytes back. VHD has 4,197,888 bytes and a virtual size of 16,781,312 bytes. |
VMDK or raw
Raw files are disks as bytes, with no header and no descriptor. They have the full size of the disk. Sparse VMDK files add a header, a descriptor and tables, and our file is 786,432 bytes for the same 16 MiB disk.
Raw is the easiest format to check, because a hash of the file is a hash of the disk. We use raw as the common ground for every comparison on this page.
VMDK or VDI
Wikipedia notes that VirtualBox supports VMDK files. Our VDI file for the same disk has 3,146,752 bytes and converted back to the same bytes. We did not open either file in VirtualBox, so we make no claim about what it accepts.
What Is the VMDK File Format Made Of? The facts we could check, and where they came from
A VMDK file stores a disk as header, descriptor, grain directory, tables and grains of data, or as a text descriptor with data files. Facts below come from our checks of 15 files and 21 damaged copies. Sources are Wikipedia, FileInfo and the libvmdk notes.
| Part | What we could check |
|---|---|
| Maker | VMware. FileInfo lists VMware as the developer and names the type Virtual Machine Disk File. |
| Name | Virtual Machine Disk, per Wikipedia. |
| Specification | Wikipedia says the format became open with revision 5.0 in 2011. |
| Size limit | Wikipedia gives a limit of 2 TB for VMDK files, and VMware vSphere 5.5 added 62 TB in 2013. |
| Media types |
Wikipedia lists application/ and application/.
|
| Container | A text descriptor with data files, or one sparse file with the descriptor inside. We tested both. |
| Signature |
KDMV at the start of a sparse file, and # Disk DescriptorFile at the start of a descriptor.
|
| Byte order | Little-endian, and a sector is 512 bytes, per the libvmdk documentation. |
| Header version | 1, 2 or 3 per libvmdk. Our files have version 1 in 6 files, 2 in 1 and 3 in the 2 stream files. |
| Checksum | We found none in the header, the tables or the grains of our files. |
| Readers | FileInfo lists VMware Workstation, VirtualBox and others. We tested qemu-img, libvmdk, dissect and 7-Zip. |
About the values we list
Layout facts come from our own tests of 15 VMDK files and from the pages we name. The Wikipedia page on VMDK files gives name, history and limits. The FileInfo record for VMDK gives maker and programs.
The libvmdk header notes give the header fields and the disk types. We did not use the VMware specification, and we make no claim beyond what we list.
What we left out
We used no Windows machine, no VMware product and no VirtualBox. We did not test vmfs disks, COWD files, encrypted disks, disks over 16 MiB, VMware or VirtualBox converters or web converters. We started no virtual machine. Our readers worked on Linux, and other software can accept or refuse files that they treat differently.
We made 14 of the 15 files with qemu-img, so the files show how that tool writes VMDK files. Our damaged copies come from one file and change one thing at a time. We compared full disks by SHA-256.
Sources checked
For the format and its history, see Wikipedia on the VMDK format. For the file type, see FileInfo on the .vmdk ending.
Our readers are qemu-img in the QEMU project, libvmdk from libyal and dissect.hypervisor from Fox-IT. Our SEsparse test file comes from dissect.hypervisor. 7-Zip is reader four.
Frequently Asked Questions About VMDK Files
What is a VMDK file?
A VMDK file is the virtual hard disk of a virtual machine. VMware made the format, per FileInfo and Wikipedia. It can be one file or a small text descriptor with data files beside it. All 15 of our test files end in .vmdk, and they are four kinds.
What does VMDK stand for?
VMDK stands for Virtual Machine Disk, per Wikipedia. FileInfo names the type Virtual Machine Disk File and lists VMware as the developer. Wikipedia says the format became open with revision 5.0 in 2011.
How do I open a VMDK file?
VMware Workstation, VMware Fusion and VirtualBox open it, per FileInfo, and we did not test them. Without those, qemu-img, libvmdk, dissect and 7-Zip all opened 12 of our 15 files. Copy the file and its data files first.
How do I convert a VMDK file to a raw disk?
Use `qemu-img convert -f vmdk -O raw disk.vmdk disk.raw`. The raw file from our example had the same SHA-256 as the source disk. QCOW2, VDI and VHDX gave the same bytes back, and VHD added 4,096 bytes of size. We tested no VMware converter.
Why is my VMDK file only a few hundred bytes?
In our tests files that small were descriptors, which are text files that name the data files. Our flat descriptor has 512 bytes, and its data file has 16,777,216 bytes. The disk lives in the data files, so keep them beside the descriptor.
Can I rename a VMDK file?
Not by itself. We renamed both VMDK files of a flat disk, and all 4 readers refused it until we edited the extent line to the new name. Sparse files in one piece have no such line, but we did not rename one in a VMware tool.
Is a VMDK file safe to open?
Opening one with a reader starts nothing. The risk is the disk inside, which can contain any file or private data. Our readers left every file unchanged. We started no virtual machine and scanned nothing for malware.
Why will my VMDK file not open?
One cause is a missing data file or parent, because all 4 readers refused descriptors alone. Others are renamed files, damaged headers, cut files and readers that do not know the kind. Start with the files beside it, then work down the cause list in the part called Why Will Your VMDK File Not Open.
Can I repair a damaged VMDK file?
In part. Our repair script restored 12 of our 21 damaged copies, all of them header damage. It cannot restore cut files, zeroed tables or changed grains. We did not test a repaired file in VMware. Keep the original, and work on a copy.
Why do two readers give different results?
qemu-img and dissect gave the original disk on 8 of our 21 damaged copies, and libvmdk gave it on 4 and refused 14. 7-Zip refused our stream files, and only dissect opened our SEsparse file. We did not check what VMware accepts.
Is a file that opens a good file?
No. Zeroing the grain directory gave 16 MiB of blank disk in all 3 readers with no error. Changing one byte in every one of 11 grains opened 11 times with no warning. Convert the disk to raw and compare hashes with known good copies.
How do sparse, flat and stream VMDK files differ?
Sparse files grow as data arrives, and ours is 786,432 bytes. Flat disks have a descriptor and a data file of full size, 16,777,216 bytes for ours. Stream files have compressed grains, and ours is 403,456 bytes. 7-Zip refused the stream kind.
Still Stuck With a VMDK File? Where to go next, depending on what went wrong
Look at the files beside it and print the first bytes. The cause list names what to try in order.
The cause can be the tables and not the file. The last cause names what we saw in copies C4 and C5.
Is it an archive of files? The page on ZIP archives covers the compressed archive.
Is it a database from the disk? The SQLITE file page covers the SQLite format.
Is it a generic data file? The DAT file page covers the .dat file type.
Is it a file type you do not know? Browse the file extension resource library, or send it on the submit a file type page.
Do you need the format facts? Use the format part for the layout and the sources of VMDK files.