]> git.lizzy.rs Git - rust.git/commitdiff
Implement more native file I/O
authorAlex Crichton <alex@alexcrichton.com>
Wed, 13 Nov 2013 22:48:45 +0000 (14:48 -0800)
committerAlex Crichton <alex@alexcrichton.com>
Tue, 19 Nov 2013 17:59:21 +0000 (09:59 -0800)
This implements a fair amount of the unimpl() functionality in io::native
relating to filesystem operations. I've also modified all io::fs tests to run in
both a native and uv environment (so everything is actually tested).

There are a two bits of remaining functionality which I was unable to get
working:

* change_file_times on windows
* lstat on windows

I think that change_file_times may just need a better interface, but lstat has a
large implementation in libuv which I didn't want to tackle trying to copy.

src/libstd/io/buffered.rs
src/libstd/io/fs.rs
src/libstd/io/native/file.rs
src/libstd/io/native/mod.rs
src/libstd/io/stdio.rs
src/libstd/libc.rs
src/rt/rust_builtin.c
src/rt/rustrt.def.in
src/test/run-pass/conditional-compile.rs

index 2d8f1a721661993684a4a248739693b98a65253d..d74acb5f59baa0a705d0bd01cb5a5df74be19e03 100644 (file)
@@ -391,7 +391,6 @@ fn test_buffered_writer() {
     // newtype struct autoderef weirdness
     #[test]
     fn test_buffered_stream() {
-        use rt;
         struct S;
 
         impl io::Writer for S {
index d5514eb14d3da1aaf6dda86d6e385a676020e4b4..cc3f8bacb24dccf403307c7787ee4e0faa71e386 100644 (file)
@@ -191,7 +191,7 @@ pub fn path<'a>(&'a self) -> &'a Path {
     ///
     /// This function will raise on the `io_error` condition on failure.
     pub fn fsync(&mut self) {
-        self.fd.fsync();
+        self.fd.fsync().map_err(|e| io_error::cond.raise(e));
     }
 
     /// This function is similar to `fsync`, except that it may not synchronize
@@ -203,23 +203,23 @@ pub fn fsync(&mut self) {
     ///
     /// This function will raise on the `io_error` condition on failure.
     pub fn datasync(&mut self) {
-        self.fd.datasync();
+        self.fd.datasync().map_err(|e| io_error::cond.raise(e));
     }
 
-    /// Either truncates or extends the underlying file, as extended from the
-    /// file's current position. This is equivalent to the unix `truncate`
+    /// Either truncates or extends the underlying file, updating the size of
+    /// this file to become `size`. This is equivalent to unix's `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.
+    /// If the `size` is less than the current file's size, then the file will
+    /// be shrunk. If it is greater than the current file's size, then the file
+    /// will be extended to `size` and have all of the intermediate data filled
+    /// in 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);
+    pub fn truncate(&mut self, size: i64) {
+        self.fd.truncate(size).map_err(|e| io_error::cond.raise(e));
     }
 }
 
@@ -715,29 +715,68 @@ pub fn is_dir(&self) -> bool {
 }
 
 #[cfg(test)]
+#[allow(unused_imports)]
 mod test {
     use prelude::*;
-    use io::{SeekSet, SeekCur, SeekEnd, io_error, Read, Open, ReadWrite};
+    use io::{SeekSet, SeekCur, SeekEnd, io_error, Read, Open,
+             ReadWrite};
     use io;
     use str;
-    use super::{File, rmdir, mkdir, readdir, rmdir_recursive, mkdir_recursive,
-                copy, unlink, stat, symlink, link, readlink, chmod,
-                lstat, change_file_times};
+    use io::fs::{File, rmdir, mkdir, readdir, rmdir_recursive,
+                 mkdir_recursive, copy, unlink, stat, symlink, link,
+                 readlink, chmod, lstat, change_file_times};
+    use util;
+    use path::Path;
+    use io;
+    use ops::Drop;
+
+    struct TempDir(Path);
+
+    impl Drop for TempDir {
+        fn drop(&mut self) {
+            // Gee, seeing how we're testing the fs module I sure hope that we
+            // at least implement this correctly!
+            io::fs::rmdir_recursive(&**self);
+        }
+    }
 
-    fn tmpdir() -> Path {
+    fn tmpdir() -> TempDir {
         use os;
         use rand;
         let ret = os::tmpdir().join(format!("rust-{}", rand::random::<u32>()));
-        mkdir(&ret, io::UserRWX);
-        ret
+        io::fs::mkdir(&ret, io::UserRWX);
+        TempDir(ret)
     }
 
-    fn free<T>(_: T) {}
+    macro_rules! test (
+        { fn $name:ident() $b:block } => (
+            mod $name {
+                use prelude::*;
+                use io::{SeekSet, SeekCur, SeekEnd, io_error, Read, Open,
+                         ReadWrite};
+                use io;
+                use str;
+                use io::fs::{File, rmdir, mkdir, readdir, rmdir_recursive,
+                             mkdir_recursive, copy, unlink, stat, symlink, link,
+                             readlink, chmod, lstat, change_file_times};
+                use io::fs::test::tmpdir;
+                use util;
+
+                fn f() $b
+
+                #[test] fn uv() { f() }
+                #[test] fn native() {
+                    use rt::test::run_in_newsched_task;
+                    run_in_newsched_task(f);
+                }
+            }
+        )
+    )
 
-    #[test]
-    fn file_test_io_smoke_test() {
+    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 tmpdir = tmpdir();
+        let filename = &tmpdir.join("file_rt_io_file_test.txt");
         {
             let mut write_stream = File::open_mode(filename, Open, ReadWrite);
             write_stream.write(message.as_bytes());
@@ -752,11 +791,11 @@ fn file_test_io_smoke_test() {
             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");
+    test!(fn invalid_path_raises() {
+        let tmpdir = tmpdir();
+        let filename = &tmpdir.join("file_that_does_not_exist.txt");
         let mut called = false;
         do io_error::cond.trap(|_| {
             called = true;
@@ -765,11 +804,11 @@ fn file_test_io_invalid_path_opened_without_create_should_raise_condition() {
             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");
+    test!(fn file_test_iounlinking_invalid_path_should_raise_condition() {
+        let tmpdir = tmpdir();
+        let filename = &tmpdir.join("file_another_file_that_does_not_exist.txt");
         let mut called = false;
         do io_error::cond.trap(|_| {
             called = true;
@@ -777,13 +816,13 @@ fn file_test_iounlinking_invalid_path_should_raise_condition() {
             unlink(filename);
         }
         assert!(called);
-    }
+    })
 
-    #[test]
-    fn file_test_io_non_positional_read() {
+    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 tmpdir = tmpdir();
+        let filename = &tmpdir.join("file_rt_io_file_test_positional.txt");
         {
             let mut rw_stream = File::open_mode(filename, Open, ReadWrite);
             rw_stream.write(message.as_bytes());
@@ -802,16 +841,16 @@ fn file_test_io_non_positional_read() {
         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() {
+    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 tmpdir = tmpdir();
+        let filename = &tmpdir.join("file_rt_io_file_test_seeking.txt");
         {
             let mut rw_stream = File::open_mode(filename, Open, ReadWrite);
             rw_stream.write(message.as_bytes());
@@ -828,16 +867,16 @@ fn file_test_io_seek_and_tell_smoke_test() {
         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() {
+    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 tmpdir = tmpdir();
+        let filename = &tmpdir.join("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());
@@ -851,17 +890,17 @@ fn file_test_io_seek_and_write() {
         unlink(filename);
         let read_str = str::from_utf8(read_mem);
         assert!(read_str == final_msg.to_owned());
-    }
+    })
 
-    #[test]
-    fn file_test_io_seek_shakedown() {
+    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 tmpdir = tmpdir();
+        let filename = &tmpdir.join("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());
@@ -885,11 +924,11 @@ fn file_test_io_seek_shakedown() {
             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");
+    test!(fn file_test_stat_is_correct_on_is_file() {
+        let tmpdir = tmpdir();
+        let filename = &tmpdir.join("file_stat_correct_on_is_file.txt");
         {
             let mut fs = File::open_mode(filename, Open, ReadWrite);
             let msg = "hw";
@@ -898,49 +937,49 @@ fn file_test_stat_is_correct_on_is_file() {
         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");
+    test!(fn file_test_stat_is_correct_on_is_dir() {
+        let tmpdir = tmpdir();
+        let filename = &tmpdir.join("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");
+    test!(fn file_test_fileinfo_false_when_checking_is_file_on_a_directory() {
+        let tmpdir = tmpdir();
+        let dir = &tmpdir.join("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");
+    test!(fn file_test_fileinfo_check_exists_before_and_after_file_creation() {
+        let tmpdir = tmpdir();
+        let file = &tmpdir.join("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");
+    test!(fn file_test_directoryinfo_check_exists_before_and_after_mkdir() {
+        let tmpdir = tmpdir();
+        let dir = &tmpdir.join("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() {
+    test!(fn file_test_directoryinfo_readdir() {
         use std::str;
-        let dir = &Path::new("./tmp/di_readdir");
+        let tmpdir = tmpdir();
+        let dir = &tmpdir.join("di_readdir");
         mkdir(dir, io::UserRWX);
         let prefix = "foo";
         for n in range(0,3) {
@@ -966,15 +1005,13 @@ fn file_test_directoryinfo_readdir() {
             unlink(f);
         }
         rmdir(dir);
-    }
+    })
 
-    #[test]
-    fn recursive_mkdir_slash() {
+    test!(fn recursive_mkdir_slash() {
         mkdir_recursive(&Path::new("/"), io::UserRWX);
-    }
+    })
 
-    #[test]
-    fn unicode_path_is_dir() {
+    test!(fn unicode_path_is_dir() {
         assert!(Path::new(".").is_dir());
         assert!(!Path::new("test/stdtest/fs.rs").is_dir());
 
@@ -990,12 +1027,9 @@ fn unicode_path_is_dir() {
         File::create(&filepath); // ignore return; touch only
         assert!(!filepath.is_dir());
         assert!(filepath.exists());
+    })
 
-        rmdir_recursive(&tmpdir);
-    }
-
-    #[test]
-    fn unicode_path_exists() {
+    test!(fn unicode_path_exists() {
         assert!(Path::new(".").exists());
         assert!(!Path::new("test/nonexistent-bogus-path").exists());
 
@@ -1005,11 +1039,9 @@ fn unicode_path_exists() {
         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() {
+    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)) {
@@ -1019,10 +1051,9 @@ fn copy_file_does_not_exist() {
                 assert!(!to.exists());
             }
         }
-    }
+    })
 
-    #[test]
-    fn copy_file_ok() {
+    test!(fn copy_file_ok() {
         let tmpdir = tmpdir();
         let input = tmpdir.join("in.txt");
         let out = tmpdir.join("out.txt");
@@ -1033,23 +1064,19 @@ fn copy_file_ok() {
         assert_eq!(contents.as_slice(), bytes!("hello"));
 
         assert_eq!(input.stat().perm, out.stat().perm);
-        rmdir_recursive(&tmpdir);
-    }
+    })
 
-    #[test]
-    fn copy_file_dst_dir() {
+    test!(fn copy_file_dst_dir() {
         let tmpdir = tmpdir();
         let out = tmpdir.join("out");
 
         File::create(&out);
-        match io::result(|| copy(&out, &tmpdir)) {
+        match io::result(|| copy(&out, &*tmpdir)) {
             Ok(*) => fail!(), Err(*) => {}
         }
-        rmdir_recursive(&tmpdir);
-    }
+    })
 
-    #[test]
-    fn copy_file_dst_exists() {
+    test!(fn copy_file_dst_exists() {
         let tmpdir = tmpdir();
         let input = tmpdir.join("in");
         let output = tmpdir.join("out");
@@ -1060,24 +1087,19 @@ fn copy_file_dst_exists() {
 
         assert_eq!(File::open(&output).read_to_end(),
                    (bytes!("foo")).to_owned());
+    })
 
-        rmdir_recursive(&tmpdir);
-    }
-
-    #[test]
-    fn copy_file_src_dir() {
+    test!(fn copy_file_src_dir() {
         let tmpdir = tmpdir();
         let out = tmpdir.join("out");
 
-        match io::result(|| copy(&tmpdir, &out)) {
+        match io::result(|| copy(&*tmpdir, &out)) {
             Ok(*) => fail!(), Err(*) => {}
         }
         assert!(!out.exists());
-        rmdir_recursive(&tmpdir);
-    }
+    })
 
-    #[test]
-    fn copy_file_preserves_perm_bits() {
+    test!(fn copy_file_preserves_perm_bits() {
         let tmpdir = tmpdir();
         let input = tmpdir.join("in.txt");
         let out = tmpdir.join("out.txt");
@@ -1089,56 +1111,51 @@ fn copy_file_preserves_perm_bits() {
 
         chmod(&input, io::UserFile);
         chmod(&out, io::UserFile);
-        rmdir_recursive(&tmpdir);
-    }
+    })
 
-    #[test]
-    #[ignore(cfg(windows))] // FIXME(#10264) operation not permitted?
-    fn symlinks_work() {
+    #[cfg(not(windows))] // FIXME(#10264) operation not permitted?
+    test!(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);
+        if cfg!(not(windows)) {
+            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() {
+    #[cfg(not(windows))] // apparently windows doesn't like symlinks
+    test!(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() {
+    test!(fn readlink_not_symlink() {
         let tmpdir = tmpdir();
-        match io::result(|| readlink(&tmpdir)) {
+        match io::result(|| readlink(&*tmpdir)) {
             Ok(*) => fail!("wanted a failure"),
             Err(*) => {}
         }
-        rmdir_recursive(&tmpdir);
-    }
+    })
 
-    #[test]
-    fn links_work() {
+    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);
+        if cfg!(not(windows)) {
+            assert_eq!(lstat(&out).kind, io::TypeFile);
+            assert_eq!(stat(&out).unstable.nlink, 2);
+        }
         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
@@ -1151,12 +1168,9 @@ fn links_work() {
             Ok(*) => fail!("wanted a failure"),
             Err(*) => {}
         }
+    })
 
-        rmdir_recursive(&tmpdir);
-    }
-
-    #[test]
-    fn chmod_works() {
+    test!(fn chmod_works() {
         let tmpdir = tmpdir();
         let file = tmpdir.join("in.txt");
 
@@ -1171,11 +1185,9 @@ fn chmod_works() {
         }
 
         chmod(&file, io::UserFile);
-        rmdir_recursive(&tmpdir);
-    }
+    })
 
-    #[test]
-    fn sync_doesnt_kill_anything() {
+    test!(fn sync_doesnt_kill_anything() {
         let tmpdir = tmpdir();
         let path = tmpdir.join("in.txt");
 
@@ -1185,24 +1197,23 @@ fn sync_doesnt_kill_anything() {
         file.write(bytes!("foo"));
         file.fsync();
         file.datasync();
-        free(file);
-
-        rmdir_recursive(&tmpdir);
-    }
+        util::ignore(file);
+    })
 
-    #[test]
-    fn truncate_works() {
+    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"));
+        file.fsync();
 
         // 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"));
+        file.fsync();
         assert_eq!(stat(&path).size, 10);
         assert_eq!(File::open(&path).read_to_end(),
                    (bytes!("foobar", 0, 0, 0, 0)).to_owned());
@@ -1213,16 +1224,14 @@ fn truncate_works() {
         file.truncate(2);
         assert_eq!(stat(&path).size, 2);
         file.write(bytes!("wut"));
+        file.fsync();
         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);
-    }
+        util::ignore(file);
+    })
 
-    #[test]
-    fn open_flavors() {
+    test!(fn open_flavors() {
         let tmpdir = tmpdir();
 
         match io::result(|| File::open_mode(&tmpdir.join("a"), io::Open,
@@ -1258,9 +1267,7 @@ fn open_flavors() {
             f.write("bar".as_bytes());
         }
         assert_eq!(stat(&tmpdir.join("h")).size, 3);
-
-        rmdir_recursive(&tmpdir);
-    }
+    })
 
     #[test]
     fn utime() {
@@ -1271,8 +1278,6 @@ fn utime() {
         change_file_times(&path, 1000, 2000);
         assert_eq!(path.stat().accessed, 1000);
         assert_eq!(path.stat().modified, 2000);
-
-        rmdir_recursive(&tmpdir);
     }
 
     #[test]
@@ -1283,7 +1288,5 @@ fn utime_noexist() {
             Ok(*) => fail!(),
             Err(*) => {}
         }
-
-        rmdir_recursive(&tmpdir);
     }
 }
index 5e39460ba6a4dc9e2361be9a85b09759f3716fed..03d9dc7ef6e6b6d9e51fe06dce6b35756c5d93d3 100644 (file)
 
 #[allow(non_camel_case_types)];
 
+use c_str::CString;
 use io::IoError;
 use io;
+use libc::c_int;
 use libc;
 use ops::Drop;
 use option::{Some, None, Option};
 use os;
+use path::{Path, GenericPath};
 use ptr::RawPtr;
 use result::{Result, Ok, Err};
 use rt::rtio;
+use super::IoResult;
+use unstable::intrinsics;
 use vec::ImmutableVector;
+use vec;
+
+#[cfg(windows)] use os::win32::{as_utf16_p, fill_utf16_buf_and_decode};
+#[cfg(windows)] use ptr;
+#[cfg(windows)] use str;
 
 fn keep_going(data: &[u8], f: &fn(*u8, uint) -> i64) -> i64 {
     #[cfg(windows)] static eintr: int = 0; // doesn't matter
@@ -122,26 +132,157 @@ fn read(&mut self, buf: &mut [u8]) -> Result<int, IoError> {
     fn write(&mut self, buf: &[u8]) -> Result<(), IoError> {
         self.inner_write(buf)
     }
-    fn pread(&mut self, _buf: &mut [u8], _offset: u64) -> Result<int, IoError> {
-        Err(super::unimpl())
+    fn pread(&mut self, buf: &mut [u8], offset: u64) -> Result<int, IoError> {
+        return os_pread(self.fd, vec::raw::to_ptr(buf), buf.len(), offset);
+
+        #[cfg(windows)]
+        fn os_pread(fd: c_int, buf: *u8, amt: uint, offset: u64) -> IoResult<int> {
+            unsafe {
+                let mut overlap: libc::OVERLAPPED = intrinsics::init();
+                let handle = libc::get_osfhandle(fd) as libc::HANDLE;
+                let mut bytes_read = 0;
+                overlap.Offset = offset as libc::DWORD;
+                overlap.OffsetHigh = (offset >> 32) as libc::DWORD;
+
+                match libc::ReadFile(handle, buf as libc::LPVOID,
+                                     amt as libc::DWORD,
+                                     &mut bytes_read, &mut overlap) {
+                    0 => Err(super::last_error()),
+                    _ => Ok(bytes_read as int)
+                }
+            }
+        }
+
+        #[cfg(unix)]
+        fn os_pread(fd: c_int, buf: *u8, amt: uint, offset: u64) -> IoResult<int> {
+            match unsafe {
+                libc::pread(fd, buf as *libc::c_void, amt 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) -> Result<(), IoError> {
-        Err(super::unimpl())
+    fn pwrite(&mut self, buf: &[u8], offset: u64) -> Result<(), IoError> {
+        return os_pwrite(self.fd, vec::raw::to_ptr(buf), buf.len(), offset);
+
+        #[cfg(windows)]
+        fn os_pwrite(fd: c_int, buf: *u8, amt: uint, offset: u64) -> IoResult<()> {
+            unsafe {
+                let mut overlap: libc::OVERLAPPED = intrinsics::init();
+                let handle = libc::get_osfhandle(fd) as libc::HANDLE;
+                overlap.Offset = offset as libc::DWORD;
+                overlap.OffsetHigh = (offset >> 32) as libc::DWORD;
+
+                match libc::WriteFile(handle, buf as libc::LPVOID,
+                                      amt as libc::DWORD,
+                                      ptr::mut_null(), &mut overlap) {
+                    0 => Err(super::last_error()),
+                    _ => Ok(()),
+                }
+            }
+        }
+
+        #[cfg(unix)]
+        fn os_pwrite(fd: c_int, buf: *u8, amt: uint, offset: u64) -> IoResult<()> {
+            super::mkerr_libc(unsafe {
+                libc::pwrite(fd, buf as *libc::c_void, amt as libc::size_t,
+                             offset as libc::off_t)
+            } as c_int)
+        }
     }
-    fn seek(&mut self, _pos: i64, _whence: io::SeekStyle) -> Result<u64, IoError> {
-        Err(super::unimpl())
+    #[cfg(windows)]
+    fn seek(&mut self, pos: i64, style: io::SeekStyle) -> Result<u64, IoError> {
+        let whence = match style {
+            io::SeekSet => libc::FILE_BEGIN,
+            io::SeekEnd => libc::FILE_END,
+            io::SeekCur => libc::FILE_CURRENT,
+        };
+        unsafe {
+            let handle = libc::get_osfhandle(self.fd) as libc::HANDLE;
+            let mut newpos = 0;
+            match libc::SetFilePointerEx(handle, pos, &mut newpos, whence) {
+                0 => Err(super::last_error()),
+                _ => Ok(newpos as u64),
+            }
+        }
+    }
+    #[cfg(unix)]
+    fn seek(&mut self, pos: i64, whence: io::SeekStyle) -> Result<u64, IoError> {
+        let whence = match whence {
+            io::SeekSet => libc::SEEK_SET,
+            io::SeekEnd => libc::SEEK_END,
+            io::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) -> Result<u64, IoError> {
-        Err(super::unimpl())
+        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) -> Result<(), IoError> {
-        Err(super::unimpl())
+        return os_fsync(self.fd);
+
+        #[cfg(windows)]
+        fn os_fsync(fd: c_int) -> IoResult<()> {
+            super::mkerr_winbool(unsafe {
+                let handle = libc::get_osfhandle(fd);
+                libc::FlushFileBuffers(handle as libc::HANDLE)
+            })
+        }
+        #[cfg(unix)]
+        fn os_fsync(fd: c_int) -> IoResult<()> {
+            super::mkerr_libc(unsafe { libc::fsync(fd) })
+        }
     }
+    #[cfg(windows)]
+    fn datasync(&mut self) -> Result<(), IoError> { return self.fsync(); }
+
+    #[cfg(not(windows))]
     fn datasync(&mut self) -> Result<(), IoError> {
-        Err(super::unimpl())
+        return super::mkerr_libc(os_datasync(self.fd));
+
+        #[cfg(target_os = "macos")]
+        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 { unsafe { libc::fdatasync(fd) } }
+        #[cfg(not(target_os = "macos"), not(target_os = "linux"))]
+        fn os_datasync(fd: c_int) -> c_int { unsafe { libc::fsync(fd) } }
     }
-    fn truncate(&mut self, _offset: i64) -> Result<(), IoError> {
-        Err(super::unimpl())
+
+    #[cfg(windows)]
+    fn truncate(&mut self, offset: i64) -> Result<(), IoError> {
+        let orig_pos = match self.tell() { Ok(i) => i, Err(e) => return Err(e) };
+        match self.seek(offset, io::SeekSet) {
+            Ok(_) => {}, Err(e) => return Err(e),
+        };
+        let ret = unsafe {
+            let handle = libc::get_osfhandle(self.fd) as libc::HANDLE;
+            match libc::SetEndOfFile(handle) {
+                0 => Err(super::last_error()),
+                _ => Ok(())
+            }
+        };
+        self.seek(orig_pos as i64, io::SeekSet);
+        return ret;
+    }
+    #[cfg(unix)]
+    fn truncate(&mut self, offset: i64) -> Result<(), IoError> {
+        super::mkerr_libc(unsafe {
+            libc::ftruncate(self.fd, offset as libc::off_t)
+        })
     }
 }
 
@@ -179,7 +320,8 @@ fn drop(&mut self) {
 }
 
 pub struct CFile {
-    priv file: *libc::FILE
+    priv file: *libc::FILE,
+    priv fd: FileDesc,
 }
 
 impl CFile {
@@ -187,7 +329,16 @@ impl CFile {
     ///
     /// The `CFile` takes ownership of the `FILE` pointer and will close it upon
     /// destruction.
-    pub fn new(file: *libc::FILE) -> CFile { CFile { file: file } }
+    pub fn new(file: *libc::FILE) -> CFile {
+        CFile {
+            file: file,
+            fd: FileDesc::new(unsafe { libc::fileno(file) }, false)
+        }
+    }
+
+    pub fn flush(&mut self) -> Result<(), IoError> {
+        super::mkerr_libc(unsafe { libc::fflush(self.file) })
+    }
 }
 
 impl rtio::RtioFileStream for CFile {
@@ -221,11 +372,13 @@ fn write(&mut self, buf: &[u8]) -> Result<(), IoError> {
         }
     }
 
-    fn pread(&mut self, _buf: &mut [u8], _offset: u64) -> Result<int, IoError> {
-        Err(super::unimpl())
+    fn pread(&mut self, buf: &mut [u8], offset: u64) -> Result<int, IoError> {
+        self.flush();
+        self.fd.pread(buf, offset)
     }
-    fn pwrite(&mut self, _buf: &[u8], _offset: u64) -> Result<(), IoError> {
-        Err(super::unimpl())
+    fn pwrite(&mut self, buf: &[u8], offset: u64) -> Result<(), IoError> {
+        self.flush();
+        self.fd.pwrite(buf, offset)
     }
     fn seek(&mut self, pos: i64, style: io::SeekStyle) -> Result<u64, IoError> {
         let whence = match style {
@@ -249,13 +402,16 @@ fn tell(&self) -> Result<u64, IoError> {
         }
     }
     fn fsync(&mut self) -> Result<(), IoError> {
-        Err(super::unimpl())
+        self.flush();
+        self.fd.fsync()
     }
     fn datasync(&mut self) -> Result<(), IoError> {
-        Err(super::unimpl())
+        self.flush();
+        self.fd.fsync()
     }
-    fn truncate(&mut self, _offset: i64) -> Result<(), IoError> {
-        Err(super::unimpl())
+    fn truncate(&mut self, offset: i64) -> Result<(), IoError> {
+        self.flush();
+        self.fd.truncate(offset)
     }
 }
 
@@ -265,529 +421,561 @@ fn drop(&mut self) {
     }
 }
 
-#[cfg(test)]
-mod tests {
-    use libc;
-    use os;
-    use io::{io_error, SeekSet, Writer, Reader};
-    use result::Ok;
-    use super::{CFile, FileDesc};
+pub fn open(path: &CString, fm: io::FileMode, fa: io::FileAccess)
+        -> IoResult<FileDesc> {
+    let flags = match fm {
+        io::Open => 0,
+        io::Append => libc::O_APPEND,
+        io::Truncate => libc::O_TRUNC,
+    };
+    // Opening with a write permission must silently create the file.
+    let (flags, mode) = match fa {
+        io::Read => (flags | libc::O_RDONLY, 0),
+        io::Write => (flags | libc::O_WRONLY | libc::O_CREAT,
+                      libc::S_IRUSR | libc::S_IWUSR),
+        io::ReadWrite => (flags | libc::O_RDWR | libc::O_CREAT,
+                          libc::S_IRUSR | libc::S_IWUSR),
+    };
+
+    return match os_open(path, flags, mode) {
+        -1 => Err(super::last_error()),
+        fd => Ok(FileDesc::new(fd, true)),
+    };
 
-    #[ignore(cfg(target_os = "freebsd"))] // hmm, maybe pipes have a tiny buffer
-    fn test_file_desc() {
-        // Run this test with some pipes so we don't have to mess around with
-        // opening or closing files.
-        unsafe {
-            let os::Pipe { input, out } = os::pipe();
-            let mut reader = FileDesc::new(input, true);
-            let mut writer = FileDesc::new(out, true);
-
-            writer.inner_write(bytes!("test"));
-            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 => fail!("invalid read: {:?}", r)
-            }
-
-            assert!(writer.inner_read(buf).is_err());
-            assert!(reader.inner_write(buf).is_err());
+    #[cfg(windows)]
+    fn os_open(path: &CString, flags: c_int, mode: c_int) -> c_int {
+        do as_utf16_p(path.as_str().unwrap()) |path| {
+            unsafe { libc::wopen(path, flags, mode) }
         }
     }
 
-    #[ignore(cfg(windows))] // apparently windows doesn't like tmpfile
-    fn test_cfile() {
-        unsafe {
-            let f = libc::tmpfile();
-            assert!(!f.is_null());
-            let mut file = CFile::new(f);
+    #[cfg(unix)]
+    fn os_open(path: &CString, flags: c_int, mode: c_int) -> c_int {
+        unsafe { libc::open(path.with_ref(|p| p), flags, mode) }
+    }
+}
 
-            file.write(bytes!("test"));
-            let mut buf = [0u8, ..4];
-            file.seek(0, SeekSet);
-            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 => fail!("invalid read: {:?}", r)
+pub fn mkdir(p: &CString, mode: io::FilePermission) -> IoResult<()> {
+    return os_mkdir(p, mode as c_int);
+
+    #[cfg(windows)]
+    fn os_mkdir(p: &CString, _mode: c_int) -> IoResult<()> {
+        super::mkerr_winbool(unsafe {
+            // FIXME: turn mode into something useful? #2623
+            do as_utf16_p(p.as_str().unwrap()) |buf| {
+                libc::CreateDirectoryW(buf, ptr::mut_null())
             }
-        }
+        })
+    }
+
+    #[cfg(unix)]
+    fn os_mkdir(p: &CString, mode: c_int) -> IoResult<()> {
+        super::mkerr_libc(unsafe {
+            libc::mkdir(p.with_ref(|p| p), mode as libc::mode_t)
+        })
     }
 }
 
-// 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;
+pub fn readdir(p: &CString) -> IoResult<~[Path]> {
+    fn prune(root: &CString, dirs: ~[Path]) -> ~[Path] {
+        let root = unsafe { CString::new(root.with_ref(|p| p), false) };
+        let root = Path::new(root);
 
-    #[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;
+        dirs.move_iter().filter(|path| {
+            path.as_vec() != bytes!(".") && path.as_vec() != bytes!("..")
+        }).map(|path| root.join(path)).collect()
+    }
 
-    // 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.
+    unsafe {
+        #[cfg(not(windows))]
+        unsafe fn get_list(p: &CString) -> IoResult<~[Path]> {
+            use libc::{dirent_t};
+            use libc::{opendir, readdir, closedir};
+            extern {
+                fn rust_list_dir_val(ptr: *dirent_t) -> *libc::c_char;
+            }
+            debug!("os::list_dir -- BEFORE OPENDIR");
 
-    mod rustrt {
-        use libc::{c_char, c_int};
-        use libc;
+            let dir_ptr = do p.with_ref |buf| {
+                opendir(buf)
+            };
 
-        extern {
-            pub fn rust_path_is_dir(path: *libc::c_char) -> c_int;
-            pub fn rust_path_exists(path: *libc::c_char) -> c_int;
+            if (dir_ptr as uint != 0) {
+                let mut paths = ~[];
+                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);
+                Ok(paths)
+            } else {
+                Err(super::last_error())
+            }
         }
 
-        // 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;
+        unsafe fn get_list(p: &CString) -> IoResult<~[Path]> {
+            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 p = CString::new(p.with_ref(|p| p), false);
+            let p = Path::new(p);
+            let star = p.join("*");
+            do as_utf16_p(star.as_str().unwrap()) |path_ptr| {
+                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 paths = ~[];
+                    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);
+                    Ok(paths)
+                } else {
+                    Err(super::last_error())
+                }
+            }
         }
+
+        get_list(p).map(|paths| prune(p, paths))
     }
+}
+
+pub fn unlink(p: &CString) -> IoResult<()> {
+    return os_unlink(p);
 
-    /// 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(windows)]
+    fn os_unlink(p: &CString) -> IoResult<()> {
+        super::mkerr_winbool(unsafe {
+            do as_utf16_p(p.as_str().unwrap()) |buf| {
+                libc::DeleteFileW(buf)
+            }
         })
     }
 
     #[cfg(unix)]
-    /// Indicates whether a path represents a directory
-    pub fn path_is_dir(p: &Path) -> bool {
-        unsafe {
-            do p.with_c_str |buf| {
-                rustrt::rust_path_is_dir(buf) != 0 as c_int
+    fn os_unlink(p: &CString) -> IoResult<()> {
+        super::mkerr_libc(unsafe { libc::unlink(p.with_ref(|p| p)) })
+    }
+}
+
+pub fn rename(old: &CString, new: &CString) -> IoResult<()> {
+    return os_rename(old, new);
+
+    #[cfg(windows)]
+    fn os_rename(old: &CString, new: &CString) -> IoResult<()> {
+        super::mkerr_winbool(unsafe {
+            do as_utf16_p(old.as_str().unwrap()) |old| {
+                do as_utf16_p(new.as_str().unwrap()) |new| {
+                    libc::MoveFileExW(old, new, libc::MOVEFILE_REPLACE_EXISTING)
+                }
             }
-        }
+        })
+    }
+
+    #[cfg(unix)]
+    fn os_rename(old: &CString, new: &CString) -> IoResult<()> {
+        super::mkerr_libc(unsafe {
+            libc::rename(old.with_ref(|p| p), new.with_ref(|p| p))
+        })
     }
+}
 
+pub fn chmod(p: &CString, mode: io::FilePermission) -> IoResult<()> {
+    return super::mkerr_libc(os_chmod(p, mode as c_int));
 
     #[cfg(windows)]
-    pub fn path_is_dir(p: &Path) -> bool {
+    fn os_chmod(p: &CString, mode: c_int) -> c_int {
         unsafe {
-            do os::win32::as_utf16_p(p.as_str().unwrap()) |buf| {
-                rustrt::rust_path_is_dir_u16(buf) != 0 as c_int
+            do as_utf16_p(p.as_str().unwrap()) |p| {
+                libc::wchmod(p, mode)
             }
         }
     }
 
     #[cfg(unix)]
-    /// Indicates whether a path exists
-    pub fn path_exists(p: &Path) -> bool {
+    fn os_chmod(p: &CString, mode: c_int) -> c_int {
+        unsafe { libc::chmod(p.with_ref(|p| p), mode as libc::mode_t) }
+    }
+}
+
+pub fn rmdir(p: &CString) -> IoResult<()> {
+    return super::mkerr_libc(os_rmdir(p));
+
+    #[cfg(windows)]
+    fn os_rmdir(p: &CString) -> c_int {
         unsafe {
-            do p.with_c_str |buf| {
-                rustrt::rust_path_exists(buf) != 0 as c_int
-            }
+            do as_utf16_p(p.as_str().unwrap()) |p| { libc::wrmdir(p) }
         }
     }
 
+    #[cfg(unix)]
+    fn os_rmdir(p: &CString) -> c_int {
+        unsafe { libc::rmdir(p.with_ref(|p| p)) }
+    }
+}
+
+pub fn chown(p: &CString, uid: int, gid: int) -> IoResult<()> {
+    return super::mkerr_libc(os_chown(p, uid, gid));
+
+    // libuv has this as a no-op, so seems like this should as well?
     #[cfg(windows)]
-    pub fn path_exists(p: &Path) -> bool {
+    fn os_chown(_p: &CString, _uid: int, _gid: int) -> c_int { 0 }
+
+    #[cfg(unix)]
+    fn os_chown(p: &CString, uid: int, gid: int) -> c_int {
         unsafe {
-            do os::win32::as_utf16_p(p.as_str().unwrap()) |buf| {
-                rustrt::rust_path_exists_u16(buf) != 0 as c_int
-            }
+            libc::chown(p.with_ref(|p| p), uid as libc::uid_t,
+                        gid as libc::gid_t)
         }
     }
+}
 
-    /// Creates a directory at the specified path
-    pub fn make_dir(p: &Path, mode: c_int) -> bool {
-        return mkdir(p, mode);
+pub fn readlink(p: &CString) -> IoResult<Path> {
+    return os_readlink(p);
 
-        #[cfg(windows)]
-        fn mkdir(p: &Path, _mode: c_int) -> bool {
+    // XXX: I have a feeling that this reads intermediate symlinks as well.
+    #[cfg(windows)]
+    fn os_readlink(p: &CString) -> IoResult<Path> {
+        let handle = unsafe {
+            do as_utf16_p(p.as_str().unwrap()) |p| {
+                libc::CreateFileW(p,
+                                  libc::GENERIC_READ,
+                                  libc::FILE_SHARE_READ,
+                                  ptr::mut_null(),
+                                  libc::OPEN_EXISTING,
+                                  libc::FILE_ATTRIBUTE_NORMAL,
+                                  ptr::mut_null())
+            }
+        };
+        if handle == ptr::mut_null() { return Err(super::last_error()) }
+        let ret = do fill_utf16_buf_and_decode |buf, sz| {
             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)
-                }
+                libc::GetFinalPathNameByHandleW(handle, buf as *u16, sz,
+                                                libc::VOLUME_NAME_NT)
             }
-        }
+        };
+        let ret = match ret {
+            Some(s) => Ok(Path::new(s)),
+            None => Err(super::last_error()),
+        };
+        unsafe { libc::CloseHandle(handle) };
+        return ret;
 
-        #[cfg(unix)]
-        fn mkdir(p: &Path, mode: c_int) -> bool {
-            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;
+    #[cfg(unix)]
+    fn os_readlink(p: &CString) -> IoResult<Path> {
+        let p = p.with_ref(|p| p);
+        let mut len = unsafe { libc::pathconf(p, libc::_PC_NAME_MAX) };
+        if len == -1 {
+            len = 1024; // XXX: read PATH_MAX from C ffi?
         }
-        if p.filename().is_some() {
-            let mut p_ = p.clone();
-            p_.pop();
-            if !mkdir_recursive(&p_, mode) {
-                return false;
+        let mut buf = vec::with_capacity::<u8>(len as uint);
+        match unsafe {
+            libc::readlink(p, vec::raw::to_ptr(buf) as *mut libc::c_char,
+                           len as libc::size_t)
+        } {
+            -1 => Err(super::last_error()),
+            n => {
+                assert!(n > 0);
+                unsafe { vec::raw::set_len(&mut buf, n as uint); }
+                Ok(Path::new(buf))
             }
         }
-        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] {
-                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] {
-                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()
-        }
-    }
+pub fn symlink(src: &CString, dst: &CString) -> IoResult<()> {
+    return os_symlink(src, dst);
 
-    /// 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;
-                    }
-                }
+    #[cfg(windows)]
+    fn os_symlink(src: &CString, dst: &CString) -> IoResult<()> {
+        super::mkerr_winbool(do as_utf16_p(src.as_str().unwrap()) |src| {
+            do as_utf16_p(dst.as_str().unwrap()) |dst| {
+                unsafe { libc::CreateSymbolicLinkW(dst, src, 0) }
             }
-            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(unix)]
+    fn os_symlink(src: &CString, dst: &CString) -> IoResult<()> {
+        super::mkerr_libc(unsafe {
+            libc::symlink(src.with_ref(|p| p), dst.with_ref(|p| p))
+        })
+    }
+}
 
-        #[cfg(windows)]
-        fn rmdir(p: &Path) -> bool {
-            unsafe {
-                use os::win32::as_utf16_p;
-                return do as_utf16_p(p.as_str().unwrap()) |buf| {
-                    libc::RemoveDirectoryW(buf) != (0 as libc::BOOL)
-                };
-            }
-        }
+pub fn link(src: &CString, dst: &CString) -> IoResult<()> {
+    return os_link(src, dst);
 
-        #[cfg(unix)]
-        fn rmdir(p: &Path) -> bool {
-            do p.with_c_str |buf| {
-                unsafe {
-                    libc::rmdir(buf) == (0 as c_int)
-                }
+    #[cfg(windows)]
+    fn os_link(src: &CString, dst: &CString) -> IoResult<()> {
+        super::mkerr_winbool(do as_utf16_p(src.as_str().unwrap()) |src| {
+            do as_utf16_p(dst.as_str().unwrap()) |dst| {
+                unsafe { libc::CreateHardLinkW(dst, src, ptr::mut_null()) }
             }
-        }
+        })
     }
 
-    /// Deletes an existing file
-    pub fn remove_file(p: &Path) -> bool {
-        return unlink(p);
+    #[cfg(unix)]
+    fn os_link(src: &CString, dst: &CString) -> IoResult<()> {
+        super::mkerr_libc(unsafe {
+            libc::link(src.with_ref(|p| p), dst.with_ref(|p| p))
+        })
+    }
+}
 
-        #[cfg(windows)]
-        fn unlink(p: &Path) -> bool {
-            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 {
-            unsafe {
-                do p.with_c_str |buf| {
-                    libc::unlink(buf) == (0 as c_int)
-                }
-            }
+#[cfg(windows)]
+fn mkstat(stat: &libc::stat, path: &CString) -> io::FileStat {
+    let path = unsafe { CString::new(path.with_ref(|p| p), false) };
+
+    // FileStat times are in milliseconds
+    fn mktime(secs: u64, nsecs: u64) -> u64 { secs * 1000 + nsecs / 1000000 }
+
+    let kind = match (stat.st_mode as c_int) & libc::S_IFMT {
+        libc::S_IFREG => io::TypeFile,
+        libc::S_IFDIR => io::TypeDirectory,
+        libc::S_IFIFO => io::TypeNamedPipe,
+        libc::S_IFBLK => io::TypeBlockSpecial,
+        libc::S_IFLNK => io::TypeSymlink,
+        _ => io::TypeUnknown,
+    };
+
+    io::FileStat {
+        path: Path::new(path),
+        size: stat.st_size as u64,
+        kind: kind,
+        perm: (stat.st_mode) as io::FilePermission & io::AllPermissions,
+        created: stat.st_ctime as u64,
+        modified: stat.st_mtime as u64,
+        accessed: stat.st_atime as u64,
+        unstable: io::UnstableFileStat {
+            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,
         }
     }
+}
 
-    /// Renames an existing file or directory
-    pub fn rename_file(old: &Path, new: &Path) -> bool {
-        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)
-                }
-           }
+#[cfg(unix)]
+fn mkstat(stat: &libc::stat, path: &CString) -> io::FileStat {
+    let path = unsafe { CString::new(path.with_ref(|p| p), false) };
+
+    // FileStat times are in milliseconds
+    fn mktime(secs: u64, nsecs: u64) -> u64 { secs * 1000 + nsecs / 1000000 }
+
+    let kind = match (stat.st_mode as c_int) & libc::S_IFMT {
+        libc::S_IFREG => io::TypeFile,
+        libc::S_IFDIR => io::TypeDirectory,
+        libc::S_IFIFO => io::TypeNamedPipe,
+        libc::S_IFBLK => io::TypeBlockSpecial,
+        libc::S_IFLNK => io::TypeSymlink,
+        _ => io::TypeUnknown,
+    };
+
+    #[cfg(not(target_os = "linux"), not(target_os = "android"))]
+    fn flags(stat: &libc::stat) -> u64 { stat.st_flags as u64 }
+    #[cfg(target_os = "linux")] #[cfg(target_os = "android")]
+    fn flags(_stat: &libc::stat) -> u64 { 0 }
+
+    #[cfg(not(target_os = "linux"), not(target_os = "android"))]
+    fn gen(stat: &libc::stat) -> u64 { stat.st_gen as u64 }
+    #[cfg(target_os = "linux")] #[cfg(target_os = "android")]
+    fn gen(_stat: &libc::stat) -> u64 { 0 }
+
+    io::FileStat {
+        path: Path::new(path),
+        size: stat.st_size as u64,
+        kind: kind,
+        perm: (stat.st_mode) as io::FilePermission & io::AllPermissions,
+        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),
+        unstable: io::UnstableFileStat {
+            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),
         }
     }
+}
 
-    /// Copies a file from one location to another
-    pub fn copy_file(from: &Path, to: &Path) -> bool {
-        return do_copy_file(from, to);
+pub fn stat(p: &CString) -> IoResult<io::FileStat> {
+    return os_stat(p);
 
-        #[cfg(windows)]
-        fn do_copy_file(from: &Path, to: &Path) -> bool {
-            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(windows)]
+    fn os_stat(p: &CString) -> IoResult<io::FileStat> {
+        let mut stat: libc::stat = unsafe { intrinsics::uninit() };
+        do as_utf16_p(p.as_str().unwrap()) |up| {
+            match unsafe { libc::wstat(up, &mut stat) } {
+                0 => Ok(mkstat(&stat, p)),
+                _ => Err(super::last_error()),
             }
         }
+    }
 
-        #[cfg(unix)]
-        fn do_copy_file(from: &Path, to: &Path) -> bool {
-            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;
-            }
+    #[cfg(unix)]
+    fn os_stat(p: &CString) -> IoResult<io::FileStat> {
+        let mut stat: libc::stat = unsafe { intrinsics::uninit() };
+        match unsafe { libc::stat(p.with_ref(|p| p), &mut stat) } {
+            0 => Ok(mkstat(&stat, p)),
+            _ => Err(super::last_error()),
         }
     }
+}
 
-    #[test]
-    fn tmpdir() {
-        let p = os::tmpdir();
-        let s = p.as_str();
-        assert!(s.is_some() && s.unwrap() != ".");
-    }
+pub fn lstat(p: &CString) -> IoResult<io::FileStat> {
+    return os_lstat(p);
 
-    // Issue #712
-    #[test]
-    fn test_list_dir_no_invalid_memory_access() {
-        list_dir(&Path::new("."));
+    // XXX: windows implementation is missing
+    #[cfg(windows)]
+    fn os_lstat(_p: &CString) -> IoResult<io::FileStat> {
+        Err(super::unimpl())
     }
 
-    #[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());
+    #[cfg(unix)]
+    fn os_lstat(p: &CString) -> IoResult<io::FileStat> {
+        let mut stat: libc::stat = unsafe { intrinsics::uninit() };
+        match unsafe { libc::lstat(p.with_ref(|p| p), &mut stat) } {
+            0 => Ok(mkstat(&stat, p)),
+            _ => Err(super::last_error()),
         }
     }
+}
+
+pub fn utime(p: &CString, atime: u64, mtime: u64) -> IoResult<()> {
+    return super::mkerr_libc(os_utime(p, atime, mtime));
 
-    #[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);
+    fn os_utime(p: &CString, atime: u64, mtime: u64) -> c_int {
+        let buf = libc::utimbuf {
+            actime: (atime / 1000) as libc::time64_t,
+            modtime: (mtime / 1000) as libc::time64_t,
+        };
+        unsafe {
+            do as_utf16_p(p.as_str().unwrap()) |p| {
+                libc::wutime(p, &buf)
+            }
+        }
     }
 
-    #[test]
-    fn test_path_is_dir() {
-        use io::fs::{mkdir_recursive};
-        use 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());
+    #[cfg(unix)]
+    fn os_utime(p: &CString, atime: u64, mtime: u64) -> c_int {
+        let buf = libc::utimbuf {
+            actime: (atime / 1000) as libc::time_t,
+            modtime: (mtime / 1000) as libc::time_t,
+        };
+        unsafe { libc::utime(p.with_ref(|p| p), &buf) }
+    }
+}
 
-        mkdir_recursive(&dirpath, UserRWX);
+#[cfg(test)]
+mod tests {
+    use io::native::file::{CFile, FileDesc};
+    use io::fs;
+    use io;
+    use libc;
+    use os;
+    use path::Path;
+    use rand;
+    use result::Ok;
+    use rt::rtio::RtioFileStream;
 
-        assert!((path_is_dir(&dirpath)));
+    fn tmpdir() -> Path {
+        let ret = os::tmpdir().join(format!("rust-{}", rand::random::<u32>()));
+        fs::mkdir(&ret, io::UserRWX);
+        ret
+    }
 
-        let mut filepath = dirpath;
-        filepath.push("unicode-file-\uac00\u4e00\u30fc\u4f60\u597d.rs");
-        debug!("path_is_dir filepath: {}", filepath.display());
+    #[ignore(cfg(target_os = "freebsd"))] // hmm, maybe pipes have a tiny buffer
+    fn test_file_desc() {
+        // Run this test with some pipes so we don't have to mess around with
+        // opening or closing files.
+        unsafe {
+            let os::Pipe { input, out } = os::pipe();
+            let mut reader = FileDesc::new(input, true);
+            let mut writer = FileDesc::new(out, true);
 
-        File::create(&filepath); // ignore return; touch only
-        assert!((!path_is_dir(&filepath)));
+            writer.inner_write(bytes!("test"));
+            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 => fail!("invalid read: {:?}", r)
+            }
 
-        assert!((!path_is_dir(&Path::new(
-                     "test/unicode-bogus-dir-\uac00\u4e00\u30fc\u4f60\u597d"))));
+            assert!(writer.inner_read(buf).is_err());
+            assert!(reader.inner_write(buf).is_err());
+        }
     }
 
-    #[test]
-    fn test_path_exists() {
-        use io::fs::mkdir_recursive;
-        use 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>())); // 각丁ー再见
+    #[ignore(cfg(windows))] // apparently windows doesn't like tmpfile
+    fn test_cfile() {
+        unsafe {
+            let f = libc::tmpfile();
+            assert!(!f.is_null());
+            let mut file = CFile::new(f);
 
-        mkdir_recursive(&dirpath, UserRWX);
-        assert!((path_exists(&dirpath)));
-        assert!((!path_exists(&Path::new(
-                     "test/unicode-bogus-path-\uac01\u4e01\u30fc\u518d\u89c1"))));
+            file.write(bytes!("test"));
+            let mut buf = [0u8, ..4];
+            file.seek(0, io::SeekSet);
+            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 => fail!("invalid read: {:?}", r)
+            }
+        }
     }
 }
index d7aa6c14fcd9f86f6b4577781359407aeae37875..cec0de00ec2b5f06cea114646be0279bbb22d66c 100644 (file)
@@ -90,6 +90,24 @@ fn get_err(errno: i32) -> (io::IoErrorKind, &'static str) {
     }
 }
 
+// unix has nonzero values as errors
+fn mkerr_libc(ret: libc::c_int) -> IoResult<()> {
+    if ret != 0 {
+        Err(last_error())
+    } else {
+        Ok(())
+    }
+}
+
+// windows has zero values as errors
+fn mkerr_winbool(ret: libc::c_int) -> IoResult<()> {
+    if ret == 0 {
+        Err(last_error())
+    } else {
+        Ok(())
+    }
+}
+
 /// Implementation of rt::rtio's IoFactory trait to generate handles to the
 /// native I/O functionality.
 pub struct IoFactory;
@@ -125,51 +143,51 @@ fn fs_from_raw_fd(&mut self, fd: c_int,
         };
         ~file::FileDesc::new(fd, close) as ~RtioFileStream
     }
-    fn fs_open(&mut self, _path: &CString, _fm: io::FileMode, _fa: io::FileAccess)
+    fn fs_open(&mut self, path: &CString, fm: io::FileMode, fa: io::FileAccess)
         -> IoResult<~RtioFileStream> {
-        Err(unimpl())
+        file::open(path, fm, fa).map(|fd| ~fd as ~RtioFileStream)
     }
-    fn fs_unlink(&mut self, _path: &CString) -> IoResult<()> {
-        Err(unimpl())
+    fn fs_unlink(&mut self, path: &CString) -> IoResult<()> {
+        file::unlink(path)
     }
-    fn fs_stat(&mut self, _path: &CString) -> IoResult<io::FileStat> {
-        Err(unimpl())
+    fn fs_stat(&mut self, path: &CString) -> IoResult<io::FileStat> {
+        file::stat(path)
     }
-    fn fs_mkdir(&mut self, _path: &CString,
-                _mode: io::FilePermission) -> IoResult<()> {
-        Err(unimpl())
+    fn fs_mkdir(&mut self, path: &CString,
+                mode: io::FilePermission) -> IoResult<()> {
+        file::mkdir(path, mode)
     }
-    fn fs_chmod(&mut self, _path: &CString,
-                _mode: io::FilePermission) -> IoResult<()> {
-        Err(unimpl())
+    fn fs_chmod(&mut self, path: &CString,
+                mode: io::FilePermission) -> IoResult<()> {
+        file::chmod(path, mode)
     }
-    fn fs_rmdir(&mut self, _path: &CString) -> IoResult<()> {
-        Err(unimpl())
+    fn fs_rmdir(&mut self, path: &CString) -> IoResult<()> {
+        file::rmdir(path)
     }
-    fn fs_rename(&mut self, _path: &CString, _to: &CString) -> IoResult<()> {
-        Err(unimpl())
+    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<~[Path]> {
-        Err(unimpl())
+    fn fs_readdir(&mut self, path: &CString, _flags: c_int) -> IoResult<~[Path]> {
+        file::readdir(path)
     }
-    fn fs_lstat(&mut self, _path: &CString) -> IoResult<io::FileStat> {
-        Err(unimpl())
+    fn fs_lstat(&mut self, path: &CString) -> IoResult<io::FileStat> {
+        file::lstat(path)
     }
-    fn fs_chown(&mut self, _path: &CString, _uid: int, _gid: int) -> IoResult<()> {
-        Err(unimpl())
+    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<Path> {
-        Err(unimpl())
+    fn fs_readlink(&mut self, path: &CString) -> IoResult<Path> {
+        file::readlink(path)
     }
-    fn fs_symlink(&mut self, _src: &CString, _dst: &CString) -> IoResult<()> {
-        Err(unimpl())
+    fn fs_symlink(&mut self, src: &CString, dst: &CString) -> IoResult<()> {
+        file::symlink(src, dst)
     }
-    fn fs_link(&mut self, _src: &CString, _dst: &CString) -> IoResult<()> {
-        Err(unimpl())
+    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<()> {
-        Err(unimpl())
+    fn fs_utime(&mut self, src: &CString, atime: u64,
+                mtime: u64) -> IoResult<()> {
+        file::utime(src, atime, mtime)
     }
 
     // misc
@@ -183,14 +201,18 @@ fn spawn(&mut self, config: ProcessConfig)
              io.move_iter().map(|p| p.map(|p| ~p as ~RtioPipe)).collect())
         })
     }
-    fn pipe_open(&mut self, _fd: c_int) -> IoResult<~RtioPipe> {
-        Err(unimpl())
+    fn pipe_open(&mut self, fd: c_int) -> IoResult<~RtioPipe> {
+        Ok(~file::FileDesc::new(fd, true) as ~RtioPipe)
     }
     fn tty_open(&mut self, fd: c_int, _readable: bool) -> IoResult<~RtioTTY> {
         if unsafe { libc::isatty(fd) } != 0 {
             Ok(~file::FileDesc::new(fd, true) as ~RtioTTY)
         } else {
-            Err(unimpl())
+            Err(IoError {
+                kind: io::MismatchedFileTypeForOperation,
+                desc: "file descriptor is not a TTY",
+                detail: None,
+            })
         }
     }
     fn signal(&mut self, _signal: Signum, _channel: SharedChan<Signum>)
index 6df9ea6c60a6d6f1ca04e8dd93af3fd6379a7204..49cac428cb23e19d01678f73a76a6d5aa13ae658 100644 (file)
@@ -316,12 +316,22 @@ fn write(&mut self, buf: &[u8]) {
 #[cfg(test)]
 mod tests {
     use super::*;
+    use rt::test::run_in_newsched_task;
 
     #[test]
-    fn smoke() {
+    fn smoke_uv() {
         // Just make sure we can acquire handles
         stdin();
         stdout();
         stderr();
     }
+
+    #[test]
+    fn smoke_native() {
+        do run_in_newsched_task {
+            stdin();
+            stdout();
+            stderr();
+        }
+    }
 }
index 190f6a7c86f7b06d30df414a18fa837dc3c0cdd4..b3528c5d3ab7f7f35e87e1daa17d4d178defcba6 100644 (file)
@@ -329,6 +329,11 @@ pub struct stat {
                     __unused5: c_long,
                 }
 
+                pub struct utimbuf {
+                    actime: time_t,
+                    modtime: time_t,
+                }
+
                 pub struct pthread_attr_t {
                     __size: [u32, ..9]
                 }
@@ -365,6 +370,11 @@ pub struct stat {
                     st_ino: c_ulonglong
                 }
 
+                pub struct utimbuf {
+                    actime: time_t,
+                    modtime: time_t,
+                }
+
                 pub struct pthread_attr_t {
                     __size: [u32, ..9]
                 }
@@ -403,6 +413,11 @@ pub struct stat {
                     st_pad5: [c_long, ..14],
                 }
 
+                pub struct utimbuf {
+                    actime: time_t,
+                    modtime: time_t,
+                }
+
                 pub struct pthread_attr_t {
                     __size: [u32, ..9]
                 }
@@ -479,6 +494,11 @@ pub struct stat {
                     __unused: [c_long, ..3],
                 }
 
+                pub struct utimbuf {
+                    actime: time_t,
+                    modtime: time_t,
+                }
+
                 pub struct pthread_attr_t {
                     __size: [u64, ..7]
                 }
@@ -594,6 +614,11 @@ pub struct stat {
                     __unused: [uint8_t, ..2],
                 }
 
+                pub struct utimbuf {
+                    actime: time_t,
+                    modtime: time_t,
+                }
+
                 pub type pthread_attr_t = *c_void;
             }
             pub mod posix08 {
@@ -629,6 +654,12 @@ pub struct stat {
                     st_mtime: time64_t,
                     st_ctime: time64_t,
                 }
+
+                // note that this is called utimbuf64 in win32
+                pub struct utimbuf {
+                    actime: time64_t,
+                    modtime: time64_t,
+                }
             }
         }
 
@@ -679,7 +710,7 @@ pub mod extra {
                 use libc::types::os::arch::c95::{c_char, c_int, c_uint, size_t};
                 use libc::types::os::arch::c95::{c_long, c_ulong};
                 use libc::types::os::arch::c95::{wchar_t};
-                use libc::types::os::arch::c99::{c_ulonglong};
+                use libc::types::os::arch::c99::{c_ulonglong, c_longlong};
 
                 pub type BOOL = c_int;
                 pub type BYTE = u8;
@@ -692,8 +723,13 @@ pub mod extra {
                 pub type HANDLE = LPVOID;
                 pub type HMODULE = c_uint;
 
+                pub type LONG = c_long;
+                pub type PLONG = *mut c_long;
                 pub type LONG_PTR = c_long;
 
+                pub type LARGE_INTEGER = c_longlong;
+                pub type PLARGE_INTEGER = *mut c_longlong;
+
                 pub type LPCWSTR = *WCHAR;
                 pub type LPCSTR = *CHAR;
                 pub type LPCTSTR = *CHAR;
@@ -795,6 +831,16 @@ pub struct MEMORY_BASIC_INFORMATION {
                     Type: DWORD
                 }
                 pub type LPMEMORY_BASIC_INFORMATION = *mut MEMORY_BASIC_INFORMATION;
+
+                pub struct OVERLAPPED {
+                    Internal: *c_ulong,
+                    InternalHigh: *c_ulong,
+                    Offset: DWORD,
+                    OffsetHigh: DWORD,
+                    hEvent: HANDLE,
+                }
+
+                pub type LPOVERLAPPED = *mut OVERLAPPED;
             }
         }
 
@@ -1065,6 +1111,11 @@ pub struct stat {
                     st_qspare: [int64_t, ..2],
                 }
 
+                pub struct utimbuf {
+                    actime: time_t,
+                    modtime: time_t,
+                }
+
                 pub struct pthread_attr_t {
                     __sig: c_long,
                     __opaque: [c_char, ..36]
@@ -1151,6 +1202,11 @@ pub struct stat {
                     st_qspare: [int64_t, ..2],
                 }
 
+                pub struct utimbuf {
+                    actime: time_t,
+                    modtime: time_t,
+                }
+
                 pub struct pthread_attr_t {
                     __sig: c_long,
                     __opaque: [c_char, ..56]
@@ -1337,6 +1393,72 @@ pub mod extra {
             pub static PROCESSOR_ARCHITECTURE_IA64 : WORD = 6;
             pub static PROCESSOR_ARCHITECTURE_AMD64 : WORD = 9;
             pub static PROCESSOR_ARCHITECTURE_UNKNOWN : WORD = 0xffff;
+
+            pub static MOVEFILE_COPY_ALLOWED: DWORD = 2;
+            pub static MOVEFILE_CREATE_HARDLINK: DWORD = 16;
+            pub static MOVEFILE_DELAY_UNTIL_REBOOT: DWORD = 4;
+            pub static MOVEFILE_FAIL_IF_NOT_TRACKABLE: DWORD = 32;
+            pub static MOVEFILE_REPLACE_EXISTING: DWORD = 1;
+            pub static MOVEFILE_WRITE_THROUGH: DWORD = 8;
+
+            pub static SYMBOLIC_LINK_FLAG_DIRECTORY: DWORD = 1;
+
+            pub static FILE_SHARE_DELETE: DWORD = 0x4;
+            pub static FILE_SHARE_READ: DWORD = 0x1;
+            pub static FILE_SHARE_WRITE: DWORD = 0x2;
+
+            pub static CREATE_ALWAYS: DWORD = 2;
+            pub static CREATE_NEW: DWORD = 1;
+            pub static OPEN_ALWAYS: DWORD = 4;
+            pub static OPEN_EXISTING: DWORD = 3;
+            pub static TRUNCATE_EXISTING: DWORD = 5;
+
+            pub static FILE_ATTRIBUTE_ARCHIVE: DWORD = 0x20;
+            pub static FILE_ATTRIBUTE_COMPRESSED: DWORD = 0x800;
+            pub static FILE_ATTRIBUTE_DEVICE: DWORD = 0x40;
+            pub static FILE_ATTRIBUTE_DIRECTORY: DWORD = 0x10;
+            pub static FILE_ATTRIBUTE_ENCRYPTED: DWORD = 0x4000;
+            pub static FILE_ATTRIBUTE_HIDDEN: DWORD = 0x2;
+            pub static FILE_ATTRIBUTE_INTEGRITY_STREAM: DWORD = 0x8000;
+            pub static FILE_ATTRIBUTE_NORMAL: DWORD = 0x80;
+            pub static FILE_ATTRIBUTE_NOT_CONTENT_INDEXED: DWORD = 0x2000;
+            pub static FILE_ATTRIBUTE_NO_SCRUB_DATA: DWORD = 0x20000;
+            pub static FILE_ATTRIBUTE_OFFLINE: DWORD = 0x1000;
+            pub static FILE_ATTRIBUTE_READONLY: DWORD = 0x1;
+            pub static FILE_ATTRIBUTE_REPARSE_POINT: DWORD = 0x400;
+            pub static FILE_ATTRIBUTE_SPARSE_FILE: DWORD = 0x200;
+            pub static FILE_ATTRIBUTE_SYSTEM: DWORD = 0x4;
+            pub static FILE_ATTRIBUTE_TEMPORARY: DWORD = 0x100;
+            pub static FILE_ATTRIBUTE_VIRTUAL: DWORD = 0x10000;
+
+            pub static FILE_FLAG_BACKUP_SEMANTICS: DWORD = 0x02000000;
+            pub static FILE_FLAG_DELETE_ON_CLOSE: DWORD = 0x04000000;
+            pub static FILE_FLAG_NO_BUFFERING: DWORD = 0x20000000;
+            pub static FILE_FLAG_OPEN_NO_RECALL: DWORD = 0x00100000;
+            pub static FILE_FLAG_OPEN_REPARSE_POINT: DWORD = 0x00200000;
+            pub static FILE_FLAG_OVERLAPPED: DWORD = 0x40000000;
+            pub static FILE_FLAG_POSIX_SEMANTICS: DWORD = 0x0100000;
+            pub static FILE_FLAG_RANDOM_ACCESS: DWORD = 0x10000000;
+            pub static FILE_FLAG_SESSION_AWARE: DWORD = 0x00800000;
+            pub static FILE_FLAG_SEQUENTIAL_SCAN: DWORD = 0x08000000;
+            pub static FILE_FLAG_WRITE_THROUGH: DWORD = 0x80000000;
+
+            pub static FILE_NAME_NORMALIZED: DWORD = 0x0;
+            pub static FILE_NAME_OPENED: DWORD = 0x8;
+
+            pub static VOLUME_NAME_DOS: DWORD = 0x0;
+            pub static VOLUME_NAME_GUID: DWORD = 0x1;
+            pub static VOLUME_NAME_NONE: DWORD = 0x4;
+            pub static VOLUME_NAME_NT: DWORD = 0x2;
+
+            pub static GENERIC_READ: DWORD = 0x80000000;
+            pub static GENERIC_WRITE: DWORD = 0x40000000;
+            pub static GENERIC_EXECUTE: DWORD = 0x20000000;
+            pub static GENERIC_ALL: DWORD = 0x10000000;
+
+            pub static FILE_BEGIN: DWORD = 0;
+            pub static FILE_CURRENT: DWORD = 1;
+            pub static FILE_END: DWORD = 2;
         }
         pub mod sysconf {
         }
@@ -2873,18 +2995,26 @@ pub fn strncpy(dst: *c_char, src: *c_char, n: size_t)
     pub mod posix88 {
         #[nolink]
         pub mod stat_ {
-            use libc::types::os::common::posix01::stat;
-            use libc::types::os::arch::c95::{c_int, c_char};
+            use libc::types::os::common::posix01::{stat, utimbuf};
+            use libc::types::os::arch::c95::{c_int, c_char, wchar_t};
 
             extern {
                 #[link_name = "_chmod"]
                 pub fn chmod(path: *c_char, mode: c_int) -> c_int;
+                #[link_name = "_wchmod"]
+                pub fn wchmod(path: *wchar_t, mode: c_int) -> c_int;
                 #[link_name = "_mkdir"]
                 pub fn mkdir(path: *c_char) -> c_int;
+                #[link_name = "_wrmdir"]
+                pub fn wrmdir(path: *wchar_t) -> c_int;
                 #[link_name = "_fstat64"]
                 pub fn fstat(fildes: c_int, buf: *mut stat) -> c_int;
                 #[link_name = "_stat64"]
                 pub fn stat(path: *c_char, buf: *mut stat) -> c_int;
+                #[link_name = "_wstat64"]
+                pub fn wstat(path: *wchar_t, buf: *mut stat) -> c_int;
+                #[link_name = "_wutime64"]
+                pub fn wutime(file: *wchar_t, buf: *utimbuf) -> c_int;
             }
         }
 
@@ -2907,11 +3037,14 @@ pub mod stdio {
 
         #[nolink]
         pub mod fcntl {
-            use libc::types::os::arch::c95::{c_int, c_char};
+            use libc::types::os::arch::c95::{c_int, c_char, wchar_t};
             extern {
                 #[link_name = "_open"]
                 pub fn open(path: *c_char, oflag: c_int, mode: c_int)
                             -> c_int;
+                #[link_name = "_wopen"]
+                pub fn wopen(path: *wchar_t, oflag: c_int, mode: c_int)
+                            -> c_int;
                 #[link_name = "_creat"]
                 pub fn creat(path: *c_char, mode: c_int) -> c_int;
             }
@@ -3079,9 +3212,12 @@ pub mod unistd {
             use libc::types::common::c95::c_void;
             use libc::types::os::arch::c95::{c_char, c_int, c_long, c_uint};
             use libc::types::os::arch::c95::{size_t};
+            use libc::types::os::arch::posix01::utimbuf;
             use libc::types::os::arch::posix88::{gid_t, off_t, pid_t};
             use libc::types::os::arch::posix88::{ssize_t, uid_t};
 
+            pub static _PC_NAME_MAX: c_int = 4;
+
             extern {
                 pub fn access(path: *c_char, amode: c_int) -> c_int;
                 pub fn alarm(seconds: c_uint) -> c_uint;
@@ -3130,6 +3266,11 @@ pub fn read(fd: c_int, buf: *mut c_void, count: size_t)
                 pub fn unlink(c: *c_char) -> c_int;
                 pub fn write(fd: c_int, buf: *c_void, count: size_t)
                              -> ssize_t;
+                pub fn pread(fd: c_int, buf: *c_void, count: size_t,
+                             offset: off_t) -> ssize_t;
+                pub fn pwrite(fd: c_int, buf: *c_void, count: size_t,
+                              offset: off_t) -> ssize_t;
+                pub fn utime(file: *c_char, buf: *utimbuf) -> c_int;
             }
         }
 
@@ -3201,7 +3342,7 @@ pub mod stat_ {
         #[nolink]
         pub mod unistd {
             use libc::types::os::arch::c95::{c_char, c_int, size_t};
-            use libc::types::os::arch::posix88::{ssize_t};
+            use libc::types::os::arch::posix88::{ssize_t, off_t};
 
             extern {
                 pub fn readlink(path: *c_char,
@@ -3221,6 +3362,8 @@ pub fn setenv(name: *c_char, val: *c_char, overwrite: c_int)
                 pub fn putenv(string: *c_char) -> c_int;
 
                 pub fn symlink(path1: *c_char, path2: *c_char) -> c_int;
+
+                pub fn ftruncate(fd: c_int, length: off_t) -> c_int;
             }
         }
 
@@ -3374,12 +3517,13 @@ pub mod kernel32 {
             use libc::types::os::arch::extra::{BOOL, DWORD, SIZE_T, HMODULE};
             use libc::types::os::arch::extra::{LPCWSTR, LPWSTR, LPCTSTR,
                                                LPTSTR, LPTCH, LPDWORD, LPVOID,
-                                               LPCVOID};
+                                               LPCVOID, LPOVERLAPPED};
             use libc::types::os::arch::extra::{LPSECURITY_ATTRIBUTES, LPSTARTUPINFO,
                                                LPPROCESS_INFORMATION,
                                                LPMEMORY_BASIC_INFORMATION,
                                                LPSYSTEM_INFO};
-            use libc::types::os::arch::extra::{HANDLE, LPHANDLE};
+            use libc::types::os::arch::extra::{HANDLE, LPHANDLE, LARGE_INTEGER,
+                                               PLARGE_INTEGER};
 
             extern "system" {
                 pub fn GetEnvironmentVariableW(n: LPCWSTR,
@@ -3486,6 +3630,43 @@ pub fn MapViewOfFile(hFileMappingObject: HANDLE,
                                      dwNumberOfBytesToMap: SIZE_T)
                                      -> LPVOID;
                 pub fn UnmapViewOfFile(lpBaseAddress: LPCVOID) -> BOOL;
+                pub fn MoveFileExW(lpExistingFileName: LPCWSTR,
+                                   lpNewFileName: LPCWSTR,
+                                   dwFlags: DWORD) -> BOOL;
+                pub fn CreateSymbolicLinkW(lpSymlinkFileName: LPCWSTR,
+                                           lpTargetFileName: LPCWSTR,
+                                           dwFlags: DWORD) -> BOOL;
+                pub fn CreateHardLinkW(lpSymlinkFileName: LPCWSTR,
+                                       lpTargetFileName: LPCWSTR,
+                                       lpSecurityAttributes: LPSECURITY_ATTRIBUTES)
+                                        -> BOOL;
+                pub fn FlushFileBuffers(hFile: HANDLE) -> BOOL;
+                pub fn CreateFileW(lpFileName: LPCWSTR,
+                                   dwDesiredAccess: DWORD,
+                                   dwShareMode: DWORD,
+                                   lpSecurityAttributes: LPSECURITY_ATTRIBUTES,
+                                   dwCreationDisposition: DWORD,
+                                   dwFlagsAndAttributes: DWORD,
+                                   hTemplateFile: HANDLE) -> HANDLE;
+                pub fn GetFinalPathNameByHandleW(hFile: HANDLE,
+                                                 lpszFilePath: LPCWSTR,
+                                                 cchFilePath: DWORD,
+                                                 dwFlags: DWORD) -> DWORD;
+                pub fn ReadFile(hFile: HANDLE,
+                                lpBuffer: LPVOID,
+                                nNumberOfBytesToRead: DWORD,
+                                lpNumberOfBytesRead: LPDWORD,
+                                lpOverlapped: LPOVERLAPPED) -> BOOL;
+                pub fn WriteFile(hFile: HANDLE,
+                                 lpBuffer: LPVOID,
+                                 nNumberOfBytesToRead: DWORD,
+                                 lpNumberOfBytesRead: LPDWORD,
+                                 lpOverlapped: LPOVERLAPPED) -> BOOL;
+                pub fn SetFilePointerEx(hFile: HANDLE,
+                                        liDistanceToMove: LARGE_INTEGER,
+                                        lpNewFilePointer: PLARGE_INTEGER,
+                                        dwMoveMethod: DWORD) -> BOOL;
+                pub fn SetEndOfFile(hFile: HANDLE) -> BOOL;
             }
         }
 
index c8ed61bfc41a91bc51f1116ce6f93242b54cabb1..c50bdc7c2c68c6da1604a66b3bf0fc5c0b2d0b4d 100644 (file)
@@ -110,62 +110,6 @@ rust_list_dir_wfd_fp_buf(void* wfd) {
 }
 #endif
 
-int
-rust_path_is_dir(const char *path) {
-    struct stat buf;
-    if (stat(path, &buf)) {
-        return 0;
-    }
-    return S_ISDIR(buf.st_mode);
-}
-
-int
-#if defined(__WIN32__)
-rust_path_is_dir_u16(const wchar_t *path) {
-    struct _stat buf;
-    // Don't use GetFileAttributesW, it cannot get attributes of
-    // some system files (e.g. pagefile.sys).
-    if (_wstat(path, &buf)) {
-        return 0;
-    }
-    return S_ISDIR(buf.st_mode);
-}
-#else
-rust_path_is_dir_u16(const void *path) {
-    // Wide version of function is only used on Windows.
-    return 0;
-}
-#endif
-
-int
-rust_path_exists(const char *path) {
-    struct stat buf;
-    if (stat(path, &buf)) {
-        return 0;
-    }
-    return 1;
-}
-
-int
-#if defined(__WIN32__)
-rust_path_exists_u16(const wchar_t *path) {
-    struct _stat buf;
-    if (_wstat(path, &buf)) {
-        return 0;
-    }
-    return 1;
-}
-#else
-rust_path_exists_u16(const void *path) {
-    // Wide version of function is only used on Windows.
-    return 0;
-}
-#endif
-
-FILE* rust_get_stdin() {return stdin;}
-FILE* rust_get_stdout() {return stdout;}
-FILE* rust_get_stderr() {return stderr;}
-
 #if defined(__WIN32__)
 void
 rust_get_time(int64_t *sec, int32_t *nsec) {
index c5b5e7f2c467a374c970b2d11e69d58331d8f425..2a3e687ee55551835127e4a11ccc795cf26b9614 100644 (file)
@@ -9,13 +9,6 @@ rust_localtime
 rust_timegm
 rust_mktime
 rust_precise_time_ns
-rust_path_is_dir
-rust_path_is_dir_u16
-rust_path_exists
-rust_path_exists_u16
-rust_get_stdin
-rust_get_stdout
-rust_get_stderr
 rust_list_dir_val
 rust_list_dir_wfd_size
 rust_list_dir_wfd_fp_buf
index 89f4440f5bb33056e51bcad98a173402662024c7..6b0f328629eb17e4abde23d20304ef8be1cff875 100644 (file)
@@ -109,8 +109,8 @@ mod test_foreign_items {
     pub mod rustrt {
         extern {
             #[cfg(bogus)]
-            pub fn rust_get_stdin() -> ~str;
-            pub fn rust_get_stdin() -> ~str;
+            pub fn write() -> ~str;
+            pub fn write() -> ~str;
         }
     }
 }