Working with Tarballs - Rust Cookbook (original) (raw)
Rust Cookbook
Working with Tarballs
Decompress a tarball
Decompress (GzDecoder) and extract (Archive::unpack) all files from a compressed tarball named archive.tar.gz
located in the current working directory to the same location.
use std::fs::File;
use flate2::read::GzDecoder;
use tar::Archive;
fn main() -> Result<(), std::io::Error> {
let path = "archive.tar.gz";
let tar_gz = File::open(path)?;
let tar = GzDecoder::new(tar_gz);
let mut archive = Archive::new(tar);
archive.unpack(".")?;
Ok(())
}
Compress a directory into tarball
Compress /var/log
directory into archive.tar.gz
.
Creates a File wrapped in GzEncoderand tar::Builder.
Adds contents of /var/log
directory recursively into the archive under backup/logs
path with Builder::append_dir_all.GzEncoder is responsible for transparently compressing the data prior to writing it into archive.tar.gz
.
use std::fs::File;
use flate2::Compression;
use flate2::write::GzEncoder;
fn main() -> Result<(), std::io::Error> {
let tar_gz = File::create("archive.tar.gz")?;
let enc = GzEncoder::new(tar_gz, Compression::default());
let mut tar = tar::Builder::new(enc);
tar.append_dir_all("backup/logs", "/var/log")?;
tar.finish()?;
Ok(())
}
To add the contents without renaming them, an empty string can be used as the first argument of Builder::append_dir_all:
use std::fs::File;
use flate2::Compression;
use flate2::write::GzEncoder;
fn main() -> Result<(), std::io::Error> {
let tar_gz = File::create("archive.tar.gz")?;
let enc = GzEncoder::new(tar_gz, Compression::default());
let mut tar = tar::Builder::new(enc);
tar.append_dir_all("", "/var/log")?;
tar.finish()?;
Ok(())
}
The default behavior of tar::Builder differs from the GNU tar
utility's defaults tar(1), notably tar::Builder::follow_symlinks(true) is the equivalent of tar --dereference
.
Decompress a tarball while removing a prefix from the paths
Iterate over the Archive::entries. Use Path::strip_prefix to remove the specified path prefix (bundle/logs
). Finally, extract the tar::Entryvia Entry::unpack.
use error_chain::error_chain;
use std::fs::File;
use std::path::PathBuf;
use flate2::read::GzDecoder;
use tar::Archive;
error_chain! {
foreign_links {
Io(std::io::Error);
StripPrefixError(::std::path::StripPrefixError);
}
}
fn main() -> Result<(), std::io::Error> {
let file = File::open("archive.tar.gz")?;
let mut archive = Archive::new(GzDecoder::new(file));
let prefix = "bundle/logs";
println!("Extracted the following files:");
archive
.entries()?
.filter_map(|e| e.ok())
.map(|mut entry| -> Result<PathBuf, Box<dyn std::error::Error>> {
let path = entry.path()?.strip_prefix(prefix)?.to_owned();
entry.unpack(&path)?;
Ok(path)
})
.filter_map(|e| e.ok())
.for_each(|x| println!("> {}", x.display()));
Ok(())
}