Skip to content

Commit db22322

Browse files
committed
Make collection of non-existent files more clear
(DIS-962)
1 parent 0f8c210 commit db22322

File tree

2 files changed

+176
-15
lines changed

2 files changed

+176
-15
lines changed

acquire/collector.py

Lines changed: 24 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -341,6 +341,11 @@ def collect_path(
341341
path = self.target.fs.path(path)
342342

343343
try:
344+
# If a path does not exist, is_dir(), is_file() and is_symlink() will return False (and not raise an
345+
# exception), so we need to explicitly check for this.
346+
# For now we use path._fs.lexists(str(path)) instead of path.get().lexists(str(path)) as the latter has some
347+
# issues.
348+
exists = path._fs.lexists(str(path))
344349
is_dir = path.is_dir()
345350
is_file = path.is_file()
346351
is_symlink = path.is_symlink()
@@ -356,23 +361,29 @@ def collect_path(
356361
log.error("- OSError while collecting path %s", path)
357362
return
358363
except Exception:
359-
log.error("- Failed to collect path %s", path, exc_info=True)
360364
self.report.add_path_failed(module_name, path)
365+
log.error("- Failed to collect path %s", path, exc_info=True)
361366
return
362367

363-
if is_dir:
364-
self.collect_dir(path, seen_paths=seen_paths, module_name=module_name)
365-
elif is_file:
366-
self.collect_file(path, module_name=module_name)
367-
elif is_symlink:
368-
log.error(
369-
"- Can't collect %s (symlink to %s) in module %s",
370-
path,
371-
path.get().readlink(),
372-
module_name,
373-
)
368+
if exists:
369+
if is_dir:
370+
self.collect_dir(path, seen_paths=seen_paths, module_name=module_name)
371+
elif is_file:
372+
self.collect_file(path, module_name=module_name)
373+
elif is_symlink:
374+
self.report.add_path_failed(module_name, path)
375+
log.error(
376+
"- Can't collect %s (symlink to %s) in module %s",
377+
path,
378+
path.get().readlink(),
379+
module_name,
380+
)
381+
else:
382+
self.report.add_path_failed(module_name, path)
383+
log.error("- Don't know how to collect %s in module %s", path, module_name)
374384
else:
375-
log.error("- Don't know how to collect %s in module %s", path, module_name)
385+
self.report.add_path_missing(module_name, path)
386+
log.error("- Path %s is not found", path)
376387

377388
def collect_command_output(
378389
self,

tests/test_collector.py

Lines changed: 152 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
1-
from unittest.mock import Mock
1+
import errno
2+
from unittest.mock import Mock, patch
23

4+
import pytest
35
from dissect.target import Target
4-
from dissect.target.filesystem import VirtualFilesystem
6+
from dissect.target.filesystem import VirtualFile, VirtualFilesystem, VirtualSymlink
57

68
from acquire.collector import Collector
79

@@ -23,3 +25,151 @@ def test_collector():
2325
collector.collect_file("$MFT", module_name="test")
2426

2527
assert not collector.report.was_path_seen(fs_2.get("$MFT"))
28+
29+
30+
@pytest.fixture
31+
def mock_file():
32+
return Mock()
33+
34+
35+
@pytest.fixture
36+
def mock_fs(mock_file):
37+
fs = VirtualFilesystem(case_sensitive=False)
38+
fs.makedirs("/foo/bar")
39+
fs.map_file_entry("/foo/bar/some-file", VirtualFile(fs, "some-file", mock_file))
40+
fs.map_file_entry("/foo/bar/some-symlink", VirtualSymlink(fs, "some-symlink", "/foo/bar/some_file"))
41+
return fs
42+
43+
44+
@pytest.fixture
45+
def mock_target(mock_fs):
46+
target = Target()
47+
target.fs.mount("/", mock_fs)
48+
target.filesystems.add(mock_fs)
49+
return target
50+
51+
52+
@pytest.fixture
53+
def mock_collector(mock_target):
54+
collector = Collector(mock_target, Mock())
55+
return collector
56+
57+
58+
MOCK_SEEN_PATHS = set()
59+
MOCK_MODULE_NAME = "DUMMY"
60+
61+
62+
def test_collector_collect_path_no_module_name(mock_collector):
63+
with pytest.raises(ValueError):
64+
mock_collector.collect_path("/some/path")
65+
66+
67+
def test_collector_collect_path_dir_as_target_path(mock_target, mock_collector):
68+
with patch.object(mock_collector, "collect_dir", autospec=True):
69+
path = mock_target.fs.path("/foo/bar")
70+
mock_collector.collect_path(
71+
path,
72+
seen_paths=MOCK_SEEN_PATHS,
73+
module_name=MOCK_MODULE_NAME,
74+
)
75+
mock_collector.collect_dir.assert_called()
76+
77+
78+
def test_collector_collect_path_dir(mock_collector):
79+
with patch.object(mock_collector, "collect_dir", autospec=True):
80+
mock_collector.collect_path(
81+
"/foo/bar",
82+
seen_paths=MOCK_SEEN_PATHS,
83+
module_name=MOCK_MODULE_NAME,
84+
)
85+
mock_collector.collect_dir.assert_called()
86+
87+
88+
def test_collector_collect_path_file(mock_collector):
89+
with patch.object(mock_collector, "collect_file", autospec=True):
90+
mock_collector.collect_path(
91+
"/foo/bar/some-file",
92+
seen_paths=MOCK_SEEN_PATHS,
93+
module_name=MOCK_MODULE_NAME,
94+
)
95+
mock_collector.collect_file.assert_called()
96+
97+
98+
def test_collector_collect_path_symlink(mock_collector):
99+
with patch("acquire.collector.log") as mock_log:
100+
with patch.object(mock_collector, "report", autospec=True) as mock_report:
101+
mock_collector.collect_path(
102+
"/foo/bar/some-symlink",
103+
seen_paths=MOCK_SEEN_PATHS,
104+
module_name=MOCK_MODULE_NAME,
105+
)
106+
mock_report.add_path_failed.assert_called()
107+
mock_log.error.assert_called()
108+
assert mock_log.error.call_args.args[0] == "- Can't collect %s (symlink to %s) in module %s"
109+
110+
111+
def test_collector_collect_path_non_existing_file(mock_collector):
112+
with patch("acquire.collector.log", autospec=True) as mock_log:
113+
with patch.object(mock_collector, "report", autospec=True) as mock_report:
114+
mock_collector.collect_path(
115+
"/foo/bar/non-existing-file",
116+
seen_paths=MOCK_SEEN_PATHS,
117+
module_name=MOCK_MODULE_NAME,
118+
)
119+
mock_report.add_path_missing.assert_called()
120+
mock_log.error.assert_called()
121+
assert mock_log.error.call_args.args[0] == "- Path %s is not found"
122+
123+
124+
def test_collector_collect_path_unknown_file_type(mock_target, mock_collector):
125+
with patch("acquire.collector.log", autospec=True) as mock_log:
126+
with patch.object(mock_collector, "report", autospec=True) as mock_report:
127+
with patch.object(mock_target.fs, "lexists", return_value=True, autospec=True):
128+
mock_collector.collect_path(
129+
"/foo/bar/non-existing-file",
130+
seen_paths=MOCK_SEEN_PATHS,
131+
module_name=MOCK_MODULE_NAME,
132+
)
133+
mock_report.add_path_failed.assert_called()
134+
mock_log.error.assert_called()
135+
assert mock_log.error.call_args.args[0] == "- Don't know how to collect %s in module %s"
136+
137+
138+
@pytest.mark.parametrize(
139+
"report_func, exception, log_msg",
140+
[
141+
(
142+
"add_path_missing",
143+
OSError(errno.ENOENT, "foo"),
144+
"- Path %s is not found",
145+
),
146+
(
147+
"add_path_failed",
148+
OSError(errno.EACCES, "foo"),
149+
"- Permission denied while accessing path %s",
150+
),
151+
(
152+
"add_path_failed",
153+
OSError(255, "foo"),
154+
"- OSError while collecting path %s",
155+
),
156+
(
157+
"add_path_failed",
158+
Exception,
159+
"- Failed to collect path %s",
160+
),
161+
],
162+
)
163+
def test_collector_collect_path_with_exception(mock_target, mock_collector, report_func, exception, log_msg):
164+
with patch("acquire.collector.log", autospec=True) as mock_log:
165+
with patch.object(mock_collector, "report", autospec=True) as mock_report:
166+
with patch.object(mock_target.fs, "lexists", side_effect=exception, autospec=True):
167+
mock_collector.collect_path(
168+
"/foo/bar/non-existing-file",
169+
seen_paths=MOCK_SEEN_PATHS,
170+
module_name=MOCK_MODULE_NAME,
171+
)
172+
report_func = getattr(mock_report, report_func)
173+
report_func.assert_called()
174+
mock_log.error.assert_called()
175+
assert mock_log.error.call_args.args[0] == log_msg

0 commit comments

Comments
 (0)