Four round-6 findings. FileSectorSource::read_sectors guarded its output buffer with a debug_assert, which is compiled out in release — so an undersized buffer panicked with 'range end index out of range' instead of returning an error, out of a public SectorSource impl where the length is caller input. Drive::read_fua already carries this exact guard, with a comment recording the same panic being fixed there, and PrefetchedSectorSource has a regression test for the same case; this impl had been given neither. The new test is red in release for precisely the predicted reason: 'range end index 8192 out of range for slice of length 2049'. parse_track's sample-rate ladder ended in an unconditional S48, so any SamplingFrequency below 44100 was recorded as 48 kHz. A 32000 Hz AC-3 or DTS track is legal and common in broadcast-sourced content, and the wrong rate then propagated into the reconstructed AudioStream. Anything below the lowest mapped rate is now Unknown, which is what the crate's canonical SampleRate::from_hz already returned — the ladder disagreed with it. The ladder itself stays, because the MKV element is a float and wants tolerance rather than exact equality. shim_open_exclusive used the mach port from IOMainPort without checking the return; on failure the port is left untouched and every IOKit call below ran against an uninitialised value. shim_list_drives in the same file does check it. build.rs treated cc and ar as successful if the process merely SPAWNED, so a genuine compile error in the macOS C shim produced no object file and surfaced later as an unexplained link failure against a missing symbol. The shim is macOS-only and is neither linted nor compiled on the other two platforms, so a mistake in it has exactly one chance to be noticed. The last two have no test: one needs IOMainPort to fail, the other needs a deliberately broken C shim, and neither is reachable from the test harness. Both mirror a correct sibling in the same file, which is the evidence available.
105 lines
4.3 KiB
Rust
105 lines
4.3 KiB
Rust
fn main() {
|
|
emit_git_suffix();
|
|
|
|
let target = std::env::var("CARGO_CFG_TARGET_OS").unwrap_or_default();
|
|
if target == "macos" {
|
|
println!("cargo:rustc-link-lib=framework=IOKit");
|
|
println!("cargo:rustc-link-lib=framework=CoreFoundation");
|
|
|
|
let out_dir = std::env::var("OUT_DIR").unwrap();
|
|
let obj = format!("{out_dir}/macos_shim.o");
|
|
let lib = format!("{out_dir}/libmacos_scsi.a");
|
|
|
|
// Build the shim for the TARGET arch, not the host's. A bare `cc` on an
|
|
// Apple-Silicon CI runner defaults to arm64, so cross-building to
|
|
// x86_64-apple-darwin would link a host-arch object against x86_64 Rust
|
|
// code → "Undefined symbols for architecture x86_64". (Still raw `cc`,
|
|
// not the `cc` crate, which breaks IOKit exclusive access.)
|
|
let target_arch = std::env::var("CARGO_CFG_TARGET_ARCH").unwrap_or_default();
|
|
let clang_arch: &str = if target_arch == "aarch64" {
|
|
"arm64"
|
|
} else {
|
|
&target_arch // x86_64 → x86_64
|
|
};
|
|
|
|
let cc_status = std::process::Command::new("cc")
|
|
.args([
|
|
"-arch",
|
|
clang_arch,
|
|
"-c",
|
|
"src/scsi/macos_shim.c",
|
|
"-o",
|
|
&obj,
|
|
"-framework",
|
|
"IOKit",
|
|
"-framework",
|
|
"CoreFoundation",
|
|
"-Wall",
|
|
"-O2",
|
|
])
|
|
.status()
|
|
.expect("failed to spawn cc for macos_shim.c");
|
|
// `.status()` succeeding only means the process RAN. A real compile error
|
|
// exits non-zero, and ignoring that left no object file, which surfaced
|
|
// much later as an unexplained link failure against a missing symbol. The
|
|
// shim is macOS-only and is neither linted nor compiled on the other two
|
|
// platforms, so a mistake in it has exactly one chance to be noticed.
|
|
assert!(cc_status.success(), "cc failed to compile macos_shim.c");
|
|
|
|
let ar_status = std::process::Command::new("ar")
|
|
.args(["rcs", &lib, &obj])
|
|
.status()
|
|
.expect("failed to spawn ar");
|
|
assert!(ar_status.success(), "ar failed to create the static lib");
|
|
|
|
println!("cargo:rustc-link-search=native={out_dir}");
|
|
println!("cargo:rustc-link-lib=static=macos_scsi");
|
|
println!("cargo:rerun-if-changed=src/scsi/macos_shim.c");
|
|
}
|
|
}
|
|
|
|
/// Bake the git short hash into the build as `GIT_SUFFIX` so any muxed MKV or
|
|
/// FVI index is traceable to the exact source revision (e.g. ` (g835cc99)`).
|
|
/// Empty when git or the repo is unavailable (e.g. a crates.io tarball build),
|
|
/// leaving just the package version. Always emitted so `env!("GIT_SUFFIX")`
|
|
/// resolves on every target.
|
|
fn emit_git_suffix() {
|
|
// Version label for the muxing-app / FVI generator tag. `FREEMKV_BUILD_LABEL`
|
|
// overrides the Cargo package version when set (non-empty) — used to stamp a
|
|
// pre-release/test build without bumping Cargo.toml and disturbing the
|
|
// tag-pinned [patch] version matching. Unset → the package version.
|
|
let version = std::env::var("FREEMKV_BUILD_LABEL")
|
|
.ok()
|
|
.filter(|s| !s.trim().is_empty())
|
|
.or_else(|| std::env::var("CARGO_PKG_VERSION").ok())
|
|
.unwrap_or_default();
|
|
println!("cargo:rustc-env=FREEMKV_VERSION={version}");
|
|
println!("cargo:rerun-if-env-changed=FREEMKV_BUILD_LABEL");
|
|
|
|
let suffix = git_short_hash()
|
|
.map(|h| format!(" (g{h})"))
|
|
.unwrap_or_default();
|
|
println!("cargo:rustc-env=GIT_SUFFIX={suffix}");
|
|
|
|
// Re-run when HEAD (or the branch it points at) moves so the stamp stays
|
|
// current without a clean rebuild.
|
|
println!("cargo:rerun-if-changed=.git/HEAD");
|
|
if let Ok(head) = std::fs::read_to_string(".git/HEAD")
|
|
&& let Some(ref_path) = head.strip_prefix("ref: ")
|
|
{
|
|
println!("cargo:rerun-if-changed=.git/{}", ref_path.trim());
|
|
}
|
|
}
|
|
|
|
fn git_short_hash() -> Option<String> {
|
|
let out = std::process::Command::new("git")
|
|
.args(["rev-parse", "--short=7", "HEAD"])
|
|
.output()
|
|
.ok()?;
|
|
if !out.status.success() {
|
|
return None;
|
|
}
|
|
let h = String::from_utf8(out.stdout).ok()?.trim().to_string();
|
|
if h.is_empty() { None } else { Some(h) }
|
|
}
|