Skip to content

Commit

Permalink
Implementation of a PAX header writer
Browse files Browse the repository at this point in the history
This crate currently supports reading the PAX headers. This adds a way to write
some PAX headers in a Builder.
Also implemented tests to showcase usage
  • Loading branch information
gwitrand-ovh committed Oct 22, 2024
1 parent 97d5033 commit 3c86863
Show file tree
Hide file tree
Showing 3 changed files with 82 additions and 3 deletions.
46 changes: 46 additions & 0 deletions src/pax.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#![allow(dead_code)]
use std::io;
use std::io::Write;
use std::slice;
use std::str;

Expand Down Expand Up @@ -145,3 +146,48 @@ impl<'entry> PaxExtension<'entry> {
self.value
}
}

/// Extension trait for `Builder` to append PAX extended headers.
impl<T: Write> crate::Builder<T> {
/// Append PAX extended headers to the archive.
///
/// Takes in an iterator over the list of headers to add to convert it into a header set formatted.
///
/// Returns io::Error if an error occurs, else it returns ()
pub fn append_pax_extensions<'a>(
&mut self,
headers: impl IntoIterator<Item = (String, String)>,
) -> Result<(), io::Error> {
// Store the headers formatted before write
let mut data: Vec<u8> = Vec::new();

// For each key in headers, convert into a sized space and add it to data.
// This will then be written in the file
for (key, value) in headers {
let mut len_len = 1;
let mut max_len = 10;
let rest_len = 3 + key.len() + value.len();
while rest_len + len_len >= max_len {
len_len += 1;
max_len *= 10;
}
let len = rest_len + len_len;
write!(&mut data, "{} {}={}\n", len, key, value)?;
}

// Ignore the header append if it's empty.
if data.is_empty() {
return Ok(());
}

// Create a header of type XHeader, set the size to the length of the
// data, set the entry type to XHeader, and set the checksum
// then append the header and the data to the archive.
let mut header = crate::Header::new_ustar();
let data_as_bytes: &[u8] = &data;
header.set_size(data_as_bytes.len() as u64);
header.set_entry_type(crate::EntryType::XHeader);
header.set_cksum();
self.append(&header, data_as_bytes)
}
}
36 changes: 34 additions & 2 deletions tests/all.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@ extern crate xattr;

use std::fs::{self, File};
use std::io::prelude::*;
use std::io::{self, Cursor};
use std::io::{self, BufWriter, Cursor};
use std::iter::repeat;
use std::path::{Path, PathBuf};

use filetime::FileTime;
use tar::{Archive, Builder, Entries, EntryType, Header, HeaderMode};
use tar::{Archive, Builder, Entries, Entry, EntryType, Header, HeaderMode};
use tempfile::{Builder as TempBuilder, TempDir};

macro_rules! t {
Expand Down Expand Up @@ -925,6 +925,38 @@ fn pax_simple() {
assert_eq!(third.value(), Ok("1453146164.953123768"));
}

#[test]
fn pax_simple_write() {
let td = t!(TempBuilder::new().prefix("tar-rs").tempdir());
let pax_path = td.path().join("pax.tar");
let file: File = t!(File::create(&pax_path));
let mut ar: Builder<BufWriter<File>> = Builder::new(BufWriter::new(file));

let mut pax_builder: Vec<(String, String)> = Vec::new();
let key: String = "arbitrary_pax_key".to_string();
let value: String = "arbitrary_pax_value".to_string();
pax_builder.push((key, value));

t!(ar.append_pax_extensions(pax_builder.into_iter()));
t!(ar.append_file("test2", &mut t!(File::open(&pax_path))));
t!(ar.finish());
drop(ar);

let mut archive_opened = Archive::new(t!(File::open(pax_path)));
let mut entries = t!(archive_opened.entries());
let mut f: Entry<File> = t!(entries.next().unwrap());
let pax_headers = t!(f.pax_extensions());

assert!(pax_headers.is_some(), "pax_headers is None");
let mut pax_headers = pax_headers.unwrap();
let pax_arbitrary = t!(pax_headers.next().unwrap());

assert_eq!(pax_arbitrary.key(), Ok("arbitrary_pax_key"));
assert_eq!(pax_arbitrary.value(), Ok("arbitrary_pax_value"));

assert!(entries.next().is_none());
}

#[test]
fn pax_path() {
let mut ar = Archive::new(tar!("pax2.tar"));
Expand Down
3 changes: 2 additions & 1 deletion tests/entry.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
extern crate tar;
extern crate tempfile;

use std::fs::{create_dir, File};
use std::fs::create_dir;
use std::fs::File;
use std::io::Read;

use tempfile::Builder;
Expand Down

0 comments on commit 3c86863

Please sign in to comment.