about summary refs log tree commit diff
path: root/src/libstd/sys
diff options
context:
space:
mode:
Diffstat (limited to 'src/libstd/sys')
-rw-r--r--src/libstd/sys/common/args.rs100
-rw-r--r--src/libstd/sys/common/io.rs3
-rw-r--r--src/libstd/sys/common/memchr.rs230
-rw-r--r--src/libstd/sys/common/mod.rs4
-rw-r--r--src/libstd/sys/unix/args.rs211
-rw-r--r--src/libstd/sys/unix/env.rs173
-rw-r--r--src/libstd/sys/unix/memchr.rs57
-rw-r--r--src/libstd/sys/unix/mod.rs4
-rw-r--r--src/libstd/sys/unix/os.rs120
-rw-r--r--src/libstd/sys/unix/path.rs29
-rw-r--r--src/libstd/sys/unix/stdio.rs2
-rw-r--r--src/libstd/sys/windows/args.rs76
-rw-r--r--src/libstd/sys/windows/env.rs19
-rw-r--r--src/libstd/sys/windows/memchr.rs15
-rw-r--r--src/libstd/sys/windows/mod.rs4
-rw-r--r--src/libstd/sys/windows/os.rs56
-rw-r--r--src/libstd/sys/windows/path.rs108
-rw-r--r--src/libstd/sys/windows/stdio.rs2
18 files changed, 934 insertions, 279 deletions
diff --git a/src/libstd/sys/common/args.rs b/src/libstd/sys/common/args.rs
deleted file mode 100644
index b5330463e30..00000000000
--- a/src/libstd/sys/common/args.rs
+++ /dev/null
@@ -1,100 +0,0 @@
-// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-//! Global storage for command line arguments
-//!
-//! The current incarnation of the Rust runtime expects for
-//! the processes `argc` and `argv` arguments to be stored
-//! in a globally-accessible location for use by the `os` module.
-//!
-//! Only valid to call on Linux. Mac and Windows use syscalls to
-//! discover the command line arguments.
-//!
-//! FIXME #7756: Would be nice for this to not exist.
-
-#![allow(dead_code)] // different code on OSX/linux/etc
-
-/// One-time global initialization.
-pub unsafe fn init(argc: isize, argv: *const *const u8) { imp::init(argc, argv) }
-
-/// One-time global cleanup.
-pub unsafe fn cleanup() { imp::cleanup() }
-
-/// Make a clone of the global arguments.
-pub fn clone() -> Option<Vec<Vec<u8>>> { imp::clone() }
-
-#[cfg(any(target_os = "linux",
-          target_os = "android",
-          target_os = "freebsd",
-          target_os = "dragonfly",
-          target_os = "bitrig",
-          target_os = "netbsd",
-          target_os = "openbsd",
-          target_os = "solaris",
-          target_os = "emscripten",
-          target_os = "haiku"))]
-mod imp {
-    use libc::c_char;
-    use mem;
-    use ffi::CStr;
-
-    use sys_common::mutex::Mutex;
-
-    static mut GLOBAL_ARGS_PTR: usize = 0;
-    static LOCK: Mutex = Mutex::new();
-
-    pub unsafe fn init(argc: isize, argv: *const *const u8) {
-        let args = (0..argc).map(|i| {
-            CStr::from_ptr(*argv.offset(i) as *const c_char).to_bytes().to_vec()
-        }).collect();
-
-        LOCK.lock();
-        let ptr = get_global_ptr();
-        assert!((*ptr).is_none());
-        (*ptr) = Some(box args);
-        LOCK.unlock();
-    }
-
-    pub unsafe fn cleanup() {
-        LOCK.lock();
-        *get_global_ptr() = None;
-        LOCK.unlock();
-    }
-
-    pub fn clone() -> Option<Vec<Vec<u8>>> {
-        unsafe {
-            LOCK.lock();
-            let ptr = get_global_ptr();
-            let ret = (*ptr).as_ref().map(|s| (**s).clone());
-            LOCK.unlock();
-            return ret
-        }
-    }
-
-    fn get_global_ptr() -> *mut Option<Box<Vec<Vec<u8>>>> {
-        unsafe { mem::transmute(&GLOBAL_ARGS_PTR) }
-    }
-
-}
-
-#[cfg(any(target_os = "macos",
-          target_os = "ios",
-          target_os = "windows"))]
-mod imp {
-    pub unsafe fn init(_argc: isize, _argv: *const *const u8) {
-    }
-
-    pub fn cleanup() {
-    }
-
-    pub fn clone() -> Option<Vec<Vec<u8>>> {
-        panic!()
-    }
-}
diff --git a/src/libstd/sys/common/io.rs b/src/libstd/sys/common/io.rs
index 47cec4ef5c2..0483725dd83 100644
--- a/src/libstd/sys/common/io.rs
+++ b/src/libstd/sys/common/io.rs
@@ -50,7 +50,8 @@ pub unsafe fn read_to_end_uninitialized(r: &mut Read, buf: &mut Vec<u8>) -> io::
     }
 }
 
-#[cfg(all(test, not(target_os = "emscripten")))]
+#[cfg(test)]
+#[allow(dead_code)] // not used on emscripten
 pub mod test {
     use path::{Path, PathBuf};
     use env;
diff --git a/src/libstd/sys/common/memchr.rs b/src/libstd/sys/common/memchr.rs
new file mode 100644
index 00000000000..3824a5fb528
--- /dev/null
+++ b/src/libstd/sys/common/memchr.rs
@@ -0,0 +1,230 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+//
+// Original implementation taken from rust-memchr
+// Copyright 2015 Andrew Gallant, bluss and Nicolas Koch
+
+#[allow(dead_code)]
+pub mod fallback {
+    use cmp;
+    use mem;
+
+    const LO_U64: u64 = 0x0101010101010101;
+    const HI_U64: u64 = 0x8080808080808080;
+
+    // use truncation
+    const LO_USIZE: usize = LO_U64 as usize;
+    const HI_USIZE: usize = HI_U64 as usize;
+
+    /// Return `true` if `x` contains any zero byte.
+    ///
+    /// From *Matters Computational*, J. Arndt
+    ///
+    /// "The idea is to subtract one from each of the bytes and then look for
+    /// bytes where the borrow propagated all the way to the most significant
+    /// bit."
+    #[inline]
+    fn contains_zero_byte(x: usize) -> bool {
+        x.wrapping_sub(LO_USIZE) & !x & HI_USIZE != 0
+    }
+
+    #[cfg(target_pointer_width = "32")]
+    #[inline]
+    fn repeat_byte(b: u8) -> usize {
+        let mut rep = (b as usize) << 8 | b as usize;
+        rep = rep << 16 | rep;
+        rep
+    }
+
+    #[cfg(target_pointer_width = "64")]
+    #[inline]
+    fn repeat_byte(b: u8) -> usize {
+        let mut rep = (b as usize) << 8 | b as usize;
+        rep = rep << 16 | rep;
+        rep = rep << 32 | rep;
+        rep
+    }
+
+    /// Return the first index matching the byte `a` in `text`.
+    pub fn memchr(x: u8, text: &[u8]) -> Option<usize> {
+        // Scan for a single byte value by reading two `usize` words at a time.
+        //
+        // Split `text` in three parts
+        // - unaligned initial part, before the first word aligned address in text
+        // - body, scan by 2 words at a time
+        // - the last remaining part, < 2 word size
+        let len = text.len();
+        let ptr = text.as_ptr();
+        let usize_bytes = mem::size_of::<usize>();
+
+        // search up to an aligned boundary
+        let align = (ptr as usize) & (usize_bytes- 1);
+        let mut offset;
+        if align > 0 {
+            offset = cmp::min(usize_bytes - align, len);
+            if let Some(index) = text[..offset].iter().position(|elt| *elt == x) {
+                return Some(index);
+            }
+        } else {
+            offset = 0;
+        }
+
+        // search the body of the text
+        let repeated_x = repeat_byte(x);
+
+        if len >= 2 * usize_bytes {
+            while offset <= len - 2 * usize_bytes {
+                unsafe {
+                    let u = *(ptr.offset(offset as isize) as *const usize);
+                    let v = *(ptr.offset((offset + usize_bytes) as isize) as *const usize);
+
+                    // break if there is a matching byte
+                    let zu = contains_zero_byte(u ^ repeated_x);
+                    let zv = contains_zero_byte(v ^ repeated_x);
+                    if zu || zv {
+                        break;
+                    }
+                }
+                offset += usize_bytes * 2;
+            }
+        }
+
+        // find the byte after the point the body loop stopped
+        text[offset..].iter().position(|elt| *elt == x).map(|i| offset + i)
+    }
+
+    /// Return the last index matching the byte `a` in `text`.
+    pub fn memrchr(x: u8, text: &[u8]) -> Option<usize> {
+        // Scan for a single byte value by reading two `usize` words at a time.
+        //
+        // Split `text` in three parts
+        // - unaligned tail, after the last word aligned address in text
+        // - body, scan by 2 words at a time
+        // - the first remaining bytes, < 2 word size
+        let len = text.len();
+        let ptr = text.as_ptr();
+        let usize_bytes = mem::size_of::<usize>();
+
+        // search to an aligned boundary
+        let end_align = (ptr as usize + len) & (usize_bytes - 1);
+        let mut offset;
+        if end_align > 0 {
+            offset = if end_align >= len { 0 } else { len - end_align };
+            if let Some(index) = text[offset..].iter().rposition(|elt| *elt == x) {
+                return Some(offset + index);
+            }
+        } else {
+            offset = len;
+        }
+
+        // search the body of the text
+        let repeated_x = repeat_byte(x);
+
+        while offset >= 2 * usize_bytes {
+            unsafe {
+                let u = *(ptr.offset(offset as isize - 2 * usize_bytes as isize) as *const usize);
+                let v = *(ptr.offset(offset as isize - usize_bytes as isize) as *const usize);
+
+                // break if there is a matching byte
+                let zu = contains_zero_byte(u ^ repeated_x);
+                let zv = contains_zero_byte(v ^ repeated_x);
+                if zu || zv {
+                    break;
+                }
+            }
+            offset -= 2 * usize_bytes;
+        }
+
+        // find the byte before the point the body loop stopped
+        text[..offset].iter().rposition(|elt| *elt == x)
+    }
+
+    // test fallback implementations on all platforms
+    #[test]
+    fn matches_one() {
+        assert_eq!(Some(0), memchr(b'a', b"a"));
+    }
+
+    #[test]
+    fn matches_begin() {
+        assert_eq!(Some(0), memchr(b'a', b"aaaa"));
+    }
+
+    #[test]
+    fn matches_end() {
+        assert_eq!(Some(4), memchr(b'z', b"aaaaz"));
+    }
+
+    #[test]
+    fn matches_nul() {
+        assert_eq!(Some(4), memchr(b'\x00', b"aaaa\x00"));
+    }
+
+    #[test]
+    fn matches_past_nul() {
+        assert_eq!(Some(5), memchr(b'z', b"aaaa\x00z"));
+    }
+
+    #[test]
+    fn no_match_empty() {
+        assert_eq!(None, memchr(b'a', b""));
+    }
+
+    #[test]
+    fn no_match() {
+        assert_eq!(None, memchr(b'a', b"xyz"));
+    }
+
+    #[test]
+    fn matches_one_reversed() {
+        assert_eq!(Some(0), memrchr(b'a', b"a"));
+    }
+
+    #[test]
+    fn matches_begin_reversed() {
+        assert_eq!(Some(3), memrchr(b'a', b"aaaa"));
+    }
+
+    #[test]
+    fn matches_end_reversed() {
+        assert_eq!(Some(0), memrchr(b'z', b"zaaaa"));
+    }
+
+    #[test]
+    fn matches_nul_reversed() {
+        assert_eq!(Some(4), memrchr(b'\x00', b"aaaa\x00"));
+    }
+
+    #[test]
+    fn matches_past_nul_reversed() {
+        assert_eq!(Some(0), memrchr(b'z', b"z\x00aaaa"));
+    }
+
+    #[test]
+    fn no_match_empty_reversed() {
+        assert_eq!(None, memrchr(b'a', b""));
+    }
+
+    #[test]
+    fn no_match_reversed() {
+        assert_eq!(None, memrchr(b'a', b"xyz"));
+    }
+
+    #[test]
+    fn each_alignment_reversed() {
+        let mut data = [1u8; 64];
+        let needle = 2;
+        let pos = 40;
+        data[pos] = needle;
+        for start in 0..16 {
+            assert_eq!(Some(pos - start), memrchr(needle, &data[start..]));
+        }
+    }
+}
diff --git a/src/libstd/sys/common/mod.rs b/src/libstd/sys/common/mod.rs
index d1ca6765107..2845f895f18 100644
--- a/src/libstd/sys/common/mod.rs
+++ b/src/libstd/sys/common/mod.rs
@@ -25,12 +25,12 @@ macro_rules! rtassert {
     })
 }
 
-pub mod args;
 pub mod at_exit_imp;
 #[cfg(any(not(cargobuild), feature = "backtrace"))]
 pub mod backtrace;
 pub mod condvar;
 pub mod io;
+pub mod memchr;
 pub mod mutex;
 pub mod net;
 pub mod poison;
@@ -91,7 +91,7 @@ pub fn at_exit<F: FnOnce() + Send + 'static>(f: F) -> Result<(), ()> {
 pub fn cleanup() {
     static CLEANUP: Once = Once::new();
     CLEANUP.call_once(|| unsafe {
-        args::cleanup();
+        sys::args::cleanup();
         sys::stack_overflow::cleanup();
         at_exit_imp::cleanup();
     });
diff --git a/src/libstd/sys/unix/args.rs b/src/libstd/sys/unix/args.rs
new file mode 100644
index 00000000000..c64db333e51
--- /dev/null
+++ b/src/libstd/sys/unix/args.rs
@@ -0,0 +1,211 @@
+// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! Global initialization and retreival of command line arguments.
+//!
+//! On some platforms these are stored during runtime startup,
+//! and on some they are retrieved from the system on demand.
+
+#![allow(dead_code)] // runtime init functions not used during testing
+
+use ffi::OsString;
+use marker::PhantomData;
+use vec;
+
+/// One-time global initialization.
+pub unsafe fn init(argc: isize, argv: *const *const u8) { imp::init(argc, argv) }
+
+/// One-time global cleanup.
+pub unsafe fn cleanup() { imp::cleanup() }
+
+/// Returns the command line arguments
+pub fn args() -> Args {
+    imp::args()
+}
+
+pub struct Args {
+    iter: vec::IntoIter<OsString>,
+    _dont_send_or_sync_me: PhantomData<*mut ()>,
+}
+
+impl Iterator for Args {
+    type Item = OsString;
+    fn next(&mut self) -> Option<OsString> { self.iter.next() }
+    fn size_hint(&self) -> (usize, Option<usize>) { self.iter.size_hint() }
+}
+
+impl ExactSizeIterator for Args {
+    fn len(&self) -> usize { self.iter.len() }
+}
+
+impl DoubleEndedIterator for Args {
+    fn next_back(&mut self) -> Option<OsString> { self.iter.next_back() }
+}
+
+#[cfg(any(target_os = "linux",
+          target_os = "android",
+          target_os = "freebsd",
+          target_os = "dragonfly",
+          target_os = "bitrig",
+          target_os = "netbsd",
+          target_os = "openbsd",
+          target_os = "solaris",
+          target_os = "emscripten",
+          target_os = "haiku"))]
+mod imp {
+    use os::unix::prelude::*;
+    use mem;
+    use ffi::{CStr, OsString};
+    use marker::PhantomData;
+    use libc;
+    use super::Args;
+
+    use sys_common::mutex::Mutex;
+
+    static mut GLOBAL_ARGS_PTR: usize = 0;
+    static LOCK: Mutex = Mutex::new();
+
+    pub unsafe fn init(argc: isize, argv: *const *const u8) {
+        let args = (0..argc).map(|i| {
+            CStr::from_ptr(*argv.offset(i) as *const libc::c_char).to_bytes().to_vec()
+        }).collect();
+
+        LOCK.lock();
+        let ptr = get_global_ptr();
+        assert!((*ptr).is_none());
+        (*ptr) = Some(box args);
+        LOCK.unlock();
+    }
+
+    pub unsafe fn cleanup() {
+        LOCK.lock();
+        *get_global_ptr() = None;
+        LOCK.unlock();
+    }
+
+    pub fn args() -> Args {
+        let bytes = clone().unwrap_or(Vec::new());
+        let v: Vec<OsString> = bytes.into_iter().map(|v| {
+            OsStringExt::from_vec(v)
+        }).collect();
+        Args { iter: v.into_iter(), _dont_send_or_sync_me: PhantomData }
+    }
+
+    fn clone() -> Option<Vec<Vec<u8>>> {
+        unsafe {
+            LOCK.lock();
+            let ptr = get_global_ptr();
+            let ret = (*ptr).as_ref().map(|s| (**s).clone());
+            LOCK.unlock();
+            return ret
+        }
+    }
+
+    fn get_global_ptr() -> *mut Option<Box<Vec<Vec<u8>>>> {
+        unsafe { mem::transmute(&GLOBAL_ARGS_PTR) }
+    }
+
+}
+
+#[cfg(any(target_os = "macos",
+          target_os = "ios"))]
+mod imp {
+    use ffi::CStr;
+    use marker::PhantomData;
+    use libc;
+    use super::Args;
+
+    pub unsafe fn init(_argc: isize, _argv: *const *const u8) {
+    }
+
+    pub fn cleanup() {
+    }
+
+    #[cfg(target_os = "macos")]
+    pub fn args() -> Args {
+        use os::unix::prelude::*;
+        extern {
+            // These functions are in crt_externs.h.
+            fn _NSGetArgc() -> *mut libc::c_int;
+            fn _NSGetArgv() -> *mut *mut *mut libc::c_char;
+        }
+
+        let vec = unsafe {
+            let (argc, argv) = (*_NSGetArgc() as isize,
+                                *_NSGetArgv() as *const *const libc::c_char);
+            (0.. argc as isize).map(|i| {
+                let bytes = CStr::from_ptr(*argv.offset(i)).to_bytes().to_vec();
+                OsStringExt::from_vec(bytes)
+            }).collect::<Vec<_>>()
+        };
+        Args {
+            iter: vec.into_iter(),
+            _dont_send_or_sync_me: PhantomData,
+        }
+    }
+
+    // As _NSGetArgc and _NSGetArgv aren't mentioned in iOS docs
+    // and use underscores in their names - they're most probably
+    // are considered private and therefore should be avoided
+    // Here is another way to get arguments using Objective C
+    // runtime
+    //
+    // In general it looks like:
+    // res = Vec::new()
+    // let args = [[NSProcessInfo processInfo] arguments]
+    // for i in (0..[args count])
+    //      res.push([args objectAtIndex:i])
+    // res
+    #[cfg(target_os = "ios")]
+    pub fn args() -> Args {
+        use ffi::OsString;
+        use mem;
+        use str;
+
+        extern {
+            fn sel_registerName(name: *const libc::c_uchar) -> Sel;
+            fn objc_msgSend(obj: NsId, sel: Sel, ...) -> NsId;
+            fn objc_getClass(class_name: *const libc::c_uchar) -> NsId;
+        }
+
+        #[link(name = "Foundation", kind = "framework")]
+        #[link(name = "objc")]
+        #[cfg(not(cargobuild))]
+        extern {}
+
+        type Sel = *const libc::c_void;
+        type NsId = *const libc::c_void;
+
+        let mut res = Vec::new();
+
+        unsafe {
+            let process_info_sel = sel_registerName("processInfo\0".as_ptr());
+            let arguments_sel = sel_registerName("arguments\0".as_ptr());
+            let utf8_sel = sel_registerName("UTF8String\0".as_ptr());
+            let count_sel = sel_registerName("count\0".as_ptr());
+            let object_at_sel = sel_registerName("objectAtIndex:\0".as_ptr());
+
+            let klass = objc_getClass("NSProcessInfo\0".as_ptr());
+            let info = objc_msgSend(klass, process_info_sel);
+            let args = objc_msgSend(info, arguments_sel);
+
+            let cnt: usize = mem::transmute(objc_msgSend(args, count_sel));
+            for i in 0..cnt {
+                let tmp = objc_msgSend(args, object_at_sel, i);
+                let utf_c_str: *const libc::c_char =
+                    mem::transmute(objc_msgSend(tmp, utf8_sel));
+                let bytes = CStr::from_ptr(utf_c_str).to_bytes();
+                res.push(OsString::from(str::from_utf8(bytes).unwrap()))
+            }
+        }
+
+        Args { iter: res.into_iter(), _dont_send_or_sync_me: PhantomData }
+    }
+}
diff --git a/src/libstd/sys/unix/env.rs b/src/libstd/sys/unix/env.rs
new file mode 100644
index 00000000000..92c4899b3d5
--- /dev/null
+++ b/src/libstd/sys/unix/env.rs
@@ -0,0 +1,173 @@
+// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#[cfg(target_os = "linux")]
+pub mod os {
+    pub const FAMILY: &'static str = "unix";
+    pub const OS: &'static str = "linux";
+    pub const DLL_PREFIX: &'static str = "lib";
+    pub const DLL_SUFFIX: &'static str = ".so";
+    pub const DLL_EXTENSION: &'static str = "so";
+    pub const EXE_SUFFIX: &'static str = "";
+    pub const EXE_EXTENSION: &'static str = "";
+}
+
+#[cfg(target_os = "macos")]
+pub mod os {
+    pub const FAMILY: &'static str = "unix";
+    pub const OS: &'static str = "macos";
+    pub const DLL_PREFIX: &'static str = "lib";
+    pub const DLL_SUFFIX: &'static str = ".dylib";
+    pub const DLL_EXTENSION: &'static str = "dylib";
+    pub const EXE_SUFFIX: &'static str = "";
+    pub const EXE_EXTENSION: &'static str = "";
+}
+
+#[cfg(target_os = "ios")]
+pub mod os {
+    pub const FAMILY: &'static str = "unix";
+    pub const OS: &'static str = "ios";
+    pub const DLL_PREFIX: &'static str = "lib";
+    pub const DLL_SUFFIX: &'static str = ".dylib";
+    pub const DLL_EXTENSION: &'static str = "dylib";
+    pub const EXE_SUFFIX: &'static str = "";
+    pub const EXE_EXTENSION: &'static str = "";
+}
+
+#[cfg(target_os = "freebsd")]
+pub mod os {
+    pub const FAMILY: &'static str = "unix";
+    pub const OS: &'static str = "freebsd";
+    pub const DLL_PREFIX: &'static str = "lib";
+    pub const DLL_SUFFIX: &'static str = ".so";
+    pub const DLL_EXTENSION: &'static str = "so";
+    pub const EXE_SUFFIX: &'static str = "";
+    pub const EXE_EXTENSION: &'static str = "";
+}
+
+#[cfg(target_os = "dragonfly")]
+pub mod os {
+    pub const FAMILY: &'static str = "unix";
+    pub const OS: &'static str = "dragonfly";
+    pub const DLL_PREFIX: &'static str = "lib";
+    pub const DLL_SUFFIX: &'static str = ".so";
+    pub const DLL_EXTENSION: &'static str = "so";
+    pub const EXE_SUFFIX: &'static str = "";
+    pub const EXE_EXTENSION: &'static str = "";
+}
+
+#[cfg(target_os = "bitrig")]
+pub mod os {
+    pub const FAMILY: &'static str = "unix";
+    pub const OS: &'static str = "bitrig";
+    pub const DLL_PREFIX: &'static str = "lib";
+    pub const DLL_SUFFIX: &'static str = ".so";
+    pub const DLL_EXTENSION: &'static str = "so";
+    pub const EXE_SUFFIX: &'static str = "";
+    pub const EXE_EXTENSION: &'static str = "";
+}
+
+#[cfg(target_os = "netbsd")]
+pub mod os {
+    pub const FAMILY: &'static str = "unix";
+    pub const OS: &'static str = "netbsd";
+    pub const DLL_PREFIX: &'static str = "lib";
+    pub const DLL_SUFFIX: &'static str = ".so";
+    pub const DLL_EXTENSION: &'static str = "so";
+    pub const EXE_SUFFIX: &'static str = "";
+    pub const EXE_EXTENSION: &'static str = "";
+}
+
+#[cfg(target_os = "openbsd")]
+pub mod os {
+    pub const FAMILY: &'static str = "unix";
+    pub const OS: &'static str = "openbsd";
+    pub const DLL_PREFIX: &'static str = "lib";
+    pub const DLL_SUFFIX: &'static str = ".so";
+    pub const DLL_EXTENSION: &'static str = "so";
+    pub const EXE_SUFFIX: &'static str = "";
+    pub const EXE_EXTENSION: &'static str = "";
+}
+
+#[cfg(target_os = "android")]
+pub mod os {
+    pub const FAMILY: &'static str = "unix";
+    pub const OS: &'static str = "android";
+    pub const DLL_PREFIX: &'static str = "lib";
+    pub const DLL_SUFFIX: &'static str = ".so";
+    pub const DLL_EXTENSION: &'static str = "so";
+    pub const EXE_SUFFIX: &'static str = "";
+    pub const EXE_EXTENSION: &'static str = "";
+}
+
+#[cfg(target_os = "solaris")]
+pub mod os {
+    pub const FAMILY: &'static str = "unix";
+    pub const OS: &'static str = "solaris";
+    pub const DLL_PREFIX: &'static str = "lib";
+    pub const DLL_SUFFIX: &'static str = ".so";
+    pub const DLL_EXTENSION: &'static str = "so";
+    pub const EXE_SUFFIX: &'static str = "";
+    pub const EXE_EXTENSION: &'static str = "";
+}
+
+#[cfg(all(target_os = "nacl", not(target_arch = "le32")))]
+pub mod os {
+    pub const FAMILY: &'static str = "unix";
+    pub const OS: &'static str = "nacl";
+    pub const DLL_PREFIX: &'static str = "lib";
+    pub const DLL_SUFFIX: &'static str = ".so";
+    pub const DLL_EXTENSION: &'static str = "so";
+    pub const EXE_SUFFIX: &'static str = ".nexe";
+    pub const EXE_EXTENSION: &'static str = "nexe";
+}
+#[cfg(all(target_os = "nacl", target_arch = "le32"))]
+pub mod os {
+    pub const FAMILY: &'static str = "unix";
+    pub const OS: &'static str = "pnacl";
+    pub const DLL_PREFIX: &'static str = "lib";
+    pub const DLL_SUFFIX: &'static str = ".pso";
+    pub const DLL_EXTENSION: &'static str = "pso";
+    pub const EXE_SUFFIX: &'static str = ".pexe";
+    pub const EXE_EXTENSION: &'static str = "pexe";
+}
+
+#[cfg(target_os = "haiku")]
+mod os {
+    pub const FAMILY: &'static str = "unix";
+    pub const OS: &'static str = "haiku";
+    pub const DLL_PREFIX: &'static str = "lib";
+    pub const DLL_SUFFIX: &'static str = ".so";
+    pub const DLL_EXTENSION: &'static str = "so";
+    pub const EXE_SUFFIX: &'static str = "";
+    pub const EXE_EXTENSION: &'static str = "";
+}
+
+#[cfg(all(target_os = "emscripten", target_arch = "asmjs"))]
+mod os {
+    pub const FAMILY: &'static str = "unix";
+    pub const OS: &'static str = "emscripten";
+    pub const DLL_PREFIX: &'static str = "lib";
+    pub const DLL_SUFFIX: &'static str = ".so";
+    pub const DLL_EXTENSION: &'static str = "so";
+    pub const EXE_SUFFIX: &'static str = ".js";
+    pub const EXE_EXTENSION: &'static str = "js";
+}
+
+#[cfg(all(target_os = "emscripten", target_arch = "wasm32"))]
+mod os {
+    pub const FAMILY: &'static str = "unix";
+    pub const OS: &'static str = "emscripten";
+    pub const DLL_PREFIX: &'static str = "lib";
+    pub const DLL_SUFFIX: &'static str = ".so";
+    pub const DLL_EXTENSION: &'static str = "so";
+    pub const EXE_SUFFIX: &'static str = ".js";
+    pub const EXE_EXTENSION: &'static str = "js";
+}
diff --git a/src/libstd/sys/unix/memchr.rs b/src/libstd/sys/unix/memchr.rs
new file mode 100644
index 00000000000..5038e0750c8
--- /dev/null
+++ b/src/libstd/sys/unix/memchr.rs
@@ -0,0 +1,57 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+//
+// Original implementation taken from rust-memchr
+// Copyright 2015 Andrew Gallant, bluss and Nicolas Koch
+
+pub fn memchr(needle: u8, haystack: &[u8]) -> Option<usize> {
+    use libc;
+
+    let p = unsafe {
+        libc::memchr(
+            haystack.as_ptr() as *const libc::c_void,
+            needle as libc::c_int,
+            haystack.len() as libc::size_t)
+    };
+    if p.is_null() {
+        None
+    } else {
+        Some(p as usize - (haystack.as_ptr() as usize))
+    }
+}
+
+pub fn memrchr(needle: u8, haystack: &[u8]) -> Option<usize> {
+
+    #[cfg(target_os = "linux")]
+    fn memrchr_specific(needle: u8, haystack: &[u8]) -> Option<usize> {
+        use libc;
+
+        // GNU's memrchr() will - unlike memchr() - error if haystack is empty.
+        if haystack.is_empty() {return None}
+        let p = unsafe {
+            libc::memrchr(
+                haystack.as_ptr() as *const libc::c_void,
+                needle as libc::c_int,
+                haystack.len() as libc::size_t)
+        };
+        if p.is_null() {
+            None
+        } else {
+            Some(p as usize - (haystack.as_ptr() as usize))
+        }
+    }
+
+    #[cfg(not(target_os = "linux"))]
+    fn memrchr_specific(needle: u8, haystack: &[u8]) -> Option<usize> {
+        ::sys_common::memchr::fallback::memrchr(needle, haystack)
+    }
+
+    memrchr_specific(needle, haystack)
+}
diff --git a/src/libstd/sys/unix/mod.rs b/src/libstd/sys/unix/mod.rs
index 3fbeda58e82..dc410cba89e 100644
--- a/src/libstd/sys/unix/mod.rs
+++ b/src/libstd/sys/unix/mod.rs
@@ -30,17 +30,21 @@ use libc;
 #[macro_use]
 pub mod weak;
 
+pub mod args;
 pub mod android;
 #[cfg(any(not(cargobuild), feature = "backtrace"))]
 pub mod backtrace;
 pub mod condvar;
+pub mod env;
 pub mod ext;
 pub mod fd;
 pub mod fs;
+pub mod memchr;
 pub mod mutex;
 pub mod net;
 pub mod os;
 pub mod os_str;
+pub mod path;
 pub mod pipe;
 pub mod process;
 pub mod rand;
diff --git a/src/libstd/sys/unix/os.rs b/src/libstd/sys/unix/os.rs
index 850c3d52715..c6118a333b1 100644
--- a/src/libstd/sys/unix/os.rs
+++ b/src/libstd/sys/unix/os.rs
@@ -347,126 +347,6 @@ pub fn current_exe() -> io::Result<PathBuf> {
     }
 }
 
-pub struct Args {
-    iter: vec::IntoIter<OsString>,
-    _dont_send_or_sync_me: PhantomData<*mut ()>,
-}
-
-impl Iterator for Args {
-    type Item = OsString;
-    fn next(&mut self) -> Option<OsString> { self.iter.next() }
-    fn size_hint(&self) -> (usize, Option<usize>) { self.iter.size_hint() }
-}
-
-impl ExactSizeIterator for Args {
-    fn len(&self) -> usize { self.iter.len() }
-}
-
-impl DoubleEndedIterator for Args {
-    fn next_back(&mut self) -> Option<OsString> { self.iter.next_back() }
-}
-
-/// Returns the command line arguments
-///
-/// Returns a list of the command line arguments.
-#[cfg(target_os = "macos")]
-pub fn args() -> Args {
-    extern {
-        // These functions are in crt_externs.h.
-        fn _NSGetArgc() -> *mut c_int;
-        fn _NSGetArgv() -> *mut *mut *mut c_char;
-    }
-
-    let vec = unsafe {
-        let (argc, argv) = (*_NSGetArgc() as isize,
-                            *_NSGetArgv() as *const *const c_char);
-        (0.. argc as isize).map(|i| {
-            let bytes = CStr::from_ptr(*argv.offset(i)).to_bytes().to_vec();
-            OsStringExt::from_vec(bytes)
-        }).collect::<Vec<_>>()
-    };
-    Args {
-        iter: vec.into_iter(),
-        _dont_send_or_sync_me: PhantomData,
-    }
-}
-
-// As _NSGetArgc and _NSGetArgv aren't mentioned in iOS docs
-// and use underscores in their names - they're most probably
-// are considered private and therefore should be avoided
-// Here is another way to get arguments using Objective C
-// runtime
-//
-// In general it looks like:
-// res = Vec::new()
-// let args = [[NSProcessInfo processInfo] arguments]
-// for i in (0..[args count])
-//      res.push([args objectAtIndex:i])
-// res
-#[cfg(target_os = "ios")]
-pub fn args() -> Args {
-    use mem;
-
-    extern {
-        fn sel_registerName(name: *const libc::c_uchar) -> Sel;
-        fn objc_msgSend(obj: NsId, sel: Sel, ...) -> NsId;
-        fn objc_getClass(class_name: *const libc::c_uchar) -> NsId;
-    }
-
-    #[link(name = "Foundation", kind = "framework")]
-    #[link(name = "objc")]
-    #[cfg(not(cargobuild))]
-    extern {}
-
-    type Sel = *const libc::c_void;
-    type NsId = *const libc::c_void;
-
-    let mut res = Vec::new();
-
-    unsafe {
-        let process_info_sel = sel_registerName("processInfo\0".as_ptr());
-        let arguments_sel = sel_registerName("arguments\0".as_ptr());
-        let utf8_sel = sel_registerName("UTF8String\0".as_ptr());
-        let count_sel = sel_registerName("count\0".as_ptr());
-        let object_at_sel = sel_registerName("objectAtIndex:\0".as_ptr());
-
-        let klass = objc_getClass("NSProcessInfo\0".as_ptr());
-        let info = objc_msgSend(klass, process_info_sel);
-        let args = objc_msgSend(info, arguments_sel);
-
-        let cnt: usize = mem::transmute(objc_msgSend(args, count_sel));
-        for i in 0..cnt {
-            let tmp = objc_msgSend(args, object_at_sel, i);
-            let utf_c_str: *const libc::c_char =
-                mem::transmute(objc_msgSend(tmp, utf8_sel));
-            let bytes = CStr::from_ptr(utf_c_str).to_bytes();
-            res.push(OsString::from(str::from_utf8(bytes).unwrap()))
-        }
-    }
-
-    Args { iter: res.into_iter(), _dont_send_or_sync_me: PhantomData }
-}
-
-#[cfg(any(target_os = "linux",
-          target_os = "android",
-          target_os = "freebsd",
-          target_os = "dragonfly",
-          target_os = "bitrig",
-          target_os = "netbsd",
-          target_os = "openbsd",
-          target_os = "solaris",
-          target_os = "nacl",
-          target_os = "emscripten",
-          target_os = "haiku"))]
-pub fn args() -> Args {
-    use sys_common;
-    let bytes = sys_common::args::clone().unwrap_or(Vec::new());
-    let v: Vec<OsString> = bytes.into_iter().map(|v| {
-        OsStringExt::from_vec(v)
-    }).collect();
-    Args { iter: v.into_iter(), _dont_send_or_sync_me: PhantomData }
-}
-
 pub struct Env {
     iter: vec::IntoIter<(OsString, OsString)>,
     _dont_send_or_sync_me: PhantomData<*mut ()>,
diff --git a/src/libstd/sys/unix/path.rs b/src/libstd/sys/unix/path.rs
new file mode 100644
index 00000000000..bf9af7a4353
--- /dev/null
+++ b/src/libstd/sys/unix/path.rs
@@ -0,0 +1,29 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use path::Prefix;
+use ffi::OsStr;
+
+#[inline]
+pub fn is_sep_byte(b: u8) -> bool {
+    b == b'/'
+}
+
+#[inline]
+pub fn is_verbatim_sep(b: u8) -> bool {
+    b == b'/'
+}
+
+pub fn parse_prefix(_: &OsStr) -> Option<Prefix> {
+    None
+}
+
+pub const MAIN_SEP_STR: &'static str = "/";
+pub const MAIN_SEP: char = '/';
diff --git a/src/libstd/sys/unix/stdio.rs b/src/libstd/sys/unix/stdio.rs
index 972bdbc3818..947ba2cc752 100644
--- a/src/libstd/sys/unix/stdio.rs
+++ b/src/libstd/sys/unix/stdio.rs
@@ -65,3 +65,5 @@ impl io::Write for Stderr {
     }
     fn flush(&mut self) -> io::Result<()> { Ok(()) }
 }
+
+pub const EBADF_ERR: i32 = ::libc::EBADF as i32;
diff --git a/src/libstd/sys/windows/args.rs b/src/libstd/sys/windows/args.rs
new file mode 100644
index 00000000000..aa61f9adb82
--- /dev/null
+++ b/src/libstd/sys/windows/args.rs
@@ -0,0 +1,76 @@
+// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![allow(dead_code)] // runtime init functions not used during testing
+
+use os::windows::prelude::*;
+use sys::c;
+use slice;
+use ops::Range;
+use ffi::OsString;
+use libc::{c_int, c_void};
+
+pub unsafe fn init(_argc: isize, _argv: *const *const u8) { }
+
+pub unsafe fn cleanup() { }
+
+pub fn args() -> Args {
+    unsafe {
+        let mut nArgs: c_int = 0;
+        let lpCmdLine = c::GetCommandLineW();
+        let szArgList = c::CommandLineToArgvW(lpCmdLine, &mut nArgs);
+
+        // szArcList can be NULL if CommandLinToArgvW failed,
+        // but in that case nArgs is 0 so we won't actually
+        // try to read a null pointer
+        Args { cur: szArgList, range: 0..(nArgs as isize) }
+    }
+}
+
+pub struct Args {
+    range: Range<isize>,
+    cur: *mut *mut u16,
+}
+
+unsafe fn os_string_from_ptr(ptr: *mut u16) -> OsString {
+    let mut len = 0;
+    while *ptr.offset(len) != 0 { len += 1; }
+
+    // Push it onto the list.
+    let ptr = ptr as *const u16;
+    let buf = slice::from_raw_parts(ptr, len as usize);
+    OsStringExt::from_wide(buf)
+}
+
+impl Iterator for Args {
+    type Item = OsString;
+    fn next(&mut self) -> Option<OsString> {
+        self.range.next().map(|i| unsafe { os_string_from_ptr(*self.cur.offset(i)) } )
+    }
+    fn size_hint(&self) -> (usize, Option<usize>) { self.range.size_hint() }
+}
+
+impl DoubleEndedIterator for Args {
+    fn next_back(&mut self) -> Option<OsString> {
+        self.range.next_back().map(|i| unsafe { os_string_from_ptr(*self.cur.offset(i)) } )
+    }
+}
+
+impl ExactSizeIterator for Args {
+    fn len(&self) -> usize { self.range.len() }
+}
+
+impl Drop for Args {
+    fn drop(&mut self) {
+        // self.cur can be null if CommandLineToArgvW previously failed,
+        // but LocalFree ignores NULL pointers
+        unsafe { c::LocalFree(self.cur as *mut c_void); }
+    }
+}
diff --git a/src/libstd/sys/windows/env.rs b/src/libstd/sys/windows/env.rs
new file mode 100644
index 00000000000..e6d74895774
--- /dev/null
+++ b/src/libstd/sys/windows/env.rs
@@ -0,0 +1,19 @@
+// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+pub mod os {
+    pub const FAMILY: &'static str = "windows";
+    pub const OS: &'static str = "windows";
+    pub const DLL_PREFIX: &'static str = "";
+    pub const DLL_SUFFIX: &'static str = ".dll";
+    pub const DLL_EXTENSION: &'static str = "dll";
+    pub const EXE_SUFFIX: &'static str = ".exe";
+    pub const EXE_EXTENSION: &'static str = "exe";
+}
diff --git a/src/libstd/sys/windows/memchr.rs b/src/libstd/sys/windows/memchr.rs
new file mode 100644
index 00000000000..5a5386acaa5
--- /dev/null
+++ b/src/libstd/sys/windows/memchr.rs
@@ -0,0 +1,15 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+//
+// Original implementation taken from rust-memchr
+// Copyright 2015 Andrew Gallant, bluss and Nicolas Koch
+
+// Fallback memchr is fastest on windows
+pub use sys_common::memchr::fallback::{memchr, memrchr};
diff --git a/src/libstd/sys/windows/mod.rs b/src/libstd/sys/windows/mod.rs
index 9741a704e8f..9cd6e6ca176 100644
--- a/src/libstd/sys/windows/mod.rs
+++ b/src/libstd/sys/windows/mod.rs
@@ -18,17 +18,21 @@ use time::Duration;
 
 #[macro_use] pub mod compat;
 
+pub mod args;
 pub mod backtrace;
 pub mod c;
 pub mod condvar;
 pub mod dynamic_lib;
+pub mod env;
 pub mod ext;
 pub mod fs;
 pub mod handle;
+pub mod memchr;
 pub mod mutex;
 pub mod net;
 pub mod os;
 pub mod os_str;
+pub mod path;
 pub mod pipe;
 pub mod process;
 pub mod rand;
diff --git a/src/libstd/sys/windows/os.rs b/src/libstd/sys/windows/os.rs
index 260fc3c4db6..7e28dd1e259 100644
--- a/src/libstd/sys/windows/os.rs
+++ b/src/libstd/sys/windows/os.rs
@@ -18,8 +18,6 @@ use error::Error as StdError;
 use ffi::{OsString, OsStr};
 use fmt;
 use io;
-use libc::{c_int, c_void};
-use ops::Range;
 use os::windows::ffi::EncodeWide;
 use path::{self, PathBuf};
 use ptr;
@@ -272,60 +270,6 @@ pub fn unsetenv(n: &OsStr) -> io::Result<()> {
     }).map(|_| ())
 }
 
-pub struct Args {
-    range: Range<isize>,
-    cur: *mut *mut u16,
-}
-
-unsafe fn os_string_from_ptr(ptr: *mut u16) -> OsString {
-    let mut len = 0;
-    while *ptr.offset(len) != 0 { len += 1; }
-
-    // Push it onto the list.
-    let ptr = ptr as *const u16;
-    let buf = slice::from_raw_parts(ptr, len as usize);
-    OsStringExt::from_wide(buf)
-}
-
-impl Iterator for Args {
-    type Item = OsString;
-    fn next(&mut self) -> Option<OsString> {
-        self.range.next().map(|i| unsafe { os_string_from_ptr(*self.cur.offset(i)) } )
-    }
-    fn size_hint(&self) -> (usize, Option<usize>) { self.range.size_hint() }
-}
-
-impl DoubleEndedIterator for Args {
-    fn next_back(&mut self) -> Option<OsString> {
-        self.range.next_back().map(|i| unsafe { os_string_from_ptr(*self.cur.offset(i)) } )
-    }
-}
-
-impl ExactSizeIterator for Args {
-    fn len(&self) -> usize { self.range.len() }
-}
-
-impl Drop for Args {
-    fn drop(&mut self) {
-        // self.cur can be null if CommandLineToArgvW previously failed,
-        // but LocalFree ignores NULL pointers
-        unsafe { c::LocalFree(self.cur as *mut c_void); }
-    }
-}
-
-pub fn args() -> Args {
-    unsafe {
-        let mut nArgs: c_int = 0;
-        let lpCmdLine = c::GetCommandLineW();
-        let szArgList = c::CommandLineToArgvW(lpCmdLine, &mut nArgs);
-
-        // szArcList can be NULL if CommandLinToArgvW failed,
-        // but in that case nArgs is 0 so we won't actually
-        // try to read a null pointer
-        Args { cur: szArgList, range: 0..(nArgs as isize) }
-    }
-}
-
 pub fn temp_dir() -> PathBuf {
     super::fill_utf16_buf(|buf, sz| unsafe {
         c::GetTempPathW(sz, buf)
diff --git a/src/libstd/sys/windows/path.rs b/src/libstd/sys/windows/path.rs
new file mode 100644
index 00000000000..2b47808451b
--- /dev/null
+++ b/src/libstd/sys/windows/path.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.
+
+use ascii::*;
+
+use path::Prefix;
+use ffi::OsStr;
+use mem;
+
+fn os_str_as_u8_slice(s: &OsStr) -> &[u8] {
+    unsafe { mem::transmute(s) }
+}
+unsafe fn u8_slice_as_os_str(s: &[u8]) -> &OsStr {
+    mem::transmute(s)
+}
+
+#[inline]
+pub fn is_sep_byte(b: u8) -> bool {
+    b == b'/' || b == b'\\'
+}
+
+#[inline]
+pub fn is_verbatim_sep(b: u8) -> bool {
+    b == b'\\'
+}
+
+pub fn parse_prefix<'a>(path: &'a OsStr) -> Option<Prefix> {
+    use path::Prefix::*;
+    unsafe {
+        // The unsafety here stems from converting between &OsStr and &[u8]
+        // and back. This is safe to do because (1) we only look at ASCII
+        // contents of the encoding and (2) new &OsStr values are produced
+        // only from ASCII-bounded slices of existing &OsStr values.
+        let mut path = os_str_as_u8_slice(path);
+
+        if path.starts_with(br"\\") {
+            // \\
+            path = &path[2..];
+            if path.starts_with(br"?\") {
+                // \\?\
+                path = &path[2..];
+                if path.starts_with(br"UNC\") {
+                    // \\?\UNC\server\share
+                    path = &path[4..];
+                    let (server, share) = match parse_two_comps(path, is_verbatim_sep) {
+                        Some((server, share)) =>
+                            (u8_slice_as_os_str(server), u8_slice_as_os_str(share)),
+                        None => (u8_slice_as_os_str(path), u8_slice_as_os_str(&[])),
+                    };
+                    return Some(VerbatimUNC(server, share));
+                } else {
+                    // \\?\path
+                    let idx = path.iter().position(|&b| b == b'\\');
+                    if idx == Some(2) && path[1] == b':' {
+                        let c = path[0];
+                        if c.is_ascii() && (c as char).is_alphabetic() {
+                            // \\?\C:\ path
+                            return Some(VerbatimDisk(c.to_ascii_uppercase()));
+                        }
+                    }
+                    let slice = &path[..idx.unwrap_or(path.len())];
+                    return Some(Verbatim(u8_slice_as_os_str(slice)));
+                }
+            } else if path.starts_with(b".\\") {
+                // \\.\path
+                path = &path[2..];
+                let pos = path.iter().position(|&b| b == b'\\');
+                let slice = &path[..pos.unwrap_or(path.len())];
+                return Some(DeviceNS(u8_slice_as_os_str(slice)));
+            }
+            match parse_two_comps(path, is_sep_byte) {
+                Some((server, share)) if !server.is_empty() && !share.is_empty() => {
+                    // \\server\share
+                    return Some(UNC(u8_slice_as_os_str(server), u8_slice_as_os_str(share)));
+                }
+                _ => (),
+            }
+        } else if path.get(1) == Some(& b':') {
+            // C:
+            let c = path[0];
+            if c.is_ascii() && (c as char).is_alphabetic() {
+                return Some(Disk(c.to_ascii_uppercase()));
+            }
+        }
+        return None;
+    }
+
+    fn parse_two_comps(mut path: &[u8], f: fn(u8) -> bool) -> Option<(&[u8], &[u8])> {
+        let first = match path.iter().position(|x| f(*x)) {
+            None => return None,
+            Some(x) => &path[..x],
+        };
+        path = &path[(first.len() + 1)..];
+        let idx = path.iter().position(|x| f(*x));
+        let second = &path[..idx.unwrap_or(path.len())];
+        Some((first, second))
+    }
+}
+
+pub const MAIN_SEP_STR: &'static str = "\\";
+pub const MAIN_SEP: char = '\\';
diff --git a/src/libstd/sys/windows/stdio.rs b/src/libstd/sys/windows/stdio.rs
index 01249f05f62..5f097d2631d 100644
--- a/src/libstd/sys/windows/stdio.rs
+++ b/src/libstd/sys/windows/stdio.rs
@@ -205,3 +205,5 @@ impl Output {
 fn invalid_encoding() -> io::Error {
     io::Error::new(io::ErrorKind::InvalidData, "text was not valid unicode")
 }
+
+pub const EBADF_ERR: i32 = ::sys::c::ERROR_INVALID_HANDLE as i32;