Working with Tarballs

Decompress a tarball

flate2 tar cat-compression

Decompress (flate2::read::GzDecoder⮳) and extract (tar::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;

pub fn main() -> Result<(), std::io::Error> {
    let path = "temp/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 a tarball

flate2 tar cat-compression

Compress /var/log directory into archive.tar.gz.

Creates a std::fs::File⮳ wrapped in flate2::write::GzEncoder⮳ and tar::Builder

Adds contents of /var/log directory recursively into the archive under backup/logspath with tar::Builder::append_dir_all⮳. flate2::write::GzEncoder⮳ is responsible for transparently compressing the data prior to writing it into archive.tar.gz.


use std::fs::create_dir;
use std::fs::exists;
use std::fs::File;

use flate2::write::GzEncoder;
use flate2::Compression;

pub fn main() -> Result<(), std::io::Error> {
    // Create a temporary folder
    if !exists("temp")? {
        create_dir("temp")?;
    }
    // Create the archive file
    let tar_gz_file = File::create("temp/archive.tar.gz")?;
    // Create the compression encoder
    let enc = GzEncoder::new(tar_gz_file, Compression::default());
    // Create a new archive builder with the underlying file as the
    // destination of all data written.
    let mut tar = tar::Builder::new(enc);
    // Archive the /var/log directory and all of its contents
    // (recursively), renaming it in the process
    tar.append_dir_all("temp/backup/var/log", "/var/log")?;
    Ok(())
}

Decompress a tarball while removing a prefix from the paths

flate2 tar cat-compression

Iterate over the tar::Archive::entries⮳. Use std::path::Path::strip_prefix⮳ to remove the specified path prefix (bundle/logs). Finally, extract the tar::Entry⮳ via tar::Entry::unpack⮳.

use std::fs::File;
use std::path::PathBuf;

use anyhow::Result;
use flate2::read::GzDecoder;
use tar::Archive;

pub fn main() -> Result<()> {
    let file = File::open("temp/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> {
            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(())
}