diff --git a/TROUBLESHOOTING.md b/TROUBLESHOOTING.md index 05a19aa..853f9ff 100644 --- a/TROUBLESHOOTING.md +++ b/TROUBLESHOOTING.md @@ -141,7 +141,7 @@ If your machine has a free SATA port, use it. freemkv uses a three-layer recovery model. See [`docs/rip-recovery.md`](docs/rip-recovery.md) for full details. -- **Pass 1 (`freemkv_engine::recovery::copy`):** Fast sweep with 64 KB reads. On failure, zero-fills the block and skips forward. Writes a ddrescue-format mapfile for later retry. +- **Pass 1 (`freemkv_engine::recovery::sweep`):** Fast sweep with 64 KB reads. On failure, zero-fills the block and skips forward. Writes a ddrescue-format mapfile for later retry. - **Pass 2+ (`freemkv_engine::recovery::patch`):** Targeted re-reads of bad ranges with a long 60-second timeout per CDB. The drive firmware performs its own ECC and laser power retries within that window. - **In-stream (DiscStream):** Adaptive batch halving -- reduces request size on failure to isolate bad sectors within a larger block. diff --git a/docs/clpi.md b/docs/clpi.md index ce810af..cfbf890 100644 --- a/docs/clpi.md +++ b/docs/clpi.md @@ -69,13 +69,23 @@ Each stream PID entry header (14 bytes): ``` Offset Size Field ------ ---- ----- -0 2 Stream PID -2 2 Reserved + EP stream type -4 2 Number of coarse entries -6 4 Number of fine entries (note: 32-bit, can be large) -10 4 EP map start offset (relative to EP map start) +2 2 stream_PID (byte-aligned) +4 10 Bit-packed block, 80 bits total (see below) ``` +The stream PID entry is **not** byte-aligned past `stream_PID`. Bytes 4..14 are one +80-bit packed field, read as a `u64` plus a trailing `u16`: + +Bits Width Field +---- ----- ----- +0-9 10 reserved +10-13 4 EP_stream_type +14-29 16 num_EP_coarse +30-47 18 num_EP_fine +48-79 32 EP_map_start_address (relative to the EP map start) + +Note `num_EP_fine` is **18 bits**, not 32. See `parse_cpi` in `src/clpi.rs`. + libfreemkv parses only the first stream (primary video), which is sufficient for sector-level seeking. ### Two-Level Index diff --git a/docs/udf.md b/docs/udf.md index 5e52c14..1f02f2a 100644 --- a/docs/udf.md +++ b/docs/udf.md @@ -114,7 +114,7 @@ The `read_filesystem()` function in `src/udf.rs` follows the pointer chain above 2. Scans sectors 32-63 for the Partition Descriptor and Logical Volume Descriptor. 3. If two partition maps exist and the second is Type 2, reads the metadata file ICB at partition_start to find metadata_start. 4. Reads the FSD at metadata_start, extracts the root directory ICB LBA. -5. Calls `read_directory()` recursively (max depth 3) to build the full file tree. +5. Calls `read_directory()` recursively (max depth `MAX_DIR_DEPTH` = 8) to build the full file tree. Each directory read involves two sector reads: one for the ICB, then one or more for the directory data. File sizes are read from info_length in each file's ICB. diff --git a/src/io/pipeline.rs b/src/io/pipeline.rs index ec23cfc..1039492 100644 --- a/src/io/pipeline.rs +++ b/src/io/pipeline.rs @@ -184,7 +184,8 @@ pub const WRITE_PIPELINE_DEPTH: usize = 16; /// Channel depth for write-through pipelines. Each `send` fully /// drains before the next can enqueue. Use this when the producer /// must observe consumer side-effects (e.g. mapfile state) before -/// emitting the next item. Currently used by `disc::patch`. +/// emitting the next item. Used by `freemkv_engine::recovery::patch` — the +/// recovery strategy moved to that crate in 1.6.0, so there is no `patch` here. pub const WRITE_THROUGH_DEPTH: usize = 1; /// Outcome of [`Sink::apply`]: either keep feeding items diff --git a/src/mux/codec/truehd.rs b/src/mux/codec/truehd.rs index 10cba86..4d70b33 100644 --- a/src/mux/codec/truehd.rs +++ b/src/mux/codec/truehd.rs @@ -255,7 +255,8 @@ fn mlp_major_sync_header_size(ms: &[u8]) -> Option { /// 0x002D). The stored trailer is the last 2 header bytes; because /// MLP's checksum is byte-reversed relative to a standard CRC, a standard CRC of /// the header body XOR the little-endian word before the trailer must equal the -/// trailer read big-endian. +/// trailer read LITTLE-endian. (Comparing it big-endian was the bug this function +/// was fixed for; the body and the inline note below are authoritative.) fn mlp_major_sync_crc_ok(ms: &[u8], mshdr: usize) -> bool { if mshdr < 4 || ms.len() < mshdr { return false; diff --git a/src/sector/decrypting.rs b/src/sector/decrypting.rs index fcc4467..a0252c3 100644 --- a/src/sector/decrypting.rs +++ b/src/sector/decrypting.rs @@ -50,8 +50,7 @@ pub type KeyFetchFn = std::sync::Arc]) -> Vec<[u8; 16]> + Send /// `len()` and never assumes a fixed N (32 is all we've seen, but the contract /// is "whatever the source returns, ≥ 1, is all of them"). /// -/// A **stateless, shared** pair of `Arc` — the decorator owns the only -/// mutable state (its call-count cap and spent flag), so one `KeyFetch` is built +/// A **stateless, shared** pair of `Arc`, so one `KeyFetch` is built /// once and cloned cheaply (two `Arc` bumps) into every read path. `Send + Sync` /// so it can ride the mux highway's producer thread. #[derive(Clone)]