about summary refs log tree commit diff
path: root/src/libstd/rt
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2013-11-04 12:21:11 -0800
committerbors <bors@rust-lang.org>2013-11-04 12:21:11 -0800
commit658637baf45b41e4cff049440bc07f267d810218 (patch)
tree019eee1761d43461ef06f1e5307b57b0b8b47019 /src/libstd/rt
parent70e9b5ab3912da84a32557bc1a34db5fb2178927 (diff)
parent3c3ed1499a9b9e23d4a2d2243a7b0b1c9015f34b (diff)
downloadrust-658637baf45b41e4cff049440bc07f267d810218.tar.gz
rust-658637baf45b41e4cff049440bc07f267d810218.zip
auto merge of #10179 : alexcrichton/rust/rt-improvements, r=cmr
This fleshes out the io::file module a fair bit more, adding all of the functionality that I can think of that we would want. Some questions about the representation which I'm curious about:

* I modified `FileStat` to be a little less platform-agnostic, but it's still fairly platform-specific. I don't want to hide information that we have, but I don't want to depend on this information being available. One possible route is to have an `extra` field which has all this os-dependent stuff which is clearly documented as it should be avoided.

* Does it make sense for directory functions to be top-level functions instead of static methods? It seems silly to import `std::rt::io::file` and `std::rt::io::File` at the top of files that need to deal with directories and files.
Diffstat (limited to 'src/libstd/rt')
-rw-r--r--src/libstd/rt/io/file.rs952
-rw-r--r--src/libstd/rt/io/fs.rs1247
-rw-r--r--src/libstd/rt/io/mod.rs154
-rw-r--r--src/libstd/rt/io/native/file.rs485
-rw-r--r--src/libstd/rt/io/net/unix.rs3
-rw-r--r--src/libstd/rt/io/option.rs2
-rw-r--r--src/libstd/rt/io/signal.rs6
-rw-r--r--src/libstd/rt/io/timer.rs1
-rw-r--r--src/libstd/rt/rtio.rs31
-rw-r--r--src/libstd/rt/sched.rs2
10 files changed, 1881 insertions, 1002 deletions
diff --git a/src/libstd/rt/io/file.rs b/src/libstd/rt/io/file.rs
deleted file mode 100644
index 99a4a709504..00000000000
--- a/src/libstd/rt/io/file.rs
+++ /dev/null
@@ -1,952 +0,0 @@
-// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-/*! Synchronous File I/O
-
-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.
-
-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.
-*/
-
-use prelude::*;
-use c_str::ToCStr;
-use super::{Reader, Writer, Seek};
-use super::{SeekStyle, Read, Write};
-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;
-
-/// 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};
-///
-///     let p = &Path("/some/file/path.txt");
-///
-///     do io_error::cond.trap(|_| {
-///         // hoo-boy...
-///     }).inside {
-///         let stream = match open(p, Create, ReadWrite) {
-///             Some(s) => s,
-///             None => fail!("whoops! I'm sure this raised, anyways..")
-///         };
-///         // do some stuff with that stream
-///
-///         // the file stream will be closed at the end of this block
-///     }
-///     // ..
-///
-/// `FileMode` and `FileAccess` provide information about the permissions
-/// context in which a given stream is created. More information about them
-/// can be found in `std::rt::io`'s docs.
-///
-/// 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`
-///
-/// # Errors
-///
-/// 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
-/// * Filesystem-level errors (full disk, etc)
-pub fn open<P: ToCStr>(path: &P,
-                       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 {
-                fd: fd,
-                last_nread: -1
-            }),
-            Err(ioerr) => {
-                io_error::cond.raise(ioerr);
-                None
-            }
-        }
-    }
-}
-
-/// Unlink a file from the underlying filesystem.
-///
-/// # Example
-///
-///     use std;
-///     use std::path::Path;
-///     use std::rt::io::file::unlink;
-///
-///     let p = &Path("/some/file/path.txt");
-///     unlink(p);
-///     // if we made it here without failing, then the
-///     // unlink operation was successful
-///
-/// Note that, just because an unlink call was successful, it is not
-/// guaranteed that a file is immediately deleted (e.g. depending on
-/// platform, other open file descriptors may prevent immediate removal)
-///
-/// # 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) {
-    do with_local_io |io| {
-        match io.fs_unlink(&path.to_c_str()) {
-            Ok(_) => Some(()),
-            Err(ioerr) => {
-                io_error::cond.raise(ioerr);
-                None
-            }
-        }
-    };
-}
-
-/// Create a new, empty directory at the provided path
-///
-/// # Example
-///
-///     use std;
-///     use std::path::Path;
-///     use std::rt::io::file::mkdir;
-///
-///     let p = &Path("/some/dir");
-///     mkdir(p);
-///     // 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) {
-    do with_local_io |io| {
-        match io.fs_mkdir(&path.to_c_str()) {
-            Ok(_) => Some(()),
-            Err(ioerr) => {
-                io_error::cond.raise(ioerr);
-                None
-            }
-        }
-    };
-}
-
-/// Remove an existing, empty directory
-///
-/// # Example
-///
-///     use std;
-///     use std::path::Path;
-///     use std::rt::io::file::rmdir;
-///
-///     let p = &Path("/some/dir");
-///     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) {
-    do with_local_io |io| {
-        match io.fs_rmdir(&path.to_c_str()) {
-            Ok(_) => Some(()),
-            Err(ioerr) => {
-                io_error::cond.raise(ioerr);
-                None
-            }
-        }
-    };
-}
-
-/// Get information on the file, directory, etc at the provided path
-///
-/// Given a path, query the file system to get information about a file,
-/// directory, etc.
-///
-/// Returns a `Some(std::rt::io::PathInfo)` on success
-///
-/// # Example
-///
-///     use std;
-///     use std::path::Path;
-///     use std::rt::io::file::stat;
-///
-///     let p = &Path("/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 {
-///             // 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> {
-    do with_local_io |io| {
-        match io.fs_stat(&path.to_c_str()) {
-            Ok(p) => Some(p),
-            Err(ioerr) => {
-                io_error::cond.raise(ioerr);
-                None
-            }
-        }
-    }
-}
-
-/// Retrieve a vector containing all entries within a provided directory
-///
-/// # Example
-///
-///     use std;
-///     use std::path::Path;
-///     use std::rt::io::file::readdir;
-///
-///     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"); }
-///     }
-///
-/// # Errors
-///
-/// Will raise an `io_error` condition if the provided `path` 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]> {
-    do with_local_io |io| {
-        match io.fs_readdir(&path.to_c_str(), 0) {
-            Ok(p) => Some(p),
-            Err(ioerr) => {
-                io_error::cond.raise(ioerr);
-                None
-            }
-        }
-    }
-}
-
-/// Constrained version of `FileStream` that only exposes read-specific operations.
-///
-/// Can be retreived via `FileInfo.open_reader()`.
-pub struct FileReader { priv stream: FileStream }
-
-/// 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)
-    }
-
-    fn eof(&mut self) -> bool {
-        self.stream.eof()
-    }
-}
-
-/// a `std::rt::io::Seek` trait impl for file I/O.
-impl Seek for FileReader {
-    fn tell(&self) -> u64 {
-        self.stream.tell()
-    }
-
-    fn seek(&mut self, pos: i64, style: SeekStyle) {
-        self.stream.seek(pos, style);
-    }
-}
-
-/// Constrained version of `FileStream` that only exposes write-specific operations.
-///
-/// Can be retreived via `FileInfo.open_writer()`.
-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();
-    }
-}
-
-/// 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);
-    }
-}
-
-/// Unconstrained file access type that exposes read and write operations
-///
-/// Can be retreived via `file::open()` and `FileInfo.open_stream()`.
-///
-/// # Errors
-///
-/// This type will raise an io_error condition if operations are attempted against
-/// it for which its underlying file descriptor was not configured at creation
-/// 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()`.
-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) {
-            Ok(read) => {
-                self.last_nread = read;
-                match read {
-                    0 => None,
-                    _ => Some(read as uint)
-                }
-            },
-            Err(ioerr) => {
-                // EOF is indicated by returning None
-                if ioerr.kind != EndOfFile {
-                    io_error::cond.raise(ioerr);
-                }
-                return None;
-            }
-        }
-    }
-
-    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) {
-            Ok(_) => (),
-            Err(ioerr) => {
-                io_error::cond.raise(ioerr);
-            }
-        }
-    }
-}
-
-/// a `std::rt::io:Seek` trait impl for file I/O.
-impl Seek for FileStream {
-    fn tell(&self) -> u64 {
-        let res = self.fd.tell();
-        match res {
-            Ok(cursor) => cursor,
-            Err(ioerr) => {
-                io_error::cond.raise(ioerr);
-                return -1;
-            }
-        }
-    }
-
-    fn seek(&mut self, pos: i64, style: SeekStyle) {
-        match self.fd.seek(pos, style) {
-            Ok(_) => {
-                // successful seek resets EOF indicator
-                self.last_nread = -1;
-                ()
-            },
-            Err(ioerr) => {
-                io_error::cond.raise(ioerr);
-            }
-        }
-    }
-}
-
-/// 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
-    ///
-    /// 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())
-    }
-
-    /// Boolean value indicator whether the underlying file exists on the filesystem
-    ///
-    /// # Errors
-    ///
-    /// Will not raise a condition
-    fn exists(&self) -> bool {
-        match ignore_io_error(|| self.stat()) {
-            Some(_) => true,
-            None => false
-        }
-    }
-
-}
-
-/// 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).
-    ///
-    /// # 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)
-        }
-    }
-
-    /// 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
-    /// not a directory (eg files, named pipes, links, etc)
-    ///
-    /// # Errors
-    ///
-    /// Will not raise a condition
-    fn is_dir(&self) -> bool {
-        match ignore_io_error(|| self.stat()) {
-            Some(s) => s.is_dir,
-            None => 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 option::{Some, None};
-    use path::Path;
-    use super::*;
-    use iter::range;
-    #[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();
-                write_stream.write(message.as_bytes());
-            }
-            {
-                use str;
-                let mut read_stream = open(filename, Open, Read).unwrap();
-                let mut read_buf = [0, .. 1028];
-                let read_str = match read_stream.read(read_buf).unwrap() {
-                    -1|0 => fail!("shouldn't happen"),
-                    n => str::from_utf8(read_buf.slice_to(n))
-                };
-                assert!(read_str == message.to_owned());
-            }
-            unlink(filename);
-        }
-    }
-
-    #[test]
-    fn file_test_io_invalid_path_opened_without_create_should_raise_condition() {
-        do run_in_mt_newsched_task {
-            let filename = &Path::new("./tmp/file_that_does_not_exist.txt");
-            let mut called = false;
-            do io_error::cond.trap(|_| {
-                called = true;
-            }).inside {
-                let result = open(filename, Open, Read);
-                assert!(result.is_none());
-            }
-            assert!(called);
-        }
-    }
-
-    #[test]
-    fn file_test_iounlinking_invalid_path_should_raise_condition() {
-        do run_in_mt_newsched_task {
-            let filename = &Path::new("./tmp/file_another_file_that_does_not_exist.txt");
-            let mut called = false;
-            do io_error::cond.trap(|_| {
-                called = true;
-            }).inside {
-                unlink(filename);
-            }
-            assert!(called);
-        }
-    }
-
-    #[test]
-    fn file_test_io_non_positional_read() {
-        do run_in_mt_newsched_task {
-            use str;
-            let message = "ten-four";
-            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();
-                rw_stream.write(message.as_bytes());
-            }
-            {
-                let mut read_stream = open(filename, Open, Read).unwrap();
-                {
-                    let read_buf = read_mem.mut_slice(0, 4);
-                    read_stream.read(read_buf);
-                }
-                {
-                    let read_buf = read_mem.mut_slice(4, 8);
-                    read_stream.read(read_buf);
-                }
-            }
-            unlink(filename);
-            let read_str = str::from_utf8(read_mem);
-            assert!(read_str == message.to_owned());
-        }
-    }
-
-    #[test]
-    fn file_test_io_seek_and_tell_smoke_test() {
-        do run_in_mt_newsched_task {
-            use str;
-            let message = "ten-four";
-            let mut read_mem = [0, .. 4];
-            let set_cursor = 4 as u64;
-            let mut tell_pos_pre_read;
-            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();
-                rw_stream.write(message.as_bytes());
-            }
-            {
-                let mut read_stream = open(filename, Open, Read).unwrap();
-                read_stream.seek(set_cursor as i64, SeekSet);
-                tell_pos_pre_read = read_stream.tell();
-                read_stream.read(read_mem);
-                tell_pos_post_read = read_stream.tell();
-            }
-            unlink(filename);
-            let read_str = str::from_utf8(read_mem);
-            assert!(read_str == message.slice(4, 8).to_owned());
-            assert!(tell_pos_pre_read == set_cursor);
-            assert!(tell_pos_post_read == message.len() as u64);
-        }
-    }
-
-    #[test]
-    fn file_test_io_seek_and_write() {
-        do run_in_mt_newsched_task {
-            use str;
-            let initial_msg =   "food-is-yummy";
-            let overwrite_msg =    "-the-bar!!";
-            let final_msg =     "foo-the-bar!!";
-            let seek_idx = 3;
-            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();
-                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();
-                read_stream.read(read_mem);
-            }
-            unlink(filename);
-            let read_str = str::from_utf8(read_mem);
-            assert!(read_str == final_msg.to_owned());
-        }
-    }
-
-    #[test]
-    fn file_test_io_seek_shakedown() {
-        do run_in_mt_newsched_task {
-            use str;          // 01234567890123
-            let initial_msg =   "qwer-asdf-zxcv";
-            let chunk_one = "qwer";
-            let chunk_two = "asdf";
-            let chunk_three = "zxcv";
-            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();
-                rw_stream.write(initial_msg.as_bytes());
-            }
-            {
-                let mut read_stream = open(filename, Open, Read).unwrap();
-
-                read_stream.seek(-4, SeekEnd);
-                read_stream.read(read_mem);
-                let read_str = str::from_utf8(read_mem);
-                assert!(read_str == chunk_three.to_owned());
-
-                read_stream.seek(-9, SeekCur);
-                read_stream.read(read_mem);
-                let read_str = str::from_utf8(read_mem);
-                assert!(read_str == chunk_two.to_owned());
-
-                read_stream.seek(0, SeekSet);
-                read_stream.read(read_mem);
-                let read_str = str::from_utf8(read_mem);
-                assert!(read_str == chunk_one.to_owned());
-            }
-            unlink(filename);
-        }
-    }
-
-    #[test]
-    fn file_test_stat_is_correct_on_is_file() {
-        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 msg = "hw";
-                fs.write(msg.as_bytes());
-            }
-            let stat_res = match stat(filename) {
-                Some(s) => s,
-                None => fail!("shouldn't happen")
-            };
-            assert!(stat_res.is_file);
-            unlink(filename);
-        }
-    }
-
-    #[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")
-            };
-            assert!(stat_res.is_dir);
-            rmdir(filename);
-        }
-    }
-
-    #[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);
-            assert!(dir.is_file() == false);
-            rmdir(dir);
-        }
-    }
-
-    #[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);
-            }
-            assert!(file.exists());
-            file.unlink();
-            assert!(!file.exists());
-        }
-    }
-
-    #[test]
-    fn file_test_directoryinfo_check_exists_before_and_after_mkdir() {
-        do run_in_mt_newsched_task {
-            let dir = &Path::new("./tmp/before_and_after_dir");
-            assert!(!dir.exists());
-            dir.mkdir();
-            assert!(dir.exists());
-            assert!(dir.is_dir());
-            dir.rmdir();
-            assert!(!dir.exists());
-        }
-    }
-
-    #[test]
-    fn file_test_directoryinfo_readdir() {
-        use str;
-        do run_in_mt_newsched_task {
-            let dir = &Path::new("./tmp/di_readdir");
-            dir.mkdir();
-            let prefix = "foo";
-            for n in range(0,3) {
-                let f = dir.join(format!("{}.txt", n));
-                let mut w = f.open_writer(Create);
-                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")
-            }
-            dir.rmdir();
-        }
-    }
-}
diff --git a/src/libstd/rt/io/fs.rs b/src/libstd/rt/io/fs.rs
new file mode 100644
index 00000000000..22d7ea55f3b
--- /dev/null
+++ b/src/libstd/rt/io/fs.rs
@@ -0,0 +1,1247 @@
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+/*! Synchronous File I/O
+
+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 `Path` object.
+
+All operations in this module, including those as part of `File` 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 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.
+
+# Example
+
+    use std::rt::io::{File, fs};
+
+    let path = Path::new("foo.txt");
+
+    // create the file, whether it exists or not
+    let mut file = File::create(&path);
+    file.write(bytes!("foobar"));
+
+    // open the file in read-only mode
+    let mut file = File::open(&path);
+    file.read_to_end();
+
+    println!("{}", path.stat().size);
+    fs::symlink(&path, &Path::new("bar.txt"));
+    fs::unlink(&path);
+
+*/
+
+use c_str::ToCStr;
+use iter::Iterator;
+use super::{Reader, Writer, Seek};
+use super::{SeekStyle, Read, Write, Open, IoError, Truncate,
+            FileMode, FileAccess, FileStat, io_error, FilePermission};
+use rt::rtio::{RtioFileStream, IoFactory, with_local_io};
+use rt::io;
+use option::{Some, None, Option};
+use result::{Ok, Err, Result};
+use path;
+use path::{Path, GenericPath};
+use vec::OwnedVector;
+
+/// Unconstrained file access type that exposes read and write operations
+///
+/// Can be constructed via `File::open()`, `File::create()`, and
+/// `File::open_mode()`.
+///
+/// # Errors
+///
+/// This type will raise an io_error condition if operations are attempted against
+/// it for which its underlying file descriptor was not configured at creation
+/// time, via the `FileAccess` parameter to `File::open_mode()`.
+pub struct File {
+    priv fd: ~RtioFileStream,
+    priv path: Path,
+    priv last_nread: int,
+}
+
+fn io_raise<T>(f: &fn(io: &mut IoFactory) -> Result<T, IoError>) -> Option<T> {
+    do with_local_io |io| {
+        match f(io) {
+            Ok(t) => Some(t),
+            Err(ioerr) => {
+                io_error::cond.raise(ioerr);
+                None
+            }
+        }
+    }
+}
+
+impl File {
+    /// Open a file at `path` in the mode specified by the `mode` and `access`
+    /// arguments
+    ///
+    /// # Example
+    ///
+    ///     use std::rt::io::{File, io_error, Open, ReadWrite};
+    ///
+    ///     let p = Path::new("/some/file/path.txt");
+    ///
+    ///     do io_error::cond.trap(|_| {
+    ///         // hoo-boy...
+    ///     }).inside {
+    ///         let file = match File::open_mode(&p, Open, ReadWrite) {
+    ///             Some(s) => s,
+    ///             None => fail!("whoops! I'm sure this raised, anyways..")
+    ///         };
+    ///         // do some stuff with that file
+    ///
+    ///         // the file will be closed at the end of this block
+    ///     }
+    ///     // ..
+    ///
+    /// `FileMode` and `FileAccess` provide information about the permissions
+    /// context in which a given stream is created. More information about them
+    /// can be found in `std::rt::io`'s docs. If a file is opened with `Write`
+    /// or `ReadWrite` access, then it will be created it it does not already
+    /// exist.
+    ///
+    /// Note that, with this function, a `File` is returned regardless of the
+    /// access-limitations indicated by `FileAccess` (e.g. calling `write` on a
+    /// `File` opened as `Read` will raise an `io_error` condition at runtime).
+    ///
+    /// # Errors
+    ///
+    /// This function will raise an `io_error` condition under a number of
+    /// different circumstances, to include but not limited to:
+    ///
+    /// * Opening a file that does not exist with `Read` access.
+    /// * Attempting to open a file with a `FileAccess` that the user lacks
+    ///   permissions for
+    /// * Filesystem-level errors (full disk, etc)
+    pub fn open_mode(path: &Path,
+                     mode: FileMode,
+                     access: FileAccess) -> Option<File> {
+        do with_local_io |io| {
+            match io.fs_open(&path.to_c_str(), mode, access) {
+                Ok(fd) => Some(File {
+                    path: path.clone(),
+                    fd: fd,
+                    last_nread: -1
+                }),
+                Err(ioerr) => {
+                    io_error::cond.raise(ioerr);
+                    None
+                }
+            }
+        }
+    }
+
+    /// Attempts to open a file in read-only mode. This function is equivalent to
+    /// `File::open_mode(path, Open, Read)`, and will raise all of the same
+    /// errors that `File::open_mode` does.
+    ///
+    /// For more information, see the `File::open_mode` function.
+    ///
+    /// # Example
+    ///
+    ///     use std::rt::io::File;
+    ///
+    ///     let contents = File::open(&Path::new("foo.txt")).read_to_end();
+    pub fn open(path: &Path) -> Option<File> {
+        File::open_mode(path, Open, Read)
+    }
+
+    /// Attempts to create a file in write-only mode. This function is
+    /// equivalent to `File::open_mode(path, Truncate, Write)`, and will
+    /// raise all of the same errors that `File::open_mode` does.
+    ///
+    /// For more information, see the `File::open_mode` function.
+    ///
+    /// # Example
+    ///
+    ///     use std::rt::io::File;
+    ///
+    ///     let mut f = File::create(&Path::new("foo.txt"));
+    ///     f.write(bytes!("This is a sample file"));
+    pub fn create(path: &Path) -> Option<File> {
+        File::open_mode(path, Truncate, Write)
+    }
+
+    /// Returns the original path which was used to open this file.
+    pub fn path<'a>(&'a self) -> &'a Path {
+        &self.path
+    }
+
+    /// Synchronizes all modifications to this file to its permanent storage
+    /// device. This will flush any internal buffers necessary to perform this
+    /// operation.
+    ///
+    /// # Errors
+    ///
+    /// This function will raise on the `io_error` condition on failure.
+    pub fn fsync(&mut self) {
+        self.fd.fsync();
+    }
+
+    /// This function is similar to `fsync`, except that it may not synchronize
+    /// file metadata to the filesystem. This is intended for use case which
+    /// must synchronize content, but don't need the metadata on disk. The goal
+    /// of this method is to reduce disk operations.
+    ///
+    /// # Errors
+    ///
+    /// This function will raise on the `io_error` condition on failure.
+    pub fn datasync(&mut self) {
+        self.fd.datasync();
+    }
+
+    /// Either truncates or extends the underlying file, as extended from the
+    /// file's current position. This is equivalent to the unix `truncate`
+    /// function.
+    ///
+    /// The offset given is added to the file's current position and the result
+    /// is the new size of the file. If the new size is less than the current
+    /// size, then the file is truncated. If the new size is greater than the
+    /// current size, then the file is expanded to be filled with 0s.
+    ///
+    /// # Errors
+    ///
+    /// On error, this function will raise on the `io_error` condition.
+    pub fn truncate(&mut self, offset: i64) {
+        self.fd.truncate(offset);
+    }
+}
+
+/// Unlink a file from the underlying filesystem.
+///
+/// # Example
+///
+///     use std::rt::io::fs;
+///
+///     let p = Path::new("/some/file/path.txt");
+///     fs::unlink(&p);
+///     // if we made it here without failing, then the
+///     // unlink operation was successful
+///
+/// Note that, just because an unlink call was successful, it is not
+/// guaranteed that a file is immediately deleted (e.g. depending on
+/// platform, other open file descriptors may prevent immediate removal)
+///
+/// # Errors
+///
+/// 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 io_raise |io| { io.fs_unlink(&path.to_c_str()) };
+}
+
+/// Given a path, query the file system to get information about a file,
+/// directory, etc. This function will traverse symlinks to query
+/// information about the destination file.
+///
+/// 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::rt::io;
+///     use std::rt::io::fs;
+///
+///     let p = Path::new("/some/file/path.txt");
+///     match io::result(|| fs::stat(&p)) {
+///         Ok(stat) => { /* ... */ }
+///         Err(e) => { /* handle error */ }
+///     }
+///
+/// # 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(path: &Path) -> FileStat {
+    do io_raise |io| {
+        io.fs_stat(&path.to_c_str())
+    }.unwrap_or_else(dummystat)
+}
+
+fn dummystat() -> FileStat {
+    FileStat {
+        path: Path::new(""),
+        size: 0,
+        kind: io::TypeFile,
+        perm: 0,
+        created: 0,
+        modified: 0,
+        accessed: 0,
+        unstable: io::UnstableFileStat {
+            device: 0,
+            inode: 0,
+            rdev: 0,
+            nlink: 0,
+            uid: 0,
+            gid: 0,
+            blksize: 0,
+            blocks: 0,
+            flags: 0,
+            gen: 0,
+        }
+    }
+}
+
+/// Perform the same operation as the `stat` function, except that this
+/// function does not traverse through symlinks. This will return
+/// information about the symlink file instead of the file that it points
+/// to.
+///
+/// # Errors
+///
+/// See `stat`
+pub fn lstat(path: &Path) -> FileStat {
+    do io_raise |io| {
+        io.fs_lstat(&path.to_c_str())
+    }.unwrap_or_else(dummystat)
+}
+
+/// Rename a file or directory to a new name.
+///
+/// # Example
+///
+///     use std::rt::io::fs;
+///
+///     fs::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 io_raise |io| {
+        io.fs_rename(&from.to_c_str(), &to.to_c_str())
+    };
+}
+
+/// Copies the contents of one file to another. This function will also
+/// copy the permission bits of the original file to the destination file.
+///
+/// Note that if `from` and `to` both point to the same file, then the file
+/// will likely get truncated by this operation.
+///
+/// # Example
+///
+///     use std::rt::io::fs;
+///
+///     fs::copy(&Path::new("foo.txt"), &Path::new("bar.txt"));
+///     // Oh boy, nothing was raised!
+///
+/// # Errors
+///
+/// Will raise an `io_error` condition is the following situtations, but is
+/// not limited to just these cases:
+///
+/// * The `from` path is not a file
+/// * The `from` file does not exist
+/// * The current process does not have the permission rights to access
+///   `from` or write `to`
+///
+/// Note that this copy is not atomic in that once the destination is
+/// ensured to not exist, there is nothing preventing the destination from
+/// being created and then destroyed by this operation.
+pub fn copy(from: &Path, to: &Path) {
+    if !from.is_file() {
+        return io_error::cond.raise(IoError {
+            kind: io::MismatchedFileTypeForOperation,
+            desc: "the source path is not an existing file",
+            detail: None,
+        });
+    }
+
+    let mut reader = match File::open(from) { Some(f) => f, None => return };
+    let mut writer = match File::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
+        }
+    }
+
+    chmod(to, from.stat().perm)
+}
+
+/// Changes the permission mode bits found on a file or a directory. This
+/// function takes a mask from the `io` module
+///
+/// # Example
+///
+///     use std::rt::io;
+///     use std::rt::io::fs;
+///
+///     fs::chmod(&Path::new("file.txt"), io::UserFile);
+///     fs::chmod(&Path::new("file.txt"), io::UserRead | io::UserWrite);
+///     fs::chmod(&Path::new("dir"),      io::UserDir);
+///     fs::chmod(&Path::new("file.exe"), io::UserExec);
+///
+/// # Errors
+///
+/// If this funciton encounters an I/O error, it will raise on the `io_error`
+/// condition. Some possible error situations are not having the permission to
+/// change the attributes of a file or the file not existing.
+pub fn chmod(path: &Path, mode: io::FilePermission) {
+    do io_raise |io| {
+        io.fs_chmod(&path.to_c_str(), mode)
+    };
+}
+
+/// Change the user and group owners of a file at the specified path.
+///
+/// # Errors
+///
+/// This funtion will raise on the `io_error` condition on failure.
+pub fn chown(path: &Path, uid: int, gid: int) {
+    do io_raise |io| { io.fs_chown(&path.to_c_str(), uid, gid) };
+}
+
+/// Creates a new hard link on the filesystem. The `dst` path will be a
+/// link pointing to the `src` path. Note that systems often require these
+/// two paths to both be located on the same filesystem.
+///
+/// # Errors
+///
+/// This function will raise on the `io_error` condition on failure.
+pub fn link(src: &Path, dst: &Path) {
+    do io_raise |io| { io.fs_link(&src.to_c_str(), &dst.to_c_str()) };
+}
+
+/// Creates a new symbolic link on the filesystem. The `dst` path will be a
+/// symlink pointing to the `src` path.
+///
+/// # Errors
+///
+/// This function will raise on the `io_error` condition on failure.
+pub fn symlink(src: &Path, dst: &Path) {
+    do io_raise |io| { io.fs_symlink(&src.to_c_str(), &dst.to_c_str()) };
+}
+
+/// Reads a symlink, returning the file that the symlink points to.
+///
+/// # Errors
+///
+/// This function will raise on the `io_error` condition on failure. Failure
+/// conditions include reading a file that does not exist or reading a file
+/// which is not a symlink.
+pub fn readlink(path: &Path) -> Option<Path> {
+    do io_raise |io| { io.fs_readlink(&path.to_c_str()) }
+}
+
+/// Create a new, empty directory at the provided path
+///
+/// # Example
+///
+///     use std::libc::S_IRWXU;
+///     use std::rt::io::fs;
+///
+///     let p = Path::new("/some/dir");
+///     fs::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(path: &Path, mode: FilePermission) {
+    do io_raise |io| {
+        io.fs_mkdir(&path.to_c_str(), mode)
+    };
+}
+
+/// Remove an existing, empty directory
+///
+/// # Example
+///
+///     use std::rt::io::fs;
+///
+///     let p = Path::new("/some/dir");
+///     fs::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(path: &Path) {
+    do io_raise |io| {
+        io.fs_rmdir(&path.to_c_str())
+    };
+}
+
+/// Retrieve a vector containing all entries within a provided directory
+///
+/// # Example
+///
+///     use std::rt::io::fs;
+///
+///     // one possible implementation of fs::walk_dir only visiting files
+///     fn visit_dirs(dir: &Path, cb: &fn(&Path)) {
+///         if dir.is_dir() {
+///             let contents = fs::readdir(dir).unwrap();
+///             for entry in contents.iter() {
+///                 if entry.is_dir() { visit_dirs(entry, cb); }
+///                 else { cb(entry); }
+///             }
+///         }
+///         else { fail!("nope"); }
+///     }
+///
+/// # Errors
+///
+/// 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(path: &Path) -> ~[Path] {
+    do io_raise |io| {
+        io.fs_readdir(&path.to_c_str(), 0)
+    }.unwrap_or_else(|| ~[])
+}
+
+/// Returns an iterator which will recursively walk the directory structure
+/// rooted at `path`. The path given will not be iterated over, and this will
+/// perform iteration in a top-down order.
+pub fn walk_dir(path: &Path) -> WalkIterator {
+    WalkIterator { stack: readdir(path) }
+}
+
+/// An iterator which walks over a directory
+pub struct WalkIterator {
+    priv stack: ~[Path],
+}
+
+impl Iterator<Path> for WalkIterator {
+    fn next(&mut self) -> Option<Path> {
+        match self.stack.shift_opt() {
+            Some(path) => {
+                if path.is_dir() {
+                    self.stack.push_all_move(readdir(&path));
+                }
+                Some(path)
+            }
+            None => None
+        }
+    }
+}
+
+/// Recursively create a directory and all of its parent components if they
+/// are missing.
+///
+/// # Errors
+///
+/// This function will raise on the `io_error` condition if an error
+/// happens, see `fs::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)
+}
+
+/// Removes a directory at this path, after removing all its contents. Use
+/// carefully!
+///
+/// # Errors
+///
+/// This function will raise on the `io_error` condition if an error
+/// happens. See `file::unlink` and `fs::readdir` for possible error
+/// conditions.
+pub fn rmdir_recursive(path: &Path) {
+    let children = readdir(path);
+    for child in children.iter() {
+        if child.is_dir() {
+            rmdir_recursive(child);
+        } else {
+            unlink(child);
+        }
+    }
+    // Directory should now be empty
+    rmdir(path);
+}
+
+impl Reader for File {
+    fn read(&mut self, buf: &mut [u8]) -> Option<uint> {
+        match self.fd.read(buf) {
+            Ok(read) => {
+                self.last_nread = read;
+                match read {
+                    0 => None,
+                    _ => Some(read as uint)
+                }
+            },
+            Err(ioerr) => {
+                // EOF is indicated by returning None
+                if ioerr.kind != io::EndOfFile {
+                    io_error::cond.raise(ioerr);
+                }
+                return None;
+            }
+        }
+    }
+
+    fn eof(&mut self) -> bool { self.last_nread == 0 }
+}
+
+impl Writer for File {
+    fn write(&mut self, buf: &[u8]) {
+        match self.fd.write(buf) {
+            Ok(()) => (),
+            Err(ioerr) => {
+                io_error::cond.raise(ioerr);
+            }
+        }
+    }
+}
+
+impl Seek for File {
+    fn tell(&self) -> u64 {
+        let res = self.fd.tell();
+        match res {
+            Ok(cursor) => cursor,
+            Err(ioerr) => {
+                io_error::cond.raise(ioerr);
+                return -1;
+            }
+        }
+    }
+
+    fn seek(&mut self, pos: i64, style: SeekStyle) {
+        match self.fd.seek(pos, style) {
+            Ok(_) => {
+                // successful seek resets EOF indicator
+                self.last_nread = -1;
+                ()
+            },
+            Err(ioerr) => {
+                io_error::cond.raise(ioerr);
+            }
+        }
+    }
+}
+
+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`.
+    pub fn stat(&self) -> FileStat { stat(self) }
+
+    /// 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
+    pub fn exists(&self) -> bool {
+        io::result(|| self.stat()).is_ok()
+    }
+
+    /// 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
+    pub fn is_file(&self) -> bool {
+        match io::result(|| self.stat()) {
+            Ok(s) => s.kind == io::TypeFile,
+            Err(*) => false
+        }
+    }
+
+    /// 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
+    /// not a directory (eg files, named pipes, links, etc)
+    ///
+    /// # Errors
+    ///
+    /// Will not raise a condition
+    pub fn is_dir(&self) -> bool {
+        match io::result(|| self.stat()) {
+            Ok(s) => s.kind == io::TypeDirectory,
+            Err(*) => false
+        }
+    }
+}
+
+#[cfg(test)]
+mod test {
+    use prelude::*;
+    use rt::io::{SeekSet, SeekCur, SeekEnd, io_error, Read, Open, ReadWrite};
+    use rt::io;
+    use str;
+    use super::{File, rmdir, mkdir, readdir, rmdir_recursive, mkdir_recursive,
+                copy, unlink, stat, symlink, link, readlink, chmod, chown,
+                lstat};
+
+    fn tmpdir() -> Path {
+        use os;
+        use rand;
+        let ret = os::tmpdir().join(format!("rust-{}", rand::random::<u32>()));
+        mkdir(&ret, io::UserRWX);
+        ret
+    }
+
+    fn free<T>(_: T) {}
+
+    #[test]
+    fn file_test_io_smoke_test() {
+        let message = "it's alright. have a good time";
+        let filename = &Path::new("./tmp/file_rt_io_file_test.txt");
+        {
+            let mut write_stream = File::open_mode(filename, Open, ReadWrite);
+            write_stream.write(message.as_bytes());
+        }
+        {
+            let mut read_stream = File::open_mode(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"),
+                n => str::from_utf8(read_buf.slice_to(n))
+            };
+            assert!(read_str == message.to_owned());
+        }
+        unlink(filename);
+    }
+
+    #[test]
+    fn file_test_io_invalid_path_opened_without_create_should_raise_condition() {
+        let filename = &Path::new("./tmp/file_that_does_not_exist.txt");
+        let mut called = false;
+        do io_error::cond.trap(|_| {
+            called = true;
+        }).inside {
+            let result = File::open_mode(filename, Open, Read);
+            assert!(result.is_none());
+        }
+        assert!(called);
+    }
+
+    #[test]
+    fn file_test_iounlinking_invalid_path_should_raise_condition() {
+        let filename = &Path::new("./tmp/file_another_file_that_does_not_exist.txt");
+        let mut called = false;
+        do io_error::cond.trap(|_| {
+            called = true;
+        }).inside {
+            unlink(filename);
+        }
+        assert!(called);
+    }
+
+    #[test]
+    fn file_test_io_non_positional_read() {
+        let message = "ten-four";
+        let mut read_mem = [0, .. 8];
+        let filename = &Path::new("./tmp/file_rt_io_file_test_positional.txt");
+        {
+            let mut rw_stream = File::open_mode(filename, Open, ReadWrite);
+            rw_stream.write(message.as_bytes());
+        }
+        {
+            let mut read_stream = File::open_mode(filename, Open, Read);
+            {
+                let read_buf = read_mem.mut_slice(0, 4);
+                read_stream.read(read_buf);
+            }
+            {
+                let read_buf = read_mem.mut_slice(4, 8);
+                read_stream.read(read_buf);
+            }
+        }
+        unlink(filename);
+        let read_str = str::from_utf8(read_mem);
+        assert!(read_str == message.to_owned());
+    }
+
+    #[test]
+    fn file_test_io_seek_and_tell_smoke_test() {
+        let message = "ten-four";
+        let mut read_mem = [0, .. 4];
+        let set_cursor = 4 as u64;
+        let mut tell_pos_pre_read;
+        let mut tell_pos_post_read;
+        let filename = &Path::new("./tmp/file_rt_io_file_test_seeking.txt");
+        {
+            let mut rw_stream = File::open_mode(filename, Open, ReadWrite);
+            rw_stream.write(message.as_bytes());
+        }
+        {
+            let mut read_stream = File::open_mode(filename, Open, Read);
+            read_stream.seek(set_cursor as i64, SeekSet);
+            tell_pos_pre_read = read_stream.tell();
+            read_stream.read(read_mem);
+            tell_pos_post_read = read_stream.tell();
+        }
+        unlink(filename);
+        let read_str = str::from_utf8(read_mem);
+        assert!(read_str == message.slice(4, 8).to_owned());
+        assert!(tell_pos_pre_read == set_cursor);
+        assert!(tell_pos_post_read == message.len() as u64);
+    }
+
+    #[test]
+    fn file_test_io_seek_and_write() {
+        let initial_msg =   "food-is-yummy";
+        let overwrite_msg =    "-the-bar!!";
+        let final_msg =     "foo-the-bar!!";
+        let seek_idx = 3;
+        let mut read_mem = [0, .. 13];
+        let filename = &Path::new("./tmp/file_rt_io_file_test_seek_and_write.txt");
+        {
+            let mut rw_stream = File::open_mode(filename, Open, 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 = File::open_mode(filename, Open, Read);
+            read_stream.read(read_mem);
+        }
+        unlink(filename);
+        let read_str = str::from_utf8(read_mem);
+        assert!(read_str == final_msg.to_owned());
+    }
+
+    #[test]
+    fn file_test_io_seek_shakedown() {
+        use std::str;          // 01234567890123
+        let initial_msg =   "qwer-asdf-zxcv";
+        let chunk_one = "qwer";
+        let chunk_two = "asdf";
+        let chunk_three = "zxcv";
+        let mut read_mem = [0, .. 4];
+        let filename = &Path::new("./tmp/file_rt_io_file_test_seek_shakedown.txt");
+        {
+            let mut rw_stream = File::open_mode(filename, Open, ReadWrite);
+            rw_stream.write(initial_msg.as_bytes());
+        }
+        {
+            let mut read_stream = File::open_mode(filename, Open, Read);
+
+            read_stream.seek(-4, SeekEnd);
+            read_stream.read(read_mem);
+            let read_str = str::from_utf8(read_mem);
+            assert!(read_str == chunk_three.to_owned());
+
+            read_stream.seek(-9, SeekCur);
+            read_stream.read(read_mem);
+            let read_str = str::from_utf8(read_mem);
+            assert!(read_str == chunk_two.to_owned());
+
+            read_stream.seek(0, SeekSet);
+            read_stream.read(read_mem);
+            let read_str = str::from_utf8(read_mem);
+            assert!(read_str == chunk_one.to_owned());
+        }
+        unlink(filename);
+    }
+
+    #[test]
+    fn file_test_stat_is_correct_on_is_file() {
+        let filename = &Path::new("./tmp/file_stat_correct_on_is_file.txt");
+        {
+            let mut fs = File::open_mode(filename, Open, ReadWrite);
+            let msg = "hw";
+            fs.write(msg.as_bytes());
+        }
+        let stat_res = stat(filename);
+        assert_eq!(stat_res.kind, io::TypeFile);
+        unlink(filename);
+    }
+
+    #[test]
+    fn file_test_stat_is_correct_on_is_dir() {
+        let filename = &Path::new("./tmp/file_stat_correct_on_is_dir");
+        mkdir(filename, io::UserRWX);
+        let stat_res = filename.stat();
+        assert!(stat_res.kind == io::TypeDirectory);
+        rmdir(filename);
+    }
+
+    #[test]
+    fn file_test_fileinfo_false_when_checking_is_file_on_a_directory() {
+        let dir = &Path::new("./tmp/fileinfo_false_on_dir");
+        mkdir(dir, io::UserRWX);
+        assert!(dir.is_file() == false);
+        rmdir(dir);
+    }
+
+    #[test]
+    fn file_test_fileinfo_check_exists_before_and_after_file_creation() {
+        let file = &Path::new("./tmp/fileinfo_check_exists_b_and_a.txt");
+        File::create(file).write(bytes!("foo"));
+        assert!(file.exists());
+        unlink(file);
+        assert!(!file.exists());
+    }
+
+    #[test]
+    fn file_test_directoryinfo_check_exists_before_and_after_mkdir() {
+        let dir = &Path::new("./tmp/before_and_after_dir");
+        assert!(!dir.exists());
+        mkdir(dir, io::UserRWX);
+        assert!(dir.exists());
+        assert!(dir.is_dir());
+        rmdir(dir);
+        assert!(!dir.exists());
+    }
+
+    #[test]
+    fn file_test_directoryinfo_readdir() {
+        use std::str;
+        let dir = &Path::new("./tmp/di_readdir");
+        mkdir(dir, io::UserRWX);
+        let prefix = "foo";
+        for n in range(0,3) {
+            let f = dir.join(format!("{}.txt", n));
+            let mut w = File::create(&f);
+            let msg_str = (prefix + n.to_str().to_owned()).to_owned();
+            let msg = msg_str.as_bytes();
+            w.write(msg);
+        }
+        let files = readdir(dir);
+        let mut mem = [0u8, .. 4];
+        for f in files.iter() {
+            {
+                let n = f.filestem_str();
+                File::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);
+        }
+        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");
+        File::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");
+
+        File::create(&input).write(bytes!("hello"));
+        copy(&input, &out);
+        let contents = File::open(&out).read_to_end();
+        assert_eq!(contents.as_slice(), bytes!("hello"));
+
+        assert_eq!(input.stat().perm, out.stat().perm);
+        rmdir_recursive(&tmpdir);
+    }
+
+    #[test]
+    fn copy_file_dst_dir() {
+        let tmpdir = tmpdir();
+        let out = tmpdir.join("out");
+
+        File::create(&out);
+        match io::result(|| copy(&out, &tmpdir)) {
+            Ok(*) => fail!(), Err(*) => {}
+        }
+        rmdir_recursive(&tmpdir);
+    }
+
+    #[test]
+    fn copy_file_dst_exists() {
+        let tmpdir = tmpdir();
+        let input = tmpdir.join("in");
+        let output = tmpdir.join("out");
+
+        File::create(&input).write("foo".as_bytes());
+        File::create(&output).write("bar".as_bytes());
+        copy(&input, &output);
+
+        assert_eq!(File::open(&output).read_to_end(),
+                   (bytes!("foo")).to_owned());
+
+        rmdir_recursive(&tmpdir);
+    }
+
+    #[test]
+    fn copy_file_src_dir() {
+        let tmpdir = tmpdir();
+        let out = tmpdir.join("out");
+
+        match io::result(|| copy(&tmpdir, &out)) {
+            Ok(*) => fail!(), Err(*) => {}
+        }
+        assert!(!out.exists());
+        rmdir_recursive(&tmpdir);
+    }
+
+    #[test]
+    fn copy_file_preserves_perm_bits() {
+        let tmpdir = tmpdir();
+        let input = tmpdir.join("in.txt");
+        let out = tmpdir.join("out.txt");
+
+        File::create(&input);
+        chmod(&input, io::UserRead);
+        copy(&input, &out);
+        assert!(out.stat().perm & io::UserWrite == 0);
+
+        chmod(&input, io::UserFile);
+        chmod(&out, io::UserFile);
+        rmdir_recursive(&tmpdir);
+    }
+
+    #[test]
+    #[ignore(cfg(windows))] // FIXME(#10264) operation not permitted?
+    fn symlinks_work() {
+        let tmpdir = tmpdir();
+        let input = tmpdir.join("in.txt");
+        let out = tmpdir.join("out.txt");
+
+        File::create(&input).write("foobar".as_bytes());
+        symlink(&input, &out);
+        assert_eq!(lstat(&out).kind, io::TypeSymlink);
+        assert_eq!(stat(&out).size, stat(&input).size);
+        assert_eq!(File::open(&out).read_to_end(), (bytes!("foobar")).to_owned());
+
+        rmdir_recursive(&tmpdir);
+    }
+
+    #[test]
+    #[ignore(cfg(windows))] // apparently windows doesn't like symlinks
+    fn symlink_noexist() {
+        let tmpdir = tmpdir();
+        // symlinks can point to things that don't exist
+        symlink(&tmpdir.join("foo"), &tmpdir.join("bar"));
+        assert!(readlink(&tmpdir.join("bar")).unwrap() == tmpdir.join("foo"));
+        rmdir_recursive(&tmpdir);
+    }
+
+    #[test]
+    fn readlink_not_symlink() {
+        let tmpdir = tmpdir();
+        match io::result(|| readlink(&tmpdir)) {
+            Ok(*) => fail!("wanted a failure"),
+            Err(*) => {}
+        }
+        rmdir_recursive(&tmpdir);
+    }
+
+    #[test]
+    fn links_work() {
+        let tmpdir = tmpdir();
+        let input = tmpdir.join("in.txt");
+        let out = tmpdir.join("out.txt");
+
+        File::create(&input).write("foobar".as_bytes());
+        link(&input, &out);
+        assert_eq!(lstat(&out).kind, io::TypeFile);
+        assert_eq!(stat(&out).size, stat(&input).size);
+        assert_eq!(stat(&out).unstable.nlink, 2);
+        assert_eq!(File::open(&out).read_to_end(), (bytes!("foobar")).to_owned());
+
+        // can't link to yourself
+        match io::result(|| link(&input, &input)) {
+            Ok(*) => fail!("wanted a failure"),
+            Err(*) => {}
+        }
+        // can't link to something that doesn't exist
+        match io::result(|| link(&tmpdir.join("foo"), &tmpdir.join("bar"))) {
+            Ok(*) => fail!("wanted a failure"),
+            Err(*) => {}
+        }
+
+        rmdir_recursive(&tmpdir);
+    }
+
+    #[test]
+    fn chmod_works() {
+        let tmpdir = tmpdir();
+        let file = tmpdir.join("in.txt");
+
+        File::create(&file);
+        assert!(stat(&file).perm & io::UserWrite == io::UserWrite);
+        chmod(&file, io::UserRead);
+        assert!(stat(&file).perm & io::UserWrite == 0);
+
+        match io::result(|| chmod(&tmpdir.join("foo"), io::UserRWX)) {
+            Ok(*) => fail!("wanted a failure"),
+            Err(*) => {}
+        }
+
+        chmod(&file, io::UserFile);
+        rmdir_recursive(&tmpdir);
+    }
+
+    #[test]
+    fn sync_doesnt_kill_anything() {
+        let tmpdir = tmpdir();
+        let path = tmpdir.join("in.txt");
+
+        let mut file = File::open_mode(&path, io::Open, io::ReadWrite).unwrap();
+        file.fsync();
+        file.datasync();
+        file.write(bytes!("foo"));
+        file.fsync();
+        file.datasync();
+        free(file);
+
+        rmdir_recursive(&tmpdir);
+    }
+
+    #[test]
+    fn truncate_works() {
+        let tmpdir = tmpdir();
+        let path = tmpdir.join("in.txt");
+
+        let mut file = File::open_mode(&path, io::Open, io::ReadWrite).unwrap();
+        file.write(bytes!("foo"));
+
+        // Do some simple things with truncation
+        assert_eq!(stat(&path).size, 3);
+        file.truncate(10);
+        assert_eq!(stat(&path).size, 10);
+        file.write(bytes!("bar"));
+        assert_eq!(stat(&path).size, 10);
+        assert_eq!(File::open(&path).read_to_end(),
+                   (bytes!("foobar", 0, 0, 0, 0)).to_owned());
+
+        // Truncate to a smaller length, don't seek, and then write something.
+        // Ensure that the intermediate zeroes are all filled in (we're seeked
+        // past the end of the file).
+        file.truncate(2);
+        assert_eq!(stat(&path).size, 2);
+        file.write(bytes!("wut"));
+        assert_eq!(stat(&path).size, 9);
+        assert_eq!(File::open(&path).read_to_end(),
+                   (bytes!("fo", 0, 0, 0, 0, "wut")).to_owned());
+        free(file);
+
+        rmdir_recursive(&tmpdir);
+    }
+
+    #[test]
+    fn open_flavors() {
+        let tmpdir = tmpdir();
+
+        match io::result(|| File::open_mode(&tmpdir.join("a"), io::Open,
+                                            io::Read)) {
+            Ok(*) => fail!(), Err(*) => {}
+        }
+        File::open_mode(&tmpdir.join("b"), io::Open, io::Write).unwrap();
+        File::open_mode(&tmpdir.join("c"), io::Open, io::ReadWrite).unwrap();
+        File::open_mode(&tmpdir.join("d"), io::Append, io::Write).unwrap();
+        File::open_mode(&tmpdir.join("e"), io::Append, io::ReadWrite).unwrap();
+        File::open_mode(&tmpdir.join("f"), io::Truncate, io::Write).unwrap();
+        File::open_mode(&tmpdir.join("g"), io::Truncate, io::ReadWrite).unwrap();
+
+        File::create(&tmpdir.join("h")).write("foo".as_bytes());
+        File::open_mode(&tmpdir.join("h"), io::Open, io::Read).unwrap();
+        {
+            let mut f = File::open_mode(&tmpdir.join("h"), io::Open,
+                                        io::Read).unwrap();
+            match io::result(|| f.write("wut".as_bytes())) {
+                Ok(*) => fail!(), Err(*) => {}
+            }
+        }
+        assert_eq!(stat(&tmpdir.join("h")).size, 3);
+        {
+            let mut f = File::open_mode(&tmpdir.join("h"), io::Append,
+                                        io::Write).unwrap();
+            f.write("bar".as_bytes());
+        }
+        assert_eq!(stat(&tmpdir.join("h")).size, 6);
+        {
+            let mut f = File::open_mode(&tmpdir.join("h"), io::Truncate,
+                                        io::Write).unwrap();
+            f.write("bar".as_bytes());
+        }
+        assert_eq!(stat(&tmpdir.join("h")).size, 3);
+
+        rmdir_recursive(&tmpdir);
+    }
+}
diff --git a/src/libstd/rt/io/mod.rs b/src/libstd/rt/io/mod.rs
index be205749186..f01ce5012eb 100644
--- a/src/libstd/rt/io/mod.rs
+++ b/src/libstd/rt/io/mod.rs
@@ -231,8 +231,6 @@ Out of scope
 * Trait for things that are both readers and writers, Stream?
 * How to handle newline conversion
 * String conversion
-* File vs. FileStream? File is shorter but could also be used for getting file info
-  - maybe File is for general file querying and *also* has a static `open` method
 * open vs. connect for generic stream opening
 * Do we need `close` at all? dtors might be good enough
 * How does I/O relate to the Iterator trait?
@@ -245,8 +243,10 @@ Out of scope
 use cast;
 use int;
 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;
@@ -259,7 +259,7 @@ pub use self::stdio::stderr;
 pub use self::stdio::print;
 pub use self::stdio::println;
 
-pub use self::file::FileStream;
+pub use self::fs::File;
 pub use self::timer::Timer;
 pub use self::net::ip::IpAddr;
 pub use self::net::tcp::TcpListener;
@@ -268,8 +268,8 @@ pub use self::net::udp::UdpStream;
 pub use self::pipe::PipeStream;
 pub use self::process::Process;
 
-/// Synchronous, non-blocking file I/O.
-pub mod file;
+/// Synchronous, non-blocking filesystem operations.
+pub mod fs;
 
 /// Synchronous, in-memory I/O.
 pub mod pipe;
@@ -418,6 +418,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
@@ -450,7 +462,7 @@ pub trait Reader {
     ///
     /// # Example
     ///
-    ///     let reader = FileStream::new()
+    ///     let reader = File::open(&Path::new("foo.txt"))
     ///     while !reader.eof() {
     ///         println(reader.read_line());
     ///     }
@@ -1089,51 +1101,119 @@ pub fn placeholder_error() -> IoError {
     }
 }
 
-/// Instructions on how to open a file and return a `FileStream`.
+/// A mode specifies how a file should be opened or created. These modes are
+/// passed to `File::open_mode` and are used to control where the file is
+/// positioned when it is initially opened.
 pub enum FileMode {
-    /// Opens an existing file. IoError if file does not exist.
+    /// Opens a file positioned at the beginning.
     Open,
-    /// Creates a file. IoError if file exists.
-    Create,
-    /// Opens an existing file or creates a new one.
-    OpenOrCreate,
-    /// Opens an existing file or creates a new one, positioned at EOF.
+    /// Opens a file positioned at EOF.
     Append,
-    /// Opens an existing file, truncating it to 0 bytes.
+    /// Opens a file, truncating it if it already exists.
     Truncate,
-    /// Opens an existing file or creates a new one, truncating it to 0 bytes.
-    CreateOrTruncate,
 }
 
-/// Access permissions with which the file should be opened.
-/// `FileStream`s opened with `Read` will raise an `io_error` condition if written to.
+/// Access permissions with which the file should be opened. `File`s
+/// opened with `Read` will raise an `io_error` condition if written to.
 pub enum FileAccess {
     Read,
     Write,
-    ReadWrite
+    ReadWrite,
+}
+
+/// Different kinds of files which can be identified by a call to stat
+#[deriving(Eq)]
+pub enum FileType {
+    TypeFile,
+    TypeDirectory,
+    TypeNamedPipe,
+    TypeBlockSpecial,
+    TypeSymlink,
+    TypeUnknown,
 }
 
 pub struct FileStat {
-    /// A `Path` object containing information about the `PathInfo`'s location
+    /// The path that this stat structure is describing
     path: Path,
-    /// `true` if the file pointed at by the `PathInfo` is a regular file
-    is_file: bool,
-    /// `true` if the file pointed at by the `PathInfo` is a directory
-    is_dir: bool,
-    /// The file pointed at by the `PathInfo`'s device
-    device: u64,
-    /// The file pointed at by the `PathInfo`'s mode
-    mode: u64,
-    /// The file pointed at by the `PathInfo`'s inode
-    inode: u64,
-    /// The file pointed at by the `PathInfo`'s size in bytes
+    /// The size of the file, in bytes
     size: u64,
-    /// The file pointed at by the `PathInfo`'s creation time
+    /// The kind of file this path points to (directory, file, pipe, etc.)
+    kind: FileType,
+    /// The file permissions currently on the file
+    perm: FilePermission,
+
+    // XXX: These time fields are pretty useless without an actual time
+    //      representation, what are the milliseconds relative to?
+
+    /// The time that the file was created at, in platform-dependent
+    /// milliseconds
     created: u64,
-    /// The file pointed at by the `PathInfo`'s last-modification time in
-    /// platform-dependent msecs
+    /// The time that this file was last modified, in platform-dependent
+    /// milliseconds
     modified: u64,
-    /// The file pointed at by the `PathInfo`'s last-accessd time (e.g. read) in
-    /// platform-dependent msecs
+    /// The time that this file was last accessed, in platform-dependent
+    /// milliseconds
     accessed: u64,
+
+    /// Information returned by stat() which is not guaranteed to be
+    /// platform-independent. This information may be useful on some platforms,
+    /// but it may have different meanings or no meaning at all on other
+    /// platforms.
+    ///
+    /// Usage of this field is discouraged, but if access is desired then the
+    /// fields are located here.
+    #[unstable]
+    unstable: UnstableFileStat,
+}
+
+/// This structure represents all of the possible information which can be
+/// returned from a `stat` syscall which is not contained in the `FileStat`
+/// structure. This information is not necessarily platform independent, and may
+/// have different meanings or no meaning at all on some platforms.
+#[unstable]
+pub struct UnstableFileStat {
+    device: u64,
+    inode: u64,
+    rdev: u64,
+    nlink: u64,
+    uid: u64,
+    gid: u64,
+    blksize: u64,
+    blocks: u64,
+    flags: u64,
+    gen: u64,
 }
+
+/// A set of permissions for a file or directory is represented by a set of
+/// flags which are or'd together.
+pub type FilePermission = u32;
+
+// Each permission bit
+pub static UserRead: FilePermission     = 0x100;
+pub static UserWrite: FilePermission    = 0x080;
+pub static UserExecute: FilePermission  = 0x040;
+pub static GroupRead: FilePermission    = 0x020;
+pub static GroupWrite: FilePermission   = 0x010;
+pub static GroupExecute: FilePermission = 0x008;
+pub static OtherRead: FilePermission    = 0x004;
+pub static OtherWrite: FilePermission   = 0x002;
+pub static OtherExecute: FilePermission = 0x001;
+
+// Common combinations of these bits
+pub static UserRWX: FilePermission  = UserRead | UserWrite | UserExecute;
+pub static GroupRWX: FilePermission = GroupRead | GroupWrite | GroupExecute;
+pub static OtherRWX: FilePermission = OtherRead | OtherWrite | OtherExecute;
+
+/// A set of permissions for user owned files, this is equivalent to 0644 on
+/// unix-like systems.
+pub static UserFile: FilePermission = UserRead | UserWrite | GroupRead | OtherRead;
+/// A set of permissions for user owned directories, this is equivalent to 0755
+/// on unix-like systems.
+pub static UserDir: FilePermission = UserRWX | GroupRead | GroupExecute |
+                                     OtherRead | OtherExecute;
+/// A set of permissions for user owned executables, this is equivalent to 0755
+/// on unix-like systems.
+pub static UserExec: FilePermission = UserDir;
+
+/// A mask for all possible permission bits
+pub static AllPermissions: FilePermission = 0x1ff;
diff --git a/src/libstd/rt/io/native/file.rs b/src/libstd/rt/io/native/file.rs
index 9f9e7dcee9f..35057f475cf 100644
--- a/src/libstd/rt/io/native/file.rs
+++ b/src/libstd/rt/io/native/file.rs
@@ -297,3 +297,488 @@ 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 libc::{size_t, c_void, c_int};
+    use libc;
+    use vec;
+
+    #[cfg(not(windows))] use c_str::CString;
+    #[cfg(not(windows))] use libc::fclose;
+    #[cfg(test)] #[cfg(windows)] use os;
+    #[cfg(test)] use rand;
+    #[cfg(windows)] use str;
+    #[cfg(windows)] use ptr;
+
+    // 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().perm;
+
+                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::fs::{mkdir_recursive};
+        use rt::io::{File, 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());
+
+        File::create(&filepath); // 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::fs::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/option.rs b/src/libstd/rt/io/option.rs
index 234b46458b4..5938252571f 100644
--- a/src/libstd/rt/io/option.rs
+++ b/src/libstd/rt/io/option.rs
@@ -11,7 +11,7 @@
 //! Implementations of I/O traits for the Option type
 //!
 //! I/O constructors return option types to allow errors to be handled.
-//! These implementations allow e.g. `Option<FileStream>` to be used
+//! These implementations allow e.g. `Option<File>` to be used
 //! as a `Reader` without unwrapping the option first.
 
 use option::*;
diff --git a/src/libstd/rt/io/signal.rs b/src/libstd/rt/io/signal.rs
index b782d713950..0f48f83a57e 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)]
@@ -208,6 +209,7 @@ mod test {
     #[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 82ff8071896..d24de7cbfee 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);
@@ -91,28 +91,42 @@ pub fn with_local_io<T>(f: &fn(&mut IoFactory) -> Option<T>) -> Option<T> {
 }
 
 pub trait IoFactory {
+    // networking
     fn tcp_connect(&mut self, addr: SocketAddr) -> Result<~RtioTcpStream, IoError>;
     fn tcp_bind(&mut self, addr: SocketAddr) -> Result<~RtioTcpListener, IoError>;
     fn udp_bind(&mut self, addr: SocketAddr) -> Result<~RtioUdpSocket, IoError>;
+    fn unix_bind(&mut self, path: &CString) ->
+        Result<~RtioUnixListener, IoError>;
+    fn unix_connect(&mut self, path: &CString) -> Result<~RtioPipe, IoError>;
     fn get_host_addresses(&mut self, host: Option<&str>, servname: Option<&str>,
                           hint: Option<ai::Hint>) -> Result<~[ai::Info], IoError>;
-    fn timer_init(&mut self) -> Result<~RtioTimer, IoError>;
+
+    // filesystem operations
     fn fs_from_raw_fd(&mut self, fd: c_int, close: CloseBehavior) -> ~RtioFileStream;
     fn fs_open(&mut self, path: &CString, fm: FileMode, fa: FileAccess)
         -> 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) -> 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) ->
         Result<~[Path], IoError>;
+    fn fs_lstat(&mut self, path: &CString) -> Result<FileStat, IoError>;
+    fn fs_chown(&mut self, path: &CString, uid: int, gid: int) ->
+        Result<(), IoError>;
+    fn fs_readlink(&mut self, path: &CString) -> Result<Path, IoError>;
+    fn fs_symlink(&mut self, src: &CString, dst: &CString) -> Result<(), IoError>;
+    fn fs_link(&mut self, src: &CString, dst: &CString) -> Result<(), IoError>;
+
+    // misc
+    fn timer_init(&mut self) -> Result<~RtioTimer, IoError>;
     fn spawn(&mut self, config: ProcessConfig)
             -> Result<(~RtioProcess, ~[Option<~RtioPipe>]), IoError>;
-
     fn pipe_open(&mut self, fd: c_int) -> Result<~RtioPipe, IoError>;
-    fn unix_bind(&mut self, path: &CString) ->
-        Result<~RtioUnixListener, IoError>;
-    fn unix_connect(&mut self, path: &CString) -> Result<~RtioPipe, IoError>;
     fn tty_open(&mut self, fd: c_int, readable: bool)
             -> Result<~RtioTTY, IoError>;
     fn signal(&mut self, signal: Signum, channel: SharedChan<Signum>)
@@ -173,6 +187,9 @@ pub trait RtioFileStream {
     fn pwrite(&mut self, buf: &[u8], offset: u64) -> Result<(), IoError>;
     fn seek(&mut self, pos: i64, whence: SeekStyle) -> Result<u64, IoError>;
     fn tell(&self) -> Result<u64, IoError>;
+    fn fsync(&mut self) -> Result<(), IoError>;
+    fn datasync(&mut self) -> Result<(), IoError>;
+    fn truncate(&mut self, offset: i64) -> Result<(), IoError>;
 }
 
 pub trait RtioProcess {
diff --git a/src/libstd/rt/sched.rs b/src/libstd/rt/sched.rs
index fd4dab60ff3..e71cd92589c 100644
--- a/src/libstd/rt/sched.rs
+++ b/src/libstd/rt/sched.rs
@@ -836,7 +836,7 @@ impl ClosureConverter for UnsafeTaskReceiver {
 }
 
 // On unix, we read randomness straight from /dev/urandom, but the
-// default constructor of an XorShiftRng does this via io::file, which
+// default constructor of an XorShiftRng does this via io::fs, which
 // relies on the scheduler existing, so we have to manually load
 // randomness. Windows has its own C API for this, so we don't need to
 // worry there.