about summary refs log tree commit diff
path: root/library/std/src/sys
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2022-03-19 02:16:00 +0000
committerbors <bors@rust-lang.org>2022-03-19 02:16:00 +0000
commit31535841701e0bf7ef33998024376f2cedd8b3e3 (patch)
treee7324ba6fe7594fb039b2a4cd064ed457f43f57e /library/std/src/sys
parent9b701e7eaa08c2b2ef8c6e59b8b33436cb10aa45 (diff)
parent30b4182fa7ff8718335771b80a7687acb86f498a (diff)
downloadrust-31535841701e0bf7ef33998024376f2cedd8b3e3.tar.gz
rust-31535841701e0bf7ef33998024376f2cedd8b3e3.zip
Auto merge of #95101 - Dylan-DPC:rollup-r1f1v9t, r=Dylan-DPC
Rollup of 6 pull requests

Successful merges:

 - #92519 (Use verbatim paths for `process::Command` if necessary)
 - #92612 (Update stdlib for the l4re target)
 - #92663 (Implement `Write for Cursor<[u8; N]>`, plus `A: Allocator` cursor support)
 - #93263 (Consistently present absent stdio handles on Windows as NULL handles.)
 - #93692 (keyword_docs: document use of `in` with `pub` keyword)
 - #94984 (add `CStr` method that accepts any slice containing a nul-terminated string)

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup
Diffstat (limited to 'library/std/src/sys')
-rw-r--r--library/std/src/sys/unix/l4re.rs58
-rw-r--r--library/std/src/sys/unix/mod.rs1
-rw-r--r--library/std/src/sys/unix/process/process_unix.rs5
-rw-r--r--library/std/src/sys/windows/process.rs67
-rw-r--r--library/std/src/sys/windows/process/tests.rs7
5 files changed, 93 insertions, 45 deletions
diff --git a/library/std/src/sys/unix/l4re.rs b/library/std/src/sys/unix/l4re.rs
index d13e1ecbbfe..f052d8f7f05 100644
--- a/library/std/src/sys/unix/l4re.rs
+++ b/library/std/src/sys/unix/l4re.rs
@@ -13,6 +13,7 @@ pub mod net {
     use crate::fmt;
     use crate::io::{self, IoSlice, IoSliceMut};
     use crate::net::{Ipv4Addr, Ipv6Addr, Shutdown, SocketAddr};
+    use crate::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, RawFd};
     use crate::sys::fd::FileDesc;
     use crate::sys_common::{AsInner, FromInner, IntoInner};
     use crate::time::Duration;
@@ -59,7 +60,7 @@ pub mod net {
         }
 
         pub fn is_read_vectored(&self) -> bool {
-            unimpl!();
+            false
         }
 
         pub fn peek(&self, _: &mut [u8]) -> io::Result<usize> {
@@ -83,7 +84,7 @@ pub mod net {
         }
 
         pub fn is_write_vectored(&self) -> bool {
-            unimpl!();
+            false
         }
 
         pub fn set_timeout(&self, _: Option<Duration>, _: libc::c_int) -> io::Result<()> {
@@ -121,23 +122,52 @@ pub mod net {
         pub fn take_error(&self) -> io::Result<Option<io::Error>> {
             unimpl!();
         }
+
+        // This is used by sys_common code to abstract over Windows and Unix.
+        pub fn as_raw(&self) -> RawFd {
+            self.as_raw_fd()
+        }
+    }
+
+    impl AsInner<FileDesc> for Socket {
+        fn as_inner(&self) -> &FileDesc {
+            &self.0
+        }
+    }
+
+    impl FromInner<FileDesc> for Socket {
+        fn from_inner(file_desc: FileDesc) -> Socket {
+            Socket(file_desc)
+        }
     }
 
-    impl AsInner<libc::c_int> for Socket {
-        fn as_inner(&self) -> &libc::c_int {
-            self.0.as_inner()
+    impl IntoInner<FileDesc> for Socket {
+        fn into_inner(self) -> FileDesc {
+            self.0
         }
     }
 
-    impl FromInner<libc::c_int> for Socket {
-        fn from_inner(fd: libc::c_int) -> Socket {
-            Socket(FileDesc::new(fd))
+    impl AsFd for Socket {
+        fn as_fd(&self) -> BorrowedFd<'_> {
+            self.0.as_fd()
         }
     }
 
-    impl IntoInner<libc::c_int> for Socket {
-        fn into_inner(self) -> libc::c_int {
-            self.0.into_raw()
+    impl AsRawFd for Socket {
+        fn as_raw_fd(&self) -> RawFd {
+            self.0.as_raw_fd()
+        }
+    }
+
+    impl IntoRawFd for Socket {
+        fn into_raw_fd(self) -> RawFd {
+            self.0.into_raw_fd()
+        }
+    }
+
+    impl FromRawFd for Socket {
+        unsafe fn from_raw_fd(raw_fd: RawFd) -> Self {
+            Self(FromRawFd::from_raw_fd(raw_fd))
         }
     }
 
@@ -191,7 +221,7 @@ pub mod net {
         }
 
         pub fn is_read_vectored(&self) -> bool {
-            unimpl!();
+            false
         }
 
         pub fn write(&self, _: &[u8]) -> io::Result<usize> {
@@ -203,7 +233,7 @@ pub mod net {
         }
 
         pub fn is_write_vectored(&self) -> bool {
-            unimpl!();
+            false
         }
 
         pub fn peer_addr(&self) -> io::Result<SocketAddr> {
@@ -497,7 +527,7 @@ pub mod net {
 
     impl LookupHost {
         pub fn port(&self) -> u16 {
-            unimpl!();
+            0 // unimplemented
         }
     }
 
diff --git a/library/std/src/sys/unix/mod.rs b/library/std/src/sys/unix/mod.rs
index 605cc499b3c..7423d90263d 100644
--- a/library/std/src/sys/unix/mod.rs
+++ b/library/std/src/sys/unix/mod.rs
@@ -80,6 +80,7 @@ pub unsafe fn init(argc: isize, argv: *const *const u8) {
                 target_os = "macos",
                 target_os = "ios",
                 target_os = "redox",
+                target_os = "l4re",
             )))] {
                 use crate::sys::os::errno;
                 let pfds: &mut [_] = &mut [
diff --git a/library/std/src/sys/unix/process/process_unix.rs b/library/std/src/sys/unix/process/process_unix.rs
index 9d2803b40c4..2a97a802a20 100644
--- a/library/std/src/sys/unix/process/process_unix.rs
+++ b/library/std/src/sys/unix/process/process_unix.rs
@@ -27,7 +27,10 @@ use crate::sys::weak::weak;
 use libc::RTP_ID as pid_t;
 
 #[cfg(not(target_os = "vxworks"))]
-use libc::{c_int, gid_t, pid_t, uid_t};
+use libc::{c_int, pid_t};
+
+#[cfg(not(any(target_os = "vxworks", target_os = "l4re")))]
+use libc::{gid_t, uid_t};
 
 ////////////////////////////////////////////////////////////////////////////////
 // Command
diff --git a/library/std/src/sys/windows/process.rs b/library/std/src/sys/windows/process.rs
index fafd1412d4c..a13585a0222 100644
--- a/library/std/src/sys/windows/process.rs
+++ b/library/std/src/sys/windows/process.rs
@@ -19,12 +19,12 @@ use crate::path::{Path, PathBuf};
 use crate::ptr;
 use crate::sys::c;
 use crate::sys::c::NonZeroDWORD;
+use crate::sys::cvt;
 use crate::sys::fs::{File, OpenOptions};
 use crate::sys::handle::Handle;
 use crate::sys::path;
 use crate::sys::pipe::{self, AnonPipe};
 use crate::sys::stdio;
-use crate::sys::{cvt, to_u16s};
 use crate::sys_common::mutex::StaticMutex;
 use crate::sys_common::process::{CommandEnv, CommandEnvs};
 use crate::sys_common::{AsInner, IntoInner};
@@ -269,8 +269,13 @@ impl Command {
             None
         };
         let program = resolve_exe(&self.program, || env::var_os("PATH"), child_paths)?;
+        // Case insensitive "ends_with" of UTF-16 encoded ".bat" or ".cmd"
+        let is_batch_file = matches!(
+            program.len().checked_sub(5).and_then(|i| program.get(i..)),
+            Some([46, 98 | 66, 97 | 65, 116 | 84, 0] | [46, 99 | 67, 109 | 77, 100 | 68, 0])
+        );
         let mut cmd_str =
-            make_command_line(program.as_os_str(), &self.args, self.force_quotes_enabled)?;
+            make_command_line(&program, &self.args, self.force_quotes_enabled, is_batch_file)?;
         cmd_str.push(0); // add null terminator
 
         // stolen from the libuv code.
@@ -309,7 +314,6 @@ impl Command {
         si.hStdOutput = stdout.as_raw_handle();
         si.hStdError = stderr.as_raw_handle();
 
-        let program = to_u16s(&program)?;
         unsafe {
             cvt(c::CreateProcessW(
                 program.as_ptr(),
@@ -366,7 +370,7 @@ fn resolve_exe<'a>(
     exe_path: &'a OsStr,
     parent_paths: impl FnOnce() -> Option<OsString>,
     child_paths: Option<&OsStr>,
-) -> io::Result<PathBuf> {
+) -> io::Result<Vec<u16>> {
     // Early return if there is no filename.
     if exe_path.is_empty() || path::has_trailing_slash(exe_path) {
         return Err(io::const_io_error!(
@@ -388,19 +392,19 @@ fn resolve_exe<'a>(
         if has_exe_suffix {
             // The application name is a path to a `.exe` file.
             // Let `CreateProcessW` figure out if it exists or not.
-            return Ok(exe_path.into());
+            return path::maybe_verbatim(Path::new(exe_path));
         }
         let mut path = PathBuf::from(exe_path);
 
         // Append `.exe` if not already there.
         path = path::append_suffix(path, EXE_SUFFIX.as_ref());
-        if program_exists(&path) {
+        if let Some(path) = program_exists(&path) {
             return Ok(path);
         } else {
             // It's ok to use `set_extension` here because the intent is to
             // remove the extension that was just added.
             path.set_extension("");
-            return Ok(path);
+            return path::maybe_verbatim(&path);
         }
     } else {
         ensure_no_nuls(exe_path)?;
@@ -415,7 +419,7 @@ fn resolve_exe<'a>(
             if !has_extension {
                 path.set_extension(EXE_EXTENSION);
             }
-            if program_exists(&path) { Some(path) } else { None }
+            program_exists(&path)
         });
         if let Some(path) = result {
             return Ok(path);
@@ -431,10 +435,10 @@ fn search_paths<Paths, Exists>(
     parent_paths: Paths,
     child_paths: Option<&OsStr>,
     mut exists: Exists,
-) -> Option<PathBuf>
+) -> Option<Vec<u16>>
 where
     Paths: FnOnce() -> Option<OsString>,
-    Exists: FnMut(PathBuf) -> Option<PathBuf>,
+    Exists: FnMut(PathBuf) -> Option<Vec<u16>>,
 {
     // 1. Child paths
     // This is for consistency with Rust's historic behaviour.
@@ -486,17 +490,18 @@ where
 }
 
 /// Check if a file exists without following symlinks.
-fn program_exists(path: &Path) -> bool {
+fn program_exists(path: &Path) -> Option<Vec<u16>> {
     unsafe {
-        to_u16s(path)
-            .map(|path| {
-                // Getting attributes using `GetFileAttributesW` does not follow symlinks
-                // and it will almost always be successful if the link exists.
-                // There are some exceptions for special system files (e.g. the pagefile)
-                // but these are not executable.
-                c::GetFileAttributesW(path.as_ptr()) != c::INVALID_FILE_ATTRIBUTES
-            })
-            .unwrap_or(false)
+        let path = path::maybe_verbatim(path).ok()?;
+        // Getting attributes using `GetFileAttributesW` does not follow symlinks
+        // and it will almost always be successful if the link exists.
+        // There are some exceptions for special system files (e.g. the pagefile)
+        // but these are not executable.
+        if c::GetFileAttributesW(path.as_ptr()) == c::INVALID_FILE_ATTRIBUTES {
+            None
+        } else {
+            Some(path)
+        }
     }
 }
 
@@ -730,7 +735,12 @@ enum Quote {
 
 // Produces a wide string *without terminating null*; returns an error if
 // `prog` or any of the `args` contain a nul.
-fn make_command_line(prog: &OsStr, args: &[Arg], force_quotes: bool) -> io::Result<Vec<u16>> {
+fn make_command_line(
+    prog: &[u16],
+    args: &[Arg],
+    force_quotes: bool,
+    is_batch_file: bool,
+) -> io::Result<Vec<u16>> {
     // Encode the command and arguments in a command line string such
     // that the spawned process may recover them using CommandLineToArgvW.
     let mut cmd: Vec<u16> = Vec::new();
@@ -739,17 +749,18 @@ fn make_command_line(prog: &OsStr, args: &[Arg], force_quotes: bool) -> io::Resu
     // 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)?;
+    // Always quote the program name so CreateProcess to avoid ambiguity when
+    // the child process parses its arguments.
+    // Note that quotes aren't escaped here because they can't be used in arg0.
+    // But that's ok because file paths can't contain quotes.
+    cmd.push(b'"' as u16);
+    cmd.extend_from_slice(prog.strip_suffix(&[0]).unwrap_or(prog));
+    cmd.push(b'"' as u16);
+
     for arg in args {
         cmd.push(' ' as u16);
         let (arg, quote) = match arg {
diff --git a/library/std/src/sys/windows/process/tests.rs b/library/std/src/sys/windows/process/tests.rs
index d8c9beb0c19..96477fb19da 100644
--- a/library/std/src/sys/windows/process/tests.rs
+++ b/library/std/src/sys/windows/process/tests.rs
@@ -3,11 +3,12 @@ use super::Arg;
 use crate::env;
 use crate::ffi::{OsStr, OsString};
 use crate::process::Command;
+use crate::sys::to_u16s;
 
 #[test]
 fn test_raw_args() {
     let command_line = &make_command_line(
-        OsStr::new("quoted exe"),
+        &to_u16s("quoted exe").unwrap(),
         &[
             Arg::Regular(OsString::from("quote me")),
             Arg::Raw(OsString::from("quote me *not*")),
@@ -16,6 +17,7 @@ fn test_raw_args() {
             Arg::Regular(OsString::from("optional-quotes")),
         ],
         false,
+        false,
     )
     .unwrap();
     assert_eq!(
@@ -28,9 +30,10 @@ fn test_raw_args() {
 fn test_make_command_line() {
     fn test_wrapper(prog: &str, args: &[&str], force_quotes: bool) -> String {
         let command_line = &make_command_line(
-            OsStr::new(prog),
+            &to_u16s(prog).unwrap(),
             &args.iter().map(|a| Arg::Regular(OsString::from(a))).collect::<Vec<_>>(),
             force_quotes,
+            false,
         )
         .unwrap();
         String::from_utf16(command_line).unwrap()