Refactor into separate modules

This commit is contained in:
Nathan Fisher 2023-07-04 00:51:47 -04:00
parent 162e027365
commit 82ede31688
7 changed files with 516 additions and 489 deletions

56
src/checksum.rs Normal file
View File

@ -0,0 +1,56 @@
use {
crate::Error,
std::io::{Read, Write},
};
#[derive(Debug)]
pub enum Checksum {
Md5([u8; 16]),
Sha1([u8; 20]),
Sha256([u8; 32]),
Skip,
}
impl Checksum {
pub fn read<T: Read>(reader: &mut T) -> Result<Self, Error> {
let mut buf = [0; 1];
reader.read_exact(&mut buf)?;
match buf[0] {
0 => {
let mut sum = [0; 16];
reader.read_exact(&mut sum)?;
Ok(Self::Md5(sum))
}
1 => {
let mut sum = [0; 20];
reader.read_exact(&mut sum)?;
Ok(Self::Sha1(sum))
}
2 => {
let mut sum = [0; 32];
reader.read_exact(&mut sum)?;
Ok(Self::Sha256(sum))
}
_ => Ok(Self::Skip),
}
}
pub fn write<T: Write>(&self, writer: &mut T) -> Result<(), Error> {
match self {
Self::Md5(sum) => {
writer.write_all(&[b'0'])?;
writer.write_all(&sum[..])?;
}
Self::Sha1(sum) => {
writer.write_all(&[b'1'])?;
writer.write_all(&sum[..])?;
}
Self::Sha256(sum) => {
writer.write_all(&[b'2'])?;
writer.write_all(&sum[..])?;
}
Self::Skip => writer.write_all(&[b'3'])?,
}
Ok(())
}
}

66
src/error.rs Normal file
View File

@ -0,0 +1,66 @@
use std::{array::TryFromSliceError, fmt, io, num::TryFromIntError, string::FromUtf8Error};
#[derive(Debug)]
pub enum Error {
Int(TryFromIntError),
Io(io::Error),
Utf8(FromUtf8Error),
Slice(TryFromSliceError),
InvalidChecksum,
MissingData,
UnexpectedData,
UnknownFileType,
Other(String),
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Int(e) => write!(f, "{e}"),
Self::Utf8(e) => write!(f, "{e}"),
Self::Slice(e) => write!(f, "{e}"),
Self::Io(e) => write!(f, "{e}"),
Self::InvalidChecksum => write!(f, "invalid checksum"),
Self::MissingData => write!(f, "missing data"),
Self::UnexpectedData => write!(f, "unexpected data"),
Self::UnknownFileType => write!(f, "unknown file type"),
Self::Other(s) => write!(f, "{s}"),
}
}
}
impl std::error::Error for Error {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match self {
Self::Int(e) => Some(e),
Self::Io(e) => Some(e),
Self::Utf8(e) => Some(e),
Self::Slice(e) => Some(e),
_ => None,
}
}
}
impl From<TryFromIntError> for Error {
fn from(value: TryFromIntError) -> Self {
Self::Int(value)
}
}
impl From<io::Error> for Error {
fn from(value: io::Error) -> Self {
Self::Io(value)
}
}
impl From<FromUtf8Error> for Error {
fn from(value: FromUtf8Error) -> Self {
Self::Utf8(value)
}
}
impl From<TryFromSliceError> for Error {
fn from(value: TryFromSliceError) -> Self {
Self::Slice(value)
}
}

82
src/file.rs Normal file
View File

@ -0,0 +1,82 @@
use {
crate::{Checksum, Error},
md5::{Digest, Md5},
sha1::Sha1,
sha2::Sha256,
std::io::{Read, Write},
};
#[derive(Debug)]
pub struct File {
pub len: u64,
pub checksum: Checksum,
pub data: Vec<u8>,
}
impl File {
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 checksum = Checksum::read(reader)?;
let mut data = Vec::with_capacity(len.try_into()?);
let mut handle = reader.take(len);
handle.read_exact(&mut data)?;
match checksum {
Checksum::Md5(sum) => {
let mut hasher = Md5::new();
hasher.update(&data);
let res = hasher.finalize();
if res == sum.into() {
Ok(Self {
len,
checksum,
data,
})
} else {
Err(Error::InvalidChecksum)
}
}
Checksum::Sha1(sum) => {
let mut hasher = Sha1::new();
hasher.update(&data);
let res = hasher.finalize();
if res == sum.into() {
Ok(Self {
len,
checksum,
data,
})
} else {
Err(Error::InvalidChecksum)
}
}
Checksum::Sha256(sum) => {
let mut hasher = Sha256::new();
hasher.update(&data);
let res = hasher.finalize();
if res == sum.into() {
Ok(Self {
len,
checksum,
data,
})
} else {
Err(Error::InvalidChecksum)
}
}
_ => Ok(Self {
len,
checksum,
data,
}),
}
}
pub fn write<T: Write>(&self, writer: &mut T) -> Result<(), Error> {
writer.write_all(&self.len.to_be_bytes())?;
Checksum::write(&self.checksum, writer)?;
writer.write_all(&self.data)?;
Ok(())
}
}

92
src/filetype.rs Normal file
View File

@ -0,0 +1,92 @@
use {
crate::{Error, File, Special},
std::io::{Read, Write},
};
#[repr(u8)]
#[derive(Debug)]
pub enum FileType {
Normal(File),
HardLink(String),
SoftLink(String),
Directory,
Character(Special),
Block(Special),
Fifo,
}
impl FileType {
pub fn read<T: Read>(reader: &mut T) -> Result<Self, Error> {
let mut buf = [0; 1];
reader.read_exact(&mut buf)?;
match buf[0] {
0 => {
let file = File::read(reader)?;
Ok(Self::Normal(file))
}
1 => {
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_exact(&mut buf)?;
let s = String::from_utf8(buf)?;
Ok(Self::HardLink(s))
}
2 => {
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_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),
}
}
pub fn write<T: Write>(&self, writer: &mut T) -> Result<(), Error> {
match self {
Self::Normal(f) => {
writer.write_all(&[0])?;
f.write(writer)?;
}
Self::HardLink(s) => {
writer.write_all(&[1])?;
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(())
}
}

View File

@ -1,490 +1,9 @@
use {
md5::{Digest, Md5},
sha1::Sha1,
sha2::Sha256,
std::{
array::TryFromSliceError,
collections::HashMap,
fmt, fs,
io::{self, BufReader, Read, Write},
num::TryFromIntError,
os::unix::fs::MetadataExt,
string::FromUtf8Error,
sync::Mutex,
},
mod checksum;
mod error;
mod file;
mod filetype;
mod node;
mod special;
pub use {
checksum::Checksum, error::Error, file::File, filetype::FileType, node::Node, special::Special,
};
#[derive(Debug)]
pub enum Error {
Int(TryFromIntError),
Io(io::Error),
Utf8(FromUtf8Error),
Slice(TryFromSliceError),
InvalidChecksum,
MissingData,
UnexpectedData,
UnknownFileType,
Other(String),
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Int(e) => write!(f, "{e}"),
Self::Utf8(e) => write!(f, "{e}"),
Self::Slice(e) => write!(f, "{e}"),
Self::Io(e) => write!(f, "{e}"),
Self::InvalidChecksum => write!(f, "invalid checksum"),
Self::MissingData => write!(f, "missing data"),
Self::UnexpectedData => write!(f, "unexpected data"),
Self::UnknownFileType => write!(f, "unknown file type"),
Self::Other(s) => write!(f, "{s}"),
}
}
}
impl std::error::Error for Error {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match self {
Self::Int(e) => Some(e),
Self::Io(e) => Some(e),
Self::Utf8(e) => Some(e),
Self::Slice(e) => Some(e),
_ => None,
}
}
}
impl From<TryFromIntError> for Error {
fn from(value: TryFromIntError) -> Self {
Self::Int(value)
}
}
impl From<io::Error> for Error {
fn from(value: io::Error) -> Self {
Self::Io(value)
}
}
impl From<FromUtf8Error> for Error {
fn from(value: FromUtf8Error) -> Self {
Self::Utf8(value)
}
}
impl From<TryFromSliceError> for Error {
fn from(value: TryFromSliceError) -> Self {
Self::Slice(value)
}
}
#[derive(Debug)]
pub struct Special {
pub major: u32,
pub minor: u32,
}
impl Special {
pub fn read<T: Read>(reader: &mut T) -> Result<Self, Error> {
let mut buf = [0; 8];
reader.read_exact(&mut buf)?;
let major: [u8; 4] = buf[..4].try_into()?;
let major = u32::from_le_bytes(major);
let minor: [u8; 4] = buf[4..].try_into()?;
let minor = u32::from_le_bytes(minor);
Ok(Self { major, minor })
}
pub fn write<T: Write>(&self, writer: &mut T) -> Result<(), Error> {
writer.write_all(&self.major.to_le_bytes())?;
writer.write_all(&self.minor.to_le_bytes())?;
Ok(())
}
fn from_rdev(rdev: u32) -> Self {
Self {
major: rdev >> 8,
minor: rdev & 0xff,
}
}
}
#[derive(Debug)]
pub enum Checksum {
Md5([u8; 16]),
Sha1([u8; 20]),
Sha256([u8; 32]),
Skip,
}
impl Checksum {
pub fn read<T: Read>(reader: &mut T) -> Result<Self, Error> {
let mut buf = [0; 1];
reader.read_exact(&mut buf)?;
match buf[0] {
0 => {
let mut sum = [0; 16];
reader.read_exact(&mut sum)?;
Ok(Self::Md5(sum))
}
1 => {
let mut sum = [0; 20];
reader.read_exact(&mut sum)?;
Ok(Self::Sha1(sum))
}
2 => {
let mut sum = [0; 32];
reader.read_exact(&mut sum)?;
Ok(Self::Sha256(sum))
}
_ => Ok(Self::Skip),
}
}
pub fn write<T: Write>(&self, writer: &mut T) -> Result<(), Error> {
match self {
Self::Md5(sum) => {
writer.write_all(&[b'0'])?;
writer.write_all(&sum[..])?;
}
Self::Sha1(sum) => {
writer.write_all(&[b'1'])?;
writer.write_all(&sum[..])?;
}
Self::Sha256(sum) => {
writer.write_all(&[b'2'])?;
writer.write_all(&sum[..])?;
}
Self::Skip => writer.write_all(&[b'3'])?,
}
Ok(())
}
}
#[derive(Debug)]
pub struct File {
pub len: u64,
pub checksum: Checksum,
pub data: Vec<u8>,
}
impl File {
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 checksum = Checksum::read(reader)?;
let mut data = Vec::with_capacity(len.try_into()?);
let mut handle = reader.take(len);
handle.read_exact(&mut data)?;
match checksum {
Checksum::Md5(sum) => {
let mut hasher = Md5::new();
hasher.update(&data);
let res = hasher.finalize();
if res == sum.into() {
Ok(Self {
len,
checksum,
data,
})
} else {
Err(Error::InvalidChecksum)
}
}
Checksum::Sha1(sum) => {
let mut hasher = Sha1::new();
hasher.update(&data);
let res = hasher.finalize();
if res == sum.into() {
Ok(Self {
len,
checksum,
data,
})
} else {
Err(Error::InvalidChecksum)
}
}
Checksum::Sha256(sum) => {
let mut hasher = Sha256::new();
hasher.update(&data);
let res = hasher.finalize();
if res == sum.into() {
Ok(Self {
len,
checksum,
data,
})
} else {
Err(Error::InvalidChecksum)
}
}
_ => Ok(Self {
len,
checksum,
data,
}),
}
}
pub fn write<T: Write>(&self, writer: &mut T) -> Result<(), Error> {
writer.write_all(&self.len.to_be_bytes())?;
Checksum::write(&self.checksum, writer)?;
writer.write_all(&self.data)?;
Ok(())
}
}
#[repr(u8)]
#[derive(Debug)]
pub enum FileType {
Normal(File),
HardLink(String),
SoftLink(String),
Directory,
Character(Special),
Block(Special),
Fifo,
}
impl FileType {
pub fn read<T: Read>(reader: &mut T) -> Result<Self, Error> {
let mut buf = [0; 1];
reader.read_exact(&mut buf)?;
match buf[0] {
0 => {
let file = File::read(reader)?;
Ok(Self::Normal(file))
}
1 => {
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_exact(&mut buf)?;
let s = String::from_utf8(buf)?;
Ok(Self::HardLink(s))
}
2 => {
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_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),
}
}
pub fn write<T: Write>(&self, writer: &mut T) -> Result<(), Error> {
match self {
Self::Normal(f) => {
writer.write_all(&[0])?;
f.write(writer)?;
}
Self::HardLink(s) => {
writer.write_all(&[1])?;
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(())
}
}
#[derive(Debug, PartialEq)]
enum Kind {
Normal,
Dir,
Char,
Block,
Pipe,
}
impl From<u32> for Kind {
fn from(value: u32) -> Self {
if value & 0o60000 != 0 {
Self::Block
} else if value & 0o20000 != 0 {
Self::Char
} else if value & 0o10000 != 0 {
Self::Pipe
} else if value & 0o40000 != 0 {
Self::Dir
} else if value & 0o100000 != 0 {
Self::Normal
} else {
panic!();
}
}
}
#[derive(Debug)]
pub struct Node {
pub name: String,
pub mode: u32,
pub uid: u32,
pub gid: u32,
pub mtime: u64,
pub filetype: FileType,
}
impl Node {
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 mut buf = [0; 20];
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 mtime: [u8; 8] = buf[12..].try_into()?;
let filetype = FileType::read(reader)?;
Ok(Self {
name: String::from_utf8(name)?,
mode: u32::from_le_bytes(mode),
uid: u32::from_le_bytes(uid),
gid: u32::from_le_bytes(gid),
mtime: u64::from_le_bytes(mtime),
filetype,
})
}
pub fn write<T: 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.mode, self.uid, self.gid]
.iter()
.try_for_each(|f| writer.write_all(&f.to_le_bytes()))?;
writer.write_all(&self.mtime.to_le_bytes())?;
self.filetype.write(writer)?;
Ok(())
}
pub fn from_path(
path: &str,
checksum: Checksum,
links: Mutex<HashMap<u64, String>>,
) -> Result<Self, Error> {
let name = String::from(path);
let fd = fs::File::open(path)?;
let meta = fd.metadata()?;
let mode = meta.mode();
let uid = meta.uid();
let gid = meta.gid();
let mtime = meta.mtime().try_into()?;
let mut reader = BufReader::new(fd);
let ft = meta.file_type();
let filetype = 'blk: {
if ft.is_dir() {
FileType::Directory
} else if ft.is_symlink() {
let target = fs::read_link(path)?;
let target = target
.to_str()
.ok_or(Error::Other("bad path".to_string()))?
.to_string();
FileType::SoftLink(target)
} else {
if meta.nlink() > 1 {
if let Ok(mut list) = links.lock() {
let inode = meta.ino();
if let Some(target) = list.get(&inode).cloned() {
break 'blk FileType::HardLink(target);
} else {
list.insert(inode, name.clone());
}
}
}
let kind = Kind::from(mode);
if kind == Kind::Char {
let device = Special::from_rdev(meta.rdev().try_into()?);
break 'blk FileType::Character(device);
} else if kind == Kind::Block {
let device = Special::from_rdev(meta.rdev().try_into()?);
break 'blk FileType::Block(device);
} else if kind == Kind::Pipe {
break 'blk FileType::Fifo;
} else if kind == Kind::Normal {
let mut len = meta.len();
let mut data = Vec::with_capacity(len.try_into()?);
len = reader.read_to_end(&mut data)?.try_into()?;
let checksum = match checksum {
Checksum::Md5(mut cs) => {
let mut hasher = Md5::new();
hasher.update(&data);
cs = hasher.finalize().into();
Checksum::Md5(cs)
}
Checksum::Sha1(mut cs) => {
let mut hasher = Sha1::new();
hasher.update(&data);
cs = hasher.finalize().into();
Checksum::Sha1(cs)
}
Checksum::Sha256(mut cs) => {
let mut hasher = Sha256::new();
hasher.update(&data);
cs = hasher.finalize().into();
Checksum::Sha256(cs)
}
Checksum::Skip => checksum,
};
break 'blk FileType::Normal(File {
len,
checksum,
data,
});
} else {
return Err(Error::UnknownFileType);
}
}
};
Ok(Self {
name,
mode,
uid,
gid,
mtime,
filetype,
})
}
}

177
src/node.rs Normal file
View File

@ -0,0 +1,177 @@
use {
crate::{Checksum, Error, File, FileType, Special},
md5::{Digest, Md5},
sha1::Sha1,
sha2::Sha256,
std::{
collections::HashMap,
fs,
io::{BufReader, Read, Write},
os::unix::fs::MetadataExt,
sync::Mutex,
},
};
#[derive(Debug, PartialEq)]
enum Kind {
Normal,
Dir,
Char,
Block,
Pipe,
}
impl From<u32> for Kind {
fn from(value: u32) -> Self {
if value & 0o60000 != 0 {
Self::Block
} else if value & 0o20000 != 0 {
Self::Char
} else if value & 0o10000 != 0 {
Self::Pipe
} else if value & 0o40000 != 0 {
Self::Dir
} else if value & 0o100000 != 0 {
Self::Normal
} else {
panic!();
}
}
}
#[derive(Debug)]
pub struct Node {
pub name: String,
pub mode: u32,
pub uid: u32,
pub gid: u32,
pub mtime: u64,
pub filetype: FileType,
}
impl Node {
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 mut buf = [0; 20];
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 mtime: [u8; 8] = buf[12..].try_into()?;
let filetype = FileType::read(reader)?;
Ok(Self {
name: String::from_utf8(name)?,
mode: u32::from_le_bytes(mode),
uid: u32::from_le_bytes(uid),
gid: u32::from_le_bytes(gid),
mtime: u64::from_le_bytes(mtime),
filetype,
})
}
pub fn write<T: 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.mode, self.uid, self.gid]
.iter()
.try_for_each(|f| writer.write_all(&f.to_le_bytes()))?;
writer.write_all(&self.mtime.to_le_bytes())?;
self.filetype.write(writer)?;
Ok(())
}
pub fn from_path(
path: &str,
checksum: Checksum,
links: Mutex<HashMap<u64, String>>,
) -> Result<Self, Error> {
let name = String::from(path);
let fd = fs::File::open(path)?;
let meta = fd.metadata()?;
let mode = meta.mode();
let uid = meta.uid();
let gid = meta.gid();
let mtime = meta.mtime().try_into()?;
let mut reader = BufReader::new(fd);
let ft = meta.file_type();
let filetype = 'blk: {
if ft.is_dir() {
FileType::Directory
} else if ft.is_symlink() {
let target = fs::read_link(path)?;
let target = target
.to_str()
.ok_or(Error::Other("bad path".to_string()))?
.to_string();
FileType::SoftLink(target)
} else {
if meta.nlink() > 1 {
if let Ok(mut list) = links.lock() {
let inode = meta.ino();
if let Some(target) = list.get(&inode).cloned() {
break 'blk FileType::HardLink(target);
} else {
list.insert(inode, name.clone());
}
}
}
let kind = Kind::from(mode);
if kind == Kind::Char {
let device = Special::from_rdev(meta.rdev().try_into()?);
break 'blk FileType::Character(device);
} else if kind == Kind::Block {
let device = Special::from_rdev(meta.rdev().try_into()?);
break 'blk FileType::Block(device);
} else if kind == Kind::Pipe {
break 'blk FileType::Fifo;
} else if kind == Kind::Normal {
let mut len = meta.len();
let mut data = Vec::with_capacity(len.try_into()?);
len = reader.read_to_end(&mut data)?.try_into()?;
let checksum = match checksum {
Checksum::Md5(mut cs) => {
let mut hasher = Md5::new();
hasher.update(&data);
cs = hasher.finalize().into();
Checksum::Md5(cs)
}
Checksum::Sha1(mut cs) => {
let mut hasher = Sha1::new();
hasher.update(&data);
cs = hasher.finalize().into();
Checksum::Sha1(cs)
}
Checksum::Sha256(mut cs) => {
let mut hasher = Sha256::new();
hasher.update(&data);
cs = hasher.finalize().into();
Checksum::Sha256(cs)
}
Checksum::Skip => checksum,
};
break 'blk FileType::Normal(File {
len,
checksum,
data,
});
} else {
return Err(Error::UnknownFileType);
}
}
};
Ok(Self {
name,
mode,
uid,
gid,
mtime,
filetype,
})
}
}

35
src/special.rs Normal file
View File

@ -0,0 +1,35 @@
use {
crate::Error,
std::io::{Read, Write},
};
#[derive(Debug)]
pub struct Special {
pub major: u32,
pub minor: u32,
}
impl Special {
pub fn read<T: Read>(reader: &mut T) -> Result<Self, Error> {
let mut buf = [0; 8];
reader.read_exact(&mut buf)?;
let major: [u8; 4] = buf[..4].try_into()?;
let major = u32::from_le_bytes(major);
let minor: [u8; 4] = buf[4..].try_into()?;
let minor = u32::from_le_bytes(minor);
Ok(Self { major, minor })
}
pub fn write<T: Write>(&self, writer: &mut T) -> Result<(), Error> {
writer.write_all(&self.major.to_le_bytes())?;
writer.write_all(&self.minor.to_le_bytes())?;
Ok(())
}
pub(super) fn from_rdev(rdev: u32) -> Self {
Self {
major: rdev >> 8,
minor: rdev & 0xff,
}
}
}