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