From f1ca04d7064e813949d224bbac97dce79c14ac88 Mon Sep 17 00:00:00 2001 From: Nathan Fisher Date: Sat, 8 Jul 2023 00:39:52 -0400 Subject: [PATCH] Flesh out extract method for Stream --- Format.md | 12 +++++++++--- src/lib.rs | 6 +++++- src/stream.rs | 34 +++++++++++++++++++++++++++++----- 3 files changed, 43 insertions(+), 9 deletions(-) diff --git a/Format.md b/Format.md index fcb51f4..84feee5 100644 --- a/Format.md +++ b/Format.md @@ -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 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 -of the string "\x89haggis". To be clear, that is the integer `0x89` plus -"haggis". The first file header immediately follows this string. +of the string "\x89haggis". To be clear, that is the integer `0x89` plus "haggis". +The following four bytes store the number of nodes making up the archive. | **bytes** | **meaning** | | ----- | ------- | | 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 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) | diff --git a/src/lib.rs b/src/lib.rs index 41832aa..8fb6e94 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -52,8 +52,10 @@ pub fn stream_archive( files: Vec, algorithm: Algorithm, ) -> Result<(), Error> { - let links = Mutex::new(HashMap::new()); 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 { let node = Node::from_path(f, algorithm, &links)?; node.write(&mut writer)?; @@ -94,6 +96,8 @@ pub fn par_stream_archive( sender: &Sender, ) -> Result<(), Error> { writer.write_all(&MAGIC)?; + let len = u32::try_from(files.len())?; + writer.write_all(&len.to_le_bytes())?; let links = Mutex::new(HashMap::::new()); let writer = Mutex::new(writer); let s = sender.clone(); diff --git a/src/stream.rs b/src/stream.rs index 8a26769..bfc41ca 100644 --- a/src/stream.rs +++ b/src/stream.rs @@ -1,7 +1,7 @@ use crate::MAGIC; use { - crate::{Error, Node}, + crate::{Error, FileType, Node}, std::{ io::{ErrorKind, Read}, iter::Iterator, @@ -17,6 +17,7 @@ use { /// type which implements `Read`, such as a file or a network stream. #[derive(Debug)] pub struct Stream { + pub length: u32, reader: R, } @@ -48,10 +49,11 @@ pub enum Message { impl Stream { pub fn new(mut reader: R) -> Result { - let mut buf = [0; 7]; + let mut buf = [0; 11]; reader.read_exact(&mut buf)?; - if buf == MAGIC { - Ok(Self { reader }) + let length = u32::from_le_bytes(buf[7..].try_into()?); + if buf[0..7] == MAGIC { + Ok(Self { length ,reader }) } else { Err(Error::InvalidMagic) } @@ -72,7 +74,29 @@ impl Stream { ) -> Result<(), Error> { let s = sender.clone(); 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(())