use ext::no_std::pipelines::{pipe::Pipe, tap::Tap};
use std::fs;
use tar::{Archive, Builder};
fn mark_file_or_dir(r#in: &str, vec: &mut Vec<u8>) {
let meta = fs::metadata(r#in).unwrap();
if meta.is_dir() {
vec.push(0)
} else if meta.is_file() {
vec.push(1)
} else {
panic!("unsupported file type")
}
}
fn judge_file_or_dir(
last: u8,
byt: Vec<u8>,
f1: impl FnOnce(&mut Archive<&[u8]>),
f2: impl FnOnce(&mut Archive<&[u8]>),
) {
let tar = &mut Archive::new(byt.as_slice());
match last {
0 => f1(tar),
1 => f2(tar),
_ => panic!("file type error"),
}
}
fn archive(r#in: &str, file_ext_name: &str, f: impl FnOnce(Vec<u8>) -> Vec<u8>) {
Builder::new(vec![])
.tap_mut(|b| {
b.append_dir_all("", r#in)
.unwrap_or_else(|_| b.append_path(r#in).unwrap())
}).into_inner().unwrap()
.pipe(f)
.tap_mut(|vec| mark_file_or_dir(r#in, vec)) .pipe(|byt| fs::write(format!("{in}{file_ext_name}"), byt).unwrap())
}
fn restore(r#in: &str, file_ext_name: &str, f: impl FnOnce(Vec<u8>) -> Vec<u8>) {
fs::read(r#in)
.unwrap()
.pipe(|mut v| (v.pop().unwrap(), v))
.pipe(|(last, data)| (f(data), last))
.pipe(|(byt, last)| {
r#in.trim_end_matches(file_ext_name).pipe(|name| {
judge_file_or_dir(
last,
byt,
|tar| tar.unpack(name).unwrap(),
|tar| {
tar.entries().unwrap().for_each(|file| {
file.unwrap().unpack(name).unwrap();
})
},
)
})
})
}
pub fn pack<'a, F1, F2>(r#in: &'a str) -> impl FnOnce(&'a str, F1, F2) where F1: FnOnce(Vec<u8>) -> Vec<u8>, F2: FnOnce(Vec<u8>) -> Vec<u8> {
|file_ext_name, compress, encrypt|
archive(r#in, file_ext_name, |data| data.pipe(compress).pipe(encrypt))
}
pub fn unpack<'a, F1, F2>(r#in: &'a str) -> impl FnOnce(&'a str, F1, F2) where F1: FnOnce(Vec<u8>) -> Vec<u8>, F2: FnOnce(Vec<u8>) -> Vec<u8> {
|file_ext_name, decompress, decrypt|
restore(r#in, file_ext_name, |data| data.pipe(decrypt).pipe(decompress))
}