Initial commit
This commit is contained in:
commit
0ddfb168f5
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
/target
|
7
Cargo.lock
generated
Normal file
7
Cargo.lock
generated
Normal file
@ -0,0 +1,7 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "pk-rs"
|
||||
version = "0.1.0"
|
8
Cargo.toml
Normal file
8
Cargo.toml
Normal file
@ -0,0 +1,8 @@
|
||||
[package]
|
||||
name = "pk-rs"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
191
src/lib.rs
Normal file
191
src/lib.rs
Normal file
@ -0,0 +1,191 @@
|
||||
use std::{string::FromUtf8Error, array::TryFromSliceError, fmt, io::{Write, self, Read}, num::TryFromIntError};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Error {
|
||||
Int(TryFromIntError),
|
||||
Io(io::Error),
|
||||
Utf8(FromUtf8Error),
|
||||
Slice(TryFromSliceError),
|
||||
UnknownFileType,
|
||||
}
|
||||
|
||||
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::UnknownFileType => write!(f, "unknown file type"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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(())
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(u8)]
|
||||
#[derive(Debug)]
|
||||
pub enum FileType {
|
||||
Normal = 0,
|
||||
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 => Ok(Self::Normal),
|
||||
1 => {
|
||||
let mut l = [0; 8];
|
||||
reader.read_exact(&mut l)?;
|
||||
let len = u64::from_le_bytes(l);
|
||||
let mut buf = Vec::with_capacity(len.try_into()?);
|
||||
let mut handle = reader.take(len);
|
||||
handle.read(&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 buf = Vec::with_capacity(len.try_into()?);
|
||||
let mut handle = reader.take(len);
|
||||
handle.read(&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 => writer.write_all(&[0])?,
|
||||
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)]
|
||||
pub struct Header {
|
||||
pub name: String,
|
||||
pub filetype: FileType,
|
||||
pub mode: u32,
|
||||
pub uid: u32,
|
||||
pub gid: u32,
|
||||
pub size: u64,
|
||||
pub mtime: u64,
|
||||
}
|
||||
|
||||
impl Header {
|
||||
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.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())
|
||||
})?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user