diff options
| author | Mathieu David <mathieudavid@mathieudavid.org> | 2015-07-27 20:46:01 +0200 |
|---|---|---|
| committer | Mathieu David <mathieudavid@mathieudavid.org> | 2015-07-27 20:46:01 +0200 |
| commit | f6e9240a99e86d2c799dc29f179dd2870e51f71d (patch) | |
| tree | a7e5ba20745b16949a45a4612b2708e262693a7b /src/libstd/sys | |
| parent | 003c3eaa62981b791f9eb7bcad015baa1e00d98c (diff) | |
| parent | 3351afeecffcc9ebaeb1188a5cde976da8e4a5aa (diff) | |
| download | rust-f6e9240a99e86d2c799dc29f179dd2870e51f71d.tar.gz rust-f6e9240a99e86d2c799dc29f179dd2870e51f71d.zip | |
Fix the relative path issue by including the files using include_bytes!
Diffstat (limited to 'src/libstd/sys')
41 files changed, 1182 insertions, 427 deletions
diff --git a/src/libstd/sys/common/io.rs b/src/libstd/sys/common/io.rs new file mode 100644 index 00000000000..151d853fc9f --- /dev/null +++ b/src/libstd/sys/common/io.rs @@ -0,0 +1,139 @@ +// 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 prelude::v1::*; +use io; +use io::ErrorKind; +use io::Read; +use slice::from_raw_parts_mut; + +// Provides read_to_end functionality over an uninitialized buffer. +// This function is unsafe because it calls the underlying +// read function with a slice into uninitialized memory. The default +// implementation of read_to_end for readers will zero out new memory in +// the buf before passing it to read, but avoiding this zero can often +// lead to a fairly significant performance win. +// +// Implementations using this method have to adhere to two guarantees: +// * The implementation of read never reads the buffer provided. +// * The implementation of read correctly reports how many bytes were written. +pub unsafe fn read_to_end_uninitialized(r: &mut Read, buf: &mut Vec<u8>) -> io::Result<usize> { + + let start_len = buf.len(); + buf.reserve(16); + + // Always try to read into the empty space of the vector (from the length to the capacity). + // If the vector ever fills up then we reserve an extra byte which should trigger the normal + // reallocation routines for the vector, which will likely double the size. + // + // This function is similar to the read_to_end function in std::io, but the logic about + // reservations and slicing is different enough that this is duplicated here. + loop { + if buf.len() == buf.capacity() { + buf.reserve(1); + } + + let buf_slice = from_raw_parts_mut(buf.as_mut_ptr().offset(buf.len() as isize), + buf.capacity() - buf.len()); + + match r.read(buf_slice) { + Ok(0) => { return Ok(buf.len() - start_len); } + Ok(n) => { let len = buf.len() + n; buf.set_len(len); }, + Err(ref e) if e.kind() == ErrorKind::Interrupted => { } + Err(e) => { return Err(e); } + } + } +} + +#[cfg(test)] +mod tests { + use prelude::v1::*; + use io::prelude::*; + use super::*; + use io; + use io::{ErrorKind, Take, Repeat, repeat}; + use test; + use slice::from_raw_parts; + + struct ErrorRepeat { + lr: Take<Repeat> + } + + fn error_repeat(byte: u8, limit: u64) -> ErrorRepeat { + ErrorRepeat { lr: repeat(byte).take(limit) } + } + + impl Read for ErrorRepeat { + fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { + let ret = self.lr.read(buf); + if let Ok(0) = ret { + return Err(io::Error::new(ErrorKind::Other, "")) + } + ret + } + } + + fn init_vec_data() -> Vec<u8> { + let mut vec = vec![10u8; 200]; + unsafe { vec.set_len(0); } + vec + } + + fn assert_all_eq(buf: &[u8], value: u8) { + for n in buf { + assert_eq!(*n, value); + } + } + + fn validate(buf: &Vec<u8>, good_read_len: usize) { + assert_all_eq(buf, 1u8); + let cap = buf.capacity(); + let end_slice = unsafe { from_raw_parts(buf.as_ptr().offset(good_read_len as isize), + cap - good_read_len) }; + assert_all_eq(end_slice, 10u8); + } + + #[test] + fn read_to_end_uninit_error() { + let mut er = error_repeat(1,100); + let mut vec = init_vec_data(); + if let Err(_) = unsafe { read_to_end_uninitialized(&mut er, &mut vec) } { + validate(&vec, 100); + } else { + assert!(false); + } + } + + #[test] + fn read_to_end_uninit_zero_len_vec() { + let mut er = repeat(1).take(100); + let mut vec = Vec::new(); + let n = unsafe{ read_to_end_uninitialized(&mut er, &mut vec).unwrap() }; + assert_all_eq(&vec, 1u8); + assert_eq!(vec.len(), n); + } + + #[test] + fn read_to_end_uninit_good() { + let mut er = repeat(1).take(100); + let mut vec = init_vec_data(); + let n = unsafe{ read_to_end_uninitialized(&mut er, &mut vec).unwrap() }; + validate(&vec, 100); + assert_eq!(vec.len(), n); + } + + #[bench] + fn bench_uninitialized(b: &mut test::Bencher) { + b.iter(|| { + let mut lr = repeat(1).take(10000000); + let mut vec = Vec::with_capacity(1024); + unsafe { read_to_end_uninitialized(&mut lr, &mut vec) }; + }); + } +} diff --git a/src/libstd/sys/common/mod.rs b/src/libstd/sys/common/mod.rs index b528575bbed..69c54f98917 100644 --- a/src/libstd/sys/common/mod.rs +++ b/src/libstd/sys/common/mod.rs @@ -16,6 +16,7 @@ pub mod backtrace; pub mod condvar; pub mod mutex; pub mod net; +pub mod io; pub mod poison; pub mod remutex; pub mod rwlock; diff --git a/src/libstd/sys/common/net.rs b/src/libstd/sys/common/net.rs index 5890e6a7889..6dd222b8f6e 100644 --- a/src/libstd/sys/common/net.rs +++ b/src/libstd/sys/common/net.rs @@ -184,6 +184,8 @@ impl TcpStream { pub fn socket(&self) -> &Socket { &self.inner } + pub fn into_socket(self) -> Socket { self.inner } + pub fn set_nodelay(&self, nodelay: bool) -> io::Result<()> { setsockopt(&self.inner, libc::IPPROTO_TCP, libc::TCP_NODELAY, nodelay as c_int) @@ -336,6 +338,8 @@ impl TcpListener { pub fn socket(&self) -> &Socket { &self.inner } + pub fn into_socket(self) -> Socket { self.inner } + pub fn socket_addr(&self) -> io::Result<SocketAddr> { sockname(|buf, len| unsafe { libc::getsockname(*self.inner.as_inner(), buf, len) @@ -396,6 +400,8 @@ impl UdpSocket { pub fn socket(&self) -> &Socket { &self.inner } + pub fn into_socket(self) -> Socket { self.inner } + pub fn socket_addr(&self) -> io::Result<SocketAddr> { sockname(|buf, len| unsafe { libc::getsockname(*self.inner.as_inner(), buf, len) diff --git a/src/libstd/sys/common/stack.rs b/src/libstd/sys/common/stack.rs index 11982ebc572..41c8ac4aed3 100644 --- a/src/libstd/sys/common/stack.rs +++ b/src/libstd/sys/common/stack.rs @@ -170,8 +170,7 @@ pub unsafe fn record_sp_limit(limit: usize) { asm!("movl $$0x48+90*4, %eax movl $0, %gs:(%eax)" :: "r"(limit) : "eax" : "volatile") } - #[cfg(all(target_arch = "x86", - any(target_os = "linux", target_os = "freebsd")))] + #[cfg(all(target_arch = "x86", target_os = "linux"))] #[inline(always)] unsafe fn target_record_sp_limit(limit: usize) { asm!("movl $0, %gs:48" :: "r"(limit) :: "volatile") @@ -197,11 +196,14 @@ pub unsafe fn record_sp_limit(limit: usize) { // aarch64 - FIXME(AARCH64): missing... // powerpc - FIXME(POWERPC): missing... // arm-ios - iOS segmented stack is disabled for now, see related notes - // openbsd - segmented stack is disabled + // openbsd/bitrig/netbsd - no segmented stacks. + // x86-freebsd - no segmented stacks. #[cfg(any(target_arch = "aarch64", target_arch = "powerpc", all(target_arch = "arm", target_os = "ios"), + all(target_arch = "x86", target_os = "freebsd"), target_os = "bitrig", + target_os = "netbsd", target_os = "openbsd"))] unsafe fn target_record_sp_limit(_: usize) { } @@ -261,8 +263,7 @@ pub unsafe fn get_sp_limit() -> usize { movl %gs:(%eax), $0" : "=r"(limit) :: "eax" : "volatile"); return limit; } - #[cfg(all(target_arch = "x86", - any(target_os = "linux", target_os = "freebsd")))] + #[cfg(all(target_arch = "x86", target_os = "linux"))] #[inline(always)] unsafe fn target_get_sp_limit() -> usize { let limit; @@ -290,15 +291,18 @@ pub unsafe fn get_sp_limit() -> usize { // aarch64 - FIXME(AARCH64): missing... // powerpc - FIXME(POWERPC): missing... - // arm-ios - iOS doesn't support segmented stacks yet. - // openbsd - OpenBSD doesn't support segmented stacks. + // arm-ios - no segmented stacks. + // openbsd/bitrig/netbsd - no segmented stacks. + // x86-freebsd - no segmented stacks.. // // This function might be called by runtime though // so it is unsafe to unreachable, let's return a fixed constant. #[cfg(any(target_arch = "aarch64", target_arch = "powerpc", all(target_arch = "arm", target_os = "ios"), + all(target_arch = "x86", target_os = "freebsd"), target_os = "bitrig", + target_os = "netbsd", target_os = "openbsd"))] #[inline(always)] unsafe fn target_get_sp_limit() -> usize { diff --git a/src/libstd/sys/common/thread_info.rs b/src/libstd/sys/common/thread_info.rs index ae55bae37aa..bb47c946e49 100644 --- a/src/libstd/sys/common/thread_info.rs +++ b/src/libstd/sys/common/thread_info.rs @@ -18,7 +18,7 @@ use thread::Thread; use thread::LocalKeyState; struct ThreadInfo { - stack_guard: usize, + stack_guard: Option<usize>, thread: Thread, } @@ -33,7 +33,7 @@ impl ThreadInfo { THREAD_INFO.with(move |c| { if c.borrow().is_none() { *c.borrow_mut() = Some(ThreadInfo { - stack_guard: 0, + stack_guard: None, thread: NewThread::new(None), }) } @@ -47,10 +47,10 @@ pub fn current_thread() -> Option<Thread> { } pub fn stack_guard() -> Option<usize> { - ThreadInfo::with(|info| info.stack_guard) + ThreadInfo::with(|info| info.stack_guard).and_then(|o| o) } -pub fn set(stack_guard: usize, thread: Thread) { +pub fn set(stack_guard: Option<usize>, thread: Thread) { THREAD_INFO.with(|c| assert!(c.borrow().is_none())); THREAD_INFO.with(move |c| *c.borrow_mut() = Some(ThreadInfo{ stack_guard: stack_guard, diff --git a/src/libstd/sys/common/wtf8.rs b/src/libstd/sys/common/wtf8.rs index 8ea673d2162..6f15d606724 100644 --- a/src/libstd/sys/common/wtf8.rs +++ b/src/libstd/sys/common/wtf8.rs @@ -32,17 +32,18 @@ use core::str::next_code_point; use ascii::*; use borrow::Cow; +use char; use cmp; use fmt; use hash::{Hash, Hasher}; use iter::FromIterator; use mem; use ops; +use rustc_unicode::str::{Utf16Item, utf16_items}; use slice; use str; use string::String; use sys_common::AsInner; -use rustc_unicode::str::{Utf16Item, utf16_items}; use vec::Vec; const UTF8_REPLACEMENT_CHARACTER: &'static [u8] = b"\xEF\xBF\xBD"; @@ -107,7 +108,7 @@ impl CodePoint { pub fn to_char(&self) -> Option<char> { match self.value { 0xD800 ... 0xDFFF => None, - _ => Some(unsafe { mem::transmute(self.value) }) + _ => Some(unsafe { char::from_u32_unchecked(self.value) }) } } @@ -213,18 +214,16 @@ impl Wtf8Buf { // Attempt to not use an intermediate buffer by just pushing bytes // directly onto this string. let slice = slice::from_raw_parts_mut( - self.bytes.as_mut_ptr().offset(cur_len as isize), - 4 + self.bytes.as_mut_ptr().offset(cur_len as isize), 4 ); - let used = encode_utf8_raw(code_point.value, mem::transmute(slice)) - .unwrap_or(0); + let used = encode_utf8_raw(code_point.value, slice).unwrap(); self.bytes.set_len(cur_len + used); } } #[inline] pub fn as_slice(&self) -> &Wtf8 { - unsafe { mem::transmute(&*self.bytes) } + unsafe { Wtf8::from_bytes_unchecked(&self.bytes) } } /// Reserves capacity for at least `additional` more bytes to be inserted @@ -457,7 +456,16 @@ impl Wtf8 { /// Since WTF-8 is a superset of UTF-8, this always succeeds. #[inline] pub fn from_str(value: &str) -> &Wtf8 { - unsafe { mem::transmute(value.as_bytes()) } + unsafe { Wtf8::from_bytes_unchecked(value.as_bytes()) } + } + + /// Creates a WTF-8 slice from a WTF-8 byte slice. + /// + /// Since the byte slice is not checked for valid WTF-8, this functions is + /// marked unsafe. + #[inline] + unsafe fn from_bytes_unchecked(value: &[u8]) -> &Wtf8 { + mem::transmute(value) } /// Returns the length, in WTF-8 bytes. @@ -682,7 +690,7 @@ fn decode_surrogate(second_byte: u8, third_byte: u8) -> u16 { #[inline] fn decode_surrogate_pair(lead: u16, trail: u16) -> char { let code_point = 0x10000 + ((((lead - 0xD800) as u32) << 10) | (trail - 0xDC00) as u32); - unsafe { mem::transmute(code_point) } + unsafe { char::from_u32_unchecked(code_point) } } /// Copied from core::str::StrPrelude::is_char_boundary @@ -699,7 +707,7 @@ pub fn is_code_point_boundary(slice: &Wtf8, index: usize) -> bool { #[inline] pub unsafe fn slice_unchecked(s: &Wtf8, begin: usize, end: usize) -> &Wtf8 { // memory layout of an &[u8] and &Wtf8 are the same - mem::transmute(slice::from_raw_parts( + Wtf8::from_bytes_unchecked(slice::from_raw_parts( s.bytes.as_ptr().offset(begin as isize), end - begin )) @@ -821,7 +829,6 @@ mod tests { use prelude::v1::*; use borrow::Cow; use super::*; - use mem::transmute; #[test] fn code_point_from_u32() { @@ -962,7 +969,7 @@ mod tests { string.push_wtf8(Wtf8::from_str(" 💩")); assert_eq!(string.bytes, b"a\xC3\xA9 \xF0\x9F\x92\xA9"); - fn w(value: &[u8]) -> &Wtf8 { unsafe { transmute(value) } } + fn w(v: &[u8]) -> &Wtf8 { unsafe { Wtf8::from_bytes_unchecked(v) } } let mut string = Wtf8Buf::new(); string.push_wtf8(w(b"\xED\xA0\xBD")); // lead diff --git a/src/libstd/sys/unix/backtrace.rs b/src/libstd/sys/unix/backtrace.rs index b23a3eee1a1..ed6421f3670 100644 --- a/src/libstd/sys/unix/backtrace.rs +++ b/src/libstd/sys/unix/backtrace.rs @@ -107,8 +107,6 @@ use sys_common::backtrace::*; #[cfg(all(target_os = "ios", target_arch = "arm"))] #[inline(never)] pub fn write(w: &mut Write) -> io::Result<()> { - use result; - extern { fn backtrace(buf: *mut *mut libc::c_void, sz: libc::c_int) -> libc::c_int; @@ -127,10 +125,10 @@ pub fn write(w: &mut Write) -> io::Result<()> { let cnt = unsafe { backtrace(buf.as_mut_ptr(), SIZE as libc::c_int) as usize}; // skipping the first one as it is write itself - let iter = (1..cnt).map(|i| { - print(w, i as isize, buf[i], buf[i]) - }); - result::fold(iter, (), |_, _| ()) + for i in 1..cnt { + try!(print(w, i as isize, buf[i], buf[i])) + } + Ok(()) } #[cfg(not(all(target_os = "ios", target_arch = "arm")))] @@ -363,6 +361,7 @@ fn print(w: &mut Write, idx: isize, addr: *mut libc::c_void, let selfname = if cfg!(target_os = "freebsd") || cfg!(target_os = "dragonfly") || cfg!(target_os = "bitrig") || + cfg!(target_os = "netbsd") || cfg!(target_os = "openbsd") { env::current_exe().ok() } else { diff --git a/src/libstd/sys/unix/c.rs b/src/libstd/sys/unix/c.rs index 99a6731c57d..eeecf7f50f7 100644 --- a/src/libstd/sys/unix/c.rs +++ b/src/libstd/sys/unix/c.rs @@ -34,6 +34,7 @@ use libc; target_os = "freebsd", target_os = "dragonfly", target_os = "bitrig", + target_os = "netbsd", target_os = "openbsd"))] pub const FIOCLEX: libc::c_ulong = 0x20006601; @@ -60,6 +61,7 @@ pub const _SC_GETPW_R_SIZE_MAX: libc::c_int = 70; target_os = "dragonfly"))] pub const _SC_GETPW_R_SIZE_MAX: libc::c_int = 71; #[cfg(any(target_os = "bitrig", + target_os = "netbsd", target_os = "openbsd"))] pub const _SC_GETPW_R_SIZE_MAX: libc::c_int = 101; #[cfg(target_os = "android")] @@ -82,6 +84,7 @@ pub struct passwd { target_os = "freebsd", target_os = "dragonfly", target_os = "bitrig", + target_os = "netbsd", target_os = "openbsd"))] pub struct passwd { pub pw_name: *mut libc::c_char, @@ -321,6 +324,7 @@ mod signal_os { target_os = "freebsd", target_os = "dragonfly", target_os = "bitrig", + target_os = "netbsd", target_os = "openbsd"))] mod signal_os { use libc; @@ -348,7 +352,7 @@ mod signal_os { pub struct sigset_t { bits: [u32; 4], } - #[cfg(any(target_os = "bitrig", target_os = "openbsd"))] + #[cfg(any(target_os = "bitrig", target_os = "netbsd", target_os = "openbsd"))] pub type sigset_t = libc::c_uint; // This structure has more fields, but we're not all that interested in @@ -365,7 +369,7 @@ mod signal_os { pub _status: libc::c_int, pub si_addr: *mut libc::c_void } - #[cfg(any(target_os = "bitrig", target_os = "openbsd"))] + #[cfg(any(target_os = "bitrig", target_os = "netbsd", target_os = "openbsd"))] #[repr(C)] pub struct siginfo { pub si_signo: libc::c_int, @@ -375,7 +379,7 @@ mod signal_os { } #[cfg(any(target_os = "macos", target_os = "ios", - target_os = "bitrig", target_os = "openbsd"))] + target_os = "bitrig", target_os = "netbsd", target_os = "openbsd"))] #[repr(C)] pub struct sigaction { pub sa_sigaction: sighandler_t, diff --git a/src/libstd/sys/unix/ext/fs.rs b/src/libstd/sys/unix/ext/fs.rs index 97703b83056..4ee790b0161 100644 --- a/src/libstd/sys/unix/ext/fs.rs +++ b/src/libstd/sys/unix/ext/fs.rs @@ -16,6 +16,7 @@ use prelude::v1::*; use fs::{self, Permissions, OpenOptions}; use io; +use libc; use os::raw::c_long; use os::unix::raw; use path::Path; @@ -178,6 +179,27 @@ impl MetadataExt for fs::Metadata { } } +/// Add special unix types (block/char device, fifo and socket) +#[unstable(feature = "file_type_ext", reason = "recently added API")] +pub trait FileTypeExt { + /// Returns whether this file type is a block device. + fn is_block_device(&self) -> bool; + /// Returns whether this file type is a char device. + fn is_char_device(&self) -> bool; + /// Returns whether this file type is a fifo. + fn is_fifo(&self) -> bool; + /// Returns whether this file type is a socket. + fn is_socket(&self) -> bool; +} + +#[unstable(feature = "file_type_ext", reason = "recently added API")] +impl FileTypeExt for fs::FileType { + fn is_block_device(&self) -> bool { self.as_inner().is(libc::S_IFBLK) } + fn is_char_device(&self) -> bool { self.as_inner().is(libc::S_IFCHR) } + fn is_fifo(&self) -> bool { self.as_inner().is(libc::S_IFIFO) } + fn is_socket(&self) -> bool { self.as_inner().is(libc::S_IFSOCK) } +} + /// Unix-specific extension methods for `fs::DirEntry` #[stable(feature = "dir_entry_ext", since = "1.1.0")] pub trait DirEntryExt { diff --git a/src/libstd/sys/unix/ext/io.rs b/src/libstd/sys/unix/ext/io.rs index 79e59ddab5b..580d2dbcf74 100644 --- a/src/libstd/sys/unix/ext/io.rs +++ b/src/libstd/sys/unix/ext/io.rs @@ -16,7 +16,7 @@ use fs; use net; use os::raw; use sys; -use sys_common::{self, AsInner, FromInner}; +use sys_common::{self, AsInner, FromInner, IntoInner}; /// Raw file descriptors. #[stable(feature = "rust1", since = "1.0.0")] @@ -59,6 +59,18 @@ pub trait FromRawFd { unsafe fn from_raw_fd(fd: RawFd) -> Self; } +/// A trait to express the ability to consume an object and acquire ownership of +/// its raw file descriptor. +#[unstable(feature = "into_raw_os", reason = "recently added API")] +pub trait IntoRawFd { + /// Consumes this object, returning the raw underlying file descriptor. + /// + /// This function **transfers ownership** of the underlying file descriptor + /// to the caller. Callers are then the unique owners of the file descriptor + /// and must close the descriptor once it's no longer needed. + fn into_raw_fd(self) -> RawFd; +} + #[stable(feature = "rust1", since = "1.0.0")] impl AsRawFd for fs::File { fn as_raw_fd(&self) -> RawFd { @@ -71,6 +83,11 @@ impl FromRawFd for fs::File { fs::File::from_inner(sys::fs::File::from_inner(fd)) } } +impl IntoRawFd for fs::File { + fn into_raw_fd(self) -> RawFd { + self.into_inner().into_fd().into_raw() + } +} #[stable(feature = "rust1", since = "1.0.0")] impl AsRawFd for net::TcpStream { @@ -106,3 +123,19 @@ impl FromRawFd for net::UdpSocket { net::UdpSocket::from_inner(sys_common::net::UdpSocket::from_inner(socket)) } } + +impl IntoRawFd for net::TcpStream { + fn into_raw_fd(self) -> RawFd { + self.into_inner().into_socket().into_inner() + } +} +impl IntoRawFd for net::TcpListener { + fn into_raw_fd(self) -> RawFd { + self.into_inner().into_socket().into_inner() + } +} +impl IntoRawFd for net::UdpSocket { + fn into_raw_fd(self) -> RawFd { + self.into_inner().into_socket().into_inner() + } +} diff --git a/src/libstd/sys/unix/ext/mod.rs b/src/libstd/sys/unix/ext/mod.rs index 48c77480899..f7dee1a8f35 100644 --- a/src/libstd/sys/unix/ext/mod.rs +++ b/src/libstd/sys/unix/ext/mod.rs @@ -45,7 +45,7 @@ pub mod prelude { #[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")] pub use super::ffi::{OsStrExt, OsStringExt}; #[doc(no_inline)] - pub use super::fs::{PermissionsExt, OpenOptionsExt, MetadataExt}; + pub use super::fs::{PermissionsExt, OpenOptionsExt, MetadataExt, FileTypeExt}; #[doc(no_inline)] pub use super::fs::{DirEntryExt}; #[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")] diff --git a/src/libstd/sys/unix/ext/process.rs b/src/libstd/sys/unix/ext/process.rs index cfe7a1f2dda..63adae17581 100644 --- a/src/libstd/sys/unix/ext/process.rs +++ b/src/libstd/sys/unix/ext/process.rs @@ -13,11 +13,11 @@ #![stable(feature = "rust1", since = "1.0.0")] use os::unix::raw::{uid_t, gid_t}; -use os::unix::io::{FromRawFd, RawFd, AsRawFd}; +use os::unix::io::{FromRawFd, RawFd, AsRawFd, IntoRawFd}; use prelude::v1::*; use process; use sys; -use sys_common::{AsInnerMut, AsInner, FromInner}; +use sys_common::{AsInnerMut, AsInner, FromInner, IntoInner}; /// Unix-specific extensions to the `std::process::Command` builder #[stable(feature = "rust1", since = "1.0.0")] @@ -92,3 +92,21 @@ impl AsRawFd for process::ChildStderr { self.as_inner().fd().raw() } } + +impl IntoRawFd for process::ChildStdin { + fn into_raw_fd(self) -> RawFd { + self.into_inner().into_fd().into_raw() + } +} + +impl IntoRawFd for process::ChildStdout { + fn into_raw_fd(self) -> RawFd { + self.into_inner().into_fd().into_raw() + } +} + +impl IntoRawFd for process::ChildStderr { + fn into_raw_fd(self) -> RawFd { + self.into_inner().into_fd().into_raw() + } +} diff --git a/src/libstd/sys/unix/fs.rs b/src/libstd/sys/unix/fs.rs index 128284834ab..0c99a30f107 100644 --- a/src/libstd/sys/unix/fs.rs +++ b/src/libstd/sys/unix/fs.rs @@ -14,7 +14,7 @@ use os::unix::prelude::*; use ffi::{CString, CStr, OsString, OsStr}; use fmt; -use io::{self, Error, SeekFrom}; +use io::{self, Error, ErrorKind, SeekFrom}; use libc::{self, c_int, size_t, off_t, c_char, mode_t}; use mem; use path::{Path, PathBuf}; @@ -113,7 +113,7 @@ impl FileType { pub fn is_file(&self) -> bool { self.is(libc::S_IFREG) } pub fn is_symlink(&self) -> bool { self.is(libc::S_IFLNK) } - fn is(&self, mode: mode_t) -> bool { self.mode & libc::S_IFMT == mode } + pub fn is(&self, mode: mode_t) -> bool { self.mode & libc::S_IFMT == mode } } impl FromInner<raw::mode_t> for FilePermissions { @@ -331,6 +331,8 @@ impl File { } pub fn fd(&self) -> &FileDesc { &self.0 } + + pub fn into_fd(self) -> FileDesc { self.0 } } impl DirBuilder { @@ -370,13 +372,25 @@ impl fmt::Debug for File { readlink(&p).ok() } - #[cfg(not(target_os = "linux"))] + #[cfg(target_os = "macos")] + fn get_path(fd: c_int) -> Option<PathBuf> { + let mut buf = vec![0;libc::PATH_MAX as usize]; + let n = unsafe { libc::fcntl(fd, libc::F_GETPATH, buf.as_ptr()) }; + if n == -1 { + return None; + } + let l = buf.iter().position(|&c| c == 0).unwrap(); + buf.truncate(l as usize); + Some(PathBuf::from(OsString::from_vec(buf))) + } + + #[cfg(not(any(target_os = "linux", target_os = "macos")))] fn get_path(_fd: c_int) -> Option<PathBuf> { // FIXME(#24570): implement this for other Unix platforms None } - #[cfg(target_os = "linux")] + #[cfg(any(target_os = "linux", target_os = "macos"))] fn get_mode(fd: c_int) -> Option<(bool, bool)> { let mode = unsafe { libc::fcntl(fd, libc::F_GETFL) }; if mode == -1 { @@ -390,7 +404,7 @@ impl fmt::Debug for File { } } - #[cfg(not(target_os = "linux"))] + #[cfg(not(any(target_os = "linux", target_os = "macos")))] fn get_mode(_fd: c_int) -> Option<(bool, bool)> { // FIXME(#24570): implement this for other Unix platforms None @@ -516,3 +530,19 @@ pub fn canonicalize(p: &Path) -> io::Result<PathBuf> { buf.truncate(p); Ok(PathBuf::from(OsString::from_vec(buf))) } + +pub fn copy(from: &Path, to: &Path) -> io::Result<u64> { + use fs::{File, PathExt, set_permissions}; + if !from.is_file() { + return Err(Error::new(ErrorKind::InvalidInput, + "the source path is not an existing file")) + } + + let mut reader = try!(File::open(from)); + let mut writer = try!(File::create(to)); + let perm = try!(reader.metadata()).permissions(); + + let ret = try!(io::copy(&mut reader, &mut writer)); + try!(set_permissions(to, perm)); + Ok(ret) +} diff --git a/src/libstd/sys/unix/mod.rs b/src/libstd/sys/unix/mod.rs index c1a4e8cee9e..6fd20b940bb 100644 --- a/src/libstd/sys/unix/mod.rs +++ b/src/libstd/sys/unix/mod.rs @@ -26,6 +26,7 @@ use ops::Neg; #[cfg(target_os = "linux")] pub use os::linux as platform; #[cfg(target_os = "macos")] pub use os::macos as platform; #[cfg(target_os = "nacl")] pub use os::nacl as platform; +#[cfg(target_os = "netbsd")] pub use os::netbsd as platform; #[cfg(target_os = "openbsd")] pub use os::openbsd as platform; pub mod backtrace; diff --git a/src/libstd/sys/unix/net.rs b/src/libstd/sys/unix/net.rs index 1f40c18be2f..37eb7fd2ac8 100644 --- a/src/libstd/sys/unix/net.rs +++ b/src/libstd/sys/unix/net.rs @@ -17,7 +17,7 @@ use str; use sys::c; use net::SocketAddr; use sys::fd::FileDesc; -use sys_common::{AsInner, FromInner}; +use sys_common::{AsInner, FromInner, IntoInner}; use sys_common::net::{getsockopt, setsockopt}; use time::Duration; @@ -127,3 +127,7 @@ impl AsInner<c_int> for Socket { impl FromInner<c_int> for Socket { fn from_inner(fd: c_int) -> Socket { Socket(FileDesc::new(fd)) } } + +impl IntoInner<c_int> for Socket { + fn into_inner(self) -> c_int { self.0.into_raw() } +} diff --git a/src/libstd/sys/unix/os.rs b/src/libstd/sys/unix/os.rs index 5178d7b8fb1..2b6b50a1a56 100644 --- a/src/libstd/sys/unix/os.rs +++ b/src/libstd/sys/unix/os.rs @@ -22,25 +22,17 @@ use io; use iter; use libc::{self, c_int, c_char, c_void}; use mem; -use ptr; use path::{self, PathBuf}; +use ptr; use slice; use str; use sys::c; use sys::fd; use vec; -const BUF_BYTES: usize = 2048; +const GETCWD_BUF_BYTES: usize = 2048; const TMPBUF_SZ: usize = 128; -fn bytes2path(b: &[u8]) -> PathBuf { - PathBuf::from(<OsStr as OsStrExt>::from_bytes(b)) -} - -fn os2path(os: OsString) -> PathBuf { - bytes2path(os.as_bytes()) -} - /// Returns the platform-specific value of errno pub fn errno() -> i32 { #[cfg(any(target_os = "macos", @@ -51,23 +43,13 @@ pub fn errno() -> i32 { __error() } - #[cfg(target_os = "bitrig")] - fn errno_location() -> *const c_int { - extern { - fn __errno() -> *const c_int; - } - unsafe { - __errno() - } - } - #[cfg(target_os = "dragonfly")] unsafe fn errno_location() -> *const c_int { extern { fn __dfly_error() -> *const c_int; } __dfly_error() } - #[cfg(target_os = "openbsd")] + #[cfg(any(target_os = "bitrig", target_os = "netbsd", target_os = "openbsd"))] unsafe fn errno_location() -> *const c_int { extern { fn __errno() -> *const c_int; } __errno() @@ -112,12 +94,24 @@ pub fn error_string(errno: i32) -> String { } pub fn getcwd() -> io::Result<PathBuf> { - let mut buf = [0 as c_char; BUF_BYTES]; - unsafe { - if libc::getcwd(buf.as_mut_ptr(), buf.len() as libc::size_t).is_null() { - Err(io::Error::last_os_error()) - } else { - Ok(bytes2path(CStr::from_ptr(buf.as_ptr()).to_bytes())) + let mut buf = Vec::new(); + let mut n = GETCWD_BUF_BYTES; + loop { + unsafe { + buf.reserve(n); + let ptr = buf.as_mut_ptr() as *mut libc::c_char; + if !libc::getcwd(ptr, buf.capacity() as libc::size_t).is_null() { + let len = CStr::from_ptr(buf.as_ptr() as *const libc::c_char).to_bytes().len(); + buf.set_len(len); + buf.shrink_to_fit(); + return Ok(PathBuf::from(OsString::from_vec(buf))); + } else { + let error = io::Error::last_os_error(); + if error.raw_os_error() != Some(libc::ERANGE) { + return Err(error); + } + } + n *= 2; } } } @@ -139,11 +133,14 @@ pub struct SplitPaths<'a> { } pub fn split_paths<'a>(unparsed: &'a OsStr) -> SplitPaths<'a> { + fn bytes_to_path(b: &[u8]) -> PathBuf { + PathBuf::from(<OsStr as OsStrExt>::from_bytes(b)) + } fn is_colon(b: &u8) -> bool { *b == b':' } let unparsed = unparsed.as_bytes(); SplitPaths { iter: unparsed.split(is_colon as fn(&u8) -> bool) - .map(bytes2path as fn(&'a [u8]) -> PathBuf) + .map(bytes_to_path as fn(&'a [u8]) -> PathBuf) } } @@ -214,7 +211,7 @@ pub fn current_exe() -> io::Result<PathBuf> { ::fs::read_link("/proc/curproc/file") } -#[cfg(any(target_os = "bitrig", target_os = "openbsd"))] +#[cfg(any(target_os = "bitrig", target_os = "netbsd", target_os = "openbsd"))] pub fn current_exe() -> io::Result<PathBuf> { use sync::StaticMutex; static LOCK: StaticMutex = StaticMutex::new(); @@ -356,6 +353,7 @@ pub fn args() -> Args { target_os = "freebsd", target_os = "dragonfly", target_os = "bitrig", + target_os = "netbsd", target_os = "openbsd"))] pub fn args() -> Args { use rt; @@ -453,7 +451,7 @@ pub fn page_size() -> usize { } pub fn temp_dir() -> PathBuf { - getenv("TMPDIR".as_ref()).map(os2path).unwrap_or_else(|| { + getenv("TMPDIR".as_ref()).map(PathBuf::from).unwrap_or_else(|| { if cfg!(target_os = "android") { PathBuf::from("/data/local/tmp") } else { @@ -465,7 +463,7 @@ pub fn temp_dir() -> PathBuf { pub fn home_dir() -> Option<PathBuf> { return getenv("HOME".as_ref()).or_else(|| unsafe { fallback() - }).map(os2path); + }).map(PathBuf::from); #[cfg(any(target_os = "android", target_os = "ios"))] diff --git a/src/libstd/sys/unix/pipe.rs b/src/libstd/sys/unix/pipe.rs index 946857c05bc..140f0c042ba 100644 --- a/src/libstd/sys/unix/pipe.rs +++ b/src/libstd/sys/unix/pipe.rs @@ -46,4 +46,5 @@ impl AnonPipe { pub fn raw(&self) -> libc::c_int { self.0.raw() } pub fn fd(&self) -> &FileDesc { &self.0 } + pub fn into_fd(self) -> FileDesc { self.0 } } diff --git a/src/libstd/sys/unix/process.rs b/src/libstd/sys/unix/process.rs index 695d0ddfaaf..cc78dd4e5ef 100644 --- a/src/libstd/sys/unix/process.rs +++ b/src/libstd/sys/unix/process.rs @@ -423,6 +423,7 @@ fn translate_status(status: c_int) -> ExitStatus { target_os = "freebsd", target_os = "dragonfly", target_os = "bitrig", + target_os = "netbsd", target_os = "openbsd"))] mod imp { pub fn WIFEXITED(status: i32) -> bool { (status & 0x7f) == 0 } diff --git a/src/libstd/sys/unix/stack_overflow.rs b/src/libstd/sys/unix/stack_overflow.rs index 52494a17b9d..62689c39255 100644 --- a/src/libstd/sys/unix/stack_overflow.rs +++ b/src/libstd/sys/unix/stack_overflow.rs @@ -35,6 +35,7 @@ impl Drop for Handler { #[cfg(any(target_os = "linux", target_os = "macos", target_os = "bitrig", + target_os = "netbsd", target_os = "openbsd"))] mod imp { use sys_common::stack; @@ -149,6 +150,7 @@ mod imp { #[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "bitrig", + target_os = "netbsd", target_os = "openbsd")))] mod imp { use libc; diff --git a/src/libstd/sys/unix/sync.rs b/src/libstd/sys/unix/sync.rs index 41e1e206a42..9c8a1f4ca40 100644 --- a/src/libstd/sys/unix/sync.rs +++ b/src/libstd/sys/unix/sync.rs @@ -55,6 +55,7 @@ extern { #[cfg(any(target_os = "freebsd", target_os = "dragonfly", target_os = "bitrig", + target_os = "netbsd", target_os = "openbsd"))] mod os { use libc; diff --git a/src/libstd/sys/unix/thread.rs b/src/libstd/sys/unix/thread.rs index bb0e12e8df8..6be61f06926 100644 --- a/src/libstd/sys/unix/thread.rs +++ b/src/libstd/sys/unix/thread.rs @@ -105,6 +105,7 @@ impl Thread { #[cfg(any(target_os = "freebsd", target_os = "dragonfly", target_os = "bitrig", + target_os = "netbsd", target_os = "openbsd"))] pub fn set_name(name: &str) { extern { @@ -162,20 +163,25 @@ impl Drop for Thread { #[cfg(all(not(target_os = "linux"), not(target_os = "macos"), not(target_os = "bitrig"), + not(target_os = "netbsd"), not(target_os = "openbsd")))] pub mod guard { - pub unsafe fn current() -> usize { 0 } - pub unsafe fn main() -> usize { 0 } - pub unsafe fn init() {} + use prelude::v1::*; + + pub unsafe fn current() -> Option<usize> { None } + pub unsafe fn init() -> Option<usize> { None } } #[cfg(any(target_os = "linux", target_os = "macos", target_os = "bitrig", + target_os = "netbsd", target_os = "openbsd"))] #[allow(unused_imports)] pub mod guard { + use prelude::v1::*; + use libc::{self, pthread_t}; use libc::funcs::posix88::mman::mmap; use libc::consts::os::posix88::{PROT_NONE, @@ -188,30 +194,38 @@ pub mod guard { use super::{pthread_self, pthread_attr_destroy}; use sys::os; - // These are initialized in init() and only read from after - static mut GUARD_PAGE: usize = 0; - #[cfg(any(target_os = "macos", target_os = "bitrig", + target_os = "netbsd", target_os = "openbsd"))] - unsafe fn get_stack_start() -> *mut libc::c_void { - current() as *mut libc::c_void + unsafe fn get_stack_start() -> Option<*mut libc::c_void> { + current().map(|s| s as *mut libc::c_void) } #[cfg(any(target_os = "linux", target_os = "android"))] - unsafe fn get_stack_start() -> *mut libc::c_void { + unsafe fn get_stack_start() -> Option<*mut libc::c_void> { + use super::pthread_attr_init; + + let mut ret = None; let mut attr: libc::pthread_attr_t = mem::zeroed(); - assert_eq!(pthread_getattr_np(pthread_self(), &mut attr), 0); - let mut stackaddr = ptr::null_mut(); - let mut stacksize = 0; - assert_eq!(pthread_attr_getstack(&attr, &mut stackaddr, &mut stacksize), 0); + assert_eq!(pthread_attr_init(&mut attr), 0); + if pthread_getattr_np(pthread_self(), &mut attr) == 0 { + let mut stackaddr = ptr::null_mut(); + let mut stacksize = 0; + assert_eq!(pthread_attr_getstack(&attr, &mut stackaddr, + &mut stacksize), 0); + ret = Some(stackaddr); + } assert_eq!(pthread_attr_destroy(&mut attr), 0); - stackaddr + ret } - pub unsafe fn init() { + pub unsafe fn init() -> Option<usize> { let psize = os::page_size(); - let mut stackaddr = get_stack_start(); + let mut stackaddr = match get_stack_start() { + Some(addr) => addr, + None => return None, + }; // Ensure stackaddr is page aligned! A parent process might // have reset RLIMIT_STACK to be non-page aligned. The @@ -241,25 +255,21 @@ pub mod guard { let offset = if cfg!(target_os = "linux") {2} else {1}; - GUARD_PAGE = stackaddr as usize + offset * psize; - } - - pub unsafe fn main() -> usize { - GUARD_PAGE + Some(stackaddr as usize + offset * psize) } #[cfg(target_os = "macos")] - pub unsafe fn current() -> usize { + pub unsafe fn current() -> Option<usize> { extern { fn pthread_get_stackaddr_np(thread: pthread_t) -> *mut libc::c_void; fn pthread_get_stacksize_np(thread: pthread_t) -> libc::size_t; } - (pthread_get_stackaddr_np(pthread_self()) as libc::size_t - - pthread_get_stacksize_np(pthread_self())) as usize + Some((pthread_get_stackaddr_np(pthread_self()) as libc::size_t - + pthread_get_stacksize_np(pthread_self())) as usize) } - #[cfg(any(target_os = "openbsd", target_os = "bitrig"))] - pub unsafe fn current() -> usize { + #[cfg(any(target_os = "openbsd", target_os = "netbsd", target_os = "bitrig"))] + pub unsafe fn current() -> Option<usize> { #[repr(C)] struct stack_t { ss_sp: *mut libc::c_void, @@ -276,30 +286,36 @@ pub mod guard { assert_eq!(pthread_stackseg_np(pthread_self(), &mut current_stack), 0); let extra = if cfg!(target_os = "bitrig") {3} else {1} * os::page_size(); - if pthread_main_np() == 1 { + Some(if pthread_main_np() == 1 { // main thread current_stack.ss_sp as usize - current_stack.ss_size as usize + extra } else { // new thread current_stack.ss_sp as usize - current_stack.ss_size as usize - } + }) } #[cfg(any(target_os = "linux", target_os = "android"))] - pub unsafe fn current() -> usize { + pub unsafe fn current() -> Option<usize> { + use super::pthread_attr_init; + + let mut ret = None; let mut attr: libc::pthread_attr_t = mem::zeroed(); - assert_eq!(pthread_getattr_np(pthread_self(), &mut attr), 0); - let mut guardsize = 0; - assert_eq!(pthread_attr_getguardsize(&attr, &mut guardsize), 0); - if guardsize == 0 { - panic!("there is no guard page"); + assert_eq!(pthread_attr_init(&mut attr), 0); + if pthread_getattr_np(pthread_self(), &mut attr) == 0 { + let mut guardsize = 0; + assert_eq!(pthread_attr_getguardsize(&attr, &mut guardsize), 0); + if guardsize == 0 { + panic!("there is no guard page"); + } + let mut stackaddr = ptr::null_mut(); + let mut size = 0; + assert_eq!(pthread_attr_getstack(&attr, &mut stackaddr, &mut size), 0); + + ret = Some(stackaddr as usize + guardsize as usize); } - let mut stackaddr = ptr::null_mut(); - let mut size = 0; - assert_eq!(pthread_attr_getstack(&attr, &mut stackaddr, &mut size), 0); assert_eq!(pthread_attr_destroy(&mut attr), 0); - - stackaddr as usize + guardsize as usize + return ret } #[cfg(any(target_os = "linux", target_os = "android"))] diff --git a/src/libstd/sys/unix/thread_local.rs b/src/libstd/sys/unix/thread_local.rs index 3afe84b2580..7238adfcc56 100644 --- a/src/libstd/sys/unix/thread_local.rs +++ b/src/libstd/sys/unix/thread_local.rs @@ -46,6 +46,7 @@ type pthread_key_t = ::libc::c_ulong; #[cfg(any(target_os = "freebsd", target_os = "dragonfly", target_os = "bitrig", + target_os = "netbsd", target_os = "openbsd"))] type pthread_key_t = ::libc::c_int; @@ -54,6 +55,7 @@ type pthread_key_t = ::libc::c_int; target_os = "freebsd", target_os = "dragonfly", target_os = "bitrig", + target_os = "netbsd", target_os = "openbsd")))] type pthread_key_t = ::libc::c_uint; diff --git a/src/libstd/sys/unix/time.rs b/src/libstd/sys/unix/time.rs index 6b84baeca7d..db0d0f15061 100644 --- a/src/libstd/sys/unix/time.rs +++ b/src/libstd/sys/unix/time.rs @@ -80,6 +80,7 @@ mod inner { // OpenBSD provide it via libc #[cfg(not(any(target_os = "android", target_os = "bitrig", + target_os = "netbsd", target_os = "openbsd", target_env = "musl")))] #[link(name = "rt")] diff --git a/src/libstd/sys/windows/c.rs b/src/libstd/sys/windows/c.rs index 3c9b2ef1b98..06c14b39e12 100644 --- a/src/libstd/sys/windows/c.rs +++ b/src/libstd/sys/windows/c.rs @@ -13,6 +13,9 @@ #![allow(bad_style, dead_code, overflowing_literals)] use libc; +use libc::{c_uint, c_ulong}; +use libc::{DWORD, BOOL, BOOLEAN, ERROR_CALL_NOT_IMPLEMENTED, LPVOID, HANDLE}; +use libc::{LPCWSTR, LONG}; pub use self::GET_FILEEX_INFO_LEVELS::*; pub use self::FILE_INFO_BY_HANDLE_CLASS::*; @@ -50,9 +53,13 @@ pub const WSA_FLAG_NO_HANDLE_INHERIT: libc::DWORD = 0x80; pub const ERROR_NO_MORE_FILES: libc::DWORD = 18; pub const TOKEN_READ: libc::DWORD = 0x20008; pub const FILE_FLAG_OPEN_REPARSE_POINT: libc::DWORD = 0x00200000; +pub const FILE_FLAG_BACKUP_SEMANTICS: libc::DWORD = 0x02000000; pub const MAXIMUM_REPARSE_DATA_BUFFER_SIZE: usize = 16 * 1024; pub const FSCTL_GET_REPARSE_POINT: libc::DWORD = 0x900a8; pub const IO_REPARSE_TAG_SYMLINK: libc::DWORD = 0xa000000c; +pub const IO_REPARSE_TAG_MOUNT_POINT: libc::DWORD = 0xa0000003; +pub const FSCTL_SET_REPARSE_POINT: libc::DWORD = 0x900a4; +pub const FSCTL_DELETE_REPARSE_POINT: libc::DWORD = 0x900ac; pub const SYMBOLIC_LINK_FLAG_DIRECTORY: libc::DWORD = 0x1; @@ -61,6 +68,16 @@ pub const STD_INPUT_HANDLE: libc::DWORD = -10i32 as libc::DWORD; pub const STD_OUTPUT_HANDLE: libc::DWORD = -11i32 as libc::DWORD; pub const STD_ERROR_HANDLE: libc::DWORD = -12i32 as libc::DWORD; +pub const HANDLE_FLAG_INHERIT: libc::DWORD = 0x00000001; + +pub const PROGRESS_CONTINUE: libc::DWORD = 0; +pub const PROGRESS_CANCEL: libc::DWORD = 1; +pub const PROGRESS_STOP: libc::DWORD = 2; +pub const PROGRESS_QUIET: libc::DWORD = 3; + +pub const TOKEN_ADJUST_PRIVILEGES: libc::DWORD = 0x0020; +pub const SE_PRIVILEGE_ENABLED: libc::DWORD = 2; + #[repr(C)] #[cfg(target_arch = "x86")] pub struct WSADATA { @@ -240,7 +257,79 @@ pub struct SYMBOLIC_LINK_REPARSE_BUFFER { pub PathBuffer: libc::WCHAR, } +pub type PCONDITION_VARIABLE = *mut CONDITION_VARIABLE; +pub type PSRWLOCK = *mut SRWLOCK; +pub type ULONG = c_ulong; +pub type ULONG_PTR = c_ulong; +pub type LPBOOL = *mut BOOL; + +pub type LPPROGRESS_ROUTINE = ::option::Option<unsafe extern "system" fn( + TotalFileSize: libc::LARGE_INTEGER, + TotalBytesTransferred: libc::LARGE_INTEGER, + StreamSize: libc::LARGE_INTEGER, + StreamBytesTransferred: libc::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 +} + +pub const CONDITION_VARIABLE_INIT: CONDITION_VARIABLE = CONDITION_VARIABLE { + ptr: 0 as *mut _, +}; +pub const SRWLOCK_INIT: SRWLOCK = SRWLOCK { ptr: 0 as *mut _ }; + +#[repr(C)] +pub struct LUID { + pub LowPart: libc::DWORD, + pub HighPart: libc::c_long, +} + +pub type PLUID = *mut LUID; + +#[repr(C)] +pub struct TOKEN_PRIVILEGES { + pub PrivilegeCount: libc::DWORD, + pub Privileges: [LUID_AND_ATTRIBUTES; 1], +} + +pub type PTOKEN_PRIVILEGES = *mut TOKEN_PRIVILEGES; + +#[repr(C)] +pub struct LUID_AND_ATTRIBUTES { + pub Luid: LUID, + pub Attributes: libc::DWORD, +} + +#[repr(C)] +pub struct REPARSE_MOUNTPOINT_DATA_BUFFER { + pub ReparseTag: libc::DWORD, + pub ReparseDataLength: libc::DWORD, + pub Reserved: libc::WORD, + pub ReparseTargetLength: libc::WORD, + pub ReparseTargetMaximumLength: libc::WORD, + pub Reserved1: libc::WORD, + pub ReparseTarget: libc::WCHAR, +} + + #[link(name = "ws2_32")] +#[link(name = "userenv")] extern "system" { pub fn WSAStartup(wVersionRequested: libc::WORD, lpWSAData: LPWSADATA) -> libc::c_int; @@ -295,115 +384,13 @@ extern "system" { pub fn CancelIo(hFile: libc::HANDLE) -> libc::BOOL; pub fn CancelIoEx(hFile: libc::HANDLE, lpOverlapped: libc::LPOVERLAPPED) -> libc::BOOL; -} - -pub mod compat { - use prelude::v1::*; - - use ffi::CString; - use libc::types::os::arch::extra::{LPCWSTR, HMODULE, LPCSTR, LPVOID}; - use sync::atomic::{AtomicUsize, Ordering}; - extern "system" { - fn GetModuleHandleW(lpModuleName: LPCWSTR) -> HMODULE; - fn GetProcAddress(hModule: HMODULE, lpProcName: LPCSTR) -> LPVOID; - } - - fn store_func(ptr: &AtomicUsize, module: &str, symbol: &str, - fallback: usize) -> usize { - let mut module: Vec<u16> = module.utf16_units().collect(); - module.push(0); - let symbol = CString::new(symbol).unwrap(); - let func = unsafe { - let handle = GetModuleHandleW(module.as_ptr()); - GetProcAddress(handle, symbol.as_ptr()) as usize - }; - let value = if func == 0 {fallback} else {func}; - ptr.store(value, Ordering::SeqCst); - value - } - - /// Macro for creating a compatibility fallback for a Windows function - /// - /// # Examples - /// ``` - /// compat_fn!(adll32::SomeFunctionW(_arg: LPCWSTR) { - /// // Fallback implementation - /// }) - /// ``` - /// - /// Note that arguments unused by the fallback implementation should not be - /// called `_` as they are used to be passed to the real function if - /// available. - macro_rules! compat_fn { - ($module:ident::$symbol:ident($($argname:ident: $argtype:ty),*) - -> $rettype:ty { $fallback:expr }) => ( - #[inline(always)] - pub unsafe fn $symbol($($argname: $argtype),*) -> $rettype { - use sync::atomic::{AtomicUsize, Ordering}; - use mem; - - static PTR: AtomicUsize = AtomicUsize::new(0); - - fn load() -> usize { - ::sys::c::compat::store_func(&PTR, - stringify!($module), - stringify!($symbol), - fallback as usize) - } - - extern "system" fn fallback($($argname: $argtype),*) - -> $rettype { $fallback } - - let addr = match PTR.load(Ordering::SeqCst) { - 0 => load(), - n => n, - }; - let f: extern "system" fn($($argtype),*) -> $rettype = - mem::transmute(addr); - f($($argname),*) - } - ) - } - - /// Compatibility layer for functions in `kernel32.dll` - /// - /// Latest versions of Windows this is needed for: - /// - /// * `CreateSymbolicLinkW`: Windows XP, Windows Server 2003 - /// * `GetFinalPathNameByHandleW`: Windows XP, Windows Server 2003 - pub mod kernel32 { - use libc::c_uint; - use libc::types::os::arch::extra::{DWORD, LPCWSTR, BOOLEAN, HANDLE}; - use libc::consts::os::extra::ERROR_CALL_NOT_IMPLEMENTED; - use sys::c::SetLastError; - - compat_fn! { - kernel32::CreateSymbolicLinkW(_lpSymlinkFileName: LPCWSTR, - _lpTargetFileName: LPCWSTR, - _dwFlags: DWORD) -> BOOLEAN { - unsafe { SetLastError(ERROR_CALL_NOT_IMPLEMENTED as DWORD); 0 } - } - } - - compat_fn! { - kernel32::GetFinalPathNameByHandleW(_hFile: HANDLE, - _lpszFilePath: LPCWSTR, - _cchFilePath: DWORD, - _dwFlags: DWORD) -> DWORD { - unsafe { SetLastError(ERROR_CALL_NOT_IMPLEMENTED as DWORD); 0 } - } - } - - compat_fn! { - kernel32::SetThreadErrorMode(_dwNewMode: DWORD, _lpOldMode: *mut DWORD) -> c_uint { - unsafe { SetLastError(ERROR_CALL_NOT_IMPLEMENTED as DWORD); 0 } - } - } - } -} + 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); -extern "system" { // FIXME - pInputControl should be PCONSOLE_READCONSOLE_CONTROL pub fn ReadConsoleW(hConsoleInput: libc::HANDLE, lpBuffer: libc::LPVOID, @@ -447,10 +434,6 @@ extern "system" { lpCreationTime: *const libc::FILETIME, lpLastAccessTime: *const libc::FILETIME, lpLastWriteTime: *const libc::FILETIME) -> libc::BOOL; - pub fn SetFileInformationByHandle(hFile: libc::HANDLE, - FileInformationClass: FILE_INFO_BY_HANDLE_CLASS, - lpFileInformation: libc::LPVOID, - dwBufferSize: libc::DWORD) -> libc::BOOL; pub fn GetTempPathW(nBufferLength: libc::DWORD, lpBuffer: libc::LPCWSTR) -> libc::DWORD; pub fn OpenProcessToken(ProcessHandle: libc::HANDLE, @@ -483,11 +466,88 @@ extern "system" { pub fn SwitchToThread() -> libc::BOOL; pub fn Sleep(dwMilliseconds: libc::DWORD); pub fn GetProcessId(handle: libc::HANDLE) -> libc::DWORD; -} - -#[link(name = "userenv")] -extern "system" { pub fn GetUserProfileDirectoryW(hToken: libc::HANDLE, lpProfileDir: libc::LPCWSTR, lpcchSize: *mut libc::DWORD) -> libc::BOOL; + pub fn SetHandleInformation(hObject: libc::HANDLE, + dwMask: libc::DWORD, + dwFlags: libc::DWORD) -> libc::BOOL; + pub fn CopyFileExW(lpExistingFileName: libc::LPCWSTR, + lpNewFileName: libc::LPCWSTR, + lpProgressRoutine: LPPROGRESS_ROUTINE, + lpData: libc::LPVOID, + pbCancel: LPBOOL, + dwCopyFlags: libc::DWORD) -> libc::BOOL; + pub fn LookupPrivilegeValueW(lpSystemName: libc::LPCWSTR, + lpName: libc::LPCWSTR, + lpLuid: PLUID) -> libc::BOOL; + pub fn AdjustTokenPrivileges(TokenHandle: libc::HANDLE, + DisableAllPrivileges: libc::BOOL, + NewState: PTOKEN_PRIVILEGES, + BufferLength: libc::DWORD, + PreviousState: PTOKEN_PRIVILEGES, + ReturnLength: *mut libc::DWORD) -> libc::BOOL; +} + +// Functions that aren't available on Windows XP, 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 SetThreadErrorMode(_dwNewMode: DWORD, + _lpOldMode: *mut DWORD) -> c_uint { + 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 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") + } } diff --git a/src/libstd/sys/windows/compat.rs b/src/libstd/sys/windows/compat.rs new file mode 100644 index 00000000000..3a03b91f24e --- /dev/null +++ b/src/libstd/sys/windows/compat.rs @@ -0,0 +1,88 @@ +// 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 prelude::v1::*; + +use ffi::CString; +use libc::{LPVOID, LPCWSTR, HMODULE, LPCSTR}; +use sync::atomic::{AtomicUsize, Ordering}; + +extern "system" { + fn GetModuleHandleW(lpModuleName: LPCWSTR) -> HMODULE; + fn GetProcAddress(hModule: HMODULE, lpProcName: LPCSTR) -> LPVOID; +} + +pub fn lookup(module: &str, symbol: &str) -> Option<usize> { + let mut module: Vec<u16> = module.utf16_units().collect(); + module.push(0); + let symbol = CString::new(symbol).unwrap(); + unsafe { + let handle = GetModuleHandleW(module.as_ptr()); + match 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/src/libstd/sys/windows/condvar.rs b/src/libstd/sys/windows/condvar.rs index baa7d1ceea3..04d62200e9b 100644 --- a/src/libstd/sys/windows/condvar.rs +++ b/src/libstd/sys/windows/condvar.rs @@ -12,35 +12,35 @@ use prelude::v1::*; use cell::UnsafeCell; use libc::{self, DWORD}; -use sys::os; +use sys::c; use sys::mutex::{self, Mutex}; -use sys::sync as ffi; +use sys::os; use time::Duration; -pub struct Condvar { inner: UnsafeCell<ffi::CONDITION_VARIABLE> } +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(ffi::CONDITION_VARIABLE_INIT) } + Condvar { inner: UnsafeCell::new(c::CONDITION_VARIABLE_INIT) } } #[inline] pub unsafe fn wait(&self, mutex: &Mutex) { - let r = ffi::SleepConditionVariableSRW(self.inner.get(), - mutex::raw(mutex), - libc::INFINITE, - 0); + let r = c::SleepConditionVariableSRW(self.inner.get(), + mutex::raw(mutex), + libc::INFINITE, + 0); debug_assert!(r != 0); } pub unsafe fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool { - let r = ffi::SleepConditionVariableSRW(self.inner.get(), - mutex::raw(mutex), - super::dur2timeout(dur), - 0); + let r = c::SleepConditionVariableSRW(self.inner.get(), + mutex::raw(mutex), + super::dur2timeout(dur), + 0); if r == 0 { const ERROR_TIMEOUT: DWORD = 0x5B4; debug_assert_eq!(os::errno() as usize, ERROR_TIMEOUT as usize); @@ -52,12 +52,12 @@ impl Condvar { #[inline] pub unsafe fn notify_one(&self) { - ffi::WakeConditionVariable(self.inner.get()) + c::WakeConditionVariable(self.inner.get()) } #[inline] pub unsafe fn notify_all(&self) { - ffi::WakeAllConditionVariable(self.inner.get()) + c::WakeAllConditionVariable(self.inner.get()) } pub unsafe fn destroy(&self) { diff --git a/src/libstd/sys/windows/ext/io.rs b/src/libstd/sys/windows/ext/io.rs index f4717eb2425..185f1abe64b 100644 --- a/src/libstd/sys/windows/ext/io.rs +++ b/src/libstd/sys/windows/ext/io.rs @@ -13,7 +13,7 @@ use fs; use os::windows::raw; use net; -use sys_common::{self, AsInner, FromInner}; +use sys_common::{self, AsInner, FromInner, IntoInner}; use sys; /// Raw HANDLEs. @@ -50,6 +50,18 @@ pub trait FromRawHandle { 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`. +#[unstable(feature = "into_raw_os", reason = "recently added API")] +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. + fn into_raw_handle(self) -> RawHandle; +} + #[stable(feature = "rust1", since = "1.0.0")] impl AsRawHandle for fs::File { fn as_raw_handle(&self) -> RawHandle { @@ -65,6 +77,12 @@ impl FromRawHandle for fs::File { } } +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 { @@ -90,6 +108,18 @@ pub trait FromRawSocket { 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`. +#[unstable(feature = "into_raw_os", reason = "recently added API")] +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. + fn into_raw_socket(self) -> RawSocket; +} + #[stable(feature = "rust1", since = "1.0.0")] impl AsRawSocket for net::TcpStream { fn as_raw_socket(&self) -> RawSocket { @@ -130,3 +160,21 @@ impl FromRawSocket for net::UdpSocket { net::UdpSocket::from_inner(sys_common::net::UdpSocket::from_inner(sock)) } } + +impl IntoRawSocket for net::TcpStream { + fn into_raw_socket(self) -> RawSocket { + self.into_inner().into_socket().into_inner() + } +} + +impl IntoRawSocket for net::TcpListener { + fn into_raw_socket(self) -> RawSocket { + self.into_inner().into_socket().into_inner() + } +} + +impl IntoRawSocket for net::UdpSocket { + fn into_raw_socket(self) -> RawSocket { + self.into_inner().into_socket().into_inner() + } +} diff --git a/src/libstd/sys/windows/ext/process.rs b/src/libstd/sys/windows/ext/process.rs index 6f59be2687a..fde21e9a798 100644 --- a/src/libstd/sys/windows/ext/process.rs +++ b/src/libstd/sys/windows/ext/process.rs @@ -12,10 +12,10 @@ #![stable(feature = "process_extensions", since = "1.2.0")] -use os::windows::io::{FromRawHandle, RawHandle, AsRawHandle}; +use os::windows::io::{FromRawHandle, RawHandle, AsRawHandle, IntoRawHandle}; use process; use sys; -use sys_common::{AsInner, FromInner}; +use sys_common::{AsInner, FromInner, IntoInner}; #[stable(feature = "process_extensions", since = "1.2.0")] impl FromRawHandle for process::Stdio { @@ -32,6 +32,12 @@ impl AsRawHandle for process::Child { } } +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 { @@ -52,3 +58,21 @@ impl AsRawHandle for process::ChildStderr { self.as_inner().handle().raw() as *mut _ } } + +impl IntoRawHandle for process::ChildStdin { + fn into_raw_handle(self) -> RawHandle { + self.into_inner().into_handle().into_raw() as *mut _ + } +} + +impl IntoRawHandle for process::ChildStdout { + fn into_raw_handle(self) -> RawHandle { + self.into_inner().into_handle().into_raw() as *mut _ + } +} + +impl IntoRawHandle for process::ChildStderr { + fn into_raw_handle(self) -> RawHandle { + self.into_inner().into_handle().into_raw() as *mut _ + } +} diff --git a/src/libstd/sys/windows/ext/raw.rs b/src/libstd/sys/windows/ext/raw.rs index e1796d4b5f0..92d53e2e428 100644 --- a/src/libstd/sys/windows/ext/raw.rs +++ b/src/libstd/sys/windows/ext/raw.rs @@ -10,7 +10,7 @@ //! Windows-specific primitives -#[stable(feature = "raw_ext", since = "1.1.0")] +#![stable(feature = "raw_ext", since = "1.1.0")] use os::raw::c_void; diff --git a/src/libstd/sys/windows/fs.rs b/src/libstd/sys/windows/fs.rs index 437b2cc6491..4ce6d53cf12 100644 --- a/src/libstd/sys/windows/fs.rs +++ b/src/libstd/sys/windows/fs.rs @@ -30,12 +30,12 @@ pub struct File { handle: Handle } pub struct FileAttr { data: c::WIN32_FILE_ATTRIBUTE_DATA, - is_symlink: bool, + reparse_tag: libc::DWORD, } #[derive(Copy, Clone, PartialEq, Eq, Hash)] pub enum FileType { - Dir, File, Symlink, ReparsePoint + Dir, File, Symlink, ReparsePoint, MountPoint, } pub struct ReadDir { @@ -133,7 +133,7 @@ impl DirEntry { pub fn file_type(&self) -> io::Result<FileType> { Ok(FileType::new(self.data.dwFileAttributes, - self.data.dwReserved0 == c::IO_REPARSE_TAG_SYMLINK)) + /* reparse_tag = */ self.data.dwReserved0)) } pub fn metadata(&self) -> io::Result<FileAttr> { @@ -146,7 +146,7 @@ impl DirEntry { nFileSizeHigh: self.data.nFileSizeHigh, nFileSizeLow: self.data.nFileSizeLow, }, - is_symlink: self.data.dwReserved0 == c::IO_REPARSE_TAG_SYMLINK, + reparse_tag: self.data.dwReserved0, }) } } @@ -218,10 +218,12 @@ impl OpenOptions { } impl File { - fn open_reparse_point(path: &Path) -> io::Result<File> { + fn open_reparse_point(path: &Path, write: bool) -> io::Result<File> { let mut opts = OpenOptions::new(); - opts.read(true); - opts.flags_and_attributes(c::FILE_FLAG_OPEN_REPARSE_POINT); + opts.read(!write); + opts.write(write); + opts.flags_and_attributes(c::FILE_FLAG_OPEN_REPARSE_POINT | + c::FILE_FLAG_BACKUP_SEMANTICS); File::open(path, &opts) } @@ -278,10 +280,13 @@ impl File { nFileSizeHigh: info.nFileSizeHigh, nFileSizeLow: info.nFileSizeLow, }, - is_symlink: false, + reparse_tag: 0, }; if attr.is_reparse_point() { - attr.is_symlink = self.is_symlink(); + 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) } @@ -314,15 +319,13 @@ impl File { pub fn handle(&self) -> &Handle { &self.handle } - fn is_symlink(&self) -> bool { - self.readlink().is_ok() - } - - fn readlink(&self) -> io::Result<PathBuf> { - let mut space = [0u8; c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE]; - let mut bytes = 0; + 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<(libc::DWORD, &'a c::REPARSE_DATA_BUFFER)> { unsafe { + let mut bytes = 0; try!(cvt({ c::DeviceIoControl(self.handle.raw(), c::FSCTL_GET_REPARSE_POINT, @@ -333,12 +336,20 @@ impl File { &mut bytes, 0 as *mut _) })); - let buf: *const c::REPARSE_DATA_BUFFER = space.as_ptr() as *const _; - if (*buf).ReparseTag != c::IO_REPARSE_TAG_SYMLINK { - return Err(io::Error::new(io::ErrorKind::Other, "not a symlink")) - } + 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) = try!(self.reparse_point(&mut space)); + if buf.ReparseTag != c::IO_REPARSE_TAG_SYMLINK { + return Err(io::Error::new(io::ErrorKind::Other, "not a symlink")) + } + + unsafe { let info: *const c::SYMBOLIC_LINK_REPARSE_BUFFER = - &(*buf).rest as *const _ as *const _; + &buf.rest as *const _ as *const _; let path_buffer = &(*info).PathBuffer as *const _ as *const u16; let subst_off = (*info).SubstituteNameOffset / 2; let subst_ptr = path_buffer.offset(subst_off as isize); @@ -348,8 +359,6 @@ impl File { Ok(PathBuf::from(OsString::from_wide(subst))) } } - - pub fn into_handle(self) -> Handle { self.handle } } impl FromInner<libc::HANDLE> for File { @@ -360,10 +369,13 @@ impl FromInner<libc::HANDLE> for File { impl fmt::Debug for File { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - // FIXME(#24570): add more info here (e.g. path, mode) - f.debug_struct("File") - .field("handle", &self.handle.raw()) - .finish() + // 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() } } @@ -383,7 +395,7 @@ impl FileAttr { pub fn attrs(&self) -> u32 { self.data.dwFileAttributes as u32 } pub fn file_type(&self) -> FileType { - FileType::new(self.data.dwFileAttributes, self.is_symlink) + FileType::new(self.data.dwFileAttributes, self.reparse_tag) } pub fn created(&self) -> u64 { self.to_u64(&self.data.ftCreationTime) } @@ -414,12 +426,12 @@ impl FilePermissions { } impl FileType { - fn new(attrs: libc::DWORD, is_symlink: bool) -> FileType { + fn new(attrs: libc::DWORD, reparse_tag: libc::DWORD) -> FileType { if attrs & libc::FILE_ATTRIBUTE_REPARSE_POINT != 0 { - if is_symlink { - FileType::Symlink - } else { - FileType::ReparsePoint + match reparse_tag { + c::IO_REPARSE_TAG_SYMLINK => FileType::Symlink, + c::IO_REPARSE_TAG_MOUNT_POINT => FileType::MountPoint, + _ => FileType::ReparsePoint, } } else if attrs & c::FILE_ATTRIBUTE_DIRECTORY != 0 { FileType::Dir @@ -430,7 +442,9 @@ impl FileType { pub fn is_dir(&self) -> bool { *self == FileType::Dir } pub fn is_file(&self) -> bool { *self == FileType::File } - pub fn is_symlink(&self) -> bool { *self == FileType::Symlink } + pub fn is_symlink(&self) -> bool { + *self == FileType::Symlink || *self == FileType::MountPoint + } } impl DirBuilder { @@ -488,7 +502,7 @@ pub fn rmdir(p: &Path) -> io::Result<()> { } pub fn readlink(p: &Path) -> io::Result<PathBuf> { - let file = try!(File::open_reparse_point(p)); + let file = try!(File::open_reparse_point(p, false)); file.readlink() } @@ -497,12 +511,11 @@ pub fn symlink(src: &Path, dst: &Path) -> io::Result<()> { } pub fn symlink_inner(src: &Path, dst: &Path, dir: bool) -> io::Result<()> { - use sys::c::compat::kernel32::CreateSymbolicLinkW; let src = to_utf16(src); let dst = to_utf16(dst); let flags = if dir { c::SYMBOLIC_LINK_FLAG_DIRECTORY } else { 0 }; try!(cvt(unsafe { - CreateSymbolicLinkW(dst.as_ptr(), src.as_ptr(), flags) as libc::BOOL + c::CreateSymbolicLinkW(dst.as_ptr(), src.as_ptr(), flags) as libc::BOOL })); Ok(()) } @@ -518,8 +531,15 @@ pub fn link(src: &Path, dst: &Path) -> io::Result<()> { pub fn stat(p: &Path) -> io::Result<FileAttr> { let attr = try!(lstat(p)); - if attr.data.dwFileAttributes & libc::FILE_ATTRIBUTE_REPARSE_POINT != 0 { - let opts = OpenOptions::new(); + + // If this is a reparse point, then we need to reopen the file to get the + // actual destination. We also pass the FILE_FLAG_BACKUP_SEMANTICS flag to + // ensure that we can open directories (this path may be a directory + // junction). Once the file is opened we ask the opened handle what its + // metadata information is. + if attr.is_reparse_point() { + let mut opts = OpenOptions::new(); + opts.flags_and_attributes(c::FILE_FLAG_BACKUP_SEMANTICS); let file = try!(File::open(p, &opts)); file.file_attr() } else { @@ -535,9 +555,10 @@ pub fn lstat(p: &Path) -> io::Result<FileAttr> { c::GetFileExInfoStandard, &mut attr.data as *mut _ as *mut _))); if attr.is_reparse_point() { - attr.is_symlink = File::open_reparse_point(p).map(|f| { - f.is_symlink() - }).unwrap_or(false); + attr.reparse_tag = File::open_reparse_point(p, false).and_then(|f| { + let mut b = [0; c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE]; + f.reparse_point(&mut b).map(|(_, b)| b.ReparseTag) + }).unwrap_or(0); } Ok(attr) } @@ -564,16 +585,164 @@ pub fn utimes(p: &Path, atime: u64, mtime: u64) -> io::Result<()> { Ok(()) } -pub fn canonicalize(p: &Path) -> io::Result<PathBuf> { - use sys::c::compat::kernel32::GetFinalPathNameByHandleW; - - let mut opts = OpenOptions::new(); - opts.read(true); - let f = try!(File::open(p, &opts)); +fn get_path(f: &File) -> io::Result<PathBuf> { super::fill_utf16_buf(|buf, sz| unsafe { - GetFinalPathNameByHandleW(f.handle.raw(), buf, sz, - libc::VOLUME_NAME_DOS) + c::GetFinalPathNameByHandleW(f.handle.raw(), buf, sz, + libc::VOLUME_NAME_DOS) }, |buf| { PathBuf::from(OsString::from_wide(buf)) }) } + +pub fn canonicalize(p: &Path) -> io::Result<PathBuf> { + let mut opts = OpenOptions::new(); + opts.read(true); + let f = try!(File::open(p, &opts)); + get_path(&f) +} + +pub fn copy(from: &Path, to: &Path) -> io::Result<u64> { + unsafe extern "system" fn callback( + _TotalFileSize: libc::LARGE_INTEGER, + TotalBytesTransferred: libc::LARGE_INTEGER, + _StreamSize: libc::LARGE_INTEGER, + _StreamBytesTransferred: libc::LARGE_INTEGER, + _dwStreamNumber: libc::DWORD, + _dwCallbackReason: libc::DWORD, + _hSourceFile: HANDLE, + _hDestinationFile: HANDLE, + lpData: libc::LPVOID, + ) -> libc::DWORD { + *(lpData as *mut i64) = TotalBytesTransferred; + c::PROGRESS_CONTINUE + } + let pfrom = to_utf16(from); + let pto = to_utf16(to); + let mut size = 0i64; + try!(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) +} + +#[test] +fn directory_junctions_are_directories() { + use ffi::OsStr; + use env; + use rand::{self, StdRng, Rng}; + + macro_rules! t { + ($e:expr) => (match $e { + Ok(e) => e, + Err(e) => panic!("{} failed with: {}", stringify!($e), e), + }) + } + + let d = DirBuilder::new(); + let p = env::temp_dir(); + let mut r = rand::thread_rng(); + let ret = p.join(&format!("rust-{}", r.next_u32())); + let foo = ret.join("foo"); + let bar = ret.join("bar"); + t!(d.mkdir(&ret)); + t!(d.mkdir(&foo)); + t!(d.mkdir(&bar)); + + t!(create_junction(&bar, &foo)); + let metadata = stat(&bar); + t!(delete_junction(&bar)); + + t!(rmdir(&foo)); + t!(rmdir(&bar)); + t!(rmdir(&ret)); + + let metadata = t!(metadata); + assert!(metadata.file_type().is_dir()); + + // 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 + fn create_junction(src: &Path, dst: &Path) -> io::Result<()> { + let f = try!(opendir(src, true)); + let h = f.handle().raw(); + + unsafe { + let mut data = [0u8; c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE]; + let mut db = data.as_mut_ptr() + as *mut c::REPARSE_MOUNTPOINT_DATA_BUFFER; + let mut buf = &mut (*db).ReparseTarget as *mut _; + let mut i = 0; + let v = br"\??\"; + let v = v.iter().map(|x| *x as u16); + for c in v.chain(dst.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 libc::WORD; + (*db).ReparseTargetLength = ((i - 1) * 2) as libc::WORD; + (*db).ReparseDataLength = + (*db).ReparseTargetLength as libc::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, + 0 as *mut _, 0, + &mut ret, + 0 as *mut _)).map(|_| ()) + } + } + + fn opendir(p: &Path, write: bool) -> io::Result<File> { + unsafe { + let mut token = 0 as *mut _; + let mut tp: c::TOKEN_PRIVILEGES = mem::zeroed(); + try!(cvt(c::OpenProcessToken(c::GetCurrentProcess(), + c::TOKEN_ADJUST_PRIVILEGES, + &mut token))); + let name: &OsStr = if write { + "SeRestorePrivilege".as_ref() + } else { + "SeBackupPrivilege".as_ref() + }; + let name = name.encode_wide().chain(Some(0)).collect::<Vec<_>>(); + try!(cvt(c::LookupPrivilegeValueW(0 as *const _, + name.as_ptr(), + &mut tp.Privileges[0].Luid))); + tp.PrivilegeCount = 1; + tp.Privileges[0].Attributes = c::SE_PRIVILEGE_ENABLED; + let size = mem::size_of::<c::TOKEN_PRIVILEGES>() as libc::DWORD; + try!(cvt(c::AdjustTokenPrivileges(token, libc::FALSE, &mut tp, size, + 0 as *mut _, 0 as *mut _))); + try!(cvt(libc::CloseHandle(token))); + + File::open_reparse_point(p, write) + } + } + + fn delete_junction(p: &Path) -> io::Result<()> { + unsafe { + let f = try!(opendir(p, true)); + let h = f.handle().raw(); + let mut data = [0u8; c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE]; + let mut db = data.as_mut_ptr() + as *mut c::REPARSE_MOUNTPOINT_DATA_BUFFER; + (*db).ReparseTag = c::IO_REPARSE_TAG_MOUNT_POINT; + let mut bytes = 0; + cvt(c::DeviceIoControl(h as *mut _, + c::FSCTL_DELETE_REPARSE_POINT, + data.as_ptr() as *mut _, + (*db).ReparseDataLength + 8, + 0 as *mut _, 0, + &mut bytes, + 0 as *mut _)).map(|_| ()) + } + } +} diff --git a/src/libstd/sys/windows/mod.rs b/src/libstd/sys/windows/mod.rs index 18c8add17a6..b6d080109df 100644 --- a/src/libstd/sys/windows/mod.rs +++ b/src/libstd/sys/windows/mod.rs @@ -22,6 +22,8 @@ use os::windows::ffi::{OsStrExt, OsStringExt}; use path::PathBuf; use time::Duration; +#[macro_use] pub mod compat; + pub mod backtrace; pub mod c; pub mod condvar; @@ -36,7 +38,6 @@ pub mod pipe; pub mod process; pub mod rwlock; pub mod stack_overflow; -pub mod sync; pub mod thread; pub mod thread_local; pub mod time; diff --git a/src/libstd/sys/windows/mutex.rs b/src/libstd/sys/windows/mutex.rs index 29e370698ad..277c3d14c0e 100644 --- a/src/libstd/sys/windows/mutex.rs +++ b/src/libstd/sys/windows/mutex.rs @@ -8,57 +8,154 @@ // 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 there 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 prelude::v1::*; use cell::UnsafeCell; -use sys::sync as ffi; use mem; +use sync::atomic::{AtomicUsize, Ordering}; +use sys::c; +use sys::compat; -pub struct Mutex { inner: UnsafeCell<ffi::SRWLOCK> } +pub struct Mutex { + lock: AtomicUsize, + held: UnsafeCell<bool>, +} unsafe impl Send for Mutex {} unsafe impl Sync for Mutex {} -#[inline] -pub unsafe fn raw(m: &Mutex) -> ffi::PSRWLOCK { - m.inner.get() +#[derive(Clone, Copy)] +enum Kind { + SRWLock = 1, + CriticalSection = 2, } -// So you might be asking why we're using SRWLock instead of CriticalSection? -// -// 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 there there are no guarantees of fairness. +#[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 { inner: UnsafeCell::new(ffi::SRWLOCK_INIT) } + Mutex { + lock: AtomicUsize::new(0), + held: UnsafeCell::new(false), + } } - #[inline] pub unsafe fn lock(&self) { - ffi::AcquireSRWLockExclusive(self.inner.get()) + 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"); + } + } + } } - #[inline] pub unsafe fn try_lock(&self) -> bool { - ffi::TryAcquireSRWLockExclusive(self.inner.get()) != 0 + 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 + } + } + } } - #[inline] pub unsafe fn unlock(&self) { - ffi::ReleaseSRWLockExclusive(self.inner.get()) + *self.held.get() = false; + match kind() { + Kind::SRWLock => c::ReleaseSRWLockExclusive(raw(self)), + Kind::CriticalSection => (*self.remutex()).unlock(), + } } - #[inline] 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::new(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 + } + } } -pub struct ReentrantMutex { inner: UnsafeCell<ffi::CRITICAL_SECTION> } +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 {} @@ -69,23 +166,23 @@ impl ReentrantMutex { } pub unsafe fn init(&mut self) { - ffi::InitializeCriticalSection(self.inner.get()); + c::InitializeCriticalSection(self.inner.get()); } pub unsafe fn lock(&self) { - ffi::EnterCriticalSection(self.inner.get()); + c::EnterCriticalSection(self.inner.get()); } #[inline] pub unsafe fn try_lock(&self) -> bool { - ffi::TryEnterCriticalSection(self.inner.get()) != 0 + c::TryEnterCriticalSection(self.inner.get()) != 0 } pub unsafe fn unlock(&self) { - ffi::LeaveCriticalSection(self.inner.get()); + c::LeaveCriticalSection(self.inner.get()); } pub unsafe fn destroy(&self) { - ffi::DeleteCriticalSection(self.inner.get()); + c::DeleteCriticalSection(self.inner.get()); } } diff --git a/src/libstd/sys/windows/net.rs b/src/libstd/sys/windows/net.rs index 0b905267236..d58355ed1fe 100644 --- a/src/libstd/sys/windows/net.rs +++ b/src/libstd/sys/windows/net.rs @@ -21,7 +21,7 @@ use rt; use sync::Once; use sys; use sys::c; -use sys_common::{AsInner, FromInner}; +use sys_common::{AsInner, FromInner, IntoInner}; use sys_common::net::{setsockopt, getsockopt}; use time::Duration; @@ -82,26 +82,31 @@ impl Socket { SocketAddr::V4(..) => libc::AF_INET, SocketAddr::V6(..) => libc::AF_INET6, }; - let socket = unsafe { - c::WSASocketW(fam, ty, 0, 0 as *mut _, 0, - c::WSA_FLAG_OVERLAPPED | c::WSA_FLAG_NO_HANDLE_INHERIT) - }; - match socket { - INVALID_SOCKET => Err(last_error()), - n => Ok(Socket(n)), - } + let socket = try!(unsafe { + match c::WSASocketW(fam, ty, 0, 0 as *mut _, 0, + c::WSA_FLAG_OVERLAPPED) { + INVALID_SOCKET => Err(last_error()), + n => Ok(Socket(n)), + } + }); + try!(socket.set_no_inherit()); + Ok(socket) } pub fn accept(&self, storage: *mut libc::sockaddr, len: *mut libc::socklen_t) -> io::Result<Socket> { - match unsafe { libc::accept(self.0, storage, len) } { - INVALID_SOCKET => Err(last_error()), - n => Ok(Socket(n)), - } + let socket = try!(unsafe { + match libc::accept(self.0, storage, len) { + INVALID_SOCKET => Err(last_error()), + n => Ok(Socket(n)), + } + }); + try!(socket.set_no_inherit()); + Ok(socket) } pub fn duplicate(&self) -> io::Result<Socket> { - unsafe { + let socket = try!(unsafe { let mut info: c::WSAPROTOCOL_INFO = mem::zeroed(); try!(cvt(c::WSADuplicateSocketW(self.0, c::GetCurrentProcessId(), @@ -110,12 +115,13 @@ impl Socket { info.iSocketType, info.iProtocol, &mut info, 0, - c::WSA_FLAG_OVERLAPPED | - c::WSA_FLAG_NO_HANDLE_INHERIT) { + c::WSA_FLAG_OVERLAPPED) { INVALID_SOCKET => Err(last_error()), n => Ok(Socket(n)), } - } + }); + try!(socket.set_no_inherit()); + Ok(socket) } pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> { @@ -156,6 +162,13 @@ impl Socket { 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 libc::HANDLE, + c::HANDLE_FLAG_INHERIT, 0) + }).map(|_| ()) + } } impl Drop for Socket { @@ -171,3 +184,11 @@ impl AsInner<libc::SOCKET> for Socket { impl FromInner<libc::SOCKET> for Socket { fn from_inner(sock: libc::SOCKET) -> Socket { Socket(sock) } } + +impl IntoInner<libc::SOCKET> for Socket { + fn into_inner(self) -> libc::SOCKET { + let ret = self.0; + mem::forget(self); + ret + } +} diff --git a/src/libstd/sys/windows/pipe.rs b/src/libstd/sys/windows/pipe.rs index b2a6607314a..a7ece66e0f1 100644 --- a/src/libstd/sys/windows/pipe.rs +++ b/src/libstd/sys/windows/pipe.rs @@ -37,6 +37,7 @@ pub fn anon_pipe() -> io::Result<(AnonPipe, AnonPipe)> { impl AnonPipe { pub fn handle(&self) -> &Handle { &self.inner } + pub fn into_handle(self) -> Handle { self.inner } pub fn raw(&self) -> libc::HANDLE { self.inner.raw() } diff --git a/src/libstd/sys/windows/process.rs b/src/libstd/sys/windows/process.rs index 0b0268d4746..ca33e11eea0 100644 --- a/src/libstd/sys/windows/process.rs +++ b/src/libstd/sys/windows/process.rs @@ -220,6 +220,8 @@ impl Process { } pub fn handle(&self) -> &Handle { &self.handle } + + pub fn into_handle(self) -> Handle { self.handle } } #[derive(PartialEq, Eq, Clone, Copy, Debug)] diff --git a/src/libstd/sys/windows/rwlock.rs b/src/libstd/sys/windows/rwlock.rs index e727638e3e9..25865286db0 100644 --- a/src/libstd/sys/windows/rwlock.rs +++ b/src/libstd/sys/windows/rwlock.rs @@ -11,40 +11,40 @@ use prelude::v1::*; use cell::UnsafeCell; -use sys::sync as ffi; +use sys::c; -pub struct RWLock { inner: UnsafeCell<ffi::SRWLOCK> } +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(ffi::SRWLOCK_INIT) } + RWLock { inner: UnsafeCell::new(c::SRWLOCK_INIT) } } #[inline] pub unsafe fn read(&self) { - ffi::AcquireSRWLockShared(self.inner.get()) + c::AcquireSRWLockShared(self.inner.get()) } #[inline] pub unsafe fn try_read(&self) -> bool { - ffi::TryAcquireSRWLockShared(self.inner.get()) != 0 + c::TryAcquireSRWLockShared(self.inner.get()) != 0 } #[inline] pub unsafe fn write(&self) { - ffi::AcquireSRWLockExclusive(self.inner.get()) + c::AcquireSRWLockExclusive(self.inner.get()) } #[inline] pub unsafe fn try_write(&self) -> bool { - ffi::TryAcquireSRWLockExclusive(self.inner.get()) != 0 + c::TryAcquireSRWLockExclusive(self.inner.get()) != 0 } #[inline] pub unsafe fn read_unlock(&self) { - ffi::ReleaseSRWLockShared(self.inner.get()) + c::ReleaseSRWLockShared(self.inner.get()) } #[inline] pub unsafe fn write_unlock(&self) { - ffi::ReleaseSRWLockExclusive(self.inner.get()) + c::ReleaseSRWLockExclusive(self.inner.get()) } #[inline] diff --git a/src/libstd/sys/windows/stack_overflow.rs b/src/libstd/sys/windows/stack_overflow.rs index 79b7de4f341..491b53c4ed9 100644 --- a/src/libstd/sys/windows/stack_overflow.rs +++ b/src/libstd/sys/windows/stack_overflow.rs @@ -8,12 +8,14 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use rt::util::report_overflow; use core::prelude::*; -use ptr; -use mem; + +use libc::types::os::arch::extra::{LPVOID, DWORD, LONG}; use libc; -use libc::types::os::arch::extra::{LPVOID, DWORD, LONG, BOOL}; +use mem; +use ptr; +use rt::util::report_overflow; +use sys::c; use sys_common::stack; pub struct Handler { @@ -69,13 +71,18 @@ pub unsafe fn cleanup() { } pub unsafe fn make_handler() -> Handler { - if SetThreadStackGuarantee(&mut 0x5000) == 0 { - panic!("failed to reserve stack space for exception handling"); + // 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 libc::GetLastError() as u32 != libc::ERROR_CALL_NOT_IMPLEMENTED as u32 { + panic!("failed to reserve stack space for exception handling"); + } } Handler { _data: 0 as *mut libc::c_void } } +#[repr(C)] pub struct EXCEPTION_RECORD { pub ExceptionCode: DWORD, pub ExceptionFlags: DWORD, @@ -85,6 +92,7 @@ pub struct EXCEPTION_RECORD { pub ExceptionInformation: [LPVOID; EXCEPTION_MAXIMUM_PARAMETERS] } +#[repr(C)] pub struct EXCEPTION_POINTERS { pub ExceptionRecord: *mut EXCEPTION_RECORD, pub ContextRecord: LPVOID @@ -103,5 +111,4 @@ extern "system" { fn AddVectoredExceptionHandler(FirstHandler: ULONG, VectoredHandler: PVECTORED_EXCEPTION_HANDLER) -> LPVOID; - fn SetThreadStackGuarantee(StackSizeInBytes: *mut ULONG) -> BOOL; } diff --git a/src/libstd/sys/windows/stdio.rs b/src/libstd/sys/windows/stdio.rs index 9961fef714a..356787d5bf0 100644 --- a/src/libstd/sys/windows/stdio.rs +++ b/src/libstd/sys/windows/stdio.rs @@ -12,7 +12,6 @@ use prelude::v1::*; use io::prelude::*; use io::{self, Cursor}; -use iter::repeat; use libc; use ptr; use str; @@ -94,7 +93,7 @@ impl Stdin { 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<u16> = repeat(0u16).take(0x1000).collect(); + let mut utf16 = vec![0u16; 0x1000]; let mut num = 0; try!(cvt(unsafe { c::ReadConsoleW(handle, diff --git a/src/libstd/sys/windows/sync.rs b/src/libstd/sys/windows/sync.rs deleted file mode 100644 index 5410259540e..00000000000 --- a/src/libstd/sys/windows/sync.rs +++ /dev/null @@ -1,60 +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 libc::{BOOL, DWORD, LPVOID, LONG, HANDLE, c_ulong}; -use libc::types::os::arch::extra::BOOLEAN; - -pub type PCONDITION_VARIABLE = *mut CONDITION_VARIABLE; -pub type PSRWLOCK = *mut SRWLOCK; -pub type ULONG = c_ulong; -pub type ULONG_PTR = c_ulong; - -#[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 -} - -pub const CONDITION_VARIABLE_INIT: CONDITION_VARIABLE = CONDITION_VARIABLE { - ptr: 0 as *mut _, -}; -pub const SRWLOCK_INIT: SRWLOCK = SRWLOCK { ptr: 0 as *mut _ }; - -extern "system" { - // condition variables - pub fn SleepConditionVariableSRW(ConditionVariable: PCONDITION_VARIABLE, - SRWLock: PSRWLOCK, - dwMilliseconds: DWORD, - Flags: ULONG) -> BOOL; - pub fn WakeConditionVariable(ConditionVariable: PCONDITION_VARIABLE); - pub fn WakeAllConditionVariable(ConditionVariable: PCONDITION_VARIABLE); - - // slim rwlocks - pub fn AcquireSRWLockExclusive(SRWLock: PSRWLOCK); - pub fn AcquireSRWLockShared(SRWLock: PSRWLOCK); - pub fn ReleaseSRWLockExclusive(SRWLock: PSRWLOCK); - pub fn ReleaseSRWLockShared(SRWLock: PSRWLOCK); - pub fn TryAcquireSRWLockExclusive(SRWLock: PSRWLOCK) -> BOOLEAN; - pub fn TryAcquireSRWLockShared(SRWLock: PSRWLOCK) -> BOOLEAN; - - 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); -} diff --git a/src/libstd/sys/windows/thread.rs b/src/libstd/sys/windows/thread.rs index 50dfee4ab10..42805c2ac52 100644 --- a/src/libstd/sys/windows/thread.rs +++ b/src/libstd/sys/windows/thread.rs @@ -86,7 +86,8 @@ impl Thread { } pub mod guard { - pub unsafe fn main() -> usize { 0 } - pub unsafe fn current() -> usize { 0 } - pub unsafe fn init() {} + use prelude::v1::*; + + pub unsafe fn current() -> Option<usize> { None } + pub unsafe fn init() -> Option<usize> { None } } diff --git a/src/libstd/sys/windows/thread_local.rs b/src/libstd/sys/windows/thread_local.rs index 5002de55988..7550b7ce6c3 100644 --- a/src/libstd/sys/windows/thread_local.rs +++ b/src/libstd/sys/windows/thread_local.rs @@ -221,8 +221,8 @@ unsafe fn unregister_dtor(key: Key) -> bool { // // # The article mentions crazy stuff about "/INCLUDE"? // -// It sure does! This seems to work for now, so maybe we'll just run into -// that if we start linking with msvc? +// It sure does! We include it below for MSVC targets, but it look like for GNU +// targets we don't require it. #[link_section = ".CRT$XLB"] #[linkage = "external"] @@ -231,6 +231,13 @@ pub static p_thread_callback: unsafe extern "system" fn(LPVOID, DWORD, LPVOID) = on_tls_callback; +#[cfg(all(target_env = "msvc", target_pointer_width = "64"))] +#[link_args = "/INCLUDE:_tls_used"] +extern {} +#[cfg(all(target_env = "msvc", target_pointer_width = "32"))] +#[link_args = "/INCLUDE:__tls_used"] +extern {} + #[allow(warnings)] unsafe extern "system" fn on_tls_callback(h: LPVOID, dwReason: DWORD, |
