95 lines
2.8 KiB
Rust
95 lines
2.8 KiB
Rust
use hpk_package::{
|
|
sha2::{Digest, Sha256},
|
|
tar::{Node, Owner},
|
|
Entry,
|
|
};
|
|
use std::{
|
|
error::Error,
|
|
ffi::OsStr,
|
|
fmt::Write,
|
|
fs,
|
|
io::Read,
|
|
os::unix::fs::MetadataExt,
|
|
path::{Path, PathBuf},
|
|
};
|
|
|
|
#[derive(Clone, Debug)]
|
|
/// An intermediate type used in the creation of a package archive
|
|
pub struct Item {
|
|
pub entry: Entry,
|
|
pub data: Vec<u8>,
|
|
}
|
|
|
|
impl Item {
|
|
pub fn try_create(path: &Path) -> Result<Self, Box<dyn Error>> {
|
|
let path = fix_path(path);
|
|
let meta = fs::metadata(&path)?;
|
|
let filename = format!("{}", path.display());
|
|
let owner = Some(Owner::default());
|
|
if meta.is_file() {
|
|
let mut data = vec![];
|
|
let mut fd = fs::File::open(path)?;
|
|
let path = PathBuf::from(&filename);
|
|
let size = fd.read_to_end(&mut data)?;
|
|
let mut sha256sum = String::new();
|
|
let mut hasher = Sha256::new();
|
|
hasher.update(&data);
|
|
let res = hasher.finalize();
|
|
for c in res {
|
|
write!(sha256sum, "{c:02x}")?;
|
|
}
|
|
let mode = meta.mode();
|
|
Ok(Self {
|
|
entry: Entry::File {
|
|
path,
|
|
sha256sum,
|
|
mode,
|
|
size,
|
|
},
|
|
data: Node::read_data_to_tar(&data, &filename, &meta, owner)?.to_vec()?,
|
|
})
|
|
} else if meta.is_dir() {
|
|
let mode = meta.mode();
|
|
let path = PathBuf::from(&filename);
|
|
Ok(Self {
|
|
entry: Entry::Directory { path, mode },
|
|
data: Node::read_data_to_tar(&[0; 0], &filename, &meta, owner)?.to_vec()?,
|
|
})
|
|
} else if meta.is_symlink() {
|
|
let target = fs::read_link(path)?;
|
|
let path = PathBuf::from(&filename);
|
|
Ok(Self {
|
|
entry: Entry::Link { path, target },
|
|
data: Node::read_data_to_tar(&[0; 0], &filename, &meta, owner)?.to_vec()?,
|
|
})
|
|
} else {
|
|
unreachable!();
|
|
}
|
|
}
|
|
}
|
|
|
|
fn fix_path(path: &Path) -> PathBuf {
|
|
let path = if let Ok(p) = path.strip_prefix("./") {
|
|
p
|
|
} else {
|
|
path
|
|
};
|
|
if path.is_file() || path.is_symlink() {
|
|
match path.ancestors().last().and_then(Path::to_str) {
|
|
Some("etc" | "var") => {
|
|
let ext = if let Some(x) = path.extension().and_then(OsStr::to_str) {
|
|
format!("{x}.new")
|
|
} else {
|
|
"new".to_string()
|
|
};
|
|
let mut path = path.to_path_buf();
|
|
path.set_extension(ext);
|
|
path
|
|
}
|
|
_ => path.to_path_buf(),
|
|
}
|
|
} else {
|
|
path.to_path_buf()
|
|
}
|
|
}
|