Flesh out extract method for Stream
This commit is contained in:
parent
70e7846d3a
commit
f1ca04d706
12
Format.md
12
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) |
|
||||
|
@ -52,8 +52,10 @@ pub fn stream_archive<W: Write>(
|
||||
files: Vec<String>,
|
||||
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<W: Write + Send>(
|
||||
sender: &Sender<Message>,
|
||||
) -> 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::<u64, String>::new());
|
||||
let writer = Mutex::new(writer);
|
||||
let s = sender.clone();
|
||||
|
@ -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<R: Read + Send> {
|
||||
pub length: u32,
|
||||
reader: R,
|
||||
}
|
||||
|
||||
@ -48,10 +49,11 @@ pub enum Message {
|
||||
|
||||
impl<R: Read + Send> Stream<R> {
|
||||
pub fn new(mut reader: R) -> Result<Self, Error> {
|
||||
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<R: Read + Send> Stream<R> {
|
||||
) -> 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(())
|
||||
|
Loading…
Reference in New Issue
Block a user