Add Listing type for generating a listing of files in an archive

This commit is contained in:
Nathan Fisher 2023-12-22 19:03:17 -05:00
parent c2e377d09e
commit ae7c9b08b3
3 changed files with 139 additions and 6 deletions

View File

@ -16,6 +16,7 @@ mod checksum;
mod error;
mod file;
mod filetype;
mod listing;
pub(crate) mod nix;
mod node;
mod special;
@ -26,6 +27,7 @@ pub use {
error::Error,
file::File,
filetype::FileType,
listing::Listing,
node::Node,
special::Special,
stream::Stream,

131
src/listing.rs Normal file
View File

@ -0,0 +1,131 @@
use {
crate::{filetype::Flag, Error, Special},
std::io::{Read, Seek, SeekFrom},
};
#[derive(Debug)]
pub enum Kind {
Normal(u64),
HardLink(String),
SoftLink(String),
Directory,
Character(Special),
Block(Special),
Fifo,
Eof,
}
impl Kind {
fn read<R: Read + Seek>(reader: &mut R, flag: Flag) -> Result<Self, Error> {
match flag {
Flag::Normal => {
let mut len = [0; 8];
reader.read_exact(&mut len)?;
let len = u64::from_le_bytes(len);
let mut buf = [0; 1];
reader.read_exact(&mut buf)?;
match buf[0] {
0 => {
let bytes = reader.seek(SeekFrom::Current(len as i64 + 16))?;
if bytes - 16 != len {
return Err(Error::MissingData);
}
}
1 => {
let bytes = reader.seek(SeekFrom::Current(len as i64 + 20))?;
if bytes - 20 != len {
return Err(Error::MissingData);
}
}
2 => {
let bytes = reader.seek(SeekFrom::Current(len as i64 + 32))?;
if bytes - 32 != len {
return Err(Error::MissingData);
}
}
_ => {}
}
Ok(Self::Normal(len))
}
Flag::HardLink => {
let mut len = [0; 2];
reader.read_exact(&mut len)?;
let len = u16::from_le_bytes(len);
let mut buf = Vec::with_capacity(len.into());
let mut handle = reader.take(len.into());
handle.read_to_end(&mut buf)?;
let s = String::from_utf8(buf)?;
Ok(Self::HardLink(s))
}
Flag::SoftLink => {
let mut len = [0; 2];
reader.read_exact(&mut len)?;
let len = u16::from_le_bytes(len);
let mut buf = Vec::with_capacity(len.into());
let mut handle = reader.take(len.into());
handle.read_to_end(&mut buf)?;
let s = String::from_utf8(buf)?;
Ok(Self::SoftLink(s))
}
Flag::Directory => Ok(Self::Directory),
Flag::Character => {
let sp = Special::read(reader)?;
Ok(Self::Character(sp))
}
Flag::Block => {
let sp = Special::read(reader)?;
Ok(Self::Block(sp))
}
Flag::Fifo => Ok(Self::Fifo),
Flag::Eof => Ok(Self::Eof),
}
}
}
#[derive(Debug)]
pub struct Listing {
pub name: String,
pub uid: u32,
pub gid: u32,
pub mtime: u64,
pub mode: u16,
pub kind: Kind,
}
impl Listing {
pub fn read<R: Read + Seek>(reader: &mut R) -> Result<Self, Error> {
let mut len = [0; 2];
reader.read_exact(&mut len)?;
let len = u16::from_le_bytes(len);
if len == 0 {
return Ok(Self {
name: String::new(),
mode: 0,
uid: 0,
gid: 0,
mtime: 0,
kind: Kind::Eof,
});
}
let mut name = Vec::with_capacity(len.into());
let mut handle = reader.take(len.into());
handle.read_to_end(&mut name)?;
let mut buf = [0; 18];
reader.read_exact(&mut buf)?;
let uid: [u8; 4] = buf[0..4].try_into()?;
let gid: [u8; 4] = buf[4..8].try_into()?;
let mtime: [u8; 8] = buf[8..16].try_into()?;
let raw_mode: [u8; 2] = buf[16..18].try_into()?;
let raw_mode = u16::from_le_bytes(raw_mode);
let (flag, mode) = Flag::extract_from_raw(raw_mode)?;
let kind = Kind::read(reader, flag)?;
Ok(Self {
name: String::from_utf8(name)?,
uid: u32::from_le_bytes(uid),
gid: u32::from_le_bytes(gid),
mtime: u64::from_le_bytes(mtime),
mode,
kind,
})
}
}

View File

@ -250,9 +250,9 @@ impl Node {
if n_path.exists() {
fs::remove_file(&n_path)?;
}
nix::mkfifo(&n_path.to_str().ok_or(Error::BadPath)?, self.mode.into())?;
nix::mkfifo(n_path.to_str().ok_or(Error::BadPath)?, self.mode.into())?;
if euid == 0 {
nix::chown(&n_path.to_str().ok_or(Error::BadPath)?, self.uid, self.gid)?;
nix::chown(n_path.to_str().ok_or(Error::BadPath)?, self.uid, self.gid)?;
}
}
FileType::Block(ref b) => {
@ -261,7 +261,7 @@ impl Node {
fs::remove_file(&n_path)?;
}
nix::mknod(
&n_path.to_str().ok_or(Error::BadPath)?,
n_path.to_str().ok_or(Error::BadPath)?,
self.mode.into(),
b.major,
b.minor,
@ -274,7 +274,7 @@ impl Node {
fs::remove_file(&n_path)?;
}
nix::mknod(
&n_path.to_str().ok_or(Error::BadPath)?,
n_path.to_str().ok_or(Error::BadPath)?,
self.mode.into(),
c.major,
c.minor,
@ -292,9 +292,9 @@ impl Node {
writer.write_all(&n.data)?;
}
if euid == 0 {
nix::chown(&n_path.to_str().ok_or(Error::BadPath)?, self.uid, self.gid)?;
nix::chown(n_path.to_str().ok_or(Error::BadPath)?, self.uid, self.gid)?;
}
nix::chmod(&n_path.to_str().ok_or(Error::BadPath)?, self.mode.into())?;
nix::chmod(n_path.to_str().ok_or(Error::BadPath)?, self.mode.into())?;
}
FileType::HardLink(ref t) => {
let target = if let Some(prefix) = prefix {