]> git.lizzy.rs Git - rust.git/commitdiff
Refactor std::os to use sys::os
authorAaron Turon <aturon@mozilla.com>
Tue, 25 Nov 2014 00:21:39 +0000 (16:21 -0800)
committerAaron Turon <aturon@mozilla.com>
Fri, 19 Dec 2014 07:31:34 +0000 (23:31 -0800)
src/libstd/os.rs
src/libstd/sys/unix/os.rs
src/libstd/sys/windows/os.rs

index 6e02c03602f1c34b9f14de8d24d3de85a33e60f6..550e9e06aae014c3adc41fde080eb8097a3b9d25 100644 (file)
@@ -46,7 +46,6 @@
 use os;
 use path::{Path, GenericPath, BytesContainer};
 use sys;
-use sys::os as os_imp;
 use ptr::RawPtr;
 use ptr;
 use result::Result;
@@ -78,7 +77,6 @@ pub fn num_cpus() -> uint {
 }
 
 pub const TMPBUF_SZ : uint = 1000u;
-const BUF_BYTES : uint = 2048u;
 
 /// Returns the current working directory as a `Path`.
 ///
@@ -96,118 +94,12 @@ pub fn num_cpus() -> uint {
 /// ```rust
 /// use std::os;
 ///
-/// // We assume that we are in a valid directory like "/home".
+/// // We assume that we are in a valid directory.
 /// let current_working_directory = os::getcwd().unwrap();
 /// println!("The current directory is {}", current_working_directory.display());
-/// // /home
 /// ```
-#[cfg(unix)]
-pub fn getcwd() -> IoResult<Path> {
-    use c_str::CString;
-
-    let mut buf = [0 as c_char, ..BUF_BYTES];
-    unsafe {
-        if libc::getcwd(buf.as_mut_ptr(), buf.len() as libc::size_t).is_null() {
-            Err(IoError::last_error())
-        } else {
-            Ok(Path::new(CString::new(buf.as_ptr(), false)))
-        }
-    }
-}
-
-/// Returns the current working directory as a `Path`.
-///
-/// # Errors
-///
-/// Returns an `Err` if the current working directory value is invalid.
-/// Possible cases:
-///
-/// * Current directory does not exist.
-/// * There are insufficient permissions to access the current directory.
-/// * The internal buffer is not large enough to hold the path.
-///
-/// # Example
-///
-/// ```rust
-/// use std::os;
-///
-/// // We assume that we are in a valid directory like "C:\\Windows".
-/// let current_working_directory = os::getcwd().unwrap();
-/// println!("The current directory is {}", current_working_directory.display());
-/// // C:\\Windows
-/// ```
-#[cfg(windows)]
 pub fn getcwd() -> IoResult<Path> {
-    use libc::DWORD;
-    use libc::GetCurrentDirectoryW;
-    use io::OtherIoError;
-
-    let mut buf = [0 as u16, ..BUF_BYTES];
-    unsafe {
-        if libc::GetCurrentDirectoryW(buf.len() as DWORD, buf.as_mut_ptr()) == 0 as DWORD {
-            return Err(IoError::last_error());
-        }
-    }
-
-    match String::from_utf16(::str::truncate_utf16_at_nul(&buf)) {
-        Some(ref cwd) => Ok(Path::new(cwd)),
-        None => Err(IoError {
-            kind: OtherIoError,
-            desc: "GetCurrentDirectoryW returned invalid UTF-16",
-            detail: None,
-        }),
-    }
-}
-
-#[cfg(windows)]
-pub mod windoze {
-    use libc::types::os::arch::extra::DWORD;
-    use libc;
-    use ops::FnMut;
-    use option::Option;
-    use option::Option::None;
-    use option;
-    use os::TMPBUF_SZ;
-    use slice::SliceExt;
-    use string::String;
-    use str::StrPrelude;
-    use vec::Vec;
-
-    pub fn fill_utf16_buf_and_decode<F>(mut f: F) -> Option<String> where
-        F: FnMut(*mut u16, DWORD) -> DWORD,
-    {
-
-        unsafe {
-            let mut n = TMPBUF_SZ as DWORD;
-            let mut res = None;
-            let mut done = false;
-            while !done {
-                let mut buf = Vec::from_elem(n as uint, 0u16);
-                let k = f(buf.as_mut_ptr(), n);
-                if k == (0 as DWORD) {
-                    done = true;
-                } else if k == n &&
-                          libc::GetLastError() ==
-                          libc::ERROR_INSUFFICIENT_BUFFER as DWORD {
-                    n *= 2 as DWORD;
-                } else if k >= n {
-                    n = k;
-                } else {
-                    done = true;
-                }
-                if k != 0 && done {
-                    let sub = buf.slice(0, k as uint);
-                    // We want to explicitly catch the case when the
-                    // closure returned invalid UTF-16, rather than
-                    // set `res` to None and continue.
-                    let s = String::from_utf16(sub)
-                        .expect("fill_utf16_buf_and_decode: closure created invalid UTF-16");
-                    res = option::Option::Some(s)
-                }
-            }
-            return res;
-        }
-    }
+    sys::os::getcwd()
 }
 
 /*
@@ -253,71 +145,6 @@ pub fn env() -> Vec<(String,String)> {
 /// environment variables of the current process.
 pub fn env_as_bytes() -> Vec<(Vec<u8>,Vec<u8>)> {
     unsafe {
-        #[cfg(windows)]
-        unsafe fn get_env_pairs() -> Vec<Vec<u8>> {
-            use slice;
-
-            use libc::funcs::extra::kernel32::{
-                GetEnvironmentStringsW,
-                FreeEnvironmentStringsW
-            };
-            let ch = GetEnvironmentStringsW();
-            if ch as uint == 0 {
-                panic!("os::env() failure getting env string from OS: {}",
-                       os::last_os_error());
-            }
-            // Here, we lossily decode the string as UTF16.
-            //
-            // The docs suggest that the result should be in Unicode, but
-            // Windows doesn't guarantee it's actually UTF16 -- it doesn't
-            // validate the environment string passed to CreateProcess nor
-            // SetEnvironmentVariable.  Yet, it's unlikely that returning a
-            // raw u16 buffer would be of practical use since the result would
-            // be inherently platform-dependent and introduce additional
-            // complexity to this code.
-            //
-            // Using the non-Unicode version of GetEnvironmentStrings is even
-            // worse since the result is in an OEM code page.  Characters that
-            // can't be encoded in the code page would be turned into question
-            // marks.
-            let mut result = Vec::new();
-            let mut i = 0;
-            while *ch.offset(i) != 0 {
-                let p = &*ch.offset(i);
-                let mut len = 0;
-                while *(p as *const _).offset(len) != 0 {
-                    len += 1;
-                }
-                let p = p as *const u16;
-                let s = slice::from_raw_buf(&p, len as uint);
-                result.push(String::from_utf16_lossy(s).into_bytes());
-                i += len as int + 1;
-            }
-            FreeEnvironmentStringsW(ch);
-            result
-        }
-        #[cfg(unix)]
-        unsafe fn get_env_pairs() -> Vec<Vec<u8>> {
-            use c_str::CString;
-
-            extern {
-                fn rust_env_pairs() -> *const *const c_char;
-            }
-            let mut environ = rust_env_pairs();
-            if environ as uint == 0 {
-                panic!("os::env() failure getting env string from OS: {}",
-                       os::last_os_error());
-            }
-            let mut result = Vec::new();
-            while *environ != 0 as *const _ {
-                let env_pair =
-                    CString::new(*environ, false).as_bytes_no_nul().to_vec();
-                result.push(env_pair);
-                environ = environ.offset(1);
-            }
-            result
-        }
-
         fn env_convert(input: Vec<Vec<u8>>) -> Vec<(Vec<u8>, Vec<u8>)> {
             let mut pairs = Vec::new();
             for p in input.iter() {
@@ -330,7 +157,7 @@ fn env_convert(input: Vec<Vec<u8>>) -> Vec<(Vec<u8>, Vec<u8>)> {
             pairs
         }
         with_env_lock(|| {
-            let unparsed_environ = get_env_pairs();
+            let unparsed_environ = sys::os::get_env_pairs();
             env_convert(unparsed_environ)
         })
     }
@@ -390,7 +217,7 @@ pub fn getenv_as_bytes(n: &str) -> Option<Vec<u8>> {
 pub fn getenv(n: &str) -> Option<String> {
     unsafe {
         with_env_lock(|| {
-            use os::windoze::{fill_utf16_buf_and_decode};
+            use sys::os::fill_utf16_buf_and_decode;
             let mut n: Vec<u16> = n.utf16_units().collect();
             n.push(0);
             fill_utf16_buf_and_decode(|buf, sz| {
@@ -506,52 +333,7 @@ fn _unsetenv(n: &str) {
 /// }
 /// ```
 pub fn split_paths<T: BytesContainer>(unparsed: T) -> Vec<Path> {
-    #[cfg(unix)]
-    fn _split_paths<T: BytesContainer>(unparsed: T) -> Vec<Path> {
-        unparsed.container_as_bytes()
-                .split(|b| *b == b':')
-                .map(Path::new)
-                .collect()
-    }
-
-    #[cfg(windows)]
-    fn _split_paths<T: BytesContainer>(unparsed: T) -> Vec<Path> {
-        // On Windows, the PATH environment variable is semicolon separated.  Double
-        // quotes are used as a way of introducing literal semicolons (since
-        // c:\some;dir is a valid Windows path). Double quotes are not themselves
-        // permitted in path names, so there is no way to escape a double quote.
-        // Quoted regions can appear in arbitrary locations, so
-        //
-        //   c:\foo;c:\som"e;di"r;c:\bar
-        //
-        // Should parse as [c:\foo, c:\some;dir, c:\bar].
-        //
-        // (The above is based on testing; there is no clear reference available
-        // for the grammar.)
-
-        let mut parsed = Vec::new();
-        let mut in_progress = Vec::new();
-        let mut in_quote = false;
-
-        for b in unparsed.container_as_bytes().iter() {
-            match *b {
-                b';' if !in_quote => {
-                    parsed.push(Path::new(in_progress.as_slice()));
-                    in_progress.truncate(0)
-                }
-                b'"' => {
-                    in_quote = !in_quote;
-                }
-                _  => {
-                    in_progress.push(*b);
-                }
-            }
-        }
-        parsed.push(Path::new(in_progress));
-        parsed
-    }
-
-    _split_paths(unparsed)
+    sys::os::split_paths(unparsed.container_as_bytes())
 }
 
 /// Joins a collection of `Path`s appropriately for the `PATH`
@@ -576,42 +358,7 @@ fn _split_paths<T: BytesContainer>(unparsed: T) -> Vec<Path> {
 /// os::setenv(key, os::join_paths(paths.as_slice()).unwrap());
 /// ```
 pub fn join_paths<T: BytesContainer>(paths: &[T]) -> Result<Vec<u8>, &'static str> {
-    #[cfg(windows)]
-    fn _join_paths<T: BytesContainer>(paths: &[T]) -> Result<Vec<u8>, &'static str> {
-        let mut joined = Vec::new();
-        let sep = b';';
-
-        for (i, path) in paths.iter().map(|p| p.container_as_bytes()).enumerate() {
-            if i > 0 { joined.push(sep) }
-            if path.contains(&b'"') {
-                return Err("path segment contains `\"`");
-            } else if path.contains(&sep) {
-                joined.push(b'"');
-                joined.push_all(path);
-                joined.push(b'"');
-            } else {
-                joined.push_all(path);
-            }
-        }
-
-        Ok(joined)
-    }
-
-    #[cfg(unix)]
-    fn _join_paths<T: BytesContainer>(paths: &[T]) -> Result<Vec<u8>, &'static str> {
-        let mut joined = Vec::new();
-        let sep = b':';
-
-        for (i, path) in paths.iter().map(|p| p.container_as_bytes()).enumerate() {
-            if i > 0 { joined.push(sep) }
-            if path.contains(&sep) { return Err("path segment contains separator `:`") }
-            joined.push_all(path);
-        }
-
-        Ok(joined)
-    }
-
-    _join_paths(paths)
+    sys::os::join_paths(paths)
 }
 
 /// A low-level OS in-memory pipe.
@@ -664,69 +411,7 @@ pub fn dll_filename(base: &str) -> String {
 /// };
 /// ```
 pub fn self_exe_name() -> Option<Path> {
-
-    #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
-    fn load_self() -> Option<Vec<u8>> {
-        unsafe {
-            use libc::funcs::bsd44::*;
-            use libc::consts::os::extra::*;
-            let mut mib = vec![CTL_KERN as c_int,
-                               KERN_PROC as c_int,
-                               KERN_PROC_PATHNAME as c_int,
-                               -1 as c_int];
-            let mut sz: libc::size_t = 0;
-            let err = sysctl(mib.as_mut_ptr(), mib.len() as ::libc::c_uint,
-                             ptr::null_mut(), &mut sz, ptr::null_mut(),
-                             0u as libc::size_t);
-            if err != 0 { return None; }
-            if sz == 0 { return None; }
-            let mut v: Vec<u8> = Vec::with_capacity(sz as uint);
-            let err = sysctl(mib.as_mut_ptr(), mib.len() as ::libc::c_uint,
-                             v.as_mut_ptr() as *mut c_void, &mut sz,
-                             ptr::null_mut(), 0u as libc::size_t);
-            if err != 0 { return None; }
-            if sz == 0 { return None; }
-            v.set_len(sz as uint - 1); // chop off trailing NUL
-            Some(v)
-        }
-    }
-
-    #[cfg(any(target_os = "linux", target_os = "android"))]
-    fn load_self() -> Option<Vec<u8>> {
-        use std::io;
-
-        match io::fs::readlink(&Path::new("/proc/self/exe")) {
-            Ok(path) => Some(path.into_vec()),
-            Err(..) => None
-        }
-    }
-
-    #[cfg(any(target_os = "macos", target_os = "ios"))]
-    fn load_self() -> Option<Vec<u8>> {
-        unsafe {
-            use libc::funcs::extra::_NSGetExecutablePath;
-            let mut sz: u32 = 0;
-            _NSGetExecutablePath(ptr::null_mut(), &mut sz);
-            if sz == 0 { return None; }
-            let mut v: Vec<u8> = Vec::with_capacity(sz as uint);
-            let err = _NSGetExecutablePath(v.as_mut_ptr() as *mut i8, &mut sz);
-            if err != 0 { return None; }
-            v.set_len(sz as uint - 1); // chop off trailing NUL
-            Some(v)
-        }
-    }
-
-    #[cfg(windows)]
-    fn load_self() -> Option<Vec<u8>> {
-        unsafe {
-            use os::windoze::fill_utf16_buf_and_decode;
-            fill_utf16_buf_and_decode(|buf, sz| {
-                libc::GetModuleFileNameW(0u as libc::DWORD, buf, sz)
-            }).map(|s| s.into_string().into_bytes())
-        }
-    }
-
-    load_self().and_then(Path::new_opt)
+    sys::os::load_self().and_then(Path::new_opt)
 }
 
 /// Optionally returns the filesystem path to the current executable which is
@@ -842,7 +527,6 @@ fn lookup() -> Path {
     }
 }
 
-///
 /// Convert a relative path to an absolute path
 ///
 /// If the given path is relative, return it prepended with the current working
@@ -887,37 +571,12 @@ pub fn make_absolute(p: &Path) -> IoResult<Path> {
 /// println!("Successfully changed working directory to {}!", root.display());
 /// ```
 pub fn change_dir(p: &Path) -> IoResult<()> {
-    return chdir(p);
-
-    #[cfg(windows)]
-    fn chdir(p: &Path) -> IoResult<()> {
-        let mut p = p.as_str().unwrap().utf16_units().collect::<Vec<u16>>();
-        p.push(0);
-
-        unsafe {
-            match libc::SetCurrentDirectoryW(p.as_ptr()) != (0 as libc::BOOL) {
-                true => Ok(()),
-                false => Err(IoError::last_error()),
-            }
-        }
-    }
-
-    #[cfg(unix)]
-    fn chdir(p: &Path) -> IoResult<()> {
-        p.with_c_str(|buf| {
-            unsafe {
-                match libc::chdir(buf) == (0 as c_int) {
-                    true => Ok(()),
-                    false => Err(IoError::last_error()),
-                }
-            }
-        })
-    }
+    return sys::os::chdir(p);
 }
 
 /// Returns the platform-specific value of errno
 pub fn errno() -> uint {
-    os_imp::errno() as uint
+    sys::os::errno() as uint
 }
 
 /// Return the string corresponding to an `errno()` value of `errnum`.
@@ -930,7 +589,7 @@ pub fn errno() -> uint {
 /// println!("{}", os::error_string(os::errno() as uint));
 /// ```
 pub fn error_string(errnum: uint) -> String {
-    return os_imp::error_string(errnum as i32);
+    return sys::os::error_string(errnum as i32);
 }
 
 /// Get a string representing the platform-dependent last error
@@ -1144,38 +803,9 @@ pub fn args_as_bytes() -> Vec<Vec<u8>> {
     pub fn _NSGetArgv() -> *mut *mut *mut c_char;
 }
 
-// Round up `from` to be divisible by `to`
-fn round_up(from: uint, to: uint) -> uint {
-    let r = if from % to == 0 {
-        from
-    } else {
-        from + to - (from % to)
-    };
-    if r == 0 {
-        to
-    } else {
-        r
-    }
-}
-
 /// Returns the page size of the current architecture in bytes.
-#[cfg(unix)]
 pub fn page_size() -> uint {
-    unsafe {
-        libc::sysconf(libc::_SC_PAGESIZE) as uint
-    }
-}
-
-/// Returns the page size of the current architecture in bytes.
-#[cfg(windows)]
-pub fn page_size() -> uint {
-    use mem;
-    unsafe {
-        let mut info = mem::zeroed();
-        libc::GetSystemInfo(&mut info);
-
-        return info.dwPageSize as uint;
-    }
+    sys::os::page_size()
 }
 
 /// A memory mapped file or chunk of memory. This is a very system-specific
@@ -1325,6 +955,20 @@ fn from_error(err: MapError) -> Box<Error> {
     }
 }
 
+// Round up `from` to be divisible by `to`
+fn round_up(from: uint, to: uint) -> uint {
+    let r = if from % to == 0 {
+        from
+    } else {
+        from + to - (from % to)
+    };
+    if r == 0 {
+        to
+    } else {
+        r
+    }
+}
+
 #[cfg(unix)]
 impl MemoryMap {
     /// Create a new mapping with the given `options`, at least `min_len` bytes
index d951977fa5943e0514cc239ad1a7c0f083d53458..0ed079df55b353f79e882346738db8ddc56dd350 100644 (file)
@@ -8,14 +8,24 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use libc;
-use libc::{c_int, c_char};
+//! Implementation of `std::os` functionality for unix systems
+
 use prelude::*;
-use io::IoResult;
+
+use error::{FromError, Error};
+use fmt;
+use io::{IoError, IoResult};
+use libc::{mod, c_int, c_char, c_void};
+use path::{Path, GenericPath, BytesContainer};
+use ptr::{mod, RawPtr};
+use sync::atomic::{AtomicInt, INIT_ATOMIC_INT, SeqCst};
 use sys::fs::FileDesc;
+use os;
 
 use os::TMPBUF_SZ;
 
+const BUF_BYTES : uint = 2048u;
+
 /// Returns the platform-specific value of errno
 pub fn errno() -> int {
     #[cfg(any(target_os = "macos",
@@ -110,3 +120,122 @@ pub unsafe fn pipe() -> IoResult<(FileDesc, FileDesc)> {
         Err(super::last_error())
     }
 }
+
+pub fn getcwd() -> IoResult<Path> {
+    use c_str::CString;
+
+    let mut buf = [0 as c_char, ..BUF_BYTES];
+    unsafe {
+        if libc::getcwd(buf.as_mut_ptr(), buf.len() as libc::size_t).is_null() {
+            Err(IoError::last_error())
+        } else {
+            Ok(Path::new(CString::new(buf.as_ptr(), false)))
+        }
+    }
+}
+
+pub unsafe fn get_env_pairs() -> Vec<Vec<u8>> {
+    use c_str::CString;
+
+    extern {
+        fn rust_env_pairs() -> *const *const c_char;
+    }
+    let mut environ = rust_env_pairs();
+    if environ as uint == 0 {
+        panic!("os::env() failure getting env string from OS: {}",
+               os::last_os_error());
+    }
+    let mut result = Vec::new();
+    while *environ != 0 as *const _ {
+        let env_pair =
+            CString::new(*environ, false).as_bytes_no_nul().to_vec();
+        result.push(env_pair);
+        environ = environ.offset(1);
+    }
+    result
+}
+
+pub fn split_paths(unparsed: &[u8]) -> Vec<Path> {
+    unparsed.split(|b| *b == b':').map(Path::new).collect()
+}
+
+pub fn join_paths<T: BytesContainer>(paths: &[T]) -> Result<Vec<u8>, &'static str> {
+    let mut joined = Vec::new();
+    let sep = b':';
+
+    for (i, path) in paths.iter().map(|p| p.container_as_bytes()).enumerate() {
+        if i > 0 { joined.push(sep) }
+        if path.contains(&sep) { return Err("path segment contains separator `:`") }
+        joined.push_all(path);
+    }
+
+    Ok(joined)
+}
+
+#[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
+pub fn load_self() -> Option<Vec<u8>> {
+    unsafe {
+        use libc::funcs::bsd44::*;
+        use libc::consts::os::extra::*;
+        let mut mib = vec![CTL_KERN as c_int,
+                           KERN_PROC as c_int,
+                           KERN_PROC_PATHNAME as c_int,
+                           -1 as c_int];
+        let mut sz: libc::size_t = 0;
+        let err = sysctl(mib.as_mut_ptr(), mib.len() as ::libc::c_uint,
+                         ptr::null_mut(), &mut sz, ptr::null_mut(),
+                         0u as libc::size_t);
+        if err != 0 { return None; }
+        if sz == 0 { return None; }
+        let mut v: Vec<u8> = Vec::with_capacity(sz as uint);
+        let err = sysctl(mib.as_mut_ptr(), mib.len() as ::libc::c_uint,
+                         v.as_mut_ptr() as *mut c_void, &mut sz,
+                         ptr::null_mut(), 0u as libc::size_t);
+        if err != 0 { return None; }
+        if sz == 0 { return None; }
+        v.set_len(sz as uint - 1); // chop off trailing NUL
+        Some(v)
+    }
+}
+
+#[cfg(any(target_os = "linux", target_os = "android"))]
+pub fn load_self() -> Option<Vec<u8>> {
+    use std::io;
+
+    match io::fs::readlink(&Path::new("/proc/self/exe")) {
+        Ok(path) => Some(path.into_vec()),
+        Err(..) => None
+    }
+}
+
+#[cfg(any(target_os = "macos", target_os = "ios"))]
+pub fn load_self() -> Option<Vec<u8>> {
+    unsafe {
+        use libc::funcs::extra::_NSGetExecutablePath;
+        let mut sz: u32 = 0;
+        _NSGetExecutablePath(ptr::null_mut(), &mut sz);
+        if sz == 0 { return None; }
+        let mut v: Vec<u8> = Vec::with_capacity(sz as uint);
+        let err = _NSGetExecutablePath(v.as_mut_ptr() as *mut i8, &mut sz);
+        if err != 0 { return None; }
+        v.set_len(sz as uint - 1); // chop off trailing NUL
+        Some(v)
+    }
+}
+
+pub fn chdir(p: &Path) -> IoResult<()> {
+    p.with_c_str(|buf| {
+        unsafe {
+            match libc::chdir(buf) == (0 as c_int) {
+                true => Ok(()),
+                false => Err(IoError::last_error()),
+            }
+        }
+    })
+}
+
+pub fn page_size() -> uint {
+    unsafe {
+        libc::sysconf(libc::_SC_PAGESIZE) as uint
+    }
+}
index aa43b42e74643ea1144d14a0637ded88b52a7c79..5c690180c44d4ed5f6981cc3b87892235f2f6aab 100644 (file)
@@ -8,17 +8,27 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+//! Implementation of `std::os` functionality for Windows
+
 // 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 fmt;
 use io::{IoResult, IoError};
+use libc::{c_int, c_char, c_void};
+use libc;
+use os;
+use path::{Path, GenericPath, BytesContainer};
+use ptr::{mod, RawPtr};
+use sync::atomic::{AtomicInt, INIT_ATOMIC_INT, SeqCst};
 use sys::fs::FileDesc;
-use ptr;
 
 use os::TMPBUF_SZ;
+use libc::types::os::arch::extra::DWORD;
+
+const BUF_BYTES : uint = 2048u;
 
 pub fn errno() -> uint {
     use libc::types::os::arch::extra::DWORD;
@@ -101,3 +111,185 @@ pub unsafe fn pipe() -> IoResult<(FileDesc, FileDesc)> {
         _ => Err(IoError::last_error()),
     }
 }
+
+pub fn fill_utf16_buf_and_decode(f: |*mut u16, DWORD| -> DWORD) -> Option<String> {
+    unsafe {
+        let mut n = TMPBUF_SZ as DWORD;
+        let mut res = None;
+        let mut done = false;
+        while !done {
+            let mut buf = Vec::from_elem(n as uint, 0u16);
+            let k = f(buf.as_mut_ptr(), n);
+            if k == (0 as DWORD) {
+                done = true;
+            } else if k == n &&
+                      libc::GetLastError() ==
+                      libc::ERROR_INSUFFICIENT_BUFFER as DWORD {
+                n *= 2 as DWORD;
+            } else if k >= n {
+                n = k;
+            } else {
+                done = true;
+            }
+            if k != 0 && done {
+                let sub = buf.slice(0, k as uint);
+                // We want to explicitly catch the case when the
+                // closure returned invalid UTF-16, rather than
+                // set `res` to None and continue.
+                let s = String::from_utf16(sub)
+                    .expect("fill_utf16_buf_and_decode: closure created invalid UTF-16");
+                res = option::Some(s)
+            }
+        }
+        return res;
+    }
+}
+
+pub fn getcwd() -> IoResult<Path> {
+    use libc::DWORD;
+    use libc::GetCurrentDirectoryW;
+    use io::OtherIoError;
+
+    let mut buf = [0 as u16, ..BUF_BYTES];
+    unsafe {
+        if libc::GetCurrentDirectoryW(buf.len() as DWORD, buf.as_mut_ptr()) == 0 as DWORD {
+            return Err(IoError::last_error());
+        }
+    }
+
+    match String::from_utf16(::str::truncate_utf16_at_nul(&buf)) {
+        Some(ref cwd) => Ok(Path::new(cwd)),
+        None => Err(IoError {
+            kind: OtherIoError,
+            desc: "GetCurrentDirectoryW returned invalid UTF-16",
+            detail: None,
+        }),
+    }
+}
+
+pub unsafe fn get_env_pairs() -> Vec<Vec<u8>> {
+    use libc::funcs::extra::kernel32::{
+        GetEnvironmentStringsW,
+        FreeEnvironmentStringsW
+    };
+    let ch = GetEnvironmentStringsW();
+    if ch as uint == 0 {
+        panic!("os::env() failure getting env string from OS: {}",
+               os::last_os_error());
+    }
+    // Here, we lossily decode the string as UTF16.
+    //
+    // The docs suggest that the result should be in Unicode, but
+    // Windows doesn't guarantee it's actually UTF16 -- it doesn't
+    // validate the environment string passed to CreateProcess nor
+    // SetEnvironmentVariable.  Yet, it's unlikely that returning a
+    // raw u16 buffer would be of practical use since the result would
+    // be inherently platform-dependent and introduce additional
+    // complexity to this code.
+    //
+    // Using the non-Unicode version of GetEnvironmentStrings is even
+    // worse since the result is in an OEM code page.  Characters that
+    // can't be encoded in the code page would be turned into question
+    // marks.
+    let mut result = Vec::new();
+    let mut i = 0;
+    while *ch.offset(i) != 0 {
+        let p = &*ch.offset(i);
+        let mut len = 0;
+        while *(p as *const _).offset(len) != 0 {
+            len += 1;
+        }
+        let p = p as *const u16;
+        let s = slice::from_raw_buf(&p, len as uint);
+        result.push(String::from_utf16_lossy(s).into_bytes());
+        i += len as int + 1;
+    }
+    FreeEnvironmentStringsW(ch);
+    result
+}
+
+pub fn split_paths(unparsed: &[u8]) -> Vec<Path> {
+    // On Windows, the PATH environment variable is semicolon separated.  Double
+    // quotes are used as a way of introducing literal semicolons (since
+    // c:\some;dir is a valid Windows path). Double quotes are not themselves
+    // permitted in path names, so there is no way to escape a double quote.
+    // Quoted regions can appear in arbitrary locations, so
+    //
+    //   c:\foo;c:\som"e;di"r;c:\bar
+    //
+    // Should parse as [c:\foo, c:\some;dir, c:\bar].
+    //
+    // (The above is based on testing; there is no clear reference available
+    // for the grammar.)
+
+    let mut parsed = Vec::new();
+    let mut in_progress = Vec::new();
+    let mut in_quote = false;
+
+    for b in unparsed.iter() {
+        match *b {
+            b';' if !in_quote => {
+                parsed.push(Path::new(in_progress.as_slice()));
+                in_progress.truncate(0)
+            }
+            b'"' => {
+                in_quote = !in_quote;
+            }
+            _  => {
+                in_progress.push(*b);
+            }
+        }
+    }
+    parsed.push(Path::new(in_progress));
+    parsed
+}
+
+pub fn join_paths<T: BytesContainer>(paths: &[T]) -> Result<Vec<u8>, &'static str> {
+    let mut joined = Vec::new();
+    let sep = b';';
+
+    for (i, path) in paths.iter().map(|p| p.container_as_bytes()).enumerate() {
+        if i > 0 { joined.push(sep) }
+        if path.contains(&b'"') {
+            return Err("path segment contains `\"`");
+        } else if path.contains(&sep) {
+            joined.push(b'"');
+            joined.push_all(path);
+            joined.push(b'"');
+        } else {
+            joined.push_all(path);
+        }
+    }
+
+    Ok(joined)
+}
+
+pub fn load_self() -> Option<Vec<u8>> {
+    unsafe {
+        fill_utf16_buf_and_decode(|buf, sz| {
+            libc::GetModuleFileNameW(0u as libc::DWORD, buf, sz)
+        }).map(|s| s.into_string().into_bytes())
+    }
+}
+
+pub fn chdir(p: &Path) -> IoResult<()> {
+    let mut p = p.as_str().unwrap().utf16_units().collect::<Vec<u16>>();
+    p.push(0);
+
+    unsafe {
+        match libc::SetCurrentDirectoryW(p.as_ptr()) != (0 as libc::BOOL) {
+            true => Ok(()),
+            false => Err(IoError::last_error()),
+        }
+    }
+}
+
+pub fn page_size() -> uint {
+    use mem;
+    unsafe {
+        let mut info = mem::zeroed();
+        libc::GetSystemInfo(&mut info);
+
+        return info.dwPageSize as uint;
+    }
+}