mux: thread halt into live AACS key-map resolution; cover Session arm
Round-2 follow-ups to 6d6e60f (inline base-map resolve on the live
single-pass Session/Live mux arms).
Fix 1 (halt threading) — the inline resolve chain sampled ciphertext off
the LIVE drive with no cancel token, so an operator /api/stop during key
resolution was not honored (the FMTS probe can issue hundreds of reads,
each able to stall to the 60s SCSI recovery timeout — violating the
"don't hammer a struggling live drive" rule). Add an optional
`halt: Option<&Halt>` to `resolve_mux_key_map`, `resolve_fmts_key_map`,
`resolve_inline_base_map`, and `Disc::resolve_content_key_map`, and poll
it at each loop boundary (FMTS anchor + per-index probe loops, multi-CPS
extent loop) — returning Err(Halted) promptly. Live/Session arms pass the
driver's halt; sweep/patch pass their own token (via Halt::from_arc);
file-backed probe/ISO callers pass None. Tested with a pre-cancelled halt
(Err Halted, no extent sampling) and a None-halt no-abort case;
mutation-verified (dropping the extent-loop check → Ok, not Err).
Fix 2 (Session-arm coverage) — the MuxInput::Session arm ran the same
resolve→install→decrypt sequence as Live but had NO end-to-end test
(DiscSession only exposed open(), which needs live hardware). Add a
#[cfg(test)] DiscSession::from_parts_for_test (injected reader + scanned
disc, no Drive), an end-to-end AACS decrypt test through the Session arm
(mutation-verified: dropping with_key_map → mux aborts), and a
missing-reader clean-error (not panic) test.
Fix 3 (cleanups) — io_error_code: remove the unreachable typed-Error
downcast branch (From<Error> for io::Error stringifies; no path builds an
io::Error holding a typed Error), keeping the stringify parse is_halt /
is_skippable_title_stub rely on. Add a resolve_keys_for test covering the
largest-title sampling branch. Document the patch wedge-exit coverage gap
(TODO) in passn_handler_ab.rs.
This commit is contained in:
@@ -814,6 +814,18 @@ fn profile_08_batch_fail_singles_ok() {
|
||||
/// Run a single-always-bad-sector (LBA 130, inside a NonTrimmed [128,192)
|
||||
/// range) patch pass with the given failure step and return the final map
|
||||
/// stats. 256-sector synthetic disc; everything outside the range is Finished.
|
||||
///
|
||||
/// TODO(coverage gap): these HARDWARE_ERROR / ILLEGAL_REQUEST cases assert only
|
||||
/// the persistent-sense RECOVERY CONTRACT (never Unreadable, byte conservation,
|
||||
/// dead sector stays pending) — they do NOT exercise the patch WEDGE-EXIT path.
|
||||
/// A single dead sector in one range structurally cannot reach either exit:
|
||||
/// `WEDGE_ABORT_THRESHOLD=16` needs 16 CONSECUTIVE wedge-family senses within a
|
||||
/// range, and the `wedged_threshold=50` exit additionally needs `range_idx > 0`
|
||||
/// (a prior range already processed). No test anywhere asserts
|
||||
/// `PatchOutcome::wedged_exit == true`. A real wedge-exit fixture (a first
|
||||
/// throwaway range, then a second range of >=16 sectors that ALL always-fail
|
||||
/// with HARDWARE_ERROR, in reverse mode) is a separate, larger synthetic build;
|
||||
/// left out here rather than bent into this shared single-sector helper.
|
||||
fn single_dead_sector_patch_stats(step: ScriptStep) -> libfreemkv::disc::mapfile::MapStats {
|
||||
let capacity_sectors: u32 = 256;
|
||||
let (mut reader, _trace) = ScriptedSectorReader::new(capacity_sectors);
|
||||
|
||||
Reference in New Issue
Block a user