Skip to content

Fix review findings in the TIBX parser - #1

Open
mniedermaier wants to merge 1 commit into
falklindner:feature/tibx-parserfrom
mniedermaier:tibx-review-fixes
Open

mniedermaier wants to merge 1 commit into
falklindner:feature/tibx-parserfrom
mniedermaier:tibx-review-fixes

Conversation

@mniedermaier

Copy link
Copy Markdown

Fixes for issues found while reviewing fox-it#30 (fox-it/dissect.archive). Each fix comes with a regression test that fails on the current feature/tibx-parser and passes with this change.

Changes

Correctness

  • recovery_points() missed backups stored in ctrees. It read the slices tree (TLV[5]) only from its mem-tree, while has_records also counts ctree records. It now walks iter_tree_cells with keep-first merging and honours tombstones.
  • Shared-segment layout counted re-recorded extents twice. An incremental re-records unchanged extents under its own slice (seen in t1_chain_inc.tibx, so far only for whole-segment extents). For a multi-extent segment, the duplicate (segment_id, extent_index) shifted every later extent. Each index now counts once.
  • Volumes opened before use_recovery_point() read wrong data. The layout was rebuilt from the filtered extents, so a stale volume's extents fell back to base 0 through .get(..., 0). The layout is now built from the unfiltered table. A segment is written by one backup, so the layout does not depend on the selected point.
  • Encrypted segments skipped the length check. A short decode was zero-filled by TibxVolume.read. It now raises CorruptArchiveError, like the plaintext path.
  • find_split_parts(): stems with glob characters (Backup [PC1]) found no parts, and .TIBX was not matched on case-sensitive filesystems. Directory entries are now matched with SPLIT_PART_RE, and parts are ordered by number.

Robustness

  • A missing zstd module (no full extra below 3.14, or a Python 3.14 built without zstd) now raises UnsupportedFormatError instead of ModuleNotFoundError, so volumes() keeps working, as the codec.py docstring intends. test_open_without_zstd is updated accordingly.
  • TibxVolume.__repr__ shows span instead of size, so it no longer reads the boot sector and needs no password on a locked archive.

Performance

  • use_recovery_point() only resets the view caches (extents, streams, volumes). The segment index, the segment cache and the layout are kept.
  • unlock() resets _segment_cache_bytes together with the cache. Before, the stale count shrank the effective budget.

Not changed (for discussion)

  • _is_volume/_bitmap_spans can in principle hide an unrecognised-FS partition (e.g. BitLocker) whose span equals a bitmap span of another stream: a 1 GiB partition next to a 4 TiB one at 512-byte clusters. This is tuned on your corpus, so I left it alone.
  • find_split_parts() still stitches Server-2024.tibx with an unrelated Server.tibx. Requiring contiguous numbering would fix that, unless Acronis leaves gaps after version cleanup.

Testing

All TIBX tests pass (253), including test_tibx_acronis.py against the LFS samples. ruff check, ruff format --check and vermin are clean.

🤖 Generated with Claude Code

- recovery_points() reads the slices tree from its ctrees as well as its
  mem-tree, merged keep-first, so backups whose records were moved to disk
  are no longer missing
- The layout of extents sharing a segment counts an extent once even when
  an incremental records it again under a later slice, and is built from
  every extent, so a volume opened before use_recovery_point() still reads
  from the right place
- use_recovery_point() keeps the segment index and segment cache, which do
  not depend on the selected point; unlock() resets the cache's byte count
- A missing zstd module raises UnsupportedFormatError, so volumes() works
  without the full extra
- TibxVolume repr shows the span, which needs no read and so no password
- An encrypted segment that decodes short raises CorruptArchiveError, as a
  plaintext one does
- find_split_parts() handles stems with glob characters and upper-case
  extensions, and orders parts by number

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant