summaryrefslogtreecommitdiffstats
path: root/library/std/src/os/windows
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:02:58 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:02:58 +0000
commit698f8c2f01ea549d77d7dc3338a12e04c11057b9 (patch)
tree173a775858bd501c378080a10dca74132f05bc50 /library/std/src/os/windows
parentInitial commit. (diff)
downloadrustc-698f8c2f01ea549d77d7dc3338a12e04c11057b9.tar.xz
rustc-698f8c2f01ea549d77d7dc3338a12e04c11057b9.zip
Adding upstream version 1.64.0+dfsg1.upstream/1.64.0+dfsg1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'library/std/src/os/windows')
-rw-r--r--library/std/src/os/windows/ffi.rs136
-rw-r--r--library/std/src/os/windows/fs.rs605
-rw-r--r--library/std/src/os/windows/io/handle.rs576
-rw-r--r--library/std/src/os/windows/io/mod.rs65
-rw-r--r--library/std/src/os/windows/io/raw.rs305
-rw-r--r--library/std/src/os/windows/io/socket.rs338
-rw-r--r--library/std/src/os/windows/io/tests.rs21
-rw-r--r--library/std/src/os/windows/mod.rs58
-rw-r--r--library/std/src/os/windows/process.rs259
-rw-r--r--library/std/src/os/windows/raw.rs16
-rw-r--r--library/std/src/os/windows/thread.rs25
11 files changed, 2404 insertions, 0 deletions
diff --git a/library/std/src/os/windows/ffi.rs b/library/std/src/os/windows/ffi.rs
new file mode 100644
index 000000000..96bab59d3
--- /dev/null
+++ b/library/std/src/os/windows/ffi.rs
@@ -0,0 +1,136 @@
+//! Windows-specific extensions to primitives in the [`std::ffi`] module.
+//!
+//! # Overview
+//!
+//! For historical reasons, the Windows API uses a form of potentially
+//! ill-formed UTF-16 encoding for strings. Specifically, the 16-bit
+//! code units in Windows strings may contain [isolated surrogate code
+//! points which are not paired together][ill-formed-utf-16]. The
+//! Unicode standard requires that surrogate code points (those in the
+//! range U+D800 to U+DFFF) always be *paired*, because in the UTF-16
+//! encoding a *surrogate code unit pair* is used to encode a single
+//! character. For compatibility with code that does not enforce
+//! these pairings, Windows does not enforce them, either.
+//!
+//! While it is not always possible to convert such a string losslessly into
+//! a valid UTF-16 string (or even UTF-8), it is often desirable to be
+//! able to round-trip such a string from and to Windows APIs
+//! losslessly. For example, some Rust code may be "bridging" some
+//! Windows APIs together, just passing `WCHAR` strings among those
+//! APIs without ever really looking into the strings.
+//!
+//! If Rust code *does* need to look into those strings, it can
+//! convert them to valid UTF-8, possibly lossily, by substituting
+//! invalid sequences with [`U+FFFD REPLACEMENT CHARACTER`][U+FFFD], as is
+//! conventionally done in other Rust APIs that deal with string
+//! encodings.
+//!
+//! # `OsStringExt` and `OsStrExt`
+//!
+//! [`OsString`] is the Rust wrapper for owned strings in the
+//! preferred representation of the operating system. On Windows,
+//! this struct gets augmented with an implementation of the
+//! [`OsStringExt`] trait, which has an [`OsStringExt::from_wide`] method. This
+//! lets you create an [`OsString`] from a `&[u16]` slice; presumably
+//! you get such a slice out of a `WCHAR` Windows API.
+//!
+//! Similarly, [`OsStr`] is the Rust wrapper for borrowed strings from
+//! preferred representation of the operating system. On Windows, the
+//! [`OsStrExt`] trait provides the [`OsStrExt::encode_wide`] method, which
+//! outputs an [`EncodeWide`] iterator. You can [`collect`] this
+//! iterator, for example, to obtain a `Vec<u16>`; you can later get a
+//! pointer to this vector's contents and feed it to Windows APIs.
+//!
+//! These traits, along with [`OsString`] and [`OsStr`], work in
+//! conjunction so that it is possible to **round-trip** strings from
+//! Windows and back, with no loss of data, even if the strings are
+//! ill-formed UTF-16.
+//!
+//! [ill-formed-utf-16]: https://simonsapin.github.io/wtf-8/#ill-formed-utf-16
+//! [`collect`]: crate::iter::Iterator::collect
+//! [U+FFFD]: crate::char::REPLACEMENT_CHARACTER
+//! [`std::ffi`]: crate::ffi
+
+#![stable(feature = "rust1", since = "1.0.0")]
+
+use crate::ffi::{OsStr, OsString};
+use crate::sealed::Sealed;
+use crate::sys::os_str::Buf;
+use crate::sys_common::wtf8::Wtf8Buf;
+use crate::sys_common::{AsInner, FromInner};
+
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use crate::sys_common::wtf8::EncodeWide;
+
+/// Windows-specific extensions to [`OsString`].
+///
+/// This trait is sealed: it cannot be implemented outside the standard library.
+/// This is so that future additional methods are not breaking changes.
+#[stable(feature = "rust1", since = "1.0.0")]
+pub trait OsStringExt: Sealed {
+ /// Creates an `OsString` from a potentially ill-formed UTF-16 slice of
+ /// 16-bit code units.
+ ///
+ /// This is lossless: calling [`OsStrExt::encode_wide`] on the resulting string
+ /// will always return the original code units.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::ffi::OsString;
+ /// use std::os::windows::prelude::*;
+ ///
+ /// // UTF-16 encoding for "Unicode".
+ /// let source = [0x0055, 0x006E, 0x0069, 0x0063, 0x006F, 0x0064, 0x0065];
+ ///
+ /// let string = OsString::from_wide(&source[..]);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ fn from_wide(wide: &[u16]) -> Self;
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl OsStringExt for OsString {
+ fn from_wide(wide: &[u16]) -> OsString {
+ FromInner::from_inner(Buf { inner: Wtf8Buf::from_wide(wide) })
+ }
+}
+
+/// Windows-specific extensions to [`OsStr`].
+///
+/// This trait is sealed: it cannot be implemented outside the standard library.
+/// This is so that future additional methods are not breaking changes.
+#[stable(feature = "rust1", since = "1.0.0")]
+pub trait OsStrExt: Sealed {
+ /// Re-encodes an `OsStr` as a wide character sequence, i.e., potentially
+ /// ill-formed UTF-16.
+ ///
+ /// This is lossless: calling [`OsStringExt::from_wide`] and then
+ /// `encode_wide` on the result will yield the original code units.
+ /// Note that the encoding does not add a final null terminator.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::ffi::OsString;
+ /// use std::os::windows::prelude::*;
+ ///
+ /// // UTF-16 encoding for "Unicode".
+ /// let source = [0x0055, 0x006E, 0x0069, 0x0063, 0x006F, 0x0064, 0x0065];
+ ///
+ /// let string = OsString::from_wide(&source[..]);
+ ///
+ /// let result: Vec<u16> = string.encode_wide().collect();
+ /// assert_eq!(&source[..], &result[..]);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ fn encode_wide(&self) -> EncodeWide<'_>;
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl OsStrExt for OsStr {
+ #[inline]
+ fn encode_wide(&self) -> EncodeWide<'_> {
+ self.as_inner().inner.encode_wide()
+ }
+}
diff --git a/library/std/src/os/windows/fs.rs b/library/std/src/os/windows/fs.rs
new file mode 100644
index 000000000..a091f06dd
--- /dev/null
+++ b/library/std/src/os/windows/fs.rs
@@ -0,0 +1,605 @@
+//! Windows-specific extensions to primitives in the [`std::fs`] module.
+//!
+//! [`std::fs`]: crate::fs
+
+#![stable(feature = "rust1", since = "1.0.0")]
+
+use crate::fs::{self, Metadata, OpenOptions};
+use crate::io;
+use crate::path::Path;
+use crate::sealed::Sealed;
+use crate::sys;
+use crate::sys_common::{AsInner, AsInnerMut};
+
+/// Windows-specific extensions to [`fs::File`].
+#[stable(feature = "file_offset", since = "1.15.0")]
+pub trait FileExt {
+ /// Seeks to a given position and reads a number of bytes.
+ ///
+ /// Returns the number of bytes read.
+ ///
+ /// The offset is relative to the start of the file and thus independent
+ /// from the current cursor. The current cursor **is** affected by this
+ /// function, it is set to the end of the read.
+ ///
+ /// Reading beyond the end of the file will always return with a length of
+ /// 0\.
+ ///
+ /// Note that similar to `File::read`, it is not an error to return with a
+ /// short read. When returning from such a short read, the file pointer is
+ /// still updated.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::io;
+ /// use std::fs::File;
+ /// use std::os::windows::prelude::*;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let mut file = File::open("foo.txt")?;
+ /// let mut buffer = [0; 10];
+ ///
+ /// // Read 10 bytes, starting 72 bytes from the
+ /// // start of the file.
+ /// file.seek_read(&mut buffer[..], 72)?;
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "file_offset", since = "1.15.0")]
+ fn seek_read(&self, buf: &mut [u8], offset: u64) -> io::Result<usize>;
+
+ /// Seeks to a given position and writes a number of bytes.
+ ///
+ /// Returns the number of bytes written.
+ ///
+ /// The offset is relative to the start of the file and thus independent
+ /// from the current cursor. The current cursor **is** affected by this
+ /// function, it is set to the end of the write.
+ ///
+ /// When writing beyond the end of the file, the file is appropriately
+ /// extended and the intermediate bytes are left uninitialized.
+ ///
+ /// Note that similar to `File::write`, it is not an error to return a
+ /// short write. When returning from such a short write, the file pointer
+ /// is still updated.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs::File;
+ /// use std::os::windows::prelude::*;
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let mut buffer = File::create("foo.txt")?;
+ ///
+ /// // Write a byte string starting 72 bytes from
+ /// // the start of the file.
+ /// buffer.seek_write(b"some bytes", 72)?;
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "file_offset", since = "1.15.0")]
+ fn seek_write(&self, buf: &[u8], offset: u64) -> io::Result<usize>;
+}
+
+#[stable(feature = "file_offset", since = "1.15.0")]
+impl FileExt for fs::File {
+ fn seek_read(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> {
+ self.as_inner().read_at(buf, offset)
+ }
+
+ fn seek_write(&self, buf: &[u8], offset: u64) -> io::Result<usize> {
+ self.as_inner().write_at(buf, offset)
+ }
+}
+
+/// Windows-specific extensions to [`fs::OpenOptions`].
+#[stable(feature = "open_options_ext", since = "1.10.0")]
+pub trait OpenOptionsExt {
+ /// Overrides the `dwDesiredAccess` argument to the call to [`CreateFile`]
+ /// with the specified value.
+ ///
+ /// This will override the `read`, `write`, and `append` flags on the
+ /// `OpenOptions` structure. This method provides fine-grained control over
+ /// the permissions to read, write and append data, attributes (like hidden
+ /// and system), and extended attributes.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs::OpenOptions;
+ /// use std::os::windows::prelude::*;
+ ///
+ /// // Open without read and write permission, for example if you only need
+ /// // to call `stat` on the file
+ /// let file = OpenOptions::new().access_mode(0).open("foo.txt");
+ /// ```
+ ///
+ /// [`CreateFile`]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilea
+ #[stable(feature = "open_options_ext", since = "1.10.0")]
+ fn access_mode(&mut self, access: u32) -> &mut Self;
+
+ /// Overrides the `dwShareMode` argument to the call to [`CreateFile`] with
+ /// the specified value.
+ ///
+ /// By default `share_mode` is set to
+ /// `FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE`. This allows
+ /// other processes to read, write, and delete/rename the same file
+ /// while it is open. Removing any of the flags will prevent other
+ /// processes from performing the corresponding operation until the file
+ /// handle is closed.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs::OpenOptions;
+ /// use std::os::windows::prelude::*;
+ ///
+ /// // Do not allow others to read or modify this file while we have it open
+ /// // for writing.
+ /// let file = OpenOptions::new()
+ /// .write(true)
+ /// .share_mode(0)
+ /// .open("foo.txt");
+ /// ```
+ ///
+ /// [`CreateFile`]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilea
+ #[stable(feature = "open_options_ext", since = "1.10.0")]
+ fn share_mode(&mut self, val: u32) -> &mut Self;
+
+ /// Sets extra flags for the `dwFileFlags` argument to the call to
+ /// [`CreateFile2`] to the specified value (or combines it with
+ /// `attributes` and `security_qos_flags` to set the `dwFlagsAndAttributes`
+ /// for [`CreateFile`]).
+ ///
+ /// Custom flags can only set flags, not remove flags set by Rust's options.
+ /// This option overwrites any previously set custom flags.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// # #![allow(unexpected_cfgs)]
+ /// # #[cfg(for_demonstration_only)]
+ /// extern crate winapi;
+ /// # mod winapi { pub const FILE_FLAG_DELETE_ON_CLOSE: u32 = 0x04000000; }
+ ///
+ /// use std::fs::OpenOptions;
+ /// use std::os::windows::prelude::*;
+ ///
+ /// let file = OpenOptions::new()
+ /// .create(true)
+ /// .write(true)
+ /// .custom_flags(winapi::FILE_FLAG_DELETE_ON_CLOSE)
+ /// .open("foo.txt");
+ /// ```
+ ///
+ /// [`CreateFile`]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilea
+ /// [`CreateFile2`]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfile2
+ #[stable(feature = "open_options_ext", since = "1.10.0")]
+ fn custom_flags(&mut self, flags: u32) -> &mut Self;
+
+ /// Sets the `dwFileAttributes` argument to the call to [`CreateFile2`] to
+ /// the specified value (or combines it with `custom_flags` and
+ /// `security_qos_flags` to set the `dwFlagsAndAttributes` for
+ /// [`CreateFile`]).
+ ///
+ /// If a _new_ file is created because it does not yet exist and
+ /// `.create(true)` or `.create_new(true)` are specified, the new file is
+ /// given the attributes declared with `.attributes()`.
+ ///
+ /// If an _existing_ file is opened with `.create(true).truncate(true)`, its
+ /// existing attributes are preserved and combined with the ones declared
+ /// with `.attributes()`.
+ ///
+ /// In all other cases the attributes get ignored.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// # #![allow(unexpected_cfgs)]
+ /// # #[cfg(for_demonstration_only)]
+ /// extern crate winapi;
+ /// # mod winapi { pub const FILE_ATTRIBUTE_HIDDEN: u32 = 2; }
+ ///
+ /// use std::fs::OpenOptions;
+ /// use std::os::windows::prelude::*;
+ ///
+ /// let file = OpenOptions::new()
+ /// .write(true)
+ /// .create(true)
+ /// .attributes(winapi::FILE_ATTRIBUTE_HIDDEN)
+ /// .open("foo.txt");
+ /// ```
+ ///
+ /// [`CreateFile`]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilea
+ /// [`CreateFile2`]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfile2
+ #[stable(feature = "open_options_ext", since = "1.10.0")]
+ fn attributes(&mut self, val: u32) -> &mut Self;
+
+ /// Sets the `dwSecurityQosFlags` argument to the call to [`CreateFile2`] to
+ /// the specified value (or combines it with `custom_flags` and `attributes`
+ /// to set the `dwFlagsAndAttributes` for [`CreateFile`]).
+ ///
+ /// By default `security_qos_flags` is not set. It should be specified when
+ /// opening a named pipe, to control to which degree a server process can
+ /// act on behalf of a client process (security impersonation level).
+ ///
+ /// When `security_qos_flags` is not set, a malicious program can gain the
+ /// elevated privileges of a privileged Rust process when it allows opening
+ /// user-specified paths, by tricking it into opening a named pipe. So
+ /// arguably `security_qos_flags` should also be set when opening arbitrary
+ /// paths. However the bits can then conflict with other flags, specifically
+ /// `FILE_FLAG_OPEN_NO_RECALL`.
+ ///
+ /// For information about possible values, see [Impersonation Levels] on the
+ /// Windows Dev Center site. The `SECURITY_SQOS_PRESENT` flag is set
+ /// automatically when using this method.
+
+ /// # Examples
+ ///
+ /// ```no_run
+ /// # #![allow(unexpected_cfgs)]
+ /// # #[cfg(for_demonstration_only)]
+ /// extern crate winapi;
+ /// # mod winapi { pub const SECURITY_IDENTIFICATION: u32 = 0; }
+ /// use std::fs::OpenOptions;
+ /// use std::os::windows::prelude::*;
+ ///
+ /// let file = OpenOptions::new()
+ /// .write(true)
+ /// .create(true)
+ ///
+ /// // Sets the flag value to `SecurityIdentification`.
+ /// .security_qos_flags(winapi::SECURITY_IDENTIFICATION)
+ ///
+ /// .open(r"\\.\pipe\MyPipe");
+ /// ```
+ ///
+ /// [`CreateFile`]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilea
+ /// [`CreateFile2`]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfile2
+ /// [Impersonation Levels]:
+ /// https://docs.microsoft.com/en-us/windows/win32/api/winnt/ne-winnt-security_impersonation_level
+ #[stable(feature = "open_options_ext", since = "1.10.0")]
+ fn security_qos_flags(&mut self, flags: u32) -> &mut Self;
+}
+
+#[stable(feature = "open_options_ext", since = "1.10.0")]
+impl OpenOptionsExt for OpenOptions {
+ fn access_mode(&mut self, access: u32) -> &mut OpenOptions {
+ self.as_inner_mut().access_mode(access);
+ self
+ }
+
+ fn share_mode(&mut self, share: u32) -> &mut OpenOptions {
+ self.as_inner_mut().share_mode(share);
+ self
+ }
+
+ fn custom_flags(&mut self, flags: u32) -> &mut OpenOptions {
+ self.as_inner_mut().custom_flags(flags);
+ self
+ }
+
+ fn attributes(&mut self, attributes: u32) -> &mut OpenOptions {
+ self.as_inner_mut().attributes(attributes);
+ self
+ }
+
+ fn security_qos_flags(&mut self, flags: u32) -> &mut OpenOptions {
+ self.as_inner_mut().security_qos_flags(flags);
+ self
+ }
+}
+
+/// Windows-specific extensions to [`fs::Metadata`].
+///
+/// The data members that this trait exposes correspond to the members
+/// of the [`BY_HANDLE_FILE_INFORMATION`] structure.
+///
+/// [`BY_HANDLE_FILE_INFORMATION`]:
+/// https://docs.microsoft.com/en-us/windows/win32/api/fileapi/ns-fileapi-by_handle_file_information
+#[stable(feature = "metadata_ext", since = "1.1.0")]
+pub trait MetadataExt {
+ /// Returns the value of the `dwFileAttributes` field of this metadata.
+ ///
+ /// This field contains the file system attribute information for a file
+ /// or directory. For possible values and their descriptions, see
+ /// [File Attribute Constants] in the Windows Dev Center.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::io;
+ /// use std::fs;
+ /// use std::os::windows::prelude::*;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let metadata = fs::metadata("foo.txt")?;
+ /// let attributes = metadata.file_attributes();
+ /// Ok(())
+ /// }
+ /// ```
+ ///
+ /// [File Attribute Constants]:
+ /// https://docs.microsoft.com/en-us/windows/win32/fileio/file-attribute-constants
+ #[stable(feature = "metadata_ext", since = "1.1.0")]
+ fn file_attributes(&self) -> u32;
+
+ /// Returns the value of the `ftCreationTime` field of this metadata.
+ ///
+ /// The returned 64-bit value is equivalent to a [`FILETIME`] struct,
+ /// which represents the number of 100-nanosecond intervals since
+ /// January 1, 1601 (UTC). The struct is automatically
+ /// converted to a `u64` value, as that is the recommended way
+ /// to use it.
+ ///
+ /// If the underlying filesystem does not support creation time, the
+ /// returned value is 0.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::io;
+ /// use std::fs;
+ /// use std::os::windows::prelude::*;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let metadata = fs::metadata("foo.txt")?;
+ /// let creation_time = metadata.creation_time();
+ /// Ok(())
+ /// }
+ /// ```
+ ///
+ /// [`FILETIME`]: https://docs.microsoft.com/en-us/windows/win32/api/minwinbase/ns-minwinbase-filetime
+ #[stable(feature = "metadata_ext", since = "1.1.0")]
+ fn creation_time(&self) -> u64;
+
+ /// Returns the value of the `ftLastAccessTime` field of this metadata.
+ ///
+ /// The returned 64-bit value is equivalent to a [`FILETIME`] struct,
+ /// which represents the number of 100-nanosecond intervals since
+ /// January 1, 1601 (UTC). The struct is automatically
+ /// converted to a `u64` value, as that is the recommended way
+ /// to use it.
+ ///
+ /// For a file, the value specifies the last time that a file was read
+ /// from or written to. For a directory, the value specifies when
+ /// the directory was created. For both files and directories, the
+ /// specified date is correct, but the time of day is always set to
+ /// midnight.
+ ///
+ /// If the underlying filesystem does not support last access time, the
+ /// returned value is 0.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::io;
+ /// use std::fs;
+ /// use std::os::windows::prelude::*;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let metadata = fs::metadata("foo.txt")?;
+ /// let last_access_time = metadata.last_access_time();
+ /// Ok(())
+ /// }
+ /// ```
+ ///
+ /// [`FILETIME`]: https://docs.microsoft.com/en-us/windows/win32/api/minwinbase/ns-minwinbase-filetime
+ #[stable(feature = "metadata_ext", since = "1.1.0")]
+ fn last_access_time(&self) -> u64;
+
+ /// Returns the value of the `ftLastWriteTime` field of this metadata.
+ ///
+ /// The returned 64-bit value is equivalent to a [`FILETIME`] struct,
+ /// which represents the number of 100-nanosecond intervals since
+ /// January 1, 1601 (UTC). The struct is automatically
+ /// converted to a `u64` value, as that is the recommended way
+ /// to use it.
+ ///
+ /// For a file, the value specifies the last time that a file was written
+ /// to. For a directory, the structure specifies when the directory was
+ /// created.
+ ///
+ /// If the underlying filesystem does not support the last write time,
+ /// the returned value is 0.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::io;
+ /// use std::fs;
+ /// use std::os::windows::prelude::*;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let metadata = fs::metadata("foo.txt")?;
+ /// let last_write_time = metadata.last_write_time();
+ /// Ok(())
+ /// }
+ /// ```
+ ///
+ /// [`FILETIME`]: https://docs.microsoft.com/en-us/windows/win32/api/minwinbase/ns-minwinbase-filetime
+ #[stable(feature = "metadata_ext", since = "1.1.0")]
+ fn last_write_time(&self) -> u64;
+
+ /// Returns the value of the `nFileSize{High,Low}` fields of this
+ /// metadata.
+ ///
+ /// The returned value does not have meaning for directories.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::io;
+ /// use std::fs;
+ /// use std::os::windows::prelude::*;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let metadata = fs::metadata("foo.txt")?;
+ /// let file_size = metadata.file_size();
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext", since = "1.1.0")]
+ fn file_size(&self) -> u64;
+
+ /// Returns the value of the `dwVolumeSerialNumber` field of this
+ /// metadata.
+ ///
+ /// This will return `None` if the `Metadata` instance was created from a
+ /// call to `DirEntry::metadata`. If this `Metadata` was created by using
+ /// `fs::metadata` or `File::metadata`, then this will return `Some`.
+ #[unstable(feature = "windows_by_handle", issue = "63010")]
+ fn volume_serial_number(&self) -> Option<u32>;
+
+ /// Returns the value of the `nNumberOfLinks` field of this
+ /// metadata.
+ ///
+ /// This will return `None` if the `Metadata` instance was created from a
+ /// call to `DirEntry::metadata`. If this `Metadata` was created by using
+ /// `fs::metadata` or `File::metadata`, then this will return `Some`.
+ #[unstable(feature = "windows_by_handle", issue = "63010")]
+ fn number_of_links(&self) -> Option<u32>;
+
+ /// Returns the value of the `nFileIndex{Low,High}` fields of this
+ /// metadata.
+ ///
+ /// This will return `None` if the `Metadata` instance was created from a
+ /// call to `DirEntry::metadata`. If this `Metadata` was created by using
+ /// `fs::metadata` or `File::metadata`, then this will return `Some`.
+ #[unstable(feature = "windows_by_handle", issue = "63010")]
+ fn file_index(&self) -> Option<u64>;
+}
+
+#[stable(feature = "metadata_ext", since = "1.1.0")]
+impl MetadataExt for Metadata {
+ fn file_attributes(&self) -> u32 {
+ self.as_inner().attrs()
+ }
+ fn creation_time(&self) -> u64 {
+ self.as_inner().created_u64()
+ }
+ fn last_access_time(&self) -> u64 {
+ self.as_inner().accessed_u64()
+ }
+ fn last_write_time(&self) -> u64 {
+ self.as_inner().modified_u64()
+ }
+ fn file_size(&self) -> u64 {
+ self.as_inner().size()
+ }
+ fn volume_serial_number(&self) -> Option<u32> {
+ self.as_inner().volume_serial_number()
+ }
+ fn number_of_links(&self) -> Option<u32> {
+ self.as_inner().number_of_links()
+ }
+ fn file_index(&self) -> Option<u64> {
+ self.as_inner().file_index()
+ }
+}
+
+/// Windows-specific extensions to [`fs::FileType`].
+///
+/// On Windows, a symbolic link knows whether it is a file or directory.
+#[stable(feature = "windows_file_type_ext", since = "1.64.0")]
+pub trait FileTypeExt: Sealed {
+ /// Returns `true` if this file type is a symbolic link that is also a directory.
+ #[stable(feature = "windows_file_type_ext", since = "1.64.0")]
+ fn is_symlink_dir(&self) -> bool;
+ /// Returns `true` if this file type is a symbolic link that is also a file.
+ #[stable(feature = "windows_file_type_ext", since = "1.64.0")]
+ fn is_symlink_file(&self) -> bool;
+}
+
+#[stable(feature = "windows_file_type_ext", since = "1.64.0")]
+impl Sealed for fs::FileType {}
+
+#[stable(feature = "windows_file_type_ext", since = "1.64.0")]
+impl FileTypeExt for fs::FileType {
+ fn is_symlink_dir(&self) -> bool {
+ self.as_inner().is_symlink_dir()
+ }
+ fn is_symlink_file(&self) -> bool {
+ self.as_inner().is_symlink_file()
+ }
+}
+
+/// Creates a new symlink to a non-directory file on the filesystem.
+///
+/// The `link` path will be a file symbolic link pointing to the `original`
+/// path.
+///
+/// The `original` path should not be a directory or a symlink to a directory,
+/// otherwise the symlink will be broken. Use [`symlink_dir`] for directories.
+///
+/// This function currently corresponds to [`CreateSymbolicLinkW`][CreateSymbolicLinkW].
+/// Note that this [may change in the future][changes].
+///
+/// [CreateSymbolicLinkW]: https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-createsymboliclinkw
+/// [changes]: io#platform-specific-behavior
+///
+/// # Examples
+///
+/// ```no_run
+/// use std::os::windows::fs;
+///
+/// fn main() -> std::io::Result<()> {
+/// fs::symlink_file("a.txt", "b.txt")?;
+/// Ok(())
+/// }
+/// ```
+///
+/// # Limitations
+///
+/// Windows treats symlink creation as a [privileged action][symlink-security],
+/// therefore this function is likely to fail unless the user makes changes to
+/// their system to permit symlink creation. Users can try enabling Developer
+/// Mode, granting the `SeCreateSymbolicLinkPrivilege` privilege, or running
+/// the process as an administrator.
+///
+/// [symlink-security]: https://docs.microsoft.com/en-us/windows/security/threat-protection/security-policy-settings/create-symbolic-links
+#[stable(feature = "symlink", since = "1.1.0")]
+pub fn symlink_file<P: AsRef<Path>, Q: AsRef<Path>>(original: P, link: Q) -> io::Result<()> {
+ sys::fs::symlink_inner(original.as_ref(), link.as_ref(), false)
+}
+
+/// Creates a new symlink to a directory on the filesystem.
+///
+/// The `link` path will be a directory symbolic link pointing to the `original`
+/// path.
+///
+/// The `original` path must be a directory or a symlink to a directory,
+/// otherwise the symlink will be broken. Use [`symlink_file`] for other files.
+///
+/// This function currently corresponds to [`CreateSymbolicLinkW`][CreateSymbolicLinkW].
+/// Note that this [may change in the future][changes].
+///
+/// [CreateSymbolicLinkW]: https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-createsymboliclinkw
+/// [changes]: io#platform-specific-behavior
+///
+/// # Examples
+///
+/// ```no_run
+/// use std::os::windows::fs;
+///
+/// fn main() -> std::io::Result<()> {
+/// fs::symlink_dir("a", "b")?;
+/// Ok(())
+/// }
+/// ```
+///
+/// # Limitations
+///
+/// Windows treats symlink creation as a [privileged action][symlink-security],
+/// therefore this function is likely to fail unless the user makes changes to
+/// their system to permit symlink creation. Users can try enabling Developer
+/// Mode, granting the `SeCreateSymbolicLinkPrivilege` privilege, or running
+/// the process as an administrator.
+///
+/// [symlink-security]: https://docs.microsoft.com/en-us/windows/security/threat-protection/security-policy-settings/create-symbolic-links
+#[stable(feature = "symlink", since = "1.1.0")]
+pub fn symlink_dir<P: AsRef<Path>, Q: AsRef<Path>>(original: P, link: Q) -> io::Result<()> {
+ sys::fs::symlink_inner(original.as_ref(), link.as_ref(), true)
+}
diff --git a/library/std/src/os/windows/io/handle.rs b/library/std/src/os/windows/io/handle.rs
new file mode 100644
index 000000000..16cc8fa27
--- /dev/null
+++ b/library/std/src/os/windows/io/handle.rs
@@ -0,0 +1,576 @@
+//! Owned and borrowed OS handles.
+
+#![stable(feature = "io_safety", since = "1.63.0")]
+
+use super::raw::{AsRawHandle, FromRawHandle, IntoRawHandle, RawHandle};
+use crate::fmt;
+use crate::fs;
+use crate::io;
+use crate::marker::PhantomData;
+use crate::mem::forget;
+use crate::ptr;
+use crate::sys::c;
+use crate::sys::cvt;
+use crate::sys_common::{AsInner, FromInner, IntoInner};
+
+/// A borrowed handle.
+///
+/// This has a lifetime parameter to tie it to the lifetime of something that
+/// owns the handle.
+///
+/// This uses `repr(transparent)` and has the representation of a host handle,
+/// so it can be used in FFI in places where a handle is passed as an argument,
+/// it is not captured or consumed.
+///
+/// Note that it *may* have the value `-1`, which in `BorrowedHandle` always
+/// represents a valid handle value, such as [the current process handle], and
+/// not `INVALID_HANDLE_VALUE`, despite the two having the same value. See
+/// [here] for the full story.
+///
+/// And, it *may* have the value `NULL` (0), which can occur when consoles are
+/// detached from processes, or when `windows_subsystem` is used.
+///
+/// This type's `.to_owned()` implementation returns another `BorrowedHandle`
+/// rather than an `OwnedHandle`. It just makes a trivial copy of the raw
+/// handle, which is then borrowed under the same lifetime.
+///
+/// [here]: https://devblogs.microsoft.com/oldnewthing/20040302-00/?p=40443
+/// [the current process handle]: https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-getcurrentprocess#remarks
+#[derive(Copy, Clone)]
+#[repr(transparent)]
+#[stable(feature = "io_safety", since = "1.63.0")]
+pub struct BorrowedHandle<'handle> {
+ handle: RawHandle,
+ _phantom: PhantomData<&'handle OwnedHandle>,
+}
+
+/// An owned handle.
+///
+/// This closes the handle on drop.
+///
+/// Note that it *may* have the value `-1`, which in `OwnedHandle` always
+/// represents a valid handle value, such as [the current process handle], and
+/// not `INVALID_HANDLE_VALUE`, despite the two having the same value. See
+/// [here] for the full story.
+///
+/// And, it *may* have the value `NULL` (0), which can occur when consoles are
+/// detached from processes, or when `windows_subsystem` is used.
+///
+/// `OwnedHandle` uses [`CloseHandle`] to close its handle on drop. As such,
+/// it must not be used with handles to open registry keys which need to be
+/// closed with [`RegCloseKey`] instead.
+///
+/// [`CloseHandle`]: https://docs.microsoft.com/en-us/windows/win32/api/handleapi/nf-handleapi-closehandle
+/// [`RegCloseKey`]: https://docs.microsoft.com/en-us/windows/win32/api/winreg/nf-winreg-regclosekey
+///
+/// [here]: https://devblogs.microsoft.com/oldnewthing/20040302-00/?p=40443
+/// [the current process handle]: https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-getcurrentprocess#remarks
+#[repr(transparent)]
+#[stable(feature = "io_safety", since = "1.63.0")]
+pub struct OwnedHandle {
+ handle: RawHandle,
+}
+
+/// FFI type for handles in return values or out parameters, where `NULL` is used
+/// as a sentry value to indicate errors, such as in the return value of `CreateThread`. This uses
+/// `repr(transparent)` and has the representation of a host handle, so that it can be used in such
+/// FFI declarations.
+///
+/// The only thing you can usefully do with a `HandleOrNull` is to convert it into an
+/// `OwnedHandle` using its [`TryFrom`] implementation; this conversion takes care of the check for
+/// `NULL`. This ensures that such FFI calls cannot start using the handle without
+/// checking for `NULL` first.
+///
+/// This type may hold any handle value that [`OwnedHandle`] may hold. As with `OwnedHandle`, when
+/// it holds `-1`, that value is interpreted as a valid handle value, such as
+/// [the current process handle], and not `INVALID_HANDLE_VALUE`.
+///
+/// If this holds a non-null handle, it will close the handle on drop.
+///
+/// [the current process handle]: https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-getcurrentprocess#remarks
+#[repr(transparent)]
+#[stable(feature = "io_safety", since = "1.63.0")]
+#[derive(Debug)]
+pub struct HandleOrNull(OwnedHandle);
+
+/// FFI type for handles in return values or out parameters, where `INVALID_HANDLE_VALUE` is used
+/// as a sentry value to indicate errors, such as in the return value of `CreateFileW`. This uses
+/// `repr(transparent)` and has the representation of a host handle, so that it can be used in such
+/// FFI declarations.
+///
+/// The only thing you can usefully do with a `HandleOrInvalid` is to convert it into an
+/// `OwnedHandle` using its [`TryFrom`] implementation; this conversion takes care of the check for
+/// `INVALID_HANDLE_VALUE`. This ensures that such FFI calls cannot start using the handle without
+/// checking for `INVALID_HANDLE_VALUE` first.
+///
+/// This type may hold any handle value that [`OwnedHandle`] may hold, except that when it holds
+/// `-1`, that value is interpreted to mean `INVALID_HANDLE_VALUE`.
+///
+/// If holds a handle other than `INVALID_HANDLE_VALUE`, it will close the handle on drop.
+#[repr(transparent)]
+#[stable(feature = "io_safety", since = "1.63.0")]
+#[derive(Debug)]
+pub struct HandleOrInvalid(OwnedHandle);
+
+// The Windows [`HANDLE`] type may be transferred across and shared between
+// thread boundaries (despite containing a `*mut void`, which in general isn't
+// `Send` or `Sync`).
+//
+// [`HANDLE`]: std::os::windows::raw::HANDLE
+#[stable(feature = "io_safety", since = "1.63.0")]
+unsafe impl Send for OwnedHandle {}
+#[stable(feature = "io_safety", since = "1.63.0")]
+unsafe impl Send for HandleOrNull {}
+#[stable(feature = "io_safety", since = "1.63.0")]
+unsafe impl Send for HandleOrInvalid {}
+#[stable(feature = "io_safety", since = "1.63.0")]
+unsafe impl Send for BorrowedHandle<'_> {}
+#[stable(feature = "io_safety", since = "1.63.0")]
+unsafe impl Sync for OwnedHandle {}
+#[stable(feature = "io_safety", since = "1.63.0")]
+unsafe impl Sync for HandleOrNull {}
+#[stable(feature = "io_safety", since = "1.63.0")]
+unsafe impl Sync for HandleOrInvalid {}
+#[stable(feature = "io_safety", since = "1.63.0")]
+unsafe impl Sync for BorrowedHandle<'_> {}
+
+impl BorrowedHandle<'_> {
+ /// Return a `BorrowedHandle` holding the given raw handle.
+ ///
+ /// # Safety
+ ///
+ /// The resource pointed to by `handle` must be a valid open handle, it
+ /// must remain open for the duration of the returned `BorrowedHandle`.
+ ///
+ /// Note that it *may* have the value `INVALID_HANDLE_VALUE` (-1), which is
+ /// sometimes a valid handle value. See [here] for the full story.
+ ///
+ /// And, it *may* have the value `NULL` (0), which can occur when consoles are
+ /// detached from processes, or when `windows_subsystem` is used.
+ ///
+ /// [here]: https://devblogs.microsoft.com/oldnewthing/20040302-00/?p=40443
+ #[inline]
+ #[rustc_const_stable(feature = "io_safety", since = "1.63.0")]
+ #[stable(feature = "io_safety", since = "1.63.0")]
+ pub const unsafe fn borrow_raw(handle: RawHandle) -> Self {
+ Self { handle, _phantom: PhantomData }
+ }
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl TryFrom<HandleOrNull> for OwnedHandle {
+ type Error = NullHandleError;
+
+ #[inline]
+ fn try_from(handle_or_null: HandleOrNull) -> Result<Self, NullHandleError> {
+ let owned_handle = handle_or_null.0;
+ if owned_handle.handle.is_null() {
+ // Don't call `CloseHandle`; it'd be harmless, except that it could
+ // overwrite the `GetLastError` error.
+ forget(owned_handle);
+
+ Err(NullHandleError(()))
+ } else {
+ Ok(owned_handle)
+ }
+ }
+}
+
+impl OwnedHandle {
+ /// Creates a new `OwnedHandle` instance that shares the same underlying
+ /// object as the existing `OwnedHandle` instance.
+ #[stable(feature = "io_safety", since = "1.63.0")]
+ pub fn try_clone(&self) -> crate::io::Result<Self> {
+ self.as_handle().try_clone_to_owned()
+ }
+}
+
+impl BorrowedHandle<'_> {
+ /// Creates a new `OwnedHandle` instance that shares the same underlying
+ /// object as the existing `BorrowedHandle` instance.
+ #[stable(feature = "io_safety", since = "1.63.0")]
+ pub fn try_clone_to_owned(&self) -> crate::io::Result<OwnedHandle> {
+ self.duplicate(0, false, c::DUPLICATE_SAME_ACCESS)
+ }
+
+ pub(crate) fn duplicate(
+ &self,
+ access: c::DWORD,
+ inherit: bool,
+ options: c::DWORD,
+ ) -> io::Result<OwnedHandle> {
+ let handle = self.as_raw_handle();
+
+ // `Stdin`, `Stdout`, and `Stderr` can all hold null handles, such as
+ // in a process with a detached console. `DuplicateHandle` would fail
+ // if we passed it a null handle, but we can treat null as a valid
+ // handle which doesn't do any I/O, and allow it to be duplicated.
+ if handle.is_null() {
+ return unsafe { Ok(OwnedHandle::from_raw_handle(handle)) };
+ }
+
+ let mut ret = ptr::null_mut();
+ cvt(unsafe {
+ let cur_proc = c::GetCurrentProcess();
+ c::DuplicateHandle(
+ cur_proc,
+ handle,
+ cur_proc,
+ &mut ret,
+ access,
+ inherit as c::BOOL,
+ options,
+ )
+ })?;
+ unsafe { Ok(OwnedHandle::from_raw_handle(ret)) }
+ }
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl TryFrom<HandleOrInvalid> for OwnedHandle {
+ type Error = InvalidHandleError;
+
+ #[inline]
+ fn try_from(handle_or_invalid: HandleOrInvalid) -> Result<Self, InvalidHandleError> {
+ let owned_handle = handle_or_invalid.0;
+ if owned_handle.handle == c::INVALID_HANDLE_VALUE {
+ // Don't call `CloseHandle`; it'd be harmless, except that it could
+ // overwrite the `GetLastError` error.
+ forget(owned_handle);
+
+ Err(InvalidHandleError(()))
+ } else {
+ Ok(owned_handle)
+ }
+ }
+}
+
+/// This is the error type used by [`HandleOrNull`] when attempting to convert
+/// into a handle, to indicate that the value is null.
+// The empty field prevents constructing this, and allows extending it in the future.
+#[stable(feature = "io_safety", since = "1.63.0")]
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub struct NullHandleError(());
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl fmt::Display for NullHandleError {
+ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+ "A HandleOrNull could not be converted to a handle because it was null".fmt(fmt)
+ }
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl crate::error::Error for NullHandleError {}
+
+/// This is the error type used by [`HandleOrInvalid`] when attempting to
+/// convert into a handle, to indicate that the value is
+/// `INVALID_HANDLE_VALUE`.
+// The empty field prevents constructing this, and allows extending it in the future.
+#[stable(feature = "io_safety", since = "1.63.0")]
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub struct InvalidHandleError(());
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl fmt::Display for InvalidHandleError {
+ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+ "A HandleOrInvalid could not be converted to a handle because it was INVALID_HANDLE_VALUE"
+ .fmt(fmt)
+ }
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl crate::error::Error for InvalidHandleError {}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl AsRawHandle for BorrowedHandle<'_> {
+ #[inline]
+ fn as_raw_handle(&self) -> RawHandle {
+ self.handle
+ }
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl AsRawHandle for OwnedHandle {
+ #[inline]
+ fn as_raw_handle(&self) -> RawHandle {
+ self.handle
+ }
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl IntoRawHandle for OwnedHandle {
+ #[inline]
+ fn into_raw_handle(self) -> RawHandle {
+ let handle = self.handle;
+ forget(self);
+ handle
+ }
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl FromRawHandle for OwnedHandle {
+ #[inline]
+ unsafe fn from_raw_handle(handle: RawHandle) -> Self {
+ Self { handle }
+ }
+}
+
+impl HandleOrNull {
+ /// Constructs a new instance of `Self` from the given `RawHandle` returned
+ /// from a Windows API that uses null to indicate failure, such as
+ /// `CreateThread`.
+ ///
+ /// Use `HandleOrInvalid` instead of `HandleOrNull` for APIs that
+ /// use `INVALID_HANDLE_VALUE` to indicate failure.
+ ///
+ /// # Safety
+ ///
+ /// The passed `handle` value must either satisfy the safety requirements
+ /// of [`FromRawHandle::from_raw_handle`], or be null. Note that not all
+ /// Windows APIs use null for errors; see [here] for the full story.
+ ///
+ /// [here]: https://devblogs.microsoft.com/oldnewthing/20040302-00/?p=40443
+ #[stable(feature = "io_safety", since = "1.63.0")]
+ #[inline]
+ pub unsafe fn from_raw_handle(handle: RawHandle) -> Self {
+ Self(OwnedHandle::from_raw_handle(handle))
+ }
+}
+
+impl HandleOrInvalid {
+ /// Constructs a new instance of `Self` from the given `RawHandle` returned
+ /// from a Windows API that uses `INVALID_HANDLE_VALUE` to indicate
+ /// failure, such as `CreateFileW`.
+ ///
+ /// Use `HandleOrNull` instead of `HandleOrInvalid` for APIs that
+ /// use null to indicate failure.
+ ///
+ /// # Safety
+ ///
+ /// The passed `handle` value must either satisfy the safety requirements
+ /// of [`FromRawHandle::from_raw_handle`], or be
+ /// `INVALID_HANDLE_VALUE` (-1). Note that not all Windows APIs use
+ /// `INVALID_HANDLE_VALUE` for errors; see [here] for the full story.
+ ///
+ /// [here]: https://devblogs.microsoft.com/oldnewthing/20040302-00/?p=40443
+ #[stable(feature = "io_safety", since = "1.63.0")]
+ #[inline]
+ pub unsafe fn from_raw_handle(handle: RawHandle) -> Self {
+ Self(OwnedHandle::from_raw_handle(handle))
+ }
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl Drop for OwnedHandle {
+ #[inline]
+ fn drop(&mut self) {
+ unsafe {
+ let _ = c::CloseHandle(self.handle);
+ }
+ }
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl fmt::Debug for BorrowedHandle<'_> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_struct("BorrowedHandle").field("handle", &self.handle).finish()
+ }
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl fmt::Debug for OwnedHandle {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_struct("OwnedHandle").field("handle", &self.handle).finish()
+ }
+}
+
+/// A trait to borrow the handle from an underlying object.
+#[stable(feature = "io_safety", since = "1.63.0")]
+pub trait AsHandle {
+ /// Borrows the handle.
+ ///
+ /// # Example
+ ///
+ /// ```rust,no_run
+ /// use std::fs::File;
+ /// # use std::io;
+ /// use std::os::windows::io::{AsHandle, BorrowedHandle};
+ ///
+ /// let mut f = File::open("foo.txt")?;
+ /// let borrowed_handle: BorrowedHandle<'_> = f.as_handle();
+ /// # Ok::<(), io::Error>(())
+ /// ```
+ #[stable(feature = "io_safety", since = "1.63.0")]
+ fn as_handle(&self) -> BorrowedHandle<'_>;
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl<T: AsHandle> AsHandle for &T {
+ #[inline]
+ fn as_handle(&self) -> BorrowedHandle<'_> {
+ T::as_handle(self)
+ }
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl<T: AsHandle> AsHandle for &mut T {
+ #[inline]
+ fn as_handle(&self) -> BorrowedHandle<'_> {
+ T::as_handle(self)
+ }
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl AsHandle for BorrowedHandle<'_> {
+ #[inline]
+ fn as_handle(&self) -> BorrowedHandle<'_> {
+ *self
+ }
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl AsHandle for OwnedHandle {
+ #[inline]
+ fn as_handle(&self) -> BorrowedHandle<'_> {
+ // Safety: `OwnedHandle` and `BorrowedHandle` have the same validity
+ // invariants, and the `BorrowdHandle` is bounded by the lifetime
+ // of `&self`.
+ unsafe { BorrowedHandle::borrow_raw(self.as_raw_handle()) }
+ }
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl AsHandle for fs::File {
+ #[inline]
+ fn as_handle(&self) -> BorrowedHandle<'_> {
+ self.as_inner().as_handle()
+ }
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl From<fs::File> for OwnedHandle {
+ #[inline]
+ fn from(file: fs::File) -> OwnedHandle {
+ file.into_inner().into_inner().into_inner().into()
+ }
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl From<OwnedHandle> for fs::File {
+ #[inline]
+ fn from(owned: OwnedHandle) -> Self {
+ Self::from_inner(FromInner::from_inner(FromInner::from_inner(owned)))
+ }
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl AsHandle for crate::io::Stdin {
+ #[inline]
+ fn as_handle(&self) -> BorrowedHandle<'_> {
+ unsafe { BorrowedHandle::borrow_raw(self.as_raw_handle()) }
+ }
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl<'a> AsHandle for crate::io::StdinLock<'a> {
+ #[inline]
+ fn as_handle(&self) -> BorrowedHandle<'_> {
+ unsafe { BorrowedHandle::borrow_raw(self.as_raw_handle()) }
+ }
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl AsHandle for crate::io::Stdout {
+ #[inline]
+ fn as_handle(&self) -> BorrowedHandle<'_> {
+ unsafe { BorrowedHandle::borrow_raw(self.as_raw_handle()) }
+ }
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl<'a> AsHandle for crate::io::StdoutLock<'a> {
+ #[inline]
+ fn as_handle(&self) -> BorrowedHandle<'_> {
+ unsafe { BorrowedHandle::borrow_raw(self.as_raw_handle()) }
+ }
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl AsHandle for crate::io::Stderr {
+ #[inline]
+ fn as_handle(&self) -> BorrowedHandle<'_> {
+ unsafe { BorrowedHandle::borrow_raw(self.as_raw_handle()) }
+ }
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl<'a> AsHandle for crate::io::StderrLock<'a> {
+ #[inline]
+ fn as_handle(&self) -> BorrowedHandle<'_> {
+ unsafe { BorrowedHandle::borrow_raw(self.as_raw_handle()) }
+ }
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl AsHandle for crate::process::ChildStdin {
+ #[inline]
+ fn as_handle(&self) -> BorrowedHandle<'_> {
+ unsafe { BorrowedHandle::borrow_raw(self.as_raw_handle()) }
+ }
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl From<crate::process::ChildStdin> for OwnedHandle {
+ #[inline]
+ fn from(child_stdin: crate::process::ChildStdin) -> OwnedHandle {
+ unsafe { OwnedHandle::from_raw_handle(child_stdin.into_raw_handle()) }
+ }
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl AsHandle for crate::process::ChildStdout {
+ #[inline]
+ fn as_handle(&self) -> BorrowedHandle<'_> {
+ unsafe { BorrowedHandle::borrow_raw(self.as_raw_handle()) }
+ }
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl From<crate::process::ChildStdout> for OwnedHandle {
+ #[inline]
+ fn from(child_stdout: crate::process::ChildStdout) -> OwnedHandle {
+ unsafe { OwnedHandle::from_raw_handle(child_stdout.into_raw_handle()) }
+ }
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl AsHandle for crate::process::ChildStderr {
+ #[inline]
+ fn as_handle(&self) -> BorrowedHandle<'_> {
+ unsafe { BorrowedHandle::borrow_raw(self.as_raw_handle()) }
+ }
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl From<crate::process::ChildStderr> for OwnedHandle {
+ #[inline]
+ fn from(child_stderr: crate::process::ChildStderr) -> OwnedHandle {
+ unsafe { OwnedHandle::from_raw_handle(child_stderr.into_raw_handle()) }
+ }
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl<T> AsHandle for crate::thread::JoinHandle<T> {
+ #[inline]
+ fn as_handle(&self) -> BorrowedHandle<'_> {
+ unsafe { BorrowedHandle::borrow_raw(self.as_raw_handle()) }
+ }
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl<T> From<crate::thread::JoinHandle<T>> for OwnedHandle {
+ #[inline]
+ fn from(join_handle: crate::thread::JoinHandle<T>) -> OwnedHandle {
+ join_handle.into_inner().into_handle().into_inner()
+ }
+}
diff --git a/library/std/src/os/windows/io/mod.rs b/library/std/src/os/windows/io/mod.rs
new file mode 100644
index 000000000..e2a401fb6
--- /dev/null
+++ b/library/std/src/os/windows/io/mod.rs
@@ -0,0 +1,65 @@
+//! Windows-specific extensions to general I/O primitives.
+//!
+//! Just like raw pointers, raw Windows handles and sockets point to resources
+//! with dynamic lifetimes, and they can dangle if they outlive their resources
+//! or be forged if they're created from invalid values.
+//!
+//! This module provides three types for representing raw handles and sockets
+//! with different ownership properties: raw, borrowed, and owned, which are
+//! analogous to types used for representing pointers:
+//!
+//! | Type | Analogous to |
+//! | ---------------------- | ------------ |
+//! | [`RawHandle`] | `*const _` |
+//! | [`RawSocket`] | `*const _` |
+//! | | |
+//! | [`BorrowedHandle<'a>`] | `&'a _` |
+//! | [`BorrowedSocket<'a>`] | `&'a _` |
+//! | | |
+//! | [`OwnedHandle`] | `Box<_>` |
+//! | [`OwnedSocket`] | `Box<_>` |
+//!
+//! Like raw pointers, `RawHandle` and `RawSocket` values are primitive values.
+//! And in new code, they should be considered unsafe to do I/O on (analogous
+//! to dereferencing them). Rust did not always provide this guidance, so
+//! existing code in the Rust ecosystem often doesn't mark `RawHandle` and
+//! `RawSocket` usage as unsafe. Once the `io_safety` feature is stable,
+//! libraries will be encouraged to migrate, either by adding `unsafe` to APIs
+//! that dereference `RawHandle` and `RawSocket` values, or by using to
+//! `BorrowedHandle`, `BorrowedSocket`, `OwnedHandle`, or `OwnedSocket`.
+//!
+//! Like references, `BorrowedHandle` and `BorrowedSocket` values are tied to a
+//! lifetime, to ensure that they don't outlive the resource they point to.
+//! These are safe to use. `BorrowedHandle` and `BorrowedSocket` values may be
+//! used in APIs which provide safe access to any system call except for
+//! `CloseHandle`, `closesocket`, or any other call that would end the
+//! dynamic lifetime of the resource without ending the lifetime of the
+//! handle or socket.
+//!
+//! `BorrowedHandle` and `BorrowedSocket` values may be used in APIs which
+//! provide safe access to `DuplicateHandle` and `WSADuplicateSocketW` and
+//! related functions, so types implementing `AsHandle`, `AsSocket`,
+//! `From<OwnedHandle>`, or `From<OwnedSocket>` should not assume they always
+//! have exclusive access to the underlying object.
+//!
+//! Like boxes, `OwnedHandle` and `OwnedSocket` values conceptually own the
+//! resource they point to, and free (close) it when they are dropped.
+//!
+//! [`BorrowedHandle<'a>`]: crate::os::windows::io::BorrowedHandle
+//! [`BorrowedSocket<'a>`]: crate::os::windows::io::BorrowedSocket
+
+#![stable(feature = "rust1", since = "1.0.0")]
+
+mod handle;
+mod raw;
+mod socket;
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+pub use handle::*;
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use raw::*;
+#[stable(feature = "io_safety", since = "1.63.0")]
+pub use socket::*;
+
+#[cfg(test)]
+mod tests;
diff --git a/library/std/src/os/windows/io/raw.rs b/library/std/src/os/windows/io/raw.rs
new file mode 100644
index 000000000..49e4f304f
--- /dev/null
+++ b/library/std/src/os/windows/io/raw.rs
@@ -0,0 +1,305 @@
+//! Windows-specific extensions to general I/O primitives.
+
+#![stable(feature = "rust1", since = "1.0.0")]
+
+use crate::fs;
+use crate::io;
+use crate::net;
+#[cfg(doc)]
+use crate::os::windows::io::{AsHandle, AsSocket};
+use crate::os::windows::io::{OwnedHandle, OwnedSocket};
+use crate::os::windows::raw;
+use crate::ptr;
+use crate::sys;
+use crate::sys::c;
+use crate::sys_common::{self, AsInner, FromInner, IntoInner};
+
+/// Raw HANDLEs.
+#[stable(feature = "rust1", since = "1.0.0")]
+pub type RawHandle = raw::HANDLE;
+
+/// Raw SOCKETs.
+#[stable(feature = "rust1", since = "1.0.0")]
+pub type RawSocket = raw::SOCKET;
+
+/// Extracts raw handles.
+#[stable(feature = "rust1", since = "1.0.0")]
+pub trait AsRawHandle {
+ /// Extracts the raw handle.
+ ///
+ /// This function is typically used to **borrow** an owned handle.
+ /// When used in this way, this method does **not** pass ownership of the
+ /// raw handle to the caller, and the handle is only guaranteed
+ /// to be valid while the original object has not yet been destroyed.
+ ///
+ /// This function may return null, such as when called on [`Stdin`],
+ /// [`Stdout`], or [`Stderr`] when the console is detached.
+ ///
+ /// However, borrowing is not strictly required. See [`AsHandle::as_handle`]
+ /// for an API which strictly borrows a handle.
+ ///
+ /// [`Stdin`]: io::Stdin
+ /// [`Stdout`]: io::Stdout
+ /// [`Stderr`]: io::Stderr
+ #[stable(feature = "rust1", since = "1.0.0")]
+ fn as_raw_handle(&self) -> RawHandle;
+}
+
+/// Construct I/O objects from raw handles.
+#[stable(feature = "from_raw_os", since = "1.1.0")]
+pub trait FromRawHandle {
+ /// Constructs a new I/O object from the specified raw handle.
+ ///
+ /// This function is typically used to **consume ownership** of the handle
+ /// given, passing responsibility for closing the handle to the returned
+ /// object. When used in this way, the returned object
+ /// will take responsibility for closing it when the object goes out of
+ /// scope.
+ ///
+ /// However, consuming ownership is not strictly required. Use a
+ /// `From<OwnedHandle>::from` implementation for an API which strictly
+ /// consumes ownership.
+ ///
+ /// # Safety
+ ///
+ /// The `handle` passed in must:
+ /// - be a valid an open handle,
+ /// - be a handle for a resource that may be freed via [`CloseHandle`]
+ /// (as opposed to `RegCloseKey` or other close functions).
+ ///
+ /// Note that the handle *may* have the value `INVALID_HANDLE_VALUE` (-1),
+ /// which is sometimes a valid handle value. See [here] for the full story.
+ ///
+ /// [`CloseHandle`]: https://docs.microsoft.com/en-us/windows/win32/api/handleapi/nf-handleapi-closehandle
+ /// [here]: https://devblogs.microsoft.com/oldnewthing/20040302-00/?p=40443
+ #[stable(feature = "from_raw_os", since = "1.1.0")]
+ unsafe fn from_raw_handle(handle: RawHandle) -> Self;
+}
+
+/// A trait to express the ability to consume an object and acquire ownership of
+/// its raw `HANDLE`.
+#[stable(feature = "into_raw_os", since = "1.4.0")]
+pub trait IntoRawHandle {
+ /// Consumes this object, returning the raw underlying handle.
+ ///
+ /// This function is typically used to **transfer ownership** of the underlying
+ /// handle to the caller. When used in this way, callers are then the unique
+ /// owners of the handle and must close it once it's no longer needed.
+ ///
+ /// However, transferring ownership is not strictly required. Use a
+ /// `Into<OwnedHandle>::into` implementation for an API which strictly
+ /// transfers ownership.
+ #[stable(feature = "into_raw_os", since = "1.4.0")]
+ fn into_raw_handle(self) -> RawHandle;
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl AsRawHandle for fs::File {
+ #[inline]
+ fn as_raw_handle(&self) -> RawHandle {
+ self.as_inner().as_raw_handle() as RawHandle
+ }
+}
+
+#[stable(feature = "asraw_stdio", since = "1.21.0")]
+impl AsRawHandle for io::Stdin {
+ fn as_raw_handle(&self) -> RawHandle {
+ stdio_handle(unsafe { c::GetStdHandle(c::STD_INPUT_HANDLE) as RawHandle })
+ }
+}
+
+#[stable(feature = "asraw_stdio", since = "1.21.0")]
+impl AsRawHandle for io::Stdout {
+ fn as_raw_handle(&self) -> RawHandle {
+ stdio_handle(unsafe { c::GetStdHandle(c::STD_OUTPUT_HANDLE) as RawHandle })
+ }
+}
+
+#[stable(feature = "asraw_stdio", since = "1.21.0")]
+impl AsRawHandle for io::Stderr {
+ fn as_raw_handle(&self) -> RawHandle {
+ stdio_handle(unsafe { c::GetStdHandle(c::STD_ERROR_HANDLE) as RawHandle })
+ }
+}
+
+#[stable(feature = "asraw_stdio_locks", since = "1.35.0")]
+impl<'a> AsRawHandle for io::StdinLock<'a> {
+ fn as_raw_handle(&self) -> RawHandle {
+ stdio_handle(unsafe { c::GetStdHandle(c::STD_INPUT_HANDLE) as RawHandle })
+ }
+}
+
+#[stable(feature = "asraw_stdio_locks", since = "1.35.0")]
+impl<'a> AsRawHandle for io::StdoutLock<'a> {
+ fn as_raw_handle(&self) -> RawHandle {
+ stdio_handle(unsafe { c::GetStdHandle(c::STD_OUTPUT_HANDLE) as RawHandle })
+ }
+}
+
+#[stable(feature = "asraw_stdio_locks", since = "1.35.0")]
+impl<'a> AsRawHandle for io::StderrLock<'a> {
+ fn as_raw_handle(&self) -> RawHandle {
+ stdio_handle(unsafe { c::GetStdHandle(c::STD_ERROR_HANDLE) as RawHandle })
+ }
+}
+
+// Translate a handle returned from `GetStdHandle` into a handle to return to
+// the user.
+fn stdio_handle(raw: RawHandle) -> RawHandle {
+ // `GetStdHandle` isn't expected to actually fail, so when it returns
+ // `INVALID_HANDLE_VALUE`, it means we were launched from a parent which
+ // didn't provide us with stdio handles, such as a parent with a detached
+ // console. In that case, return null to the user, which is consistent
+ // with what they'd get in the parent, and which avoids the problem that
+ // `INVALID_HANDLE_VALUE` aliases the current process handle.
+ if raw == c::INVALID_HANDLE_VALUE { ptr::null_mut() } else { raw }
+}
+
+#[stable(feature = "from_raw_os", since = "1.1.0")]
+impl FromRawHandle for fs::File {
+ #[inline]
+ unsafe fn from_raw_handle(handle: RawHandle) -> fs::File {
+ let handle = handle as c::HANDLE;
+ fs::File::from_inner(sys::fs::File::from_inner(FromInner::from_inner(
+ OwnedHandle::from_raw_handle(handle),
+ )))
+ }
+}
+
+#[stable(feature = "into_raw_os", since = "1.4.0")]
+impl IntoRawHandle for fs::File {
+ #[inline]
+ fn into_raw_handle(self) -> RawHandle {
+ self.into_inner().into_raw_handle() as *mut _
+ }
+}
+
+/// Extracts raw sockets.
+#[stable(feature = "rust1", since = "1.0.0")]
+pub trait AsRawSocket {
+ /// Extracts the raw socket.
+ ///
+ /// This function is typically used to **borrow** an owned socket.
+ /// When used in this way, this method does **not** pass ownership of the
+ /// raw socket to the caller, and the socket is only guaranteed
+ /// to be valid while the original object has not yet been destroyed.
+ ///
+ /// However, borrowing is not strictly required. See [`AsSocket::as_socket`]
+ /// for an API which strictly borrows a socket.
+ #[stable(feature = "rust1", since = "1.0.0")]
+ fn as_raw_socket(&self) -> RawSocket;
+}
+
+/// Creates I/O objects from raw sockets.
+#[stable(feature = "from_raw_os", since = "1.1.0")]
+pub trait FromRawSocket {
+ /// Constructs a new I/O object from the specified raw socket.
+ ///
+ /// This function is typically used to **consume ownership** of the socket
+ /// given, passing responsibility for closing the socket to the returned
+ /// object. When used in this way, the returned object
+ /// will take responsibility for closing it when the object goes out of
+ /// scope.
+ ///
+ /// However, consuming ownership is not strictly required. Use a
+ /// `From<OwnedSocket>::from` implementation for an API which strictly
+ /// consumes ownership.
+ ///
+ /// # Safety
+ ///
+ /// The `socket` passed in must:
+ /// - be a valid an open socket,
+ /// - be a socket that may be freed via [`closesocket`].
+ ///
+ /// [`closesocket`]: https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-closesocket
+ #[stable(feature = "from_raw_os", since = "1.1.0")]
+ unsafe fn from_raw_socket(sock: RawSocket) -> Self;
+}
+
+/// A trait to express the ability to consume an object and acquire ownership of
+/// its raw `SOCKET`.
+#[stable(feature = "into_raw_os", since = "1.4.0")]
+pub trait IntoRawSocket {
+ /// Consumes this object, returning the raw underlying socket.
+ ///
+ /// This function is typically used to **transfer ownership** of the underlying
+ /// socket to the caller. When used in this way, callers are then the unique
+ /// owners of the socket and must close it once it's no longer needed.
+ ///
+ /// However, transferring ownership is not strictly required. Use a
+ /// `Into<OwnedSocket>::into` implementation for an API which strictly
+ /// transfers ownership.
+ #[stable(feature = "into_raw_os", since = "1.4.0")]
+ fn into_raw_socket(self) -> RawSocket;
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl AsRawSocket for net::TcpStream {
+ #[inline]
+ fn as_raw_socket(&self) -> RawSocket {
+ self.as_inner().socket().as_raw_socket()
+ }
+}
+#[stable(feature = "rust1", since = "1.0.0")]
+impl AsRawSocket for net::TcpListener {
+ #[inline]
+ fn as_raw_socket(&self) -> RawSocket {
+ self.as_inner().socket().as_raw_socket()
+ }
+}
+#[stable(feature = "rust1", since = "1.0.0")]
+impl AsRawSocket for net::UdpSocket {
+ #[inline]
+ fn as_raw_socket(&self) -> RawSocket {
+ self.as_inner().socket().as_raw_socket()
+ }
+}
+
+#[stable(feature = "from_raw_os", since = "1.1.0")]
+impl FromRawSocket for net::TcpStream {
+ #[inline]
+ unsafe fn from_raw_socket(sock: RawSocket) -> net::TcpStream {
+ let sock = sys::net::Socket::from_inner(OwnedSocket::from_raw_socket(sock));
+ net::TcpStream::from_inner(sys_common::net::TcpStream::from_inner(sock))
+ }
+}
+#[stable(feature = "from_raw_os", since = "1.1.0")]
+impl FromRawSocket for net::TcpListener {
+ #[inline]
+ unsafe fn from_raw_socket(sock: RawSocket) -> net::TcpListener {
+ let sock = sys::net::Socket::from_inner(OwnedSocket::from_raw_socket(sock));
+ net::TcpListener::from_inner(sys_common::net::TcpListener::from_inner(sock))
+ }
+}
+#[stable(feature = "from_raw_os", since = "1.1.0")]
+impl FromRawSocket for net::UdpSocket {
+ #[inline]
+ unsafe fn from_raw_socket(sock: RawSocket) -> net::UdpSocket {
+ let sock = sys::net::Socket::from_inner(OwnedSocket::from_raw_socket(sock));
+ net::UdpSocket::from_inner(sys_common::net::UdpSocket::from_inner(sock))
+ }
+}
+
+#[stable(feature = "into_raw_os", since = "1.4.0")]
+impl IntoRawSocket for net::TcpStream {
+ #[inline]
+ fn into_raw_socket(self) -> RawSocket {
+ self.into_inner().into_socket().into_inner().into_raw_socket()
+ }
+}
+
+#[stable(feature = "into_raw_os", since = "1.4.0")]
+impl IntoRawSocket for net::TcpListener {
+ #[inline]
+ fn into_raw_socket(self) -> RawSocket {
+ self.into_inner().into_socket().into_inner().into_raw_socket()
+ }
+}
+
+#[stable(feature = "into_raw_os", since = "1.4.0")]
+impl IntoRawSocket for net::UdpSocket {
+ #[inline]
+ fn into_raw_socket(self) -> RawSocket {
+ self.into_inner().into_socket().into_inner().into_raw_socket()
+ }
+}
diff --git a/library/std/src/os/windows/io/socket.rs b/library/std/src/os/windows/io/socket.rs
new file mode 100644
index 000000000..72cb3406d
--- /dev/null
+++ b/library/std/src/os/windows/io/socket.rs
@@ -0,0 +1,338 @@
+//! Owned and borrowed OS sockets.
+
+#![stable(feature = "io_safety", since = "1.63.0")]
+
+use super::raw::{AsRawSocket, FromRawSocket, IntoRawSocket, RawSocket};
+use crate::fmt;
+use crate::io;
+use crate::marker::PhantomData;
+use crate::mem;
+use crate::mem::forget;
+use crate::sys;
+use crate::sys::c;
+#[cfg(not(target_vendor = "uwp"))]
+use crate::sys::cvt;
+
+/// A borrowed socket.
+///
+/// This has a lifetime parameter to tie it to the lifetime of something that
+/// owns the socket.
+///
+/// This uses `repr(transparent)` and has the representation of a host socket,
+/// so it can be used in FFI in places where a socket is passed as an argument,
+/// it is not captured or consumed, and it never has the value
+/// `INVALID_SOCKET`.
+///
+/// This type's `.to_owned()` implementation returns another `BorrowedSocket`
+/// rather than an `OwnedSocket`. It just makes a trivial copy of the raw
+/// socket, which is then borrowed under the same lifetime.
+#[derive(Copy, Clone)]
+#[repr(transparent)]
+#[rustc_layout_scalar_valid_range_start(0)]
+// This is -2, in two's complement. -1 is `INVALID_SOCKET`.
+#[cfg_attr(target_pointer_width = "32", rustc_layout_scalar_valid_range_end(0xFF_FF_FF_FE))]
+#[cfg_attr(
+ target_pointer_width = "64",
+ rustc_layout_scalar_valid_range_end(0xFF_FF_FF_FF_FF_FF_FF_FE)
+)]
+#[rustc_nonnull_optimization_guaranteed]
+#[stable(feature = "io_safety", since = "1.63.0")]
+pub struct BorrowedSocket<'socket> {
+ socket: RawSocket,
+ _phantom: PhantomData<&'socket OwnedSocket>,
+}
+
+/// An owned socket.
+///
+/// This closes the socket on drop.
+///
+/// This uses `repr(transparent)` and has the representation of a host socket,
+/// so it can be used in FFI in places where a socket is passed as a consumed
+/// argument or returned as an owned value, and it never has the value
+/// `INVALID_SOCKET`.
+#[repr(transparent)]
+#[rustc_layout_scalar_valid_range_start(0)]
+// This is -2, in two's complement. -1 is `INVALID_SOCKET`.
+#[cfg_attr(target_pointer_width = "32", rustc_layout_scalar_valid_range_end(0xFF_FF_FF_FE))]
+#[cfg_attr(
+ target_pointer_width = "64",
+ rustc_layout_scalar_valid_range_end(0xFF_FF_FF_FF_FF_FF_FF_FE)
+)]
+#[rustc_nonnull_optimization_guaranteed]
+#[stable(feature = "io_safety", since = "1.63.0")]
+pub struct OwnedSocket {
+ socket: RawSocket,
+}
+
+impl BorrowedSocket<'_> {
+ /// Return a `BorrowedSocket` holding the given raw socket.
+ ///
+ /// # Safety
+ ///
+ /// The resource pointed to by `raw` must remain open for the duration of
+ /// the returned `BorrowedSocket`, and it must not have the value
+ /// `INVALID_SOCKET`.
+ #[inline]
+ #[rustc_const_stable(feature = "io_safety", since = "1.63.0")]
+ #[stable(feature = "io_safety", since = "1.63.0")]
+ pub const unsafe fn borrow_raw(socket: RawSocket) -> Self {
+ assert!(socket != c::INVALID_SOCKET as RawSocket);
+ Self { socket, _phantom: PhantomData }
+ }
+}
+
+impl OwnedSocket {
+ /// Creates a new `OwnedSocket` instance that shares the same underlying
+ /// object as the existing `OwnedSocket` instance.
+ #[stable(feature = "io_safety", since = "1.63.0")]
+ pub fn try_clone(&self) -> io::Result<Self> {
+ self.as_socket().try_clone_to_owned()
+ }
+
+ // FIXME(strict_provenance_magic): we defined RawSocket to be a u64 ;-;
+ #[cfg(not(target_vendor = "uwp"))]
+ pub(crate) fn set_no_inherit(&self) -> io::Result<()> {
+ cvt(unsafe {
+ c::SetHandleInformation(self.as_raw_socket() as c::HANDLE, c::HANDLE_FLAG_INHERIT, 0)
+ })
+ .map(drop)
+ }
+
+ #[cfg(target_vendor = "uwp")]
+ pub(crate) fn set_no_inherit(&self) -> io::Result<()> {
+ Err(io::const_io_error!(io::ErrorKind::Unsupported, "Unavailable on UWP"))
+ }
+}
+
+impl BorrowedSocket<'_> {
+ /// Creates a new `OwnedSocket` instance that shares the same underlying
+ /// object as the existing `BorrowedSocket` instance.
+ #[stable(feature = "io_safety", since = "1.63.0")]
+ pub fn try_clone_to_owned(&self) -> io::Result<OwnedSocket> {
+ let mut info = unsafe { mem::zeroed::<c::WSAPROTOCOL_INFO>() };
+ let result = unsafe {
+ c::WSADuplicateSocketW(self.as_raw_socket(), c::GetCurrentProcessId(), &mut info)
+ };
+ sys::net::cvt(result)?;
+ let socket = unsafe {
+ c::WSASocketW(
+ info.iAddressFamily,
+ info.iSocketType,
+ info.iProtocol,
+ &mut info,
+ 0,
+ c::WSA_FLAG_OVERLAPPED | c::WSA_FLAG_NO_HANDLE_INHERIT,
+ )
+ };
+
+ if socket != c::INVALID_SOCKET {
+ unsafe { Ok(OwnedSocket::from_raw_socket(socket)) }
+ } else {
+ let error = unsafe { c::WSAGetLastError() };
+
+ if error != c::WSAEPROTOTYPE && error != c::WSAEINVAL {
+ return Err(io::Error::from_raw_os_error(error));
+ }
+
+ let socket = unsafe {
+ c::WSASocketW(
+ info.iAddressFamily,
+ info.iSocketType,
+ info.iProtocol,
+ &mut info,
+ 0,
+ c::WSA_FLAG_OVERLAPPED,
+ )
+ };
+
+ if socket == c::INVALID_SOCKET {
+ return Err(last_error());
+ }
+
+ unsafe {
+ let socket = OwnedSocket::from_raw_socket(socket);
+ socket.set_no_inherit()?;
+ Ok(socket)
+ }
+ }
+ }
+}
+
+/// Returns the last error from the Windows socket interface.
+fn last_error() -> io::Error {
+ io::Error::from_raw_os_error(unsafe { c::WSAGetLastError() })
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl AsRawSocket for BorrowedSocket<'_> {
+ #[inline]
+ fn as_raw_socket(&self) -> RawSocket {
+ self.socket
+ }
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl AsRawSocket for OwnedSocket {
+ #[inline]
+ fn as_raw_socket(&self) -> RawSocket {
+ self.socket
+ }
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl IntoRawSocket for OwnedSocket {
+ #[inline]
+ fn into_raw_socket(self) -> RawSocket {
+ let socket = self.socket;
+ forget(self);
+ socket
+ }
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl FromRawSocket for OwnedSocket {
+ #[inline]
+ unsafe fn from_raw_socket(socket: RawSocket) -> Self {
+ debug_assert_ne!(socket, c::INVALID_SOCKET as RawSocket);
+ Self { socket }
+ }
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl Drop for OwnedSocket {
+ #[inline]
+ fn drop(&mut self) {
+ unsafe {
+ let _ = c::closesocket(self.socket);
+ }
+ }
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl fmt::Debug for BorrowedSocket<'_> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_struct("BorrowedSocket").field("socket", &self.socket).finish()
+ }
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl fmt::Debug for OwnedSocket {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_struct("OwnedSocket").field("socket", &self.socket).finish()
+ }
+}
+
+/// A trait to borrow the socket from an underlying object.
+#[stable(feature = "io_safety", since = "1.63.0")]
+pub trait AsSocket {
+ /// Borrows the socket.
+ #[stable(feature = "io_safety", since = "1.63.0")]
+ fn as_socket(&self) -> BorrowedSocket<'_>;
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl<T: AsSocket> AsSocket for &T {
+ #[inline]
+ fn as_socket(&self) -> BorrowedSocket<'_> {
+ T::as_socket(self)
+ }
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl<T: AsSocket> AsSocket for &mut T {
+ #[inline]
+ fn as_socket(&self) -> BorrowedSocket<'_> {
+ T::as_socket(self)
+ }
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl AsSocket for BorrowedSocket<'_> {
+ #[inline]
+ fn as_socket(&self) -> BorrowedSocket<'_> {
+ *self
+ }
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl AsSocket for OwnedSocket {
+ #[inline]
+ fn as_socket(&self) -> BorrowedSocket<'_> {
+ // Safety: `OwnedSocket` and `BorrowedSocket` have the same validity
+ // invariants, and the `BorrowdSocket` is bounded by the lifetime
+ // of `&self`.
+ unsafe { BorrowedSocket::borrow_raw(self.as_raw_socket()) }
+ }
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl AsSocket for crate::net::TcpStream {
+ #[inline]
+ fn as_socket(&self) -> BorrowedSocket<'_> {
+ unsafe { BorrowedSocket::borrow_raw(self.as_raw_socket()) }
+ }
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl From<crate::net::TcpStream> for OwnedSocket {
+ #[inline]
+ fn from(tcp_stream: crate::net::TcpStream) -> OwnedSocket {
+ unsafe { OwnedSocket::from_raw_socket(tcp_stream.into_raw_socket()) }
+ }
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl From<OwnedSocket> for crate::net::TcpStream {
+ #[inline]
+ fn from(owned: OwnedSocket) -> Self {
+ unsafe { Self::from_raw_socket(owned.into_raw_socket()) }
+ }
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl AsSocket for crate::net::TcpListener {
+ #[inline]
+ fn as_socket(&self) -> BorrowedSocket<'_> {
+ unsafe { BorrowedSocket::borrow_raw(self.as_raw_socket()) }
+ }
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl From<crate::net::TcpListener> for OwnedSocket {
+ #[inline]
+ fn from(tcp_listener: crate::net::TcpListener) -> OwnedSocket {
+ unsafe { OwnedSocket::from_raw_socket(tcp_listener.into_raw_socket()) }
+ }
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl From<OwnedSocket> for crate::net::TcpListener {
+ #[inline]
+ fn from(owned: OwnedSocket) -> Self {
+ unsafe { Self::from_raw_socket(owned.into_raw_socket()) }
+ }
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl AsSocket for crate::net::UdpSocket {
+ #[inline]
+ fn as_socket(&self) -> BorrowedSocket<'_> {
+ unsafe { BorrowedSocket::borrow_raw(self.as_raw_socket()) }
+ }
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl From<crate::net::UdpSocket> for OwnedSocket {
+ #[inline]
+ fn from(udp_socket: crate::net::UdpSocket) -> OwnedSocket {
+ unsafe { OwnedSocket::from_raw_socket(udp_socket.into_raw_socket()) }
+ }
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl From<OwnedSocket> for crate::net::UdpSocket {
+ #[inline]
+ fn from(owned: OwnedSocket) -> Self {
+ unsafe { Self::from_raw_socket(owned.into_raw_socket()) }
+ }
+}
diff --git a/library/std/src/os/windows/io/tests.rs b/library/std/src/os/windows/io/tests.rs
new file mode 100644
index 000000000..41734e52e
--- /dev/null
+++ b/library/std/src/os/windows/io/tests.rs
@@ -0,0 +1,21 @@
+#[test]
+fn test_niche_optimizations_socket() {
+ use crate::mem::size_of;
+ use crate::os::windows::io::{
+ BorrowedSocket, FromRawSocket, IntoRawSocket, OwnedSocket, RawSocket,
+ };
+
+ assert_eq!(size_of::<Option<OwnedSocket>>(), size_of::<RawSocket>());
+ assert_eq!(size_of::<Option<BorrowedSocket<'static>>>(), size_of::<RawSocket>(),);
+ unsafe {
+ #[cfg(target_pointer_width = "32")]
+ let (min, max) = (i32::MIN as u32, i32::MAX as u32);
+ #[cfg(target_pointer_width = "64")]
+ let (min, max) = (i64::MIN as u64, i64::MAX as u64);
+
+ assert_eq!(OwnedSocket::from_raw_socket(min).into_raw_socket(), min);
+ assert_eq!(OwnedSocket::from_raw_socket(max).into_raw_socket(), max);
+ assert_eq!(Some(OwnedSocket::from_raw_socket(min)).unwrap().into_raw_socket(), min);
+ assert_eq!(Some(OwnedSocket::from_raw_socket(max)).unwrap().into_raw_socket(), max);
+ }
+}
diff --git a/library/std/src/os/windows/mod.rs b/library/std/src/os/windows/mod.rs
new file mode 100644
index 000000000..52eb3b7c0
--- /dev/null
+++ b/library/std/src/os/windows/mod.rs
@@ -0,0 +1,58 @@
+//! Platform-specific extensions to `std` for Windows.
+//!
+//! Provides access to platform-level information for Windows, and exposes
+//! Windows-specific idioms that would otherwise be inappropriate as part
+//! the core `std` library. These extensions allow developers to use
+//! `std` types and idioms with Windows in a way that the normal
+//! platform-agnostic idioms would not normally support.
+//!
+//! # Examples
+//!
+//! ```no_run
+//! use std::fs::File;
+//! use std::os::windows::prelude::*;
+//!
+//! fn main() -> std::io::Result<()> {
+//! let f = File::create("foo.txt")?;
+//! let handle = f.as_raw_handle();
+//!
+//! // use handle with native windows bindings
+//!
+//! Ok(())
+//! }
+//! ```
+
+#![stable(feature = "rust1", since = "1.0.0")]
+#![doc(cfg(windows))]
+
+pub mod ffi;
+pub mod fs;
+pub mod io;
+pub mod process;
+pub mod raw;
+pub mod thread;
+
+/// A prelude for conveniently writing platform-specific code.
+///
+/// Includes all extension traits, and some important type definitions.
+#[stable(feature = "rust1", since = "1.0.0")]
+pub mod prelude {
+ #[doc(no_inline)]
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub use super::ffi::{OsStrExt, OsStringExt};
+ #[doc(no_inline)]
+ #[stable(feature = "file_offset", since = "1.15.0")]
+ pub use super::fs::FileExt;
+ #[doc(no_inline)]
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub use super::fs::{MetadataExt, OpenOptionsExt};
+ #[doc(no_inline)]
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub use super::io::{
+ AsHandle, AsSocket, BorrowedHandle, BorrowedSocket, FromRawHandle, FromRawSocket,
+ HandleOrInvalid, IntoRawHandle, IntoRawSocket, OwnedHandle, OwnedSocket,
+ };
+ #[doc(no_inline)]
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub use super::io::{AsRawHandle, AsRawSocket, RawHandle, RawSocket};
+}
diff --git a/library/std/src/os/windows/process.rs b/library/std/src/os/windows/process.rs
new file mode 100644
index 000000000..073168cf2
--- /dev/null
+++ b/library/std/src/os/windows/process.rs
@@ -0,0 +1,259 @@
+//! Windows-specific extensions to primitives in the [`std::process`] module.
+//!
+//! [`std::process`]: crate::process
+
+#![stable(feature = "process_extensions", since = "1.2.0")]
+
+use crate::ffi::OsStr;
+use crate::os::windows::io::{
+ AsHandle, AsRawHandle, BorrowedHandle, FromRawHandle, IntoRawHandle, OwnedHandle, RawHandle,
+};
+use crate::process;
+use crate::sealed::Sealed;
+use crate::sys;
+use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner};
+
+#[stable(feature = "process_extensions", since = "1.2.0")]
+impl FromRawHandle for process::Stdio {
+ unsafe fn from_raw_handle(handle: RawHandle) -> process::Stdio {
+ let handle = sys::handle::Handle::from_raw_handle(handle as *mut _);
+ let io = sys::process::Stdio::Handle(handle);
+ process::Stdio::from_inner(io)
+ }
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl From<OwnedHandle> for process::Stdio {
+ fn from(handle: OwnedHandle) -> process::Stdio {
+ let handle = sys::handle::Handle::from_inner(handle);
+ let io = sys::process::Stdio::Handle(handle);
+ process::Stdio::from_inner(io)
+ }
+}
+
+#[stable(feature = "process_extensions", since = "1.2.0")]
+impl AsRawHandle for process::Child {
+ #[inline]
+ fn as_raw_handle(&self) -> RawHandle {
+ self.as_inner().handle().as_raw_handle() as *mut _
+ }
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl AsHandle for process::Child {
+ #[inline]
+ fn as_handle(&self) -> BorrowedHandle<'_> {
+ self.as_inner().handle().as_handle()
+ }
+}
+
+#[stable(feature = "into_raw_os", since = "1.4.0")]
+impl IntoRawHandle for process::Child {
+ fn into_raw_handle(self) -> RawHandle {
+ self.into_inner().into_handle().into_raw_handle() as *mut _
+ }
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl From<process::Child> for OwnedHandle {
+ fn from(child: process::Child) -> OwnedHandle {
+ child.into_inner().into_handle().into_inner()
+ }
+}
+
+#[stable(feature = "process_extensions", since = "1.2.0")]
+impl AsRawHandle for process::ChildStdin {
+ #[inline]
+ fn as_raw_handle(&self) -> RawHandle {
+ self.as_inner().handle().as_raw_handle() as *mut _
+ }
+}
+
+#[stable(feature = "process_extensions", since = "1.2.0")]
+impl AsRawHandle for process::ChildStdout {
+ #[inline]
+ fn as_raw_handle(&self) -> RawHandle {
+ self.as_inner().handle().as_raw_handle() as *mut _
+ }
+}
+
+#[stable(feature = "process_extensions", since = "1.2.0")]
+impl AsRawHandle for process::ChildStderr {
+ #[inline]
+ fn as_raw_handle(&self) -> RawHandle {
+ self.as_inner().handle().as_raw_handle() as *mut _
+ }
+}
+
+#[stable(feature = "into_raw_os", since = "1.4.0")]
+impl IntoRawHandle for process::ChildStdin {
+ fn into_raw_handle(self) -> RawHandle {
+ self.into_inner().into_handle().into_raw_handle() as *mut _
+ }
+}
+
+#[stable(feature = "into_raw_os", since = "1.4.0")]
+impl IntoRawHandle for process::ChildStdout {
+ fn into_raw_handle(self) -> RawHandle {
+ self.into_inner().into_handle().into_raw_handle() as *mut _
+ }
+}
+
+#[stable(feature = "into_raw_os", since = "1.4.0")]
+impl IntoRawHandle for process::ChildStderr {
+ fn into_raw_handle(self) -> RawHandle {
+ self.into_inner().into_handle().into_raw_handle() as *mut _
+ }
+}
+
+/// Windows-specific extensions to [`process::ExitStatus`].
+///
+/// This trait is sealed: it cannot be implemented outside the standard library.
+/// This is so that future additional methods are not breaking changes.
+#[stable(feature = "exit_status_from", since = "1.12.0")]
+pub trait ExitStatusExt: Sealed {
+ /// Creates a new `ExitStatus` from the raw underlying `u32` return value of
+ /// a process.
+ #[stable(feature = "exit_status_from", since = "1.12.0")]
+ fn from_raw(raw: u32) -> Self;
+}
+
+#[stable(feature = "exit_status_from", since = "1.12.0")]
+impl ExitStatusExt for process::ExitStatus {
+ fn from_raw(raw: u32) -> Self {
+ process::ExitStatus::from_inner(From::from(raw))
+ }
+}
+
+/// Windows-specific extensions to the [`process::Command`] builder.
+///
+/// This trait is sealed: it cannot be implemented outside the standard library.
+/// This is so that future additional methods are not breaking changes.
+#[stable(feature = "windows_process_extensions", since = "1.16.0")]
+pub trait CommandExt: Sealed {
+ /// Sets the [process creation flags][1] to be passed to `CreateProcess`.
+ ///
+ /// These will always be ORed with `CREATE_UNICODE_ENVIRONMENT`.
+ ///
+ /// [1]: https://docs.microsoft.com/en-us/windows/win32/procthread/process-creation-flags
+ #[stable(feature = "windows_process_extensions", since = "1.16.0")]
+ fn creation_flags(&mut self, flags: u32) -> &mut process::Command;
+
+ /// Forces all arguments to be wrapped in quote (`"`) characters.
+ ///
+ /// This is useful for passing arguments to [MSYS2/Cygwin][1] based
+ /// executables: these programs will expand unquoted arguments containing
+ /// wildcard characters (`?` and `*`) by searching for any file paths
+ /// matching the wildcard pattern.
+ ///
+ /// Adding quotes has no effect when passing arguments to programs
+ /// that use [msvcrt][2]. This includes programs built with both
+ /// MinGW and MSVC.
+ ///
+ /// [1]: <https://github.com/msys2/MSYS2-packages/issues/2176>
+ /// [2]: <https://msdn.microsoft.com/en-us/library/17w5ykft.aspx>
+ #[unstable(feature = "windows_process_extensions_force_quotes", issue = "82227")]
+ fn force_quotes(&mut self, enabled: bool) -> &mut process::Command;
+
+ /// Append literal text to the command line without any quoting or escaping.
+ ///
+ /// This is useful for passing arguments to `cmd.exe /c`, which doesn't follow
+ /// `CommandLineToArgvW` escaping rules.
+ #[stable(feature = "windows_process_extensions_raw_arg", since = "1.62.0")]
+ fn raw_arg<S: AsRef<OsStr>>(&mut self, text_to_append_as_is: S) -> &mut process::Command;
+
+ /// When [`process::Command`] creates pipes, request that our side is always async.
+ ///
+ /// By default [`process::Command`] may choose to use pipes where both ends
+ /// are opened for synchronous read or write operations. By using
+ /// `async_pipes(true)`, this behavior is overridden so that our side is
+ /// always async.
+ ///
+ /// This is important because if doing async I/O a pipe or a file has to be
+ /// opened for async access.
+ ///
+ /// The end of the pipe sent to the child process will always be synchronous
+ /// regardless of this option.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// #![feature(windows_process_extensions_async_pipes)]
+ /// use std::os::windows::process::CommandExt;
+ /// use std::process::{Command, Stdio};
+ ///
+ /// # let program = "";
+ ///
+ /// Command::new(program)
+ /// .async_pipes(true)
+ /// .stdin(Stdio::piped())
+ /// .stdout(Stdio::piped())
+ /// .stderr(Stdio::piped());
+ /// ```
+ #[unstable(feature = "windows_process_extensions_async_pipes", issue = "98289")]
+ fn async_pipes(&mut self, always_async: bool) -> &mut process::Command;
+}
+
+#[stable(feature = "windows_process_extensions", since = "1.16.0")]
+impl CommandExt for process::Command {
+ fn creation_flags(&mut self, flags: u32) -> &mut process::Command {
+ self.as_inner_mut().creation_flags(flags);
+ self
+ }
+
+ fn force_quotes(&mut self, enabled: bool) -> &mut process::Command {
+ self.as_inner_mut().force_quotes(enabled);
+ self
+ }
+
+ fn raw_arg<S: AsRef<OsStr>>(&mut self, raw_text: S) -> &mut process::Command {
+ self.as_inner_mut().raw_arg(raw_text.as_ref());
+ self
+ }
+
+ fn async_pipes(&mut self, always_async: bool) -> &mut process::Command {
+ // FIXME: This currently has an intentional no-op implementation.
+ // For the time being our side of the pipes will always be async.
+ // Once the ecosystem has adjusted, we may then be able to start making
+ // use of synchronous pipes within the standard library.
+ let _ = always_async;
+ self
+ }
+}
+
+#[unstable(feature = "windows_process_extensions_main_thread_handle", issue = "96723")]
+pub trait ChildExt: Sealed {
+ /// Extracts the main thread raw handle, without taking ownership
+ #[unstable(feature = "windows_process_extensions_main_thread_handle", issue = "96723")]
+ fn main_thread_handle(&self) -> BorrowedHandle<'_>;
+}
+
+#[unstable(feature = "windows_process_extensions_main_thread_handle", issue = "96723")]
+impl ChildExt for process::Child {
+ fn main_thread_handle(&self) -> BorrowedHandle<'_> {
+ self.handle.main_thread_handle()
+ }
+}
+
+/// Windows-specific extensions to [`process::ExitCode`].
+///
+/// This trait is sealed: it cannot be implemented outside the standard library.
+/// This is so that future additional methods are not breaking changes.
+#[unstable(feature = "windows_process_exit_code_from", issue = "none")]
+pub trait ExitCodeExt: Sealed {
+ /// Creates a new `ExitCode` from the raw underlying `u32` return value of
+ /// a process.
+ ///
+ /// The exit code should not be 259, as this conflicts with the `STILL_ACTIVE`
+ /// macro returned from the `GetExitCodeProcess` function to signal that the
+ /// process has yet to run to completion.
+ #[unstable(feature = "windows_process_exit_code_from", issue = "none")]
+ fn from_raw(raw: u32) -> Self;
+}
+
+#[unstable(feature = "windows_process_exit_code_from", issue = "none")]
+impl ExitCodeExt for process::ExitCode {
+ fn from_raw(raw: u32) -> Self {
+ process::ExitCode::from_inner(From::from(raw))
+ }
+}
diff --git a/library/std/src/os/windows/raw.rs b/library/std/src/os/windows/raw.rs
new file mode 100644
index 000000000..0ef3adade
--- /dev/null
+++ b/library/std/src/os/windows/raw.rs
@@ -0,0 +1,16 @@
+//! Windows-specific primitives.
+
+#![stable(feature = "raw_ext", since = "1.1.0")]
+
+use crate::os::raw::c_void;
+
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type HANDLE = *mut c_void;
+#[cfg(target_pointer_width = "32")]
+#[doc(cfg(all()))]
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type SOCKET = u32;
+#[cfg(target_pointer_width = "64")]
+#[doc(cfg(all()))]
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type SOCKET = u64;
diff --git a/library/std/src/os/windows/thread.rs b/library/std/src/os/windows/thread.rs
new file mode 100644
index 000000000..d81d6d0ac
--- /dev/null
+++ b/library/std/src/os/windows/thread.rs
@@ -0,0 +1,25 @@
+//! Windows-specific extensions to primitives in the [`std::thread`] module.
+//!
+//! [`std::thread`]: crate::thread
+
+#![stable(feature = "thread_extensions", since = "1.9.0")]
+
+use crate::os::windows::io::{AsRawHandle, IntoRawHandle, RawHandle};
+use crate::sys_common::{AsInner, IntoInner};
+use crate::thread;
+
+#[stable(feature = "thread_extensions", since = "1.9.0")]
+impl<T> AsRawHandle for thread::JoinHandle<T> {
+ #[inline]
+ fn as_raw_handle(&self) -> RawHandle {
+ self.as_inner().handle().as_raw_handle() as *mut _
+ }
+}
+
+#[stable(feature = "thread_extensions", since = "1.9.0")]
+impl<T> IntoRawHandle for thread::JoinHandle<T> {
+ #[inline]
+ fn into_raw_handle(self) -> RawHandle {
+ self.into_inner().into_handle().into_raw_handle() as *mut _
+ }
+}