From d23ed418a1332fe5c212f61236817a5de69f73bd Mon Sep 17 00:00:00 2001 From: Tobias Brumhard Date: Wed, 3 May 2023 15:30:16 +0200 Subject: [PATCH] Use tmpdir for files --- Cargo.lock | 47 ++++++++++++++++++++++++++++++++++++++++++++--- Cargo.toml | 1 + maskfile.md | 7 ++++--- src/main.rs | 52 ++++++++++++++++++++++++++++++++-------------------- 4 files changed, 81 insertions(+), 26 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e31b3b8..54513d6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -316,6 +316,15 @@ dependencies = [ "libc", ] +[[package]] +name = "fastrand" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be" +dependencies = [ + "instant", +] + [[package]] name = "filetime" version = "0.2.21" @@ -324,7 +333,7 @@ checksum = "5cbc844cecaee9d4443931972e1289c8ff485cb4cc2767cb03ca139ed6885153" dependencies = [ "cfg-if", "libc", - "redox_syscall", + "redox_syscall 0.2.16", "windows-sys 0.48.0", ] @@ -611,6 +620,15 @@ dependencies = [ "serde", ] +[[package]] +name = "instant" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" +dependencies = [ + "cfg-if", +] + [[package]] name = "io-lifetimes" version = "1.0.10" @@ -788,7 +806,7 @@ checksum = "9069cbb9f99e3a5083476ccb29ceb1de18b9118cafa53e90c9551235de2b9521" dependencies = [ "cfg-if", "libc", - "redox_syscall", + "redox_syscall 0.2.16", "smallvec", "windows-sys 0.45.0", ] @@ -858,6 +876,15 @@ dependencies = [ "bitflags", ] +[[package]] +name = "redox_syscall" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" +dependencies = [ + "bitflags", +] + [[package]] name = "redox_users" version = "0.4.3" @@ -865,7 +892,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" dependencies = [ "getrandom", - "redox_syscall", + "redox_syscall 0.2.16", "thiserror", ] @@ -881,6 +908,7 @@ dependencies = [ "serde", "serde_json", "tar", + "tempfile", "tokio", "tracing", "tracing-subscriber", @@ -1069,6 +1097,19 @@ dependencies = [ "xattr", ] +[[package]] +name = "tempfile" +version = "3.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9fbec84f381d5795b08656e4912bec604d162bff9291d6189a78f4c8ab87998" +dependencies = [ + "cfg-if", + "fastrand", + "redox_syscall 0.3.5", + "rustix", + "windows-sys 0.45.0", +] + [[package]] name = "termcolor" version = "1.2.0" diff --git a/Cargo.toml b/Cargo.toml index 798d0a3..8d5c5fd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,6 +16,7 @@ futures = "0.3.28" serde = "1.0.160" serde_json = "1.0.96" tar = "0.4.38" +tempfile = "3.5.0" tokio = { version = "1.28.0", features = ["full"] } tracing = "0.1.37" tracing-subscriber = "0.3.17" diff --git a/maskfile.md b/maskfile.md index c07bc2d..7a0bf0f 100644 --- a/maskfile.md +++ b/maskfile.md @@ -2,11 +2,12 @@ ## test-run -> builds the test docker image and runs +> builds the test docker image and runs dump ```sh image_name="reinlinsen-test" -rm -rf "$image_name"* +out_dir="$image_name-fs" +rm -rf "$out_dir" docker build -f test.Dockerfile -t "$image_name" . -cargo run -- --image "$image_name" dump +cargo run -- --image "$image_name" dump -o "$out_dir" ``` diff --git a/src/main.rs b/src/main.rs index 8606289..498acc8 100644 --- a/src/main.rs +++ b/src/main.rs @@ -9,6 +9,7 @@ use std::fs::{self, File}; use std::path::{Path, PathBuf}; use std::sync::Arc; use tar::Archive; +use tempfile::tempfile; use tokio::fs::OpenOptions; use tokio::io::AsyncWriteExt; use tokio::sync::Mutex; @@ -35,13 +36,16 @@ enum Commands { /// subcommands that operatate on single layers Layer { #[arg(long, short)] - layer: u8, + layer: usize, #[command(subcommand)] command: LayerCommands, }, /// full dump of all layers - Dump {}, + Dump { + #[arg(long, short)] + output: PathBuf, + }, /// extract a file from the full dump Extract {}, } @@ -65,28 +69,36 @@ enum LayerCommands { #[tokio::main] async fn main() -> Result<()> { tracing_subscriber::fmt().init(); - let cli = Cli::parse(); - - if !matches!(cli.command, Commands::Dump {}) { - todo!() - } + let cli = Cli::try_parse()?; + let tmp_dir = tempfile::tempdir()?; let base_name = name_from_image(&cli.image); - let tar_file = format!("{base_name}.tar"); - save_image(&cli.image, &tar_file).await?; - extract_tar(&tar_file, &base_name)?; - let manifest = read_manifest(&format!("{base_name}/manifest.json"))?; - let config = read_config(&format! {"{}/{}", base_name, manifest.config})?; - extract_layers(&manifest.layers, &base_name, &format!("{base_name}-fs"))?; + let archive_path = tmp_dir.path().join(format!("{base_name}.tar")); + save_image(&cli.image, &archive_path).await?; + + let unpack_path = tmp_dir.path().join(&base_name); + extract_tar(&archive_path, &unpack_path)?; + + let manifest_path = unpack_path.join("manifest.json"); + let manifest = read_manifest(&manifest_path)?; + + let config_path = unpack_path.join(manifest.config); + let config = read_config(&config_path)?; + + if let Commands::Dump { output } = cli.command { + extract_layers(&manifest.layers, &unpack_path, &output)?; + } else { + todo!() + } Ok(()) } #[instrument(skip(layers))] -fn extract_layers + Debug + Display>( +fn extract_layers + Debug>( layers: &[String], - tar_dir: P, + unpack_path: P, out_dir: P, ) -> Result<()> { _ = fs::remove_dir_all(&out_dir); @@ -94,7 +106,7 @@ fn extract_layers + Debug + Display>( for layer in layers { tracing::info!(layer, "unpacking layer"); - let file = File::open(format!("{tar_dir}/{layer}"))?; + let file = File::open(unpack_path.as_ref().join(&layer))?; let mut archive = Archive::new(file); for file in archive.entries()? { let mut f = file?; @@ -151,13 +163,13 @@ struct HistoryEntry { comment: String, } -fn read_config(path: &str) -> Result { +fn read_config + Debug>(path: P) -> Result { let config_str = fs::read_to_string(path)?; let config: Config = serde_json::from_str(&config_str)?; Ok(config) } -fn read_manifest(path: &str) -> Result { +fn read_manifest + Debug>(path: P) -> Result { let manifest_str = fs::read_to_string(path)?; let mut manifests: Vec = serde_json::from_str(&manifest_str)?; @@ -169,9 +181,9 @@ fn read_manifest(path: &str) -> Result { } #[instrument] -fn extract_tar + Debug>(path: P, out_dir: P) -> Result<()> { +fn extract_tar + Debug>(archive_path: P, out_dir: P) -> Result<()> { tracing::info!("recreating output dir"); - let file = File::open(path)?; + let file = File::open(archive_path)?; _ = fs::remove_dir_all(&out_dir); fs::create_dir(&out_dir)?;