From 84ef9bd21fb48fb6b5fbc8dafc3de9f361bade3b Mon Sep 17 00:00:00 2001 From: Yosi Pramajaya Date: Sun, 13 Dec 2020 02:41:43 +0700 Subject: [PATCH] fix(cli/compile): error when the output path already exists (#8681) --- cli/standalone.rs | 19 +++++++ cli/tests/integration_tests.rs | 98 ++++++++++++++++++++++++++++++++++ 2 files changed, 117 insertions(+) diff --git a/cli/standalone.rs b/cli/standalone.rs index 067fec36a1..6559242bdb 100644 --- a/cli/standalone.rs +++ b/cli/standalone.rs @@ -5,6 +5,7 @@ use crate::tokio_util; use crate::version; use crate::worker::MainWorker; use crate::worker::WorkerOptions; +use deno_core::error::bail; use deno_core::error::type_error; use deno_core::error::AnyError; use deno_core::futures::FutureExt; @@ -169,6 +170,24 @@ pub async fn create_standalone_binary( } else { output }; + + if output.exists() { + // If the output is a directory, throw error + if output.is_dir() { + bail!("Could not compile: {:?} is a directory.", &output); + } + + // Make sure we don't overwrite any file not created by Deno compiler. + // Check for magic trailer in last 16 bytes + let mut output_file = File::open(&output)?; + output_file.seek(SeekFrom::End(-16))?; + let mut trailer = [0; 16]; + output_file.read_exact(&mut trailer)?; + let (magic_trailer, _) = trailer.split_at(8); + if magic_trailer != MAGIC_TRAILER { + bail!("Could not compile: cannot overwrite {:?}.", &output); + } + } tokio::fs::write(&output, final_bin).await?; #[cfg(unix)] { diff --git a/cli/tests/integration_tests.rs b/cli/tests/integration_tests.rs index eeffb00970..cb6dfad6d9 100644 --- a/cli/tests/integration_tests.rs +++ b/cli/tests/integration_tests.rs @@ -4650,3 +4650,101 @@ fn standalone_no_module_load() { assert!(util::strip_ansi_codes(&stderr_str) .contains("Self-contained binaries don't support module loading")); } + +#[test] +fn compile_with_directory_exists_error() { + let dir = TempDir::new().expect("tempdir fail"); + let exe = if cfg!(windows) { + dir.path().join("args.exe") + } else { + dir.path().join("args") + }; + std::fs::create_dir(&exe).expect("cannot create directory"); + let output = util::deno_cmd() + .current_dir(util::root_path()) + .arg("compile") + .arg("--unstable") + .arg("./cli/tests/028_args.ts") + .arg("--output") + .arg(&exe) + .stderr(std::process::Stdio::piped()) + .spawn() + .unwrap() + .wait_with_output() + .unwrap(); + assert!(!output.status.success()); + let expected_stderr = + format!("Could not compile: {:?} is a directory.\n", &exe); + let stderr = String::from_utf8(output.stderr).unwrap(); + assert!(stderr.contains(&expected_stderr)); +} + +#[test] +fn compile_with_conflict_file_exists_error() { + let dir = TempDir::new().expect("tempdir fail"); + let exe = if cfg!(windows) { + dir.path().join("args.exe") + } else { + dir.path().join("args") + }; + std::fs::write(&exe, b"SHOULD NOT BE OVERWRITTEN") + .expect("cannot create file"); + let output = util::deno_cmd() + .current_dir(util::root_path()) + .arg("compile") + .arg("--unstable") + .arg("./cli/tests/028_args.ts") + .arg("--output") + .arg(&exe) + .stderr(std::process::Stdio::piped()) + .spawn() + .unwrap() + .wait_with_output() + .unwrap(); + assert!(!output.status.success()); + let expected_stderr = + format!("Could not compile: cannot overwrite {:?}.\n", &exe); + let stderr = String::from_utf8(output.stderr).unwrap(); + assert!(stderr.contains(&expected_stderr)); + assert!(std::fs::read(&exe) + .expect("cannot read file") + .eq(b"SHOULD NOT BE OVERWRITTEN")); +} + +#[test] +fn compile_and_overwrite_file() { + let dir = TempDir::new().expect("tempdir fail"); + let exe = if cfg!(windows) { + dir.path().join("args.exe") + } else { + dir.path().join("args") + }; + let output = util::deno_cmd() + .current_dir(util::root_path()) + .arg("compile") + .arg("--unstable") + .arg("./cli/tests/028_args.ts") + .arg("--output") + .arg(&exe) + .stderr(std::process::Stdio::piped()) + .spawn() + .unwrap() + .wait_with_output() + .unwrap(); + assert!(output.status.success()); + assert!(&exe.exists()); + + let recompile_output = util::deno_cmd() + .current_dir(util::root_path()) + .arg("compile") + .arg("--unstable") + .arg("./cli/tests/028_args.ts") + .arg("--output") + .arg(&exe) + .stderr(std::process::Stdio::piped()) + .spawn() + .unwrap() + .wait_with_output() + .unwrap(); + assert!(recompile_output.status.success()); +}