dissect.vmfs.descriptor

Module Contents

Classes

DirEntry

Directory entry representation.

FileDescriptor

VMFS file descriptor implementation.

FileDescriptor5

VMFS5 file descriptor implementation.

FileDescriptor6

VMFS6 file descriptor implementation.

BlockStream

Implements a file-like object for VMFS files.

BestEffortBlockStream

Implements a file-like object for VMFS files in the case we don't have a volume available.

class dissect.vmfs.descriptor.DirEntry(vmfs: dissect.vmfs.vmfs.VMFS, address: int, name: str, type: dissect.vmfs.c_vmfs.FS3_DescriptorType, raw: dissect.vmfs.c_vmfs.c_vmfs.FS3_DirEntry | dissect.vmfs.c_vmfs.c_vmfs.FS6_DirEntry | None = None)

Directory entry representation.

Parameters:
  • vmfs – The VMFS instance this directory entry belongs to.

  • address – The address of the file descriptor of this directory entry.

  • name – The name of the directory entry.

  • type – The type of the directory entry.

  • raw – The raw directory entry struct, if available.

vmfs
address
name
type
raw = None
__repr__() str
property file_descriptor: FileDescriptor

Resolve this directory entry to its file descriptor.

fd
class dissect.vmfs.descriptor.FileDescriptor(vmfs: dissect.vmfs.vmfs.VMFS, address: int)

VMFS file descriptor implementation.

See FileDescriptor5 and FileDescriptor6 for the VMFS5 and VMFS6 specific implementations.

File descriptors are basically the inodes of VMFS and are all stored in the .fdc.sf resource. They are the combination of a lock block, a metadata block, and a bit of space for data. They start with lock information, which allows multiple ESXi hosts to stay in sync and place locks. This is followed by the FS3_FileMetadata structure is and contains fields that you would expect of an “inode”.

The file descriptor on disk roughly looks like the following:

struct FS3_FileDescriptor {
    FS3_DiskLock lockBlock;
    FS3_FileMetadata metaBlock;
    char data[N];
};

On VMFS5, each block is 512 bytes large, and there’s 1024 bytes of data. On VMFS6, the block size is determined by the metadata alignment. The entire file descriptor is two metadata blocks large, with the lock occupying the first metadata block, and the metadata and data occupying the second metadata block.

Data is stored in a way that is also similar to many Unix filesystems. There is is some space at the end of the metadata for either a block pointer array, or some resident data. On VMFS5, the block pointer array and the data portion are stored in the same place, whereas on VMFS6, the block pointer array is aligned to the end of the file descriptor, and the data portion is aligned to the end of the metadata structure.

The “zeroLevelAddrType” (or ZLA) determines how to interpret the block pointer array. They can generally be seperated into two kinds: direct and indirect. Like other filesystems, direct blocks refer directly to filesystem blocks, or offsets on disk, that contain data. With indirect blocks, you first need to go through one or more layers of indirection go get to the final filesystem block. View the documentation of BlockStream for more information.

Directory entries are also stored very differently between VMFS5 and VMFS6. Refer to : func:FileDescriptor5._iterdir and FileDescriptor6._iterdir() for more information on how these work.

vmfs
address
__repr__() str
debug() str

Return a debug string for this file descriptor.

Mimicks vmkfstool -D output.

static from_bytes(vmfs: dissect.vmfs.vmfs.VMFS, address: int, buf: bytes) FileDescriptor | FileDescriptor5 | FileDescriptor6

Create a FileDescriptor5 or FileDescriptor6 from a bytes buffer.

property raw: memoryview

The raw buffer of this file descriptor.

property lock_info: dissect.vmfs.c_vmfs.c_vmfs.FS3_DiskLock

The lock info of this file descriptor.

property metadata: dissect.vmfs.c_vmfs.c_vmfs.FS3_FileMetadata

The file metadata of this file descriptor.

property data: memoryview

The data portion of this file descriptor.

property blocks: list[int]

The block array of this file.

Also referred to as the pointer array, or data addresses.

On VMFS5, this is stored in the data portion of the file descriptor as an array of 32-bit integers. On VMFS6, it’s aligned to the end of the file descriptor, and is an array of 64-bit integers.

property rdm_mapping: dissect.vmfs.c_vmfs.c_vmfs.FS3_RawDiskMap

The RDM mapping of this file, if this file is an RDM file.

The RDM mapping is stored in the data portion of the file descriptor.

property parent: FileDescriptor | None

The parent file descriptor of this file, if it has one.

property size: int

The size of this file.

property type: int

The type of this descriptor. Not to be confused with the file type.

property zla: dissect.vmfs.c_vmfs.FS3_ZeroLevelAddrType

The “Zero Level Address” type of this file.

property mode: int

The file mode of this file.

The mode in the metadata only contains a type bit for directories, we add the appropriate type bits for regular files, symlinks and RDM files.

Access the mode through the metadata attribute to get the raw mode value.

property block_size: int

The file specific block size of this file.

property atime: datetime.datetime

The last access time of this file.

property mtime: datetime.datetime

The last modified time of this file.

property ctime: datetime.datetime

The creation time of this file.

The destination of this symlink, if this file descriptor is a symlink.

is_dir() bool

Return whether this file descriptor is a directory.

is_file() bool

Return whether this file descriptor is a regular file.

Return whether this file descriptor is a symlink.

is_system() bool

Return whether this file descriptor is a system file.

is_rdm() bool

Return whether this file descriptor is an RDM file.

listdir() dict[str, DirEntry]

A dictionary of the content of this directory, if this file descriptor is a directory.

iterdir() collections.abc.Iterator[DirEntry]

Iterate file descriptors of the directory entries, if this file descriptor is a directory.

get(name: str) DirEntry

Get a child directory entry by name.

Parameters:

name – The name of the directory entry to get.

open() BlockStream

Open a read-only stream for this file descriptor.

class dissect.vmfs.descriptor.FileDescriptor5(vmfs: dissect.vmfs.vmfs.VMFS, address: int)

Bases: FileDescriptor

VMFS5 file descriptor implementation.

class dissect.vmfs.descriptor.FileDescriptor6(vmfs: dissect.vmfs.vmfs.VMFS, address: int)

Bases: FileDescriptor

VMFS6 file descriptor implementation.

class dissect.vmfs.descriptor.BlockStream(descriptor: FileDescriptor)

Bases: dissect.util.stream.AlignedStream

Implements a file-like object for VMFS files.

VMFS file content can be resident or divided over one or more file blocks. These blocks can be directly or indirectly referenced. If they’re directly referenced, we can read immediately from the block, otherwise we need to go through one or more layers of indirection.

Indirection is implemented using PB or PB2 blocks. The actual indirection algorithm differs slightly between VMFS versions.

Eventual file blocks can also differ between FB (filesystem block), SB (sub/small block) and LFB (large filesystem block).

See FileDescriptor5._resolve_offset() and FileDescriptor6._resolve_offset() for more information on how to resolve offsets.

descriptor
class dissect.vmfs.descriptor.BestEffortBlockStream(descriptor: FileDescriptor)

Bases: dissect.util.stream.AlignedStream

Implements a file-like object for VMFS files in the case we don’t have a volume available.

If we don’t have a volume handle, we can’t read any file blocks on disk, but we can still read resident and sub-block data.

This duplicates some code, but it gives us a cleaner implementation of the happy path while still allowing us to read some data in the case we only have a bunch of system files.

descriptor