Some work on extract
for Node, requiring some plumbing which is in
`nix` module
This commit is contained in:
parent
283228ff46
commit
5fd1d09e77
1
Cargo.lock
generated
1
Cargo.lock
generated
@ -60,6 +60,7 @@ dependencies = [
|
||||
name = "haggis"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"md-5",
|
||||
"sha1",
|
||||
"sha2",
|
||||
|
@ -4,8 +4,10 @@ version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
[features]
|
||||
|
||||
[dependencies]
|
||||
libc = "0.2"
|
||||
md-5 = "0.10"
|
||||
sha1 = "0.10"
|
||||
sha2 = "0.10"
|
||||
|
12
src/error.rs
12
src/error.rs
@ -1,4 +1,6 @@
|
||||
use std::{array::TryFromSliceError, fmt, io, num::TryFromIntError, string::FromUtf8Error};
|
||||
use std::{
|
||||
array::TryFromSliceError, ffi::NulError, fmt, io, num::TryFromIntError, string::FromUtf8Error,
|
||||
};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Error {
|
||||
@ -8,6 +10,7 @@ pub enum Error {
|
||||
Slice(TryFromSliceError),
|
||||
InvalidChecksum,
|
||||
MissingData,
|
||||
NulError,
|
||||
UnexpectedData,
|
||||
UnknownFileType,
|
||||
Other(String),
|
||||
@ -22,6 +25,7 @@ impl fmt::Display for Error {
|
||||
Self::Io(e) => write!(f, "{e}"),
|
||||
Self::InvalidChecksum => write!(f, "invalid checksum"),
|
||||
Self::MissingData => write!(f, "missing data"),
|
||||
Self::NulError => write!(f, "nul error"),
|
||||
Self::UnexpectedData => write!(f, "unexpected data"),
|
||||
Self::UnknownFileType => write!(f, "unknown file type"),
|
||||
Self::Other(s) => write!(f, "{s}"),
|
||||
@ -64,3 +68,9 @@ impl From<TryFromSliceError> for Error {
|
||||
Self::Slice(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<NulError> for Error {
|
||||
fn from(_value: NulError) -> Self {
|
||||
Self::NulError
|
||||
}
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ mod checksum;
|
||||
mod error;
|
||||
mod file;
|
||||
mod filetype;
|
||||
pub mod nix;
|
||||
mod node;
|
||||
mod special;
|
||||
mod stream;
|
||||
|
37
src/nix/mod.rs
Normal file
37
src/nix/mod.rs
Normal file
@ -0,0 +1,37 @@
|
||||
#![allow(clippy::must_use_candidate)]
|
||||
use {
|
||||
crate::Error,
|
||||
std::{ffi::CString, io},
|
||||
};
|
||||
|
||||
pub fn geteuid() -> u32 {
|
||||
unsafe { libc::geteuid() }
|
||||
}
|
||||
|
||||
pub fn chown(path: &str, uid: u32, gid: u32) -> Result<(), Error> {
|
||||
let ret = unsafe { libc::chown(CString::new(path)?.as_ptr(), uid, gid) };
|
||||
if ret == 0 {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(Error::Io(io::Error::last_os_error()))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn mkfifo(path: &str, mode: u32) -> Result<(), Error> {
|
||||
let ret = unsafe { libc::mkfifo(CString::new(path)?.as_ptr(), mode.try_into()?) };
|
||||
if ret == 0 {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(Error::Io(io::Error::last_os_error()))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn mknod(path: &str, mode: u32, major: u32, minor: u32) -> Result<(), Error> {
|
||||
let dev = libc::makedev(major, minor);
|
||||
let res = unsafe { libc::mknod(CString::new(path)?.as_ptr(), mode.try_into()?, dev) };
|
||||
if res == 0 {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(Error::Io(io::Error::last_os_error()))
|
||||
}
|
||||
}
|
55
src/node.rs
55
src/node.rs
@ -1,5 +1,5 @@
|
||||
use {
|
||||
crate::{Checksum, Error, File, FileType, Special},
|
||||
crate::{nix, Checksum, Error, File, FileType, Special},
|
||||
md5::{Digest, Md5},
|
||||
sha1::Sha1,
|
||||
sha2::Sha256,
|
||||
@ -7,7 +7,8 @@ use {
|
||||
collections::HashMap,
|
||||
fs,
|
||||
io::{BufReader, Read, Write},
|
||||
os::unix::fs::MetadataExt,
|
||||
os::unix::fs::{symlink, DirBuilderExt, MetadataExt},
|
||||
path::{Path, PathBuf},
|
||||
sync::Mutex,
|
||||
},
|
||||
};
|
||||
@ -208,6 +209,56 @@ impl Node {
|
||||
}
|
||||
|
||||
pub fn extract(&self, prefix: Option<&str>) -> Result<(), Error> {
|
||||
let euid = nix::geteuid();
|
||||
let path = 'blk: {
|
||||
if let Some(prefix) = prefix {
|
||||
if self.name.starts_with('/') {
|
||||
break 'blk format!("{prefix}{}", self.name);
|
||||
}
|
||||
}
|
||||
self.name.clone()
|
||||
};
|
||||
match self.filetype {
|
||||
FileType::Eof => {}
|
||||
FileType::Fifo => {
|
||||
nix::mkfifo(&path, self.mode)?;
|
||||
if euid == 0 {
|
||||
nix::chown(&path, self.uid, self.gid)?;
|
||||
}
|
||||
},
|
||||
FileType::Block(ref b) => todo!(),
|
||||
FileType::Character(ref c) => todo!(),
|
||||
FileType::Normal(ref n) => todo!(),
|
||||
FileType::HardLink(ref t) => {
|
||||
let target = if let Some(prefix) = prefix {
|
||||
format!("{prefix}/{t}")
|
||||
} else {
|
||||
t.to_string()
|
||||
};
|
||||
fs::hard_link(&target, &path)?;
|
||||
},
|
||||
FileType::SoftLink(ref t) => {
|
||||
symlink(&self.name, t)?;
|
||||
}
|
||||
FileType::Directory => {
|
||||
self.mkdir(&PathBuf::from(&path))?;
|
||||
}
|
||||
}
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn mkdir(&self, dir: &Path) -> Result<(), Error> {
|
||||
if let Some(p) = dir.parent() {
|
||||
if !p.exists() {
|
||||
self.mkdir(&p)?;
|
||||
}
|
||||
}
|
||||
if !dir.exists () {
|
||||
fs::DirBuilder::new().mode(self.mode).create(dir)?;
|
||||
}
|
||||
if nix::geteuid() == 0 {
|
||||
nix::chown(dir.to_str().ok_or(Error::NulError)?, self.uid, self.gid)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user