diff options
Diffstat (limited to 'src/libstd/sys/windows')
37 files changed, 0 insertions, 7710 deletions
diff --git a/src/libstd/sys/windows/alloc.rs b/src/libstd/sys/windows/alloc.rs deleted file mode 100644 index 99b4d6c72a0..00000000000 --- a/src/libstd/sys/windows/alloc.rs +++ /dev/null @@ -1,61 +0,0 @@ -use crate::alloc::{GlobalAlloc, Layout, System}; -use crate::sys::c; -use crate::sys_common::alloc::{realloc_fallback, MIN_ALIGN}; - -#[repr(C)] -struct Header(*mut u8); - -unsafe fn get_header<'a>(ptr: *mut u8) -> &'a mut Header { - &mut *(ptr as *mut Header).offset(-1) -} - -unsafe fn align_ptr(ptr: *mut u8, align: usize) -> *mut u8 { - let aligned = ptr.add(align - (ptr as usize & (align - 1))); - *get_header(aligned) = Header(ptr); - aligned -} - -#[inline] -unsafe fn allocate_with_flags(layout: Layout, flags: c::DWORD) -> *mut u8 { - if layout.align() <= MIN_ALIGN { - return c::HeapAlloc(c::GetProcessHeap(), flags, layout.size()) as *mut u8; - } - - let size = layout.size() + layout.align(); - let ptr = c::HeapAlloc(c::GetProcessHeap(), flags, size); - if ptr.is_null() { ptr as *mut u8 } else { align_ptr(ptr as *mut u8, layout.align()) } -} - -#[stable(feature = "alloc_system_type", since = "1.28.0")] -unsafe impl GlobalAlloc for System { - #[inline] - unsafe fn alloc(&self, layout: Layout) -> *mut u8 { - allocate_with_flags(layout, 0) - } - - #[inline] - unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 { - allocate_with_flags(layout, c::HEAP_ZERO_MEMORY) - } - - #[inline] - unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) { - if layout.align() <= MIN_ALIGN { - let err = c::HeapFree(c::GetProcessHeap(), 0, ptr as c::LPVOID); - debug_assert!(err != 0, "Failed to free heap memory: {}", c::GetLastError()); - } else { - let header = get_header(ptr); - let err = c::HeapFree(c::GetProcessHeap(), 0, header.0 as c::LPVOID); - debug_assert!(err != 0, "Failed to free heap memory: {}", c::GetLastError()); - } - } - - #[inline] - unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 { - if layout.align() <= MIN_ALIGN { - c::HeapReAlloc(c::GetProcessHeap(), 0, ptr as c::LPVOID, new_size) as *mut u8 - } else { - realloc_fallback(self, ptr, layout, new_size) - } - } -} diff --git a/src/libstd/sys/windows/args.rs b/src/libstd/sys/windows/args.rs deleted file mode 100644 index 5fbea2a2910..00000000000 --- a/src/libstd/sys/windows/args.rs +++ /dev/null @@ -1,266 +0,0 @@ -#![allow(dead_code)] // runtime init functions not used during testing - -use crate::ffi::OsString; -use crate::fmt; -use crate::os::windows::prelude::*; -use crate::path::PathBuf; -use crate::slice; -use crate::sys::c; -use crate::sys::windows::os::current_exe; -use crate::vec; - -use core::iter; - -pub unsafe fn init(_argc: isize, _argv: *const *const u8) {} - -pub unsafe fn cleanup() {} - -pub fn args() -> Args { - unsafe { - let lp_cmd_line = c::GetCommandLineW(); - let parsed_args_list = parse_lp_cmd_line(lp_cmd_line as *const u16, || { - current_exe().map(PathBuf::into_os_string).unwrap_or_else(|_| OsString::new()) - }); - - Args { parsed_args_list: parsed_args_list.into_iter() } - } -} - -/// Implements the Windows command-line argument parsing algorithm. -/// -/// Microsoft's documentation for the Windows CLI argument format can be found at -/// <https://docs.microsoft.com/en-us/previous-versions//17w5ykft(v=vs.85)>. -/// -/// Windows includes a function to do this in shell32.dll, -/// but linking with that DLL causes the process to be registered as a GUI application. -/// GUI applications add a bunch of overhead, even if no windows are drawn. See -/// <https://randomascii.wordpress.com/2018/12/03/a-not-called-function-can-cause-a-5x-slowdown/>. -/// -/// This function was tested for equivalence to the shell32.dll implementation in -/// Windows 10 Pro v1803, using an exhaustive test suite available at -/// <https://gist.github.com/notriddle/dde431930c392e428055b2dc22e638f5> or -/// <https://paste.gg/p/anonymous/47d6ed5f5bd549168b1c69c799825223>. -unsafe fn parse_lp_cmd_line<F: Fn() -> OsString>( - lp_cmd_line: *const u16, - exe_name: F, -) -> Vec<OsString> { - const BACKSLASH: u16 = '\\' as u16; - const QUOTE: u16 = '"' as u16; - const TAB: u16 = '\t' as u16; - const SPACE: u16 = ' ' as u16; - let mut ret_val = Vec::new(); - if lp_cmd_line.is_null() || *lp_cmd_line == 0 { - ret_val.push(exe_name()); - return ret_val; - } - let mut cmd_line = { - let mut end = 0; - while *lp_cmd_line.offset(end) != 0 { - end += 1; - } - slice::from_raw_parts(lp_cmd_line, end as usize) - }; - // The executable name at the beginning is special. - cmd_line = match cmd_line[0] { - // The executable name ends at the next quote mark, - // no matter what. - QUOTE => { - let args = { - let mut cut = cmd_line[1..].splitn(2, |&c| c == QUOTE); - if let Some(exe) = cut.next() { - ret_val.push(OsString::from_wide(exe)); - } - cut.next() - }; - if let Some(args) = args { - args - } else { - return ret_val; - } - } - // Implement quirk: when they say whitespace here, - // they include the entire ASCII control plane: - // "However, if lpCmdLine starts with any amount of whitespace, CommandLineToArgvW - // will consider the first argument to be an empty string. Excess whitespace at the - // end of lpCmdLine is ignored." - 0..=SPACE => { - ret_val.push(OsString::new()); - &cmd_line[1..] - } - // The executable name ends at the next whitespace, - // no matter what. - _ => { - let args = { - let mut cut = cmd_line.splitn(2, |&c| c > 0 && c <= SPACE); - if let Some(exe) = cut.next() { - ret_val.push(OsString::from_wide(exe)); - } - cut.next() - }; - if let Some(args) = args { - args - } else { - return ret_val; - } - } - }; - let mut cur = Vec::new(); - let mut in_quotes = false; - let mut was_in_quotes = false; - let mut backslash_count: usize = 0; - for &c in cmd_line { - match c { - // backslash - BACKSLASH => { - backslash_count += 1; - was_in_quotes = false; - } - QUOTE if backslash_count % 2 == 0 => { - cur.extend(iter::repeat(b'\\' as u16).take(backslash_count / 2)); - backslash_count = 0; - if was_in_quotes { - cur.push('"' as u16); - was_in_quotes = false; - } else { - was_in_quotes = in_quotes; - in_quotes = !in_quotes; - } - } - QUOTE if backslash_count % 2 != 0 => { - cur.extend(iter::repeat(b'\\' as u16).take(backslash_count / 2)); - backslash_count = 0; - was_in_quotes = false; - cur.push(b'"' as u16); - } - SPACE | TAB if !in_quotes => { - cur.extend(iter::repeat(b'\\' as u16).take(backslash_count)); - if !cur.is_empty() || was_in_quotes { - ret_val.push(OsString::from_wide(&cur[..])); - cur.truncate(0); - } - backslash_count = 0; - was_in_quotes = false; - } - _ => { - cur.extend(iter::repeat(b'\\' as u16).take(backslash_count)); - backslash_count = 0; - was_in_quotes = false; - cur.push(c); - } - } - } - cur.extend(iter::repeat(b'\\' as u16).take(backslash_count)); - // include empty quoted strings at the end of the arguments list - if !cur.is_empty() || was_in_quotes || in_quotes { - ret_val.push(OsString::from_wide(&cur[..])); - } - ret_val -} - -pub struct Args { - parsed_args_list: vec::IntoIter<OsString>, -} - -pub struct ArgsInnerDebug<'a> { - args: &'a Args, -} - -impl<'a> fmt::Debug for ArgsInnerDebug<'a> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.args.parsed_args_list.as_slice().fmt(f) - } -} - -impl Args { - pub fn inner_debug(&self) -> ArgsInnerDebug<'_> { - ArgsInnerDebug { args: self } - } -} - -impl Iterator for Args { - type Item = OsString; - fn next(&mut self) -> Option<OsString> { - self.parsed_args_list.next() - } - fn size_hint(&self) -> (usize, Option<usize>) { - self.parsed_args_list.size_hint() - } -} - -impl DoubleEndedIterator for Args { - fn next_back(&mut self) -> Option<OsString> { - self.parsed_args_list.next_back() - } -} - -impl ExactSizeIterator for Args { - fn len(&self) -> usize { - self.parsed_args_list.len() - } -} - -#[cfg(test)] -mod tests { - use crate::ffi::OsString; - use crate::sys::windows::args::*; - - fn chk(string: &str, parts: &[&str]) { - let mut wide: Vec<u16> = OsString::from(string).encode_wide().collect(); - wide.push(0); - let parsed = unsafe { - parse_lp_cmd_line(wide.as_ptr() as *const u16, || OsString::from("TEST.EXE")) - }; - let expected: Vec<OsString> = parts.iter().map(|k| OsString::from(k)).collect(); - assert_eq!(parsed.as_slice(), expected.as_slice()); - } - - #[test] - fn empty() { - chk("", &["TEST.EXE"]); - chk("\0", &["TEST.EXE"]); - } - - #[test] - fn single_words() { - chk("EXE one_word", &["EXE", "one_word"]); - chk("EXE a", &["EXE", "a"]); - chk("EXE 😅", &["EXE", "😅"]); - chk("EXE 😅🤦", &["EXE", "😅🤦"]); - } - - #[test] - fn official_examples() { - chk(r#"EXE "abc" d e"#, &["EXE", "abc", "d", "e"]); - chk(r#"EXE a\\\b d"e f"g h"#, &["EXE", r#"a\\\b"#, "de fg", "h"]); - chk(r#"EXE a\\\"b c d"#, &["EXE", r#"a\"b"#, "c", "d"]); - chk(r#"EXE a\\\\"b c" d e"#, &["EXE", r#"a\\b c"#, "d", "e"]); - } - - #[test] - fn whitespace_behavior() { - chk(r#" test"#, &["", "test"]); - chk(r#" test"#, &["", "test"]); - chk(r#" test test2"#, &["", "test", "test2"]); - chk(r#" test test2"#, &["", "test", "test2"]); - chk(r#"test test2 "#, &["test", "test2"]); - chk(r#"test test2 "#, &["test", "test2"]); - chk(r#"test "#, &["test"]); - } - - #[test] - fn genius_quotes() { - chk(r#"EXE "" """#, &["EXE", "", ""]); - chk(r#"EXE "" """"#, &["EXE", "", "\""]); - chk( - r#"EXE "this is """all""" in the same argument""#, - &["EXE", "this is \"all\" in the same argument"], - ); - chk(r#"EXE "a"""#, &["EXE", "a\""]); - chk(r#"EXE "a"" a"#, &["EXE", "a\"", "a"]); - // quotes cannot be escaped in command names - chk(r#""EXE" check"#, &["EXE", "check"]); - chk(r#""EXE check""#, &["EXE check"]); - chk(r#""EXE """for""" check"#, &["EXE ", r#"for""#, "check"]); - chk(r#""EXE \"for\" check"#, &[r#"EXE \"#, r#"for""#, "check"]); - } -} diff --git a/src/libstd/sys/windows/c.rs b/src/libstd/sys/windows/c.rs deleted file mode 100644 index f440442ca30..00000000000 --- a/src/libstd/sys/windows/c.rs +++ /dev/null @@ -1,1098 +0,0 @@ -//! C definitions used by libnative that don't belong in liblibc - -#![allow(nonstandard_style)] -#![cfg_attr(test, allow(dead_code))] -#![unstable(issue = "none", feature = "windows_c")] - -use crate::os::raw::{c_char, c_int, c_long, c_longlong, c_uint, c_ulong, c_ushort}; -use crate::ptr; - -use libc::{c_void, size_t, wchar_t}; - -pub use self::EXCEPTION_DISPOSITION::*; -pub use self::FILE_INFO_BY_HANDLE_CLASS::*; - -pub type DWORD = c_ulong; -pub type HANDLE = LPVOID; -pub type HINSTANCE = HANDLE; -pub type HMODULE = HINSTANCE; -pub type HRESULT = LONG; -pub type BOOL = c_int; -pub type BYTE = u8; -pub type BOOLEAN = BYTE; -pub type GROUP = c_uint; -pub type LARGE_INTEGER = c_longlong; -pub type LONG = c_long; -pub type UINT = c_uint; -pub type WCHAR = u16; -pub type USHORT = c_ushort; -pub type SIZE_T = usize; -pub type WORD = u16; -pub type CHAR = c_char; -pub type ULONG_PTR = usize; -pub type ULONG = c_ulong; - -pub type LPBOOL = *mut BOOL; -pub type LPBYTE = *mut BYTE; -pub type LPCSTR = *const CHAR; -pub type LPCWSTR = *const WCHAR; -pub type LPDWORD = *mut DWORD; -pub type LPHANDLE = *mut HANDLE; -pub type LPOVERLAPPED = *mut OVERLAPPED; -pub type LPPROCESS_INFORMATION = *mut PROCESS_INFORMATION; -pub type LPSECURITY_ATTRIBUTES = *mut SECURITY_ATTRIBUTES; -pub type LPSTARTUPINFO = *mut STARTUPINFO; -pub type LPVOID = *mut c_void; -pub type LPWCH = *mut WCHAR; -pub type LPWIN32_FIND_DATAW = *mut WIN32_FIND_DATAW; -pub type LPWSADATA = *mut WSADATA; -pub type LPWSAPROTOCOL_INFO = *mut WSAPROTOCOL_INFO; -pub type LPSTR = *mut CHAR; -pub type LPWSTR = *mut WCHAR; -pub type LPFILETIME = *mut FILETIME; -pub type LPWSABUF = *mut WSABUF; -pub type LPWSAOVERLAPPED = *mut c_void; -pub type LPWSAOVERLAPPED_COMPLETION_ROUTINE = *mut c_void; - -pub type PCONDITION_VARIABLE = *mut CONDITION_VARIABLE; -pub type PLARGE_INTEGER = *mut c_longlong; -pub type PSRWLOCK = *mut SRWLOCK; - -pub type SOCKET = crate::os::windows::raw::SOCKET; -pub type socklen_t = c_int; -pub type ADDRESS_FAMILY = USHORT; - -pub const TRUE: BOOL = 1; -pub const FALSE: BOOL = 0; - -pub const FILE_ATTRIBUTE_READONLY: DWORD = 0x1; -pub const FILE_ATTRIBUTE_DIRECTORY: DWORD = 0x10; -pub const FILE_ATTRIBUTE_REPARSE_POINT: DWORD = 0x400; - -pub const FILE_SHARE_DELETE: DWORD = 0x4; -pub const FILE_SHARE_READ: DWORD = 0x1; -pub const FILE_SHARE_WRITE: DWORD = 0x2; - -pub const CREATE_ALWAYS: DWORD = 2; -pub const CREATE_NEW: DWORD = 1; -pub const OPEN_ALWAYS: DWORD = 4; -pub const OPEN_EXISTING: DWORD = 3; -pub const TRUNCATE_EXISTING: DWORD = 5; - -pub const FILE_WRITE_DATA: DWORD = 0x00000002; -pub const FILE_APPEND_DATA: DWORD = 0x00000004; -pub const FILE_WRITE_EA: DWORD = 0x00000010; -pub const FILE_WRITE_ATTRIBUTES: DWORD = 0x00000100; -pub const READ_CONTROL: DWORD = 0x00020000; -pub const SYNCHRONIZE: DWORD = 0x00100000; -pub const GENERIC_READ: DWORD = 0x80000000; -pub const GENERIC_WRITE: DWORD = 0x40000000; -pub const STANDARD_RIGHTS_WRITE: DWORD = READ_CONTROL; -pub const FILE_GENERIC_WRITE: DWORD = STANDARD_RIGHTS_WRITE - | FILE_WRITE_DATA - | FILE_WRITE_ATTRIBUTES - | FILE_WRITE_EA - | FILE_APPEND_DATA - | SYNCHRONIZE; - -pub const FILE_FLAG_OPEN_REPARSE_POINT: DWORD = 0x00200000; -pub const FILE_FLAG_BACKUP_SEMANTICS: DWORD = 0x02000000; -pub const SECURITY_SQOS_PRESENT: DWORD = 0x00100000; - -pub const FIONBIO: c_ulong = 0x8004667e; - -#[repr(C)] -#[derive(Copy)] -pub struct WIN32_FIND_DATAW { - pub dwFileAttributes: DWORD, - pub ftCreationTime: FILETIME, - pub ftLastAccessTime: FILETIME, - pub ftLastWriteTime: FILETIME, - pub nFileSizeHigh: DWORD, - pub nFileSizeLow: DWORD, - pub dwReserved0: DWORD, - pub dwReserved1: DWORD, - pub cFileName: [wchar_t; 260], // #define MAX_PATH 260 - pub cAlternateFileName: [wchar_t; 14], -} -impl Clone for WIN32_FIND_DATAW { - fn clone(&self) -> Self { - *self - } -} - -pub const WSA_FLAG_OVERLAPPED: DWORD = 0x01; -pub const WSA_FLAG_NO_HANDLE_INHERIT: DWORD = 0x80; - -pub const WSADESCRIPTION_LEN: usize = 256; -pub const WSASYS_STATUS_LEN: usize = 128; -pub const WSAPROTOCOL_LEN: DWORD = 255; -pub const INVALID_SOCKET: SOCKET = !0; - -pub const WSAEACCES: c_int = 10013; -pub const WSAEINVAL: c_int = 10022; -pub const WSAEWOULDBLOCK: c_int = 10035; -pub const WSAEPROTOTYPE: c_int = 10041; -pub const WSAEADDRINUSE: c_int = 10048; -pub const WSAEADDRNOTAVAIL: c_int = 10049; -pub const WSAECONNABORTED: c_int = 10053; -pub const WSAECONNRESET: c_int = 10054; -pub const WSAENOTCONN: c_int = 10057; -pub const WSAESHUTDOWN: c_int = 10058; -pub const WSAETIMEDOUT: c_int = 10060; -pub const WSAECONNREFUSED: c_int = 10061; - -pub const MAX_PROTOCOL_CHAIN: DWORD = 7; - -pub const MAXIMUM_REPARSE_DATA_BUFFER_SIZE: usize = 16 * 1024; -pub const FSCTL_GET_REPARSE_POINT: DWORD = 0x900a8; -pub const IO_REPARSE_TAG_SYMLINK: DWORD = 0xa000000c; -pub const IO_REPARSE_TAG_MOUNT_POINT: DWORD = 0xa0000003; -pub const SYMLINK_FLAG_RELATIVE: DWORD = 0x00000001; -pub const FSCTL_SET_REPARSE_POINT: DWORD = 0x900a4; - -pub const SYMBOLIC_LINK_FLAG_DIRECTORY: DWORD = 0x1; -pub const SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE: DWORD = 0x2; - -// Note that these are not actually HANDLEs, just values to pass to GetStdHandle -pub const STD_INPUT_HANDLE: DWORD = -10i32 as DWORD; -pub const STD_OUTPUT_HANDLE: DWORD = -11i32 as DWORD; -pub const STD_ERROR_HANDLE: DWORD = -12i32 as DWORD; - -pub const PROGRESS_CONTINUE: DWORD = 0; - -// List of Windows system error codes with descriptions: -// https://docs.microsoft.com/en-us/windows/win32/debug/system-error-codes#system-error-codes -pub const ERROR_FILE_NOT_FOUND: DWORD = 2; -pub const ERROR_PATH_NOT_FOUND: DWORD = 3; -pub const ERROR_ACCESS_DENIED: DWORD = 5; -pub const ERROR_INVALID_HANDLE: DWORD = 6; -pub const ERROR_NO_MORE_FILES: DWORD = 18; -pub const ERROR_HANDLE_EOF: DWORD = 38; -pub const ERROR_FILE_EXISTS: DWORD = 80; -pub const ERROR_INVALID_PARAMETER: DWORD = 87; -pub const ERROR_BROKEN_PIPE: DWORD = 109; -pub const ERROR_CALL_NOT_IMPLEMENTED: DWORD = 120; -pub const ERROR_SEM_TIMEOUT: DWORD = 121; -pub const ERROR_INSUFFICIENT_BUFFER: DWORD = 122; -pub const ERROR_ALREADY_EXISTS: DWORD = 183; -pub const ERROR_ENVVAR_NOT_FOUND: DWORD = 203; -pub const ERROR_NO_DATA: DWORD = 232; -pub const ERROR_DRIVER_CANCEL_TIMEOUT: DWORD = 594; -pub const ERROR_OPERATION_ABORTED: DWORD = 995; -pub const ERROR_IO_PENDING: DWORD = 997; -pub const ERROR_SERVICE_REQUEST_TIMEOUT: DWORD = 1053; -pub const ERROR_COUNTER_TIMEOUT: DWORD = 1121; -pub const ERROR_TIMEOUT: DWORD = 1460; -pub const ERROR_RESOURCE_CALL_TIMED_OUT: DWORD = 5910; -pub const ERROR_CTX_MODEM_RESPONSE_TIMEOUT: DWORD = 7012; -pub const ERROR_CTX_CLIENT_QUERY_TIMEOUT: DWORD = 7040; -pub const FRS_ERR_SYSVOL_POPULATE_TIMEOUT: DWORD = 8014; -pub const ERROR_DS_TIMELIMIT_EXCEEDED: DWORD = 8226; -pub const DNS_ERROR_RECORD_TIMED_OUT: DWORD = 9705; -pub const ERROR_IPSEC_IKE_TIMED_OUT: DWORD = 13805; -pub const ERROR_RUNLEVEL_SWITCH_TIMEOUT: DWORD = 15402; -pub const ERROR_RUNLEVEL_SWITCH_AGENT_TIMEOUT: DWORD = 15403; - -pub const E_NOTIMPL: HRESULT = 0x80004001u32 as HRESULT; - -pub const INVALID_HANDLE_VALUE: HANDLE = !0 as HANDLE; - -pub const FACILITY_NT_BIT: DWORD = 0x1000_0000; - -pub const FORMAT_MESSAGE_FROM_SYSTEM: DWORD = 0x00001000; -pub const FORMAT_MESSAGE_FROM_HMODULE: DWORD = 0x00000800; -pub const FORMAT_MESSAGE_IGNORE_INSERTS: DWORD = 0x00000200; - -pub const TLS_OUT_OF_INDEXES: DWORD = 0xFFFFFFFF; - -pub const DLL_THREAD_DETACH: DWORD = 3; -pub const DLL_PROCESS_DETACH: DWORD = 0; - -pub const INFINITE: DWORD = !0; - -pub const DUPLICATE_SAME_ACCESS: DWORD = 0x00000002; - -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 DETACHED_PROCESS: DWORD = 0x00000008; -pub const CREATE_NEW_PROCESS_GROUP: DWORD = 0x00000200; -pub const CREATE_UNICODE_ENVIRONMENT: DWORD = 0x00000400; -pub const STARTF_USESTDHANDLES: DWORD = 0x00000100; - -pub const AF_INET: c_int = 2; -pub const AF_INET6: c_int = 23; -pub const SD_BOTH: c_int = 2; -pub const SD_RECEIVE: c_int = 0; -pub const SD_SEND: c_int = 1; -pub const SOCK_DGRAM: c_int = 2; -pub const SOCK_STREAM: c_int = 1; -pub const SOL_SOCKET: c_int = 0xffff; -pub const SO_RCVTIMEO: c_int = 0x1006; -pub const SO_SNDTIMEO: c_int = 0x1005; -pub const IPPROTO_IP: c_int = 0; -pub const IPPROTO_TCP: c_int = 6; -pub const IPPROTO_IPV6: c_int = 41; -pub const TCP_NODELAY: c_int = 0x0001; -pub const IP_TTL: c_int = 4; -pub const IPV6_V6ONLY: c_int = 27; -pub const SO_ERROR: c_int = 0x1007; -pub const SO_BROADCAST: c_int = 0x0020; -pub const IP_MULTICAST_LOOP: c_int = 11; -pub const IPV6_MULTICAST_LOOP: c_int = 11; -pub const IP_MULTICAST_TTL: c_int = 10; -pub const IP_ADD_MEMBERSHIP: c_int = 12; -pub const IP_DROP_MEMBERSHIP: c_int = 13; -pub const IPV6_ADD_MEMBERSHIP: c_int = 12; -pub const IPV6_DROP_MEMBERSHIP: c_int = 13; -pub const MSG_PEEK: c_int = 0x2; - -#[repr(C)] -pub struct ip_mreq { - pub imr_multiaddr: in_addr, - pub imr_interface: in_addr, -} - -#[repr(C)] -pub struct ipv6_mreq { - pub ipv6mr_multiaddr: in6_addr, - pub ipv6mr_interface: c_uint, -} - -pub const VOLUME_NAME_DOS: DWORD = 0x0; -pub const MOVEFILE_REPLACE_EXISTING: DWORD = 1; - -pub const FILE_BEGIN: DWORD = 0; -pub const FILE_CURRENT: DWORD = 1; -pub const FILE_END: DWORD = 2; - -pub const WAIT_OBJECT_0: DWORD = 0x00000000; -pub const WAIT_TIMEOUT: DWORD = 258; -pub const WAIT_FAILED: DWORD = 0xFFFFFFFF; - -pub const PIPE_ACCESS_INBOUND: DWORD = 0x00000001; -pub const PIPE_ACCESS_OUTBOUND: DWORD = 0x00000002; -pub const FILE_FLAG_FIRST_PIPE_INSTANCE: DWORD = 0x00080000; -pub const FILE_FLAG_OVERLAPPED: DWORD = 0x40000000; -pub const PIPE_WAIT: DWORD = 0x00000000; -pub const PIPE_TYPE_BYTE: DWORD = 0x00000000; -pub const PIPE_REJECT_REMOTE_CLIENTS: DWORD = 0x00000008; -pub const PIPE_READMODE_BYTE: DWORD = 0x00000000; - -pub const FD_SETSIZE: usize = 64; - -pub const STACK_SIZE_PARAM_IS_A_RESERVATION: DWORD = 0x00010000; - -pub const HEAP_ZERO_MEMORY: DWORD = 0x00000008; - -#[repr(C)] -#[cfg(not(target_pointer_width = "64"))] -pub struct WSADATA { - pub wVersion: WORD, - pub wHighVersion: WORD, - pub szDescription: [u8; WSADESCRIPTION_LEN + 1], - pub szSystemStatus: [u8; WSASYS_STATUS_LEN + 1], - pub iMaxSockets: u16, - pub iMaxUdpDg: u16, - pub lpVendorInfo: *mut u8, -} -#[repr(C)] -#[cfg(target_pointer_width = "64")] -pub struct WSADATA { - pub wVersion: WORD, - pub wHighVersion: WORD, - pub iMaxSockets: u16, - pub iMaxUdpDg: u16, - pub lpVendorInfo: *mut u8, - pub szDescription: [u8; WSADESCRIPTION_LEN + 1], - pub szSystemStatus: [u8; WSASYS_STATUS_LEN + 1], -} - -#[derive(Copy, Clone)] -#[repr(C)] -pub struct WSABUF { - pub len: ULONG, - pub buf: *mut CHAR, -} - -#[repr(C)] -pub struct WSAPROTOCOL_INFO { - pub dwServiceFlags1: DWORD, - pub dwServiceFlags2: DWORD, - pub dwServiceFlags3: DWORD, - pub dwServiceFlags4: DWORD, - pub dwProviderFlags: DWORD, - pub ProviderId: GUID, - pub dwCatalogEntryId: DWORD, - pub ProtocolChain: WSAPROTOCOLCHAIN, - pub iVersion: c_int, - pub iAddressFamily: c_int, - pub iMaxSockAddr: c_int, - pub iMinSockAddr: c_int, - pub iSocketType: c_int, - pub iProtocol: c_int, - pub iProtocolMaxOffset: c_int, - pub iNetworkByteOrder: c_int, - pub iSecurityScheme: c_int, - pub dwMessageSize: DWORD, - pub dwProviderReserved: DWORD, - pub szProtocol: [u16; (WSAPROTOCOL_LEN as usize) + 1], -} - -#[repr(C)] -#[derive(Copy, Clone)] -pub struct WIN32_FILE_ATTRIBUTE_DATA { - pub dwFileAttributes: DWORD, - pub ftCreationTime: FILETIME, - pub ftLastAccessTime: FILETIME, - pub ftLastWriteTime: FILETIME, - pub nFileSizeHigh: DWORD, - pub nFileSizeLow: DWORD, -} - -#[repr(C)] -#[allow(dead_code)] // we only use some variants -pub enum FILE_INFO_BY_HANDLE_CLASS { - FileBasicInfo = 0, - FileStandardInfo = 1, - FileNameInfo = 2, - FileRenameInfo = 3, - FileDispositionInfo = 4, - FileAllocationInfo = 5, - FileEndOfFileInfo = 6, - FileStreamInfo = 7, - FileCompressionInfo = 8, - FileAttributeTagInfo = 9, - FileIdBothDirectoryInfo = 10, // 0xA - FileIdBothDirectoryRestartInfo = 11, // 0xB - FileIoPriorityHintInfo = 12, // 0xC - FileRemoteProtocolInfo = 13, // 0xD - FileFullDirectoryInfo = 14, // 0xE - FileFullDirectoryRestartInfo = 15, // 0xF - FileStorageInfo = 16, // 0x10 - FileAlignmentInfo = 17, // 0x11 - FileIdInfo = 18, // 0x12 - FileIdExtdDirectoryInfo = 19, // 0x13 - FileIdExtdDirectoryRestartInfo = 20, // 0x14 - MaximumFileInfoByHandlesClass, -} - -#[repr(C)] -pub struct FILE_BASIC_INFO { - pub CreationTime: LARGE_INTEGER, - pub LastAccessTime: LARGE_INTEGER, - pub LastWriteTime: LARGE_INTEGER, - pub ChangeTime: LARGE_INTEGER, - pub FileAttributes: DWORD, -} - -#[repr(C)] -pub struct FILE_END_OF_FILE_INFO { - pub EndOfFile: LARGE_INTEGER, -} - -#[repr(C)] -pub struct REPARSE_DATA_BUFFER { - pub ReparseTag: c_uint, - pub ReparseDataLength: c_ushort, - pub Reserved: c_ushort, - pub rest: (), -} - -#[repr(C)] -pub struct SYMBOLIC_LINK_REPARSE_BUFFER { - pub SubstituteNameOffset: c_ushort, - pub SubstituteNameLength: c_ushort, - pub PrintNameOffset: c_ushort, - pub PrintNameLength: c_ushort, - pub Flags: c_ulong, - pub PathBuffer: WCHAR, -} - -#[repr(C)] -pub struct MOUNT_POINT_REPARSE_BUFFER { - pub SubstituteNameOffset: c_ushort, - pub SubstituteNameLength: c_ushort, - pub PrintNameOffset: c_ushort, - pub PrintNameLength: c_ushort, - pub PathBuffer: WCHAR, -} - -pub type LPPROGRESS_ROUTINE = crate::option::Option< - unsafe extern "system" fn( - TotalFileSize: LARGE_INTEGER, - TotalBytesTransferred: LARGE_INTEGER, - StreamSize: LARGE_INTEGER, - StreamBytesTransferred: LARGE_INTEGER, - dwStreamNumber: DWORD, - dwCallbackReason: DWORD, - hSourceFile: HANDLE, - hDestinationFile: HANDLE, - lpData: LPVOID, - ) -> DWORD, ->; - -#[repr(C)] -pub struct CONDITION_VARIABLE { - pub ptr: LPVOID, -} -#[repr(C)] -pub struct SRWLOCK { - pub ptr: LPVOID, -} -#[repr(C)] -pub struct CRITICAL_SECTION { - CriticalSectionDebug: LPVOID, - LockCount: LONG, - RecursionCount: LONG, - OwningThread: HANDLE, - LockSemaphore: HANDLE, - SpinCount: ULONG_PTR, -} - -#[repr(C)] -pub struct REPARSE_MOUNTPOINT_DATA_BUFFER { - pub ReparseTag: DWORD, - pub ReparseDataLength: DWORD, - pub Reserved: WORD, - pub ReparseTargetLength: WORD, - pub ReparseTargetMaximumLength: WORD, - pub Reserved1: WORD, - pub ReparseTarget: WCHAR, -} - -#[repr(C)] -pub struct GUID { - pub Data1: DWORD, - pub Data2: WORD, - pub Data3: WORD, - pub Data4: [BYTE; 8], -} - -#[repr(C)] -pub struct WSAPROTOCOLCHAIN { - pub ChainLen: c_int, - pub ChainEntries: [DWORD; MAX_PROTOCOL_CHAIN as usize], -} - -#[repr(C)] -pub struct SECURITY_ATTRIBUTES { - pub nLength: DWORD, - pub lpSecurityDescriptor: LPVOID, - pub bInheritHandle: BOOL, -} - -#[repr(C)] -pub struct PROCESS_INFORMATION { - pub hProcess: HANDLE, - pub hThread: HANDLE, - pub dwProcessId: DWORD, - pub dwThreadId: DWORD, -} - -#[repr(C)] -pub struct STARTUPINFO { - pub cb: DWORD, - pub lpReserved: LPWSTR, - pub lpDesktop: LPWSTR, - pub lpTitle: LPWSTR, - pub dwX: DWORD, - pub dwY: DWORD, - pub dwXSize: DWORD, - pub dwYSize: DWORD, - pub dwXCountChars: DWORD, - pub dwYCountCharts: DWORD, - pub dwFillAttribute: DWORD, - pub dwFlags: DWORD, - pub wShowWindow: WORD, - pub cbReserved2: WORD, - pub lpReserved2: LPBYTE, - pub hStdInput: HANDLE, - pub hStdOutput: HANDLE, - pub hStdError: HANDLE, -} - -#[repr(C)] -pub struct SOCKADDR { - pub sa_family: ADDRESS_FAMILY, - pub sa_data: [CHAR; 14], -} - -#[repr(C)] -#[derive(Copy, Clone)] -pub struct FILETIME { - pub dwLowDateTime: DWORD, - pub dwHighDateTime: DWORD, -} - -#[repr(C)] -pub struct OVERLAPPED { - pub Internal: *mut c_ulong, - pub InternalHigh: *mut c_ulong, - pub Offset: DWORD, - pub OffsetHigh: DWORD, - pub hEvent: HANDLE, -} - -#[repr(C)] -#[allow(dead_code)] // we only use some variants -pub enum ADDRESS_MODE { - AddrMode1616, - AddrMode1632, - AddrModeReal, - AddrModeFlat, -} - -#[repr(C)] -pub struct SOCKADDR_STORAGE_LH { - pub ss_family: ADDRESS_FAMILY, - pub __ss_pad1: [CHAR; 6], - pub __ss_align: i64, - pub __ss_pad2: [CHAR; 112], -} - -#[repr(C)] -pub struct ADDRINFOA { - pub ai_flags: c_int, - pub ai_family: c_int, - pub ai_socktype: c_int, - pub ai_protocol: c_int, - pub ai_addrlen: size_t, - pub ai_canonname: *mut c_char, - pub ai_addr: *mut SOCKADDR, - pub ai_next: *mut ADDRINFOA, -} - -#[repr(C)] -#[derive(Copy, Clone)] -pub struct sockaddr_in { - pub sin_family: ADDRESS_FAMILY, - pub sin_port: USHORT, - pub sin_addr: in_addr, - pub sin_zero: [CHAR; 8], -} - -#[repr(C)] -#[derive(Copy, Clone)] -pub struct sockaddr_in6 { - pub sin6_family: ADDRESS_FAMILY, - pub sin6_port: USHORT, - pub sin6_flowinfo: c_ulong, - pub sin6_addr: in6_addr, - pub sin6_scope_id: c_ulong, -} - -#[repr(C)] -#[derive(Copy, Clone)] -pub struct in_addr { - pub s_addr: u32, -} - -#[repr(C)] -#[derive(Copy, Clone)] -pub struct in6_addr { - pub s6_addr: [u8; 16], -} - -#[repr(C)] -#[derive(Copy, Clone)] -#[allow(dead_code)] // we only use some variants -pub enum EXCEPTION_DISPOSITION { - ExceptionContinueExecution, - ExceptionContinueSearch, - ExceptionNestedException, - ExceptionCollidedUnwind, -} - -#[repr(C)] -#[derive(Copy)] -pub struct fd_set { - pub fd_count: c_uint, - pub fd_array: [SOCKET; FD_SETSIZE], -} - -impl Clone for fd_set { - fn clone(&self) -> fd_set { - *self - } -} - -#[repr(C)] -#[derive(Copy, Clone)] -pub struct timeval { - pub tv_sec: c_long, - pub tv_usec: c_long, -} - -// Functions forbidden when targeting UWP -cfg_if::cfg_if! { -if #[cfg(not(target_vendor = "uwp"))] { - pub const EXCEPTION_CONTINUE_SEARCH: LONG = 0; - pub const EXCEPTION_STACK_OVERFLOW: DWORD = 0xc00000fd; - pub const EXCEPTION_MAXIMUM_PARAMETERS: usize = 15; - - #[repr(C)] - pub struct EXCEPTION_RECORD { - pub ExceptionCode: DWORD, - pub ExceptionFlags: DWORD, - pub ExceptionRecord: *mut EXCEPTION_RECORD, - pub ExceptionAddress: LPVOID, - pub NumberParameters: DWORD, - pub ExceptionInformation: [LPVOID; EXCEPTION_MAXIMUM_PARAMETERS] - } - - pub enum CONTEXT {} - - #[repr(C)] - pub struct EXCEPTION_POINTERS { - pub ExceptionRecord: *mut EXCEPTION_RECORD, - pub ContextRecord: *mut CONTEXT, - } - - pub type PVECTORED_EXCEPTION_HANDLER = extern "system" - fn(ExceptionInfo: *mut EXCEPTION_POINTERS) -> LONG; - - #[repr(C)] - #[derive(Copy, Clone)] - pub struct CONSOLE_READCONSOLE_CONTROL { - pub nLength: ULONG, - pub nInitialChars: ULONG, - pub dwCtrlWakeupMask: ULONG, - pub dwControlKeyState: ULONG, - } - - pub type PCONSOLE_READCONSOLE_CONTROL = *mut CONSOLE_READCONSOLE_CONTROL; - - #[repr(C)] - pub struct BY_HANDLE_FILE_INFORMATION { - pub dwFileAttributes: DWORD, - pub ftCreationTime: FILETIME, - pub ftLastAccessTime: FILETIME, - pub ftLastWriteTime: FILETIME, - pub dwVolumeSerialNumber: DWORD, - pub nFileSizeHigh: DWORD, - pub nFileSizeLow: DWORD, - pub nNumberOfLinks: DWORD, - pub nFileIndexHigh: DWORD, - pub nFileIndexLow: DWORD, - } - - pub type LPBY_HANDLE_FILE_INFORMATION = *mut BY_HANDLE_FILE_INFORMATION; - pub type LPCVOID = *const c_void; - - pub const HANDLE_FLAG_INHERIT: DWORD = 0x00000001; - - pub const TOKEN_READ: DWORD = 0x20008; - - extern "system" { - #[link_name = "SystemFunction036"] - pub fn RtlGenRandom(RandomBuffer: *mut u8, RandomBufferLength: ULONG) -> BOOLEAN; - - pub fn ReadConsoleW(hConsoleInput: HANDLE, - lpBuffer: LPVOID, - nNumberOfCharsToRead: DWORD, - lpNumberOfCharsRead: LPDWORD, - pInputControl: PCONSOLE_READCONSOLE_CONTROL) -> BOOL; - - pub fn WriteConsoleW(hConsoleOutput: HANDLE, - lpBuffer: LPCVOID, - nNumberOfCharsToWrite: DWORD, - lpNumberOfCharsWritten: LPDWORD, - lpReserved: LPVOID) -> BOOL; - - pub fn GetConsoleMode(hConsoleHandle: HANDLE, - lpMode: LPDWORD) -> BOOL; - // Allowed but unused by UWP - pub fn OpenProcessToken(ProcessHandle: HANDLE, - DesiredAccess: DWORD, - TokenHandle: *mut HANDLE) -> BOOL; - pub fn GetUserProfileDirectoryW(hToken: HANDLE, - lpProfileDir: LPWSTR, - lpcchSize: *mut DWORD) -> BOOL; - pub fn GetFileInformationByHandle(hFile: HANDLE, - lpFileInformation: LPBY_HANDLE_FILE_INFORMATION) - -> BOOL; - pub fn SetHandleInformation(hObject: HANDLE, - dwMask: DWORD, - dwFlags: DWORD) -> BOOL; - pub fn AddVectoredExceptionHandler(FirstHandler: ULONG, - VectoredHandler: PVECTORED_EXCEPTION_HANDLER) - -> LPVOID; - pub fn CreateHardLinkW(lpSymlinkFileName: LPCWSTR, - lpTargetFileName: LPCWSTR, - lpSecurityAttributes: LPSECURITY_ATTRIBUTES) - -> BOOL; - } -} -} - -// UWP specific functions & types -cfg_if::cfg_if! { -if #[cfg(target_vendor = "uwp")] { - pub const BCRYPT_USE_SYSTEM_PREFERRED_RNG: DWORD = 0x00000002; - - #[repr(C)] - pub struct FILE_STANDARD_INFO { - pub AllocationSize: LARGE_INTEGER, - pub EndOfFile: LARGE_INTEGER, - pub NumberOfLinks: DWORD, - pub DeletePending: BOOLEAN, - pub Directory: BOOLEAN, - } - - extern "system" { - pub fn GetFileInformationByHandleEx(hFile: HANDLE, - fileInfoClass: FILE_INFO_BY_HANDLE_CLASS, - lpFileInformation: LPVOID, - dwBufferSize: DWORD) -> BOOL; - pub fn BCryptGenRandom(hAlgorithm: LPVOID, pBuffer: *mut u8, - cbBuffer: ULONG, dwFlags: ULONG) -> LONG; - } -} -} - -// Shared between Desktop & UWP -extern "system" { - pub fn WSAStartup(wVersionRequested: WORD, lpWSAData: LPWSADATA) -> c_int; - pub fn WSACleanup() -> c_int; - pub fn WSAGetLastError() -> c_int; - pub fn WSADuplicateSocketW( - s: SOCKET, - dwProcessId: DWORD, - lpProtocolInfo: LPWSAPROTOCOL_INFO, - ) -> c_int; - pub fn WSASend( - s: SOCKET, - lpBuffers: LPWSABUF, - dwBufferCount: DWORD, - lpNumberOfBytesSent: LPDWORD, - dwFlags: DWORD, - lpOverlapped: LPWSAOVERLAPPED, - lpCompletionRoutine: LPWSAOVERLAPPED_COMPLETION_ROUTINE, - ) -> c_int; - pub fn WSARecv( - s: SOCKET, - lpBuffers: LPWSABUF, - dwBufferCount: DWORD, - lpNumberOfBytesRecvd: LPDWORD, - lpFlags: LPDWORD, - lpOverlapped: LPWSAOVERLAPPED, - lpCompletionRoutine: LPWSAOVERLAPPED_COMPLETION_ROUTINE, - ) -> c_int; - pub fn GetCurrentProcessId() -> DWORD; - pub fn WSASocketW( - af: c_int, - kind: c_int, - protocol: c_int, - lpProtocolInfo: LPWSAPROTOCOL_INFO, - g: GROUP, - dwFlags: DWORD, - ) -> SOCKET; - pub fn ioctlsocket(s: SOCKET, cmd: c_long, argp: *mut c_ulong) -> c_int; - pub fn InitializeCriticalSection(CriticalSection: *mut CRITICAL_SECTION); - pub fn EnterCriticalSection(CriticalSection: *mut CRITICAL_SECTION); - pub fn TryEnterCriticalSection(CriticalSection: *mut CRITICAL_SECTION) -> BOOL; - pub fn LeaveCriticalSection(CriticalSection: *mut CRITICAL_SECTION); - pub fn DeleteCriticalSection(CriticalSection: *mut CRITICAL_SECTION); - - pub fn RemoveDirectoryW(lpPathName: LPCWSTR) -> BOOL; - pub fn SetFileAttributesW(lpFileName: LPCWSTR, dwFileAttributes: DWORD) -> BOOL; - pub fn SetLastError(dwErrCode: DWORD); - pub fn GetCommandLineW() -> *mut LPCWSTR; - pub fn GetTempPathW(nBufferLength: DWORD, lpBuffer: LPCWSTR) -> DWORD; - pub fn GetCurrentProcess() -> HANDLE; - pub fn GetCurrentThread() -> HANDLE; - pub fn GetStdHandle(which: DWORD) -> HANDLE; - pub fn ExitProcess(uExitCode: c_uint) -> !; - pub fn DeviceIoControl( - hDevice: HANDLE, - dwIoControlCode: DWORD, - lpInBuffer: LPVOID, - nInBufferSize: DWORD, - lpOutBuffer: LPVOID, - nOutBufferSize: DWORD, - lpBytesReturned: LPDWORD, - lpOverlapped: LPOVERLAPPED, - ) -> BOOL; - pub fn CreateThread( - lpThreadAttributes: LPSECURITY_ATTRIBUTES, - dwStackSize: SIZE_T, - lpStartAddress: extern "system" fn(*mut c_void) -> DWORD, - lpParameter: LPVOID, - dwCreationFlags: DWORD, - lpThreadId: LPDWORD, - ) -> HANDLE; - pub fn WaitForSingleObject(hHandle: HANDLE, dwMilliseconds: DWORD) -> DWORD; - pub fn SwitchToThread() -> BOOL; - pub fn Sleep(dwMilliseconds: DWORD); - pub fn GetProcessId(handle: HANDLE) -> DWORD; - pub fn CopyFileExW( - lpExistingFileName: LPCWSTR, - lpNewFileName: LPCWSTR, - lpProgressRoutine: LPPROGRESS_ROUTINE, - lpData: LPVOID, - pbCancel: LPBOOL, - dwCopyFlags: DWORD, - ) -> BOOL; - pub fn FormatMessageW( - flags: DWORD, - lpSrc: LPVOID, - msgId: DWORD, - langId: DWORD, - buf: LPWSTR, - nsize: DWORD, - args: *const c_void, - ) -> DWORD; - pub fn TlsAlloc() -> DWORD; - pub fn TlsGetValue(dwTlsIndex: DWORD) -> LPVOID; - pub fn TlsSetValue(dwTlsIndex: DWORD, lpTlsvalue: LPVOID) -> BOOL; - pub fn GetLastError() -> DWORD; - pub fn QueryPerformanceFrequency(lpFrequency: *mut LARGE_INTEGER) -> BOOL; - pub fn QueryPerformanceCounter(lpPerformanceCount: *mut LARGE_INTEGER) -> BOOL; - pub fn GetExitCodeProcess(hProcess: HANDLE, lpExitCode: LPDWORD) -> BOOL; - pub fn TerminateProcess(hProcess: HANDLE, uExitCode: UINT) -> BOOL; - pub fn CreateProcessW( - lpApplicationName: LPCWSTR, - lpCommandLine: LPWSTR, - lpProcessAttributes: LPSECURITY_ATTRIBUTES, - lpThreadAttributes: LPSECURITY_ATTRIBUTES, - bInheritHandles: BOOL, - dwCreationFlags: DWORD, - lpEnvironment: LPVOID, - lpCurrentDirectory: LPCWSTR, - lpStartupInfo: LPSTARTUPINFO, - lpProcessInformation: LPPROCESS_INFORMATION, - ) -> BOOL; - pub fn GetEnvironmentVariableW(n: LPCWSTR, v: LPWSTR, nsize: DWORD) -> DWORD; - pub fn SetEnvironmentVariableW(n: LPCWSTR, v: LPCWSTR) -> BOOL; - pub fn GetEnvironmentStringsW() -> LPWCH; - pub fn FreeEnvironmentStringsW(env_ptr: LPWCH) -> BOOL; - pub fn GetModuleFileNameW(hModule: HMODULE, lpFilename: LPWSTR, nSize: DWORD) -> DWORD; - pub fn CreateDirectoryW( - lpPathName: LPCWSTR, - lpSecurityAttributes: LPSECURITY_ATTRIBUTES, - ) -> BOOL; - pub fn DeleteFileW(lpPathName: LPCWSTR) -> BOOL; - pub fn GetCurrentDirectoryW(nBufferLength: DWORD, lpBuffer: LPWSTR) -> DWORD; - pub fn SetCurrentDirectoryW(lpPathName: LPCWSTR) -> BOOL; - pub fn WideCharToMultiByte( - CodePage: UINT, - dwFlags: DWORD, - lpWideCharStr: LPCWSTR, - cchWideChar: c_int, - lpMultiByteStr: LPSTR, - cbMultiByte: c_int, - lpDefaultChar: LPCSTR, - lpUsedDefaultChar: LPBOOL, - ) -> c_int; - - pub fn closesocket(socket: SOCKET) -> c_int; - pub fn recv(socket: SOCKET, buf: *mut c_void, len: c_int, flags: c_int) -> c_int; - pub fn send(socket: SOCKET, buf: *const c_void, len: c_int, flags: c_int) -> c_int; - pub fn recvfrom( - socket: SOCKET, - buf: *mut c_void, - len: c_int, - flags: c_int, - addr: *mut SOCKADDR, - addrlen: *mut c_int, - ) -> c_int; - pub fn sendto( - socket: SOCKET, - buf: *const c_void, - len: c_int, - flags: c_int, - addr: *const SOCKADDR, - addrlen: c_int, - ) -> c_int; - pub fn shutdown(socket: SOCKET, how: c_int) -> c_int; - pub fn accept(socket: SOCKET, address: *mut SOCKADDR, address_len: *mut c_int) -> SOCKET; - pub fn DuplicateHandle( - hSourceProcessHandle: HANDLE, - hSourceHandle: HANDLE, - hTargetProcessHandle: HANDLE, - lpTargetHandle: LPHANDLE, - dwDesiredAccess: DWORD, - bInheritHandle: BOOL, - dwOptions: DWORD, - ) -> BOOL; - pub fn ReadFile( - hFile: HANDLE, - lpBuffer: LPVOID, - nNumberOfBytesToRead: DWORD, - lpNumberOfBytesRead: LPDWORD, - lpOverlapped: LPOVERLAPPED, - ) -> BOOL; - pub fn WriteFile( - hFile: HANDLE, - lpBuffer: LPVOID, - nNumberOfBytesToWrite: DWORD, - lpNumberOfBytesWritten: LPDWORD, - lpOverlapped: LPOVERLAPPED, - ) -> BOOL; - pub fn CloseHandle(hObject: HANDLE) -> BOOL; - pub fn MoveFileExW(lpExistingFileName: LPCWSTR, lpNewFileName: LPCWSTR, dwFlags: DWORD) - -> BOOL; - pub fn SetFilePointerEx( - hFile: HANDLE, - liDistanceToMove: LARGE_INTEGER, - lpNewFilePointer: PLARGE_INTEGER, - dwMoveMethod: DWORD, - ) -> BOOL; - pub fn FlushFileBuffers(hFile: HANDLE) -> BOOL; - pub fn CreateFileW( - lpFileName: LPCWSTR, - dwDesiredAccess: DWORD, - dwShareMode: DWORD, - lpSecurityAttributes: LPSECURITY_ATTRIBUTES, - dwCreationDisposition: DWORD, - dwFlagsAndAttributes: DWORD, - hTemplateFile: HANDLE, - ) -> HANDLE; - - pub fn FindFirstFileW(fileName: LPCWSTR, findFileData: LPWIN32_FIND_DATAW) -> HANDLE; - pub fn FindNextFileW(findFile: HANDLE, findFileData: LPWIN32_FIND_DATAW) -> BOOL; - pub fn FindClose(findFile: HANDLE) -> BOOL; - pub fn getsockopt( - s: SOCKET, - level: c_int, - optname: c_int, - optval: *mut c_char, - optlen: *mut c_int, - ) -> c_int; - pub fn setsockopt( - s: SOCKET, - level: c_int, - optname: c_int, - optval: *const c_void, - optlen: c_int, - ) -> c_int; - pub fn getsockname(socket: SOCKET, address: *mut SOCKADDR, address_len: *mut c_int) -> c_int; - pub fn getpeername(socket: SOCKET, address: *mut SOCKADDR, address_len: *mut c_int) -> c_int; - pub fn bind(socket: SOCKET, address: *const SOCKADDR, address_len: socklen_t) -> c_int; - pub fn listen(socket: SOCKET, backlog: c_int) -> c_int; - pub fn connect(socket: SOCKET, address: *const SOCKADDR, len: c_int) -> c_int; - pub fn getaddrinfo( - node: *const c_char, - service: *const c_char, - hints: *const ADDRINFOA, - res: *mut *mut ADDRINFOA, - ) -> c_int; - pub fn freeaddrinfo(res: *mut ADDRINFOA); - - pub fn GetProcAddress(handle: HMODULE, name: LPCSTR) -> *mut c_void; - pub fn GetModuleHandleW(lpModuleName: LPCWSTR) -> HMODULE; - - pub fn GetSystemTimeAsFileTime(lpSystemTimeAsFileTime: LPFILETIME); - - pub fn CreateEventW( - lpEventAttributes: LPSECURITY_ATTRIBUTES, - bManualReset: BOOL, - bInitialState: BOOL, - lpName: LPCWSTR, - ) -> HANDLE; - pub fn WaitForMultipleObjects( - nCount: DWORD, - lpHandles: *const HANDLE, - bWaitAll: BOOL, - dwMilliseconds: DWORD, - ) -> DWORD; - pub fn CreateNamedPipeW( - lpName: LPCWSTR, - dwOpenMode: DWORD, - dwPipeMode: DWORD, - nMaxInstances: DWORD, - nOutBufferSize: DWORD, - nInBufferSize: DWORD, - nDefaultTimeOut: DWORD, - lpSecurityAttributes: LPSECURITY_ATTRIBUTES, - ) -> HANDLE; - pub fn CancelIo(handle: HANDLE) -> BOOL; - pub fn GetOverlappedResult( - hFile: HANDLE, - lpOverlapped: LPOVERLAPPED, - lpNumberOfBytesTransferred: LPDWORD, - bWait: BOOL, - ) -> BOOL; - pub fn select( - nfds: c_int, - readfds: *mut fd_set, - writefds: *mut fd_set, - exceptfds: *mut fd_set, - timeout: *const timeval, - ) -> c_int; - - pub fn GetProcessHeap() -> HANDLE; - pub fn HeapAlloc(hHeap: HANDLE, dwFlags: DWORD, dwBytes: SIZE_T) -> LPVOID; - pub fn HeapReAlloc(hHeap: HANDLE, dwFlags: DWORD, lpMem: LPVOID, dwBytes: SIZE_T) -> LPVOID; - pub fn HeapFree(hHeap: HANDLE, dwFlags: DWORD, lpMem: LPVOID) -> BOOL; -} - -// Functions that aren't available on every version of Windows that we support, -// but we still use them and just provide some form of a fallback implementation. -compat_fn! { - kernel32: - - pub fn CreateSymbolicLinkW(_lpSymlinkFileName: LPCWSTR, - _lpTargetFileName: LPCWSTR, - _dwFlags: DWORD) -> BOOLEAN { - SetLastError(ERROR_CALL_NOT_IMPLEMENTED as DWORD); 0 - } - pub fn GetFinalPathNameByHandleW(_hFile: HANDLE, - _lpszFilePath: LPCWSTR, - _cchFilePath: DWORD, - _dwFlags: DWORD) -> DWORD { - SetLastError(ERROR_CALL_NOT_IMPLEMENTED as DWORD); 0 - } - #[cfg(not(target_vendor = "uwp"))] - pub fn SetThreadStackGuarantee(_size: *mut c_ulong) -> BOOL { - SetLastError(ERROR_CALL_NOT_IMPLEMENTED as DWORD); 0 - } - pub fn SetThreadDescription(hThread: HANDLE, - lpThreadDescription: LPCWSTR) -> HRESULT { - SetLastError(ERROR_CALL_NOT_IMPLEMENTED as DWORD); E_NOTIMPL - } - pub fn SetFileInformationByHandle(_hFile: HANDLE, - _FileInformationClass: FILE_INFO_BY_HANDLE_CLASS, - _lpFileInformation: LPVOID, - _dwBufferSize: DWORD) -> BOOL { - SetLastError(ERROR_CALL_NOT_IMPLEMENTED as DWORD); 0 - } - pub fn GetSystemTimePreciseAsFileTime(lpSystemTimeAsFileTime: LPFILETIME) - -> () { - GetSystemTimeAsFileTime(lpSystemTimeAsFileTime) - } - pub fn SleepConditionVariableSRW(ConditionVariable: PCONDITION_VARIABLE, - SRWLock: PSRWLOCK, - dwMilliseconds: DWORD, - Flags: ULONG) -> BOOL { - panic!("condition variables not available") - } - pub fn WakeConditionVariable(ConditionVariable: PCONDITION_VARIABLE) - -> () { - panic!("condition variables not available") - } - pub fn WakeAllConditionVariable(ConditionVariable: PCONDITION_VARIABLE) - -> () { - panic!("condition variables not available") - } - pub fn AcquireSRWLockExclusive(SRWLock: PSRWLOCK) -> () { - panic!("rwlocks not available") - } - pub fn AcquireSRWLockShared(SRWLock: PSRWLOCK) -> () { - panic!("rwlocks not available") - } - pub fn ReleaseSRWLockExclusive(SRWLock: PSRWLOCK) -> () { - panic!("rwlocks not available") - } - pub fn ReleaseSRWLockShared(SRWLock: PSRWLOCK) -> () { - panic!("rwlocks not available") - } - pub fn TryAcquireSRWLockExclusive(SRWLock: PSRWLOCK) -> BOOLEAN { - panic!("rwlocks not available") - } - pub fn TryAcquireSRWLockShared(SRWLock: PSRWLOCK) -> BOOLEAN { - panic!("rwlocks not available") - } -} diff --git a/src/libstd/sys/windows/cmath.rs b/src/libstd/sys/windows/cmath.rs deleted file mode 100644 index 1a5421facd0..00000000000 --- a/src/libstd/sys/windows/cmath.rs +++ /dev/null @@ -1,92 +0,0 @@ -#![cfg(not(test))] - -use libc::{c_double, c_float}; - -extern "C" { - pub fn acos(n: c_double) -> c_double; - pub fn asin(n: c_double) -> c_double; - pub fn atan(n: c_double) -> c_double; - pub fn atan2(a: c_double, b: c_double) -> c_double; - pub fn cbrt(n: c_double) -> c_double; - pub fn cbrtf(n: c_float) -> c_float; - pub fn cosh(n: c_double) -> c_double; - pub fn expm1(n: c_double) -> c_double; - pub fn expm1f(n: c_float) -> c_float; - pub fn fdim(a: c_double, b: c_double) -> c_double; - pub fn fdimf(a: c_float, b: c_float) -> c_float; - #[cfg_attr(target_env = "msvc", link_name = "_hypot")] - pub fn hypot(x: c_double, y: c_double) -> c_double; - #[cfg_attr(target_env = "msvc", link_name = "_hypotf")] - pub fn hypotf(x: c_float, y: c_float) -> c_float; - pub fn log1p(n: c_double) -> c_double; - pub fn log1pf(n: c_float) -> c_float; - pub fn sinh(n: c_double) -> c_double; - pub fn tan(n: c_double) -> c_double; - pub fn tanh(n: c_double) -> c_double; -} - -pub use self::shims::*; - -#[cfg(not(all(target_env = "msvc", target_arch = "x86")))] -mod shims { - use libc::c_float; - - extern "C" { - pub fn acosf(n: c_float) -> c_float; - pub fn asinf(n: c_float) -> c_float; - pub fn atan2f(a: c_float, b: c_float) -> c_float; - pub fn atanf(n: c_float) -> c_float; - pub fn coshf(n: c_float) -> c_float; - pub fn sinhf(n: c_float) -> c_float; - pub fn tanf(n: c_float) -> c_float; - pub fn tanhf(n: c_float) -> c_float; - } -} - -// On 32-bit x86 MSVC these functions aren't defined, so we just define shims -// which promote everything fo f64, perform the calculation, and then demote -// 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; - - #[inline] - pub unsafe fn acosf(n: c_float) -> c_float { - f64::acos(n as f64) as c_float - } - - #[inline] - pub unsafe fn asinf(n: c_float) -> c_float { - f64::asin(n as f64) as c_float - } - - #[inline] - pub unsafe fn atan2f(n: c_float, b: c_float) -> c_float { - f64::atan2(n as f64, b as f64) as c_float - } - - #[inline] - pub unsafe fn atanf(n: c_float) -> c_float { - f64::atan(n as f64) as c_float - } - - #[inline] - pub unsafe fn coshf(n: c_float) -> c_float { - f64::cosh(n as f64) as c_float - } - - #[inline] - pub unsafe fn sinhf(n: c_float) -> c_float { - f64::sinh(n as f64) as c_float - } - - #[inline] - pub unsafe fn tanf(n: c_float) -> c_float { - f64::tan(n as f64) as c_float - } - - #[inline] - pub unsafe fn tanhf(n: c_float) -> c_float { - f64::tanh(n as f64) as c_float - } -} diff --git a/src/libstd/sys/windows/compat.rs b/src/libstd/sys/windows/compat.rs deleted file mode 100644 index d6d433f9d08..00000000000 --- a/src/libstd/sys/windows/compat.rs +++ /dev/null @@ -1,72 +0,0 @@ -//! A "compatibility layer" for spanning XP and Windows 7 -//! -//! The standard library currently binds many functions that are not available -//! on Windows XP, but we would also like to support building executables that -//! run on XP. To do this we specify all non-XP APIs as having a fallback -//! implementation to do something reasonable. -//! -//! This dynamic runtime detection of whether a function is available is -//! implemented with `GetModuleHandle` and `GetProcAddress` paired with a -//! static-per-function which caches the result of the first check. In this -//! manner we pay a semi-large one-time cost up front for detecting whether a -//! function is available but afterwards it's just a load and a jump. - -use crate::ffi::CString; -use crate::sync::atomic::{AtomicUsize, Ordering}; -use crate::sys::c; - -pub fn lookup(module: &str, symbol: &str) -> Option<usize> { - let mut module: Vec<u16> = module.encode_utf16().collect(); - module.push(0); - let symbol = CString::new(symbol).unwrap(); - unsafe { - let handle = c::GetModuleHandleW(module.as_ptr()); - match c::GetProcAddress(handle, symbol.as_ptr()) as usize { - 0 => None, - n => Some(n), - } - } -} - -pub fn store_func(ptr: &AtomicUsize, module: &str, symbol: &str, fallback: usize) -> usize { - let value = lookup(module, symbol).unwrap_or(fallback); - ptr.store(value, Ordering::SeqCst); - value -} - -macro_rules! compat_fn { - ($module:ident: $( - $(#[$meta:meta])* - pub fn $symbol:ident($($argname:ident: $argtype:ty),*) - -> $rettype:ty { - $($body:expr);* - } - )*) => ($( - #[allow(unused_variables)] - $(#[$meta])* - pub unsafe fn $symbol($($argname: $argtype),*) -> $rettype { - use crate::sync::atomic::{AtomicUsize, Ordering}; - use crate::mem; - type F = unsafe extern "system" fn($($argtype),*) -> $rettype; - - static PTR: AtomicUsize = AtomicUsize::new(0); - - fn load() -> usize { - crate::sys::compat::store_func(&PTR, - stringify!($module), - stringify!($symbol), - fallback as usize) - } - unsafe extern "system" fn fallback($($argname: $argtype),*) - -> $rettype { - $($body);* - } - - let addr = match PTR.load(Ordering::SeqCst) { - 0 => load(), - n => n, - }; - mem::transmute::<usize, F>(addr)($($argname),*) - } - )*) -} diff --git a/src/libstd/sys/windows/condvar.rs b/src/libstd/sys/windows/condvar.rs deleted file mode 100644 index 8f7f6854cc2..00000000000 --- a/src/libstd/sys/windows/condvar.rs +++ /dev/null @@ -1,56 +0,0 @@ -use crate::cell::UnsafeCell; -use crate::sys::c; -use crate::sys::mutex::{self, Mutex}; -use crate::sys::os; -use crate::time::Duration; - -pub struct Condvar { - inner: UnsafeCell<c::CONDITION_VARIABLE>, -} - -unsafe impl Send for Condvar {} -unsafe impl Sync for Condvar {} - -impl Condvar { - pub const fn new() -> Condvar { - Condvar { inner: UnsafeCell::new(c::CONDITION_VARIABLE_INIT) } - } - - #[inline] - pub unsafe fn init(&mut self) {} - - #[inline] - pub unsafe fn wait(&self, mutex: &Mutex) { - let r = c::SleepConditionVariableSRW(self.inner.get(), mutex::raw(mutex), c::INFINITE, 0); - debug_assert!(r != 0); - } - - pub unsafe fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool { - let r = c::SleepConditionVariableSRW( - self.inner.get(), - mutex::raw(mutex), - super::dur2timeout(dur), - 0, - ); - if r == 0 { - debug_assert_eq!(os::errno() as usize, c::ERROR_TIMEOUT as usize); - false - } else { - true - } - } - - #[inline] - pub unsafe fn notify_one(&self) { - c::WakeConditionVariable(self.inner.get()) - } - - #[inline] - pub unsafe fn notify_all(&self) { - c::WakeAllConditionVariable(self.inner.get()) - } - - pub unsafe fn destroy(&self) { - // ... - } -} diff --git a/src/libstd/sys/windows/env.rs b/src/libstd/sys/windows/env.rs deleted file mode 100644 index f0a99d6200c..00000000000 --- a/src/libstd/sys/windows/env.rs +++ /dev/null @@ -1,9 +0,0 @@ -pub mod os { - pub const FAMILY: &str = "windows"; - pub const OS: &str = "windows"; - pub const DLL_PREFIX: &str = ""; - pub const DLL_SUFFIX: &str = ".dll"; - pub const DLL_EXTENSION: &str = "dll"; - pub const EXE_SUFFIX: &str = ".exe"; - pub const EXE_EXTENSION: &str = "exe"; -} diff --git a/src/libstd/sys/windows/ext/ffi.rs b/src/libstd/sys/windows/ext/ffi.rs deleted file mode 100644 index 6e78119383f..00000000000 --- a/src/libstd/sys/windows/ext/ffi.rs +++ /dev/null @@ -1,142 +0,0 @@ -//! Windows-specific extensions to the 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 a [`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 [`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 -//! [`OsString`]: ../../../ffi/struct.OsString.html -//! [`OsStr`]: ../../../ffi/struct.OsStr.html -//! [`OsStringExt`]: trait.OsStringExt.html -//! [`OsStrExt`]: trait.OsStrExt.html -//! [`EncodeWide`]: struct.EncodeWide.html -//! [`from_wide`]: trait.OsStringExt.html#tymethod.from_wide -//! [`encode_wide`]: trait.OsStrExt.html#tymethod.encode_wide -//! [`collect`]: ../../../iter/trait.Iterator.html#method.collect -//! [U+FFFD]: ../../../char/constant.REPLACEMENT_CHARACTER.html - -#![stable(feature = "rust1", since = "1.0.0")] - -use crate::ffi::{OsStr, OsString}; -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`]. -/// -/// [`OsString`]: ../../../../std/ffi/struct.OsString.html -#[stable(feature = "rust1", since = "1.0.0")] -pub trait OsStringExt { - /// Creates an `OsString` from a potentially ill-formed UTF-16 slice of - /// 16-bit code units. - /// - /// This is lossless: calling [`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[..]); - /// ``` - /// - /// [`encode_wide`]: ./trait.OsStrExt.html#tymethod.encode_wide - #[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`]. -/// -/// [`OsStr`]: ../../../../std/ffi/struct.OsStr.html -#[stable(feature = "rust1", since = "1.0.0")] -pub trait OsStrExt { - /// Re-encodes an `OsStr` as a wide character sequence, i.e., potentially - /// ill-formed UTF-16. - /// - /// This is lossless: calling [`OsString::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[..]); - /// ``` - /// - /// [`OsString::from_wide`]: ./trait.OsStringExt.html#tymethod.from_wide - #[stable(feature = "rust1", since = "1.0.0")] - fn encode_wide(&self) -> EncodeWide<'_>; -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl OsStrExt for OsStr { - fn encode_wide(&self) -> EncodeWide<'_> { - self.as_inner().inner.encode_wide() - } -} diff --git a/src/libstd/sys/windows/ext/fs.rs b/src/libstd/sys/windows/ext/fs.rs deleted file mode 100644 index 81b2bf99872..00000000000 --- a/src/libstd/sys/windows/ext/fs.rs +++ /dev/null @@ -1,565 +0,0 @@ -//! Windows-specific extensions for the primitives in the `std::fs` module. - -#![stable(feature = "rust1", since = "1.0.0")] - -use crate::fs::{self, Metadata, OpenOptions}; -use crate::io; -use crate::path::Path; -use crate::sys; -use crate::sys_common::{AsInner, AsInnerMut}; - -/// Windows-specific extensions to [`File`]. -/// -/// [`File`]: ../../../fs/struct.File.html -#[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`]. -/// -/// [`fs::OpenOptions`]: ../../../../std/fs/struct.OpenOptions.html -#[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 - /// # #[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 - /// # #[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 - /// # #[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. -/// -/// [`fs::Metadata`]: ../../../../std/fs/struct.Metadata.html -/// [`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 [`FileType`]. -/// -/// On Windows, a symbolic link knows whether it is a file or directory. -/// -/// [`FileType`]: ../../../../std/fs/struct.FileType.html -#[unstable(feature = "windows_file_type_ext", issue = "none")] -pub trait FileTypeExt { - /// Returns `true` if this file type is a symbolic link that is also a directory. - #[unstable(feature = "windows_file_type_ext", issue = "none")] - fn is_symlink_dir(&self) -> bool; - /// Returns `true` if this file type is a symbolic link that is also a file. - #[unstable(feature = "windows_file_type_ext", issue = "none")] - fn is_symlink_file(&self) -> bool; -} - -#[unstable(feature = "windows_file_type_ext", issue = "none")] -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 file symbolic link on the filesystem. -/// -/// The `dst` path will be a file symbolic link pointing to the `src` -/// path. -/// -/// # Examples -/// -/// ```no_run -/// use std::os::windows::fs; -/// -/// fn main() -> std::io::Result<()> { -/// fs::symlink_file("a.txt", "b.txt")?; -/// Ok(()) -/// } -/// ``` -#[stable(feature = "symlink", since = "1.1.0")] -pub fn symlink_file<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dst: Q) -> io::Result<()> { - sys::fs::symlink_inner(src.as_ref(), dst.as_ref(), false) -} - -/// Creates a new directory symlink on the filesystem. -/// -/// The `dst` path will be a directory symbolic link pointing to the `src` -/// path. -/// -/// # Examples -/// -/// ```no_run -/// use std::os::windows::fs; -/// -/// fn main() -> std::io::Result<()> { -/// fs::symlink_dir("a", "b")?; -/// Ok(()) -/// } -/// ``` -#[stable(feature = "symlink", since = "1.1.0")] -pub fn symlink_dir<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dst: Q) -> io::Result<()> { - sys::fs::symlink_inner(src.as_ref(), dst.as_ref(), true) -} diff --git a/src/libstd/sys/windows/ext/io.rs b/src/libstd/sys/windows/ext/io.rs deleted file mode 100644 index 4573ee58932..00000000000 --- a/src/libstd/sys/windows/ext/io.rs +++ /dev/null @@ -1,220 +0,0 @@ -#![stable(feature = "rust1", since = "1.0.0")] - -use crate::fs; -use crate::io; -use crate::net; -use crate::os::windows::raw; -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, without taking any ownership. - #[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 will **consume ownership** of the handle given, - /// passing responsibility for closing the handle to the returned - /// object. - /// - /// This function is also unsafe as the primitives currently returned - /// have the contract that they are the sole owner of the file - /// descriptor they are wrapping. Usage of this function could - /// accidentally allow violating this contract which can cause memory - /// unsafety in code that relies on it being true. - #[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 **transfers ownership** of the underlying handle to the - /// caller. Callers are then the unique owners of the handle and must close - /// it once it's no longer needed. - #[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 { - fn as_raw_handle(&self) -> RawHandle { - self.as_inner().handle().raw() as RawHandle - } -} - -#[stable(feature = "asraw_stdio", since = "1.21.0")] -impl AsRawHandle for io::Stdin { - fn as_raw_handle(&self) -> RawHandle { - 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 { - 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 { - 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 { - 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 { - 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 { - unsafe { c::GetStdHandle(c::STD_ERROR_HANDLE) as RawHandle } - } -} - -#[stable(feature = "from_raw_os", since = "1.1.0")] -impl FromRawHandle for fs::File { - unsafe fn from_raw_handle(handle: RawHandle) -> fs::File { - let handle = handle as c::HANDLE; - fs::File::from_inner(sys::fs::File::from_inner(handle)) - } -} - -#[stable(feature = "into_raw_os", since = "1.4.0")] -impl IntoRawHandle for fs::File { - fn into_raw_handle(self) -> RawHandle { - self.into_inner().into_handle().into_raw() as *mut _ - } -} - -/// Extracts raw sockets. -#[stable(feature = "rust1", since = "1.0.0")] -pub trait AsRawSocket { - /// Extracts the underlying raw socket from this object. - #[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 { - /// Creates a new I/O object from the given raw socket. - /// - /// This function will **consume ownership** of the socket provided and - /// it will be closed when the returned object goes out of scope. - /// - /// This function is also unsafe as the primitives currently returned - /// have the contract that they are the sole owner of the file - /// descriptor they are wrapping. Usage of this function could - /// accidentally allow violating this contract which can cause memory - /// unsafety in code that relies on it being true. - #[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 **transfers ownership** of the underlying socket to the - /// caller. Callers are then the unique owners of the socket and must close - /// it once it's no longer needed. - #[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 { - fn as_raw_socket(&self) -> RawSocket { - *self.as_inner().socket().as_inner() - } -} -#[stable(feature = "rust1", since = "1.0.0")] -impl AsRawSocket for net::TcpListener { - fn as_raw_socket(&self) -> RawSocket { - *self.as_inner().socket().as_inner() - } -} -#[stable(feature = "rust1", since = "1.0.0")] -impl AsRawSocket for net::UdpSocket { - fn as_raw_socket(&self) -> RawSocket { - *self.as_inner().socket().as_inner() - } -} - -#[stable(feature = "from_raw_os", since = "1.1.0")] -impl FromRawSocket for net::TcpStream { - unsafe fn from_raw_socket(sock: RawSocket) -> net::TcpStream { - let sock = sys::net::Socket::from_inner(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 { - unsafe fn from_raw_socket(sock: RawSocket) -> net::TcpListener { - let sock = sys::net::Socket::from_inner(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 { - unsafe fn from_raw_socket(sock: RawSocket) -> net::UdpSocket { - let sock = sys::net::Socket::from_inner(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 { - fn into_raw_socket(self) -> RawSocket { - self.into_inner().into_socket().into_inner() - } -} - -#[stable(feature = "into_raw_os", since = "1.4.0")] -impl IntoRawSocket for net::TcpListener { - fn into_raw_socket(self) -> RawSocket { - self.into_inner().into_socket().into_inner() - } -} - -#[stable(feature = "into_raw_os", since = "1.4.0")] -impl IntoRawSocket for net::UdpSocket { - fn into_raw_socket(self) -> RawSocket { - self.into_inner().into_socket().into_inner() - } -} diff --git a/src/libstd/sys/windows/ext/mod.rs b/src/libstd/sys/windows/ext/mod.rs deleted file mode 100644 index 613d3dc189a..00000000000 --- a/src/libstd/sys/windows/ext/mod.rs +++ /dev/null @@ -1,40 +0,0 @@ -//! 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. - -#![stable(feature = "rust1", since = "1.0.0")] -#![doc(cfg(windows))] -#![allow(missing_docs)] - -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::{AsRawHandle, AsRawSocket, RawHandle, RawSocket}; - #[doc(no_inline)] - #[stable(feature = "rust1", since = "1.0.0")] - pub use super::io::{FromRawHandle, FromRawSocket, IntoRawHandle, IntoRawSocket}; -} diff --git a/src/libstd/sys/windows/ext/process.rs b/src/libstd/sys/windows/ext/process.rs deleted file mode 100644 index 8c34a9faf1d..00000000000 --- a/src/libstd/sys/windows/ext/process.rs +++ /dev/null @@ -1,113 +0,0 @@ -//! Extensions to `std::process` for Windows. - -#![stable(feature = "process_extensions", since = "1.2.0")] - -use crate::os::windows::io::{AsRawHandle, FromRawHandle, IntoRawHandle, RawHandle}; -use crate::process; -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::new(handle as *mut _); - 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 { - fn as_raw_handle(&self) -> RawHandle { - self.as_inner().handle().raw() as *mut _ - } -} - -#[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() as *mut _ - } -} - -#[stable(feature = "process_extensions", since = "1.2.0")] -impl AsRawHandle for process::ChildStdin { - fn as_raw_handle(&self) -> RawHandle { - self.as_inner().handle().raw() as *mut _ - } -} - -#[stable(feature = "process_extensions", since = "1.2.0")] -impl AsRawHandle for process::ChildStdout { - fn as_raw_handle(&self) -> RawHandle { - self.as_inner().handle().raw() as *mut _ - } -} - -#[stable(feature = "process_extensions", since = "1.2.0")] -impl AsRawHandle for process::ChildStderr { - fn as_raw_handle(&self) -> RawHandle { - self.as_inner().handle().raw() 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() 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() 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() as *mut _ - } -} - -/// Windows-specific extensions to [`process::ExitStatus`]. -/// -/// [`process::ExitStatus`]: ../../../../std/process/struct.ExitStatus.html -#[stable(feature = "exit_status_from", since = "1.12.0")] -pub trait ExitStatusExt { - /// 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. -/// -/// [`process::Command`]: ../../../../std/process/struct.Command.html -#[stable(feature = "windows_process_extensions", since = "1.16.0")] -pub trait CommandExt { - /// 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; -} - -#[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 - } -} diff --git a/src/libstd/sys/windows/ext/raw.rs b/src/libstd/sys/windows/ext/raw.rs deleted file mode 100644 index 7f2a2877828..00000000000 --- a/src/libstd/sys/windows/ext/raw.rs +++ /dev/null @@ -1,14 +0,0 @@ -//! 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")] -#[stable(feature = "raw_ext", since = "1.1.0")] -pub type SOCKET = u32; -#[cfg(target_pointer_width = "64")] -#[stable(feature = "raw_ext", since = "1.1.0")] -pub type SOCKET = u64; diff --git a/src/libstd/sys/windows/ext/thread.rs b/src/libstd/sys/windows/ext/thread.rs deleted file mode 100644 index 41c29f5b950..00000000000 --- a/src/libstd/sys/windows/ext/thread.rs +++ /dev/null @@ -1,21 +0,0 @@ -//! Extensions to `std::thread` for Windows. - -#![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> { - fn as_raw_handle(&self) -> RawHandle { - self.as_inner().handle().raw() as *mut _ - } -} - -#[stable(feature = "thread_extensions", since = "1.9.0")] -impl<T> IntoRawHandle for thread::JoinHandle<T> { - fn into_raw_handle(self) -> RawHandle { - self.into_inner().into_handle().into_raw() as *mut _ - } -} diff --git a/src/libstd/sys/windows/fs.rs b/src/libstd/sys/windows/fs.rs deleted file mode 100644 index cdbfac267b9..00000000000 --- a/src/libstd/sys/windows/fs.rs +++ /dev/null @@ -1,938 +0,0 @@ -use crate::os::windows::prelude::*; - -use crate::ffi::OsString; -use crate::fmt; -use crate::io::{self, Error, IoSlice, IoSliceMut, SeekFrom}; -use crate::mem; -use crate::path::{Path, PathBuf}; -use crate::ptr; -use crate::slice; -use crate::sync::Arc; -use crate::sys::handle::Handle; -use crate::sys::time::SystemTime; -use crate::sys::{c, cvt}; -use crate::sys_common::FromInner; - -use super::to_u16s; - -pub struct File { - handle: Handle, -} - -#[derive(Clone)] -pub struct FileAttr { - attributes: c::DWORD, - creation_time: c::FILETIME, - last_access_time: c::FILETIME, - last_write_time: c::FILETIME, - file_size: u64, - reparse_tag: c::DWORD, - volume_serial_number: Option<u32>, - number_of_links: Option<u32>, - file_index: Option<u64>, -} - -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] -pub struct FileType { - attributes: c::DWORD, - reparse_tag: c::DWORD, -} - -pub struct ReadDir { - handle: FindNextFileHandle, - root: Arc<PathBuf>, - first: Option<c::WIN32_FIND_DATAW>, -} - -struct FindNextFileHandle(c::HANDLE); - -unsafe impl Send for FindNextFileHandle {} -unsafe impl Sync for FindNextFileHandle {} - -pub struct DirEntry { - root: Arc<PathBuf>, - data: c::WIN32_FIND_DATAW, -} - -#[derive(Clone, Debug)] -pub struct OpenOptions { - // generic - read: bool, - write: bool, - append: bool, - truncate: bool, - create: bool, - create_new: bool, - // system-specific - custom_flags: u32, - access_mode: Option<c::DWORD>, - attributes: c::DWORD, - share_mode: c::DWORD, - security_qos_flags: c::DWORD, - security_attributes: usize, // FIXME: should be a reference -} - -#[derive(Clone, PartialEq, Eq, Debug)] -pub struct FilePermissions { - attrs: c::DWORD, -} - -#[derive(Debug)] -pub struct DirBuilder; - -impl fmt::Debug for ReadDir { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - // This will only be called from std::fs::ReadDir, which will add a "ReadDir()" frame. - // Thus the result will be e g 'ReadDir("C:\")' - fmt::Debug::fmt(&*self.root, f) - } -} - -impl Iterator for ReadDir { - type Item = io::Result<DirEntry>; - fn next(&mut self) -> Option<io::Result<DirEntry>> { - if let Some(first) = self.first.take() { - if let Some(e) = DirEntry::new(&self.root, &first) { - return Some(Ok(e)); - } - } - unsafe { - let mut wfd = mem::zeroed(); - loop { - if c::FindNextFileW(self.handle.0, &mut wfd) == 0 { - if c::GetLastError() == c::ERROR_NO_MORE_FILES { - return None; - } else { - return Some(Err(Error::last_os_error())); - } - } - if let Some(e) = DirEntry::new(&self.root, &wfd) { - return Some(Ok(e)); - } - } - } - } -} - -impl Drop for FindNextFileHandle { - fn drop(&mut self) { - let r = unsafe { c::FindClose(self.0) }; - debug_assert!(r != 0); - } -} - -impl DirEntry { - fn new(root: &Arc<PathBuf>, wfd: &c::WIN32_FIND_DATAW) -> Option<DirEntry> { - match &wfd.cFileName[0..3] { - // check for '.' and '..' - &[46, 0, ..] | &[46, 46, 0, ..] => return None, - _ => {} - } - - Some(DirEntry { root: root.clone(), data: *wfd }) - } - - pub fn path(&self) -> PathBuf { - self.root.join(&self.file_name()) - } - - pub fn file_name(&self) -> OsString { - let filename = super::truncate_utf16_at_nul(&self.data.cFileName); - OsString::from_wide(filename) - } - - pub fn file_type(&self) -> io::Result<FileType> { - Ok(FileType::new( - self.data.dwFileAttributes, - /* reparse_tag = */ self.data.dwReserved0, - )) - } - - pub fn metadata(&self) -> io::Result<FileAttr> { - Ok(FileAttr { - attributes: self.data.dwFileAttributes, - creation_time: self.data.ftCreationTime, - last_access_time: self.data.ftLastAccessTime, - last_write_time: self.data.ftLastWriteTime, - file_size: ((self.data.nFileSizeHigh as u64) << 32) | (self.data.nFileSizeLow as u64), - reparse_tag: if self.data.dwFileAttributes & c::FILE_ATTRIBUTE_REPARSE_POINT != 0 { - // reserved unless this is a reparse point - self.data.dwReserved0 - } else { - 0 - }, - volume_serial_number: None, - number_of_links: None, - file_index: None, - }) - } -} - -impl OpenOptions { - pub fn new() -> OpenOptions { - OpenOptions { - // generic - read: false, - write: false, - append: false, - truncate: false, - create: false, - create_new: false, - // system-specific - custom_flags: 0, - access_mode: None, - share_mode: c::FILE_SHARE_READ | c::FILE_SHARE_WRITE | c::FILE_SHARE_DELETE, - attributes: 0, - security_qos_flags: 0, - security_attributes: 0, - } - } - - pub fn read(&mut self, read: bool) { - self.read = read; - } - pub fn write(&mut self, write: bool) { - self.write = write; - } - pub fn append(&mut self, append: bool) { - self.append = append; - } - pub fn truncate(&mut self, truncate: bool) { - self.truncate = truncate; - } - pub fn create(&mut self, create: bool) { - self.create = create; - } - pub fn create_new(&mut self, create_new: bool) { - self.create_new = create_new; - } - - pub fn custom_flags(&mut self, flags: u32) { - self.custom_flags = flags; - } - pub fn access_mode(&mut self, access_mode: u32) { - self.access_mode = Some(access_mode); - } - pub fn share_mode(&mut self, share_mode: u32) { - self.share_mode = share_mode; - } - pub fn attributes(&mut self, attrs: u32) { - self.attributes = attrs; - } - pub fn security_qos_flags(&mut self, flags: u32) { - // We have to set `SECURITY_SQOS_PRESENT` here, because one of the valid flags we can - // receive is `SECURITY_ANONYMOUS = 0x0`, which we can't check for later on. - self.security_qos_flags = flags | c::SECURITY_SQOS_PRESENT; - } - pub fn security_attributes(&mut self, attrs: c::LPSECURITY_ATTRIBUTES) { - self.security_attributes = attrs as usize; - } - - fn get_access_mode(&self) -> io::Result<c::DWORD> { - const ERROR_INVALID_PARAMETER: i32 = 87; - - match (self.read, self.write, self.append, self.access_mode) { - (.., Some(mode)) => Ok(mode), - (true, false, false, None) => Ok(c::GENERIC_READ), - (false, true, false, None) => Ok(c::GENERIC_WRITE), - (true, true, false, None) => Ok(c::GENERIC_READ | c::GENERIC_WRITE), - (false, _, true, None) => Ok(c::FILE_GENERIC_WRITE & !c::FILE_WRITE_DATA), - (true, _, true, None) => { - Ok(c::GENERIC_READ | (c::FILE_GENERIC_WRITE & !c::FILE_WRITE_DATA)) - } - (false, false, false, None) => Err(Error::from_raw_os_error(ERROR_INVALID_PARAMETER)), - } - } - - fn get_creation_mode(&self) -> io::Result<c::DWORD> { - const ERROR_INVALID_PARAMETER: i32 = 87; - - match (self.write, self.append) { - (true, false) => {} - (false, false) => { - if self.truncate || self.create || self.create_new { - return Err(Error::from_raw_os_error(ERROR_INVALID_PARAMETER)); - } - } - (_, true) => { - if self.truncate && !self.create_new { - return Err(Error::from_raw_os_error(ERROR_INVALID_PARAMETER)); - } - } - } - - Ok(match (self.create, self.truncate, self.create_new) { - (false, false, false) => c::OPEN_EXISTING, - (true, false, false) => c::OPEN_ALWAYS, - (false, true, false) => c::TRUNCATE_EXISTING, - (true, true, false) => c::CREATE_ALWAYS, - (_, _, true) => c::CREATE_NEW, - }) - } - - fn get_flags_and_attributes(&self) -> c::DWORD { - self.custom_flags - | self.attributes - | self.security_qos_flags - | if self.create_new { c::FILE_FLAG_OPEN_REPARSE_POINT } else { 0 } - } -} - -impl File { - pub fn open(path: &Path, opts: &OpenOptions) -> io::Result<File> { - let path = to_u16s(path)?; - let handle = unsafe { - c::CreateFileW( - path.as_ptr(), - opts.get_access_mode()?, - opts.share_mode, - opts.security_attributes as *mut _, - opts.get_creation_mode()?, - opts.get_flags_and_attributes(), - ptr::null_mut(), - ) - }; - if handle == c::INVALID_HANDLE_VALUE { - Err(Error::last_os_error()) - } else { - Ok(File { handle: Handle::new(handle) }) - } - } - - pub fn fsync(&self) -> io::Result<()> { - cvt(unsafe { c::FlushFileBuffers(self.handle.raw()) })?; - Ok(()) - } - - pub fn datasync(&self) -> io::Result<()> { - self.fsync() - } - - 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.raw(), - c::FileEndOfFileInfo, - &mut info as *mut _ as *mut _, - size as c::DWORD, - ) - })?; - Ok(()) - } - - #[cfg(not(target_vendor = "uwp"))] - pub fn file_attr(&self) -> io::Result<FileAttr> { - unsafe { - let mut info: c::BY_HANDLE_FILE_INFORMATION = mem::zeroed(); - cvt(c::GetFileInformationByHandle(self.handle.raw(), &mut info))?; - let mut reparse_tag = 0; - if info.dwFileAttributes & c::FILE_ATTRIBUTE_REPARSE_POINT != 0 { - let mut b = [0; c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE]; - if let Ok((_, buf)) = self.reparse_point(&mut b) { - reparse_tag = buf.ReparseTag; - } - } - Ok(FileAttr { - attributes: info.dwFileAttributes, - creation_time: info.ftCreationTime, - last_access_time: info.ftLastAccessTime, - last_write_time: info.ftLastWriteTime, - file_size: (info.nFileSizeLow as u64) | ((info.nFileSizeHigh as u64) << 32), - reparse_tag, - volume_serial_number: Some(info.dwVolumeSerialNumber), - number_of_links: Some(info.nNumberOfLinks), - file_index: Some( - (info.nFileIndexLow as u64) | ((info.nFileIndexHigh as u64) << 32), - ), - }) - } - } - - #[cfg(target_vendor = "uwp")] - pub fn file_attr(&self) -> io::Result<FileAttr> { - unsafe { - let mut info: c::FILE_BASIC_INFO = mem::zeroed(); - let size = mem::size_of_val(&info); - cvt(c::GetFileInformationByHandleEx( - self.handle.raw(), - c::FileBasicInfo, - &mut info as *mut _ as *mut libc::c_void, - size as c::DWORD, - ))?; - let mut attr = FileAttr { - attributes: info.FileAttributes, - creation_time: c::FILETIME { - dwLowDateTime: info.CreationTime as c::DWORD, - dwHighDateTime: (info.CreationTime >> 32) as c::DWORD, - }, - last_access_time: c::FILETIME { - dwLowDateTime: info.LastAccessTime as c::DWORD, - dwHighDateTime: (info.LastAccessTime >> 32) as c::DWORD, - }, - last_write_time: c::FILETIME { - dwLowDateTime: info.LastWriteTime as c::DWORD, - dwHighDateTime: (info.LastWriteTime >> 32) as c::DWORD, - }, - file_size: 0, - reparse_tag: 0, - volume_serial_number: None, - number_of_links: None, - file_index: None, - }; - let mut info: c::FILE_STANDARD_INFO = mem::zeroed(); - let size = mem::size_of_val(&info); - cvt(c::GetFileInformationByHandleEx( - self.handle.raw(), - c::FileStandardInfo, - &mut info as *mut _ as *mut libc::c_void, - size as c::DWORD, - ))?; - attr.file_size = info.AllocationSize as u64; - attr.number_of_links = Some(info.NumberOfLinks); - if attr.file_type().is_reparse_point() { - let mut b = [0; c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE]; - if let Ok((_, buf)) = self.reparse_point(&mut b) { - attr.reparse_tag = buf.ReparseTag; - } - } - Ok(attr) - } - } - - pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> { - self.handle.read(buf) - } - - pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> { - self.handle.read_vectored(bufs) - } - - #[inline] - pub fn is_read_vectored(&self) -> bool { - self.handle.is_read_vectored() - } - - pub fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> { - self.handle.read_at(buf, offset) - } - - pub fn write(&self, buf: &[u8]) -> io::Result<usize> { - self.handle.write(buf) - } - - pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result<usize> { - self.handle.write_vectored(bufs) - } - - #[inline] - pub fn is_write_vectored(&self) -> bool { - self.handle.is_write_vectored() - } - - pub fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize> { - self.handle.write_at(buf, offset) - } - - pub fn flush(&self) -> io::Result<()> { - Ok(()) - } - - pub fn seek(&self, pos: SeekFrom) -> io::Result<u64> { - let (whence, pos) = match pos { - // Casting to `i64` is fine, `SetFilePointerEx` reinterprets this - // integer as `u64`. - SeekFrom::Start(n) => (c::FILE_BEGIN, n as i64), - SeekFrom::End(n) => (c::FILE_END, n), - SeekFrom::Current(n) => (c::FILE_CURRENT, n), - }; - let pos = pos as c::LARGE_INTEGER; - let mut newpos = 0; - cvt(unsafe { c::SetFilePointerEx(self.handle.raw(), pos, &mut newpos, whence) })?; - Ok(newpos as u64) - } - - pub fn duplicate(&self) -> io::Result<File> { - Ok(File { handle: self.handle.duplicate(0, false, c::DUPLICATE_SAME_ACCESS)? }) - } - - pub fn handle(&self) -> &Handle { - &self.handle - } - - pub fn into_handle(self) -> Handle { - self.handle - } - - fn reparse_point<'a>( - &self, - space: &'a mut [u8; c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE], - ) -> io::Result<(c::DWORD, &'a c::REPARSE_DATA_BUFFER)> { - unsafe { - let mut bytes = 0; - cvt({ - c::DeviceIoControl( - self.handle.raw(), - c::FSCTL_GET_REPARSE_POINT, - ptr::null_mut(), - 0, - space.as_mut_ptr() as *mut _, - space.len() as c::DWORD, - &mut bytes, - ptr::null_mut(), - ) - })?; - Ok((bytes, &*(space.as_ptr() as *const c::REPARSE_DATA_BUFFER))) - } - } - - fn readlink(&self) -> io::Result<PathBuf> { - let mut space = [0u8; c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE]; - let (_bytes, buf) = self.reparse_point(&mut space)?; - unsafe { - let (path_buffer, subst_off, subst_len, relative) = match buf.ReparseTag { - c::IO_REPARSE_TAG_SYMLINK => { - let info: *const c::SYMBOLIC_LINK_REPARSE_BUFFER = - &buf.rest as *const _ as *const _; - ( - &(*info).PathBuffer as *const _ as *const u16, - (*info).SubstituteNameOffset / 2, - (*info).SubstituteNameLength / 2, - (*info).Flags & c::SYMLINK_FLAG_RELATIVE != 0, - ) - } - c::IO_REPARSE_TAG_MOUNT_POINT => { - let info: *const c::MOUNT_POINT_REPARSE_BUFFER = - &buf.rest as *const _ as *const _; - ( - &(*info).PathBuffer as *const _ as *const u16, - (*info).SubstituteNameOffset / 2, - (*info).SubstituteNameLength / 2, - false, - ) - } - _ => { - return Err(io::Error::new( - io::ErrorKind::Other, - "Unsupported reparse point type", - )); - } - }; - let subst_ptr = path_buffer.offset(subst_off as isize); - let mut subst = slice::from_raw_parts(subst_ptr, subst_len as usize); - // Absolute paths start with an NT internal namespace prefix `\??\` - // We should not let it leak through. - if !relative && subst.starts_with(&[92u16, 63u16, 63u16, 92u16]) { - subst = &subst[4..]; - } - Ok(PathBuf::from(OsString::from_wide(subst))) - } - } - - pub fn set_permissions(&self, perm: FilePermissions) -> io::Result<()> { - let mut 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.raw(), - c::FileBasicInfo, - &mut info as *mut _ as *mut _, - size as c::DWORD, - ) - })?; - Ok(()) - } -} - -impl FromInner<c::HANDLE> for File { - fn from_inner(handle: c::HANDLE) -> File { - File { handle: Handle::new(handle) } - } -} - -impl fmt::Debug for File { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - // FIXME(#24570): add more info here (e.g., mode) - let mut b = f.debug_struct("File"); - b.field("handle", &self.handle.raw()); - if let Ok(path) = get_path(&self) { - b.field("path", &path); - } - b.finish() - } -} - -impl FileAttr { - pub fn size(&self) -> u64 { - self.file_size - } - - pub fn perm(&self) -> FilePermissions { - FilePermissions { attrs: self.attributes } - } - - pub fn attrs(&self) -> u32 { - self.attributes - } - - pub fn file_type(&self) -> FileType { - FileType::new(self.attributes, self.reparse_tag) - } - - pub fn modified(&self) -> io::Result<SystemTime> { - Ok(SystemTime::from(self.last_write_time)) - } - - pub fn accessed(&self) -> io::Result<SystemTime> { - Ok(SystemTime::from(self.last_access_time)) - } - - pub fn created(&self) -> io::Result<SystemTime> { - Ok(SystemTime::from(self.creation_time)) - } - - pub fn modified_u64(&self) -> u64 { - to_u64(&self.last_write_time) - } - - pub fn accessed_u64(&self) -> u64 { - to_u64(&self.last_access_time) - } - - pub fn created_u64(&self) -> u64 { - to_u64(&self.creation_time) - } - - pub fn volume_serial_number(&self) -> Option<u32> { - self.volume_serial_number - } - - pub fn number_of_links(&self) -> Option<u32> { - self.number_of_links - } - - pub fn file_index(&self) -> Option<u64> { - self.file_index - } -} - -fn to_u64(ft: &c::FILETIME) -> u64 { - (ft.dwLowDateTime as u64) | ((ft.dwHighDateTime as u64) << 32) -} - -impl FilePermissions { - pub fn readonly(&self) -> bool { - self.attrs & c::FILE_ATTRIBUTE_READONLY != 0 - } - - pub fn set_readonly(&mut self, readonly: bool) { - if readonly { - self.attrs |= c::FILE_ATTRIBUTE_READONLY; - } else { - self.attrs &= !c::FILE_ATTRIBUTE_READONLY; - } - } -} - -impl FileType { - fn new(attrs: c::DWORD, reparse_tag: c::DWORD) -> FileType { - FileType { attributes: attrs, reparse_tag: reparse_tag } - } - pub fn is_dir(&self) -> bool { - !self.is_symlink() && self.is_directory() - } - pub fn is_file(&self) -> bool { - !self.is_symlink() && !self.is_directory() - } - pub fn is_symlink(&self) -> bool { - self.is_reparse_point() && self.is_reparse_tag_name_surrogate() - } - pub fn is_symlink_dir(&self) -> bool { - self.is_symlink() && self.is_directory() - } - pub fn is_symlink_file(&self) -> bool { - self.is_symlink() && !self.is_directory() - } - fn is_directory(&self) -> bool { - self.attributes & c::FILE_ATTRIBUTE_DIRECTORY != 0 - } - fn is_reparse_point(&self) -> bool { - self.attributes & c::FILE_ATTRIBUTE_REPARSE_POINT != 0 - } - fn is_reparse_tag_name_surrogate(&self) -> bool { - self.reparse_tag & 0x20000000 != 0 - } -} - -impl DirBuilder { - pub fn new() -> DirBuilder { - DirBuilder - } - - pub fn mkdir(&self, p: &Path) -> io::Result<()> { - let p = to_u16s(p)?; - cvt(unsafe { c::CreateDirectoryW(p.as_ptr(), ptr::null_mut()) })?; - Ok(()) - } -} - -pub fn readdir(p: &Path) -> io::Result<ReadDir> { - let root = p.to_path_buf(); - let star = p.join("*"); - let path = to_u16s(&star)?; - - unsafe { - let mut wfd = mem::zeroed(); - let find_handle = c::FindFirstFileW(path.as_ptr(), &mut wfd); - if find_handle != c::INVALID_HANDLE_VALUE { - Ok(ReadDir { - handle: FindNextFileHandle(find_handle), - root: Arc::new(root), - first: Some(wfd), - }) - } else { - Err(Error::last_os_error()) - } - } -} - -pub fn unlink(p: &Path) -> io::Result<()> { - let p_u16s = to_u16s(p)?; - cvt(unsafe { c::DeleteFileW(p_u16s.as_ptr()) })?; - Ok(()) -} - -pub fn rename(old: &Path, new: &Path) -> io::Result<()> { - let old = to_u16s(old)?; - let new = to_u16s(new)?; - cvt(unsafe { c::MoveFileExW(old.as_ptr(), new.as_ptr(), c::MOVEFILE_REPLACE_EXISTING) })?; - Ok(()) -} - -pub fn rmdir(p: &Path) -> io::Result<()> { - let p = to_u16s(p)?; - cvt(unsafe { c::RemoveDirectoryW(p.as_ptr()) })?; - Ok(()) -} - -pub fn remove_dir_all(path: &Path) -> io::Result<()> { - let filetype = lstat(path)?.file_type(); - if filetype.is_symlink() { - // On Windows symlinks to files and directories are removed differently. - // rmdir only deletes dir symlinks and junctions, not file symlinks. - rmdir(path) - } else { - remove_dir_all_recursive(path) - } -} - -fn remove_dir_all_recursive(path: &Path) -> io::Result<()> { - for child in readdir(path)? { - let child = child?; - let child_type = child.file_type()?; - if child_type.is_dir() { - remove_dir_all_recursive(&child.path())?; - } else if child_type.is_symlink_dir() { - rmdir(&child.path())?; - } else { - unlink(&child.path())?; - } - } - rmdir(path) -} - -pub fn readlink(path: &Path) -> io::Result<PathBuf> { - // Open the link with no access mode, instead of generic read. - // By default FILE_LIST_DIRECTORY is denied for the junction "C:\Documents and Settings", so - // this is needed for a common case. - let mut opts = OpenOptions::new(); - opts.access_mode(0); - opts.custom_flags(c::FILE_FLAG_OPEN_REPARSE_POINT | c::FILE_FLAG_BACKUP_SEMANTICS); - let file = File::open(&path, &opts)?; - file.readlink() -} - -pub fn symlink(src: &Path, dst: &Path) -> io::Result<()> { - symlink_inner(src, dst, false) -} - -pub fn symlink_inner(src: &Path, dst: &Path, dir: bool) -> io::Result<()> { - let src = to_u16s(src)?; - let dst = to_u16s(dst)?; - let flags = if dir { c::SYMBOLIC_LINK_FLAG_DIRECTORY } else { 0 }; - // Formerly, symlink creation required the SeCreateSymbolicLink privilege. For the Windows 10 - // Creators Update, Microsoft loosened this to allow unprivileged symlink creation if the - // computer is in Developer Mode, but SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE must be - // added to dwFlags to opt into this behaviour. - let result = cvt(unsafe { - c::CreateSymbolicLinkW( - dst.as_ptr(), - src.as_ptr(), - flags | c::SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE, - ) as c::BOOL - }); - if let Err(err) = result { - if err.raw_os_error() == Some(c::ERROR_INVALID_PARAMETER as i32) { - // Older Windows objects to SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE, - // so if we encounter ERROR_INVALID_PARAMETER, retry without that flag. - cvt(unsafe { c::CreateSymbolicLinkW(dst.as_ptr(), src.as_ptr(), flags) as c::BOOL })?; - } else { - return Err(err); - } - } - Ok(()) -} - -#[cfg(not(target_vendor = "uwp"))] -pub fn link(src: &Path, dst: &Path) -> io::Result<()> { - let src = to_u16s(src)?; - let dst = to_u16s(dst)?; - cvt(unsafe { c::CreateHardLinkW(dst.as_ptr(), src.as_ptr(), ptr::null_mut()) })?; - Ok(()) -} - -#[cfg(target_vendor = "uwp")] -pub fn link(_src: &Path, _dst: &Path) -> io::Result<()> { - return Err(io::Error::new(io::ErrorKind::Other, "hard link are not supported on UWP")); -} - -pub fn stat(path: &Path) -> io::Result<FileAttr> { - let mut opts = OpenOptions::new(); - // No read or write permissions are necessary - opts.access_mode(0); - // This flag is so we can open directories too - opts.custom_flags(c::FILE_FLAG_BACKUP_SEMANTICS); - let file = File::open(path, &opts)?; - file.file_attr() -} - -pub fn lstat(path: &Path) -> io::Result<FileAttr> { - let mut opts = OpenOptions::new(); - // No read or write permissions are necessary - opts.access_mode(0); - opts.custom_flags(c::FILE_FLAG_BACKUP_SEMANTICS | c::FILE_FLAG_OPEN_REPARSE_POINT); - let file = File::open(path, &opts)?; - file.file_attr() -} - -pub fn set_perm(p: &Path, perm: FilePermissions) -> io::Result<()> { - let p = to_u16s(p)?; - unsafe { - cvt(c::SetFileAttributesW(p.as_ptr(), perm.attrs))?; - Ok(()) - } -} - -fn get_path(f: &File) -> io::Result<PathBuf> { - super::fill_utf16_buf( - |buf, sz| unsafe { - c::GetFinalPathNameByHandleW(f.handle.raw(), buf, sz, c::VOLUME_NAME_DOS) - }, - |buf| PathBuf::from(OsString::from_wide(buf)), - ) -} - -pub fn canonicalize(p: &Path) -> io::Result<PathBuf> { - let mut opts = OpenOptions::new(); - // No read or write permissions are necessary - opts.access_mode(0); - // This flag is so we can open directories too - opts.custom_flags(c::FILE_FLAG_BACKUP_SEMANTICS); - let f = File::open(p, &opts)?; - get_path(&f) -} - -pub fn copy(from: &Path, to: &Path) -> io::Result<u64> { - unsafe extern "system" fn callback( - _TotalFileSize: c::LARGE_INTEGER, - _TotalBytesTransferred: c::LARGE_INTEGER, - _StreamSize: c::LARGE_INTEGER, - StreamBytesTransferred: c::LARGE_INTEGER, - dwStreamNumber: c::DWORD, - _dwCallbackReason: c::DWORD, - _hSourceFile: c::HANDLE, - _hDestinationFile: c::HANDLE, - lpData: c::LPVOID, - ) -> c::DWORD { - if dwStreamNumber == 1 { - *(lpData as *mut i64) = StreamBytesTransferred; - } - c::PROGRESS_CONTINUE - } - let pfrom = to_u16s(from)?; - let pto = to_u16s(to)?; - let mut size = 0i64; - cvt(unsafe { - c::CopyFileExW( - pfrom.as_ptr(), - pto.as_ptr(), - Some(callback), - &mut size as *mut _ as *mut _, - ptr::null_mut(), - 0, - ) - })?; - Ok(size as u64) -} - -#[allow(dead_code)] -pub fn symlink_junction<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dst: Q) -> io::Result<()> { - symlink_junction_inner(src.as_ref(), dst.as_ref()) -} - -// Creating a directory junction on windows involves dealing with reparse -// points and the DeviceIoControl function, and this code is a skeleton of -// what can be found here: -// -// http://www.flexhex.com/docs/articles/hard-links.phtml -#[allow(dead_code)] -fn symlink_junction_inner(target: &Path, junction: &Path) -> io::Result<()> { - let d = DirBuilder::new(); - d.mkdir(&junction)?; - - let mut opts = OpenOptions::new(); - opts.write(true); - opts.custom_flags(c::FILE_FLAG_OPEN_REPARSE_POINT | c::FILE_FLAG_BACKUP_SEMANTICS); - let f = File::open(junction, &opts)?; - let h = f.handle().raw(); - - unsafe { - let mut data = [0u8; c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE]; - let db = data.as_mut_ptr() as *mut c::REPARSE_MOUNTPOINT_DATA_BUFFER; - let buf = &mut (*db).ReparseTarget as *mut c::WCHAR; - let mut i = 0; - // FIXME: this conversion is very hacky - let v = br"\??\"; - let v = v.iter().map(|x| *x as u16); - for c in v.chain(target.as_os_str().encode_wide()) { - *buf.offset(i) = c; - i += 1; - } - *buf.offset(i) = 0; - i += 1; - (*db).ReparseTag = c::IO_REPARSE_TAG_MOUNT_POINT; - (*db).ReparseTargetMaximumLength = (i * 2) as c::WORD; - (*db).ReparseTargetLength = ((i - 1) * 2) as c::WORD; - (*db).ReparseDataLength = (*db).ReparseTargetLength as c::DWORD + 12; - - let mut ret = 0; - cvt(c::DeviceIoControl( - h as *mut _, - c::FSCTL_SET_REPARSE_POINT, - data.as_ptr() as *mut _, - (*db).ReparseDataLength + 8, - ptr::null_mut(), - 0, - &mut ret, - ptr::null_mut(), - )) - .map(drop) - } -} diff --git a/src/libstd/sys/windows/handle.rs b/src/libstd/sys/windows/handle.rs deleted file mode 100644 index 0d4baa3b340..00000000000 --- a/src/libstd/sys/windows/handle.rs +++ /dev/null @@ -1,233 +0,0 @@ -#![unstable(issue = "none", feature = "windows_handle")] - -use crate::cmp; -use crate::io::{self, ErrorKind, IoSlice, IoSliceMut, Read}; -use crate::mem; -use crate::ops::Deref; -use crate::ptr; -use crate::sys::c; -use crate::sys::cvt; - -/// An owned container for `HANDLE` object, closing them on Drop. -/// -/// All methods are inherited through a `Deref` impl to `RawHandle` -pub struct Handle(RawHandle); - -/// A wrapper type for `HANDLE` objects to give them proper Send/Sync inference -/// as well as Rust-y methods. -/// -/// This does **not** drop the handle when it goes out of scope, use `Handle` -/// instead for that. -#[derive(Copy, Clone)] -pub struct RawHandle(c::HANDLE); - -unsafe impl Send for RawHandle {} -unsafe impl Sync for RawHandle {} - -impl Handle { - pub fn new(handle: c::HANDLE) -> Handle { - Handle(RawHandle::new(handle)) - } - - pub fn new_event(manual: bool, init: bool) -> io::Result<Handle> { - unsafe { - let event = - c::CreateEventW(ptr::null_mut(), manual as c::BOOL, init as c::BOOL, ptr::null()); - if event.is_null() { Err(io::Error::last_os_error()) } else { Ok(Handle::new(event)) } - } - } - - pub fn into_raw(self) -> c::HANDLE { - let ret = self.raw(); - mem::forget(self); - ret - } -} - -impl Deref for Handle { - type Target = RawHandle; - fn deref(&self) -> &RawHandle { - &self.0 - } -} - -impl Drop for Handle { - fn drop(&mut self) { - unsafe { - let _ = c::CloseHandle(self.raw()); - } - } -} - -impl RawHandle { - pub fn new(handle: c::HANDLE) -> RawHandle { - RawHandle(handle) - } - - pub fn raw(&self) -> c::HANDLE { - self.0 - } - - pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> { - let mut read = 0; - let len = cmp::min(buf.len(), <c::DWORD>::MAX as usize) as c::DWORD; - let res = cvt(unsafe { - c::ReadFile(self.0, buf.as_mut_ptr() as c::LPVOID, len, &mut read, ptr::null_mut()) - }); - - match res { - Ok(_) => Ok(read as usize), - - // The special treatment of BrokenPipe is to deal with Windows - // pipe semantics, which yields this error when *reading* from - // a pipe after the other end has closed; we interpret that as - // EOF on the pipe. - Err(ref e) if e.kind() == ErrorKind::BrokenPipe => Ok(0), - - Err(e) => Err(e), - } - } - - pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> { - crate::io::default_read_vectored(|buf| self.read(buf), bufs) - } - - #[inline] - pub fn is_read_vectored(&self) -> bool { - false - } - - pub fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> { - let mut read = 0; - let len = cmp::min(buf.len(), <c::DWORD>::MAX as usize) as c::DWORD; - let res = unsafe { - let mut overlapped: c::OVERLAPPED = mem::zeroed(); - overlapped.Offset = offset as u32; - overlapped.OffsetHigh = (offset >> 32) as u32; - cvt(c::ReadFile(self.0, buf.as_mut_ptr() as c::LPVOID, len, &mut read, &mut overlapped)) - }; - match res { - Ok(_) => Ok(read as usize), - Err(ref e) if e.raw_os_error() == Some(c::ERROR_HANDLE_EOF as i32) => Ok(0), - Err(e) => Err(e), - } - } - - pub unsafe fn read_overlapped( - &self, - buf: &mut [u8], - overlapped: *mut c::OVERLAPPED, - ) -> io::Result<Option<usize>> { - let len = cmp::min(buf.len(), <c::DWORD>::MAX as usize) as c::DWORD; - let mut amt = 0; - let res = cvt(c::ReadFile(self.0, buf.as_ptr() as c::LPVOID, len, &mut amt, overlapped)); - match res { - Ok(_) => Ok(Some(amt as usize)), - Err(e) => { - if e.raw_os_error() == Some(c::ERROR_IO_PENDING as i32) { - Ok(None) - } else if e.raw_os_error() == Some(c::ERROR_BROKEN_PIPE as i32) { - Ok(Some(0)) - } else { - Err(e) - } - } - } - } - - pub fn overlapped_result( - &self, - overlapped: *mut c::OVERLAPPED, - wait: bool, - ) -> io::Result<usize> { - unsafe { - let mut bytes = 0; - let wait = if wait { c::TRUE } else { c::FALSE }; - let res = cvt(c::GetOverlappedResult(self.raw(), overlapped, &mut bytes, wait)); - match res { - Ok(_) => Ok(bytes as usize), - Err(e) => { - if e.raw_os_error() == Some(c::ERROR_HANDLE_EOF as i32) - || e.raw_os_error() == Some(c::ERROR_BROKEN_PIPE as i32) - { - Ok(0) - } else { - Err(e) - } - } - } - } - } - - pub fn cancel_io(&self) -> io::Result<()> { - unsafe { cvt(c::CancelIo(self.raw())).map(drop) } - } - - pub fn write(&self, buf: &[u8]) -> io::Result<usize> { - let mut amt = 0; - let len = cmp::min(buf.len(), <c::DWORD>::MAX as usize) as c::DWORD; - cvt(unsafe { - c::WriteFile(self.0, buf.as_ptr() as c::LPVOID, len, &mut amt, ptr::null_mut()) - })?; - Ok(amt as usize) - } - - pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result<usize> { - crate::io::default_write_vectored(|buf| self.write(buf), bufs) - } - - #[inline] - pub fn is_write_vectored(&self) -> bool { - false - } - - pub fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize> { - let mut written = 0; - let len = cmp::min(buf.len(), <c::DWORD>::MAX as usize) as c::DWORD; - unsafe { - let mut overlapped: c::OVERLAPPED = mem::zeroed(); - overlapped.Offset = offset as u32; - overlapped.OffsetHigh = (offset >> 32) as u32; - cvt(c::WriteFile( - self.0, - buf.as_ptr() as c::LPVOID, - len, - &mut written, - &mut overlapped, - ))?; - } - Ok(written as usize) - } - - pub fn duplicate( - &self, - access: c::DWORD, - inherit: bool, - options: c::DWORD, - ) -> io::Result<Handle> { - let mut ret = 0 as c::HANDLE; - cvt(unsafe { - let cur_proc = c::GetCurrentProcess(); - c::DuplicateHandle( - cur_proc, - self.0, - cur_proc, - &mut ret, - access, - inherit as c::BOOL, - options, - ) - })?; - Ok(Handle::new(ret)) - } -} - -impl<'a> Read for &'a RawHandle { - fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { - (**self).read(buf) - } - - fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> { - (**self).read_vectored(bufs) - } -} diff --git a/src/libstd/sys/windows/io.rs b/src/libstd/sys/windows/io.rs deleted file mode 100644 index fb06df1f80c..00000000000 --- a/src/libstd/sys/windows/io.rs +++ /dev/null @@ -1,80 +0,0 @@ -use crate::marker::PhantomData; -use crate::slice; -use crate::sys::c; - -#[derive(Copy, Clone)] -#[repr(transparent)] -pub struct IoSlice<'a> { - vec: c::WSABUF, - _p: PhantomData<&'a [u8]>, -} - -impl<'a> IoSlice<'a> { - #[inline] - pub fn new(buf: &'a [u8]) -> IoSlice<'a> { - assert!(buf.len() <= c::ULONG::MAX as usize); - IoSlice { - vec: c::WSABUF { - len: buf.len() as c::ULONG, - buf: buf.as_ptr() as *mut u8 as *mut c::CHAR, - }, - _p: PhantomData, - } - } - - #[inline] - pub fn advance(&mut self, n: usize) { - if (self.vec.len as usize) < n { - panic!("advancing IoSlice beyond its length"); - } - - unsafe { - self.vec.len -= n as c::ULONG; - self.vec.buf = self.vec.buf.add(n); - } - } - - #[inline] - pub fn as_slice(&self) -> &[u8] { - unsafe { slice::from_raw_parts(self.vec.buf as *mut u8, self.vec.len as usize) } - } -} - -#[repr(transparent)] -pub struct IoSliceMut<'a> { - vec: c::WSABUF, - _p: PhantomData<&'a mut [u8]>, -} - -impl<'a> IoSliceMut<'a> { - #[inline] - pub fn new(buf: &'a mut [u8]) -> IoSliceMut<'a> { - assert!(buf.len() <= c::ULONG::MAX as usize); - IoSliceMut { - vec: c::WSABUF { len: buf.len() as c::ULONG, buf: buf.as_mut_ptr() as *mut c::CHAR }, - _p: PhantomData, - } - } - - #[inline] - pub fn advance(&mut self, n: usize) { - if (self.vec.len as usize) < n { - panic!("advancing IoSliceMut beyond its length"); - } - - unsafe { - self.vec.len -= n as c::ULONG; - self.vec.buf = self.vec.buf.add(n); - } - } - - #[inline] - pub fn as_slice(&self) -> &[u8] { - unsafe { slice::from_raw_parts(self.vec.buf as *mut u8, self.vec.len as usize) } - } - - #[inline] - pub fn as_mut_slice(&mut self) -> &mut [u8] { - unsafe { slice::from_raw_parts_mut(self.vec.buf as *mut u8, self.vec.len as usize) } - } -} diff --git a/src/libstd/sys/windows/memchr.rs b/src/libstd/sys/windows/memchr.rs deleted file mode 100644 index b9e5bcc1b4b..00000000000 --- a/src/libstd/sys/windows/memchr.rs +++ /dev/null @@ -1,5 +0,0 @@ -// Original implementation taken from rust-memchr. -// Copyright 2015 Andrew Gallant, bluss and Nicolas Koch - -// Fallback memchr is fastest on Windows. -pub use core::slice::memchr::{memchr, memrchr}; diff --git a/src/libstd/sys/windows/mod.rs b/src/libstd/sys/windows/mod.rs deleted file mode 100644 index 9a52371280e..00000000000 --- a/src/libstd/sys/windows/mod.rs +++ /dev/null @@ -1,334 +0,0 @@ -#![allow(missing_docs, nonstandard_style)] - -use crate::ffi::{OsStr, OsString}; -use crate::io::ErrorKind; -use crate::os::windows::ffi::{OsStrExt, OsStringExt}; -use crate::path::PathBuf; -use crate::ptr; -use crate::time::Duration; - -pub use self::rand::hashmap_random_keys; -pub use libc::strlen; - -#[macro_use] -pub mod compat; - -pub mod alloc; -pub mod args; -pub mod c; -pub mod cmath; -pub mod condvar; -pub mod env; -pub mod ext; -pub mod fs; -pub mod handle; -pub mod io; -pub mod memchr; -pub mod mutex; -pub mod net; -pub mod os; -pub mod os_str; -pub mod path; -pub mod pipe; -pub mod process; -pub mod rand; -pub mod rwlock; -pub mod thread; -pub mod thread_local_dtor; -pub mod thread_local_key; -pub mod time; -cfg_if::cfg_if! { - if #[cfg(not(target_vendor = "uwp"))] { - pub mod stdio; - pub mod stack_overflow; - } else { - pub mod stdio_uwp; - pub mod stack_overflow_uwp; - pub use self::stdio_uwp as stdio; - pub use self::stack_overflow_uwp as stack_overflow; - } -} - -#[cfg(not(test))] -pub fn init() {} - -pub fn decode_error_kind(errno: i32) -> ErrorKind { - match errno as c::DWORD { - c::ERROR_ACCESS_DENIED => return ErrorKind::PermissionDenied, - c::ERROR_ALREADY_EXISTS => return ErrorKind::AlreadyExists, - c::ERROR_FILE_EXISTS => return ErrorKind::AlreadyExists, - c::ERROR_BROKEN_PIPE => return ErrorKind::BrokenPipe, - c::ERROR_FILE_NOT_FOUND => return ErrorKind::NotFound, - c::ERROR_PATH_NOT_FOUND => return ErrorKind::NotFound, - c::ERROR_NO_DATA => return ErrorKind::BrokenPipe, - c::ERROR_INVALID_PARAMETER => return ErrorKind::InvalidInput, - c::ERROR_SEM_TIMEOUT - | c::WAIT_TIMEOUT - | c::ERROR_DRIVER_CANCEL_TIMEOUT - | c::ERROR_OPERATION_ABORTED - | c::ERROR_SERVICE_REQUEST_TIMEOUT - | c::ERROR_COUNTER_TIMEOUT - | c::ERROR_TIMEOUT - | c::ERROR_RESOURCE_CALL_TIMED_OUT - | c::ERROR_CTX_MODEM_RESPONSE_TIMEOUT - | c::ERROR_CTX_CLIENT_QUERY_TIMEOUT - | c::FRS_ERR_SYSVOL_POPULATE_TIMEOUT - | c::ERROR_DS_TIMELIMIT_EXCEEDED - | c::DNS_ERROR_RECORD_TIMED_OUT - | c::ERROR_IPSEC_IKE_TIMED_OUT - | c::ERROR_RUNLEVEL_SWITCH_TIMEOUT - | c::ERROR_RUNLEVEL_SWITCH_AGENT_TIMEOUT => return ErrorKind::TimedOut, - _ => {} - } - - match errno { - c::WSAEACCES => ErrorKind::PermissionDenied, - c::WSAEADDRINUSE => ErrorKind::AddrInUse, - c::WSAEADDRNOTAVAIL => ErrorKind::AddrNotAvailable, - c::WSAECONNABORTED => ErrorKind::ConnectionAborted, - c::WSAECONNREFUSED => ErrorKind::ConnectionRefused, - c::WSAECONNRESET => ErrorKind::ConnectionReset, - c::WSAEINVAL => ErrorKind::InvalidInput, - c::WSAENOTCONN => ErrorKind::NotConnected, - c::WSAEWOULDBLOCK => ErrorKind::WouldBlock, - c::WSAETIMEDOUT => ErrorKind::TimedOut, - - _ => ErrorKind::Other, - } -} - -pub fn unrolled_find_u16s(needle: u16, haystack: &[u16]) -> Option<usize> { - let ptr = haystack.as_ptr(); - let mut len = haystack.len(); - let mut start = &haystack[..]; - - // For performance reasons unfold the loop eight times. - while len >= 8 { - if start[0] == needle { - return Some((start.as_ptr() as usize - ptr as usize) / 2); - } - if start[1] == needle { - return Some((start[1..].as_ptr() as usize - ptr as usize) / 2); - } - if start[2] == needle { - return Some((start[2..].as_ptr() as usize - ptr as usize) / 2); - } - if start[3] == needle { - return Some((start[3..].as_ptr() as usize - ptr as usize) / 2); - } - if start[4] == needle { - return Some((start[4..].as_ptr() as usize - ptr as usize) / 2); - } - if start[5] == needle { - return Some((start[5..].as_ptr() as usize - ptr as usize) / 2); - } - if start[6] == needle { - return Some((start[6..].as_ptr() as usize - ptr as usize) / 2); - } - if start[7] == needle { - return Some((start[7..].as_ptr() as usize - ptr as usize) / 2); - } - - start = &start[8..]; - len -= 8; - } - - for (i, c) in start.iter().enumerate() { - if *c == needle { - return Some((start.as_ptr() as usize - ptr as usize) / 2 + i); - } - } - None -} - -pub fn to_u16s<S: AsRef<OsStr>>(s: S) -> crate::io::Result<Vec<u16>> { - fn inner(s: &OsStr) -> crate::io::Result<Vec<u16>> { - let mut maybe_result: Vec<u16> = s.encode_wide().collect(); - if unrolled_find_u16s(0, &maybe_result).is_some() { - return Err(crate::io::Error::new( - ErrorKind::InvalidInput, - "strings passed to WinAPI cannot contain NULs", - )); - } - maybe_result.push(0); - Ok(maybe_result) - } - inner(s.as_ref()) -} - -// Many Windows APIs follow a pattern of where we hand a buffer and then they -// will report back to us how large the buffer should be or how many bytes -// currently reside in the buffer. This function is an abstraction over these -// functions by making them easier to call. -// -// The first callback, `f1`, is yielded a (pointer, len) pair which can be -// passed to a syscall. The `ptr` is valid for `len` items (u16 in this case). -// The closure is expected to return what the syscall returns which will be -// interpreted by this function to determine if the syscall needs to be invoked -// again (with more buffer space). -// -// Once the syscall has completed (errors bail out early) the second closure is -// yielded the data which has been read from the syscall. The return value -// from this closure is then the return value of the function. -fn fill_utf16_buf<F1, F2, T>(mut f1: F1, f2: F2) -> crate::io::Result<T> -where - F1: FnMut(*mut u16, c::DWORD) -> c::DWORD, - F2: FnOnce(&[u16]) -> T, -{ - // Start off with a stack buf but then spill over to the heap if we end up - // needing more space. - let mut stack_buf = [0u16; 512]; - let mut heap_buf = Vec::new(); - unsafe { - let mut n = stack_buf.len(); - loop { - let buf = if n <= stack_buf.len() { - &mut stack_buf[..] - } else { - let extra = n - heap_buf.len(); - heap_buf.reserve(extra); - heap_buf.set_len(n); - &mut heap_buf[..] - }; - - // This function is typically called on windows API functions which - // will return the correct length of the string, but these functions - // also return the `0` on error. In some cases, however, the - // returned "correct length" may actually be 0! - // - // To handle this case we call `SetLastError` to reset it to 0 and - // then check it again if we get the "0 error value". If the "last - // error" is still 0 then we interpret it as a 0 length buffer and - // not an actual error. - c::SetLastError(0); - let k = match f1(buf.as_mut_ptr(), n as c::DWORD) { - 0 if c::GetLastError() == 0 => 0, - 0 => return Err(crate::io::Error::last_os_error()), - n => n, - } as usize; - if k == n && c::GetLastError() == c::ERROR_INSUFFICIENT_BUFFER { - n *= 2; - } else if k >= n { - n = k; - } else { - return Ok(f2(&buf[..k])); - } - } - } -} - -fn os2path(s: &[u16]) -> PathBuf { - PathBuf::from(OsString::from_wide(s)) -} - -#[allow(dead_code)] // Only used in backtrace::gnu::get_executable_filename() -fn wide_char_to_multi_byte( - code_page: u32, - flags: u32, - s: &[u16], - no_default_char: bool, -) -> crate::io::Result<Vec<i8>> { - unsafe { - let mut size = c::WideCharToMultiByte( - code_page, - flags, - s.as_ptr(), - s.len() as i32, - ptr::null_mut(), - 0, - ptr::null(), - ptr::null_mut(), - ); - if size == 0 { - return Err(crate::io::Error::last_os_error()); - } - - let mut buf = Vec::with_capacity(size as usize); - buf.set_len(size as usize); - - let mut used_default_char = c::FALSE; - size = c::WideCharToMultiByte( - code_page, - flags, - s.as_ptr(), - s.len() as i32, - buf.as_mut_ptr(), - buf.len() as i32, - ptr::null(), - if no_default_char { &mut used_default_char } else { ptr::null_mut() }, - ); - if size == 0 { - return Err(crate::io::Error::last_os_error()); - } - if no_default_char && used_default_char == c::TRUE { - return Err(crate::io::Error::new( - crate::io::ErrorKind::InvalidData, - "string cannot be converted to requested code page", - )); - } - - buf.set_len(size as usize); - - Ok(buf) - } -} - -pub fn truncate_utf16_at_nul(v: &[u16]) -> &[u16] { - match unrolled_find_u16s(0, v) { - // don't include the 0 - Some(i) => &v[..i], - None => v, - } -} - -pub trait IsZero { - fn is_zero(&self) -> bool; -} - -macro_rules! impl_is_zero { - ($($t:ident)*) => ($(impl IsZero for $t { - fn is_zero(&self) -> bool { - *self == 0 - } - })*) -} - -impl_is_zero! { i8 i16 i32 i64 isize u8 u16 u32 u64 usize } - -pub fn cvt<I: IsZero>(i: I) -> crate::io::Result<I> { - if i.is_zero() { Err(crate::io::Error::last_os_error()) } else { Ok(i) } -} - -pub fn dur2timeout(dur: Duration) -> c::DWORD { - // Note that a duration is a (u64, u32) (seconds, nanoseconds) pair, and the - // timeouts in windows APIs are typically u32 milliseconds. To translate, we - // have two pieces to take care of: - // - // * Nanosecond precision is rounded up - // * Greater than u32::MAX milliseconds (50 days) is rounded up to INFINITE - // (never time out). - dur.as_secs() - .checked_mul(1000) - .and_then(|ms| ms.checked_add((dur.subsec_nanos() as u64) / 1_000_000)) - .and_then(|ms| ms.checked_add(if dur.subsec_nanos() % 1_000_000 > 0 { 1 } else { 0 })) - .map(|ms| if ms > <c::DWORD>::MAX as u64 { c::INFINITE } else { ms as c::DWORD }) - .unwrap_or(c::INFINITE) -} - -// On Windows, use the processor-specific __fastfail mechanism. In Windows 8 -// and later, this will terminate the process immediately without running any -// in-process exception handlers. In earlier versions of Windows, this -// sequence of instructions will be treated as an access violation, -// terminating the process but without necessarily bypassing all exception -// handlers. -// -// https://docs.microsoft.com/en-us/cpp/intrinsics/fastfail -#[allow(unreachable_code)] -pub fn abort_internal() -> ! { - #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] - unsafe { - llvm_asm!("int $$0x29" :: "{ecx}"(7) ::: volatile); // 7 is FAST_FAIL_FATAL_APP_EXIT - crate::intrinsics::unreachable(); - } - crate::intrinsics::abort(); -} diff --git a/src/libstd/sys/windows/mutex.rs b/src/libstd/sys/windows/mutex.rs deleted file mode 100644 index 63dfc640908..00000000000 --- a/src/libstd/sys/windows/mutex.rs +++ /dev/null @@ -1,184 +0,0 @@ -//! System Mutexes -//! -//! The Windows implementation of mutexes is a little odd and it may not be -//! immediately obvious what's going on. The primary oddness is that SRWLock is -//! used instead of CriticalSection, and this is done because: -//! -//! 1. SRWLock is several times faster than CriticalSection according to -//! benchmarks performed on both Windows 8 and Windows 7. -//! -//! 2. CriticalSection allows recursive locking while SRWLock deadlocks. The -//! Unix implementation deadlocks so consistency is preferred. See #19962 for -//! more details. -//! -//! 3. While CriticalSection is fair and SRWLock is not, the current Rust policy -//! is that there are no guarantees of fairness. -//! -//! The downside of this approach, however, is that SRWLock is not available on -//! Windows XP, so we continue to have a fallback implementation where -//! CriticalSection is used and we keep track of who's holding the mutex to -//! detect recursive locks. - -use crate::cell::UnsafeCell; -use crate::mem::{self, MaybeUninit}; -use crate::sync::atomic::{AtomicUsize, Ordering}; -use crate::sys::c; -use crate::sys::compat; - -pub struct Mutex { - lock: AtomicUsize, - held: UnsafeCell<bool>, -} - -unsafe impl Send for Mutex {} -unsafe impl Sync for Mutex {} - -#[derive(Clone, Copy)] -enum Kind { - SRWLock = 1, - CriticalSection = 2, -} - -#[inline] -pub unsafe fn raw(m: &Mutex) -> c::PSRWLOCK { - debug_assert!(mem::size_of::<c::SRWLOCK>() <= mem::size_of_val(&m.lock)); - &m.lock as *const _ as *mut _ -} - -impl Mutex { - pub const fn new() -> Mutex { - Mutex { - // This works because SRWLOCK_INIT is 0 (wrapped in a struct), so we are also properly - // initializing an SRWLOCK here. - lock: AtomicUsize::new(0), - held: UnsafeCell::new(false), - } - } - #[inline] - pub unsafe fn init(&mut self) {} - pub unsafe fn lock(&self) { - match kind() { - Kind::SRWLock => c::AcquireSRWLockExclusive(raw(self)), - Kind::CriticalSection => { - let re = self.remutex(); - (*re).lock(); - if !self.flag_locked() { - (*re).unlock(); - panic!("cannot recursively lock a mutex"); - } - } - } - } - pub unsafe fn try_lock(&self) -> bool { - match kind() { - Kind::SRWLock => c::TryAcquireSRWLockExclusive(raw(self)) != 0, - Kind::CriticalSection => { - let re = self.remutex(); - if !(*re).try_lock() { - false - } else if self.flag_locked() { - true - } else { - (*re).unlock(); - false - } - } - } - } - pub unsafe fn unlock(&self) { - *self.held.get() = false; - match kind() { - Kind::SRWLock => c::ReleaseSRWLockExclusive(raw(self)), - Kind::CriticalSection => (*self.remutex()).unlock(), - } - } - pub unsafe fn destroy(&self) { - match kind() { - Kind::SRWLock => {} - Kind::CriticalSection => match self.lock.load(Ordering::SeqCst) { - 0 => {} - n => { - Box::from_raw(n as *mut ReentrantMutex).destroy(); - } - }, - } - } - - unsafe fn remutex(&self) -> *mut ReentrantMutex { - match self.lock.load(Ordering::SeqCst) { - 0 => {} - n => return n as *mut _, - } - let re = box ReentrantMutex::uninitialized(); - re.init(); - let re = Box::into_raw(re); - match self.lock.compare_and_swap(0, re as usize, Ordering::SeqCst) { - 0 => re, - n => { - Box::from_raw(re).destroy(); - n as *mut _ - } - } - } - - unsafe fn flag_locked(&self) -> bool { - if *self.held.get() { - false - } else { - *self.held.get() = true; - true - } - } -} - -fn kind() -> Kind { - static KIND: AtomicUsize = AtomicUsize::new(0); - - let val = KIND.load(Ordering::SeqCst); - if val == Kind::SRWLock as usize { - return Kind::SRWLock; - } else if val == Kind::CriticalSection as usize { - return Kind::CriticalSection; - } - - let ret = match compat::lookup("kernel32", "AcquireSRWLockExclusive") { - None => Kind::CriticalSection, - Some(..) => Kind::SRWLock, - }; - KIND.store(ret as usize, Ordering::SeqCst); - ret -} - -pub struct ReentrantMutex { - inner: UnsafeCell<MaybeUninit<c::CRITICAL_SECTION>>, -} - -unsafe impl Send for ReentrantMutex {} -unsafe impl Sync for ReentrantMutex {} - -impl ReentrantMutex { - pub const fn uninitialized() -> ReentrantMutex { - ReentrantMutex { inner: UnsafeCell::new(MaybeUninit::uninit()) } - } - - pub unsafe fn init(&self) { - c::InitializeCriticalSection((&mut *self.inner.get()).as_mut_ptr()); - } - - pub unsafe fn lock(&self) { - c::EnterCriticalSection((&mut *self.inner.get()).as_mut_ptr()); - } - - #[inline] - pub unsafe fn try_lock(&self) -> bool { - c::TryEnterCriticalSection((&mut *self.inner.get()).as_mut_ptr()) != 0 - } - - pub unsafe fn unlock(&self) { - c::LeaveCriticalSection((&mut *self.inner.get()).as_mut_ptr()); - } - - pub unsafe fn destroy(&self) { - c::DeleteCriticalSection((&mut *self.inner.get()).as_mut_ptr()); - } -} diff --git a/src/libstd/sys/windows/net.rs b/src/libstd/sys/windows/net.rs deleted file mode 100644 index 9e74454bc23..00000000000 --- a/src/libstd/sys/windows/net.rs +++ /dev/null @@ -1,438 +0,0 @@ -#![unstable(issue = "none", feature = "windows_net")] - -use crate::cmp; -use crate::io::{self, IoSlice, IoSliceMut, Read}; -use crate::mem; -use crate::net::{Shutdown, SocketAddr}; -use crate::ptr; -use crate::sync::Once; -use crate::sys; -use crate::sys::c; -use crate::sys_common::net; -use crate::sys_common::{self, AsInner, FromInner, IntoInner}; -use crate::time::Duration; - -use libc::{c_int, c_long, c_ulong, c_void}; - -pub type wrlen_t = i32; - -pub mod netc { - pub use crate::sys::c::ADDRESS_FAMILY as sa_family_t; - pub use crate::sys::c::ADDRINFOA as addrinfo; - pub use crate::sys::c::SOCKADDR as sockaddr; - pub use crate::sys::c::SOCKADDR_STORAGE_LH as sockaddr_storage; - pub use crate::sys::c::*; -} - -pub struct Socket(c::SOCKET); - -/// Checks whether the Windows socket interface has been started already, and -/// if not, starts it. -pub fn init() { - static START: Once = Once::new(); - - START.call_once(|| unsafe { - let mut data: c::WSADATA = mem::zeroed(); - let ret = c::WSAStartup( - 0x202, // version 2.2 - &mut data, - ); - assert_eq!(ret, 0); - - let _ = sys_common::at_exit(|| { - c::WSACleanup(); - }); - }); -} - -/// Returns the last error from the Windows socket interface. -fn last_error() -> io::Error { - io::Error::from_raw_os_error(unsafe { c::WSAGetLastError() }) -} - -#[doc(hidden)] -pub trait IsMinusOne { - fn is_minus_one(&self) -> bool; -} - -macro_rules! impl_is_minus_one { - ($($t:ident)*) => ($(impl IsMinusOne for $t { - fn is_minus_one(&self) -> bool { - *self == -1 - } - })*) -} - -impl_is_minus_one! { i8 i16 i32 i64 isize } - -/// Checks if the signed integer is the Windows constant `SOCKET_ERROR` (-1) -/// and if so, returns the last error from the Windows socket interface. This -/// function must be called before another call to the socket API is made. -pub fn cvt<T: IsMinusOne>(t: T) -> io::Result<T> { - if t.is_minus_one() { Err(last_error()) } else { Ok(t) } -} - -/// A variant of `cvt` for `getaddrinfo` which return 0 for a success. -pub fn cvt_gai(err: c_int) -> io::Result<()> { - if err == 0 { Ok(()) } else { Err(last_error()) } -} - -/// Just to provide the same interface as sys/unix/net.rs -pub fn cvt_r<T, F>(mut f: F) -> io::Result<T> -where - T: IsMinusOne, - F: FnMut() -> T, -{ - cvt(f()) -} - -impl Socket { - pub fn new(addr: &SocketAddr, ty: c_int) -> io::Result<Socket> { - let fam = match *addr { - SocketAddr::V4(..) => c::AF_INET, - SocketAddr::V6(..) => c::AF_INET6, - }; - let socket = unsafe { - match c::WSASocketW( - fam, - ty, - 0, - ptr::null_mut(), - 0, - c::WSA_FLAG_OVERLAPPED | c::WSA_FLAG_NO_HANDLE_INHERIT, - ) { - c::INVALID_SOCKET => match c::WSAGetLastError() { - c::WSAEPROTOTYPE | c::WSAEINVAL => { - match c::WSASocketW(fam, ty, 0, ptr::null_mut(), 0, c::WSA_FLAG_OVERLAPPED) - { - c::INVALID_SOCKET => Err(last_error()), - n => { - let s = Socket(n); - s.set_no_inherit()?; - Ok(s) - } - } - } - n => Err(io::Error::from_raw_os_error(n)), - }, - n => Ok(Socket(n)), - } - }?; - Ok(socket) - } - - pub fn connect_timeout(&self, addr: &SocketAddr, timeout: Duration) -> io::Result<()> { - self.set_nonblocking(true)?; - let r = unsafe { - let (addrp, len) = addr.into_inner(); - cvt(c::connect(self.0, addrp, len)) - }; - self.set_nonblocking(false)?; - - match r { - Ok(_) => return Ok(()), - Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => {} - Err(e) => return Err(e), - } - - if timeout.as_secs() == 0 && timeout.subsec_nanos() == 0 { - return Err(io::Error::new( - io::ErrorKind::InvalidInput, - "cannot set a 0 duration timeout", - )); - } - - let mut timeout = c::timeval { - tv_sec: timeout.as_secs() as c_long, - tv_usec: (timeout.subsec_nanos() / 1000) as c_long, - }; - if timeout.tv_sec == 0 && timeout.tv_usec == 0 { - timeout.tv_usec = 1; - } - - let fds = unsafe { - let mut fds = mem::zeroed::<c::fd_set>(); - fds.fd_count = 1; - fds.fd_array[0] = self.0; - fds - }; - - let mut writefds = fds; - let mut errorfds = fds; - - let n = - unsafe { cvt(c::select(1, ptr::null_mut(), &mut writefds, &mut errorfds, &timeout))? }; - - match n { - 0 => Err(io::Error::new(io::ErrorKind::TimedOut, "connection timed out")), - _ => { - if writefds.fd_count != 1 { - if let Some(e) = self.take_error()? { - return Err(e); - } - } - Ok(()) - } - } - } - - pub fn accept(&self, storage: *mut c::SOCKADDR, len: *mut c_int) -> io::Result<Socket> { - let socket = unsafe { - match c::accept(self.0, storage, len) { - c::INVALID_SOCKET => Err(last_error()), - n => Ok(Socket(n)), - } - }?; - Ok(socket) - } - - pub fn duplicate(&self) -> io::Result<Socket> { - let socket = unsafe { - let mut info: c::WSAPROTOCOL_INFO = mem::zeroed(); - cvt(c::WSADuplicateSocketW(self.0, c::GetCurrentProcessId(), &mut info))?; - - match c::WSASocketW( - info.iAddressFamily, - info.iSocketType, - info.iProtocol, - &mut info, - 0, - c::WSA_FLAG_OVERLAPPED | c::WSA_FLAG_NO_HANDLE_INHERIT, - ) { - c::INVALID_SOCKET => match c::WSAGetLastError() { - c::WSAEPROTOTYPE | c::WSAEINVAL => { - match c::WSASocketW( - info.iAddressFamily, - info.iSocketType, - info.iProtocol, - &mut info, - 0, - c::WSA_FLAG_OVERLAPPED, - ) { - c::INVALID_SOCKET => Err(last_error()), - n => { - let s = Socket(n); - s.set_no_inherit()?; - Ok(s) - } - } - } - n => Err(io::Error::from_raw_os_error(n)), - }, - n => Ok(Socket(n)), - } - }?; - Ok(socket) - } - - fn recv_with_flags(&self, buf: &mut [u8], flags: c_int) -> io::Result<usize> { - // On unix when a socket is shut down all further reads return 0, so we - // do the same on windows to map a shut down socket to returning EOF. - let len = cmp::min(buf.len(), i32::MAX as usize) as i32; - unsafe { - match c::recv(self.0, buf.as_mut_ptr() as *mut c_void, len, flags) { - -1 if c::WSAGetLastError() == c::WSAESHUTDOWN => Ok(0), - -1 => Err(last_error()), - n => Ok(n as usize), - } - } - } - - pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> { - self.recv_with_flags(buf, 0) - } - - pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> { - // On unix when a socket is shut down all further reads return 0, so we - // do the same on windows to map a shut down socket to returning EOF. - let len = cmp::min(bufs.len(), c::DWORD::MAX as usize) as c::DWORD; - let mut nread = 0; - let mut flags = 0; - unsafe { - let ret = c::WSARecv( - self.0, - bufs.as_mut_ptr() as *mut c::WSABUF, - len, - &mut nread, - &mut flags, - ptr::null_mut(), - ptr::null_mut(), - ); - match ret { - 0 => Ok(nread as usize), - _ if c::WSAGetLastError() == c::WSAESHUTDOWN => Ok(0), - _ => Err(last_error()), - } - } - } - - #[inline] - pub fn is_read_vectored(&self) -> bool { - true - } - - pub fn peek(&self, buf: &mut [u8]) -> io::Result<usize> { - self.recv_with_flags(buf, c::MSG_PEEK) - } - - fn recv_from_with_flags( - &self, - buf: &mut [u8], - flags: c_int, - ) -> io::Result<(usize, SocketAddr)> { - let mut storage: c::SOCKADDR_STORAGE_LH = unsafe { mem::zeroed() }; - let mut addrlen = mem::size_of_val(&storage) as c::socklen_t; - let len = cmp::min(buf.len(), <wrlen_t>::MAX as usize) as wrlen_t; - - // On unix when a socket is shut down all further reads return 0, so we - // do the same on windows to map a shut down socket to returning EOF. - unsafe { - match c::recvfrom( - self.0, - buf.as_mut_ptr() as *mut c_void, - len, - flags, - &mut storage as *mut _ as *mut _, - &mut addrlen, - ) { - -1 if c::WSAGetLastError() == c::WSAESHUTDOWN => { - Ok((0, net::sockaddr_to_addr(&storage, addrlen as usize)?)) - } - -1 => Err(last_error()), - n => Ok((n as usize, net::sockaddr_to_addr(&storage, addrlen as usize)?)), - } - } - } - - pub fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> { - self.recv_from_with_flags(buf, 0) - } - - pub fn peek_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> { - self.recv_from_with_flags(buf, c::MSG_PEEK) - } - - pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result<usize> { - let len = cmp::min(bufs.len(), c::DWORD::MAX as usize) as c::DWORD; - let mut nwritten = 0; - unsafe { - cvt(c::WSASend( - self.0, - bufs.as_ptr() as *const c::WSABUF as *mut c::WSABUF, - len, - &mut nwritten, - 0, - ptr::null_mut(), - ptr::null_mut(), - ))?; - } - Ok(nwritten as usize) - } - - #[inline] - pub fn is_write_vectored(&self) -> bool { - true - } - - pub fn set_timeout(&self, dur: Option<Duration>, kind: c_int) -> io::Result<()> { - let timeout = match dur { - Some(dur) => { - let timeout = sys::dur2timeout(dur); - if timeout == 0 { - return Err(io::Error::new( - io::ErrorKind::InvalidInput, - "cannot set a 0 duration timeout", - )); - } - timeout - } - None => 0, - }; - net::setsockopt(self, c::SOL_SOCKET, kind, timeout) - } - - pub fn timeout(&self, kind: c_int) -> io::Result<Option<Duration>> { - let raw: c::DWORD = net::getsockopt(self, c::SOL_SOCKET, kind)?; - if raw == 0 { - Ok(None) - } else { - let secs = raw / 1000; - let nsec = (raw % 1000) * 1000000; - Ok(Some(Duration::new(secs as u64, nsec as u32))) - } - } - - #[cfg(not(target_vendor = "uwp"))] - fn set_no_inherit(&self) -> io::Result<()> { - sys::cvt(unsafe { c::SetHandleInformation(self.0 as c::HANDLE, c::HANDLE_FLAG_INHERIT, 0) }) - .map(drop) - } - - #[cfg(target_vendor = "uwp")] - fn set_no_inherit(&self) -> io::Result<()> { - Err(io::Error::new(io::ErrorKind::Other, "Unavailable on UWP")) - } - - pub fn shutdown(&self, how: Shutdown) -> io::Result<()> { - let how = match how { - Shutdown::Write => c::SD_SEND, - Shutdown::Read => c::SD_RECEIVE, - Shutdown::Both => c::SD_BOTH, - }; - cvt(unsafe { c::shutdown(self.0, how) })?; - Ok(()) - } - - pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { - let mut nonblocking = nonblocking as c_ulong; - let r = unsafe { c::ioctlsocket(self.0, c::FIONBIO as c_int, &mut nonblocking) }; - if r == 0 { Ok(()) } else { Err(io::Error::last_os_error()) } - } - - pub fn set_nodelay(&self, nodelay: bool) -> io::Result<()> { - net::setsockopt(self, c::IPPROTO_TCP, c::TCP_NODELAY, nodelay as c::BYTE) - } - - pub fn nodelay(&self) -> io::Result<bool> { - let raw: c::BYTE = net::getsockopt(self, c::IPPROTO_TCP, c::TCP_NODELAY)?; - Ok(raw != 0) - } - - pub fn take_error(&self) -> io::Result<Option<io::Error>> { - let raw: c_int = net::getsockopt(self, c::SOL_SOCKET, c::SO_ERROR)?; - if raw == 0 { Ok(None) } else { Ok(Some(io::Error::from_raw_os_error(raw as i32))) } - } -} - -#[unstable(reason = "not public", issue = "none", feature = "fd_read")] -impl<'a> Read for &'a Socket { - fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { - (**self).read(buf) - } -} - -impl Drop for Socket { - fn drop(&mut self) { - let _ = unsafe { c::closesocket(self.0) }; - } -} - -impl AsInner<c::SOCKET> for Socket { - fn as_inner(&self) -> &c::SOCKET { - &self.0 - } -} - -impl FromInner<c::SOCKET> for Socket { - fn from_inner(sock: c::SOCKET) -> Socket { - Socket(sock) - } -} - -impl IntoInner<c::SOCKET> for Socket { - fn into_inner(self) -> c::SOCKET { - let ret = self.0; - mem::forget(self); - ret - } -} diff --git a/src/libstd/sys/windows/os.rs b/src/libstd/sys/windows/os.rs deleted file mode 100644 index a0da2498bb7..00000000000 --- a/src/libstd/sys/windows/os.rs +++ /dev/null @@ -1,347 +0,0 @@ -//! Implementation of `std::os` functionality for Windows. - -#![allow(nonstandard_style)] - -use crate::os::windows::prelude::*; - -use crate::error::Error as StdError; -use crate::ffi::{OsStr, OsString}; -use crate::fmt; -use crate::io; -use crate::os::windows::ffi::EncodeWide; -use crate::path::{self, PathBuf}; -use crate::ptr; -use crate::slice; -use crate::sys::{c, cvt}; - -use super::to_u16s; - -pub fn errno() -> i32 { - unsafe { c::GetLastError() as i32 } -} - -/// Gets a detailed string description for the given error number. -pub fn error_string(mut errnum: i32) -> String { - // This value is calculated from the macro - // MAKELANGID(LANG_SYSTEM_DEFAULT, SUBLANG_SYS_DEFAULT) - let langId = 0x0800 as c::DWORD; - - let mut buf = [0 as c::WCHAR; 2048]; - - unsafe { - let mut module = ptr::null_mut(); - let mut flags = 0; - - // NTSTATUS errors may be encoded as HRESULT, which may returned from - // GetLastError. For more information about Windows error codes, see - // `[MS-ERREF]`: https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-erref/0642cb2f-2075-4469-918c-4441e69c548a - if (errnum & c::FACILITY_NT_BIT as i32) != 0 { - // format according to https://support.microsoft.com/en-us/help/259693 - const NTDLL_DLL: &[u16] = &[ - 'N' as _, 'T' as _, 'D' as _, 'L' as _, 'L' as _, '.' as _, 'D' as _, 'L' as _, - 'L' as _, 0, - ]; - module = c::GetModuleHandleW(NTDLL_DLL.as_ptr()); - - if !module.is_null() { - errnum ^= c::FACILITY_NT_BIT as i32; - flags = c::FORMAT_MESSAGE_FROM_HMODULE; - } - } - - let res = c::FormatMessageW( - flags | c::FORMAT_MESSAGE_FROM_SYSTEM | c::FORMAT_MESSAGE_IGNORE_INSERTS, - module, - errnum as c::DWORD, - langId, - buf.as_mut_ptr(), - buf.len() as c::DWORD, - ptr::null(), - ) as usize; - if res == 0 { - // Sometimes FormatMessageW can fail e.g., system doesn't like langId, - let fm_err = errno(); - return format!("OS Error {} (FormatMessageW() returned error {})", errnum, fm_err); - } - - match String::from_utf16(&buf[..res]) { - Ok(mut msg) => { - // Trim trailing CRLF inserted by FormatMessageW - let len = msg.trim_end().len(); - msg.truncate(len); - msg - } - Err(..) => format!( - "OS Error {} (FormatMessageW() returned \ - invalid UTF-16)", - errnum - ), - } - } -} - -pub struct Env { - base: c::LPWCH, - cur: c::LPWCH, -} - -impl Iterator for Env { - type Item = (OsString, OsString); - - fn next(&mut self) -> Option<(OsString, OsString)> { - loop { - unsafe { - if *self.cur == 0 { - return None; - } - let p = self.cur as *const u16; - let mut len = 0; - while *p.offset(len) != 0 { - len += 1; - } - let s = slice::from_raw_parts(p, len as usize); - self.cur = self.cur.offset(len + 1); - - // Windows allows environment variables to start with an equals - // symbol (in any other position, this is the separator between - // variable name and value). Since`s` has at least length 1 at - // this point (because the empty string terminates the array of - // environment variables), we can safely slice. - let pos = match s[1..].iter().position(|&u| u == b'=' as u16).map(|p| p + 1) { - Some(p) => p, - None => continue, - }; - return Some(( - OsStringExt::from_wide(&s[..pos]), - OsStringExt::from_wide(&s[pos + 1..]), - )); - } - } - } -} - -impl Drop for Env { - fn drop(&mut self) { - unsafe { - c::FreeEnvironmentStringsW(self.base); - } - } -} - -pub fn env() -> Env { - unsafe { - let ch = c::GetEnvironmentStringsW(); - if ch as usize == 0 { - panic!("failure getting env string from OS: {}", io::Error::last_os_error()); - } - Env { base: ch, cur: ch } - } -} - -pub struct SplitPaths<'a> { - data: EncodeWide<'a>, - must_yield: bool, -} - -pub fn split_paths(unparsed: &OsStr) -> SplitPaths<'_> { - SplitPaths { data: unparsed.encode_wide(), must_yield: true } -} - -impl<'a> Iterator for SplitPaths<'a> { - type Item = PathBuf; - fn next(&mut self) -> Option<PathBuf> { - // On Windows, the PATH environment variable is semicolon separated. - // Double quotes are used as a way of introducing literal semicolons - // (since c:\some;dir is a valid Windows path). Double quotes are not - // themselves permitted in path names, so there is no way to escape a - // double quote. Quoted regions can appear in arbitrary locations, so - // - // c:\foo;c:\som"e;di"r;c:\bar - // - // Should parse as [c:\foo, c:\some;dir, c:\bar]. - // - // (The above is based on testing; there is no clear reference available - // for the grammar.) - - let must_yield = self.must_yield; - self.must_yield = false; - - let mut in_progress = Vec::new(); - let mut in_quote = false; - for b in self.data.by_ref() { - if b == '"' as u16 { - in_quote = !in_quote; - } else if b == ';' as u16 && !in_quote { - self.must_yield = true; - break; - } else { - in_progress.push(b) - } - } - - if !must_yield && in_progress.is_empty() { - None - } else { - Some(super::os2path(&in_progress)) - } - } -} - -#[derive(Debug)] -pub struct JoinPathsError; - -pub fn join_paths<I, T>(paths: I) -> Result<OsString, JoinPathsError> -where - I: Iterator<Item = T>, - T: AsRef<OsStr>, -{ - let mut joined = Vec::new(); - let sep = b';' as u16; - - for (i, path) in paths.enumerate() { - let path = path.as_ref(); - if i > 0 { - joined.push(sep) - } - let v = path.encode_wide().collect::<Vec<u16>>(); - if v.contains(&(b'"' as u16)) { - return Err(JoinPathsError); - } else if v.contains(&sep) { - joined.push(b'"' as u16); - joined.extend_from_slice(&v[..]); - joined.push(b'"' as u16); - } else { - joined.extend_from_slice(&v[..]); - } - } - - Ok(OsStringExt::from_wide(&joined[..])) -} - -impl fmt::Display for JoinPathsError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - "path segment contains `\"`".fmt(f) - } -} - -impl StdError for JoinPathsError { - #[allow(deprecated)] - fn description(&self) -> &str { - "failed to join paths" - } -} - -pub fn current_exe() -> io::Result<PathBuf> { - super::fill_utf16_buf( - |buf, sz| unsafe { c::GetModuleFileNameW(ptr::null_mut(), buf, sz) }, - super::os2path, - ) -} - -pub fn getcwd() -> io::Result<PathBuf> { - super::fill_utf16_buf(|buf, sz| unsafe { c::GetCurrentDirectoryW(sz, buf) }, super::os2path) -} - -pub fn chdir(p: &path::Path) -> io::Result<()> { - let p: &OsStr = p.as_ref(); - let mut p = p.encode_wide().collect::<Vec<_>>(); - p.push(0); - - cvt(unsafe { c::SetCurrentDirectoryW(p.as_ptr()) }).map(drop) -} - -pub fn getenv(k: &OsStr) -> io::Result<Option<OsString>> { - let k = to_u16s(k)?; - let res = super::fill_utf16_buf( - |buf, sz| unsafe { c::GetEnvironmentVariableW(k.as_ptr(), buf, sz) }, - |buf| OsStringExt::from_wide(buf), - ); - match res { - Ok(value) => Ok(Some(value)), - Err(e) => { - if e.raw_os_error() == Some(c::ERROR_ENVVAR_NOT_FOUND as i32) { - Ok(None) - } else { - Err(e) - } - } - } -} - -pub fn setenv(k: &OsStr, v: &OsStr) -> io::Result<()> { - let k = to_u16s(k)?; - let v = to_u16s(v)?; - - cvt(unsafe { c::SetEnvironmentVariableW(k.as_ptr(), v.as_ptr()) }).map(drop) -} - -pub fn unsetenv(n: &OsStr) -> io::Result<()> { - let v = to_u16s(n)?; - cvt(unsafe { c::SetEnvironmentVariableW(v.as_ptr(), ptr::null()) }).map(drop) -} - -pub fn temp_dir() -> PathBuf { - super::fill_utf16_buf(|buf, sz| unsafe { c::GetTempPathW(sz, buf) }, super::os2path).unwrap() -} - -#[cfg(not(target_vendor = "uwp"))] -fn home_dir_crt() -> Option<PathBuf> { - unsafe { - use crate::sys::handle::Handle; - - let me = c::GetCurrentProcess(); - let mut token = ptr::null_mut(); - if c::OpenProcessToken(me, c::TOKEN_READ, &mut token) == 0 { - return None; - } - let _handle = Handle::new(token); - super::fill_utf16_buf( - |buf, mut sz| { - match c::GetUserProfileDirectoryW(token, buf, &mut sz) { - 0 if c::GetLastError() != c::ERROR_INSUFFICIENT_BUFFER => 0, - 0 => sz, - _ => sz - 1, // sz includes the null terminator - } - }, - super::os2path, - ) - .ok() - } -} - -#[cfg(target_vendor = "uwp")] -fn home_dir_crt() -> Option<PathBuf> { - None -} - -pub fn home_dir() -> Option<PathBuf> { - crate::env::var_os("HOME") - .or_else(|| crate::env::var_os("USERPROFILE")) - .map(PathBuf::from) - .or_else(|| home_dir_crt()) -} - -pub fn exit(code: i32) -> ! { - unsafe { c::ExitProcess(code as c::UINT) } -} - -pub fn getpid() -> u32 { - unsafe { c::GetCurrentProcessId() as u32 } -} - -#[cfg(test)] -mod tests { - use crate::io::Error; - use crate::sys::c; - - // tests `error_string` above - #[test] - fn ntstatus_error() { - const STATUS_UNSUCCESSFUL: u32 = 0xc000_0001; - assert!( - !Error::from_raw_os_error((STATUS_UNSUCCESSFUL | c::FACILITY_NT_BIT) as _) - .to_string() - .contains("FormatMessageW() returned error") - ); - } -} diff --git a/src/libstd/sys/windows/os_str.rs b/src/libstd/sys/windows/os_str.rs deleted file mode 100644 index 2f5fc72ab44..00000000000 --- a/src/libstd/sys/windows/os_str.rs +++ /dev/null @@ -1,216 +0,0 @@ -/// The underlying OsString/OsStr implementation on Windows is a -/// wrapper around the "WTF-8" encoding; see the `wtf8` module for more. -use crate::borrow::Cow; -use crate::fmt; -use crate::mem; -use crate::rc::Rc; -use crate::sync::Arc; -use crate::sys_common::wtf8::{Wtf8, Wtf8Buf}; -use crate::sys_common::{AsInner, FromInner, IntoInner}; - -#[derive(Clone, Hash)] -pub struct Buf { - pub inner: Wtf8Buf, -} - -impl IntoInner<Wtf8Buf> for Buf { - fn into_inner(self) -> Wtf8Buf { - self.inner - } -} - -impl FromInner<Wtf8Buf> for Buf { - fn from_inner(inner: Wtf8Buf) -> Self { - Buf { inner } - } -} - -impl AsInner<Wtf8> for Buf { - fn as_inner(&self) -> &Wtf8 { - &self.inner - } -} - -impl fmt::Debug for Buf { - fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Debug::fmt(self.as_slice(), formatter) - } -} - -impl fmt::Display for Buf { - fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Display::fmt(self.as_slice(), formatter) - } -} - -pub struct Slice { - pub inner: Wtf8, -} - -impl fmt::Debug for Slice { - fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Debug::fmt(&self.inner, formatter) - } -} - -impl fmt::Display for Slice { - fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Display::fmt(&self.inner, formatter) - } -} - -impl Buf { - pub fn with_capacity(capacity: usize) -> Buf { - Buf { inner: Wtf8Buf::with_capacity(capacity) } - } - - pub fn clear(&mut self) { - self.inner.clear() - } - - pub fn capacity(&self) -> usize { - self.inner.capacity() - } - - pub fn from_string(s: String) -> Buf { - Buf { inner: Wtf8Buf::from_string(s) } - } - - pub fn as_slice(&self) -> &Slice { - // Safety: Slice is just a wrapper for Wtf8, - // and self.inner.as_slice() returns &Wtf8. - // Therefore, transmuting &Wtf8 to &Slice is safe. - unsafe { mem::transmute(self.inner.as_slice()) } - } - - pub fn as_mut_slice(&mut self) -> &mut Slice { - // Safety: Slice is just a wrapper for Wtf8, - // and self.inner.as_mut_slice() returns &mut Wtf8. - // Therefore, transmuting &mut Wtf8 to &mut Slice is safe. - // Additionally, care should be taken to ensure the slice - // is always valid Wtf8. - unsafe { mem::transmute(self.inner.as_mut_slice()) } - } - - pub fn into_string(self) -> Result<String, Buf> { - self.inner.into_string().map_err(|buf| Buf { inner: buf }) - } - - pub fn push_slice(&mut self, s: &Slice) { - self.inner.push_wtf8(&s.inner) - } - - pub fn reserve(&mut self, additional: usize) { - self.inner.reserve(additional) - } - - pub fn reserve_exact(&mut self, additional: usize) { - self.inner.reserve_exact(additional) - } - - pub fn shrink_to_fit(&mut self) { - self.inner.shrink_to_fit() - } - - #[inline] - pub fn shrink_to(&mut self, min_capacity: usize) { - self.inner.shrink_to(min_capacity) - } - - #[inline] - pub fn into_box(self) -> Box<Slice> { - unsafe { mem::transmute(self.inner.into_box()) } - } - - #[inline] - pub fn from_box(boxed: Box<Slice>) -> Buf { - let inner: Box<Wtf8> = unsafe { mem::transmute(boxed) }; - Buf { inner: Wtf8Buf::from_box(inner) } - } - - #[inline] - pub fn into_arc(&self) -> Arc<Slice> { - self.as_slice().into_arc() - } - - #[inline] - pub fn into_rc(&self) -> Rc<Slice> { - self.as_slice().into_rc() - } -} - -impl Slice { - #[inline] - pub fn from_str(s: &str) -> &Slice { - unsafe { mem::transmute(Wtf8::from_str(s)) } - } - - pub fn to_str(&self) -> Option<&str> { - self.inner.as_str() - } - - pub fn to_string_lossy(&self) -> Cow<'_, str> { - self.inner.to_string_lossy() - } - - pub fn to_owned(&self) -> Buf { - let mut buf = Wtf8Buf::with_capacity(self.inner.len()); - buf.push_wtf8(&self.inner); - Buf { inner: buf } - } - - pub fn clone_into(&self, buf: &mut Buf) { - self.inner.clone_into(&mut buf.inner) - } - - #[inline] - pub fn into_box(&self) -> Box<Slice> { - unsafe { mem::transmute(self.inner.into_box()) } - } - - pub fn empty_box() -> Box<Slice> { - unsafe { mem::transmute(Wtf8::empty_box()) } - } - - #[inline] - pub fn into_arc(&self) -> Arc<Slice> { - let arc = self.inner.into_arc(); - unsafe { Arc::from_raw(Arc::into_raw(arc) as *const Slice) } - } - - #[inline] - pub fn into_rc(&self) -> Rc<Slice> { - let rc = self.inner.into_rc(); - unsafe { Rc::from_raw(Rc::into_raw(rc) as *const Slice) } - } - - #[inline] - pub fn make_ascii_lowercase(&mut self) { - self.inner.make_ascii_lowercase() - } - - #[inline] - pub fn make_ascii_uppercase(&mut self) { - self.inner.make_ascii_uppercase() - } - - #[inline] - pub fn to_ascii_lowercase(&self) -> Buf { - Buf { inner: self.inner.to_ascii_lowercase() } - } - - #[inline] - pub fn to_ascii_uppercase(&self) -> Buf { - Buf { inner: self.inner.to_ascii_uppercase() } - } - - #[inline] - pub fn is_ascii(&self) -> bool { - self.inner.is_ascii() - } - - #[inline] - pub fn eq_ignore_ascii_case(&self, other: &Self) -> bool { - self.inner.eq_ignore_ascii_case(&other.inner) - } -} diff --git a/src/libstd/sys/windows/path.rs b/src/libstd/sys/windows/path.rs deleted file mode 100644 index dda3ed68cfc..00000000000 --- a/src/libstd/sys/windows/path.rs +++ /dev/null @@ -1,107 +0,0 @@ -use crate::ffi::OsStr; -use crate::mem; -use crate::path::Prefix; - -#[cfg(test)] -mod tests; - -pub const MAIN_SEP_STR: &str = "\\"; -pub const MAIN_SEP: char = '\\'; - -// The unsafety here stems from converting between `&OsStr` and `&[u8]` -// and back. This is safe to do because (1) we only look at ASCII -// contents of the encoding and (2) new &OsStr values are produced -// only from ASCII-bounded slices of existing &OsStr values. -fn os_str_as_u8_slice(s: &OsStr) -> &[u8] { - unsafe { mem::transmute(s) } -} -unsafe fn u8_slice_as_os_str(s: &[u8]) -> &OsStr { - mem::transmute(s) -} - -#[inline] -pub fn is_sep_byte(b: u8) -> bool { - b == b'/' || b == b'\\' -} - -#[inline] -pub fn is_verbatim_sep(b: u8) -> bool { - b == b'\\' -} - -// In most DOS systems, it is not possible to have more than 26 drive letters. -// See <https://en.wikipedia.org/wiki/Drive_letter_assignment#Common_assignments>. -pub fn is_valid_drive_letter(disk: u8) -> bool { - disk.is_ascii_alphabetic() -} - -pub fn parse_prefix(path: &OsStr) -> Option<Prefix<'_>> { - use Prefix::{DeviceNS, Disk, Verbatim, VerbatimDisk, VerbatimUNC, UNC}; - - let path = os_str_as_u8_slice(path); - - // \\ - if let Some(path) = path.strip_prefix(br"\\") { - // \\?\ - if let Some(path) = path.strip_prefix(br"?\") { - // \\?\UNC\server\share - if let Some(path) = path.strip_prefix(br"UNC\") { - let (server, share) = match get_first_two_components(path, is_verbatim_sep) { - Some((server, share)) => unsafe { - (u8_slice_as_os_str(server), u8_slice_as_os_str(share)) - }, - None => (unsafe { u8_slice_as_os_str(path) }, OsStr::new("")), - }; - return Some(VerbatimUNC(server, share)); - } else { - // \\?\path - match path { - // \\?\C:\path - [c, b':', b'\\', ..] if is_valid_drive_letter(*c) => { - return Some(VerbatimDisk(c.to_ascii_uppercase())); - } - // \\?\cat_pics - _ => { - let idx = path.iter().position(|&b| b == b'\\').unwrap_or(path.len()); - let slice = &path[..idx]; - return Some(Verbatim(unsafe { u8_slice_as_os_str(slice) })); - } - } - } - } else if let Some(path) = path.strip_prefix(b".\\") { - // \\.\COM42 - let idx = path.iter().position(|&b| b == b'\\').unwrap_or(path.len()); - let slice = &path[..idx]; - return Some(DeviceNS(unsafe { u8_slice_as_os_str(slice) })); - } - match get_first_two_components(path, is_sep_byte) { - Some((server, share)) if !server.is_empty() && !share.is_empty() => { - // \\server\share - return Some(unsafe { UNC(u8_slice_as_os_str(server), u8_slice_as_os_str(share)) }); - } - _ => {} - } - } else if let [c, b':', ..] = path { - // C: - if is_valid_drive_letter(*c) { - return Some(Disk(c.to_ascii_uppercase())); - } - } - None -} - -/// Returns the first two path components with predicate `f`. -/// -/// The two components returned will be use by caller -/// to construct `VerbatimUNC` or `UNC` Windows path prefix. -/// -/// Returns [`None`] if there are no separators in path. -fn get_first_two_components(path: &[u8], f: fn(u8) -> bool) -> Option<(&[u8], &[u8])> { - let idx = path.iter().position(|&x| f(x))?; - // Panic safe - // The max `idx+1` is `path.len()` and `path[path.len()..]` is a valid index. - let (first, path) = (&path[..idx], &path[idx + 1..]); - let idx = path.iter().position(|&x| f(x)).unwrap_or(path.len()); - let second = &path[..idx]; - Some((first, second)) -} diff --git a/src/libstd/sys/windows/path/tests.rs b/src/libstd/sys/windows/path/tests.rs deleted file mode 100644 index fbac1dc1ca1..00000000000 --- a/src/libstd/sys/windows/path/tests.rs +++ /dev/null @@ -1,21 +0,0 @@ -use super::*; - -#[test] -fn test_get_first_two_components() { - assert_eq!( - get_first_two_components(br"server\share", is_verbatim_sep), - Some((&b"server"[..], &b"share"[..])), - ); - - assert_eq!( - get_first_two_components(br"server\", is_verbatim_sep), - Some((&b"server"[..], &b""[..])) - ); - - assert_eq!( - get_first_two_components(br"\server\", is_verbatim_sep), - Some((&b""[..], &b"server"[..])) - ); - - assert_eq!(get_first_two_components(br"there are no separators here", is_verbatim_sep), None,); -} diff --git a/src/libstd/sys/windows/pipe.rs b/src/libstd/sys/windows/pipe.rs deleted file mode 100644 index 104a8db4659..00000000000 --- a/src/libstd/sys/windows/pipe.rs +++ /dev/null @@ -1,368 +0,0 @@ -use crate::os::windows::prelude::*; - -use crate::ffi::OsStr; -use crate::io::{self, IoSlice, IoSliceMut}; -use crate::mem; -use crate::path::Path; -use crate::ptr; -use crate::slice; -use crate::sync::atomic::AtomicUsize; -use crate::sync::atomic::Ordering::SeqCst; -use crate::sys::c; -use crate::sys::fs::{File, OpenOptions}; -use crate::sys::handle::Handle; -use crate::sys::hashmap_random_keys; - -//////////////////////////////////////////////////////////////////////////////// -// Anonymous pipes -//////////////////////////////////////////////////////////////////////////////// - -pub struct AnonPipe { - inner: Handle, -} - -pub struct Pipes { - pub ours: AnonPipe, - pub theirs: AnonPipe, -} - -/// Although this looks similar to `anon_pipe` in the Unix module it's actually -/// subtly different. Here we'll return two pipes in the `Pipes` return value, -/// but one is intended for "us" where as the other is intended for "someone -/// else". -/// -/// Currently the only use case for this function is pipes for stdio on -/// processes in the standard library, so "ours" is the one that'll stay in our -/// process whereas "theirs" will be inherited to a child. -/// -/// The ours/theirs pipes are *not* specifically readable or writable. Each -/// one only supports a read or a write, but which is which depends on the -/// boolean flag given. If `ours_readable` is `true`, then `ours` is readable and -/// `theirs` is writable. Conversely, if `ours_readable` is `false`, then `ours` -/// is writable and `theirs` is readable. -/// -/// Also note that the `ours` pipe is always a handle opened up in overlapped -/// mode. This means that technically speaking it should only ever be used -/// with `OVERLAPPED` instances, but also works out ok if it's only ever used -/// once at a time (which we do indeed guarantee). -pub fn anon_pipe(ours_readable: bool, their_handle_inheritable: bool) -> io::Result<Pipes> { - // Note that we specifically do *not* use `CreatePipe` here because - // unfortunately the anonymous pipes returned do not support overlapped - // operations. Instead, we create a "hopefully unique" name and create a - // named pipe which has overlapped operations enabled. - // - // Once we do this, we connect do it as usual via `CreateFileW`, and then - // we return those reader/writer halves. Note that the `ours` pipe return - // value is always the named pipe, whereas `theirs` is just the normal file. - // This should hopefully shield us from child processes which assume their - // stdout is a named pipe, which would indeed be odd! - unsafe { - let ours; - let mut name; - let mut tries = 0; - let mut reject_remote_clients_flag = c::PIPE_REJECT_REMOTE_CLIENTS; - loop { - tries += 1; - name = format!( - r"\\.\pipe\__rust_anonymous_pipe1__.{}.{}", - c::GetCurrentProcessId(), - random_number() - ); - let wide_name = OsStr::new(&name).encode_wide().chain(Some(0)).collect::<Vec<_>>(); - let mut flags = c::FILE_FLAG_FIRST_PIPE_INSTANCE | c::FILE_FLAG_OVERLAPPED; - if ours_readable { - flags |= c::PIPE_ACCESS_INBOUND; - } else { - flags |= c::PIPE_ACCESS_OUTBOUND; - } - - let handle = c::CreateNamedPipeW( - wide_name.as_ptr(), - flags, - c::PIPE_TYPE_BYTE - | c::PIPE_READMODE_BYTE - | c::PIPE_WAIT - | reject_remote_clients_flag, - 1, - 4096, - 4096, - 0, - ptr::null_mut(), - ); - - // We pass the `FILE_FLAG_FIRST_PIPE_INSTANCE` flag above, and we're - // also just doing a best effort at selecting a unique name. If - // `ERROR_ACCESS_DENIED` is returned then it could mean that we - // accidentally conflicted with an already existing pipe, so we try - // again. - // - // Don't try again too much though as this could also perhaps be a - // legit error. - // If `ERROR_INVALID_PARAMETER` is returned, this probably means we're - // running on pre-Vista version where `PIPE_REJECT_REMOTE_CLIENTS` is - // not supported, so we continue retrying without it. This implies - // reduced security on Windows versions older than Vista by allowing - // connections to this pipe from remote machines. - // Proper fix would increase the number of FFI imports and introduce - // significant amount of Windows XP specific code with no clean - // testing strategy - // For more info, see https://github.com/rust-lang/rust/pull/37677. - if handle == c::INVALID_HANDLE_VALUE { - let err = io::Error::last_os_error(); - let raw_os_err = err.raw_os_error(); - if tries < 10 { - if raw_os_err == Some(c::ERROR_ACCESS_DENIED as i32) { - continue; - } else if reject_remote_clients_flag != 0 - && raw_os_err == Some(c::ERROR_INVALID_PARAMETER as i32) - { - reject_remote_clients_flag = 0; - tries -= 1; - continue; - } - } - return Err(err); - } - ours = Handle::new(handle); - break; - } - - // Connect to the named pipe we just created. This handle is going to be - // returned in `theirs`, so if `ours` is readable we want this to be - // writable, otherwise if `ours` is writable we want this to be - // readable. - // - // Additionally we don't enable overlapped mode on this because most - // client processes aren't enabled to work with that. - let mut opts = OpenOptions::new(); - opts.write(ours_readable); - opts.read(!ours_readable); - opts.share_mode(0); - let size = mem::size_of::<c::SECURITY_ATTRIBUTES>(); - let mut sa = c::SECURITY_ATTRIBUTES { - nLength: size as c::DWORD, - lpSecurityDescriptor: ptr::null_mut(), - bInheritHandle: their_handle_inheritable as i32, - }; - opts.security_attributes(&mut sa); - let theirs = File::open(Path::new(&name), &opts)?; - let theirs = AnonPipe { inner: theirs.into_handle() }; - - Ok(Pipes { - ours: AnonPipe { inner: ours }, - theirs: AnonPipe { inner: theirs.into_handle() }, - }) - } -} - -fn random_number() -> usize { - static N: AtomicUsize = AtomicUsize::new(0); - loop { - if N.load(SeqCst) != 0 { - return N.fetch_add(1, SeqCst); - } - - N.store(hashmap_random_keys().0 as usize, SeqCst); - } -} - -impl AnonPipe { - pub fn handle(&self) -> &Handle { - &self.inner - } - pub fn into_handle(self) -> Handle { - self.inner - } - - pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> { - self.inner.read(buf) - } - - pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> { - self.inner.read_vectored(bufs) - } - - #[inline] - pub fn is_read_vectored(&self) -> bool { - self.inner.is_read_vectored() - } - - pub fn write(&self, buf: &[u8]) -> io::Result<usize> { - self.inner.write(buf) - } - - pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result<usize> { - self.inner.write_vectored(bufs) - } - - #[inline] - pub fn is_write_vectored(&self) -> bool { - self.inner.is_write_vectored() - } -} - -pub fn read2(p1: AnonPipe, v1: &mut Vec<u8>, p2: AnonPipe, v2: &mut Vec<u8>) -> io::Result<()> { - let p1 = p1.into_handle(); - let p2 = p2.into_handle(); - - let mut p1 = AsyncPipe::new(p1, v1)?; - let mut p2 = AsyncPipe::new(p2, v2)?; - let objs = [p1.event.raw(), p2.event.raw()]; - - // In a loop we wait for either pipe's scheduled read operation to complete. - // If the operation completes with 0 bytes, that means EOF was reached, in - // which case we just finish out the other pipe entirely. - // - // Note that overlapped I/O is in general super unsafe because we have to - // be careful to ensure that all pointers in play are valid for the entire - // duration of the I/O operation (where tons of operations can also fail). - // The destructor for `AsyncPipe` ends up taking care of most of this. - loop { - let res = unsafe { c::WaitForMultipleObjects(2, objs.as_ptr(), c::FALSE, c::INFINITE) }; - if res == c::WAIT_OBJECT_0 { - if !p1.result()? || !p1.schedule_read()? { - return p2.finish(); - } - } else if res == c::WAIT_OBJECT_0 + 1 { - if !p2.result()? || !p2.schedule_read()? { - return p1.finish(); - } - } else { - return Err(io::Error::last_os_error()); - } - } -} - -struct AsyncPipe<'a> { - pipe: Handle, - event: Handle, - overlapped: Box<c::OVERLAPPED>, // needs a stable address - dst: &'a mut Vec<u8>, - state: State, -} - -#[derive(PartialEq, Debug)] -enum State { - NotReading, - Reading, - Read(usize), -} - -impl<'a> AsyncPipe<'a> { - fn new(pipe: Handle, dst: &'a mut Vec<u8>) -> io::Result<AsyncPipe<'a>> { - // Create an event which we'll use to coordinate our overlapped - // operations, this event will be used in WaitForMultipleObjects - // and passed as part of the OVERLAPPED handle. - // - // Note that we do a somewhat clever thing here by flagging the - // event as being manually reset and setting it initially to the - // signaled state. This means that we'll naturally fall through the - // WaitForMultipleObjects call above for pipes created initially, - // and the only time an even will go back to "unset" will be once an - // I/O operation is successfully scheduled (what we want). - let event = Handle::new_event(true, true)?; - let mut overlapped: Box<c::OVERLAPPED> = unsafe { Box::new(mem::zeroed()) }; - overlapped.hEvent = event.raw(); - Ok(AsyncPipe { pipe, overlapped, event, dst, state: State::NotReading }) - } - - /// Executes an overlapped read operation. - /// - /// Must not currently be reading, and returns whether the pipe is currently - /// at EOF or not. If the pipe is not at EOF then `result()` must be called - /// to complete the read later on (may block), but if the pipe is at EOF - /// then `result()` should not be called as it will just block forever. - fn schedule_read(&mut self) -> io::Result<bool> { - assert_eq!(self.state, State::NotReading); - let amt = unsafe { - let slice = slice_to_end(self.dst); - self.pipe.read_overlapped(slice, &mut *self.overlapped)? - }; - - // If this read finished immediately then our overlapped event will - // remain signaled (it was signaled coming in here) and we'll progress - // down to the method below. - // - // Otherwise the I/O operation is scheduled and the system set our event - // to not signaled, so we flag ourselves into the reading state and move - // on. - self.state = match amt { - Some(0) => return Ok(false), - Some(amt) => State::Read(amt), - None => State::Reading, - }; - Ok(true) - } - - /// Wait for the result of the overlapped operation previously executed. - /// - /// Takes a parameter `wait` which indicates if this pipe is currently being - /// read whether the function should block waiting for the read to complete. - /// - /// Returns values: - /// - /// * `true` - finished any pending read and the pipe is not at EOF (keep - /// going) - /// * `false` - finished any pending read and pipe is at EOF (stop issuing - /// reads) - fn result(&mut self) -> io::Result<bool> { - let amt = match self.state { - State::NotReading => return Ok(true), - State::Reading => self.pipe.overlapped_result(&mut *self.overlapped, true)?, - State::Read(amt) => amt, - }; - self.state = State::NotReading; - unsafe { - let len = self.dst.len(); - self.dst.set_len(len + amt); - } - Ok(amt != 0) - } - - /// Finishes out reading this pipe entirely. - /// - /// Waits for any pending and schedule read, and then calls `read_to_end` - /// if necessary to read all the remaining information. - fn finish(&mut self) -> io::Result<()> { - while self.result()? && self.schedule_read()? { - // ... - } - Ok(()) - } -} - -impl<'a> Drop for AsyncPipe<'a> { - fn drop(&mut self) { - match self.state { - State::Reading => {} - _ => return, - } - - // If we have a pending read operation, then we have to make sure that - // it's *done* before we actually drop this type. The kernel requires - // that the `OVERLAPPED` and buffer pointers are valid for the entire - // I/O operation. - // - // To do that, we call `CancelIo` to cancel any pending operation, and - // if that succeeds we wait for the overlapped result. - // - // If anything here fails, there's not really much we can do, so we leak - // the buffer/OVERLAPPED pointers to ensure we're at least memory safe. - if self.pipe.cancel_io().is_err() || self.result().is_err() { - let buf = mem::take(self.dst); - let overlapped = Box::new(unsafe { mem::zeroed() }); - let overlapped = mem::replace(&mut self.overlapped, overlapped); - mem::forget((buf, overlapped)); - } - } -} - -unsafe fn slice_to_end(v: &mut Vec<u8>) -> &mut [u8] { - if v.capacity() == 0 { - v.reserve(16); - } - if v.capacity() == v.len() { - v.reserve(1); - } - slice::from_raw_parts_mut(v.as_mut_ptr().add(v.len()), v.capacity() - v.len()) -} diff --git a/src/libstd/sys/windows/process.rs b/src/libstd/sys/windows/process.rs deleted file mode 100644 index 7d6d4775eec..00000000000 --- a/src/libstd/sys/windows/process.rs +++ /dev/null @@ -1,566 +0,0 @@ -#![unstable(feature = "process_internals", issue = "none")] - -use crate::borrow::Borrow; -use crate::collections::BTreeMap; -use crate::env; -use crate::env::split_paths; -use crate::ffi::{OsStr, OsString}; -use crate::fmt; -use crate::fs; -use crate::io::{self, Error, ErrorKind}; -use crate::mem; -use crate::os::windows::ffi::OsStrExt; -use crate::path::Path; -use crate::ptr; -use crate::sys::c; -use crate::sys::cvt; -use crate::sys::fs::{File, OpenOptions}; -use crate::sys::handle::Handle; -use crate::sys::mutex::Mutex; -use crate::sys::pipe::{self, AnonPipe}; -use crate::sys::stdio; -use crate::sys_common::process::CommandEnv; -use crate::sys_common::AsInner; - -use libc::{c_void, EXIT_FAILURE, EXIT_SUCCESS}; - -//////////////////////////////////////////////////////////////////////////////// -// Command -//////////////////////////////////////////////////////////////////////////////// - -#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd)] -#[doc(hidden)] -pub struct EnvKey(OsString); - -impl From<OsString> for EnvKey { - fn from(mut k: OsString) -> Self { - k.make_ascii_uppercase(); - EnvKey(k) - } -} - -impl From<EnvKey> for OsString { - fn from(k: EnvKey) -> Self { - k.0 - } -} - -impl Borrow<OsStr> for EnvKey { - fn borrow(&self) -> &OsStr { - &self.0 - } -} - -impl AsRef<OsStr> for EnvKey { - fn as_ref(&self) -> &OsStr { - &self.0 - } -} - -fn ensure_no_nuls<T: AsRef<OsStr>>(str: T) -> io::Result<T> { - if str.as_ref().encode_wide().any(|b| b == 0) { - Err(io::Error::new(ErrorKind::InvalidInput, "nul byte found in provided data")) - } else { - Ok(str) - } -} - -pub struct Command { - program: OsString, - args: Vec<OsString>, - env: CommandEnv, - cwd: Option<OsString>, - flags: u32, - detach: bool, // not currently exposed in std::process - stdin: Option<Stdio>, - stdout: Option<Stdio>, - stderr: Option<Stdio>, -} - -pub enum Stdio { - Inherit, - Null, - MakePipe, - Handle(Handle), -} - -pub struct StdioPipes { - pub stdin: Option<AnonPipe>, - pub stdout: Option<AnonPipe>, - pub stderr: Option<AnonPipe>, -} - -struct DropGuard<'a> { - lock: &'a Mutex, -} - -impl Command { - pub fn new(program: &OsStr) -> Command { - Command { - program: program.to_os_string(), - args: Vec::new(), - env: Default::default(), - cwd: None, - flags: 0, - detach: false, - stdin: None, - stdout: None, - stderr: None, - } - } - - pub fn arg(&mut self, arg: &OsStr) { - self.args.push(arg.to_os_string()) - } - pub fn env_mut(&mut self) -> &mut CommandEnv { - &mut self.env - } - pub fn cwd(&mut self, dir: &OsStr) { - self.cwd = Some(dir.to_os_string()) - } - pub fn stdin(&mut self, stdin: Stdio) { - self.stdin = Some(stdin); - } - pub fn stdout(&mut self, stdout: Stdio) { - self.stdout = Some(stdout); - } - pub fn stderr(&mut self, stderr: Stdio) { - self.stderr = Some(stderr); - } - pub fn creation_flags(&mut self, flags: u32) { - self.flags = flags; - } - - pub fn spawn( - &mut self, - default: Stdio, - needs_stdin: bool, - ) -> io::Result<(Process, StdioPipes)> { - let maybe_env = self.env.capture_if_changed(); - // To have the spawning semantics of unix/windows stay the same, we need - // to read the *child's* PATH if one is provided. See #15149 for more - // details. - let program = maybe_env.as_ref().and_then(|env| { - if let Some(v) = env.get(OsStr::new("PATH")) { - // Split the value and test each path to see if the - // program exists. - for path in split_paths(&v) { - let path = path - .join(self.program.to_str().unwrap()) - .with_extension(env::consts::EXE_EXTENSION); - if fs::metadata(&path).is_ok() { - return Some(path.into_os_string()); - } - } - } - None - }); - - let mut si = zeroed_startupinfo(); - si.cb = mem::size_of::<c::STARTUPINFO>() as c::DWORD; - si.dwFlags = c::STARTF_USESTDHANDLES; - - let program = program.as_ref().unwrap_or(&self.program); - let mut cmd_str = make_command_line(program, &self.args)?; - cmd_str.push(0); // add null terminator - - // stolen from the libuv code. - let mut flags = self.flags | c::CREATE_UNICODE_ENVIRONMENT; - if self.detach { - flags |= c::DETACHED_PROCESS | c::CREATE_NEW_PROCESS_GROUP; - } - - let (envp, _data) = make_envp(maybe_env)?; - let (dirp, _data) = make_dirp(self.cwd.as_ref())?; - let mut pi = zeroed_process_information(); - - // Prepare all stdio handles to be inherited by the child. This - // currently involves duplicating any existing ones with the ability to - // be inherited by child processes. Note, however, that once an - // inheritable handle is created, *any* spawned child will inherit that - // handle. We only want our own child to inherit this handle, so we wrap - // the remaining portion of this spawn in a mutex. - // - // For more information, msdn also has an article about this race: - // http://support.microsoft.com/kb/315939 - static CREATE_PROCESS_LOCK: Mutex = Mutex::new(); - let _guard = DropGuard::new(&CREATE_PROCESS_LOCK); - - let mut pipes = StdioPipes { stdin: None, stdout: None, stderr: None }; - let null = Stdio::Null; - let default_stdin = if needs_stdin { &default } else { &null }; - let stdin = self.stdin.as_ref().unwrap_or(default_stdin); - let stdout = self.stdout.as_ref().unwrap_or(&default); - let stderr = self.stderr.as_ref().unwrap_or(&default); - let stdin = stdin.to_handle(c::STD_INPUT_HANDLE, &mut pipes.stdin)?; - let stdout = stdout.to_handle(c::STD_OUTPUT_HANDLE, &mut pipes.stdout)?; - let stderr = stderr.to_handle(c::STD_ERROR_HANDLE, &mut pipes.stderr)?; - si.hStdInput = stdin.raw(); - si.hStdOutput = stdout.raw(); - si.hStdError = stderr.raw(); - - unsafe { - cvt(c::CreateProcessW( - ptr::null(), - cmd_str.as_mut_ptr(), - ptr::null_mut(), - ptr::null_mut(), - c::TRUE, - flags, - envp, - dirp, - &mut si, - &mut pi, - )) - }?; - - // We close the thread handle because we don't care about keeping - // the thread id valid, and we aren't keeping the thread handle - // around to be able to close it later. - drop(Handle::new(pi.hThread)); - - Ok((Process { handle: Handle::new(pi.hProcess) }, pipes)) - } -} - -impl fmt::Debug for Command { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{:?}", self.program)?; - for arg in &self.args { - write!(f, " {:?}", arg)?; - } - Ok(()) - } -} - -impl<'a> DropGuard<'a> { - fn new(lock: &'a Mutex) -> DropGuard<'a> { - unsafe { - lock.lock(); - DropGuard { lock } - } - } -} - -impl<'a> Drop for DropGuard<'a> { - fn drop(&mut self) { - unsafe { - self.lock.unlock(); - } - } -} - -impl Stdio { - fn to_handle(&self, stdio_id: c::DWORD, pipe: &mut Option<AnonPipe>) -> io::Result<Handle> { - match *self { - // If no stdio handle is available, then inherit means that it - // should still be unavailable so propagate the - // INVALID_HANDLE_VALUE. - Stdio::Inherit => match stdio::get_handle(stdio_id) { - Ok(io) => { - let io = Handle::new(io); - let ret = io.duplicate(0, true, c::DUPLICATE_SAME_ACCESS); - io.into_raw(); - ret - } - Err(..) => Ok(Handle::new(c::INVALID_HANDLE_VALUE)), - }, - - Stdio::MakePipe => { - let ours_readable = stdio_id != c::STD_INPUT_HANDLE; - let pipes = pipe::anon_pipe(ours_readable, true)?; - *pipe = Some(pipes.ours); - Ok(pipes.theirs.into_handle()) - } - - Stdio::Handle(ref handle) => handle.duplicate(0, true, c::DUPLICATE_SAME_ACCESS), - - // Open up a reference to NUL with appropriate read/write - // permissions as well as the ability to be inherited to child - // processes (as this is about to be inherited). - Stdio::Null => { - let size = mem::size_of::<c::SECURITY_ATTRIBUTES>(); - let mut sa = c::SECURITY_ATTRIBUTES { - nLength: size as c::DWORD, - lpSecurityDescriptor: ptr::null_mut(), - bInheritHandle: 1, - }; - let mut opts = OpenOptions::new(); - opts.read(stdio_id == c::STD_INPUT_HANDLE); - opts.write(stdio_id != c::STD_INPUT_HANDLE); - opts.security_attributes(&mut sa); - File::open(Path::new("NUL"), &opts).map(|file| file.into_handle()) - } - } - } -} - -impl From<AnonPipe> for Stdio { - fn from(pipe: AnonPipe) -> Stdio { - Stdio::Handle(pipe.into_handle()) - } -} - -impl From<File> for Stdio { - fn from(file: File) -> Stdio { - Stdio::Handle(file.into_handle()) - } -} - -//////////////////////////////////////////////////////////////////////////////// -// Processes -//////////////////////////////////////////////////////////////////////////////// - -/// A value representing a child process. -/// -/// The lifetime of this value is linked to the lifetime of the actual -/// process - the Process destructor calls self.finish() which waits -/// for the process to terminate. -pub struct Process { - handle: Handle, -} - -impl Process { - pub fn kill(&mut self) -> io::Result<()> { - cvt(unsafe { c::TerminateProcess(self.handle.raw(), 1) })?; - Ok(()) - } - - pub fn id(&self) -> u32 { - unsafe { c::GetProcessId(self.handle.raw()) as u32 } - } - - pub fn wait(&mut self) -> io::Result<ExitStatus> { - unsafe { - let res = c::WaitForSingleObject(self.handle.raw(), c::INFINITE); - if res != c::WAIT_OBJECT_0 { - return Err(Error::last_os_error()); - } - let mut status = 0; - cvt(c::GetExitCodeProcess(self.handle.raw(), &mut status))?; - Ok(ExitStatus(status)) - } - } - - pub fn try_wait(&mut self) -> io::Result<Option<ExitStatus>> { - unsafe { - match c::WaitForSingleObject(self.handle.raw(), 0) { - c::WAIT_OBJECT_0 => {} - c::WAIT_TIMEOUT => { - return Ok(None); - } - _ => return Err(io::Error::last_os_error()), - } - let mut status = 0; - cvt(c::GetExitCodeProcess(self.handle.raw(), &mut status))?; - Ok(Some(ExitStatus(status))) - } - } - - pub fn handle(&self) -> &Handle { - &self.handle - } - - pub fn into_handle(self) -> Handle { - self.handle - } -} - -#[derive(PartialEq, Eq, Clone, Copy, Debug)] -pub struct ExitStatus(c::DWORD); - -impl ExitStatus { - pub fn success(&self) -> bool { - self.0 == 0 - } - pub fn code(&self) -> Option<i32> { - Some(self.0 as i32) - } -} - -/// Converts a raw `c::DWORD` to a type-safe `ExitStatus` by wrapping it without copying. -impl From<c::DWORD> for ExitStatus { - fn from(u: c::DWORD) -> ExitStatus { - ExitStatus(u) - } -} - -impl fmt::Display for ExitStatus { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - // Windows exit codes with the high bit set typically mean some form of - // unhandled exception or warning. In this scenario printing the exit - // code in decimal doesn't always make sense because it's a very large - // and somewhat gibberish number. The hex code is a bit more - // recognizable and easier to search for, so print that. - if self.0 & 0x80000000 != 0 { - write!(f, "exit code: {:#x}", self.0) - } else { - write!(f, "exit code: {}", self.0) - } - } -} - -#[derive(PartialEq, Eq, Clone, Copy, Debug)] -pub struct ExitCode(c::DWORD); - -impl ExitCode { - pub const SUCCESS: ExitCode = ExitCode(EXIT_SUCCESS as _); - pub const FAILURE: ExitCode = ExitCode(EXIT_FAILURE as _); - - #[inline] - pub fn as_i32(&self) -> i32 { - self.0 as i32 - } -} - -fn zeroed_startupinfo() -> c::STARTUPINFO { - c::STARTUPINFO { - cb: 0, - lpReserved: ptr::null_mut(), - lpDesktop: ptr::null_mut(), - lpTitle: ptr::null_mut(), - dwX: 0, - dwY: 0, - dwXSize: 0, - dwYSize: 0, - dwXCountChars: 0, - dwYCountCharts: 0, - dwFillAttribute: 0, - dwFlags: 0, - wShowWindow: 0, - cbReserved2: 0, - lpReserved2: ptr::null_mut(), - hStdInput: c::INVALID_HANDLE_VALUE, - hStdOutput: c::INVALID_HANDLE_VALUE, - hStdError: c::INVALID_HANDLE_VALUE, - } -} - -fn zeroed_process_information() -> c::PROCESS_INFORMATION { - c::PROCESS_INFORMATION { - hProcess: ptr::null_mut(), - hThread: ptr::null_mut(), - dwProcessId: 0, - dwThreadId: 0, - } -} - -// Produces a wide string *without terminating null*; returns an error if -// `prog` or any of the `args` contain a nul. -fn make_command_line(prog: &OsStr, args: &[OsString]) -> io::Result<Vec<u16>> { - // Encode the command and arguments in a command line string such - // that the spawned process may recover them using CommandLineToArgvW. - let mut cmd: Vec<u16> = Vec::new(); - // Always quote the program name so CreateProcess doesn't interpret args as - // part of the name if the binary wasn't found first time. - append_arg(&mut cmd, prog, true)?; - for arg in args { - cmd.push(' ' as u16); - append_arg(&mut cmd, arg, false)?; - } - return Ok(cmd); - - fn append_arg(cmd: &mut Vec<u16>, arg: &OsStr, force_quotes: bool) -> io::Result<()> { - // If an argument has 0 characters then we need to quote it to ensure - // that it actually gets passed through on the command line or otherwise - // it will be dropped entirely when parsed on the other end. - ensure_no_nuls(arg)?; - let arg_bytes = &arg.as_inner().inner.as_inner(); - let quote = force_quotes - || arg_bytes.iter().any(|c| *c == b' ' || *c == b'\t') - || arg_bytes.is_empty(); - if quote { - cmd.push('"' as u16); - } - - let mut backslashes: usize = 0; - for x in arg.encode_wide() { - if x == '\\' as u16 { - backslashes += 1; - } else { - if x == '"' as u16 { - // Add n+1 backslashes to total 2n+1 before internal '"'. - cmd.extend((0..=backslashes).map(|_| '\\' as u16)); - } - backslashes = 0; - } - cmd.push(x); - } - - if quote { - // Add n backslashes to total 2n before ending '"'. - cmd.extend((0..backslashes).map(|_| '\\' as u16)); - cmd.push('"' as u16); - } - Ok(()) - } -} - -fn make_envp(maybe_env: Option<BTreeMap<EnvKey, OsString>>) -> io::Result<(*mut c_void, Vec<u16>)> { - // On Windows we pass an "environment block" which is not a char**, but - // rather a concatenation of null-terminated k=v\0 sequences, with a final - // \0 to terminate. - if let Some(env) = maybe_env { - let mut blk = Vec::new(); - - for (k, v) in env { - blk.extend(ensure_no_nuls(k.0)?.encode_wide()); - blk.push('=' as u16); - blk.extend(ensure_no_nuls(v)?.encode_wide()); - blk.push(0); - } - blk.push(0); - Ok((blk.as_mut_ptr() as *mut c_void, blk)) - } else { - Ok((ptr::null_mut(), Vec::new())) - } -} - -fn make_dirp(d: Option<&OsString>) -> io::Result<(*const u16, Vec<u16>)> { - match d { - Some(dir) => { - let mut dir_str: Vec<u16> = ensure_no_nuls(dir)?.encode_wide().collect(); - dir_str.push(0); - Ok((dir_str.as_ptr(), dir_str)) - } - None => Ok((ptr::null(), Vec::new())), - } -} - -#[cfg(test)] -mod tests { - use super::make_command_line; - use crate::ffi::{OsStr, OsString}; - - #[test] - fn test_make_command_line() { - fn test_wrapper(prog: &str, args: &[&str]) -> String { - let command_line = &make_command_line( - OsStr::new(prog), - &args.iter().map(|a| OsString::from(a)).collect::<Vec<OsString>>(), - ) - .unwrap(); - String::from_utf16(command_line).unwrap() - } - - assert_eq!(test_wrapper("prog", &["aaa", "bbb", "ccc"]), "\"prog\" aaa bbb ccc"); - - assert_eq!( - test_wrapper("C:\\Program Files\\blah\\blah.exe", &["aaa"]), - "\"C:\\Program Files\\blah\\blah.exe\" aaa" - ); - assert_eq!( - test_wrapper("C:\\Program Files\\test", &["aa\"bb"]), - "\"C:\\Program Files\\test\" aa\\\"bb" - ); - assert_eq!(test_wrapper("echo", &["a b c"]), "\"echo\" \"a b c\""); - assert_eq!( - test_wrapper("echo", &["\" \\\" \\", "\\"]), - "\"echo\" \"\\\" \\\\\\\" \\\\\" \\" - ); - assert_eq!( - test_wrapper("\u{03c0}\u{042f}\u{97f3}\u{00e6}\u{221e}", &[]), - "\"\u{03c0}\u{042f}\u{97f3}\u{00e6}\u{221e}\"" - ); - } -} diff --git a/src/libstd/sys/windows/rand.rs b/src/libstd/sys/windows/rand.rs deleted file mode 100644 index 87ea416bf67..00000000000 --- a/src/libstd/sys/windows/rand.rs +++ /dev/null @@ -1,33 +0,0 @@ -use crate::io; -use crate::mem; -use crate::sys::c; - -#[cfg(not(target_vendor = "uwp"))] -pub fn hashmap_random_keys() -> (u64, u64) { - let mut v = (0, 0); - let ret = - unsafe { c::RtlGenRandom(&mut v as *mut _ as *mut u8, mem::size_of_val(&v) as c::ULONG) }; - if ret == 0 { - panic!("couldn't generate random bytes: {}", io::Error::last_os_error()); - } - v -} - -#[cfg(target_vendor = "uwp")] -pub fn hashmap_random_keys() -> (u64, u64) { - use crate::ptr; - - let mut v = (0, 0); - let ret = unsafe { - c::BCryptGenRandom( - ptr::null_mut(), - &mut v as *mut _ as *mut u8, - mem::size_of_val(&v) as c::ULONG, - c::BCRYPT_USE_SYSTEM_PREFERRED_RNG, - ) - }; - if ret != 0 { - panic!("couldn't generate random bytes: {}", io::Error::last_os_error()); - } - return v; -} diff --git a/src/libstd/sys/windows/rwlock.rs b/src/libstd/sys/windows/rwlock.rs deleted file mode 100644 index a769326352c..00000000000 --- a/src/libstd/sys/windows/rwlock.rs +++ /dev/null @@ -1,44 +0,0 @@ -use crate::cell::UnsafeCell; -use crate::sys::c; - -pub struct RWLock { - inner: UnsafeCell<c::SRWLOCK>, -} - -unsafe impl Send for RWLock {} -unsafe impl Sync for RWLock {} - -impl RWLock { - pub const fn new() -> RWLock { - RWLock { inner: UnsafeCell::new(c::SRWLOCK_INIT) } - } - #[inline] - pub unsafe fn read(&self) { - c::AcquireSRWLockShared(self.inner.get()) - } - #[inline] - pub unsafe fn try_read(&self) -> bool { - c::TryAcquireSRWLockShared(self.inner.get()) != 0 - } - #[inline] - pub unsafe fn write(&self) { - c::AcquireSRWLockExclusive(self.inner.get()) - } - #[inline] - pub unsafe fn try_write(&self) -> bool { - c::TryAcquireSRWLockExclusive(self.inner.get()) != 0 - } - #[inline] - pub unsafe fn read_unlock(&self) { - c::ReleaseSRWLockShared(self.inner.get()) - } - #[inline] - pub unsafe fn write_unlock(&self) { - c::ReleaseSRWLockExclusive(self.inner.get()) - } - - #[inline] - pub unsafe fn destroy(&self) { - // ... - } -} diff --git a/src/libstd/sys/windows/stack_overflow.rs b/src/libstd/sys/windows/stack_overflow.rs deleted file mode 100644 index 187ad4e66c3..00000000000 --- a/src/libstd/sys/windows/stack_overflow.rs +++ /dev/null @@ -1,41 +0,0 @@ -#![cfg_attr(test, allow(dead_code))] - -use crate::sys::c; -use crate::sys_common::util::report_overflow; - -pub struct Handler; - -impl Handler { - pub unsafe fn new() -> 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 { - if c::GetLastError() as u32 != c::ERROR_CALL_NOT_IMPLEMENTED as u32 { - panic!("failed to reserve stack space for exception handling"); - } - } - Handler - } -} - -extern "system" fn vectored_handler(ExceptionInfo: *mut c::EXCEPTION_POINTERS) -> c::LONG { - unsafe { - let rec = &(*(*ExceptionInfo).ExceptionRecord); - let code = rec.ExceptionCode; - - if code == c::EXCEPTION_STACK_OVERFLOW { - report_overflow(); - } - c::EXCEPTION_CONTINUE_SEARCH - } -} - -pub unsafe fn init() { - if c::AddVectoredExceptionHandler(0, vectored_handler).is_null() { - panic!("failed to install exception handler"); - } - // Set the thread stack guarantee for the main thread. - let _h = Handler::new(); -} - -pub unsafe fn cleanup() {} diff --git a/src/libstd/sys/windows/stack_overflow_uwp.rs b/src/libstd/sys/windows/stack_overflow_uwp.rs deleted file mode 100644 index e7236cf359c..00000000000 --- a/src/libstd/sys/windows/stack_overflow_uwp.rs +++ /dev/null @@ -1,13 +0,0 @@ -#![cfg_attr(test, allow(dead_code))] - -pub struct Handler; - -impl Handler { - pub fn new() -> Handler { - Handler - } -} - -pub unsafe fn init() {} - -pub unsafe fn cleanup() {} diff --git a/src/libstd/sys/windows/stdio.rs b/src/libstd/sys/windows/stdio.rs deleted file mode 100644 index c84896296ec..00000000000 --- a/src/libstd/sys/windows/stdio.rs +++ /dev/null @@ -1,295 +0,0 @@ -#![unstable(issue = "none", feature = "windows_stdio")] - -use crate::char::decode_utf16; -use crate::cmp; -use crate::io; -use crate::ptr; -use crate::str; -use crate::sys::c; -use crate::sys::cvt; -use crate::sys::handle::Handle; - -// Don't cache handles but get them fresh for every read/write. This allows us to track changes to -// the value over time (such as if a process calls `SetStdHandle` while it's running). See #40490. -pub struct Stdin { - surrogate: u16, -} -pub struct Stdout; -pub struct Stderr; - -// Apparently Windows doesn't handle large reads on stdin or writes to stdout/stderr well (see -// #13304 for details). -// -// From MSDN (2011): "The storage for this buffer is allocated from a shared heap for the -// process that is 64 KB in size. The maximum size of the buffer will depend on heap usage." -// -// We choose the cap at 8 KiB because libuv does the same, and it seems to be acceptable so far. -const MAX_BUFFER_SIZE: usize = 8192; - -// The standard buffer size of BufReader for Stdin should be able to hold 3x more bytes than there -// are `u16`'s in MAX_BUFFER_SIZE. This ensures the read data can always be completely decoded from -// UTF-16 to UTF-8. -pub const STDIN_BUF_SIZE: usize = MAX_BUFFER_SIZE / 2 * 3; - -pub fn get_handle(handle_id: c::DWORD) -> io::Result<c::HANDLE> { - let handle = unsafe { c::GetStdHandle(handle_id) }; - if handle == c::INVALID_HANDLE_VALUE { - Err(io::Error::last_os_error()) - } else if handle.is_null() { - Err(io::Error::from_raw_os_error(c::ERROR_INVALID_HANDLE as i32)) - } else { - Ok(handle) - } -} - -fn is_console(handle: c::HANDLE) -> bool { - // `GetConsoleMode` will return false (0) if this is a pipe (we don't care about the reported - // mode). This will only detect Windows Console, not other terminals connected to a pipe like - // MSYS. Which is exactly what we need, as only Windows Console needs a conversion to UTF-16. - let mut mode = 0; - unsafe { c::GetConsoleMode(handle, &mut mode) != 0 } -} - -fn write(handle_id: c::DWORD, data: &[u8]) -> io::Result<usize> { - let handle = get_handle(handle_id)?; - if !is_console(handle) { - let handle = Handle::new(handle); - let ret = handle.write(data); - handle.into_raw(); // Don't close the handle - return ret; - } - - // As the console is meant for presenting text, we assume bytes of `data` come from a string - // and are encoded as UTF-8, which needs to be encoded as UTF-16. - // - // If the data is not valid UTF-8 we write out as many bytes as are valid. - // Only when there are no valid bytes (which will happen on the next call), return an error. - let len = cmp::min(data.len(), MAX_BUFFER_SIZE / 2); - let utf8 = match str::from_utf8(&data[..len]) { - Ok(s) => s, - Err(ref e) if e.valid_up_to() == 0 => { - return Err(io::Error::new( - io::ErrorKind::InvalidData, - "Windows stdio in console mode does not support writing non-UTF-8 byte sequences", - )); - } - Err(e) => str::from_utf8(&data[..e.valid_up_to()]).unwrap(), - }; - let mut utf16 = [0u16; MAX_BUFFER_SIZE / 2]; - let mut len_utf16 = 0; - for (chr, dest) in utf8.encode_utf16().zip(utf16.iter_mut()) { - *dest = chr; - len_utf16 += 1; - } - let utf16 = &utf16[..len_utf16]; - - let mut written = write_u16s(handle, &utf16)?; - - // Figure out how many bytes of as UTF-8 were written away as UTF-16. - if written == utf16.len() { - Ok(utf8.len()) - } else { - // Make sure we didn't end up writing only half of a surrogate pair (even though the chance - // is tiny). Because it is not possible for user code to re-slice `data` in such a way that - // a missing surrogate can be produced (and also because of the UTF-8 validation above), - // write the missing surrogate out now. - // Buffering it would mean we have to lie about the number of bytes written. - let first_char_remaining = utf16[written]; - if first_char_remaining >= 0xDCEE && first_char_remaining <= 0xDFFF { - // low surrogate - // We just hope this works, and give up otherwise - let _ = write_u16s(handle, &utf16[written..written + 1]); - written += 1; - } - // Calculate the number of bytes of `utf8` that were actually written. - let mut count = 0; - for ch in utf16[..written].iter() { - count += match ch { - 0x0000..=0x007F => 1, - 0x0080..=0x07FF => 2, - 0xDCEE..=0xDFFF => 1, // Low surrogate. We already counted 3 bytes for the other. - _ => 3, - }; - } - debug_assert!(String::from_utf16(&utf16[..written]).unwrap() == utf8[..count]); - Ok(count) - } -} - -fn write_u16s(handle: c::HANDLE, data: &[u16]) -> io::Result<usize> { - let mut written = 0; - cvt(unsafe { - c::WriteConsoleW( - handle, - data.as_ptr() as c::LPCVOID, - data.len() as u32, - &mut written, - ptr::null_mut(), - ) - })?; - Ok(written as usize) -} - -impl Stdin { - pub fn new() -> io::Result<Stdin> { - Ok(Stdin { surrogate: 0 }) - } -} - -impl io::Read for Stdin { - fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { - let handle = get_handle(c::STD_INPUT_HANDLE)?; - if !is_console(handle) { - let handle = Handle::new(handle); - let ret = handle.read(buf); - handle.into_raw(); // Don't close the handle - return ret; - } - - if buf.len() == 0 { - return Ok(0); - } else if buf.len() < 4 { - return Err(io::Error::new( - io::ErrorKind::InvalidInput, - "Windows stdin in console mode does not support a buffer too small to \ - guarantee holding one arbitrary UTF-8 character (4 bytes)", - )); - } - - let mut utf16_buf = [0u16; MAX_BUFFER_SIZE / 2]; - // In the worst case, an UTF-8 string can take 3 bytes for every `u16` of an UTF-16. So - // we can read at most a third of `buf.len()` chars and uphold the guarantee no data gets - // lost. - let amount = cmp::min(buf.len() / 3, utf16_buf.len()); - let read = read_u16s_fixup_surrogates(handle, &mut utf16_buf, amount, &mut self.surrogate)?; - - utf16_to_utf8(&utf16_buf[..read], buf) - } -} - -// We assume that if the last `u16` is an unpaired surrogate they got sliced apart by our -// buffer size, and keep it around for the next read hoping to put them together. -// This is a best effort, and may not work if we are not the only reader on Stdin. -fn read_u16s_fixup_surrogates( - handle: c::HANDLE, - buf: &mut [u16], - mut amount: usize, - surrogate: &mut u16, -) -> io::Result<usize> { - // Insert possibly remaining unpaired surrogate from last read. - let mut start = 0; - if *surrogate != 0 { - buf[0] = *surrogate; - *surrogate = 0; - start = 1; - if amount == 1 { - // Special case: `Stdin::read` guarantees we can always read at least one new `u16` - // and combine it with an unpaired surrogate, because the UTF-8 buffer is at least - // 4 bytes. - amount = 2; - } - } - let mut amount = read_u16s(handle, &mut buf[start..amount])? + start; - - if amount > 0 { - let last_char = buf[amount - 1]; - if last_char >= 0xD800 && last_char <= 0xDBFF { - // high surrogate - *surrogate = last_char; - amount -= 1; - } - } - Ok(amount) -} - -fn read_u16s(handle: c::HANDLE, buf: &mut [u16]) -> io::Result<usize> { - // Configure the `pInputControl` parameter to not only return on `\r\n` but also Ctrl-Z, the - // traditional DOS method to indicate end of character stream / user input (SUB). - // See #38274 and https://stackoverflow.com/questions/43836040/win-api-readconsole. - const CTRL_Z: u16 = 0x1A; - const CTRL_Z_MASK: c::ULONG = 1 << CTRL_Z; - let mut input_control = c::CONSOLE_READCONSOLE_CONTROL { - nLength: crate::mem::size_of::<c::CONSOLE_READCONSOLE_CONTROL>() as c::ULONG, - nInitialChars: 0, - dwCtrlWakeupMask: CTRL_Z_MASK, - dwControlKeyState: 0, - }; - - let mut amount = 0; - cvt(unsafe { - c::ReadConsoleW( - handle, - buf.as_mut_ptr() as c::LPVOID, - buf.len() as u32, - &mut amount, - &mut input_control as c::PCONSOLE_READCONSOLE_CONTROL, - ) - })?; - - if amount > 0 && buf[amount as usize - 1] == CTRL_Z { - amount -= 1; - } - Ok(amount as usize) -} - -#[allow(unused)] -fn utf16_to_utf8(utf16: &[u16], utf8: &mut [u8]) -> io::Result<usize> { - let mut written = 0; - for chr in decode_utf16(utf16.iter().cloned()) { - match chr { - Ok(chr) => { - chr.encode_utf8(&mut utf8[written..]); - written += chr.len_utf8(); - } - Err(_) => { - // We can't really do any better than forget all data and return an error. - return Err(io::Error::new( - io::ErrorKind::InvalidData, - "Windows stdin in console mode does not support non-UTF-16 input; \ - encountered unpaired surrogate", - )); - } - } - } - Ok(written) -} - -impl Stdout { - pub fn new() -> io::Result<Stdout> { - Ok(Stdout) - } -} - -impl io::Write for Stdout { - fn write(&mut self, buf: &[u8]) -> io::Result<usize> { - write(c::STD_OUTPUT_HANDLE, buf) - } - - fn flush(&mut self) -> io::Result<()> { - Ok(()) - } -} - -impl Stderr { - pub fn new() -> io::Result<Stderr> { - Ok(Stderr) - } -} - -impl io::Write for Stderr { - fn write(&mut self, buf: &[u8]) -> io::Result<usize> { - write(c::STD_ERROR_HANDLE, buf) - } - - fn flush(&mut self) -> io::Result<()> { - Ok(()) - } -} - -pub fn is_ebadf(err: &io::Error) -> bool { - err.raw_os_error() == Some(c::ERROR_INVALID_HANDLE as i32) -} - -pub fn panic_output() -> Option<impl io::Write> { - Stderr::new().ok() -} diff --git a/src/libstd/sys/windows/stdio_uwp.rs b/src/libstd/sys/windows/stdio_uwp.rs deleted file mode 100644 index 5bdabf6d4b7..00000000000 --- a/src/libstd/sys/windows/stdio_uwp.rs +++ /dev/null @@ -1,84 +0,0 @@ -#![unstable(issue = "none", feature = "windows_stdio")] - -use crate::io; -use crate::mem::ManuallyDrop; -use crate::sys::c; -use crate::sys::handle::Handle; - -pub struct Stdin {} -pub struct Stdout; -pub struct Stderr; - -const MAX_BUFFER_SIZE: usize = 8192; -pub const STDIN_BUF_SIZE: usize = MAX_BUFFER_SIZE / 2 * 3; - -pub fn get_handle(handle_id: c::DWORD) -> io::Result<c::HANDLE> { - let handle = unsafe { c::GetStdHandle(handle_id) }; - if handle == c::INVALID_HANDLE_VALUE { - Err(io::Error::last_os_error()) - } else if handle.is_null() { - Err(io::Error::from_raw_os_error(c::ERROR_INVALID_HANDLE as i32)) - } else { - Ok(handle) - } -} - -fn write(handle_id: c::DWORD, data: &[u8]) -> io::Result<usize> { - let handle = get_handle(handle_id)?; - let handle = Handle::new(handle); - ManuallyDrop::new(handle).write(data) -} - -impl Stdin { - pub fn new() -> io::Result<Stdin> { - Ok(Stdin {}) - } -} - -impl io::Read for Stdin { - fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { - let handle = get_handle(c::STD_INPUT_HANDLE)?; - let handle = Handle::new(handle); - ManuallyDrop::new(handle).read(buf) - } -} - -impl Stdout { - pub fn new() -> io::Result<Stdout> { - Ok(Stdout) - } -} - -impl io::Write for Stdout { - fn write(&mut self, buf: &[u8]) -> io::Result<usize> { - write(c::STD_OUTPUT_HANDLE, buf) - } - - fn flush(&mut self) -> io::Result<()> { - Ok(()) - } -} - -impl Stderr { - pub fn new() -> io::Result<Stderr> { - Ok(Stderr) - } -} - -impl io::Write for Stderr { - fn write(&mut self, buf: &[u8]) -> io::Result<usize> { - write(c::STD_ERROR_HANDLE, buf) - } - - fn flush(&mut self) -> io::Result<()> { - Ok(()) - } -} - -pub fn is_ebadf(err: &io::Error) -> bool { - err.raw_os_error() == Some(c::ERROR_INVALID_HANDLE as i32) -} - -pub fn panic_output() -> Option<impl io::Write> { - Stderr::new().ok() -} diff --git a/src/libstd/sys/windows/thread.rs b/src/libstd/sys/windows/thread.rs deleted file mode 100644 index 38839ea5e90..00000000000 --- a/src/libstd/sys/windows/thread.rs +++ /dev/null @@ -1,110 +0,0 @@ -use crate::ffi::CStr; -use crate::io; -use crate::ptr; -use crate::sys::c; -use crate::sys::handle::Handle; -use crate::sys::stack_overflow; -use crate::time::Duration; - -use libc::c_void; - -use super::to_u16s; - -pub const DEFAULT_MIN_STACK_SIZE: usize = 2 * 1024 * 1024; - -pub struct Thread { - handle: Handle, -} - -impl Thread { - // unsafe: see thread::Builder::spawn_unchecked for safety requirements - pub unsafe fn new(stack: usize, p: Box<dyn FnOnce()>) -> io::Result<Thread> { - let p = Box::into_raw(box p); - - // FIXME On UNIX, we guard against stack sizes that are too small but - // that's because pthreads enforces that stacks are at least - // PTHREAD_STACK_MIN bytes big. Windows has no such lower limit, it's - // just that below a certain threshold you can't do anything useful. - // That threshold is application and architecture-specific, however. - // Round up to the next 64 kB because that's what the NT kernel does, - // might as well make it explicit. - let stack_size = (stack + 0xfffe) & (!0xfffe); - let ret = c::CreateThread( - ptr::null_mut(), - stack_size, - thread_start, - p as *mut _, - c::STACK_SIZE_PARAM_IS_A_RESERVATION, - ptr::null_mut(), - ); - - return if ret as usize == 0 { - // The thread failed to start and as a result p was not consumed. Therefore, it is - // safe to reconstruct the box so that it gets deallocated. - drop(Box::from_raw(p)); - Err(io::Error::last_os_error()) - } else { - Ok(Thread { handle: Handle::new(ret) }) - }; - - extern "system" fn thread_start(main: *mut c_void) -> c::DWORD { - unsafe { - // Next, set up our stack overflow handler which may get triggered if we run - // out of stack. - let _handler = stack_overflow::Handler::new(); - // Finally, let's run some code. - Box::from_raw(main as *mut Box<dyn FnOnce()>)(); - } - 0 - } - } - - pub fn set_name(name: &CStr) { - if let Ok(utf8) = name.to_str() { - if let Ok(utf16) = to_u16s(utf8) { - unsafe { - c::SetThreadDescription(c::GetCurrentThread(), utf16.as_ptr()); - }; - }; - }; - } - - pub fn join(self) { - let rc = unsafe { c::WaitForSingleObject(self.handle.raw(), c::INFINITE) }; - if rc == c::WAIT_FAILED { - panic!("failed to join on thread: {}", io::Error::last_os_error()); - } - } - - pub fn yield_now() { - // This function will return 0 if there are no other threads to execute, - // but this also means that the yield was useless so this isn't really a - // case that needs to be worried about. - unsafe { - c::SwitchToThread(); - } - } - - pub fn sleep(dur: Duration) { - unsafe { c::Sleep(super::dur2timeout(dur)) } - } - - pub fn handle(&self) -> &Handle { - &self.handle - } - - pub fn into_handle(self) -> Handle { - self.handle - } -} - -#[cfg_attr(test, allow(dead_code))] -pub mod guard { - pub type Guard = !; - pub unsafe fn current() -> Option<Guard> { - None - } - pub unsafe fn init() -> Option<Guard> { - None - } -} diff --git a/src/libstd/sys/windows/thread_local_dtor.rs b/src/libstd/sys/windows/thread_local_dtor.rs deleted file mode 100644 index 7be13bc4b2b..00000000000 --- a/src/libstd/sys/windows/thread_local_dtor.rs +++ /dev/null @@ -1,4 +0,0 @@ -#![unstable(feature = "thread_local_internals", issue = "none")] -#![cfg(target_thread_local)] - -pub use crate::sys_common::thread_local_dtor::register_dtor_fallback as register_dtor; diff --git a/src/libstd/sys/windows/thread_local_key.rs b/src/libstd/sys/windows/thread_local_key.rs deleted file mode 100644 index 82901871e78..00000000000 --- a/src/libstd/sys/windows/thread_local_key.rs +++ /dev/null @@ -1,252 +0,0 @@ -use crate::mem; -use crate::ptr; -use crate::sync::atomic::AtomicPtr; -use crate::sync::atomic::Ordering::SeqCst; -use crate::sys::c; - -pub type Key = c::DWORD; -pub type Dtor = unsafe extern "C" fn(*mut u8); - -// Turns out, like pretty much everything, Windows is pretty close the -// functionality that Unix provides, but slightly different! In the case of -// TLS, Windows does not provide an API to provide a destructor for a TLS -// variable. This ends up being pretty crucial to this implementation, so we -// need a way around this. -// -// The solution here ended up being a little obscure, but fear not, the -// internet has informed me [1][2] that this solution is not unique (no way -// I could have thought of it as well!). The key idea is to insert some hook -// somewhere to run arbitrary code on thread termination. With this in place -// we'll be able to run anything we like, including all TLS destructors! -// -// To accomplish this feat, we perform a number of threads, all contained -// within this module: -// -// * All TLS destructors are tracked by *us*, not the windows runtime. This -// means that we have a global list of destructors for each TLS key that -// we know about. -// * When a thread exits, we run over the entire list and run dtors for all -// non-null keys. This attempts to match Unix semantics in this regard. -// -// This ends up having the overhead of using a global list, having some -// locks here and there, and in general just adding some more code bloat. We -// attempt to optimize runtime by forgetting keys that don't have -// destructors, but this only gets us so far. -// -// For more details and nitty-gritty, see the code sections below! -// -// [1]: http://www.codeproject.com/Articles/8113/Thread-Local-Storage-The-C-Way -// [2]: https://github.com/ChromiumWebApps/chromium/blob/master/base -// /threading/thread_local_storage_win.cc#L42 - -// ------------------------------------------------------------------------- -// Native bindings -// -// This section is just raw bindings to the native functions that Windows -// provides, There's a few extra calls to deal with destructors. - -#[inline] -pub unsafe fn create(dtor: Option<Dtor>) -> Key { - let key = c::TlsAlloc(); - assert!(key != c::TLS_OUT_OF_INDEXES); - if let Some(f) = dtor { - register_dtor(key, f); - } - key -} - -#[inline] -pub unsafe fn set(key: Key, value: *mut u8) { - let r = c::TlsSetValue(key, value as c::LPVOID); - debug_assert!(r != 0); -} - -#[inline] -pub unsafe fn get(key: Key) -> *mut u8 { - c::TlsGetValue(key) as *mut u8 -} - -#[inline] -pub unsafe fn destroy(_key: Key) { - rtabort!("can't destroy tls keys on windows") -} - -#[inline] -pub fn requires_synchronized_create() -> bool { - true -} - -// ------------------------------------------------------------------------- -// Dtor registration -// -// Windows has no native support for running destructors so we manage our own -// list of destructors to keep track of how to destroy keys. We then install a -// callback later to get invoked whenever a thread exits, running all -// appropriate destructors. -// -// Currently unregistration from this list is not supported. A destructor can be -// registered but cannot be unregistered. There's various simplifying reasons -// for doing this, the big ones being: -// -// 1. Currently we don't even support deallocating TLS keys, so normal operation -// doesn't need to deallocate a destructor. -// 2. There is no point in time where we know we can unregister a destructor -// because it could always be getting run by some remote thread. -// -// Typically processes have a statically known set of TLS keys which is pretty -// small, and we'd want to keep this memory alive for the whole process anyway -// really. -// -// Perhaps one day we can fold the `Box` here into a static allocation, -// expanding the `StaticKey` structure to contain not only a slot for the TLS -// key but also a slot for the destructor queue on windows. An optimization for -// another day! - -static DTORS: AtomicPtr<Node> = AtomicPtr::new(ptr::null_mut()); - -struct Node { - dtor: Dtor, - key: Key, - next: *mut Node, -} - -#[cfg(miri)] -extern "Rust" { - /// Miri-provided extern function to mark the block `ptr` points to as a "root" - /// for some static memory. This memory and everything reachable by it is not - /// considered leaking even if it still exists when the program terminates. - /// - /// `ptr` has to point to the beginning of an allocated block. - fn miri_static_root(ptr: *const u8); -} - -unsafe fn register_dtor(key: Key, dtor: Dtor) { - let mut node = Box::new(Node { key, dtor, next: ptr::null_mut() }); - - let mut head = DTORS.load(SeqCst); - loop { - node.next = head; - match DTORS.compare_exchange(head, &mut *node, SeqCst, SeqCst) { - Ok(_) => { - #[cfg(miri)] - miri_static_root(&*node as *const _ as *const u8); - - mem::forget(node); - return; - } - Err(cur) => head = cur, - } - } -} - -// ------------------------------------------------------------------------- -// Where the Magic (TM) Happens -// -// If you're looking at this code, and wondering "what is this doing?", -// you're not alone! I'll try to break this down step by step: -// -// # What's up with CRT$XLB? -// -// For anything about TLS destructors to work on Windows, we have to be able -// to run *something* when a thread exits. To do so, we place a very special -// static in a very special location. If this is encoded in just the right -// way, the kernel's loader is apparently nice enough to run some function -// of ours whenever a thread exits! How nice of the kernel! -// -// Lots of detailed information can be found in source [1] above, but the -// gist of it is that this is leveraging a feature of Microsoft's PE format -// (executable format) which is not actually used by any compilers today. -// This apparently translates to any callbacks in the ".CRT$XLB" section -// being run on certain events. -// -// So after all that, we use the compiler's #[link_section] feature to place -// a callback pointer into the magic section so it ends up being called. -// -// # What's up with this callback? -// -// The callback specified receives a number of parameters from... someone! -// (the kernel? the runtime? I'm not quite sure!) There are a few events that -// this gets invoked for, but we're currently only interested on when a -// thread or a process "detaches" (exits). The process part happens for the -// last thread and the thread part happens for any normal thread. -// -// # Ok, what's up with running all these destructors? -// -// This will likely need to be improved over time, but this function -// attempts a "poor man's" destructor callback system. Once we've got a list -// of what to run, we iterate over all keys, check their values, and then run -// destructors if the values turn out to be non null (setting them to null just -// beforehand). We do this a few times in a loop to basically match Unix -// semantics. If we don't reach a fixed point after a short while then we just -// inevitably leak something most likely. -// -// # The article mentions weird stuff about "/INCLUDE"? -// -// It sure does! Specifically we're talking about this quote: -// -// The Microsoft run-time library facilitates this process by defining a -// memory image of the TLS Directory and giving it the special name -// “__tls_used” (Intel x86 platforms) or “_tls_used” (other platforms). The -// linker looks for this memory image and uses the data there to create the -// TLS Directory. Other compilers that support TLS and work with the -// Microsoft linker must use this same technique. -// -// Basically what this means is that if we want support for our TLS -// destructors/our hook being called then we need to make sure the linker does -// not omit this symbol. Otherwise it will omit it and our callback won't be -// wired up. -// -// We don't actually use the `/INCLUDE` linker flag here like the article -// mentions because the Rust compiler doesn't propagate linker flags, but -// instead we use a shim function which performs a volatile 1-byte load from -// the address of the symbol to ensure it sticks around. - -#[link_section = ".CRT$XLB"] -#[allow(dead_code, unused_variables)] -#[used] // we don't want LLVM eliminating this symbol for any reason, and -// when the symbol makes it to the linker the linker will take over -pub static p_thread_callback: unsafe extern "system" fn(c::LPVOID, c::DWORD, c::LPVOID) = - on_tls_callback; - -#[allow(dead_code, unused_variables)] -unsafe extern "system" fn on_tls_callback(h: c::LPVOID, dwReason: c::DWORD, pv: c::LPVOID) { - if dwReason == c::DLL_THREAD_DETACH || dwReason == c::DLL_PROCESS_DETACH { - run_dtors(); - } - - // See comments above for what this is doing. Note that we don't need this - // trickery on GNU windows, just on MSVC. - reference_tls_used(); - #[cfg(target_env = "msvc")] - unsafe fn reference_tls_used() { - extern "C" { - static _tls_used: u8; - } - crate::intrinsics::volatile_load(&_tls_used); - } - #[cfg(not(target_env = "msvc"))] - unsafe fn reference_tls_used() {} -} - -#[allow(dead_code)] // actually called above -unsafe fn run_dtors() { - let mut any_run = true; - for _ in 0..5 { - if !any_run { - break; - } - any_run = false; - let mut cur = DTORS.load(SeqCst); - while !cur.is_null() { - let ptr = c::TlsGetValue((*cur).key); - - if !ptr.is_null() { - c::TlsSetValue((*cur).key, ptr::null_mut()); - ((*cur).dtor)(ptr as *mut _); - any_run = true; - } - - cur = (*cur).next; - } - } -} diff --git a/src/libstd/sys/windows/time.rs b/src/libstd/sys/windows/time.rs deleted file mode 100644 index 900260169c7..00000000000 --- a/src/libstd/sys/windows/time.rs +++ /dev/null @@ -1,228 +0,0 @@ -use crate::cmp::Ordering; -use crate::convert::TryInto; -use crate::fmt; -use crate::mem; -use crate::sys::c; -use crate::time::Duration; - -use core::hash::{Hash, Hasher}; - -const NANOS_PER_SEC: u64 = 1_000_000_000; -const INTERVALS_PER_SEC: u64 = NANOS_PER_SEC / 100; - -#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Debug, Hash)] -pub struct Instant { - // This duration is relative to an arbitrary microsecond epoch - // from the winapi QueryPerformanceCounter function. - t: Duration, -} - -#[derive(Copy, Clone)] -pub struct SystemTime { - t: c::FILETIME, -} - -const INTERVALS_TO_UNIX_EPOCH: u64 = 11_644_473_600 * INTERVALS_PER_SEC; - -pub const UNIX_EPOCH: SystemTime = SystemTime { - t: c::FILETIME { - dwLowDateTime: INTERVALS_TO_UNIX_EPOCH as u32, - dwHighDateTime: (INTERVALS_TO_UNIX_EPOCH >> 32) as u32, - }, -}; - -impl Instant { - pub fn now() -> Instant { - // High precision timing on windows operates in "Performance Counter" - // units, as returned by the WINAPI QueryPerformanceCounter function. - // These relate to seconds by a factor of QueryPerformanceFrequency. - // In order to keep unit conversions out of normal interval math, we - // measure in QPC units and immediately convert to nanoseconds. - perf_counter::PerformanceCounterInstant::now().into() - } - - pub fn actually_monotonic() -> bool { - false - } - - pub const fn zero() -> Instant { - Instant { t: Duration::from_secs(0) } - } - - pub fn checked_sub_instant(&self, other: &Instant) -> Option<Duration> { - // On windows there's a threshold below which we consider two timestamps - // equivalent due to measurement error. For more details + doc link, - // check the docs on epsilon. - let epsilon = perf_counter::PerformanceCounterInstant::epsilon(); - if other.t > self.t && other.t - self.t <= epsilon { - Some(Duration::new(0, 0)) - } else { - self.t.checked_sub(other.t) - } - } - - pub fn checked_add_duration(&self, other: &Duration) -> Option<Instant> { - Some(Instant { t: self.t.checked_add(*other)? }) - } - - pub fn checked_sub_duration(&self, other: &Duration) -> Option<Instant> { - Some(Instant { t: self.t.checked_sub(*other)? }) - } -} - -impl SystemTime { - pub fn now() -> SystemTime { - unsafe { - let mut t: SystemTime = mem::zeroed(); - c::GetSystemTimePreciseAsFileTime(&mut t.t); - t - } - } - - fn from_intervals(intervals: i64) -> SystemTime { - SystemTime { - t: c::FILETIME { - dwLowDateTime: intervals as c::DWORD, - dwHighDateTime: (intervals >> 32) as c::DWORD, - }, - } - } - - fn intervals(&self) -> i64 { - (self.t.dwLowDateTime as i64) | ((self.t.dwHighDateTime as i64) << 32) - } - - pub fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> { - let me = self.intervals(); - let other = other.intervals(); - if me >= other { - Ok(intervals2dur((me - other) as u64)) - } else { - Err(intervals2dur((other - me) as u64)) - } - } - - pub fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> { - let intervals = self.intervals().checked_add(checked_dur2intervals(other)?)?; - Some(SystemTime::from_intervals(intervals)) - } - - pub fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> { - let intervals = self.intervals().checked_sub(checked_dur2intervals(other)?)?; - Some(SystemTime::from_intervals(intervals)) - } -} - -impl PartialEq for SystemTime { - fn eq(&self, other: &SystemTime) -> bool { - self.intervals() == other.intervals() - } -} - -impl Eq for SystemTime {} - -impl PartialOrd for SystemTime { - fn partial_cmp(&self, other: &SystemTime) -> Option<Ordering> { - Some(self.cmp(other)) - } -} - -impl Ord for SystemTime { - fn cmp(&self, other: &SystemTime) -> Ordering { - self.intervals().cmp(&other.intervals()) - } -} - -impl fmt::Debug for SystemTime { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("SystemTime").field("intervals", &self.intervals()).finish() - } -} - -impl From<c::FILETIME> for SystemTime { - fn from(t: c::FILETIME) -> SystemTime { - SystemTime { t } - } -} - -impl Hash for SystemTime { - fn hash<H: Hasher>(&self, state: &mut H) { - self.intervals().hash(state) - } -} - -fn checked_dur2intervals(dur: &Duration) -> Option<i64> { - dur.as_secs() - .checked_mul(INTERVALS_PER_SEC)? - .checked_add(dur.subsec_nanos() as u64 / 100)? - .try_into() - .ok() -} - -fn intervals2dur(intervals: u64) -> Duration { - Duration::new(intervals / INTERVALS_PER_SEC, ((intervals % INTERVALS_PER_SEC) * 100) as u32) -} - -mod perf_counter { - use super::NANOS_PER_SEC; - use crate::sync::atomic::{AtomicUsize, Ordering::SeqCst}; - use crate::sys::c; - use crate::sys::cvt; - use crate::sys_common::mul_div_u64; - use crate::time::Duration; - - pub struct PerformanceCounterInstant { - ts: c::LARGE_INTEGER, - } - impl PerformanceCounterInstant { - pub fn now() -> Self { - Self { ts: query() } - } - - // Per microsoft docs, the margin of error for cross-thread time comparisons - // using QueryPerformanceCounter is 1 "tick" -- defined as 1/frequency(). - // Reference: https://docs.microsoft.com/en-us/windows/desktop/SysInfo - // /acquiring-high-resolution-time-stamps - pub fn epsilon() -> Duration { - let epsilon = NANOS_PER_SEC / (frequency() as u64); - Duration::from_nanos(epsilon) - } - } - impl From<PerformanceCounterInstant> for super::Instant { - fn from(other: PerformanceCounterInstant) -> Self { - let freq = frequency() as u64; - let instant_nsec = mul_div_u64(other.ts as u64, NANOS_PER_SEC, freq); - Self { t: Duration::from_nanos(instant_nsec) } - } - } - - fn frequency() -> c::LARGE_INTEGER { - static mut FREQUENCY: c::LARGE_INTEGER = 0; - static STATE: AtomicUsize = AtomicUsize::new(0); - - unsafe { - // If a previous thread has filled in this global state, use that. - if STATE.load(SeqCst) == 2 { - return FREQUENCY; - } - - // ... otherwise learn for ourselves ... - let mut frequency = 0; - cvt(c::QueryPerformanceFrequency(&mut frequency)).unwrap(); - - // ... and attempt to be the one thread that stores it globally for - // all other threads - if STATE.compare_exchange(0, 1, SeqCst, SeqCst).is_ok() { - FREQUENCY = frequency; - STATE.store(2, SeqCst); - } - frequency - } - } - - fn query() -> c::LARGE_INTEGER { - let mut qpc_value: c::LARGE_INTEGER = 0; - cvt(unsafe { c::QueryPerformanceCounter(&mut qpc_value) }).unwrap(); - qpc_value - } -} |
