From 83bef862e333a42a12e63b9597f58041e38106c1 Mon Sep 17 00:00:00 2001 From: Schamper <1254028+Schamper@users.noreply.github.com> Date: Thu, 22 Feb 2024 13:25:20 +0100 Subject: [PATCH 1/5] Add filesystem support for vmtar --- .gitattributes | 24 +++++++++--------- dissect/target/filesystem.py | 1 + dissect/target/filesystems/vmtar.py | 23 +++++++++++++++++ dissect/target/helpers/fsutil.py | 12 ++++++++- .../cpio/initrd.img-6.1.0-15-amd64 | 0 .../cpio/initrd.img-6.1.0-17-amd64 | 0 .../symlink_disk.ext4 | Bin tests/_data/filesystems/vmtar/simple.vmtar | Bin 0 -> 211 bytes tests/filesystems/test_cpio.py | 4 +-- tests/filesystems/test_vmtar.py | 15 +++++++++++ 10 files changed, 64 insertions(+), 15 deletions(-) create mode 100644 dissect/target/filesystems/vmtar.py rename tests/_data/{loaders => filesystems}/cpio/initrd.img-6.1.0-15-amd64 (100%) rename tests/_data/{loaders => filesystems}/cpio/initrd.img-6.1.0-17-amd64 (100%) rename tests/_data/{filesystem => filesystems}/symlink_disk.ext4 (100%) create mode 100644 tests/_data/filesystems/vmtar/simple.vmtar create mode 100644 tests/filesystems/test_vmtar.py diff --git a/.gitattributes b/.gitattributes index be7e7a8ba..73de4c566 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,21 +1,21 @@ +tests/_data/filesystems/cpio/initrd.img-6.1.0-15-amd64 filter=lfs diff=lfs merge=lfs -text +tests/_data/filesystems/cpio/initrd.img-6.1.0-17-amd64 filter=lfs diff=lfs merge=lfs -text +tests/_data/loaders/tar/test-anon-filesystems.tar filter=lfs diff=lfs merge=lfs -text tests/_data/loaders/tar/uppercase_driveletter.tar filter=lfs diff=lfs merge=lfs -text -tests/_data/plugins/apps/browser/iexplore/WebCacheV01.dat.gz filter=lfs diff=lfs merge=lfs -text -tests/_data/plugins/apps/browser/firefox/places.sqlite filter=lfs diff=lfs merge=lfs -text -tests/_data/plugins/apps/browser/firefox/cookies.sqlite filter=lfs diff=lfs merge=lfs -text tests/_data/plugins/apps/browser/chrome/History.sqlite filter=lfs diff=lfs merge=lfs -text -tests/_data/plugins/apps/browser/edge/History.sqlite filter=lfs diff=lfs merge=lfs -text tests/_data/plugins/apps/browser/chromium/Cookies.sqlite filter=lfs diff=lfs merge=lfs -text tests/_data/plugins/apps/browser/chromium/History.sqlite filter=lfs diff=lfs merge=lfs -text -tests/_data/plugins/os/windows/dpapi/** filter=lfs diff=lfs merge=lfs -text -tests/_data/plugins/os/windows/notifications/appdb.dat.v3.gz filter=lfs diff=lfs merge=lfs -text -tests/_data/plugins/os/windows/notifications/wpndatabase.db filter=lfs diff=lfs merge=lfs -text -tests/_data/volumes/bde/enc-volume.bin filter=lfs diff=lfs merge=lfs -text -tests/_data/volumes/md/md-nested.bin.gz filter=lfs diff=lfs merge=lfs -text -tests/_data/loaders/tar/test-anon-filesystems.tar filter=lfs diff=lfs merge=lfs -text +tests/_data/plugins/apps/browser/edge/History.sqlite filter=lfs diff=lfs merge=lfs -text +tests/_data/plugins/apps/browser/firefox/cookies.sqlite filter=lfs diff=lfs merge=lfs -text tests/_data/plugins/apps/browser/firefox/cookies.sqlite filter=lfs diff=lfs merge=lfs -text +tests/_data/plugins/apps/browser/firefox/places.sqlite filter=lfs diff=lfs merge=lfs -text +tests/_data/plugins/apps/browser/iexplore/WebCacheV01.dat.gz filter=lfs diff=lfs merge=lfs -text tests/_data/plugins/apps/container/docker/docker.tgz filter=lfs diff=lfs merge=lfs -text -tests/_data/loaders/cpio/initrd.img-6.1.0-15-amd64 filter=lfs diff=lfs merge=lfs -text -tests/_data/loaders/cpio/initrd.img-6.1.0-17-amd64 filter=lfs diff=lfs merge=lfs -text tests/_data/plugins/os/unix/locate/locatedb filter=lfs diff=lfs merge=lfs -text tests/_data/plugins/os/unix/locate/mlocate.db filter=lfs diff=lfs merge=lfs -text tests/_data/plugins/os/unix/locate/plocate.db filter=lfs diff=lfs merge=lfs -text +tests/_data/plugins/os/windows/dpapi/** filter=lfs diff=lfs merge=lfs -text +tests/_data/plugins/os/windows/notifications/appdb.dat.v3.gz filter=lfs diff=lfs merge=lfs -text +tests/_data/plugins/os/windows/notifications/wpndatabase.db filter=lfs diff=lfs merge=lfs -text +tests/_data/volumes/bde/enc-volume.bin filter=lfs diff=lfs merge=lfs -text +tests/_data/volumes/md/md-nested.bin.gz filter=lfs diff=lfs merge=lfs -text diff --git a/dissect/target/filesystem.py b/dissect/target/filesystem.py index 9df001c48..cd1c89684 100644 --- a/dissect/target/filesystem.py +++ b/dissect/target/filesystem.py @@ -1621,6 +1621,7 @@ def open_multi_volume(fhs: list[BinaryIO], *args, **kwargs) -> Filesystem: register("squashfs", "SquashFSFilesystem") register("zip", "ZipFilesystem") register("tar", "TarFilesystem") +register("vmtar", "VmtarFilesystem") register("cpio", "CpioFilesystem") register("ad1", "AD1Filesystem") register("jffs", "JFFSFilesystem") diff --git a/dissect/target/filesystems/vmtar.py b/dissect/target/filesystems/vmtar.py new file mode 100644 index 000000000..eb652ec23 --- /dev/null +++ b/dissect/target/filesystems/vmtar.py @@ -0,0 +1,23 @@ +from typing import BinaryIO, Optional + +from dissect.hypervisor.util import vmtar + +from dissect.target.filesystems.tar import TarFilesystem +from dissect.target.helpers.fsutil import open_decompress + + +class VmtarFilesystem(TarFilesystem): + __type__ = "vmtar" + + def __init__(self, fh: BinaryIO, base: Optional[str] = None, *args, **kwargs): + fh = open_decompress(fileobj=open_decompress(fileobj=fh)) + super().__init__(fh, base, tarinfo=vmtar.VisorTarInfo, *args, **kwargs) + + @staticmethod + def _detect(fh: BinaryIO) -> bool: + """Detect a vmtar file on a given file-like object.""" + # vmtar files can be double compressed (gzip + lzma) + fh = open_decompress(fileobj=open_decompress(fileobj=fh)) + + fh.seek(257) + return fh.read(8) == b"visor \x00" diff --git a/dissect/target/helpers/fsutil.py b/dissect/target/helpers/fsutil.py index cab58d1cc..53a4a85a7 100644 --- a/dissect/target/helpers/fsutil.py +++ b/dissect/target/helpers/fsutil.py @@ -13,6 +13,13 @@ from pathlib import Path from typing import Any, BinaryIO, Iterator, Optional, Sequence, TextIO, Union +try: + import lzma + + HAVE_XZ = True +except ImportError: + HAVE_XZ = False + try: import bz2 @@ -492,7 +499,7 @@ def open_decompress( else: file = fileobj - magic = file.read(4) + magic = file.read(5) file.seek(0) if "b" in mode: @@ -503,6 +510,9 @@ def open_decompress( if magic[:2] == b"\x1f\x8b": return gzip.open(file, mode, encoding=encoding, errors=errors, newline=newline) + if HAVE_XZ and magic[:5] == b"\xfd7zXZ": + return lzma.open(file, mode, encoding=encoding, errors=errors, newline=newline) + if HAVE_BZ2 and magic[:3] == b"BZh" and 0x31 <= magic[3] <= 0x39: # In a valid bz2 header the 4th byte is in the range b'1' ... b'9'. return bz2.open(file, mode, encoding=encoding, errors=errors, newline=newline) diff --git a/tests/_data/loaders/cpio/initrd.img-6.1.0-15-amd64 b/tests/_data/filesystems/cpio/initrd.img-6.1.0-15-amd64 similarity index 100% rename from tests/_data/loaders/cpio/initrd.img-6.1.0-15-amd64 rename to tests/_data/filesystems/cpio/initrd.img-6.1.0-15-amd64 diff --git a/tests/_data/loaders/cpio/initrd.img-6.1.0-17-amd64 b/tests/_data/filesystems/cpio/initrd.img-6.1.0-17-amd64 similarity index 100% rename from tests/_data/loaders/cpio/initrd.img-6.1.0-17-amd64 rename to tests/_data/filesystems/cpio/initrd.img-6.1.0-17-amd64 diff --git a/tests/_data/filesystem/symlink_disk.ext4 b/tests/_data/filesystems/symlink_disk.ext4 similarity index 100% rename from tests/_data/filesystem/symlink_disk.ext4 rename to tests/_data/filesystems/symlink_disk.ext4 diff --git a/tests/_data/filesystems/vmtar/simple.vmtar b/tests/_data/filesystems/vmtar/simple.vmtar new file mode 100644 index 0000000000000000000000000000000000000000..1b11886921ec705cdb71782f6e7d2ab7453fa921 GIT binary patch literal 211 zcmb2|=3oE=X2v}X&j0_KS4BiIFt9wkw#AK!L6K1mC|9EYbnyeh{|wc!3?`DE@A`P! z0`6^@@I~HmgOSLSR{;$Af1|?B&3Ll;>-D||Iv310r@qekXa80svPI+R#OZ68-m$cu zX{&#i-egZ+As3m+!Ul^*{}K-`43u None: - cpio_path = Path(absolute_path("_data/loaders/cpio/initrd.img-6.1.0-17-amd64")) + cpio_path = Path(absolute_path("_data/filesystems/cpio/initrd.img-6.1.0-17-amd64")) with cpio_path.open("rb") as fh: assert CpioFilesystem.detect(fh) @@ -15,7 +15,7 @@ def test_cpio_uncompressed() -> None: def test_cpio_compressed_zstd() -> None: - cpio_path = Path(absolute_path("_data/loaders/cpio/initrd.img-6.1.0-15-amd64")) + cpio_path = Path(absolute_path("_data/filesystems/cpio/initrd.img-6.1.0-15-amd64")) with cpio_path.open("rb") as fh: assert CpioFilesystem.detect(fh) diff --git a/tests/filesystems/test_vmtar.py b/tests/filesystems/test_vmtar.py new file mode 100644 index 000000000..340e9e521 --- /dev/null +++ b/tests/filesystems/test_vmtar.py @@ -0,0 +1,15 @@ +from pathlib import Path + +from dissect.target.filesystems.vmtar import VmtarFilesystem +from tests._utils import absolute_path + + +def test_filesystems_vmtar(): + vmtar_path = Path(absolute_path("_data/filesystems/vmtar/simple.vmtar")) + + with vmtar_path.open("rb") as fh: + assert VmtarFilesystem.detect(fh) + + fs = VmtarFilesystem(fh) + assert [f.name for f in fs.path("/").iterdir()] == ["hello_world.txt"] + assert fs.get("hello_world.txt").open().read() == b"hello_from_a_tar_file\n" From 0458479dc74a2b9dc0b2267552ce3b854e78748d Mon Sep 17 00:00:00 2001 From: Schamper <1254028+Schamper@users.noreply.github.com> Date: Thu, 22 Feb 2024 13:33:49 +0100 Subject: [PATCH 2/5] Fix test file path --- tests/test_filesystem.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_filesystem.py b/tests/test_filesystem.py index f661ffb26..99f8f59b9 100644 --- a/tests/test_filesystem.py +++ b/tests/test_filesystem.py @@ -210,7 +210,7 @@ def test_recursive_symlink_open_across_layers(target_bare): def test_recursive_symlink_dev(target_bare): - fs1 = ExtFilesystem(fh=open(absolute_path("_data/filesystem/symlink_disk.ext4"), "rb")) + fs1 = ExtFilesystem(fh=open(absolute_path("_data/filesystems/symlink_disk.ext4"), "rb")) target_bare.fs.mount(fs=fs1, path="/") with pytest.raises(SymlinkRecursionError): From 32aaeafd2957029f9e1039e22408c48ecace94b1 Mon Sep 17 00:00:00 2001 From: Erik Schamper <1254028+Schamper@users.noreply.github.com> Date: Mon, 26 Feb 2024 11:30:36 +0100 Subject: [PATCH 3/5] Update tests/filesystems/test_vmtar.py Co-authored-by: Miauwkeru --- tests/filesystems/test_vmtar.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/filesystems/test_vmtar.py b/tests/filesystems/test_vmtar.py index 340e9e521..c407fd3fe 100644 --- a/tests/filesystems/test_vmtar.py +++ b/tests/filesystems/test_vmtar.py @@ -4,7 +4,7 @@ from tests._utils import absolute_path -def test_filesystems_vmtar(): +def test_filesystems_vmtar() -> None: vmtar_path = Path(absolute_path("_data/filesystems/vmtar/simple.vmtar")) with vmtar_path.open("rb") as fh: From 872a03c8bf207499cc09d818c0929817db4e5342 Mon Sep 17 00:00:00 2001 From: Schamper <1254028+Schamper@users.noreply.github.com> Date: Mon, 26 Feb 2024 12:54:29 +0100 Subject: [PATCH 4/5] Improve type hints --- tests/test_filesystem.py | 95 +++++++++++++++++++++------------------- 1 file changed, 50 insertions(+), 45 deletions(-) diff --git a/tests/test_filesystem.py b/tests/test_filesystem.py index 99f8f59b9..2b9d881ed 100644 --- a/tests/test_filesystem.py +++ b/tests/test_filesystem.py @@ -2,21 +2,22 @@ import stat from datetime import datetime, timezone from io import BytesIO +from pathlib import Path from tempfile import NamedTemporaryFile, TemporaryDirectory -from typing import Union +from typing import Any from unittest.mock import Mock, patch import pytest -from _pytest.fixtures import FixtureRequest from dissect.util import ts -from dissect.target import filesystem +from dissect.target import Target, filesystem from dissect.target.exceptions import ( FileNotFoundError, NotADirectoryError, SymlinkRecursionError, ) from dissect.target.filesystem import ( + FilesystemEntry, MappedFile, RootFilesystem, RootFilesystemEntry, @@ -40,7 +41,7 @@ @pytest.fixture -def vfs(): +def vfs() -> VirtualFilesystem: vfs = VirtualFilesystem() vfs.map_file_entry("/path/to/some/file", VirtualFile(vfs, "path/to/some/file", None)) @@ -54,7 +55,7 @@ def vfs(): return vfs -def test_get(vfs): +def test_get(vfs: VirtualFilesystem) -> None: assert vfs.get("dirlink1").name == "dirlink1" assert vfs.get("dirlink1").is_symlink() assert vfs.get("dirlink1").is_dir() @@ -86,7 +87,7 @@ def test_get(vfs): assert vfs.get("filelink2").stat() == vfs.get("/path/to/some/file").stat() -def test_symlink_across_layers(target_bare): +def test_symlink_across_layers(target_bare: Target) -> None: vfs1 = VirtualFilesystem() vfs1.makedirs("/path/to/symlink/") vfs1.symlink("../target", "/path/to/symlink/target") @@ -105,7 +106,7 @@ def test_symlink_across_layers(target_bare): assert target_dir.stat() == target_entry.entries[0].stat() -def test_symlink_files_across_layers(target_bare): +def test_symlink_files_across_layers(target_bare: Target) -> None: vfs1 = VirtualFilesystem() vfs1.makedirs("/path/to/symlink/") vfs1.symlink("../target", "/path/to/symlink/target") @@ -125,7 +126,7 @@ def test_symlink_files_across_layers(target_bare): assert target_dir.stat() == target_entry.stat() -def test_symlink_to_symlink_across_layers(target_bare): +def test_symlink_to_symlink_across_layers(target_bare: Target) -> None: vfs1 = VirtualFilesystem() vfs1.makedirs("/path/to/symlink/") target_dir = vfs1.makedirs("/path/target") @@ -145,7 +146,7 @@ def test_symlink_to_symlink_across_layers(target_bare): assert target_dir.stat() == target_entry.stat() -def test_recursive_symlink_across_layers(target_bare): +def test_recursive_symlink_across_layers(target_bare: Target) -> None: vfs1 = VirtualFilesystem() vfs1.makedirs("/path/to/symlink/") vfs1.symlink("../target", "/path/to/symlink/target") @@ -163,7 +164,7 @@ def test_recursive_symlink_across_layers(target_bare): target_bare.fs.get("/path/to/symlink/target/").readlink_ext() -def test_symlink_across_3_layers(target_bare): +def test_symlink_across_3_layers(target_bare: Target) -> None: vfs1 = VirtualFilesystem() vfs1.makedirs("/path/to/symlink/") vfs1.symlink("../target", "/path/to/symlink/target") @@ -191,7 +192,7 @@ def test_symlink_across_3_layers(target_bare): assert stat_a == stat_b -def test_recursive_symlink_open_across_layers(target_bare): +def test_recursive_symlink_open_across_layers(target_bare: Target) -> None: vfs1 = VirtualFilesystem() vfs1.makedirs("/path/to/symlink/") vfs1.symlink("../target", "/path/to/symlink/target") @@ -209,7 +210,7 @@ def test_recursive_symlink_open_across_layers(target_bare): target_bare.fs.get("/path/to/symlink/target/").open() -def test_recursive_symlink_dev(target_bare): +def test_recursive_symlink_dev(target_bare: Target) -> None: fs1 = ExtFilesystem(fh=open(absolute_path("_data/filesystems/symlink_disk.ext4"), "rb")) target_bare.fs.mount(fs=fs1, path="/") @@ -242,7 +243,7 @@ def test_recursive_symlink_dev(target_bare): ), ], ) -def test_link_resolve(entry, link_dict): +def test_link_resolve(entry: type[FilesystemEntry], link_dict: dict[str, Any]) -> None: """Test wether each filesystem resolves a link as intended.""" if entry is None: pytest.skip("dissect.vmfs is required") @@ -270,7 +271,7 @@ def test_link_resolve(entry, link_dict): assert link.readlink_ext() == actual_file -def test_virtual_symlink_to_dir_get(vfs): +def test_virtual_symlink_to_dir_get(vfs: VirtualFilesystem) -> None: some_file = vfs.get("/path/to/some/file") symlink = vfs.get("/dirlink1") @@ -279,13 +280,13 @@ def test_virtual_symlink_to_dir_get(vfs): assert some_file is some_file2 -def test_virtual_symlink_to_file_get(vfs): +def test_virtual_symlink_to_file_get(vfs: VirtualFilesystem) -> None: symlink = vfs.get("/filelink1") with pytest.raises(NotADirectoryError): symlink.get("does_not_exist") -def test_virtual_symlink_to_symlink_get(vfs): +def test_virtual_symlink_to_symlink_get(vfs: VirtualFilesystem) -> None: some_file = vfs.get("/path/to/some/file") symlink = vfs.get("/dirlink2") @@ -309,7 +310,7 @@ def test_virtual_symlink_to_symlink_get(vfs): "/dirlink1", ], ) -def test_virtual_entry_get_self(vfs, path, entry_name): +def test_virtual_entry_get_self(vfs: VirtualFilesystem, path: str, entry_name: str) -> None: some_entry = vfs.get(entry_name) some_entry2 = some_entry.get(path) @@ -347,7 +348,7 @@ def test_virtual_filesystem_get(): ("/", "/dirlink2/../../../"), ], ) -def test_virtual_filesystem_get_equal_vfs_paths(vfs, vfs_path1, vfs_path2): +def test_virtual_filesystem_get_equal_vfs_paths(vfs: VirtualFilesystem, vfs_path1: str, vfs_path2: str) -> None: assert vfs.get(vfs_path1) is vfs.get(vfs_path2) @@ -362,7 +363,7 @@ def test_virtual_filesystem_get_equal_vfs_paths(vfs, vfs_path1, vfs_path2): ("/dirlink1", "/dirlink2"), ], ) -def test_virtual_filesystem_get_unequal_vfs_paths(vfs, vfs_path1, vfs_path2): +def test_virtual_filesystem_get_unequal_vfs_paths(vfs: VirtualFilesystem, vfs_path1: str, vfs_path2: str) -> None: assert vfs.get(vfs_path1) is not vfs.get(vfs_path2) @@ -375,12 +376,14 @@ def test_virtual_filesystem_get_unequal_vfs_paths(vfs, vfs_path1, vfs_path2): ("/path/to/other/path/to/some/non-exisiting-file", FileNotFoundError), ], ) -def test_virtual_filesystem_get_erroring_vfs_paths(vfs, vfs_path, exception): +def test_virtual_filesystem_get_erroring_vfs_paths( + vfs: VirtualFilesystem, vfs_path: str, exception: type[Exception] +) -> None: with pytest.raises(exception): vfs.get(vfs_path) -def test_virtual_filesystem_get_case_sensitive(): +def test_virtual_filesystem_get_case_sensitive() -> None: vfs = VirtualFilesystem() vfs.map_file_entry("/path/to/some/file_lower_case", VirtualFile(vfs, "file_lower_case", None)) vfs.map_file_entry("/path/TO/some/FILE_UPPER_CASE", VirtualFile(vfs, "FILE_UPPER_CASE", None)) @@ -393,7 +396,7 @@ def test_virtual_filesystem_get_case_sensitive(): assert vfs.get("/path/TO/some/file_upper_case") -def test_virtual_filesystem_get_case_insensitive(): +def test_virtual_filesystem_get_case_insensitive() -> None: vfs = VirtualFilesystem(case_sensitive=False) vfs.map_file_entry("/path/to/some/file_lower_case", VirtualFile(vfs, "file_lower_case", None)) vfs.map_file_entry("/path/TO/some/FILE_UPPER_CASE", VirtualFile(vfs, "FILE_UPPER_CASE", None)) @@ -417,7 +420,7 @@ def test_virtual_filesystem_get_case_insensitive(): ), ], ) -def test_virtual_filesystem_makedirs(paths): +def test_virtual_filesystem_makedirs(paths: str) -> None: vfs = VirtualFilesystem() for vfspath in paths: @@ -432,7 +435,7 @@ def test_virtual_filesystem_makedirs(paths): assert vfs_entry.path == partial_path.strip("/") -def test_virtual_filesystem_makedirs_root(): +def test_virtual_filesystem_makedirs_root() -> None: vfs = VirtualFilesystem() vfspath = "/" @@ -443,7 +446,7 @@ def test_virtual_filesystem_makedirs_root(): assert vfs_entry is vfs.root -def test_virtual_filesystem_map_fs(vfs): +def test_virtual_filesystem_map_fs(vfs: VirtualFilesystem) -> None: root_vfs = VirtualFilesystem() map_path = "/some/dir/" file_path = "/path/to/some/file" @@ -460,11 +463,11 @@ def test_virtual_filesystem_map_fs(vfs): root_vfs.get(file_path) -def test_virtual_filesystem_mount(vfs): +def test_virtual_filesystem_mount(vfs: VirtualFilesystem) -> None: assert vfs.mount == vfs.map_fs -def test_virtual_filesystem_map_dir(tmp_path): +def test_virtual_filesystem_map_dir(tmp_path: Path) -> None: vfs = VirtualFilesystem() vfs_path = "/map/point/" with ( @@ -510,7 +513,7 @@ def test_virtual_filesystem_map_dir(tmp_path): "/path///to/file", ], ) -def test_virtual_filesystem_map_file(vfs_path): +def test_virtual_filesystem_map_file(vfs_path: str) -> None: vfs = VirtualFilesystem() real_path = "/tmp/foo" @@ -524,7 +527,7 @@ def test_virtual_filesystem_map_file(vfs_path): assert vfs_entry.entry == real_path -def test_virtual_filesystem_map_file_as_dir(): +def test_virtual_filesystem_map_file_as_dir() -> None: vfs = VirtualFilesystem() real_path = "/tmp/foo" @@ -540,7 +543,7 @@ def test_virtual_filesystem_map_file_as_dir(): "/path///to/file", ], ) -def test_virtual_filesystem_map_file_fh(vfs_path): +def test_virtual_filesystem_map_file_fh(vfs_path: str) -> None: vfs = VirtualFilesystem() fh = Mock() @@ -554,7 +557,7 @@ def test_virtual_filesystem_map_file_fh(vfs_path): assert vfs_entry.entry is fh -def test_virtual_filesystem_map_file_fh_as_dir(): +def test_virtual_filesystem_map_file_fh_as_dir() -> None: vfs = VirtualFilesystem() fh = Mock() @@ -577,7 +580,7 @@ def test_virtual_filesystem_map_file_fh_as_dir(): "/", ], ) -def test_virtual_filesystem_map_file_entry(vfs_path): +def test_virtual_filesystem_map_file_entry(vfs_path: str) -> None: vfs = VirtualFilesystem() entry_path = fsutil.normalize(vfs_path, alt_separator=vfs.alt_separator).strip("/") dir_entry = VirtualDirectory(vfs, entry_path) @@ -621,7 +624,7 @@ def test_virtual_filesystem_map_file_entry(vfs_path): ), ], ) -def test_virtual_filesystem_link(vfs_path, link_path): +def test_virtual_filesystem_link(vfs_path: str, link_path: str) -> None: vfs = VirtualFilesystem() entry_path = fsutil.normalize(vfs_path, alt_separator=vfs.alt_separator).strip("/") file_object = Mock() @@ -708,7 +711,7 @@ def test_virtual_filesystem_stat( vfs: VirtualFilesystem, src_entry: str, dst_entry: str, - request: FixtureRequest, + request: pytest.FixtureRequest, ) -> None: src_entry = request.getfixturevalue(src_entry) dst_entry = request.getfixturevalue(dst_entry) @@ -726,7 +729,7 @@ def test_virtual_filesystem_stat( "filelink_entry", ], ) -def test_virtual_filesystem_lstat(vfs: VirtualFilesystem, entry: str, request: FixtureRequest) -> None: +def test_virtual_filesystem_lstat(vfs: VirtualFilesystem, entry: str, request: pytest.FixtureRequest) -> None: entry = request.getfixturevalue(entry) assert vfs.lstat(entry.path) == entry.lstat() @@ -746,7 +749,7 @@ def test_virtual_filesystem_is_dir( vfs: VirtualFilesystem, src_entry: str, dst_entry: str, - request: FixtureRequest, + request: pytest.FixtureRequest, ) -> None: src_entry = request.getfixturevalue(src_entry) dst_entry = request.getfixturevalue(dst_entry) @@ -770,7 +773,7 @@ def test_virtual_filesystem_is_file( vfs: VirtualFilesystem, src_entry: str, dst_entry: str, - request: FixtureRequest, + request: pytest.FixtureRequest, ) -> None: src_entry = request.getfixturevalue(src_entry) dst_entry = request.getfixturevalue(dst_entry) @@ -814,7 +817,7 @@ def test_virutal_directory_is_dir(virt_dir: VirtualDirectory) -> None: assert virt_dir.is_dir(follow_symlinks=False) -def test_virutal_directory_is_file(virt_dir: VirtualDirectory): +def test_virutal_directory_is_file(virt_dir: VirtualDirectory) -> None: assert not virt_dir.is_file(follow_symlinks=True) assert not virt_dir.is_file(follow_symlinks=False) @@ -843,7 +846,7 @@ def test_virutal_file_is_file(virt_file: VirtualFile) -> None: assert virt_file.is_file(follow_symlinks=False) -def test_virtual_symlink_stat(filelink_entry: VirtualSymlink, file_entry: Union[VirtualFile, VirtualDirectory]) -> None: +def test_virtual_symlink_stat(filelink_entry: VirtualSymlink, file_entry: VirtualFile | VirtualDirectory) -> None: assert filelink_entry.stat(follow_symlinks=False) == filelink_entry.lstat() assert filelink_entry.stat(follow_symlinks=True) == file_entry.stat() @@ -859,7 +862,7 @@ def test_virtual_symlink_lstat(filelink_entry: VirtualSymlink) -> None: ("filelink_entry", False), ), ) -def test_virtual_symlink_is_dir(virt_link: str, is_dir: bool, request: FixtureRequest) -> None: +def test_virtual_symlink_is_dir(virt_link: str, is_dir: bool, request: pytest.FixtureRequest) -> None: virt_link = request.getfixturevalue(virt_link) assert virt_link.is_dir(follow_symlinks=False) is False @@ -873,7 +876,7 @@ def test_virtual_symlink_is_dir(virt_link: str, is_dir: bool, request: FixtureRe ("filelink_entry", True), ), ) -def test_virtual_symlink_is_file(virt_link: str, is_file: bool, request: FixtureRequest) -> None: +def test_virtual_symlink_is_file(virt_link: str, is_file: bool, request: pytest.FixtureRequest) -> None: virt_link = request.getfixturevalue(virt_link) assert virt_link.is_file(follow_symlinks=False) is False @@ -996,7 +999,7 @@ def root_filelink_entry(rootfs: RootFilesystem) -> VirtualSymlink: ("root_filelink_entry", "root_file_entry"), ], ) -def test_root_filesystem_entry_stat(src_entry: str, dst_entry: str, request: FixtureRequest) -> None: +def test_root_filesystem_entry_stat(src_entry: str, dst_entry: str, request: pytest.FixtureRequest) -> None: src_entry = request.getfixturevalue(src_entry) dst_entry = request.getfixturevalue(dst_entry) @@ -1012,7 +1015,7 @@ def test_root_filesystem_entry_stat(src_entry: str, dst_entry: str, request: Fix ("root_file_entry", stat.S_IFREG), ], ) -def test_root_filesystem_entry_lstat(entry: str, st_mode: int, request: FixtureRequest) -> None: +def test_root_filesystem_entry_lstat(entry: str, st_mode: int, request: pytest.FixtureRequest) -> None: entry = request.getfixturevalue(entry) assert entry.lstat().st_mode == st_mode @@ -1027,7 +1030,9 @@ def test_root_filesystem_entry_lstat(entry: str, st_mode: int, request: FixtureR ("root_filelink_entry", False, False), ], ) -def test_root_filesystem_entry_is_dir(entry: str, src_is_dir: bool, dst_is_dir: bool, request: FixtureRequest) -> None: +def test_root_filesystem_entry_is_dir( + entry: str, src_is_dir: bool, dst_is_dir: bool, request: pytest.FixtureRequest +) -> None: entry = request.getfixturevalue(entry) assert entry.is_dir(follow_symlinks=False) == src_is_dir @@ -1047,7 +1052,7 @@ def test_root_filesystem_entry_is_file( entry: str, src_is_file: bool, dst_is_file: bool, - request: FixtureRequest, + request: pytest.FixtureRequest, ) -> None: entry = request.getfixturevalue(entry) From 837e9c304bf3b8f8aa4a2e869519e20f096a20f2 Mon Sep 17 00:00:00 2001 From: Schamper <1254028+Schamper@users.noreply.github.com> Date: Mon, 26 Feb 2024 13:33:55 +0100 Subject: [PATCH 5/5] Add annotation import --- tests/test_filesystem.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/test_filesystem.py b/tests/test_filesystem.py index 2b9d881ed..6f2ebc9d9 100644 --- a/tests/test_filesystem.py +++ b/tests/test_filesystem.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import os import stat from datetime import datetime, timezone