From ce7fe5f019815aaebf0111d9c52e27bcb35ce84d Mon Sep 17 00:00:00 2001 From: Nathan Fisher Date: Fri, 7 Jul 2023 19:20:21 -0400 Subject: [PATCH] Add "magic" to file start --- Format.md | 9 +++++++-- src/error.rs | 2 ++ src/lib.rs | 6 +++++- src/stream.rs | 26 ++++++++++++++++---------- 4 files changed, 30 insertions(+), 13 deletions(-) diff --git a/Format.md b/Format.md index 9e0fdc7..fcb51f4 100644 --- a/Format.md +++ b/Format.md @@ -68,10 +68,15 @@ 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 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. + | **bytes** | **meaning** | | ----- | ------- | -| 0-8 | The length of the filename (64 bit unsigned int) | -| 8 to the length specified above | The bytes making up the filename | +| 0-6 | "\x89haggis" - the haggis "magic" identifier | +| 7-15 | 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) | | the next 4 bytes | the gid of the file's owner (32 bit unsigned int) | diff --git a/src/error.rs b/src/error.rs index 64e2d71..f753cca 100644 --- a/src/error.rs +++ b/src/error.rs @@ -10,6 +10,7 @@ pub enum Error { Slice(TryFromSliceError), InvalidChecksum, InvalidAlgorithm, + InvalidMagic, MissingData, MutexError, NulError, @@ -28,6 +29,7 @@ impl fmt::Display for Error { Self::Io(e) => write!(f, "{e}"), Self::InvalidAlgorithm => write!(f, "invalid algorithm"), Self::InvalidChecksum => write!(f, "invalid checksum"), + Self::InvalidMagic => write!(f, "invalid magic"), Self::MissingData => write!(f, "missing data"), Self::MutexError => write!(f, "mutex error"), Self::NulError => write!(f, "nul error"), diff --git a/src/lib.rs b/src/lib.rs index 790b2a1..9b6f934 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -30,6 +30,8 @@ pub use { stream::Stream, }; +pub static MAGIC: [u8; 7] = [0x89, b'h', b'a', b'g', b'g', b'i', b's' ]; + /// Creates a haggis archive from a list of files pub fn create_archive(path: &str, files: Vec, algorithm: Algorithm) -> Result<(), Error> { let fd = fs::OpenOptions::new() @@ -48,6 +50,7 @@ pub fn stream_archive( algorithm: Algorithm, ) -> Result<(), Error> { let links = Mutex::new(HashMap::new()); + writer.write_all(&MAGIC)?; for f in &files { let node = Node::from_path(f, algorithm, &links)?; node.write(&mut writer)?; @@ -82,11 +85,12 @@ pub fn par_create_archive( /// Streams a Haggis archive from a list of files, processing each file in parallel #[cfg(feature = "parallel")] pub fn par_stream_archive( - writer: W, + mut writer: W, files: Vec, algorithm: Algorithm, sender: &Sender, ) -> Result<(), Error> { + writer.write_all(&MAGIC)?; 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 e8f95d1..8a26769 100644 --- a/src/stream.rs +++ b/src/stream.rs @@ -1,3 +1,5 @@ +use crate::MAGIC; + use { crate::{Error, Node}, std::{ @@ -14,17 +16,11 @@ use { /// An iterator over a series of archive `Node`'s. This struct is generic over any /// type which implements `Read`, such as a file or a network stream. #[derive(Debug)] -pub struct Stream { - reader: T, +pub struct Stream { + reader: R, } -impl From for Stream { - fn from(value: T) -> Self { - Self { reader: value } - } -} - -impl Iterator for Stream { +impl Iterator for Stream { type Item = Result; fn next(&mut self) -> Option { @@ -50,7 +46,17 @@ pub enum Message { Eof, } -impl Stream { +impl Stream { + pub fn new(mut reader: R) -> Result { + let mut buf = [0; 7]; + reader.read_exact(&mut buf)?; + if buf == MAGIC { + Ok(Self { reader }) + } else { + Err(Error::InvalidMagic) + } + } + pub fn extract(&mut self, prefix: Option<&str>) -> Result<(), Error> { for node in self { node?.extract(prefix)?;