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
12 changes: 11 additions & 1 deletion src/resolve.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,16 @@ std::vector<Finding> resolve(std::vector<Finding> candidates, size_t file_size,
const std::set<std::string>& coalesce_types) {
std::sort(candidates.begin(), candidates.end(), less);

// A partition table is authoritative about the medium's layout, so a finding
// starting exactly on a partition boundary is a real region, not interior
// noise — even when an earlier finding's self-declared size overruns it
// (see scan.cpp). Otherwise a stale superblock recording a pre-repartition
// size demotes every partition it spans to a footnote on itself.
std::set<size_t> part_starts;
for (const auto& f : candidates)
for (const auto& m : f.members)
if (m.offset != SIZE_MAX) part_starts.insert(m.offset);

std::vector<Finding> kept;
size_t owner_end = 0; // end of the span owned by the current owner
int owner = -1; // index in `kept` of the owning region, or -1
Expand All @@ -38,7 +48,7 @@ std::vector<Finding> resolve(std::vector<Finding> candidates, size_t file_size,
continue;
}
// Starts inside a region already owned by a confident, sized finding.
if (f.offset < owner_end) {
if (f.offset < owner_end && !part_starts.count(f.offset)) {
if (owner >= 0) kept[owner].also_matched.push_back(demote(f));
continue;
}
Expand Down
20 changes: 18 additions & 2 deletions src/scan.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,13 @@ std::vector<Finding> scan(const Reader& r, const std::vector<Signature>& sigs) {
// Scan with skip-ahead: once a confident, sized finding claims a region,
// restart the automaton past it so we neither validate nor traverse its
// interior (the compressed blocks inside a squashfs, etc.).
// That size is self-declared, though, and can overrun a region the partition
// table already accounts for (a stale superblock in unpartitioned space
// still recording its pre-repartition size). Skipping the whole extent would
// step over those partitions' superblocks without ever validating them, so
// they would be missed entirely rather than demoted. Clamp the jump at the
// next partition start.
std::set<size_t> part_starts; // absolute partition offsets seen so far
std::vector<Finding> candidates;
size_t next_scan = 0;
while (next_scan < n) {
Expand All @@ -138,9 +145,18 @@ std::vector<Finding> scan(const Reader& r, const std::vector<Signature>& sigs) {
if (!f) return true;
const bool owns_region =
f->confidence >= static_cast<uint8_t>(Confidence::Structural) && f->size > 0;
const size_t end = f->offset + f->size;
const size_t foff = f->offset;
const size_t end = foff + f->size;
for (const auto& m : f->members)
if (m.offset != SIZE_MAX) part_starts.insert(m.offset);
candidates.push_back(std::move(*f));
if (owns_region) { skip_to = end; return false; }
if (owns_region) {
size_t lim = end;
auto it = part_starts.upper_bound(foff); // first boundary after it
if (it != part_starts.end() && *it < lim) lim = *it;
skip_to = lim; // > foff >= next_scan, so the loop still advances
return false;
}
return true;
});
if (skip_to > next_scan)
Expand Down
Loading