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
27 changes: 21 additions & 6 deletions dissect/hypervisor/util/vmtar.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,8 @@ class VisorTarInfo(tarfile.TarInfo):
fixUpPgs: int | None

@classmethod
def frombuf(cls, buf: bytes, encoding: str, errors: str) -> VisorTarInfo:
obj = super().frombuf(buf, encoding, errors)

def _init_visor_attrs(cls, obj: VisorTarInfo, buf: bytes) -> None:
"""Initialize visor-specific attributes from the raw header buffer."""
obj.is_visor = buf[257:264] == b"visor "
if obj.is_visor:
obj.offset_data = struct.unpack("<I", buf[496:500])[0]
Expand All @@ -35,6 +34,19 @@ def frombuf(cls, buf: bytes, encoding: str, errors: str) -> VisorTarInfo:
obj.textPgs = None
obj.fixUpPgs = None

@classmethod
def frombuf(cls, buf: bytes, encoding: str, errors: str) -> VisorTarInfo:
obj = super().frombuf(buf, encoding, errors)
cls._init_visor_attrs(obj, buf)
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.

wouldn't it now technically call the _init_visor_attrs twice? as super().frombuf calls cls._frombuf which already initiates _init_visor_attrs?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Yeah, but _init_visor_attrs is idempotent

return obj

@classmethod
def _frombuf(cls, buf: bytes, encoding: str, errors: str, **kwargs) -> VisorTarInfo:
# Python 3.13.13+ refactored tarfile to call _frombuf directly instead of
# frombuf in fromtarfile and _proc_gnulong/_proc_pax. We must override _frombuf
# to ensure visor-specific attributes are initialized for all code paths.
obj = super()._frombuf(buf, encoding, errors, **kwargs)
cls._init_visor_attrs(obj, buf)
return obj

def _proc_member(self, tarfile: tarfile.TarFile) -> VisorTarInfo | tarfile.TarInfo:
Expand Down Expand Up @@ -76,6 +88,8 @@ def visoropen(cls, name: str, mode: str = "r", fileobj: BinaryIO | None = None,
try:
t = cls.taropen(name, mode, fileobj, **kwargs)
except Exception:
if fileobj is not None:
fileobj.seek(0)
try:
fileobj = GzipFile(name, mode + "b", fileobj=fileobj)
except OSError as e:
Expand Down Expand Up @@ -103,10 +117,11 @@ def visoropen(cls, name: str, mode: str = "r", fileobj: BinaryIO | None = None,
compressed = True

# If we get here, we have a valid visor tar file
if fileobj is not None and compressed:
# Just read the entire file into memory, it's probably small
if fileobj is not None:
fileobj.seek(0)
fileobj = BytesIO(fileobj.read())
if compressed:
# Read the decompressed data into a BytesIO to make random reads faster
fileobj = BytesIO(fileobj.read())

t = cls.taropen(name, mode, fileobj, **kwargs)

Expand Down
1 change: 1 addition & 0 deletions tests/util/test_vmtar.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ def test_vmtar() -> None:
# The test file has no textPgs/fixUpPgs
assert all(member.is_visor for member in members.values())
assert set(members.keys()) == {
"test",
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Reviewer: The directory should also be a member, right?

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.

I would think it should also be included, and not only the file contents. @Schamper was there a reason it wasn't included?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Probably oversight because I didn't rewind the file pointer :) should be included.

"test/file1",
"test/file2",
"test/file3",
Expand Down
Loading