dissect.hypervisor 3.15.dev2__py3-none-any.whl → 3.16.dev1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- dissect/hypervisor/disk/vmdk.py +74 -33
- {dissect.hypervisor-3.15.dev2.dist-info → dissect.hypervisor-3.16.dev1.dist-info}/METADATA +1 -1
- {dissect.hypervisor-3.15.dev2.dist-info → dissect.hypervisor-3.16.dev1.dist-info}/RECORD +8 -8
- {dissect.hypervisor-3.15.dev2.dist-info → dissect.hypervisor-3.16.dev1.dist-info}/WHEEL +1 -1
- {dissect.hypervisor-3.15.dev2.dist-info → dissect.hypervisor-3.16.dev1.dist-info}/COPYRIGHT +0 -0
- {dissect.hypervisor-3.15.dev2.dist-info → dissect.hypervisor-3.16.dev1.dist-info}/LICENSE +0 -0
- {dissect.hypervisor-3.15.dev2.dist-info → dissect.hypervisor-3.16.dev1.dist-info}/entry_points.txt +0 -0
- {dissect.hypervisor-3.15.dev2.dist-info → dissect.hypervisor-3.16.dev1.dist-info}/top_level.txt +0 -0
dissect/hypervisor/disk/vmdk.py
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
1
3
|
import ctypes
|
|
2
4
|
import io
|
|
3
5
|
import logging
|
|
@@ -5,6 +7,7 @@ import os
|
|
|
5
7
|
import textwrap
|
|
6
8
|
import zlib
|
|
7
9
|
from bisect import bisect_right
|
|
10
|
+
from dataclasses import dataclass
|
|
8
11
|
from functools import lru_cache
|
|
9
12
|
from pathlib import Path
|
|
10
13
|
|
|
@@ -59,13 +62,13 @@ class VMDK(AlignedStream):
|
|
|
59
62
|
if self.descriptor.attr["parentCID"] != "ffffffff":
|
|
60
63
|
self.parent = open_parent(path.parent, self.descriptor.attr["parentFileNameHint"])
|
|
61
64
|
|
|
62
|
-
for
|
|
63
|
-
if
|
|
64
|
-
sdisk_fh = path.with_name(filename).open("rb")
|
|
65
|
+
for extent in self.descriptor.extents:
|
|
66
|
+
if extent.type in ["SPARSE", "VMFSSPARSE", "SESPARSE"]:
|
|
67
|
+
sdisk_fh = path.with_name(extent.filename).open("rb")
|
|
65
68
|
self.disks.append(SparseDisk(sdisk_fh, parent=self.parent))
|
|
66
|
-
elif
|
|
67
|
-
rdisk_fh = path.with_name(filename).open("rb")
|
|
68
|
-
self.disks.append(RawDisk(rdisk_fh,
|
|
69
|
+
elif extent.type in ["VMFS", "FLAT"]:
|
|
70
|
+
rdisk_fh = path.with_name(extent.filename).open("rb")
|
|
71
|
+
self.disks.append(RawDisk(rdisk_fh, extent.sectors * SECTOR_SIZE))
|
|
69
72
|
|
|
70
73
|
elif magic in (COWD_MAGIC, VMDK_MAGIC, SESPARSE_MAGIC):
|
|
71
74
|
sparse_disk = SparseDisk(fh)
|
|
@@ -398,8 +401,37 @@ class SparseExtentHeader:
|
|
|
398
401
|
return getattr(self.hdr, attr)
|
|
399
402
|
|
|
400
403
|
|
|
404
|
+
@dataclass
|
|
405
|
+
class ExtentDescriptor:
|
|
406
|
+
access_mode: str
|
|
407
|
+
sectors: int
|
|
408
|
+
type: str
|
|
409
|
+
filename: str | None = None
|
|
410
|
+
start_sector: int | None = None
|
|
411
|
+
partition_uuid: str | None = None
|
|
412
|
+
device_identifier: str | None = None
|
|
413
|
+
|
|
414
|
+
def __post_init__(self) -> None:
|
|
415
|
+
self._raw = " ".join(map(str, [v for v in self.__dict__.values() if v is not None]))
|
|
416
|
+
self.sectors = int(self.sectors)
|
|
417
|
+
|
|
418
|
+
if self.filename:
|
|
419
|
+
self.filename = self.filename.strip('"')
|
|
420
|
+
|
|
421
|
+
if self.start_sector:
|
|
422
|
+
self.start_sector = int(self.start_sector)
|
|
423
|
+
|
|
424
|
+
def __repr__(self) -> str:
|
|
425
|
+
return f"<ExtentDescriptor {self._raw}>"
|
|
426
|
+
|
|
427
|
+
def __str__(self) -> str:
|
|
428
|
+
return self._raw
|
|
429
|
+
|
|
430
|
+
|
|
401
431
|
class DiskDescriptor:
|
|
402
|
-
def __init__(
|
|
432
|
+
def __init__(
|
|
433
|
+
self, attr: dict, extents: list[ExtentDescriptor], disk_db: dict, sectors: int, raw_config: str | None = None
|
|
434
|
+
):
|
|
403
435
|
self.attr = attr
|
|
404
436
|
self.extents = extents
|
|
405
437
|
self.ddb = disk_db
|
|
@@ -407,9 +439,15 @@ class DiskDescriptor:
|
|
|
407
439
|
self.raw = raw_config
|
|
408
440
|
|
|
409
441
|
@classmethod
|
|
410
|
-
def parse(cls, vmdk_config):
|
|
442
|
+
def parse(cls, vmdk_config: str) -> DiskDescriptor:
|
|
443
|
+
"""Return :class:`DiskDescriptor` based on the provided ``vmdk_config``.
|
|
444
|
+
|
|
445
|
+
Resources:
|
|
446
|
+
- https://github.com/libyal/libvmdk/blob/main/documentation/VMWare%20Virtual%20Disk%20Format%20(VMDK).asciidoc
|
|
447
|
+
""" # noqa: E501
|
|
448
|
+
|
|
411
449
|
descriptor_settings = {}
|
|
412
|
-
extents = []
|
|
450
|
+
extents: list[ExtentDescriptor] = []
|
|
413
451
|
disk_db = {}
|
|
414
452
|
sectors = 0
|
|
415
453
|
|
|
@@ -420,11 +458,16 @@ class DiskDescriptor:
|
|
|
420
458
|
continue
|
|
421
459
|
|
|
422
460
|
if line.startswith("RW ") or line.startswith("RDONLY ") or line.startswith("NOACCESS "):
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
461
|
+
# Extent descriptors can have up to seven values according to libvmdk documentation.
|
|
462
|
+
parts = line.split(" ", maxsplit=6)
|
|
463
|
+
|
|
464
|
+
if len(parts) < 3:
|
|
465
|
+
log.warning("Unexpected ExtentDescriptor format in vmdk config: %s, ignoring", line)
|
|
466
|
+
continue
|
|
467
|
+
|
|
468
|
+
extent = ExtentDescriptor(*parts)
|
|
469
|
+
sectors += extent.sectors
|
|
470
|
+
extents.append(extent)
|
|
428
471
|
continue
|
|
429
472
|
|
|
430
473
|
setting, _, value = line.partition("=")
|
|
@@ -438,35 +481,33 @@ class DiskDescriptor:
|
|
|
438
481
|
|
|
439
482
|
return cls(descriptor_settings, extents, disk_db, sectors, vmdk_config)
|
|
440
483
|
|
|
441
|
-
def __str__(self):
|
|
442
|
-
str_template =
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
484
|
+
def __str__(self) -> str:
|
|
485
|
+
str_template = textwrap.dedent(
|
|
486
|
+
"""\
|
|
487
|
+
# Disk DescriptorFile
|
|
488
|
+
version=1
|
|
489
|
+
{}
|
|
490
|
+
|
|
491
|
+
# Extent Description
|
|
492
|
+
{}
|
|
446
493
|
|
|
447
|
-
|
|
448
|
-
|
|
494
|
+
# The Disk Data Base
|
|
495
|
+
#DDB
|
|
449
496
|
|
|
450
|
-
|
|
451
|
-
|
|
497
|
+
{}"""
|
|
498
|
+
)
|
|
452
499
|
|
|
453
|
-
{}"""
|
|
454
|
-
str_template = textwrap.dedent(str_template)
|
|
455
500
|
descriptor_settings = []
|
|
456
501
|
for setting, value in self.attr.items():
|
|
457
|
-
if setting
|
|
458
|
-
|
|
459
|
-
descriptor_settings.append("{}={}".format(setting, value))
|
|
502
|
+
if setting != "version":
|
|
503
|
+
descriptor_settings.append(f"{setting}={value}")
|
|
460
504
|
descriptor_settings = "\n".join(descriptor_settings)
|
|
461
505
|
|
|
462
|
-
extents =
|
|
463
|
-
for access_type, size, extent_type, filename in self.extents:
|
|
464
|
-
extents.append('{} {} {} "{}"'.format(access_type, size, extent_type, filename))
|
|
465
|
-
extents = "\n".join(extents)
|
|
506
|
+
extents = "\n".join(map(str, self.extents))
|
|
466
507
|
|
|
467
508
|
disk_db = []
|
|
468
509
|
for setting, value in self.ddb.items():
|
|
469
|
-
disk_db.append('{} = "{}"'
|
|
510
|
+
disk_db.append(f'{setting} = "{value}"')
|
|
470
511
|
disk_db = "\n".join(disk_db)
|
|
471
512
|
|
|
472
513
|
return str_template.format(descriptor_settings, extents, disk_db)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: dissect.hypervisor
|
|
3
|
-
Version: 3.
|
|
3
|
+
Version: 3.16.dev1
|
|
4
4
|
Summary: A Dissect module implementing parsers for various hypervisor disk, backup and configuration files
|
|
5
5
|
Author-email: Dissect Team <dissect@fox-it.com>
|
|
6
6
|
License: Affero General Public License v3
|
|
@@ -23,17 +23,17 @@ dissect/hypervisor/disk/qcow2.py,sha256=K4zstjte7SxX2psSbAj4YqwGeplfIvfbq5ScP4mz
|
|
|
23
23
|
dissect/hypervisor/disk/vdi.py,sha256=_kX7ZGOVo_98ckMaiaDEmw4VjNgM57cY4YUSYrk2JGs,1851
|
|
24
24
|
dissect/hypervisor/disk/vhd.py,sha256=OqSdEO2NGMI5DjgxWFbtZp8bPjSon7moMJn_5152MbI,3660
|
|
25
25
|
dissect/hypervisor/disk/vhdx.py,sha256=FVGTY5mUKFb7oRNKNiLGd5ngGfaGvERtFCGhAlyZD_k,12631
|
|
26
|
-
dissect/hypervisor/disk/vmdk.py,sha256=
|
|
26
|
+
dissect/hypervisor/disk/vmdk.py,sha256=nXDWHziwbN1dxD-ehasuFG98mmhrf1Y9rNil0nAcUtI,19104
|
|
27
27
|
dissect/hypervisor/tools/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
28
28
|
dissect/hypervisor/tools/envelope.py,sha256=6_RLtKmFnZ69fx8HlvFgsjDjNrfnXD73dgszpG1mYQE,967
|
|
29
29
|
dissect/hypervisor/tools/vma.py,sha256=N8x4Yh45BM5MweLSriwhAfSegbjw_Ko4i2yayMWF3rw,5422
|
|
30
30
|
dissect/hypervisor/util/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
31
31
|
dissect/hypervisor/util/envelope.py,sha256=6nEJfgsxj696qxaLOQ2k5MrVWA2uLkbB5zxxRAvboF4,10405
|
|
32
32
|
dissect/hypervisor/util/vmtar.py,sha256=oNJ-qTvQVOl7al_vExpg_T4LnGyE72O9hjOmQBiTKSA,1469
|
|
33
|
-
dissect.hypervisor-3.
|
|
34
|
-
dissect.hypervisor-3.
|
|
35
|
-
dissect.hypervisor-3.
|
|
36
|
-
dissect.hypervisor-3.
|
|
37
|
-
dissect.hypervisor-3.
|
|
38
|
-
dissect.hypervisor-3.
|
|
39
|
-
dissect.hypervisor-3.
|
|
33
|
+
dissect.hypervisor-3.16.dev1.dist-info/COPYRIGHT,sha256=EOOoIwk_inOMUD4c1ylpzMtYLjGzmc-MLEVAEdLLr20,305
|
|
34
|
+
dissect.hypervisor-3.16.dev1.dist-info/LICENSE,sha256=DZak_2itbUtvHzD3E7GNUYSRK6jdOJ-GqncQ2weavLA,34523
|
|
35
|
+
dissect.hypervisor-3.16.dev1.dist-info/METADATA,sha256=QOBhT6Hp2GKbf6I4utzIYJIIxeu0ZKLCshWUlIeCFqw,3458
|
|
36
|
+
dissect.hypervisor-3.16.dev1.dist-info/WHEEL,sha256=OVMc5UfuAQiSplgO0_WdW7vXVGAt9Hdd6qtN4HotdyA,91
|
|
37
|
+
dissect.hypervisor-3.16.dev1.dist-info/entry_points.txt,sha256=qwOrIPRV4bYsKo2sAZznUqegFTMu1sm7ld-o7w_h_5U,124
|
|
38
|
+
dissect.hypervisor-3.16.dev1.dist-info/top_level.txt,sha256=Mn-CQzEYsAbkxrUI0TnplHuXnGVKzxpDw_po_sXpvv4,8
|
|
39
|
+
dissect.hypervisor-3.16.dev1.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
{dissect.hypervisor-3.15.dev2.dist-info → dissect.hypervisor-3.16.dev1.dist-info}/entry_points.txt
RENAMED
|
File without changes
|
{dissect.hypervisor-3.15.dev2.dist-info → dissect.hypervisor-3.16.dev1.dist-info}/top_level.txt
RENAMED
|
File without changes
|