Auto merge of #60260 - videolabs:rust_uwp2, r=alexcrichton

Add support for UWP targets

Hi,

This pull request aims at adding support for UWP (Universal Windows Apps) platform.
A few notes:
- This requires a very recent mingw-w64 version (containing this commit and the previous related ones: e8c433c871 (diff-eefdfbfe9cec5f4ebab88c9a64d423a9))
- This was tested using LLVM/clang rather than gcc, and so far it assumes that LLVM/clang will be the native compiler. This is mostly due to the fact that the support for exceptions/stack unwinding for UWP got much more attention in libunwind
- The "uwp" part of the target needs support for it in the `cc-rs` & `backtrace-rs` crates. I'll create the MR there right after I submit this one and will link everything together, but I'm not sure what's the correct way of dealing with external dependencies in the context of rust
- Enabling import libraries and copying them across stages requires a change in cargo, for which I'll open a MR right after I submit this one as well
- The i686 stack unwinding is unsupported for now, because LLVM assumes SjLj, while rust seems to assume SEH will be used. I'm unsure how to fix this

Also, this is my first encounter with rust, so please bear with my code, it might not feel so idiomatic or even correct :)

I'm pretty sure there's a way of doing things in a cleaner way when it comes to win/c.rs, maybe having a UWP & desktop specific modules, and import those conditionally? It doesn't feel right to sprinkle `#[cfg(...)]` all over the place

Off course, I'll gladly update anything you see fit (to the extent of my abilities/knowledge :) )!

Thanks,
This commit is contained in:
bors 2019-07-26 02:18:12 +00:00
commit 4268e7ee22
20 changed files with 529 additions and 117 deletions

View File

@ -325,7 +325,7 @@ impl Step for StartupObjects {
fn run(self, builder: &Builder<'_>) {
let for_compiler = self.compiler;
let target = self.target;
if !target.contains("pc-windows-gnu") {
if !target.contains("windows-gnu") {
return
}
@ -1126,6 +1126,7 @@ pub fn run_cargo(builder: &Builder<'_>,
// Skip files like executables
if !filename.ends_with(".rlib") &&
!filename.ends_with(".lib") &&
!filename.ends_with(".a") &&
!is_dylib(&filename) &&
!(is_check && filename.ends_with(".rmeta")) {
continue;

View File

@ -368,6 +368,26 @@ impl<'a> Linker for GccLinker<'a> {
}
} else {
self.cmd.arg("-shared");
if self.sess.target.target.options.is_like_windows {
// The output filename already contains `dll_suffix` so
// the resulting import library will have a name in the
// form of libfoo.dll.a
let implib_name = out_filename
.file_name()
.and_then(|file| file.to_str())
.map(|file| format!("{}{}{}",
self.sess.target.target.options.staticlib_prefix,
file,
self.sess.target.target.options.staticlib_suffix));
if let Some(implib_name) = implib_name {
let implib = out_filename
.parent()
.map(|dir| dir.join(&implib_name));
if let Some(implib) = implib {
self.linker_arg(&format!("--out-implib,{}", (*implib).to_str().unwrap()));
}
}
}
}
}

View File

@ -0,0 +1,27 @@
use crate::spec::{LinkerFlavor, Target, TargetResult};
pub fn target() -> TargetResult {
let mut base = super::windows_uwp_base::opts();
base.cpu = "pentium4".to_string();
base.max_atomic_width = Some(64);
base.eliminate_frame_pointer = false; // Required for backtraces
// Mark all dynamic libraries and executables as compatible with the larger 4GiB address
// space available to x86 Windows binaries on x86_64.
base.pre_link_args
.get_mut(&LinkerFlavor::Gcc).unwrap().push("-Wl,--large-address-aware".to_string());
Ok(Target {
llvm_target: "i686-pc-windows-gnu".to_string(),
target_endian: "little".to_string(),
target_pointer_width: "32".to_string(),
target_c_int_width: "32".to_string(),
data_layout: "e-m:x-p:32:32-i64:64-f80:32-n8:16:32-a:0:32-S32".to_string(),
arch: "x86".to_string(),
target_os: "windows".to_string(),
target_env: "gnu".to_string(),
target_vendor: "uwp".to_string(),
linker_flavor: LinkerFlavor::Gcc,
options: base,
})
}

View File

@ -60,6 +60,7 @@ mod solaris_base;
mod uefi_base;
mod windows_base;
mod windows_msvc_base;
mod windows_uwp_base;
mod thumb_base;
mod l4re_base;
mod fuchsia_base;
@ -434,6 +435,8 @@ supported_targets! {
("x86_64-pc-windows-gnu", x86_64_pc_windows_gnu),
("i686-pc-windows-gnu", i686_pc_windows_gnu),
("i686-uwp-windows-gnu", i686_uwp_windows_gnu),
("x86_64-uwp-windows-gnu", x86_64_uwp_windows_gnu),
("aarch64-pc-windows-msvc", aarch64_pc_windows_msvc),
("x86_64-pc-windows-msvc", x86_64_pc_windows_msvc),

View File

@ -0,0 +1,64 @@
use crate::spec::{LinkArgs, LinkerFlavor, TargetOptions};
use std::default::Default;
pub fn opts() -> TargetOptions {
let mut pre_link_args = LinkArgs::new();
pre_link_args.insert(LinkerFlavor::Gcc, vec![
// Tell GCC to avoid linker plugins, because we are not bundling
// them with Windows installer, and Rust does its own LTO anyways.
"-fno-use-linker-plugin".to_string(),
// Always enable DEP (NX bit) when it is available
"-Wl,--nxcompat".to_string(),
]);
let mut late_link_args = LinkArgs::new();
late_link_args.insert(LinkerFlavor::Gcc, vec![
//"-lwinstorecompat".to_string(),
//"-lmingwex".to_string(),
//"-lwinstorecompat".to_string(),
"-lwinstorecompat".to_string(),
"-lruntimeobject".to_string(),
"-lsynchronization".to_string(),
"-lvcruntime140_app".to_string(),
"-lucrt".to_string(),
"-lwindowsapp".to_string(),
"-lmingwex".to_string(),
"-lmingw32".to_string(),
]);
TargetOptions {
// FIXME(#13846) this should be enabled for windows
function_sections: false,
linker: Some("gcc".to_string()),
dynamic_linking: true,
executables: false,
dll_prefix: String::new(),
dll_suffix: ".dll".to_string(),
exe_suffix: ".exe".to_string(),
staticlib_prefix: "lib".to_string(),
staticlib_suffix: ".a".to_string(),
no_default_libraries: true,
target_family: Some("windows".to_string()),
is_like_windows: true,
allows_weak_linkage: false,
pre_link_args,
pre_link_objects_exe: vec![
"rsbegin.o".to_string(), // Rust compiler runtime initialization, see rsbegin.rs
],
pre_link_objects_dll: vec![
"rsbegin.o".to_string(),
],
late_link_args,
post_link_objects: vec![
"rsend.o".to_string(),
],
custom_unwind_resume: true,
abi_return_struct_as_int: true,
emit_debug_gdb_scripts: false,
requires_uwtable: true,
limit_rdylib_exports: false,
.. Default::default()
}
}

View File

@ -0,0 +1,22 @@
use crate::spec::{LinkerFlavor, Target, TargetResult};
pub fn target() -> TargetResult {
let mut base = super::windows_uwp_base::opts();
base.cpu = "x86-64".to_string();
base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string());
base.max_atomic_width = Some(64);
Ok(Target {
llvm_target: "x86_64-pc-windows-gnu".to_string(),
target_endian: "little".to_string(),
target_pointer_width: "64".to_string(),
target_c_int_width: "32".to_string(),
data_layout: "e-m:w-i64:64-f80:128-n8:16:32:64-S128".to_string(),
arch: "x86_64".to_string(),
target_os: "windows".to_string(),
target_env: "gnu".to_string(),
target_vendor: "uwp".to_string(),
linker_flavor: LinkerFlavor::Gcc,
options: base,
})
}

View File

@ -39,6 +39,10 @@ fn main() {
println!("cargo:rustc-link-lib=framework=Security");
println!("cargo:rustc-link-lib=framework=Foundation");
println!("cargo:rustc-link-lib=resolv");
} else if target.contains("uwp") {
println!("cargo:rustc-link-lib=ws2_32");
// For BCryptGenRandom
println!("cargo:rustc-link-lib=bcrypt");
} else if target.contains("windows") {
println!("cargo:rustc-link-lib=advapi32");
println!("cargo:rustc-link-lib=ws2_32");

View File

@ -34,9 +34,7 @@ pub type ULONG = c_ulong;
pub type LPBOOL = *mut BOOL;
pub type LPBYTE = *mut BYTE;
pub type LPBY_HANDLE_FILE_INFORMATION = *mut BY_HANDLE_FILE_INFORMATION;
pub type LPCSTR = *const CHAR;
pub type LPCVOID = *const c_void;
pub type LPCWSTR = *const WCHAR;
pub type LPDWORD = *mut DWORD;
pub type LPHANDLE = *mut HANDLE;
@ -121,6 +119,7 @@ impl Clone for WIN32_FIND_DATAW {
}
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;
@ -130,6 +129,7 @@ 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;
@ -141,7 +141,6 @@ pub const WSAECONNREFUSED: c_int = 10061;
pub const MAX_PROTOCOL_CHAIN: DWORD = 7;
pub const TOKEN_READ: DWORD = 0x20008;
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;
@ -157,8 +156,6 @@ 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 HANDLE_FLAG_INHERIT: DWORD = 0x00000001;
pub const PROGRESS_CONTINUE: DWORD = 0;
pub const ERROR_FILE_NOT_FOUND: DWORD = 2;
@ -259,10 +256,6 @@ pub const WAIT_OBJECT_0: DWORD = 0x00000000;
pub const WAIT_TIMEOUT: DWORD = 258;
pub const WAIT_FAILED: DWORD = 0xFFFFFFFF;
pub const EXCEPTION_CONTINUE_SEARCH: LONG = 0;
pub const EXCEPTION_STACK_OVERFLOW: DWORD = 0xc00000fd;
pub const EXCEPTION_MAXIMUM_PARAMETERS: usize = 15;
pub const PIPE_ACCESS_INBOUND: DWORD = 0x00000001;
pub const PIPE_ACCESS_OUTBOUND: DWORD = 0x00000002;
pub const FILE_FLAG_FIRST_PIPE_INSTANCE: DWORD = 0x00080000;
@ -342,20 +335,6 @@ pub struct WIN32_FILE_ATTRIBUTE_DATA {
pub nFileSizeLow: DWORD,
}
#[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,
}
#[repr(C)]
#[allow(dead_code)] // we only use some variants
pub enum FILE_INFO_BY_HANDLE_CLASS {
@ -461,25 +440,6 @@ pub struct REPARSE_MOUNTPOINT_DATA_BUFFER {
pub ReparseTarget: WCHAR,
}
#[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]
}
#[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)]
pub struct GUID {
pub Data1: DWORD,
@ -562,8 +522,6 @@ pub enum ADDRESS_MODE {
AddrModeFlat,
}
pub enum CONTEXT {}
#[repr(C)]
pub struct SOCKADDR_STORAGE_LH {
pub ss_family: ADDRESS_FAMILY,
@ -625,16 +583,6 @@ pub enum EXCEPTION_DISPOSITION {
ExceptionCollidedUnwind
}
#[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)]
#[derive(Copy)]
pub struct fd_set {
@ -655,6 +603,134 @@ pub struct timeval {
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 NumberOfLink: 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;
@ -694,34 +770,13 @@ extern "system" {
pub fn LeaveCriticalSection(CriticalSection: *mut CRITICAL_SECTION);
pub fn DeleteCriticalSection(CriticalSection: *mut CRITICAL_SECTION);
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;
pub fn RemoveDirectoryW(lpPathName: LPCWSTR) -> BOOL;
pub fn SetFileAttributesW(lpFileName: LPCWSTR,
dwFileAttributes: DWORD) -> BOOL;
pub fn GetFileInformationByHandle(hFile: HANDLE,
lpFileInformation: LPBY_HANDLE_FILE_INFORMATION)
-> BOOL;
pub fn SetLastError(dwErrCode: DWORD);
pub fn GetCommandLineW() -> *mut LPCWSTR;
pub fn GetTempPathW(nBufferLength: DWORD,
lpBuffer: LPCWSTR) -> DWORD;
pub fn OpenProcessToken(ProcessHandle: HANDLE,
DesiredAccess: DWORD,
TokenHandle: *mut HANDLE) -> BOOL;
pub fn GetCurrentProcess() -> HANDLE;
pub fn GetCurrentThread() -> HANDLE;
pub fn GetStdHandle(which: DWORD) -> HANDLE;
@ -746,21 +801,12 @@ extern "system" {
pub fn SwitchToThread() -> BOOL;
pub fn Sleep(dwMilliseconds: DWORD);
pub fn GetProcessId(handle: HANDLE) -> DWORD;
pub fn GetUserProfileDirectoryW(hToken: HANDLE,
lpProfileDir: LPWSTR,
lpcchSize: *mut DWORD) -> BOOL;
pub fn SetHandleInformation(hObject: HANDLE,
dwMask: DWORD,
dwFlags: DWORD) -> BOOL;
pub fn CopyFileExW(lpExistingFileName: LPCWSTR,
lpNewFileName: LPCWSTR,
lpProgressRoutine: LPPROGRESS_ROUTINE,
lpData: LPVOID,
pbCancel: LPBOOL,
dwCopyFlags: DWORD) -> BOOL;
pub fn AddVectoredExceptionHandler(FirstHandler: ULONG,
VectoredHandler: PVECTORED_EXCEPTION_HANDLER)
-> LPVOID;
pub fn FormatMessageW(flags: DWORD,
lpSrc: LPVOID,
msgId: DWORD,
@ -857,10 +903,6 @@ extern "system" {
lpOverlapped: LPOVERLAPPED)
-> BOOL;
pub fn CloseHandle(hObject: HANDLE) -> BOOL;
pub fn CreateHardLinkW(lpSymlinkFileName: LPCWSTR,
lpTargetFileName: LPCWSTR,
lpSecurityAttributes: LPSECURITY_ATTRIBUTES)
-> BOOL;
pub fn MoveFileExW(lpExistingFileName: LPCWSTR,
lpNewFileName: LPCWSTR,
dwFlags: DWORD)
@ -950,8 +992,6 @@ extern "system" {
exceptfds: *mut fd_set,
timeout: *const timeval) -> c_int;
#[link_name = "SystemFunction036"]
pub fn RtlGenRandom(RandomBuffer: *mut u8, RandomBufferLength: ULONG) -> BOOLEAN;
pub fn GetProcessHeap() -> HANDLE;
pub fn HeapAlloc(hHeap: HANDLE, dwFlags: DWORD, dwBytes: SIZE_T) -> LPVOID;
@ -975,6 +1015,7 @@ compat_fn! {
_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
}

View File

@ -37,12 +37,14 @@ pub fn store_func(ptr: &AtomicUsize, module: &str, symbol: &str,
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;

View File

@ -287,6 +287,7 @@ impl File {
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();
@ -310,6 +311,49 @@ impl File {
}
}
#[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,
};
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;
if attr.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)
}
@ -670,6 +714,7 @@ pub fn symlink_inner(src: &Path, dst: &Path, dir: bool) -> io::Result<()> {
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)?;
@ -679,6 +724,12 @@ pub fn link(src: &Path, dst: &Path) -> io::Result<()> {
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

View File

@ -33,11 +33,20 @@ pub mod pipe;
pub mod process;
pub mod rand;
pub mod rwlock;
pub mod stack_overflow;
pub mod thread;
pub mod thread_local;
pub mod time;
pub mod stdio;
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() {

View File

@ -97,12 +97,26 @@ impl Socket {
};
let socket = unsafe {
match c::WSASocketW(fam, ty, 0, ptr::null_mut(), 0,
c::WSA_FLAG_OVERLAPPED) {
c::INVALID_SOCKET => Err(last_error()),
c::WSA_FLAG_OVERLAPPED | c::WSA_FLAG_NO_HANDLE_INHERIT) {
c::INVALID_SOCKET => {
match c::WSAGetLastError() {
c::WSAEPROTOTYPE => {
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)),
}
}?;
socket.set_no_inherit()?;
Ok(socket)
}
@ -168,7 +182,6 @@ impl Socket {
n => Ok(Socket(n)),
}
}?;
socket.set_no_inherit()?;
Ok(socket)
}
@ -178,16 +191,34 @@ impl Socket {
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::INVALID_SOCKET => Err(last_error()),
c::WSA_FLAG_OVERLAPPED | c::WSA_FLAG_NO_HANDLE_INHERIT) {
c::INVALID_SOCKET => {
match c::WSAGetLastError() {
c::WSAEPROTOTYPE => {
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)),
}
}?;
socket.set_no_inherit()?;
Ok(socket)
}
@ -312,6 +343,7 @@ impl Socket {
}
}
#[cfg(not(target_vendor = "uwp"))]
fn set_no_inherit(&self) -> io::Result<()> {
sys::cvt(unsafe {
c::SetHandleInformation(self.0 as c::HANDLE,
@ -319,6 +351,11 @@ impl Socket {
}).map(|_| ())
}
#[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,

View File

@ -13,7 +13,6 @@ use crate::path::{self, PathBuf};
use crate::ptr;
use crate::slice;
use crate::sys::{c, cvt};
use crate::sys::handle::Handle;
use super::to_u16s;
@ -284,10 +283,11 @@ pub fn temp_dir() -> PathBuf {
}, super::os2path).unwrap()
}
pub fn home_dir() -> Option<PathBuf> {
crate::env::var_os("HOME").or_else(|| {
crate::env::var_os("USERPROFILE")
}).map(PathBuf::from).or_else(|| unsafe {
#[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 {
@ -301,7 +301,18 @@ pub fn home_dir() -> Option<PathBuf> {
_ => 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) -> ! {

View File

@ -45,7 +45,7 @@ pub struct Pipes {
/// 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) -> io::Result<Pipes> {
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
@ -137,6 +137,13 @@ pub fn anon_pipe(ours_readable: bool) -> io::Result<Pipes> {
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() };

View File

@ -267,13 +267,8 @@ impl Stdio {
Stdio::MakePipe => {
let ours_readable = stdio_id != c::STD_INPUT_HANDLE;
let pipes = pipe::anon_pipe(ours_readable)?;
let pipes = pipe::anon_pipe(ours_readable, true)?;
*pipe = Some(pipes.ours);
cvt(unsafe {
c::SetHandleInformation(pipes.theirs.handle().raw(),
c::HANDLE_FLAG_INHERIT,
c::HANDLE_FLAG_INHERIT)
})?;
Ok(pipes.theirs.into_handle())
}

View File

@ -2,6 +2,7 @@ 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 {
@ -14,3 +15,20 @@ pub fn hashmap_random_keys() -> (u64, u64) {
}
return 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
}

View File

@ -0,0 +1,13 @@
#![cfg_attr(test, allow(dead_code))]
pub struct Handler;
impl Handler {
pub fn new() -> Handler {
Handler
}
}
pub unsafe fn init() {}
pub unsafe fn cleanup() {}

View File

@ -0,0 +1,85 @@
#![unstable(issue = "0", feature = "windows_stdio")]
use crate::io;
use crate::sys::c;
use crate::sys::handle::Handle;
use crate::mem::ManuallyDrop;
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()
}

View File

@ -30,9 +30,11 @@ fn main() {
println!("cargo:rustc-link-lib=gcc_s");
} else if target.contains("dragonfly") {
println!("cargo:rustc-link-lib=gcc_pic");
} else if target.contains("windows-gnu") {
} else if target.contains("pc-windows-gnu") {
println!("cargo:rustc-link-lib=static-nobundle=gcc_eh");
println!("cargo:rustc-link-lib=static-nobundle=pthread");
} else if target.contains("uwp-windows-gnu") {
println!("cargo:rustc-link-lib=unwind");
} else if target.contains("fuchsia") {
println!("cargo:rustc-link-lib=unwind");
} else if target.contains("haiku") {

View File

@ -5,7 +5,7 @@ all:
$(call REMOVE_RLIBS,bar)
$(call REMOVE_DYLIBS,bar)
rm $(call STATICLIB,bar)
rm -f $(TMPDIR)/bar.{dll.exp,dll.lib,pdb}
rm -f $(TMPDIR)/{lib,}bar.{dll.exp,dll.lib,pdb,dll.a}
# Check that $(TMPDIR) is empty.
[ "$$(ls -1 $(TMPDIR) | wc -l)" -eq "0" ]
@ -78,8 +78,8 @@ all:
rm $(TMPDIR)/$(call BIN,foo)
$(RUSTC) foo.rs --crate-type=dylib --emit=link=$(TMPDIR)/$(call BIN,foo)
rm $(TMPDIR)/$(call BIN,foo)
rm -f $(TMPDIR)/foo.{dll.exp,dll.lib,pdb}
[ "$$(ls -1 $(TMPDIR) | wc -l)" -eq "0" ]
rm -f $(TMPDIR)/{lib,}foo.{dll.exp,dll.lib,pdb,dll.a,exe.lib}
[ "$$(ls -1 $(TMPDIR) | wc -l)" -eq "0" ] || (ls -1 $(TMPDIR) && exit 1)
$(RUSTC) foo.rs --crate-type=staticlib -o $(TMPDIR)/foo
rm $(TMPDIR)/foo