From bc65ce0f8c9cefa1c33010698a11a414174b02db Mon Sep 17 00:00:00 2001 From: Simon LUCIDO Date: Mon, 30 Oct 2023 14:42:48 +0100 Subject: [PATCH] fix: properly create cpio/gzip archive Signed-off-by: Simon LUCIDO --- initramfs/Cargo.toml | 2 +- initramfs/src/image.rs | 50 ++++++++++++++++++++++++++++++++---------- 2 files changed, 40 insertions(+), 12 deletions(-) diff --git a/initramfs/Cargo.toml b/initramfs/Cargo.toml index e7008c2..dfa851a 100644 --- a/initramfs/Cargo.toml +++ b/initramfs/Cargo.toml @@ -18,6 +18,6 @@ env_logger = { version = "0.10.0" } flate2 = { version = "1.0.25" } tar = { version = "0.4.38" } bytes = "1.4.0" -libflate = "0.1" +libflate = "2.0.0" cpio = "0.2.2" openssl = { version = "0.10", features = ["vendored"] } diff --git a/initramfs/src/image.rs b/initramfs/src/image.rs index 37ab4de..e5e18a8 100644 --- a/initramfs/src/image.rs +++ b/initramfs/src/image.rs @@ -8,7 +8,7 @@ use anyhow::{anyhow, Result}; use bytes::Bytes; use cpio::{newc::Builder, write_cpio}; use libflate::gzip::{Decoder, Encoder}; -use log::debug; +use log::{debug, info}; use serde::Deserialize; use tar::Archive; @@ -95,9 +95,9 @@ impl Image { ) .map_err(|e| anyhow!(e).context("Failed to create gzip encoder"))?; - let mut entries = HashMap::new(); + let mut entries: HashMap>)> = HashMap::new(); - for layer in self.layers.clone() { + for layer in self.layers.clone().into_iter() { let mut archive = Archive::new(Decoder::new(layer.content)?); for entry in archive @@ -113,7 +113,21 @@ impl Image { .ok_or_else(|| anyhow!("Failed to convert path to string"))? .to_string(); - if entries.contains_key(&path) { + // This means we need to delete everything that is in the parent directory + if path.contains(".wh..wh..opq") { + debug!("Found opaque whiteout file : {}", &path); + + let parent = path.trim_end_matches(".wh..wh..opq"); + let keys = entries + .keys() + .filter(|key| key.starts_with(parent)) + .cloned() + .collect::>(); + + keys.iter().for_each(|key| { + entries.remove(key); + }); + continue; } @@ -139,9 +153,21 @@ impl Image { debug!("Adding {} to archive", &path); let mut contents = Vec::new(); - entry - .read_to_end(&mut contents) - .map_err(|e| anyhow!(e).context("Failed to read entry"))?; + if headers.entry_type().is_symlink() { + let link_path = headers + .link_name() + .map_err(|e| anyhow!(e).context("Failed to get link name of entry"))? + .ok_or(anyhow!("Failed to get link name of entry"))? + .to_str() + .ok_or_else(|| anyhow!("Failed to convert link name to string"))? + .to_string(); + + contents.extend_from_slice(link_path.as_bytes()); + } else { + entry + .read_to_end(&mut contents) + .map_err(|e| anyhow!(e).context("Failed to read entry"))?; + } entries.insert(path, (builder, Cursor::new(contents))); } @@ -181,11 +207,13 @@ impl Image { ), ); - let test = entries - .drain() - .map(|(_, (builder, contents))| (builder, contents)); + info!("Writing cpio to disk"); + + let inputs = entries.drain().map(|(_, data)| data); + let archive = - write_cpio(test, archive).map_err(|e| anyhow!(e).context("Failed to write cpio"))?; + write_cpio(inputs, archive).map_err(|e| anyhow!(e).context("Failed to write cpio"))?; + let handler = archive .finish() .into_result()