acquire 3.16.dev5__tar.gz → 3.16.dev7__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {acquire-3.16.dev5/acquire.egg-info → acquire-3.16.dev7}/PKG-INFO +1 -1
- {acquire-3.16.dev5 → acquire-3.16.dev7}/acquire/acquire.py +2 -0
- acquire-3.16.dev7/acquire/outputs/__init__.py +9 -0
- {acquire-3.16.dev5 → acquire-3.16.dev7}/acquire/outputs/tar.py +9 -2
- {acquire-3.16.dev5 → acquire-3.16.dev7}/acquire/outputs/zip.py +38 -19
- {acquire-3.16.dev5 → acquire-3.16.dev7}/acquire/utils.py +22 -2
- {acquire-3.16.dev5 → acquire-3.16.dev7}/acquire/version.py +2 -2
- {acquire-3.16.dev5 → acquire-3.16.dev7/acquire.egg-info}/PKG-INFO +1 -1
- {acquire-3.16.dev5 → acquire-3.16.dev7}/acquire.egg-info/SOURCES.txt +1 -0
- {acquire-3.16.dev5 → acquire-3.16.dev7}/tests/test_outputs_tar.py +5 -3
- acquire-3.16.dev7/tests/test_outputs_zip.py +47 -0
- {acquire-3.16.dev5 → acquire-3.16.dev7}/tests/test_utils.py +5 -4
- acquire-3.16.dev5/acquire/outputs/__init__.py +0 -7
- {acquire-3.16.dev5 → acquire-3.16.dev7}/COPYRIGHT +0 -0
- {acquire-3.16.dev5 → acquire-3.16.dev7}/LICENSE +0 -0
- {acquire-3.16.dev5 → acquire-3.16.dev7}/MANIFEST.in +0 -0
- {acquire-3.16.dev5 → acquire-3.16.dev7}/README.md +0 -0
- {acquire-3.16.dev5 → acquire-3.16.dev7}/acquire/__init__.py +0 -0
- {acquire-3.16.dev5 → acquire-3.16.dev7}/acquire/collector.py +0 -0
- {acquire-3.16.dev5 → acquire-3.16.dev7}/acquire/crypt.py +0 -0
- {acquire-3.16.dev5 → acquire-3.16.dev7}/acquire/dynamic/__init__.py +0 -0
- {acquire-3.16.dev5 → acquire-3.16.dev7}/acquire/dynamic/windows/__init__.py +0 -0
- {acquire-3.16.dev5 → acquire-3.16.dev7}/acquire/dynamic/windows/collect.py +0 -0
- {acquire-3.16.dev5 → acquire-3.16.dev7}/acquire/dynamic/windows/exceptions.py +0 -0
- {acquire-3.16.dev5 → acquire-3.16.dev7}/acquire/dynamic/windows/handles.py +0 -0
- {acquire-3.16.dev5 → acquire-3.16.dev7}/acquire/dynamic/windows/named_objects.py +0 -0
- {acquire-3.16.dev5 → acquire-3.16.dev7}/acquire/dynamic/windows/ntdll.py +0 -0
- {acquire-3.16.dev5 → acquire-3.16.dev7}/acquire/dynamic/windows/types.py +0 -0
- {acquire-3.16.dev5 → acquire-3.16.dev7}/acquire/esxi.py +0 -0
- {acquire-3.16.dev5 → acquire-3.16.dev7}/acquire/gui/__init__.py +0 -0
- {acquire-3.16.dev5 → acquire-3.16.dev7}/acquire/gui/base.py +0 -0
- {acquire-3.16.dev5 → acquire-3.16.dev7}/acquire/gui/win32.py +0 -0
- {acquire-3.16.dev5 → acquire-3.16.dev7}/acquire/hashes.py +0 -0
- {acquire-3.16.dev5 → acquire-3.16.dev7}/acquire/log.py +0 -0
- {acquire-3.16.dev5 → acquire-3.16.dev7}/acquire/outputs/base.py +0 -0
- {acquire-3.16.dev5 → acquire-3.16.dev7}/acquire/outputs/dir.py +0 -0
- {acquire-3.16.dev5 → acquire-3.16.dev7}/acquire/tools/__init__.py +0 -0
- {acquire-3.16.dev5 → acquire-3.16.dev7}/acquire/tools/decrypter.py +0 -0
- {acquire-3.16.dev5 → acquire-3.16.dev7}/acquire/uploaders/__init__.py +0 -0
- {acquire-3.16.dev5 → acquire-3.16.dev7}/acquire/uploaders/minio.py +0 -0
- {acquire-3.16.dev5 → acquire-3.16.dev7}/acquire/uploaders/plugin.py +0 -0
- {acquire-3.16.dev5 → acquire-3.16.dev7}/acquire/uploaders/plugin_registry.py +0 -0
- {acquire-3.16.dev5 → acquire-3.16.dev7}/acquire/volatilestream.py +0 -0
- {acquire-3.16.dev5 → acquire-3.16.dev7}/acquire.egg-info/dependency_links.txt +0 -0
- {acquire-3.16.dev5 → acquire-3.16.dev7}/acquire.egg-info/entry_points.txt +0 -0
- {acquire-3.16.dev5 → acquire-3.16.dev7}/acquire.egg-info/requires.txt +0 -0
- {acquire-3.16.dev5 → acquire-3.16.dev7}/acquire.egg-info/top_level.txt +0 -0
- {acquire-3.16.dev5 → acquire-3.16.dev7}/pyproject.toml +0 -0
- {acquire-3.16.dev5 → acquire-3.16.dev7}/setup.cfg +0 -0
- {acquire-3.16.dev5 → acquire-3.16.dev7}/tests/__init__.py +0 -0
- {acquire-3.16.dev5 → acquire-3.16.dev7}/tests/conftest.py +0 -0
- {acquire-3.16.dev5 → acquire-3.16.dev7}/tests/docs/Makefile +0 -0
- {acquire-3.16.dev5 → acquire-3.16.dev7}/tests/docs/conf.py +0 -0
- {acquire-3.16.dev5 → acquire-3.16.dev7}/tests/docs/index.rst +0 -0
- {acquire-3.16.dev5 → acquire-3.16.dev7}/tests/test_acquire_command.py +0 -0
- {acquire-3.16.dev5 → acquire-3.16.dev7}/tests/test_acquire_modules.py +0 -0
- {acquire-3.16.dev5 → acquire-3.16.dev7}/tests/test_collector.py +0 -0
- {acquire-3.16.dev5 → acquire-3.16.dev7}/tests/test_decryptor_funcs.py +0 -0
- {acquire-3.16.dev5 → acquire-3.16.dev7}/tests/test_esxi_memory.py +0 -0
- {acquire-3.16.dev5 → acquire-3.16.dev7}/tests/test_file_sorting.py +0 -0
- {acquire-3.16.dev5 → acquire-3.16.dev7}/tests/test_gui.py +0 -0
- {acquire-3.16.dev5 → acquire-3.16.dev7}/tests/test_minio_uploader.py +0 -0
- {acquire-3.16.dev5 → acquire-3.16.dev7}/tests/test_misc_users.py +0 -0
- {acquire-3.16.dev5 → acquire-3.16.dev7}/tests/test_outputs_dir.py +0 -0
- {acquire-3.16.dev5 → acquire-3.16.dev7}/tests/test_plugin.py +0 -0
- {acquire-3.16.dev5 → acquire-3.16.dev7}/tox.ini +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: acquire
|
|
3
|
-
Version: 3.16.
|
|
3
|
+
Version: 3.16.dev7
|
|
4
4
|
Summary: A tool to quickly gather forensic artifacts from disk images or a live system into a lightweight container
|
|
5
5
|
Author-email: Dissect Team <dissect@fox-it.com>
|
|
6
6
|
License: Affero General Public License v3
|
|
@@ -924,6 +924,7 @@ class Misc(Module):
|
|
|
924
924
|
("glob", "sysvol/Windows/Logs/WindowsUpdate/WindowsUpdate*.etl"),
|
|
925
925
|
("glob", "sysvol/Windows/Logs/CBS/CBS*.log"),
|
|
926
926
|
("dir", "sysvol/ProgramData/Microsoft/Search/Data/Applications/Windows"),
|
|
927
|
+
("dir", "sysvol/Windows/SoftwareDistribution/DataStore"),
|
|
927
928
|
]
|
|
928
929
|
|
|
929
930
|
|
|
@@ -1782,6 +1783,7 @@ def acquire_target(target: Target, args: argparse.Namespace, output_ts: Optional
|
|
|
1782
1783
|
output = OUTPUTS[args.output_type](
|
|
1783
1784
|
output_path,
|
|
1784
1785
|
compress=args.compress,
|
|
1786
|
+
compression_method=args.compress_method,
|
|
1785
1787
|
encrypt=args.encrypt,
|
|
1786
1788
|
public_key=args.public_key,
|
|
1787
1789
|
)
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
from acquire.outputs.dir import DirectoryOutput
|
|
2
|
+
from acquire.outputs.tar import TAR_COMPRESSION_METHODS, TarOutput
|
|
3
|
+
from acquire.outputs.zip import ZIP_COMPRESSION_METHODS, ZipOutput
|
|
4
|
+
|
|
5
|
+
__all__ = ["DirectoryOutput", "TarOutput", "ZipOutput"]
|
|
6
|
+
|
|
7
|
+
OUTPUTS = {"tar": TarOutput, "dir": DirectoryOutput, "zip": ZipOutput}
|
|
8
|
+
|
|
9
|
+
COMPRESSION_METHODS = {*TAR_COMPRESSION_METHODS, *ZIP_COMPRESSION_METHODS}
|
|
@@ -8,6 +8,8 @@ from dissect.target.filesystem import FilesystemEntry
|
|
|
8
8
|
from acquire.crypt import EncryptedStream
|
|
9
9
|
from acquire.outputs.base import Output
|
|
10
10
|
|
|
11
|
+
TAR_COMPRESSION_METHODS = {"gzip": "gz", "bzip2": "bz2", "xz": "xz"}
|
|
12
|
+
|
|
11
13
|
|
|
12
14
|
class TarOutput(Output):
|
|
13
15
|
"""Tar archive acquire output format. Output can be compressed and/or encrypted.
|
|
@@ -15,6 +17,7 @@ class TarOutput(Output):
|
|
|
15
17
|
Args:
|
|
16
18
|
path: The path to write the tar archive to.
|
|
17
19
|
compress: Whether to compress the tar archive.
|
|
20
|
+
compression_method: Compression method to use (Default: gzip). Supports "gzip", "bzip2", "xz".
|
|
18
21
|
encrypt: Whether to encrypt the tar archive.
|
|
19
22
|
public_key: The RSA public key to encrypt the header with.
|
|
20
23
|
"""
|
|
@@ -23,15 +26,19 @@ class TarOutput(Output):
|
|
|
23
26
|
self,
|
|
24
27
|
path: Path,
|
|
25
28
|
compress: bool = False,
|
|
29
|
+
compression_method: str = "gzip",
|
|
26
30
|
encrypt: bool = False,
|
|
27
31
|
public_key: Optional[bytes] = None,
|
|
28
32
|
) -> None:
|
|
33
|
+
self.compression = None
|
|
29
34
|
ext = ".tar" if ".tar" not in path.suffixes else ""
|
|
30
35
|
mode = "w|" if encrypt else "w:"
|
|
31
36
|
|
|
32
37
|
if compress:
|
|
33
|
-
|
|
34
|
-
|
|
38
|
+
self.compression = TAR_COMPRESSION_METHODS.get(compression_method, "gz")
|
|
39
|
+
|
|
40
|
+
ext += f".{self.compression}" if f".{self.compression}" not in path.suffixes else ""
|
|
41
|
+
mode += self.compression
|
|
35
42
|
|
|
36
43
|
if encrypt:
|
|
37
44
|
ext += ".enc"
|
|
@@ -11,6 +11,8 @@ from dissect.target.filesystem import FilesystemEntry
|
|
|
11
11
|
from acquire.crypt import EncryptedStream
|
|
12
12
|
from acquire.outputs.base import Output
|
|
13
13
|
|
|
14
|
+
ZIP_COMPRESSION_METHODS = {"deflate": zipfile.ZIP_DEFLATED, "bzip2": zipfile.ZIP_BZIP2, "lzma": zipfile.ZIP_LZMA}
|
|
15
|
+
|
|
14
16
|
|
|
15
17
|
class ZipOutput(Output):
|
|
16
18
|
"""Zip archive acquire output format. Output can be compressed and/or encrypted.
|
|
@@ -18,6 +20,7 @@ class ZipOutput(Output):
|
|
|
18
20
|
Args:
|
|
19
21
|
path: The path to write the zip archive to.
|
|
20
22
|
compress: Whether to compress the zip archive.
|
|
23
|
+
compression_method: Compression method to use (Default: Deflate). Supports "deflate", "bzip2", "lzma".
|
|
21
24
|
encrypt: Whether to encrypt the zip archive.
|
|
22
25
|
public_key: The RSA public key to encrypt the header with.
|
|
23
26
|
"""
|
|
@@ -26,6 +29,7 @@ class ZipOutput(Output):
|
|
|
26
29
|
self,
|
|
27
30
|
path: Path,
|
|
28
31
|
compress: bool = False,
|
|
32
|
+
compression_method: str = "deflate",
|
|
29
33
|
encrypt: bool = False,
|
|
30
34
|
public_key: Optional[bytes] = None,
|
|
31
35
|
) -> None:
|
|
@@ -38,7 +42,7 @@ class ZipOutput(Output):
|
|
|
38
42
|
self.path = path.with_suffix(path.suffix + ext)
|
|
39
43
|
|
|
40
44
|
if compress:
|
|
41
|
-
self.compression = zipfile.ZIP_DEFLATED
|
|
45
|
+
self.compression = ZIP_COMPRESSION_METHODS.get(compression_method, zipfile.ZIP_DEFLATED)
|
|
42
46
|
else:
|
|
43
47
|
self.compression = zipfile.ZIP_STORED
|
|
44
48
|
|
|
@@ -78,32 +82,19 @@ class ZipOutput(Output):
|
|
|
78
82
|
info.compress_type = self.compression
|
|
79
83
|
|
|
80
84
|
if entry:
|
|
85
|
+
info.external_attr = self._get_external_attr(entry)
|
|
86
|
+
|
|
81
87
|
if entry.is_symlink():
|
|
82
88
|
# System which created ZIP archive, 3 = Unix; 0 = Windows
|
|
83
89
|
# Windows does not have symlinks, so this must be a unixoid system
|
|
84
90
|
info.create_system = 3
|
|
85
91
|
|
|
86
|
-
# The Python zipfile module accepts the 16-bit "Mode" field (that stores st_mode field from
|
|
87
|
-
# struct stat, containing user/group/other permissions, setuid/setgid and symlink info, etc) of the
|
|
88
|
-
# ASi extra block for Unix as bits 16-31 of the external_attr
|
|
89
|
-
unix_st_mode = (
|
|
90
|
-
stat.S_IFLNK
|
|
91
|
-
| stat.S_IRUSR
|
|
92
|
-
| stat.S_IWUSR
|
|
93
|
-
| stat.S_IXUSR
|
|
94
|
-
| stat.S_IRGRP
|
|
95
|
-
| stat.S_IWGRP
|
|
96
|
-
| stat.S_IXGRP
|
|
97
|
-
| stat.S_IROTH
|
|
98
|
-
| stat.S_IWOTH
|
|
99
|
-
| stat.S_IXOTH
|
|
100
|
-
)
|
|
101
|
-
info.external_attr = unix_st_mode << 16
|
|
102
|
-
|
|
103
92
|
lstat = entry.lstat()
|
|
104
93
|
if lstat:
|
|
94
|
+
# Python zipfile module does not support timestamps before 1980
|
|
105
95
|
dt = datetime.fromtimestamp(lstat.st_mtime)
|
|
106
|
-
|
|
96
|
+
year = max(dt.year, 1980)
|
|
97
|
+
info.date_time = (year, dt.month, dt.day, dt.hour, dt.minute, dt.second)
|
|
107
98
|
|
|
108
99
|
with self.archive.open(info, "w") as zfh:
|
|
109
100
|
shutil.copyfileobj(fh, zfh)
|
|
@@ -113,3 +104,31 @@ class ZipOutput(Output):
|
|
|
113
104
|
self.archive.close()
|
|
114
105
|
if self._fh:
|
|
115
106
|
self._fh.close()
|
|
107
|
+
|
|
108
|
+
def _get_external_attr(self, entry: FilesystemEntry) -> int:
|
|
109
|
+
"""Return the appropriate external attributes of the entry."""
|
|
110
|
+
|
|
111
|
+
# The Python zipfile module accepts the 16-bit "Mode" field (that stores st_mode field from
|
|
112
|
+
# struct stat, containing user/group/other permissions, setuid/setgid and symlink info, etc) of the
|
|
113
|
+
# ASi extra block for Unix as bits 16-31 of the external_attr
|
|
114
|
+
unix_st_mode = stat.S_IFREG
|
|
115
|
+
|
|
116
|
+
if entry.is_symlink():
|
|
117
|
+
unix_st_mode = stat.S_IFLNK
|
|
118
|
+
elif entry.is_dir():
|
|
119
|
+
unix_st_mode = stat.S_IFDIR
|
|
120
|
+
|
|
121
|
+
unix_st_mode = (
|
|
122
|
+
unix_st_mode
|
|
123
|
+
| stat.S_IRUSR
|
|
124
|
+
| stat.S_IWUSR
|
|
125
|
+
| stat.S_IXUSR
|
|
126
|
+
| stat.S_IRGRP
|
|
127
|
+
| stat.S_IWGRP
|
|
128
|
+
| stat.S_IXGRP
|
|
129
|
+
| stat.S_IROTH
|
|
130
|
+
| stat.S_IWOTH
|
|
131
|
+
| stat.S_IXOTH
|
|
132
|
+
) << 16
|
|
133
|
+
|
|
134
|
+
return unix_st_mode
|
|
@@ -16,7 +16,12 @@ from typing import Any, Optional
|
|
|
16
16
|
|
|
17
17
|
from dissect.target import Target
|
|
18
18
|
|
|
19
|
-
from acquire.outputs import
|
|
19
|
+
from acquire.outputs import (
|
|
20
|
+
COMPRESSION_METHODS,
|
|
21
|
+
OUTPUTS,
|
|
22
|
+
TAR_COMPRESSION_METHODS,
|
|
23
|
+
ZIP_COMPRESSION_METHODS,
|
|
24
|
+
)
|
|
20
25
|
from acquire.uploaders.plugin_registry import UploaderRegistry
|
|
21
26
|
|
|
22
27
|
|
|
@@ -75,7 +80,7 @@ def create_argument_parser(profiles: dict, volatile: dict, modules: dict) -> arg
|
|
|
75
80
|
parser.add_argument(
|
|
76
81
|
"-ot",
|
|
77
82
|
"--output-type",
|
|
78
|
-
choices=OUTPUTS
|
|
83
|
+
choices=OUTPUTS,
|
|
79
84
|
default="tar",
|
|
80
85
|
help="output type (default: tar)",
|
|
81
86
|
)
|
|
@@ -84,6 +89,11 @@ def create_argument_parser(profiles: dict, volatile: dict, modules: dict) -> arg
|
|
|
84
89
|
action=argparse.BooleanOptionalAction,
|
|
85
90
|
help="compress output (if supported by the output type)",
|
|
86
91
|
)
|
|
92
|
+
parser.add_argument(
|
|
93
|
+
"--compress-method",
|
|
94
|
+
choices=COMPRESSION_METHODS,
|
|
95
|
+
help="compression method (if supported by the output type)",
|
|
96
|
+
)
|
|
87
97
|
parser.add_argument(
|
|
88
98
|
"--encrypt",
|
|
89
99
|
action=argparse.BooleanOptionalAction,
|
|
@@ -320,6 +330,16 @@ def check_and_set_acquire_args(
|
|
|
320
330
|
if not args.children and args.skip_parent:
|
|
321
331
|
raise ValueError("--skip-parent can only be set with --children")
|
|
322
332
|
|
|
333
|
+
if args.compress:
|
|
334
|
+
if (args.output_type == "zip" and args.compress_method) and args.compress_method not in ZIP_COMPRESSION_METHODS:
|
|
335
|
+
raise ValueError(
|
|
336
|
+
f"Invalid compression method for zip, allowed are: {', '.join(ZIP_COMPRESSION_METHODS.keys())}"
|
|
337
|
+
)
|
|
338
|
+
if (args.output_type == "tar" and args.compress_method) and args.compress_method not in TAR_COMPRESSION_METHODS:
|
|
339
|
+
raise ValueError(
|
|
340
|
+
f"Invalid compression method for tar, allowed are: {', '.join(TAR_COMPRESSION_METHODS.keys())}"
|
|
341
|
+
)
|
|
342
|
+
|
|
323
343
|
|
|
324
344
|
def get_user_name() -> str:
|
|
325
345
|
try:
|
|
@@ -12,5 +12,5 @@ __version__: str
|
|
|
12
12
|
__version_tuple__: VERSION_TUPLE
|
|
13
13
|
version_tuple: VERSION_TUPLE
|
|
14
14
|
|
|
15
|
-
__version__ = version = '3.16.
|
|
16
|
-
__version_tuple__ = version_tuple = (3, 16, '
|
|
15
|
+
__version__ = version = '3.16.dev7'
|
|
16
|
+
__version_tuple__ = version_tuple = (3, 16, 'dev7')
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: acquire
|
|
3
|
-
Version: 3.16.
|
|
3
|
+
Version: 3.16.dev7
|
|
4
4
|
Summary: A tool to quickly gather forensic artifacts from disk images or a live system into a lightweight container
|
|
5
5
|
Author-email: Dissect Team <dissect@fox-it.com>
|
|
6
6
|
License: Affero General Public License v3
|
|
@@ -7,9 +7,10 @@ from dissect.target.filesystem import VirtualFilesystem
|
|
|
7
7
|
from acquire.outputs import TarOutput
|
|
8
8
|
|
|
9
9
|
|
|
10
|
-
@pytest.fixture
|
|
11
|
-
def tar_output(tmp_path: Path) -> TarOutput:
|
|
12
|
-
|
|
10
|
+
@pytest.fixture(params=[(True, "gzip"), (True, "bzip2"), (True, "xz"), (False, None)])
|
|
11
|
+
def tar_output(tmp_path: Path, request: pytest.FixtureRequest) -> TarOutput:
|
|
12
|
+
compress, compression_method = request.param
|
|
13
|
+
return TarOutput(tmp_path, compress=compress, compression_method=compression_method)
|
|
13
14
|
|
|
14
15
|
|
|
15
16
|
@pytest.mark.parametrize(
|
|
@@ -28,6 +29,7 @@ def test_tar_output_write_entry(mock_fs: VirtualFilesystem, tar_output: TarOutpu
|
|
|
28
29
|
tar_file = tarfile.open(tar_output.path)
|
|
29
30
|
files = tar_file.getmembers()
|
|
30
31
|
|
|
32
|
+
assert tar_output.path.suffix == f".{tar_output.compression}" if tar_output.compression else ".tar"
|
|
31
33
|
assert len(files) == 1
|
|
32
34
|
|
|
33
35
|
file = files[0]
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import stat
|
|
2
|
+
import zipfile
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
|
|
5
|
+
import pytest
|
|
6
|
+
from dissect.target.filesystem import VirtualFilesystem
|
|
7
|
+
|
|
8
|
+
from acquire.outputs import ZipOutput
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
@pytest.fixture(params=[(True, "deflate"), (True, "bzip2"), (True, "lzma"), (False, None)])
|
|
12
|
+
def zip_output(tmp_path: Path, request: pytest.FixtureRequest) -> ZipOutput:
|
|
13
|
+
compress, compression_method = request.param
|
|
14
|
+
return ZipOutput(tmp_path, compress=compress, compression_method=compression_method)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@pytest.mark.parametrize(
|
|
18
|
+
"entry_name",
|
|
19
|
+
[
|
|
20
|
+
"/foo/bar/some-file",
|
|
21
|
+
"/foo/bar/some-symlink",
|
|
22
|
+
"/foo/bar/some-dir",
|
|
23
|
+
],
|
|
24
|
+
)
|
|
25
|
+
def test_zip_output_write_entry(mock_fs: VirtualFilesystem, zip_output: ZipOutput, entry_name: str) -> None:
|
|
26
|
+
entry = mock_fs.get(entry_name)
|
|
27
|
+
|
|
28
|
+
assert zip_output.compression == zip_output.archive.compression
|
|
29
|
+
zip_output.write_entry(entry_name, entry)
|
|
30
|
+
zip_output.close()
|
|
31
|
+
|
|
32
|
+
zip_file = zipfile.ZipFile(zip_output.path, mode="r")
|
|
33
|
+
files = zip_file.filelist
|
|
34
|
+
assert len(files) == 1
|
|
35
|
+
|
|
36
|
+
file = files[0]
|
|
37
|
+
assert file.filename == entry_name
|
|
38
|
+
|
|
39
|
+
file_type = file.external_attr >> 16
|
|
40
|
+
|
|
41
|
+
# zipfile only supports is_dir(). we have all the information we need to determine the file type in 'external_attr'
|
|
42
|
+
if entry.is_dir():
|
|
43
|
+
assert stat.S_ISDIR(file_type)
|
|
44
|
+
elif entry.is_symlink():
|
|
45
|
+
assert stat.S_ISLNK(file_type)
|
|
46
|
+
elif entry.is_file():
|
|
47
|
+
assert stat.S_ISREG(file_type)
|
|
@@ -491,10 +491,11 @@ def test_utils_normalize_path(
|
|
|
491
491
|
if os == "windows":
|
|
492
492
|
case_sensitive = False
|
|
493
493
|
|
|
494
|
-
with
|
|
495
|
-
mock_target
|
|
496
|
-
|
|
497
|
-
mock_target.
|
|
494
|
+
with (
|
|
495
|
+
patch.object(mock_target, "os", new=os),
|
|
496
|
+
patch.object(mock_target.fs, "_case_sensitive", new=case_sensitive),
|
|
497
|
+
patch.object(mock_target.fs, "_alt_separator", new=("\\" if os == "windows" else "/")),
|
|
498
|
+
patch.dict(mock_target.props, {"sysvol_drive": sysvol}),
|
|
498
499
|
):
|
|
499
500
|
if as_path:
|
|
500
501
|
path = TargetPath(mock_target.fs, path)
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
from acquire.outputs.dir import DirectoryOutput
|
|
2
|
-
from acquire.outputs.tar import TarOutput
|
|
3
|
-
from acquire.outputs.zip import ZipOutput
|
|
4
|
-
|
|
5
|
-
__all__ = ["DirectoryOutput", "TarOutput", "ZipOutput"]
|
|
6
|
-
|
|
7
|
-
OUTPUTS = {"tar": TarOutput, "dir": DirectoryOutput, "zip": ZipOutput}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|