auto merge of #10495 : alexcrichton/rust/more-native-io, r=brson

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 few bits of remaining functionality which I was unable to get
working:

* truncate on windows
* change_file_times on windows
* lstat on windows

I think that change_file_times may just need a better interface, but the other
two have large implementations in libuv which I didn't want to tackle trying to
copy. I found a `chsize` function to work for truncate on windows, but it
doesn't quite seem to be working out.
This commit is contained in:
bors 2013-11-19 10:56:42 -08:00
commit eef913b290
9 changed files with 1099 additions and 759 deletions

View file

@ -391,7 +391,6 @@ mod test {
// newtype struct autoderef weirdness
#[test]
fn test_buffered_stream() {
use rt;
struct S;
impl io::Writer for S {

View file

@ -191,7 +191,7 @@ impl File {
///
/// 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 @@ impl File {
///
/// 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 @@ impl path::Path {
}
#[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;
fn tmpdir() -> Path {
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() -> 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;
#[test]
fn file_test_io_smoke_test() {
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() {
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 @@ mod 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 @@ mod test {
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 @@ mod test {
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 @@ mod test {
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 @@ mod 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 @@ mod test {
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 @@ mod test {
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 @@ mod test {
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 @@ mod test {
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 @@ mod test {
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 @@ mod test {
mkdir(&unicode, io::UserRWX);
assert!(unicode.exists());
assert!(!Path::new("test/unicode-bogus-path-각丁ー再见").exists());
rmdir_recursive(&tmpdir);
}
})
#[test]
fn copy_file_does_not_exist() {
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 @@ mod test {
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 @@ mod test {
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 @@ mod test {
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 @@ mod test {
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 @@ mod test {
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 @@ mod test {
}
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 @@ mod test {
file.write(bytes!("foo"));
file.fsync();
file.datasync();
free(file);
util::ignore(file);
})
rmdir_recursive(&tmpdir);
}
#[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 @@ mod test {
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);
util::ignore(file);
})
rmdir_recursive(&tmpdir);
}
#[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 @@ mod test {
f.write("bar".as_bytes());
}
assert_eq!(stat(&tmpdir.join("h")).size, 3);
rmdir_recursive(&tmpdir);
}
})
#[test]
fn utime() {
@ -1271,8 +1278,6 @@ mod test {
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 @@ mod test {
Ok(*) => fail!(),
Err(*) => {}
}
rmdir_recursive(&tmpdir);
}
}

File diff suppressed because it is too large Load diff

View file

@ -90,6 +90,24 @@ fn last_error() -> IoError {
}
}
// 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 @@ impl rtio::IoFactory for IoFactory {
};
~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 @@ impl rtio::IoFactory for IoFactory {
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>)

View file

@ -316,12 +316,22 @@ impl Writer for StdWriter {
#[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();
}
}
}

View file

@ -329,6 +329,11 @@ pub mod types {
__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 mod types {
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 mod types {
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 mod types {
__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 mod types {
__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 mod types {
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 types {
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 types {
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 mod types {
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 mod types {
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 mod types {
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 consts {
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 mod funcs {
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 funcs {
#[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 funcs {
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 mod funcs {
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 funcs {
#[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 mod funcs {
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 funcs {
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 mod funcs {
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;
}
}

View 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) {

View 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

View 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;
}
}
}