From ae7c9b08b3ad4e30c250e509418283e25c47ed90 Mon Sep 17 00:00:00 2001 From: Nathan Fisher Date: Fri, 22 Dec 2023 19:03:17 -0500 Subject: [PATCH] Add Listing type for generating a listing of files in an archive --- src/lib.rs | 2 + src/listing.rs | 131 +++++++++++++++++++++++++++++++++++++++++++++++++ src/node.rs | 12 ++--- 3 files changed, 139 insertions(+), 6 deletions(-) create mode 100644 src/listing.rs diff --git a/src/lib.rs b/src/lib.rs index d3e97a2..4c6a88f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -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, diff --git a/src/listing.rs b/src/listing.rs new file mode 100644 index 0000000..8d7f0a5 --- /dev/null +++ b/src/listing.rs @@ -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(reader: &mut R, flag: Flag) -> Result { + 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(reader: &mut R) -> Result { + 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, + }) + } +} diff --git a/src/node.rs b/src/node.rs index e22c063..09eb84d 100644 --- a/src/node.rs +++ b/src/node.rs @@ -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 {