dissect.vmfs.vmfs#

Module Contents#

Classes#

VMFS

VMFS filesystem implementation.

FileDescriptor

VMFS FileDescriptor implementation.

BlockStream

Implements a file-like object for VMFS files.

class dissect.vmfs.vmfs.VMFS(volume=None, vh=None, fdc=None, fbb=None, sbc=None, pbc=None, pb2=None, jbc=None)#

VMFS filesystem implementation.

Assumes that an LVM has already been loaded.

We implement it quite a bit different from how ESXi seems to use it. ESXi doesn’t really distinguish between disk partitions and LVM volumes. Everything is a VMFS volume, and it either contains a filesystem header at 0x01300000 or it doesn’t. Either it contains an LVM that requires multiple extents or it doesn’t. It’s all VMFS, LVM doesn’t really exist and it’s really just an extra header that specifies if the _filesystem_ requires multiple extents or not.

This doesn’t really fit with how the rest of dissect is architected, so we act like the LVM is a “proper LVM” that exposes a logical volume. We then load a “VMFS filesystem” on top of this logical volume. This volume is made up of one or more extents that are loaded beforehand.

A lot of the math consists of bitwise shifts and masks, which translate to modulo or multiplication operations. For the sake of “maintainability” in relation to the original “code”, we keep this as bitwise masks, at the sacrifice of some human readability. Comments explaining as such are placed where appropriate.

property is_vmfs5#
property is_vmfs6#
get(path, node=None)#
file_descriptor(address, name=None, filetype=None)#
iter_fd()#
class dissect.vmfs.vmfs.FileDescriptor(vmfs, address, name=None, filetype=None)#

VMFS FileDescriptor implementation.

FileDescriptors are basically the inodes of VMFS and are all located in the fdc.sf resource. They start with heartbeat/lock information that describes their lock state so that multiple ESXi hosts can stay in sync and can’t access files while they’re in use. The actual FileDescriptor struct is at a specific offset (md/metadata alignment) and contains fields that you would expect of an “inode”.

Data is stored in a way that is also similar to many Unix filesystems. There is some space for resident data (actually quite large, between 1-4k) or blocks. The “ZLA” determines how to interpret these blocks. However, they can generally be seperated into two kinds: direct and indirect. Like other filesystems, direct blocks refer directly to the filesystem blocks containg the data, whereas with indirect blocks, you first need to go through one or more layers of indirection go get to the final filesystem block. This is where PB and PB2 addresses come into play.

There are two methods of storing directory data. The “legacy” VMFS5 way and the newer VMFS6 way. The VMFS5 way is really just an array of directory entry structs, but the VMFS6 way is a bit more complex. The data contains blocks aligned on the metadata alignment. Each block contains different data, such as what appears to be a hash table, or a heartbeat/allocation bitmap. Eventually you’ll also get to a block containing actual directory entries, which is once again (mostly) an array of directory entries.

property parent#
property size#

The size of this file.

property type#

The type of this file.

property zla#

The ZLA of this file.

property mode#

The file mode of this file.

property block_size#

The file specific block size of this file.

__repr__()#

Return repr(self).

raw()#

The raw buffer of this file descriptor.

lock_info()#

The parsed lock info of this file descriptor.

descriptor()#

The parsed file descriptor struct for this file descriptor.

blocks()#

The block array of this file.

atime()#

The last access time of this file.

mtime()#

The last modified time of this file.

ctime()#

The creation time of this file.

The destination of this file, if it’s a symlink.

is_dir()#

Is this file a directory?

is_file()#

Is this file a regular file?

Is this file a symlink?

is_system()#

Is this file a system file?

is_rdm()#

Is this file a RDM file?

listdir()#

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

iterdir()#

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

open()#

Open this file and return a new file-like object.

class dissect.vmfs.vmfs.BlockStream(descriptor)#

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 referenced 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).