Add Node
structure
This commit is contained in:
parent
8386ca76d3
commit
85e55dc456
123
src/lib.rs
123
src/lib.rs
@ -1,4 +1,10 @@
|
|||||||
use std::{string::FromUtf8Error, array::TryFromSliceError, fmt, io::{Write, self, Read}, num::TryFromIntError};
|
use std::{
|
||||||
|
array::TryFromSliceError,
|
||||||
|
fmt,
|
||||||
|
io::{self, Read, Write},
|
||||||
|
num::TryFromIntError,
|
||||||
|
string::FromUtf8Error,
|
||||||
|
};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
@ -6,6 +12,8 @@ pub enum Error {
|
|||||||
Io(io::Error),
|
Io(io::Error),
|
||||||
Utf8(FromUtf8Error),
|
Utf8(FromUtf8Error),
|
||||||
Slice(TryFromSliceError),
|
Slice(TryFromSliceError),
|
||||||
|
MissingData,
|
||||||
|
UnexpectedData,
|
||||||
UnknownFileType,
|
UnknownFileType,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -16,6 +24,8 @@ impl fmt::Display for Error {
|
|||||||
Self::Utf8(e) => write!(f, "{e}"),
|
Self::Utf8(e) => write!(f, "{e}"),
|
||||||
Self::Slice(e) => write!(f, "{e}"),
|
Self::Slice(e) => write!(f, "{e}"),
|
||||||
Self::Io(e) => write!(f, "{e}"),
|
Self::Io(e) => write!(f, "{e}"),
|
||||||
|
Self::MissingData => write!(f, "missing data"),
|
||||||
|
Self::UnexpectedData => write!(f, "unexpected data"),
|
||||||
Self::UnknownFileType => write!(f, "unknown file type"),
|
Self::UnknownFileType => write!(f, "unknown file type"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -100,34 +110,34 @@ impl FileType {
|
|||||||
match buf[0] {
|
match buf[0] {
|
||||||
0 => Ok(Self::Normal),
|
0 => Ok(Self::Normal),
|
||||||
1 => {
|
1 => {
|
||||||
let mut l = [0; 8];
|
let mut len = [0; 8];
|
||||||
reader.read_exact(&mut l)?;
|
reader.read_exact(&mut len)?;
|
||||||
let len = u64::from_le_bytes(l);
|
let len = u64::from_le_bytes(len);
|
||||||
let mut buf = Vec::with_capacity(len.try_into()?);
|
let mut buf = Vec::with_capacity(len.try_into()?);
|
||||||
let mut handle = reader.take(len);
|
let mut handle = reader.take(len);
|
||||||
handle.read(&mut buf)?;
|
handle.read_exact(&mut buf)?;
|
||||||
let s = String::from_utf8(buf)?;
|
let s = String::from_utf8(buf)?;
|
||||||
Ok(Self::HardLink(s))
|
Ok(Self::HardLink(s))
|
||||||
},
|
}
|
||||||
2 => {
|
2 => {
|
||||||
let mut l = [0; 8];
|
let mut len = [0; 8];
|
||||||
reader.read_exact(&mut l)?;
|
reader.read_exact(&mut len)?;
|
||||||
let len = u64::from_le_bytes(l);
|
let len = u64::from_le_bytes(len);
|
||||||
let mut buf = Vec::with_capacity(len.try_into()?);
|
let mut buf = Vec::with_capacity(len.try_into()?);
|
||||||
let mut handle = reader.take(len);
|
let mut handle = reader.take(len);
|
||||||
handle.read(&mut buf)?;
|
handle.read_exact(&mut buf)?;
|
||||||
let s = String::from_utf8(buf)?;
|
let s = String::from_utf8(buf)?;
|
||||||
Ok(Self::SoftLink(s))
|
Ok(Self::SoftLink(s))
|
||||||
},
|
}
|
||||||
3 => Ok(Self::Directory),
|
3 => Ok(Self::Directory),
|
||||||
4 => {
|
4 => {
|
||||||
let sp = Special::read(reader)?;
|
let sp = Special::read(reader)?;
|
||||||
Ok(Self::Character(sp))
|
Ok(Self::Character(sp))
|
||||||
},
|
}
|
||||||
5 => {
|
5 => {
|
||||||
let sp = Special::read(reader)?;
|
let sp = Special::read(reader)?;
|
||||||
Ok(Self::Block(sp))
|
Ok(Self::Block(sp))
|
||||||
},
|
}
|
||||||
6 => Ok(Self::Fifo),
|
6 => Ok(Self::Fifo),
|
||||||
_ => Err(Error::UnknownFileType),
|
_ => Err(Error::UnknownFileType),
|
||||||
}
|
}
|
||||||
@ -141,22 +151,22 @@ impl FileType {
|
|||||||
let len = s.len() as u64;
|
let len = s.len() as u64;
|
||||||
writer.write_all(&len.to_le_bytes())?;
|
writer.write_all(&len.to_le_bytes())?;
|
||||||
writer.write_all(s.as_bytes())?;
|
writer.write_all(s.as_bytes())?;
|
||||||
},
|
}
|
||||||
Self::SoftLink(s) => {
|
Self::SoftLink(s) => {
|
||||||
writer.write_all(&[2])?;
|
writer.write_all(&[2])?;
|
||||||
let len = s.len() as u64;
|
let len = s.len() as u64;
|
||||||
writer.write_all(&len.to_le_bytes())?;
|
writer.write_all(&len.to_le_bytes())?;
|
||||||
writer.write_all(s.as_bytes())?;
|
writer.write_all(s.as_bytes())?;
|
||||||
},
|
}
|
||||||
Self::Directory => writer.write_all(&[3])?,
|
Self::Directory => writer.write_all(&[3])?,
|
||||||
Self::Character(s) => {
|
Self::Character(s) => {
|
||||||
writer.write_all(&[4])?;
|
writer.write_all(&[4])?;
|
||||||
s.write(writer)?;
|
s.write(writer)?;
|
||||||
},
|
}
|
||||||
Self::Block(s) => {
|
Self::Block(s) => {
|
||||||
writer.write_all(&[5])?;
|
writer.write_all(&[5])?;
|
||||||
s.write(writer)?;
|
s.write(writer)?;
|
||||||
},
|
}
|
||||||
Self::Fifo => writer.write_all(&[6])?,
|
Self::Fifo => writer.write_all(&[6])?,
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -175,17 +185,84 @@ pub struct Header {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Header {
|
impl Header {
|
||||||
|
pub fn read<T: Read>(reader: &mut T) -> Result<Self, Error> {
|
||||||
|
let mut len = [0; 8];
|
||||||
|
reader.read_exact(&mut len)?;
|
||||||
|
let len = u64::from_le_bytes(len);
|
||||||
|
let mut name = Vec::with_capacity(len.try_into()?);
|
||||||
|
let mut handle = reader.take(len);
|
||||||
|
handle.read_exact(&mut name)?;
|
||||||
|
let filetype = FileType::read(reader)?;
|
||||||
|
let mut buf = [0; 28];
|
||||||
|
reader.read_exact(&mut buf)?;
|
||||||
|
let mode: [u8; 4] = buf[..4].try_into()?;
|
||||||
|
let uid: [u8; 4] = buf[4..8].try_into()?;
|
||||||
|
let gid: [u8; 4] = buf[8..12].try_into()?;
|
||||||
|
let size: [u8; 8] = buf[12..20].try_into()?;
|
||||||
|
let mtime: [u8; 8] = buf[20..].try_into()?;
|
||||||
|
Ok(Self {
|
||||||
|
name: String::from_utf8(name)?,
|
||||||
|
filetype,
|
||||||
|
mode: u32::from_le_bytes(mode),
|
||||||
|
uid: u32::from_le_bytes(uid),
|
||||||
|
gid: u32::from_le_bytes(gid),
|
||||||
|
size: u64::from_le_bytes(size),
|
||||||
|
mtime: u64::from_le_bytes(mtime),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
pub fn write<T: Write>(&self, writer: &mut T) -> Result<(), Error> {
|
pub fn write<T: Write>(&self, writer: &mut T) -> Result<(), Error> {
|
||||||
let len = self.name.len() as u64;
|
let len = self.name.len() as u64;
|
||||||
writer.write_all(&len.to_le_bytes())?;
|
writer.write_all(&len.to_le_bytes())?;
|
||||||
writer.write_all(self.name.as_bytes())?;
|
writer.write_all(self.name.as_bytes())?;
|
||||||
self.filetype.write(writer)?;
|
self.filetype.write(writer)?;
|
||||||
[self.mode, self.uid, self.gid].iter().try_for_each(|f| {
|
[self.mode, self.uid, self.gid]
|
||||||
writer.write_all(&f.to_le_bytes())
|
.iter()
|
||||||
})?;
|
.try_for_each(|f| writer.write_all(&f.to_le_bytes()))?;
|
||||||
[self.size, self.mtime].iter().try_for_each(|f| {
|
[self.size, self.mtime]
|
||||||
writer.write_all(&f.to_le_bytes())
|
.iter()
|
||||||
})?;
|
.try_for_each(|f| writer.write_all(&f.to_le_bytes()))?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Node {
|
||||||
|
pub header: Header,
|
||||||
|
pub data: Option<Vec<u8>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Node {
|
||||||
|
pub fn read<T: Read>(reader: &mut T) -> Result<Self, Error> {
|
||||||
|
let header = Header::read(reader)?;
|
||||||
|
let data = match header.filetype {
|
||||||
|
FileType::Normal => {
|
||||||
|
let mut data = Vec::with_capacity(header.size.try_into()?);
|
||||||
|
let mut handle = reader.take(header.size);
|
||||||
|
handle.read_exact(&mut data)?;
|
||||||
|
Some(data)
|
||||||
|
}
|
||||||
|
_ => None,
|
||||||
|
};
|
||||||
|
Ok(Self { header, data })
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn write<T: Write>(&self, writer: &mut T) -> Result<(), Error> {
|
||||||
|
self.header.write(writer)?;
|
||||||
|
match self.header.filetype {
|
||||||
|
FileType::Normal => {
|
||||||
|
if let Some(ref data) = self.data {
|
||||||
|
writer.write_all(data)?;
|
||||||
|
} else {
|
||||||
|
return Err(Error::MissingData);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_ => {
|
||||||
|
if self.data.is_some() {
|
||||||
|
return Err(Error::UnexpectedData);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user