From 85e55dc456787346b16bddb3f3f729e69f33763d Mon Sep 17 00:00:00 2001 From: Nathan Fisher Date: Sun, 2 Jul 2023 01:32:34 -0400 Subject: [PATCH] Add `Node` structure --- src/lib.rs | 123 +++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 100 insertions(+), 23 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 453ed02..10d62d2 100644 --- a/src/lib.rs +++ b/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)] pub enum Error { @@ -6,6 +12,8 @@ pub enum Error { Io(io::Error), Utf8(FromUtf8Error), Slice(TryFromSliceError), + MissingData, + UnexpectedData, UnknownFileType, } @@ -16,6 +24,8 @@ impl fmt::Display for Error { Self::Utf8(e) => write!(f, "{e}"), Self::Slice(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"), } } @@ -100,34 +110,34 @@ impl FileType { match buf[0] { 0 => Ok(Self::Normal), 1 => { - let mut l = [0; 8]; - reader.read_exact(&mut l)?; - let len = u64::from_le_bytes(l); + let mut len = [0; 8]; + reader.read_exact(&mut len)?; + let len = u64::from_le_bytes(len); let mut buf = Vec::with_capacity(len.try_into()?); let mut handle = reader.take(len); - handle.read(&mut buf)?; + handle.read_exact(&mut buf)?; let s = String::from_utf8(buf)?; Ok(Self::HardLink(s)) - }, + } 2 => { - let mut l = [0; 8]; - reader.read_exact(&mut l)?; - let len = u64::from_le_bytes(l); + let mut len = [0; 8]; + reader.read_exact(&mut len)?; + let len = u64::from_le_bytes(len); let mut buf = Vec::with_capacity(len.try_into()?); let mut handle = reader.take(len); - handle.read(&mut buf)?; + handle.read_exact(&mut buf)?; let s = String::from_utf8(buf)?; Ok(Self::SoftLink(s)) - }, + } 3 => Ok(Self::Directory), 4 => { let sp = Special::read(reader)?; Ok(Self::Character(sp)) - }, + } 5 => { let sp = Special::read(reader)?; Ok(Self::Block(sp)) - }, + } 6 => Ok(Self::Fifo), _ => Err(Error::UnknownFileType), } @@ -141,22 +151,22 @@ impl FileType { let len = s.len() as u64; writer.write_all(&len.to_le_bytes())?; writer.write_all(s.as_bytes())?; - }, + } Self::SoftLink(s) => { writer.write_all(&[2])?; let len = s.len() as u64; writer.write_all(&len.to_le_bytes())?; writer.write_all(s.as_bytes())?; - }, + } Self::Directory => writer.write_all(&[3])?, Self::Character(s) => { writer.write_all(&[4])?; s.write(writer)?; - }, + } Self::Block(s) => { writer.write_all(&[5])?; s.write(writer)?; - }, + } Self::Fifo => writer.write_all(&[6])?, } Ok(()) @@ -175,17 +185,84 @@ pub struct Header { } impl Header { + pub fn read(reader: &mut T) -> Result { + 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(&self, writer: &mut T) -> Result<(), Error> { let len = self.name.len() as u64; writer.write_all(&len.to_le_bytes())?; writer.write_all(self.name.as_bytes())?; self.filetype.write(writer)?; - [self.mode, self.uid, self.gid].iter().try_for_each(|f| { - writer.write_all(&f.to_le_bytes()) - })?; - [self.size, self.mtime].iter().try_for_each(|f| { - writer.write_all(&f.to_le_bytes()) - })?; + [self.mode, self.uid, self.gid] + .iter() + .try_for_each(|f| writer.write_all(&f.to_le_bytes()))?; + [self.size, self.mtime] + .iter() + .try_for_each(|f| writer.write_all(&f.to_le_bytes()))?; + Ok(()) + } +} + +#[derive(Debug)] +pub struct Node { + pub header: Header, + pub data: Option>, +} + +impl Node { + pub fn read(reader: &mut T) -> Result { + 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(&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(()) } }