Skip to content

Commit

Permalink
feat(FileSystem): new open method for random access
Browse files Browse the repository at this point in the history
The mode parameter is limited to either of `rb+`, `wb+`, `xb+`.
  • Loading branch information
e3krisztian committed Aug 30, 2023
1 parent ebe141e commit e5e923a
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 2 deletions.
34 changes: 34 additions & 0 deletions tests/test_file_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -572,6 +572,40 @@ def test_create_hardlink_outside_sandbox(self, sandbox: FileSystem):
assert not os.path.lexists(output_path)
assert sandbox.problems

@pytest.mark.parametrize("path", [Path("ok-path"), Path("../outside-path")])
def test_open(self, path: Path, sandbox: FileSystem):
# can perform normal file operations
with sandbox.open(path) as f:
f.seek(100)
f.write(b"text")
assert f.tell() == 104
f.seek(102)
assert f.read(3) == b"xt"

# and it is also persisted
with sandbox.open(path, "rb+") as f:
assert f.read() == bytes(100) + b"text"

def test_open_no_path_traversal(self, sandbox: FileSystem):
path = Path("file")
with sandbox.open(path) as f:
f.write(b"content")

assert (sandbox.root / path).read_bytes() == b"content"
assert sandbox.problems == []

def test_open_outside_sandbox(self, sandbox: FileSystem):
path = Path("../file")
with sandbox.open(path) as f:
f.write(b"content")

assert not (sandbox.root / path).exists()
assert sandbox.problems
# the open is redirected to a lost+found directory, as path traversal is most probably a handler problem
# and the extraction could be successful on real hw/fw, we just do not know where to extract
real_out_path = ".unblob-lost+found/_e90583b491d2138aab0c8a12478ee050701910fd80c84289ae747e7c/file"
assert (sandbox.root / real_out_path).read_bytes() == b"content"


@pytest.mark.parametrize(
"input_path, expected_path",
Expand Down
15 changes: 14 additions & 1 deletion unblob/file_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
import struct
import unicodedata
from pathlib import Path
from typing import Iterable, Iterator, List, Optional, Tuple, Union
from typing import Iterable, Iterator, List, Literal, Optional, Tuple, Union

from dissect.cstruct import Instance, cstruct
from structlog import get_logger
Expand Down Expand Up @@ -590,3 +590,16 @@ def create_hardlink(self, src: Path, dst: Path):
"Not enough privileges to create hardlink to block/char device."
)
self.record_problem(safe_link.format_report(not_enough_privileges))

def open( # noqa: A003
self, path, mode: Literal["wb+", "rb+", "xb+"] = "wb+"
) -> io.BufferedRandom:
"""Create/open binary file for random access read-writing.
There is no intention in supporting anything other than binary files opened for random access.
"""
logger.debug("create/open binary file for writing", file_path=path)
safe_path = self._get_extraction_path(path, "open")

self._ensure_parent_dir(safe_path)
return safe_path.open(mode)
3 changes: 2 additions & 1 deletion vulture_whitelist.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

import unblob.plugins
from unblob import cli
from unblob.file_utils import File, iterbits, round_down
from unblob.file_utils import File, FileSystem, iterbits, round_down
from unblob.handlers.compression.lzo import HeaderFlags as LZOHeaderFlags
from unblob.models import SingleFile, TaskResult, _JSONEncoder
from unblob.parser import _HexStringToRegex
Expand All @@ -32,6 +32,7 @@

unblob.plugins.hookimpl
File.from_bytes
FileSystem.open

iterbits
round_down
Expand Down

0 comments on commit e5e923a

Please sign in to comment.