Files
freemkv-keysources/src/mapfile.rs
T
MattJackson da5bd08d3f sources: stateful one-key-at-a-time providers, UK-first keydb, shared resolve loop
Each source implements next_key (a cursor over its candidates) instead of
returning them all at once. The keydb hands its per-disc candidates out
UK-first (UK > VK > MK > DK) so a stale/wrong VUK never pre-empts a good UK in
the same entry; online and mapfile are one-shot. MultiSource composes sources
in the caller's chosen order and resolve_and_apply drives the
next_key -> decrypt_with loop, stopping at the first key that decrypts.
read_sample_units moves here so the CLI and autorip share one content sampler.
2026-06-05 09:23:17 -07:00

47 lines
1.5 KiB
Rust

//! Mapfile cache source (source #3).
//!
//! A rip's ddrescue-style mapfile persists the resolved unit keys in its
//! `# freemkv-uk:` header (written at sweep time when the disc was keyed). On
//! resume / deferred mux, that mapfile is the fastest source — the keys are
//! already resolved, no keydb parse and no network round-trip. This source
//! reads them back as a terminal [`Key::Unit`] candidate.
//!
//! It is keyed by the mapfile path (the disc identity is implicit in which
//! mapfile belongs to which rip), so it ignores [`DiscInputs`].
use std::path::PathBuf;
use libfreemkv::disc::mapfile::Mapfile;
use libfreemkv::{DiscInputs, Key, KeySource};
/// A [`KeySource`] backed by a rip mapfile's persisted unit keys.
pub struct MapfileSource {
path: PathBuf,
/// The mapfile holds exactly one (terminal) UK set, so it is read once —
/// this flips true after the first `next_key`.
asked: bool,
}
impl MapfileSource {
/// A mapfile source reading the given `*.mapfile` path.
pub fn new(path: impl Into<PathBuf>) -> Self {
Self {
path: path.into(),
asked: false,
}
}
}
impl KeySource for MapfileSource {
fn next_key(&mut self, _inputs: &DiscInputs) -> Option<Key> {
if self.asked {
return None;
}
self.asked = true;
// A missing/unreadable/keyless mapfile simply offers nothing.
let map = Mapfile::load(&self.path).ok()?;
let uks = map.unit_keys();
(!uks.is_empty()).then(|| Key::Unit(uks.to_vec()))
}
}