Files
libfreemkv/docs/image-writer.md
T
Matthew Jackson 6e14fc0c0c libfreemkv: 1.7.0 groundwork — sector-recycle soundness + CI hardening
Security
- Remove the unsafe Vec::set_len over recycled sector buffers — UB reachable
  from safe code (GHSA-j8ww-f5fg-9pmh, low). Uses Vec::resize; pooling unchanged.

CI / tooling
- clippy on stable with the MSRV single-sourced from Cargo.toml; cargo-deny
  dependency-audit gate with first-party git sources allowed (#15); audience-based
  comment-guard (#17).

Docs
- README (keydb ownership, BD-J parser count), drive-access transport/reset
  notes, mux timeline module-doc links.
2026-09-02 12:40:55 -07:00

1.7 KiB

src/io/image_writer.rs

Why this is not freemkv_engine::copy

The engine's copy is the RECOVERY path — mapfile sidecar, --multipass sweep/patch, damage-jump, ECC-aware batching, auto-resume. Every one of those exists because an optical drive returns read errors on marginal media. A file-backed or synthesized source has no marginal media: a read either succeeds or the underlying file is broken, and retrying it is pointless.

Routing a non-drive source through the recovery path is not merely wasteful, it is wrong. Its mapfile identity check compares AACS unit keys and the VID, both of which are empty for an already-decrypted source, so identity passes for ANY such source: a second run with a different input to the same output path would resume over the previous image and produce wrong content at exit zero. Keeping the two paths separate makes that unrepresentable.

So: drive sources get freemkv_engine::copy. Everything else gets this.

write_image rationale

The output is a faithful image of whatever the source presents — decrypted if the caller wrapped the source in a DecryptingSectorSource, ciphertext if it did not. write_image performs no decryption itself and makes no decryption decision; that belongs to the caller, which knows whether the run is --raw.

On cancellation the partial file is left in place — the caller decides whether a partial image is worth keeping, and deleting a multi-gigabyte file the user may want to inspect is not this function's call to make.

A short read from the source is treated as an error rather than zero-filled: silently padding a truncated source would produce an image that looks complete and is not.