1- from __future__ import annotations
2-
31import ctypes
42import io
53import logging
64import os
75import textwrap
86import zlib
97from bisect import bisect_right
10- from dataclasses import dataclass
118from functools import lru_cache
129from pathlib import Path
1310
@@ -62,13 +59,13 @@ def __init__(self, fh):
6259 if self .descriptor .attr ["parentCID" ] != "ffffffff" :
6360 self .parent = open_parent (path .parent , self .descriptor .attr ["parentFileNameHint" ])
6461
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" )
62+ for _ , size , extent_type , filename in self .descriptor .extents :
63+ if extent_type in ["SPARSE" , "VMFSSPARSE" , "SESPARSE" ]:
64+ sdisk_fh = path .with_name (filename ).open ("rb" )
6865 self .disks .append (SparseDisk (sdisk_fh , parent = self .parent ))
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 ))
66+ elif extent_type in ["VMFS" , "FLAT" ]:
67+ rdisk_fh = path .with_name (filename ).open ("rb" )
68+ self .disks .append (RawDisk (rdisk_fh , size * SECTOR_SIZE ))
7269
7370 elif magic in (COWD_MAGIC , VMDK_MAGIC , SESPARSE_MAGIC ):
7471 sparse_disk = SparseDisk (fh )
@@ -401,53 +398,18 @@ def __getattr__(self, attr):
401398 return getattr (self .hdr , attr )
402399
403400
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-
431401class DiskDescriptor :
432- def __init__ (
433- self , attr : dict , extents : list [ExtentDescriptor ], disk_db : dict , sectors : int , raw_config : str | None = None
434- ):
402+ def __init__ (self , attr , extents , disk_db , sectors , raw_config = None ):
435403 self .attr = attr
436404 self .extents = extents
437405 self .ddb = disk_db
438406 self .sectors = sectors
439407 self .raw = raw_config
440408
441409 @classmethod
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-
410+ def parse (cls , vmdk_config ):
449411 descriptor_settings = {}
450- extents : list [ ExtentDescriptor ] = []
412+ extents = []
451413 disk_db = {}
452414 sectors = 0
453415
@@ -458,16 +420,11 @@ def parse(cls, vmdk_config: str) -> DiskDescriptor:
458420 continue
459421
460422 if line .startswith ("RW " ) or line .startswith ("RDONLY " ) or line .startswith ("NOACCESS " ):
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 )
423+ access_type , size , extent_type , filename = line .split (" " , 3 )
424+ filename = filename .strip ('"' )
425+ size = int (size )
426+ sectors += size
427+ extents .append ([access_type , size , extent_type , filename ])
471428 continue
472429
473430 setting , _ , value = line .partition ("=" )
@@ -481,33 +438,35 @@ def parse(cls, vmdk_config: str) -> DiskDescriptor:
481438
482439 return cls (descriptor_settings , extents , disk_db , sectors , vmdk_config )
483440
484- def __str__ (self ) -> str :
485- str_template = textwrap .dedent (
486- """\
487- # Disk DescriptorFile
488- version=1
489- {}
490-
491- # Extent Description
492- {}
441+ def __str__ (self ):
442+ str_template = """\
443+ # Disk DescriptorFile
444+ version=1
445+ {}
493446
494- # The Disk Data Base
495- #DDB
447+ # Extent Description
448+ {}
496449
497- {}"""
498- )
450+ # The Disk Data Base
451+ #DDB
499452
453+ {}"""
454+ str_template = textwrap .dedent (str_template )
500455 descriptor_settings = []
501456 for setting , value in self .attr .items ():
502- if setting != "version" :
503- descriptor_settings .append (f"{ setting } ={ value } " )
457+ if setting == "version" :
458+ continue
459+ descriptor_settings .append ("{}={}" .format (setting , value ))
504460 descriptor_settings = "\n " .join (descriptor_settings )
505461
506- extents = "\n " .join (map (str , self .extents ))
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 )
507466
508467 disk_db = []
509468 for setting , value in self .ddb .items ():
510- disk_db .append (f' { setting } = "{ value } "' )
469+ disk_db .append ('{ } = "{}"'. format ( setting , value ) )
511470 disk_db = "\n " .join (disk_db )
512471
513472 return str_template .format (descriptor_settings , extents , disk_db )
0 commit comments