cargo-binstall/crates/binstalk-downloader/src/download/zip_extraction.rs
Jiahao XU e704abe7ac
Use rc-zip-sync for zip extraction (#1942)
* Use rc-zip-sync for zip extraction

Fixed #1080

In this commit, binstalk-downloader is updated to
- first download the zip into a temporary file, since
  there is no correct way to extract zip from a stream.
- then use rc-zip-sync to read from the zip and extract
  it to filesystem.

Signed-off-by: Jiahao XU <Jiahao_XU@outlook.com>

* Fix returned `ExtractedFiles` in `do_extract_zip`

Signed-off-by: Jiahao XU <30436523+NobodyXu@users.noreply.github.com>

* Fix clippy in zip_extraction.rs

Signed-off-by: Jiahao XU <30436523+NobodyXu@users.noreply.github.com>

---------

Signed-off-by: Jiahao XU <Jiahao_XU@outlook.com>
Signed-off-by: Jiahao XU <30436523+NobodyXu@users.noreply.github.com>
2024-10-30 00:16:54 +00:00

66 lines
2 KiB
Rust

use std::{
fs::{self, create_dir_all, File},
io::{self, Read},
path::Path,
};
use cfg_if::cfg_if;
use rc_zip_sync::{rc_zip::parse::EntryKind, ReadZip};
use super::{DownloadError, ExtractedFiles};
pub(super) fn do_extract_zip(f: File, dir: &Path) -> Result<ExtractedFiles, DownloadError> {
let mut extracted_files = ExtractedFiles::new();
for entry in f.read_zip()?.entries() {
let Some(name) = entry.sanitized_name().map(Path::new) else {
continue;
};
let path = dir.join(name);
let do_extract_file = || {
let mut entry_writer = File::create(&path)?;
let mut entry_reader = entry.reader();
io::copy(&mut entry_reader, &mut entry_writer)?;
Ok::<_, io::Error>(())
};
let parent = path
.parent()
.expect("all full entry paths should have parent paths");
create_dir_all(parent)?;
match entry.kind() {
EntryKind::Symlink => {
extracted_files.add_file(name);
cfg_if! {
if #[cfg(windows)] {
do_extract_file()?;
} else {
match fs::symlink_metadata(&path) {
Ok(metadata) if metadata.is_file() => fs::remove_file(&path)?,
_ => (),
}
let mut src = String::new();
entry.reader().read_to_string(&mut src)?;
// validate pointing path before creating a symbolic link
if src.contains("..") {
continue;
}
std::os::unix::fs::symlink(src, &path)?;
}
}
}
EntryKind::Directory => (),
EntryKind::File => {
extracted_files.add_file(name);
do_extract_file()?;
}
}
}
Ok(extracted_files)
}