about summary refs log tree commit diff
path: root/src/libstd/rt
diff options
context:
space:
mode:
authorAlex Crichton <alex@alexcrichton.com>2013-10-25 17:04:37 -0700
committerAlex Crichton <alex@alexcrichton.com>2013-11-03 15:15:42 -0800
commit9c1851019f1ef9511fa8731b8f1acb0796d1e97f (patch)
tree0cd6d600bfc077e1d19722afdb042c9c016db621 /src/libstd/rt
parent7bf58c2baaac3f7cb3c8e8d735b27ac9e7d3cd78 (diff)
downloadrust-9c1851019f1ef9511fa8731b8f1acb0796d1e97f.tar.gz
rust-9c1851019f1ef9511fa8731b8f1acb0796d1e97f.zip
Remove all blocking std::os blocking functions
This commit moves all thread-blocking I/O functions from the std::os module.
Their replacements can be found in either std::rt::io::file or in a hidden
"old_os" module inside of native::file. I didn't want to outright delete these
functions because they have a lot of special casing learned over time for each
OS/platform, and I imagine that these will someday get integrated into a
blocking implementation of IoFactory. For now, they're moved to a private module
to prevent bitrot and still have tests to ensure that they work.

I've also expanded the extensions to a few more methods defined on Path, most of
which were previously defined in std::os but now have non-thread-blocking
implementations as part of using the current IoFactory.

The api of io::file is in flux, but I plan on changing it in the next commit as
well.

Closes #10057
Diffstat (limited to 'src/libstd/rt')
-rw-r--r--src/libstd/rt/io/file.rs793
-rw-r--r--src/libstd/rt/io/mod.rs21
-rw-r--r--src/libstd/rt/io/native/file.rs483
-rw-r--r--src/libstd/rt/io/net/unix.rs3
-rw-r--r--src/libstd/rt/io/signal.rs7
-rw-r--r--src/libstd/rt/io/timer.rs1
-rw-r--r--src/libstd/rt/rtio.rs7
7 files changed, 900 insertions, 415 deletions
diff --git a/src/libstd/rt/io/file.rs b/src/libstd/rt/io/file.rs
index 99a4a709504..b6c0b58434f 100644
--- a/src/libstd/rt/io/file.rs
+++ b/src/libstd/rt/io/file.rs
@@ -13,50 +13,43 @@
 This module provides a set of functions and traits for working
 with regular files & directories on a filesystem.
 
-At the top-level of the module are a set of freestanding functions,
-associated with various filesystem operations. They all operate
-on a `ToCStr` object. This trait is already defined for common
-objects such as strings and `Path` instances.
+At the top-level of the module are a set of freestanding functions, associated
+with various filesystem operations. They all operate on a `Path` object.
 
 All operations in this module, including those as part of `FileStream` et al
 block the task during execution. Most will raise `std::rt::io::io_error`
 conditions in the event of failure.
 
-Also included in this module are the `FileInfo` and `DirectoryInfo` traits. When
-`use`'d alongside a value whose type implements them (A `std::path::Path` impl is
-a part of this module), they expose a set of functions for operations against
-a given file location, depending on whether the path already exists. Whenever
-possible, the `{FileInfo, DirectoryInfo}` preserve the same semantics as their
-free function counterparts.
+Also included in this module is an implementation block on the `Path` object
+defined in `std::path::Path`. The impl adds useful methods about inspecting the
+metadata of a file. This includes getting the `stat` information, reading off
+particular bits of it, etc.
+
 */
 
-use prelude::*;
 use c_str::ToCStr;
 use super::{Reader, Writer, Seek};
-use super::{SeekStyle, Read, Write};
+use super::{SeekStyle, Read, Write, Open, CreateOrTruncate,
+            FileMode, FileAccess, FileStat, io_error, FilePermission};
 use rt::rtio::{RtioFileStream, IoFactory, with_local_io};
-use rt::io::{io_error, EndOfFile,
-            FileMode, FileAccess, FileStat, IoError,
-            PathAlreadyExists, PathDoesntExist,
-            MismatchedFileTypeForOperation, ignore_io_error};
-use option::{Some, None};
-use path::Path;
+use rt::io;
+use option::{Some, None, Option};
+use result::{Ok, Err};
+use path;
+use path::{Path, GenericPath};
 
 /// Open a file for reading/writing, as indicated by `path`.
 ///
 /// # Example
 ///
-///     use std;
-///     use std::path::Path;
-///     use std::rt::io::file::open;
-///     use std::rt::io::{FileMode, FileAccess};
+///     use std::rt::{io, file, io_error};
 ///
-///     let p = &Path("/some/file/path.txt");
+///     let p = Path::new("/some/file/path.txt");
 ///
 ///     do io_error::cond.trap(|_| {
 ///         // hoo-boy...
 ///     }).inside {
-///         let stream = match open(p, Create, ReadWrite) {
+///         let stream = match file::open_stream(&p, io::Create, io::ReadWrite) {
 ///             Some(s) => s,
 ///             None => fail!("whoops! I'm sure this raised, anyways..")
 ///         };
@@ -72,24 +65,23 @@ use path::Path;
 ///
 /// Note that, with this function, a `FileStream` is returned regardless of
 /// the access-limitations indicated by `FileAccess` (e.g. calling `write` on a
-/// `FileStream` opened as `ReadOnly` will raise an `io_error` condition at runtime). If you
-/// desire a more-correctly-constrained interface to files, use the
-/// `{open_stream, open_reader, open_writer}` methods that are a part of `FileInfo`
+/// `FileStream` opened as `ReadOnly` will raise an `io_error` condition at
+/// runtime). If you desire a more-correctly-constrained interface to files,
+/// use the `{open_stream, open, create}` methods that are a part of `Path`.
 ///
 /// # Errors
 ///
-/// This function will raise an `io_error` condition under a number of different circumstances,
-/// to include but not limited to:
+/// This function will raise an `io_error` condition under a number of different
+/// circumstances, to include but not limited to:
 ///
-/// * Opening a file that already exists with `FileMode` of `Create` or vice versa (e.g.
-///   opening a non-existant file with `FileMode` or `Open`)
-/// * Attempting to open a file with a `FileAccess` that the user lacks permissions
-///   for
+/// * Opening a file that already exists with `FileMode` of `Create` or vice
+///   versa (e.g.  opening a non-existant file with `FileMode` or `Open`)
+/// * Attempting to open a file with a `FileAccess` that the user lacks
+///   permissions for
 /// * Filesystem-level errors (full disk, etc)
-pub fn open<P: ToCStr>(path: &P,
-                       mode: FileMode,
-                       access: FileAccess
-                      ) -> Option<FileStream> {
+pub fn open_stream(path: &Path,
+                   mode: FileMode,
+                   access: FileAccess) -> Option<FileStream> {
     do with_local_io |io| {
         match io.fs_open(&path.to_c_str(), mode, access) {
             Ok(fd) => Some(FileStream {
@@ -104,16 +96,32 @@ pub fn open<P: ToCStr>(path: &P,
     }
 }
 
+/// Attempts to open a file in read-only mode. This function is equivalent to
+/// `open_stream(path, Open, Read)`, and will raise all of the same errors that
+/// `open_stream` does.
+///
+/// For more information, see the `open_stream` function.
+pub fn open(path: &Path) -> Option<FileReader> {
+    open_stream(path, Open, Read).map(|s| FileReader { stream: s })
+}
+
+/// Attempts to create a file in write-only mode. This function is equivalent to
+/// `open_stream(path, CreateOrTruncate, Write)`, and will raise all of the
+/// same errors that `open_stream` does.
+///
+/// For more information, see the `open_stream` function.
+pub fn create(path: &Path) -> Option<FileWriter> {
+    open_stream(path, CreateOrTruncate, Write).map(|s| FileWriter { stream: s })
+}
+
 /// Unlink a file from the underlying filesystem.
 ///
 /// # Example
 ///
-///     use std;
-///     use std::path::Path;
-///     use std::rt::io::file::unlink;
+///     use std::rt::io::file;
 ///
-///     let p = &Path("/some/file/path.txt");
-///     unlink(p);
+///     let p = Path::new("/some/file/path.txt");
+///     file::unlink(&p);
 ///     // if we made it here without failing, then the
 ///     // unlink operation was successful
 ///
@@ -123,12 +131,13 @@ pub fn open<P: ToCStr>(path: &P,
 ///
 /// # Errors
 ///
-/// This function will raise an `io_error` condition if the user lacks permissions to
-/// remove the file or if some other filesystem-level error occurs
-pub fn unlink<P: ToCStr>(path: &P) {
+/// This function will raise an `io_error` condition if the path points to a
+/// directory, the user lacks permissions to remove the file, or if some other
+/// filesystem-level error occurs.
+pub fn unlink(path: &Path) {
     do with_local_io |io| {
         match io.fs_unlink(&path.to_c_str()) {
-            Ok(_) => Some(()),
+            Ok(()) => Some(()),
             Err(ioerr) => {
                 io_error::cond.raise(ioerr);
                 None
@@ -141,21 +150,21 @@ pub fn unlink<P: ToCStr>(path: &P) {
 ///
 /// # Example
 ///
-///     use std;
-///     use std::path::Path;
-///     use std::rt::io::file::mkdir;
+///     use std::libc::S_IRWXU;
+///     use std::rt::io::file;
 ///
-///     let p = &Path("/some/dir");
-///     mkdir(p);
+///     let p = Path::new("/some/dir");
+///     file::mkdir(&p, S_IRWXU as int);
 ///     // If we got here, our directory exists! Horray!
 ///
 /// # Errors
 ///
-/// This call will raise an `io_error` condition if the user lacks permissions to make a
-/// new directory at the provided path, or if the directory already exists
-pub fn mkdir<P: ToCStr>(path: &P) {
+/// This call will raise an `io_error` condition if the user lacks permissions
+/// to make a new directory at the provided path, or if the directory already
+/// exists.
+pub fn mkdir(path: &Path, mode: FilePermission) {
     do with_local_io |io| {
-        match io.fs_mkdir(&path.to_c_str()) {
+        match io.fs_mkdir(&path.to_c_str(), mode) {
             Ok(_) => Some(()),
             Err(ioerr) => {
                 io_error::cond.raise(ioerr);
@@ -169,19 +178,18 @@ pub fn mkdir<P: ToCStr>(path: &P) {
 ///
 /// # Example
 ///
-///     use std;
-///     use std::path::Path;
-///     use std::rt::io::file::rmdir;
+///     use std::rt::io::file;
 ///
-///     let p = &Path("/some/dir");
-///     rmdir(p);
+///     let p = Path::new("/some/dir");
+///     file::rmdir(&p);
 ///     // good riddance, you mean ol' directory
 ///
 /// # Errors
 ///
-/// This call will raise an `io_error` condition if the user lacks permissions to remove the
-/// directory at the provided path, or if the directory isn't empty
-pub fn rmdir<P: ToCStr>(path: &P) {
+/// This call will raise an `io_error` condition if the user lacks permissions
+/// to remove the directory at the provided path, or if the directory isn't
+/// empty.
+pub fn rmdir(path: &Path) {
     do with_local_io |io| {
         match io.fs_rmdir(&path.to_c_str()) {
             Ok(_) => Some(()),
@@ -198,37 +206,31 @@ pub fn rmdir<P: ToCStr>(path: &P) {
 /// Given a path, query the file system to get information about a file,
 /// directory, etc.
 ///
-/// Returns a `Some(std::rt::io::PathInfo)` on success
+/// Returns a fully-filled out stat structure on succes, and on failure it will
+/// return a dummy stat structure (it is expected that the condition raised is
+/// handled as well).
 ///
 /// # Example
 ///
-///     use std;
-///     use std::path::Path;
-///     use std::rt::io::file::stat;
+///     use std::rt::io::{file, io_error};
 ///
-///     let p = &Path("/some/file/path.txt");
+///     let p = Path::new("/some/file/path.txt");
 ///
 ///     do io_error::cond.trap(|_| {
 ///         // hoo-boy...
 ///     }).inside {
-///         let info = match stat(p) {
-///             Some(s) => s,
-///             None => fail!("whoops! I'm sure this raised, anyways..");
-///         }
-///         if stat.is_file {
+///         let info = file::stat(p);
+///         if info.is_file {
 ///             // just imagine the possibilities ...
 ///         }
-///
-///         // the file stream will be closed at the end of this block
 ///     }
-///     // ..
 ///
 /// # Errors
 ///
 /// This call will raise an `io_error` condition if the user lacks the requisite
 /// permissions to perform a `stat` call on the given path or if there is no
 /// entry in the filesystem at the provided path.
-pub fn stat<P: ToCStr>(path: &P) -> Option<FileStat> {
+pub fn stat(path: &Path) -> FileStat {
     do with_local_io |io| {
         match io.fs_stat(&path.to_c_str()) {
             Ok(p) => Some(p),
@@ -237,20 +239,31 @@ pub fn stat<P: ToCStr>(path: &P) -> Option<FileStat> {
                 None
             }
         }
-    }
+    }.unwrap_or_else(|| {
+        FileStat {
+            path: Path::new(path.to_c_str()),
+            is_file: false,
+            is_dir: false,
+            device: 0,
+            mode: 0,
+            inode: 0,
+            size: 0,
+            created: 0,
+            modified: 0,
+            accessed: 0,
+        }
+    })
 }
 
 /// Retrieve a vector containing all entries within a provided directory
 ///
 /// # Example
 ///
-///     use std;
-///     use std::path::Path;
-///     use std::rt::io::file::readdir;
+///     use std::rt::io::file;
 ///
 ///     fn visit_dirs(dir: &Path, cb: &fn(&Path)) {
 ///         if dir.is_dir() {
-///             let contents = dir.readdir();
+///             let contents = file::readdir(dir).unwrap();
 ///             for entry in contents.iter() {
 ///                 if entry.is_dir() { visit_dirs(entry, cb); }
 ///                 else { cb(entry); }
@@ -261,10 +274,10 @@ pub fn stat<P: ToCStr>(path: &P) -> Option<FileStat> {
 ///
 /// # Errors
 ///
-/// Will raise an `io_error` condition if the provided `path` doesn't exist,
+/// Will raise an `io_error` condition if the provided `from` doesn't exist,
 /// the process lacks permissions to view the contents or if the `path` points
 /// at a non-directory file
-pub fn readdir<P: ToCStr>(path: &P) -> Option<~[Path]> {
+pub fn readdir(path: &Path) -> ~[Path] {
     do with_local_io |io| {
         match io.fs_readdir(&path.to_c_str(), 0) {
             Ok(p) => Some(p),
@@ -273,66 +286,169 @@ pub fn readdir<P: ToCStr>(path: &P) -> Option<~[Path]> {
                 None
             }
         }
-    }
+    }.unwrap_or_else(|| ~[])
 }
 
-/// Constrained version of `FileStream` that only exposes read-specific operations.
+/// Rename a file or directory to a new name.
 ///
-/// Can be retreived via `FileInfo.open_reader()`.
-pub struct FileReader { priv stream: FileStream }
+/// # Example
+///
+///     use std::rt::io::file;
+///
+///     file::rename(Path::new("foo"), Path::new("bar"));
+///     // Oh boy, nothing was raised!
+///
+/// # Errors
+///
+/// Will raise an `io_error` condition if the provided `path` doesn't exist,
+/// the process lacks permissions to view the contents, or if some other
+/// intermittent I/O error occurs.
+pub fn rename(from: &Path, to: &Path) {
+    do with_local_io |io| {
+        match io.fs_rename(&from.to_c_str(), &to.to_c_str()) {
+            Ok(()) => Some(()),
+            Err(ioerr) => {
+                io_error::cond.raise(ioerr);
+                None
+            }
+        }
+    };
+}
 
-/// a `std::rt::io::Reader` trait impl for file I/O.
-impl Reader for FileReader {
-    fn read(&mut self, buf: &mut [u8]) -> Option<uint> {
-        self.stream.read(buf)
+/// Copies the contents of one file to another.
+///
+/// # Example
+///
+///     use std::rt::io::file;
+///
+///     file::copy(Path::new("foo.txt"), Path::new("bar.txt"));
+///     // Oh boy, nothing was raised!
+///
+/// # Errors
+///
+/// Will raise an `io_error` condition if the provided `from` doesn't exist,
+/// the process lacks permissions to view the contents, or if some other
+/// intermittent I/O error occurs (such as `to` couldn't be created).
+pub fn copy(from: &Path, to: &Path) {
+    let mut reader = match open(from) { Some(f) => f, None => return };
+    let mut writer = match create(to) { Some(f) => f, None => return };
+    let mut buf = [0, ..io::DEFAULT_BUF_SIZE];
+
+    loop {
+        match reader.read(buf) {
+            Some(amt) => writer.write(buf.slice_to(amt)),
+            None => break
+        }
     }
 
-    fn eof(&mut self) -> bool {
-        self.stream.eof()
-    }
+    // FIXME(#10131) this is an awful way to pull out the permission bits.
+    //               If this comment is removed, then there should be a test
+    //               asserting that permission bits are maintained using the
+    //               permission interface created.
+    chmod(to, (from.stat().mode & 0xfff) as u32);
 }
 
-/// a `std::rt::io::Seek` trait impl for file I/O.
-impl Seek for FileReader {
-    fn tell(&self) -> u64 {
-        self.stream.tell()
-    }
+// This function is not public because it's got a terrible interface for `mode`
+// FIXME(#10131)
+fn chmod(path: &Path, mode: u32) {
+    do with_local_io |io| {
+        match io.fs_chmod(&path.to_c_str(), mode) {
+            Ok(()) => Some(()),
+            Err(ioerr) => {
+                io_error::cond.raise(ioerr);
+                None
+            }
+        }
+    };
+}
 
-    fn seek(&mut self, pos: i64, style: SeekStyle) {
-        self.stream.seek(pos, style);
+/// Recursively walk a directory structure. This function will call the
+/// provided closure on all directories and files found inside the path
+/// pointed to by `self`. If the closure returns `false`, then the iteration
+/// will be short-circuited.
+pub fn walk_dir(path: &Path, f: &fn(&Path) -> bool) -> bool {
+    let files = readdir(path);
+    files.iter().advance(|q| {
+        f(q) && (!q.is_dir() || walk_dir(q, |p| f(p)))
+    })
+}
+
+/// Recursively create a directory and all of its parent components if they
+/// are missing.
+///
+/// # Failure
+///
+/// This function will raise on the `io_error` condition if an error
+/// happens, see `file::mkdir` for more information about error conditions
+/// and performance.
+pub fn mkdir_recursive(path: &Path, mode: FilePermission) {
+    // tjc: if directory exists but with different permissions,
+    // should we return false?
+    if path.is_dir() {
+        return
+    }
+    if path.filename().is_some() {
+        mkdir_recursive(&path.dir_path(), mode);
     }
+    mkdir(path, mode)
 }
 
-/// Constrained version of `FileStream` that only exposes write-specific operations.
+/// Removes a directory at this path, after removing all its contents. Use
+/// carefully!
 ///
-/// Can be retreived via `FileInfo.open_writer()`.
+/// # Failure
+///
+/// This function will raise on the `io_error` condition if an error
+/// happens. See `file::unlink` and `file::readdir` for possible error
+/// conditions.
+pub fn rmdir_recursive(path: &Path) {
+    do walk_dir(path) |inner| {
+        if inner.is_dir() {
+            rmdir_recursive(inner);
+        } else {
+            unlink(inner);
+        }
+        true
+    };
+    // Directory should now be empty
+    rmdir(path);
+}
+
+/// Constrained version of `FileStream` that only exposes read-specific
+/// operations.
+///
+/// Can be retreived via `Path.open()` or `file::open`.
+pub struct FileReader { priv stream: FileStream }
+
+impl Reader for FileReader {
+    fn read(&mut self, buf: &mut [u8]) -> Option<uint> { self.stream.read(buf) }
+    fn eof(&mut self) -> bool { self.stream.eof() }
+}
+
+impl Seek for FileReader {
+    fn tell(&self) -> u64 { self.stream.tell() }
+    fn seek(&mut self, p: i64, s: SeekStyle) { self.stream.seek(p, s) }
+}
+
+/// Constrained version of `FileStream` that only exposes write-specific
+/// operations.
+///
+/// Can be retreived via `Path.create()` or `file::create`.
 pub struct FileWriter { priv stream: FileStream }
 
-/// a `std::rt::io::Writer` trait impl for file I/O.
 impl Writer for FileWriter {
-    fn write(&mut self, buf: &[u8]) {
-        self.stream.write(buf);
-    }
-
-    fn flush(&mut self) {
-        self.stream.flush();
-    }
+    fn write(&mut self, buf: &[u8]) { self.stream.write(buf); }
+    fn flush(&mut self) { self.stream.flush(); }
 }
 
-/// a `std::rt::io::Seek` trait impl for file I/O.
 impl Seek for FileWriter {
-    fn tell(&self) -> u64 {
-        self.stream.tell()
-    }
-
-    fn seek(&mut self, pos: i64, style: SeekStyle) {
-        self.stream.seek(pos, style);
-    }
+    fn tell(&self) -> u64 { self.stream.tell() }
+    fn seek(&mut self, p: i64, s: SeekStyle) { self.stream.seek(p, s); }
 }
 
 /// Unconstrained file access type that exposes read and write operations
 ///
-/// Can be retreived via `file::open()` and `FileInfo.open_stream()`.
+/// Can be retreived via `file::open()` and `Path.open_stream()`.
 ///
 /// # Errors
 ///
@@ -341,13 +457,12 @@ impl Seek for FileWriter {
 /// time, via the `FileAccess` parameter to `file::open()`.
 ///
 /// For this reason, it is best to use the access-constrained wrappers that are
-/// exposed via `FileInfo.open_reader()` and `FileInfo.open_writer()`.
+/// exposed via `Path.open()` and `Path.create()`.
 pub struct FileStream {
     priv fd: ~RtioFileStream,
     priv last_nread: int,
 }
 
-/// a `std::rt::io::Reader` trait impl for file I/O.
 impl Reader for FileStream {
     fn read(&mut self, buf: &mut [u8]) -> Option<uint> {
         match self.fd.read(buf) {
@@ -360,7 +475,7 @@ impl Reader for FileStream {
             },
             Err(ioerr) => {
                 // EOF is indicated by returning None
-                if ioerr.kind != EndOfFile {
+                if ioerr.kind != io::EndOfFile {
                     io_error::cond.raise(ioerr);
                 }
                 return None;
@@ -368,12 +483,9 @@ impl Reader for FileStream {
         }
     }
 
-    fn eof(&mut self) -> bool {
-        self.last_nread == 0
-    }
+    fn eof(&mut self) -> bool { self.last_nread == 0 }
 }
 
-/// a `std::rt::io::Writer` trait impl for file I/O.
 impl Writer for FileStream {
     fn write(&mut self, buf: &[u8]) {
         match self.fd.write(buf) {
@@ -385,7 +497,6 @@ impl Writer for FileStream {
     }
 }
 
-/// a `std::rt::io:Seek` trait impl for file I/O.
 impl Seek for FileStream {
     fn tell(&self) -> u64 {
         let res = self.fd.tell();
@@ -412,166 +523,40 @@ impl Seek for FileStream {
     }
 }
 
-/// Shared functionality between `FileInfo` and `DirectoryInfo`
-pub trait FileSystemInfo {
-    /// Get the filesystem path that this instance points at,
-    /// whether it is valid or not. In this way, it can be used to
-    /// to specify a path of a non-existent file which it
-    /// later creates
-    fn get_path<'a>(&'a self) -> &'a Path;
-
-    /// Get information on the file, directory, etc at the provided path
+impl path::Path {
+    /// Get information on the file, directory, etc at this path.
     ///
     /// Consult the `file::stat` documentation for more info.
     ///
-    /// This call preserves identical runtime/error semantics with `file::stat`
-    fn stat(&self) -> Option<FileStat> {
-        stat(self.get_path())
-    }
+    /// This call preserves identical runtime/error semantics with `file::stat`.
+    pub fn stat(&self) -> FileStat { stat(self) }
 
-    /// Boolean value indicator whether the underlying file exists on the filesystem
+    /// Boolean value indicator whether the underlying file exists on the local
+    /// filesystem. This will return true if the path points to either a
+    /// directory or a file.
     ///
     /// # Errors
     ///
     /// Will not raise a condition
-    fn exists(&self) -> bool {
-        match ignore_io_error(|| self.stat()) {
-            Some(_) => true,
-            None => false
-        }
+    pub fn exists(&self) -> bool {
+        io::result(|| self.stat()).is_ok()
     }
 
-}
-
-/// Represents a file, whose underlying path may or may not be valid
-///
-/// # Example
-///
-/// * Check if a file exists, reading from it if so
-///
-/// ```rust
-/// use std;
-/// use std::path::Path;
-/// use std::rt::io::file::{FileInfo, FileReader};
-///
-/// let f = &Path("/some/file/path.txt");
-/// if f.exists() {
-///     let reader = f.open_reader(Open);
-///     let mut mem = [0u8, 8*64000];
-///     reader.read(mem);
-///     // ...
-/// }
-/// ```
-///
-/// * Is the given path a file?
-///
-/// ```rust
-/// let f = get_file_path_from_wherever();
-/// match f.is_file() {
-///    true => doing_something_with_a_file(f),
-///    _ => {}
-/// }
-/// ```
-pub trait FileInfo : FileSystemInfo {
-    /// Whether the underlying implemention (be it a file path,
-    /// or something else) points at a "regular file" on the FS. Will return
-    /// false for paths to non-existent locations or directories or
-    /// other non-regular files (named pipes, etc).
+    /// Whether the underlying implemention (be it a file path, or something
+    /// else) points at a "regular file" on the FS. Will return false for paths
+    /// to non-existent locations or directories or other non-regular files
+    /// (named pipes, etc).
     ///
     /// # Errors
     ///
     /// Will not raise a condition
-    fn is_file(&self) -> bool {
-        match ignore_io_error(|| self.stat()) {
-            Some(s) => s.is_file,
-            None => false
-        }
-    }
-
-    /// Attempts to open a regular file for reading/writing based
-    /// on provided inputs
-    ///
-    /// See `file::open` for more information on runtime semantics and error conditions
-    fn open_stream(&self, mode: FileMode, access: FileAccess) -> Option<FileStream> {
-        match ignore_io_error(|| self.stat()) {
-            Some(s) => match s.is_file {
-                true => open(self.get_path(), mode, access),
-                false => None
-            },
-            None => open(self.get_path(), mode, access)
+    pub fn is_file(&self) -> bool {
+        match io::result(|| self.stat()) {
+            Ok(s) => s.is_file,
+            Err(*) => false
         }
     }
 
-    /// Attempts to open a regular file in read-only mode, based
-    /// on provided inputs
-    ///
-    /// See `file::open` for more information on runtime semantics and error conditions
-    fn open_reader(&self, mode: FileMode) -> Option<FileReader> {
-        match self.open_stream(mode, Read) {
-            Some(s) => Some(FileReader { stream: s}),
-            None => None
-        }
-    }
-
-    /// Attempts to open a regular file in write-only mode, based
-    /// on provided inputs
-    ///
-    /// See `file::open` for more information on runtime semantics and error conditions
-    fn open_writer(&self, mode: FileMode) -> Option<FileWriter> {
-        match self.open_stream(mode, Write) {
-            Some(s) => Some(FileWriter { stream: s}),
-            None => None
-        }
-    }
-
-    /// Attempt to remove a file from the filesystem
-    ///
-    /// See `file::unlink` for more information on runtime semantics and error conditions
-    fn unlink(&self) {
-        unlink(self.get_path());
-    }
-}
-
-/// `FileSystemInfo` implementation for `Path`s
-impl FileSystemInfo for Path {
-    fn get_path<'a>(&'a self) -> &'a Path { self }
-}
-
-/// `FileInfo` implementation for `Path`s
-impl FileInfo for Path { }
-
-/// Represents a directory, whose underlying path may or may not be valid
-///
-/// # Example
-///
-/// * Check if a directory exists, `mkdir`'ing it if not
-///
-/// ```rust
-/// use std;
-/// use std::path::Path;
-/// use std::rt::io::file::{DirectoryInfo};
-///
-/// let dir = &Path("/some/dir");
-/// if !dir.exists() {
-///     dir.mkdir();
-/// }
-/// ```
-///
-/// * Is the given path a directory? If so, iterate on its contents
-///
-/// ```rust
-/// fn visit_dirs(dir: &Path, cb: &fn(&Path)) {
-///     if dir.is_dir() {
-///         let contents = dir.readdir();
-///         for entry in contents.iter() {
-///             if entry.is_dir() { visit_dirs(entry, cb); }
-///             else { cb(entry); }
-///         }
-///     }
-///     else { fail!("nope"); }
-/// }
-/// ```
-pub trait DirectoryInfo : FileSystemInfo {
     /// Whether the underlying implemention (be it a file path,
     /// or something else) is pointing at a directory in the underlying FS.
     /// Will return false for paths to non-existent locations or if the item is
@@ -580,109 +565,50 @@ pub trait DirectoryInfo : FileSystemInfo {
     /// # Errors
     ///
     /// Will not raise a condition
-    fn is_dir(&self) -> bool {
-        match ignore_io_error(|| self.stat()) {
-            Some(s) => s.is_dir,
-            None => false
+    pub fn is_dir(&self) -> bool {
+        match io::result(|| self.stat()) {
+            Ok(s) => s.is_dir,
+            Err(*) => false
         }
     }
-
-    /// Create a directory at the location pointed to by the
-    /// type underlying the given `DirectoryInfo`.
-    ///
-    /// # Errors
-    ///
-    /// This method will raise a `PathAlreadyExists` kind of `io_error` condition
-    /// if the provided path exists
-    ///
-    /// See `file::mkdir` for more information on runtime semantics and error conditions
-    fn mkdir(&self) {
-        match ignore_io_error(|| self.stat()) {
-            Some(_) => {
-                let path = self.get_path();
-                io_error::cond.raise(IoError {
-                    kind: PathAlreadyExists,
-                    desc: "Path already exists",
-                    detail:
-                        Some(format!("{} already exists; can't mkdir it",
-                                     path.display()))
-                })
-            },
-            None => mkdir(self.get_path())
-        }
-    }
-
-    /// Remove a directory at the given location.
-    ///
-    /// # Errors
-    ///
-    /// This method will raise a `PathDoesntExist` kind of `io_error` condition
-    /// if the provided path exists. It will raise a `MismatchedFileTypeForOperation`
-    /// kind of `io_error` condition if the provided path points at any
-    /// non-directory file type
-    ///
-    /// See `file::rmdir` for more information on runtime semantics and error conditions
-    fn rmdir(&self) {
-        match ignore_io_error(|| self.stat()) {
-            Some(s) => {
-                match s.is_dir {
-                    true => rmdir(self.get_path()),
-                    false => {
-                        let path = self.get_path();
-                        let ioerr = IoError {
-                            kind: MismatchedFileTypeForOperation,
-                            desc: "Cannot do rmdir() on a non-directory",
-                            detail: Some(format!(
-                                "{} is a non-directory; can't rmdir it",
-                                path.display()))
-                        };
-                        io_error::cond.raise(ioerr);
-                    }
-                }
-            },
-            None => {
-                let path = self.get_path();
-                io_error::cond.raise(IoError {
-                    kind: PathDoesntExist,
-                    desc: "Path doesn't exist",
-                    detail: Some(format!("{} doesn't exist; can't rmdir it",
-                                         path.display()))
-                })
-            }
-        }
-    }
-
-    // Get a collection of all entries at the given
-    // directory
-    fn readdir(&self) -> Option<~[Path]> {
-        readdir(self.get_path())
-    }
 }
 
-/// `DirectoryInfo` impl for `path::Path`
-impl DirectoryInfo for Path { }
-
 #[cfg(test)]
 mod test {
-    use super::super::{SeekSet, SeekCur, SeekEnd,
-                       io_error, Read, Create, Open, ReadWrite};
-    use super::super::super::test::*;
+    use path::{Path, GenericPath};
+    use result::{Ok, Err};
     use option::{Some, None};
-    use path::Path;
-    use super::*;
     use iter::range;
+    use rt::test::run_in_mt_newsched_task;
+    use super::{open_stream, unlink, stat, copy, rmdir, mkdir, readdir,
+                open, create, rmdir_recursive, mkdir_recursive};
+
+    use rt::io;
+    use rt::io::Reader;
+    use super::super::{SeekSet, SeekCur, SeekEnd,
+                       io_error, Read, Create, Open, ReadWrite};
+    use vec::Vector;
+
+    fn tmpdir() -> Path {
+        use os;
+        use rand;
+        let ret = os::tmpdir().join(format!("rust-{}", rand::random::<u32>()));
+        mkdir(&ret, io::UserRWX);
+        ret
+    }
+
     #[test]
     fn file_test_io_smoke_test() {
         do run_in_mt_newsched_task {
             let message = "it's alright. have a good time";
             let filename = &Path::new("./tmp/file_rt_io_file_test.txt");
             {
-                let mut write_stream = open(filename, Create, ReadWrite).unwrap();
+                let mut write_stream = open_stream(filename, Create, ReadWrite);
                 write_stream.write(message.as_bytes());
             }
             {
                 use str;
-                let mut read_stream = open(filename, Open, Read).unwrap();
+                let mut read_stream = open_stream(filename, Open, Read);
                 let mut read_buf = [0, .. 1028];
                 let read_str = match read_stream.read(read_buf).unwrap() {
                     -1|0 => fail!("shouldn't happen"),
@@ -702,7 +628,7 @@ mod test {
             do io_error::cond.trap(|_| {
                 called = true;
             }).inside {
-                let result = open(filename, Open, Read);
+                let result = open_stream(filename, Open, Read);
                 assert!(result.is_none());
             }
             assert!(called);
@@ -731,11 +657,11 @@ mod test {
             let mut read_mem = [0, .. 8];
             let filename = &Path::new("./tmp/file_rt_io_file_test_positional.txt");
             {
-                let mut rw_stream = open(filename, Create, ReadWrite).unwrap();
+                let mut rw_stream = open_stream(filename, Create, ReadWrite);
                 rw_stream.write(message.as_bytes());
             }
             {
-                let mut read_stream = open(filename, Open, Read).unwrap();
+                let mut read_stream = open_stream(filename, Open, Read);
                 {
                     let read_buf = read_mem.mut_slice(0, 4);
                     read_stream.read(read_buf);
@@ -762,11 +688,11 @@ mod test {
             let mut tell_pos_post_read;
             let filename = &Path::new("./tmp/file_rt_io_file_test_seeking.txt");
             {
-                let mut rw_stream = open(filename, Create, ReadWrite).unwrap();
+                let mut rw_stream = open_stream(filename, Create, ReadWrite);
                 rw_stream.write(message.as_bytes());
             }
             {
-                let mut read_stream = open(filename, Open, Read).unwrap();
+                let mut read_stream = open_stream(filename, Open, Read);
                 read_stream.seek(set_cursor as i64, SeekSet);
                 tell_pos_pre_read = read_stream.tell();
                 read_stream.read(read_mem);
@@ -791,13 +717,13 @@ mod test {
             let mut read_mem = [0, .. 13];
             let filename = &Path::new("./tmp/file_rt_io_file_test_seek_and_write.txt");
             {
-                let mut rw_stream = open(filename, Create, ReadWrite).unwrap();
+                let mut rw_stream = open_stream(filename, Create, ReadWrite);
                 rw_stream.write(initial_msg.as_bytes());
                 rw_stream.seek(seek_idx as i64, SeekSet);
                 rw_stream.write(overwrite_msg.as_bytes());
             }
             {
-                let mut read_stream = open(filename, Open, Read).unwrap();
+                let mut read_stream = open_stream(filename, Open, Read);
                 read_stream.read(read_mem);
             }
             unlink(filename);
@@ -817,11 +743,11 @@ mod test {
             let mut read_mem = [0, .. 4];
             let filename = &Path::new("./tmp/file_rt_io_file_test_seek_shakedown.txt");
             {
-                let mut rw_stream = open(filename, Create, ReadWrite).unwrap();
+                let mut rw_stream = open_stream(filename, Create, ReadWrite);
                 rw_stream.write(initial_msg.as_bytes());
             }
             {
-                let mut read_stream = open(filename, Open, Read).unwrap();
+                let mut read_stream = open_stream(filename, Open, Read);
 
                 read_stream.seek(-4, SeekEnd);
                 read_stream.read(read_mem);
@@ -847,14 +773,11 @@ mod test {
         do run_in_mt_newsched_task {
             let filename = &Path::new("./tmp/file_stat_correct_on_is_file.txt");
             {
-                let mut fs = open(filename, Create, ReadWrite).unwrap();
+                let mut fs = open_stream(filename, Create, ReadWrite);
                 let msg = "hw";
                 fs.write(msg.as_bytes());
             }
-            let stat_res = match stat(filename) {
-                Some(s) => s,
-                None => fail!("shouldn't happen")
-            };
+            let stat_res = stat(filename);
             assert!(stat_res.is_file);
             unlink(filename);
         }
@@ -864,11 +787,8 @@ mod test {
     fn file_test_stat_is_correct_on_is_dir() {
         do run_in_mt_newsched_task {
             let filename = &Path::new("./tmp/file_stat_correct_on_is_dir");
-            mkdir(filename);
-            let stat_res = match stat(filename) {
-                Some(s) => s,
-                None => fail!("shouldn't happen")
-            };
+            mkdir(filename, io::UserRWX);
+            let stat_res = filename.stat();
             assert!(stat_res.is_dir);
             rmdir(filename);
         }
@@ -878,7 +798,7 @@ mod test {
     fn file_test_fileinfo_false_when_checking_is_file_on_a_directory() {
         do run_in_mt_newsched_task {
             let dir = &Path::new("./tmp/fileinfo_false_on_dir");
-            mkdir(dir);
+            mkdir(dir, io::UserRWX);
             assert!(dir.is_file() == false);
             rmdir(dir);
         }
@@ -888,13 +808,9 @@ mod test {
     fn file_test_fileinfo_check_exists_before_and_after_file_creation() {
         do run_in_mt_newsched_task {
             let file = &Path::new("./tmp/fileinfo_check_exists_b_and_a.txt");
-            {
-                let msg = "foo".as_bytes();
-                let mut w = file.open_writer(Create);
-                w.write(msg);
-            }
+            create(file).write(bytes!("foo"));
             assert!(file.exists());
-            file.unlink();
+            unlink(file);
             assert!(!file.exists());
         }
     }
@@ -904,10 +820,10 @@ mod test {
         do run_in_mt_newsched_task {
             let dir = &Path::new("./tmp/before_and_after_dir");
             assert!(!dir.exists());
-            dir.mkdir();
+            mkdir(dir, io::UserRWX);
             assert!(dir.exists());
             assert!(dir.is_dir());
-            dir.rmdir();
+            rmdir(dir);
             assert!(!dir.exists());
         }
     }
@@ -917,36 +833,99 @@ mod test {
         use str;
         do run_in_mt_newsched_task {
             let dir = &Path::new("./tmp/di_readdir");
-            dir.mkdir();
+            mkdir(dir, io::UserRWX);
             let prefix = "foo";
             for n in range(0,3) {
                 let f = dir.join(format!("{}.txt", n));
-                let mut w = f.open_writer(Create);
+                let mut w = create(&f);
                 let msg_str = (prefix + n.to_str().to_owned()).to_owned();
                 let msg = msg_str.as_bytes();
                 w.write(msg);
             }
-            match dir.readdir() {
-                Some(files) => {
-                    let mut mem = [0u8, .. 4];
-                    for f in files.iter() {
-                        {
-                            let n = f.filestem_str();
-                            let mut r = f.open_reader(Open);
-                            r.read(mem);
-                            let read_str = str::from_utf8(mem);
-                            let expected = match n {
-                                None|Some("") => fail!("really shouldn't happen.."),
-                                Some(n) => prefix+n
-                            };
-                            assert!(expected == read_str);
-                        }
-                        f.unlink();
-                    }
-                },
-                None => fail!("shouldn't happen")
+            let files = readdir(dir);
+            let mut mem = [0u8, .. 4];
+            for f in files.iter() {
+                {
+                    let n = f.filestem_str();
+                    open(f).read(mem);
+                    let read_str = str::from_utf8(mem);
+                    let expected = match n {
+                        None|Some("") => fail!("really shouldn't happen.."),
+                        Some(n) => prefix+n
+                    };
+                    assert!(expected == read_str);
+                }
+                unlink(f);
             }
-            dir.rmdir();
+            rmdir(dir);
         }
     }
+
+    #[test]
+    fn recursive_mkdir_slash() {
+        mkdir_recursive(&Path::new("/"), io::UserRWX);
+    }
+
+    #[test]
+    fn unicode_path_is_dir() {
+        assert!(Path::new(".").is_dir());
+        assert!(!Path::new("test/stdtest/fs.rs").is_dir());
+
+        let tmpdir = tmpdir();
+
+        let mut dirpath = tmpdir.clone();
+        dirpath.push(format!("test-가一ー你好"));
+        mkdir(&dirpath, io::UserRWX);
+        assert!(dirpath.is_dir());
+
+        let mut filepath = dirpath;
+        filepath.push("unicode-file-\uac00\u4e00\u30fc\u4f60\u597d.rs");
+        create(&filepath); // ignore return; touch only
+        assert!(!filepath.is_dir());
+        assert!(filepath.exists());
+
+        rmdir_recursive(&tmpdir);
+    }
+
+    #[test]
+    fn unicode_path_exists() {
+        assert!(Path::new(".").exists());
+        assert!(!Path::new("test/nonexistent-bogus-path").exists());
+
+        let tmpdir = tmpdir();
+        let unicode = tmpdir.clone();
+        let unicode = unicode.join(format!("test-각丁ー再见"));
+        mkdir(&unicode, io::UserRWX);
+        assert!(unicode.exists());
+        assert!(!Path::new("test/unicode-bogus-path-각丁ー再见").exists());
+        rmdir_recursive(&tmpdir);
+    }
+
+    #[test]
+    fn copy_file_does_not_exist() {
+        let from = Path::new("test/nonexistent-bogus-path");
+        let to = Path::new("test/other-bogus-path");
+        match io::result(|| copy(&from, &to)) {
+            Ok(*) => fail!(),
+            Err(*) => {
+                assert!(!from.exists());
+                assert!(!to.exists());
+            }
+        }
+    }
+
+    #[test]
+    fn copy_file_ok() {
+        let tmpdir = tmpdir();
+        let input = tmpdir.join("in.txt");
+        let out = tmpdir.join("out.txt");
+
+        create(&input).write(bytes!("hello"));
+        copy(&input, &out);
+        let contents = open(&out).read_to_end();
+        assert_eq!(contents.as_slice(), bytes!("hello"));
+
+        assert_eq!(input.stat().mode, out.stat().mode);
+        rmdir_recursive(&tmpdir);
+    }
 }
diff --git a/src/libstd/rt/io/mod.rs b/src/libstd/rt/io/mod.rs
index be205749186..51204ca73b9 100644
--- a/src/libstd/rt/io/mod.rs
+++ b/src/libstd/rt/io/mod.rs
@@ -244,9 +244,12 @@ Out of scope
 
 use cast;
 use int;
+use libc;
 use path::Path;
-use prelude::*;
 use str::{StrSlice, OwnedStr};
+use option::{Option, Some, None};
+use result::{Ok, Err, Result};
+use iter::Iterator;
 use to_str::ToStr;
 use uint;
 use unstable::finally::Finally;
@@ -418,6 +421,18 @@ pub fn ignore_io_error<T>(cb: &fn() -> T) -> T {
     }
 }
 
+/// Helper for catching an I/O error and wrapping it in a Result object. The
+/// return result will be the last I/O error that happened or the result of the
+/// closure if no error occurred.
+pub fn result<T>(cb: &fn() -> T) -> Result<T, IoError> {
+    let mut err = None;
+    let ret = io_error::cond.trap(|e| err = Some(e)).inside(cb);
+    match err {
+        Some(e) => Err(e),
+        None => Ok(ret),
+    }
+}
+
 pub trait Reader {
 
     // Only two methods which need to get implemented for this trait
@@ -1137,3 +1152,7 @@ pub struct FileStat {
     /// platform-dependent msecs
     accessed: u64,
 }
+
+// FIXME(#10131): this needs to get designed for real
+pub type FilePermission = u32;
+pub static UserRWX: FilePermission = libc::S_IRWXU as FilePermission;
diff --git a/src/libstd/rt/io/native/file.rs b/src/libstd/rt/io/native/file.rs
index 9f9e7dcee9f..e26cc166c8d 100644
--- a/src/libstd/rt/io/native/file.rs
+++ b/src/libstd/rt/io/native/file.rs
@@ -297,3 +297,486 @@ mod tests {
         }
     }
 }
+
+// n.b. these functions were all part of the old `std::os` module. There's lots
+//      of fun little nuances that were taken care of by these functions, but
+//      they are all thread-blocking versions that are no longer desired (we now
+//      use a non-blocking event loop implementation backed by libuv).
+//
+//      In theory we will have a thread-blocking version of the event loop (if
+//      desired), so these functions may just need to get adapted to work in
+//      those situtations. For now, I'm leaving the code around so it doesn't
+//      get bitrotted instantaneously.
+mod old_os {
+    use prelude::*;
+    use c_str::CString;
+    use libc::fclose;
+    use libc::{size_t, c_void, c_int};
+    use libc;
+    use vec;
+
+    #[cfg(test)] use os;
+    #[cfg(test)] use rand;
+
+    // On Windows, wide character version of function must be used to support
+    // unicode, so functions should be split into at least two versions,
+    // which are for Windows and for non-Windows, if necessary.
+    // See https://github.com/mozilla/rust/issues/9822 for more information.
+
+    mod rustrt {
+        use libc::{c_char, c_int};
+        use libc;
+
+        extern {
+            pub fn rust_path_is_dir(path: *libc::c_char) -> c_int;
+            pub fn rust_path_exists(path: *libc::c_char) -> c_int;
+        }
+
+        // Uses _wstat instead of stat.
+        #[cfg(windows)]
+        extern {
+            pub fn rust_path_is_dir_u16(path: *u16) -> c_int;
+            pub fn rust_path_exists_u16(path: *u16) -> c_int;
+        }
+    }
+
+    /// Recursively walk a directory structure
+    pub fn walk_dir(p: &Path, f: &fn(&Path) -> bool) -> bool {
+        let r = list_dir(p);
+        r.iter().advance(|q| {
+            let path = &p.join(q);
+            f(path) && (!path_is_dir(path) || walk_dir(path, |p| f(p)))
+        })
+    }
+
+    #[cfg(unix)]
+    /// Indicates whether a path represents a directory
+    pub fn path_is_dir(p: &Path) -> bool {
+        #[fixed_stack_segment]; #[inline(never)];
+        unsafe {
+            do p.with_c_str |buf| {
+                rustrt::rust_path_is_dir(buf) != 0 as c_int
+            }
+        }
+    }
+
+
+    #[cfg(windows)]
+    pub fn path_is_dir(p: &Path) -> bool {
+        #[fixed_stack_segment]; #[inline(never)];
+        unsafe {
+            do os::win32::as_utf16_p(p.as_str().unwrap()) |buf| {
+                rustrt::rust_path_is_dir_u16(buf) != 0 as c_int
+            }
+        }
+    }
+
+    #[cfg(unix)]
+    /// Indicates whether a path exists
+    pub fn path_exists(p: &Path) -> bool {
+        #[fixed_stack_segment]; #[inline(never)];
+        unsafe {
+            do p.with_c_str |buf| {
+                rustrt::rust_path_exists(buf) != 0 as c_int
+            }
+        }
+    }
+
+    #[cfg(windows)]
+    pub fn path_exists(p: &Path) -> bool {
+        #[fixed_stack_segment]; #[inline(never)];
+        unsafe {
+            do os::win32::as_utf16_p(p.as_str().unwrap()) |buf| {
+                rustrt::rust_path_exists_u16(buf) != 0 as c_int
+            }
+        }
+    }
+
+    /// Creates a directory at the specified path
+    pub fn make_dir(p: &Path, mode: c_int) -> bool {
+        return mkdir(p, mode);
+
+        #[cfg(windows)]
+        fn mkdir(p: &Path, _mode: c_int) -> bool {
+            #[fixed_stack_segment]; #[inline(never)];
+            unsafe {
+                use os::win32::as_utf16_p;
+                // FIXME: turn mode into something useful? #2623
+                do as_utf16_p(p.as_str().unwrap()) |buf| {
+                    libc::CreateDirectoryW(buf, ptr::mut_null())
+                        != (0 as libc::BOOL)
+                }
+            }
+        }
+
+        #[cfg(unix)]
+        fn mkdir(p: &Path, mode: c_int) -> bool {
+            #[fixed_stack_segment]; #[inline(never)];
+            do p.with_c_str |buf| {
+                unsafe {
+                    libc::mkdir(buf, mode as libc::mode_t) == (0 as c_int)
+                }
+            }
+        }
+    }
+
+    /// Creates a directory with a given mode.
+    /// Returns true iff creation
+    /// succeeded. Also creates all intermediate subdirectories
+    /// if they don't already exist, giving all of them the same mode.
+
+    // tjc: if directory exists but with different permissions,
+    // should we return false?
+    pub fn mkdir_recursive(p: &Path, mode: c_int) -> bool {
+        if path_is_dir(p) {
+            return true;
+        }
+        if p.filename().is_some() {
+            let mut p_ = p.clone();
+            p_.pop();
+            if !mkdir_recursive(&p_, mode) {
+                return false;
+            }
+        }
+        return make_dir(p, mode);
+    }
+
+    /// Lists the contents of a directory
+    ///
+    /// Each resulting Path is a relative path with no directory component.
+    pub fn list_dir(p: &Path) -> ~[Path] {
+        unsafe {
+            #[cfg(target_os = "linux")]
+            #[cfg(target_os = "android")]
+            #[cfg(target_os = "freebsd")]
+            #[cfg(target_os = "macos")]
+            unsafe fn get_list(p: &Path) -> ~[Path] {
+                #[fixed_stack_segment]; #[inline(never)];
+                use libc::{dirent_t};
+                use libc::{opendir, readdir, closedir};
+                extern {
+                    fn rust_list_dir_val(ptr: *dirent_t) -> *libc::c_char;
+                }
+                let mut paths = ~[];
+                debug!("os::list_dir -- BEFORE OPENDIR");
+
+                let dir_ptr = do p.with_c_str |buf| {
+                    opendir(buf)
+                };
+
+                if (dir_ptr as uint != 0) {
+                    debug!("os::list_dir -- opendir() SUCCESS");
+                    let mut entry_ptr = readdir(dir_ptr);
+                    while (entry_ptr as uint != 0) {
+                        let cstr = CString::new(rust_list_dir_val(entry_ptr), false);
+                        paths.push(Path::new(cstr));
+                        entry_ptr = readdir(dir_ptr);
+                    }
+                    closedir(dir_ptr);
+                }
+                else {
+                    debug!("os::list_dir -- opendir() FAILURE");
+                }
+                debug!("os::list_dir -- AFTER -- \\#: {}", paths.len());
+                paths
+            }
+            #[cfg(windows)]
+            unsafe fn get_list(p: &Path) -> ~[Path] {
+                #[fixed_stack_segment]; #[inline(never)];
+                use libc::consts::os::extra::INVALID_HANDLE_VALUE;
+                use libc::{wcslen, free};
+                use libc::funcs::extra::kernel32::{
+                    FindFirstFileW,
+                    FindNextFileW,
+                    FindClose,
+                };
+                use libc::types::os::arch::extra::HANDLE;
+                use os::win32::{
+                    as_utf16_p
+                };
+                use rt::global_heap::malloc_raw;
+
+                #[nolink]
+                extern {
+                    fn rust_list_dir_wfd_size() -> libc::size_t;
+                    fn rust_list_dir_wfd_fp_buf(wfd: *libc::c_void) -> *u16;
+                }
+                let star = p.join("*");
+                do as_utf16_p(star.as_str().unwrap()) |path_ptr| {
+                    let mut paths = ~[];
+                    let wfd_ptr = malloc_raw(rust_list_dir_wfd_size() as uint);
+                    let find_handle = FindFirstFileW(path_ptr, wfd_ptr as HANDLE);
+                    if find_handle as libc::c_int != INVALID_HANDLE_VALUE {
+                        let mut more_files = 1 as libc::c_int;
+                        while more_files != 0 {
+                            let fp_buf = rust_list_dir_wfd_fp_buf(wfd_ptr);
+                            if fp_buf as uint == 0 {
+                                fail!("os::list_dir() failure: got null ptr from wfd");
+                            }
+                            else {
+                                let fp_vec = vec::from_buf(
+                                    fp_buf, wcslen(fp_buf) as uint);
+                                let fp_str = str::from_utf16(fp_vec);
+                                paths.push(Path::new(fp_str));
+                            }
+                            more_files = FindNextFileW(find_handle, wfd_ptr as HANDLE);
+                        }
+                        FindClose(find_handle);
+                        free(wfd_ptr)
+                    }
+                    paths
+                }
+            }
+            do get_list(p).move_iter().filter |path| {
+                path.as_vec() != bytes!(".") && path.as_vec() != bytes!("..")
+            }.collect()
+        }
+    }
+
+    /// Removes a directory at the specified path, after removing
+    /// all its contents. Use carefully!
+    pub fn remove_dir_recursive(p: &Path) -> bool {
+        let mut error_happened = false;
+        do walk_dir(p) |inner| {
+            if !error_happened {
+                if path_is_dir(inner) {
+                    if !remove_dir_recursive(inner) {
+                        error_happened = true;
+                    }
+                }
+                else {
+                    if !remove_file(inner) {
+                        error_happened = true;
+                    }
+                }
+            }
+            true
+        };
+        // Directory should now be empty
+        !error_happened && remove_dir(p)
+    }
+
+    /// Removes a directory at the specified path
+    pub fn remove_dir(p: &Path) -> bool {
+       return rmdir(p);
+
+        #[cfg(windows)]
+        fn rmdir(p: &Path) -> bool {
+            #[fixed_stack_segment]; #[inline(never)];
+            unsafe {
+                use os::win32::as_utf16_p;
+                return do as_utf16_p(p.as_str().unwrap()) |buf| {
+                    libc::RemoveDirectoryW(buf) != (0 as libc::BOOL)
+                };
+            }
+        }
+
+        #[cfg(unix)]
+        fn rmdir(p: &Path) -> bool {
+            #[fixed_stack_segment]; #[inline(never)];
+            do p.with_c_str |buf| {
+                unsafe {
+                    libc::rmdir(buf) == (0 as c_int)
+                }
+            }
+        }
+    }
+
+    /// Deletes an existing file
+    pub fn remove_file(p: &Path) -> bool {
+        return unlink(p);
+
+        #[cfg(windows)]
+        fn unlink(p: &Path) -> bool {
+            #[fixed_stack_segment]; #[inline(never)];
+            unsafe {
+                use os::win32::as_utf16_p;
+                return do as_utf16_p(p.as_str().unwrap()) |buf| {
+                    libc::DeleteFileW(buf) != (0 as libc::BOOL)
+                };
+            }
+        }
+
+        #[cfg(unix)]
+        fn unlink(p: &Path) -> bool {
+            #[fixed_stack_segment]; #[inline(never)];
+            unsafe {
+                do p.with_c_str |buf| {
+                    libc::unlink(buf) == (0 as c_int)
+                }
+            }
+        }
+    }
+
+    /// Renames an existing file or directory
+    pub fn rename_file(old: &Path, new: &Path) -> bool {
+        #[fixed_stack_segment]; #[inline(never)];
+        unsafe {
+           do old.with_c_str |old_buf| {
+                do new.with_c_str |new_buf| {
+                    libc::rename(old_buf, new_buf) == (0 as c_int)
+                }
+           }
+        }
+    }
+
+    /// Copies a file from one location to another
+    pub fn copy_file(from: &Path, to: &Path) -> bool {
+        return do_copy_file(from, to);
+
+        #[cfg(windows)]
+        fn do_copy_file(from: &Path, to: &Path) -> bool {
+            #[fixed_stack_segment]; #[inline(never)];
+            unsafe {
+                use os::win32::as_utf16_p;
+                return do as_utf16_p(from.as_str().unwrap()) |fromp| {
+                    do as_utf16_p(to.as_str().unwrap()) |top| {
+                        libc::CopyFileW(fromp, top, (0 as libc::BOOL)) !=
+                            (0 as libc::BOOL)
+                    }
+                }
+            }
+        }
+
+        #[cfg(unix)]
+        fn do_copy_file(from: &Path, to: &Path) -> bool {
+            #[fixed_stack_segment]; #[inline(never)];
+            unsafe {
+                let istream = do from.with_c_str |fromp| {
+                    do "rb".with_c_str |modebuf| {
+                        libc::fopen(fromp, modebuf)
+                    }
+                };
+                if istream as uint == 0u {
+                    return false;
+                }
+                // Preserve permissions
+                let from_mode = from.stat().mode;
+
+                let ostream = do to.with_c_str |top| {
+                    do "w+b".with_c_str |modebuf| {
+                        libc::fopen(top, modebuf)
+                    }
+                };
+                if ostream as uint == 0u {
+                    fclose(istream);
+                    return false;
+                }
+                let bufsize = 8192u;
+                let mut buf = vec::with_capacity::<u8>(bufsize);
+                let mut done = false;
+                let mut ok = true;
+                while !done {
+                    do buf.as_mut_buf |b, _sz| {
+                      let nread = libc::fread(b as *mut c_void, 1u as size_t,
+                                              bufsize as size_t,
+                                              istream);
+                      if nread > 0 as size_t {
+                          if libc::fwrite(b as *c_void, 1u as size_t, nread,
+                                          ostream) != nread {
+                              ok = false;
+                              done = true;
+                          }
+                      } else {
+                          done = true;
+                      }
+                  }
+                }
+                fclose(istream);
+                fclose(ostream);
+
+                // Give the new file the old file's permissions
+                if do to.with_c_str |to_buf| {
+                    libc::chmod(to_buf, from_mode as libc::mode_t)
+                } != 0 {
+                    return false; // should be a condition...
+                }
+                return ok;
+            }
+        }
+    }
+
+    #[test]
+    fn tmpdir() {
+        let p = os::tmpdir();
+        let s = p.as_str();
+        assert!(s.is_some() && s.unwrap() != ".");
+    }
+
+    // Issue #712
+    #[test]
+    fn test_list_dir_no_invalid_memory_access() {
+        list_dir(&Path::new("."));
+    }
+
+    #[test]
+    fn test_list_dir() {
+        let dirs = list_dir(&Path::new("."));
+        // Just assuming that we've got some contents in the current directory
+        assert!(dirs.len() > 0u);
+
+        for dir in dirs.iter() {
+            debug!("{:?}", (*dir).clone());
+        }
+    }
+
+    #[test]
+    #[cfg(not(windows))]
+    fn test_list_dir_root() {
+        let dirs = list_dir(&Path::new("/"));
+        assert!(dirs.len() > 1);
+    }
+    #[test]
+    #[cfg(windows)]
+    fn test_list_dir_root() {
+        let dirs = list_dir(&Path::new("C:\\"));
+        assert!(dirs.len() > 1);
+    }
+
+    #[test]
+    fn test_path_is_dir() {
+        use rt::io::file::{open_stream, mkdir_recursive};
+        use rt::io::{OpenOrCreate, Read, UserRWX};
+
+        assert!((path_is_dir(&Path::new("."))));
+        assert!((!path_is_dir(&Path::new("test/stdtest/fs.rs"))));
+
+        let mut dirpath = os::tmpdir();
+        dirpath.push(format!("rust-test-{}/test-\uac00\u4e00\u30fc\u4f60\u597d",
+            rand::random::<u32>())); // 가一ー你好
+        debug!("path_is_dir dirpath: {}", dirpath.display());
+
+        mkdir_recursive(&dirpath, UserRWX);
+
+        assert!((path_is_dir(&dirpath)));
+
+        let mut filepath = dirpath;
+        filepath.push("unicode-file-\uac00\u4e00\u30fc\u4f60\u597d.rs");
+        debug!("path_is_dir filepath: {}", filepath.display());
+
+        open_stream(&filepath, OpenOrCreate, Read); // ignore return; touch only
+        assert!((!path_is_dir(&filepath)));
+
+        assert!((!path_is_dir(&Path::new(
+                     "test/unicode-bogus-dir-\uac00\u4e00\u30fc\u4f60\u597d"))));
+    }
+
+    #[test]
+    fn test_path_exists() {
+        use rt::io::file::mkdir_recursive;
+        use rt::io::UserRWX;
+
+        assert!((path_exists(&Path::new("."))));
+        assert!((!path_exists(&Path::new(
+                     "test/nonexistent-bogus-path"))));
+
+        let mut dirpath = os::tmpdir();
+        dirpath.push(format!("rust-test-{}/test-\uac01\u4e01\u30fc\u518d\u89c1",
+            rand::random::<u32>())); // 각丁ー再见
+
+        mkdir_recursive(&dirpath, UserRWX);
+        assert!((path_exists(&dirpath)));
+        assert!((!path_exists(&Path::new(
+                     "test/unicode-bogus-path-\uac01\u4e01\u30fc\u518d\u89c1"))));
+    }
+}
diff --git a/src/libstd/rt/io/net/unix.rs b/src/libstd/rt/io/net/unix.rs
index f30423812ba..dd8a999c6de 100644
--- a/src/libstd/rt/io/net/unix.rs
+++ b/src/libstd/rt/io/net/unix.rs
@@ -156,7 +156,6 @@ mod tests {
     use rt::test::*;
     use rt::io::*;
     use rt::comm::oneshot;
-    use os;
 
     fn smalltest(server: ~fn(UnixStream), client: ~fn(UnixStream)) {
         let server = Cell::new(server);
@@ -290,7 +289,7 @@ mod tests {
         do run_in_mt_newsched_task {
             let path = next_test_unix();
             let _acceptor = UnixListener::bind(&path).listen();
-            assert!(os::path_exists(&path));
+            assert!(path.exists());
         }
     }
 }
diff --git a/src/libstd/rt/io/signal.rs b/src/libstd/rt/io/signal.rs
index b782d713950..1b856ab0755 100644
--- a/src/libstd/rt/io/signal.rs
+++ b/src/libstd/rt/io/signal.rs
@@ -19,6 +19,7 @@ definitions for a number of signals.
 
 */
 
+use container::{Map, MutableMap};
 use comm::{Port, SharedChan, stream};
 use hashmap;
 use option::{Some, None};
@@ -146,10 +147,10 @@ impl Listener {
 
 #[cfg(test)]
 mod test {
-    use super::*;
-
     use libc;
     use rt::io::timer;
+    use super::{Listener, Interrupt};
+    use comm::{GenericPort, Peekable};
 
     // kill is only available on Unixes
     #[cfg(unix)]
@@ -207,7 +208,7 @@ mod test {
     #[cfg(windows)]
     #[test]
     fn test_io_signal_invalid_signum() {
-        use rt::io;
+        use super::User1;
         let mut s = Listener::new();
         let mut called = false;
         do io::io_error::cond.trap(|_| {
diff --git a/src/libstd/rt/io/timer.rs b/src/libstd/rt/io/timer.rs
index 500cd91b3db..36092dfbe34 100644
--- a/src/libstd/rt/io/timer.rs
+++ b/src/libstd/rt/io/timer.rs
@@ -108,6 +108,7 @@ impl Timer {
 
 #[cfg(test)]
 mod test {
+    use prelude::*;
     use super::*;
     use rt::test::*;
     use cell::Cell;
diff --git a/src/libstd/rt/rtio.rs b/src/libstd/rt/rtio.rs
index 44d9f59c410..a0db1f1df00 100644
--- a/src/libstd/rt/rtio.rs
+++ b/src/libstd/rt/rtio.rs
@@ -22,7 +22,7 @@ use super::io::process::ProcessConfig;
 use super::io::net::ip::{IpAddr, SocketAddr};
 use path::Path;
 use super::io::{SeekStyle};
-use super::io::{FileMode, FileAccess, FileStat};
+use super::io::{FileMode, FileAccess, FileStat, FilePermission};
 
 pub trait EventLoop {
     fn run(&mut self);
@@ -102,7 +102,10 @@ pub trait IoFactory {
         -> Result<~RtioFileStream, IoError>;
     fn fs_unlink(&mut self, path: &CString) -> Result<(), IoError>;
     fn fs_stat(&mut self, path: &CString) -> Result<FileStat, IoError>;
-    fn fs_mkdir(&mut self, path: &CString, mode: int) -> Result<(), IoError>;
+    fn fs_mkdir(&mut self, path: &CString,
+                mode: FilePermission) -> Result<(), IoError>;
+    fn fs_chmod(&mut self, path: &CString,
+                mode: FilePermission) -> Result<(), IoError>;
     fn fs_rmdir(&mut self, path: &CString) -> Result<(), IoError>;
     fn fs_rename(&mut self, path: &CString, to: &CString) -> Result<(), IoError>;
     fn fs_readdir(&mut self, path: &CString, flags: c_int) ->