Created
July 25, 2025 20:07
-
-
Save cgwalters/f9e9afcc8d94572554184c3b2d5b054e to your computer and use it in GitHub Desktop.
tar metadump
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//! Given an input tarball on stdin, output a copy of it where all regular | |
//! file data is empty. This is a bit like how e.g. XFS supports "metadump". | |
use std::io::{stdin, stdout}; | |
use clap::Parser; | |
use color_eyre::eyre::eyre; | |
use color_eyre::{eyre::Report, Result}; | |
#[derive(Parser, Debug)] | |
#[clap(author, version, about)] | |
struct Args {} | |
/// Copy a tar entry to a new tar archive, optionally using a different filesystem path. | |
pub(crate) fn copy_entry( | |
mut entry: tar::Entry<impl std::io::Read>, | |
dest: &mut tar::Builder<impl std::io::Write>, | |
) -> Result<()> { | |
// Make copies of both the header and path, since that's required for the append APIs | |
let path = (*entry.path()?).to_owned(); | |
let mut header = entry.header().clone(); | |
if let Some(headers) = entry.pax_extensions()? { | |
let extensions = headers | |
.map(|ext| { | |
let ext = ext?; | |
Ok((ext.key()?, ext.value_bytes())) | |
}) | |
.collect::<Result<Vec<_>>>()?; | |
dest.append_pax_extensions(extensions.as_slice().iter().copied())?; | |
} | |
// Need to use the entry.link_name() not the header.link_name() | |
// api as the header api does not handle long paths: | |
// https://github.com/alexcrichton/tar-rs/issues/192 | |
match entry.header().entry_type() { | |
tar::EntryType::Symlink => { | |
let target = entry.link_name()?.ok_or_else(|| eyre!("Invalid link"))?; | |
dest.append_link(&mut header, path, target) | |
} | |
tar::EntryType::Link => { | |
let target = entry.link_name()?.ok_or_else(|| eyre!("Invalid link"))?; | |
dest.append_link(&mut header, path, target) | |
} | |
_ => { | |
header.set_size(0); | |
dest.append_data(&mut header, path, std::io::empty()) | |
} | |
} | |
.map_err(Into::into) | |
} | |
#[tokio::main] | |
async fn main() -> Result<(), Report> { | |
color_eyre::install()?; | |
let _args = Args::parse(); | |
let mut i = tar::Archive::new(stdin().lock()); | |
let mut o = tar::Builder::new(stdout().lock()); | |
for entry in i.entries()? { | |
copy_entry(entry?, &mut o)?; | |
} | |
Ok(()) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment