diff options
author | David Sherret <dsherret@users.noreply.github.com> | 2024-05-14 14:26:48 -0400 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-05-14 14:26:48 -0400 |
commit | f16b4d4df8bd03f2d0c5e5d6855e334fa768e828 (patch) | |
tree | 6b99b3a79486cd73c32145bca981e13fc626549b /cli/util | |
parent | c0e3b6ed9d955bc59a8d88e177219b541881c63d (diff) |
fix(npm): make tarball extraction more reliable (#23759)
1. Extracts to a directory beside the destination.
2. Renames to the destination with retries.
Diffstat (limited to 'cli/util')
-rw-r--r-- | cli/util/fs.rs | 12 | ||||
-rw-r--r-- | cli/util/path.rs | 26 |
2 files changed, 28 insertions, 10 deletions
diff --git a/cli/util/fs.rs b/cli/util/fs.rs index 92820ebe8..fdc7855e6 100644 --- a/cli/util/fs.rs +++ b/cli/util/fs.rs @@ -2,7 +2,6 @@ use std::collections::HashSet; use std::env::current_dir; -use std::fmt::Write as FmtWrite; use std::fs::FileType; use std::fs::OpenOptions; use std::io::Error; @@ -23,12 +22,12 @@ use deno_core::error::AnyError; pub use deno_core::normalize_path; use deno_core::unsync::spawn_blocking; use deno_core::ModuleSpecifier; -use deno_runtime::deno_crypto::rand; use deno_runtime::deno_fs::FileSystem; use deno_runtime::deno_node::PathClean; use crate::util::gitignore::DirGitIgnores; use crate::util::gitignore::GitIgnoreTree; +use crate::util::path::get_atomic_file_path; use crate::util::progress_bar::ProgressBar; use crate::util::progress_bar::ProgressBarStyle; use crate::util::progress_bar::ProgressMessagePrompt; @@ -56,14 +55,7 @@ pub fn atomic_write_file<T: AsRef<[u8]>>( } fn inner(file_path: &Path, data: &[u8], mode: u32) -> std::io::Result<()> { - let temp_file_path = { - let rand: String = (0..4).fold(String::new(), |mut output, _| { - let _ = write!(output, "{:02x}", rand::random::<u8>()); - output - }); - let extension = format!("{rand}.tmp"); - file_path.with_extension(extension) - }; + let temp_file_path = get_atomic_file_path(file_path); if let Err(write_err) = atomic_write_file_raw(&temp_file_path, file_path, data, mode) diff --git a/cli/util/path.rs b/cli/util/path.rs index a3109ad04..3c848edea 100644 --- a/cli/util/path.rs +++ b/cli/util/path.rs @@ -42,6 +42,32 @@ pub fn get_extension(file_path: &Path) -> Option<String> { .map(|e| e.to_lowercase()); } +pub fn get_atomic_dir_path(file_path: &Path) -> PathBuf { + let rand = gen_rand_path_component(); + let new_file_name = format!( + ".{}_{}", + file_path + .file_name() + .map(|f| f.to_string_lossy()) + .unwrap_or(Cow::Borrowed("")), + rand + ); + file_path.with_file_name(new_file_name) +} + +pub fn get_atomic_file_path(file_path: &Path) -> PathBuf { + let rand = gen_rand_path_component(); + let extension = format!("{rand}.tmp"); + file_path.with_extension(extension) +} + +fn gen_rand_path_component() -> String { + (0..4).fold(String::new(), |mut output, _| { + output.push_str(&format!("{:02x}", rand::random::<u8>())); + output + }) +} + /// TypeScript figures out the type of file based on the extension, but we take /// other factors into account like the file headers. The hack here is to map the /// specifier passed to TypeScript to a new specifier with the file extension. |