///
/// 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
///
/// 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));
}
}
}
#[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());
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;
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;
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());
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());
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());
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());
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";
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) {
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());
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());
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)) {
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");
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");
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");
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
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");
}
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");
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());
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,
f.write("bar".as_bytes());
}
assert_eq!(stat(&tmpdir.join("h")).size, 3);
-
- rmdir_recursive(&tmpdir);
- }
+ })
#[test]
fn utime() {
change_file_times(&path, 1000, 2000);
assert_eq!(path.stat().accessed, 1000);
assert_eq!(path.stat().modified, 2000);
-
- rmdir_recursive(&tmpdir);
}
#[test]
Ok(*) => fail!(),
Err(*) => {}
}
-
- rmdir_recursive(&tmpdir);
}
}
#[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
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)
+ })
}
}
}
pub struct CFile {
- priv file: *libc::FILE
+ priv file: *libc::FILE,
+ priv fd: FileDesc,
}
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 {
}
}
- 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 {
}
}
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)
}
}
}
}
-#[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)
+ }
+ }
}
}
__unused5: c_long,
}
+ pub struct utimbuf {
+ actime: time_t,
+ modtime: time_t,
+ }
+
pub struct pthread_attr_t {
__size: [u32, ..9]
}
st_ino: c_ulonglong
}
+ pub struct utimbuf {
+ actime: time_t,
+ modtime: time_t,
+ }
+
pub struct pthread_attr_t {
__size: [u32, ..9]
}
st_pad5: [c_long, ..14],
}
+ pub struct utimbuf {
+ actime: time_t,
+ modtime: time_t,
+ }
+
pub struct pthread_attr_t {
__size: [u32, ..9]
}
__unused: [c_long, ..3],
}
+ pub struct utimbuf {
+ actime: time_t,
+ modtime: time_t,
+ }
+
pub struct pthread_attr_t {
__size: [u64, ..7]
}
__unused: [uint8_t, ..2],
}
+ pub struct utimbuf {
+ actime: time_t,
+ modtime: time_t,
+ }
+
pub type pthread_attr_t = *c_void;
}
pub mod posix08 {
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,
+ }
}
}
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;
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;
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;
}
}
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]
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]
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 {
}
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;
}
}
#[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;
}
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;
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;
}
}
#[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,
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;
}
}
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,
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;
}
}