Anchor the folder encryption probe on a unit boundary
probe_folder_encryption sampled AACS units starting from the largest extent anywhere in the disc. AACS units are 3 sectors and a unit boundary is only guaranteed at the START of a clip, so that anchor is only correct when the largest extent happens to be a clip first extent. For any clip over ~2 GiB it is not. The planner caps an allocation descriptor at MAX_AD_BYTES = 524287 sectors, so every full piece of a split file ties on sector_count and max_by_key returns the LAST tie — an extent beginning (k-1)*524287 sectors into the file. 524287 % 3 == 1, so that start misses the unit boundary for two file sizes in three. The 6144-byte sample windows then begin mid-source-packet and the byte read as the CPI flag is content. Both verdicts fail in a costly direction: a decrypted folder is rejected as encrypted (DirImageEncrypted on something perfectly rippable — the exact case scan_dir was added to rescue), or real ciphertext reads as clear and the mux writes it out as video at exit 0. is_unit_aligned cannot catch it: it measures against the same wrong base. Now the largest TITLE first extent, which is unit-aligned by construction and is also the more meaningful sample — the main feature rather than whichever fragment happened to be biggest. The existing tests could not reach this: their fixture m2ts is 786,432 bytes, a single extent, which is always its own first.
This commit is contained in:
+24
-2
@@ -508,11 +508,33 @@ fn probe_folder_encryption(reader: &mut dyn SectorSource, disc: &Disc) -> Result
|
||||
use crate::consts::SECTOR_BYTES;
|
||||
|
||||
const UNIT_SECTORS: u32 = 3;
|
||||
// Anchor on the largest TITLE's FIRST extent, not on the largest extent
|
||||
// anywhere.
|
||||
//
|
||||
// AACS units are 3 sectors, and a unit boundary is only guaranteed at the
|
||||
// START of a clip. `max_by_key` over every extent picked a mid-file one for
|
||||
// any clip big enough to be split: the planner caps an allocation
|
||||
// descriptor at MAX_AD_BYTES = 524287 sectors, every full piece of a split
|
||||
// file therefore ties on sector_count, and `max_by_key` returns the LAST
|
||||
// tie — an extent starting (k-1)*524287 sectors in. 524287 % 3 == 1, so
|
||||
// that start is off the unit boundary for two file sizes in three.
|
||||
//
|
||||
// The sampling then reads 6144-byte windows that begin mid-source-packet,
|
||||
// so the CPI byte it thinks it is testing is content. Both verdicts are
|
||||
// wrong in a costly direction: a decrypted folder gets rejected as
|
||||
// encrypted (DirImageEncrypted on something perfectly rippable), or
|
||||
// genuine ciphertext reads as clear and the mux writes it out as video at
|
||||
// exit 0. `is_unit_aligned` cannot catch it, because it measures against
|
||||
// this same wrong base.
|
||||
let Some(extent) = disc
|
||||
.titles
|
||||
.iter()
|
||||
.flat_map(|t| t.extents.iter())
|
||||
.max_by_key(|e| e.sector_count)
|
||||
.max_by_key(|t| {
|
||||
t.extents
|
||||
.iter()
|
||||
.fold(0u64, |a, e| a.saturating_add(e.sector_count as u64))
|
||||
})
|
||||
.and_then(|t| t.extents.first())
|
||||
else {
|
||||
// No content to judge. A folder with an AACS directory and no titles
|
||||
// has nothing to rip either way; leave the structural verdict alone.
|
||||
|
||||
Reference in New Issue
Block a user