about summary refs log tree commit diff
path: root/src/libstd/sys
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2015-04-30 00:07:10 +0000
committerbors <bors@rust-lang.org>2015-04-30 00:07:10 +0000
commit5449f5d29e175230a1285ebe92394f50c76e1df6 (patch)
treec89deb8cc68b46e6fc768e862c32bd3e830a31c3 /src/libstd/sys
parent551a74dddd84cf01440ee84148ebd18bc68bd7c8 (diff)
parent1b34c099a6a624947877315875018093587a8834 (diff)
downloadrust-5449f5d29e175230a1285ebe92394f50c76e1df6.tar.gz
rust-5449f5d29e175230a1285ebe92394f50c76e1df6.zip
Auto merge of #24967 - alexcrichton:rollup, r=alexcrichton
Diffstat (limited to 'src/libstd/sys')
-rw-r--r--src/libstd/sys/unix/c.rs2
-rw-r--r--src/libstd/sys/unix/ext.rs337
-rw-r--r--src/libstd/sys/unix/ext/ffi.rs62
-rw-r--r--src/libstd/sys/unix/ext/fs.rs207
-rw-r--r--src/libstd/sys/unix/ext/io.rs108
-rw-r--r--src/libstd/sys/unix/ext/mod.rs53
-rw-r--r--src/libstd/sys/unix/ext/process.rs65
-rw-r--r--src/libstd/sys/unix/ext/raw.rs22
-rw-r--r--src/libstd/sys/unix/fs2.rs136
-rw-r--r--src/libstd/sys/unix/mod.rs10
-rw-r--r--src/libstd/sys/windows/backtrace.rs1
-rw-r--r--src/libstd/sys/windows/ext.rs301
-rw-r--r--src/libstd/sys/windows/ext/ffi.rs58
-rw-r--r--src/libstd/sys/windows/ext/fs.rs150
-rw-r--r--src/libstd/sys/windows/ext/io.rs131
-rw-r--r--src/libstd/sys/windows/ext/mod.rs35
-rw-r--r--src/libstd/sys/windows/ext/raw.rs21
-rw-r--r--src/libstd/sys/windows/fs2.rs234
-rw-r--r--src/libstd/sys/windows/handle.rs13
-rw-r--r--src/libstd/sys/windows/process2.rs278
-rw-r--r--src/libstd/sys/windows/stdio.rs16
21 files changed, 1340 insertions, 900 deletions
diff --git a/src/libstd/sys/unix/c.rs b/src/libstd/sys/unix/c.rs
index aa4bf821207..1e68eac5a67 100644
--- a/src/libstd/sys/unix/c.rs
+++ b/src/libstd/sys/unix/c.rs
@@ -161,6 +161,8 @@ extern {
     pub fn gai_strerror(errcode: libc::c_int) -> *const libc::c_char;
     pub fn setgroups(ngroups: libc::c_int,
                      ptr: *const libc::c_void) -> libc::c_int;
+    pub fn realpath(pathname: *const libc::c_char, resolved: *mut libc::c_char)
+                    -> *mut libc::c_char;
 }
 
 #[cfg(any(target_os = "macos", target_os = "ios"))]
diff --git a/src/libstd/sys/unix/ext.rs b/src/libstd/sys/unix/ext.rs
deleted file mode 100644
index 66aaf26b09b..00000000000
--- a/src/libstd/sys/unix/ext.rs
+++ /dev/null
@@ -1,337 +0,0 @@
-// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-//! Experimental extensions to `std` for Unix platforms.
-//!
-//! For now, this module is limited to extracting file descriptors,
-//! but its functionality will grow over time.
-//!
-//! # Example
-//!
-//! ```no_run
-//! use std::fs::File;
-//! use std::os::unix::prelude::*;
-//!
-//! fn main() {
-//!     let f = File::create("foo.txt").unwrap();
-//!     let fd = f.as_raw_fd();
-//!
-//!     // use fd with native unix bindings
-//! }
-//! ```
-
-#![stable(feature = "rust1", since = "1.0.0")]
-
-/// Unix-specific extensions to general I/O primitives
-#[stable(feature = "rust1", since = "1.0.0")]
-pub mod io {
-    use fs;
-    use libc;
-    use net;
-    use sys_common::{net2, AsInner, FromInner};
-    use sys;
-
-    /// Raw file descriptors.
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub type RawFd = libc::c_int;
-
-    /// A trait to extract the raw unix file descriptor from an underlying
-    /// object.
-    ///
-    /// This is only available on unix platforms and must be imported in order
-    /// to call the method. Windows platforms have a corresponding `AsRawHandle`
-    /// and `AsRawSocket` set of traits.
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub trait AsRawFd {
-        /// Extracts the raw file descriptor.
-        ///
-        /// This method does **not** pass ownership of the raw file descriptor
-        /// to the caller. The descriptor is only guarantee to be valid while
-        /// the original object has not yet been destroyed.
-        #[stable(feature = "rust1", since = "1.0.0")]
-        fn as_raw_fd(&self) -> RawFd;
-    }
-
-    /// A trait to express the ability to construct an object from a raw file
-    /// descriptor.
-    #[unstable(feature = "from_raw_os",
-               reason = "recent addition to std::os::unix::io")]
-    pub trait FromRawFd {
-        /// Constructs a new instances of `Self` from the given raw file
-        /// descriptor.
-        ///
-        /// This function **consumes ownership** of the specified file
-        /// descriptor. The returned object will take responsibility for closing
-        /// it when the object goes out of scope.
-        ///
-        /// This function is also unsafe as the primitives currently returned
-        /// have the contract that they are the sole owner of the file
-        /// descriptor they are wrapping. Usage of this function could
-        /// accidentally allow violating this contract which can cause memory
-        /// unsafety in code that relies on it being true.
-        unsafe fn from_raw_fd(fd: RawFd) -> Self;
-    }
-
-    #[stable(feature = "rust1", since = "1.0.0")]
-    impl AsRawFd for fs::File {
-        fn as_raw_fd(&self) -> RawFd {
-            self.as_inner().fd().raw()
-        }
-    }
-    #[unstable(feature = "from_raw_os", reason = "trait is unstable")]
-    impl FromRawFd for fs::File {
-        unsafe fn from_raw_fd(fd: RawFd) -> fs::File {
-            fs::File::from_inner(sys::fs2::File::from_inner(fd))
-        }
-    }
-
-    #[stable(feature = "rust1", since = "1.0.0")]
-    impl AsRawFd for net::TcpStream {
-        fn as_raw_fd(&self) -> RawFd { *self.as_inner().socket().as_inner() }
-    }
-    #[stable(feature = "rust1", since = "1.0.0")]
-    impl AsRawFd for net::TcpListener {
-        fn as_raw_fd(&self) -> RawFd { *self.as_inner().socket().as_inner() }
-    }
-    #[stable(feature = "rust1", since = "1.0.0")]
-    impl AsRawFd for net::UdpSocket {
-        fn as_raw_fd(&self) -> RawFd { *self.as_inner().socket().as_inner() }
-    }
-
-    #[unstable(feature = "from_raw_os", reason = "trait is unstable")]
-    impl FromRawFd for net::TcpStream {
-        unsafe fn from_raw_fd(fd: RawFd) -> net::TcpStream {
-            let socket = sys::net::Socket::from_inner(fd);
-            net::TcpStream::from_inner(net2::TcpStream::from_inner(socket))
-        }
-    }
-    #[unstable(feature = "from_raw_os", reason = "trait is unstable")]
-    impl FromRawFd for net::TcpListener {
-        unsafe fn from_raw_fd(fd: RawFd) -> net::TcpListener {
-            let socket = sys::net::Socket::from_inner(fd);
-            net::TcpListener::from_inner(net2::TcpListener::from_inner(socket))
-        }
-    }
-    #[unstable(feature = "from_raw_os", reason = "trait is unstable")]
-    impl FromRawFd for net::UdpSocket {
-        unsafe fn from_raw_fd(fd: RawFd) -> net::UdpSocket {
-            let socket = sys::net::Socket::from_inner(fd);
-            net::UdpSocket::from_inner(net2::UdpSocket::from_inner(socket))
-        }
-    }
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// OsString and OsStr
-////////////////////////////////////////////////////////////////////////////////
-
-/// Unix-specific extension to the primitives in the `std::ffi` module
-#[stable(feature = "rust1", since = "1.0.0")]
-pub mod ffi {
-    use ffi::{OsStr, OsString};
-    use mem;
-    use prelude::v1::*;
-    use sys::os_str::Buf;
-    use sys_common::{FromInner, IntoInner, AsInner};
-
-    /// Unix-specific extensions to `OsString`.
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub trait OsStringExt {
-        /// Creates an `OsString` from a byte vector.
-        #[stable(feature = "rust1", since = "1.0.0")]
-        fn from_vec(vec: Vec<u8>) -> Self;
-
-        /// Yields the underlying byte vector of this `OsString`.
-        #[stable(feature = "rust1", since = "1.0.0")]
-        fn into_vec(self) -> Vec<u8>;
-    }
-
-    #[stable(feature = "rust1", since = "1.0.0")]
-    impl OsStringExt for OsString {
-        fn from_vec(vec: Vec<u8>) -> OsString {
-            FromInner::from_inner(Buf { inner: vec })
-        }
-        fn into_vec(self) -> Vec<u8> {
-            self.into_inner().inner
-        }
-    }
-
-    /// Unix-specific extensions to `OsStr`.
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub trait OsStrExt {
-        #[stable(feature = "rust1", since = "1.0.0")]
-        fn from_bytes(slice: &[u8]) -> &Self;
-
-        /// Gets the underlying byte view of the `OsStr` slice.
-        #[stable(feature = "rust1", since = "1.0.0")]
-        fn as_bytes(&self) -> &[u8];
-    }
-
-    #[stable(feature = "rust1", since = "1.0.0")]
-    impl OsStrExt for OsStr {
-        fn from_bytes(slice: &[u8]) -> &OsStr {
-            unsafe { mem::transmute(slice) }
-        }
-        fn as_bytes(&self) -> &[u8] {
-            &self.as_inner().inner
-        }
-    }
-}
-
-/// Unix-specific extensions to primitives in the `std::fs` module.
-#[unstable(feature = "fs_ext",
-           reason = "may want a more useful mode abstraction")]
-pub mod fs {
-    use sys;
-    use sys_common::{FromInner, AsInner, AsInnerMut};
-    use fs::{Permissions, OpenOptions};
-    use path::Path;
-    use convert::AsRef;
-    use io;
-
-    /// Unix-specific extensions to `Permissions`
-    pub trait PermissionsExt {
-        fn mode(&self) -> i32;
-        fn set_mode(&mut self, mode: i32);
-    }
-
-    impl PermissionsExt for Permissions {
-        fn mode(&self) -> i32 { self.as_inner().mode() }
-
-        fn set_mode(&mut self, mode: i32) {
-            *self = FromInner::from_inner(FromInner::from_inner(mode));
-        }
-    }
-
-    /// Unix-specific extensions to `OpenOptions`
-    pub trait OpenOptionsExt {
-        /// Sets the mode bits that a new file will be created with.
-        ///
-        /// If a new file is created as part of a `File::open_opts` call then this
-        /// specified `mode` will be used as the permission bits for the new file.
-        fn mode(&mut self, mode: i32) -> &mut Self;
-    }
-
-    impl OpenOptionsExt for OpenOptions {
-        fn mode(&mut self, mode: i32) -> &mut OpenOptions {
-            self.as_inner_mut().mode(mode); self
-        }
-    }
-
-    /// Creates a new symbolic link on the filesystem.
-    ///
-    /// The `dst` path will be a symbolic link pointing to the `src` path.
-    ///
-    /// # Note
-    ///
-    /// On Windows, you must specify whether a symbolic link points to a file
-    /// or directory.  Use `os::windows::fs::symlink_file` to create a
-    /// symbolic link to a file, or `os::windows::fs::symlink_dir` to create a
-    /// symbolic link to a directory.  Additionally, the process must have
-    /// `SeCreateSymbolicLinkPrivilege` in order to be able to create a
-    /// symbolic link.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// #![feature(fs_ext)]
-    /// use std::os::unix::fs;
-    ///
-    /// # fn foo() -> std::io::Result<()> {
-    /// try!(fs::symlink("a.txt", "b.txt"));
-    /// # Ok(())
-    /// # }
-    /// ```
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn symlink<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dst: Q) -> io::Result<()>
-    {
-        sys::fs2::symlink(src.as_ref(), dst.as_ref())
-    }
-
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// Process and Command
-////////////////////////////////////////////////////////////////////////////////
-
-/// Unix-specific extensions to primitives in the `std::process` module.
-#[stable(feature = "rust1", since = "1.0.0")]
-pub mod process {
-    use prelude::v1::*;
-    use libc::{uid_t, gid_t};
-    use process;
-    use sys;
-    use sys_common::{AsInnerMut, AsInner};
-
-    /// Unix-specific extensions to the `std::process::Command` builder
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub trait CommandExt {
-        /// Sets the child process's user id. This translates to a
-        /// `setuid` call in the child process. Failure in the `setuid`
-        /// call will cause the spawn to fail.
-        #[stable(feature = "rust1", since = "1.0.0")]
-        fn uid(&mut self, id: uid_t) -> &mut process::Command;
-
-        /// Similar to `uid`, but sets the group id of the child process. This has
-        /// the same semantics as the `uid` field.
-        #[stable(feature = "rust1", since = "1.0.0")]
-        fn gid(&mut self, id: gid_t) -> &mut process::Command;
-    }
-
-    #[stable(feature = "rust1", since = "1.0.0")]
-    impl CommandExt for process::Command {
-        fn uid(&mut self, id: uid_t) -> &mut process::Command {
-            self.as_inner_mut().uid = Some(id);
-            self
-        }
-
-        fn gid(&mut self, id: gid_t) -> &mut process::Command {
-            self.as_inner_mut().gid = Some(id);
-            self
-        }
-    }
-
-    /// Unix-specific extensions to `std::process::ExitStatus`
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub trait ExitStatusExt {
-        /// If the process was terminated by a signal, returns that signal.
-        #[stable(feature = "rust1", since = "1.0.0")]
-        fn signal(&self) -> Option<i32>;
-    }
-
-    #[stable(feature = "rust1", since = "1.0.0")]
-    impl ExitStatusExt for process::ExitStatus {
-        fn signal(&self) -> Option<i32> {
-            match *self.as_inner() {
-                sys::process2::ExitStatus::Signal(s) => Some(s),
-                _ => None
-            }
-        }
-    }
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// Prelude
-////////////////////////////////////////////////////////////////////////////////
-
-/// A prelude for conveniently writing platform-specific code.
-///
-/// Includes all extension traits, and some important type definitions.
-#[stable(feature = "rust1", since = "1.0.0")]
-pub mod prelude {
-    #[doc(no_inline)]
-    pub use super::io::{RawFd, AsRawFd};
-    #[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};
-    #[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")]
-    pub use super::process::{CommandExt, ExitStatusExt};
-}
diff --git a/src/libstd/sys/unix/ext/ffi.rs b/src/libstd/sys/unix/ext/ffi.rs
new file mode 100644
index 00000000000..825e74cabde
--- /dev/null
+++ b/src/libstd/sys/unix/ext/ffi.rs
@@ -0,0 +1,62 @@
+// 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.
+
+//! Unix-specific extension to the primitives in the `std::ffi` module
+
+#![stable(feature = "rust1", since = "1.0.0")]
+
+use ffi::{OsStr, OsString};
+use mem;
+use prelude::v1::*;
+use sys::os_str::Buf;
+use sys_common::{FromInner, IntoInner, AsInner};
+
+/// Unix-specific extensions to `OsString`.
+#[stable(feature = "rust1", since = "1.0.0")]
+pub trait OsStringExt {
+    /// Creates an `OsString` from a byte vector.
+    #[stable(feature = "rust1", since = "1.0.0")]
+    fn from_vec(vec: Vec<u8>) -> Self;
+
+    /// Yields the underlying byte vector of this `OsString`.
+    #[stable(feature = "rust1", since = "1.0.0")]
+    fn into_vec(self) -> Vec<u8>;
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl OsStringExt for OsString {
+    fn from_vec(vec: Vec<u8>) -> OsString {
+        FromInner::from_inner(Buf { inner: vec })
+    }
+    fn into_vec(self) -> Vec<u8> {
+        self.into_inner().inner
+    }
+}
+
+/// Unix-specific extensions to `OsStr`.
+#[stable(feature = "rust1", since = "1.0.0")]
+pub trait OsStrExt {
+    #[stable(feature = "rust1", since = "1.0.0")]
+    fn from_bytes(slice: &[u8]) -> &Self;
+
+    /// Gets the underlying byte view of the `OsStr` slice.
+    #[stable(feature = "rust1", since = "1.0.0")]
+    fn as_bytes(&self) -> &[u8];
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl OsStrExt for OsStr {
+    fn from_bytes(slice: &[u8]) -> &OsStr {
+        unsafe { mem::transmute(slice) }
+    }
+    fn as_bytes(&self) -> &[u8] {
+        &self.as_inner().inner
+    }
+}
diff --git a/src/libstd/sys/unix/ext/fs.rs b/src/libstd/sys/unix/ext/fs.rs
new file mode 100644
index 00000000000..2e4ed38e50f
--- /dev/null
+++ b/src/libstd/sys/unix/ext/fs.rs
@@ -0,0 +1,207 @@
+// 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.
+
+//! Unix-specific extensions to primitives in the `std::fs` module.
+
+#![stable(feature = "rust1", since = "1.0.0")]
+
+use prelude::v1::*;
+
+use fs::{self, Permissions, OpenOptions};
+use io;
+use mem;
+use os::raw::c_long;
+use os::unix::raw;
+use path::Path;
+use sys::platform;
+use sys;
+use sys_common::{FromInner, AsInner, AsInnerMut};
+
+#[unstable(feature = "fs_mode", reason = "recently added API")]
+pub const USER_READ: raw::mode_t = 0o400;
+#[unstable(feature = "fs_mode", reason = "recently added API")]
+pub const USER_WRITE: raw::mode_t = 0o200;
+#[unstable(feature = "fs_mode", reason = "recently added API")]
+pub const USER_EXECUTE: raw::mode_t = 0o100;
+#[unstable(feature = "fs_mode", reason = "recently added API")]
+pub const USER_RWX: raw::mode_t = 0o700;
+#[unstable(feature = "fs_mode", reason = "recently added API")]
+pub const GROUP_READ: raw::mode_t = 0o040;
+#[unstable(feature = "fs_mode", reason = "recently added API")]
+pub const GROUP_WRITE: raw::mode_t = 0o020;
+#[unstable(feature = "fs_mode", reason = "recently added API")]
+pub const GROUP_EXECUTE: raw::mode_t = 0o010;
+#[unstable(feature = "fs_mode", reason = "recently added API")]
+pub const GROUP_RWX: raw::mode_t = 0o070;
+#[unstable(feature = "fs_mode", reason = "recently added API")]
+pub const OTHER_READ: raw::mode_t = 0o004;
+#[unstable(feature = "fs_mode", reason = "recently added API")]
+pub const OTHER_WRITE: raw::mode_t = 0o002;
+#[unstable(feature = "fs_mode", reason = "recently added API")]
+pub const OTHER_EXECUTE: raw::mode_t = 0o001;
+#[unstable(feature = "fs_mode", reason = "recently added API")]
+pub const OTHER_RWX: raw::mode_t = 0o007;
+#[unstable(feature = "fs_mode", reason = "recently added API")]
+pub const ALL_READ: raw::mode_t = 0o444;
+#[unstable(feature = "fs_mode", reason = "recently added API")]
+pub const ALL_WRITE: raw::mode_t = 0o222;
+#[unstable(feature = "fs_mode", reason = "recently added API")]
+pub const ALL_EXECUTE: raw::mode_t = 0o111;
+#[unstable(feature = "fs_mode", reason = "recently added API")]
+pub const ALL_RWX: raw::mode_t = 0o777;
+#[unstable(feature = "fs_mode", reason = "recently added API")]
+pub const SETUID: raw::mode_t = 0o4000;
+#[unstable(feature = "fs_mode", reason = "recently added API")]
+pub const SETGID: raw::mode_t = 0o2000;
+#[unstable(feature = "fs_mode", reason = "recently added API")]
+pub const STICKY_BIT: raw::mode_t = 0o1000;
+
+/// Unix-specific extensions to `Permissions`
+#[unstable(feature = "fs_ext",
+           reason = "may want a more useful mode abstraction")]
+pub trait PermissionsExt {
+    fn mode(&self) -> raw::mode_t;
+    fn set_mode(&mut self, mode: raw::mode_t);
+    fn from_mode(mode: raw::mode_t) -> Self;
+}
+
+impl PermissionsExt for Permissions {
+    fn mode(&self) -> raw::mode_t { self.as_inner().mode() }
+
+    fn set_mode(&mut self, mode: raw::mode_t) {
+        *self = FromInner::from_inner(FromInner::from_inner(mode));
+    }
+
+    fn from_mode(mode: raw::mode_t) -> Permissions {
+        FromInner::from_inner(FromInner::from_inner(mode))
+    }
+}
+
+/// Unix-specific extensions to `OpenOptions`
+#[unstable(feature = "fs_ext",
+           reason = "may want a more useful mode abstraction")]
+pub trait OpenOptionsExt {
+    /// Sets the mode bits that a new file will be created with.
+    ///
+    /// If a new file is created as part of a `File::open_opts` call then this
+    /// specified `mode` will be used as the permission bits for the new file.
+    fn mode(&mut self, mode: raw::mode_t) -> &mut Self;
+}
+
+impl OpenOptionsExt for OpenOptions {
+    fn mode(&mut self, mode: raw::mode_t) -> &mut OpenOptions {
+        self.as_inner_mut().mode(mode); self
+    }
+}
+
+#[unstable(feature = "metadata_ext", reason = "recently added API")]
+pub struct Metadata(sys::fs2::FileAttr);
+
+#[unstable(feature = "metadata_ext", reason = "recently added API")]
+pub trait MetadataExt {
+    fn as_raw(&self) -> &Metadata;
+}
+
+impl MetadataExt for fs::Metadata {
+    fn as_raw(&self) -> &Metadata {
+        let inner: &sys::fs2::FileAttr = self.as_inner();
+        unsafe { mem::transmute(inner) }
+    }
+}
+
+impl AsInner<platform::raw::stat> for Metadata {
+    fn as_inner(&self) -> &platform::raw::stat { self.0.as_inner() }
+}
+
+// Hm, why are there casts here to the returned type, shouldn't the types always
+// be the same? Right you are! Turns out, however, on android at least the types
+// in the raw `stat` structure are not the same as the types being returned. Who
+// knew!
+//
+// As a result to make sure this compiles for all platforms we do the manual
+// casts and rely on manual lowering to `stat` if the raw type is desired.
+#[unstable(feature = "metadata_ext", reason = "recently added API")]
+impl Metadata {
+    pub fn dev(&self) -> raw::dev_t { self.0.raw().st_dev as raw::dev_t }
+    pub fn ino(&self) -> raw::ino_t { self.0.raw().st_ino as raw::ino_t }
+    pub fn mode(&self) -> raw::mode_t { self.0.raw().st_mode as raw::mode_t }
+    pub fn nlink(&self) -> raw::nlink_t { self.0.raw().st_nlink as raw::nlink_t }
+    pub fn uid(&self) -> raw::uid_t { self.0.raw().st_uid as raw::uid_t }
+    pub fn gid(&self) -> raw::gid_t { self.0.raw().st_gid as raw::gid_t }
+    pub fn rdev(&self) -> raw::dev_t { self.0.raw().st_rdev as raw::dev_t }
+    pub fn size(&self) -> raw::off_t { self.0.raw().st_size as raw::off_t }
+    pub fn atime(&self) -> raw::time_t { self.0.raw().st_atime }
+    pub fn atime_nsec(&self) -> c_long { self.0.raw().st_atime }
+    pub fn mtime(&self) -> raw::time_t { self.0.raw().st_mtime }
+    pub fn mtime_nsec(&self) -> c_long { self.0.raw().st_mtime }
+    pub fn ctime(&self) -> raw::time_t { self.0.raw().st_ctime }
+    pub fn ctime_nsec(&self) -> c_long { self.0.raw().st_ctime }
+
+    pub fn blksize(&self) -> raw::blksize_t {
+        self.0.raw().st_blksize as raw::blksize_t
+    }
+    pub fn blocks(&self) -> raw::blkcnt_t {
+        self.0.raw().st_blocks as raw::blkcnt_t
+    }
+}
+
+#[unstable(feature = "dir_entry_ext", reason = "recently added API")]
+pub trait DirEntryExt {
+    fn ino(&self) -> raw::ino_t;
+}
+
+impl DirEntryExt for fs::DirEntry {
+    fn ino(&self) -> raw::ino_t { self.as_inner().ino() }
+}
+
+/// Creates a new symbolic link on the filesystem.
+///
+/// The `dst` path will be a symbolic link pointing to the `src` path.
+///
+/// # Note
+///
+/// On Windows, you must specify whether a symbolic link points to a file
+/// or directory.  Use `os::windows::fs::symlink_file` to create a
+/// symbolic link to a file, or `os::windows::fs::symlink_dir` to create a
+/// symbolic link to a directory.  Additionally, the process must have
+/// `SeCreateSymbolicLinkPrivilege` in order to be able to create a
+/// symbolic link.
+///
+/// # Examples
+///
+/// ```
+/// use std::os::unix::fs;
+///
+/// # fn foo() -> std::io::Result<()> {
+/// try!(fs::symlink("a.txt", "b.txt"));
+/// # Ok(())
+/// # }
+/// ```
+#[stable(feature = "rust1", since = "1.0.0")]
+pub fn symlink<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dst: Q) -> io::Result<()>
+{
+    sys::fs2::symlink(src.as_ref(), dst.as_ref())
+}
+
+#[unstable(feature = "dir_builder", reason = "recently added API")]
+/// An extension trait for `fs::DirBuilder` for unix-specific options.
+pub trait DirBuilderExt {
+    /// Sets the mode to create new directories with. This option defaults to
+    /// 0o777.
+    fn mode(&mut self, mode: raw::mode_t) -> &mut Self;
+}
+
+impl DirBuilderExt for fs::DirBuilder {
+    fn mode(&mut self, mode: raw::mode_t) -> &mut fs::DirBuilder {
+        self.as_inner_mut().set_mode(mode);
+        self
+    }
+}
+
diff --git a/src/libstd/sys/unix/ext/io.rs b/src/libstd/sys/unix/ext/io.rs
new file mode 100644
index 00000000000..8cb4b4907f6
--- /dev/null
+++ b/src/libstd/sys/unix/ext/io.rs
@@ -0,0 +1,108 @@
+// 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.
+
+//! Unix-specific extensions to general I/O primitives
+
+#![stable(feature = "rust1", since = "1.0.0")]
+
+use fs;
+use net;
+use os::raw;
+use sys;
+use sys_common::{net2, AsInner, FromInner};
+
+/// Raw file descriptors.
+#[stable(feature = "rust1", since = "1.0.0")]
+pub type RawFd = raw::c_int;
+
+/// A trait to extract the raw unix file descriptor from an underlying
+/// object.
+///
+/// This is only available on unix platforms and must be imported in order
+/// to call the method. Windows platforms have a corresponding `AsRawHandle`
+/// and `AsRawSocket` set of traits.
+#[stable(feature = "rust1", since = "1.0.0")]
+pub trait AsRawFd {
+    /// Extracts the raw file descriptor.
+    ///
+    /// This method does **not** pass ownership of the raw file descriptor
+    /// to the caller. The descriptor is only guarantee to be valid while
+    /// the original object has not yet been destroyed.
+    #[stable(feature = "rust1", since = "1.0.0")]
+    fn as_raw_fd(&self) -> RawFd;
+}
+
+/// A trait to express the ability to construct an object from a raw file
+/// descriptor.
+#[unstable(feature = "from_raw_os",
+           reason = "recent addition to std::os::unix::io")]
+pub trait FromRawFd {
+    /// Constructs a new instances of `Self` from the given raw file
+    /// descriptor.
+    ///
+    /// This function **consumes ownership** of the specified file
+    /// descriptor. The returned object will take responsibility for closing
+    /// it when the object goes out of scope.
+    ///
+    /// This function is also unsafe as the primitives currently returned
+    /// have the contract that they are the sole owner of the file
+    /// descriptor they are wrapping. Usage of this function could
+    /// accidentally allow violating this contract which can cause memory
+    /// unsafety in code that relies on it being true.
+    unsafe fn from_raw_fd(fd: RawFd) -> Self;
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl AsRawFd for fs::File {
+    fn as_raw_fd(&self) -> RawFd {
+        self.as_inner().fd().raw()
+    }
+}
+#[unstable(feature = "from_raw_os", reason = "trait is unstable")]
+impl FromRawFd for fs::File {
+    unsafe fn from_raw_fd(fd: RawFd) -> fs::File {
+        fs::File::from_inner(sys::fs2::File::from_inner(fd))
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl AsRawFd for net::TcpStream {
+    fn as_raw_fd(&self) -> RawFd { *self.as_inner().socket().as_inner() }
+}
+#[stable(feature = "rust1", since = "1.0.0")]
+impl AsRawFd for net::TcpListener {
+    fn as_raw_fd(&self) -> RawFd { *self.as_inner().socket().as_inner() }
+}
+#[stable(feature = "rust1", since = "1.0.0")]
+impl AsRawFd for net::UdpSocket {
+    fn as_raw_fd(&self) -> RawFd { *self.as_inner().socket().as_inner() }
+}
+
+#[unstable(feature = "from_raw_os", reason = "trait is unstable")]
+impl FromRawFd for net::TcpStream {
+    unsafe fn from_raw_fd(fd: RawFd) -> net::TcpStream {
+        let socket = sys::net::Socket::from_inner(fd);
+        net::TcpStream::from_inner(net2::TcpStream::from_inner(socket))
+    }
+}
+#[unstable(feature = "from_raw_os", reason = "trait is unstable")]
+impl FromRawFd for net::TcpListener {
+    unsafe fn from_raw_fd(fd: RawFd) -> net::TcpListener {
+        let socket = sys::net::Socket::from_inner(fd);
+        net::TcpListener::from_inner(net2::TcpListener::from_inner(socket))
+    }
+}
+#[unstable(feature = "from_raw_os", reason = "trait is unstable")]
+impl FromRawFd for net::UdpSocket {
+    unsafe fn from_raw_fd(fd: RawFd) -> net::UdpSocket {
+        let socket = sys::net::Socket::from_inner(fd);
+        net::UdpSocket::from_inner(net2::UdpSocket::from_inner(socket))
+    }
+}
diff --git a/src/libstd/sys/unix/ext/mod.rs b/src/libstd/sys/unix/ext/mod.rs
new file mode 100644
index 00000000000..6fde45a7301
--- /dev/null
+++ b/src/libstd/sys/unix/ext/mod.rs
@@ -0,0 +1,53 @@
+// 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.
+
+//! Experimental extensions to `std` for Unix platforms.
+//!
+//! For now, this module is limited to extracting file descriptors,
+//! but its functionality will grow over time.
+//!
+//! # Example
+//!
+//! ```no_run
+//! use std::fs::File;
+//! use std::os::unix::prelude::*;
+//!
+//! fn main() {
+//!     let f = File::create("foo.txt").unwrap();
+//!     let fd = f.as_raw_fd();
+//!
+//!     // use fd with native unix bindings
+//! }
+//! ```
+
+#![stable(feature = "rust1", since = "1.0.0")]
+
+pub mod io;
+pub mod ffi;
+pub mod fs;
+pub mod process;
+pub mod raw;
+
+/// A prelude for conveniently writing platform-specific code.
+///
+/// Includes all extension traits, and some important type definitions.
+#[stable(feature = "rust1", since = "1.0.0")]
+pub mod prelude {
+    #[doc(no_inline)]
+    pub use super::io::{RawFd, AsRawFd};
+    #[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};
+    #[doc(no_inline)]
+    pub use super::fs::{DirEntryExt};
+    #[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")]
+    pub use super::process::{CommandExt, ExitStatusExt};
+}
diff --git a/src/libstd/sys/unix/ext/process.rs b/src/libstd/sys/unix/ext/process.rs
new file mode 100644
index 00000000000..8c9d0a86583
--- /dev/null
+++ b/src/libstd/sys/unix/ext/process.rs
@@ -0,0 +1,65 @@
+// 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.
+
+//! Unix-specific extensions to primitives in the `std::process` module.
+
+#![stable(feature = "rust1", since = "1.0.0")]
+
+use os::unix::raw::{uid_t, gid_t};
+use prelude::v1::*;
+use process;
+use sys;
+use sys_common::{AsInnerMut, AsInner};
+
+/// Unix-specific extensions to the `std::process::Command` builder
+#[stable(feature = "rust1", since = "1.0.0")]
+pub trait CommandExt {
+    /// Sets the child process's user id. This translates to a
+    /// `setuid` call in the child process. Failure in the `setuid`
+    /// call will cause the spawn to fail.
+    #[stable(feature = "rust1", since = "1.0.0")]
+    fn uid(&mut self, id: uid_t) -> &mut process::Command;
+
+    /// Similar to `uid`, but sets the group id of the child process. This has
+    /// the same semantics as the `uid` field.
+    #[stable(feature = "rust1", since = "1.0.0")]
+    fn gid(&mut self, id: gid_t) -> &mut process::Command;
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl CommandExt for process::Command {
+    fn uid(&mut self, id: uid_t) -> &mut process::Command {
+        self.as_inner_mut().uid = Some(id);
+        self
+    }
+
+    fn gid(&mut self, id: gid_t) -> &mut process::Command {
+        self.as_inner_mut().gid = Some(id);
+        self
+    }
+}
+
+/// Unix-specific extensions to `std::process::ExitStatus`
+#[stable(feature = "rust1", since = "1.0.0")]
+pub trait ExitStatusExt {
+    /// If the process was terminated by a signal, returns that signal.
+    #[stable(feature = "rust1", since = "1.0.0")]
+    fn signal(&self) -> Option<i32>;
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl ExitStatusExt for process::ExitStatus {
+    fn signal(&self) -> Option<i32> {
+        match *self.as_inner() {
+            sys::process2::ExitStatus::Signal(s) => Some(s),
+            _ => None
+        }
+    }
+}
diff --git a/src/libstd/sys/unix/ext/raw.rs b/src/libstd/sys/unix/ext/raw.rs
new file mode 100644
index 00000000000..8fe4b90456a
--- /dev/null
+++ b/src/libstd/sys/unix/ext/raw.rs
@@ -0,0 +1,22 @@
+// 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.
+
+//! Unix-specific primitives available on all unix platforms
+
+#![unstable(feature = "raw_ext", reason = "recently added API")]
+
+pub type uid_t = u32;
+pub type gid_t = u32;
+pub type pid_t = i32;
+
+#[doc(inline)]
+pub use sys::platform::raw::{dev_t, ino_t, mode_t, nlink_t, off_t, blksize_t};
+#[doc(inline)]
+pub use sys::platform::raw::{blkcnt_t, time_t};
diff --git a/src/libstd/sys/unix/fs2.rs b/src/libstd/sys/unix/fs2.rs
index 8eb84b26f22..350161c751c 100644
--- a/src/libstd/sys/unix/fs2.rs
+++ b/src/libstd/sys/unix/fs2.rs
@@ -21,14 +21,15 @@ use path::{Path, PathBuf};
 use ptr;
 use sync::Arc;
 use sys::fd::FileDesc;
+use sys::platform::raw;
 use sys::{c, cvt, cvt_r};
-use sys_common::FromInner;
+use sys_common::{AsInner, FromInner};
 use vec::Vec;
 
 pub struct File(FileDesc);
 
 pub struct FileAttr {
-    stat: libc::stat,
+    stat: raw::stat,
 }
 
 pub struct ReadDir {
@@ -57,13 +58,12 @@ pub struct OpenOptions {
 #[derive(Clone, PartialEq, Eq, Debug)]
 pub struct FilePermissions { mode: mode_t }
 
+#[derive(Copy, Clone, PartialEq, Eq, Hash)]
+pub struct FileType { mode: mode_t }
+
+pub struct DirBuilder { mode: mode_t }
+
 impl FileAttr {
-    pub fn is_dir(&self) -> bool {
-        (self.stat.st_mode as mode_t) & libc::S_IFMT == libc::S_IFDIR
-    }
-    pub fn is_file(&self) -> bool {
-        (self.stat.st_mode as mode_t) & libc::S_IFMT == libc::S_IFREG
-    }
     pub fn size(&self) -> u64 { self.stat.st_size as u64 }
     pub fn perm(&self) -> FilePermissions {
         FilePermissions { mode: (self.stat.st_mode as mode_t) & 0o777 }
@@ -76,12 +76,35 @@ impl FileAttr {
         self.mktime(self.stat.st_mtime as u64, self.stat.st_mtime_nsec as u64)
     }
 
+    pub fn file_type(&self) -> FileType {
+        FileType { mode: self.stat.st_mode as mode_t }
+    }
+
+    pub fn raw(&self) -> &raw::stat { &self.stat }
+
     // times are in milliseconds (currently)
     fn mktime(&self, secs: u64, nsecs: u64) -> u64 {
         secs * 1000 + nsecs / 1000000
     }
 }
 
+impl AsInner<raw::stat> for FileAttr {
+    fn as_inner(&self) -> &raw::stat { &self.stat }
+}
+
+#[unstable(feature = "metadata_ext", reason = "recently added API")]
+pub trait MetadataExt {
+    fn as_raw_stat(&self) -> &raw::stat;
+}
+
+impl MetadataExt for ::fs::Metadata {
+    fn as_raw_stat(&self) -> &raw::stat { &self.as_inner().stat }
+}
+
+impl MetadataExt for ::os::unix::fs::Metadata {
+    fn as_raw_stat(&self) -> &raw::stat { self.as_inner() }
+}
+
 impl FilePermissions {
     pub fn readonly(&self) -> bool { self.mode & 0o222 == 0 }
     pub fn set_readonly(&mut self, readonly: bool) {
@@ -91,11 +114,19 @@ impl FilePermissions {
             self.mode |= 0o222;
         }
     }
-    pub fn mode(&self) -> i32 { self.mode as i32 }
+    pub fn mode(&self) -> raw::mode_t { self.mode }
 }
 
-impl FromInner<i32> for FilePermissions {
-    fn from_inner(mode: i32) -> FilePermissions {
+impl FileType {
+    pub fn is_dir(&self) -> bool { self.is(libc::S_IFDIR) }
+    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 }
+}
+
+impl FromInner<raw::mode_t> for FilePermissions {
+    fn from_inner(mode: raw::mode_t) -> FilePermissions {
         FilePermissions { mode: mode as mode_t }
     }
 }
@@ -147,6 +178,33 @@ impl DirEntry {
         self.root.join(<OsStr as OsStrExt>::from_bytes(self.name_bytes()))
     }
 
+    pub fn file_name(&self) -> OsString {
+        OsStr::from_bytes(self.name_bytes()).to_os_string()
+    }
+
+    pub fn metadata(&self) -> io::Result<FileAttr> {
+        lstat(&self.path())
+    }
+
+    pub fn file_type(&self) -> io::Result<FileType> {
+        extern {
+            fn rust_dir_get_mode(ptr: *mut libc::dirent_t) -> c_int;
+        }
+        unsafe {
+            match rust_dir_get_mode(self.dirent()) {
+                -1 => lstat(&self.path()).map(|m| m.file_type()),
+                n => Ok(FileType { mode: n as mode_t }),
+            }
+        }
+    }
+
+    pub fn ino(&self) -> raw::ino_t {
+        extern {
+            fn rust_dir_get_ino(ptr: *mut libc::dirent_t) -> raw::ino_t;
+        }
+        unsafe { rust_dir_get_ino(self.dirent()) }
+    }
+
     fn name_bytes(&self) -> &[u8] {
         extern {
             fn rust_list_dir_val(ptr: *mut libc::dirent_t) -> *const c_char;
@@ -191,7 +249,7 @@ impl OpenOptions {
         self.flag(libc::O_CREAT, create);
     }
 
-    pub fn mode(&mut self, mode: i32) {
+    pub fn mode(&mut self, mode: raw::mode_t) {
         self.mode = mode as mode_t;
     }
 
@@ -228,8 +286,10 @@ impl File {
     pub fn into_fd(self) -> FileDesc { self.0 }
 
     pub fn file_attr(&self) -> io::Result<FileAttr> {
-        let mut stat: libc::stat = unsafe { mem::zeroed() };
-        try!(cvt(unsafe { libc::fstat(self.0.raw(), &mut stat) }));
+        let mut stat: raw::stat = unsafe { mem::zeroed() };
+        try!(cvt(unsafe {
+            libc::fstat(self.0.raw(), &mut stat as *mut _ as *mut _)
+        }));
         Ok(FileAttr { stat: stat })
     }
 
@@ -284,6 +344,22 @@ impl File {
     pub fn fd(&self) -> &FileDesc { &self.0 }
 }
 
+impl DirBuilder {
+    pub fn new() -> DirBuilder {
+        DirBuilder { mode: 0o777 }
+    }
+
+    pub fn mkdir(&self, p: &Path) -> io::Result<()> {
+        let p = try!(cstr(p));
+        try!(cvt(unsafe { libc::mkdir(p.as_ptr(), self.mode) }));
+        Ok(())
+    }
+
+    pub fn set_mode(&mut self, mode: mode_t) {
+        self.mode = mode;
+    }
+}
+
 fn cstr(path: &Path) -> io::Result<CString> {
     path.as_os_str().to_cstring().ok_or(
         io::Error::new(io::ErrorKind::InvalidInput, "path contained a null"))
@@ -343,12 +419,6 @@ impl fmt::Debug for File {
     }
 }
 
-pub fn mkdir(p: &Path) -> io::Result<()> {
-    let p = try!(cstr(p));
-    try!(cvt(unsafe { libc::mkdir(p.as_ptr(), 0o777) }));
-    Ok(())
-}
-
 pub fn readdir(p: &Path) -> io::Result<ReadDir> {
     let root = Arc::new(p.to_path_buf());
     let p = try!(cstr(p));
@@ -420,15 +490,19 @@ pub fn link(src: &Path, dst: &Path) -> io::Result<()> {
 
 pub fn stat(p: &Path) -> io::Result<FileAttr> {
     let p = try!(cstr(p));
-    let mut stat: libc::stat = unsafe { mem::zeroed() };
-    try!(cvt(unsafe { libc::stat(p.as_ptr(), &mut stat) }));
+    let mut stat: raw::stat = unsafe { mem::zeroed() };
+    try!(cvt(unsafe {
+        libc::stat(p.as_ptr(), &mut stat as *mut _ as *mut _)
+    }));
     Ok(FileAttr { stat: stat })
 }
 
 pub fn lstat(p: &Path) -> io::Result<FileAttr> {
     let p = try!(cstr(p));
-    let mut stat: libc::stat = unsafe { mem::zeroed() };
-    try!(cvt(unsafe { libc::lstat(p.as_ptr(), &mut stat) }));
+    let mut stat: raw::stat = unsafe { mem::zeroed() };
+    try!(cvt(unsafe {
+        libc::lstat(p.as_ptr(), &mut stat as *mut _ as *mut _)
+    }));
     Ok(FileAttr { stat: stat })
 }
 
@@ -438,3 +512,17 @@ pub fn utimes(p: &Path, atime: u64, mtime: u64) -> io::Result<()> {
     try!(cvt(unsafe { c::utimes(p.as_ptr(), buf.as_ptr()) }));
     Ok(())
 }
+
+pub fn canonicalize(p: &Path) -> io::Result<PathBuf> {
+    let path = try!(CString::new(p.as_os_str().as_bytes()));
+    let mut buf = vec![0u8; 16 * 1024];
+    unsafe {
+        let r = c::realpath(path.as_ptr(), buf.as_mut_ptr() as *mut _);
+        if r.is_null() {
+            return Err(io::Error::last_os_error())
+        }
+    }
+    let p = buf.iter().position(|i| *i == 0).unwrap();
+    buf.truncate(p);
+    Ok(PathBuf::from(OsString::from_vec(buf)))
+}
diff --git a/src/libstd/sys/unix/mod.rs b/src/libstd/sys/unix/mod.rs
index d99753a6a4c..78b798d3bff 100644
--- a/src/libstd/sys/unix/mod.rs
+++ b/src/libstd/sys/unix/mod.rs
@@ -18,6 +18,16 @@ use libc;
 use num::One;
 use ops::Neg;
 
+#[cfg(target_os = "android")]   pub use os::android as platform;
+#[cfg(target_os = "bitrig")]    pub use os::bitrig as platform;
+#[cfg(target_os = "dragonfly")] pub use os::dragonfly as platform;
+#[cfg(target_os = "freebsd")]   pub use os::freebsd as platform;
+#[cfg(target_os = "ios")]       pub use os::ios as platform;
+#[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 = "openbsd")]   pub use os::openbsd as platform;
+
 pub mod backtrace;
 pub mod c;
 pub mod condvar;
diff --git a/src/libstd/sys/windows/backtrace.rs b/src/libstd/sys/windows/backtrace.rs
index 385834a6226..d94dfdeeea4 100644
--- a/src/libstd/sys/windows/backtrace.rs
+++ b/src/libstd/sys/windows/backtrace.rs
@@ -283,7 +283,6 @@ mod arch {
     }
 }
 
-#[repr(C)]
 struct Cleanup {
     handle: libc::HANDLE,
     SymCleanup: SymCleanupFn,
diff --git a/src/libstd/sys/windows/ext.rs b/src/libstd/sys/windows/ext.rs
deleted file mode 100644
index dd747d202a0..00000000000
--- a/src/libstd/sys/windows/ext.rs
+++ /dev/null
@@ -1,301 +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.
-
-//! Experimental extensions to `std` for Windows.
-//!
-//! For now, this module is limited to extracting handles, file
-//! descriptors, and sockets, but its functionality will grow over
-//! time.
-
-#![stable(feature = "rust1", since = "1.0.0")]
-
-#[stable(feature = "rust1", since = "1.0.0")]
-pub mod io {
-    use fs;
-    use libc;
-    use net;
-    use sys_common::{net2, AsInner, FromInner};
-    use sys;
-
-    /// Raw HANDLEs.
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub type RawHandle = libc::HANDLE;
-
-    /// Raw SOCKETs.
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub type RawSocket = libc::SOCKET;
-
-    /// Extract raw handles.
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub trait AsRawHandle {
-        /// Extracts the raw handle, without taking any ownership.
-        #[stable(feature = "rust1", since = "1.0.0")]
-        fn as_raw_handle(&self) -> RawHandle;
-    }
-
-    /// Construct I/O objects from raw handles.
-    #[unstable(feature = "from_raw_os",
-               reason = "recent addition to the std::os::windows::io module")]
-    pub trait FromRawHandle {
-        /// Constructs a new I/O object from the specified raw handle.
-        ///
-        /// This function will **consume ownership** of the handle given,
-        /// passing responsibility for closing the handle to the returned
-        /// object.
-        ///
-        /// This function is also unsafe as the primitives currently returned
-        /// have the contract that they are the sole owner of the file
-        /// descriptor they are wrapping. Usage of this function could
-        /// accidentally allow violating this contract which can cause memory
-        /// unsafety in code that relies on it being true.
-        unsafe fn from_raw_handle(handle: RawHandle) -> Self;
-    }
-
-    #[stable(feature = "rust1", since = "1.0.0")]
-    impl AsRawHandle for fs::File {
-        fn as_raw_handle(&self) -> RawHandle {
-            self.as_inner().handle().raw()
-        }
-    }
-
-    #[unstable(feature = "from_raw_os", reason = "trait is unstable")]
-    impl FromRawHandle for fs::File {
-        unsafe fn from_raw_handle(handle: RawHandle) -> fs::File {
-            fs::File::from_inner(sys::fs2::File::from_inner(handle))
-        }
-    }
-
-    /// Extract raw sockets.
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub trait AsRawSocket {
-        /// Extracts the underlying raw socket from this object.
-        #[stable(feature = "rust1", since = "1.0.0")]
-        fn as_raw_socket(&self) -> RawSocket;
-    }
-
-    /// Create I/O objects from raw sockets.
-    #[unstable(feature = "from_raw_os", reason = "recent addition to module")]
-    pub trait FromRawSocket {
-        /// Creates a new I/O object from the given raw socket.
-        ///
-        /// This function will **consume ownership** of the socket provided and
-        /// it will be closed when the returned object goes out of scope.
-        ///
-        /// This function is also unsafe as the primitives currently returned
-        /// have the contract that they are the sole owner of the file
-        /// descriptor they are wrapping. Usage of this function could
-        /// accidentally allow violating this contract which can cause memory
-        /// unsafety in code that relies on it being true.
-        unsafe fn from_raw_socket(sock: RawSocket) -> Self;
-    }
-
-    #[stable(feature = "rust1", since = "1.0.0")]
-    impl AsRawSocket for net::TcpStream {
-        fn as_raw_socket(&self) -> RawSocket {
-            *self.as_inner().socket().as_inner()
-        }
-    }
-    #[stable(feature = "rust1", since = "1.0.0")]
-    impl AsRawSocket for net::TcpListener {
-        fn as_raw_socket(&self) -> RawSocket {
-            *self.as_inner().socket().as_inner()
-        }
-    }
-    #[stable(feature = "rust1", since = "1.0.0")]
-    impl AsRawSocket for net::UdpSocket {
-        fn as_raw_socket(&self) -> RawSocket {
-            *self.as_inner().socket().as_inner()
-        }
-    }
-
-    #[unstable(feature = "from_raw_os", reason = "trait is unstable")]
-    impl FromRawSocket for net::TcpStream {
-        unsafe fn from_raw_socket(sock: RawSocket) -> net::TcpStream {
-            let sock = sys::net::Socket::from_inner(sock);
-            net::TcpStream::from_inner(net2::TcpStream::from_inner(sock))
-        }
-    }
-    #[unstable(feature = "from_raw_os", reason = "trait is unstable")]
-    impl FromRawSocket for net::TcpListener {
-        unsafe fn from_raw_socket(sock: RawSocket) -> net::TcpListener {
-            let sock = sys::net::Socket::from_inner(sock);
-            net::TcpListener::from_inner(net2::TcpListener::from_inner(sock))
-        }
-    }
-    #[unstable(feature = "from_raw_os", reason = "trait is unstable")]
-    impl FromRawSocket for net::UdpSocket {
-        unsafe fn from_raw_socket(sock: RawSocket) -> net::UdpSocket {
-            let sock = sys::net::Socket::from_inner(sock);
-            net::UdpSocket::from_inner(net2::UdpSocket::from_inner(sock))
-        }
-    }
-}
-
-/// Windows-specific extensions to the primitives in the `std::ffi` module.
-#[stable(feature = "rust1", since = "1.0.0")]
-pub mod ffi {
-    use ffi::{OsString, OsStr};
-    use sys::os_str::Buf;
-    use sys_common::wtf8::Wtf8Buf;
-    use sys_common::{FromInner, AsInner};
-
-    pub use sys_common::wtf8::EncodeWide;
-
-    /// Windows-specific extensions to `OsString`.
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub trait OsStringExt {
-        /// Creates an `OsString` from a potentially ill-formed UTF-16 slice of
-        /// 16-bit code units.
-        ///
-        /// This is lossless: calling `.encode_wide()` on the resulting string
-        /// will always return the original code units.
-        #[stable(feature = "rust1", since = "1.0.0")]
-        fn from_wide(wide: &[u16]) -> Self;
-    }
-
-    #[stable(feature = "rust1", since = "1.0.0")]
-    impl OsStringExt for OsString {
-        fn from_wide(wide: &[u16]) -> OsString {
-            FromInner::from_inner(Buf { inner: Wtf8Buf::from_wide(wide) })
-        }
-    }
-
-    /// Windows-specific extensions to `OsStr`.
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub trait OsStrExt {
-        /// Re-encodes an `OsStr` as a wide character sequence,
-        /// i.e. potentially ill-formed UTF-16.
-        ///
-        /// This is lossless. Note that the encoding does not include a final
-        /// null.
-        #[stable(feature = "rust1", since = "1.0.0")]
-        fn encode_wide(&self) -> EncodeWide;
-    }
-
-    #[stable(feature = "rust1", since = "1.0.0")]
-    impl OsStrExt for OsStr {
-        fn encode_wide(&self) -> EncodeWide {
-            self.as_inner().inner.encode_wide()
-        }
-    }
-}
-
-/// Windows-specific extensions for the primitives in `std::fs`
-#[unstable(feature = "fs_ext", reason = "may require more thought/methods")]
-pub mod fs {
-    use fs::OpenOptions;
-    use sys;
-    use sys_common::AsInnerMut;
-    use path::Path;
-    use convert::AsRef;
-    use io;
-
-    /// Windows-specific extensions to `OpenOptions`
-    pub trait OpenOptionsExt {
-        /// Overrides the `dwDesiredAccess` argument to the call to `CreateFile`
-        /// with the specified value.
-        fn desired_access(&mut self, access: i32) -> &mut Self;
-
-        /// Overrides the `dwCreationDisposition` argument to the call to
-        /// `CreateFile` with the specified value.
-        ///
-        /// This will override any values of the standard `create` flags, for
-        /// example.
-        fn creation_disposition(&mut self, val: i32) -> &mut Self;
-
-        /// Overrides the `dwFlagsAndAttributes` argument to the call to
-        /// `CreateFile` with the specified value.
-        ///
-        /// This will override any values of the standard flags on the
-        /// `OpenOptions` structure.
-        fn flags_and_attributes(&mut self, val: i32) -> &mut Self;
-
-        /// Overrides the `dwShareMode` argument to the call to `CreateFile` with
-        /// the specified value.
-        ///
-        /// This will override any values of the standard flags on the
-        /// `OpenOptions` structure.
-        fn share_mode(&mut self, val: i32) -> &mut Self;
-    }
-
-    impl OpenOptionsExt for OpenOptions {
-        fn desired_access(&mut self, access: i32) -> &mut OpenOptions {
-            self.as_inner_mut().desired_access(access); self
-        }
-        fn creation_disposition(&mut self, access: i32) -> &mut OpenOptions {
-            self.as_inner_mut().creation_disposition(access); self
-        }
-        fn flags_and_attributes(&mut self, access: i32) -> &mut OpenOptions {
-            self.as_inner_mut().flags_and_attributes(access); self
-        }
-        fn share_mode(&mut self, access: i32) -> &mut OpenOptions {
-            self.as_inner_mut().share_mode(access); self
-        }
-    }
-
-    /// Creates a new file symbolic link on the filesystem.
-    ///
-    /// The `dst` path will be a file symbolic link pointing to the `src`
-    /// path.
-    ///
-    /// # Examples
-    ///
-    /// ```ignore
-    /// #![feature(fs_ext)]
-    /// use std::os::windows::fs;
-    ///
-    /// # fn foo() -> std::io::Result<()> {
-    /// try!(fs::symlink_file("a.txt", "b.txt"));
-    /// # Ok(())
-    /// # }
-    /// ```
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn symlink_file<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dst: Q)
-                                                        -> io::Result<()>
-    {
-        sys::fs2::symlink_inner(src.as_ref(), dst.as_ref(), false)
-    }
-
-    /// Creates a new directory symlink on the filesystem.
-    ///
-    /// The `dst` path will be a directory symbolic link pointing to the `src`
-    /// path.
-    ///
-    /// # Examples
-    ///
-    /// ```ignore
-    /// #![feature(fs_ext)]
-    /// use std::os::windows::fs;
-    ///
-    /// # fn foo() -> std::io::Result<()> {
-    /// try!(fs::symlink_file("a", "b"));
-    /// # Ok(())
-    /// # }
-    /// ```
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn symlink_dir<P: AsRef<Path>, Q: AsRef<Path>> (src: P, dst: Q)
-                                                        -> io::Result<()>
-    {
-        sys::fs2::symlink_inner(src.as_ref(), dst.as_ref(), true)
-    }
-}
-
-/// A prelude for conveniently writing platform-specific code.
-///
-/// Includes all extension traits, and some important type definitions.
-#[stable(feature = "rust1", since = "1.0.0")]
-pub mod prelude {
-    #[doc(no_inline)]
-    pub use super::io::{RawSocket, RawHandle, AsRawSocket, AsRawHandle};
-    #[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")]
-    pub use super::ffi::{OsStrExt, OsStringExt};
-    #[doc(no_inline)]
-    pub use super::fs::OpenOptionsExt;
-}
diff --git a/src/libstd/sys/windows/ext/ffi.rs b/src/libstd/sys/windows/ext/ffi.rs
new file mode 100644
index 00000000000..3fa96f4dd13
--- /dev/null
+++ b/src/libstd/sys/windows/ext/ffi.rs
@@ -0,0 +1,58 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! Windows-specific extensions to the primitives in the `std::ffi` module.
+
+#![stable(feature = "rust1", since = "1.0.0")]
+
+use ffi::{OsString, OsStr};
+use sys::os_str::Buf;
+use sys_common::wtf8::Wtf8Buf;
+use sys_common::{FromInner, AsInner};
+
+pub use sys_common::wtf8::EncodeWide;
+
+/// Windows-specific extensions to `OsString`.
+#[stable(feature = "rust1", since = "1.0.0")]
+pub trait OsStringExt {
+    /// Creates an `OsString` from a potentially ill-formed UTF-16 slice of
+    /// 16-bit code units.
+    ///
+    /// This is lossless: calling `.encode_wide()` on the resulting string
+    /// will always return the original code units.
+    #[stable(feature = "rust1", since = "1.0.0")]
+    fn from_wide(wide: &[u16]) -> Self;
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl OsStringExt for OsString {
+    fn from_wide(wide: &[u16]) -> OsString {
+        FromInner::from_inner(Buf { inner: Wtf8Buf::from_wide(wide) })
+    }
+}
+
+/// Windows-specific extensions to `OsStr`.
+#[stable(feature = "rust1", since = "1.0.0")]
+pub trait OsStrExt {
+    /// Re-encodes an `OsStr` as a wide character sequence,
+    /// i.e. potentially ill-formed UTF-16.
+    ///
+    /// This is lossless. Note that the encoding does not include a final
+    /// null.
+    #[stable(feature = "rust1", since = "1.0.0")]
+    fn encode_wide(&self) -> EncodeWide;
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl OsStrExt for OsStr {
+    fn encode_wide(&self) -> EncodeWide {
+        self.as_inner().inner.encode_wide()
+    }
+}
diff --git a/src/libstd/sys/windows/ext/fs.rs b/src/libstd/sys/windows/ext/fs.rs
new file mode 100644
index 00000000000..23c1fcf4b3c
--- /dev/null
+++ b/src/libstd/sys/windows/ext/fs.rs
@@ -0,0 +1,150 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! Windows-specific extensions for the primitives in `std::fs`
+
+#![stable(feature = "rust1", since = "1.0.0")]
+
+use prelude::v1::*;
+
+use fs::{OpenOptions, Metadata};
+use io;
+use path::Path;
+use sys;
+use sys_common::{AsInnerMut, AsInner};
+
+/// Windows-specific extensions to `OpenOptions`
+#[unstable(feature = "fs_ext", reason = "may require more thought/methods")]
+pub trait OpenOptionsExt {
+    /// Overrides the `dwDesiredAccess` argument to the call to `CreateFile`
+    /// with the specified value.
+    fn desired_access(&mut self, access: i32) -> &mut Self;
+
+    /// Overrides the `dwCreationDisposition` argument to the call to
+    /// `CreateFile` with the specified value.
+    ///
+    /// This will override any values of the standard `create` flags, for
+    /// example.
+    fn creation_disposition(&mut self, val: i32) -> &mut Self;
+
+    /// Overrides the `dwFlagsAndAttributes` argument to the call to
+    /// `CreateFile` with the specified value.
+    ///
+    /// This will override any values of the standard flags on the
+    /// `OpenOptions` structure.
+    fn flags_and_attributes(&mut self, val: i32) -> &mut Self;
+
+    /// Overrides the `dwShareMode` argument to the call to `CreateFile` with
+    /// the specified value.
+    ///
+    /// This will override any values of the standard flags on the
+    /// `OpenOptions` structure.
+    fn share_mode(&mut self, val: i32) -> &mut Self;
+}
+
+impl OpenOptionsExt for OpenOptions {
+    fn desired_access(&mut self, access: i32) -> &mut OpenOptions {
+        self.as_inner_mut().desired_access(access); self
+    }
+    fn creation_disposition(&mut self, access: i32) -> &mut OpenOptions {
+        self.as_inner_mut().creation_disposition(access); self
+    }
+    fn flags_and_attributes(&mut self, access: i32) -> &mut OpenOptions {
+        self.as_inner_mut().flags_and_attributes(access); self
+    }
+    fn share_mode(&mut self, access: i32) -> &mut OpenOptions {
+        self.as_inner_mut().share_mode(access); self
+    }
+}
+
+/// Extension methods for `fs::Metadata` to access the raw fields contained
+/// within.
+#[unstable(feature = "metadata_ext", reason = "recently added API")]
+pub trait MetadataExt {
+    /// Returns the value of the `dwFileAttributes` field of this metadata.
+    ///
+    /// This field contains the file system attribute information for a file
+    /// or directory.
+    fn file_attributes(&self) -> u32;
+
+    /// Returns the value of the `ftCreationTime` field of this metadata.
+    ///
+    /// The returned 64-bit value represents the number of 100-nanosecond
+    /// intervals since January 1, 1601 (UTC).
+    fn creation_time(&self) -> u64;
+
+    /// Returns the value of the `ftLastAccessTime` field of this metadata.
+    ///
+    /// The returned 64-bit value represents the number of 100-nanosecond
+    /// intervals since January 1, 1601 (UTC).
+    fn last_access_time(&self) -> u64;
+
+    /// Returns the value of the `ftLastWriteTime` field of this metadata.
+    ///
+    /// The returned 64-bit value represents the number of 100-nanosecond
+    /// intervals since January 1, 1601 (UTC).
+    fn last_write_time(&self) -> u64;
+
+    /// Returns the value of the `nFileSize{High,Low}` fields of this
+    /// metadata.
+    ///
+    /// The returned value does not have meaning for directories.
+    fn file_size(&self) -> u64;
+}
+
+impl MetadataExt for Metadata {
+    fn file_attributes(&self) -> u32 { self.as_inner().attrs() }
+    fn creation_time(&self) -> u64 { self.as_inner().created() }
+    fn last_access_time(&self) -> u64 { self.as_inner().accessed() }
+    fn last_write_time(&self) -> u64 { self.as_inner().modified() }
+    fn file_size(&self) -> u64 { self.as_inner().size() }
+}
+
+/// Creates a new file symbolic link on the filesystem.
+///
+/// The `dst` path will be a file symbolic link pointing to the `src`
+/// path.
+///
+/// # Examples
+///
+/// ```ignore
+/// use std::os::windows::fs;
+///
+/// # fn foo() -> std::io::Result<()> {
+/// try!(fs::symlink_file("a.txt", "b.txt"));
+/// # Ok(())
+/// # }
+/// ```
+#[stable(feature = "rust1", since = "1.0.0")]
+pub fn symlink_file<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dst: Q)
+                                                    -> io::Result<()> {
+    sys::fs2::symlink_inner(src.as_ref(), dst.as_ref(), false)
+}
+
+/// Creates a new directory symlink on the filesystem.
+///
+/// The `dst` path will be a directory symbolic link pointing to the `src`
+/// path.
+///
+/// # Examples
+///
+/// ```ignore
+/// use std::os::windows::fs;
+///
+/// # fn foo() -> std::io::Result<()> {
+/// try!(fs::symlink_file("a", "b"));
+/// # Ok(())
+/// # }
+/// ```
+#[stable(feature = "rust1", since = "1.0.0")]
+pub fn symlink_dir<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dst: Q)
+                                                   -> io::Result<()> {
+    sys::fs2::symlink_inner(src.as_ref(), dst.as_ref(), true)
+}
diff --git a/src/libstd/sys/windows/ext/io.rs b/src/libstd/sys/windows/ext/io.rs
new file mode 100644
index 00000000000..b88a6316eee
--- /dev/null
+++ b/src/libstd/sys/windows/ext/io.rs
@@ -0,0 +1,131 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![stable(feature = "rust1", since = "1.0.0")]
+
+use fs;
+use os::windows::raw;
+use net;
+use sys_common::{net2, AsInner, FromInner};
+use sys;
+
+/// Raw HANDLEs.
+#[stable(feature = "rust1", since = "1.0.0")]
+pub type RawHandle = raw::HANDLE;
+
+/// Raw SOCKETs.
+#[stable(feature = "rust1", since = "1.0.0")]
+pub type RawSocket = raw::SOCKET;
+
+/// Extract raw handles.
+#[stable(feature = "rust1", since = "1.0.0")]
+pub trait AsRawHandle {
+    /// Extracts the raw handle, without taking any ownership.
+    #[stable(feature = "rust1", since = "1.0.0")]
+    fn as_raw_handle(&self) -> RawHandle;
+}
+
+/// Construct I/O objects from raw handles.
+#[unstable(feature = "from_raw_os",
+           reason = "recent addition to the std::os::windows::io module")]
+pub trait FromRawHandle {
+    /// Constructs a new I/O object from the specified raw handle.
+    ///
+    /// This function will **consume ownership** of the handle given,
+    /// passing responsibility for closing the handle to the returned
+    /// object.
+    ///
+    /// This function is also unsafe as the primitives currently returned
+    /// have the contract that they are the sole owner of the file
+    /// descriptor they are wrapping. Usage of this function could
+    /// accidentally allow violating this contract which can cause memory
+    /// unsafety in code that relies on it being true.
+    unsafe fn from_raw_handle(handle: RawHandle) -> Self;
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl AsRawHandle for fs::File {
+    fn as_raw_handle(&self) -> RawHandle {
+        self.as_inner().handle().raw() as RawHandle
+    }
+}
+
+#[unstable(feature = "from_raw_os", reason = "trait is unstable")]
+impl FromRawHandle for fs::File {
+    unsafe fn from_raw_handle(handle: RawHandle) -> fs::File {
+        let handle = handle as ::libc::HANDLE;
+        fs::File::from_inner(sys::fs2::File::from_inner(handle))
+    }
+}
+
+/// Extract raw sockets.
+#[stable(feature = "rust1", since = "1.0.0")]
+pub trait AsRawSocket {
+    /// Extracts the underlying raw socket from this object.
+    #[stable(feature = "rust1", since = "1.0.0")]
+    fn as_raw_socket(&self) -> RawSocket;
+}
+
+/// Create I/O objects from raw sockets.
+#[unstable(feature = "from_raw_os", reason = "recent addition to module")]
+pub trait FromRawSocket {
+    /// Creates a new I/O object from the given raw socket.
+    ///
+    /// This function will **consume ownership** of the socket provided and
+    /// it will be closed when the returned object goes out of scope.
+    ///
+    /// This function is also unsafe as the primitives currently returned
+    /// have the contract that they are the sole owner of the file
+    /// descriptor they are wrapping. Usage of this function could
+    /// accidentally allow violating this contract which can cause memory
+    /// unsafety in code that relies on it being true.
+    unsafe fn from_raw_socket(sock: RawSocket) -> Self;
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl AsRawSocket for net::TcpStream {
+    fn as_raw_socket(&self) -> RawSocket {
+        *self.as_inner().socket().as_inner()
+    }
+}
+#[stable(feature = "rust1", since = "1.0.0")]
+impl AsRawSocket for net::TcpListener {
+    fn as_raw_socket(&self) -> RawSocket {
+        *self.as_inner().socket().as_inner()
+    }
+}
+#[stable(feature = "rust1", since = "1.0.0")]
+impl AsRawSocket for net::UdpSocket {
+    fn as_raw_socket(&self) -> RawSocket {
+        *self.as_inner().socket().as_inner()
+    }
+}
+
+#[unstable(feature = "from_raw_os", reason = "trait is unstable")]
+impl FromRawSocket for net::TcpStream {
+    unsafe fn from_raw_socket(sock: RawSocket) -> net::TcpStream {
+        let sock = sys::net::Socket::from_inner(sock);
+        net::TcpStream::from_inner(net2::TcpStream::from_inner(sock))
+    }
+}
+#[unstable(feature = "from_raw_os", reason = "trait is unstable")]
+impl FromRawSocket for net::TcpListener {
+    unsafe fn from_raw_socket(sock: RawSocket) -> net::TcpListener {
+        let sock = sys::net::Socket::from_inner(sock);
+        net::TcpListener::from_inner(net2::TcpListener::from_inner(sock))
+    }
+}
+#[unstable(feature = "from_raw_os", reason = "trait is unstable")]
+impl FromRawSocket for net::UdpSocket {
+    unsafe fn from_raw_socket(sock: RawSocket) -> net::UdpSocket {
+        let sock = sys::net::Socket::from_inner(sock);
+        net::UdpSocket::from_inner(net2::UdpSocket::from_inner(sock))
+    }
+}
diff --git a/src/libstd/sys/windows/ext/mod.rs b/src/libstd/sys/windows/ext/mod.rs
new file mode 100644
index 00000000000..08dfa4cc877
--- /dev/null
+++ b/src/libstd/sys/windows/ext/mod.rs
@@ -0,0 +1,35 @@
+// 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.
+
+//! Experimental extensions to `std` for Windows.
+//!
+//! For now, this module is limited to extracting handles, file
+//! descriptors, and sockets, but its functionality will grow over
+//! time.
+
+#![stable(feature = "rust1", since = "1.0.0")]
+
+pub mod ffi;
+pub mod fs;
+pub mod io;
+pub mod raw;
+
+/// A prelude for conveniently writing platform-specific code.
+///
+/// Includes all extension traits, and some important type definitions.
+#[stable(feature = "rust1", since = "1.0.0")]
+pub mod prelude {
+    #[doc(no_inline)]
+    pub use super::io::{RawSocket, RawHandle, AsRawSocket, AsRawHandle};
+    #[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")]
+    pub use super::ffi::{OsStrExt, OsStringExt};
+    #[doc(no_inline)]
+    pub use super::fs::{OpenOptionsExt, MetadataExt};
+}
diff --git a/src/libstd/sys/windows/ext/raw.rs b/src/libstd/sys/windows/ext/raw.rs
new file mode 100644
index 00000000000..656e480ad09
--- /dev/null
+++ b/src/libstd/sys/windows/ext/raw.rs
@@ -0,0 +1,21 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! Windows-specific primitives
+
+#![unstable(feature = "raw_ext", reason = "recently added API")]
+
+use os::raw;
+
+pub type HANDLE = *mut raw::c_void;
+#[cfg(target_pointer_width = "32")]
+pub type SOCKET = u32;
+#[cfg(target_pointer_width = "64")]
+pub type SOCKET = u64;
diff --git a/src/libstd/sys/windows/fs2.rs b/src/libstd/sys/windows/fs2.rs
index 5ac9a0ace58..03a56e2958a 100644
--- a/src/libstd/sys/windows/fs2.rs
+++ b/src/libstd/sys/windows/fs2.rs
@@ -27,7 +27,16 @@ use sys_common::FromInner;
 use vec::Vec;
 
 pub struct File { handle: Handle }
-pub struct FileAttr { data: c::WIN32_FILE_ATTRIBUTE_DATA }
+
+pub struct FileAttr {
+    data: c::WIN32_FILE_ATTRIBUTE_DATA,
+    is_symlink: bool,
+}
+
+#[derive(Copy, Clone, PartialEq, Eq, Hash)]
+pub enum FileType {
+    Dir, File, Symlink, ReparsePoint
+}
 
 pub struct ReadDir {
     handle: FindNextFileHandle,
@@ -56,11 +65,14 @@ pub struct OpenOptions {
     share_mode: Option<libc::DWORD>,
     creation_disposition: Option<libc::DWORD>,
     flags_and_attributes: Option<libc::DWORD>,
+    security_attributes: usize, // *mut T doesn't have a Default impl
 }
 
 #[derive(Clone, PartialEq, Eq, Debug)]
 pub struct FilePermissions { attrs: libc::DWORD }
 
+pub struct DirBuilder;
+
 impl Iterator for ReadDir {
     type Item = io::Result<DirEntry>;
     fn next(&mut self) -> Option<io::Result<DirEntry>> {
@@ -111,8 +123,31 @@ impl DirEntry {
     }
 
     pub fn path(&self) -> PathBuf {
+        self.root.join(&self.file_name())
+    }
+
+    pub fn file_name(&self) -> OsString {
         let filename = super::truncate_utf16_at_nul(&self.data.cFileName);
-        self.root.join(&<OsString as OsStringExt>::from_wide(filename))
+        OsString::from_wide(filename)
+    }
+
+    pub fn file_type(&self) -> io::Result<FileType> {
+        Ok(FileType::new(self.data.dwFileAttributes,
+                         self.data.dwReserved0 == c::IO_REPARSE_TAG_SYMLINK))
+    }
+
+    pub fn metadata(&self) -> io::Result<FileAttr> {
+        Ok(FileAttr {
+            data: c::WIN32_FILE_ATTRIBUTE_DATA {
+                dwFileAttributes: self.data.dwFileAttributes,
+                ftCreationTime: self.data.ftCreationTime,
+                ftLastAccessTime: self.data.ftLastAccessTime,
+                ftLastWriteTime: self.data.ftLastWriteTime,
+                nFileSizeHigh: self.data.nFileSizeHigh,
+                nFileSizeLow: self.data.nFileSizeLow,
+            },
+            is_symlink: self.data.dwReserved0 == c::IO_REPARSE_TAG_SYMLINK,
+        })
     }
 }
 
@@ -135,6 +170,9 @@ impl OpenOptions {
     pub fn share_mode(&mut self, val: i32) {
         self.share_mode = Some(val as libc::DWORD);
     }
+    pub fn security_attributes(&mut self, attrs: libc::LPSECURITY_ATTRIBUTES) {
+        self.security_attributes = attrs as usize;
+    }
 
     fn get_desired_access(&self) -> libc::DWORD {
         self.desired_access.unwrap_or({
@@ -180,13 +218,20 @@ impl OpenOptions {
 }
 
 impl File {
+    fn open_reparse_point(path: &Path) -> io::Result<File> {
+        let mut opts = OpenOptions::new();
+        opts.read(true);
+        opts.flags_and_attributes(c::FILE_FLAG_OPEN_REPARSE_POINT as i32);
+        File::open(path, &opts)
+    }
+
     pub fn open(path: &Path, opts: &OpenOptions) -> io::Result<File> {
         let path = to_utf16(path);
         let handle = unsafe {
             libc::CreateFileW(path.as_ptr(),
                               opts.get_desired_access(),
                               opts.get_share_mode(),
-                              ptr::null_mut(),
+                              opts.security_attributes as *mut _,
                               opts.get_creation_disposition(),
                               opts.get_flags_and_attributes(),
                               ptr::null_mut())
@@ -224,7 +269,7 @@ impl File {
             let mut info: c::BY_HANDLE_FILE_INFORMATION = mem::zeroed();
             try!(cvt(c::GetFileInformationByHandle(self.handle.raw(),
                                                    &mut info)));
-            Ok(FileAttr {
+            let mut attr = FileAttr {
                 data: c::WIN32_FILE_ATTRIBUTE_DATA {
                     dwFileAttributes: info.dwFileAttributes,
                     ftCreationTime: info.ftCreationTime,
@@ -232,8 +277,13 @@ impl File {
                     ftLastWriteTime: info.ftLastWriteTime,
                     nFileSizeHigh: info.nFileSizeHigh,
                     nFileSizeLow: info.nFileSizeLow,
-                }
-            })
+                },
+                is_symlink: false,
+            };
+            if attr.is_reparse_point() {
+                attr.is_symlink = self.is_symlink();
+            }
+            Ok(attr)
         }
     }
 
@@ -263,6 +313,43 @@ 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;
+
+        unsafe {
+            try!(cvt({
+                c::DeviceIoControl(self.handle.raw(),
+                                   c::FSCTL_GET_REPARSE_POINT,
+                                   0 as *mut _,
+                                   0,
+                                   space.as_mut_ptr() as *mut _,
+                                   space.len() as libc::DWORD,
+                                   &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"))
+            }
+            let info: *const c::SYMBOLIC_LINK_REPARSE_BUFFER =
+                    &(*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);
+            let subst_len = (*info).SubstituteNameLength / 2;
+            let subst = slice::from_raw_parts(subst_ptr, subst_len as usize);
+
+            Ok(PathBuf::from(OsString::from_wide(subst)))
+        }
+    }
+
+    pub fn into_handle(self) -> Handle { self.handle }
 }
 
 impl FromInner<libc::HANDLE> for File {
@@ -285,27 +372,30 @@ pub fn to_utf16(s: &Path) -> Vec<u16> {
 }
 
 impl FileAttr {
-    pub fn is_dir(&self) -> bool {
-        self.data.dwFileAttributes & c::FILE_ATTRIBUTE_DIRECTORY != 0
-    }
-    pub fn is_file(&self) -> bool {
-        !self.is_dir()
-    }
     pub fn size(&self) -> u64 {
         ((self.data.nFileSizeHigh as u64) << 32) | (self.data.nFileSizeLow as u64)
     }
+
     pub fn perm(&self) -> FilePermissions {
         FilePermissions { attrs: self.data.dwFileAttributes }
     }
 
-    pub fn accessed(&self) -> u64 { self.to_ms(&self.data.ftLastAccessTime) }
-    pub fn modified(&self) -> u64 { self.to_ms(&self.data.ftLastWriteTime) }
+    pub fn attrs(&self) -> u32 { self.data.dwFileAttributes as u32 }
 
-    fn to_ms(&self, ft: &libc::FILETIME) -> u64 {
-        // FILETIME is in 100ns intervals and there are 10000 intervals in a
-        // millisecond.
-        let bits = (ft.dwLowDateTime as u64) | ((ft.dwHighDateTime as u64) << 32);
-        bits / 10000
+    pub fn file_type(&self) -> FileType {
+        FileType::new(self.data.dwFileAttributes, self.is_symlink)
+    }
+
+    pub fn created(&self) -> u64 { self.to_u64(&self.data.ftCreationTime) }
+    pub fn accessed(&self) -> u64 { self.to_u64(&self.data.ftLastAccessTime) }
+    pub fn modified(&self) -> u64 { self.to_u64(&self.data.ftLastWriteTime) }
+
+    fn to_u64(&self, ft: &libc::FILETIME) -> u64 {
+        (ft.dwLowDateTime as u64) | ((ft.dwHighDateTime as u64) << 32)
+    }
+
+    fn is_reparse_point(&self) -> bool {
+        self.data.dwFileAttributes & libc::FILE_ATTRIBUTE_REPARSE_POINT != 0
     }
 }
 
@@ -323,12 +413,36 @@ impl FilePermissions {
     }
 }
 
-pub fn mkdir(p: &Path) -> io::Result<()> {
-    let p = to_utf16(p);
-    try!(cvt(unsafe {
-        libc::CreateDirectoryW(p.as_ptr(), ptr::null_mut())
-    }));
-    Ok(())
+impl FileType {
+    fn new(attrs: libc::DWORD, is_symlink: bool) -> FileType {
+        if attrs & libc::FILE_ATTRIBUTE_REPARSE_POINT != 0 {
+            if is_symlink {
+                FileType::Symlink
+            } else {
+                FileType::ReparsePoint
+            }
+        } else if attrs & c::FILE_ATTRIBUTE_DIRECTORY != 0 {
+            FileType::Dir
+        } else {
+            FileType::File
+        }
+    }
+
+    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 }
+}
+
+impl DirBuilder {
+    pub fn new() -> DirBuilder { DirBuilder }
+
+    pub fn mkdir(&self, p: &Path) -> io::Result<()> {
+        let p = to_utf16(p);
+        try!(cvt(unsafe {
+            libc::CreateDirectoryW(p.as_ptr(), ptr::null_mut())
+        }));
+        Ok(())
+    }
 }
 
 pub fn readdir(p: &Path) -> io::Result<ReadDir> {
@@ -374,40 +488,8 @@ pub fn rmdir(p: &Path) -> io::Result<()> {
 }
 
 pub fn readlink(p: &Path) -> io::Result<PathBuf> {
-    let mut opts = OpenOptions::new();
-    opts.read(true);
-    opts.flags_and_attributes(c::FILE_FLAG_OPEN_REPARSE_POINT as i32);
-    let file = try!(File::open(p, &opts));
-
-    let mut space = [0u8; c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE];
-    let mut bytes = 0;
-
-    unsafe {
-        try!(cvt({
-            c::DeviceIoControl(file.handle.raw(),
-                               c::FSCTL_GET_REPARSE_POINT,
-                               0 as *mut _,
-                               0,
-                               space.as_mut_ptr() as *mut _,
-                               space.len() as libc::DWORD,
-                               &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"))
-        }
-        let info: *const c::SYMBOLIC_LINK_REPARSE_BUFFER =
-                &(*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);
-        let subst_len = (*info).SubstituteNameLength / 2;
-        let subst = slice::from_raw_parts(subst_ptr, subst_len as usize);
-
-        Ok(PathBuf::from(OsString::from_wide(subst)))
-    }
-
+    let file = try!(File::open_reparse_point(p));
+    file.readlink()
 }
 
 pub fn symlink(src: &Path, dst: &Path) -> io::Result<()> {
@@ -435,12 +517,28 @@ pub fn link(src: &Path, dst: &Path) -> io::Result<()> {
 }
 
 pub fn stat(p: &Path) -> io::Result<FileAttr> {
-    let p = to_utf16(p);
+    let attr = try!(lstat(p));
+    if attr.data.dwFileAttributes & libc::FILE_ATTRIBUTE_REPARSE_POINT != 0 {
+        let opts = OpenOptions::new();
+        let file = try!(File::open(p, &opts));
+        file.file_attr()
+    } else {
+        Ok(attr)
+    }
+}
+
+pub fn lstat(p: &Path) -> io::Result<FileAttr> {
+    let utf16 = to_utf16(p);
     unsafe {
         let mut attr: FileAttr = mem::zeroed();
-        try!(cvt(c::GetFileAttributesExW(p.as_ptr(),
+        try!(cvt(c::GetFileAttributesExW(utf16.as_ptr(),
                                          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);
+        }
         Ok(attr)
     }
 }
@@ -465,3 +563,17 @@ 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));
+    super::fill_utf16_buf(|buf, sz| unsafe {
+        GetFinalPathNameByHandleW(f.handle.raw(), buf, sz,
+                                  libc::VOLUME_NAME_DOS)
+    }, |buf| {
+        PathBuf::from(OsString::from_wide(buf))
+    })
+}
diff --git a/src/libstd/sys/windows/handle.rs b/src/libstd/sys/windows/handle.rs
index c3a30aae9e0..9481e180ce5 100644
--- a/src/libstd/sys/windows/handle.rs
+++ b/src/libstd/sys/windows/handle.rs
@@ -12,6 +12,7 @@ use prelude::v1::*;
 
 use io::ErrorKind;
 use io;
+use libc::funcs::extra::kernel32::{GetCurrentProcess, DuplicateHandle};
 use libc::{self, HANDLE};
 use mem;
 use ptr;
@@ -65,6 +66,18 @@ impl Handle {
         }));
         Ok(amt as usize)
     }
+
+    pub fn duplicate(&self, access: libc::DWORD, inherit: bool,
+                     options: libc::DWORD) -> io::Result<Handle> {
+        let mut ret = 0 as libc::HANDLE;
+        try!(cvt(unsafe {
+            let cur_proc = GetCurrentProcess();
+            DuplicateHandle(cur_proc, self.0, cur_proc, &mut ret,
+                            access, inherit as libc::BOOL,
+                            options)
+        }));
+        Ok(Handle::new(ret))
+    }
 }
 
 impl Drop for Handle {
diff --git a/src/libstd/sys/windows/process2.rs b/src/libstd/sys/windows/process2.rs
index 2e5585d2f43..5aad5f668dd 100644
--- a/src/libstd/sys/windows/process2.rs
+++ b/src/libstd/sys/windows/process2.rs
@@ -13,17 +13,23 @@ use prelude::v1::*;
 use ascii::*;
 use collections::HashMap;
 use collections;
+use env::split_paths;
 use env;
 use ffi::{OsString, OsStr};
 use fmt;
 use fs;
 use io::{self, Error};
 use libc::{self, c_void};
+use mem;
 use os::windows::ffi::OsStrExt;
+use path::Path;
 use ptr;
 use sync::{StaticMutex, MUTEX_INIT};
+use sys::c;
+use sys::fs2::{OpenOptions, File};
 use sys::handle::Handle;
 use sys::pipe2::AnonPipe;
+use sys::stdio;
 use sys::{self, cvt};
 use sys_common::{AsInner, FromInner};
 
@@ -90,18 +96,12 @@ impl Command {
 // Processes
 ////////////////////////////////////////////////////////////////////////////////
 
-// `CreateProcess` is racy!
-// http://support.microsoft.com/kb/315939
-static CREATE_PROCESS_LOCK: StaticMutex = MUTEX_INIT;
-
 /// A value representing a child process.
 ///
 /// The lifetime of this value is linked to the lifetime of the actual
 /// process - the Process destructor calls self.finish() which waits
 /// for the process to terminate.
 pub struct Process {
-    /// A HANDLE to the process, which will prevent the pid being
-    /// re-used until the handle is closed.
     handle: Handle,
 }
 
@@ -112,32 +112,17 @@ pub enum Stdio {
 }
 
 impl Process {
-    #[allow(deprecated)]
     pub fn spawn(cfg: &Command,
-                 in_fd: Stdio,
-                 out_fd: Stdio,
-                 err_fd: Stdio) -> io::Result<Process>
+                 in_handle: Stdio,
+                 out_handle: Stdio,
+                 err_handle: Stdio) -> io::Result<Process>
     {
-        use libc::types::os::arch::extra::{DWORD, HANDLE, STARTUPINFO};
-        use libc::consts::os::extra::{
-            TRUE, FALSE,
-            STARTF_USESTDHANDLES,
-            INVALID_HANDLE_VALUE,
-            DUPLICATE_SAME_ACCESS
-        };
-        use libc::funcs::extra::kernel32::{
-            GetCurrentProcess,
-            DuplicateHandle,
-            CloseHandle,
-            CreateProcessW
-        };
-
-        use env::split_paths;
-        use mem;
-        use iter::Iterator;
-
-        // To have the spawning semantics of unix/windows stay the same, we need to
-        // read the *child's* PATH if one is provided. See #15149 for more details.
+        use libc::{TRUE, STARTF_USESTDHANDLES};
+        use libc::{DWORD, STARTUPINFO, CreateProcessW};
+
+        // To have the spawning semantics of unix/windows stay the same, we need
+        // to read the *child's* PATH if one is provided. See #15149 for more
+        // details.
         let program = cfg.env.as_ref().and_then(|env| {
             for (key, v) in env {
                 if OsStr::new("PATH") != &**key { continue }
@@ -156,118 +141,51 @@ impl Process {
             None
         });
 
-        unsafe {
-            let mut si = zeroed_startupinfo();
-            si.cb = mem::size_of::<STARTUPINFO>() as DWORD;
-            si.dwFlags = STARTF_USESTDHANDLES;
-
-            let cur_proc = GetCurrentProcess();
-
-            let set_fd = |fd: &Stdio, slot: &mut HANDLE,
-                          is_stdin: bool| {
-                match *fd {
-                    Stdio::Inherit => {}
-
-                    // Similarly to unix, we don't actually leave holes for the
-                    // stdio file descriptors, but rather open up /dev/null
-                    // equivalents. These equivalents are drawn from libuv's
-                    // windows process spawning.
-                    Stdio::None => {
-                        let access = if is_stdin {
-                            libc::FILE_GENERIC_READ
-                        } else {
-                            libc::FILE_GENERIC_WRITE | libc::FILE_READ_ATTRIBUTES
-                        };
-                        let size = mem::size_of::<libc::SECURITY_ATTRIBUTES>();
-                        let mut sa = libc::SECURITY_ATTRIBUTES {
-                            nLength: size as libc::DWORD,
-                            lpSecurityDescriptor: ptr::null_mut(),
-                            bInheritHandle: 1,
-                        };
-                        let mut filename: Vec<u16> = "NUL".utf16_units().collect();
-                        filename.push(0);
-                        *slot = libc::CreateFileW(filename.as_ptr(),
-                                                  access,
-                                                  libc::FILE_SHARE_READ |
-                                                      libc::FILE_SHARE_WRITE,
-                                                  &mut sa,
-                                                  libc::OPEN_EXISTING,
-                                                  0,
-                                                  ptr::null_mut());
-                        if *slot == INVALID_HANDLE_VALUE {
-                            return Err(Error::last_os_error())
-                        }
-                    }
-                    Stdio::Piped(ref pipe) => {
-                        let orig = pipe.handle().raw();
-                        if DuplicateHandle(cur_proc, orig, cur_proc, slot,
-                                           0, TRUE, DUPLICATE_SAME_ACCESS) == FALSE {
-                            return Err(Error::last_os_error())
-                        }
-                    }
-                }
-                Ok(())
-            };
-
-            try!(set_fd(&in_fd, &mut si.hStdInput, true));
-            try!(set_fd(&out_fd, &mut si.hStdOutput, false));
-            try!(set_fd(&err_fd, &mut si.hStdError, false));
+        let mut si = zeroed_startupinfo();
+        si.cb = mem::size_of::<STARTUPINFO>() as DWORD;
+        si.dwFlags = STARTF_USESTDHANDLES;
 
-            let mut cmd_str = make_command_line(program.as_ref().unwrap_or(&cfg.program),
-                                            &cfg.args);
-            cmd_str.push(0); // add null terminator
+        let stdin = try!(in_handle.to_handle(c::STD_INPUT_HANDLE));
+        let stdout = try!(out_handle.to_handle(c::STD_OUTPUT_HANDLE));
+        let stderr = try!(err_handle.to_handle(c::STD_ERROR_HANDLE));
 
-            let mut pi = zeroed_process_information();
-            let mut create_err = None;
-
-            // stolen from the libuv code.
-            let mut flags = libc::CREATE_UNICODE_ENVIRONMENT;
-            if cfg.detach {
-                flags |= libc::DETACHED_PROCESS | libc::CREATE_NEW_PROCESS_GROUP;
-            }
+        si.hStdInput = stdin.raw();
+        si.hStdOutput = stdout.raw();
+        si.hStdError = stderr.raw();
 
-            with_envp(cfg.env.as_ref(), |envp| {
-                with_dirp(cfg.cwd.as_ref(), |dirp| {
-                    let _lock = CREATE_PROCESS_LOCK.lock().unwrap();
-                    let created = CreateProcessW(ptr::null(),
-                                                 cmd_str.as_mut_ptr(),
-                                                 ptr::null_mut(),
-                                                 ptr::null_mut(),
-                                                 TRUE,
-                                                 flags, envp, dirp,
-                                                 &mut si, &mut pi);
-                    if created == FALSE {
-                        create_err = Some(Error::last_os_error());
-                    }
-                })
-            });
+        let program = program.as_ref().unwrap_or(&cfg.program);
+        let mut cmd_str = make_command_line(program, &cfg.args);
+        cmd_str.push(0); // add null terminator
 
-            if !in_fd.inherited() {
-                assert!(CloseHandle(si.hStdInput) != 0);
-            }
-            if !out_fd.inherited() {
-                assert!(CloseHandle(si.hStdOutput) != 0);
-            }
-            if !err_fd.inherited() {
-                assert!(CloseHandle(si.hStdError) != 0);
-            }
+        // stolen from the libuv code.
+        let mut flags = libc::CREATE_UNICODE_ENVIRONMENT;
+        if cfg.detach {
+            flags |= libc::DETACHED_PROCESS | libc::CREATE_NEW_PROCESS_GROUP;
+        }
 
-            match create_err {
-                Some(err) => return Err(err),
-                None => {}
-            }
+        let (envp, _data) = make_envp(cfg.env.as_ref());
+        let (dirp, _data) = make_dirp(cfg.cwd.as_ref());
+        let mut pi = zeroed_process_information();
+        try!(unsafe {
+            // `CreateProcess` is racy!
+            // http://support.microsoft.com/kb/315939
+            static CREATE_PROCESS_LOCK: StaticMutex = MUTEX_INIT;
+            let _lock = CREATE_PROCESS_LOCK.lock();
+
+            cvt(CreateProcessW(ptr::null(),
+                               cmd_str.as_mut_ptr(),
+                               ptr::null_mut(),
+                               ptr::null_mut(),
+                               TRUE, flags, envp, dirp,
+                               &mut si, &mut pi))
+        });
 
-            // We close the thread handle because we don't care about keeping the
-            // thread id valid, and we aren't keeping the thread handle around to be
-            // able to close it later. We don't close the process handle however
-            // because std::we want the process id to stay valid at least until the
-            // calling code closes the process handle.
-            assert!(CloseHandle(pi.hThread) != 0);
+        // We close the thread handle because we don't care about keeping
+        // the thread id valid, and we aren't keeping the thread handle
+        // around to be able to close it later.
+        drop(Handle::new(pi.hThread));
 
-            Ok(Process {
-                handle: Handle::new(pi.hProcess)
-            })
-        }
+        Ok(Process { handle: Handle::new(pi.hProcess) })
     }
 
     pub unsafe fn kill(&self) -> io::Result<()> {
@@ -276,45 +194,25 @@ impl Process {
     }
 
     pub fn wait(&self) -> io::Result<ExitStatus> {
-        use libc::consts::os::extra::{
-            FALSE,
-            STILL_ACTIVE,
-            INFINITE,
-            WAIT_OBJECT_0,
-        };
-        use libc::funcs::extra::kernel32::{
-            GetExitCodeProcess,
-            WaitForSingleObject,
-        };
+        use libc::{STILL_ACTIVE, INFINITE, WAIT_OBJECT_0};
+        use libc::{GetExitCodeProcess, WaitForSingleObject};
 
         unsafe {
             loop {
                 let mut status = 0;
-                if GetExitCodeProcess(self.handle.raw(), &mut status) == FALSE {
-                    let err = Err(Error::last_os_error());
-                    return err;
-                }
+                try!(cvt(GetExitCodeProcess(self.handle.raw(), &mut status)));
                 if status != STILL_ACTIVE {
                     return Ok(ExitStatus(status as i32));
                 }
                 match WaitForSingleObject(self.handle.raw(), INFINITE) {
                     WAIT_OBJECT_0 => {}
-                    _ => {
-                        let err = Err(Error::last_os_error());
-                        return err
-                    }
+                    _ => return Err(Error::last_os_error()),
                 }
             }
         }
     }
 }
 
-impl Stdio {
-    fn inherited(&self) -> bool {
-        match *self { Stdio::Inherit => true, _ => false }
-    }
-}
-
 #[derive(PartialEq, Eq, Clone, Copy, Debug)]
 pub struct ExitStatus(i32);
 
@@ -415,9 +313,8 @@ fn make_command_line(prog: &OsStr, args: &[OsString]) -> Vec<u16> {
     }
 }
 
-fn with_envp<F, T>(env: Option<&collections::HashMap<OsString, OsString>>, cb: F) -> T
-    where F: FnOnce(*mut c_void) -> T,
-{
+fn make_envp(env: Option<&collections::HashMap<OsString, OsString>>)
+             -> (*mut c_void, Vec<u16>) {
     // On Windows we pass an "environment block" which is not a char**, but
     // rather a concatenation of null-terminated k=v\0 sequences, with a final
     // \0 to terminate.
@@ -432,22 +329,57 @@ fn with_envp<F, T>(env: Option<&collections::HashMap<OsString, OsString>>, cb: F
                 blk.push(0);
             }
             blk.push(0);
-            cb(blk.as_mut_ptr() as *mut c_void)
+            (blk.as_mut_ptr() as *mut c_void, blk)
         }
-        _ => cb(ptr::null_mut())
+        _ => (ptr::null_mut(), Vec::new())
     }
 }
 
-fn with_dirp<T, F>(d: Option<&OsString>, cb: F) -> T where
-    F: FnOnce(*const u16) -> T,
-{
+fn make_dirp(d: Option<&OsString>) -> (*const u16, Vec<u16>) {
     match d {
-      Some(dir) => {
-          let mut dir_str: Vec<u16> = dir.encode_wide().collect();
-          dir_str.push(0);
-          cb(dir_str.as_ptr())
-      },
-      None => cb(ptr::null())
+        Some(dir) => {
+            let mut dir_str: Vec<u16> = dir.encode_wide().collect();
+            dir_str.push(0);
+            (dir_str.as_ptr(), dir_str)
+        },
+        None => (ptr::null(), Vec::new())
+    }
+}
+
+impl Stdio {
+    fn to_handle(&self, stdio_id: libc::DWORD) -> io::Result<Handle> {
+        use libc::DUPLICATE_SAME_ACCESS;
+
+        match *self {
+            Stdio::Inherit => {
+                stdio::get(stdio_id).and_then(|io| {
+                    io.handle().duplicate(0, true, DUPLICATE_SAME_ACCESS)
+                })
+            }
+            Stdio::Piped(ref pipe) => {
+                pipe.handle().duplicate(0, true, DUPLICATE_SAME_ACCESS)
+            }
+
+            // Similarly to unix, we don't actually leave holes for the
+            // stdio file descriptors, but rather open up /dev/null
+            // equivalents. These equivalents are drawn from libuv's
+            // windows process spawning.
+            Stdio::None => {
+                let size = mem::size_of::<libc::SECURITY_ATTRIBUTES>();
+                let mut sa = libc::SECURITY_ATTRIBUTES {
+                    nLength: size as libc::DWORD,
+                    lpSecurityDescriptor: ptr::null_mut(),
+                    bInheritHandle: 1,
+                };
+                let mut opts = OpenOptions::new();
+                opts.read(stdio_id == c::STD_INPUT_HANDLE);
+                opts.write(stdio_id != c::STD_INPUT_HANDLE);
+                opts.security_attributes(&mut sa);
+                File::open(Path::new("NUL"), &opts).map(|file| {
+                    file.into_handle()
+                })
+            }
+        }
     }
 }
 
diff --git a/src/libstd/sys/windows/stdio.rs b/src/libstd/sys/windows/stdio.rs
index 91f6f328ff6..03547165f5d 100644
--- a/src/libstd/sys/windows/stdio.rs
+++ b/src/libstd/sys/windows/stdio.rs
@@ -21,9 +21,9 @@ use sys::c;
 use sys::cvt;
 use sys::handle::Handle;
 
-struct NoClose(Option<Handle>);
+pub struct NoClose(Option<Handle>);
 
-enum Output {
+pub enum Output {
     Console(NoClose),
     Pipe(NoClose),
 }
@@ -35,7 +35,7 @@ pub struct Stdin {
 pub struct Stdout(Output);
 pub struct Stderr(Output);
 
-fn get(handle: libc::DWORD) -> io::Result<Output> {
+pub fn get(handle: libc::DWORD) -> io::Result<Output> {
     let handle = unsafe { c::GetStdHandle(handle) };
     if handle == libc::INVALID_HANDLE_VALUE {
         Err(io::Error::last_os_error())
@@ -159,6 +159,16 @@ impl Drop for NoClose {
     }
 }
 
+impl Output {
+    pub fn handle(&self) -> &Handle {
+        let nc = match *self {
+            Output::Console(ref c) => c,
+            Output::Pipe(ref c) => c,
+        };
+        nc.0.as_ref().unwrap()
+    }
+}
+
 fn invalid_encoding() -> io::Error {
     io::Error::new(io::ErrorKind::InvalidInput, "text was not valid unicode")
 }