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"
|
name = "haggis"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"libc",
|
||||||
"md-5",
|
"md-5",
|
||||||
"sha1",
|
"sha1",
|
||||||
"sha2",
|
"sha2",
|
||||||
|
@ -4,8 +4,10 @@ version = "0.1.0"
|
|||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
[features]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
libc = "0.2"
|
||||||
md-5 = "0.10"
|
md-5 = "0.10"
|
||||||
sha1 = "0.10"
|
sha1 = "0.10"
|
||||||
sha2 = "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)]
|
#[derive(Debug)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
@ -8,6 +10,7 @@ pub enum Error {
|
|||||||
Slice(TryFromSliceError),
|
Slice(TryFromSliceError),
|
||||||
InvalidChecksum,
|
InvalidChecksum,
|
||||||
MissingData,
|
MissingData,
|
||||||
|
NulError,
|
||||||
UnexpectedData,
|
UnexpectedData,
|
||||||
UnknownFileType,
|
UnknownFileType,
|
||||||
Other(String),
|
Other(String),
|
||||||
@ -22,6 +25,7 @@ impl fmt::Display for Error {
|
|||||||
Self::Io(e) => write!(f, "{e}"),
|
Self::Io(e) => write!(f, "{e}"),
|
||||||
Self::InvalidChecksum => write!(f, "invalid checksum"),
|
Self::InvalidChecksum => write!(f, "invalid checksum"),
|
||||||
Self::MissingData => write!(f, "missing data"),
|
Self::MissingData => write!(f, "missing data"),
|
||||||
|
Self::NulError => write!(f, "nul error"),
|
||||||
Self::UnexpectedData => write!(f, "unexpected data"),
|
Self::UnexpectedData => write!(f, "unexpected data"),
|
||||||
Self::UnknownFileType => write!(f, "unknown file type"),
|
Self::UnknownFileType => write!(f, "unknown file type"),
|
||||||
Self::Other(s) => write!(f, "{s}"),
|
Self::Other(s) => write!(f, "{s}"),
|
||||||
@ -64,3 +68,9 @@ impl From<TryFromSliceError> for Error {
|
|||||||
Self::Slice(value)
|
Self::Slice(value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<NulError> for Error {
|
||||||
|
fn from(_value: NulError) -> Self {
|
||||||
|
Self::NulError
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -2,6 +2,7 @@ mod checksum;
|
|||||||
mod error;
|
mod error;
|
||||||
mod file;
|
mod file;
|
||||||
mod filetype;
|
mod filetype;
|
||||||
|
pub mod nix;
|
||||||
mod node;
|
mod node;
|
||||||
mod special;
|
mod special;
|
||||||
mod stream;
|
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 {
|
use {
|
||||||
crate::{Checksum, Error, File, FileType, Special},
|
crate::{nix, Checksum, Error, File, FileType, Special},
|
||||||
md5::{Digest, Md5},
|
md5::{Digest, Md5},
|
||||||
sha1::Sha1,
|
sha1::Sha1,
|
||||||
sha2::Sha256,
|
sha2::Sha256,
|
||||||
@ -7,7 +7,8 @@ use {
|
|||||||
collections::HashMap,
|
collections::HashMap,
|
||||||
fs,
|
fs,
|
||||||
io::{BufReader, Read, Write},
|
io::{BufReader, Read, Write},
|
||||||
os::unix::fs::MetadataExt,
|
os::unix::fs::{symlink, DirBuilderExt, MetadataExt},
|
||||||
|
path::{Path, PathBuf},
|
||||||
sync::Mutex,
|
sync::Mutex,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
@ -208,6 +209,56 @@ impl Node {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn extract(&self, prefix: Option<&str>) -> Result<(), Error> {
|
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!()
|
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