aacs: rustfmt verify-gate files + correct cert/unit-key test fixtures to libaacs-strict layout; 1.1.0-beta.1 changelog
This commit is contained in:
@@ -4,6 +4,18 @@
|
|||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
||||||
|
- **Post-read decrypt-verify gate.** Every AACS unit read off the disc is now
|
||||||
|
buffered, re-aligned to its clip-file 6144-byte unit grid, and verified
|
||||||
|
(CPI flag → decrypt → strict all-32 TS-sync, matching libaacs `_verify_ts`)
|
||||||
|
before it is signed off as good. A unit that neither a held nor a
|
||||||
|
freshly-fetched key decrypts is treated exactly like a bad read — re-read by
|
||||||
|
the patch pass, terminal loss only if truly unrecoverable — closing the
|
||||||
|
"silent bad read" class where a sector reads OK but its ciphertext is subtly
|
||||||
|
wrong. **Fail-safe:** it only ever downgrades a unit it is *confident* is bad;
|
||||||
|
every uncertainty (no keys, a merely-missing key, an unread/zero-filled sector,
|
||||||
|
a non-AACS disc) leaves the read byte-for-byte as before. Gated by a
|
||||||
|
compile-time kill-switch (`POST_READ_VERIFY`), and container-pluggable (BD/UHD
|
||||||
|
transport stream today, with an HD-DVD program-stream seam in place).
|
||||||
- **Every error is now `Error: E<code> <message>`, with an Error Codes
|
- **Every error is now `Error: E<code> <message>`, with an Error Codes
|
||||||
reference.** User-facing errors show their code so you can look it up, and a
|
reference.** User-facing errors show their code so you can look it up, and a
|
||||||
new **Error Codes** page lists every code with its message, cause, and next
|
new **Error Codes** page lists every code with its message, cause, and next
|
||||||
@@ -13,11 +25,22 @@
|
|||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
|
- **AACS decrypt acceptance is now standards-strict.** A key is accepted only
|
||||||
|
when the decrypted unit has the TS sync byte on *all* 32 source packets
|
||||||
|
(libaacs `_verify_ts`), replacing a majority-vote heuristic where a wrong key
|
||||||
|
could coincidentally restore enough syncs to pass and silently corrupt a unit.
|
||||||
- keydb download/save moved out of the library into freemkv-keysources;
|
- keydb download/save moved out of the library into freemkv-keysources;
|
||||||
libfreemkv no longer has any keydb I/O (it already held no keys).
|
libfreemkv no longer has any keydb I/O (it already held no keys).
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
|
- **AACS content-certificate bus-encryption flag read from the wrong bit.** The
|
||||||
|
flag is bit 7 of byte 1 (libaacs `p[1] >> 7`) but was read as bit 0, so a
|
||||||
|
bus-encrypted disc parsed as *not* bus-encrypted — defeating the fail-loud
|
||||||
|
guard that refuses to decrypt bus-wrapped data to garbage when no bus key was
|
||||||
|
obtained. Also corrected the cc_id offset (byte 14) and the AACS2 type marker
|
||||||
|
(`0x10`). Confirmed against real retail content certificates.
|
||||||
|
|
||||||
- **DVD rips now start on the movie, not the disc menu.** A VTS title VOB's
|
- **DVD rips now start on the movie, not the disc menu.** A VTS title VOB's
|
||||||
start sector was read from the IFO as a VTS-relative pointer but used as an
|
start sector was read from the IFO as a VTS-relative pointer but used as an
|
||||||
absolute disc address, so a DVD title's read extents began `ifo_lba` sectors
|
absolute disc address, so a DVD title's read extents began `ifo_lba` sectors
|
||||||
|
|||||||
+12
-8
@@ -2521,15 +2521,19 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn parse_unit_key_ro_title_cps_mapping_first_play_top_menu_then_titles() {
|
fn parse_unit_key_ro_title_cps_mapping_first_play_top_menu_then_titles() {
|
||||||
// [20..22] first_play, [22..24] top_menu, [24..26] num_titles, then
|
// [20..22] first_play, [22..24] top_menu, [24..26] num_titles, then
|
||||||
// per-title 2-byte pad + 2-byte CPS unit at 26 + i*4 + 2.
|
// per-title 2-byte pad + 2-byte CPS unit at 26 + i*4 + 2. Each on-disc
|
||||||
let mut data = build_unit_key_ro(2, 64);
|
// 1-based CPS number in `1..=num_uk` is validated and converted to a
|
||||||
data[20..22].copy_from_slice(&7u16.to_be_bytes()); // first_play
|
// 0-based key index (libaacs unit_key.c); an out-of-range number → 0.
|
||||||
data[22..24].copy_from_slice(&9u16.to_be_bytes()); // top_menu
|
let mut data = build_unit_key_ro(4, 64); // num_uk = 4 → CPS 1..=4 valid
|
||||||
data[24..26].copy_from_slice(&2u16.to_be_bytes()); // num_titles
|
data[20..22].copy_from_slice(&1u16.to_be_bytes()); // first_play CPS 1
|
||||||
data[28..30].copy_from_slice(&3u16.to_be_bytes()); // title 0 CPS
|
data[22..24].copy_from_slice(&2u16.to_be_bytes()); // top_menu CPS 2
|
||||||
data[32..34].copy_from_slice(&4u16.to_be_bytes()); // title 1 CPS
|
data[24..26].copy_from_slice(&3u16.to_be_bytes()); // num_titles = 3
|
||||||
|
data[28..30].copy_from_slice(&3u16.to_be_bytes()); // title 0 CPS 3
|
||||||
|
data[32..34].copy_from_slice(&4u16.to_be_bytes()); // title 1 CPS 4
|
||||||
|
data[36..38].copy_from_slice(&9u16.to_be_bytes()); // title 2 CPS 9 (> num_uk)
|
||||||
let p = parse_unit_key_ro(&data, AacsVersion::V20).unwrap();
|
let p = parse_unit_key_ro(&data, AacsVersion::V20).unwrap();
|
||||||
assert_eq!(p.title_cps_unit, vec![7, 9, 3, 4]);
|
// 1-based CPS {1,2,3,4} → 0-based {0,1,2,3}; out-of-range 9 → 0.
|
||||||
|
assert_eq!(p.title_cps_unit, vec![0, 1, 2, 3, 0]);
|
||||||
}
|
}
|
||||||
// ── MKB record framing: rec_len is BE24 incl. 4-byte header ────────────
|
// ── MKB record framing: rec_len is BE24 incl. 4-byte header ────────────
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
+2
-2
@@ -32,8 +32,8 @@ pub use trace::{KeyNode, KeyOutcome, KeyStep, ResolutionTrace, UnlockOutcome, Un
|
|||||||
// AES primitives (aes_ecb_encrypt, aes_ecb_decrypt, aes_cbc_decrypt) are pub(crate) in decrypt.rs.
|
// AES primitives (aes_ecb_encrypt, aes_ecb_decrypt, aes_cbc_decrypt) are pub(crate) in decrypt.rs.
|
||||||
pub use decrypt::{
|
pub use decrypt::{
|
||||||
ALIGNED_UNIT_LEN, ALIGNED_UNIT_SECTORS, UnitKeyResult, aacs_unit_encrypted,
|
ALIGNED_UNIT_LEN, ALIGNED_UNIT_SECTORS, UnitKeyResult, aacs_unit_encrypted,
|
||||||
aacs_unit_needs_decrypt, decrypt_bus, decrypt_unit, decrypt_unit_full, decrypt_unit_try_keys,
|
aacs_unit_needs_decrypt, decrypt_bus, decrypt_unit, decrypt_unit_checked, decrypt_unit_full,
|
||||||
decrypt_unit_checked, is_unit_aligned, ts_packet_total, ts_sync_count, ts_sync_destroyed,
|
decrypt_unit_try_keys, is_unit_aligned, ts_packet_total, ts_sync_count, ts_sync_destroyed,
|
||||||
unit_is_clean_ps, unit_is_clean_ts, unit_key_validates,
|
unit_is_clean_ps, unit_is_clean_ts, unit_key_validates,
|
||||||
};
|
};
|
||||||
// `probe` is a reproduction-harness helper (see keys.rs), not part of the
|
// `probe` is a reproduction-harness helper (see keys.rs), not part of the
|
||||||
|
|||||||
+4
-3
@@ -547,11 +547,12 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// A content certificate: type byte@0 (0x00 = V10, else V20),
|
/// A content certificate: type byte@0 (0x00 = V10, else V20),
|
||||||
/// bus_encryption bit0@1, cc_id@2..8 (aacs/keys.rs parse_content_cert).
|
/// bus_encryption bit7@1, cc_id@14..20 (aacs/keys.rs parse_content_cert,
|
||||||
|
/// which requires ≥20 bytes and reads the bus flag from `data[1] >> 7`).
|
||||||
fn build_content_cert(cert_type: u8, bus_encryption: bool) -> Vec<u8> {
|
fn build_content_cert(cert_type: u8, bus_encryption: bool) -> Vec<u8> {
|
||||||
let mut v = vec![0u8; 8];
|
let mut v = vec![0u8; 20];
|
||||||
v[0] = cert_type;
|
v[0] = cert_type;
|
||||||
v[1] = if bus_encryption { 0x01 } else { 0x00 };
|
v[1] = if bus_encryption { 0x80 } else { 0x00 };
|
||||||
v
|
v
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -304,7 +304,6 @@ impl Disc {
|
|||||||
None => base_keys.clone(),
|
None => base_keys.clone(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// True for the AACS-encrypted stream files (`.m2ts`, `.ssif`). Every other UDF
|
/// True for the AACS-encrypted stream files (`.m2ts`, `.ssif`). Every other UDF
|
||||||
@@ -1187,7 +1186,6 @@ mod tests {
|
|||||||
std::fs::read(dir.join(rel)).ok()
|
std::fs::read(dir.join(rel)).ok()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// ── Tests ─────────────────────────────────────────────────────────────
|
// ── Tests ─────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
/// BDMV extraction: STREAM/*.m2ts written decrypted (here clear via
|
/// BDMV extraction: STREAM/*.m2ts written decrypted (here clear via
|
||||||
|
|||||||
+69
-19
@@ -439,7 +439,10 @@ impl UnitVerifier {
|
|||||||
}
|
}
|
||||||
let accept = self.accept_for(clip);
|
let accept = self.accept_for(clip);
|
||||||
if readable
|
if readable
|
||||||
&& matches!(self.decryptability(&raw, accept), Decryptability::Undecryptable)
|
&& matches!(
|
||||||
|
self.decryptability(&raw, accept),
|
||||||
|
Decryptability::Undecryptable
|
||||||
|
)
|
||||||
{
|
{
|
||||||
push_ranges(&mut bad, &lbas);
|
push_ranges(&mut bad, &lbas);
|
||||||
}
|
}
|
||||||
@@ -550,7 +553,10 @@ mod tests {
|
|||||||
|
|
||||||
/// One contiguous full unit at disc LBA `lba` (size 6144 = 3 sectors).
|
/// One contiguous full unit at disc LBA `lba` (size 6144 = 3 sectors).
|
||||||
fn one_clip(lba: u32) -> Vec<ClipLayout> {
|
fn one_clip(lba: u32) -> Vec<ClipLayout> {
|
||||||
vec![ts_clip(ALIGNED_UNIT_LEN as u64, vec![(lba, ALIGNED_UNIT_LEN as u32)])]
|
vec![ts_clip(
|
||||||
|
ALIGNED_UNIT_LEN as u64,
|
||||||
|
vec![(lba, ALIGNED_UNIT_LEN as u32)],
|
||||||
|
)]
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Build a BD-TS `ClipLayout` (the only container current enumeration emits).
|
/// Build a BD-TS `ClipLayout` (the only container current enumeration emits).
|
||||||
@@ -615,7 +621,10 @@ mod tests {
|
|||||||
u[4] = 0x00; // break the first packet's sync
|
u[4] = 0x00; // break the first packet's sync
|
||||||
let mut v = UnitVerifier::new(&one_clip(100), &aacs_keys(&[[1; 16]]), None).unwrap();
|
let mut v = UnitVerifier::new(&one_clip(100), &aacs_keys(&[[1; 16]]), None).unwrap();
|
||||||
let bad = v.observe(100, &u);
|
let bad = v.observe(100, &u);
|
||||||
assert!(bad.is_empty(), "clear-but-not-clean unit -> skip, never false-bad");
|
assert!(
|
||||||
|
bad.is_empty(),
|
||||||
|
"clear-but-not-clean unit -> skip, never false-bad"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ── encrypted (CPI set) content ────────────────────────────────────────
|
// ── encrypted (CPI set) content ────────────────────────────────────────
|
||||||
@@ -699,7 +708,10 @@ mod tests {
|
|||||||
c.fetch_add(1, std::sync::atomic::Ordering::SeqCst);
|
c.fetch_add(1, std::sync::atomic::Ordering::SeqCst);
|
||||||
vec![real]
|
vec![real]
|
||||||
});
|
});
|
||||||
let clips = vec![ts_clip(2 * ALIGNED_UNIT_LEN as u64, vec![(200, 2 * ALIGNED_UNIT_LEN as u32)])];
|
let clips = vec![ts_clip(
|
||||||
|
2 * ALIGNED_UNIT_LEN as u64,
|
||||||
|
vec![(200, 2 * ALIGNED_UNIT_LEN as u32)],
|
||||||
|
)];
|
||||||
let mut v = UnitVerifier::new(&clips, &aacs_keys(&[[0x01; 16]]), Some(fetch)).unwrap();
|
let mut v = UnitVerifier::new(&clips, &aacs_keys(&[[0x01; 16]]), Some(fetch)).unwrap();
|
||||||
let mut u0 = clear_unit();
|
let mut u0 = clear_unit();
|
||||||
encrypt_unit(&mut u0, &real);
|
encrypt_unit(&mut u0, &real);
|
||||||
@@ -724,7 +736,10 @@ mod tests {
|
|||||||
let real = [0x42; 16];
|
let real = [0x42; 16];
|
||||||
let mut u = clear_unit();
|
let mut u = clear_unit();
|
||||||
encrypt_unit(&mut u, &real);
|
encrypt_unit(&mut u, &real);
|
||||||
let clips = vec![ts_clip(ALIGNED_UNIT_LEN as u64, vec![(10, 4096), (5000, 2048)])];
|
let clips = vec![ts_clip(
|
||||||
|
ALIGNED_UNIT_LEN as u64,
|
||||||
|
vec![(10, 4096), (5000, 2048)],
|
||||||
|
)];
|
||||||
// Wrong key + a fetch that yields wrong keys => confident bad, fragmented.
|
// Wrong key + a fetch that yields wrong keys => confident bad, fragmented.
|
||||||
let fetch: KeyFetch = Arc::new(|_s: &[Vec<u8>]| vec![[0xEE; 16]]);
|
let fetch: KeyFetch = Arc::new(|_s: &[Vec<u8>]| vec![[0xEE; 16]]);
|
||||||
let mut v = UnitVerifier::new(&clips, &aacs_keys(&[[0x01; 16]]), Some(fetch)).unwrap();
|
let mut v = UnitVerifier::new(&clips, &aacs_keys(&[[0x01; 16]]), Some(fetch)).unwrap();
|
||||||
@@ -748,7 +763,10 @@ mod tests {
|
|||||||
let key = [0x5a; 16];
|
let key = [0x5a; 16];
|
||||||
let mut u0 = clear_unit();
|
let mut u0 = clear_unit();
|
||||||
encrypt_unit(&mut u0, &key);
|
encrypt_unit(&mut u0, &key);
|
||||||
let clips = vec![ts_clip(ALIGNED_UNIT_LEN as u64 + 2048, vec![(100, ALIGNED_UNIT_LEN as u32 + 2048)])];
|
let clips = vec![ts_clip(
|
||||||
|
ALIGNED_UNIT_LEN as u64 + 2048,
|
||||||
|
vec![(100, ALIGNED_UNIT_LEN as u32 + 2048)],
|
||||||
|
)];
|
||||||
let mut v = UnitVerifier::new(&clips, &aacs_keys(&[key]), None).unwrap();
|
let mut v = UnitVerifier::new(&clips, &aacs_keys(&[key]), None).unwrap();
|
||||||
// Feed full unit 0 (good) + the tail sector (garbage). Only unit 0 is
|
// Feed full unit 0 (good) + the tail sector (garbage). Only unit 0 is
|
||||||
// judged; the tail is never a verdict.
|
// judged; the tail is never a verdict.
|
||||||
@@ -843,7 +861,10 @@ mod tests {
|
|||||||
let key = [0x5a; 16];
|
let key = [0x5a; 16];
|
||||||
let mut u = clear_unit();
|
let mut u = clear_unit();
|
||||||
encrypt_unit(&mut u, &key);
|
encrypt_unit(&mut u, &key);
|
||||||
let mut iso = MockIso { sectors: Default::default(), err_lba: None };
|
let mut iso = MockIso {
|
||||||
|
sectors: Default::default(),
|
||||||
|
err_lba: None,
|
||||||
|
};
|
||||||
place_unit(&mut iso, [100, 101, 102], &u);
|
place_unit(&mut iso, [100, 101, 102], &u);
|
||||||
let mut v = UnitVerifier::new(&one_clip(100), &aacs_keys(&[key]), None).unwrap();
|
let mut v = UnitVerifier::new(&one_clip(100), &aacs_keys(&[key]), None).unwrap();
|
||||||
let bad = v.reverify_iso(&mut iso, &[(100 * 2048, 3 * 2048)], &|_| true);
|
let bad = v.reverify_iso(&mut iso, &[(100 * 2048, 3 * 2048)], &|_| true);
|
||||||
@@ -855,15 +876,23 @@ mod tests {
|
|||||||
let real = [0x11; 16];
|
let real = [0x11; 16];
|
||||||
let mut u = clear_unit();
|
let mut u = clear_unit();
|
||||||
encrypt_unit(&mut u, &real);
|
encrypt_unit(&mut u, &real);
|
||||||
let mut iso = MockIso { sectors: Default::default(), err_lba: None };
|
let mut iso = MockIso {
|
||||||
|
sectors: Default::default(),
|
||||||
|
err_lba: None,
|
||||||
|
};
|
||||||
place_unit(&mut iso, [100, 101, 102], &u);
|
place_unit(&mut iso, [100, 101, 102], &u);
|
||||||
// Wrong held key + a fetch that yields a wrong key => confident bad.
|
// Wrong held key + a fetch that yields a wrong key => confident bad.
|
||||||
let fetch: KeyFetch = Arc::new(|_s: &[Vec<u8>]| vec![[0xEE; 16]]);
|
let fetch: KeyFetch = Arc::new(|_s: &[Vec<u8>]| vec![[0xEE; 16]]);
|
||||||
let mut v = UnitVerifier::new(&one_clip(100), &aacs_keys(&[[0x22; 16]]), Some(fetch)).unwrap();
|
let mut v =
|
||||||
|
UnitVerifier::new(&one_clip(100), &aacs_keys(&[[0x22; 16]]), Some(fetch)).unwrap();
|
||||||
// A range covering only ONE sector of the unit still re-reads the WHOLE
|
// A range covering only ONE sector of the unit still re-reads the WHOLE
|
||||||
// unit from the ISO (patch re-reads partial units).
|
// unit from the ISO (patch re-reads partial units).
|
||||||
let bad = v.reverify_iso(&mut iso, &[(101 * 2048, 2048)], &|_| true);
|
let bad = v.reverify_iso(&mut iso, &[(101 * 2048, 2048)], &|_| true);
|
||||||
assert_eq!(bad, vec![(100, 3)], "undecryptable unit -> full 3-sector range");
|
assert_eq!(
|
||||||
|
bad,
|
||||||
|
vec![(100, 3)],
|
||||||
|
"undecryptable unit -> full 3-sector range"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -872,8 +901,14 @@ mod tests {
|
|||||||
let mut u = clear_unit();
|
let mut u = clear_unit();
|
||||||
encrypt_unit(&mut u, &key);
|
encrypt_unit(&mut u, &key);
|
||||||
// Unit 0: sectors at 10, 11 (extent A) and 5000 (extent B).
|
// Unit 0: sectors at 10, 11 (extent A) and 5000 (extent B).
|
||||||
let clips = vec![ts_clip(ALIGNED_UNIT_LEN as u64, vec![(10, 4096), (5000, 2048)])];
|
let clips = vec![ts_clip(
|
||||||
let mut iso = MockIso { sectors: Default::default(), err_lba: None };
|
ALIGNED_UNIT_LEN as u64,
|
||||||
|
vec![(10, 4096), (5000, 2048)],
|
||||||
|
)];
|
||||||
|
let mut iso = MockIso {
|
||||||
|
sectors: Default::default(),
|
||||||
|
err_lba: None,
|
||||||
|
};
|
||||||
place_unit(&mut iso, [10, 11, 5000], &u);
|
place_unit(&mut iso, [10, 11, 5000], &u);
|
||||||
let mut v = UnitVerifier::new(&clips, &aacs_keys(&[key]), None).unwrap();
|
let mut v = UnitVerifier::new(&clips, &aacs_keys(&[key]), None).unwrap();
|
||||||
// Range touches only the distant fragment; whole unit still assembled.
|
// Range touches only the distant fragment; whole unit still assembled.
|
||||||
@@ -892,9 +927,13 @@ mod tests {
|
|||||||
};
|
};
|
||||||
place_unit(&mut iso, [100, 101, 102], &u);
|
place_unit(&mut iso, [100, 101, 102], &u);
|
||||||
let fetch: KeyFetch = Arc::new(|_s: &[Vec<u8>]| vec![[0xEE; 16]]);
|
let fetch: KeyFetch = Arc::new(|_s: &[Vec<u8>]| vec![[0xEE; 16]]);
|
||||||
let mut v = UnitVerifier::new(&one_clip(100), &aacs_keys(&[[0x22; 16]]), Some(fetch)).unwrap();
|
let mut v =
|
||||||
|
UnitVerifier::new(&one_clip(100), &aacs_keys(&[[0x22; 16]]), Some(fetch)).unwrap();
|
||||||
let bad = v.reverify_iso(&mut iso, &[(100 * 2048, 3 * 2048)], &|_| true);
|
let bad = v.reverify_iso(&mut iso, &[(100 * 2048, 3 * 2048)], &|_| true);
|
||||||
assert!(bad.is_empty(), "ISO read error on a sector -> skip (fail-safe)");
|
assert!(
|
||||||
|
bad.is_empty(),
|
||||||
|
"ISO read error on a sector -> skip (fail-safe)"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -906,14 +945,22 @@ mod tests {
|
|||||||
let real = [0x11; 16];
|
let real = [0x11; 16];
|
||||||
let mut u = clear_unit();
|
let mut u = clear_unit();
|
||||||
encrypt_unit(&mut u, &real);
|
encrypt_unit(&mut u, &real);
|
||||||
let mut iso = MockIso { sectors: Default::default(), err_lba: None };
|
let mut iso = MockIso {
|
||||||
|
sectors: Default::default(),
|
||||||
|
err_lba: None,
|
||||||
|
};
|
||||||
place_unit(&mut iso, [100, 101, 102], &u);
|
place_unit(&mut iso, [100, 101, 102], &u);
|
||||||
let fetch: KeyFetch = Arc::new(|_s: &[Vec<u8>]| panic!("must NOT key-fetch an unread unit"));
|
let fetch: KeyFetch =
|
||||||
let mut v = UnitVerifier::new(&one_clip(100), &aacs_keys(&[[0x22; 16]]), Some(fetch)).unwrap();
|
Arc::new(|_s: &[Vec<u8>]| panic!("must NOT key-fetch an unread unit"));
|
||||||
|
let mut v =
|
||||||
|
UnitVerifier::new(&one_clip(100), &aacs_keys(&[[0x22; 16]]), Some(fetch)).unwrap();
|
||||||
// 102 not Finished -> the whole unit is skipped.
|
// 102 not Finished -> the whole unit is skipped.
|
||||||
let is_finished = |lba: u32| lba != 102;
|
let is_finished = |lba: u32| lba != 102;
|
||||||
let bad = v.reverify_iso(&mut iso, &[(100 * 2048, 3 * 2048)], &is_finished);
|
let bad = v.reverify_iso(&mut iso, &[(100 * 2048, 3 * 2048)], &is_finished);
|
||||||
assert!(bad.is_empty(), "unit with an unread sector is skipped, not flagged or fetched");
|
assert!(
|
||||||
|
bad.is_empty(),
|
||||||
|
"unit with an unread sector is skipped, not flagged or fetched"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -951,7 +998,10 @@ mod tests {
|
|||||||
// Open more partials than the cap with single-sector feeds; the map must
|
// Open more partials than the cap with single-sector feeds; the map must
|
||||||
// never exceed the cap (oldest evicted, unverified — fail-safe).
|
// never exceed the cap (oldest evicted, unverified — fail-safe).
|
||||||
let mut v = UnitVerifier::new(
|
let mut v = UnitVerifier::new(
|
||||||
&vec![ts_clip((MAX_INFLIGHT_UNITS as u64 + 100) * ALIGNED_UNIT_LEN as u64, vec![(0, u32::MAX / 2)])],
|
&vec![ts_clip(
|
||||||
|
(MAX_INFLIGHT_UNITS as u64 + 100) * ALIGNED_UNIT_LEN as u64,
|
||||||
|
vec![(0, u32::MAX / 2)],
|
||||||
|
)],
|
||||||
&aacs_keys(&[[1; 16]]),
|
&aacs_keys(&[[1; 16]]),
|
||||||
None,
|
None,
|
||||||
)
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user