From de764a7ccbbcaf90db88569ce7a8b5e2214cfcd8 Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Thu, 16 Dec 2021 17:21:34 +0000 Subject: [PATCH] Quote bat script command line --- library/std/src/process/tests.rs | 19 +++++++++++++++++++ library/std/src/sys/windows/process.rs | 16 ++++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/library/std/src/process/tests.rs b/library/std/src/process/tests.rs index 67b747e410732..630a8a4c47ad0 100644 --- a/library/std/src/process/tests.rs +++ b/library/std/src/process/tests.rs @@ -416,3 +416,22 @@ fn env_empty() { let p = Command::new("cmd").args(&["/C", "exit 0"]).env_clear().spawn(); assert!(p.is_ok()); } + +// See issue #91991 +#[test] +#[cfg(windows)] +fn run_bat_script() { + let tempdir = crate::sys_common::io::test::tmpdir(); + let script_path = tempdir.join("hello.cmd"); + + crate::fs::write(&script_path, "@echo Hello, %~1!").unwrap(); + let output = Command::new(&script_path) + .arg("fellow Rustaceans") + .stdout(crate::process::Stdio::piped()) + .spawn() + .unwrap() + .wait_with_output() + .unwrap(); + assert!(output.status.success()); + assert_eq!(String::from_utf8_lossy(&output.stdout).trim(), "Hello, fellow Rustaceans!"); +} diff --git a/library/std/src/sys/windows/process.rs b/library/std/src/sys/windows/process.rs index 66b210ce1bfb3..e84dfbce4a754 100644 --- a/library/std/src/sys/windows/process.rs +++ b/library/std/src/sys/windows/process.rs @@ -704,6 +704,19 @@ fn make_command_line(prog: &OsStr, args: &[Arg], force_quotes: bool) -> io::Resu // Encode the command and arguments in a command line string such // that the spawned process may recover them using CommandLineToArgvW. let mut cmd: Vec = Vec::new(); + + // CreateFileW has special handling for .bat and .cmd files, which means we + // need to add an extra pair of quotes surrounding the whole command line + // so they are properly passed on to the script. + // See issue #91991. + let is_batch_file = Path::new(prog) + .extension() + .map(|ext| ext.eq_ignore_ascii_case("cmd") || ext.eq_ignore_ascii_case("bat")) + .unwrap_or(false); + if is_batch_file { + cmd.push(b'"' as u16); + } + // Always quote the program name so CreateProcess doesn't interpret args as // part of the name if the binary wasn't found first time. append_arg(&mut cmd, prog, Quote::Always)?; @@ -715,6 +728,9 @@ fn make_command_line(prog: &OsStr, args: &[Arg], force_quotes: bool) -> io::Resu }; append_arg(&mut cmd, arg, quote)?; } + if is_batch_file { + cmd.push(b'"' as u16); + } return Ok(cmd); fn append_arg(cmd: &mut Vec, arg: &OsStr, quote: Quote) -> io::Result<()> {