about summary refs log tree commit diff
path: root/library/std/src/sys/process
diff options
context:
space:
mode:
authorMatthias Krüger <476013+matthiaskrgr@users.noreply.github.com>2025-04-09 14:52:36 +0200
committerGitHub <noreply@github.com>2025-04-09 14:52:36 +0200
commit9e541c46733200a5ab5b6cbaf2b5c15249cda843 (patch)
tree87d4f535be882e940a6aab8f7fa3ec098fed8643 /library/std/src/sys/process
parentf06e5c1e35bc5bc6131c6f8a0eb782097e3f28c3 (diff)
parentedfc74722556c659de6fa03b23af3b9c8ceb8ac2 (diff)
Rollup merge of #138869 - ChrisDenton:command-curdir, r=tgross35
Try not to use 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 in the subprocess that assume the current directory isn't verbatim (including Windows APIs). cc ``@ehuss``

Side note: we now have a lot of ad-hoc fixes like this spread about the place. It'd be good to make a proper `WindowsPath` type that handles all this in one place. But that's a bigger job for another PR.
Diffstat (limited to 'library/std/src/sys/process')
-rw-r--r--library/std/src/sys/process/windows.rs32
1 files changed, 28 insertions, 4 deletions
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<BTreeMap<EnvKey, OsString>>) -> io::Result<(*mut
 fn make_dirp(d: Option<&OsString>) -> io::Result<(*const u16, Vec<u16>)> {
     match d {
         Some(dir) => {
-            let mut dir_str: Vec<u16> = ensure_no_nuls(dir)?.encode_wide().collect();
-            dir_str.push(0);
-            Ok((dir_str.as_ptr(), dir_str))
+            let mut dir_str: Vec<u16> = 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())),
     }