From edfc74722556c659de6fa03b23af3b9c8ceb8ac2 Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Mon, 24 Mar 2025 18:57:07 +0000 Subject: Avoid verbatim paths in Command::current_dir If possible, we should try not to use verbatim paths in Command::current_dir. It might work but it might also break code (including some Windows APIs) that assume the current directory isn't verbatim. --- library/std/src/sys/process/windows.rs | 32 ++++++++++++++++++++++++++++---- 1 file changed, 28 insertions(+), 4 deletions(-) (limited to 'library/std/src/sys/process') diff --git a/library/std/src/sys/process/windows.rs b/library/std/src/sys/process/windows.rs index 06c15e08f3f..4cfdf908c58 100644 --- a/library/std/src/sys/process/windows.rs +++ b/library/std/src/sys/process/windows.rs @@ -19,7 +19,7 @@ use crate::sys::args::{self, Arg}; use crate::sys::c::{self, EXIT_FAILURE, EXIT_SUCCESS}; use crate::sys::fs::{File, OpenOptions}; use crate::sys::handle::Handle; -use crate::sys::pal::api::{self, WinError}; +use crate::sys::pal::api::{self, WinError, utf16}; use crate::sys::pal::{ensure_no_nuls, fill_utf16_buf}; use crate::sys::pipe::{self, AnonPipe}; use crate::sys::{cvt, path, stdio}; @@ -880,9 +880,33 @@ fn make_envp(maybe_env: Option>) -> io::Result<(*mut fn make_dirp(d: Option<&OsString>) -> io::Result<(*const u16, Vec)> { match d { Some(dir) => { - let mut dir_str: Vec = ensure_no_nuls(dir)?.encode_wide().collect(); - dir_str.push(0); - Ok((dir_str.as_ptr(), dir_str)) + let mut dir_str: Vec = ensure_no_nuls(dir)?.encode_wide().chain([0]).collect(); + // Try to remove the `\\?\` prefix, if any. + // This is necessary because the current directory does not support verbatim paths. + // However. this can only be done if it doesn't change how the path will be resolved. + let ptr = if dir_str.starts_with(utf16!(r"\\?\UNC")) { + // Turn the `C` in `UNC` into a `\` so we can then use `\\rest\of\path`. + let start = r"\\?\UN".len(); + dir_str[start] = b'\\' as u16; + if path::is_absolute_exact(&dir_str[start..]) { + dir_str[start..].as_ptr() + } else { + // Revert the above change. + dir_str[start] = b'C' as u16; + dir_str.as_ptr() + } + } else if dir_str.starts_with(utf16!(r"\\?\")) { + // Strip the leading `\\?\` + let start = r"\\?\".len(); + if path::is_absolute_exact(&dir_str[start..]) { + dir_str[start..].as_ptr() + } else { + dir_str.as_ptr() + } + } else { + dir_str.as_ptr() + }; + Ok((ptr, dir_str)) } None => Ok((ptr::null(), Vec::new())), } -- cgit 1.4.1-3-g733a5