about summary refs log tree commit diff
diff options
context:
space:
mode:
authorAaron Turon <aturon@mozilla.com>2014-09-30 17:03:56 -0700
committerAaron Turon <aturon@mozilla.com>2014-11-08 20:40:38 -0800
commit3a527f2b3311d5b1c6dd7c72db71c45596e6db49 (patch)
tree1a550dd4b679b0ccf13acef6cc7879e486a3d3de
parent93c85eb8bdcc910a27caf6abd20207a626ae98e5 (diff)
downloadrust-3a527f2b3311d5b1c6dd7c72db71c45596e6db49.tar.gz
rust-3a527f2b3311d5b1c6dd7c72db71c45596e6db49.zip
Runtime removal: add private sys, sys_common modules
These modules will house the code that used to be part of the runtime system
in libnative. The `sys_common` module contains a few low-level but
cross-platform details. The `sys` module is set up using `#[cfg()]` to
include either a unix or windows implementation of a common API
surface. This API surface is *not* exported directly in `libstd`, but is
instead used to bulid `std::os` and `std::io`.

Ultimately, the low-level details in `sys` will be exposed in a
controlled way through a separate platform-specific surface, but that
setup is not part of this patch.
-rw-r--r--src/libnative/io/mod.rs3
-rw-r--r--src/libnative/io/util.rs209
-rw-r--r--src/libstd/io/mod.rs92
-rw-r--r--src/libstd/lib.rs7
-rw-r--r--src/libstd/os.rs155
-rw-r--r--src/libstd/sys/common/mod.rs91
-rw-r--r--src/libstd/sys/unix/c.rs (renamed from src/libnative/io/c_unix.rs)3
-rw-r--r--src/libstd/sys/unix/mod.rs92
-rw-r--r--src/libstd/sys/unix/os.rs101
-rw-r--r--src/libstd/sys/windows/c.rs (renamed from src/libnative/io/c_windows.rs)14
-rw-r--r--src/libstd/sys/windows/mod.rs178
-rw-r--r--src/libstd/sys/windows/os.rs103
12 files changed, 592 insertions, 456 deletions
diff --git a/src/libnative/io/mod.rs b/src/libnative/io/mod.rs
index 954f7bbc59a..90f8f6c214e 100644
--- a/src/libnative/io/mod.rs
+++ b/src/libnative/io/mod.rs
@@ -73,9 +73,6 @@ pub mod pipe;
 #[path = "tty_windows.rs"]
 mod tty;
 
-#[cfg(unix)]    #[path = "c_unix.rs"]  mod c;
-#[cfg(windows)] #[path = "c_windows.rs"] mod c;
-
 fn unimpl() -> IoError {
     #[cfg(unix)] use libc::ENOSYS as ERROR;
     #[cfg(windows)] use libc::ERROR_CALL_NOT_IMPLEMENTED as ERROR;
diff --git a/src/libnative/io/util.rs b/src/libnative/io/util.rs
deleted file mode 100644
index 5f69ec00cdd..00000000000
--- a/src/libnative/io/util.rs
+++ /dev/null
@@ -1,209 +0,0 @@
-// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-use libc;
-use std::cmp;
-use std::mem;
-use std::os;
-use std::ptr;
-use std::rt::rtio::{IoResult, IoError};
-
-use super::c;
-use super::net;
-use super::{retry, last_error};
-
-#[deriving(Show)]
-pub enum SocketStatus {
-    Readable,
-    Writable,
-}
-
-pub fn timeout(desc: &'static str) -> IoError {
-    #[cfg(unix)] use libc::ETIMEDOUT as ERROR;
-    #[cfg(windows)] use libc::ERROR_OPERATION_ABORTED as ERROR;
-    IoError {
-        code: ERROR as uint,
-        extra: 0,
-        detail: Some(desc.to_string()),
-    }
-}
-
-pub fn short_write(n: uint, desc: &'static str) -> IoError {
-    #[cfg(unix)] use libc::EAGAIN as ERROR;
-    #[cfg(windows)] use libc::ERROR_OPERATION_ABORTED as ERROR;
-    IoError {
-        code: ERROR as uint,
-        extra: n,
-        detail: Some(desc.to_string()),
-    }
-}
-
-pub fn eof() -> IoError {
-    IoError {
-        code: libc::EOF as uint,
-        extra: 0,
-        detail: None,
-    }
-}
-
-#[cfg(windows)]
-pub fn ms_to_timeval(ms: u64) -> libc::timeval {
-    libc::timeval {
-        tv_sec: (ms / 1000) as libc::c_long,
-        tv_usec: ((ms % 1000) * 1000) as libc::c_long,
-    }
-}
-#[cfg(not(windows))]
-pub fn ms_to_timeval(ms: u64) -> libc::timeval {
-    libc::timeval {
-        tv_sec: (ms / 1000) as libc::time_t,
-        tv_usec: ((ms % 1000) * 1000) as libc::suseconds_t,
-    }
-}
-
-#[cfg(unix)]
-pub fn wouldblock() -> bool {
-    let err = os::errno();
-    err == libc::EWOULDBLOCK as int || err == libc::EAGAIN as int
-}
-
-#[cfg(windows)]
-pub fn wouldblock() -> bool {
-    let err = os::errno();
-    err == libc::WSAEWOULDBLOCK as uint
-}
-
-#[cfg(unix)]
-pub fn set_nonblocking(fd: net::sock_t, nb: bool) -> IoResult<()> {
-    let set = nb as libc::c_int;
-    super::mkerr_libc(retry(|| unsafe { c::ioctl(fd, c::FIONBIO, &set) }))
-}
-
-#[cfg(windows)]
-pub fn set_nonblocking(fd: net::sock_t, nb: bool) -> IoResult<()> {
-    let mut set = nb as libc::c_ulong;
-    if unsafe { c::ioctlsocket(fd, c::FIONBIO, &mut set) != 0 } {
-        Err(last_error())
-    } else {
-        Ok(())
-    }
-}
-
-// See http://developerweb.net/viewtopic.php?id=3196 for where this is
-// derived from.
-pub fn connect_timeout(fd: net::sock_t,
-                       addrp: *const libc::sockaddr,
-                       len: libc::socklen_t,
-                       timeout_ms: u64) -> IoResult<()> {
-    use std::os;
-    #[cfg(unix)]    use libc::EINPROGRESS as INPROGRESS;
-    #[cfg(windows)] use libc::WSAEINPROGRESS as INPROGRESS;
-    #[cfg(unix)]    use libc::EWOULDBLOCK as WOULDBLOCK;
-    #[cfg(windows)] use libc::WSAEWOULDBLOCK as WOULDBLOCK;
-
-    // Make sure the call to connect() doesn't block
-    try!(set_nonblocking(fd, true));
-
-    let ret = match unsafe { libc::connect(fd, addrp, len) } {
-        // If the connection is in progress, then we need to wait for it to
-        // finish (with a timeout). The current strategy for doing this is
-        // to use select() with a timeout.
-        -1 if os::errno() as int == INPROGRESS as int ||
-              os::errno() as int == WOULDBLOCK as int => {
-            let mut set: c::fd_set = unsafe { mem::zeroed() };
-            c::fd_set(&mut set, fd);
-            match await(fd, &mut set, timeout_ms) {
-                0 => Err(timeout("connection timed out")),
-                -1 => Err(last_error()),
-                _ => {
-                    let err: libc::c_int = try!(
-                        net::getsockopt(fd, libc::SOL_SOCKET, libc::SO_ERROR));
-                    if err == 0 {
-                        Ok(())
-                    } else {
-                        Err(IoError {
-                            code: err as uint,
-                            extra: 0,
-                            detail: Some(os::error_string(err as uint)),
-                        })
-                    }
-                }
-            }
-        }
-
-        -1 => Err(last_error()),
-        _ => Ok(()),
-    };
-
-    // be sure to turn blocking I/O back on
-    try!(set_nonblocking(fd, false));
-    return ret;
-
-    #[cfg(unix)]
-    fn await(fd: net::sock_t, set: &mut c::fd_set,
-             timeout: u64) -> libc::c_int {
-        let start = ::io::timer::now();
-        retry(|| unsafe {
-            // Recalculate the timeout each iteration (it is generally
-            // undefined what the value of the 'tv' is after select
-            // returns EINTR).
-            let mut tv = ms_to_timeval(timeout - (::io::timer::now() - start));
-            c::select(fd + 1, ptr::null_mut(), set as *mut _,
-                      ptr::null_mut(), &mut tv)
-        })
-    }
-    #[cfg(windows)]
-    fn await(_fd: net::sock_t, set: &mut c::fd_set,
-             timeout: u64) -> libc::c_int {
-        let mut tv = ms_to_timeval(timeout);
-        unsafe { c::select(1, ptr::null_mut(), set, ptr::null_mut(), &mut tv) }
-    }
-}
-
-pub fn await(fds: &[net::sock_t], deadline: Option<u64>,
-             status: SocketStatus) -> IoResult<()> {
-    let mut set: c::fd_set = unsafe { mem::zeroed() };
-    let mut max = 0;
-    for &fd in fds.iter() {
-        c::fd_set(&mut set, fd);
-        max = cmp::max(max, fd + 1);
-    }
-    if cfg!(windows) {
-        max = fds.len() as net::sock_t;
-    }
-
-    let (read, write) = match status {
-        Readable => (&mut set as *mut _, ptr::null_mut()),
-        Writable => (ptr::null_mut(), &mut set as *mut _),
-    };
-    let mut tv: libc::timeval = unsafe { mem::zeroed() };
-
-    match retry(|| {
-        let now = ::io::timer::now();
-        let tvp = match deadline {
-            None => ptr::null_mut(),
-            Some(deadline) => {
-                // If we're past the deadline, then pass a 0 timeout to
-                // select() so we can poll the status
-                let ms = if deadline < now {0} else {deadline - now};
-                tv = ms_to_timeval(ms);
-                &mut tv as *mut _
-            }
-        };
-        let r = unsafe {
-            c::select(max as libc::c_int, read, write, ptr::null_mut(), tvp)
-        };
-        r
-    }) {
-        -1 => Err(last_error()),
-        0 => Err(timeout("timed out")),
-        _ => Ok(()),
-    }
-}
diff --git a/src/libstd/io/mod.rs b/src/libstd/io/mod.rs
index c404741b7c3..78abbb9f80d 100644
--- a/src/libstd/io/mod.rs
+++ b/src/libstd/io/mod.rs
@@ -236,8 +236,7 @@ use os;
 use boxed::Box;
 use result::{Ok, Err, Result};
 use rt::rtio;
-use slice::{AsSlice, SlicePrelude};
-use str::{Str, StrPrelude};
+use sys;
 use str;
 use string::String;
 use uint;
@@ -312,91 +311,10 @@ impl IoError {
     /// struct is filled with an allocated string describing the error
     /// in more detail, retrieved from the operating system.
     pub fn from_errno(errno: uint, detail: bool) -> IoError {
-
-        #[cfg(windows)]
-        fn get_err(errno: i32) -> (IoErrorKind, &'static str) {
-            match errno {
-                libc::EOF => (EndOfFile, "end of file"),
-                libc::ERROR_NO_DATA => (BrokenPipe, "the pipe is being closed"),
-                libc::ERROR_FILE_NOT_FOUND => (FileNotFound, "file not found"),
-                libc::ERROR_INVALID_NAME => (InvalidInput, "invalid file name"),
-                libc::WSAECONNREFUSED => (ConnectionRefused, "connection refused"),
-                libc::WSAECONNRESET => (ConnectionReset, "connection reset"),
-                libc::ERROR_ACCESS_DENIED | libc::WSAEACCES =>
-                    (PermissionDenied, "permission denied"),
-                libc::WSAEWOULDBLOCK => {
-                    (ResourceUnavailable, "resource temporarily unavailable")
-                }
-                libc::WSAENOTCONN => (NotConnected, "not connected"),
-                libc::WSAECONNABORTED => (ConnectionAborted, "connection aborted"),
-                libc::WSAEADDRNOTAVAIL => (ConnectionRefused, "address not available"),
-                libc::WSAEADDRINUSE => (ConnectionRefused, "address in use"),
-                libc::ERROR_BROKEN_PIPE => (EndOfFile, "the pipe has ended"),
-                libc::ERROR_OPERATION_ABORTED =>
-                    (TimedOut, "operation timed out"),
-                libc::WSAEINVAL => (InvalidInput, "invalid argument"),
-                libc::ERROR_CALL_NOT_IMPLEMENTED =>
-                    (IoUnavailable, "function not implemented"),
-                libc::ERROR_INVALID_HANDLE =>
-                    (MismatchedFileTypeForOperation,
-                     "invalid handle provided to function"),
-                libc::ERROR_NOTHING_TO_TERMINATE =>
-                    (InvalidInput, "no process to kill"),
-
-                // libuv maps this error code to EISDIR. we do too. if it is found
-                // to be incorrect, we can add in some more machinery to only
-                // return this message when ERROR_INVALID_FUNCTION after certain
-                // Windows calls.
-                libc::ERROR_INVALID_FUNCTION => (InvalidInput,
-                                                 "illegal operation on a directory"),
-
-                _ => (OtherIoError, "unknown error")
-            }
-        }
-
-        #[cfg(not(windows))]
-        fn get_err(errno: i32) -> (IoErrorKind, &'static str) {
-            // FIXME: this should probably be a bit more descriptive...
-            match errno {
-                libc::EOF => (EndOfFile, "end of file"),
-                libc::ECONNREFUSED => (ConnectionRefused, "connection refused"),
-                libc::ECONNRESET => (ConnectionReset, "connection reset"),
-                libc::EPERM | libc::EACCES =>
-                    (PermissionDenied, "permission denied"),
-                libc::EPIPE => (BrokenPipe, "broken pipe"),
-                libc::ENOTCONN => (NotConnected, "not connected"),
-                libc::ECONNABORTED => (ConnectionAborted, "connection aborted"),
-                libc::EADDRNOTAVAIL => (ConnectionRefused, "address not available"),
-                libc::EADDRINUSE => (ConnectionRefused, "address in use"),
-                libc::ENOENT => (FileNotFound, "no such file or directory"),
-                libc::EISDIR => (InvalidInput, "illegal operation on a directory"),
-                libc::ENOSYS => (IoUnavailable, "function not implemented"),
-                libc::EINVAL => (InvalidInput, "invalid argument"),
-                libc::ENOTTY =>
-                    (MismatchedFileTypeForOperation,
-                     "file descriptor is not a TTY"),
-                libc::ETIMEDOUT => (TimedOut, "operation timed out"),
-                libc::ECANCELED => (TimedOut, "operation aborted"),
-
-                // These two constants can have the same value on some systems,
-                // but different values on others, so we can't use a match
-                // clause
-                x if x == libc::EAGAIN || x == libc::EWOULDBLOCK =>
-                    (ResourceUnavailable, "resource temporarily unavailable"),
-
-                _ => (OtherIoError, "unknown error")
-            }
-        }
-
-        let (kind, desc) = get_err(errno as i32);
-        IoError {
-            kind: kind,
-            desc: desc,
-            detail: if detail && kind == OtherIoError {
-                Some(os::error_string(errno).as_slice().chars().map(|c| c.to_lowercase()).collect())
-            } else {
-                None
-            },
+        let mut err = sys::decode_error(errno as i32);
+        if detail && err.kind == OtherIoError {
+            err.detail = Some(os::error_string(errno).as_slice().chars()
+                                 .map(|c| c.to_lowercase()).collect())
         }
     }
 
diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs
index f10a1d5e5ed..7eac455f97f 100644
--- a/src/libstd/lib.rs
+++ b/src/libstd/lib.rs
@@ -242,6 +242,13 @@ pub mod io;
 pub mod path;
 pub mod fmt;
 
+#[cfg(unix)]
+#[path = "sys/unix/mod.rs"] mod sys;
+#[cfg(windows)]
+#[path = "sys/windows/mod.rs"] mod sys;
+
+#[path = "sys/common/mod.rs"] mod sys_common;
+
 // FIXME #7809: This shouldn't be pub, and it should be reexported under 'unstable'
 // but name resolution doesn't work without it being pub.
 pub mod rt;
diff --git a/src/libstd/os.rs b/src/libstd/os.rs
index 0042a3ae205..175e23bf819 100644
--- a/src/libstd/os.rs
+++ b/src/libstd/os.rs
@@ -34,7 +34,7 @@
 use clone::Clone;
 use error::{FromError, Error};
 use fmt;
-use io::{IoResult, IoError};
+use io::IoResult;
 use iter::Iterator;
 use libc::{c_void, c_int};
 use libc;
@@ -43,6 +43,7 @@ use ops::Drop;
 use option::{Some, None, Option};
 use os;
 use path::{Path, GenericPath, BytesContainer};
+use sys::os as os_imp;
 use ptr::RawPtr;
 use ptr;
 use result::{Err, Ok, Result};
@@ -905,59 +906,9 @@ pub fn change_dir(p: &Path) -> bool {
     }
 }
 
-#[cfg(unix)]
-/// Returns the platform-specific value of errno
-pub fn errno() -> int {
-    #[cfg(any(target_os = "macos",
-              target_os = "ios",
-              target_os = "freebsd"))]
-    fn errno_location() -> *const c_int {
-        extern {
-            fn __error() -> *const c_int;
-        }
-        unsafe {
-            __error()
-        }
-    }
-
-    #[cfg(target_os = "dragonfly")]
-    fn errno_location() -> *const c_int {
-        extern {
-            fn __dfly_error() -> *const c_int;
-        }
-        unsafe {
-            __dfly_error()
-        }
-    }
-
-    #[cfg(any(target_os = "linux", target_os = "android"))]
-    fn errno_location() -> *const c_int {
-        extern {
-            fn __errno_location() -> *const c_int;
-        }
-        unsafe {
-            __errno_location()
-        }
-    }
-
-    unsafe {
-        (*errno_location()) as int
-    }
-}
-
-#[cfg(windows)]
 /// Returns the platform-specific value of errno
 pub fn errno() -> uint {
-    use libc::types::os::arch::extra::DWORD;
-
-    #[link_name = "kernel32"]
-    extern "system" {
-        fn GetLastError() -> DWORD;
-    }
-
-    unsafe {
-        GetLastError() as uint
-    }
+    os_imp::errno() as uint
 }
 
 /// Return the string corresponding to an `errno()` value of `errnum`.
@@ -969,105 +920,7 @@ pub fn errno() -> uint {
 /// println!("{}", os::error_string(os::errno() as uint));
 /// ```
 pub fn error_string(errnum: uint) -> String {
-    return strerror(errnum);
-
-    #[cfg(unix)]
-    fn strerror(errnum: uint) -> String {
-        #[cfg(any(target_os = "macos",
-                  target_os = "ios",
-                  target_os = "android",
-                  target_os = "freebsd",
-                  target_os = "dragonfly"))]
-        fn strerror_r(errnum: c_int, buf: *mut c_char, buflen: libc::size_t)
-                      -> c_int {
-            extern {
-                fn strerror_r(errnum: c_int, buf: *mut c_char,
-                              buflen: libc::size_t) -> c_int;
-            }
-            unsafe {
-                strerror_r(errnum, buf, buflen)
-            }
-        }
-
-        // GNU libc provides a non-compliant version of strerror_r by default
-        // and requires macros to instead use the POSIX compliant variant.
-        // So we just use __xpg_strerror_r which is always POSIX compliant
-        #[cfg(target_os = "linux")]
-        fn strerror_r(errnum: c_int, buf: *mut c_char,
-                      buflen: libc::size_t) -> c_int {
-            extern {
-                fn __xpg_strerror_r(errnum: c_int,
-                                    buf: *mut c_char,
-                                    buflen: libc::size_t)
-                                    -> c_int;
-            }
-            unsafe {
-                __xpg_strerror_r(errnum, buf, buflen)
-            }
-        }
-
-        let mut buf = [0 as c_char, ..TMPBUF_SZ];
-
-        let p = buf.as_mut_ptr();
-        unsafe {
-            if strerror_r(errnum as c_int, p, buf.len() as libc::size_t) < 0 {
-                panic!("strerror_r failure");
-            }
-
-            ::string::raw::from_buf(p as *const u8)
-        }
-    }
-
-    #[cfg(windows)]
-    fn strerror(errnum: uint) -> String {
-        use libc::types::os::arch::extra::DWORD;
-        use libc::types::os::arch::extra::LPWSTR;
-        use libc::types::os::arch::extra::LPVOID;
-        use libc::types::os::arch::extra::WCHAR;
-
-        #[link_name = "kernel32"]
-        extern "system" {
-            fn FormatMessageW(flags: DWORD,
-                              lpSrc: LPVOID,
-                              msgId: DWORD,
-                              langId: DWORD,
-                              buf: LPWSTR,
-                              nsize: DWORD,
-                              args: *const c_void)
-                              -> DWORD;
-        }
-
-        static FORMAT_MESSAGE_FROM_SYSTEM: DWORD = 0x00001000;
-        static FORMAT_MESSAGE_IGNORE_INSERTS: DWORD = 0x00000200;
-
-        // This value is calculated from the macro
-        // MAKELANGID(LANG_SYSTEM_DEFAULT, SUBLANG_SYS_DEFAULT)
-        let langId = 0x0800 as DWORD;
-
-        let mut buf = [0 as WCHAR, ..TMPBUF_SZ];
-
-        unsafe {
-            let res = FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM |
-                                     FORMAT_MESSAGE_IGNORE_INSERTS,
-                                     ptr::null_mut(),
-                                     errnum as DWORD,
-                                     langId,
-                                     buf.as_mut_ptr(),
-                                     buf.len() as DWORD,
-                                     ptr::null());
-            if res == 0 {
-                // Sometimes FormatMessageW can fail e.g. system doesn't like langId,
-                let fm_err = errno();
-                return format!("OS Error {} (FormatMessageW() returned error {})", errnum, fm_err);
-            }
-
-            let msg = String::from_utf16(::str::truncate_utf16_at_nul(buf));
-            match msg {
-                Some(msg) => format!("OS Error {}: {}", errnum, msg),
-                None => format!("OS Error {} (FormatMessageW() returned invalid UTF-16)", errnum),
-            }
-        }
-    }
+    return os_imp::error_string(errnum as i32);
 }
 
 /// Get a string representing the platform-dependent last error
diff --git a/src/libstd/sys/common/mod.rs b/src/libstd/sys/common/mod.rs
new file mode 100644
index 00000000000..402c62bb35e
--- /dev/null
+++ b/src/libstd/sys/common/mod.rs
@@ -0,0 +1,91 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![allow(missing_doc)]
+#![allow(dead_code)]
+
+use io::{mod, IoError, IoResult};
+use prelude::*;
+use num;
+use sys::{last_error, retry, fs};
+use c_str::CString;
+use path::BytesContainer;
+use collections;
+
+pub mod net;
+
+// common error constructors
+
+pub fn eof() -> IoError {
+    IoError {
+        kind: io::EndOfFile,
+        desc: "end of file",
+        detail: None,
+    }
+}
+
+pub fn timeout(desc: &'static str) -> IoError {
+    IoError {
+        kind: io::TimedOut,
+        desc: desc,
+        detail: None,
+    }
+}
+
+pub fn short_write(n: uint, desc: &'static str) -> IoError {
+    IoError {
+        kind: if n == 0 { io::TimedOut } else { io::ShortWrite(n) },
+        desc: desc,
+        detail: None,
+    }
+}
+
+// unix has nonzero values as errors
+pub fn mkerr_libc<Int: num::Zero>(ret: Int) -> IoResult<()> {
+    if !ret.is_zero() {
+        Err(last_error())
+    } else {
+        Ok(())
+    }
+}
+
+pub fn keep_going(data: &[u8], f: |*const u8, uint| -> i64) -> i64 {
+    let origamt = data.len();
+    let mut data = data.as_ptr();
+    let mut amt = origamt;
+    while amt > 0 {
+        let ret = retry(|| f(data, amt));
+        if ret == 0 {
+            break
+        } else if ret != -1 {
+            amt -= ret as uint;
+            data = unsafe { data.offset(ret as int) };
+        } else {
+            return ret;
+        }
+    }
+    return (origamt - amt) as i64;
+}
+
+// traits for extracting representations from
+
+pub trait AsFileDesc {
+    fn as_fd(&self) -> &fs::FileDesc;
+}
+
+pub trait ProcessConfig<K: BytesContainer, V: BytesContainer> {
+    fn program(&self) -> &CString;
+    fn args(&self) -> &[CString];
+    fn env(&self) -> Option<&collections::HashMap<K, V>>;
+    fn cwd(&self) -> Option<&CString>;
+    fn uid(&self) -> Option<uint>;
+    fn gid(&self) -> Option<uint>;
+    fn detach(&self) -> bool;
+}
diff --git a/src/libnative/io/c_unix.rs b/src/libstd/sys/unix/c.rs
index f1757d367c3..e76f2a2b872 100644
--- a/src/libnative/io/c_unix.rs
+++ b/src/libstd/sys/unix/c.rs
@@ -11,6 +11,7 @@
 //! C definitions used by libnative that don't belong in liblibc
 
 #![allow(dead_code)]
+#![allow(non_camel_case_types)]
 
 pub use self::select::fd_set;
 pub use self::signal::{sigaction, siginfo, sigset_t};
@@ -106,7 +107,7 @@ mod select {
           target_os = "dragonfly",
           target_os = "linux"))]
 mod select {
-    use std::uint;
+    use uint;
     use libc;
 
     pub const FD_SETSIZE: uint = 1024;
diff --git a/src/libstd/sys/unix/mod.rs b/src/libstd/sys/unix/mod.rs
new file mode 100644
index 00000000000..ad5de2dad48
--- /dev/null
+++ b/src/libstd/sys/unix/mod.rs
@@ -0,0 +1,92 @@
+// 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.
+
+extern crate libc;
+
+use num;
+use prelude::*;
+use io::{mod, IoResult, IoError};
+
+pub mod fs;
+pub mod os;
+pub mod c;
+
+pub type sock_t = io::file::fd_t;
+pub type wrlen = libc::size_t;
+pub unsafe fn close_sock(sock: sock_t) { let _ = libc::close(sock); }
+
+pub fn last_error() -> IoError {
+    let errno = os::errno() as i32;
+    let mut err = decode_error(errno);
+    err.detail = Some(os::error_string(errno));
+    err
+}
+
+/// Convert an `errno` value into a high-level error variant and description.
+pub fn decode_error(errno: i32) -> IoError {
+    // FIXME: this should probably be a bit more descriptive...
+    let (kind, desc) = match errno {
+        libc::EOF => (io::EndOfFile, "end of file"),
+        libc::ECONNREFUSED => (io::ConnectionRefused, "connection refused"),
+        libc::ECONNRESET => (io::ConnectionReset, "connection reset"),
+        libc::EPERM | libc::EACCES =>
+            (io::PermissionDenied, "permission denied"),
+        libc::EPIPE => (io::BrokenPipe, "broken pipe"),
+        libc::ENOTCONN => (io::NotConnected, "not connected"),
+        libc::ECONNABORTED => (io::ConnectionAborted, "connection aborted"),
+        libc::EADDRNOTAVAIL => (io::ConnectionRefused, "address not available"),
+        libc::EADDRINUSE => (io::ConnectionRefused, "address in use"),
+        libc::ENOENT => (io::FileNotFound, "no such file or directory"),
+        libc::EISDIR => (io::InvalidInput, "illegal operation on a directory"),
+        libc::ENOSYS => (io::IoUnavailable, "function not implemented"),
+        libc::EINVAL => (io::InvalidInput, "invalid argument"),
+        libc::ENOTTY =>
+            (io::MismatchedFileTypeForOperation,
+             "file descriptor is not a TTY"),
+        libc::ETIMEDOUT => (io::TimedOut, "operation timed out"),
+        libc::ECANCELED => (io::TimedOut, "operation aborted"),
+
+        // These two constants can have the same value on some systems,
+        // but different values on others, so we can't use a match
+        // clause
+        x if x == libc::EAGAIN || x == libc::EWOULDBLOCK =>
+            (io::ResourceUnavailable, "resource temporarily unavailable"),
+
+        _ => (io::OtherIoError, "unknown error")
+    };
+    IoError { kind: kind, desc: desc, detail: None }
+}
+
+#[inline]
+pub fn retry<I: PartialEq + num::One + Neg<I>> (f: || -> I) -> I {
+    let minus_one = -num::one::<I>();
+    loop {
+        let n = f();
+        if n == minus_one && os::errno() == libc::EINTR as int { }
+        else { return n }
+    }
+}
+
+pub fn ms_to_timeval(ms: u64) -> libc::timeval {
+    libc::timeval {
+        tv_sec: (ms / 1000) as libc::time_t,
+        tv_usec: ((ms % 1000) * 1000) as libc::suseconds_t,
+    }
+}
+
+pub fn wouldblock() -> bool {
+    let err = os::errno();
+    err == libc::EWOULDBLOCK as int || err == libc::EAGAIN as int
+}
+
+pub fn set_nonblocking(fd: net::sock_t, nb: bool) -> IoResult<()> {
+    let set = nb as libc::c_int;
+    super::mkerr_libc(retry(|| unsafe { c::ioctl(fd, c::FIONBIO, &set) }))
+}
diff --git a/src/libstd/sys/unix/os.rs b/src/libstd/sys/unix/os.rs
new file mode 100644
index 00000000000..34699eb27c1
--- /dev/null
+++ b/src/libstd/sys/unix/os.rs
@@ -0,0 +1,101 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use libc;
+use libc::{c_int, c_char};
+use prelude::*;
+
+use os::TMPBUF_SZ;
+
+/// Returns the platform-specific value of errno
+pub fn errno() -> int {
+    #[cfg(any(target_os = "macos",
+              target_os = "ios",
+              target_os = "freebsd"))]
+    fn errno_location() -> *const c_int {
+        extern {
+            fn __error() -> *const c_int;
+        }
+        unsafe {
+            __error()
+        }
+    }
+
+    #[cfg(target_os = "dragonfly")]
+    fn errno_location() -> *const c_int {
+        extern {
+            fn __dfly_error() -> *const c_int;
+        }
+        unsafe {
+            __dfly_error()
+        }
+    }
+
+    #[cfg(any(target_os = "linux", target_os = "android"))]
+    fn errno_location() -> *const c_int {
+        extern {
+            fn __errno_location() -> *const c_int;
+        }
+        unsafe {
+            __errno_location()
+        }
+    }
+
+    unsafe {
+        (*errno_location()) as int
+    }
+}
+
+/// Get a detailed string description for the given error number
+pub fn error_string(errno: i32) -> String {
+    #[cfg(any(target_os = "macos",
+              target_os = "ios",
+              target_os = "android",
+              target_os = "freebsd",
+              target_os = "dragonfly"))]
+    fn strerror_r(errnum: c_int, buf: *mut c_char, buflen: libc::size_t)
+                  -> c_int {
+        extern {
+            fn strerror_r(errnum: c_int, buf: *mut c_char,
+                          buflen: libc::size_t) -> c_int;
+        }
+        unsafe {
+            strerror_r(errnum, buf, buflen)
+        }
+    }
+
+    // GNU libc provides a non-compliant version of strerror_r by default
+    // and requires macros to instead use the POSIX compliant variant.
+    // So we just use __xpg_strerror_r which is always POSIX compliant
+    #[cfg(target_os = "linux")]
+    fn strerror_r(errnum: c_int, buf: *mut c_char,
+                  buflen: libc::size_t) -> c_int {
+        extern {
+            fn __xpg_strerror_r(errnum: c_int,
+                                buf: *mut c_char,
+                                buflen: libc::size_t)
+                                -> c_int;
+        }
+        unsafe {
+            __xpg_strerror_r(errnum, buf, buflen)
+        }
+    }
+
+    let mut buf = [0 as c_char, ..TMPBUF_SZ];
+
+    let p = buf.as_mut_ptr();
+    unsafe {
+        if strerror_r(errno as c_int, p, buf.len() as libc::size_t) < 0 {
+            panic!("strerror_r failure");
+        }
+
+        ::string::raw::from_buf(p as *const u8)
+    }
+}
diff --git a/src/libnative/io/c_windows.rs b/src/libstd/sys/windows/c.rs
index ee6aa26ede2..b8e9b1dca3a 100644
--- a/src/libnative/io/c_windows.rs
+++ b/src/libstd/sys/windows/c.rs
@@ -11,8 +11,11 @@
 //! C definitions used by libnative that don't belong in liblibc
 
 #![allow(overflowing_literals)]
+#![allow(dead_code)]
+#![allow(non_camel_case_types)]
 
 use libc;
+use prelude::*;
 
 pub const WSADESCRIPTION_LEN: uint = 256;
 pub const WSASYS_STATUS_LEN: uint = 128;
@@ -127,9 +130,10 @@ extern "system" {
 }
 
 pub mod compat {
-    use std::intrinsics::{atomic_store_relaxed, transmute};
-    use std::iter::Iterator;
+    use intrinsics::{atomic_store_relaxed, transmute};
+    use iter::Iterator;
     use libc::types::os::arch::extra::{LPCWSTR, HMODULE, LPCSTR, LPVOID};
+    use prelude::*;
 
     extern "system" {
         fn GetModuleHandleW(lpModuleName: LPCWSTR) -> HMODULE;
@@ -174,17 +178,17 @@ pub mod compat {
 
                 extern "system" fn thunk($($argname: $argtype),*) -> $rettype {
                     unsafe {
-                        ::io::c::compat::store_func(&mut ptr as *mut _ as *mut uint,
+                        ::sys::c::compat::store_func(&mut ptr as *mut _ as *mut uint,
                                                     stringify!($module),
                                                     stringify!($symbol),
                                                     fallback as uint);
-                        ::std::intrinsics::atomic_load_relaxed(&ptr)($($argname),*)
+                        ::intrinsics::atomic_load_relaxed(&ptr)($($argname),*)
                     }
                 }
 
                 extern "system" fn fallback($($argname: $argtype),*) -> $rettype $fallback
 
-                ::std::intrinsics::atomic_load_relaxed(&ptr)($($argname),*)
+                ::intrinsics::atomic_load_relaxed(&ptr)($($argname),*)
             }
         );
 
diff --git a/src/libstd/sys/windows/mod.rs b/src/libstd/sys/windows/mod.rs
new file mode 100644
index 00000000000..5f4129c1484
--- /dev/null
+++ b/src/libstd/sys/windows/mod.rs
@@ -0,0 +1,178 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![allow(missing_doc)]
+#![allow(non_camel_case_types)]
+#![allow(non_snake_case)]
+#![allow(unused_imports)]
+#![allow(dead_code)]
+#![allow(unused_unsafe)]
+#![allow(unused_mut)]
+
+extern crate libc;
+
+use num;
+use mem;
+use prelude::*;
+use io::{mod, IoResult, IoError};
+use sync::{Once, ONCE_INIT};
+
+macro_rules! helper_init( (static $name:ident: Helper<$m:ty>) => (
+    static $name: Helper<$m> = Helper {
+        lock: ::rt::mutex::NATIVE_MUTEX_INIT,
+        chan: ::cell::UnsafeCell { value: 0 as *mut Sender<$m> },
+        signal: ::cell::UnsafeCell { value: 0 },
+        initialized: ::cell::UnsafeCell { value: false },
+    };
+) )
+
+pub mod fs;
+pub mod os;
+pub mod c;
+
+pub type sock_t = libc::SOCKET;
+pub type wrlen = libc::c_int;
+pub unsafe fn close_sock(sock: sock_t) { let _ = libc::closesocket(sock); }
+
+// windows has zero values as errors
+fn mkerr_winbool(ret: libc::c_int) -> IoResult<()> {
+    if ret == 0 {
+        Err(last_error())
+    } else {
+        Ok(())
+    }
+}
+
+pub fn last_error() -> IoError {
+    let errno = os::errno() as i32;
+    let mut err = decode_error(errno);
+    err.detail = Some(os::error_string(errno));
+    err
+}
+
+pub fn last_net_error() -> IoError {
+    let errno = unsafe { c::WSAGetLastError() as i32 };
+    let mut err = decode_error(errno);
+    err.detail = Some(os::error_string(errno));
+    err
+}
+
+pub fn last_gai_error(_errno: i32) -> IoError {
+    last_net_error()
+}
+
+/// Convert an `errno` value into a high-level error variant and description.
+pub fn decode_error(errno: i32) -> IoError {
+    let (kind, desc) = match errno {
+        libc::EOF => (io::EndOfFile, "end of file"),
+        libc::ERROR_NO_DATA => (io::BrokenPipe, "the pipe is being closed"),
+        libc::ERROR_FILE_NOT_FOUND => (io::FileNotFound, "file not found"),
+        libc::ERROR_INVALID_NAME => (io::InvalidInput, "invalid file name"),
+        libc::WSAECONNREFUSED => (io::ConnectionRefused, "connection refused"),
+        libc::WSAECONNRESET => (io::ConnectionReset, "connection reset"),
+        libc::ERROR_ACCESS_DENIED | libc::WSAEACCES =>
+            (io::PermissionDenied, "permission denied"),
+        libc::WSAEWOULDBLOCK => {
+            (io::ResourceUnavailable, "resource temporarily unavailable")
+        }
+        libc::WSAENOTCONN => (io::NotConnected, "not connected"),
+        libc::WSAECONNABORTED => (io::ConnectionAborted, "connection aborted"),
+        libc::WSAEADDRNOTAVAIL => (io::ConnectionRefused, "address not available"),
+        libc::WSAEADDRINUSE => (io::ConnectionRefused, "address in use"),
+        libc::ERROR_BROKEN_PIPE => (io::EndOfFile, "the pipe has ended"),
+        libc::ERROR_OPERATION_ABORTED =>
+            (io::TimedOut, "operation timed out"),
+        libc::WSAEINVAL => (io::InvalidInput, "invalid argument"),
+        libc::ERROR_CALL_NOT_IMPLEMENTED =>
+            (io::IoUnavailable, "function not implemented"),
+        libc::ERROR_INVALID_HANDLE =>
+            (io::MismatchedFileTypeForOperation,
+             "invalid handle provided to function"),
+        libc::ERROR_NOTHING_TO_TERMINATE =>
+            (io::InvalidInput, "no process to kill"),
+
+        // libuv maps this error code to EISDIR. we do too. if it is found
+        // to be incorrect, we can add in some more machinery to only
+        // return this message when ERROR_INVALID_FUNCTION after certain
+        // Windows calls.
+        libc::ERROR_INVALID_FUNCTION => (io::InvalidInput,
+                                         "illegal operation on a directory"),
+
+        _ => (io::OtherIoError, "unknown error")
+    };
+    IoError { kind: kind, desc: desc, detail: None }
+}
+
+pub fn decode_error_detailed(errno: i32) -> IoError {
+    let mut err = decode_error(errno);
+    err.detail = Some(os::error_string(errno));
+    err
+}
+
+#[inline]
+pub fn retry<I> (f: || -> I) -> I { f() } // PR rust-lang/rust/#17020
+
+pub fn ms_to_timeval(ms: u64) -> libc::timeval {
+    libc::timeval {
+        tv_sec: (ms / 1000) as libc::c_long,
+        tv_usec: ((ms % 1000) * 1000) as libc::c_long,
+    }
+}
+
+pub fn wouldblock() -> bool {
+    let err = os::errno();
+    err == libc::WSAEWOULDBLOCK as uint
+}
+
+pub fn set_nonblocking(fd: sock_t, nb: bool) -> IoResult<()> {
+    let mut set = nb as libc::c_ulong;
+    if unsafe { c::ioctlsocket(fd, c::FIONBIO, &mut set) != 0 } {
+        Err(last_error())
+    } else {
+        Ok(())
+    }
+}
+
+// FIXME: call this
+pub fn init_net() {
+    unsafe {
+        static START: Once = ONCE_INIT;
+
+        START.doit(|| {
+            let mut data: c::WSADATA = mem::zeroed();
+            let ret = c::WSAStartup(0x202, // version 2.2
+                                    &mut data);
+            assert_eq!(ret, 0);
+        });
+    }
+}
+
+pub fn unimpl() -> IoError {
+    IoError {
+        kind: io::IoUnavailable,
+        desc: "operation is not implemented",
+        detail: None,
+    }
+}
+
+pub fn to_utf16(s: Option<&str>) -> IoResult<Vec<u16>> {
+    match s {
+        Some(s) => Ok({
+            let mut s = s.utf16_units().collect::<Vec<u16>>();
+            s.push(0);
+            s
+        }),
+        None => Err(IoError {
+            kind: io::InvalidInput,
+            desc: "valid unicode input required",
+            detail: None
+        })
+    }
+}
diff --git a/src/libstd/sys/windows/os.rs b/src/libstd/sys/windows/os.rs
new file mode 100644
index 00000000000..aaa1aaf6327
--- /dev/null
+++ b/src/libstd/sys/windows/os.rs
@@ -0,0 +1,103 @@
+// 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.
+
+// FIXME: move various extern bindings from here into liblibc or
+// something similar
+
+use libc;
+use libc::{c_int, c_char, c_void};
+use prelude::*;
+use io::{IoResult, IoError};
+use sys::fs::FileDesc;
+use ptr;
+
+use os::TMPBUF_SZ;
+
+pub fn errno() -> uint {
+    use libc::types::os::arch::extra::DWORD;
+
+    #[link_name = "kernel32"]
+    extern "system" {
+        fn GetLastError() -> DWORD;
+    }
+
+    unsafe {
+        GetLastError() as uint
+    }
+}
+
+/// Get a detailed string description for the given error number
+pub fn error_string(errnum: i32) -> String {
+    use libc::types::os::arch::extra::DWORD;
+    use libc::types::os::arch::extra::LPWSTR;
+    use libc::types::os::arch::extra::LPVOID;
+    use libc::types::os::arch::extra::WCHAR;
+
+    #[link_name = "kernel32"]
+    extern "system" {
+        fn FormatMessageW(flags: DWORD,
+                          lpSrc: LPVOID,
+                          msgId: DWORD,
+                          langId: DWORD,
+                          buf: LPWSTR,
+                          nsize: DWORD,
+                          args: *const c_void)
+                          -> DWORD;
+    }
+
+    static FORMAT_MESSAGE_FROM_SYSTEM: DWORD = 0x00001000;
+    static FORMAT_MESSAGE_IGNORE_INSERTS: DWORD = 0x00000200;
+
+    // This value is calculated from the macro
+    // MAKELANGID(LANG_SYSTEM_DEFAULT, SUBLANG_SYS_DEFAULT)
+    let langId = 0x0800 as DWORD;
+
+    let mut buf = [0 as WCHAR, ..TMPBUF_SZ];
+
+    unsafe {
+        let res = FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM |
+                                 FORMAT_MESSAGE_IGNORE_INSERTS,
+                                 ptr::null_mut(),
+                                 errnum as DWORD,
+                                 langId,
+                                 buf.as_mut_ptr(),
+                                 buf.len() as DWORD,
+                                 ptr::null());
+        if res == 0 {
+            // Sometimes FormatMessageW can fail e.g. system doesn't like langId,
+            let fm_err = errno();
+            return format!("OS Error {} (FormatMessageW() returned error {})", errnum, fm_err);
+        }
+
+        let msg = String::from_utf16(::str::truncate_utf16_at_nul(buf));
+        match msg {
+            Some(msg) => format!("OS Error {}: {}", errnum, msg),
+            None => format!("OS Error {} (FormatMessageW() returned invalid UTF-16)", errnum),
+        }
+    }
+}
+
+pub unsafe fn pipe() -> IoResult<(FileDesc, FileDesc)> {
+    // Windows pipes work subtly differently than unix pipes, and their
+    // inheritance has to be handled in a different way that I do not
+    // fully understand. Here we explicitly make the pipe non-inheritable,
+    // which means to pass it to a subprocess they need to be duplicated
+    // first, as in std::run.
+    let mut fds = [0, ..2];
+    match libc::pipe(fds.as_mut_ptr(), 1024 as ::libc::c_uint,
+                     (libc::O_BINARY | libc::O_NOINHERIT) as c_int) {
+        0 => {
+            assert!(fds[0] != -1 && fds[0] != 0);
+            assert!(fds[1] != -1 && fds[1] != 0);
+            Ok((FileDesc::new(fds[0], true), FileDesc::new(fds[1], true)))
+        }
+        _ => Err(IoError::last_error()),
+    }
+}