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..fba369c6 100644 --- a/xtask/src/run.rs +++ b/xtask/src/run.rs @@ -1,8 +1,8 @@ use std::{ ffi::{OsStr, OsString}, fmt::Write as _, - fs::{self, OpenOptions}, - io::{BufRead as _, BufReader, Write as _}, + fs::{self, File, OpenOptions}, + io::{BufRead as _, BufReader, Cursor, Read as _, Write as _}, ops::Deref as _, path::{self, Path, PathBuf}, process::{Child, ChildStdin, Command, Output, Stdio}, @@ -300,29 +300,43 @@ 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(|| { + let archive_reader = File::open(archive).with_context(|| { + format!("failed to open the deb package {}", archive.display()) + })?; + let mut archive_reader = ar::Archive::new(archive_reader); + // This would've been easier if `ar` crate was providing some iterator + // over entries... + // https://github.com/mdsteele/rust-ar/issues/15 + let mut inner_archive = None; + while let Some(entry) = archive_reader.next_entry() { + let mut 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 mut buf = Vec::with_capacity(entry.header().size() as usize); + let _bytes_read = entry.read_to_end(&mut buf)?; + inner_archive = Some(buf); + break; + } + } + let Some(inner_archive) = inner_archive else { + bail!( + "cound not find the `data.tar.xz` archive inside the deb package {}", + archive.display() + ); + }; + let inner_archive_reader = xz2::read::XzDecoder::new(Cursor::new(inner_archive)); + let mut inner_archive_reader = tar::Archive::new(inner_archive_reader); + inner_archive_reader.unpack(&archive_dir).with_context(|| { format!( "failed to unpack archive {} to {}", archive.display(), archive_dir.display() ) })?; - let status = dpkg_child - .wait() - .with_context(|| format!("failed to wait for {dpkg:?}"))?; - if !status.success() { - bail!("{dpkg:?} exited with {status}"); - } let mut kernel_images = Vec::new(); let mut configs = Vec::new();