hpk/src/item/mod.rs

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()
}
}