Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 7 additions & 8 deletions dissect/target/containers/vdi.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,9 @@ class VdiContainer(Container):
__type__ = "vdi"

def __init__(self, fh: BinaryIO | Path, *args, **kwargs):
f = fh
if not hasattr(fh, "read"):
f = fh.open("rb")
self.vdi = vdi.VDI(f)
self.vdi = vdi.VDI(fh)

self._stream = self.vdi.open()
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As the lifecycle of the stream coincide in vdi in this usecase, and perhaps in most of the usecases, an alternative design would be to let VDI implement stream methods in terms of an internal VDISttream, and provide a factory method to get a fresh VDIStream,

Copy link
Copy Markdown
Contributor

@twiggler twiggler Feb 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The API suggests a symmetry between vdi.open() and vdi.close() that doesn't actually exist. In reality, the code operates on different levels of abstraction.

The VDI acts as a manager that you shut down using vdi.close() (Level 1).
However, it also acts as a factory to generate results (streams) via vdi.open() (Level 2).

One option would be to rename vdi.open() to vdi.get_stream() or vdi.create_stream().

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Most of these things can be ironed out once we can seriously get into making #100 happen. Currently changes around this are mostly around having the ability to create separate streams from container formats within their implementation. Any changes in dissect.target are currently just bandaid to work with that new API.

super().__init__(fh, self.vdi.size, *args, **kwargs)

@staticmethod
Expand All @@ -33,13 +31,14 @@ def detect_path(path: Path, original: list | BinaryIO) -> bool:
return path.suffix.lower() == ".vdi"

def read(self, length: int) -> bytes:
return self.vdi.read(length)
return self._stream.read(length)

def seek(self, offset: int, whence: int = io.SEEK_SET) -> int:
return self.vdi.seek(offset, whence)
return self._stream.seek(offset, whence)

def tell(self) -> int:
return self.vdi.tell()
return self._stream.tell()

def close(self) -> None:
pass
self._stream.close()
self.vdi.close()
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ dependencies = [
"dissect.database>=1.1.dev4,<2", # TODO: update on release!
"dissect.eventlog>=3,<4",
"dissect.evidence>=3.13.dev3,<4", # TODO: update on release!
"dissect.hypervisor>=3.21.dev3,<4", # TODO: update on release!
"dissect.hypervisor>=3.21.dev5,<4", # TODO: update on release!
"dissect.ntfs>=3.16.dev,<4",
"dissect.regf>=3.13,<4",
"dissect.util>=3,<4",
Expand Down
Loading