diff --git a/Cargo.lock b/Cargo.lock index 61ae8e071..ef110d04f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2559,6 +2559,7 @@ dependencies = [ "fs-err", "futures", "rayon", + "rustc-hash", "tar", "thiserror", "tokio", diff --git a/crates/puffin-extract/Cargo.toml b/crates/puffin-extract/Cargo.toml index 88a5b137c..d034f102b 100644 --- a/crates/puffin-extract/Cargo.toml +++ b/crates/puffin-extract/Cargo.toml @@ -13,13 +13,14 @@ license = { workspace = true } workspace = true [dependencies] -futures = { workspace = true } -tokio-util = { workspace = true, features = ["compat"] } async_zip = { workspace = true, features = ["tokio"] } flate2 = { workspace = true } fs-err = { workspace = true, features = ["tokio"] } +futures = { workspace = true } rayon = { workspace = true } +rustc-hash = { workspace = true } tar = { workspace = true } thiserror = { workspace = true } tokio = { workspace = true, features = ["io-util"] } +tokio-util = { workspace = true, features = ["compat"] } zip = { workspace = true } diff --git a/crates/puffin-extract/src/lib.rs b/crates/puffin-extract/src/lib.rs index 5721ae13a..9f2dc245e 100644 --- a/crates/puffin-extract/src/lib.rs +++ b/crates/puffin-extract/src/lib.rs @@ -1,7 +1,9 @@ use std::fs::OpenOptions; use std::path::{Path, PathBuf}; +use std::sync::Mutex; use rayon::prelude::*; +use rustc_hash::FxHashSet; use tokio_util::compat::{FuturesAsyncReadCompatExt, TokioAsyncReadCompatExt}; use zip::result::ZipError; use zip::ZipArchive; @@ -104,6 +106,7 @@ pub fn unzip_archive( ) -> Result<(), Error> { // Unzip in parallel. let archive = ZipArchive::new(CloneableSeekableReader::new(reader))?; + let directories = Mutex::new(FxHashSet::default()); (0..archive.len()) .par_bridge() .map(|file_number| { @@ -118,11 +121,15 @@ pub fn unzip_archive( // Create necessary parent directories. let path = target.join(enclosed_name); if file.is_dir() { - fs_err::create_dir_all(path)?; + fs_err::create_dir_all(&path)?; return Ok(()); } + if let Some(parent) = path.parent() { - fs_err::create_dir_all(parent)?; + let mut directories = directories.lock().unwrap(); + if directories.insert(parent.to_path_buf()) { + fs_err::create_dir_all(parent)?; + } } // Create the file, with the correct permissions (on Unix).