about summary refs log tree commit diff
path: root/src/libstd/sys
diff options
context:
space:
mode:
authorMathieu David <mathieudavid@mathieudavid.org>2015-07-27 20:46:01 +0200
committerMathieu David <mathieudavid@mathieudavid.org>2015-07-27 20:46:01 +0200
commitf6e9240a99e86d2c799dc29f179dd2870e51f71d (patch)
treea7e5ba20745b16949a45a4612b2708e262693a7b /src/libstd/sys
parent003c3eaa62981b791f9eb7bcad015baa1e00d98c (diff)
parent3351afeecffcc9ebaeb1188a5cde976da8e4a5aa (diff)
downloadrust-f6e9240a99e86d2c799dc29f179dd2870e51f71d.tar.gz
rust-f6e9240a99e86d2c799dc29f179dd2870e51f71d.zip
Fix the relative path issue by including the files using include_bytes!
Diffstat (limited to 'src/libstd/sys')
-rw-r--r--src/libstd/sys/common/io.rs139
-rw-r--r--src/libstd/sys/common/mod.rs1
-rw-r--r--src/libstd/sys/common/net.rs6
-rw-r--r--src/libstd/sys/common/stack.rs18
-rw-r--r--src/libstd/sys/common/thread_info.rs8
-rw-r--r--src/libstd/sys/common/wtf8.rs31
-rw-r--r--src/libstd/sys/unix/backtrace.rs11
-rw-r--r--src/libstd/sys/unix/c.rs10
-rw-r--r--src/libstd/sys/unix/ext/fs.rs22
-rw-r--r--src/libstd/sys/unix/ext/io.rs35
-rw-r--r--src/libstd/sys/unix/ext/mod.rs2
-rw-r--r--src/libstd/sys/unix/ext/process.rs22
-rw-r--r--src/libstd/sys/unix/fs.rs40
-rw-r--r--src/libstd/sys/unix/mod.rs1
-rw-r--r--src/libstd/sys/unix/net.rs6
-rw-r--r--src/libstd/sys/unix/os.rs60
-rw-r--r--src/libstd/sys/unix/pipe.rs1
-rw-r--r--src/libstd/sys/unix/process.rs1
-rw-r--r--src/libstd/sys/unix/stack_overflow.rs2
-rw-r--r--src/libstd/sys/unix/sync.rs1
-rw-r--r--src/libstd/sys/unix/thread.rs94
-rw-r--r--src/libstd/sys/unix/thread_local.rs2
-rw-r--r--src/libstd/sys/unix/time.rs1
-rw-r--r--src/libstd/sys/windows/c.rs290
-rw-r--r--src/libstd/sys/windows/compat.rs88
-rw-r--r--src/libstd/sys/windows/condvar.rs28
-rw-r--r--src/libstd/sys/windows/ext/io.rs50
-rw-r--r--src/libstd/sys/windows/ext/process.rs28
-rw-r--r--src/libstd/sys/windows/ext/raw.rs2
-rw-r--r--src/libstd/sys/windows/fs.rs269
-rw-r--r--src/libstd/sys/windows/mod.rs3
-rw-r--r--src/libstd/sys/windows/mutex.rs159
-rw-r--r--src/libstd/sys/windows/net.rs55
-rw-r--r--src/libstd/sys/windows/pipe.rs1
-rw-r--r--src/libstd/sys/windows/process.rs2
-rw-r--r--src/libstd/sys/windows/rwlock.rs18
-rw-r--r--src/libstd/sys/windows/stack_overflow.rs21
-rw-r--r--src/libstd/sys/windows/stdio.rs3
-rw-r--r--src/libstd/sys/windows/sync.rs60
-rw-r--r--src/libstd/sys/windows/thread.rs7
-rw-r--r--src/libstd/sys/windows/thread_local.rs11
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,