diff --git a/Cargo.toml b/Cargo.toml index 81409567..048494b9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -62,6 +62,7 @@ rust-version = "1.85.0" # them to do that, but in the meantime we need to be careful. [workspace.dependencies] anyhow = { version = "1", default-features = false } +ar = { version = "0.9", default-features = false } assert_matches = { version = "1.5.0", default-features = false } base64 = { version = "0.22.1", default-features = false } bindgen = { version = "0.72", default-features = false } diff --git a/xtask/Cargo.toml b/xtask/Cargo.toml index 04df81f6..d615859f 100644 --- a/xtask/Cargo.toml +++ b/xtask/Cargo.toml @@ -15,6 +15,7 @@ workspace = true [dependencies] anyhow = { workspace = true, features = ["std"] } +ar = { workspace = true } aya-tool = { path = "../aya-tool", version = "0.1.0", default-features = false } cargo_metadata = { workspace = true } clap = { workspace = true, features = ["derive"] } @@ -30,3 +31,4 @@ syn = { workspace = true } tar = { workspace = true } tempfile = { workspace = true } walkdir = { workspace = true } +xz2 = { workspace = true } diff --git a/xtask/src/run.rs b/xtask/src/run.rs index b52e8890..efa79b54 100644 --- a/xtask/src/run.rs +++ b/xtask/src/run.rs @@ -1,7 +1,7 @@ use std::{ ffi::{OsStr, OsString}, fmt::Write as _, - fs::{self, OpenOptions}, + fs::{self, File, OpenOptions}, io::{BufRead as _, BufReader, Write as _}, ops::Deref as _, path::{self, Path, PathBuf}, @@ -300,29 +300,37 @@ pub(crate) fn run(opts: Options) -> Result<()> { fs::create_dir_all(&archive_dir) .with_context(|| format!("failed to create {}", archive_dir.display()))?; - let mut dpkg = Command::new("dpkg-deb"); - dpkg.arg("--fsys-tarfile") - .arg(archive) - .stdout(Stdio::piped()); - let mut dpkg_child = dpkg - .spawn() - .with_context(|| format!("failed to spawn {dpkg:?}"))?; - let Child { stdout, .. } = &mut dpkg_child; - let stdout = stdout.take().unwrap(); - let mut archive_reader = tar::Archive::new(stdout); - archive_reader.unpack(&archive_dir).with_context(|| { - format!( - "failed to unpack archive {} to {}", - archive.display(), - archive_dir.display() - ) + let archive_reader = File::open(archive).with_context(|| { + format!("failed to open the deb package {}", archive.display()) })?; - let status = dpkg_child - .wait() - .with_context(|| format!("failed to wait for {dpkg:?}"))?; - if !status.success() { - bail!("{dpkg:?} exited with {status}"); + let mut archive_reader = ar::Archive::new(archive_reader); + // `ar` entries are borrowed from the reader, so the reader + // cannot implement `Iterator` (because `Iterator::Item` is not + // a GAT). + // + // https://github.com/mdsteele/rust-ar/issues/15 + let mut entries = 0; + while let Some(entry) = archive_reader.next_entry() { + let entry = entry.with_context(|| { + format!( + "failed to read an entry of the deb package {}", + archive.display() + ) + })?; + if entry.header().identifier() == b"data.tar.xz" { + let entry_reader = xz2::read::XzDecoder::new(entry); + let mut entry_reader = tar::Archive::new(entry_reader); + entry_reader.unpack(&archive_dir).with_context(|| { + format!( + "failed to unpack archive {} to {}", + archive.display(), + archive_dir.display() + ) + })?; + entries += 1; + } } + assert_eq!(entries, 1); let mut kernel_images = Vec::new(); let mut configs = Vec::new();