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
18 changes: 16 additions & 2 deletions dissect/target/helpers/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -149,15 +149,29 @@
# We have to append the current_year to strptime instead of adding it using replace later.
# This prevents DeprecationWarnings on cpython >= 3.13 and Exceptions on cpython >= 3.15.
# See https://github.com/python/cpython/issues/70647 and https://github.com/python/cpython/pull/117107.
compare_ts = datetime.strptime(f"{timestamp.group(0)};1900", f"{ts_format};%Y")
# Use 1904 instead of 1900 to include leap days (29 Feb).
try:
compare_ts = datetime.strptime(f"{timestamp.group(0)};1904", f"{ts_format};%Y")
except ValueError as e:
log.warning("Unable to create comparison timestamp for %r in line %r: %s", timestamp.group(0), line, e)
log.debug("", exc_info=e)
continue

Check warning on line 158 in dissect/target/helpers/utils.py

View check run for this annotation

Codecov / codecov/patch

dissect/target/helpers/utils.py#L155-L158

Added lines #L155 - L158 were not covered by tests

if last_seen_month and compare_ts.month > last_seen_month:
current_year -= 1
last_seen_month = compare_ts.month

try:
relative_ts = datetime.strptime(f"{timestamp.group(0)};{current_year}", f"{ts_format};%Y")
except ValueError as e:
log.warning("Timestamp '%s' does not match format '%s', skipping line.", timestamp.group(0), ts_format)
log.warning(

Check warning on line 167 in dissect/target/helpers/utils.py

View check run for this annotation

Codecov / codecov/patch

dissect/target/helpers/utils.py#L167

Added line #L167 was not covered by tests
"Timestamp '%s;%s' does not match format '%s;%%Y', skipping line %r: %s",
timestamp.group(0),
current_year,
ts_format,
line,
e,
)
log.debug("", exc_info=e)
continue

Expand Down
25 changes: 25 additions & 0 deletions tests/helpers/test_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,8 @@ def test_helpers_fsutil_year_rollover_helper() -> None:
mocked_stat = fsutil.stat_result([stat.S_IFREG, 1337, id(vfs), 0, 0, 0, len(content), 0, 3384460800, 0])
with patch.object(path, "stat", return_value=mocked_stat):
result = list(utils.year_rollover_helper(path, re_ts, ts_fmt))
assert len(result) == 10

year_line = [(ts.year, line) for ts, line in result]

assert result[0][0].tzinfo == datetime.timezone.utc
Expand All @@ -78,3 +80,26 @@ def test_helpers_fsutil_year_rollover_helper() -> None:

assert year_line[0] == (2022, "Jan 1 13:21:34 Line 10")
assert year_line[-1] == (2018, "Dec 31 03:14:15 Line 1")


def test_helpers_fsutil_year_rollover_helper_leap_day() -> None:
"""test if we correctly handle leap days such as 2024-02-29."""

content = """
Feb 28 11:00:00 Line 1
Feb 29 12:00:00 Line 2
Mar 1 13:00:00 Line 3
"""
fs = VirtualFilesystem()
fs.map_file_fh("file", io.BytesIO(textwrap.dedent(content).encode()))
path = fs.path("file")

re_ts = r"(\w+\s{1,2}\d+\s\d{2}:\d{2}:\d{2})"
ts_fmt = "%b %d %H:%M:%S"
mocked_stat = fsutil.stat_result(
[stat.S_IFREG, 1337, id(fs), 0, 0, 0, len(content), 0, 1709294400, 0]
) # mtime is set to 2024-03-01.

with patch.object(path, "stat", return_value=mocked_stat):
result = list(utils.year_rollover_helper(path, re_ts, ts_fmt))
assert len(result) == 3
Loading