diff options
| author | Vivian Lim <[email protected]> | 2021-02-06 22:11:59 -0800 |
|---|---|---|
| committer | Vivian Lim <[email protected]> | 2021-02-06 22:11:59 -0800 |
| commit | 64423f0e34cc4a7d78c15b345b3b8f58243d8286 (patch) | |
| tree | cc20e2e7f0fc35abf470e20e61d3d48f0d954f3b /ctr-std/src/sys/windows | |
| parent | Support libctru 2.0 (diff) | |
| download | archived-ctru-rs-64423f0e34cc4a7d78c15b345b3b8f58243d8286.tar.xz archived-ctru-rs-64423f0e34cc4a7d78c15b345b3b8f58243d8286.zip | |
Delete ctr-std to use my fork of the rust repo instead
Diffstat (limited to 'ctr-std/src/sys/windows')
37 files changed, 0 insertions, 7858 deletions
diff --git a/ctr-std/src/sys/windows/args.rs b/ctr-std/src/sys/windows/args.rs deleted file mode 100644 index 4784633..0000000 --- a/ctr-std/src/sys/windows/args.rs +++ /dev/null @@ -1,107 +0,0 @@ -// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![allow(dead_code)] // runtime init functions not used during testing - -use os::windows::prelude::*; -use sys::c; -use slice; -use ops::Range; -use ffi::OsString; -use libc::{c_int, c_void}; -use fmt; - -pub unsafe fn init(_argc: isize, _argv: *const *const u8) { } - -pub unsafe fn cleanup() { } - -pub fn args() -> Args { - unsafe { - let mut nArgs: c_int = 0; - let lpCmdLine = c::GetCommandLineW(); - let szArgList = c::CommandLineToArgvW(lpCmdLine, &mut nArgs); - - // szArcList can be NULL if CommandLinToArgvW failed, - // but in that case nArgs is 0 so we won't actually - // try to read a null pointer - Args { cur: szArgList, range: 0..(nArgs as isize) } - } -} - -pub struct Args { - range: Range<isize>, - cur: *mut *mut u16, -} - -pub struct ArgsInnerDebug<'a> { - args: &'a Args, -} - -impl<'a> fmt::Debug for ArgsInnerDebug<'a> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.write_str("[")?; - let mut first = true; - for i in self.args.range.clone() { - if !first { - f.write_str(", ")?; - } - first = false; - - // Here we do allocation which could be avoided. - fmt::Debug::fmt(&unsafe { os_string_from_ptr(*self.args.cur.offset(i)) }, f)?; - } - f.write_str("]")?; - Ok(()) - } -} - -impl Args { - pub fn inner_debug(&self) -> ArgsInnerDebug { - ArgsInnerDebug { - args: self - } - } -} - -unsafe fn os_string_from_ptr(ptr: *mut u16) -> OsString { - let mut len = 0; - while *ptr.offset(len) != 0 { len += 1; } - - // Push it onto the list. - let ptr = ptr as *const u16; - let buf = slice::from_raw_parts(ptr, len as usize); - OsStringExt::from_wide(buf) -} - -impl Iterator for Args { - type Item = OsString; - fn next(&mut self) -> Option<OsString> { - self.range.next().map(|i| unsafe { os_string_from_ptr(*self.cur.offset(i)) } ) - } - fn size_hint(&self) -> (usize, Option<usize>) { self.range.size_hint() } -} - -impl DoubleEndedIterator for Args { - fn next_back(&mut self) -> Option<OsString> { - self.range.next_back().map(|i| unsafe { os_string_from_ptr(*self.cur.offset(i)) } ) - } -} - -impl ExactSizeIterator for Args { - fn len(&self) -> usize { self.range.len() } -} - -impl Drop for Args { - fn drop(&mut self) { - // self.cur can be null if CommandLineToArgvW previously failed, - // but LocalFree ignores NULL pointers - unsafe { c::LocalFree(self.cur as *mut c_void); } - } -} diff --git a/ctr-std/src/sys/windows/backtrace/backtrace_gnu.rs b/ctr-std/src/sys/windows/backtrace/backtrace_gnu.rs deleted file mode 100644 index f0d29dd..0000000 --- a/ctr-std/src/sys/windows/backtrace/backtrace_gnu.rs +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use io; -use sys::c; -use libc::c_char; -use path::PathBuf; -use fs::{OpenOptions, File}; -use sys::ext::fs::OpenOptionsExt; -use sys::handle::Handle; -use super::super::{fill_utf16_buf, os2path, to_u16s, wide_char_to_multi_byte}; - -fn query_full_process_image_name() -> io::Result<PathBuf> { - unsafe { - let process_handle = Handle::new(c::OpenProcess(c::PROCESS_QUERY_INFORMATION, - c::FALSE, - c::GetCurrentProcessId())); - fill_utf16_buf(|buf, mut sz| { - if c::QueryFullProcessImageNameW(process_handle.raw(), 0, buf, &mut sz) == 0 { - 0 - } else { - sz - } - }, os2path) - } -} - -fn lock_and_get_executable_filename() -> io::Result<(PathBuf, File)> { - // We query the current image name, open the file without FILE_SHARE_DELETE so it - // can't be moved and then get the current image name again. If the names are the - // same than we have successfully locked the file - let image_name1 = query_full_process_image_name()?; - let file = OpenOptions::new() - .read(true) - .share_mode(c::FILE_SHARE_READ | c::FILE_SHARE_WRITE) - .open(&image_name1)?; - let image_name2 = query_full_process_image_name()?; - - if image_name1 != image_name2 { - return Err(io::Error::new(io::ErrorKind::Other, - "executable moved while trying to lock it")); - } - - Ok((image_name1, file)) -} - -// Get the executable filename for libbacktrace -// This returns the path in the ANSI code page and a File which should remain open -// for as long as the path should remain valid -pub fn get_executable_filename() -> io::Result<(Vec<c_char>, File)> { - let (executable, file) = lock_and_get_executable_filename()?; - let u16_executable = to_u16s(executable.into_os_string())?; - Ok((wide_char_to_multi_byte(c::CP_ACP, c::WC_NO_BEST_FIT_CHARS, - &u16_executable, true)?, file)) -} diff --git a/ctr-std/src/sys/windows/backtrace/mod.rs b/ctr-std/src/sys/windows/backtrace/mod.rs deleted file mode 100644 index f64cae8..0000000 --- a/ctr-std/src/sys/windows/backtrace/mod.rs +++ /dev/null @@ -1,326 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! As always, windows has something very different than unix, we mainly want -//! to avoid having to depend too much on libunwind for windows. -//! -//! If you google around, you'll find a fair bit of references to built-in -//! functions to get backtraces on windows. It turns out that most of these are -//! in an external library called dbghelp. I was unable to find this library -//! via `-ldbghelp`, but it is apparently normal to do the `dlopen` equivalent -//! of it. -//! -//! You'll also find that there's a function called CaptureStackBackTrace -//! mentioned frequently (which is also easy to use), but sadly I didn't have a -//! copy of that function in my mingw install (maybe it was broken?). Instead, -//! this takes the route of using StackWalk64 in order to walk the stack. - -#![allow(deprecated)] // dynamic_lib - -use io; -use libc::c_void; -use mem; -use ptr; -use sys::c; -use sys::dynamic_lib::DynamicLibrary; -use sys_common::backtrace::Frame; - -macro_rules! sym { - ($lib:expr, $e:expr, $t:ident) => ( - $lib.symbol($e).map(|f| unsafe { - $crate::mem::transmute::<usize, $t>(f) - }) - ) -} - -mod printing; - -#[cfg(target_env = "gnu")] -#[path = "backtrace_gnu.rs"] -pub mod gnu; - -pub use self::printing::{foreach_symbol_fileline, resolve_symname}; -use self::printing::{load_printing_fns_64, load_printing_fns_ex}; - -pub fn unwind_backtrace(frames: &mut [Frame]) -> io::Result<(usize, BacktraceContext)> { - let dbghelp = DynamicLibrary::open("dbghelp.dll")?; - - // Fetch the symbols necessary from dbghelp.dll - let SymInitialize = sym!(dbghelp, "SymInitialize", SymInitializeFn)?; - let SymCleanup = sym!(dbghelp, "SymCleanup", SymCleanupFn)?; - - // StackWalkEx might not be present and we'll fall back to StackWalk64 - let sw_var = match sym!(dbghelp, "StackWalkEx", StackWalkExFn) { - Ok(StackWalkEx) => { - StackWalkVariant::StackWalkEx(StackWalkEx, load_printing_fns_ex(&dbghelp)?) - } - Err(e) => match sym!(dbghelp, "StackWalk64", StackWalk64Fn) { - Ok(StackWalk64) => { - StackWalkVariant::StackWalk64(StackWalk64, load_printing_fns_64(&dbghelp)?) - } - Err(..) => return Err(e), - }, - }; - - // Allocate necessary structures for doing the stack walk - let process = unsafe { c::GetCurrentProcess() }; - - let backtrace_context = BacktraceContext { - handle: process, - SymCleanup, - StackWalkVariant: sw_var, - dbghelp, - }; - - // Initialize this process's symbols - let ret = unsafe { SymInitialize(process, ptr::null_mut(), c::TRUE) }; - if ret != c::TRUE { - return Ok((0, backtrace_context)); - } - - // And now that we're done with all the setup, do the stack walking! - match backtrace_context.StackWalkVariant { - StackWalkVariant::StackWalkEx(StackWalkEx, _) => { - set_frames(StackWalkEx, frames).map(|i| (i, backtrace_context)) - } - - StackWalkVariant::StackWalk64(StackWalk64, _) => { - set_frames(StackWalk64, frames).map(|i| (i, backtrace_context)) - } - } -} - -fn set_frames<W: StackWalker>(StackWalk: W, frames: &mut [Frame]) -> io::Result<usize> { - let process = unsafe { c::GetCurrentProcess() }; - let thread = unsafe { c::GetCurrentProcess() }; - let mut context: c::CONTEXT = unsafe { mem::zeroed() }; - unsafe { c::RtlCaptureContext(&mut context) }; - let mut frame = W::Item::new(); - let image = frame.init(&context); - - let mut i = 0; - while i < frames.len() - && StackWalk.walk(image, process, thread, &mut frame, &mut context) == c::TRUE - { - let addr = frame.get_addr(); - frames[i] = Frame { - symbol_addr: addr, - exact_position: addr, - inline_context: 0, - }; - - i += 1 - } - Ok(i) -} - -type SymInitializeFn = unsafe extern "system" fn(c::HANDLE, *mut c_void, c::BOOL) -> c::BOOL; -type SymCleanupFn = unsafe extern "system" fn(c::HANDLE) -> c::BOOL; - -type StackWalkExFn = unsafe extern "system" fn( - c::DWORD, - c::HANDLE, - c::HANDLE, - *mut c::STACKFRAME_EX, - *mut c::CONTEXT, - *mut c_void, - *mut c_void, - *mut c_void, - *mut c_void, - c::DWORD, -) -> c::BOOL; - -type StackWalk64Fn = unsafe extern "system" fn( - c::DWORD, - c::HANDLE, - c::HANDLE, - *mut c::STACKFRAME64, - *mut c::CONTEXT, - *mut c_void, - *mut c_void, - *mut c_void, - *mut c_void, -) -> c::BOOL; - -trait StackWalker { - type Item: StackFrame; - - fn walk(&self, c::DWORD, c::HANDLE, c::HANDLE, &mut Self::Item, &mut c::CONTEXT) -> c::BOOL; -} - -impl StackWalker for StackWalkExFn { - type Item = c::STACKFRAME_EX; - fn walk( - &self, - image: c::DWORD, - process: c::HANDLE, - thread: c::HANDLE, - frame: &mut Self::Item, - context: &mut c::CONTEXT, - ) -> c::BOOL { - unsafe { - self( - image, - process, - thread, - frame, - context, - ptr::null_mut(), - ptr::null_mut(), - ptr::null_mut(), - ptr::null_mut(), - 0, - ) - } - } -} - -impl StackWalker for StackWalk64Fn { - type Item = c::STACKFRAME64; - fn walk( - &self, - image: c::DWORD, - process: c::HANDLE, - thread: c::HANDLE, - frame: &mut Self::Item, - context: &mut c::CONTEXT, - ) -> c::BOOL { - unsafe { - self( - image, - process, - thread, - frame, - context, - ptr::null_mut(), - ptr::null_mut(), - ptr::null_mut(), - ptr::null_mut(), - ) - } - } -} - -trait StackFrame { - fn new() -> Self; - fn init(&mut self, ctx: &c::CONTEXT) -> c::DWORD; - fn get_addr(&self) -> *const u8; -} - -impl StackFrame for c::STACKFRAME_EX { - fn new() -> c::STACKFRAME_EX { - unsafe { mem::zeroed() } - } - - #[cfg(target_arch = "x86")] - fn init(&mut self, ctx: &c::CONTEXT) -> c::DWORD { - self.AddrPC.Offset = ctx.Eip as u64; - self.AddrPC.Mode = c::ADDRESS_MODE::AddrModeFlat; - self.AddrStack.Offset = ctx.Esp as u64; - self.AddrStack.Mode = c::ADDRESS_MODE::AddrModeFlat; - self.AddrFrame.Offset = ctx.Ebp as u64; - self.AddrFrame.Mode = c::ADDRESS_MODE::AddrModeFlat; - c::IMAGE_FILE_MACHINE_I386 - } - - #[cfg(target_arch = "x86_64")] - fn init(&mut self, ctx: &c::CONTEXT) -> c::DWORD { - self.AddrPC.Offset = ctx.Rip as u64; - self.AddrPC.Mode = c::ADDRESS_MODE::AddrModeFlat; - self.AddrStack.Offset = ctx.Rsp as u64; - self.AddrStack.Mode = c::ADDRESS_MODE::AddrModeFlat; - self.AddrFrame.Offset = ctx.Rbp as u64; - self.AddrFrame.Mode = c::ADDRESS_MODE::AddrModeFlat; - c::IMAGE_FILE_MACHINE_AMD64 - } - - #[cfg(target_arch = "aarch64")] - fn init(&mut self, ctx: &c::CONTEXT) -> c::DWORD { - self.AddrPC.Offset = ctx.Pc as u64; - self.AddrPC.Mode = c::ADDRESS_MODE::AddrModeFlat; - self.AddrStack.Offset = ctx.Sp as u64; - self.AddrStack.Mode = c::ADDRESS_MODE::AddrModeFlat; - self.AddrFrame.Offset = ctx.Fp as u64; - self.AddrFrame.Mode = c::ADDRESS_MODE::AddrModeFlat; - c::IMAGE_FILE_MACHINE_ARM64 - } - - fn get_addr(&self) -> *const u8 { - (self.AddrPC.Offset - 1) as *const u8 - } -} - -impl StackFrame for c::STACKFRAME64 { - fn new() -> c::STACKFRAME64 { - unsafe { mem::zeroed() } - } - - #[cfg(target_arch = "x86")] - fn init(&mut self, ctx: &c::CONTEXT) -> c::DWORD { - self.AddrPC.Offset = ctx.Eip as u64; - self.AddrPC.Mode = c::ADDRESS_MODE::AddrModeFlat; - self.AddrStack.Offset = ctx.Esp as u64; - self.AddrStack.Mode = c::ADDRESS_MODE::AddrModeFlat; - self.AddrFrame.Offset = ctx.Ebp as u64; - self.AddrFrame.Mode = c::ADDRESS_MODE::AddrModeFlat; - c::IMAGE_FILE_MACHINE_I386 - } - - #[cfg(target_arch = "x86_64")] - fn init(&mut self, ctx: &c::CONTEXT) -> c::DWORD { - self.AddrPC.Offset = ctx.Rip as u64; - self.AddrPC.Mode = c::ADDRESS_MODE::AddrModeFlat; - self.AddrStack.Offset = ctx.Rsp as u64; - self.AddrStack.Mode = c::ADDRESS_MODE::AddrModeFlat; - self.AddrFrame.Offset = ctx.Rbp as u64; - self.AddrFrame.Mode = c::ADDRESS_MODE::AddrModeFlat; - c::IMAGE_FILE_MACHINE_AMD64 - } - - #[cfg(target_arch = "aarch64")] - fn init(&mut self, ctx: &c::CONTEXT) -> c::DWORD { - self.AddrPC.Offset = ctx.Pc as u64; - self.AddrPC.Mode = c::ADDRESS_MODE::AddrModeFlat; - self.AddrStack.Offset = ctx.Sp as u64; - self.AddrStack.Mode = c::ADDRESS_MODE::AddrModeFlat; - self.AddrFrame.Offset = ctx.Fp as u64; - self.AddrFrame.Mode = c::ADDRESS_MODE::AddrModeFlat; - c::IMAGE_FILE_MACHINE_ARM64 - } - - fn get_addr(&self) -> *const u8 { - (self.AddrPC.Offset - 1) as *const u8 - } -} - -enum StackWalkVariant { - StackWalkEx(StackWalkExFn, printing::PrintingFnsEx), - StackWalk64(StackWalk64Fn, printing::PrintingFns64), -} - -pub struct BacktraceContext { - handle: c::HANDLE, - SymCleanup: SymCleanupFn, - // Only used in printing for msvc and not gnu - // The gnu version is effectively a ZST dummy. - #[allow(dead_code)] - StackWalkVariant: StackWalkVariant, - // keeping DynamycLibrary loaded until its functions no longer needed - #[allow(dead_code)] - dbghelp: DynamicLibrary, -} - -impl Drop for BacktraceContext { - fn drop(&mut self) { - unsafe { - (self.SymCleanup)(self.handle); - } - } -} diff --git a/ctr-std/src/sys/windows/backtrace/printing/mod.rs b/ctr-std/src/sys/windows/backtrace/printing/mod.rs deleted file mode 100644 index 251d502..0000000 --- a/ctr-std/src/sys/windows/backtrace/printing/mod.rs +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#[cfg(target_env = "msvc")] -#[path = "msvc.rs"] -mod printing; - -#[cfg(target_env = "gnu")] -mod printing { - pub use sys_common::gnu::libbacktrace::{foreach_symbol_fileline, resolve_symname}; - - // dummy functions to mirror those present in msvc version. - use sys::dynamic_lib::DynamicLibrary; - use io; - pub struct PrintingFnsEx {} - pub struct PrintingFns64 {} - pub fn load_printing_fns_ex(_: &DynamicLibrary) -> io::Result<PrintingFnsEx> { - Ok(PrintingFnsEx{}) - } - pub fn load_printing_fns_64(_: &DynamicLibrary) -> io::Result<PrintingFns64> { - Ok(PrintingFns64{}) - } -} - -pub use self::printing::{foreach_symbol_fileline, resolve_symname}; -pub use self::printing::{load_printing_fns_ex, load_printing_fns_64, - PrintingFnsEx, PrintingFns64}; diff --git a/ctr-std/src/sys/windows/backtrace/printing/msvc.rs b/ctr-std/src/sys/windows/backtrace/printing/msvc.rs deleted file mode 100644 index c8b946b..0000000 --- a/ctr-std/src/sys/windows/backtrace/printing/msvc.rs +++ /dev/null @@ -1,217 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use ffi::CStr; -use io; -use libc::{c_char, c_ulong}; -use mem; -use sys::backtrace::BacktraceContext; -use sys::backtrace::StackWalkVariant; -use sys::c; -use sys::dynamic_lib::DynamicLibrary; -use sys_common::backtrace::Frame; - -// Structs holding printing functions and loaders for them -// Two versions depending on whether dbghelp.dll has StackWalkEx or not -// (the former being in newer Windows versions, the older being in Win7 and before) -pub struct PrintingFnsEx { - resolve_symname: SymFromInlineContextFn, - sym_get_line: SymGetLineFromInlineContextFn, -} -pub struct PrintingFns64 { - resolve_symname: SymFromAddrFn, - sym_get_line: SymGetLineFromAddr64Fn, -} - -pub fn load_printing_fns_ex(dbghelp: &DynamicLibrary) -> io::Result<PrintingFnsEx> { - Ok(PrintingFnsEx { - resolve_symname: sym!(dbghelp, "SymFromInlineContext", SymFromInlineContextFn)?, - sym_get_line: sym!( - dbghelp, - "SymGetLineFromInlineContext", - SymGetLineFromInlineContextFn - )?, - }) -} -pub fn load_printing_fns_64(dbghelp: &DynamicLibrary) -> io::Result<PrintingFns64> { - Ok(PrintingFns64 { - resolve_symname: sym!(dbghelp, "SymFromAddr", SymFromAddrFn)?, - sym_get_line: sym!(dbghelp, "SymGetLineFromAddr64", SymGetLineFromAddr64Fn)?, - }) -} - -type SymFromAddrFn = - unsafe extern "system" fn(c::HANDLE, u64, *mut u64, *mut c::SYMBOL_INFO) -> c::BOOL; -type SymFromInlineContextFn = - unsafe extern "system" fn(c::HANDLE, u64, c::ULONG, *mut u64, *mut c::SYMBOL_INFO) -> c::BOOL; - -type SymGetLineFromAddr64Fn = - unsafe extern "system" fn(c::HANDLE, u64, *mut u32, *mut c::IMAGEHLP_LINE64) -> c::BOOL; -type SymGetLineFromInlineContextFn = unsafe extern "system" fn( - c::HANDLE, - u64, - c::ULONG, - u64, - *mut c::DWORD, - *mut c::IMAGEHLP_LINE64, -) -> c::BOOL; - -/// Converts a pointer to symbol to its string value. -pub fn resolve_symname<F>(frame: Frame, callback: F, context: &BacktraceContext) -> io::Result<()> -where - F: FnOnce(Option<&str>) -> io::Result<()>, -{ - match context.StackWalkVariant { - StackWalkVariant::StackWalkEx(_, ref fns) => resolve_symname_internal( - |process: c::HANDLE, - symbol_address: u64, - inline_context: c::ULONG, - info: *mut c::SYMBOL_INFO| unsafe { - let mut displacement = 0u64; - (fns.resolve_symname)( - process, - symbol_address, - inline_context, - &mut displacement, - info, - ) - }, - frame, - callback, - context, - ), - StackWalkVariant::StackWalk64(_, ref fns) => resolve_symname_internal( - |process: c::HANDLE, - symbol_address: u64, - _inline_context: c::ULONG, - info: *mut c::SYMBOL_INFO| unsafe { - let mut displacement = 0u64; - (fns.resolve_symname)(process, symbol_address, &mut displacement, info) - }, - frame, - callback, - context, - ), - } -} - -fn resolve_symname_internal<F, R>( - mut symbol_resolver: R, - frame: Frame, - callback: F, - context: &BacktraceContext, -) -> io::Result<()> -where - F: FnOnce(Option<&str>) -> io::Result<()>, - R: FnMut(c::HANDLE, u64, c::ULONG, *mut c::SYMBOL_INFO) -> c::BOOL, -{ - unsafe { - let mut info: c::SYMBOL_INFO = mem::zeroed(); - info.MaxNameLen = c::MAX_SYM_NAME as c_ulong; - // the struct size in C. the value is different to - // `size_of::<SYMBOL_INFO>() - MAX_SYM_NAME + 1` (== 81) - // due to struct alignment. - info.SizeOfStruct = 88; - - let ret = symbol_resolver( - context.handle, - frame.symbol_addr as u64, - frame.inline_context, - &mut info, - ); - let valid_range = if ret == c::TRUE && frame.symbol_addr as usize >= info.Address as usize { - if info.Size != 0 { - (frame.symbol_addr as usize) < info.Address as usize + info.Size as usize - } else { - true - } - } else { - false - }; - let symname = if valid_range { - let ptr = info.Name.as_ptr() as *const c_char; - CStr::from_ptr(ptr).to_str().ok() - } else { - None - }; - callback(symname) - } -} - -pub fn foreach_symbol_fileline<F>( - frame: Frame, - callback: F, - context: &BacktraceContext, -) -> io::Result<bool> -where - F: FnMut(&[u8], u32) -> io::Result<()>, -{ - match context.StackWalkVariant { - StackWalkVariant::StackWalkEx(_, ref fns) => foreach_symbol_fileline_iternal( - |process: c::HANDLE, - frame_address: u64, - inline_context: c::ULONG, - line: *mut c::IMAGEHLP_LINE64| unsafe { - let mut displacement = 0u32; - (fns.sym_get_line)( - process, - frame_address, - inline_context, - 0, - &mut displacement, - line, - ) - }, - frame, - callback, - context, - ), - StackWalkVariant::StackWalk64(_, ref fns) => foreach_symbol_fileline_iternal( - |process: c::HANDLE, - frame_address: u64, - _inline_context: c::ULONG, - line: *mut c::IMAGEHLP_LINE64| unsafe { - let mut displacement = 0u32; - (fns.sym_get_line)(process, frame_address, &mut displacement, line) - }, - frame, - callback, - context, - ), - } -} - -fn foreach_symbol_fileline_iternal<F, G>( - mut line_getter: G, - frame: Frame, - mut callback: F, - context: &BacktraceContext, -) -> io::Result<bool> -where - F: FnMut(&[u8], u32) -> io::Result<()>, - G: FnMut(c::HANDLE, u64, c::ULONG, *mut c::IMAGEHLP_LINE64) -> c::BOOL, -{ - unsafe { - let mut line: c::IMAGEHLP_LINE64 = mem::zeroed(); - line.SizeOfStruct = ::mem::size_of::<c::IMAGEHLP_LINE64>() as u32; - - let ret = line_getter( - context.handle, - frame.exact_position as u64, - frame.inline_context, - &mut line, - ); - if ret == c::TRUE { - let name = CStr::from_ptr(line.Filename).to_bytes(); - callback(name, line.LineNumber as u32)?; - } - Ok(false) - } -} diff --git a/ctr-std/src/sys/windows/c.rs b/ctr-std/src/sys/windows/c.rs deleted file mode 100644 index e514a56..0000000 --- a/ctr-std/src/sys/windows/c.rs +++ /dev/null @@ -1,1334 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! C definitions used by libnative that don't belong in liblibc - -#![allow(bad_style)] -#![cfg_attr(test, allow(dead_code))] -#![unstable(issue = "0", feature = "windows_c")] - -use os::raw::{c_int, c_uint, c_ulong, c_long, c_longlong, c_ushort, c_char}; -#[cfg(target_arch = "x86_64")] -use os::raw::c_ulonglong; -use libc::{wchar_t, size_t, c_void}; -use ptr; - -pub use self::FILE_INFO_BY_HANDLE_CLASS::*; -pub use self::EXCEPTION_DISPOSITION::*; - -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; -#[cfg(target_arch = "x86_64")] -pub type ULONGLONG = u64; -#[cfg(target_arch = "x86_64")] -pub type DWORDLONG = ULONGLONG; - -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; -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 PCONDITION_VARIABLE = *mut CONDITION_VARIABLE; -pub type PLARGE_INTEGER = *mut c_longlong; -pub type PSRWLOCK = *mut SRWLOCK; - -pub type SOCKET = ::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 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 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 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; -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 HANDLE_FLAG_INHERIT: DWORD = 0x00000001; - -pub const PROGRESS_CONTINUE: DWORD = 0; - -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_INSUFFICIENT_BUFFER: DWORD = 122; -pub const ERROR_ALREADY_EXISTS: DWORD = 183; -pub const ERROR_NO_DATA: DWORD = 232; -pub const ERROR_ENVVAR_NOT_FOUND: DWORD = 203; -pub const ERROR_OPERATION_ABORTED: DWORD = 995; -pub const ERROR_IO_PENDING: DWORD = 997; -pub const ERROR_TIMEOUT: DWORD = 0x5B4; - -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 SO_REUSEADDR: c_int = 0x0004; -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; - -#[cfg(target_env = "msvc")] -#[cfg(feature = "backtrace")] -pub const MAX_SYM_NAME: usize = 2000; -#[cfg(target_arch = "x86")] -#[cfg(feature = "backtrace")] -pub const IMAGE_FILE_MACHINE_I386: DWORD = 0x014c; -#[cfg(target_arch = "x86_64")] -#[cfg(feature = "backtrace")] -pub const IMAGE_FILE_MACHINE_AMD64: DWORD = 0x8664; -#[cfg(target_arch = "aarch64")] -#[cfg(feature = "backtrace")] -pub const IMAGE_FILE_MACHINE_ARM64: DWORD = 0xAA64; - -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; -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; - -#[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], -} - -#[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)] -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 { - 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 = ::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 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, - 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)] -#[cfg(target_env = "msvc")] -#[cfg(feature = "backtrace")] -pub struct SYMBOL_INFO { - pub SizeOfStruct: c_ulong, - pub TypeIndex: c_ulong, - pub Reserved: [u64; 2], - pub Index: c_ulong, - pub Size: c_ulong, - pub ModBase: u64, - pub Flags: c_ulong, - pub Value: u64, - pub Address: u64, - pub Register: c_ulong, - pub Scope: c_ulong, - pub Tag: c_ulong, - pub NameLen: c_ulong, - pub MaxNameLen: c_ulong, - // note that windows has this as 1, but it basically just means that - // the name is inline at the end of the struct. For us, we just bump - // the struct size up to MAX_SYM_NAME. - pub Name: [c_char; MAX_SYM_NAME], -} - -#[repr(C)] -#[cfg(target_env = "msvc")] -#[cfg(feature = "backtrace")] -pub struct IMAGEHLP_LINE64 { - pub SizeOfStruct: u32, - pub Key: *const c_void, - pub LineNumber: u32, - pub Filename: *const c_char, - pub Address: u64, -} - -#[repr(C)] -#[allow(dead_code)] // we only use some variants -pub enum ADDRESS_MODE { - AddrMode1616, - AddrMode1632, - AddrModeReal, - AddrModeFlat, -} - -#[repr(C)] -#[cfg(feature = "backtrace")] -pub struct ADDRESS64 { - pub Offset: u64, - pub Segment: u16, - pub Mode: ADDRESS_MODE, -} - -#[repr(C)] -#[cfg(feature = "backtrace")] -pub struct STACKFRAME_EX { - pub AddrPC: ADDRESS64, - pub AddrReturn: ADDRESS64, - pub AddrFrame: ADDRESS64, - pub AddrStack: ADDRESS64, - pub AddrBStore: ADDRESS64, - pub FuncTableEntry: *mut c_void, - pub Params: [u64; 4], - pub Far: BOOL, - pub Virtual: BOOL, - pub Reserved: [u64; 3], - pub KdHelp: KDHELP64, - pub StackFrameSize: DWORD, - pub InlineFrameContext: DWORD, -} - -#[repr(C)] -#[cfg(feature = "backtrace")] -pub struct STACKFRAME64 { - pub AddrPC: ADDRESS64, - pub AddrReturn: ADDRESS64, - pub AddrFrame: ADDRESS64, - pub AddrStack: ADDRESS64, - pub AddrBStore: ADDRESS64, - pub FuncTableEntry: *mut c_void, - pub Params: [u64; 4], - pub Far: BOOL, - pub Virtual: BOOL, - pub Reserved: [u64; 3], - pub KdHelp: KDHELP64, -} - -#[repr(C)] -#[cfg(feature = "backtrace")] -pub struct KDHELP64 { - pub Thread: u64, - pub ThCallbackStack: DWORD, - pub ThCallbackBStore: DWORD, - pub NextCallback: DWORD, - pub FramePointer: DWORD, - pub KiCallUserMode: u64, - pub KeUserCallbackDispatcher: u64, - pub SystemRangeStart: u64, - pub KiUserExceptionDispatcher: u64, - pub StackBase: u64, - pub StackLimit: u64, - pub Reserved: [u64; 5], -} - -#[cfg(target_arch = "x86")] -#[repr(C)] -pub struct CONTEXT { - pub ContextFlags: DWORD, - pub Dr0: DWORD, - pub Dr1: DWORD, - pub Dr2: DWORD, - pub Dr3: DWORD, - pub Dr6: DWORD, - pub Dr7: DWORD, - pub FloatSave: FLOATING_SAVE_AREA, - pub SegGs: DWORD, - pub SegFs: DWORD, - pub SegEs: DWORD, - pub SegDs: DWORD, - pub Edi: DWORD, - pub Esi: DWORD, - pub Ebx: DWORD, - pub Edx: DWORD, - pub Ecx: DWORD, - pub Eax: DWORD, - pub Ebp: DWORD, - pub Eip: DWORD, - pub SegCs: DWORD, - pub EFlags: DWORD, - pub Esp: DWORD, - pub SegSs: DWORD, - pub ExtendedRegisters: [u8; 512], -} - -#[cfg(target_arch = "x86")] -#[repr(C)] -pub struct FLOATING_SAVE_AREA { - pub ControlWord: DWORD, - pub StatusWord: DWORD, - pub TagWord: DWORD, - pub ErrorOffset: DWORD, - pub ErrorSelector: DWORD, - pub DataOffset: DWORD, - pub DataSelector: DWORD, - pub RegisterArea: [u8; 80], - pub Cr0NpxState: DWORD, -} - -#[cfg(target_arch = "x86_64")] -#[repr(C, align(16))] -pub struct CONTEXT { - pub P1Home: DWORDLONG, - pub P2Home: DWORDLONG, - pub P3Home: DWORDLONG, - pub P4Home: DWORDLONG, - pub P5Home: DWORDLONG, - pub P6Home: DWORDLONG, - - pub ContextFlags: DWORD, - pub MxCsr: DWORD, - - pub SegCs: WORD, - pub SegDs: WORD, - pub SegEs: WORD, - pub SegFs: WORD, - pub SegGs: WORD, - pub SegSs: WORD, - pub EFlags: DWORD, - - pub Dr0: DWORDLONG, - pub Dr1: DWORDLONG, - pub Dr2: DWORDLONG, - pub Dr3: DWORDLONG, - pub Dr6: DWORDLONG, - pub Dr7: DWORDLONG, - - pub Rax: DWORDLONG, - pub Rcx: DWORDLONG, - pub Rdx: DWORDLONG, - pub Rbx: DWORDLONG, - pub Rsp: DWORDLONG, - pub Rbp: DWORDLONG, - pub Rsi: DWORDLONG, - pub Rdi: DWORDLONG, - pub R8: DWORDLONG, - pub R9: DWORDLONG, - pub R10: DWORDLONG, - pub R11: DWORDLONG, - pub R12: DWORDLONG, - pub R13: DWORDLONG, - pub R14: DWORDLONG, - pub R15: DWORDLONG, - - pub Rip: DWORDLONG, - - pub FltSave: FLOATING_SAVE_AREA, - - pub VectorRegister: [M128A; 26], - pub VectorControl: DWORDLONG, - - pub DebugControl: DWORDLONG, - pub LastBranchToRip: DWORDLONG, - pub LastBranchFromRip: DWORDLONG, - pub LastExceptionToRip: DWORDLONG, - pub LastExceptionFromRip: DWORDLONG, -} - -#[cfg(target_arch = "x86_64")] -#[repr(C, align(16))] -pub struct M128A { - pub Low: c_ulonglong, - pub High: c_longlong -} - -#[cfg(target_arch = "x86_64")] -#[repr(C, align(16))] -pub struct FLOATING_SAVE_AREA { - _Dummy: [u8; 512] // FIXME: Fill this out -} - -// FIXME(#43348): This structure is used for backtrace only, and a fake -// definition is provided here only to allow rustdoc to pass type-check. This -// will not appear in the final documentation. This should be also defined for -// other architectures supported by Windows such as ARM, and for historical -// interest, maybe MIPS and PowerPC as well. -#[cfg(all(dox, not(any(target_arch = "x86_64", target_arch = "x86", target_arch = "aarch64"))))] -pub enum CONTEXT {} - -#[cfg(target_arch = "aarch64")] -pub const ARM64_MAX_BREAKPOINTS: usize = 8; - -#[cfg(target_arch = "aarch64")] -pub const ARM64_MAX_WATCHPOINTS: usize = 2; - -#[cfg(target_arch = "aarch64")] -#[repr(C)] -pub struct ARM64_NT_NEON128 { - pub D: [f64; 2], -} - -#[cfg(target_arch = "aarch64")] -#[repr(C, align(16))] -pub struct CONTEXT { - pub ContextFlags: DWORD, - pub Cpsr: DWORD, - pub X0: u64, - pub X1: u64, - pub X2: u64, - pub X3: u64, - pub X4: u64, - pub X5: u64, - pub X6: u64, - pub X7: u64, - pub X8: u64, - pub X9: u64, - pub X10: u64, - pub X11: u64, - pub X12: u64, - pub X13: u64, - pub X14: u64, - pub X15: u64, - pub X16: u64, - pub X17: u64, - pub X18: u64, - pub X19: u64, - pub X20: u64, - pub X21: u64, - pub X22: u64, - pub X23: u64, - pub X24: u64, - pub X25: u64, - pub X26: u64, - pub X27: u64, - pub X28: u64, - pub Fp: u64, - pub Lr: u64, - pub Sp: u64, - pub Pc: u64, - pub V: [ARM64_NT_NEON128; 32], - pub Fpcr: DWORD, - pub Fpsr: DWORD, - pub Bcr: [DWORD; ARM64_MAX_BREAKPOINTS], - pub Bvr: [DWORD; ARM64_MAX_BREAKPOINTS], - pub Wcr: [DWORD; ARM64_MAX_WATCHPOINTS], - pub Wvr: [DWORD; ARM64_MAX_WATCHPOINTS], -} - -#[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, 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 { - 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, -} - -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 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) -> BOOLEAN; - 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 LocalFree(ptr: *mut c_void); - pub fn CommandLineToArgvW(lpCmdLine: *mut LPCWSTR, - pNumArgs: *mut c_int) -> *mut *mut u16; - 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; - 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 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, - 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 CreateHardLinkW(lpSymlinkFileName: LPCWSTR, - lpTargetFileName: LPCWSTR, - lpSecurityAttributes: LPSECURITY_ATTRIBUTES) - -> 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; - #[cfg(feature = "backtrace")] - pub fn RtlCaptureContext(ctx: *mut CONTEXT); - 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); - - #[cfg(feature = "backtrace")] - pub fn LoadLibraryW(name: LPCWSTR) -> HMODULE; - #[cfg(feature = "backtrace")] - pub fn FreeLibrary(handle: HMODULE) -> BOOL; - 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; - - #[link_name = "SystemFunction036"] - pub fn RtlGenRandom(RandomBuffer: *mut u8, RandomBufferLength: ULONG) -> BOOLEAN; -} - -// 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 - } - 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 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") - } -} - -#[cfg(all(target_env = "gnu", feature = "backtrace"))] -mod gnu { - use super::*; - - pub const PROCESS_QUERY_INFORMATION: DWORD = 0x0400; - - pub const CP_ACP: UINT = 0; - - pub const WC_NO_BEST_FIT_CHARS: DWORD = 0x00000400; - - extern "system" { - pub fn OpenProcess(dwDesiredAccess: DWORD, - bInheritHandle: BOOL, - dwProcessId: DWORD) -> HANDLE; - } - - compat_fn! { - kernel32: - - pub fn QueryFullProcessImageNameW(_hProcess: HANDLE, - _dwFlags: DWORD, - _lpExeName: LPWSTR, - _lpdwSize: LPDWORD) -> BOOL { - SetLastError(ERROR_CALL_NOT_IMPLEMENTED as DWORD); 0 - } - } -} - -#[cfg(all(target_env = "gnu", feature = "backtrace"))] -pub use self::gnu::*; diff --git a/ctr-std/src/sys/windows/cmath.rs b/ctr-std/src/sys/windows/cmath.rs deleted file mode 100644 index b665a2c..0000000 --- a/ctr-std/src/sys/windows/cmath.rs +++ /dev/null @@ -1,103 +0,0 @@ -// Copyright 2017 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![cfg(not(test))] - -use libc::{c_float, c_double}; - -#[link_name = "m"] -extern { - 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(target_env = "msvc"))] -mod shims { - use libc::c_float; - - extern { - 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 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(target_env = "msvc")] -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/ctr-std/src/sys/windows/compat.rs b/ctr-std/src/sys/windows/compat.rs deleted file mode 100644 index cd42b7d..0000000 --- a/ctr-std/src/sys/windows/compat.rs +++ /dev/null @@ -1,81 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! 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 ffi::CString; -use sync::atomic::{AtomicUsize, Ordering}; -use 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: $( - pub fn $symbol:ident($($argname:ident: $argtype:ty),*) - -> $rettype:ty { - $($body:expr);* - } - )*) => ($( - #[allow(unused_variables)] - pub unsafe fn $symbol($($argname: $argtype),*) -> $rettype { - use sync::atomic::{AtomicUsize, Ordering}; - use mem; - type F = unsafe extern "system" fn($($argtype),*) -> $rettype; - - static PTR: AtomicUsize = AtomicUsize::new(0); - - fn load() -> usize { - ::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/ctr-std/src/sys/windows/condvar.rs b/ctr-std/src/sys/windows/condvar.rs deleted file mode 100644 index d708b32..0000000 --- a/ctr-std/src/sys/windows/condvar.rs +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use cell::UnsafeCell; -use sys::c; -use sys::mutex::{self, Mutex}; -use sys::os; -use 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/ctr-std/src/sys/windows/dynamic_lib.rs b/ctr-std/src/sys/windows/dynamic_lib.rs deleted file mode 100644 index 5227280..0000000 --- a/ctr-std/src/sys/windows/dynamic_lib.rs +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use os::windows::prelude::*; - -use ffi::{CString, OsStr}; -use io; -use sys::c; - -pub struct DynamicLibrary { - handle: c::HMODULE, -} - -impl DynamicLibrary { - pub fn open(filename: &str) -> io::Result<DynamicLibrary> { - let filename = OsStr::new(filename) - .encode_wide() - .chain(Some(0)) - .collect::<Vec<_>>(); - let result = unsafe { - c::LoadLibraryW(filename.as_ptr()) - }; - if result.is_null() { - Err(io::Error::last_os_error()) - } else { - Ok(DynamicLibrary { handle: result }) - } - } - - pub fn symbol(&self, symbol: &str) -> io::Result<usize> { - let symbol = CString::new(symbol)?; - unsafe { - match c::GetProcAddress(self.handle, symbol.as_ptr()) as usize { - 0 => Err(io::Error::last_os_error()), - n => Ok(n), - } - } - } -} - -impl Drop for DynamicLibrary { - fn drop(&mut self) { - unsafe { - c::FreeLibrary(self.handle); - } - } -} diff --git a/ctr-std/src/sys/windows/env.rs b/ctr-std/src/sys/windows/env.rs deleted file mode 100644 index e6d7489..0000000 --- a/ctr-std/src/sys/windows/env.rs +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -pub mod os { - pub const FAMILY: &'static str = "windows"; - pub const OS: &'static str = "windows"; - pub const DLL_PREFIX: &'static str = ""; - pub const DLL_SUFFIX: &'static str = ".dll"; - pub const DLL_EXTENSION: &'static str = "dll"; - pub const EXE_SUFFIX: &'static str = ".exe"; - pub const EXE_EXTENSION: &'static str = "exe"; -} diff --git a/ctr-std/src/sys/windows/ext/ffi.rs b/ctr-std/src/sys/windows/ext/ffi.rs deleted file mode 100644 index bae0d02..0000000 --- a/ctr-std/src/sys/windows/ext/ffi.rs +++ /dev/null @@ -1,152 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! 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 ffi::{OsString, OsStr}; -use sys::os_str::Buf; -use sys_common::wtf8::Wtf8Buf; -use sys_common::{FromInner, AsInner}; - -#[stable(feature = "rust1", since = "1.0.0")] -pub use 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/ctr-std/src/sys/windows/ext/fs.rs b/ctr-std/src/sys/windows/ext/fs.rs deleted file mode 100644 index 78c9e95..0000000 --- a/ctr-std/src/sys/windows/ext/fs.rs +++ /dev/null @@ -1,508 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Windows-specific extensions for the primitives in the `std::fs` module. - -#![stable(feature = "rust1", since = "1.0.0")] - -use fs::{self, OpenOptions, Metadata}; -use io; -use path::Path; -use sys; -use sys_common::{AsInnerMut, AsInner}; - -/// 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://msdn.microsoft.com/en-us/library/windows/desktop/aa363858.aspx - #[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 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://msdn.microsoft.com/en-us/library/windows/desktop/aa363858.aspx - #[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://msdn.microsoft.com/en-us/library/windows/desktop/aa363858.aspx - /// [`CreateFile2`]: https://msdn.microsoft.com/en-us/library/windows/desktop/hh449422.aspx - #[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://msdn.microsoft.com/en-us/library/windows/desktop/aa363858.aspx - /// [`CreateFile2`]: https://msdn.microsoft.com/en-us/library/windows/desktop/hh449422.aspx - #[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 set to `SECURITY_ANONYMOUS`. For - /// information about possible values, see [Impersonation Levels] on the - /// Windows Dev Center site. - /// - /// # Examples - /// - /// ```no_run - /// 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(1) - /// - /// .open("foo.txt"); - /// ``` - /// - /// [`CreateFile`]: https://msdn.microsoft.com/en-us/library/windows/desktop/aa363858.aspx - /// [`CreateFile2`]: https://msdn.microsoft.com/en-us/library/windows/desktop/hh449422.aspx - /// [Impersonation Levels]: - /// https://msdn.microsoft.com/en-us/library/windows/desktop/aa379572.aspx - #[stable(feature = "open_options_ext", since = "1.10.0")] - fn security_qos_flags(&mut self, flags: u32) -> &mut OpenOptions; -} - -#[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://msdn.microsoft.com/en-us/library/windows/desktop/aa363788.aspx -#[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://msdn.microsoft.com/en-us/library/windows/desktop/gg258117.aspx - #[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://msdn.microsoft.com/en-us/library/windows/desktop/ms724284.aspx - #[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://msdn.microsoft.com/en-us/library/windows/desktop/ms724284.aspx - #[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://msdn.microsoft.com/en-us/library/windows/desktop/ms724284.aspx - #[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; -} - -#[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() } -} - -/// 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 = "0")] -pub trait FileTypeExt { - /// Returns whether this file type is a symbolic link that is also a directory. - #[unstable(feature = "windows_file_type_ext", issue = "0")] - fn is_symlink_dir(&self) -> bool; - /// Returns whether this file type is a symbolic link that is also a file. - #[unstable(feature = "windows_file_type_ext", issue = "0")] - fn is_symlink_file(&self) -> bool; -} - -#[unstable(feature = "windows_file_type_ext", issue = "0")] -impl FileTypeExt for fs::FileType { - fn is_symlink_dir(&self) -> bool { self.as_inner().is_symlink_dir() } - fn is_symlink_file(&self) -> bool { self.as_inner().is_symlink_file() } -} - -/// Creates a new 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/ctr-std/src/sys/windows/ext/io.rs b/ctr-std/src/sys/windows/ext/io.rs deleted file mode 100644 index 90128dd..0000000 --- a/ctr-std/src/sys/windows/ext/io.rs +++ /dev/null @@ -1,209 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![stable(feature = "rust1", since = "1.0.0")] - -use fs; -use os::windows::raw; -use net; -use sys_common::{self, AsInner, FromInner, IntoInner}; -use sys; -use io; -use sys::c; - -/// 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; - -/// Extract 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 = "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 _ - } -} - -/// Extract 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; -} - -/// Create 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/ctr-std/src/sys/windows/ext/mod.rs b/ctr-std/src/sys/windows/ext/mod.rs deleted file mode 100644 index 1f10609..0000000 --- a/ctr-std/src/sys/windows/ext/mod.rs +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! 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 raw; -pub mod process; -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::io::{RawSocket, RawHandle, AsRawSocket, AsRawHandle}; - #[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")] - pub use super::io::{FromRawSocket, FromRawHandle, IntoRawSocket, IntoRawHandle}; - #[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")] - pub use super::ffi::{OsStrExt, OsStringExt}; - #[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")] - pub use super::fs::{OpenOptionsExt, MetadataExt}; - #[doc(no_inline)] #[stable(feature = "file_offset", since = "1.15.0")] - pub use super::fs::FileExt; -} diff --git a/ctr-std/src/sys/windows/ext/process.rs b/ctr-std/src/sys/windows/ext/process.rs deleted file mode 100644 index a02bcbe..0000000 --- a/ctr-std/src/sys/windows/ext/process.rs +++ /dev/null @@ -1,123 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Extensions to `std::process` for Windows. - -#![stable(feature = "process_extensions", since = "1.2.0")] - -use os::windows::io::{FromRawHandle, RawHandle, AsRawHandle, IntoRawHandle}; -use process; -use sys; -use sys_common::{AsInnerMut, AsInner, 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://msdn.microsoft.com/en-us/library/windows/desktop/ms684863(v=vs.85).aspx - #[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/ctr-std/src/sys/windows/ext/raw.rs b/ctr-std/src/sys/windows/ext/raw.rs deleted file mode 100644 index 92d53e2..0000000 --- a/ctr-std/src/sys/windows/ext/raw.rs +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Windows-specific primitives - -#![stable(feature = "raw_ext", since = "1.1.0")] - -use 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/ctr-std/src/sys/windows/ext/thread.rs b/ctr-std/src/sys/windows/ext/thread.rs deleted file mode 100644 index 36b3a3d..0000000 --- a/ctr-std/src/sys/windows/ext/thread.rs +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Extensions to `std::thread` for Windows. - -#![stable(feature = "thread_extensions", since = "1.9.0")] - -use os::windows::io::{RawHandle, AsRawHandle, IntoRawHandle}; -use thread; -use sys_common::{AsInner, IntoInner}; - -#[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/ctr-std/src/sys/windows/fast_thread_local.rs b/ctr-std/src/sys/windows/fast_thread_local.rs deleted file mode 100644 index 9fee9bd..0000000 --- a/ctr-std/src/sys/windows/fast_thread_local.rs +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![unstable(feature = "thread_local_internals", issue = "0")] -#![cfg(target_thread_local)] - -pub use sys_common::thread_local::register_dtor_fallback as register_dtor; - -pub fn requires_move_before_drop() -> bool { - false -} diff --git a/ctr-std/src/sys/windows/fs.rs b/ctr-std/src/sys/windows/fs.rs deleted file mode 100644 index 082d468..0000000 --- a/ctr-std/src/sys/windows/fs.rs +++ /dev/null @@ -1,804 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use os::windows::prelude::*; - -use ffi::OsString; -use fmt; -use io::{self, Error, SeekFrom}; -use mem; -use path::{Path, PathBuf}; -use ptr; -use slice; -use sync::Arc; -use sys::handle::Handle; -use sys::time::SystemTime; -use sys::{c, cvt}; -use 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, -} - -#[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 - }, - }) - } -} - -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) { self.security_qos_flags = flags; } - 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.security_qos_flags != 0 { c::SECURITY_SQOS_PRESENT } else { 0 } | - 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(()) - } - - 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 attr = FileAttr { - attributes: info.dwFileAttributes, - creation_time: info.ftCreationTime, - last_access_time: info.ftLastAccessTime, - last_write_time: info.ftLastWriteTime, - file_size: ((info.nFileSizeHigh as u64) << 32) | (info.nFileSizeLow as u64), - reparse_tag: 0, - }; - 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) - } - - 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_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, true, 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 as u32 } - - 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) - } - - fn is_reparse_point(&self) -> bool { - self.attributes & c::FILE_ATTRIBUTE_REPARSE_POINT != 0 - } -} - -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(()) -} - -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(()) -} - -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(|_| ()) - } -} diff --git a/ctr-std/src/sys/windows/handle.rs b/ctr-std/src/sys/windows/handle.rs deleted file mode 100644 index 3729d6d..0000000 --- a/ctr-std/src/sys/windows/handle.rs +++ /dev/null @@ -1,218 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![unstable(issue = "0", feature = "windows_handle")] - -use cmp; -use io::{ErrorKind, Read}; -use io; -use mem; -use ops::Deref; -use ptr; -use sys::c; -use 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); - return 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_value() 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_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> { - let mut read = 0; - let len = cmp::min(buf.len(), <c::DWORD>::max_value() 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_value() 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(|_| ()) - } - } - - pub fn read_to_end(&self, buf: &mut Vec<u8>) -> io::Result<usize> { - let mut me = self; - (&mut me).read_to_end(buf) - } - - pub fn write(&self, buf: &[u8]) -> io::Result<usize> { - let mut amt = 0; - let len = cmp::min(buf.len(), <c::DWORD>::max_value() 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_at(&self, buf: &[u8], offset: u64) -> io::Result<usize> { - let mut written = 0; - let len = cmp::min(buf.len(), <c::DWORD>::max_value() 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) - } -} diff --git a/ctr-std/src/sys/windows/memchr.rs b/ctr-std/src/sys/windows/memchr.rs deleted file mode 100644 index fa7c816..0000000 --- a/ctr-std/src/sys/windows/memchr.rs +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. -// -// 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/ctr-std/src/sys/windows/mod.rs b/ctr-std/src/sys/windows/mod.rs deleted file mode 100644 index ccf79de..0000000 --- a/ctr-std/src/sys/windows/mod.rs +++ /dev/null @@ -1,277 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![allow(missing_docs, bad_style)] - -use ptr; -use ffi::{OsStr, OsString}; -use io::{self, ErrorKind}; -use os::windows::ffi::{OsStrExt, OsStringExt}; -use path::PathBuf; -use time::Duration; - -pub use libc::strlen; -pub use self::rand::hashmap_random_keys; - -#[macro_use] pub mod compat; - -pub mod args; -#[cfg(feature = "backtrace")] -pub mod backtrace; -pub mod c; -pub mod cmath; -pub mod condvar; -#[cfg(feature = "backtrace")] -pub mod dynamic_lib; -pub mod env; -pub mod ext; -pub mod fast_thread_local; -pub mod fs; -pub mod handle; -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 stack_overflow; -pub mod thread; -pub mod thread_local; -pub mod time; -pub mod stdio; - -#[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_OPERATION_ABORTED => 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 to_u16s<S: AsRef<OsStr>>(s: S) -> io::Result<Vec<u16>> { - fn inner(s: &OsStr) -> io::Result<Vec<u16>> { - let mut maybe_result: Vec<u16> = s.encode_wide().collect(); - if maybe_result.iter().any(|&u| u == 0) { - return Err(io::Error::new(io::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) -> 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(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) - -> 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(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(io::Error::last_os_error()); - } - if no_default_char && used_default_char == c::TRUE { - return Err(io::Error::new(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<'a>(v: &'a [u16]) -> &'a [u16] { - match v.iter().position(|c| *c == 0) { - // 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) -> io::Result<I> { - if i.is_zero() { - Err(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_value() 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://msdn.microsoft.com/en-us/library/dn774154.aspx -#[allow(unreachable_code)] -pub unsafe fn abort_internal() -> ! { - #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] - { - asm!("int $$0x29" :: "{ecx}"(7) ::: volatile); // 7 is FAST_FAIL_FATAL_APP_EXIT - ::intrinsics::unreachable(); - } - ::intrinsics::abort(); -} diff --git a/ctr-std/src/sys/windows/mutex.rs b/ctr-std/src/sys/windows/mutex.rs deleted file mode 100644 index 9bf9f74..0000000 --- a/ctr-std/src/sys/windows/mutex.rs +++ /dev/null @@ -1,188 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! 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 cell::UnsafeCell; -use mem; -use sync::atomic::{AtomicUsize, Ordering}; -use sys::c; -use 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 { - 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 mut 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); - return ret; -} - -pub struct ReentrantMutex { inner: UnsafeCell<c::CRITICAL_SECTION> } - -unsafe impl Send for ReentrantMutex {} -unsafe impl Sync for ReentrantMutex {} - -impl ReentrantMutex { - pub unsafe fn uninitialized() -> ReentrantMutex { - mem::uninitialized() - } - - pub unsafe fn init(&mut self) { - c::InitializeCriticalSection(self.inner.get()); - } - - pub unsafe fn lock(&self) { - c::EnterCriticalSection(self.inner.get()); - } - - #[inline] - pub unsafe fn try_lock(&self) -> bool { - c::TryEnterCriticalSection(self.inner.get()) != 0 - } - - pub unsafe fn unlock(&self) { - c::LeaveCriticalSection(self.inner.get()); - } - - pub unsafe fn destroy(&self) { - c::DeleteCriticalSection(self.inner.get()); - } -} diff --git a/ctr-std/src/sys/windows/net.rs b/ctr-std/src/sys/windows/net.rs deleted file mode 100644 index cd8acff..0000000 --- a/ctr-std/src/sys/windows/net.rs +++ /dev/null @@ -1,356 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![unstable(issue = "0", feature = "windows_net")] - -use cmp; -use io::{self, Read}; -use libc::{c_int, c_void, c_ulong, c_long}; -use mem; -use net::{SocketAddr, Shutdown}; -use ptr; -use sync::Once; -use sys::c; -use sys; -use sys_common::{self, AsInner, FromInner, IntoInner}; -use sys_common::net; -use time::Duration; - -pub type wrlen_t = i32; - -pub mod netc { - pub use sys::c::*; - pub use sys::c::SOCKADDR as sockaddr; - pub use sys::c::SOCKADDR_STORAGE_LH as sockaddr_storage; - pub use sys::c::ADDRINFOA as addrinfo; - pub use sys::c::ADDRESS_FAMILY as sa_family_t; -} - -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::INVALID_SOCKET => Err(last_error()), - n => Ok(Socket(n)), - } - }?; - socket.set_no_inherit()?; - 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)), - } - }?; - socket.set_no_inherit()?; - 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::INVALID_SOCKET => Err(last_error()), - n => Ok(Socket(n)), - } - }?; - socket.set_no_inherit()?; - 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_value() 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 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_value() 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 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))) - } - } - - fn set_no_inherit(&self) -> io::Result<()> { - sys::cvt(unsafe { - c::SetHandleInformation(self.0 as c::HANDLE, - c::HANDLE_FLAG_INHERIT, 0) - }).map(|_| ()) - } - - 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 = "0", 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/ctr-std/src/sys/windows/os.rs b/ctr-std/src/sys/windows/os.rs deleted file mode 100644 index b944824..0000000 --- a/ctr-std/src/sys/windows/os.rs +++ /dev/null @@ -1,337 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Implementation of `std::os` functionality for Windows - -#![allow(bad_style)] - -use os::windows::prelude::*; - -use error::Error as StdError; -use ffi::{OsString, OsStr}; -use fmt; -use io; -use os::windows::ffi::EncodeWide; -use path::{self, PathBuf}; -use ptr; -use slice; -use sys::{c, cvt}; -use sys::handle::Handle; - -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://msdn.microsoft.com/en-us/library/cc231198.aspx - if (errnum & c::FACILITY_NT_BIT as i32) != 0 { - // format according to https://support.microsoft.com/en-us/help/259693 - const NTDLL_DLL: &'static [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 != ptr::null_mut() { - 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_right().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 { - 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(|_| ()) -} - -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(|_| ()) -} - -pub fn unsetenv(n: &OsStr) -> io::Result<()> { - let v = to_u16s(n)?; - cvt(unsafe { - c::SetEnvironmentVariableW(v.as_ptr(), ptr::null()) - }).map(|_| ()) -} - -pub fn temp_dir() -> PathBuf { - super::fill_utf16_buf(|buf, sz| unsafe { - c::GetTempPathW(sz, buf) - }, super::os2path).unwrap() -} - -pub fn home_dir() -> Option<PathBuf> { - ::env::var_os("HOME").or_else(|| { - ::env::var_os("USERPROFILE") - }).map(PathBuf::from).or_else(|| unsafe { - 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() - }) -} - -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 io::Error; - use 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/ctr-std/src/sys/windows/os_str.rs b/ctr-std/src/sys/windows/os_str.rs deleted file mode 100644 index bcc66b9..0000000 --- a/ctr-std/src/sys/windows/os_str.rs +++ /dev/null @@ -1,182 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -/// The underlying OsString/OsStr implementation on Windows is a -/// wrapper around the "WTF-8" encoding; see the `wtf8` module for more. - -use borrow::Cow; -use fmt; -use sys_common::wtf8::{Wtf8, Wtf8Buf}; -use mem; -use rc::Rc; -use sync::Arc; -use sys_common::{AsInner, IntoInner, FromInner}; - -#[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 { - unsafe { mem::transmute(self.inner.as_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 { - 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 } - } - - #[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) } - } -} diff --git a/ctr-std/src/sys/windows/path.rs b/ctr-std/src/sys/windows/path.rs deleted file mode 100644 index 98d62a0..0000000 --- a/ctr-std/src/sys/windows/path.rs +++ /dev/null @@ -1,106 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use path::Prefix; -use ffi::OsStr; -use mem; - -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'\\' -} - -pub fn parse_prefix<'a>(path: &'a OsStr) -> Option<Prefix> { - use path::Prefix::*; - unsafe { - // 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. - let mut path = os_str_as_u8_slice(path); - - if path.starts_with(br"\\") { - // \\ - path = &path[2..]; - if path.starts_with(br"?\") { - // \\?\ - path = &path[2..]; - if path.starts_with(br"UNC\") { - // \\?\UNC\server\share - path = &path[4..]; - let (server, share) = match parse_two_comps(path, is_verbatim_sep) { - Some((server, share)) => - (u8_slice_as_os_str(server), u8_slice_as_os_str(share)), - None => (u8_slice_as_os_str(path), u8_slice_as_os_str(&[])), - }; - return Some(VerbatimUNC(server, share)); - } else { - // \\?\path - let idx = path.iter().position(|&b| b == b'\\'); - if idx == Some(2) && path[1] == b':' { - let c = path[0]; - if c.is_ascii() && (c as char).is_alphabetic() { - // \\?\C:\ path - return Some(VerbatimDisk(c.to_ascii_uppercase())); - } - } - let slice = &path[..idx.unwrap_or(path.len())]; - return Some(Verbatim(u8_slice_as_os_str(slice))); - } - } else if path.starts_with(b".\\") { - // \\.\path - path = &path[2..]; - let pos = path.iter().position(|&b| b == b'\\'); - let slice = &path[..pos.unwrap_or(path.len())]; - return Some(DeviceNS(u8_slice_as_os_str(slice))); - } - match parse_two_comps(path, is_sep_byte) { - Some((server, share)) if !server.is_empty() && !share.is_empty() => { - // \\server\share - return Some(UNC(u8_slice_as_os_str(server), u8_slice_as_os_str(share))); - } - _ => (), - } - } else if path.get(1) == Some(& b':') { - // C: - let c = path[0]; - if c.is_ascii() && (c as char).is_alphabetic() { - return Some(Disk(c.to_ascii_uppercase())); - } - } - return None; - } - - fn parse_two_comps(mut path: &[u8], f: fn(u8) -> bool) -> Option<(&[u8], &[u8])> { - let first = match path.iter().position(|x| f(*x)) { - None => return None, - Some(x) => &path[..x], - }; - path = &path[(first.len() + 1)..]; - let idx = path.iter().position(|x| f(*x)); - let second = &path[..idx.unwrap_or(path.len())]; - Some((first, second)) - } -} - -pub const MAIN_SEP_STR: &'static str = "\\"; -pub const MAIN_SEP: char = '\\'; diff --git a/ctr-std/src/sys/windows/pipe.rs b/ctr-std/src/sys/windows/pipe.rs deleted file mode 100644 index df1dd74..0000000 --- a/ctr-std/src/sys/windows/pipe.rs +++ /dev/null @@ -1,364 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use os::windows::prelude::*; - -use ffi::OsStr; -use io; -use mem; -use path::Path; -use ptr; -use slice; -use sync::atomic::Ordering::SeqCst; -use sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT}; -use sys::c; -use sys::fs::{File, OpenOptions}; -use sys::handle::Handle; -use 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 where -/// `theirs` is writable. Conversely if `ours_readable` is false then `ours` is -/// writable where `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) -> 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 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 = ATOMIC_USIZE_INIT; - 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 write(&self, buf: &[u8]) -> io::Result<usize> { - self.inner.write(buf) - } -} - -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. - /// - /// Return 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::replace(self.dst, Vec::new()); - 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().offset(v.len() as isize), - v.capacity() - v.len()) -} diff --git a/ctr-std/src/sys/windows/process.rs b/ctr-std/src/sys/windows/process.rs deleted file mode 100644 index 4974a8d..0000000 --- a/ctr-std/src/sys/windows/process.rs +++ /dev/null @@ -1,581 +0,0 @@ -// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![unstable(feature = "process_internals", issue = "0")] - -use collections::BTreeMap; -use env::split_paths; -use env; -use ffi::{OsString, OsStr}; -use fmt; -use fs; -use io::{self, Error, ErrorKind}; -use libc::{c_void, EXIT_SUCCESS, EXIT_FAILURE}; -use mem; -use os::windows::ffi::OsStrExt; -use path::Path; -use ptr; -use sys::mutex::Mutex; -use sys::c; -use sys::fs::{OpenOptions, File}; -use sys::handle::Handle; -use sys::pipe::{self, AnonPipe}; -use sys::stdio; -use sys::cvt; -use sys_common::{AsInner, FromInner, IntoInner}; -use sys_common::process::{CommandEnv, EnvKey}; -use borrow::Borrow; - -//////////////////////////////////////////////////////////////////////////////// -// Command -//////////////////////////////////////////////////////////////////////////////// - -#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd)] -#[doc(hidden)] -pub struct WindowsEnvKey(OsString); - -impl From<OsString> for WindowsEnvKey { - fn from(k: OsString) -> Self { - let mut buf = k.into_inner().into_inner(); - buf.make_ascii_uppercase(); - WindowsEnvKey(FromInner::from_inner(FromInner::from_inner(buf))) - } -} - -impl From<WindowsEnvKey> for OsString { - fn from(k: WindowsEnvKey) -> Self { k.0 } -} - -impl Borrow<OsStr> for WindowsEnvKey { - fn borrow(&self) -> &OsStr { &self.0 } -} - -impl AsRef<OsStr> for WindowsEnvKey { - fn as_ref(&self) -> &OsStr { &self.0 } -} - -impl EnvKey for WindowsEnvKey {} - - -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<WindowsEnvKey>, - 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<WindowsEnvKey> { - &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: 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(stdio_id) { - Ok(io) => { - let io = Handle::new(io.handle()); - let ret = io.duplicate(0, true, - c::DUPLICATE_SAME_ACCESS); - io.into_raw(); - return 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)?; - *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()) - } - - 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) - } -} - -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 { - 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 iter = arg.encode_wide(); - let mut backslashes: usize = 0; - while let Some(x) = iter.next() { - 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 + 1)).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<WindowsEnvKey, 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 ffi::{OsStr, OsString}; - use super::make_command_line; - - #[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/ctr-std/src/sys/windows/rand.rs b/ctr-std/src/sys/windows/rand.rs deleted file mode 100644 index 2623236..0000000 --- a/ctr-std/src/sys/windows/rand.rs +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright 2013-2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use io; -use mem; -use sys::c; - -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()); - } - return v -} diff --git a/ctr-std/src/sys/windows/rwlock.rs b/ctr-std/src/sys/windows/rwlock.rs deleted file mode 100644 index 3e81ebf..0000000 --- a/ctr-std/src/sys/windows/rwlock.rs +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use cell::UnsafeCell; -use 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/ctr-std/src/sys/windows/stack_overflow.rs b/ctr-std/src/sys/windows/stack_overflow.rs deleted file mode 100644 index 4a406d7..0000000 --- a/ctr-std/src/sys/windows/stack_overflow.rs +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![cfg_attr(test, allow(dead_code))] - -use sys_common::util::report_overflow; -use sys::c; - -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/ctr-std/src/sys/windows/stdio.rs b/ctr-std/src/sys/windows/stdio.rs deleted file mode 100644 index 81b89da..0000000 --- a/ctr-std/src/sys/windows/stdio.rs +++ /dev/null @@ -1,233 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![unstable(issue = "0", feature = "windows_stdio")] - -use io::prelude::*; - -use cmp; -use io::{self, Cursor}; -use ptr; -use str; -use sync::Mutex; -use sys::c; -use sys::cvt; -use sys::handle::Handle; - -pub enum Output { - Console(c::HANDLE), - Pipe(c::HANDLE), -} - -pub struct Stdin { - utf8: Mutex<io::Cursor<Vec<u8>>>, -} -pub struct Stdout; -pub struct Stderr; - -pub fn get(handle: c::DWORD) -> io::Result<Output> { - let handle = unsafe { c::GetStdHandle(handle) }; - 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 { - let mut out = 0; - match unsafe { c::GetConsoleMode(handle, &mut out) } { - 0 => Ok(Output::Pipe(handle)), - _ => Ok(Output::Console(handle)), - } - } -} - -fn write(handle: c::DWORD, data: &[u8]) -> io::Result<usize> { - let handle = match try!(get(handle)) { - Output::Console(c) => c, - Output::Pipe(p) => { - let handle = Handle::new(p); - let ret = handle.write(data); - handle.into_raw(); - return ret - } - }; - - // As with stdin on windows, stdout often can't handle writes of large - // sizes. For an example, see #14940. For this reason, don't try to - // write the entire output buffer on windows. - // - // For some other references, it appears that this problem has been - // encountered by others [1] [2]. We choose the number 8K just because - // libuv does the same. - // - // [1]: https://tahoe-lafs.org/trac/tahoe-lafs/ticket/1232 - // [2]: http://www.mail-archive.com/[email protected]/msg00661.html - const OUT_MAX: usize = 8192; - let len = cmp::min(data.len(), OUT_MAX); - let utf8 = match str::from_utf8(&data[..len]) { - Ok(s) => s, - Err(ref e) if e.valid_up_to() == 0 => return Err(invalid_encoding()), - Err(e) => str::from_utf8(&data[..e.valid_up_to()]).unwrap(), - }; - let utf16 = utf8.encode_utf16().collect::<Vec<u16>>(); - let mut written = 0; - cvt(unsafe { - c::WriteConsoleW(handle, - utf16.as_ptr() as c::LPCVOID, - utf16.len() as u32, - &mut written, - ptr::null_mut()) - })?; - - // FIXME if this only partially writes the utf16 buffer then we need to - // figure out how many bytes of `data` were actually written - assert_eq!(written as usize, utf16.len()); - Ok(utf8.len()) -} - -impl Stdin { - pub fn new() -> io::Result<Stdin> { - Ok(Stdin { - utf8: Mutex::new(Cursor::new(Vec::new())), - }) - } - - pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> { - let handle = match try!(get(c::STD_INPUT_HANDLE)) { - Output::Console(c) => c, - Output::Pipe(p) => { - let handle = Handle::new(p); - let ret = handle.read(buf); - handle.into_raw(); - return ret - } - }; - let mut utf8 = self.utf8.lock().unwrap(); - // Read more if the buffer is empty - if utf8.position() as usize == utf8.get_ref().len() { - let mut utf16 = vec![0u16; 0x1000]; - let mut num = 0; - let mut input_control = readconsole_input_control(CTRL_Z_MASK); - cvt(unsafe { - c::ReadConsoleW(handle, - utf16.as_mut_ptr() as c::LPVOID, - utf16.len() as u32, - &mut num, - &mut input_control as c::PCONSOLE_READCONSOLE_CONTROL) - })?; - utf16.truncate(num as usize); - // FIXME: what to do about this data that has already been read? - let mut data = match String::from_utf16(&utf16) { - Ok(utf8) => utf8.into_bytes(), - Err(..) => return Err(invalid_encoding()), - }; - if let Some(&last_byte) = data.last() { - if last_byte == CTRL_Z { - data.pop(); - } - } - *utf8 = Cursor::new(data); - } - - // MemReader shouldn't error here since we just filled it - utf8.read(buf) - } - - pub fn read_to_end(&self, buf: &mut Vec<u8>) -> io::Result<usize> { - let mut me = self; - (&mut me).read_to_end(buf) - } -} - -#[unstable(reason = "not public", issue = "0", feature = "fd_read")] -impl<'a> Read for &'a Stdin { - fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { - (**self).read(buf) - } -} - -impl Stdout { - pub fn new() -> io::Result<Stdout> { - Ok(Stdout) - } - - pub fn write(&self, data: &[u8]) -> io::Result<usize> { - write(c::STD_OUTPUT_HANDLE, data) - } - - pub fn flush(&self) -> io::Result<()> { - Ok(()) - } -} - -impl Stderr { - pub fn new() -> io::Result<Stderr> { - Ok(Stderr) - } - - pub fn write(&self, data: &[u8]) -> io::Result<usize> { - write(c::STD_ERROR_HANDLE, data) - } - - pub fn flush(&self) -> io::Result<()> { - Ok(()) - } -} - -// FIXME: right now this raw stderr handle is used in a few places because -// std::io::stderr_raw isn't exposed, but once that's exposed this impl -// should go away -impl io::Write for Stderr { - fn write(&mut self, data: &[u8]) -> io::Result<usize> { - Stderr::write(self, data) - } - - fn flush(&mut self) -> io::Result<()> { - Stderr::flush(self) - } -} - -impl Output { - pub fn handle(&self) -> c::HANDLE { - match *self { - Output::Console(c) => c, - Output::Pipe(c) => c, - } - } -} - -fn invalid_encoding() -> io::Error { - io::Error::new(io::ErrorKind::InvalidData, "text was not valid unicode") -} - -fn readconsole_input_control(wakeup_mask: c::ULONG) -> c::CONSOLE_READCONSOLE_CONTROL { - c::CONSOLE_READCONSOLE_CONTROL { - nLength: ::mem::size_of::<c::CONSOLE_READCONSOLE_CONTROL>() as c::ULONG, - nInitialChars: 0, - dwCtrlWakeupMask: wakeup_mask, - dwControlKeyState: 0, - } -} - -const CTRL_Z: u8 = 0x1A; -const CTRL_Z_MASK: c::ULONG = 0x4000000; //1 << 0x1A - -pub fn is_ebadf(err: &io::Error) -> bool { - err.raw_os_error() == Some(c::ERROR_INVALID_HANDLE as i32) -} - -// The default buffer capacity is 64k, but apparently windows -// doesn't like 64k reads on stdin. See #13304 for details, but the -// idea is that on windows we use a slightly smaller buffer that's -// been seen to be acceptable. -pub const STDIN_BUF_SIZE: usize = 8 * 1024; - -pub fn stderr_prints_nothing() -> bool { - false -} diff --git a/ctr-std/src/sys/windows/thread.rs b/ctr-std/src/sys/windows/thread.rs deleted file mode 100644 index 85588cc..0000000 --- a/ctr-std/src/sys/windows/thread.rs +++ /dev/null @@ -1,101 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use boxed::FnBox; -use io; -use ffi::CStr; -use mem; -use libc::c_void; -use ptr; -use sys::c; -use sys::handle::Handle; -use sys_common::thread::*; -use time::Duration; - -use super::to_u16s; - -pub const DEFAULT_MIN_STACK_SIZE: usize = 2 * 1024 * 1024; - -pub struct Thread { - handle: Handle -} - -impl Thread { - pub unsafe fn new<'a>(stack: usize, p: Box<dyn FnBox() + 'a>) - -> io::Result<Thread> { - let p = 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 *const _ as *mut _, - c::STACK_SIZE_PARAM_IS_A_RESERVATION, - ptr::null_mut()); - - return if ret as usize == 0 { - Err(io::Error::last_os_error()) - } else { - mem::forget(p); // ownership passed to CreateThread - Ok(Thread { handle: Handle::new(ret) }) - }; - - extern "system" fn thread_start(main: *mut c_void) -> c::DWORD { - unsafe { start_thread(main as *mut u8); } - 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 } - pub unsafe fn deinit() {} -} diff --git a/ctr-std/src/sys/windows/thread_local.rs b/ctr-std/src/sys/windows/thread_local.rs deleted file mode 100644 index cdad320..0000000 --- a/ctr-std/src/sys/windows/thread_local.rs +++ /dev/null @@ -1,251 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use mem; -use ptr; -use sync::atomic::AtomicPtr; -use sync::atomic::Ordering::SeqCst; -use sys::c; - -pub type Key = c::DWORD; -pub type Dtor = unsafe extern 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); - } - return 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, -} - -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(_) => return mem::forget(node), - 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 { static _tls_used: u8; } - ::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/ctr-std/src/sys/windows/time.rs b/ctr-std/src/sys/windows/time.rs deleted file mode 100644 index 07e64d3..0000000 --- a/ctr-std/src/sys/windows/time.rs +++ /dev/null @@ -1,206 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use cmp::Ordering; -use fmt; -use mem; -use sync::Once; -use sys::c; -use sys::cvt; -use sys_common::mul_div_u64; -use time::Duration; -use convert::TryInto; -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 { - t: c::LARGE_INTEGER, -} - -#[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 { - let mut t = Instant { t: 0 }; - cvt(unsafe { - c::QueryPerformanceCounter(&mut t.t) - }).unwrap(); - t - } - - pub fn sub_instant(&self, other: &Instant) -> Duration { - // Values which are +- 1 need to be considered as basically the same - // units in time due to various measurement oddities, according to - // Windows [1] - // - // [1]: - // https://msdn.microsoft.com/en-us/library/windows/desktop - // /dn553408%28v=vs.85%29.aspx#guidance - if other.t > self.t && other.t - self.t == 1 { - return Duration::new(0, 0) - } - let diff = (self.t as u64).checked_sub(other.t as u64) - .expect("specified instant was later than \ - self"); - let nanos = mul_div_u64(diff, NANOS_PER_SEC, frequency() as u64); - Duration::new(nanos / NANOS_PER_SEC, (nanos % NANOS_PER_SEC) as u32) - } - - pub fn add_duration(&self, other: &Duration) -> Instant { - let freq = frequency() as u64; - let t = other.as_secs().checked_mul(freq).and_then(|i| { - (self.t as u64).checked_add(i) - }).and_then(|i| { - i.checked_add(mul_div_u64(other.subsec_nanos() as u64, freq, - NANOS_PER_SEC)) - }).expect("overflow when adding duration to time"); - Instant { - t: t as c::LARGE_INTEGER, - } - } - - pub fn sub_duration(&self, other: &Duration) -> Instant { - let freq = frequency() as u64; - let t = other.as_secs().checked_mul(freq).and_then(|i| { - (self.t as u64).checked_sub(i) - }).and_then(|i| { - i.checked_sub(mul_div_u64(other.subsec_nanos() as u64, freq, - NANOS_PER_SEC)) - }).expect("overflow when subtracting duration from time"); - Instant { - t: t as c::LARGE_INTEGER, - } - } -} - -impl SystemTime { - pub fn now() -> SystemTime { - unsafe { - let mut t: SystemTime = mem::zeroed(); - c::GetSystemTimeAsFileTime(&mut t.t); - return 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 add_duration(&self, other: &Duration) -> SystemTime { - let intervals = self.intervals().checked_add(dur2intervals(other)) - .expect("overflow when adding duration to time"); - SystemTime::from_intervals(intervals) - } - - pub fn sub_duration(&self, other: &Duration) -> SystemTime { - let intervals = self.intervals().checked_sub(dur2intervals(other)) - .expect("overflow when subtracting from time"); - 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: t } - } -} - -impl Hash for SystemTime { - fn hash<H : Hasher>(&self, state: &mut H) { - self.intervals().hash(state) - } -} - -fn dur2intervals(d: &Duration) -> i64 { - d.as_secs() - .checked_mul(INTERVALS_PER_SEC) - .and_then(|i| i.checked_add(d.subsec_nanos() as u64 / 100)) - .and_then(|i| i.try_into().ok()) - .expect("overflow when converting duration to intervals") -} - -fn intervals2dur(intervals: u64) -> Duration { - Duration::new(intervals / INTERVALS_PER_SEC, - ((intervals % INTERVALS_PER_SEC) * 100) as u32) -} - -fn frequency() -> c::LARGE_INTEGER { - static mut FREQUENCY: c::LARGE_INTEGER = 0; - static ONCE: Once = Once::new(); - - unsafe { - ONCE.call_once(|| { - cvt(c::QueryPerformanceFrequency(&mut FREQUENCY)).unwrap(); - }); - FREQUENCY - } -} |