Add `Archive` struct to `tar`

This commit is contained in:
Nathan Fisher 2023-03-23 13:14:17 -04:00
parent a53cb726f9
commit 405ffd194f
2 changed files with 110 additions and 5 deletions

View File

@ -1,3 +1,5 @@
use std::{fs::File, io::{self, BufReader}};
mod error;
mod header;
mod node;
@ -10,3 +12,110 @@ pub use {
pub struct Archive {
pub nodes: Vec<Node>,
}
impl Archive {
/// Write out a vector of `TarNodes` to a file or something that implements ``std::io::Write`` and ``std::io::Copy``.
///
/// # Example
///
/// ```
/// use std::fs::File;
/// use tar::tar::TarFile;
///
/// let data = Archive::new("test/1.txt".to_string()).unwrap();
///
/// let out = File::create("test/2.tar".to_string()).unwrap();
/// data.write(&out).unwrap();
/// ```
pub fn write<T: io::Write + Copy>(self, mut input: T) -> Result<usize, Error> {
let mut written = 0;
for f in self.nodes.clone() {
written += f.write(input)?;
}
/* Complete the write with 18 blocks of 512 ``0x00`` bytes per the specification */
if !self.nodes.is_empty() {
input.write_all(&[0; 9216])?;
written += 9216;
}
Ok(written)
}
/// Create a new `TarFile` struct and initialize it with a `filename` file. This will read in the file to
/// the `TarFile` struct as a `TarNode`.
///
/// # Example
///
/// ```
/// use tar::Archive;
///
/// let data = Archive::new("test/1.txt".to_string()).unwrap();
/// ```
pub fn new(filename: String) -> Result<Self, Error> {
Ok(Self {
nodes: vec![Node::read_file_to_tar(filename)?],
})
}
/// Append another file to the `TarFile.file` vector. This adds a file to the internal representation of the tar file.
///
/// # Example
///
/// ```
/// use tar::Archive;
///
/// let mut data = Archive::new("test/1.txt".to_string()).unwrap();
/// data.append("test/1.txt".to_string()).unwrap();
/// ```
pub fn append(&mut self, filename: String) -> Result<(), Error> {
self.nodes.push(Node::read_file_to_tar(filename)?);
Ok(())
}
/// Open and load an external tar file into the internal `TarFile` struct. This parses and loads up all the files
/// contained within the external tar file.
///
/// # Example
///
/// ```
/// use tar::Archive;
///
/// Archive::open("test/1.tar".to_string()).unwrap();
/// ```
pub fn open(filename: String) -> Result<Self, Error> {
let file = File::open(&filename)?;
let mut reader = BufReader::new(file);
let mut out = Self {
nodes: Vec::<Node>::new(),
};
while let Ok(t) = Node::read(&mut reader) {
out.nodes.push(t);
}
Ok(out)
}
/// Remove the first file from the Tar that matches the filename and path.
///
/// # Example
///
/// ```
/// use minitar::tar::TarFile;
///
/// let mut data = TarFile::new("test/1.tar".to_string()).unwrap();
/// data.remove("test/1.tar".to_string()).unwrap();
/// ```
pub fn remove(&mut self, filename: String) -> Result<bool, Error> {
let mut name = [0u8; 100];
name[..filename.len()].copy_from_slice(filename.as_bytes());
if let Some(i) = &self.nodes.iter().position(|x| x.header.fname == name) {
self.nodes.remove(*i);
return Ok(true);
}
Ok(false)
}
}

View File

@ -67,11 +67,7 @@ impl Node {
}
/// Create a Node from in memory data, given the filename and metadata
pub fn read_data_to_tar(
data: &[u8],
filename: &str,
meta: &Metadata,
) -> Result<Node, Error> {
pub fn read_data_to_tar(data: &[u8], filename: &str, meta: &Metadata) -> Result<Node, Error> {
let header = Header::new_from_meta(filename, meta)?;
if header.link_indicator[0] != FileType::Normal as u8 {
return Ok(Node {