Flesh out extract method for Stream

This commit is contained in:
Nathan Fisher 2023-07-08 00:39:52 -04:00
parent 70e7846d3a
commit f1ca04d706
3 changed files with 43 additions and 9 deletions

View File

@ -68,14 +68,20 @@ by 8, the third byte by 16 and the fourth byte by 24, and the bits combined
into a single 32-bit uint. This is dramatically more efficient than storing into a single 32-bit uint. This is dramatically more efficient than storing
those numbers as ascii text, as is done by Tar. those numbers as ascii text, as is done by Tar.
## The header
The first 7 bytes of a haggis file make up the "magic" identifier, consisting The first 7 bytes of a haggis file make up the "magic" identifier, consisting
of the string "\x89haggis". To be clear, that is the integer `0x89` plus of the string "\x89haggis". To be clear, that is the integer `0x89` plus "haggis".
"haggis". The first file header immediately follows this string. The following four bytes store the number of nodes making up the archive.
| **bytes** | **meaning** | | **bytes** | **meaning** |
| ----- | ------- | | ----- | ------- |
| 0-6 | "\x89haggis" - the haggis "magic" identifier | | 0-6 | "\x89haggis" - the haggis "magic" identifier |
| 7-15 | The **length** of the filename (64 bit unsigned int) | | 7-11 | The number of files in the archive (32 bit unsigned int) |
## Nodes
| **bytes** | **meaning** |
| ----- | ------- |
| the next 8 bytes | The **length** of the filename (64 bit unsigned int) |
| the next **length** bytes | The bytes making up the filename | | the next **length** bytes | The bytes making up the filename |
| the next 4 bytes | The files Unix permissions mode (32 bit unsigned int) | | the next 4 bytes | The files Unix permissions mode (32 bit unsigned int) |
| the next 4 bytes | The uid of the file's owner (32 bit unsigned int) | | the next 4 bytes | The uid of the file's owner (32 bit unsigned int) |

View File

@ -52,8 +52,10 @@ pub fn stream_archive<W: Write>(
files: Vec<String>, files: Vec<String>,
algorithm: Algorithm, algorithm: Algorithm,
) -> Result<(), Error> { ) -> Result<(), Error> {
let links = Mutex::new(HashMap::new());
writer.write_all(&MAGIC)?; writer.write_all(&MAGIC)?;
let len = u32::try_from(files.len())?;
writer.write_all(&len.to_le_bytes())?;
let links = Mutex::new(HashMap::new());
for f in &files { for f in &files {
let node = Node::from_path(f, algorithm, &links)?; let node = Node::from_path(f, algorithm, &links)?;
node.write(&mut writer)?; node.write(&mut writer)?;
@ -94,6 +96,8 @@ pub fn par_stream_archive<W: Write + Send>(
sender: &Sender<Message>, sender: &Sender<Message>,
) -> Result<(), Error> { ) -> Result<(), Error> {
writer.write_all(&MAGIC)?; writer.write_all(&MAGIC)?;
let len = u32::try_from(files.len())?;
writer.write_all(&len.to_le_bytes())?;
let links = Mutex::new(HashMap::<u64, String>::new()); let links = Mutex::new(HashMap::<u64, String>::new());
let writer = Mutex::new(writer); let writer = Mutex::new(writer);
let s = sender.clone(); let s = sender.clone();

View File

@ -1,7 +1,7 @@
use crate::MAGIC; use crate::MAGIC;
use { use {
crate::{Error, Node}, crate::{Error, FileType, Node},
std::{ std::{
io::{ErrorKind, Read}, io::{ErrorKind, Read},
iter::Iterator, iter::Iterator,
@ -17,6 +17,7 @@ use {
/// type which implements `Read`, such as a file or a network stream. /// type which implements `Read`, such as a file or a network stream.
#[derive(Debug)] #[derive(Debug)]
pub struct Stream<R: Read + Send> { pub struct Stream<R: Read + Send> {
pub length: u32,
reader: R, reader: R,
} }
@ -48,10 +49,11 @@ pub enum Message {
impl<R: Read + Send> Stream<R> { impl<R: Read + Send> Stream<R> {
pub fn new(mut reader: R) -> Result<Self, Error> { pub fn new(mut reader: R) -> Result<Self, Error> {
let mut buf = [0; 7]; let mut buf = [0; 11];
reader.read_exact(&mut buf)?; reader.read_exact(&mut buf)?;
if buf == MAGIC { let length = u32::from_le_bytes(buf[7..].try_into()?);
Ok(Self { reader }) if buf[0..7] == MAGIC {
Ok(Self { length ,reader })
} else { } else {
Err(Error::InvalidMagic) Err(Error::InvalidMagic)
} }
@ -72,7 +74,29 @@ impl<R: Read + Send> Stream<R> {
) -> Result<(), Error> { ) -> Result<(), Error> {
let s = sender.clone(); let s = sender.clone();
self.into_iter().par_bridge().try_for_each_with(s, |s, n| { self.into_iter().par_bridge().try_for_each_with(s, |s, n| {
n?.extract(prefix)?; let n = n?;
n.extract(prefix)?;
match n.filetype {
FileType::Normal(f) => {
s.send(Message::FileExtracted { name: n.name.clone(), size: f.len })
.map_err(|_| Error::SenderError)?;
},
FileType::SoftLink(t) | FileType::HardLink(t) => {
s.send(Message::LinkCreated { name: n.name.clone(), target: t.clone() })
.map_err(|_| Error::SenderError)?;
},
FileType::Directory => {
s.send(Message::DirectoryCreated { name: n.name.clone() })
.map_err(|_| Error::SenderError)?;
},
FileType::Block(_) | FileType::Character(_) | FileType::Fifo => {
s.send(Message::DeviceCreated { name: n.name.clone() })
.map_err(|_| Error::SenderError)?;
},
FileType::Eof => {
s.send(Message::Eof).map_err(|_| Error::SenderError)?;
},
}
Ok::<(), Error>(()) Ok::<(), Error>(())
})?; })?;
Ok(()) Ok(())