about summary refs log tree commit diff
path: root/src/libnative
diff options
context:
space:
mode:
authorAaron Turon <aturon@mozilla.com>2014-09-30 17:34:14 -0700
committerAaron Turon <aturon@mozilla.com>2014-11-08 20:40:38 -0800
commit0c1e1ff1e300868a29405a334e65eae690df971d (patch)
treed863379e4827ece4d4f6905bc091d60be86d7c1a /src/libnative
parent16470cf01b688c576f47b93bdb4af88db33cf1e1 (diff)
downloadrust-0c1e1ff1e300868a29405a334e65eae690df971d.tar.gz
rust-0c1e1ff1e300868a29405a334e65eae690df971d.zip
Runtime removal: refactor fs
This moves the filesystem implementation from libnative into the new
`sys` modules, refactoring along the way and hooking into `std::io::fs`.

Because this eliminates APIs in `libnative` and `librustrt`, it is a:

[breaking-change]

This functionality is likely to be available publicly, in some form,
from `std` in the future.
Diffstat (limited to 'src/libnative')
-rw-r--r--src/libnative/io/file_unix.rs554
-rw-r--r--src/libnative/io/file_windows.rs523
-rw-r--r--src/libnative/io/mod.rs83
-rw-r--r--src/libnative/io/timer_unix.rs2
4 files changed, 1 insertions, 1161 deletions
diff --git a/src/libnative/io/file_unix.rs b/src/libnative/io/file_unix.rs
deleted file mode 100644
index f616295c73d..00000000000
--- a/src/libnative/io/file_unix.rs
+++ /dev/null
@@ -1,554 +0,0 @@
-// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-//! Blocking posix-based file I/O
-
-use alloc::arc::Arc;
-use libc::{mod, c_int, c_void};
-use std::c_str::CString;
-use std::mem;
-use std::rt::rtio::{mod, IoResult};
-
-use io::{retry, keep_going};
-use io::util;
-
-pub type fd_t = libc::c_int;
-
-struct Inner {
-    fd: fd_t,
-    close_on_drop: bool,
-}
-
-pub struct FileDesc {
-    inner: Arc<Inner>
-}
-
-impl FileDesc {
-    /// Create a `FileDesc` from an open C file descriptor.
-    ///
-    /// The `FileDesc` will take ownership of the specified file descriptor and
-    /// close it upon destruction if the `close_on_drop` flag is true, otherwise
-    /// it will not close the file descriptor when this `FileDesc` is dropped.
-    ///
-    /// Note that all I/O operations done on this object will be *blocking*, but
-    /// they do not require the runtime to be active.
-    pub fn new(fd: fd_t, close_on_drop: bool) -> FileDesc {
-        FileDesc { inner: Arc::new(Inner {
-            fd: fd,
-            close_on_drop: close_on_drop
-        }) }
-    }
-
-    // FIXME(#10465) these functions should not be public, but anything in
-    //               native::io wanting to use them is forced to have all the
-    //               rtio traits in scope
-    pub fn inner_read(&mut self, buf: &mut [u8]) -> IoResult<uint> {
-        let ret = retry(|| unsafe {
-            libc::read(self.fd(),
-                       buf.as_mut_ptr() as *mut libc::c_void,
-                       buf.len() as libc::size_t)
-        });
-        if ret == 0 {
-            Err(util::eof())
-        } else if ret < 0 {
-            Err(super::last_error())
-        } else {
-            Ok(ret as uint)
-        }
-    }
-    pub fn inner_write(&mut self, buf: &[u8]) -> IoResult<()> {
-        let ret = keep_going(buf, |buf, len| {
-            unsafe {
-                libc::write(self.fd(), buf as *const libc::c_void,
-                            len as libc::size_t) as i64
-            }
-        });
-        if ret < 0 {
-            Err(super::last_error())
-        } else {
-            Ok(())
-        }
-    }
-
-    pub fn fd(&self) -> fd_t { self.inner.fd }
-}
-
-impl rtio::RtioFileStream for FileDesc {
-    fn read(&mut self, buf: &mut [u8]) -> IoResult<int> {
-        self.inner_read(buf).map(|i| i as int)
-    }
-    fn write(&mut self, buf: &[u8]) -> IoResult<()> {
-        self.inner_write(buf)
-    }
-    fn pread(&mut self, buf: &mut [u8], offset: u64) -> IoResult<int> {
-        match retry(|| unsafe {
-            libc::pread(self.fd(), buf.as_ptr() as *mut _,
-                        buf.len() as libc::size_t,
-                        offset as libc::off_t)
-        }) {
-            -1 => Err(super::last_error()),
-            n => Ok(n as int)
-        }
-    }
-    fn pwrite(&mut self, buf: &[u8], offset: u64) -> IoResult<()> {
-        super::mkerr_libc(retry(|| unsafe {
-            libc::pwrite(self.fd(), buf.as_ptr() as *const _,
-                         buf.len() as libc::size_t, offset as libc::off_t)
-        }))
-    }
-    fn seek(&mut self, pos: i64, whence: rtio::SeekStyle) -> IoResult<u64> {
-        let whence = match whence {
-            rtio::SeekSet => libc::SEEK_SET,
-            rtio::SeekEnd => libc::SEEK_END,
-            rtio::SeekCur => libc::SEEK_CUR,
-        };
-        let n = unsafe { libc::lseek(self.fd(), pos as libc::off_t, whence) };
-        if n < 0 {
-            Err(super::last_error())
-        } else {
-            Ok(n as u64)
-        }
-    }
-    fn tell(&self) -> IoResult<u64> {
-        let n = unsafe { libc::lseek(self.fd(), 0, libc::SEEK_CUR) };
-        if n < 0 {
-            Err(super::last_error())
-        } else {
-            Ok(n as u64)
-        }
-    }
-    fn fsync(&mut self) -> IoResult<()> {
-        super::mkerr_libc(retry(|| unsafe { libc::fsync(self.fd()) }))
-    }
-    fn datasync(&mut self) -> IoResult<()> {
-        return super::mkerr_libc(os_datasync(self.fd()));
-
-        #[cfg(any(target_os = "macos", target_os = "ios"))]
-        fn os_datasync(fd: c_int) -> c_int {
-            unsafe { libc::fcntl(fd, libc::F_FULLFSYNC) }
-        }
-        #[cfg(target_os = "linux")]
-        fn os_datasync(fd: c_int) -> c_int {
-            retry(|| unsafe { libc::fdatasync(fd) })
-        }
-        #[cfg(not(any(target_os = "macos", target_os = "ios", target_os = "linux")))]
-        fn os_datasync(fd: c_int) -> c_int {
-            retry(|| unsafe { libc::fsync(fd) })
-        }
-    }
-    fn truncate(&mut self, offset: i64) -> IoResult<()> {
-        super::mkerr_libc(retry(|| unsafe {
-            libc::ftruncate(self.fd(), offset as libc::off_t)
-        }))
-    }
-
-    fn fstat(&mut self) -> IoResult<rtio::FileStat> {
-        let mut stat: libc::stat = unsafe { mem::zeroed() };
-        match unsafe { libc::fstat(self.fd(), &mut stat) } {
-            0 => Ok(mkstat(&stat)),
-            _ => Err(super::last_error()),
-        }
-    }
-}
-
-impl rtio::RtioPipe for FileDesc {
-    fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> {
-        self.inner_read(buf)
-    }
-    fn write(&mut self, buf: &[u8]) -> IoResult<()> {
-        self.inner_write(buf)
-    }
-    fn clone(&self) -> Box<rtio::RtioPipe + Send> {
-        box FileDesc { inner: self.inner.clone() } as Box<rtio::RtioPipe + Send>
-    }
-
-    // Only supported on named pipes currently. Note that this doesn't have an
-    // impact on the std::io primitives, this is never called via
-    // std::io::PipeStream. If the functionality is exposed in the future, then
-    // these methods will need to be implemented.
-    fn close_read(&mut self) -> IoResult<()> {
-        Err(super::unimpl())
-    }
-    fn close_write(&mut self) -> IoResult<()> {
-        Err(super::unimpl())
-    }
-    fn set_timeout(&mut self, _t: Option<u64>) {}
-    fn set_read_timeout(&mut self, _t: Option<u64>) {}
-    fn set_write_timeout(&mut self, _t: Option<u64>) {}
-}
-
-impl rtio::RtioTTY for FileDesc {
-    fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> {
-        self.inner_read(buf)
-    }
-    fn write(&mut self, buf: &[u8]) -> IoResult<()> {
-        self.inner_write(buf)
-    }
-    fn set_raw(&mut self, _raw: bool) -> IoResult<()> {
-        Err(super::unimpl())
-    }
-    fn get_winsize(&mut self) -> IoResult<(int, int)> {
-        Err(super::unimpl())
-    }
-    fn isatty(&self) -> bool { false }
-}
-
-impl Drop for Inner {
-    fn drop(&mut self) {
-        // closing stdio file handles makes no sense, so never do it. Also, note
-        // that errors are ignored when closing a file descriptor. The reason
-        // for this is that if an error occurs we don't actually know if the
-        // file descriptor was closed or not, and if we retried (for something
-        // like EINTR), we might close another valid file descriptor (opened
-        // after we closed ours.
-        if self.close_on_drop && self.fd > libc::STDERR_FILENO {
-            let n = unsafe { libc::close(self.fd) };
-            if n != 0 {
-                println!("error {} when closing file descriptor {}", n,
-                         self.fd);
-            }
-        }
-    }
-}
-
-pub struct CFile {
-    file: *mut libc::FILE,
-    fd: FileDesc,
-}
-
-impl CFile {
-    /// Create a `CFile` from an open `FILE` pointer.
-    ///
-    /// The `CFile` takes ownership of the `FILE` pointer and will close it upon
-    /// destruction.
-    pub fn new(file: *mut libc::FILE) -> CFile {
-        CFile {
-            file: file,
-            fd: FileDesc::new(unsafe { libc::fileno(file) }, false)
-        }
-    }
-
-    pub fn flush(&mut self) -> IoResult<()> {
-        super::mkerr_libc(retry(|| unsafe { libc::fflush(self.file) }))
-    }
-}
-
-impl rtio::RtioFileStream for CFile {
-    fn read(&mut self, buf: &mut [u8]) -> IoResult<int> {
-        let ret = keep_going(buf, |buf, len| {
-            unsafe {
-                libc::fread(buf as *mut libc::c_void, 1, len as libc::size_t,
-                            self.file) as i64
-            }
-        });
-        if ret == 0 {
-            Err(util::eof())
-        } else if ret < 0 {
-            Err(super::last_error())
-        } else {
-            Ok(ret as int)
-        }
-    }
-
-    fn write(&mut self, buf: &[u8]) -> IoResult<()> {
-        let ret = keep_going(buf, |buf, len| {
-            unsafe {
-                libc::fwrite(buf as *const libc::c_void, 1, len as libc::size_t,
-                            self.file) as i64
-            }
-        });
-        if ret < 0 {
-            Err(super::last_error())
-        } else {
-            Ok(())
-        }
-    }
-
-    fn pread(&mut self, buf: &mut [u8], offset: u64) -> IoResult<int> {
-        self.flush().and_then(|()| self.fd.pread(buf, offset))
-    }
-    fn pwrite(&mut self, buf: &[u8], offset: u64) -> IoResult<()> {
-        self.flush().and_then(|()| self.fd.pwrite(buf, offset))
-    }
-    fn seek(&mut self, pos: i64, style: rtio::SeekStyle) -> IoResult<u64> {
-        let whence = match style {
-            rtio::SeekSet => libc::SEEK_SET,
-            rtio::SeekEnd => libc::SEEK_END,
-            rtio::SeekCur => libc::SEEK_CUR,
-        };
-        let n = unsafe { libc::fseek(self.file, pos as libc::c_long, whence) };
-        if n < 0 {
-            Err(super::last_error())
-        } else {
-            Ok(n as u64)
-        }
-    }
-    fn tell(&self) -> IoResult<u64> {
-        let ret = unsafe { libc::ftell(self.file) };
-        if ret < 0 {
-            Err(super::last_error())
-        } else {
-            Ok(ret as u64)
-        }
-    }
-    fn fsync(&mut self) -> IoResult<()> {
-        self.flush().and_then(|()| self.fd.fsync())
-    }
-    fn datasync(&mut self) -> IoResult<()> {
-        self.flush().and_then(|()| self.fd.datasync())
-    }
-    fn truncate(&mut self, offset: i64) -> IoResult<()> {
-        self.flush().and_then(|()| self.fd.truncate(offset))
-    }
-
-    fn fstat(&mut self) -> IoResult<rtio::FileStat> {
-        self.flush().and_then(|()| self.fd.fstat())
-    }
-}
-
-impl Drop for CFile {
-    fn drop(&mut self) {
-        unsafe { let _ = libc::fclose(self.file); }
-    }
-}
-
-pub fn open(path: &CString, fm: rtio::FileMode, fa: rtio::FileAccess)
-    -> IoResult<FileDesc>
-{
-    let flags = match fm {
-        rtio::Open => 0,
-        rtio::Append => libc::O_APPEND,
-        rtio::Truncate => libc::O_TRUNC,
-    };
-    // Opening with a write permission must silently create the file.
-    let (flags, mode) = match fa {
-        rtio::Read => (flags | libc::O_RDONLY, 0),
-        rtio::Write => (flags | libc::O_WRONLY | libc::O_CREAT,
-                        libc::S_IRUSR | libc::S_IWUSR),
-        rtio::ReadWrite => (flags | libc::O_RDWR | libc::O_CREAT,
-                            libc::S_IRUSR | libc::S_IWUSR),
-    };
-
-    match retry(|| unsafe { libc::open(path.as_ptr(), flags, mode) }) {
-        -1 => Err(super::last_error()),
-        fd => Ok(FileDesc::new(fd, true)),
-    }
-}
-
-pub fn mkdir(p: &CString, mode: uint) -> IoResult<()> {
-    super::mkerr_libc(unsafe { libc::mkdir(p.as_ptr(), mode as libc::mode_t) })
-}
-
-pub fn readdir(p: &CString) -> IoResult<Vec<CString>> {
-    use libc::{dirent_t};
-    use libc::{opendir, readdir_r, closedir};
-
-    fn prune(root: &CString, dirs: Vec<Path>) -> Vec<CString> {
-        let root = unsafe { CString::new(root.as_ptr(), false) };
-        let root = Path::new(root);
-
-        dirs.into_iter().filter(|path| {
-            path.as_vec() != b"." && path.as_vec() != b".."
-        }).map(|path| root.join(path).to_c_str()).collect()
-    }
-
-    extern {
-        fn rust_dirent_t_size() -> libc::c_int;
-        fn rust_list_dir_val(ptr: *mut dirent_t) -> *const libc::c_char;
-    }
-
-    let size = unsafe { rust_dirent_t_size() };
-    let mut buf = Vec::<u8>::with_capacity(size as uint);
-    let ptr = buf.as_mut_slice().as_mut_ptr() as *mut dirent_t;
-
-    let dir_ptr = unsafe {opendir(p.as_ptr())};
-
-    if dir_ptr as uint != 0 {
-        let mut paths = vec!();
-        let mut entry_ptr = 0 as *mut dirent_t;
-        while unsafe { readdir_r(dir_ptr, ptr, &mut entry_ptr) == 0 } {
-            if entry_ptr.is_null() { break }
-            let cstr = unsafe {
-                CString::new(rust_list_dir_val(entry_ptr), false)
-            };
-            paths.push(Path::new(cstr));
-        }
-        assert_eq!(unsafe { closedir(dir_ptr) }, 0);
-        Ok(prune(p, paths))
-    } else {
-        Err(super::last_error())
-    }
-}
-
-pub fn unlink(p: &CString) -> IoResult<()> {
-    super::mkerr_libc(unsafe { libc::unlink(p.as_ptr()) })
-}
-
-pub fn rename(old: &CString, new: &CString) -> IoResult<()> {
-    super::mkerr_libc(unsafe { libc::rename(old.as_ptr(), new.as_ptr()) })
-}
-
-pub fn chmod(p: &CString, mode: uint) -> IoResult<()> {
-    super::mkerr_libc(retry(|| unsafe {
-        libc::chmod(p.as_ptr(), mode as libc::mode_t)
-    }))
-}
-
-pub fn rmdir(p: &CString) -> IoResult<()> {
-    super::mkerr_libc(unsafe { libc::rmdir(p.as_ptr()) })
-}
-
-pub fn chown(p: &CString, uid: int, gid: int) -> IoResult<()> {
-    super::mkerr_libc(retry(|| unsafe {
-        libc::chown(p.as_ptr(), uid as libc::uid_t,
-                    gid as libc::gid_t)
-    }))
-}
-
-pub fn readlink(p: &CString) -> IoResult<CString> {
-    let p = p.as_ptr();
-    let mut len = unsafe { libc::pathconf(p as *mut _, libc::_PC_NAME_MAX) };
-    if len == -1 {
-        len = 1024; // FIXME: read PATH_MAX from C ffi?
-    }
-    let mut buf: Vec<u8> = Vec::with_capacity(len as uint);
-    match unsafe {
-        libc::readlink(p, buf.as_ptr() as *mut libc::c_char,
-                       len as libc::size_t) as libc::c_int
-    } {
-        -1 => Err(super::last_error()),
-        n => {
-            assert!(n > 0);
-            unsafe { buf.set_len(n as uint); }
-            Ok(buf.as_slice().to_c_str())
-        }
-    }
-}
-
-pub fn symlink(src: &CString, dst: &CString) -> IoResult<()> {
-    super::mkerr_libc(unsafe { libc::symlink(src.as_ptr(), dst.as_ptr()) })
-}
-
-pub fn link(src: &CString, dst: &CString) -> IoResult<()> {
-    super::mkerr_libc(unsafe { libc::link(src.as_ptr(), dst.as_ptr()) })
-}
-
-fn mkstat(stat: &libc::stat) -> rtio::FileStat {
-    // FileStat times are in milliseconds
-    fn mktime(secs: u64, nsecs: u64) -> u64 { secs * 1000 + nsecs / 1000000 }
-
-    #[cfg(not(any(target_os = "linux", target_os = "android")))]
-    fn flags(stat: &libc::stat) -> u64 { stat.st_flags as u64 }
-    #[cfg(any(target_os = "linux", target_os = "android"))]
-    fn flags(_stat: &libc::stat) -> u64 { 0 }
-
-    #[cfg(not(any(target_os = "linux", target_os = "android")))]
-    fn gen(stat: &libc::stat) -> u64 { stat.st_gen as u64 }
-    #[cfg(any(target_os = "linux", target_os = "android"))]
-    fn gen(_stat: &libc::stat) -> u64 { 0 }
-
-    rtio::FileStat {
-        size: stat.st_size as u64,
-        kind: stat.st_mode as u64,
-        perm: stat.st_mode as u64,
-        created: mktime(stat.st_ctime as u64, stat.st_ctime_nsec as u64),
-        modified: mktime(stat.st_mtime as u64, stat.st_mtime_nsec as u64),
-        accessed: mktime(stat.st_atime as u64, stat.st_atime_nsec as u64),
-        device: stat.st_dev as u64,
-        inode: stat.st_ino as u64,
-        rdev: stat.st_rdev as u64,
-        nlink: stat.st_nlink as u64,
-        uid: stat.st_uid as u64,
-        gid: stat.st_gid as u64,
-        blksize: stat.st_blksize as u64,
-        blocks: stat.st_blocks as u64,
-        flags: flags(stat),
-        gen: gen(stat),
-    }
-}
-
-pub fn stat(p: &CString) -> IoResult<rtio::FileStat> {
-    let mut stat: libc::stat = unsafe { mem::zeroed() };
-    match unsafe { libc::stat(p.as_ptr(), &mut stat) } {
-        0 => Ok(mkstat(&stat)),
-        _ => Err(super::last_error()),
-    }
-}
-
-pub fn lstat(p: &CString) -> IoResult<rtio::FileStat> {
-    let mut stat: libc::stat = unsafe { mem::zeroed() };
-    match unsafe { libc::lstat(p.as_ptr(), &mut stat) } {
-        0 => Ok(mkstat(&stat)),
-        _ => Err(super::last_error()),
-    }
-}
-
-pub fn utime(p: &CString, atime: u64, mtime: u64) -> IoResult<()> {
-    let buf = libc::utimbuf {
-        actime: (atime / 1000) as libc::time_t,
-        modtime: (mtime / 1000) as libc::time_t,
-    };
-    super::mkerr_libc(unsafe { libc::utime(p.as_ptr(), &buf) })
-}
-
-#[cfg(test)]
-mod tests {
-    use super::{CFile, FileDesc};
-    use libc;
-    use std::os;
-    use std::rt::rtio::{RtioFileStream, SeekSet};
-
-    #[cfg_attr(target_os = "freebsd", ignore)] // hmm, maybe pipes have a tiny buffer
-    #[test]
-    fn test_file_desc() {
-        // Run this test with some pipes so we don't have to mess around with
-        // opening or closing files.
-        let os::Pipe { reader, writer } = unsafe { os::pipe().unwrap() };
-        let mut reader = FileDesc::new(reader, true);
-        let mut writer = FileDesc::new(writer, true);
-
-        writer.inner_write(b"test").ok().unwrap();
-        let mut buf = [0u8, ..4];
-        match reader.inner_read(buf) {
-            Ok(4) => {
-                assert_eq!(buf[0], 't' as u8);
-                assert_eq!(buf[1], 'e' as u8);
-                assert_eq!(buf[2], 's' as u8);
-                assert_eq!(buf[3], 't' as u8);
-            }
-            r => panic!("invalid read: {}", r),
-        }
-
-        assert!(writer.inner_read(buf).is_err());
-        assert!(reader.inner_write(buf).is_err());
-    }
-
-    #[test]
-    fn test_cfile() {
-        unsafe {
-            let f = libc::tmpfile();
-            assert!(!f.is_null());
-            let mut file = CFile::new(f);
-
-            file.write(b"test").ok().unwrap();
-            let mut buf = [0u8, ..4];
-            let _ = file.seek(0, SeekSet).ok().unwrap();
-            match file.read(buf) {
-                Ok(4) => {
-                    assert_eq!(buf[0], 't' as u8);
-                    assert_eq!(buf[1], 'e' as u8);
-                    assert_eq!(buf[2], 's' as u8);
-                    assert_eq!(buf[3], 't' as u8);
-                }
-                r => panic!("invalid read: {}", r)
-            }
-        }
-    }
-}
diff --git a/src/libnative/io/file_windows.rs b/src/libnative/io/file_windows.rs
deleted file mode 100644
index eb4d4f22132..00000000000
--- a/src/libnative/io/file_windows.rs
+++ /dev/null
@@ -1,523 +0,0 @@
-// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-//! Blocking Windows-based file I/O
-
-use alloc::arc::Arc;
-use libc::{mod, c_int};
-use std::c_str::CString;
-use std::mem;
-use std::os::windows::fill_utf16_buf_and_decode;
-use std::ptr;
-use std::rt::rtio;
-use std::rt::rtio::{IoResult, IoError};
-use std::str;
-
-pub type fd_t = libc::c_int;
-
-struct Inner {
-    fd: fd_t,
-    close_on_drop: bool,
-}
-
-pub struct FileDesc {
-    inner: Arc<Inner>
-}
-
-impl FileDesc {
-    /// Create a `FileDesc` from an open C file descriptor.
-    ///
-    /// The `FileDesc` will take ownership of the specified file descriptor and
-    /// close it upon destruction if the `close_on_drop` flag is true, otherwise
-    /// it will not close the file descriptor when this `FileDesc` is dropped.
-    ///
-    /// Note that all I/O operations done on this object will be *blocking*, but
-    /// they do not require the runtime to be active.
-    pub fn new(fd: fd_t, close_on_drop: bool) -> FileDesc {
-        FileDesc { inner: Arc::new(Inner {
-            fd: fd,
-            close_on_drop: close_on_drop
-        }) }
-    }
-
-    pub fn inner_read(&mut self, buf: &mut [u8]) -> IoResult<uint> {
-        let mut read = 0;
-        let ret = unsafe {
-            libc::ReadFile(self.handle(), buf.as_ptr() as libc::LPVOID,
-                           buf.len() as libc::DWORD, &mut read,
-                           ptr::null_mut())
-        };
-        if ret != 0 {
-            Ok(read as uint)
-        } else {
-            Err(super::last_error())
-        }
-    }
-    pub fn inner_write(&mut self, buf: &[u8]) -> IoResult<()> {
-        let mut cur = buf.as_ptr();
-        let mut remaining = buf.len();
-        while remaining > 0 {
-            let mut amt = 0;
-            let ret = unsafe {
-                libc::WriteFile(self.handle(), cur as libc::LPVOID,
-                                remaining as libc::DWORD, &mut amt,
-                                ptr::null_mut())
-            };
-            if ret != 0 {
-                remaining -= amt as uint;
-                cur = unsafe { cur.offset(amt as int) };
-            } else {
-                return Err(super::last_error())
-            }
-        }
-        Ok(())
-    }
-
-    pub fn fd(&self) -> fd_t { self.inner.fd }
-
-    pub fn handle(&self) -> libc::HANDLE {
-        unsafe { libc::get_osfhandle(self.fd()) as libc::HANDLE }
-    }
-
-    // A version of seek that takes &self so that tell can call it
-    //   - the private seek should of course take &mut self.
-    fn seek_common(&self, pos: i64, style: rtio::SeekStyle) -> IoResult<u64> {
-        let whence = match style {
-            rtio::SeekSet => libc::FILE_BEGIN,
-            rtio::SeekEnd => libc::FILE_END,
-            rtio::SeekCur => libc::FILE_CURRENT,
-        };
-        unsafe {
-            let mut newpos = 0;
-            match libc::SetFilePointerEx(self.handle(), pos, &mut newpos,
-                                         whence) {
-                0 => Err(super::last_error()),
-                _ => Ok(newpos as u64),
-            }
-        }
-    }
-
-}
-
-impl rtio::RtioFileStream for FileDesc {
-    fn read(&mut self, buf: &mut [u8]) -> IoResult<int> {
-        self.inner_read(buf).map(|i| i as int)
-    }
-    fn write(&mut self, buf: &[u8]) -> IoResult<()> {
-        self.inner_write(buf)
-    }
-
-    fn pread(&mut self, buf: &mut [u8], offset: u64) -> IoResult<int> {
-        let mut read = 0;
-        let mut overlap: libc::OVERLAPPED = unsafe { mem::zeroed() };
-        overlap.Offset = offset as libc::DWORD;
-        overlap.OffsetHigh = (offset >> 32) as libc::DWORD;
-        let ret = unsafe {
-            libc::ReadFile(self.handle(), buf.as_ptr() as libc::LPVOID,
-                           buf.len() as libc::DWORD, &mut read,
-                           &mut overlap)
-        };
-        if ret != 0 {
-            Ok(read as int)
-        } else {
-            Err(super::last_error())
-        }
-    }
-    fn pwrite(&mut self, buf: &[u8], mut offset: u64) -> IoResult<()> {
-        let mut cur = buf.as_ptr();
-        let mut remaining = buf.len();
-        let mut overlap: libc::OVERLAPPED = unsafe { mem::zeroed() };
-        while remaining > 0 {
-            overlap.Offset = offset as libc::DWORD;
-            overlap.OffsetHigh = (offset >> 32) as libc::DWORD;
-            let mut amt = 0;
-            let ret = unsafe {
-                libc::WriteFile(self.handle(), cur as libc::LPVOID,
-                                remaining as libc::DWORD, &mut amt,
-                                &mut overlap)
-            };
-            if ret != 0 {
-                remaining -= amt as uint;
-                cur = unsafe { cur.offset(amt as int) };
-                offset += amt as u64;
-            } else {
-                return Err(super::last_error())
-            }
-        }
-        Ok(())
-    }
-
-    fn seek(&mut self, pos: i64, style: rtio::SeekStyle) -> IoResult<u64> {
-        self.seek_common(pos, style)
-    }
-
-    fn tell(&self) -> IoResult<u64> {
-        self.seek_common(0, rtio::SeekCur)
-    }
-
-    fn fsync(&mut self) -> IoResult<()> {
-        super::mkerr_winbool(unsafe {
-            libc::FlushFileBuffers(self.handle())
-        })
-    }
-
-    fn datasync(&mut self) -> IoResult<()> { return self.fsync(); }
-
-    fn truncate(&mut self, offset: i64) -> IoResult<()> {
-        let orig_pos = try!(self.tell());
-        let _ = try!(self.seek(offset, rtio::SeekSet));
-        let ret = unsafe {
-            match libc::SetEndOfFile(self.handle()) {
-                0 => Err(super::last_error()),
-                _ => Ok(())
-            }
-        };
-        let _ = self.seek(orig_pos as i64, rtio::SeekSet);
-        return ret;
-    }
-
-    fn fstat(&mut self) -> IoResult<rtio::FileStat> {
-        let mut stat: libc::stat = unsafe { mem::zeroed() };
-        match unsafe { libc::fstat(self.fd(), &mut stat) } {
-            0 => Ok(mkstat(&stat)),
-            _ => Err(super::last_error()),
-        }
-    }
-}
-
-impl rtio::RtioPipe for FileDesc {
-    fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> {
-        self.inner_read(buf)
-    }
-    fn write(&mut self, buf: &[u8]) -> IoResult<()> {
-        self.inner_write(buf)
-    }
-    fn clone(&self) -> Box<rtio::RtioPipe + Send> {
-        box FileDesc { inner: self.inner.clone() } as Box<rtio::RtioPipe + Send>
-    }
-
-    // Only supported on named pipes currently. Note that this doesn't have an
-    // impact on the std::io primitives, this is never called via
-    // std::io::PipeStream. If the functionality is exposed in the future, then
-    // these methods will need to be implemented.
-    fn close_read(&mut self) -> IoResult<()> {
-        Err(super::unimpl())
-    }
-    fn close_write(&mut self) -> IoResult<()> {
-        Err(super::unimpl())
-    }
-    fn set_timeout(&mut self, _t: Option<u64>) {}
-    fn set_read_timeout(&mut self, _t: Option<u64>) {}
-    fn set_write_timeout(&mut self, _t: Option<u64>) {}
-}
-
-impl rtio::RtioTTY for FileDesc {
-    fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> {
-        self.inner_read(buf)
-    }
-    fn write(&mut self, buf: &[u8]) -> IoResult<()> {
-        self.inner_write(buf)
-    }
-    fn set_raw(&mut self, _raw: bool) -> IoResult<()> {
-        Err(super::unimpl())
-    }
-    fn get_winsize(&mut self) -> IoResult<(int, int)> {
-        Err(super::unimpl())
-    }
-    fn isatty(&self) -> bool { false }
-}
-
-impl Drop for Inner {
-    fn drop(&mut self) {
-        // closing stdio file handles makes no sense, so never do it. Also, note
-        // that errors are ignored when closing a file descriptor. The reason
-        // for this is that if an error occurs we don't actually know if the
-        // file descriptor was closed or not, and if we retried (for something
-        // like EINTR), we might close another valid file descriptor (opened
-        // after we closed ours.
-        if self.close_on_drop && self.fd > libc::STDERR_FILENO {
-            let n = unsafe { libc::close(self.fd) };
-            if n != 0 {
-                println!("error {} when closing file descriptor {}", n, self.fd);
-            }
-        }
-    }
-}
-
-pub fn to_utf16(s: &CString) -> IoResult<Vec<u16>> {
-    match s.as_str() {
-        Some(s) => Ok({
-            let mut s = s.utf16_units().collect::<Vec<u16>>();
-            s.push(0);
-            s
-        }),
-        None => Err(IoError {
-            code: libc::ERROR_INVALID_NAME as uint,
-            extra: 0,
-            detail: Some("valid unicode input required".to_string()),
-        })
-    }
-}
-
-pub fn open(path: &CString, fm: rtio::FileMode, fa: rtio::FileAccess)
-        -> IoResult<FileDesc> {
-    // Flags passed to open_osfhandle
-    let flags = match fm {
-        rtio::Open => 0,
-        rtio::Append => libc::O_APPEND,
-        rtio::Truncate => libc::O_TRUNC,
-    };
-    let flags = match fa {
-        rtio::Read => flags | libc::O_RDONLY,
-        rtio::Write => flags | libc::O_WRONLY | libc::O_CREAT,
-        rtio::ReadWrite => flags | libc::O_RDWR | libc::O_CREAT,
-    };
-
-    let mut dwDesiredAccess = match fa {
-        rtio::Read => libc::FILE_GENERIC_READ,
-        rtio::Write => libc::FILE_GENERIC_WRITE,
-        rtio::ReadWrite => libc::FILE_GENERIC_READ | libc::FILE_GENERIC_WRITE
-    };
-
-    // libuv has a good comment about this, but the basic idea is what we try to
-    // emulate unix semantics by enabling all sharing by allowing things such as
-    // deleting a file while it's still open.
-    let dwShareMode = libc::FILE_SHARE_READ | libc::FILE_SHARE_WRITE |
-                      libc::FILE_SHARE_DELETE;
-
-    let dwCreationDisposition = match (fm, fa) {
-        (rtio::Truncate, rtio::Read) => libc::TRUNCATE_EXISTING,
-        (rtio::Truncate, _) => libc::CREATE_ALWAYS,
-        (rtio::Open, rtio::Read) => libc::OPEN_EXISTING,
-        (rtio::Open, _) => libc::OPEN_ALWAYS,
-        (rtio::Append, rtio::Read) => {
-            dwDesiredAccess |= libc::FILE_APPEND_DATA;
-            libc::OPEN_EXISTING
-        }
-        (rtio::Append, _) => {
-            dwDesiredAccess &= !libc::FILE_WRITE_DATA;
-            dwDesiredAccess |= libc::FILE_APPEND_DATA;
-            libc::OPEN_ALWAYS
-        }
-    };
-
-    let mut dwFlagsAndAttributes = libc::FILE_ATTRIBUTE_NORMAL;
-    // Compat with unix, this allows opening directories (see libuv)
-    dwFlagsAndAttributes |= libc::FILE_FLAG_BACKUP_SEMANTICS;
-
-    let path = try!(to_utf16(path));
-    let handle = unsafe {
-        libc::CreateFileW(path.as_ptr(),
-                          dwDesiredAccess,
-                          dwShareMode,
-                          ptr::null_mut(),
-                          dwCreationDisposition,
-                          dwFlagsAndAttributes,
-                          ptr::null_mut())
-    };
-    if handle == libc::INVALID_HANDLE_VALUE {
-        Err(super::last_error())
-    } else {
-        let fd = unsafe {
-            libc::open_osfhandle(handle as libc::intptr_t, flags)
-        };
-        if fd < 0 {
-            let _ = unsafe { libc::CloseHandle(handle) };
-            Err(super::last_error())
-        } else {
-            Ok(FileDesc::new(fd, true))
-        }
-    }
-}
-
-pub fn mkdir(p: &CString, _mode: uint) -> IoResult<()> {
-    let p = try!(to_utf16(p));
-    super::mkerr_winbool(unsafe {
-        // FIXME: turn mode into something useful? #2623
-        libc::CreateDirectoryW(p.as_ptr(), ptr::null_mut())
-    })
-}
-
-pub fn readdir(p: &CString) -> IoResult<Vec<CString>> {
-    fn prune(root: &CString, dirs: Vec<Path>) -> Vec<CString> {
-        let root = unsafe { CString::new(root.as_ptr(), false) };
-        let root = Path::new(root);
-
-        dirs.into_iter().filter(|path| {
-            path.as_vec() != b"." && path.as_vec() != b".."
-        }).map(|path| root.join(path).to_c_str()).collect()
-    }
-
-    let star = Path::new(unsafe {
-        CString::new(p.as_ptr(), false)
-    }).join("*");
-    let path = try!(to_utf16(&star.to_c_str()));
-
-    unsafe {
-        let mut wfd = mem::zeroed();
-        let find_handle = libc::FindFirstFileW(path.as_ptr(), &mut wfd);
-        if find_handle != libc::INVALID_HANDLE_VALUE {
-            let mut paths = vec![];
-            let mut more_files = 1 as libc::BOOL;
-            while more_files != 0 {
-                {
-                    let filename = str::truncate_utf16_at_nul(wfd.cFileName);
-                    match String::from_utf16(filename) {
-                        Some(filename) => paths.push(Path::new(filename)),
-                        None => {
-                            assert!(libc::FindClose(find_handle) != 0);
-                            return Err(IoError {
-                                code: super::c::ERROR_ILLEGAL_CHARACTER as uint,
-                                extra: 0,
-                                detail: Some(format!("path was not valid UTF-16: {}", filename)),
-                            })
-                        }, // FIXME #12056: Convert the UCS-2 to invalid utf-8 instead of erroring
-                    }
-                }
-                more_files = libc::FindNextFileW(find_handle, &mut wfd);
-            }
-            assert!(libc::FindClose(find_handle) != 0);
-            Ok(prune(p, paths))
-        } else {
-            Err(super::last_error())
-        }
-    }
-}
-
-pub fn unlink(p: &CString) -> IoResult<()> {
-    let p = try!(to_utf16(p));
-    super::mkerr_winbool(unsafe {
-        libc::DeleteFileW(p.as_ptr())
-    })
-}
-
-pub fn rename(old: &CString, new: &CString) -> IoResult<()> {
-    let old = try!(to_utf16(old));
-    let new = try!(to_utf16(new));
-    super::mkerr_winbool(unsafe {
-        libc::MoveFileExW(old.as_ptr(), new.as_ptr(),
-                          libc::MOVEFILE_REPLACE_EXISTING)
-    })
-}
-
-pub fn chmod(p: &CString, mode: uint) -> IoResult<()> {
-    let p = try!(to_utf16(p));
-    super::mkerr_libc(unsafe {
-        libc::wchmod(p.as_ptr(), mode as libc::c_int)
-    })
-}
-
-pub fn rmdir(p: &CString) -> IoResult<()> {
-    let p = try!(to_utf16(p));
-    super::mkerr_libc(unsafe { libc::wrmdir(p.as_ptr()) })
-}
-
-pub fn chown(_p: &CString, _uid: int, _gid: int) -> IoResult<()> {
-    // libuv has this as a no-op, so seems like this should as well?
-    Ok(())
-}
-
-pub fn readlink(p: &CString) -> IoResult<CString> {
-    // FIXME: I have a feeling that this reads intermediate symlinks as well.
-    use io::c::compat::kernel32::GetFinalPathNameByHandleW;
-    let p = try!(to_utf16(p));
-    let handle = unsafe {
-        libc::CreateFileW(p.as_ptr(),
-                          libc::GENERIC_READ,
-                          libc::FILE_SHARE_READ,
-                          ptr::null_mut(),
-                          libc::OPEN_EXISTING,
-                          libc::FILE_ATTRIBUTE_NORMAL,
-                          ptr::null_mut())
-    };
-    if handle == libc::INVALID_HANDLE_VALUE {
-        return Err(super::last_error())
-    }
-    // Specify (sz - 1) because the documentation states that it's the size
-    // without the null pointer
-    let ret = fill_utf16_buf_and_decode(|buf, sz| unsafe {
-        GetFinalPathNameByHandleW(handle,
-                                  buf as *const u16,
-                                  sz - 1,
-                                  libc::VOLUME_NAME_DOS)
-    });
-    let ret = match ret {
-        Some(ref s) if s.as_slice().starts_with(r"\\?\") => {
-            Ok(Path::new(s.as_slice().slice_from(4)).to_c_str())
-        }
-        Some(s) => Ok(Path::new(s).to_c_str()),
-        None => Err(super::last_error()),
-    };
-    assert!(unsafe { libc::CloseHandle(handle) } != 0);
-    return ret;
-}
-
-pub fn symlink(src: &CString, dst: &CString) -> IoResult<()> {
-    use io::c::compat::kernel32::CreateSymbolicLinkW;
-    let src = try!(to_utf16(src));
-    let dst = try!(to_utf16(dst));
-    super::mkerr_winbool(unsafe {
-        CreateSymbolicLinkW(dst.as_ptr(), src.as_ptr(), 0) as libc::BOOL
-    })
-}
-
-pub fn link(src: &CString, dst: &CString) -> IoResult<()> {
-    let src = try!(to_utf16(src));
-    let dst = try!(to_utf16(dst));
-    super::mkerr_winbool(unsafe {
-        libc::CreateHardLinkW(dst.as_ptr(), src.as_ptr(), ptr::null_mut())
-    })
-}
-
-fn mkstat(stat: &libc::stat) -> rtio::FileStat {
-    rtio::FileStat {
-        size: stat.st_size as u64,
-        kind: stat.st_mode as u64,
-        perm: stat.st_mode as u64,
-        created: stat.st_ctime as u64,
-        modified: stat.st_mtime as u64,
-        accessed: stat.st_atime as u64,
-        device: stat.st_dev as u64,
-        inode: stat.st_ino as u64,
-        rdev: stat.st_rdev as u64,
-        nlink: stat.st_nlink as u64,
-        uid: stat.st_uid as u64,
-        gid: stat.st_gid as u64,
-        blksize: 0,
-        blocks: 0,
-        flags: 0,
-        gen: 0,
-    }
-}
-
-pub fn stat(p: &CString) -> IoResult<rtio::FileStat> {
-    let mut stat: libc::stat = unsafe { mem::zeroed() };
-    let p = try!(to_utf16(p));
-    match unsafe { libc::wstat(p.as_ptr(), &mut stat) } {
-        0 => Ok(mkstat(&stat)),
-        _ => Err(super::last_error()),
-    }
-}
-
-pub fn lstat(_p: &CString) -> IoResult<rtio::FileStat> {
-    // FIXME: implementation is missing
-    Err(super::unimpl())
-}
-
-pub fn utime(p: &CString, atime: u64, mtime: u64) -> IoResult<()> {
-    let mut buf = libc::utimbuf {
-        actime: atime as libc::time64_t,
-        modtime: mtime as libc::time64_t,
-    };
-    let p = try!(to_utf16(p));
-    super::mkerr_libc(unsafe {
-        libc::wutime(p.as_ptr(), &mut buf)
-    })
-}
diff --git a/src/libnative/io/mod.rs b/src/libnative/io/mod.rs
index a541712e17f..baf58b83dcd 100644
--- a/src/libnative/io/mod.rs
+++ b/src/libnative/io/mod.rs
@@ -30,7 +30,6 @@ use std::rt::rtio::{mod, IoResult, IoError};
 use std::num;
 
 // Local re-exports
-pub use self::file::FileDesc;
 pub use self::process::Process;
 
 mod helper_thread;
@@ -41,13 +40,6 @@ pub mod net;
 pub mod process;
 mod util;
 
-#[cfg(unix)]
-#[path = "file_unix.rs"]
-pub mod file;
-#[cfg(windows)]
-#[path = "file_windows.rs"]
-pub mod file;
-
 #[cfg(any(target_os = "macos",
           target_os = "ios",
           target_os = "freebsd",
@@ -92,25 +84,6 @@ fn last_error() -> IoError {
     }
 }
 
-// unix has nonzero values as errors
-fn mkerr_libc <Int: num::Zero>(ret: Int) -> IoResult<()> {
-    if !ret.is_zero() {
-        Err(last_error())
-    } else {
-        Ok(())
-    }
-}
-
-// windows has zero values as errors
-#[cfg(windows)]
-fn mkerr_winbool(ret: libc::c_int) -> IoResult<()> {
-    if ret == 0 {
-        Err(last_error())
-    } else {
-        Ok(())
-    }
-}
-
 #[cfg(windows)]
 #[inline]
 fn retry<I> (f: || -> I) -> I { f() } // PR rust-lang/rust/#17020
@@ -199,62 +172,6 @@ impl rtio::IoFactory for IoFactory {
         addrinfo::GetAddrInfoRequest::run(host, servname, hint)
     }
 
-    // filesystem operations
-    fn fs_from_raw_fd(&mut self, fd: c_int, close: rtio::CloseBehavior)
-                      -> Box<rtio::RtioFileStream + Send> {
-        let close = match close {
-            rtio::CloseSynchronously | rtio::CloseAsynchronously => true,
-            rtio::DontClose => false
-        };
-        box file::FileDesc::new(fd, close) as Box<rtio::RtioFileStream + Send>
-    }
-    fn fs_open(&mut self, path: &CString, fm: rtio::FileMode,
-               fa: rtio::FileAccess)
-        -> IoResult<Box<rtio::RtioFileStream + Send>>
-    {
-        file::open(path, fm, fa).map(|fd| box fd as Box<rtio::RtioFileStream + Send>)
-    }
-    fn fs_unlink(&mut self, path: &CString) -> IoResult<()> {
-        file::unlink(path)
-    }
-    fn fs_stat(&mut self, path: &CString) -> IoResult<rtio::FileStat> {
-        file::stat(path)
-    }
-    fn fs_mkdir(&mut self, path: &CString, mode: uint) -> IoResult<()> {
-        file::mkdir(path, mode)
-    }
-    fn fs_chmod(&mut self, path: &CString, mode: uint) -> IoResult<()> {
-        file::chmod(path, mode)
-    }
-    fn fs_rmdir(&mut self, path: &CString) -> IoResult<()> {
-        file::rmdir(path)
-    }
-    fn fs_rename(&mut self, path: &CString, to: &CString) -> IoResult<()> {
-        file::rename(path, to)
-    }
-    fn fs_readdir(&mut self, path: &CString, _flags: c_int) -> IoResult<Vec<CString>> {
-        file::readdir(path)
-    }
-    fn fs_lstat(&mut self, path: &CString) -> IoResult<rtio::FileStat> {
-        file::lstat(path)
-    }
-    fn fs_chown(&mut self, path: &CString, uid: int, gid: int) -> IoResult<()> {
-        file::chown(path, uid, gid)
-    }
-    fn fs_readlink(&mut self, path: &CString) -> IoResult<CString> {
-        file::readlink(path)
-    }
-    fn fs_symlink(&mut self, src: &CString, dst: &CString) -> IoResult<()> {
-        file::symlink(src, dst)
-    }
-    fn fs_link(&mut self, src: &CString, dst: &CString) -> IoResult<()> {
-        file::link(src, dst)
-    }
-    fn fs_utime(&mut self, src: &CString, atime: u64,
-                mtime: u64) -> IoResult<()> {
-        file::utime(src, atime, mtime)
-    }
-
     // misc
     fn timer_init(&mut self) -> IoResult<Box<rtio::RtioTimer + Send>> {
         timer::Timer::new().map(|t| box t as Box<rtio::RtioTimer + Send>)
diff --git a/src/libnative/io/timer_unix.rs b/src/libnative/io/timer_unix.rs
index 38895f2a8f9..c26e2e76cee 100644
--- a/src/libnative/io/timer_unix.rs
+++ b/src/libnative/io/timer_unix.rs
@@ -56,7 +56,7 @@ use std::sync::atomic;
 use std::comm;
 
 use io::c;
-use io::file::FileDesc;
+use platform_imp::fs::FileDesc;
 use io::helper_thread::Helper;
 
 helper_init!(static HELPER: Helper<Req>)