summaryrefslogtreecommitdiffstats
path: root/library/std/src/sys/windows
diff options
context:
space:
mode:
Diffstat (limited to 'library/std/src/sys/windows')
-rw-r--r--library/std/src/sys/windows/api.rs157
-rw-r--r--library/std/src/sys/windows/c.rs4
-rw-r--r--library/std/src/sys/windows/c/windows_sys.lst10
-rw-r--r--library/std/src/sys/windows/c/windows_sys.rs65
-rw-r--r--library/std/src/sys/windows/cmath.rs6
-rw-r--r--library/std/src/sys/windows/fs.rs79
-rw-r--r--library/std/src/sys/windows/io.rs4
-rw-r--r--library/std/src/sys/windows/mod.rs16
-rw-r--r--library/std/src/sys/windows/net.rs14
-rw-r--r--library/std/src/sys/windows/os.rs6
-rw-r--r--library/std/src/sys/windows/process.rs5
-rw-r--r--library/std/src/sys/windows/stack_overflow.rs4
-rw-r--r--library/std/src/sys/windows/stdio.rs3
-rw-r--r--library/std/src/sys/windows/thread.rs15
-rw-r--r--library/std/src/sys/windows/thread_local_key.rs19
-rw-r--r--library/std/src/sys/windows/time.rs38
16 files changed, 369 insertions, 76 deletions
diff --git a/library/std/src/sys/windows/api.rs b/library/std/src/sys/windows/api.rs
new file mode 100644
index 000000000..e9f0bbfbe
--- /dev/null
+++ b/library/std/src/sys/windows/api.rs
@@ -0,0 +1,157 @@
+//! # Safe(r) wrappers around Windows API functions.
+//!
+//! This module contains fairly thin wrappers around Windows API functions,
+//! aimed at centralising safety instead of having unsafe blocks spread
+//! throughout higher level code. This makes it much easier to audit FFI safety.
+//!
+//! Not all functions can be made completely safe without more context but in
+//! such cases we should still endeavour to reduce the caller's burden of safety
+//! as much as possible.
+//!
+//! ## Guidelines for wrappers
+//!
+//! Items here should be named similarly to their raw Windows API name, except
+//! that they follow Rust's case conventions. E.g. function names are
+//! lower_snake_case. The idea here is that it should be easy for a Windows
+//! C/C++ programmer to identify the underlying function that's being wrapped
+//! while not looking too out of place in Rust code.
+//!
+//! Every use of an `unsafe` block must have a related SAFETY comment, even if
+//! it's trivially safe (for example, see `get_last_error`). Public unsafe
+//! functions must document what the caller has to do to call them safely.
+//!
+//! Avoid unchecked `as` casts. For integers, either assert that the integer
+//! is in range or use `try_into` instead. For pointers, prefer to use
+//! `ptr.cast::<Type>()` when possible.
+//!
+//! This module must only depend on core and not on std types as the eventual
+//! hope is to have std depend on sys and not the other way around.
+//! However, some amount of glue code may currently be necessary so such code
+//! should go in sys/windows/mod.rs rather than here. See `IoResult` as an example.
+
+use core::ffi::c_void;
+use core::ptr::addr_of;
+
+use super::c;
+
+/// Helper method for getting the size of `T` as a u32.
+/// Errors at compile time if the size would overflow.
+///
+/// While a type larger than u32::MAX is unlikely, it is possible if only because of a bug.
+/// However, one key motivation for this function is to avoid the temptation to
+/// use frequent `as` casts. This is risky because they are too powerful.
+/// For example, the following will compile today:
+///
+/// `std::mem::size_of::<u64> as u32`
+///
+/// Note that `size_of` is never actually called, instead a function pointer is
+/// converted to a `u32`. Clippy would warn about this but, alas, it's not run
+/// on the standard library.
+const fn win32_size_of<T: Sized>() -> u32 {
+ // Const assert that the size is less than u32::MAX.
+ // Uses a trait to workaround restriction on using generic types in inner items.
+ trait Win32SizeOf: Sized {
+ const WIN32_SIZE_OF: u32 = {
+ let size = core::mem::size_of::<Self>();
+ assert!(size <= u32::MAX as usize);
+ size as u32
+ };
+ }
+ impl<T: Sized> Win32SizeOf for T {}
+
+ T::WIN32_SIZE_OF
+}
+
+/// The `SetFileInformationByHandle` function takes a generic parameter by
+/// making the user specify the type (class), a pointer to the data and its
+/// size. This trait allows attaching that information to a Rust type so that
+/// [`set_file_information_by_handle`] can be called safely.
+///
+/// This trait is designed so that it can support variable sized types.
+/// However, currently Rust's std only uses fixed sized structures.
+///
+/// # Safety
+///
+/// * `as_ptr` must return a pointer to memory that is readable up to `size` bytes.
+/// * `CLASS` must accurately reflect the type pointed to by `as_ptr`. E.g.
+/// the `FILE_BASIC_INFO` structure has the class `FileBasicInfo`.
+pub unsafe trait SetFileInformation {
+ /// The type of information to set.
+ const CLASS: i32;
+ /// A pointer to the file information to set.
+ fn as_ptr(&self) -> *const c_void;
+ /// The size of the type pointed to by `as_ptr`.
+ fn size(&self) -> u32;
+}
+/// Helper trait for implementing `SetFileInformation` for statically sized types.
+unsafe trait SizedSetFileInformation: Sized {
+ const CLASS: i32;
+}
+unsafe impl<T: SizedSetFileInformation> SetFileInformation for T {
+ const CLASS: i32 = T::CLASS;
+ fn as_ptr(&self) -> *const c_void {
+ addr_of!(*self).cast::<c_void>()
+ }
+ fn size(&self) -> u32 {
+ win32_size_of::<Self>()
+ }
+}
+
+// SAFETY: FILE_BASIC_INFO, FILE_END_OF_FILE_INFO, FILE_ALLOCATION_INFO,
+// FILE_DISPOSITION_INFO, FILE_DISPOSITION_INFO_EX and FILE_IO_PRIORITY_HINT_INFO
+// are all plain `repr(C)` structs that only contain primitive types.
+// The given information classes correctly match with the struct.
+unsafe impl SizedSetFileInformation for c::FILE_BASIC_INFO {
+ const CLASS: i32 = c::FileBasicInfo;
+}
+unsafe impl SizedSetFileInformation for c::FILE_END_OF_FILE_INFO {
+ const CLASS: i32 = c::FileEndOfFileInfo;
+}
+unsafe impl SizedSetFileInformation for c::FILE_ALLOCATION_INFO {
+ const CLASS: i32 = c::FileAllocationInfo;
+}
+unsafe impl SizedSetFileInformation for c::FILE_DISPOSITION_INFO {
+ const CLASS: i32 = c::FileDispositionInfo;
+}
+unsafe impl SizedSetFileInformation for c::FILE_DISPOSITION_INFO_EX {
+ const CLASS: i32 = c::FileDispositionInfoEx;
+}
+unsafe impl SizedSetFileInformation for c::FILE_IO_PRIORITY_HINT_INFO {
+ const CLASS: i32 = c::FileIoPriorityHintInfo;
+}
+
+#[inline]
+pub fn set_file_information_by_handle<T: SetFileInformation>(
+ handle: c::HANDLE,
+ info: &T,
+) -> Result<(), WinError> {
+ unsafe fn set_info(
+ handle: c::HANDLE,
+ class: i32,
+ info: *const c_void,
+ size: u32,
+ ) -> Result<(), WinError> {
+ let result = c::SetFileInformationByHandle(handle, class, info, size);
+ (result != 0).then_some(()).ok_or_else(|| get_last_error())
+ }
+ // SAFETY: The `SetFileInformation` trait ensures that this is safe.
+ unsafe { set_info(handle, T::CLASS, info.as_ptr(), info.size()) }
+}
+
+/// Gets the error from the last function.
+/// This must be called immediately after the function that sets the error to
+/// avoid the risk of another function overwriting it.
+pub fn get_last_error() -> WinError {
+ // SAFETY: This just returns a thread-local u32 and has no other effects.
+ unsafe { WinError { code: c::GetLastError() } }
+}
+
+/// An error code as returned by [`get_last_error`].
+///
+/// This is usually a 16-bit Win32 error code but may be a 32-bit HRESULT or NTSTATUS.
+/// Check the documentation of the Windows API function being called for expected errors.
+#[derive(Clone, Copy, PartialEq, Eq)]
+#[repr(transparent)]
+pub struct WinError {
+ pub code: u32,
+}
diff --git a/library/std/src/sys/windows/c.rs b/library/std/src/sys/windows/c.rs
index f3637cbb9..a349e24b0 100644
--- a/library/std/src/sys/windows/c.rs
+++ b/library/std/src/sys/windows/c.rs
@@ -46,6 +46,10 @@ pub use FD_SET as fd_set;
pub use LINGER as linger;
pub use TIMEVAL as timeval;
+// https://learn.microsoft.com/en-us/cpp/c-runtime-library/exit-success-exit-failure?view=msvc-170
+pub const EXIT_SUCCESS: u32 = 0;
+pub const EXIT_FAILURE: u32 = 1;
+
pub const CONDITION_VARIABLE_INIT: CONDITION_VARIABLE = CONDITION_VARIABLE { Ptr: ptr::null_mut() };
pub const SRWLOCK_INIT: SRWLOCK = SRWLOCK { Ptr: ptr::null_mut() };
pub const INIT_ONCE_STATIC_INIT: INIT_ONCE = INIT_ONCE { Ptr: ptr::null_mut() };
diff --git a/library/std/src/sys/windows/c/windows_sys.lst b/library/std/src/sys/windows/c/windows_sys.lst
index 0aca37e2d..38bf15b7c 100644
--- a/library/std/src/sys/windows/c/windows_sys.lst
+++ b/library/std/src/sys/windows/c/windows_sys.lst
@@ -1964,6 +1964,7 @@ Windows.Win32.Networking.WinSock.ADDRESS_FAMILY
Windows.Win32.Networking.WinSock.ADDRINFOA
Windows.Win32.Networking.WinSock.AF_INET
Windows.Win32.Networking.WinSock.AF_INET6
+Windows.Win32.Networking.WinSock.AF_UNIX
Windows.Win32.Networking.WinSock.AF_UNSPEC
Windows.Win32.Networking.WinSock.bind
Windows.Win32.Networking.WinSock.closesocket
@@ -2058,6 +2059,7 @@ Windows.Win32.Networking.WinSock.SOCK_RDM
Windows.Win32.Networking.WinSock.SOCK_SEQPACKET
Windows.Win32.Networking.WinSock.SOCK_STREAM
Windows.Win32.Networking.WinSock.SOCKADDR
+Windows.Win32.Networking.WinSock.SOCKADDR_UN
Windows.Win32.Networking.WinSock.SOCKET
Windows.Win32.Networking.WinSock.SOCKET_ERROR
Windows.Win32.Networking.WinSock.SOL_SOCKET
@@ -2222,6 +2224,7 @@ Windows.Win32.Storage.FileSystem.FILE_ACCESS_RIGHTS
Windows.Win32.Storage.FileSystem.FILE_ADD_FILE
Windows.Win32.Storage.FileSystem.FILE_ADD_SUBDIRECTORY
Windows.Win32.Storage.FileSystem.FILE_ALL_ACCESS
+Windows.Win32.Storage.FileSystem.FILE_ALLOCATION_INFO
Windows.Win32.Storage.FileSystem.FILE_APPEND_DATA
Windows.Win32.Storage.FileSystem.FILE_ATTRIBUTE_ARCHIVE
Windows.Win32.Storage.FileSystem.FILE_ATTRIBUTE_COMPRESSED
@@ -2282,6 +2285,7 @@ Windows.Win32.Storage.FileSystem.FILE_GENERIC_READ
Windows.Win32.Storage.FileSystem.FILE_GENERIC_WRITE
Windows.Win32.Storage.FileSystem.FILE_ID_BOTH_DIR_INFO
Windows.Win32.Storage.FileSystem.FILE_INFO_BY_HANDLE_CLASS
+Windows.Win32.Storage.FileSystem.FILE_IO_PRIORITY_HINT_INFO
Windows.Win32.Storage.FileSystem.FILE_LIST_DIRECTORY
Windows.Win32.Storage.FileSystem.FILE_NAME_NORMALIZED
Windows.Win32.Storage.FileSystem.FILE_NAME_OPENED
@@ -2503,9 +2507,12 @@ Windows.Win32.System.Threading.CREATE_SEPARATE_WOW_VDM
Windows.Win32.System.Threading.CREATE_SHARED_WOW_VDM
Windows.Win32.System.Threading.CREATE_SUSPENDED
Windows.Win32.System.Threading.CREATE_UNICODE_ENVIRONMENT
+Windows.Win32.System.Threading.CREATE_WAITABLE_TIMER_HIGH_RESOLUTION
+Windows.Win32.System.Threading.CREATE_WAITABLE_TIMER_MANUAL_RESET
Windows.Win32.System.Threading.CreateEventW
Windows.Win32.System.Threading.CreateProcessW
Windows.Win32.System.Threading.CreateThread
+Windows.Win32.System.Threading.CreateWaitableTimerExW
Windows.Win32.System.Threading.DEBUG_ONLY_THIS_PROCESS
Windows.Win32.System.Threading.DEBUG_PROCESS
Windows.Win32.System.Threading.DeleteProcThreadAttributeList
@@ -2542,6 +2549,7 @@ Windows.Win32.System.Threading.REALTIME_PRIORITY_CLASS
Windows.Win32.System.Threading.ReleaseSRWLockExclusive
Windows.Win32.System.Threading.ReleaseSRWLockShared
Windows.Win32.System.Threading.SetThreadStackGuarantee
+Windows.Win32.System.Threading.SetWaitableTimer
Windows.Win32.System.Threading.Sleep
Windows.Win32.System.Threading.SleepConditionVariableSRW
Windows.Win32.System.Threading.SleepEx
@@ -2568,6 +2576,8 @@ Windows.Win32.System.Threading.TerminateProcess
Windows.Win32.System.Threading.THREAD_CREATE_RUN_IMMEDIATELY
Windows.Win32.System.Threading.THREAD_CREATE_SUSPENDED
Windows.Win32.System.Threading.THREAD_CREATION_FLAGS
+Windows.Win32.System.Threading.TIMER_ALL_ACCESS
+Windows.Win32.System.Threading.TIMER_MODIFY_STATE
Windows.Win32.System.Threading.TLS_OUT_OF_INDEXES
Windows.Win32.System.Threading.TlsAlloc
Windows.Win32.System.Threading.TlsFree
diff --git a/library/std/src/sys/windows/c/windows_sys.rs b/library/std/src/sys/windows/c/windows_sys.rs
index 851d15915..e0509e6a5 100644
--- a/library/std/src/sys/windows/c/windows_sys.rs
+++ b/library/std/src/sys/windows/c/windows_sys.rs
@@ -152,6 +152,15 @@ extern "system" {
}
#[link(name = "kernel32")]
extern "system" {
+ pub fn CreateWaitableTimerExW(
+ lptimerattributes: *const SECURITY_ATTRIBUTES,
+ lptimername: PCWSTR,
+ dwflags: u32,
+ dwdesiredaccess: u32,
+ ) -> HANDLE;
+}
+#[link(name = "kernel32")]
+extern "system" {
pub fn DeleteFileW(lpfilename: PCWSTR) -> BOOL;
}
#[link(name = "kernel32")]
@@ -509,6 +518,17 @@ extern "system" {
}
#[link(name = "kernel32")]
extern "system" {
+ pub fn SetWaitableTimer(
+ htimer: HANDLE,
+ lpduetime: *const i64,
+ lperiod: i32,
+ pfncompletionroutine: PTIMERAPCROUTINE,
+ lpargtocompletionroutine: *const ::core::ffi::c_void,
+ fresume: BOOL,
+ ) -> BOOL;
+}
+#[link(name = "kernel32")]
+extern "system" {
pub fn Sleep(dwmilliseconds: u32) -> ();
}
#[link(name = "kernel32")]
@@ -847,6 +867,7 @@ impl ::core::clone::Clone for ADDRINFOA {
}
pub const AF_INET: ADDRESS_FAMILY = 2u16;
pub const AF_INET6: ADDRESS_FAMILY = 23u16;
+pub const AF_UNIX: u16 = 1u16;
pub const AF_UNSPEC: ADDRESS_FAMILY = 0u16;
pub const ALL_PROCESSOR_GROUPS: u32 = 65535u32;
#[repr(C)]
@@ -1164,6 +1185,8 @@ pub const CREATE_SEPARATE_WOW_VDM: PROCESS_CREATION_FLAGS = 2048u32;
pub const CREATE_SHARED_WOW_VDM: PROCESS_CREATION_FLAGS = 4096u32;
pub const CREATE_SUSPENDED: PROCESS_CREATION_FLAGS = 4u32;
pub const CREATE_UNICODE_ENVIRONMENT: PROCESS_CREATION_FLAGS = 1024u32;
+pub const CREATE_WAITABLE_TIMER_HIGH_RESOLUTION: u32 = 2u32;
+pub const CREATE_WAITABLE_TIMER_MANUAL_RESET: u32 = 1u32;
pub const CSTR_EQUAL: COMPARESTRING_RESULT = 2i32;
pub const CSTR_GREATER_THAN: COMPARESTRING_RESULT = 3i32;
pub const CSTR_LESS_THAN: COMPARESTRING_RESULT = 1i32;
@@ -3106,6 +3129,16 @@ impl ::core::clone::Clone for FILETIME {
pub type FILE_ACCESS_RIGHTS = u32;
pub const FILE_ADD_FILE: FILE_ACCESS_RIGHTS = 2u32;
pub const FILE_ADD_SUBDIRECTORY: FILE_ACCESS_RIGHTS = 4u32;
+#[repr(C)]
+pub struct FILE_ALLOCATION_INFO {
+ pub AllocationSize: i64,
+}
+impl ::core::marker::Copy for FILE_ALLOCATION_INFO {}
+impl ::core::clone::Clone for FILE_ALLOCATION_INFO {
+ fn clone(&self) -> Self {
+ *self
+ }
+}
pub const FILE_ALL_ACCESS: FILE_ACCESS_RIGHTS = 2032127u32;
pub const FILE_APPEND_DATA: FILE_ACCESS_RIGHTS = 4u32;
pub const FILE_ATTRIBUTE_ARCHIVE: FILE_FLAGS_AND_ATTRIBUTES = 32u32;
@@ -3247,6 +3280,16 @@ impl ::core::clone::Clone for FILE_ID_BOTH_DIR_INFO {
}
}
pub type FILE_INFO_BY_HANDLE_CLASS = i32;
+#[repr(C)]
+pub struct FILE_IO_PRIORITY_HINT_INFO {
+ pub PriorityHint: PRIORITY_HINT,
+}
+impl ::core::marker::Copy for FILE_IO_PRIORITY_HINT_INFO {}
+impl ::core::clone::Clone for FILE_IO_PRIORITY_HINT_INFO {
+ fn clone(&self) -> Self {
+ *self
+ }
+}
pub const FILE_LIST_DIRECTORY: FILE_ACCESS_RIGHTS = 1u32;
pub const FILE_NAME_NORMALIZED: GETFINALPATHNAMEBYHANDLE_FLAGS = 0u32;
pub const FILE_NAME_OPENED: GETFINALPATHNAMEBYHANDLE_FLAGS = 8u32;
@@ -3752,6 +3795,7 @@ pub const PIPE_SERVER_END: NAMED_PIPE_MODE = 1u32;
pub const PIPE_TYPE_BYTE: NAMED_PIPE_MODE = 0u32;
pub const PIPE_TYPE_MESSAGE: NAMED_PIPE_MODE = 4u32;
pub const PIPE_WAIT: NAMED_PIPE_MODE = 0u32;
+pub type PRIORITY_HINT = i32;
pub type PROCESSOR_ARCHITECTURE = u16;
pub type PROCESS_CREATION_FLAGS = u32;
#[repr(C)]
@@ -3774,6 +3818,13 @@ pub const PROFILE_SERVER: PROCESS_CREATION_FLAGS = 1073741824u32;
pub const PROFILE_USER: PROCESS_CREATION_FLAGS = 268435456u32;
pub const PROGRESS_CONTINUE: u32 = 0u32;
pub type PSTR = *mut u8;
+pub type PTIMERAPCROUTINE = ::core::option::Option<
+ unsafe extern "system" fn(
+ lpargtocompletionroutine: *const ::core::ffi::c_void,
+ dwtimerlowvalue: u32,
+ dwtimerhighvalue: u32,
+ ) -> (),
+>;
pub type PWSTR = *mut u16;
pub const READ_CONTROL: FILE_ACCESS_RIGHTS = 131072u32;
pub const REALTIME_PRIORITY_CLASS: PROCESS_CREATION_FLAGS = 256u32;
@@ -3813,6 +3864,17 @@ impl ::core::clone::Clone for SOCKADDR {
*self
}
}
+#[repr(C)]
+pub struct SOCKADDR_UN {
+ pub sun_family: ADDRESS_FAMILY,
+ pub sun_path: [u8; 108],
+}
+impl ::core::marker::Copy for SOCKADDR_UN {}
+impl ::core::clone::Clone for SOCKADDR_UN {
+ fn clone(&self) -> Self {
+ *self
+ }
+}
pub type SOCKET = usize;
pub const SOCKET_ERROR: i32 = -1i32;
pub const SOCK_DGRAM: WINSOCK_SOCKET_TYPE = 2i32;
@@ -3910,6 +3972,7 @@ pub type SYMBOLIC_LINK_FLAGS = u32;
pub const SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE: SYMBOLIC_LINK_FLAGS = 2u32;
pub const SYMBOLIC_LINK_FLAG_DIRECTORY: SYMBOLIC_LINK_FLAGS = 1u32;
pub const SYMLINK_FLAG_RELATIVE: u32 = 1u32;
+pub type SYNCHRONIZATION_ACCESS_RIGHTS = u32;
pub const SYNCHRONIZE: FILE_ACCESS_RIGHTS = 1048576u32;
#[repr(C)]
pub struct SYSTEM_INFO {
@@ -3956,6 +4019,8 @@ pub const TCP_NODELAY: i32 = 1i32;
pub const THREAD_CREATE_RUN_IMMEDIATELY: THREAD_CREATION_FLAGS = 0u32;
pub const THREAD_CREATE_SUSPENDED: THREAD_CREATION_FLAGS = 4u32;
pub type THREAD_CREATION_FLAGS = u32;
+pub const TIMER_ALL_ACCESS: SYNCHRONIZATION_ACCESS_RIGHTS = 2031619u32;
+pub const TIMER_MODIFY_STATE: SYNCHRONIZATION_ACCESS_RIGHTS = 2u32;
#[repr(C)]
pub struct TIMEVAL {
pub tv_sec: i32,
diff --git a/library/std/src/sys/windows/cmath.rs b/library/std/src/sys/windows/cmath.rs
index 1b2a86f3c..36578d5a3 100644
--- a/library/std/src/sys/windows/cmath.rs
+++ b/library/std/src/sys/windows/cmath.rs
@@ -1,6 +1,6 @@
#![cfg(not(test))]
-use libc::{c_double, c_float, c_int};
+use core::ffi::{c_double, c_float, c_int};
extern "C" {
pub fn acos(n: c_double) -> c_double;
@@ -33,7 +33,7 @@ pub use self::shims::*;
#[cfg(not(all(target_env = "msvc", target_arch = "x86")))]
mod shims {
- use libc::c_float;
+ use core::ffi::c_float;
extern "C" {
pub fn acosf(n: c_float) -> c_float;
@@ -52,7 +52,7 @@ mod shims {
// back to f32. While not precisely correct should be "correct enough" for now.
#[cfg(all(target_env = "msvc", target_arch = "x86"))]
mod shims {
- use libc::c_float;
+ use core::ffi::c_float;
#[inline]
pub unsafe fn acosf(n: c_float) -> c_float {
diff --git a/library/std/src/sys/windows/fs.rs b/library/std/src/sys/windows/fs.rs
index 21a65bc25..d7e36b9a3 100644
--- a/library/std/src/sys/windows/fs.rs
+++ b/library/std/src/sys/windows/fs.rs
@@ -16,8 +16,10 @@ use crate::sys::{c, cvt, Align8};
use crate::sys_common::{AsInner, FromInner, IntoInner};
use crate::thread;
+use core::ffi::c_void;
+
use super::path::maybe_verbatim;
-use super::to_u16s;
+use super::{api, to_u16s, IoResult};
pub struct File {
handle: Handle,
@@ -121,7 +123,7 @@ impl Iterator for ReadDir {
let mut wfd = mem::zeroed();
loop {
if c::FindNextFileW(self.handle.0, &mut wfd) == 0 {
- if c::GetLastError() == c::ERROR_NO_MORE_FILES {
+ if api::get_last_error().code == c::ERROR_NO_MORE_FILES {
return None;
} else {
return Some(Err(Error::last_os_error()));
@@ -316,17 +318,8 @@ impl File {
}
pub fn truncate(&self, size: u64) -> io::Result<()> {
- let mut info = c::FILE_END_OF_FILE_INFO { EndOfFile: size as c::LARGE_INTEGER };
- let size = mem::size_of_val(&info);
- cvt(unsafe {
- c::SetFileInformationByHandle(
- self.handle.as_raw_handle(),
- c::FileEndOfFileInfo,
- &mut info as *mut _ as *mut _,
- size as c::DWORD,
- )
- })?;
- Ok(())
+ let info = c::FILE_END_OF_FILE_INFO { EndOfFile: size as i64 };
+ api::set_file_information_by_handle(self.handle.as_raw_handle(), &info).io_result()
}
#[cfg(not(target_vendor = "uwp"))]
@@ -371,7 +364,7 @@ impl File {
cvt(c::GetFileInformationByHandleEx(
self.handle.as_raw_handle(),
c::FileBasicInfo,
- &mut info as *mut _ as *mut libc::c_void,
+ &mut info as *mut _ as *mut c_void,
size as c::DWORD,
))?;
let mut attr = FileAttr {
@@ -399,7 +392,7 @@ impl File {
cvt(c::GetFileInformationByHandleEx(
self.handle.as_raw_handle(),
c::FileStandardInfo,
- &mut info as *mut _ as *mut libc::c_void,
+ &mut info as *mut _ as *mut c_void,
size as c::DWORD,
))?;
attr.file_size = info.AllocationSize as u64;
@@ -563,23 +556,14 @@ impl File {
}
pub fn set_permissions(&self, perm: FilePermissions) -> io::Result<()> {
- let mut info = c::FILE_BASIC_INFO {
+ let info = c::FILE_BASIC_INFO {
CreationTime: 0,
LastAccessTime: 0,
LastWriteTime: 0,
ChangeTime: 0,
FileAttributes: perm.attrs,
};
- let size = mem::size_of_val(&info);
- cvt(unsafe {
- c::SetFileInformationByHandle(
- self.handle.as_raw_handle(),
- c::FileBasicInfo,
- &mut info as *mut _ as *mut _,
- size as c::DWORD,
- )
- })?;
- Ok(())
+ api::set_file_information_by_handle(self.handle.as_raw_handle(), &info).io_result()
}
pub fn set_times(&self, times: FileTimes) -> io::Result<()> {
@@ -624,7 +608,7 @@ impl File {
cvt(c::GetFileInformationByHandleEx(
self.handle.as_raw_handle(),
c::FileBasicInfo,
- &mut info as *mut _ as *mut libc::c_void,
+ &mut info as *mut _ as *mut c_void,
size as c::DWORD,
))?;
Ok(info)
@@ -639,38 +623,20 @@ impl File {
/// If the operation is not supported for this filesystem or OS version
/// then errors will be `ERROR_NOT_SUPPORTED` or `ERROR_INVALID_PARAMETER`.
fn posix_delete(&self) -> io::Result<()> {
- let mut info = c::FILE_DISPOSITION_INFO_EX {
+ let info = c::FILE_DISPOSITION_INFO_EX {
Flags: c::FILE_DISPOSITION_FLAG_DELETE
| c::FILE_DISPOSITION_FLAG_POSIX_SEMANTICS
| c::FILE_DISPOSITION_FLAG_IGNORE_READONLY_ATTRIBUTE,
};
- let size = mem::size_of_val(&info);
- cvt(unsafe {
- c::SetFileInformationByHandle(
- self.handle.as_raw_handle(),
- c::FileDispositionInfoEx,
- &mut info as *mut _ as *mut _,
- size as c::DWORD,
- )
- })?;
- Ok(())
+ api::set_file_information_by_handle(self.handle.as_raw_handle(), &info).io_result()
}
/// Delete a file using win32 semantics. The file won't actually be deleted
/// until all file handles are closed. However, marking a file for deletion
/// will prevent anyone from opening a new handle to the file.
fn win32_delete(&self) -> io::Result<()> {
- let mut info = c::FILE_DISPOSITION_INFO { DeleteFile: c::TRUE as _ };
- let size = mem::size_of_val(&info);
- cvt(unsafe {
- c::SetFileInformationByHandle(
- self.handle.as_raw_handle(),
- c::FileDispositionInfo,
- &mut info as *mut _ as *mut _,
- size as c::DWORD,
- )
- })?;
- Ok(())
+ let info = c::FILE_DISPOSITION_INFO { DeleteFile: c::TRUE as _ };
+ api::set_file_information_by_handle(self.handle.as_raw_handle(), &info).io_result()
}
/// Fill the given buffer with as many directory entries as will fit.
@@ -1064,6 +1030,14 @@ impl DirBuilder {
}
pub fn readdir(p: &Path) -> io::Result<ReadDir> {
+ // We push a `*` to the end of the path which cause the empty path to be
+ // treated as the current directory. So, for consistency with other platforms,
+ // we explicitly error on the empty path.
+ if p.as_os_str().is_empty() {
+ // Return an error code consistent with other ways of opening files.
+ // E.g. fs::metadata or File::open.
+ return Err(io::Error::from_raw_os_error(c::ERROR_PATH_NOT_FOUND as i32));
+ }
let root = p.to_path_buf();
let star = p.join("*");
let path = maybe_verbatim(&star)?;
@@ -1513,6 +1487,13 @@ pub fn try_exists(path: &Path) -> io::Result<bool> {
// as the file existing.
_ if e.raw_os_error() == Some(c::ERROR_SHARING_VIOLATION as i32) => Ok(true),
+ // `ERROR_CANT_ACCESS_FILE` means that a file exists but that the
+ // reparse point could not be handled by `CreateFile`.
+ // This can happen for special files such as:
+ // * Unix domain sockets which you need to `connect` to
+ // * App exec links which require using `CreateProcess`
+ _ if e.raw_os_error() == Some(c::ERROR_CANT_ACCESS_FILE as i32) => Ok(true),
+
// Other errors such as `ERROR_ACCESS_DENIED` may indicate that the
// file exists. However, these types of errors are usually more
// permanent so we report them here.
diff --git a/library/std/src/sys/windows/io.rs b/library/std/src/sys/windows/io.rs
index fc9856cae..9b540ee07 100644
--- a/library/std/src/sys/windows/io.rs
+++ b/library/std/src/sys/windows/io.rs
@@ -3,7 +3,7 @@ use crate::mem::size_of;
use crate::os::windows::io::{AsHandle, AsRawHandle, BorrowedHandle};
use crate::slice;
use crate::sys::c;
-use libc;
+use core::ffi::c_void;
#[derive(Copy, Clone)]
#[repr(transparent)]
@@ -136,7 +136,7 @@ unsafe fn msys_tty_on(handle: c::HANDLE) -> bool {
let res = c::GetFileInformationByHandleEx(
handle,
c::FileNameInfo,
- &mut name_info as *mut _ as *mut libc::c_void,
+ &mut name_info as *mut _ as *mut c_void,
size_of::<FILE_NAME_INFO>() as u32,
);
if res == 0 {
diff --git a/library/std/src/sys/windows/mod.rs b/library/std/src/sys/windows/mod.rs
index b609ad247..c4e56e13b 100644
--- a/library/std/src/sys/windows/mod.rs
+++ b/library/std/src/sys/windows/mod.rs
@@ -44,6 +44,18 @@ cfg_if::cfg_if! {
}
}
+mod api;
+
+/// Map a Result<T, WinError> to io::Result<T>.
+trait IoResult<T> {
+ fn io_result(self) -> crate::io::Result<T>;
+}
+impl<T> IoResult<T> for Result<T, api::WinError> {
+ fn io_result(self) -> crate::io::Result<T> {
+ self.map_err(|e| crate::io::Error::from_raw_os_error(e.code as i32))
+ }
+}
+
// SAFETY: must be called only once during runtime initialization.
// NOTE: this is not guaranteed to run, for example when Rust code is called externally.
pub unsafe fn init(_argc: isize, _argv: *const *const u8, _sigpipe: u8) {
@@ -241,11 +253,11 @@ where
// not an actual error.
c::SetLastError(0);
let k = match f1(buf.as_mut_ptr().cast::<u16>(), n as c::DWORD) {
- 0 if c::GetLastError() == 0 => 0,
+ 0 if api::get_last_error().code == 0 => 0,
0 => return Err(crate::io::Error::last_os_error()),
n => n,
} as usize;
- if k == n && c::GetLastError() == c::ERROR_INSUFFICIENT_BUFFER {
+ if k == n && api::get_last_error().code == c::ERROR_INSUFFICIENT_BUFFER {
n = n.saturating_mul(2).min(c::DWORD::MAX as usize);
} else if k > n {
n = k;
diff --git a/library/std/src/sys/windows/net.rs b/library/std/src/sys/windows/net.rs
index abdcab424..c29b86366 100644
--- a/library/std/src/sys/windows/net.rs
+++ b/library/std/src/sys/windows/net.rs
@@ -15,7 +15,7 @@ use crate::sys_common::net;
use crate::sys_common::{AsInner, FromInner, IntoInner};
use crate::time::Duration;
-use libc::{c_int, c_long, c_ulong, c_ushort};
+use core::ffi::{c_int, c_long, c_ulong, c_ushort};
pub type wrlen_t = i32;
@@ -140,13 +140,15 @@ impl Socket {
}
}
+ pub fn connect(&self, addr: &SocketAddr) -> io::Result<()> {
+ let (addr, len) = addr.into_inner();
+ let result = unsafe { c::connect(self.as_raw(), addr.as_ptr(), len) };
+ cvt(result).map(drop)
+ }
+
pub fn connect_timeout(&self, addr: &SocketAddr, timeout: Duration) -> io::Result<()> {
self.set_nonblocking(true)?;
- let result = {
- let (addr, len) = addr.into_inner();
- let result = unsafe { c::connect(self.as_raw(), addr.as_ptr(), len) };
- cvt(result).map(drop)
- };
+ let result = self.connect(addr);
self.set_nonblocking(false)?;
match result {
diff --git a/library/std/src/sys/windows/os.rs b/library/std/src/sys/windows/os.rs
index 58afca088..8cc905101 100644
--- a/library/std/src/sys/windows/os.rs
+++ b/library/std/src/sys/windows/os.rs
@@ -17,10 +17,10 @@ use crate::ptr;
use crate::slice;
use crate::sys::{c, cvt};
-use super::to_u16s;
+use super::{api, to_u16s};
pub fn errno() -> i32 {
- unsafe { c::GetLastError() as i32 }
+ api::get_last_error().code as i32
}
/// Gets a detailed string description for the given error number.
@@ -336,7 +336,7 @@ fn home_dir_crt() -> Option<PathBuf> {
super::fill_utf16_buf(
|buf, mut sz| {
match c::GetUserProfileDirectoryW(token, buf, &mut sz) {
- 0 if c::GetLastError() != c::ERROR_INSUFFICIENT_BUFFER => 0,
+ 0 if api::get_last_error().code != c::ERROR_INSUFFICIENT_BUFFER => 0,
0 => sz,
_ => sz - 1, // sz includes the null terminator
}
diff --git a/library/std/src/sys/windows/process.rs b/library/std/src/sys/windows/process.rs
index cd5bf7f15..f4078d359 100644
--- a/library/std/src/sys/windows/process.rs
+++ b/library/std/src/sys/windows/process.rs
@@ -19,8 +19,7 @@ use crate::path::{Path, PathBuf};
use crate::ptr;
use crate::sync::Mutex;
use crate::sys::args::{self, Arg};
-use crate::sys::c;
-use crate::sys::c::NonZeroDWORD;
+use crate::sys::c::{self, NonZeroDWORD, EXIT_FAILURE, EXIT_SUCCESS};
use crate::sys::cvt;
use crate::sys::fs::{File, OpenOptions};
use crate::sys::handle::Handle;
@@ -30,7 +29,7 @@ use crate::sys::stdio;
use crate::sys_common::process::{CommandEnv, CommandEnvs};
use crate::sys_common::IntoInner;
-use libc::{c_void, EXIT_FAILURE, EXIT_SUCCESS};
+use core::ffi::c_void;
////////////////////////////////////////////////////////////////////////////////
// Command
diff --git a/library/std/src/sys/windows/stack_overflow.rs b/library/std/src/sys/windows/stack_overflow.rs
index 0caf0a317..627763da8 100644
--- a/library/std/src/sys/windows/stack_overflow.rs
+++ b/library/std/src/sys/windows/stack_overflow.rs
@@ -3,6 +3,8 @@
use crate::sys::c;
use crate::thread;
+use super::api;
+
pub struct Handler;
impl Handler {
@@ -10,7 +12,7 @@ impl Handler {
// This API isn't available on XP, so don't panic in that case and just
// pray it works out ok.
if c::SetThreadStackGuarantee(&mut 0x5000) == 0
- && c::GetLastError() as u32 != c::ERROR_CALL_NOT_IMPLEMENTED as u32
+ && api::get_last_error().code != c::ERROR_CALL_NOT_IMPLEMENTED
{
panic!("failed to reserve stack space for exception handling");
}
diff --git a/library/std/src/sys/windows/stdio.rs b/library/std/src/sys/windows/stdio.rs
index 3fcaaa508..a9ff909aa 100644
--- a/library/std/src/sys/windows/stdio.rs
+++ b/library/std/src/sys/windows/stdio.rs
@@ -9,6 +9,7 @@ use crate::str;
use crate::sys::c;
use crate::sys::cvt;
use crate::sys::handle::Handle;
+use crate::sys::windows::api;
use core::str::utf8_char_width;
#[cfg(test)]
@@ -369,7 +370,7 @@ fn read_u16s(handle: c::HANDLE, buf: &mut [MaybeUninit<u16>]) -> io::Result<usiz
// ReadConsoleW returns success with ERROR_OPERATION_ABORTED for Ctrl-C or Ctrl-Break.
// Explicitly check for that case here and try again.
- if amount == 0 && unsafe { c::GetLastError() } == c::ERROR_OPERATION_ABORTED {
+ if amount == 0 && api::get_last_error().code == c::ERROR_OPERATION_ABORTED {
continue;
}
break;
diff --git a/library/std/src/sys/windows/thread.rs b/library/std/src/sys/windows/thread.rs
index 18cecb656..1fe744935 100644
--- a/library/std/src/sys/windows/thread.rs
+++ b/library/std/src/sys/windows/thread.rs
@@ -10,8 +10,9 @@ use crate::sys::stack_overflow;
use crate::sys_common::FromInner;
use crate::time::Duration;
-use libc::c_void;
+use core::ffi::c_void;
+use super::time::WaitableTimer;
use super::to_u16s;
pub const DEFAULT_MIN_STACK_SIZE: usize = 2 * 1024 * 1024;
@@ -87,7 +88,17 @@ impl Thread {
}
pub fn sleep(dur: Duration) {
- unsafe { c::Sleep(super::dur2timeout(dur)) }
+ fn high_precision_sleep(dur: Duration) -> Result<(), ()> {
+ let timer = WaitableTimer::high_resolution()?;
+ timer.set(dur)?;
+ timer.wait()
+ }
+ // Attempt to use high-precision sleep (Windows 10, version 1803+).
+ // On error fallback to the standard `Sleep` function.
+ // Also preserves the zero duration behaviour of `Sleep`.
+ if dur.is_zero() || high_precision_sleep(dur).is_err() {
+ unsafe { c::Sleep(super::dur2timeout(dur)) }
+ }
}
pub fn handle(&self) -> &Handle {
diff --git a/library/std/src/sys/windows/thread_local_key.rs b/library/std/src/sys/windows/thread_local_key.rs
index 036d96596..5eee4a966 100644
--- a/library/std/src/sys/windows/thread_local_key.rs
+++ b/library/std/src/sys/windows/thread_local_key.rs
@@ -16,14 +16,19 @@ static HAS_DTORS: AtomicBool = AtomicBool::new(false);
// Using a per-thread list avoids the problems in synchronizing global state.
#[thread_local]
#[cfg(target_thread_local)]
-static mut DESTRUCTORS: Vec<(*mut u8, unsafe extern "C" fn(*mut u8))> = Vec::new();
+static DESTRUCTORS: crate::cell::RefCell<Vec<(*mut u8, unsafe extern "C" fn(*mut u8))>> =
+ crate::cell::RefCell::new(Vec::new());
// Ensure this can never be inlined because otherwise this may break in dylibs.
// See #44391.
#[inline(never)]
#[cfg(target_thread_local)]
pub unsafe fn register_keyless_dtor(t: *mut u8, dtor: unsafe extern "C" fn(*mut u8)) {
- DESTRUCTORS.push((t, dtor));
+ match DESTRUCTORS.try_borrow_mut() {
+ Ok(mut dtors) => dtors.push((t, dtor)),
+ Err(_) => rtabort!("global allocator may not use TLS"),
+ }
+
HAS_DTORS.store(true, Relaxed);
}
@@ -37,11 +42,17 @@ unsafe fn run_keyless_dtors() {
// the case that this loop always terminates because we provide the
// guarantee that a TLS key cannot be set after it is flagged for
// destruction.
- while let Some((ptr, dtor)) = DESTRUCTORS.pop() {
+ loop {
+ // Use a let-else binding to ensure the `RefCell` guard is dropped
+ // immediately. Otherwise, a panic would occur if a TLS destructor
+ // tries to access the list.
+ let Some((ptr, dtor)) = DESTRUCTORS.borrow_mut().pop() else {
+ break;
+ };
(dtor)(ptr);
}
// We're done so free the memory.
- DESTRUCTORS = Vec::new();
+ DESTRUCTORS.replace(Vec::new());
}
type Key = c::DWORD;
diff --git a/library/std/src/sys/windows/time.rs b/library/std/src/sys/windows/time.rs
index b8209a854..bece48e79 100644
--- a/library/std/src/sys/windows/time.rs
+++ b/library/std/src/sys/windows/time.rs
@@ -1,11 +1,13 @@
use crate::cmp::Ordering;
use crate::fmt;
use crate::mem;
+use crate::ptr::{null, null_mut};
use crate::sys::c;
use crate::sys_common::IntoInner;
use crate::time::Duration;
use core::hash::{Hash, Hasher};
+use core::ops::Neg;
const NANOS_PER_SEC: u64 = 1_000_000_000;
const INTERVALS_PER_SEC: u64 = NANOS_PER_SEC / 100;
@@ -222,3 +224,39 @@ mod perf_counter {
qpc_value
}
}
+
+/// A timer you can wait on.
+pub(super) struct WaitableTimer {
+ handle: c::HANDLE,
+}
+impl WaitableTimer {
+ /// Create a high-resolution timer. Will fail before Windows 10, version 1803.
+ pub fn high_resolution() -> Result<Self, ()> {
+ let handle = unsafe {
+ c::CreateWaitableTimerExW(
+ null(),
+ null(),
+ c::CREATE_WAITABLE_TIMER_HIGH_RESOLUTION,
+ c::TIMER_ALL_ACCESS,
+ )
+ };
+ if handle != null_mut() { Ok(Self { handle }) } else { Err(()) }
+ }
+ pub fn set(&self, duration: Duration) -> Result<(), ()> {
+ // Convert the Duration to a format similar to FILETIME.
+ // Negative values are relative times whereas positive values are absolute.
+ // Therefore we negate the relative duration.
+ let time = checked_dur2intervals(&duration).ok_or(())?.neg();
+ let result = unsafe { c::SetWaitableTimer(self.handle, &time, 0, None, null(), c::FALSE) };
+ if result != 0 { Ok(()) } else { Err(()) }
+ }
+ pub fn wait(&self) -> Result<(), ()> {
+ let result = unsafe { c::WaitForSingleObject(self.handle, c::INFINITE) };
+ if result != c::WAIT_FAILED { Ok(()) } else { Err(()) }
+ }
+}
+impl Drop for WaitableTimer {
+ fn drop(&mut self) {
+ unsafe { c::CloseHandle(self.handle) };
+ }
+}