From d7b6502784cad759cee9961426313017f052d5ba Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 25 Oct 2013 16:48:26 -0700 Subject: [PATCH 1/5] Move rt::io traits into the prelude These traits belong here, and were simply waiting for the std::io traits to get removed. It's time they take their rightful positions! --- src/libstd/prelude.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libstd/prelude.rs b/src/libstd/prelude.rs index a15ef879e322d..0190b02fbc08f 100644 --- a/src/libstd/prelude.rs +++ b/src/libstd/prelude.rs @@ -67,6 +67,7 @@ pub use num::{Orderable, Signed, Unsigned, Round}; pub use num::{Primitive, Int, Float, ToStrRadix, ToPrimitive, FromPrimitive}; pub use path::{GenericPath, Path, PosixPath, WindowsPath}; pub use ptr::RawPtr; +pub use rt::io::{Writer, Reader, Seek}; pub use send_str::{SendStr, SendStrOwned, SendStrStatic, IntoSendStr}; pub use str::{Str, StrVector, StrSlice, OwnedStr}; pub use to_bytes::IterBytes; From 7bf58c2baaac3f7cb3c8e8d735b27ac9e7d3cd78 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 25 Oct 2013 16:50:08 -0700 Subject: [PATCH 2/5] Modify IoFactory's fs_mkdir, and add fs_rename The invocation for making a directory should be able to specify a mode to make the directory with (instead of defaulting to one particular mode). Additionally, libuv and various OSes implement efficient versions of renaming files, so this operation is exposed as an IoFactory call. --- src/librustuv/file.rs | 15 +++++++++++++++ src/librustuv/uvio.rs | 14 +++++++++++--- src/librustuv/uvll.rs | 8 ++++++++ src/libstd/rt/rtio.rs | 3 ++- src/rt/rust_uv.cpp | 5 +++++ 5 files changed, 41 insertions(+), 4 deletions(-) diff --git a/src/librustuv/file.rs b/src/librustuv/file.rs index 575226f79028b..2303721986c42 100644 --- a/src/librustuv/file.rs +++ b/src/librustuv/file.rs @@ -206,6 +206,21 @@ impl FsRequest { assert_eq!(ret, 0); } + pub fn rename(self, loop_: &Loop, path: &CString, to: &CString, cb: FsCallback) { + let complete_cb_ptr = { + let mut me = self; + me.req_boilerplate(Some(cb)) + }; + let ret = unsafe { + uvll::fs_rename(loop_.native_handle(), + self.native_handle(), + path.with_ref(|p| p), + to.with_ref(|p| p), + complete_cb_ptr) + }; + assert_eq!(ret, 0); + } + pub fn readdir(self, loop_: &Loop, path: &CString, flags: c_int, cb: FsCallback) { let complete_cb_ptr = { diff --git a/src/librustuv/uvio.rs b/src/librustuv/uvio.rs index c34d20ed4f50f..7ecb51bb0d6ef 100644 --- a/src/librustuv/uvio.rs +++ b/src/librustuv/uvio.rs @@ -699,10 +699,9 @@ impl IoFactory for UvIoFactory { assert!(!result_cell.is_empty()); return result_cell.take(); } - fn fs_mkdir(&mut self, path: &CString) -> Result<(), IoError> { - let mode = S_IRWXU as int; + fn fs_mkdir(&mut self, path: &CString, mode: int) -> Result<(), IoError> { do uv_fs_helper(self.uv_loop(), path) |mkdir_req, l, p, cb| { - do mkdir_req.mkdir(l, p, mode as int) |req, err| { + do mkdir_req.mkdir(l, p, mode) |req, err| { cb(req, err) }; } @@ -714,6 +713,15 @@ impl IoFactory for UvIoFactory { }; } } + fn fs_rename(&mut self, path: &CString, to: &CString) -> Result<(), IoError> { + let to = to.with_ref(|p| p); + do uv_fs_helper(self.uv_loop(), path) |rename_req, l, p, cb| { + let to = unsafe { CString::new(to, false) }; + do rename_req.rename(l, p, &to) |req, err| { + cb(req, err) + }; + } + } fn fs_readdir(&mut self, path: &CString, flags: c_int) -> Result<~[Path], IoError> { use str::StrSlice; diff --git a/src/librustuv/uvll.rs b/src/librustuv/uvll.rs index 9e86ab11286e4..9f26f9506a084 100644 --- a/src/librustuv/uvll.rs +++ b/src/librustuv/uvll.rs @@ -807,6 +807,12 @@ pub unsafe fn fs_rmdir(loop_ptr: *uv_loop_t, req: *uv_fs_t, path: *c_char, rust_uv_fs_rmdir(loop_ptr, req, path, cb) } +pub unsafe fn fs_rename(loop_ptr: *uv_loop_t, req: *uv_fs_t, path: *c_char, + to: *c_char, cb: *u8) -> c_int { + #[fixed_stack_segment]; #[inline(never)]; + + rust_uv_fs_rename(loop_ptr, req, path, to, cb) +} pub unsafe fn fs_readdir(loop_ptr: *uv_loop_t, req: *uv_fs_t, path: *c_char, flags: c_int, cb: *u8) -> c_int { #[fixed_stack_segment]; #[inline(never)]; @@ -1107,6 +1113,8 @@ extern { mode: c_int, cb: *u8) -> c_int; fn rust_uv_fs_rmdir(loop_ptr: *c_void, req: *uv_fs_t, path: *c_char, cb: *u8) -> c_int; + fn rust_uv_fs_rename(loop_ptr: *c_void, req: *uv_fs_t, path: *c_char, + to: *c_char, cb: *u8) -> c_int; fn rust_uv_fs_readdir(loop_ptr: *c_void, req: *uv_fs_t, path: *c_char, flags: c_int, cb: *u8) -> c_int; fn rust_uv_fs_req_cleanup(req: *uv_fs_t); diff --git a/src/libstd/rt/rtio.rs b/src/libstd/rt/rtio.rs index 82ff8071896fe..44d9f59c41062 100644 --- a/src/libstd/rt/rtio.rs +++ b/src/libstd/rt/rtio.rs @@ -102,8 +102,9 @@ pub trait IoFactory { -> Result<~RtioFileStream, IoError>; fn fs_unlink(&mut self, path: &CString) -> Result<(), IoError>; fn fs_stat(&mut self, path: &CString) -> Result; - fn fs_mkdir(&mut self, path: &CString) -> Result<(), IoError>; + fn fs_mkdir(&mut self, path: &CString, mode: int) -> Result<(), IoError>; fn fs_rmdir(&mut self, path: &CString) -> Result<(), IoError>; + fn fs_rename(&mut self, path: &CString, to: &CString) -> Result<(), IoError>; fn fs_readdir(&mut self, path: &CString, flags: c_int) -> Result<~[Path], IoError>; fn spawn(&mut self, config: ProcessConfig) diff --git a/src/rt/rust_uv.cpp b/src/rt/rust_uv.cpp index c59dacab88990..70602100f2e0d 100644 --- a/src/rt/rust_uv.cpp +++ b/src/rt/rust_uv.cpp @@ -592,6 +592,11 @@ extern "C" int rust_uv_fs_readdir(uv_loop_t* loop, uv_fs_t* req, const char* path, int flags, uv_fs_cb cb) { return uv_fs_readdir(loop, req, path, flags, cb); } +extern "C" int +rust_uv_fs_rename(uv_loop_t *loop, uv_fs_t* req, const char *path, + const char *to, uv_fs_cb cb) { + return uv_fs_rename(loop, req, path, to, cb); +} extern "C" int rust_uv_spawn(uv_loop_t *loop, uv_process_t *p, uv_process_options_t options) { From 9c1851019f1ef9511fa8731b8f1acb0796d1e97f Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 25 Oct 2013 17:04:37 -0700 Subject: [PATCH 3/5] Remove all blocking std::os blocking functions This commit moves all thread-blocking I/O functions from the std::os module. Their replacements can be found in either std::rt::io::file or in a hidden "old_os" module inside of native::file. I didn't want to outright delete these functions because they have a lot of special casing learned over time for each OS/platform, and I imagine that these will someday get integrated into a blocking implementation of IoFactory. For now, they're moved to a private module to prevent bitrot and still have tests to ensure that they work. I've also expanded the extensions to a few more methods defined on Path, most of which were previously defined in std::os but now have non-thread-blocking implementations as part of using the current IoFactory. The api of io::file is in flux, but I plan on changing it in the next commit as well. Closes #10057 --- mk/tests.mk | 6 +- src/compiletest/compiletest.rs | 3 +- src/compiletest/errors.rs | 8 +- src/compiletest/header.rs | 5 +- src/compiletest/runtest.rs | 20 +- src/libextra/glob.rs | 13 +- src/libextra/tempfile.rs | 11 +- src/libextra/terminfo/searcher.rs | 10 +- src/libextra/test.rs | 16 +- src/libextra/uuid.rs | 1 - src/libextra/workcache.rs | 36 +- src/librustc/back/link.rs | 17 +- src/librustc/driver/driver.rs | 3 +- src/librustc/metadata/filesearch.rs | 36 +- src/librustdoc/html/render.rs | 67 +- src/librustdoc/lib.rs | 7 +- src/librustpkg/api.rs | 6 +- src/librustpkg/context.rs | 3 +- src/librustpkg/installed_packages.rs | 8 +- src/librustpkg/lib.rs | 31 +- src/librustpkg/package_id.rs | 1 - src/librustpkg/package_source.rs | 17 +- src/librustpkg/path_util.rs | 52 +- src/librustpkg/source_control.rs | 15 +- src/librustpkg/tests.rs | 231 +++-- .../testsuite/pass/src/c-dependencies/pkg.rs | 2 +- .../testsuite/pass/src/fancy-lib/pkg.rs | 8 +- src/librustpkg/util.rs | 27 +- src/librustpkg/version.rs | 4 +- src/librustpkg/workcache_support.rs | 26 +- src/librustpkg/workspace.rs | 2 +- src/librustuv/file.rs | 20 +- src/librustuv/uvio.rs | 17 +- src/librustuv/uvll.rs | 12 +- src/libstd/bool.rs | 7 +- src/libstd/os.rs | 549 +----------- src/libstd/path/posix.rs | 69 -- src/libstd/rand/os.rs | 8 +- src/libstd/rt/io/file.rs | 793 +++++++++--------- src/libstd/rt/io/mod.rs | 21 +- src/libstd/rt/io/native/file.rs | 483 +++++++++++ src/libstd/rt/io/net/unix.rs | 3 +- src/libstd/rt/io/signal.rs | 7 +- src/libstd/rt/io/timer.rs | 1 + src/libstd/rt/rtio.rs | 7 +- src/libstd/run.rs | 8 +- src/libsyntax/ext/source_util.rs | 25 +- src/libsyntax/parse/mod.rs | 16 +- src/rt/rust_uv.cpp | 4 + src/test/bench/core-std.rs | 5 +- src/test/bench/shootout-fasta.rs | 4 +- src/test/run-pass-fulldeps/qquote.rs | 1 + src/test/run-pass-fulldeps/quote-tokens.rs | 12 +- src/test/run-pass/glob-std.rs | 5 +- src/test/run-pass/rename-directory.rs | 12 +- src/test/run-pass/stat.rs | 9 +- src/test/run-pass/tempfile.rs | 65 +- 57 files changed, 1363 insertions(+), 1492 deletions(-) diff --git a/mk/tests.mk b/mk/tests.mk index eabb5f535e61d..a24791d76af97 100644 --- a/mk/tests.mk +++ b/mk/tests.mk @@ -517,8 +517,8 @@ CTEST_BUILD_BASE_rpass = run-pass CTEST_MODE_rpass = run-pass CTEST_RUNTOOL_rpass = $(CTEST_RUNTOOL) -CTEST_SRC_BASE_rpass-full = run-pass-full -CTEST_BUILD_BASE_rpass-full = run-pass-full +CTEST_SRC_BASE_rpass-full = run-pass-fulldeps +CTEST_BUILD_BASE_rpass-full = run-pass-fulldeps CTEST_MODE_rpass-full = run-pass CTEST_RUNTOOL_rpass-full = $(CTEST_RUNTOOL) @@ -673,7 +673,7 @@ PRETTY_DEPS_pretty-rfail = $(RFAIL_TESTS) PRETTY_DEPS_pretty-bench = $(BENCH_TESTS) PRETTY_DEPS_pretty-pretty = $(PRETTY_TESTS) PRETTY_DIRNAME_pretty-rpass = run-pass -PRETTY_DIRNAME_pretty-rpass-full = run-pass-full +PRETTY_DIRNAME_pretty-rpass-full = run-pass-fulldeps PRETTY_DIRNAME_pretty-rfail = run-fail PRETTY_DIRNAME_pretty-bench = bench PRETTY_DIRNAME_pretty-pretty = pretty diff --git a/src/compiletest/compiletest.rs b/src/compiletest/compiletest.rs index 7f5a72e8a2c8c..a354bc84e52b5 100644 --- a/src/compiletest/compiletest.rs +++ b/src/compiletest/compiletest.rs @@ -17,6 +17,7 @@ extern mod extra; use std::os; use std::rt; +use std::rt::io::file; use extra::getopts; use extra::getopts::groups::{optopt, optflag, reqopt}; @@ -247,7 +248,7 @@ pub fn make_tests(config: &config) -> ~[test::TestDescAndFn] { debug!("making tests from {}", config.src_base.display()); let mut tests = ~[]; - let dirs = os::list_dir_path(&config.src_base); + let dirs = file::readdir(&config.src_base); for file in dirs.iter() { let file = file.clone(); debug!("inspecting file {}", file.display()); diff --git a/src/compiletest/errors.rs b/src/compiletest/errors.rs index 0c94ec8ab8a83..dfadea37cd0d3 100644 --- a/src/compiletest/errors.rs +++ b/src/compiletest/errors.rs @@ -8,16 +8,16 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use std::rt::io::buffered::BufferedReader; +use std::rt::io::file; + pub struct ExpectedError { line: uint, kind: ~str, msg: ~str } // Load any test directives embedded in the file pub fn load_errors(testfile: &Path) -> ~[ExpectedError] { - use std::rt::io::Open; - use std::rt::io::file::FileInfo; - use std::rt::io::buffered::BufferedReader; let mut error_patterns = ~[]; - let mut rdr = BufferedReader::new(testfile.open_reader(Open).unwrap()); + let mut rdr = BufferedReader::new(file::open(testfile).unwrap()); let mut line_num = 1u; loop { let ln = match rdr.read_line() { diff --git a/src/compiletest/header.rs b/src/compiletest/header.rs index 368c96ffe8542..68e8fd7673542 100644 --- a/src/compiletest/header.rs +++ b/src/compiletest/header.rs @@ -103,11 +103,10 @@ pub fn is_test_ignored(config: &config, testfile: &Path) -> bool { } fn iter_header(testfile: &Path, it: &fn(&str) -> bool) -> bool { - use std::rt::io::Open; - use std::rt::io::file::FileInfo; use std::rt::io::buffered::BufferedReader; + use std::rt::io::file; - let mut rdr = BufferedReader::new(testfile.open_reader(Open).unwrap()); + let mut rdr = BufferedReader::new(file::open(testfile).unwrap()); loop { let ln = match rdr.read_line() { Some(ln) => ln, None => break diff --git a/src/compiletest/runtest.rs b/src/compiletest/runtest.rs index 13c4c7948b803..7fc13467217fb 100644 --- a/src/compiletest/runtest.rs +++ b/src/compiletest/runtest.rs @@ -22,9 +22,7 @@ use util::logv; use std::cell::Cell; use std::rt::io; -use std::rt::io::Writer; -use std::rt::io::Reader; -use std::rt::io::file::FileInfo; +use std::rt::io::file; use std::os; use std::str; use std::task::{spawn_sched, SingleThreaded}; @@ -173,7 +171,7 @@ fn run_pretty_test(config: &config, props: &TestProps, testfile: &Path) { let rounds = match props.pp_exact { Some(_) => 1, None => 2 }; - let src = testfile.open_reader(io::Open).read_to_end(); + let src = file::open(testfile).read_to_end(); let src = str::from_utf8_owned(src); let mut srcs = ~[src]; @@ -195,7 +193,7 @@ fn run_pretty_test(config: &config, props: &TestProps, testfile: &Path) { let mut expected = match props.pp_exact { Some(ref file) => { let filepath = testfile.dir_path().join(file); - let s = filepath.open_reader(io::Open).read_to_end(); + let s = file::open(&filepath).read_to_end(); str::from_utf8_owned(s) } None => { srcs[srcs.len() - 2u].clone() } @@ -651,10 +649,8 @@ fn compose_and_run_compiler( } fn ensure_dir(path: &Path) { - if os::path_is_dir(path) { return; } - if !os::make_dir(path, 0x1c0i32) { - fail!("can't make dir {}", path.display()); - } + if path.is_dir() { return; } + file::mkdir(path, io::UserRWX); } fn compose_and_run(config: &config, testfile: &Path, @@ -768,7 +764,7 @@ fn dump_output(config: &config, testfile: &Path, out: &str, err: &str) { fn dump_output_file(config: &config, testfile: &Path, out: &str, extension: &str) { let outfile = make_out_name(config, testfile, extension); - outfile.open_writer(io::CreateOrTruncate).write(out.as_bytes()); + file::create(&outfile).write(out.as_bytes()); } fn make_out_name(config: &config, testfile: &Path, extension: &str) -> Path { @@ -924,7 +920,7 @@ fn _dummy_exec_compiled_test(config: &config, props: &TestProps, fn _arm_push_aux_shared_library(config: &config, testfile: &Path) { let tdir = aux_output_dir_name(config, testfile); - let dirs = os::list_dir_path(&tdir); + let dirs = file::readdir(&tdir); for file in dirs.iter() { if file.extension_str() == Some("so") { // FIXME (#9639): This needs to handle non-utf8 paths @@ -1019,7 +1015,7 @@ fn disassemble_extract(config: &config, _props: &TestProps, fn count_extracted_lines(p: &Path) -> uint { - let x = p.with_extension("ll").open_reader(io::Open).read_to_end(); + let x = file::open(&p.with_extension("ll")).read_to_end(); let x = str::from_utf8_owned(x); x.line_iter().len() } diff --git a/src/libextra/glob.rs b/src/libextra/glob.rs index 5297b48b0e156..a7742f771da3c 100644 --- a/src/libextra/glob.rs +++ b/src/libextra/glob.rs @@ -24,6 +24,8 @@ */ use std::{os, path}; +use std::rt::io; +use std::rt::io::file; use std::path::is_sep; use sort; @@ -146,9 +148,14 @@ impl Iterator for GlobIterator { } fn list_dir_sorted(path: &Path) -> ~[Path] { - let mut children = os::list_dir_path(path); - sort::quick_sort(children, |p1, p2| p2.filename().unwrap() <= p1.filename().unwrap()); - children + match io::result(|| file::readdir(path)) { + Ok(children) => { + let mut children = children; + sort::quick_sort(children, |p1, p2| p2.filename() <= p1.filename()); + children + } + Err(*) => ~[] + } } /** diff --git a/src/libextra/tempfile.rs b/src/libextra/tempfile.rs index d8fa130916a46..4affe7c1cde8a 100644 --- a/src/libextra/tempfile.rs +++ b/src/libextra/tempfile.rs @@ -14,6 +14,8 @@ use std::os; use std::rand::Rng; use std::rand; +use std::rt::io; +use std::rt::io::file; /// A wrapper for a path to temporary directory implementing automatic /// scope-pased deletion. @@ -36,8 +38,9 @@ impl TempDir { let mut r = rand::rng(); for _ in range(0u, 1000) { let p = tmpdir.join(r.gen_ascii_str(16) + suffix); - if os::make_dir(&p, 0x1c0) { // 700 - return Some(TempDir { path: Some(p) }); + match io::result(|| file::mkdir(&p, io::UserRWX)) { + Err(*) => {} + Ok(()) => return Some(TempDir { path: Some(p) }) } } None @@ -69,7 +72,9 @@ impl TempDir { impl Drop for TempDir { fn drop(&mut self) { for path in self.path.iter() { - os::remove_dir_recursive(path); + if path.exists() { + file::rmdir_recursive(path); + } } } } diff --git a/src/libextra/terminfo/searcher.rs b/src/libextra/terminfo/searcher.rs index 8dff53f14a159..c5509f8aec7d7 100644 --- a/src/libextra/terminfo/searcher.rs +++ b/src/libextra/terminfo/searcher.rs @@ -14,7 +14,7 @@ use std::{os, str}; use std::os::getenv; use std::rt::io; -use std::rt::io::file::FileInfo; +use std::rt::io::file; /// Return path to database entry for `term` pub fn get_dbpath_for_term(term: &str) -> Option<~Path> { @@ -56,16 +56,16 @@ pub fn get_dbpath_for_term(term: &str) -> Option<~Path> { // Look for the terminal in all of the search directories for p in dirs_to_search.iter() { - if os::path_exists(p) { + if p.exists() { let f = str::from_char(first_char); let newp = p.join_many([f.as_slice(), term]); - if os::path_exists(&newp) { + if newp.exists() { return Some(~newp); } // on some installations the dir is named after the hex of the char (e.g. OS X) let f = format!("{:x}", first_char as uint); let newp = p.join_many([f.as_slice(), term]); - if os::path_exists(&newp) { + if newp.exists() { return Some(~newp); } } @@ -76,7 +76,7 @@ pub fn get_dbpath_for_term(term: &str) -> Option<~Path> { /// Return open file for `term` pub fn open(term: &str) -> Result<@mut io::Reader, ~str> { match get_dbpath_for_term(term) { - Some(x) => Ok(@mut x.open_reader(io::Open).unwrap() as @mut io::Reader), + Some(x) => Ok(@mut file::open(x) as @mut io::Reader), None => Err(format!("could not find terminfo entry for {}", term)) } } diff --git a/src/libextra/test.rs b/src/libextra/test.rs index f262e6c60fb35..497d4206fe327 100644 --- a/src/libextra/test.rs +++ b/src/libextra/test.rs @@ -31,7 +31,7 @@ use treemap::TreeMap; use std::clone::Clone; use std::comm::{stream, SharedChan, GenericPort, GenericChan}; use std::rt::io; -use std::rt::io::file::FileInfo; +use std::rt::io::file; use std::task; use std::to_str::ToStr; use std::f64; @@ -353,10 +353,7 @@ struct ConsoleTestState { impl ConsoleTestState { pub fn new(opts: &TestOpts) -> ConsoleTestState { let log_out = match opts.logfile { - Some(ref path) => { - let out = path.open_writer(io::CreateOrTruncate); - Some(@mut out as @mut io::Writer) - }, + Some(ref path) => Some(@mut file::create(path) as @mut io::Writer), None => None }; let out = @mut io::stdio::stdout() as @mut io::Writer; @@ -938,16 +935,15 @@ impl MetricMap { /// Load MetricDiff from a file. pub fn load(p: &Path) -> MetricMap { - assert!(os::path_exists(p)); - let f = @mut p.open_reader(io::Open) as @mut io::Reader; + assert!(p.exists()); + let f = @mut file::open(p) as @mut io::Reader; let mut decoder = json::Decoder(json::from_reader(f).unwrap()); MetricMap(Decodable::decode(&mut decoder)) } /// Write MetricDiff to a file. pub fn save(&self, p: &Path) { - let f = @mut p.open_writer(io::CreateOrTruncate); - self.to_json().to_pretty_writer(f as @mut io::Writer); + self.to_json().to_pretty_writer(@mut file::create(p) as @mut io::Writer); } /// Compare against another MetricMap. Optionally compare all @@ -1032,7 +1028,7 @@ impl MetricMap { /// `MetricChange`s are `Regression`. Returns the diff as well /// as a boolean indicating whether the ratchet succeeded. pub fn ratchet(&self, p: &Path, pct: Option) -> (MetricDiff, bool) { - let old = if os::path_exists(p) { + let old = if p.exists() { MetricMap::load(p) } else { MetricMap::new() diff --git a/src/libextra/uuid.rs b/src/libextra/uuid.rs index b94b74a696cc2..54ce349a0b484 100644 --- a/src/libextra/uuid.rs +++ b/src/libextra/uuid.rs @@ -792,7 +792,6 @@ mod test { #[test] fn test_serialize_round_trip() { - use std; use ebml; use serialize::{Encodable, Decodable}; diff --git a/src/libextra/workcache.rs b/src/libextra/workcache.rs index 507962c0b1a2a..b2be4cf811b32 100644 --- a/src/libextra/workcache.rs +++ b/src/libextra/workcache.rs @@ -17,13 +17,11 @@ use arc::{Arc,RWArc}; use treemap::TreeMap; use std::cell::Cell; use std::comm::{PortOne, oneshot}; -use std::{os, str, task}; +use std::{str, task}; use std::rt::io; -use std::rt::io::Writer; -use std::rt::io::Reader; +use std::rt::io::file; use std::rt::io::Decorator; use std::rt::io::mem::MemWriter; -use std::rt::io::file::FileInfo; /** * @@ -145,7 +143,7 @@ impl Database { db_cache: TreeMap::new(), db_dirty: false }; - if os::path_exists(&rslt.db_filename) { + if rslt.db_filename.exists() { rslt.load(); } rslt @@ -178,19 +176,19 @@ impl Database { // FIXME #4330: This should have &mut self and should set self.db_dirty to false. fn save(&self) { - let f = @mut self.db_filename.open_writer(io::CreateOrTruncate); + let f = @mut file::create(&self.db_filename); self.db_cache.to_json().to_pretty_writer(f as @mut io::Writer); } fn load(&mut self) { assert!(!self.db_dirty); - assert!(os::path_exists(&self.db_filename)); - let f = self.db_filename.open_reader(io::Open); - match f { - None => fail!("Couldn't load workcache database {}", - self.db_filename.display()), - Some(r) => - match json::from_reader(@mut r as @mut io::Reader) { + assert!(self.db_filename.exists()); + match io::result(|| file::open(&self.db_filename)) { + Err(e) => fail!("Couldn't load workcache database {}: {}", + self.db_filename.display(), + e.desc), + Ok(r) => + match json::from_reader(@mut r.unwrap() as @mut io::Reader) { Err(e) => fail!("Couldn't parse workcache database (from file {}): {}", self.db_filename.display(), e.to_str()), Ok(r) => { @@ -482,23 +480,21 @@ impl<'self, T:Send + #[test] fn test() { use std::{os, run}; - use std::rt::io::Reader; + use std::rt::io::file; use std::str::from_utf8_owned; // Create a path to a new file 'filename' in the directory in which // this test is running. fn make_path(filename: ~str) -> Path { let pth = os::self_exe_path().expect("workcache::test failed").with_filename(filename); - if os::path_exists(&pth) { - os::remove_file(&pth); + if pth.exists() { + file::unlink(&pth); } return pth; } let pth = make_path(~"foo.c"); - { - pth.open_writer(io::Create).write(bytes!("int main() { return 0; }")); - } + file::create(&pth).write(bytes!("int main() { return 0; }")); let db_path = make_path(~"db.json"); @@ -511,7 +507,7 @@ fn test() { let subcx = cx.clone(); let pth = pth.clone(); - let file_content = from_utf8_owned(pth.open_reader(io::Open).read_to_end()); + let file_content = from_utf8_owned(file::open(&pth).read_to_end()); // FIXME (#9639): This needs to handle non-utf8 paths prep.declare_input("file", pth.as_str().unwrap(), file_content); diff --git a/src/librustc/back/link.rs b/src/librustc/back/link.rs index 815ec943c4962..7d044ba998fdb 100644 --- a/src/librustc/back/link.rs +++ b/src/librustc/back/link.rs @@ -27,12 +27,11 @@ use std::char; use std::hash::Streaming; use std::hash; use std::os::consts::{macos, freebsd, linux, android, win32}; -use std::os; use std::ptr; -use std::rt::io::Writer; use std::run; use std::str; use std::vec; +use std::rt::io::file; use syntax::ast; use syntax::ast_map::{path, path_mod, path_name, path_pretty_name}; use syntax::attr; @@ -951,20 +950,18 @@ pub fn link_binary(sess: Session, // Remove the temporary object file if we aren't saving temps if !sess.opts.save_temps { - if ! os::remove_file(obj_filename) { - sess.warn(format!("failed to delete object file `{}`", - obj_filename.display())); - } + file::unlink(obj_filename); } } fn is_writeable(p: &Path) -> bool { + use std::rt::io; use std::libc::consts::os::posix88::S_IWUSR; - !os::path_exists(p) || - (match p.get_mode() { - None => false, - Some(m) => m & S_IWUSR as uint == S_IWUSR as uint + !p.exists() || + (match io::result(|| p.stat()) { + Err(*) => false, + Ok(m) => (m.mode as uint) & S_IWUSR as uint == S_IWUSR as uint }) } diff --git a/src/librustc/driver/driver.rs b/src/librustc/driver/driver.rs index fb593b56e15f5..1526b5ad9c66a 100644 --- a/src/librustc/driver/driver.rs +++ b/src/librustc/driver/driver.rs @@ -27,6 +27,7 @@ use util::ppaux; use std::hashmap::{HashMap,HashSet}; use std::rt::io; +use std::rt::io::file; use std::rt::io::mem::MemReader; use std::os; use std::vec; @@ -369,7 +370,7 @@ pub fn phase_5_run_llvm_passes(sess: Session, // Remove assembly source unless --save-temps was specified if !sess.opts.save_temps { - os::remove_file(&asm_filename); + file::unlink(&asm_filename); } } else { time(sess.time_passes(), "LLVM passes", (), |_| diff --git a/src/librustc/metadata/filesearch.rs b/src/librustc/metadata/filesearch.rs index 94dfc006076f9..44e43bd4ef3a6 100644 --- a/src/librustc/metadata/filesearch.rs +++ b/src/librustc/metadata/filesearch.rs @@ -11,6 +11,8 @@ use std::option; use std::os; +use std::rt::io; +use std::rt::io::file; use std::hashmap::HashSet; pub enum FileMatch { FileMatches, FileDoesntMatch } @@ -117,22 +119,26 @@ pub fn mk_filesearch(maybe_sysroot: &Option<@Path>, pub fn search(filesearch: @FileSearch, pick: pick) { do filesearch.for_each_lib_search_path() |lib_search_path| { debug!("searching {}", lib_search_path.display()); - let r = os::list_dir_path(lib_search_path); - let mut rslt = FileDoesntMatch; - for path in r.iter() { - debug!("testing {}", path.display()); - let maybe_picked = pick(path); - match maybe_picked { - FileMatches => { - debug!("picked {}", path.display()); - rslt = FileMatches; - } - FileDoesntMatch => { - debug!("rejected {}", path.display()); + match io::result(|| file::readdir(lib_search_path)) { + Ok(files) => { + let mut rslt = FileDoesntMatch; + for path in files.iter() { + debug!("testing {}", path.display()); + let maybe_picked = pick(path); + match maybe_picked { + FileMatches => { + debug!("picked {}", path.display()); + rslt = FileMatches; + } + FileDoesntMatch => { + debug!("rejected {}", path.display()); + } + } } + rslt } + Err(*) => FileDoesntMatch, } - rslt }; } @@ -210,7 +216,7 @@ pub fn rust_path() -> ~[Path] { break } cwd.set_filename(".rust"); - if !env_rust_path.contains(&cwd) && os::path_exists(&cwd) { + if !env_rust_path.contains(&cwd) && cwd.exists() { env_rust_path.push(cwd.clone()); } cwd.pop(); @@ -218,7 +224,7 @@ pub fn rust_path() -> ~[Path] { let h = os::homedir(); for h in h.iter() { let p = h.join(".rust"); - if !env_rust_path.contains(&p) && os::path_exists(&p) { + if !env_rust_path.contains(&p) && p.exists() { env_rust_path.push(p); } } diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 7bfe0910252be..fd7ba7c045277 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -40,10 +40,8 @@ use std::fmt; use std::hashmap::{HashMap, HashSet}; use std::local_data; use std::rt::io::buffered::BufferedWriter; -use std::rt::io::file::{FileInfo, DirectoryInfo}; -use std::rt::io::file; use std::rt::io; -use std::rt::io::Reader; +use std::rt::io::file; use std::os; use std::str; use std::task; @@ -265,8 +263,8 @@ pub fn run(mut crate: clean::Crate, dst: Path) { // Publish the search index { dst.push("search-index.js"); - let mut w = BufferedWriter::new(dst.open_writer(io::CreateOrTruncate)); - let w = &mut w as &mut io::Writer; + let mut w = BufferedWriter::new(file::create(&dst).unwrap()); + let w = &mut w as &mut Writer; write!(w, "var searchIndex = ["); for (i, item) in cache.search_index.iter().enumerate() { if i > 0 { write!(w, ","); } @@ -315,8 +313,7 @@ pub fn run(mut crate: clean::Crate, dst: Path) { /// Writes the entire contents of a string to a destination, not attempting to /// catch any errors. fn write(dst: Path, contents: &str) { - let mut w = dst.open_writer(io::CreateOrTruncate); - w.write(contents.as_bytes()); + file::create(&dst).write(contents.as_bytes()); } /// Makes a directory on the filesystem, failing the task if an error occurs and @@ -328,7 +325,7 @@ fn mkdir(path: &Path) { fail!() }).inside { if !path.is_dir() { - file::mkdir(path); + file::mkdir(path, io::UserRWX); } } } @@ -419,16 +416,13 @@ impl<'self> SourceCollector<'self> { let mut contents = ~[]; { let mut buf = [0, ..1024]; - let r = do io::io_error::cond.trap(|_| {}).inside { - p.open_reader(io::Open) - }; // If we couldn't open this file, then just returns because it // probably means that it's some standard library macro thing and we // can't have the source to it anyway. - let mut r = match r { - Some(r) => r, + let mut r = match io::result(|| file::open(&p)) { + Ok(r) => r, // eew macro hacks - None => return filename == "" + Err(*) => return filename == "" }; // read everything @@ -451,8 +445,7 @@ impl<'self> SourceCollector<'self> { } cur.push(p.filename().expect("source has no filename") + bytes!(".html")); - let w = cur.open_writer(io::CreateOrTruncate); - let mut w = BufferedWriter::new(w); + let mut w = BufferedWriter::new(file::create(&cur).unwrap()); let title = cur.filename_display().with_str(|s| format!("{} -- source", s)); let page = layout::Page { @@ -460,7 +453,7 @@ impl<'self> SourceCollector<'self> { ty: "source", root_path: root_path, }; - layout::render(&mut w as &mut io::Writer, &self.cx.layout, + layout::render(&mut w as &mut Writer, &self.cx.layout, &page, &(""), &Source(contents.as_slice())); w.flush(); return true; @@ -774,7 +767,7 @@ impl Context { /// /// The rendering driver uses this closure to queue up more work. fn item(&mut self, item: clean::Item, f: &fn(&mut Context, clean::Item)) { - fn render(w: io::file::FileWriter, cx: &mut Context, it: &clean::Item, + fn render(w: file::FileWriter, cx: &mut Context, it: &clean::Item, pushname: bool) { // A little unfortunate that this is done like this, but it sure // does make formatting *a lot* nicer. @@ -796,7 +789,7 @@ impl Context { // of the pain by using a buffered writer instead of invoking the // write sycall all the time. let mut writer = BufferedWriter::new(w); - layout::render(&mut writer as &mut io::Writer, &cx.layout, &page, + layout::render(&mut writer as &mut Writer, &cx.layout, &page, &Sidebar{ cx: cx, item: it }, &Item{ cx: cx, item: it }); writer.flush(); @@ -811,8 +804,7 @@ impl Context { do self.recurse(name) |this| { let item = item.take(); let dst = this.dst.join("index.html"); - let writer = dst.open_writer(io::CreateOrTruncate); - render(writer.unwrap(), this, &item, false); + render(file::create(&dst).unwrap(), this, &item, false); let m = match item.inner { clean::ModuleItem(m) => m, @@ -829,8 +821,7 @@ impl Context { // pages dedicated to them. _ if item.name.is_some() => { let dst = self.dst.join(item_path(&item)); - let writer = dst.open_writer(io::CreateOrTruncate); - render(writer.unwrap(), self, &item, true); + render(file::create(&dst).unwrap(), self, &item, true); } _ => {} @@ -967,7 +958,7 @@ fn shorter<'a>(s: Option<&'a str>) -> &'a str { } } -fn document(w: &mut io::Writer, item: &clean::Item) { +fn document(w: &mut Writer, item: &clean::Item) { match item.doc_value() { Some(s) => { write!(w, "
{}
", Markdown(s)); @@ -976,7 +967,7 @@ fn document(w: &mut io::Writer, item: &clean::Item) { } } -fn item_module(w: &mut io::Writer, cx: &Context, +fn item_module(w: &mut Writer, cx: &Context, item: &clean::Item, items: &[clean::Item]) { document(w, item); debug!("{:?}", items); @@ -1123,7 +1114,7 @@ fn item_module(w: &mut io::Writer, cx: &Context, write!(w, ""); } -fn item_function(w: &mut io::Writer, it: &clean::Item, f: &clean::Function) { +fn item_function(w: &mut Writer, it: &clean::Item, f: &clean::Function) { write!(w, "
{vis}{purity}fn {name}{generics}{decl}
", vis = VisSpace(it.visibility), purity = PuritySpace(f.purity), @@ -1133,7 +1124,7 @@ fn item_function(w: &mut io::Writer, it: &clean::Item, f: &clean::Function) { document(w, it); } -fn item_trait(w: &mut io::Writer, it: &clean::Item, t: &clean::Trait) { +fn item_trait(w: &mut Writer, it: &clean::Item, t: &clean::Trait) { let mut parents = ~""; if t.parents.len() > 0 { parents.push_str(": "); @@ -1176,7 +1167,7 @@ fn item_trait(w: &mut io::Writer, it: &clean::Item, t: &clean::Trait) { // Trait documentation document(w, it); - fn meth(w: &mut io::Writer, m: &clean::TraitMethod) { + fn meth(w: &mut Writer, m: &clean::TraitMethod) { write!(w, "

", shortty(m.item()), *m.item().name.get_ref()); @@ -1234,8 +1225,8 @@ fn item_trait(w: &mut io::Writer, it: &clean::Item, t: &clean::Trait) { } } -fn render_method(w: &mut io::Writer, meth: &clean::Item, withlink: bool) { - fn fun(w: &mut io::Writer, it: &clean::Item, purity: ast::purity, +fn render_method(w: &mut Writer, meth: &clean::Item, withlink: bool) { + fn fun(w: &mut Writer, it: &clean::Item, purity: ast::purity, g: &clean::Generics, selfty: &clean::SelfTy, d: &clean::FnDecl, withlink: bool) { write!(w, "{}fn {withlink, select, @@ -1264,7 +1255,7 @@ fn render_method(w: &mut io::Writer, meth: &clean::Item, withlink: bool) { } } -fn item_struct(w: &mut io::Writer, it: &clean::Item, s: &clean::Struct) { +fn item_struct(w: &mut Writer, it: &clean::Item, s: &clean::Struct) { write!(w, "
");
     render_struct(w, it, Some(&s.generics), s.struct_type, s.fields,
                   s.fields_stripped, "", true);
@@ -1288,7 +1279,7 @@ fn item_struct(w: &mut io::Writer, it: &clean::Item, s: &clean::Struct) {
     render_methods(w, it);
 }
 
-fn item_enum(w: &mut io::Writer, it: &clean::Item, e: &clean::Enum) {
+fn item_enum(w: &mut Writer, it: &clean::Item, e: &clean::Enum) {
     write!(w, "
{}enum {}{}",
            VisSpace(it.visibility),
            it.name.get_ref().as_slice(),
@@ -1365,7 +1356,7 @@ fn item_enum(w: &mut io::Writer, it: &clean::Item, e: &clean::Enum) {
     render_methods(w, it);
 }
 
-fn render_struct(w: &mut io::Writer, it: &clean::Item,
+fn render_struct(w: &mut Writer, it: &clean::Item,
                  g: Option<&clean::Generics>,
                  ty: doctree::StructType,
                  fields: &[clean::Item],
@@ -1418,7 +1409,7 @@ fn render_struct(w: &mut io::Writer, it: &clean::Item,
     }
 }
 
-fn render_methods(w: &mut io::Writer, it: &clean::Item) {
+fn render_methods(w: &mut Writer, it: &clean::Item) {
     do local_data::get(cache_key) |cache| {
         let cache = cache.unwrap();
         do cache.read |c| {
@@ -1453,7 +1444,7 @@ fn render_methods(w: &mut io::Writer, it: &clean::Item) {
     }
 }
 
-fn render_impl(w: &mut io::Writer, i: &clean::Impl, dox: &Option<~str>) {
+fn render_impl(w: &mut Writer, i: &clean::Impl, dox: &Option<~str>) {
     write!(w, "

impl{} ", i.generics); let trait_id = match i.trait_ { Some(ref ty) => { @@ -1474,7 +1465,7 @@ fn render_impl(w: &mut io::Writer, i: &clean::Impl, dox: &Option<~str>) { None => {} } - fn docmeth(w: &mut io::Writer, item: &clean::Item) -> bool { + fn docmeth(w: &mut Writer, item: &clean::Item) -> bool { write!(w, "

", *item.name.get_ref()); render_method(w, item, false); @@ -1552,7 +1543,7 @@ fn render_impl(w: &mut io::Writer, i: &clean::Impl, dox: &Option<~str>) { write!(w, ""); } -fn item_typedef(w: &mut io::Writer, it: &clean::Item, t: &clean::Typedef) { +fn item_typedef(w: &mut Writer, it: &clean::Item, t: &clean::Typedef) { write!(w, "
type {}{} = {};
", it.name.get_ref().as_slice(), t.generics, @@ -1574,7 +1565,7 @@ impl<'self> fmt::Default for Sidebar<'self> { } write!(fmt.buf, "

"); - fn block(w: &mut io::Writer, short: &str, longty: &str, + fn block(w: &mut Writer, short: &str, longty: &str, cur: &clean::Item, cx: &Context) { let items = match cx.sidebar.find_equiv(&short) { Some(items) => items.as_slice(), diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 770d535c6ea9e..7a64ca6d6fc2a 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -25,9 +25,8 @@ extern mod extra; use std::cell::Cell; use std::local_data; -use std::rt::io::Writer; -use std::rt::io::file::FileInfo; use std::rt::io; +use std::rt::io::file; use std::rt::io::mem::MemWriter; use std::rt::io::Decorator; use std::str; @@ -260,7 +259,7 @@ fn rust_input(cratefile: &str, matches: &getopts::Matches) -> Output { /// This input format purely deserializes the json output file. No passes are /// run over the deserialized output. fn json_input(input: &str) -> Result { - let input = match Path::new(input).open_reader(io::Open) { + let input = match file::open(&Path::new(input)) { Some(f) => f, None => return Err(format!("couldn't open {} for reading", input)), }; @@ -322,7 +321,7 @@ fn json_output(crate: clean::Crate, res: ~[plugins::PluginJson], dst: Path) { json.insert(~"crate", crate_json); json.insert(~"plugins", json::Object(plugins_json)); - let mut file = dst.open_writer(io::Create).unwrap(); + let mut file = file::create(&dst).unwrap(); let output = json::Object(json).to_str(); file.write(output.as_bytes()); } diff --git a/src/librustpkg/api.rs b/src/librustpkg/api.rs index c67b6f52c7e39..c0ffd66d22e43 100644 --- a/src/librustpkg/api.rs +++ b/src/librustpkg/api.rs @@ -21,7 +21,7 @@ pub use path_util::default_workspace; pub use source_control::{safe_git_clone, git_clone_url}; -use std::{os, run}; +use std::run; use extra::arc::{Arc,RWArc}; use extra::workcache; use extra::workcache::{Database, Logger, FreshnessMap}; @@ -57,12 +57,12 @@ pub fn new_default_context(c: workcache::Context, p: Path) -> BuildContext { fn file_is_fresh(path: &str, in_hash: &str) -> bool { let path = Path::new(path); - os::path_exists(&path) && in_hash == digest_file_with_date(&path) + path.exists() && in_hash == digest_file_with_date(&path) } fn binary_is_fresh(path: &str, in_hash: &str) -> bool { let path = Path::new(path); - os::path_exists(&path) && in_hash == digest_only_date(&path) + path.exists() && in_hash == digest_only_date(&path) } pub fn new_workcache_context(p: &Path) -> workcache::Context { diff --git a/src/librustpkg/context.rs b/src/librustpkg/context.rs index 77fe2ae8f704b..0ae08731546f1 100644 --- a/src/librustpkg/context.rs +++ b/src/librustpkg/context.rs @@ -14,7 +14,6 @@ use extra::workcache; use rustc::driver::session::{OptLevel, No}; use std::hashmap::HashSet; -use std::os; #[deriving(Clone)] pub struct Context { @@ -176,7 +175,7 @@ pub fn in_target(sysroot: &Path) -> bool { debug!("Checking whether {} is in target", sysroot.display()); let mut p = sysroot.dir_path(); p.set_filename("rustc"); - os::path_is_dir(&p) + p.is_dir() } impl RustcFlags { diff --git a/src/librustpkg/installed_packages.rs b/src/librustpkg/installed_packages.rs index 767a31ed78563..09b58e6e94cce 100644 --- a/src/librustpkg/installed_packages.rs +++ b/src/librustpkg/installed_packages.rs @@ -13,11 +13,13 @@ use rustc::metadata::filesearch::rust_path; use path_util::*; use std::os; +use std::rt::io; +use std::rt::io::file; pub fn list_installed_packages(f: &fn(&PkgId) -> bool) -> bool { let workspaces = rust_path(); for p in workspaces.iter() { - let binfiles = os::list_dir(&p.join("bin")); + let binfiles = do io::ignore_io_error { file::readdir(&p.join("bin")) }; for exec in binfiles.iter() { // FIXME (#9639): This needs to handle non-utf8 paths match exec.filestem_str() { @@ -29,7 +31,7 @@ pub fn list_installed_packages(f: &fn(&PkgId) -> bool) -> bool { } } } - let libfiles = os::list_dir(&p.join("lib")); + let libfiles = do io::ignore_io_error { file::readdir(&p.join("lib")) }; for lib in libfiles.iter() { debug!("Full name: {}", lib.display()); match has_library(lib) { @@ -53,7 +55,7 @@ pub fn list_installed_packages(f: &fn(&PkgId) -> bool) -> bool { } pub fn has_library(p: &Path) -> Option<~str> { - let files = os::list_dir(p); + let files = do io::ignore_io_error { file::readdir(p) }; for path in files.iter() { if path.extension_str() == Some(os::consts::DLL_EXTENSION) { let stuff : &str = path.filestem_str().expect("has_library: weird path"); diff --git a/src/librustpkg/lib.rs b/src/librustpkg/lib.rs index 517d43432eccf..bb6088adee18e 100644 --- a/src/librustpkg/lib.rs +++ b/src/librustpkg/lib.rs @@ -26,6 +26,8 @@ extern mod syntax; use std::{os, result, run, str, task}; use std::hashmap::HashSet; +use std::rt::io; +use std::rt::io::file; pub use std::path::Path; use extra::workcache; @@ -36,7 +38,7 @@ use extra::{getopts}; use syntax::{ast, diagnostic}; use messages::{error, warn, note}; use path_util::{build_pkg_id_in_workspace, built_test_in_workspace}; -use path_util::{U_RWX, in_rust_path}; +use path_util::in_rust_path; use path_util::{built_executable_in_workspace, built_library_in_workspace, default_workspace}; use path_util::{target_executable_in_workspace, target_library_in_workspace, dir_has_crate_file}; use source_control::{CheckedOutSources, is_git_dir, make_read_only}; @@ -513,7 +515,7 @@ impl CtxMethods for BuildContext { // We expect that p is relative to the package source's start directory, // so check that assumption debug!("JustOne: p = {}", p.display()); - assert!(os::path_exists(&pkg_src.start_dir.join(p))); + assert!(pkg_src.start_dir.join(p).exists()); if is_lib(p) { PkgSrc::push_crate(&mut pkg_src.libs, 0, p); } else if is_main(p) { @@ -541,8 +543,8 @@ impl CtxMethods for BuildContext { let dir = build_pkg_id_in_workspace(id, workspace); note(format!("Cleaning package {} (removing directory {})", id.to_str(), dir.display())); - if os::path_exists(&dir) { - os::remove_dir_recursive(&dir); + if dir.exists() { + file::rmdir_recursive(&dir); note(format!("Removed directory {}", dir.display())); } @@ -600,7 +602,6 @@ impl CtxMethods for BuildContext { build_inputs: &[Path], target_workspace: &Path, id: &PkgId) -> ~[~str] { - use conditions::copy_failed::cond; debug!("install_no_build: assuming {} comes from {} with target {}", id.to_str(), build_workspace.display(), target_workspace.display()); @@ -659,10 +660,8 @@ impl CtxMethods for BuildContext { for exec in subex.iter() { debug!("Copying: {} -> {}", exec.display(), sub_target_ex.display()); - if !(os::mkdir_recursive(&sub_target_ex.dir_path(), U_RWX) && - os::copy_file(exec, &sub_target_ex)) { - cond.raise(((*exec).clone(), sub_target_ex.clone())); - } + file::mkdir_recursive(&sub_target_ex.dir_path(), io::UserRWX); + file::copy(exec, &sub_target_ex); // FIXME (#9639): This needs to handle non-utf8 paths exe_thing.discover_output("binary", sub_target_ex.as_str().unwrap(), @@ -674,10 +673,8 @@ impl CtxMethods for BuildContext { .clone().expect(format!("I built {} but apparently \ didn't install it!", lib.display())); target_lib.set_filename(lib.filename().expect("weird target lib")); - if !(os::mkdir_recursive(&target_lib.dir_path(), U_RWX) && - os::copy_file(lib, &target_lib)) { - cond.raise(((*lib).clone(), target_lib.clone())); - } + file::mkdir_recursive(&target_lib.dir_path(), io::UserRWX); + file::copy(lib, &target_lib); debug!("3. discovering output {}", target_lib.display()); exe_thing.discover_output("binary", target_lib.as_str().unwrap(), @@ -710,10 +707,10 @@ impl CtxMethods for BuildContext { } fn init(&self) { - os::mkdir_recursive(&Path::new("src"), U_RWX); - os::mkdir_recursive(&Path::new("lib"), U_RWX); - os::mkdir_recursive(&Path::new("bin"), U_RWX); - os::mkdir_recursive(&Path::new("build"), U_RWX); + file::mkdir_recursive(&Path::new("src"), io::UserRWX); + file::mkdir_recursive(&Path::new("bin"), io::UserRWX); + file::mkdir_recursive(&Path::new("lib"), io::UserRWX); + file::mkdir_recursive(&Path::new("build"), io::UserRWX); } fn uninstall(&self, _id: &str, _vers: Option<~str>) { diff --git a/src/librustpkg/package_id.rs b/src/librustpkg/package_id.rs index 0fc614d7f3ce8..0da343a27bfca 100644 --- a/src/librustpkg/package_id.rs +++ b/src/librustpkg/package_id.rs @@ -10,7 +10,6 @@ use version::{try_getting_version, try_getting_local_version, Version, NoVersion, split_version}; -use std::rt::io::Writer; use std::hash::Streaming; use std::hash; diff --git a/src/librustpkg/package_source.rs b/src/librustpkg/package_source.rs index 797ea3372ccfd..a52aa68e1e471 100644 --- a/src/librustpkg/package_source.rs +++ b/src/librustpkg/package_source.rs @@ -12,7 +12,8 @@ extern mod extra; use target::*; use package_id::PkgId; -use std::path::Path; +use std::rt::io; +use std::rt::io::file; use std::os; use context::*; use crate::Crate; @@ -117,7 +118,7 @@ impl PkgSrc { debug!("Checking dirs: {:?}", to_try.map(|p| p.display().to_str()).connect(":")); - let path = to_try.iter().find(|&d| os::path_exists(d)); + let path = to_try.iter().find(|&d| d.exists()); // See the comments on the definition of PkgSrc let mut build_in_destination = use_rust_path_hack; @@ -132,7 +133,7 @@ impl PkgSrc { let package_id = PkgId::new(prefix.as_str().unwrap()); let path = build_dir.join(&package_id.path); debug!("in loop: checking if {} is a directory", path.display()); - if os::path_is_dir(&path) { + if path.is_dir() { let ps = PkgSrc::new(source_workspace, destination_workspace, use_rust_path_hack, @@ -237,7 +238,7 @@ impl PkgSrc { debug!("For package id {}, returning {}", id.to_str(), dir.display()); - if !os::path_is_dir(&dir) { + if !dir.is_dir() { cond.raise((id.clone(), ~"supplied path for package dir is a \ non-directory")); } @@ -267,7 +268,7 @@ impl PkgSrc { debug!("Checking whether {} (path = {}) exists locally. Cwd = {}, does it? {:?}", pkgid.to_str(), pkgid.path.display(), cwd.display(), - os::path_exists(&pkgid.path)); + pkgid.path.exists()); match safe_git_clone(&pkgid.path, &pkgid.version, local) { CheckedOutSources => { @@ -300,7 +301,7 @@ impl PkgSrc { // Move clone_target to local. // First, create all ancestor directories. let moved = make_dir_rwx_recursive(&local.dir_path()) - && os::rename_file(&clone_target, local); + && io::result(|| file::rename(&clone_target, local)).is_ok(); if moved { Some(local.clone()) } else { None } } @@ -312,7 +313,7 @@ impl PkgSrc { pub fn package_script_option(&self) -> Option { let maybe_path = self.start_dir.join("pkg.rs"); debug!("package_script_option: checking whether {} exists", maybe_path.display()); - if os::path_exists(&maybe_path) { + if maybe_path.exists() { Some(maybe_path) } else { None @@ -349,7 +350,7 @@ impl PkgSrc { let prefix = self.start_dir.component_iter().len(); debug!("Matching against {}", self.id.short_name); - do os::walk_dir(&self.start_dir) |pth| { + do file::walk_dir(&self.start_dir) |pth| { let maybe_known_crate_set = match pth.filename_str() { Some(filename) if filter(filename) => match filename { "lib.rs" => Some(&mut self.libs), diff --git a/src/librustpkg/path_util.rs b/src/librustpkg/path_util.rs index a48ef23115ccf..75f03533d583c 100644 --- a/src/librustpkg/path_util.rs +++ b/src/librustpkg/path_util.rs @@ -18,8 +18,9 @@ use rustc::driver::driver::host_triple; use std::libc; use std::libc::consts::os::posix88::{S_IRUSR, S_IWUSR, S_IXUSR}; -use std::os::mkdir_recursive; use std::os; +use std::rt::io; +use std::rt::io::file; use messages::*; pub fn default_workspace() -> Path { @@ -28,8 +29,8 @@ pub fn default_workspace() -> Path { fail!("Empty RUST_PATH"); } let result = p[0]; - if !os::path_is_dir(&result) { - os::mkdir_recursive(&result, U_RWX); + if !result.is_dir() { + file::mkdir_recursive(&result, io::UserRWX); } result } @@ -43,9 +44,13 @@ pub static U_RWX: i32 = (S_IRUSR | S_IWUSR | S_IXUSR) as i32; /// Creates a directory that is readable, writeable, /// and executable by the user. Returns true iff creation /// succeeded. -pub fn make_dir_rwx(p: &Path) -> bool { os::make_dir(p, U_RWX) } +pub fn make_dir_rwx(p: &Path) -> bool { + io::result(|| file::mkdir(p, io::UserRWX)).is_ok() +} -pub fn make_dir_rwx_recursive(p: &Path) -> bool { os::mkdir_recursive(p, U_RWX) } +pub fn make_dir_rwx_recursive(p: &Path) -> bool { + io::result(|| file::mkdir_recursive(p, io::UserRWX)).is_ok() +} // n.b. The next three functions ignore the package version right // now. Should fix that. @@ -59,15 +64,16 @@ pub fn workspace_contains_package_id(pkgid: &PkgId, workspace: &Path) -> bool { pub fn workspace_contains_package_id_(pkgid: &PkgId, workspace: &Path, // Returns the directory it was actually found in workspace_to_src_dir: &fn(&Path) -> Path) -> Option { - if !os::path_is_dir(workspace) { + if !workspace.is_dir() { return None; } let src_dir = workspace_to_src_dir(workspace); + if !src_dir.is_dir() { return None } let mut found = None; - do os::walk_dir(&src_dir) |p| { - if os::path_is_dir(p) { + do file::walk_dir(&src_dir) |p| { + if p.is_dir() { if *p == src_dir.join(&pkgid.path) || { let pf = p.filename_str(); do pf.iter().any |&g| { @@ -125,7 +131,7 @@ pub fn built_executable_in_workspace(pkgid: &PkgId, workspace: &Path) -> Option< result = mk_output_path(Main, Build, pkgid, result); debug!("built_executable_in_workspace: checking whether {} exists", result.display()); - if os::path_exists(&result) { + if result.exists() { Some(result) } else { @@ -152,7 +158,7 @@ fn output_in_workspace(pkgid: &PkgId, workspace: &Path, what: OutputType) -> Opt result = mk_output_path(what, Build, pkgid, result); debug!("output_in_workspace: checking whether {} exists", result.display()); - if os::path_exists(&result) { + if result.exists() { Some(result) } else { @@ -210,7 +216,7 @@ pub fn system_library(sysroot: &Path, lib_name: &str) -> Option { fn library_in(short_name: &str, version: &Version, dir_to_search: &Path) -> Option { debug!("Listing directory {}", dir_to_search.display()); - let dir_contents = os::list_dir(dir_to_search); + let dir_contents = do io::ignore_io_error { file::readdir(dir_to_search) }; debug!("dir has {:?} entries", dir_contents.len()); let lib_prefix = format!("{}{}", os::consts::DLL_PREFIX, short_name); @@ -294,7 +300,7 @@ pub fn target_executable_in_workspace(pkgid: &PkgId, workspace: &Path) -> Path { /// As a side effect, creates the lib-dir if it doesn't exist pub fn target_library_in_workspace(pkgid: &PkgId, workspace: &Path) -> Path { use conditions::bad_path::cond; - if !os::path_is_dir(workspace) { + if !workspace.is_dir() { cond.raise(((*workspace).clone(), format!("Workspace supplied to target_library_in_workspace \ is not a directory! {}", workspace.display()))); @@ -333,7 +339,7 @@ fn target_file_in_workspace(pkgid: &PkgId, workspace: &Path, (Install, Lib) => target_lib_dir(workspace), (Install, _) => target_bin_dir(workspace) }; - if !os::path_exists(&result) && !mkdir_recursive(&result, U_RWX) { + if io::result(|| file::mkdir_recursive(&result, io::UserRWX)).is_err() { cond.raise((result.clone(), format!("target_file_in_workspace couldn't \ create the {} dir (pkgid={}, workspace={}, what={:?}, where={:?}", subdir, pkgid.to_str(), workspace.display(), what, where))); @@ -344,18 +350,12 @@ fn target_file_in_workspace(pkgid: &PkgId, workspace: &Path, /// Return the directory for 's build artifacts in . /// Creates it if it doesn't exist. pub fn build_pkg_id_in_workspace(pkgid: &PkgId, workspace: &Path) -> Path { - use conditions::bad_path::cond; - let mut result = target_build_dir(workspace); result.push(&pkgid.path); debug!("Creating build dir {} for package id {}", result.display(), pkgid.to_str()); - if os::path_exists(&result) || os::mkdir_recursive(&result, U_RWX) { - result - } - else { - cond.raise((result, format!("Could not create directory for package {}", pkgid.to_str()))) - } + file::mkdir_recursive(&result, io::UserRWX); + return result; } /// Return the output file for a given directory name, @@ -398,13 +398,13 @@ pub fn mk_output_path(what: OutputType, where: Target, pub fn uninstall_package_from(workspace: &Path, pkgid: &PkgId) { let mut did_something = false; let installed_bin = target_executable_in_workspace(pkgid, workspace); - if os::path_exists(&installed_bin) { - os::remove_file(&installed_bin); + if installed_bin.exists() { + file::unlink(&installed_bin); did_something = true; } let installed_lib = target_library_in_workspace(pkgid, workspace); - if os::path_exists(&installed_lib) { - os::remove_file(&installed_lib); + if installed_lib.exists() { + file::unlink(&installed_lib); did_something = true; } if !did_something { @@ -421,7 +421,7 @@ pub fn dir_has_crate_file(dir: &Path) -> bool { fn dir_has_file(dir: &Path, file: &str) -> bool { assert!(dir.is_absolute()); - os::path_exists(&dir.join(file)) + dir.join(file).exists() } pub fn find_dir_using_rust_path_hack(p: &PkgId) -> Option { diff --git a/src/librustpkg/source_control.rs b/src/librustpkg/source_control.rs index c3e4205dfc972..a0e50ff0f9ef7 100644 --- a/src/librustpkg/source_control.rs +++ b/src/librustpkg/source_control.rs @@ -10,8 +10,9 @@ // Utils for working with version control repositories. Just git right now. -use std::{os, run, str}; +use std::{run, str}; use std::run::{ProcessOutput, ProcessOptions, Process}; +use std::rt::io::file; use extra::tempfile::TempDir; use version::*; use path_util::chmod_read_only; @@ -22,14 +23,14 @@ use path_util::chmod_read_only; /// directory (that the callee may use, for example, to check out remote sources into). /// Returns `CheckedOutSources` if the clone succeeded. pub fn safe_git_clone(source: &Path, v: &Version, target: &Path) -> CloneResult { - if os::path_exists(source) { + if source.exists() { debug!("{} exists locally! Cloning it into {}", source.display(), target.display()); // Ok to use target here; we know it will succeed - assert!(os::path_is_dir(source)); + assert!(source.is_dir()); assert!(is_git_dir(source)); - if !os::path_exists(target) { + if !target.exists() { debug!("Running: git clone {} {}", source.display(), target.display()); // FIXME (#9639): This needs to handle non-utf8 paths let outp = run::process_output("git", [~"clone", @@ -95,8 +96,8 @@ pub enum CloneResult { pub fn make_read_only(target: &Path) { // Now, make all the files in the target dir read-only - do os::walk_dir(target) |p| { - if !os::path_is_dir(p) { + do file::walk_dir(target) |p| { + if !p.is_dir() { assert!(chmod_read_only(p)); }; true @@ -138,5 +139,5 @@ fn process_output_in_cwd(prog: &str, args: &[~str], cwd: &Path) -> ProcessOutput } pub fn is_git_dir(p: &Path) -> bool { - os::path_is_dir(&p.join(".git")) + p.join(".git").is_dir() } diff --git a/src/librustpkg/tests.rs b/src/librustpkg/tests.rs index 8f1b269f1caac..60e99f242ef14 100644 --- a/src/librustpkg/tests.rs +++ b/src/librustpkg/tests.rs @@ -13,8 +13,7 @@ use context::{BuildContext, Context, RustcFlags}; use std::{os, run, str, task}; use std::rt::io; -use std::rt::io::Writer; -use std::rt::io::file::FileInfo; +use std::rt::io::file; use extra::arc::Arc; use extra::arc::RWArc; use extra::tempfile::TempDir; @@ -27,7 +26,7 @@ use installed_packages::list_installed_packages; use package_id::{PkgId}; use version::{ExactRevision, NoVersion, Version, Tagged}; use path_util::{target_executable_in_workspace, target_test_in_workspace, - target_bench_in_workspace, make_dir_rwx, U_RWX, + target_bench_in_workspace, make_dir_rwx, library_in_workspace, installed_library_in_workspace, built_bench_in_workspace, built_test_in_workspace, built_library_in_workspace, built_executable_in_workspace, target_build_dir, @@ -84,7 +83,7 @@ fn git_repo_pkg_with_tag(a_tag: ~str) -> PkgId { } fn writeFile(file_path: &Path, contents: &str) { - let mut out = file_path.open_writer(io::CreateOrTruncate); + let mut out = file::create(file_path); out.write(contents.as_bytes()); out.write(['\n' as u8]); } @@ -92,7 +91,7 @@ fn writeFile(file_path: &Path, contents: &str) { fn mk_emptier_workspace(tag: &str) -> TempDir { let workspace = TempDir::new(tag).expect("couldn't create temp dir"); let package_dir = workspace.path().join("src"); - assert!(os::mkdir_recursive(&package_dir, U_RWX)); + file::mkdir_recursive(&package_dir, io::UserRWX); workspace } @@ -107,7 +106,7 @@ fn mk_workspace(workspace: &Path, short_name: &Path, version: &Version) -> Path // FIXME (#9639): This needs to handle non-utf8 paths let package_dir = workspace.join_many([~"src", format!("{}-{}", short_name.as_str().unwrap(), version.to_str())]); - assert!(os::mkdir_recursive(&package_dir, U_RWX)); + file::mkdir_recursive(&package_dir, io::UserRWX); package_dir } @@ -120,12 +119,12 @@ fn mk_temp_workspace(short_name: &Path, version: &Version) -> (TempDir, Path) { version.to_str())]); debug!("Created {} and does it exist? {:?}", package_dir.display(), - os::path_is_dir(&package_dir)); + package_dir.is_dir()); // Create main, lib, test, and bench files debug!("mk_workspace: creating {}", package_dir.display()); - assert!(os::mkdir_recursive(&package_dir, U_RWX)); + file::mkdir_recursive(&package_dir, io::UserRWX); debug!("Created {} and does it exist? {:?}", package_dir.display(), - os::path_is_dir(&package_dir)); + package_dir.is_dir()); // Create main, lib, test, and bench files writeFile(&package_dir.join("main.rs"), @@ -162,7 +161,7 @@ fn init_git_repo(p: &Path) -> TempDir { let tmp = TempDir::new("git_local").expect("couldn't create temp dir"); let work_dir = tmp.path().join(p); let work_dir_for_opts = work_dir.clone(); - assert!(os::mkdir_recursive(&work_dir, U_RWX)); + file::mkdir_recursive(&work_dir, io::UserRWX); debug!("Running: git init in {}", work_dir.display()); run_git([~"init"], None, &work_dir_for_opts, format!("Couldn't initialize git repository in {}", work_dir.display())); @@ -199,25 +198,21 @@ fn add_git_tag(repo: &Path, tag: ~str) { fn is_rwx(p: &Path) -> bool { use std::libc::consts::os::posix88::{S_IRUSR, S_IWUSR, S_IXUSR}; - match p.get_mode() { - None => return false, - Some(m) => - ((m & S_IRUSR as uint) == S_IRUSR as uint - && (m & S_IWUSR as uint) == S_IWUSR as uint - && (m & S_IXUSR as uint) == S_IXUSR as uint) - } + if !p.exists() { return false } + let m = p.stat().mode; + (m & S_IRUSR as u64) == S_IRUSR as u64 + && (m & S_IWUSR as u64) == S_IWUSR as u64 + && (m & S_IXUSR as u64) == S_IXUSR as u64 } fn is_read_only(p: &Path) -> bool { use std::libc::consts::os::posix88::{S_IRUSR, S_IWUSR, S_IXUSR}; - match p.get_mode() { - None => return false, - Some(m) => - ((m & S_IRUSR as uint) == S_IRUSR as uint - && (m & S_IWUSR as uint) == 0 as uint - && (m & S_IXUSR as uint) == 0 as uint) - } + if !p.exists() { return false } + let m = p.stat().mode; + (m & S_IRUSR as u64) == S_IRUSR as u64 + && (m & S_IWUSR as u64) == 0 as u64 + && (m & S_IXUSR as u64) == 0 as u64 } fn test_sysroot() -> Path { @@ -289,7 +284,7 @@ fn command_line_test_with_env(args: &[~str], cwd: &Path, env: Option<~[(~str, ~s None => ~"" }; debug!("{} cd {}; {} {}", env_str, cwd.display(), cmd, args.connect(" ")); - assert!(os::path_is_dir(&*cwd)); + assert!(cwd.is_dir()); let cwd = (*cwd).clone(); let mut prog = run::Process::new(cmd, args, run::ProcessOptions { env: env.map(|e| e + os::env()), @@ -325,9 +320,9 @@ fn create_local_package_in(pkgid: &PkgId, pkgdir: &Path) -> Path { let package_dir = pkgdir.join_many([~"src", pkgid.to_str()]); // Create main, lib, test, and bench files - assert!(os::mkdir_recursive(&package_dir, U_RWX)); + file::mkdir_recursive(&package_dir, io::UserRWX); debug!("Created {} and does it exist? {:?}", package_dir.display(), - os::path_is_dir(&package_dir)); + package_dir.is_dir()); // Create main, lib, test, and bench files writeFile(&package_dir.join("main.rs"), @@ -378,7 +373,7 @@ fn lib_exists(repo: &Path, pkg_path: &Path, _v: Version) -> bool { // ??? versio debug!("assert_lib_exists: checking whether {:?} exists", lib); lib.is_some() && { let libname = lib.get_ref(); - os::path_exists(libname) && is_rwx(libname) + libname.exists() && is_rwx(libname) } } @@ -389,21 +384,21 @@ fn assert_executable_exists(repo: &Path, short_name: &str) { fn executable_exists(repo: &Path, short_name: &str) -> bool { debug!("executable_exists: repo = {}, short_name = {}", repo.display(), short_name); let exec = target_executable_in_workspace(&PkgId::new(short_name), repo); - os::path_exists(&exec) && is_rwx(&exec) + exec.exists() && is_rwx(&exec) } fn test_executable_exists(repo: &Path, short_name: &str) -> bool { debug!("test_executable_exists: repo = {}, short_name = {}", repo.display(), short_name); let exec = built_test_in_workspace(&PkgId::new(short_name), repo); do exec.map_default(false) |exec| { - os::path_exists(&exec) && is_rwx(&exec) + exec.exists() && is_rwx(&exec) } } fn remove_executable_file(p: &PkgId, workspace: &Path) { let exec = target_executable_in_workspace(&PkgId::new(p.short_name), workspace); - if os::path_exists(&exec) { - assert!(os::remove_file(&exec)); + if exec.exists() { + file::unlink(&exec); } } @@ -417,14 +412,14 @@ fn built_executable_exists(repo: &Path, short_name: &str) -> bool { let exec = built_executable_in_workspace(&PkgId::new(short_name), repo); exec.is_some() && { let execname = exec.get_ref(); - os::path_exists(execname) && is_rwx(execname) + execname.exists() && is_rwx(execname) } } fn remove_built_executable_file(p: &PkgId, workspace: &Path) { let exec = built_executable_in_workspace(&PkgId::new(p.short_name), workspace); match exec { - Some(r) => assert!(os::remove_file(&r)), + Some(r) => file::unlink(&r), None => () } } @@ -446,8 +441,9 @@ fn llvm_bitcode_file_exists(repo: &Path, short_name: &str) -> bool { } fn file_exists(repo: &Path, short_name: &str, extension: &str) -> bool { - os::path_exists(&target_build_dir(repo).join_many([short_name.to_owned(), - format!("{}.{}", short_name, extension)])) + target_build_dir(repo).join_many([short_name.to_owned(), + format!("{}.{}", short_name, extension)]) + .exists() } fn assert_built_library_exists(repo: &Path, short_name: &str) { @@ -459,7 +455,7 @@ fn built_library_exists(repo: &Path, short_name: &str) -> bool { let lib = built_library_in_workspace(&PkgId::new(short_name), repo); lib.is_some() && { let libname = lib.get_ref(); - os::path_exists(libname) && is_rwx(libname) + libname.exists() && is_rwx(libname) } } @@ -508,7 +504,7 @@ fn output_file_name(workspace: &Path, short_name: ~str) -> Path { fn touch_source_file(workspace: &Path, pkgid: &PkgId) { use conditions::bad_path::cond; let pkg_src_dir = workspace.join_many([~"src", pkgid.to_str()]); - let contents = os::list_dir_path(&pkg_src_dir); + let contents = file::readdir(&pkg_src_dir); for p in contents.iter() { if p.extension_str() == Some("rs") { // should be able to do this w/o a process @@ -527,7 +523,7 @@ fn touch_source_file(workspace: &Path, pkgid: &PkgId) { fn touch_source_file(workspace: &Path, pkgid: &PkgId) { use conditions::bad_path::cond; let pkg_src_dir = workspace.join_many([~"src", pkgid.to_str()]); - let contents = os::list_dir_path(&pkg_src_dir); + let contents = file::readdir(&pkg_src_dir); for p in contents.iter() { if p.extension_str() == Some("rs") { // should be able to do this w/o a process @@ -548,7 +544,7 @@ fn frob_source_file(workspace: &Path, pkgid: &PkgId, filename: &str) { let mut maybe_p = None; let maybe_file = pkg_src_dir.join(filename); debug!("Trying to frob {} -- {}", pkg_src_dir.display(), filename); - if os::path_exists(&maybe_file) { + if maybe_file.exists() { maybe_p = Some(maybe_file); } debug!("Frobbed? {:?}", maybe_p); @@ -557,7 +553,7 @@ fn frob_source_file(workspace: &Path, pkgid: &PkgId, filename: &str) { do io::io_error::cond.trap(|e| { cond.raise((p.clone(), format!("Bad path: {}", e.desc))); }).inside { - let mut w = p.open_writer(io::Append); + let mut w = file::open_stream(p, io::Append, io::Write); w.write(bytes!("/* hi */\n")); } } @@ -570,13 +566,14 @@ fn frob_source_file(workspace: &Path, pkgid: &PkgId, filename: &str) { fn test_make_dir_rwx() { let temp = &os::tmpdir(); let dir = temp.join("quux"); - assert!(!os::path_exists(&dir) || - os::remove_dir_recursive(&dir)); + if dir.exists() { + file::rmdir_recursive(&dir); + } debug!("Trying to make {}", dir.display()); assert!(make_dir_rwx(&dir)); - assert!(os::path_is_dir(&dir)); + assert!(dir.is_dir()); assert!(is_rwx(&dir)); - assert!(os::remove_dir_recursive(&dir)); + file::rmdir_recursive(&dir); } // n.b. I ignored the next two tests for now because something funny happens on linux @@ -603,19 +600,19 @@ fn test_install_valid() { // Check that all files exist let exec = target_executable_in_workspace(&temp_pkg_id, temp_workspace); debug!("exec = {}", exec.display()); - assert!(os::path_exists(&exec)); + assert!(exec.exists()); assert!(is_rwx(&exec)); let lib = installed_library_in_workspace(&temp_pkg_id.path, temp_workspace); debug!("lib = {:?}", lib); - assert!(lib.as_ref().map_default(false, |l| os::path_exists(l))); + assert!(lib.as_ref().map_default(false, |l| l.exists())); assert!(lib.as_ref().map_default(false, |l| is_rwx(l))); // And that the test and bench executables aren't installed - assert!(!os::path_exists(&target_test_in_workspace(&temp_pkg_id, temp_workspace))); + assert!(!target_test_in_workspace(&temp_pkg_id, temp_workspace).exists()); let bench = target_bench_in_workspace(&temp_pkg_id, temp_workspace); debug!("bench = {}", bench.display()); - assert!(!os::path_exists(&bench)); + assert!(!bench.exists()); // Make sure the db isn't dirty, so that it doesn't try to save() // asynchronously after the temporary directory that it wants to save @@ -655,19 +652,19 @@ fn test_install_valid_external() { // Check that all files exist let exec = target_executable_in_workspace(&temp_pkg_id, temp_workspace); debug!("exec = {}", exec.display()); - assert!(os::path_exists(&exec)); + assert!(exec.exists()); assert!(is_rwx(&exec)); let lib = installed_library_in_workspace(&temp_pkg_id.path, temp_workspace); debug!("lib = {:?}", lib); - assert!(lib.as_ref().map_default(false, |l| os::path_exists(l))); + assert!(lib.as_ref().map_default(false, |l| l.exists())); assert!(lib.as_ref().map_default(false, |l| is_rwx(l))); // And that the test and bench executables aren't installed - assert!(!os::path_exists(&target_test_in_workspace(&temp_pkg_id, temp_workspace))); + assert!(!target_test_in_workspace(&temp_pkg_id, temp_workspace).exists()); let bench = target_bench_in_workspace(&temp_pkg_id, temp_workspace); debug!("bench = {}", bench.display()); - assert!(!os::path_exists(&bench)); + assert!(!bench.exists()); } @@ -711,7 +708,7 @@ fn test_install_git() { debug!("Checking for files in {}", ws.display()); let exec = target_executable_in_workspace(&temp_pkg_id, &ws); debug!("exec = {}", exec.display()); - assert!(os::path_exists(&exec)); + assert!(exec.exists()); assert!(is_rwx(&exec)); let _built_lib = built_library_in_workspace(&temp_pkg_id, @@ -719,17 +716,17 @@ fn test_install_git() { assert_lib_exists(&ws, &temp_pkg_id.path, temp_pkg_id.version.clone()); let built_test = built_test_in_workspace(&temp_pkg_id, &ws).expect("test_install_git: built test should exist"); - assert!(os::path_exists(&built_test)); + assert!(built_test.exists()); let built_bench = built_bench_in_workspace(&temp_pkg_id, &ws).expect("test_install_git: built bench should exist"); - assert!(os::path_exists(&built_bench)); + assert!(built_bench.exists()); // And that the test and bench executables aren't installed let test = target_test_in_workspace(&temp_pkg_id, &ws); - assert!(!os::path_exists(&test)); + assert!(!test.exists()); debug!("test = {}", test.display()); let bench = target_bench_in_workspace(&temp_pkg_id, &ws); debug!("bench = {}", bench.display()); - assert!(!os::path_exists(&bench)); + assert!(!bench.exists()); } #[test] @@ -783,6 +780,7 @@ fn test_package_version() { let repo = repo.path(); let repo_subdir = repo.join_many(["mockgithub.com", "catamorphism", "test_pkg_version"]); debug!("Writing files in: {}", repo_subdir.display()); + file::mkdir_recursive(&repo_subdir, io::UserRWX); writeFile(&repo_subdir.join("main.rs"), "fn main() { let _x = (); }"); writeFile(&repo_subdir.join("lib.rs"), @@ -853,9 +851,9 @@ fn test_package_request_version() { let mut dir = target_build_dir(&repo.join(".rust")); dir.push(&Path::new("src/mockgithub.com/catamorphism/test_pkg_version-0.3")); debug!("dir = {}", dir.display()); - assert!(os::path_is_dir(&dir)); - assert!(os::path_exists(&dir.join("version-0.3-file.txt"))); - assert!(!os::path_exists(&dir.join("version-0.4-file.txt"))); + assert!(dir.is_dir()); + assert!(dir.join("version-0.3-file.txt").exists()); + assert!(!dir.join("version-0.4-file.txt").exists()); } #[test] @@ -904,16 +902,13 @@ fn package_script_with_default_build() { let source = Path::new(file!()).dir_path().join_many( [~"testsuite", ~"pass", ~"src", ~"fancy-lib", ~"pkg.rs"]); debug!("package_script_with_default_build: {}", source.display()); - if !os::copy_file(&source, - &dir.join_many(["src", "fancy-lib-0.1", "pkg.rs"])) { - fail!("Couldn't copy file"); - } + file::copy(&source, &dir.join_many(["src", "fancy-lib-0.1", "pkg.rs"])); command_line_test([~"install", ~"fancy-lib"], dir); assert_lib_exists(dir, &Path::new("fancy-lib"), NoVersion); - assert!(os::path_exists(&target_build_dir(dir).join_many([~"fancy-lib", ~"generated.rs"]))); + assert!(target_build_dir(dir).join_many([~"fancy-lib", ~"generated.rs"]).exists()); let generated_path = target_build_dir(dir).join_many([~"fancy-lib", ~"generated.rs"]); debug!("generated path = {}", generated_path.display()); - assert!(os::path_exists(&generated_path)); + assert!(generated_path.exists()); } #[test] @@ -921,7 +916,7 @@ fn rustpkg_build_no_arg() { let tmp = TempDir::new("rustpkg_build_no_arg").expect("rustpkg_build_no_arg failed"); let tmp = tmp.path().join(".rust"); let package_dir = tmp.join_many(["src", "foo"]); - assert!(os::mkdir_recursive(&package_dir, U_RWX)); + file::mkdir_recursive(&package_dir, io::UserRWX); writeFile(&package_dir.join("main.rs"), "fn main() { let _x = (); }"); @@ -935,7 +930,7 @@ fn rustpkg_install_no_arg() { let tmp = TempDir::new("rustpkg_install_no_arg").expect("rustpkg_install_no_arg failed"); let tmp = tmp.path().join(".rust"); let package_dir = tmp.join_many(["src", "foo"]); - assert!(os::mkdir_recursive(&package_dir, U_RWX)); + file::mkdir_recursive(&package_dir, io::UserRWX); writeFile(&package_dir.join("lib.rs"), "fn main() { let _x = (); }"); debug!("install_no_arg: dir = {}", package_dir.display()); @@ -948,7 +943,7 @@ fn rustpkg_clean_no_arg() { let tmp = TempDir::new("rustpkg_clean_no_arg").expect("rustpkg_clean_no_arg failed"); let tmp = tmp.path().join(".rust"); let package_dir = tmp.join_many(["src", "foo"]); - assert!(os::mkdir_recursive(&package_dir, U_RWX)); + file::mkdir_recursive(&package_dir, io::UserRWX); writeFile(&package_dir.join("main.rs"), "fn main() { let _x = (); }"); @@ -957,7 +952,7 @@ fn rustpkg_clean_no_arg() { assert_built_executable_exists(&tmp, "foo"); command_line_test([~"clean"], &package_dir); let res = built_executable_in_workspace(&PkgId::new("foo"), &tmp); - assert!(!res.as_ref().map_default(false, |m| { os::path_exists(m) })); + assert!(!res.as_ref().map_default(false, |m| m.exists())); } #[test] @@ -983,9 +978,9 @@ fn rust_path_test() { fn rust_path_contents() { let dir = TempDir::new("rust_path").expect("rust_path_contents failed"); let abc = &dir.path().join_many(["A", "B", "C"]); - assert!(os::mkdir_recursive(&abc.join(".rust"), U_RWX)); - assert!(os::mkdir_recursive(&abc.with_filename(".rust"), U_RWX)); - assert!(os::mkdir_recursive(&abc.dir_path().with_filename(".rust"), U_RWX)); + file::mkdir_recursive(&abc.join(".rust"), io::UserRWX); + file::mkdir_recursive(&abc.with_filename(".rust"), io::UserRWX); + file::mkdir_recursive(&abc.dir_path().with_filename(".rust"), io::UserRWX); assert!(os::change_dir(abc)); let p = rust_path(); @@ -1225,8 +1220,8 @@ fn test_non_numeric_tag() { temp_pkg_id.path.as_str().unwrap())], repo); let file1 = repo.join_many(["mockgithub.com", "catamorphism", "test-pkg", "testbranch_only"]); let file2 = repo.join_many(["mockgithub.com", "catamorphism", "test-pkg", "master_only"]); - assert!(os::path_exists(&file1)); - assert!(!os::path_exists(&file2)); + assert!(file1.exists()); + assert!(!file2.exists()); } #[test] @@ -1237,11 +1232,11 @@ fn test_extern_mod() { let lib_depend_dir = TempDir::new("foo").expect("test_extern_mod"); let lib_depend_dir = lib_depend_dir.path(); let aux_dir = lib_depend_dir.join_many(["src", "mockgithub.com", "catamorphism", "test_pkg"]); - assert!(os::mkdir_recursive(&aux_dir, U_RWX)); + file::mkdir_recursive(&aux_dir, io::UserRWX); let aux_pkg_file = aux_dir.join("lib.rs"); writeFile(&aux_pkg_file, "pub mod bar { pub fn assert_true() { assert!(true); } }\n"); - assert!(os::path_exists(&aux_pkg_file)); + assert!(aux_pkg_file.exists()); writeFile(&main_file, "extern mod test = \"mockgithub.com/catamorphism/test_pkg\";\nuse test::bar;\ @@ -1275,7 +1270,7 @@ fn test_extern_mod() { str::from_utf8(outp.output), str::from_utf8(outp.error)); } - assert!(os::path_exists(&exec_file) && is_executable(&exec_file)); + assert!(exec_file.exists() && is_executable(&exec_file)); } #[test] @@ -1286,11 +1281,11 @@ fn test_extern_mod_simpler() { let lib_depend_dir = TempDir::new("foo").expect("test_extern_mod_simpler"); let lib_depend_dir = lib_depend_dir.path(); let aux_dir = lib_depend_dir.join_many(["src", "rust-awesomeness"]); - assert!(os::mkdir_recursive(&aux_dir, U_RWX)); + file::mkdir_recursive(&aux_dir, io::UserRWX); let aux_pkg_file = aux_dir.join("lib.rs"); writeFile(&aux_pkg_file, "pub mod bar { pub fn assert_true() { assert!(true); } }\n"); - assert!(os::path_exists(&aux_pkg_file)); + assert!(aux_pkg_file.exists()); writeFile(&main_file, "extern mod test = \"rust-awesomeness\";\nuse test::bar;\ @@ -1330,7 +1325,7 @@ fn test_extern_mod_simpler() { str::from_utf8(outp.output), str::from_utf8(outp.error)); } - assert!(os::path_exists(&exec_file) && is_executable(&exec_file)); + assert!(exec_file.exists() && is_executable(&exec_file)); } #[test] @@ -1342,8 +1337,8 @@ fn test_import_rustpkg() { "extern mod rustpkg; fn main() {}"); command_line_test([~"build", ~"foo"], workspace); debug!("workspace = {}", workspace.display()); - assert!(os::path_exists(&target_build_dir(workspace).join("foo").join(format!("pkg{}", - os::EXE_SUFFIX)))); + assert!(target_build_dir(workspace).join("foo").join(format!("pkg{}", + os::EXE_SUFFIX)).exists()); } #[test] @@ -1355,8 +1350,8 @@ fn test_macro_pkg_script() { "extern mod rustpkg; fn main() { debug!(\"Hi\"); }"); command_line_test([~"build", ~"foo"], workspace); debug!("workspace = {}", workspace.display()); - assert!(os::path_exists(&target_build_dir(workspace).join("foo").join(format!("pkg{}", - os::EXE_SUFFIX)))); + assert!(target_build_dir(workspace).join("foo").join(format!("pkg{}", + os::EXE_SUFFIX)).exists()); } #[test] @@ -1436,7 +1431,7 @@ fn rust_path_hack_cwd() { // Same as rust_path_hack_test, but the CWD is the dir to build out of let cwd = TempDir::new("foo").expect("rust_path_hack_cwd"); let cwd = cwd.path().join("foo"); - assert!(os::mkdir_recursive(&cwd, U_RWX)); + file::mkdir_recursive(&cwd, io::UserRWX); writeFile(&cwd.join("lib.rs"), "pub fn f() { }"); let dest_workspace = mk_empty_workspace(&Path::new("bar"), &NoVersion, "dest_workspace"); @@ -1456,7 +1451,7 @@ fn rust_path_hack_multi_path() { // Same as rust_path_hack_test, but with a more complex package ID let cwd = TempDir::new("pkg_files").expect("rust_path_hack_cwd"); let subdir = cwd.path().join_many(["foo", "bar", "quux"]); - assert!(os::mkdir_recursive(&subdir, U_RWX)); + file::mkdir_recursive(&subdir, io::UserRWX); writeFile(&subdir.join("lib.rs"), "pub fn f() { }"); let name = ~"foo/bar/quux"; @@ -1870,21 +1865,22 @@ fn pkgid_pointing_to_subdir() { // rustpkg should recognize that and treat the part after some_repo/ as a subdir let workspace = TempDir::new("parent_repo").expect("Couldn't create temp dir"); let workspace = workspace.path(); - assert!(os::mkdir_recursive(&workspace.join_many(["src", "mockgithub.com", - "mozilla", "some_repo"]), U_RWX)); + file::mkdir_recursive(&workspace.join_many(["src", "mockgithub.com", + "mozilla", "some_repo"]), + io::UserRWX); let foo_dir = workspace.join_many(["src", "mockgithub.com", "mozilla", "some_repo", "extras", "foo"]); let bar_dir = workspace.join_many(["src", "mockgithub.com", "mozilla", "some_repo", "extras", "bar"]); - assert!(os::mkdir_recursive(&foo_dir, U_RWX)); - assert!(os::mkdir_recursive(&bar_dir, U_RWX)); + file::mkdir_recursive(&foo_dir, io::UserRWX); + file::mkdir_recursive(&bar_dir, io::UserRWX); writeFile(&foo_dir.join("lib.rs"), "pub fn f() {}"); writeFile(&bar_dir.join("lib.rs"), "pub fn g() {}"); debug!("Creating a file in {}", workspace.display()); let testpkg_dir = workspace.join_many(["src", "testpkg-0.1"]); - assert!(os::mkdir_recursive(&testpkg_dir, U_RWX)); + file::mkdir_recursive(&testpkg_dir, io::UserRWX); writeFile(&testpkg_dir.join("main.rs"), "extern mod foo = \"mockgithub.com/mozilla/some_repo/extras/foo\";\n @@ -1957,9 +1953,9 @@ fn test_target_specific_build_dir() { ~"build", ~"foo"], workspace); - assert!(os::path_is_dir(&target_build_dir(workspace))); + assert!(target_build_dir(workspace).is_dir()); assert!(built_executable_exists(workspace, "foo")); - assert!(os::list_dir(&workspace.join("build")).len() == 1); + assert!(file::readdir(&workspace.join("build")).len() == 1); } #[test] @@ -1973,10 +1969,10 @@ fn test_target_specific_install_dir() { ~"install", ~"foo"], workspace); - assert!(os::path_is_dir(&workspace.join_many([~"lib", host_triple()]))); + assert!(workspace.join_many([~"lib", host_triple()]).is_dir()); assert_lib_exists(workspace, &Path::new("foo"), NoVersion); - assert!(os::list_dir(&workspace.join("lib")).len() == 1); - assert!(os::path_is_dir(&workspace.join("bin"))); + assert!(file::readdir(&workspace.join("lib")).len() == 1); + assert!(workspace.join("bin").is_dir()); assert_executable_exists(workspace, "foo"); } @@ -1988,7 +1984,7 @@ fn test_dependencies_terminate() { let workspace = workspace.path(); let b_dir = workspace.join_many(["src", "b-0.1"]); let b_subdir = b_dir.join("test"); - assert!(os::mkdir_recursive(&b_subdir, U_RWX)); + file::mkdir_recursive(&b_subdir, io::UserRWX); writeFile(&b_subdir.join("test.rs"), "extern mod b; use b::f; #[test] fn g() { f() }"); command_line_test([~"install", ~"b"], workspace); @@ -2161,19 +2157,19 @@ fn test_installed_read_only() { debug!("Checking for files in {}", ws.display()); let exec = target_executable_in_workspace(&temp_pkg_id, &ws); debug!("exec = {}", exec.display()); - assert!(os::path_exists(&exec)); + assert!(exec.exists()); assert!(is_rwx(&exec)); let built_lib = built_library_in_workspace(&temp_pkg_id, &ws).expect("test_install_git: built lib should exist"); - assert!(os::path_exists(&built_lib)); + assert!(built_lib.exists()); assert!(is_rwx(&built_lib)); // Make sure sources are (a) under "build" and (b) read-only let src1 = target_build_dir(&ws).join_many([~"src", temp_pkg_id.to_str(), ~"main.rs"]); let src2 = target_build_dir(&ws).join_many([~"src", temp_pkg_id.to_str(), ~"lib.rs"]); - assert!(os::path_exists(&src1)); - assert!(os::path_exists(&src2)); + assert!(src1.exists()); + assert!(src2.exists()); assert!(is_read_only(&src1)); assert!(is_read_only(&src2)); } @@ -2186,7 +2182,7 @@ fn test_installed_local_changes() { debug!("repo = {}", repo.display()); let repo_subdir = repo.join_many(["mockgithub.com", "catamorphism", "test-pkg"]); debug!("repo_subdir = {}", repo_subdir.display()); - assert!(os::mkdir_recursive(&repo.join_many([".rust", "src"]), U_RWX)); + file::mkdir_recursive(&repo.join_many([".rust", "src"]), io::UserRWX); writeFile(&repo_subdir.join("main.rs"), "fn main() { let _x = (); }"); @@ -2269,7 +2265,7 @@ fn find_sources_in_cwd() { let temp_dir = TempDir::new("sources").expect("find_sources_in_cwd failed"); let temp_dir = temp_dir.path(); let source_dir = temp_dir.join("foo"); - os::mkdir_recursive(&source_dir, U_RWX); + file::mkdir_recursive(&source_dir, io::UserRWX); writeFile(&source_dir.join("main.rs"), "fn main() { let _x = (); }"); command_line_test([~"install", ~"foo"], &source_dir); @@ -2292,16 +2288,13 @@ fn test_c_dependency_ok() { debug!("dir = {}", dir.display()); let source = Path::new(file!()).dir_path().join_many( [~"testsuite", ~"pass", ~"src", ~"c-dependencies", ~"pkg.rs"]); - if !os::copy_file(&source, - &dir.join_many([~"src", ~"cdep-0.1", ~"pkg.rs"])) { - fail!("Couldn't copy file"); - } + file::copy(&source, &dir.join_many([~"src", ~"cdep-0.1", ~"pkg.rs"])); command_line_test([~"build", ~"cdep"], dir); assert_executable_exists(dir, "cdep"); let out_dir = target_build_dir(dir).join("cdep"); let c_library_path = out_dir.join(platform_library_name("foo")); debug!("c library path: {}", c_library_path.display()); - assert!(os::path_exists(&c_library_path)); + assert!(c_library_path.exists()); } #[test] @@ -2316,16 +2309,13 @@ fn test_c_dependency_no_rebuilding() { debug!("dir = {}", dir.display()); let source = Path::new(file!()).dir_path().join_many( [~"testsuite", ~"pass", ~"src", ~"c-dependencies", ~"pkg.rs"]); - if !os::copy_file(&source, - &dir.join_many([~"src", ~"cdep-0.1", ~"pkg.rs"])) { - fail!("Couldn't copy file"); - } + file::copy(&source, &dir.join_many([~"src", ~"cdep-0.1", ~"pkg.rs"])); command_line_test([~"build", ~"cdep"], dir); assert_executable_exists(dir, "cdep"); let out_dir = target_build_dir(dir).join("cdep"); let c_library_path = out_dir.join(platform_library_name("foo")); debug!("c library path: {}", c_library_path.display()); - assert!(os::path_exists(&c_library_path)); + assert!(c_library_path.exists()); // Now, make it read-only so rebuilding will fail assert!(chmod_read_only(&c_library_path)); @@ -2352,15 +2342,13 @@ fn test_c_dependency_yes_rebuilding() { [~"testsuite", ~"pass", ~"src", ~"c-dependencies", ~"pkg.rs"]); let target = dir.join_many([~"src", ~"cdep-0.1", ~"pkg.rs"]); debug!("Copying {} -> {}", source.display(), target.display()); - if !os::copy_file(&source, &target) { - fail!("Couldn't copy file"); - } + file::copy(&source, &target); command_line_test([~"build", ~"cdep"], dir); assert_executable_exists(dir, "cdep"); let out_dir = target_build_dir(dir).join("cdep"); let c_library_path = out_dir.join(platform_library_name("foo")); debug!("c library path: {}", c_library_path.display()); - assert!(os::path_exists(&c_library_path)); + assert!(c_library_path.exists()); // Now, make the Rust library read-only so rebuilding will fail match built_library_in_workspace(&PkgId::new("cdep"), dir) { @@ -2380,8 +2368,5 @@ fn test_c_dependency_yes_rebuilding() { fn is_executable(p: &Path) -> bool { use std::libc::consts::os::posix88::{S_IXUSR}; - match p.get_mode() { - None => false, - Some(mode) => mode & S_IXUSR as uint == S_IXUSR as uint - } + p.exists() && p.stat().mode & S_IXUSR as u64 == S_IXUSR as u64 } diff --git a/src/librustpkg/testsuite/pass/src/c-dependencies/pkg.rs b/src/librustpkg/testsuite/pass/src/c-dependencies/pkg.rs index 016635339a9d9..f5d6317e7a68f 100644 --- a/src/librustpkg/testsuite/pass/src/c-dependencies/pkg.rs +++ b/src/librustpkg/testsuite/pass/src/c-dependencies/pkg.rs @@ -31,7 +31,7 @@ pub fn main() { let sysroot_arg = args[1].clone(); let sysroot = Path::new(sysroot_arg); - if !os::path_exists(&sysroot) { + if !sysroot.exists() { fail!("Package script requires a sysroot that exists; {} doesn't", sysroot.display()); } diff --git a/src/librustpkg/testsuite/pass/src/fancy-lib/pkg.rs b/src/librustpkg/testsuite/pass/src/fancy-lib/pkg.rs index f82c585b1d156..e5fb6889ae09b 100644 --- a/src/librustpkg/testsuite/pass/src/fancy-lib/pkg.rs +++ b/src/librustpkg/testsuite/pass/src/fancy-lib/pkg.rs @@ -12,9 +12,7 @@ extern mod rustpkg; extern mod rustc; use std::os; -use std::rt::io; -use std::rt::io::Writer; -use std::rt::io::file::FileInfo; +use std::rt::io::file; use rustpkg::api; use rustpkg::version::NoVersion; @@ -30,7 +28,7 @@ pub fn main() { let sysroot_arg = args[1].clone(); let sysroot = Path::new(sysroot_arg); - if !os::path_exists(&sysroot) { + if !sysroot.exists() { debug!("Failing, sysroot"); fail!("Package script requires a sysroot that exists;{} doesn't", sysroot.display()); } @@ -45,7 +43,7 @@ pub fn main() { let out_path = os::self_exe_path().expect("Couldn't get self_exe path"); debug!("Writing file"); - let mut file = out_path.join("generated.rs").open_writer(io::Create); + let mut file = file::create(&out_path.join("generated.rs")); file.write("pub fn wheeeee() { let xs = [1, 2, 3]; \ for _ in xs.iter() { assert!(true); } }".as_bytes()); diff --git a/src/librustpkg/util.rs b/src/librustpkg/util.rs index 9d835dcc20be7..d0ba5ce368fcd 100644 --- a/src/librustpkg/util.rs +++ b/src/librustpkg/util.rs @@ -10,6 +10,8 @@ use std::libc; use std::os; +use std::rt::io; +use std::rt::io::file; use extra::workcache; use rustc::driver::{driver, session}; use extra::getopts::groups::getopts; @@ -32,7 +34,6 @@ use path_util::{default_workspace, built_library_in_workspace}; pub use target::{OutputType, Main, Lib, Bench, Test, JustOne, lib_name_of, lib_crate_filename}; pub use target::{Target, Build, Install}; use extra::treemap::TreeMap; -use path_util::U_RWX; pub use target::{lib_name_of, lib_crate_filename, WhatToBuild, MaybeCustom, Inferred}; use workcache_support::{digest_file_with_date, digest_only_date}; @@ -184,7 +185,7 @@ pub fn compile_input(context: &BuildContext, let mut out_dir = target_build_dir(workspace); out_dir.push(&pkg_id.path); // Make the output directory if it doesn't exist already - assert!(os::mkdir_recursive(&out_dir, U_RWX)); + file::mkdir_recursive(&out_dir, io::UserRWX); let binary = os::args()[0].to_managed(); @@ -256,11 +257,11 @@ pub fn compile_input(context: &BuildContext, // Make sure all the library directories actually exist, since the linker will complain // otherwise for p in addl_lib_search_paths.iter() { - if os::path_exists(p) { - assert!(os::path_is_dir(p)); + if p.exists() { + assert!(p.is_dir()) } else { - assert!(os::mkdir_recursive(p, U_RWX)); + file::mkdir_recursive(p, io::UserRWX); } } @@ -324,7 +325,7 @@ pub fn compile_input(context: &BuildContext, }; for p in discovered_output.iter() { debug!("About to discover output {}", p.display()); - if os::path_exists(p) { + if p.exists() { debug!("4. discovering output {}", p.display()); // FIXME (#9639): This needs to handle non-utf8 paths exec.discover_output("binary", p.as_str().unwrap(), digest_only_date(p)); @@ -629,10 +630,16 @@ fn debug_flags() -> ~[~str] { ~[] } /// Returns the last-modified date as an Option pub fn datestamp(p: &Path) -> Option { - debug!("Scrutinizing datestamp for {} - does it exist? {:?}", p.display(), os::path_exists(p)); - let out = p.stat().map(|stat| stat.modified); - debug!("Date = {:?}", out); - out.map(|t| { t as libc::time_t }) + debug!("Scrutinizing datestamp for {} - does it exist? {:?}", p.display(), + p.exists()); + match io::result(|| p.stat()) { + Ok(s) => { + let out = s.modified; + debug!("Date = {:?}", out); + Some(out as libc::time_t) + } + Err(*) => None, + } } pub type DepMap = TreeMap<~str, ~[(~str, ~str)]>; diff --git a/src/librustpkg/version.rs b/src/librustpkg/version.rs index 6ca19562724fe..eff16cb99968c 100644 --- a/src/librustpkg/version.rs +++ b/src/librustpkg/version.rs @@ -14,7 +14,7 @@ extern mod std; use extra::semver; -use std::{char, os, result, run, str}; +use std::{char, result, run, str}; use extra::tempfile::TempDir; use path_util::rust_path; @@ -100,7 +100,7 @@ pub fn try_getting_local_version(local_path: &Path) -> Option { for rp in rustpath.iter() { let local_path = rp.join(local_path); let git_dir = local_path.join(".git"); - if !os::path_is_dir(&git_dir) { + if !git_dir.is_dir() { continue; } // FIXME (#9639): This needs to handle non-utf8 paths diff --git a/src/librustpkg/workcache_support.rs b/src/librustpkg/workcache_support.rs index 2e4894b854d5c..c16224afbf4c8 100644 --- a/src/librustpkg/workcache_support.rs +++ b/src/librustpkg/workcache_support.rs @@ -9,32 +9,23 @@ // except according to those terms. use std::rt::io; -use std::rt::io::Reader; -use std::rt::io::file::FileInfo; +use std::rt::io::file; use extra::workcache; use sha1::{Digest, Sha1}; /// Hashes the file contents along with the last-modified time pub fn digest_file_with_date(path: &Path) -> ~str { use conditions::bad_path::cond; - use cond1 = conditions::bad_stat::cond; - let mut err = None; - let bytes = do io::io_error::cond.trap(|e| err = Some(e)).inside { - path.open_reader(io::Open).read_to_end() - }; - match err { - None => { + match io::result(|| file::open(path).read_to_end()) { + Ok(bytes) => { let mut sha = Sha1::new(); sha.input(bytes); - let st = match path.stat() { - Some(st) => st, - None => cond1.raise((path.clone(), format!("Couldn't get file access time"))) - }; + let st = path.stat(); sha.input_str(st.modified.to_str()); sha.result_str() } - Some(e) => { + Err(e) => { cond.raise((path.clone(), format!("Couldn't read file: {}", e.desc))); ~"" } @@ -43,13 +34,8 @@ pub fn digest_file_with_date(path: &Path) -> ~str { /// Hashes only the last-modified time pub fn digest_only_date(path: &Path) -> ~str { - use cond = conditions::bad_stat::cond; - let mut sha = Sha1::new(); - let st = match path.stat() { - Some(st) => st, - None => cond.raise((path.clone(), format!("Couldn't get file access time"))) - }; + let st = path.stat(); sha.input_str(st.modified.to_str()); sha.result_str() } diff --git a/src/librustpkg/workspace.rs b/src/librustpkg/workspace.rs index a35500372467c..e65f3ce5bb6ab 100644 --- a/src/librustpkg/workspace.rs +++ b/src/librustpkg/workspace.rs @@ -52,7 +52,7 @@ pub fn pkg_parent_workspaces(cx: &Context, pkgid: &PkgId) -> ~[Path] { } pub fn is_workspace(p: &Path) -> bool { - os::path_is_dir(&p.join("src")) + p.join("src").is_dir() } /// Construct a workspace and package-ID name based on the current directory. diff --git a/src/librustuv/file.rs b/src/librustuv/file.rs index 2303721986c42..15df189edcdd4 100644 --- a/src/librustuv/file.rs +++ b/src/librustuv/file.rs @@ -182,7 +182,7 @@ impl FsRequest { self.sync_cleanup(result) } - pub fn mkdir(self, loop_: &Loop, path: &CString, mode: int, cb: FsCallback) { + pub fn mkdir(self, loop_: &Loop, path: &CString, mode: c_int, cb: FsCallback) { let complete_cb_ptr = { let mut me = self; me.req_boilerplate(Some(cb)) @@ -221,6 +221,18 @@ impl FsRequest { assert_eq!(ret, 0); } + pub fn chmod(self, loop_: &Loop, path: &CString, mode: c_int, cb: FsCallback) { + let complete_cb_ptr = { + let mut me = self; + me.req_boilerplate(Some(cb)) + }; + let ret = path.with_ref(|p| unsafe { + uvll::fs_chmod(loop_.native_handle(), self.native_handle(), p, mode, + complete_cb_ptr) + }); + assert_eq!(ret, 0); + } + pub fn readdir(self, loop_: &Loop, path: &CString, flags: c_int, cb: FsCallback) { let complete_cb_ptr = { @@ -593,7 +605,7 @@ mod test { S_IRUSR; let mkdir_req = FsRequest::new(); do mkdir_req.mkdir(&loop_, &path.to_c_str(), - mode as int) |req,uverr| { + mode as c_int) |req,uverr| { assert!(uverr.is_none()); let loop_ = req.get_loop(); let stat_req = FsRequest::new(); @@ -626,12 +638,12 @@ mod test { let mode = S_IWUSR | S_IRUSR; let mkdir_req = FsRequest::new(); - do mkdir_req.mkdir(&loop_, &path.to_c_str(), mode as int) |req,uverr| { + do mkdir_req.mkdir(&loop_, &path.to_c_str(), mode as c_int) |req,uverr| { assert!(uverr.is_none()); let loop_ = req.get_loop(); let mkdir_req = FsRequest::new(); do mkdir_req.mkdir(&loop_, &path.to_c_str(), - mode as int) |req,uverr| { + mode as c_int) |req,uverr| { assert!(uverr.is_some()); let loop_ = req.get_loop(); let _stat = req.get_stat(); diff --git a/src/librustuv/uvio.rs b/src/librustuv/uvio.rs index 7ecb51bb0d6ef..ae8546af4b40e 100644 --- a/src/librustuv/uvio.rs +++ b/src/librustuv/uvio.rs @@ -20,6 +20,7 @@ use std::option::*; use std::ptr; use std::str; use std::result::*; +use std::rt::io; use std::rt::io::IoError; use std::rt::io::net::ip::{SocketAddr, IpAddr}; use std::rt::io::{standard_error, OtherIoError, SeekStyle, SeekSet, SeekCur, @@ -34,7 +35,7 @@ use std::rt::task::Task; use std::unstable::sync::Exclusive; use std::path::{GenericPath, Path}; use std::libc::{lseek, off_t, O_CREAT, O_APPEND, O_TRUNC, O_RDWR, O_RDONLY, - O_WRONLY, S_IRUSR, S_IWUSR, S_IRWXU}; + O_WRONLY, S_IRUSR, S_IWUSR}; use std::rt::io::{FileMode, FileAccess, OpenOrCreate, Open, Create, CreateOrTruncate, Append, Truncate, Read, Write, ReadWrite, FileStat}; @@ -699,9 +700,10 @@ impl IoFactory for UvIoFactory { assert!(!result_cell.is_empty()); return result_cell.take(); } - fn fs_mkdir(&mut self, path: &CString, mode: int) -> Result<(), IoError> { + fn fs_mkdir(&mut self, path: &CString, + perm: io::FilePermission) -> Result<(), IoError> { do uv_fs_helper(self.uv_loop(), path) |mkdir_req, l, p, cb| { - do mkdir_req.mkdir(l, p, mode) |req, err| { + do mkdir_req.mkdir(l, p, perm as c_int) |req, err| { cb(req, err) }; } @@ -722,6 +724,15 @@ impl IoFactory for UvIoFactory { }; } } + fn fs_chmod(&mut self, path: &CString, + perm: io::FilePermission) -> Result<(), IoError> { + do uv_fs_helper(self.uv_loop(), path) |chmod_req, l, p, cb| { + do chmod_req.chmod(l, p, perm as c_int) |req, err| { + cb(req, err) + }; + } + } +>>>>>>> Remove all blocking std::os blocking functions fn fs_readdir(&mut self, path: &CString, flags: c_int) -> Result<~[Path], IoError> { use str::StrSlice; diff --git a/src/librustuv/uvll.rs b/src/librustuv/uvll.rs index 9f26f9506a084..a2047ef98fa83 100644 --- a/src/librustuv/uvll.rs +++ b/src/librustuv/uvll.rs @@ -795,8 +795,8 @@ pub unsafe fn fs_fstat(loop_ptr: *uv_loop_t, req: *uv_fs_t, fd: c_int, cb: *u8) rust_uv_fs_fstat(loop_ptr, req, fd, cb) } -pub unsafe fn fs_mkdir(loop_ptr: *uv_loop_t, req: *uv_fs_t, path: *c_char, mode: int, - cb: *u8) -> c_int { +pub unsafe fn fs_mkdir(loop_ptr: *uv_loop_t, req: *uv_fs_t, path: *c_char, + mode: c_int, cb: *u8) -> c_int { #[fixed_stack_segment]; #[inline(never)]; rust_uv_fs_mkdir(loop_ptr, req, path, mode as c_int, cb) @@ -813,6 +813,12 @@ pub unsafe fn fs_rename(loop_ptr: *uv_loop_t, req: *uv_fs_t, path: *c_char, rust_uv_fs_rename(loop_ptr, req, path, to, cb) } +pub unsafe fn fs_chmod(loop_ptr: *uv_loop_t, req: *uv_fs_t, path: *c_char, + mode: c_int, cb: *u8) -> c_int { + #[fixed_stack_segment]; #[inline(never)]; + + rust_uv_fs_chmod(loop_ptr, req, path, mode as c_int, cb) +} pub unsafe fn fs_readdir(loop_ptr: *uv_loop_t, req: *uv_fs_t, path: *c_char, flags: c_int, cb: *u8) -> c_int { #[fixed_stack_segment]; #[inline(never)]; @@ -1115,6 +1121,8 @@ extern { cb: *u8) -> c_int; fn rust_uv_fs_rename(loop_ptr: *c_void, req: *uv_fs_t, path: *c_char, to: *c_char, cb: *u8) -> c_int; + fn rust_uv_fs_chmod(loop_ptr: *c_void, req: *uv_fs_t, path: *c_char, + mode: c_int, cb: *u8) -> c_int; fn rust_uv_fs_readdir(loop_ptr: *c_void, req: *uv_fs_t, path: *c_char, flags: c_int, cb: *u8) -> c_int; fn rust_uv_fs_req_cleanup(req: *uv_fs_t); diff --git a/src/libstd/bool.rs b/src/libstd/bool.rs index 2eec6ff4cba43..7f91c5e4f9054 100644 --- a/src/libstd/bool.rs +++ b/src/libstd/bool.rs @@ -317,8 +317,11 @@ impl Zero for bool { #[cfg(test)] mod tests { - use super::*; - use prelude::*; + use cmp::{Equal, Greater, Less, Eq, TotalOrd}; + use ops::{BitAnd, BitXor, BitOr}; + use from_str::{FromStr, from_str}; + use option::{Some, None}; + use super::all_values; #[test] fn test_bool() { diff --git a/src/libstd/os.rs b/src/libstd/os.rs index 1f32c6a0a35ef..12281f06005a7 100644 --- a/src/libstd/os.rs +++ b/src/libstd/os.rs @@ -35,7 +35,6 @@ use container::Container; use iter::range; use libc; use libc::{c_char, c_void, c_int, size_t}; -use libc::FILE; use option::{Some, None}; use os; use prelude::*; @@ -45,7 +44,6 @@ use to_str; use unstable::finally::Finally; use vec; -pub use libc::fclose; pub use os::consts::*; /// Delegates to the libc close() function, returning the same return value. @@ -56,28 +54,6 @@ pub fn close(fd: c_int) -> c_int { } } -// On Windows, wide character version of function must be used to support -// unicode, so functions should be split into at least two versions, -// which are for Windows and for non-Windows, if necessary. -// See https://github.com/mozilla/rust/issues/9822 for more information. - -mod rustrt { - use libc::{c_char, c_int}; - use libc; - - extern { - pub fn rust_path_is_dir(path: *libc::c_char) -> c_int; - pub fn rust_path_exists(path: *libc::c_char) -> c_int; - } - - // Uses _wstat instead of stat. - #[cfg(windows)] - extern { - pub fn rust_path_is_dir_u16(path: *u16) -> c_int; - pub fn rust_path_exists_u16(path: *u16) -> c_int; - } -} - pub static TMPBUF_SZ : uint = 1000u; static BUF_BYTES : uint = 2048u; @@ -348,15 +324,6 @@ pub fn unsetenv(n: &str) { _unsetenv(n); } -pub fn fdopen(fd: c_int) -> *FILE { - #[fixed_stack_segment]; #[inline(never)]; - do "r".with_c_str |modebuf| { - unsafe { - libc::fdopen(fd, modebuf) - } - } -} - pub struct Pipe { input: c_int, out: c_int @@ -373,8 +340,6 @@ pub fn pipe() -> Pipe { } } - - #[cfg(windows)] pub fn pipe() -> Pipe { #[fixed_stack_segment]; #[inline(never)]; @@ -574,58 +539,6 @@ pub fn tmpdir() -> Path { } } -/// Recursively walk a directory structure -pub fn walk_dir(p: &Path, f: &fn(&Path) -> bool) -> bool { - let r = list_dir(p); - r.iter().advance(|q| { - let path = &p.join(q); - f(path) && (!path_is_dir(path) || walk_dir(path, |p| f(p))) - }) -} - -#[cfg(unix)] -/// Indicates whether a path represents a directory -pub fn path_is_dir(p: &Path) -> bool { - #[fixed_stack_segment]; #[inline(never)]; - unsafe { - do p.with_c_str |buf| { - rustrt::rust_path_is_dir(buf) != 0 as c_int - } - } -} - - -#[cfg(windows)] -pub fn path_is_dir(p: &Path) -> bool { - #[fixed_stack_segment]; #[inline(never)]; - unsafe { - do os::win32::as_utf16_p(p.as_str().unwrap()) |buf| { - rustrt::rust_path_is_dir_u16(buf) != 0 as c_int - } - } -} - -#[cfg(unix)] -/// Indicates whether a path exists -pub fn path_exists(p: &Path) -> bool { - #[fixed_stack_segment]; #[inline(never)]; - unsafe { - do p.with_c_str |buf| { - rustrt::rust_path_exists(buf) != 0 as c_int - } - } -} - -#[cfg(windows)] -pub fn path_exists(p: &Path) -> bool { - #[fixed_stack_segment]; #[inline(never)]; - unsafe { - do os::win32::as_utf16_p(p.as_str().unwrap()) |buf| { - rustrt::rust_path_exists_u16(buf) != 0 as c_int - } - } -} - /** * Convert a relative path to an absolute path * @@ -646,206 +559,6 @@ pub fn make_absolute(p: &Path) -> Path { } } - -/// Creates a directory at the specified path -pub fn make_dir(p: &Path, mode: c_int) -> bool { - return mkdir(p, mode); - - #[cfg(windows)] - fn mkdir(p: &Path, _mode: c_int) -> bool { - #[fixed_stack_segment]; #[inline(never)]; - unsafe { - use os::win32::as_utf16_p; - // FIXME: turn mode into something useful? #2623 - do as_utf16_p(p.as_str().unwrap()) |buf| { - libc::CreateDirectoryW(buf, ptr::mut_null()) - != (0 as libc::BOOL) - } - } - } - - #[cfg(unix)] - fn mkdir(p: &Path, mode: c_int) -> bool { - #[fixed_stack_segment]; #[inline(never)]; - do p.with_c_str |buf| { - unsafe { - libc::mkdir(buf, mode as libc::mode_t) == (0 as c_int) - } - } - } -} - -/// Creates a directory with a given mode. -/// Returns true iff creation -/// succeeded. Also creates all intermediate subdirectories -/// if they don't already exist, giving all of them the same mode. - -// tjc: if directory exists but with different permissions, -// should we return false? -pub fn mkdir_recursive(p: &Path, mode: c_int) -> bool { - if path_is_dir(p) { - return true; - } - if p.filename().is_some() { - let mut p_ = p.clone(); - p_.pop(); - if !mkdir_recursive(&p_, mode) { - return false; - } - } - return make_dir(p, mode); -} - -/// Lists the contents of a directory -/// -/// Each resulting Path is a relative path with no directory component. -pub fn list_dir(p: &Path) -> ~[Path] { - unsafe { - #[cfg(target_os = "linux")] - #[cfg(target_os = "android")] - #[cfg(target_os = "freebsd")] - #[cfg(target_os = "macos")] - unsafe fn get_list(p: &Path) -> ~[Path] { - #[fixed_stack_segment]; #[inline(never)]; - use libc::{dirent_t}; - use libc::{opendir, readdir, closedir}; - extern { - fn rust_list_dir_val(ptr: *dirent_t) -> *libc::c_char; - } - let mut paths = ~[]; - debug!("os::list_dir -- BEFORE OPENDIR"); - - let dir_ptr = do p.with_c_str |buf| { - opendir(buf) - }; - - if (dir_ptr as uint != 0) { - debug!("os::list_dir -- opendir() SUCCESS"); - let mut entry_ptr = readdir(dir_ptr); - while (entry_ptr as uint != 0) { - let cstr = CString::new(rust_list_dir_val(entry_ptr), false); - paths.push(Path::new(cstr)); - entry_ptr = readdir(dir_ptr); - } - closedir(dir_ptr); - } - else { - debug!("os::list_dir -- opendir() FAILURE"); - } - debug!("os::list_dir -- AFTER -- \\#: {}", paths.len()); - paths - } - #[cfg(windows)] - unsafe fn get_list(p: &Path) -> ~[Path] { - #[fixed_stack_segment]; #[inline(never)]; - use libc::consts::os::extra::INVALID_HANDLE_VALUE; - use libc::{wcslen, free}; - use libc::funcs::extra::kernel32::{ - FindFirstFileW, - FindNextFileW, - FindClose, - }; - use libc::types::os::arch::extra::HANDLE; - use os::win32::{ - as_utf16_p - }; - use rt::global_heap::malloc_raw; - - #[nolink] - extern { - fn rust_list_dir_wfd_size() -> libc::size_t; - fn rust_list_dir_wfd_fp_buf(wfd: *libc::c_void) -> *u16; - } - let star = p.join("*"); - do as_utf16_p(star.as_str().unwrap()) |path_ptr| { - let mut paths = ~[]; - let wfd_ptr = malloc_raw(rust_list_dir_wfd_size() as uint); - let find_handle = FindFirstFileW(path_ptr, wfd_ptr as HANDLE); - if find_handle as libc::c_int != INVALID_HANDLE_VALUE { - let mut more_files = 1 as libc::c_int; - while more_files != 0 { - let fp_buf = rust_list_dir_wfd_fp_buf(wfd_ptr); - if fp_buf as uint == 0 { - fail!("os::list_dir() failure: got null ptr from wfd"); - } - else { - let fp_vec = vec::from_buf( - fp_buf, wcslen(fp_buf) as uint); - let fp_str = str::from_utf16(fp_vec); - paths.push(Path::new(fp_str)); - } - more_files = FindNextFileW(find_handle, wfd_ptr as HANDLE); - } - FindClose(find_handle); - free(wfd_ptr) - } - paths - } - } - do get_list(p).move_iter().filter |path| { - path.as_vec() != bytes!(".") && path.as_vec() != bytes!("..") - }.collect() - } -} - -/** - * Lists the contents of a directory - * - * This version prepends each entry with the directory. - */ -pub fn list_dir_path(p: &Path) -> ~[Path] { - list_dir(p).map(|f| p.join(f)) -} - -/// Removes a directory at the specified path, after removing -/// all its contents. Use carefully! -pub fn remove_dir_recursive(p: &Path) -> bool { - let mut error_happened = false; - do walk_dir(p) |inner| { - if !error_happened { - if path_is_dir(inner) { - if !remove_dir_recursive(inner) { - error_happened = true; - } - } - else { - if !remove_file(inner) { - error_happened = true; - } - } - } - true - }; - // Directory should now be empty - !error_happened && remove_dir(p) -} - -/// Removes a directory at the specified path -pub fn remove_dir(p: &Path) -> bool { - return rmdir(p); - - #[cfg(windows)] - fn rmdir(p: &Path) -> bool { - #[fixed_stack_segment]; #[inline(never)]; - unsafe { - use os::win32::as_utf16_p; - return do as_utf16_p(p.as_str().unwrap()) |buf| { - libc::RemoveDirectoryW(buf) != (0 as libc::BOOL) - }; - } - } - - #[cfg(unix)] - fn rmdir(p: &Path) -> bool { - #[fixed_stack_segment]; #[inline(never)]; - do p.with_c_str |buf| { - unsafe { - libc::rmdir(buf) == (0 as c_int) - } - } - } -} - /// Changes the current working directory to the specified path, returning /// whether the change was completed successfully or not. pub fn change_dir(p: &Path) -> bool { @@ -873,121 +586,6 @@ pub fn change_dir(p: &Path) -> bool { } } -/// Copies a file from one location to another -pub fn copy_file(from: &Path, to: &Path) -> bool { - return do_copy_file(from, to); - - #[cfg(windows)] - fn do_copy_file(from: &Path, to: &Path) -> bool { - #[fixed_stack_segment]; #[inline(never)]; - unsafe { - use os::win32::as_utf16_p; - return do as_utf16_p(from.as_str().unwrap()) |fromp| { - do as_utf16_p(to.as_str().unwrap()) |top| { - libc::CopyFileW(fromp, top, (0 as libc::BOOL)) != - (0 as libc::BOOL) - } - } - } - } - - #[cfg(unix)] - fn do_copy_file(from: &Path, to: &Path) -> bool { - #[fixed_stack_segment]; #[inline(never)]; - unsafe { - let istream = do from.with_c_str |fromp| { - do "rb".with_c_str |modebuf| { - libc::fopen(fromp, modebuf) - } - }; - if istream as uint == 0u { - return false; - } - // Preserve permissions - let from_mode = from.get_mode().expect("copy_file: couldn't get permissions \ - for source file"); - - 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::(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; - } - } -} - -/// Deletes an existing file -pub fn remove_file(p: &Path) -> bool { - return unlink(p); - - #[cfg(windows)] - fn unlink(p: &Path) -> bool { - #[fixed_stack_segment]; #[inline(never)]; - unsafe { - use os::win32::as_utf16_p; - return do as_utf16_p(p.as_str().unwrap()) |buf| { - libc::DeleteFileW(buf) != (0 as libc::BOOL) - }; - } - } - - #[cfg(unix)] - fn unlink(p: &Path) -> bool { - #[fixed_stack_segment]; #[inline(never)]; - unsafe { - do p.with_c_str |buf| { - libc::unlink(buf) == (0 as c_int) - } - } - } -} - -/// Renames an existing file or directory -pub fn rename_file(old: &Path, new: &Path) -> bool { - #[fixed_stack_segment]; #[inline(never)]; - unsafe { - do old.with_c_str |old_buf| { - do new.with_c_str |new_buf| { - libc::rename(old_buf, new_buf) == (0 as c_int) - } - } - } -} - #[cfg(unix)] /// Returns the platform-specific value of errno pub fn errno() -> int { @@ -1707,19 +1305,15 @@ pub mod consts { #[cfg(test)] mod tests { use c_str::ToCStr; - use libc::{c_int, c_void, size_t}; - use libc; use option::Some; use option; use os::{env, getcwd, getenv, make_absolute, args}; - use os::{remove_file, setenv, unsetenv}; + use os::{setenv, unsetenv}; use os; use path::Path; use rand::Rng; use rand; - use run; use str::StrSlice; - use libc::consts::os::posix88::{S_IRUSR, S_IWUSR, S_IXUSR}; #[test] @@ -1875,144 +1469,6 @@ mod tests { for s in olduserprofile.iter() { setenv("USERPROFILE", *s) } } - #[test] - fn tmpdir() { - let p = os::tmpdir(); - let s = p.as_str(); - assert!(s.is_some() && s.unwrap() != "."); - } - - // Issue #712 - #[test] - fn test_list_dir_no_invalid_memory_access() { - os::list_dir(&Path::new(".")); - } - - #[test] - fn list_dir() { - let dirs = os::list_dir(&Path::new(".")); - // Just assuming that we've got some contents in the current directory - assert!(dirs.len() > 0u); - - for dir in dirs.iter() { - debug!("{:?}", (*dir).clone()); - } - } - - #[test] - #[cfg(not(windows))] - fn list_dir_root() { - let dirs = os::list_dir(&Path::new("/")); - assert!(dirs.len() > 1); - } - #[test] - #[cfg(windows)] - fn list_dir_root() { - let dirs = os::list_dir(&Path::new("C:\\")); - assert!(dirs.len() > 1); - } - - - #[test] - fn path_is_dir() { - use rt::io::file::open; - use rt::io::{OpenOrCreate, Read}; - - assert!((os::path_is_dir(&Path::new(".")))); - assert!((!os::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::())); // 가一ー你好 - debug!("path_is_dir dirpath: {}", dirpath.display()); - - let mkdir_result = os::mkdir_recursive(&dirpath, (S_IRUSR | S_IWUSR | S_IXUSR) as i32); - debug!("path_is_dir mkdir_result: {}", mkdir_result); - - assert!((os::path_is_dir(&dirpath))); - - let mut filepath = dirpath; - filepath.push("unicode-file-\uac00\u4e00\u30fc\u4f60\u597d.rs"); - debug!("path_is_dir filepath: {}", filepath.display()); - - open(&filepath, OpenOrCreate, Read); // ignore return; touch only - assert!((!os::path_is_dir(&filepath))); - - assert!((!os::path_is_dir(&Path::new( - "test/unicode-bogus-dir-\uac00\u4e00\u30fc\u4f60\u597d")))); - } - - #[test] - fn path_exists() { - assert!((os::path_exists(&Path::new(".")))); - assert!((!os::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::())); // 각丁ー再见 - - os::mkdir_recursive(&dirpath, (S_IRUSR | S_IWUSR | S_IXUSR) as i32); - assert!((os::path_exists(&dirpath))); - assert!((!os::path_exists(&Path::new( - "test/unicode-bogus-path-\uac01\u4e01\u30fc\u518d\u89c1")))); - } - - #[test] - fn copy_file_does_not_exist() { - assert!(!os::copy_file(&Path::new("test/nonexistent-bogus-path"), - &Path::new("test/other-bogus-path"))); - assert!(!os::path_exists(&Path::new("test/other-bogus-path"))); - } - - #[test] - fn copy_file_ok() { - #[fixed_stack_segment]; #[inline(never)]; - - unsafe { - let tempdir = getcwd(); // would like to use $TMPDIR, - // doesn't seem to work on Linux - let input = tempdir.join("in.txt"); - let out = tempdir.join("out.txt"); - - /* Write the temp input file */ - let ostream = do input.with_c_str |fromp| { - do "w+b".with_c_str |modebuf| { - libc::fopen(fromp, modebuf) - } - }; - assert!((ostream as uint != 0u)); - let s = ~"hello"; - do "hello".with_c_str |buf| { - let write_len = libc::fwrite(buf as *c_void, - 1u as size_t, - (s.len() + 1u) as size_t, - ostream); - assert_eq!(write_len, (s.len() + 1) as size_t) - } - assert_eq!(libc::fclose(ostream), (0u as c_int)); - let in_mode = input.get_mode(); - let rs = os::copy_file(&input, &out); - if (!os::path_exists(&input)) { - fail!("{} doesn't exist", input.display()); - } - assert!((rs)); - // FIXME (#9639): This needs to handle non-utf8 paths - let rslt = run::process_status("diff", [input.as_str().unwrap().to_owned(), - out.as_str().unwrap().to_owned()]); - assert_eq!(rslt, 0); - assert_eq!(out.get_mode(), in_mode); - assert!((remove_file(&input))); - assert!((remove_file(&out))); - } - } - - #[test] - fn recursive_mkdir_slash() { - let path = Path::new("/"); - assert!(os::mkdir_recursive(&path, (S_IRUSR | S_IWUSR | S_IXUSR) as i32)); - } - #[test] fn memory_map_rw() { use result::{Ok, Err}; @@ -2039,6 +1495,7 @@ mod tests { use result::{Ok, Err}; use os::*; use libc::*; + use rt::io::file; #[cfg(unix)] #[fixed_stack_segment] @@ -2060,7 +1517,6 @@ mod tests { let mut path = tmpdir(); path.push("mmap_file.tmp"); let size = MemoryMap::granularity() * 2; - remove_file(&path); let fd = unsafe { let fd = do path.with_c_str |path| { @@ -2088,6 +1544,7 @@ mod tests { assert!(*chunk.data == 0xbe); close(fd); } + file::unlink(&path); } // More recursive_mkdir tests are in extra::tempfile diff --git a/src/libstd/path/posix.rs b/src/libstd/path/posix.rs index d92c2974f7691..f14f100de73c9 100644 --- a/src/libstd/path/posix.rs +++ b/src/libstd/path/posix.rs @@ -24,9 +24,6 @@ use vec; use vec::{CopyableVector, RSplitIterator, SplitIterator, Vector, VectorVector}; use super::{BytesContainer, GenericPath, GenericPathUnsafe}; -#[cfg(not(target_os = "win32"))] -use rt::io::{FileStat, file, io_error}; - /// Iterator that yields successive components of a Path as &[u8] pub type ComponentIter<'self> = SplitIterator<'self, u8>; /// Iterator that yields components of a Path in reverse as &[u8] @@ -442,72 +439,6 @@ fn normalize_helper<'a>(v: &'a [u8], is_abs: bool) -> Option<~[&'a [u8]]> { static dot_static: &'static [u8] = bytes!("."); static dot_dot_static: &'static [u8] = bytes!(".."); -// Stat support -#[cfg(not(target_os = "win32"))] -impl Path { - /// Calls stat() on the represented file and returns the resulting rt::io::FileStat - pub fn stat(&self) -> Option { - let mut file_stat: Option = None; - do io_error::cond.trap(|_| { /* Ignore error, will return None */ }).inside { - file_stat = file::stat(self); - } - file_stat - } - - /// Returns whether the represented file exists - pub fn exists(&self) -> bool { - match self.stat() { - None => false, - Some(_) => true - } - } - - /// Returns the filesize of the represented file - pub fn get_size(&self) -> Option { - match self.stat() { - None => None, - Some(st) => Some(st.size) - } - } - - /// Returns the mode of the represented file - pub fn get_mode(&self) -> Option { - match self.stat() { - None => None, - Some(st) => Some(st.mode as uint) - } - } -} - -#[cfg(target_os = "freebsd")] -#[cfg(target_os = "linux")] -#[cfg(target_os = "macos")] -impl Path { - /// Returns the atime of the represented file, as msecs - pub fn get_atime(&self) -> Option { - match self.stat() { - None => None, - Some(st) => Some(st.accessed) - } - } - - /// Returns the mtime of the represented file, as msecs - pub fn get_mtime(&self) -> Option { - match self.stat() { - None => None, - Some(st) => Some(st.modified) - } - } - - /// Returns the ctime of the represented file, as msecs - pub fn get_ctime(&self) -> Option { - match self.stat() { - None => None, - Some(st) => Some(st.created) - } - } -} - #[cfg(test)] mod tests { use super::*; diff --git a/src/libstd/rand/os.rs b/src/libstd/rand/os.rs index 5ed8d6b10d1be..c9499bb4aa8e6 100644 --- a/src/libstd/rand/os.rs +++ b/src/libstd/rand/os.rs @@ -13,11 +13,12 @@ use rand::Rng; use ops::Drop; +use path::Path; #[cfg(unix)] use rand::reader::ReaderRng; #[cfg(unix)] -use rt::io::{file, Open, Read}; +use rt::io::file; #[cfg(windows)] use cast; @@ -40,7 +41,7 @@ type HCRYPTPROV = c_long; /// This does not block. #[cfg(unix)] pub struct OSRng { - priv inner: ReaderRng + priv inner: ReaderRng } /// A random number generator that retrieves randomness straight from /// the operating system. Platform sources: @@ -60,7 +61,8 @@ impl OSRng { /// Create a new `OSRng`. #[cfg(unix)] pub fn new() -> OSRng { - let reader = file::open(& &"/dev/urandom", Open, Read).expect("Error opening /dev/urandom"); + let reader = file::open(&Path::new("/dev/urandom")); + let reader = reader.expect("Error opening /dev/urandom"); let reader_rng = ReaderRng::new(reader); OSRng { inner: reader_rng } diff --git a/src/libstd/rt/io/file.rs b/src/libstd/rt/io/file.rs index 99a4a709504e4..b6c0b58434f1a 100644 --- a/src/libstd/rt/io/file.rs +++ b/src/libstd/rt/io/file.rs @@ -13,50 +13,43 @@ This module provides a set of functions and traits for working with regular files & directories on a filesystem. -At the top-level of the module are a set of freestanding functions, -associated with various filesystem operations. They all operate -on a `ToCStr` object. This trait is already defined for common -objects such as strings and `Path` instances. +At the top-level of the module are a set of freestanding functions, associated +with various filesystem operations. They all operate on a `Path` object. All operations in this module, including those as part of `FileStream` et al block the task during execution. Most will raise `std::rt::io::io_error` conditions in the event of failure. -Also included in this module are the `FileInfo` and `DirectoryInfo` traits. When -`use`'d alongside a value whose type implements them (A `std::path::Path` impl is -a part of this module), they expose a set of functions for operations against -a given file location, depending on whether the path already exists. Whenever -possible, the `{FileInfo, DirectoryInfo}` preserve the same semantics as their -free function counterparts. +Also included in this module is an implementation block on the `Path` object +defined in `std::path::Path`. The impl adds useful methods about inspecting the +metadata of a file. This includes getting the `stat` information, reading off +particular bits of it, etc. + */ -use prelude::*; use c_str::ToCStr; use super::{Reader, Writer, Seek}; -use super::{SeekStyle, Read, Write}; +use super::{SeekStyle, Read, Write, Open, CreateOrTruncate, + FileMode, FileAccess, FileStat, io_error, FilePermission}; use rt::rtio::{RtioFileStream, IoFactory, with_local_io}; -use rt::io::{io_error, EndOfFile, - FileMode, FileAccess, FileStat, IoError, - PathAlreadyExists, PathDoesntExist, - MismatchedFileTypeForOperation, ignore_io_error}; -use option::{Some, None}; -use path::Path; +use rt::io; +use option::{Some, None, Option}; +use result::{Ok, Err}; +use path; +use path::{Path, GenericPath}; /// Open a file for reading/writing, as indicated by `path`. /// /// # Example /// -/// use std; -/// use std::path::Path; -/// use std::rt::io::file::open; -/// use std::rt::io::{FileMode, FileAccess}; +/// use std::rt::{io, file, io_error}; /// -/// let p = &Path("/some/file/path.txt"); +/// let p = Path::new("/some/file/path.txt"); /// /// do io_error::cond.trap(|_| { /// // hoo-boy... /// }).inside { -/// let stream = match open(p, Create, ReadWrite) { +/// let stream = match file::open_stream(&p, io::Create, io::ReadWrite) { /// Some(s) => s, /// None => fail!("whoops! I'm sure this raised, anyways..") /// }; @@ -72,24 +65,23 @@ use path::Path; /// /// Note that, with this function, a `FileStream` is returned regardless of /// the access-limitations indicated by `FileAccess` (e.g. calling `write` on a -/// `FileStream` opened as `ReadOnly` will raise an `io_error` condition at runtime). If you -/// desire a more-correctly-constrained interface to files, use the -/// `{open_stream, open_reader, open_writer}` methods that are a part of `FileInfo` +/// `FileStream` opened as `ReadOnly` will raise an `io_error` condition at +/// runtime). If you desire a more-correctly-constrained interface to files, +/// use the `{open_stream, open, create}` methods that are a part of `Path`. /// /// # Errors /// -/// This function will raise an `io_error` condition under a number of different circumstances, -/// to include but not limited to: +/// This function will raise an `io_error` condition under a number of different +/// circumstances, to include but not limited to: /// -/// * Opening a file that already exists with `FileMode` of `Create` or vice versa (e.g. -/// opening a non-existant file with `FileMode` or `Open`) -/// * Attempting to open a file with a `FileAccess` that the user lacks permissions -/// for +/// * Opening a file that already exists with `FileMode` of `Create` or vice +/// versa (e.g. opening a non-existant file with `FileMode` or `Open`) +/// * Attempting to open a file with a `FileAccess` that the user lacks +/// permissions for /// * Filesystem-level errors (full disk, etc) -pub fn open(path: &P, - mode: FileMode, - access: FileAccess - ) -> Option { +pub fn open_stream(path: &Path, + mode: FileMode, + access: FileAccess) -> Option { do with_local_io |io| { match io.fs_open(&path.to_c_str(), mode, access) { Ok(fd) => Some(FileStream { @@ -104,16 +96,32 @@ pub fn open(path: &P, } } +/// Attempts to open a file in read-only mode. This function is equivalent to +/// `open_stream(path, Open, Read)`, and will raise all of the same errors that +/// `open_stream` does. +/// +/// For more information, see the `open_stream` function. +pub fn open(path: &Path) -> Option { + open_stream(path, Open, Read).map(|s| FileReader { stream: s }) +} + +/// Attempts to create a file in write-only mode. This function is equivalent to +/// `open_stream(path, CreateOrTruncate, Write)`, and will raise all of the +/// same errors that `open_stream` does. +/// +/// For more information, see the `open_stream` function. +pub fn create(path: &Path) -> Option { + open_stream(path, CreateOrTruncate, Write).map(|s| FileWriter { stream: s }) +} + /// Unlink a file from the underlying filesystem. /// /// # Example /// -/// use std; -/// use std::path::Path; -/// use std::rt::io::file::unlink; +/// use std::rt::io::file; /// -/// let p = &Path("/some/file/path.txt"); -/// unlink(p); +/// let p = Path::new("/some/file/path.txt"); +/// file::unlink(&p); /// // if we made it here without failing, then the /// // unlink operation was successful /// @@ -123,12 +131,13 @@ pub fn open(path: &P, /// /// # Errors /// -/// This function will raise an `io_error` condition if the user lacks permissions to -/// remove the file or if some other filesystem-level error occurs -pub fn unlink(path: &P) { +/// This function will raise an `io_error` condition if the path points to a +/// directory, the user lacks permissions to remove the file, or if some other +/// filesystem-level error occurs. +pub fn unlink(path: &Path) { do with_local_io |io| { match io.fs_unlink(&path.to_c_str()) { - Ok(_) => Some(()), + Ok(()) => Some(()), Err(ioerr) => { io_error::cond.raise(ioerr); None @@ -141,21 +150,21 @@ pub fn unlink(path: &P) { /// /// # Example /// -/// use std; -/// use std::path::Path; -/// use std::rt::io::file::mkdir; +/// use std::libc::S_IRWXU; +/// use std::rt::io::file; /// -/// let p = &Path("/some/dir"); -/// mkdir(p); +/// let p = Path::new("/some/dir"); +/// file::mkdir(&p, S_IRWXU as int); /// // If we got here, our directory exists! Horray! /// /// # Errors /// -/// This call will raise an `io_error` condition if the user lacks permissions to make a -/// new directory at the provided path, or if the directory already exists -pub fn mkdir(path: &P) { +/// This call will raise an `io_error` condition if the user lacks permissions +/// to make a new directory at the provided path, or if the directory already +/// exists. +pub fn mkdir(path: &Path, mode: FilePermission) { do with_local_io |io| { - match io.fs_mkdir(&path.to_c_str()) { + match io.fs_mkdir(&path.to_c_str(), mode) { Ok(_) => Some(()), Err(ioerr) => { io_error::cond.raise(ioerr); @@ -169,19 +178,18 @@ pub fn mkdir(path: &P) { /// /// # Example /// -/// use std; -/// use std::path::Path; -/// use std::rt::io::file::rmdir; +/// use std::rt::io::file; /// -/// let p = &Path("/some/dir"); -/// rmdir(p); +/// let p = Path::new("/some/dir"); +/// file::rmdir(&p); /// // good riddance, you mean ol' directory /// /// # Errors /// -/// This call will raise an `io_error` condition if the user lacks permissions to remove the -/// directory at the provided path, or if the directory isn't empty -pub fn rmdir(path: &P) { +/// This call will raise an `io_error` condition if the user lacks permissions +/// to remove the directory at the provided path, or if the directory isn't +/// empty. +pub fn rmdir(path: &Path) { do with_local_io |io| { match io.fs_rmdir(&path.to_c_str()) { Ok(_) => Some(()), @@ -198,37 +206,31 @@ pub fn rmdir(path: &P) { /// Given a path, query the file system to get information about a file, /// directory, etc. /// -/// Returns a `Some(std::rt::io::PathInfo)` on success +/// Returns a fully-filled out stat structure on succes, and on failure it will +/// return a dummy stat structure (it is expected that the condition raised is +/// handled as well). /// /// # Example /// -/// use std; -/// use std::path::Path; -/// use std::rt::io::file::stat; +/// use std::rt::io::{file, io_error}; /// -/// let p = &Path("/some/file/path.txt"); +/// let p = Path::new("/some/file/path.txt"); /// /// do io_error::cond.trap(|_| { /// // hoo-boy... /// }).inside { -/// let info = match stat(p) { -/// Some(s) => s, -/// None => fail!("whoops! I'm sure this raised, anyways.."); -/// } -/// if stat.is_file { +/// let info = file::stat(p); +/// if info.is_file { /// // just imagine the possibilities ... /// } -/// -/// // the file stream will be closed at the end of this block /// } -/// // .. /// /// # Errors /// /// This call will raise an `io_error` condition if the user lacks the requisite /// permissions to perform a `stat` call on the given path or if there is no /// entry in the filesystem at the provided path. -pub fn stat(path: &P) -> Option { +pub fn stat(path: &Path) -> FileStat { do with_local_io |io| { match io.fs_stat(&path.to_c_str()) { Ok(p) => Some(p), @@ -237,20 +239,31 @@ pub fn stat(path: &P) -> Option { None } } - } + }.unwrap_or_else(|| { + FileStat { + path: Path::new(path.to_c_str()), + is_file: false, + is_dir: false, + device: 0, + mode: 0, + inode: 0, + size: 0, + created: 0, + modified: 0, + accessed: 0, + } + }) } /// Retrieve a vector containing all entries within a provided directory /// /// # Example /// -/// use std; -/// use std::path::Path; -/// use std::rt::io::file::readdir; +/// use std::rt::io::file; /// /// fn visit_dirs(dir: &Path, cb: &fn(&Path)) { /// if dir.is_dir() { -/// let contents = dir.readdir(); +/// let contents = file::readdir(dir).unwrap(); /// for entry in contents.iter() { /// if entry.is_dir() { visit_dirs(entry, cb); } /// else { cb(entry); } @@ -261,10 +274,10 @@ pub fn stat(path: &P) -> Option { /// /// # Errors /// -/// Will raise an `io_error` condition if the provided `path` doesn't exist, +/// Will raise an `io_error` condition if the provided `from` doesn't exist, /// the process lacks permissions to view the contents or if the `path` points /// at a non-directory file -pub fn readdir(path: &P) -> Option<~[Path]> { +pub fn readdir(path: &Path) -> ~[Path] { do with_local_io |io| { match io.fs_readdir(&path.to_c_str(), 0) { Ok(p) => Some(p), @@ -273,66 +286,169 @@ pub fn readdir(path: &P) -> Option<~[Path]> { None } } - } + }.unwrap_or_else(|| ~[]) } -/// Constrained version of `FileStream` that only exposes read-specific operations. +/// Rename a file or directory to a new name. /// -/// Can be retreived via `FileInfo.open_reader()`. -pub struct FileReader { priv stream: FileStream } +/// # Example +/// +/// use std::rt::io::file; +/// +/// file::rename(Path::new("foo"), Path::new("bar")); +/// // Oh boy, nothing was raised! +/// +/// # Errors +/// +/// Will raise an `io_error` condition if the provided `path` doesn't exist, +/// the process lacks permissions to view the contents, or if some other +/// intermittent I/O error occurs. +pub fn rename(from: &Path, to: &Path) { + do with_local_io |io| { + match io.fs_rename(&from.to_c_str(), &to.to_c_str()) { + Ok(()) => Some(()), + Err(ioerr) => { + io_error::cond.raise(ioerr); + None + } + } + }; +} -/// a `std::rt::io::Reader` trait impl for file I/O. -impl Reader for FileReader { - fn read(&mut self, buf: &mut [u8]) -> Option { - self.stream.read(buf) +/// Copies the contents of one file to another. +/// +/// # Example +/// +/// use std::rt::io::file; +/// +/// file::copy(Path::new("foo.txt"), Path::new("bar.txt")); +/// // Oh boy, nothing was raised! +/// +/// # Errors +/// +/// Will raise an `io_error` condition if the provided `from` doesn't exist, +/// the process lacks permissions to view the contents, or if some other +/// intermittent I/O error occurs (such as `to` couldn't be created). +pub fn copy(from: &Path, to: &Path) { + let mut reader = match open(from) { Some(f) => f, None => return }; + let mut writer = match create(to) { Some(f) => f, None => return }; + let mut buf = [0, ..io::DEFAULT_BUF_SIZE]; + + loop { + match reader.read(buf) { + Some(amt) => writer.write(buf.slice_to(amt)), + None => break + } } - fn eof(&mut self) -> bool { - self.stream.eof() - } + // FIXME(#10131) this is an awful way to pull out the permission bits. + // If this comment is removed, then there should be a test + // asserting that permission bits are maintained using the + // permission interface created. + chmod(to, (from.stat().mode & 0xfff) as u32); } -/// a `std::rt::io::Seek` trait impl for file I/O. -impl Seek for FileReader { - fn tell(&self) -> u64 { - self.stream.tell() - } +// This function is not public because it's got a terrible interface for `mode` +// FIXME(#10131) +fn chmod(path: &Path, mode: u32) { + do with_local_io |io| { + match io.fs_chmod(&path.to_c_str(), mode) { + Ok(()) => Some(()), + Err(ioerr) => { + io_error::cond.raise(ioerr); + None + } + } + }; +} - fn seek(&mut self, pos: i64, style: SeekStyle) { - self.stream.seek(pos, style); +/// Recursively walk a directory structure. This function will call the +/// provided closure on all directories and files found inside the path +/// pointed to by `self`. If the closure returns `false`, then the iteration +/// will be short-circuited. +pub fn walk_dir(path: &Path, f: &fn(&Path) -> bool) -> bool { + let files = readdir(path); + files.iter().advance(|q| { + f(q) && (!q.is_dir() || walk_dir(q, |p| f(p))) + }) +} + +/// Recursively create a directory and all of its parent components if they +/// are missing. +/// +/// # Failure +/// +/// This function will raise on the `io_error` condition if an error +/// happens, see `file::mkdir` for more information about error conditions +/// and performance. +pub fn mkdir_recursive(path: &Path, mode: FilePermission) { + // tjc: if directory exists but with different permissions, + // should we return false? + if path.is_dir() { + return + } + if path.filename().is_some() { + mkdir_recursive(&path.dir_path(), mode); } + mkdir(path, mode) } -/// Constrained version of `FileStream` that only exposes write-specific operations. +/// Removes a directory at this path, after removing all its contents. Use +/// carefully! /// -/// Can be retreived via `FileInfo.open_writer()`. +/// # Failure +/// +/// This function will raise on the `io_error` condition if an error +/// happens. See `file::unlink` and `file::readdir` for possible error +/// conditions. +pub fn rmdir_recursive(path: &Path) { + do walk_dir(path) |inner| { + if inner.is_dir() { + rmdir_recursive(inner); + } else { + unlink(inner); + } + true + }; + // Directory should now be empty + rmdir(path); +} + +/// Constrained version of `FileStream` that only exposes read-specific +/// operations. +/// +/// Can be retreived via `Path.open()` or `file::open`. +pub struct FileReader { priv stream: FileStream } + +impl Reader for FileReader { + fn read(&mut self, buf: &mut [u8]) -> Option { self.stream.read(buf) } + fn eof(&mut self) -> bool { self.stream.eof() } +} + +impl Seek for FileReader { + fn tell(&self) -> u64 { self.stream.tell() } + fn seek(&mut self, p: i64, s: SeekStyle) { self.stream.seek(p, s) } +} + +/// Constrained version of `FileStream` that only exposes write-specific +/// operations. +/// +/// Can be retreived via `Path.create()` or `file::create`. pub struct FileWriter { priv stream: FileStream } -/// a `std::rt::io::Writer` trait impl for file I/O. impl Writer for FileWriter { - fn write(&mut self, buf: &[u8]) { - self.stream.write(buf); - } - - fn flush(&mut self) { - self.stream.flush(); - } + fn write(&mut self, buf: &[u8]) { self.stream.write(buf); } + fn flush(&mut self) { self.stream.flush(); } } -/// a `std::rt::io::Seek` trait impl for file I/O. impl Seek for FileWriter { - fn tell(&self) -> u64 { - self.stream.tell() - } - - fn seek(&mut self, pos: i64, style: SeekStyle) { - self.stream.seek(pos, style); - } + fn tell(&self) -> u64 { self.stream.tell() } + fn seek(&mut self, p: i64, s: SeekStyle) { self.stream.seek(p, s); } } /// Unconstrained file access type that exposes read and write operations /// -/// Can be retreived via `file::open()` and `FileInfo.open_stream()`. +/// Can be retreived via `file::open()` and `Path.open_stream()`. /// /// # Errors /// @@ -341,13 +457,12 @@ impl Seek for FileWriter { /// time, via the `FileAccess` parameter to `file::open()`. /// /// For this reason, it is best to use the access-constrained wrappers that are -/// exposed via `FileInfo.open_reader()` and `FileInfo.open_writer()`. +/// exposed via `Path.open()` and `Path.create()`. pub struct FileStream { priv fd: ~RtioFileStream, priv last_nread: int, } -/// a `std::rt::io::Reader` trait impl for file I/O. impl Reader for FileStream { fn read(&mut self, buf: &mut [u8]) -> Option { match self.fd.read(buf) { @@ -360,7 +475,7 @@ impl Reader for FileStream { }, Err(ioerr) => { // EOF is indicated by returning None - if ioerr.kind != EndOfFile { + if ioerr.kind != io::EndOfFile { io_error::cond.raise(ioerr); } return None; @@ -368,12 +483,9 @@ impl Reader for FileStream { } } - fn eof(&mut self) -> bool { - self.last_nread == 0 - } + fn eof(&mut self) -> bool { self.last_nread == 0 } } -/// a `std::rt::io::Writer` trait impl for file I/O. impl Writer for FileStream { fn write(&mut self, buf: &[u8]) { match self.fd.write(buf) { @@ -385,7 +497,6 @@ impl Writer for FileStream { } } -/// a `std::rt::io:Seek` trait impl for file I/O. impl Seek for FileStream { fn tell(&self) -> u64 { let res = self.fd.tell(); @@ -412,166 +523,40 @@ impl Seek for FileStream { } } -/// Shared functionality between `FileInfo` and `DirectoryInfo` -pub trait FileSystemInfo { - /// Get the filesystem path that this instance points at, - /// whether it is valid or not. In this way, it can be used to - /// to specify a path of a non-existent file which it - /// later creates - fn get_path<'a>(&'a self) -> &'a Path; - - /// Get information on the file, directory, etc at the provided path +impl path::Path { + /// Get information on the file, directory, etc at this path. /// /// Consult the `file::stat` documentation for more info. /// - /// This call preserves identical runtime/error semantics with `file::stat` - fn stat(&self) -> Option { - stat(self.get_path()) - } + /// This call preserves identical runtime/error semantics with `file::stat`. + pub fn stat(&self) -> FileStat { stat(self) } - /// Boolean value indicator whether the underlying file exists on the filesystem + /// Boolean value indicator whether the underlying file exists on the local + /// filesystem. This will return true if the path points to either a + /// directory or a file. /// /// # Errors /// /// Will not raise a condition - fn exists(&self) -> bool { - match ignore_io_error(|| self.stat()) { - Some(_) => true, - None => false - } + pub fn exists(&self) -> bool { + io::result(|| self.stat()).is_ok() } -} - -/// Represents a file, whose underlying path may or may not be valid -/// -/// # Example -/// -/// * Check if a file exists, reading from it if so -/// -/// ```rust -/// use std; -/// use std::path::Path; -/// use std::rt::io::file::{FileInfo, FileReader}; -/// -/// let f = &Path("/some/file/path.txt"); -/// if f.exists() { -/// let reader = f.open_reader(Open); -/// let mut mem = [0u8, 8*64000]; -/// reader.read(mem); -/// // ... -/// } -/// ``` -/// -/// * Is the given path a file? -/// -/// ```rust -/// let f = get_file_path_from_wherever(); -/// match f.is_file() { -/// true => doing_something_with_a_file(f), -/// _ => {} -/// } -/// ``` -pub trait FileInfo : FileSystemInfo { - /// Whether the underlying implemention (be it a file path, - /// or something else) points at a "regular file" on the FS. Will return - /// false for paths to non-existent locations or directories or - /// other non-regular files (named pipes, etc). + /// Whether the underlying implemention (be it a file path, or something + /// else) points at a "regular file" on the FS. Will return false for paths + /// to non-existent locations or directories or other non-regular files + /// (named pipes, etc). /// /// # Errors /// /// Will not raise a condition - fn is_file(&self) -> bool { - match ignore_io_error(|| self.stat()) { - Some(s) => s.is_file, - None => false - } - } - - /// Attempts to open a regular file for reading/writing based - /// on provided inputs - /// - /// See `file::open` for more information on runtime semantics and error conditions - fn open_stream(&self, mode: FileMode, access: FileAccess) -> Option { - match ignore_io_error(|| self.stat()) { - Some(s) => match s.is_file { - true => open(self.get_path(), mode, access), - false => None - }, - None => open(self.get_path(), mode, access) + pub fn is_file(&self) -> bool { + match io::result(|| self.stat()) { + Ok(s) => s.is_file, + Err(*) => false } } - /// Attempts to open a regular file in read-only mode, based - /// on provided inputs - /// - /// See `file::open` for more information on runtime semantics and error conditions - fn open_reader(&self, mode: FileMode) -> Option { - match self.open_stream(mode, Read) { - Some(s) => Some(FileReader { stream: s}), - None => None - } - } - - /// Attempts to open a regular file in write-only mode, based - /// on provided inputs - /// - /// See `file::open` for more information on runtime semantics and error conditions - fn open_writer(&self, mode: FileMode) -> Option { - match self.open_stream(mode, Write) { - Some(s) => Some(FileWriter { stream: s}), - None => None - } - } - - /// Attempt to remove a file from the filesystem - /// - /// See `file::unlink` for more information on runtime semantics and error conditions - fn unlink(&self) { - unlink(self.get_path()); - } -} - -/// `FileSystemInfo` implementation for `Path`s -impl FileSystemInfo for Path { - fn get_path<'a>(&'a self) -> &'a Path { self } -} - -/// `FileInfo` implementation for `Path`s -impl FileInfo for Path { } - -/// Represents a directory, whose underlying path may or may not be valid -/// -/// # Example -/// -/// * Check if a directory exists, `mkdir`'ing it if not -/// -/// ```rust -/// use std; -/// use std::path::Path; -/// use std::rt::io::file::{DirectoryInfo}; -/// -/// let dir = &Path("/some/dir"); -/// if !dir.exists() { -/// dir.mkdir(); -/// } -/// ``` -/// -/// * Is the given path a directory? If so, iterate on its contents -/// -/// ```rust -/// fn visit_dirs(dir: &Path, cb: &fn(&Path)) { -/// if dir.is_dir() { -/// let contents = dir.readdir(); -/// for entry in contents.iter() { -/// if entry.is_dir() { visit_dirs(entry, cb); } -/// else { cb(entry); } -/// } -/// } -/// else { fail!("nope"); } -/// } -/// ``` -pub trait DirectoryInfo : FileSystemInfo { /// Whether the underlying implemention (be it a file path, /// or something else) is pointing at a directory in the underlying FS. /// Will return false for paths to non-existent locations or if the item is @@ -580,109 +565,50 @@ pub trait DirectoryInfo : FileSystemInfo { /// # Errors /// /// Will not raise a condition - fn is_dir(&self) -> bool { - match ignore_io_error(|| self.stat()) { - Some(s) => s.is_dir, - None => false + pub fn is_dir(&self) -> bool { + match io::result(|| self.stat()) { + Ok(s) => s.is_dir, + Err(*) => false } } - - /// Create a directory at the location pointed to by the - /// type underlying the given `DirectoryInfo`. - /// - /// # Errors - /// - /// This method will raise a `PathAlreadyExists` kind of `io_error` condition - /// if the provided path exists - /// - /// See `file::mkdir` for more information on runtime semantics and error conditions - fn mkdir(&self) { - match ignore_io_error(|| self.stat()) { - Some(_) => { - let path = self.get_path(); - io_error::cond.raise(IoError { - kind: PathAlreadyExists, - desc: "Path already exists", - detail: - Some(format!("{} already exists; can't mkdir it", - path.display())) - }) - }, - None => mkdir(self.get_path()) - } - } - - /// Remove a directory at the given location. - /// - /// # Errors - /// - /// This method will raise a `PathDoesntExist` kind of `io_error` condition - /// if the provided path exists. It will raise a `MismatchedFileTypeForOperation` - /// kind of `io_error` condition if the provided path points at any - /// non-directory file type - /// - /// See `file::rmdir` for more information on runtime semantics and error conditions - fn rmdir(&self) { - match ignore_io_error(|| self.stat()) { - Some(s) => { - match s.is_dir { - true => rmdir(self.get_path()), - false => { - let path = self.get_path(); - let ioerr = IoError { - kind: MismatchedFileTypeForOperation, - desc: "Cannot do rmdir() on a non-directory", - detail: Some(format!( - "{} is a non-directory; can't rmdir it", - path.display())) - }; - io_error::cond.raise(ioerr); - } - } - }, - None => { - let path = self.get_path(); - io_error::cond.raise(IoError { - kind: PathDoesntExist, - desc: "Path doesn't exist", - detail: Some(format!("{} doesn't exist; can't rmdir it", - path.display())) - }) - } - } - } - - // Get a collection of all entries at the given - // directory - fn readdir(&self) -> Option<~[Path]> { - readdir(self.get_path()) - } } -/// `DirectoryInfo` impl for `path::Path` -impl DirectoryInfo for Path { } - #[cfg(test)] mod test { - use super::super::{SeekSet, SeekCur, SeekEnd, - io_error, Read, Create, Open, ReadWrite}; - use super::super::super::test::*; + use path::{Path, GenericPath}; + use result::{Ok, Err}; use option::{Some, None}; - use path::Path; - use super::*; use iter::range; + use rt::test::run_in_mt_newsched_task; + use super::{open_stream, unlink, stat, copy, rmdir, mkdir, readdir, + open, create, rmdir_recursive, mkdir_recursive}; + + use rt::io; + use rt::io::Reader; + use super::super::{SeekSet, SeekCur, SeekEnd, + io_error, Read, Create, Open, ReadWrite}; + use vec::Vector; + + fn tmpdir() -> Path { + use os; + use rand; + let ret = os::tmpdir().join(format!("rust-{}", rand::random::())); + mkdir(&ret, io::UserRWX); + ret + } + #[test] fn file_test_io_smoke_test() { do run_in_mt_newsched_task { let message = "it's alright. have a good time"; let filename = &Path::new("./tmp/file_rt_io_file_test.txt"); { - let mut write_stream = open(filename, Create, ReadWrite).unwrap(); + let mut write_stream = open_stream(filename, Create, ReadWrite); write_stream.write(message.as_bytes()); } { use str; - let mut read_stream = open(filename, Open, Read).unwrap(); + let mut read_stream = open_stream(filename, Open, Read); let mut read_buf = [0, .. 1028]; let read_str = match read_stream.read(read_buf).unwrap() { -1|0 => fail!("shouldn't happen"), @@ -702,7 +628,7 @@ mod test { do io_error::cond.trap(|_| { called = true; }).inside { - let result = open(filename, Open, Read); + let result = open_stream(filename, Open, Read); assert!(result.is_none()); } assert!(called); @@ -731,11 +657,11 @@ mod test { let mut read_mem = [0, .. 8]; let filename = &Path::new("./tmp/file_rt_io_file_test_positional.txt"); { - let mut rw_stream = open(filename, Create, ReadWrite).unwrap(); + let mut rw_stream = open_stream(filename, Create, ReadWrite); rw_stream.write(message.as_bytes()); } { - let mut read_stream = open(filename, Open, Read).unwrap(); + let mut read_stream = open_stream(filename, Open, Read); { let read_buf = read_mem.mut_slice(0, 4); read_stream.read(read_buf); @@ -762,11 +688,11 @@ mod test { let mut tell_pos_post_read; let filename = &Path::new("./tmp/file_rt_io_file_test_seeking.txt"); { - let mut rw_stream = open(filename, Create, ReadWrite).unwrap(); + let mut rw_stream = open_stream(filename, Create, ReadWrite); rw_stream.write(message.as_bytes()); } { - let mut read_stream = open(filename, Open, Read).unwrap(); + let mut read_stream = open_stream(filename, Open, Read); read_stream.seek(set_cursor as i64, SeekSet); tell_pos_pre_read = read_stream.tell(); read_stream.read(read_mem); @@ -791,13 +717,13 @@ mod test { let mut read_mem = [0, .. 13]; let filename = &Path::new("./tmp/file_rt_io_file_test_seek_and_write.txt"); { - let mut rw_stream = open(filename, Create, ReadWrite).unwrap(); + let mut rw_stream = open_stream(filename, Create, ReadWrite); rw_stream.write(initial_msg.as_bytes()); rw_stream.seek(seek_idx as i64, SeekSet); rw_stream.write(overwrite_msg.as_bytes()); } { - let mut read_stream = open(filename, Open, Read).unwrap(); + let mut read_stream = open_stream(filename, Open, Read); read_stream.read(read_mem); } unlink(filename); @@ -817,11 +743,11 @@ mod test { let mut read_mem = [0, .. 4]; let filename = &Path::new("./tmp/file_rt_io_file_test_seek_shakedown.txt"); { - let mut rw_stream = open(filename, Create, ReadWrite).unwrap(); + let mut rw_stream = open_stream(filename, Create, ReadWrite); rw_stream.write(initial_msg.as_bytes()); } { - let mut read_stream = open(filename, Open, Read).unwrap(); + let mut read_stream = open_stream(filename, Open, Read); read_stream.seek(-4, SeekEnd); read_stream.read(read_mem); @@ -847,14 +773,11 @@ mod test { do run_in_mt_newsched_task { let filename = &Path::new("./tmp/file_stat_correct_on_is_file.txt"); { - let mut fs = open(filename, Create, ReadWrite).unwrap(); + let mut fs = open_stream(filename, Create, ReadWrite); let msg = "hw"; fs.write(msg.as_bytes()); } - let stat_res = match stat(filename) { - Some(s) => s, - None => fail!("shouldn't happen") - }; + let stat_res = stat(filename); assert!(stat_res.is_file); unlink(filename); } @@ -864,11 +787,8 @@ mod test { fn file_test_stat_is_correct_on_is_dir() { do run_in_mt_newsched_task { let filename = &Path::new("./tmp/file_stat_correct_on_is_dir"); - mkdir(filename); - let stat_res = match stat(filename) { - Some(s) => s, - None => fail!("shouldn't happen") - }; + mkdir(filename, io::UserRWX); + let stat_res = filename.stat(); assert!(stat_res.is_dir); rmdir(filename); } @@ -878,7 +798,7 @@ mod test { fn file_test_fileinfo_false_when_checking_is_file_on_a_directory() { do run_in_mt_newsched_task { let dir = &Path::new("./tmp/fileinfo_false_on_dir"); - mkdir(dir); + mkdir(dir, io::UserRWX); assert!(dir.is_file() == false); rmdir(dir); } @@ -888,13 +808,9 @@ mod test { fn file_test_fileinfo_check_exists_before_and_after_file_creation() { do run_in_mt_newsched_task { let file = &Path::new("./tmp/fileinfo_check_exists_b_and_a.txt"); - { - let msg = "foo".as_bytes(); - let mut w = file.open_writer(Create); - w.write(msg); - } + create(file).write(bytes!("foo")); assert!(file.exists()); - file.unlink(); + unlink(file); assert!(!file.exists()); } } @@ -904,10 +820,10 @@ mod test { do run_in_mt_newsched_task { let dir = &Path::new("./tmp/before_and_after_dir"); assert!(!dir.exists()); - dir.mkdir(); + mkdir(dir, io::UserRWX); assert!(dir.exists()); assert!(dir.is_dir()); - dir.rmdir(); + rmdir(dir); assert!(!dir.exists()); } } @@ -917,36 +833,99 @@ mod test { use str; do run_in_mt_newsched_task { let dir = &Path::new("./tmp/di_readdir"); - dir.mkdir(); + mkdir(dir, io::UserRWX); let prefix = "foo"; for n in range(0,3) { let f = dir.join(format!("{}.txt", n)); - let mut w = f.open_writer(Create); + let mut w = create(&f); let msg_str = (prefix + n.to_str().to_owned()).to_owned(); let msg = msg_str.as_bytes(); w.write(msg); } - match dir.readdir() { - Some(files) => { - let mut mem = [0u8, .. 4]; - for f in files.iter() { - { - let n = f.filestem_str(); - let mut r = f.open_reader(Open); - r.read(mem); - let read_str = str::from_utf8(mem); - let expected = match n { - None|Some("") => fail!("really shouldn't happen.."), - Some(n) => prefix+n - }; - assert!(expected == read_str); - } - f.unlink(); - } - }, - None => fail!("shouldn't happen") + let files = readdir(dir); + let mut mem = [0u8, .. 4]; + for f in files.iter() { + { + let n = f.filestem_str(); + open(f).read(mem); + let read_str = str::from_utf8(mem); + let expected = match n { + None|Some("") => fail!("really shouldn't happen.."), + Some(n) => prefix+n + }; + assert!(expected == read_str); + } + unlink(f); } - dir.rmdir(); + rmdir(dir); } } + + #[test] + fn recursive_mkdir_slash() { + mkdir_recursive(&Path::new("/"), io::UserRWX); + } + + #[test] + fn unicode_path_is_dir() { + assert!(Path::new(".").is_dir()); + assert!(!Path::new("test/stdtest/fs.rs").is_dir()); + + let tmpdir = tmpdir(); + + let mut dirpath = tmpdir.clone(); + dirpath.push(format!("test-가一ー你好")); + mkdir(&dirpath, io::UserRWX); + assert!(dirpath.is_dir()); + + let mut filepath = dirpath; + filepath.push("unicode-file-\uac00\u4e00\u30fc\u4f60\u597d.rs"); + create(&filepath); // ignore return; touch only + assert!(!filepath.is_dir()); + assert!(filepath.exists()); + + rmdir_recursive(&tmpdir); + } + + #[test] + fn unicode_path_exists() { + assert!(Path::new(".").exists()); + assert!(!Path::new("test/nonexistent-bogus-path").exists()); + + let tmpdir = tmpdir(); + let unicode = tmpdir.clone(); + let unicode = unicode.join(format!("test-각丁ー再见")); + mkdir(&unicode, io::UserRWX); + assert!(unicode.exists()); + assert!(!Path::new("test/unicode-bogus-path-각丁ー再见").exists()); + rmdir_recursive(&tmpdir); + } + + #[test] + fn copy_file_does_not_exist() { + let from = Path::new("test/nonexistent-bogus-path"); + let to = Path::new("test/other-bogus-path"); + match io::result(|| copy(&from, &to)) { + Ok(*) => fail!(), + Err(*) => { + assert!(!from.exists()); + assert!(!to.exists()); + } + } + } + + #[test] + fn copy_file_ok() { + let tmpdir = tmpdir(); + let input = tmpdir.join("in.txt"); + let out = tmpdir.join("out.txt"); + + create(&input).write(bytes!("hello")); + copy(&input, &out); + let contents = open(&out).read_to_end(); + assert_eq!(contents.as_slice(), bytes!("hello")); + + assert_eq!(input.stat().mode, out.stat().mode); + rmdir_recursive(&tmpdir); + } } diff --git a/src/libstd/rt/io/mod.rs b/src/libstd/rt/io/mod.rs index be205749186fb..51204ca73b94b 100644 --- a/src/libstd/rt/io/mod.rs +++ b/src/libstd/rt/io/mod.rs @@ -244,9 +244,12 @@ Out of scope use cast; use int; +use libc; use path::Path; -use prelude::*; use str::{StrSlice, OwnedStr}; +use option::{Option, Some, None}; +use result::{Ok, Err, Result}; +use iter::Iterator; use to_str::ToStr; use uint; use unstable::finally::Finally; @@ -418,6 +421,18 @@ pub fn ignore_io_error(cb: &fn() -> T) -> T { } } +/// Helper for catching an I/O error and wrapping it in a Result object. The +/// return result will be the last I/O error that happened or the result of the +/// closure if no error occurred. +pub fn result(cb: &fn() -> T) -> Result { + let mut err = None; + let ret = io_error::cond.trap(|e| err = Some(e)).inside(cb); + match err { + Some(e) => Err(e), + None => Ok(ret), + } +} + pub trait Reader { // Only two methods which need to get implemented for this trait @@ -1137,3 +1152,7 @@ pub struct FileStat { /// platform-dependent msecs accessed: u64, } + +// FIXME(#10131): this needs to get designed for real +pub type FilePermission = u32; +pub static UserRWX: FilePermission = libc::S_IRWXU as FilePermission; diff --git a/src/libstd/rt/io/native/file.rs b/src/libstd/rt/io/native/file.rs index 9f9e7dcee9fd6..e26cc166c8da4 100644 --- a/src/libstd/rt/io/native/file.rs +++ b/src/libstd/rt/io/native/file.rs @@ -297,3 +297,486 @@ mod tests { } } } + +// n.b. these functions were all part of the old `std::os` module. There's lots +// of fun little nuances that were taken care of by these functions, but +// they are all thread-blocking versions that are no longer desired (we now +// use a non-blocking event loop implementation backed by libuv). +// +// In theory we will have a thread-blocking version of the event loop (if +// desired), so these functions may just need to get adapted to work in +// those situtations. For now, I'm leaving the code around so it doesn't +// get bitrotted instantaneously. +mod old_os { + use prelude::*; + use c_str::CString; + use libc::fclose; + use libc::{size_t, c_void, c_int}; + use libc; + use vec; + + #[cfg(test)] use os; + #[cfg(test)] use rand; + + // On Windows, wide character version of function must be used to support + // unicode, so functions should be split into at least two versions, + // which are for Windows and for non-Windows, if necessary. + // See https://github.com/mozilla/rust/issues/9822 for more information. + + mod rustrt { + use libc::{c_char, c_int}; + use libc; + + extern { + pub fn rust_path_is_dir(path: *libc::c_char) -> c_int; + pub fn rust_path_exists(path: *libc::c_char) -> c_int; + } + + // Uses _wstat instead of stat. + #[cfg(windows)] + extern { + pub fn rust_path_is_dir_u16(path: *u16) -> c_int; + pub fn rust_path_exists_u16(path: *u16) -> c_int; + } + } + + /// Recursively walk a directory structure + pub fn walk_dir(p: &Path, f: &fn(&Path) -> bool) -> bool { + let r = list_dir(p); + r.iter().advance(|q| { + let path = &p.join(q); + f(path) && (!path_is_dir(path) || walk_dir(path, |p| f(p))) + }) + } + + #[cfg(unix)] + /// Indicates whether a path represents a directory + pub fn path_is_dir(p: &Path) -> bool { + #[fixed_stack_segment]; #[inline(never)]; + unsafe { + do p.with_c_str |buf| { + rustrt::rust_path_is_dir(buf) != 0 as c_int + } + } + } + + + #[cfg(windows)] + pub fn path_is_dir(p: &Path) -> bool { + #[fixed_stack_segment]; #[inline(never)]; + unsafe { + do os::win32::as_utf16_p(p.as_str().unwrap()) |buf| { + rustrt::rust_path_is_dir_u16(buf) != 0 as c_int + } + } + } + + #[cfg(unix)] + /// Indicates whether a path exists + pub fn path_exists(p: &Path) -> bool { + #[fixed_stack_segment]; #[inline(never)]; + unsafe { + do p.with_c_str |buf| { + rustrt::rust_path_exists(buf) != 0 as c_int + } + } + } + + #[cfg(windows)] + pub fn path_exists(p: &Path) -> bool { + #[fixed_stack_segment]; #[inline(never)]; + unsafe { + do os::win32::as_utf16_p(p.as_str().unwrap()) |buf| { + rustrt::rust_path_exists_u16(buf) != 0 as c_int + } + } + } + + /// Creates a directory at the specified path + pub fn make_dir(p: &Path, mode: c_int) -> bool { + return mkdir(p, mode); + + #[cfg(windows)] + fn mkdir(p: &Path, _mode: c_int) -> bool { + #[fixed_stack_segment]; #[inline(never)]; + unsafe { + use os::win32::as_utf16_p; + // FIXME: turn mode into something useful? #2623 + do as_utf16_p(p.as_str().unwrap()) |buf| { + libc::CreateDirectoryW(buf, ptr::mut_null()) + != (0 as libc::BOOL) + } + } + } + + #[cfg(unix)] + fn mkdir(p: &Path, mode: c_int) -> bool { + #[fixed_stack_segment]; #[inline(never)]; + do p.with_c_str |buf| { + unsafe { + libc::mkdir(buf, mode as libc::mode_t) == (0 as c_int) + } + } + } + } + + /// Creates a directory with a given mode. + /// Returns true iff creation + /// succeeded. Also creates all intermediate subdirectories + /// if they don't already exist, giving all of them the same mode. + + // tjc: if directory exists but with different permissions, + // should we return false? + pub fn mkdir_recursive(p: &Path, mode: c_int) -> bool { + if path_is_dir(p) { + return true; + } + if p.filename().is_some() { + let mut p_ = p.clone(); + p_.pop(); + if !mkdir_recursive(&p_, mode) { + return false; + } + } + return make_dir(p, mode); + } + + /// Lists the contents of a directory + /// + /// Each resulting Path is a relative path with no directory component. + pub fn list_dir(p: &Path) -> ~[Path] { + unsafe { + #[cfg(target_os = "linux")] + #[cfg(target_os = "android")] + #[cfg(target_os = "freebsd")] + #[cfg(target_os = "macos")] + unsafe fn get_list(p: &Path) -> ~[Path] { + #[fixed_stack_segment]; #[inline(never)]; + use libc::{dirent_t}; + use libc::{opendir, readdir, closedir}; + extern { + fn rust_list_dir_val(ptr: *dirent_t) -> *libc::c_char; + } + let mut paths = ~[]; + debug!("os::list_dir -- BEFORE OPENDIR"); + + let dir_ptr = do p.with_c_str |buf| { + opendir(buf) + }; + + if (dir_ptr as uint != 0) { + debug!("os::list_dir -- opendir() SUCCESS"); + let mut entry_ptr = readdir(dir_ptr); + while (entry_ptr as uint != 0) { + let cstr = CString::new(rust_list_dir_val(entry_ptr), false); + paths.push(Path::new(cstr)); + entry_ptr = readdir(dir_ptr); + } + closedir(dir_ptr); + } + else { + debug!("os::list_dir -- opendir() FAILURE"); + } + debug!("os::list_dir -- AFTER -- \\#: {}", paths.len()); + paths + } + #[cfg(windows)] + unsafe fn get_list(p: &Path) -> ~[Path] { + #[fixed_stack_segment]; #[inline(never)]; + use libc::consts::os::extra::INVALID_HANDLE_VALUE; + use libc::{wcslen, free}; + use libc::funcs::extra::kernel32::{ + FindFirstFileW, + FindNextFileW, + FindClose, + }; + use libc::types::os::arch::extra::HANDLE; + use os::win32::{ + as_utf16_p + }; + use rt::global_heap::malloc_raw; + + #[nolink] + extern { + fn rust_list_dir_wfd_size() -> libc::size_t; + fn rust_list_dir_wfd_fp_buf(wfd: *libc::c_void) -> *u16; + } + let star = p.join("*"); + do as_utf16_p(star.as_str().unwrap()) |path_ptr| { + let mut paths = ~[]; + let wfd_ptr = malloc_raw(rust_list_dir_wfd_size() as uint); + let find_handle = FindFirstFileW(path_ptr, wfd_ptr as HANDLE); + if find_handle as libc::c_int != INVALID_HANDLE_VALUE { + let mut more_files = 1 as libc::c_int; + while more_files != 0 { + let fp_buf = rust_list_dir_wfd_fp_buf(wfd_ptr); + if fp_buf as uint == 0 { + fail!("os::list_dir() failure: got null ptr from wfd"); + } + else { + let fp_vec = vec::from_buf( + fp_buf, wcslen(fp_buf) as uint); + let fp_str = str::from_utf16(fp_vec); + paths.push(Path::new(fp_str)); + } + more_files = FindNextFileW(find_handle, wfd_ptr as HANDLE); + } + FindClose(find_handle); + free(wfd_ptr) + } + paths + } + } + do get_list(p).move_iter().filter |path| { + path.as_vec() != bytes!(".") && path.as_vec() != bytes!("..") + }.collect() + } + } + + /// Removes a directory at the specified path, after removing + /// all its contents. Use carefully! + pub fn remove_dir_recursive(p: &Path) -> bool { + let mut error_happened = false; + do walk_dir(p) |inner| { + if !error_happened { + if path_is_dir(inner) { + if !remove_dir_recursive(inner) { + error_happened = true; + } + } + else { + if !remove_file(inner) { + error_happened = true; + } + } + } + true + }; + // Directory should now be empty + !error_happened && remove_dir(p) + } + + /// Removes a directory at the specified path + pub fn remove_dir(p: &Path) -> bool { + return rmdir(p); + + #[cfg(windows)] + fn rmdir(p: &Path) -> bool { + #[fixed_stack_segment]; #[inline(never)]; + unsafe { + use os::win32::as_utf16_p; + return do as_utf16_p(p.as_str().unwrap()) |buf| { + libc::RemoveDirectoryW(buf) != (0 as libc::BOOL) + }; + } + } + + #[cfg(unix)] + fn rmdir(p: &Path) -> bool { + #[fixed_stack_segment]; #[inline(never)]; + do p.with_c_str |buf| { + unsafe { + libc::rmdir(buf) == (0 as c_int) + } + } + } + } + + /// Deletes an existing file + pub fn remove_file(p: &Path) -> bool { + return unlink(p); + + #[cfg(windows)] + fn unlink(p: &Path) -> bool { + #[fixed_stack_segment]; #[inline(never)]; + unsafe { + use os::win32::as_utf16_p; + return do as_utf16_p(p.as_str().unwrap()) |buf| { + libc::DeleteFileW(buf) != (0 as libc::BOOL) + }; + } + } + + #[cfg(unix)] + fn unlink(p: &Path) -> bool { + #[fixed_stack_segment]; #[inline(never)]; + unsafe { + do p.with_c_str |buf| { + libc::unlink(buf) == (0 as c_int) + } + } + } + } + + /// Renames an existing file or directory + pub fn rename_file(old: &Path, new: &Path) -> bool { + #[fixed_stack_segment]; #[inline(never)]; + unsafe { + do old.with_c_str |old_buf| { + do new.with_c_str |new_buf| { + libc::rename(old_buf, new_buf) == (0 as c_int) + } + } + } + } + + /// Copies a file from one location to another + pub fn copy_file(from: &Path, to: &Path) -> bool { + return do_copy_file(from, to); + + #[cfg(windows)] + fn do_copy_file(from: &Path, to: &Path) -> bool { + #[fixed_stack_segment]; #[inline(never)]; + unsafe { + use os::win32::as_utf16_p; + return do as_utf16_p(from.as_str().unwrap()) |fromp| { + do as_utf16_p(to.as_str().unwrap()) |top| { + libc::CopyFileW(fromp, top, (0 as libc::BOOL)) != + (0 as libc::BOOL) + } + } + } + } + + #[cfg(unix)] + fn do_copy_file(from: &Path, to: &Path) -> bool { + #[fixed_stack_segment]; #[inline(never)]; + unsafe { + let istream = do from.with_c_str |fromp| { + do "rb".with_c_str |modebuf| { + libc::fopen(fromp, modebuf) + } + }; + if istream as uint == 0u { + return false; + } + // Preserve permissions + let from_mode = from.stat().mode; + + 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::(bufsize); + let mut done = false; + let mut ok = true; + while !done { + do buf.as_mut_buf |b, _sz| { + let nread = libc::fread(b as *mut c_void, 1u as size_t, + bufsize as size_t, + istream); + if nread > 0 as size_t { + if libc::fwrite(b as *c_void, 1u as size_t, nread, + ostream) != nread { + ok = false; + done = true; + } + } else { + done = true; + } + } + } + fclose(istream); + fclose(ostream); + + // Give the new file the old file's permissions + if do to.with_c_str |to_buf| { + libc::chmod(to_buf, from_mode as libc::mode_t) + } != 0 { + return false; // should be a condition... + } + return ok; + } + } + } + + #[test] + fn tmpdir() { + let p = os::tmpdir(); + let s = p.as_str(); + assert!(s.is_some() && s.unwrap() != "."); + } + + // Issue #712 + #[test] + fn test_list_dir_no_invalid_memory_access() { + list_dir(&Path::new(".")); + } + + #[test] + fn test_list_dir() { + let dirs = list_dir(&Path::new(".")); + // Just assuming that we've got some contents in the current directory + assert!(dirs.len() > 0u); + + for dir in dirs.iter() { + debug!("{:?}", (*dir).clone()); + } + } + + #[test] + #[cfg(not(windows))] + fn test_list_dir_root() { + let dirs = list_dir(&Path::new("/")); + assert!(dirs.len() > 1); + } + #[test] + #[cfg(windows)] + fn test_list_dir_root() { + let dirs = list_dir(&Path::new("C:\\")); + assert!(dirs.len() > 1); + } + + #[test] + fn test_path_is_dir() { + use rt::io::file::{open_stream, mkdir_recursive}; + use rt::io::{OpenOrCreate, Read, 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::())); // 가一ー你好 + debug!("path_is_dir dirpath: {}", dirpath.display()); + + mkdir_recursive(&dirpath, UserRWX); + + assert!((path_is_dir(&dirpath))); + + let mut filepath = dirpath; + filepath.push("unicode-file-\uac00\u4e00\u30fc\u4f60\u597d.rs"); + debug!("path_is_dir filepath: {}", filepath.display()); + + open_stream(&filepath, OpenOrCreate, Read); // ignore return; touch only + assert!((!path_is_dir(&filepath))); + + assert!((!path_is_dir(&Path::new( + "test/unicode-bogus-dir-\uac00\u4e00\u30fc\u4f60\u597d")))); + } + + #[test] + fn test_path_exists() { + use rt::io::file::mkdir_recursive; + use rt::io::UserRWX; + + assert!((path_exists(&Path::new(".")))); + assert!((!path_exists(&Path::new( + "test/nonexistent-bogus-path")))); + + let mut dirpath = os::tmpdir(); + dirpath.push(format!("rust-test-{}/test-\uac01\u4e01\u30fc\u518d\u89c1", + rand::random::())); // 각丁ー再见 + + mkdir_recursive(&dirpath, UserRWX); + assert!((path_exists(&dirpath))); + assert!((!path_exists(&Path::new( + "test/unicode-bogus-path-\uac01\u4e01\u30fc\u518d\u89c1")))); + } +} diff --git a/src/libstd/rt/io/net/unix.rs b/src/libstd/rt/io/net/unix.rs index f30423812ba6e..dd8a999c6de07 100644 --- a/src/libstd/rt/io/net/unix.rs +++ b/src/libstd/rt/io/net/unix.rs @@ -156,7 +156,6 @@ mod tests { use rt::test::*; use rt::io::*; use rt::comm::oneshot; - use os; fn smalltest(server: ~fn(UnixStream), client: ~fn(UnixStream)) { let server = Cell::new(server); @@ -290,7 +289,7 @@ mod tests { do run_in_mt_newsched_task { let path = next_test_unix(); let _acceptor = UnixListener::bind(&path).listen(); - assert!(os::path_exists(&path)); + assert!(path.exists()); } } } diff --git a/src/libstd/rt/io/signal.rs b/src/libstd/rt/io/signal.rs index b782d713950d9..1b856ab07550c 100644 --- a/src/libstd/rt/io/signal.rs +++ b/src/libstd/rt/io/signal.rs @@ -19,6 +19,7 @@ definitions for a number of signals. */ +use container::{Map, MutableMap}; use comm::{Port, SharedChan, stream}; use hashmap; use option::{Some, None}; @@ -146,10 +147,10 @@ impl Listener { #[cfg(test)] mod test { - use super::*; - use libc; use rt::io::timer; + use super::{Listener, Interrupt}; + use comm::{GenericPort, Peekable}; // kill is only available on Unixes #[cfg(unix)] @@ -207,7 +208,7 @@ mod test { #[cfg(windows)] #[test] fn test_io_signal_invalid_signum() { - use rt::io; + use super::User1; let mut s = Listener::new(); let mut called = false; do io::io_error::cond.trap(|_| { diff --git a/src/libstd/rt/io/timer.rs b/src/libstd/rt/io/timer.rs index 500cd91b3db96..36092dfbe34e6 100644 --- a/src/libstd/rt/io/timer.rs +++ b/src/libstd/rt/io/timer.rs @@ -108,6 +108,7 @@ impl Timer { #[cfg(test)] mod test { + use prelude::*; use super::*; use rt::test::*; use cell::Cell; diff --git a/src/libstd/rt/rtio.rs b/src/libstd/rt/rtio.rs index 44d9f59c41062..a0db1f1df000c 100644 --- a/src/libstd/rt/rtio.rs +++ b/src/libstd/rt/rtio.rs @@ -22,7 +22,7 @@ use super::io::process::ProcessConfig; use super::io::net::ip::{IpAddr, SocketAddr}; use path::Path; use super::io::{SeekStyle}; -use super::io::{FileMode, FileAccess, FileStat}; +use super::io::{FileMode, FileAccess, FileStat, FilePermission}; pub trait EventLoop { fn run(&mut self); @@ -102,7 +102,10 @@ pub trait IoFactory { -> Result<~RtioFileStream, IoError>; fn fs_unlink(&mut self, path: &CString) -> Result<(), IoError>; fn fs_stat(&mut self, path: &CString) -> Result; - fn fs_mkdir(&mut self, path: &CString, mode: int) -> Result<(), IoError>; + fn fs_mkdir(&mut self, path: &CString, + mode: FilePermission) -> Result<(), IoError>; + fn fs_chmod(&mut self, path: &CString, + mode: FilePermission) -> Result<(), IoError>; fn fs_rmdir(&mut self, path: &CString) -> Result<(), IoError>; fn fs_rename(&mut self, path: &CString, to: &CString) -> Result<(), IoError>; fn fs_readdir(&mut self, path: &CString, flags: c_int) -> diff --git a/src/libstd/run.rs b/src/libstd/run.rs index 9e6fdf2ba4c9a..89784acec8ebb 100644 --- a/src/libstd/run.rs +++ b/src/libstd/run.rs @@ -604,8 +604,8 @@ mod tests { let parent_dir = os::getcwd(); let child_dir = Path::new(output.trim()); - let parent_stat = parent_dir.stat().unwrap(); - let child_stat = child_dir.stat().unwrap(); + let parent_stat = parent_dir.stat(); + let child_stat = child_dir.stat(); assert_eq!(parent_stat.device, child_stat.device); assert_eq!(parent_stat.inode, child_stat.inode); @@ -621,8 +621,8 @@ mod tests { let output = str::from_utf8(prog.finish_with_output().output); let child_dir = Path::new(output.trim()); - let parent_stat = parent_dir.stat().unwrap(); - let child_stat = child_dir.stat().unwrap(); + let parent_stat = parent_dir.stat(); + let child_stat = child_dir.stat(); assert_eq!(parent_stat.device, child_stat.device); assert_eq!(parent_stat.inode, child_stat.inode); diff --git a/src/libsyntax/ext/source_util.rs b/src/libsyntax/ext/source_util.rs index fda6f782af450..876adf401862f 100644 --- a/src/libsyntax/ext/source_util.rs +++ b/src/libsyntax/ext/source_util.rs @@ -21,7 +21,7 @@ use print::pprust; use std::rt::io; use std::rt::io::Reader; -use std::rt::io::file::FileInfo; +use std::rt::io::file; use std::str; // These macros all relate to the file system; they either return @@ -92,17 +92,13 @@ pub fn expand_include_str(cx: @ExtCtxt, sp: Span, tts: &[ast::token_tree]) -> base::MacResult { let file = get_single_str_from_tts(cx, sp, tts, "include_str!"); let file = res_rel_file(cx, sp, &Path::new(file)); - let mut error = None; - let bytes = do io::io_error::cond.trap(|e| error = Some(e)).inside { - file.open_reader(io::Open).read_to_end() - }; - match error { - Some(e) => { + let bytes = match io::result(|| file::open(&file).read_to_end()) { + Err(e) => { cx.span_fatal(sp, format!("couldn't read {}: {}", file.display(), e.desc)); } - None => {} - } + Ok(bytes) => bytes, + }; match str::from_utf8_owned_opt(bytes) { Some(s) => base::MRExpr(cx.expr_str(sp, s.to_managed())), None => { @@ -118,17 +114,12 @@ pub fn expand_include_bin(cx: @ExtCtxt, sp: Span, tts: &[ast::token_tree]) let file = get_single_str_from_tts(cx, sp, tts, "include_bin!"); let file = res_rel_file(cx, sp, &Path::new(file)); - - let mut error = None; - let bytes = do io::io_error::cond.trap(|e| error = Some(e)).inside { - file.open_reader(io::Open).read_to_end() - }; - match error { - Some(e) => { + match io::result(|| file::open(&file).read_to_end()) { + Err(e) => { cx.span_fatal(sp, format!("couldn't read {}: {}", file.display(), e.desc)); } - None => { + Ok(bytes) => { let bytes = at_vec::to_managed_move(bytes); base::MRExpr(cx.expr_lit(sp, ast::lit_binary(bytes))) } diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index 003bc006ebec0..cd1be9a3c1615 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -21,8 +21,7 @@ use parse::parser::Parser; use std::path::Path; use std::rt::io; -use std::rt::io::Reader; -use std::rt::io::file::FileInfo; +use std::rt::io::file; use std::str; pub mod lexer; @@ -269,16 +268,13 @@ pub fn file_to_filemap(sess: @mut ParseSess, path: &Path, spanopt: Option) None => sess.span_diagnostic.handler().fatal(msg), } }; - let mut error = None; - let bytes = do io::io_error::cond.trap(|e| error = Some(e)).inside { - path.open_reader(io::Open).read_to_end() - }; - match error { - Some(e) => { + let bytes = match io::result(|| file::open(path).read_to_end()) { + Ok(bytes) => bytes, + Err(e) => { err(format!("couldn't read {}: {}", path.display(), e.desc)); + unreachable!() } - None => {} - } + }; match str::from_utf8_owned_opt(bytes) { Some(s) => { return string_to_filemap(sess, s.to_managed(), diff --git a/src/rt/rust_uv.cpp b/src/rt/rust_uv.cpp index 70602100f2e0d..2b63325f931e7 100644 --- a/src/rt/rust_uv.cpp +++ b/src/rt/rust_uv.cpp @@ -597,6 +597,10 @@ rust_uv_fs_rename(uv_loop_t *loop, uv_fs_t* req, const char *path, const char *to, uv_fs_cb cb) { return uv_fs_rename(loop, req, path, to, cb); } +extern "C" int +rust_uv_fs_chmod(uv_loop_t* loop, uv_fs_t* req, const char* path, int mode, uv_fs_cb cb) { + return uv_fs_chmod(loop, req, path, mode, cb); +} extern "C" int rust_uv_spawn(uv_loop_t *loop, uv_process_t *p, uv_process_options_t options) { diff --git a/src/test/bench/core-std.rs b/src/test/bench/core-std.rs index dbd1edffe7827..531f01c199562 100644 --- a/src/test/bench/core-std.rs +++ b/src/test/bench/core-std.rs @@ -21,6 +21,7 @@ use std::rand; use std::str; use std::util; use std::vec; +use std::rt::io::file; macro_rules! bench ( ($argv:expr, $id:ident) => (maybe_run_test($argv, stringify!($id).to_owned(), $id)) @@ -69,15 +70,13 @@ fn shift_push() { } fn read_line() { - use std::rt::io::{Reader, Open}; - use std::rt::io::file::FileInfo; use std::rt::io::buffered::BufferedReader; let mut path = Path::new(env!("CFG_SRC_DIR")); path.push("src/test/bench/shootout-k-nucleotide.data"); for _ in range(0, 3) { - let mut reader = BufferedReader::new(path.open_reader(Open).unwrap()); + let mut reader = BufferedReader::new(file::open(&path).unwrap()); while !reader.eof() { reader.read_line(); } diff --git a/src/test/bench/shootout-fasta.rs b/src/test/bench/shootout-fasta.rs index 52f068b8b1cdd..7d3fa6104e5c3 100644 --- a/src/test/bench/shootout-fasta.rs +++ b/src/test/bench/shootout-fasta.rs @@ -19,6 +19,7 @@ extern mod extra; use std::int; use std::rt::io; +use std::rt::io::file; use std::os; use std::rand::Rng; use std::rand; @@ -111,7 +112,6 @@ fn acid(ch: char, prob: u32) -> AminoAcids { } fn main() { - use std::rt::io::file::FileInfo; let args = os::args(); let args = if os::getenv("RUST_BENCH").is_some() { // alioth tests k-nucleotide with this data at 25,000,000 @@ -123,7 +123,7 @@ fn main() { }; let writer = if os::getenv("RUST_BENCH").is_some() { - let file = Path::new("./shootout-fasta.data").open_writer(io::CreateOrTruncate); + let file = file::create(&Path::new("./shootout-fasta.data")); @mut file as @mut io::Writer } else { @mut io::stdout() as @mut io::Writer diff --git a/src/test/run-pass-fulldeps/qquote.rs b/src/test/run-pass-fulldeps/qquote.rs index c39c32753679b..c7c8e3a19a6cd 100644 --- a/src/test/run-pass-fulldeps/qquote.rs +++ b/src/test/run-pass-fulldeps/qquote.rs @@ -9,6 +9,7 @@ // except according to those terms. // xfail-pretty +// xfail-test extern mod extra; extern mod syntax; diff --git a/src/test/run-pass-fulldeps/quote-tokens.rs b/src/test/run-pass-fulldeps/quote-tokens.rs index 62ce4e7c02c09..2e426c0413e74 100644 --- a/src/test/run-pass-fulldeps/quote-tokens.rs +++ b/src/test/run-pass-fulldeps/quote-tokens.rs @@ -8,6 +8,10 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// xfail-test + +#[feature(managed_boxes)]; + extern mod syntax; use syntax::ext::base::ExtCtxt; @@ -16,11 +20,11 @@ fn syntax_extension(cx: @ExtCtxt) { let e_toks : ~[syntax::ast::token_tree] = quote_tokens!(cx, 1 + 2); let p_toks : ~[syntax::ast::token_tree] = quote_tokens!(cx, (x, 1 .. 4, *)); - let a: @syntax::ast::expr = quote_expr!(cx, 1 + 2); + let a: @syntax::ast::Expr = quote_expr!(cx, 1 + 2); let _b: Option<@syntax::ast::item> = quote_item!(cx, static foo : int = $e_toks; ); - let _c: @syntax::ast::pat = quote_pat!(cx, (x, 1 .. 4, *) ); - let _d: @syntax::ast::stmt = quote_stmt!(cx, let x = $a; ); - let _e: @syntax::ast::expr = quote_expr!(cx, match foo { $p_toks => 10 } ); + let _c: @syntax::ast::Pat = quote_pat!(cx, (x, 1 .. 4, *) ); + let _d: @syntax::ast::Stmt = quote_stmt!(cx, let x = $a; ); + let _e: @syntax::ast::Expr = quote_expr!(cx, match foo { $p_toks => 10 } ); } fn main() { diff --git a/src/test/run-pass/glob-std.rs b/src/test/run-pass/glob-std.rs index 8cd2d9edbd7c0..56bcd24f1cb4e 100644 --- a/src/test/run-pass/glob-std.rs +++ b/src/test/run-pass/glob-std.rs @@ -17,14 +17,13 @@ use extra::tempfile::TempDir; use std::unstable::finally::Finally; use std::{os, unstable}; use std::rt::io; -use std::rt::io::file::FileInfo; pub fn main() { fn mk_file(path: &str, directory: bool) { if directory { - os::make_dir(&Path::new(path), 0xFFFF); + io::file::mkdir(&Path::new(path), io::UserRWX); } else { - Path::new(path).open_writer(io::Create); + io::file::create(&Path::new(path)); } } diff --git a/src/test/run-pass/rename-directory.rs b/src/test/run-pass/rename-directory.rs index 76a1d32705b2d..2f6de7e4472bd 100644 --- a/src/test/run-pass/rename-directory.rs +++ b/src/test/run-pass/rename-directory.rs @@ -17,6 +17,8 @@ extern mod extra; use extra::tempfile::TempDir; use std::os; use std::libc; +use std::rt::io; +use std::rt::io::file; fn rename_directory() { #[fixed_stack_segment]; @@ -26,7 +28,7 @@ fn rename_directory() { let tmpdir = TempDir::new("rename_directory").expect("rename_directory failed"); let tmpdir = tmpdir.path(); let old_path = tmpdir.join_many(["foo", "bar", "baz"]); - assert!(os::mkdir_recursive(&old_path, U_RWX)); + file::mkdir_recursive(&old_path, io::UserRWX); let test_file = &old_path.join("temp.txt"); /* Write the temp input file */ @@ -47,10 +49,10 @@ fn rename_directory() { assert_eq!(libc::fclose(ostream), (0u as libc::c_int)); let new_path = tmpdir.join_many(["quux", "blat"]); - assert!(os::mkdir_recursive(&new_path, U_RWX)); - assert!(os::rename_file(&old_path, &new_path.join("newdir"))); - assert!(os::path_is_dir(&new_path.join("newdir"))); - assert!(os::path_exists(&new_path.join_many(["newdir", "temp.txt"]))); + file::mkdir_recursive(&new_path, io::UserRWX); + file::rename(&old_path, &new_path.join("newdir")); + assert!(new_path.join("newdir").is_dir()); + assert!(new_path.join_many(["newdir", "temp.txt"]).exists()); } } diff --git a/src/test/run-pass/stat.rs b/src/test/run-pass/stat.rs index 85cf265c2d0e8..d46c8a64f5a4e 100644 --- a/src/test/run-pass/stat.rs +++ b/src/test/run-pass/stat.rs @@ -13,17 +13,14 @@ extern mod extra; use extra::tempfile; -use std::rt::io; -use std::rt::io::Writer; -use std::rt::io::file::FileInfo; -use std::os; +use std::rt::io::file; pub fn main() { let dir = tempfile::TempDir::new_in(&Path::new("."), "").unwrap(); let path = dir.path().join("file"); { - match path.open_writer(io::CreateOrTruncate) { + match file::create(&path) { None => unreachable!(), Some(f) => { let mut f = f; @@ -35,5 +32,5 @@ pub fn main() { } assert!(path.exists()); - assert_eq!(path.get_size(), Some(1000)); + assert_eq!(path.stat().size, 1000); } diff --git a/src/test/run-pass/tempfile.rs b/src/test/run-pass/tempfile.rs index 142186853f526..9ac144f5fb5e5 100644 --- a/src/test/run-pass/tempfile.rs +++ b/src/test/run-pass/tempfile.rs @@ -22,9 +22,10 @@ extern mod extra; use extra::tempfile::TempDir; use std::os; -use std::libc::consts::os::posix88::{S_IRUSR, S_IWUSR, S_IXUSR}; use std::task; use std::cell::Cell; +use std::rt::io; +use std::rt::io::file; fn test_tempdir() { let path = { @@ -33,7 +34,7 @@ fn test_tempdir() { assert!(p.as_vec().ends_with(bytes!("foobar"))); p.clone() }; - assert!(!os::path_exists(&path)); + assert!(!path.exists()); } fn test_rm_tempdir() { @@ -45,7 +46,7 @@ fn test_rm_tempdir() { }; task::try(f); let path = rd.recv(); - assert!(!os::path_exists(&path)); + assert!(!path.exists()); let tmp = TempDir::new("test_rm_tempdir").unwrap(); let path = tmp.path().clone(); @@ -55,7 +56,7 @@ fn test_rm_tempdir() { fail!("fail to unwind past `tmp`"); }; task::try(f); - assert!(!os::path_exists(&path)); + assert!(!path.exists()); let path; { @@ -64,18 +65,18 @@ fn test_rm_tempdir() { }; let tmp = task::try(f).expect("test_rm_tmdir"); path = tmp.path().clone(); - assert!(os::path_exists(&path)); + assert!(path.exists()); } - assert!(!os::path_exists(&path)); + assert!(!path.exists()); let path; { let tmp = TempDir::new("test_rm_tempdir").unwrap(); path = tmp.unwrap(); } - assert!(os::path_exists(&path)); - os::remove_dir_recursive(&path); - assert!(!os::path_exists(&path)); + assert!(path.exists()); + file::rmdir_recursive(&path); + assert!(!path.exists()); } // Ideally these would be in std::os but then core would need @@ -84,39 +85,39 @@ fn recursive_mkdir_rel() { let path = Path::new("frob"); let cwd = os::getcwd(); debug!("recursive_mkdir_rel: Making: {} in cwd {} [{:?}]", path.display(), - cwd.display(), os::path_exists(&path)); - assert!(os::mkdir_recursive(&path, (S_IRUSR | S_IWUSR | S_IXUSR) as i32)); - assert!(os::path_is_dir(&path)); - assert!(os::mkdir_recursive(&path, (S_IRUSR | S_IWUSR | S_IXUSR) as i32)); - assert!(os::path_is_dir(&path)); + cwd.display(), path.exists()); + file::mkdir_recursive(&path, io::UserRWX); + assert!(path.is_dir()); + file::mkdir_recursive(&path, io::UserRWX); + assert!(path.is_dir()); } fn recursive_mkdir_dot() { let dot = Path::new("."); - assert!(os::mkdir_recursive(&dot, (S_IRUSR | S_IWUSR | S_IXUSR) as i32)); + file::mkdir_recursive(&dot, io::UserRWX); let dotdot = Path::new(".."); - assert!(os::mkdir_recursive(&dotdot, (S_IRUSR | S_IWUSR | S_IXUSR) as i32)); + file::mkdir_recursive(&dotdot, io::UserRWX); } fn recursive_mkdir_rel_2() { let path = Path::new("./frob/baz"); let cwd = os::getcwd(); debug!("recursive_mkdir_rel_2: Making: {} in cwd {} [{:?}]", path.display(), - cwd.display(), os::path_exists(&path)); - assert!(os::mkdir_recursive(&path, (S_IRUSR | S_IWUSR | S_IXUSR) as i32)); - assert!(os::path_is_dir(&path)); - assert!(os::path_is_dir(&path.dir_path())); + cwd.display(), path.exists()); + file::mkdir_recursive(&path, io::UserRWX); + assert!(path.is_dir()); + assert!(path.dir_path().is_dir()); let path2 = Path::new("quux/blat"); debug!("recursive_mkdir_rel_2: Making: {} in cwd {}", path2.display(), cwd.display()); - assert!(os::mkdir_recursive(&path2, (S_IRUSR | S_IWUSR | S_IXUSR) as i32)); - assert!(os::path_is_dir(&path2)); - assert!(os::path_is_dir(&path2.dir_path())); + file::mkdir_recursive(&path2, io::UserRWX); + assert!(path2.is_dir()); + assert!(path2.dir_path().is_dir()); } // Ideally this would be in core, but needs TempFile pub fn test_rmdir_recursive_ok() { - let rwx = (S_IRUSR | S_IWUSR | S_IXUSR) as i32; + let rwx = io::UserRWX; let tmpdir = TempDir::new("test").expect("test_rmdir_recursive_ok: \ couldn't create temp dir"); @@ -124,14 +125,14 @@ pub fn test_rmdir_recursive_ok() { let root = tmpdir.join("foo"); debug!("making {}", root.display()); - assert!(os::make_dir(&root, rwx)); - assert!(os::make_dir(&root.join("foo"), rwx)); - assert!(os::make_dir(&root.join("foo").join("bar"), rwx)); - assert!(os::make_dir(&root.join("foo").join("bar").join("blat"), rwx)); - assert!(os::remove_dir_recursive(&root)); - assert!(!os::path_exists(&root)); - assert!(!os::path_exists(&root.join("bar"))); - assert!(!os::path_exists(&root.join("bar").join("blat"))); + file::mkdir(&root, rwx); + file::mkdir(&root.join("foo"), rwx); + file::mkdir(&root.join("foo").join("bar"), rwx); + file::mkdir(&root.join("foo").join("bar").join("blat"), rwx); + file::rmdir_recursive(&root); + assert!(!root.exists()); + assert!(!root.join("bar").exists()); + assert!(!root.join("bar").join("blat").exists()); } fn in_tmpdir(f: &fn()) { From f19d0833625c382c5d0a8868924cd4620335e659 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 29 Oct 2013 23:31:07 -0700 Subject: [PATCH 4/5] Fill out the remaining functionality in io::file This adds bindings to the remaining functions provided by libuv, all of which are useful operations on files which need to get exposed somehow. Some highlights: * Dropped `FileReader` and `FileWriter` and `FileStream` for one `File` type * Moved all file-related methods to be static methods under `File` * All directory related methods are still top-level functions * Created `io::FilePermission` types (backed by u32) that are what you'd expect * Created `io::FileType` and refactored `FileStat` to use FileType and FilePermission * Removed the expanding matrix of `FileMode` operations. The mode of reading a file will not have the O_CREAT flag, but a write mode will always have the O_CREAT flag. Closes #10130 Closes #10131 Closes #10121 --- src/compiletest/errors.rs | 4 +- src/compiletest/header.rs | 4 +- src/compiletest/runtest.rs | 9 +- src/etc/libc.c | 1 + src/libextra/terminfo/searcher.rs | 4 +- src/libextra/test.rs | 8 +- src/libextra/workcache.rs | 13 +- src/librustc/back/link.rs | 7 +- src/librustc/driver/driver.rs | 4 +- src/librustdoc/html/render.rs | 15 +- src/librustdoc/lib.rs | 6 +- src/librustpkg/lib.rs | 5 +- src/librustpkg/package_source.rs | 10 +- src/librustpkg/path_util.rs | 14 +- src/librustpkg/source_control.rs | 9 +- src/librustpkg/tests.rs | 35 +- .../testsuite/pass/src/fancy-lib/pkg.rs | 4 +- src/librustpkg/workcache_support.rs | 4 +- src/librustuv/file.rs | 233 +-- src/librustuv/uvio.rs | 344 +++-- src/librustuv/uvll.rs | 24 + src/libstd/libc.rs | 7 +- src/libstd/os.rs | 4 +- src/libstd/path/windows.rs | 64 - src/libstd/rand/os.rs | 8 +- src/libstd/rt/io/file.rs | 1334 ++++++++++------- src/libstd/rt/io/mod.rs | 119 +- src/libstd/rt/io/native/file.rs | 16 +- src/libstd/rt/io/option.rs | 2 +- src/libstd/rt/rtio.rs | 23 +- src/libsyntax/ext/source_util.rs | 7 +- src/libsyntax/parse/mod.rs | 5 +- src/rt/rust_uv.cpp | 4 + src/test/bench/core-std.rs | 4 +- src/test/bench/shootout-fasta.rs | 4 +- src/test/run-pass/glob-std.rs | 2 +- src/test/run-pass/rename-directory.rs | 3 +- src/test/run-pass/stat.rs | 4 +- 38 files changed, 1359 insertions(+), 1008 deletions(-) diff --git a/src/compiletest/errors.rs b/src/compiletest/errors.rs index dfadea37cd0d3..8bfef9da805f2 100644 --- a/src/compiletest/errors.rs +++ b/src/compiletest/errors.rs @@ -9,7 +9,7 @@ // except according to those terms. use std::rt::io::buffered::BufferedReader; -use std::rt::io::file; +use std::rt::io::File; pub struct ExpectedError { line: uint, kind: ~str, msg: ~str } @@ -17,7 +17,7 @@ pub struct ExpectedError { line: uint, kind: ~str, msg: ~str } pub fn load_errors(testfile: &Path) -> ~[ExpectedError] { let mut error_patterns = ~[]; - let mut rdr = BufferedReader::new(file::open(testfile).unwrap()); + let mut rdr = BufferedReader::new(File::open(testfile).unwrap()); let mut line_num = 1u; loop { let ln = match rdr.read_line() { diff --git a/src/compiletest/header.rs b/src/compiletest/header.rs index 68e8fd7673542..5571e159ee31d 100644 --- a/src/compiletest/header.rs +++ b/src/compiletest/header.rs @@ -104,9 +104,9 @@ pub fn is_test_ignored(config: &config, testfile: &Path) -> bool { fn iter_header(testfile: &Path, it: &fn(&str) -> bool) -> bool { use std::rt::io::buffered::BufferedReader; - use std::rt::io::file; + use std::rt::io::File; - let mut rdr = BufferedReader::new(file::open(testfile).unwrap()); + let mut rdr = BufferedReader::new(File::open(testfile).unwrap()); loop { let ln = match rdr.read_line() { Some(ln) => ln, None => break diff --git a/src/compiletest/runtest.rs b/src/compiletest/runtest.rs index 7fc13467217fb..d55bdc2370327 100644 --- a/src/compiletest/runtest.rs +++ b/src/compiletest/runtest.rs @@ -23,6 +23,7 @@ use util::logv; use std::cell::Cell; use std::rt::io; use std::rt::io::file; +use std::rt::io::File; use std::os; use std::str; use std::task::{spawn_sched, SingleThreaded}; @@ -171,7 +172,7 @@ fn run_pretty_test(config: &config, props: &TestProps, testfile: &Path) { let rounds = match props.pp_exact { Some(_) => 1, None => 2 }; - let src = file::open(testfile).read_to_end(); + let src = File::open(testfile).read_to_end(); let src = str::from_utf8_owned(src); let mut srcs = ~[src]; @@ -193,7 +194,7 @@ fn run_pretty_test(config: &config, props: &TestProps, testfile: &Path) { let mut expected = match props.pp_exact { Some(ref file) => { let filepath = testfile.dir_path().join(file); - let s = file::open(&filepath).read_to_end(); + let s = File::open(&filepath).read_to_end(); str::from_utf8_owned(s) } None => { srcs[srcs.len() - 2u].clone() } @@ -764,7 +765,7 @@ fn dump_output(config: &config, testfile: &Path, out: &str, err: &str) { fn dump_output_file(config: &config, testfile: &Path, out: &str, extension: &str) { let outfile = make_out_name(config, testfile, extension); - file::create(&outfile).write(out.as_bytes()); + File::create(&outfile).write(out.as_bytes()); } fn make_out_name(config: &config, testfile: &Path, extension: &str) -> Path { @@ -1015,7 +1016,7 @@ fn disassemble_extract(config: &config, _props: &TestProps, fn count_extracted_lines(p: &Path) -> uint { - let x = file::open(&p.with_extension("ll")).read_to_end(); + let x = File::open(&p.with_extension("ll")).read_to_end(); let x = str::from_utf8_owned(x); x.line_iter().len() } diff --git a/src/etc/libc.c b/src/etc/libc.c index e341f495eebb9..d86ed510361cc 100644 --- a/src/etc/libc.c +++ b/src/etc/libc.c @@ -143,6 +143,7 @@ void posix88_consts() { put_const(S_IFBLK, int); put_const(S_IFDIR, int); put_const(S_IFREG, int); + put_const(S_IFLNK, int); put_const(S_IFMT, int); put_const(S_IEXEC, int); diff --git a/src/libextra/terminfo/searcher.rs b/src/libextra/terminfo/searcher.rs index c5509f8aec7d7..09ceae66bb12d 100644 --- a/src/libextra/terminfo/searcher.rs +++ b/src/libextra/terminfo/searcher.rs @@ -14,7 +14,7 @@ use std::{os, str}; use std::os::getenv; use std::rt::io; -use std::rt::io::file; +use std::rt::io::File; /// Return path to database entry for `term` pub fn get_dbpath_for_term(term: &str) -> Option<~Path> { @@ -76,7 +76,7 @@ pub fn get_dbpath_for_term(term: &str) -> Option<~Path> { /// Return open file for `term` pub fn open(term: &str) -> Result<@mut io::Reader, ~str> { match get_dbpath_for_term(term) { - Some(x) => Ok(@mut file::open(x) as @mut io::Reader), + Some(x) => Ok(@mut File::open(x) as @mut io::Reader), None => Err(format!("could not find terminfo entry for {}", term)) } } diff --git a/src/libextra/test.rs b/src/libextra/test.rs index 497d4206fe327..4cdb3841acf9b 100644 --- a/src/libextra/test.rs +++ b/src/libextra/test.rs @@ -31,7 +31,7 @@ use treemap::TreeMap; use std::clone::Clone; use std::comm::{stream, SharedChan, GenericPort, GenericChan}; use std::rt::io; -use std::rt::io::file; +use std::rt::io::File; use std::task; use std::to_str::ToStr; use std::f64; @@ -353,7 +353,7 @@ struct ConsoleTestState { impl ConsoleTestState { pub fn new(opts: &TestOpts) -> ConsoleTestState { let log_out = match opts.logfile { - Some(ref path) => Some(@mut file::create(path) as @mut io::Writer), + Some(ref path) => Some(@mut File::create(path) as @mut io::Writer), None => None }; let out = @mut io::stdio::stdout() as @mut io::Writer; @@ -936,14 +936,14 @@ impl MetricMap { /// Load MetricDiff from a file. pub fn load(p: &Path) -> MetricMap { assert!(p.exists()); - let f = @mut file::open(p) as @mut io::Reader; + let f = @mut File::open(p) as @mut io::Reader; let mut decoder = json::Decoder(json::from_reader(f).unwrap()); MetricMap(Decodable::decode(&mut decoder)) } /// Write MetricDiff to a file. pub fn save(&self, p: &Path) { - self.to_json().to_pretty_writer(@mut file::create(p) as @mut io::Writer); + self.to_json().to_pretty_writer(@mut File::create(p) as @mut io::Writer); } /// Compare against another MetricMap. Optionally compare all diff --git a/src/libextra/workcache.rs b/src/libextra/workcache.rs index b2be4cf811b32..09d9dd828d4e5 100644 --- a/src/libextra/workcache.rs +++ b/src/libextra/workcache.rs @@ -19,7 +19,7 @@ use std::cell::Cell; use std::comm::{PortOne, oneshot}; use std::{str, task}; use std::rt::io; -use std::rt::io::file; +use std::rt::io::File; use std::rt::io::Decorator; use std::rt::io::mem::MemWriter; @@ -176,14 +176,14 @@ impl Database { // FIXME #4330: This should have &mut self and should set self.db_dirty to false. fn save(&self) { - let f = @mut file::create(&self.db_filename); + let f = @mut File::create(&self.db_filename); self.db_cache.to_json().to_pretty_writer(f as @mut io::Writer); } fn load(&mut self) { assert!(!self.db_dirty); assert!(self.db_filename.exists()); - match io::result(|| file::open(&self.db_filename)) { + match io::result(|| File::open(&self.db_filename)) { Err(e) => fail!("Couldn't load workcache database {}: {}", self.db_filename.display(), e.desc), @@ -480,7 +480,6 @@ impl<'self, T:Send + #[test] fn test() { use std::{os, run}; - use std::rt::io::file; use std::str::from_utf8_owned; // Create a path to a new file 'filename' in the directory in which @@ -488,13 +487,13 @@ fn test() { fn make_path(filename: ~str) -> Path { let pth = os::self_exe_path().expect("workcache::test failed").with_filename(filename); if pth.exists() { - file::unlink(&pth); + File::unlink(&pth); } return pth; } let pth = make_path(~"foo.c"); - file::create(&pth).write(bytes!("int main() { return 0; }")); + File::create(&pth).write(bytes!("int main() { return 0; }")); let db_path = make_path(~"db.json"); @@ -507,7 +506,7 @@ fn test() { let subcx = cx.clone(); let pth = pth.clone(); - let file_content = from_utf8_owned(file::open(&pth).read_to_end()); + let file_content = from_utf8_owned(File::open(&pth).read_to_end()); // FIXME (#9639): This needs to handle non-utf8 paths prep.declare_input("file", pth.as_str().unwrap(), file_content); diff --git a/src/librustc/back/link.rs b/src/librustc/back/link.rs index 7d044ba998fdb..81a205228073e 100644 --- a/src/librustc/back/link.rs +++ b/src/librustc/back/link.rs @@ -31,7 +31,7 @@ use std::ptr; use std::run; use std::str; use std::vec; -use std::rt::io::file; +use std::rt::io::File; use syntax::ast; use syntax::ast_map::{path, path_mod, path_name, path_pretty_name}; use syntax::attr; @@ -950,18 +950,17 @@ pub fn link_binary(sess: Session, // Remove the temporary object file if we aren't saving temps if !sess.opts.save_temps { - file::unlink(obj_filename); + File::unlink(obj_filename); } } fn is_writeable(p: &Path) -> bool { use std::rt::io; - use std::libc::consts::os::posix88::S_IWUSR; !p.exists() || (match io::result(|| p.stat()) { Err(*) => false, - Ok(m) => (m.mode as uint) & S_IWUSR as uint == S_IWUSR as uint + Ok(m) => m.perm & io::UserWrite == io::UserWrite }) } diff --git a/src/librustc/driver/driver.rs b/src/librustc/driver/driver.rs index 1526b5ad9c66a..01035385f97c7 100644 --- a/src/librustc/driver/driver.rs +++ b/src/librustc/driver/driver.rs @@ -27,7 +27,7 @@ use util::ppaux; use std::hashmap::{HashMap,HashSet}; use std::rt::io; -use std::rt::io::file; +use std::rt::io::File; use std::rt::io::mem::MemReader; use std::os; use std::vec; @@ -370,7 +370,7 @@ pub fn phase_5_run_llvm_passes(sess: Session, // Remove assembly source unless --save-temps was specified if !sess.opts.save_temps { - file::unlink(&asm_filename); + File::unlink(&asm_filename); } } else { time(sess.time_passes(), "LLVM passes", (), |_| diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index fd7ba7c045277..d0e01d1f42322 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -42,6 +42,7 @@ use std::local_data; use std::rt::io::buffered::BufferedWriter; use std::rt::io; use std::rt::io::file; +use std::rt::io::File; use std::os; use std::str; use std::task; @@ -263,7 +264,7 @@ pub fn run(mut crate: clean::Crate, dst: Path) { // Publish the search index { dst.push("search-index.js"); - let mut w = BufferedWriter::new(file::create(&dst).unwrap()); + let mut w = BufferedWriter::new(File::create(&dst).unwrap()); let w = &mut w as &mut Writer; write!(w, "var searchIndex = ["); for (i, item) in cache.search_index.iter().enumerate() { @@ -313,7 +314,7 @@ pub fn run(mut crate: clean::Crate, dst: Path) { /// Writes the entire contents of a string to a destination, not attempting to /// catch any errors. fn write(dst: Path, contents: &str) { - file::create(&dst).write(contents.as_bytes()); + File::create(&dst).write(contents.as_bytes()); } /// Makes a directory on the filesystem, failing the task if an error occurs and @@ -419,7 +420,7 @@ impl<'self> SourceCollector<'self> { // If we couldn't open this file, then just returns because it // probably means that it's some standard library macro thing and we // can't have the source to it anyway. - let mut r = match io::result(|| file::open(&p)) { + let mut r = match io::result(|| File::open(&p)) { Ok(r) => r, // eew macro hacks Err(*) => return filename == "" @@ -445,7 +446,7 @@ impl<'self> SourceCollector<'self> { } cur.push(p.filename().expect("source has no filename") + bytes!(".html")); - let mut w = BufferedWriter::new(file::create(&cur).unwrap()); + let mut w = BufferedWriter::new(File::create(&cur).unwrap()); let title = cur.filename_display().with_str(|s| format!("{} -- source", s)); let page = layout::Page { @@ -767,7 +768,7 @@ impl Context { /// /// The rendering driver uses this closure to queue up more work. fn item(&mut self, item: clean::Item, f: &fn(&mut Context, clean::Item)) { - fn render(w: file::FileWriter, cx: &mut Context, it: &clean::Item, + fn render(w: io::File, cx: &mut Context, it: &clean::Item, pushname: bool) { // A little unfortunate that this is done like this, but it sure // does make formatting *a lot* nicer. @@ -804,7 +805,7 @@ impl Context { do self.recurse(name) |this| { let item = item.take(); let dst = this.dst.join("index.html"); - render(file::create(&dst).unwrap(), this, &item, false); + render(File::create(&dst).unwrap(), this, &item, false); let m = match item.inner { clean::ModuleItem(m) => m, @@ -821,7 +822,7 @@ impl Context { // pages dedicated to them. _ if item.name.is_some() => { let dst = self.dst.join(item_path(&item)); - render(file::create(&dst).unwrap(), self, &item, true); + render(File::create(&dst).unwrap(), self, &item, true); } _ => {} diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 7a64ca6d6fc2a..c69fd9879ce2f 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -26,7 +26,7 @@ extern mod extra; use std::cell::Cell; use std::local_data; use std::rt::io; -use std::rt::io::file; +use std::rt::io::File; use std::rt::io::mem::MemWriter; use std::rt::io::Decorator; use std::str; @@ -259,7 +259,7 @@ fn rust_input(cratefile: &str, matches: &getopts::Matches) -> Output { /// This input format purely deserializes the json output file. No passes are /// run over the deserialized output. fn json_input(input: &str) -> Result { - let input = match file::open(&Path::new(input)) { + let input = match File::open(&Path::new(input)) { Some(f) => f, None => return Err(format!("couldn't open {} for reading", input)), }; @@ -321,7 +321,7 @@ fn json_output(crate: clean::Crate, res: ~[plugins::PluginJson], dst: Path) { json.insert(~"crate", crate_json); json.insert(~"plugins", json::Object(plugins_json)); - let mut file = file::create(&dst).unwrap(); + let mut file = File::create(&dst).unwrap(); let output = json::Object(json).to_str(); file.write(output.as_bytes()); } diff --git a/src/librustpkg/lib.rs b/src/librustpkg/lib.rs index bb6088adee18e..cc10f15ffb101 100644 --- a/src/librustpkg/lib.rs +++ b/src/librustpkg/lib.rs @@ -28,6 +28,7 @@ use std::{os, result, run, str, task}; use std::hashmap::HashSet; use std::rt::io; use std::rt::io::file; +use std::rt::io::File; pub use std::path::Path; use extra::workcache; @@ -661,7 +662,7 @@ impl CtxMethods for BuildContext { for exec in subex.iter() { debug!("Copying: {} -> {}", exec.display(), sub_target_ex.display()); file::mkdir_recursive(&sub_target_ex.dir_path(), io::UserRWX); - file::copy(exec, &sub_target_ex); + File::copy(exec, &sub_target_ex); // FIXME (#9639): This needs to handle non-utf8 paths exe_thing.discover_output("binary", sub_target_ex.as_str().unwrap(), @@ -674,7 +675,7 @@ impl CtxMethods for BuildContext { didn't install it!", lib.display())); target_lib.set_filename(lib.filename().expect("weird target lib")); file::mkdir_recursive(&target_lib.dir_path(), io::UserRWX); - file::copy(lib, &target_lib); + File::copy(lib, &target_lib); debug!("3. discovering output {}", target_lib.display()); exe_thing.discover_output("binary", target_lib.as_str().unwrap(), diff --git a/src/librustpkg/package_source.rs b/src/librustpkg/package_source.rs index a52aa68e1e471..5e3a90bbf58f7 100644 --- a/src/librustpkg/package_source.rs +++ b/src/librustpkg/package_source.rs @@ -14,6 +14,7 @@ use target::*; use package_id::PkgId; use std::rt::io; use std::rt::io::file; +use std::rt::io::File; use std::os; use context::*; use crate::Crate; @@ -301,7 +302,7 @@ impl PkgSrc { // Move clone_target to local. // First, create all ancestor directories. let moved = make_dir_rwx_recursive(&local.dir_path()) - && io::result(|| file::rename(&clone_target, local)).is_ok(); + && io::result(|| File::rename(&clone_target, local)).is_ok(); if moved { Some(local.clone()) } else { None } } @@ -350,7 +351,7 @@ impl PkgSrc { let prefix = self.start_dir.component_iter().len(); debug!("Matching against {}", self.id.short_name); - do file::walk_dir(&self.start_dir) |pth| { + for pth in file::walk_dir(&self.start_dir) { let maybe_known_crate_set = match pth.filename_str() { Some(filename) if filter(filename) => match filename { "lib.rs" => Some(&mut self.libs), @@ -363,11 +364,10 @@ impl PkgSrc { }; match maybe_known_crate_set { - Some(crate_set) => PkgSrc::push_crate(crate_set, prefix, pth), + Some(crate_set) => PkgSrc::push_crate(crate_set, prefix, &pth), None => () } - true - }; + } let crate_sets = [&self.libs, &self.mains, &self.tests, &self.benchs]; if crate_sets.iter().all(|crate_set| crate_set.is_empty()) { diff --git a/src/librustpkg/path_util.rs b/src/librustpkg/path_util.rs index 75f03533d583c..e8f1b2300c737 100644 --- a/src/librustpkg/path_util.rs +++ b/src/librustpkg/path_util.rs @@ -21,6 +21,7 @@ use std::libc::consts::os::posix88::{S_IRUSR, S_IWUSR, S_IXUSR}; use std::os; use std::rt::io; use std::rt::io::file; +use std::rt::io::File; use messages::*; pub fn default_workspace() -> Path { @@ -72,9 +73,9 @@ pub fn workspace_contains_package_id_(pkgid: &PkgId, workspace: &Path, if !src_dir.is_dir() { return None } let mut found = None; - do file::walk_dir(&src_dir) |p| { + for p in file::walk_dir(&src_dir) { if p.is_dir() { - if *p == src_dir.join(&pkgid.path) || { + if p == src_dir.join(&pkgid.path) || { let pf = p.filename_str(); do pf.iter().any |&g| { match split_version_general(g, '-') { @@ -89,9 +90,8 @@ pub fn workspace_contains_package_id_(pkgid: &PkgId, workspace: &Path, found = Some(p.clone()); } - }; - true - }; + } + } if found.is_some() { debug!("Found {} in {}", pkgid.to_str(), workspace.display()); @@ -399,12 +399,12 @@ pub fn uninstall_package_from(workspace: &Path, pkgid: &PkgId) { let mut did_something = false; let installed_bin = target_executable_in_workspace(pkgid, workspace); if installed_bin.exists() { - file::unlink(&installed_bin); + File::unlink(&installed_bin); did_something = true; } let installed_lib = target_library_in_workspace(pkgid, workspace); if installed_lib.exists() { - file::unlink(&installed_lib); + File::unlink(&installed_lib); did_something = true; } if !did_something { diff --git a/src/librustpkg/source_control.rs b/src/librustpkg/source_control.rs index a0e50ff0f9ef7..e5d1c9b597ffc 100644 --- a/src/librustpkg/source_control.rs +++ b/src/librustpkg/source_control.rs @@ -96,12 +96,11 @@ pub enum CloneResult { pub fn make_read_only(target: &Path) { // Now, make all the files in the target dir read-only - do file::walk_dir(target) |p| { + for p in file::walk_dir(target) { if !p.is_dir() { - assert!(chmod_read_only(p)); - }; - true - }; + assert!(chmod_read_only(&p)); + } + } } /// Source can be either a URL or a local file path. diff --git a/src/librustpkg/tests.rs b/src/librustpkg/tests.rs index 60e99f242ef14..a2ef80db6d684 100644 --- a/src/librustpkg/tests.rs +++ b/src/librustpkg/tests.rs @@ -14,6 +14,7 @@ use context::{BuildContext, Context, RustcFlags}; use std::{os, run, str, task}; use std::rt::io; use std::rt::io::file; +use std::rt::io::File; use extra::arc::Arc; use extra::arc::RWArc; use extra::tempfile::TempDir; @@ -83,7 +84,7 @@ fn git_repo_pkg_with_tag(a_tag: ~str) -> PkgId { } fn writeFile(file_path: &Path, contents: &str) { - let mut out = file::create(file_path); + let mut out = File::create(file_path); out.write(contents.as_bytes()); out.write(['\n' as u8]); } @@ -196,23 +197,13 @@ fn add_git_tag(repo: &Path, tag: ~str) { } fn is_rwx(p: &Path) -> bool { - use std::libc::consts::os::posix88::{S_IRUSR, S_IWUSR, S_IXUSR}; - if !p.exists() { return false } - let m = p.stat().mode; - (m & S_IRUSR as u64) == S_IRUSR as u64 - && (m & S_IWUSR as u64) == S_IWUSR as u64 - && (m & S_IXUSR as u64) == S_IXUSR as u64 + p.stat().perm & io::UserRWX == io::UserRWX } fn is_read_only(p: &Path) -> bool { - use std::libc::consts::os::posix88::{S_IRUSR, S_IWUSR, S_IXUSR}; - if !p.exists() { return false } - let m = p.stat().mode; - (m & S_IRUSR as u64) == S_IRUSR as u64 - && (m & S_IWUSR as u64) == 0 as u64 - && (m & S_IXUSR as u64) == 0 as u64 + p.stat().perm & io::UserRWX == io::UserRead } fn test_sysroot() -> Path { @@ -398,7 +389,7 @@ fn test_executable_exists(repo: &Path, short_name: &str) -> bool { fn remove_executable_file(p: &PkgId, workspace: &Path) { let exec = target_executable_in_workspace(&PkgId::new(p.short_name), workspace); if exec.exists() { - file::unlink(&exec); + File::unlink(&exec); } } @@ -419,7 +410,7 @@ fn built_executable_exists(repo: &Path, short_name: &str) -> bool { fn remove_built_executable_file(p: &PkgId, workspace: &Path) { let exec = built_executable_in_workspace(&PkgId::new(p.short_name), workspace); match exec { - Some(r) => file::unlink(&r), + Some(r) => File::unlink(&r), None => () } } @@ -553,7 +544,7 @@ fn frob_source_file(workspace: &Path, pkgid: &PkgId, filename: &str) { do io::io_error::cond.trap(|e| { cond.raise((p.clone(), format!("Bad path: {}", e.desc))); }).inside { - let mut w = file::open_stream(p, io::Append, io::Write); + let mut w = File::open_mode(p, io::Append, io::Write); w.write(bytes!("/* hi */\n")); } } @@ -902,7 +893,7 @@ fn package_script_with_default_build() { let source = Path::new(file!()).dir_path().join_many( [~"testsuite", ~"pass", ~"src", ~"fancy-lib", ~"pkg.rs"]); debug!("package_script_with_default_build: {}", source.display()); - file::copy(&source, &dir.join_many(["src", "fancy-lib-0.1", "pkg.rs"])); + File::copy(&source, &dir.join_many(["src", "fancy-lib-0.1", "pkg.rs"])); command_line_test([~"install", ~"fancy-lib"], dir); assert_lib_exists(dir, &Path::new("fancy-lib"), NoVersion); assert!(target_build_dir(dir).join_many([~"fancy-lib", ~"generated.rs"]).exists()); @@ -2288,7 +2279,7 @@ fn test_c_dependency_ok() { debug!("dir = {}", dir.display()); let source = Path::new(file!()).dir_path().join_many( [~"testsuite", ~"pass", ~"src", ~"c-dependencies", ~"pkg.rs"]); - file::copy(&source, &dir.join_many([~"src", ~"cdep-0.1", ~"pkg.rs"])); + File::copy(&source, &dir.join_many([~"src", ~"cdep-0.1", ~"pkg.rs"])); command_line_test([~"build", ~"cdep"], dir); assert_executable_exists(dir, "cdep"); let out_dir = target_build_dir(dir).join("cdep"); @@ -2309,7 +2300,7 @@ fn test_c_dependency_no_rebuilding() { debug!("dir = {}", dir.display()); let source = Path::new(file!()).dir_path().join_many( [~"testsuite", ~"pass", ~"src", ~"c-dependencies", ~"pkg.rs"]); - file::copy(&source, &dir.join_many([~"src", ~"cdep-0.1", ~"pkg.rs"])); + File::copy(&source, &dir.join_many([~"src", ~"cdep-0.1", ~"pkg.rs"])); command_line_test([~"build", ~"cdep"], dir); assert_executable_exists(dir, "cdep"); let out_dir = target_build_dir(dir).join("cdep"); @@ -2342,7 +2333,7 @@ fn test_c_dependency_yes_rebuilding() { [~"testsuite", ~"pass", ~"src", ~"c-dependencies", ~"pkg.rs"]); let target = dir.join_many([~"src", ~"cdep-0.1", ~"pkg.rs"]); debug!("Copying {} -> {}", source.display(), target.display()); - file::copy(&source, &target); + File::copy(&source, &target); command_line_test([~"build", ~"cdep"], dir); assert_executable_exists(dir, "cdep"); let out_dir = target_build_dir(dir).join("cdep"); @@ -2366,7 +2357,5 @@ fn test_c_dependency_yes_rebuilding() { /// Returns true if p exists and is executable fn is_executable(p: &Path) -> bool { - use std::libc::consts::os::posix88::{S_IXUSR}; - - p.exists() && p.stat().mode & S_IXUSR as u64 == S_IXUSR as u64 + p.exists() && p.stat().perm & io::UserExec == io::UserExec } diff --git a/src/librustpkg/testsuite/pass/src/fancy-lib/pkg.rs b/src/librustpkg/testsuite/pass/src/fancy-lib/pkg.rs index e5fb6889ae09b..1c3bf897bec1d 100644 --- a/src/librustpkg/testsuite/pass/src/fancy-lib/pkg.rs +++ b/src/librustpkg/testsuite/pass/src/fancy-lib/pkg.rs @@ -12,7 +12,7 @@ extern mod rustpkg; extern mod rustc; use std::os; -use std::rt::io::file; +use std::rt::io::File; use rustpkg::api; use rustpkg::version::NoVersion; @@ -43,7 +43,7 @@ pub fn main() { let out_path = os::self_exe_path().expect("Couldn't get self_exe path"); debug!("Writing file"); - let mut file = file::create(&out_path.join("generated.rs")); + let mut file = File::create(&out_path.join("generated.rs")); file.write("pub fn wheeeee() { let xs = [1, 2, 3]; \ for _ in xs.iter() { assert!(true); } }".as_bytes()); diff --git a/src/librustpkg/workcache_support.rs b/src/librustpkg/workcache_support.rs index c16224afbf4c8..d8b35f2c0332a 100644 --- a/src/librustpkg/workcache_support.rs +++ b/src/librustpkg/workcache_support.rs @@ -9,7 +9,7 @@ // except according to those terms. use std::rt::io; -use std::rt::io::file; +use std::rt::io::File; use extra::workcache; use sha1::{Digest, Sha1}; @@ -17,7 +17,7 @@ use sha1::{Digest, Sha1}; pub fn digest_file_with_date(path: &Path) -> ~str { use conditions::bad_path::cond; - match io::result(|| file::open(path).read_to_end()) { + match io::result(|| File::open(path).read_to_end()) { Ok(bytes) => { let mut sha = Sha1::new(); sha.input(bytes); diff --git a/src/librustuv/file.rs b/src/librustuv/file.rs index 15df189edcdd4..99060de1d2dd2 100644 --- a/src/librustuv/file.rs +++ b/src/librustuv/file.rs @@ -11,10 +11,9 @@ use std::ptr::null; use std::c_str; use std::c_str::CString; -use std::libc::c_void; use std::cast::transmute; use std::libc; -use std::libc::{c_int}; +use std::libc::{c_int, c_char, c_void}; use super::{Request, NativeHandle, Loop, FsCallback, Buf, status_to_maybe_uv_error, UvError}; @@ -49,12 +48,9 @@ impl FsRequest { assert_eq!(ret, 0); } - pub fn open_sync(self, loop_: &Loop, path: &CString, + pub fn open_sync(mut self, loop_: &Loop, path: &CString, flags: int, mode: int) -> Result { - let complete_cb_ptr = { - let mut me = self; - me.req_boilerplate(None) - }; + let complete_cb_ptr = self.req_boilerplate(None); let result = path.with_ref(|p| unsafe { uvll::fs_open(loop_.native_handle(), self.native_handle(), p, flags, mode, complete_cb_ptr) @@ -62,11 +58,8 @@ impl FsRequest { self.sync_cleanup(result) } - pub fn unlink(self, loop_: &Loop, path: &CString, cb: FsCallback) { - let complete_cb_ptr = { - let mut me = self; - me.req_boilerplate(Some(cb)) - }; + pub fn unlink(mut self, loop_: &Loop, path: &CString, cb: FsCallback) { + let complete_cb_ptr = self.req_boilerplate(Some(cb)); let ret = path.with_ref(|p| unsafe { uvll::fs_unlink(loop_.native_handle(), self.native_handle(), p, complete_cb_ptr) @@ -74,12 +67,9 @@ impl FsRequest { assert_eq!(ret, 0); } - pub fn unlink_sync(self, loop_: &Loop, path: &CString) + pub fn unlink_sync(mut self, loop_: &Loop, path: &CString) -> Result { - let complete_cb_ptr = { - let mut me = self; - me.req_boilerplate(None) - }; + let complete_cb_ptr = self.req_boilerplate(None); let result = path.with_ref(|p| unsafe { uvll::fs_unlink(loop_.native_handle(), self.native_handle(), p, complete_cb_ptr) @@ -87,11 +77,17 @@ impl FsRequest { self.sync_cleanup(result) } - pub fn stat(self, loop_: &Loop, path: &CString, cb: FsCallback) { - let complete_cb_ptr = { - let mut me = self; - me.req_boilerplate(Some(cb)) - }; + pub fn lstat(mut self, loop_: &Loop, path: &CString, cb: FsCallback) { + let complete_cb_ptr = self.req_boilerplate(Some(cb)); + let ret = path.with_ref(|p| unsafe { + uvll::uv_fs_lstat(loop_.native_handle(), + self.native_handle(), p, complete_cb_ptr) + }); + assert_eq!(ret, 0); + } + + pub fn stat(mut self, loop_: &Loop, path: &CString, cb: FsCallback) { + let complete_cb_ptr = self.req_boilerplate(Some(cb)); let ret = path.with_ref(|p| unsafe { uvll::fs_stat(loop_.native_handle(), self.native_handle(), p, complete_cb_ptr) @@ -99,11 +95,9 @@ impl FsRequest { assert_eq!(ret, 0); } - pub fn write(self, loop_: &Loop, fd: c_int, buf: Buf, offset: i64, cb: FsCallback) { - let complete_cb_ptr = { - let mut me = self; - me.req_boilerplate(Some(cb)) - }; + pub fn write(mut self, loop_: &Loop, fd: c_int, buf: Buf, offset: i64, + cb: FsCallback) { + let complete_cb_ptr = self.req_boilerplate(Some(cb)); let base_ptr = buf.base as *c_void; let len = buf.len as uint; let ret = unsafe { @@ -113,12 +107,9 @@ impl FsRequest { }; assert_eq!(ret, 0); } - pub fn write_sync(self, loop_: &Loop, fd: c_int, buf: Buf, offset: i64) + pub fn write_sync(mut self, loop_: &Loop, fd: c_int, buf: Buf, offset: i64) -> Result { - let complete_cb_ptr = { - let mut me = self; - me.req_boilerplate(None) - }; + let complete_cb_ptr = self.req_boilerplate(None); let base_ptr = buf.base as *c_void; let len = buf.len as uint; let result = unsafe { @@ -129,11 +120,9 @@ impl FsRequest { self.sync_cleanup(result) } - pub fn read(self, loop_: &Loop, fd: c_int, buf: Buf, offset: i64, cb: FsCallback) { - let complete_cb_ptr = { - let mut me = self; - me.req_boilerplate(Some(cb)) - }; + pub fn read(mut self, loop_: &Loop, fd: c_int, buf: Buf, offset: i64, + cb: FsCallback) { + let complete_cb_ptr = self.req_boilerplate(Some(cb)); let buf_ptr = buf.base as *c_void; let len = buf.len as uint; let ret = unsafe { @@ -143,12 +132,9 @@ impl FsRequest { }; assert_eq!(ret, 0); } - pub fn read_sync(self, loop_: &Loop, fd: c_int, buf: Buf, offset: i64) + pub fn read_sync(mut self, loop_: &Loop, fd: c_int, buf: Buf, offset: i64) -> Result { - let complete_cb_ptr = { - let mut me = self; - me.req_boilerplate(None) - }; + let complete_cb_ptr = self.req_boilerplate(None); let buf_ptr = buf.base as *c_void; let len = buf.len as uint; let result = unsafe { @@ -159,22 +145,16 @@ impl FsRequest { self.sync_cleanup(result) } - pub fn close(self, loop_: &Loop, fd: c_int, cb: FsCallback) { - let complete_cb_ptr = { - let mut me = self; - me.req_boilerplate(Some(cb)) - }; - let ret = unsafe { + pub fn close(mut self, loop_: &Loop, fd: c_int, cb: FsCallback) { + let complete_cb_ptr = self.req_boilerplate(Some(cb)); + assert_eq!(unsafe { uvll::fs_close(loop_.native_handle(), self.native_handle(), fd, complete_cb_ptr) - }; - assert_eq!(ret, 0); + }, 0); } - pub fn close_sync(self, loop_: &Loop, fd: c_int) -> Result { - let complete_cb_ptr = { - let mut me = self; - me.req_boilerplate(None) - }; + pub fn close_sync(mut self, loop_: &Loop, + fd: c_int) -> Result { + let complete_cb_ptr = self.req_boilerplate(None); let result = unsafe { uvll::fs_close(loop_.native_handle(), self.native_handle(), fd, complete_cb_ptr) @@ -182,68 +162,119 @@ impl FsRequest { self.sync_cleanup(result) } - pub fn mkdir(self, loop_: &Loop, path: &CString, mode: c_int, cb: FsCallback) { - let complete_cb_ptr = { - let mut me = self; - me.req_boilerplate(Some(cb)) - }; - let ret = path.with_ref(|p| unsafe { + pub fn mkdir(mut self, loop_: &Loop, path: &CString, mode: c_int, + cb: FsCallback) { + let complete_cb_ptr = self.req_boilerplate(Some(cb)); + assert_eq!(path.with_ref(|p| unsafe { uvll::fs_mkdir(loop_.native_handle(), self.native_handle(), p, mode, complete_cb_ptr) - }); - assert_eq!(ret, 0); + }), 0); } - pub fn rmdir(self, loop_: &Loop, path: &CString, cb: FsCallback) { - let complete_cb_ptr = { - let mut me = self; - me.req_boilerplate(Some(cb)) - }; - let ret = path.with_ref(|p| unsafe { + pub fn rmdir(mut self, loop_: &Loop, path: &CString, cb: FsCallback) { + let complete_cb_ptr = self.req_boilerplate(Some(cb)); + assert_eq!(path.with_ref(|p| unsafe { uvll::fs_rmdir(loop_.native_handle(), self.native_handle(), p, complete_cb_ptr) - }); - assert_eq!(ret, 0); + }), 0); } - pub fn rename(self, loop_: &Loop, path: &CString, to: &CString, cb: FsCallback) { - let complete_cb_ptr = { - let mut me = self; - me.req_boilerplate(Some(cb)) - }; - let ret = unsafe { + pub fn rename(mut self, loop_: &Loop, path: &CString, to: &CString, + cb: FsCallback) { + let complete_cb_ptr = self.req_boilerplate(Some(cb)); + assert_eq!(unsafe { uvll::fs_rename(loop_.native_handle(), self.native_handle(), path.with_ref(|p| p), to.with_ref(|p| p), complete_cb_ptr) - }; - assert_eq!(ret, 0); + }, 0); } - pub fn chmod(self, loop_: &Loop, path: &CString, mode: c_int, cb: FsCallback) { - let complete_cb_ptr = { - let mut me = self; - me.req_boilerplate(Some(cb)) - }; - let ret = path.with_ref(|p| unsafe { + pub fn chmod(mut self, loop_: &Loop, path: &CString, mode: c_int, + cb: FsCallback) { + let complete_cb_ptr = self.req_boilerplate(Some(cb)); + assert_eq!(path.with_ref(|p| unsafe { uvll::fs_chmod(loop_.native_handle(), self.native_handle(), p, mode, complete_cb_ptr) - }); - assert_eq!(ret, 0); + }), 0); } - pub fn readdir(self, loop_: &Loop, path: &CString, + pub fn readdir(mut self, loop_: &Loop, path: &CString, flags: c_int, cb: FsCallback) { - let complete_cb_ptr = { - let mut me = self; - me.req_boilerplate(Some(cb)) - }; - let ret = path.with_ref(|p| unsafe { + let complete_cb_ptr = self.req_boilerplate(Some(cb)); + assert_eq!(path.with_ref(|p| unsafe { uvll::fs_readdir(loop_.native_handle(), self.native_handle(), p, flags, complete_cb_ptr) - }); - assert_eq!(ret, 0); + }), 0); + } + + pub fn readlink(mut self, loop_: &Loop, path: &CString, cb: FsCallback) { + let complete_cb_ptr = self.req_boilerplate(Some(cb)); + assert_eq!(path.with_ref(|p| unsafe { + uvll::uv_fs_readlink(loop_.native_handle(), + self.native_handle(), p, complete_cb_ptr) + }), 0); + } + + pub fn chown(mut self, loop_: &Loop, path: &CString, uid: int, gid: int, + cb: FsCallback) { + let complete_cb_ptr = self.req_boilerplate(Some(cb)); + assert_eq!(path.with_ref(|p| unsafe { + uvll::uv_fs_chown(loop_.native_handle(), + self.native_handle(), p, + uid as uvll::uv_uid_t, + gid as uvll::uv_gid_t, + complete_cb_ptr) + }), 0); + } + + pub fn truncate(mut self, loop_: &Loop, file: c_int, offset: i64, + cb: FsCallback) { + let complete_cb_ptr = self.req_boilerplate(Some(cb)); + assert_eq!(unsafe { + uvll::uv_fs_ftruncate(loop_.native_handle(), + self.native_handle(), file, offset, + complete_cb_ptr) + }, 0); + } + + pub fn link(mut self, loop_: &Loop, src: &CString, dst: &CString, + cb: FsCallback) { + let complete_cb_ptr = self.req_boilerplate(Some(cb)); + assert_eq!(unsafe { + uvll::uv_fs_link(loop_.native_handle(), self.native_handle(), + src.with_ref(|p| p), + dst.with_ref(|p| p), + complete_cb_ptr) + }, 0); + } + + pub fn symlink(mut self, loop_: &Loop, src: &CString, dst: &CString, + cb: FsCallback) { + let complete_cb_ptr = self.req_boilerplate(Some(cb)); + assert_eq!(unsafe { + uvll::uv_fs_symlink(loop_.native_handle(), self.native_handle(), + src.with_ref(|p| p), + dst.with_ref(|p| p), + complete_cb_ptr) + }, 0); + } + + pub fn fsync(mut self, loop_: &Loop, fd: c_int, cb: FsCallback) { + let complete_cb_ptr = self.req_boilerplate(Some(cb)); + assert_eq!(unsafe { + uvll::uv_fs_fsync(loop_.native_handle(), self.native_handle(), fd, + complete_cb_ptr) + }, 0); + } + + pub fn datasync(mut self, loop_: &Loop, fd: c_int, cb: FsCallback) { + let complete_cb_ptr = self.req_boilerplate(Some(cb)); + assert_eq!(unsafe { + uvll::uv_fs_fdatasync(loop_.native_handle(), self.native_handle(), fd, + complete_cb_ptr) + }, 0); } // accessors/utility funcs @@ -284,10 +315,12 @@ impl FsRequest { } } - pub fn get_result(&mut self) -> c_int { - unsafe { - uvll::get_result_from_fs_req(self.native_handle()) - } + pub fn get_path(&self) -> *c_char { + unsafe { uvll::get_path_from_fs_req(self.native_handle()) } + } + + pub fn get_result(&self) -> c_int { + unsafe { uvll::get_result_from_fs_req(self.native_handle()) } } pub fn get_loop(&self) -> Loop { @@ -380,7 +413,7 @@ extern fn compl_cb(req: *uv_fs_t) { mod test { use super::*; //use std::rt::test::*; - use std::libc::{STDOUT_FILENO}; + use std::libc::{STDOUT_FILENO, c_int}; use std::vec; use std::str; use std::unstable::run_in_bare_thread; diff --git a/src/librustuv/uvio.rs b/src/librustuv/uvio.rs index ae8546af4b40e..25839c429da6a 100644 --- a/src/librustuv/uvio.rs +++ b/src/librustuv/uvio.rs @@ -8,18 +8,15 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::c_str::{ToCStr, CString}; +use std::c_str::CString; use std::cast::transmute; use std::cast; use std::cell::Cell; -use std::clone::Clone; use std::comm::{SendDeferred, SharedChan, Port, PortOne, GenericChan}; +use std::libc; use std::libc::{c_int, c_uint, c_void, pid_t}; -use std::ops::Drop; -use std::option::*; use std::ptr; use std::str; -use std::result::*; use std::rt::io; use std::rt::io::IoError; use std::rt::io::net::ip::{SocketAddr, IpAddr}; @@ -33,22 +30,16 @@ use std::rt::sched::{Scheduler, SchedHandle}; use std::rt::tube::Tube; use std::rt::task::Task; use std::unstable::sync::Exclusive; -use std::path::{GenericPath, Path}; -use std::libc::{lseek, off_t, O_CREAT, O_APPEND, O_TRUNC, O_RDWR, O_RDONLY, - O_WRONLY, S_IRUSR, S_IWUSR}; -use std::rt::io::{FileMode, FileAccess, OpenOrCreate, Open, Create, - CreateOrTruncate, Append, Truncate, Read, Write, ReadWrite, - FileStat}; +use std::libc::{lseek, off_t}; +use std::rt::io::{FileMode, FileAccess, FileStat}; use std::rt::io::signal::Signum; use std::task; use ai = std::rt::io::net::addrinfo; -#[cfg(test)] use std::container::Container; #[cfg(test)] use std::unstable::run_in_bare_thread; #[cfg(test)] use std::rt::test::{spawntask, next_test_ip4, run_in_mt_newsched_task}; -#[cfg(test)] use std::iter::{Iterator, range}; #[cfg(test)] use std::rt::comm::oneshot; use super::*; @@ -418,24 +409,25 @@ impl UvIoFactory { } } -/// Helper for a variety of simple uv_fs_* functions that -/// have no ret val -fn uv_fs_helper(loop_: &mut Loop, path: &CString, - cb: ~fn(&mut FsRequest, &mut Loop, &CString, - ~fn(&FsRequest, Option))) - -> Result<(), IoError> { +/// Helper for a variety of simple uv_fs_* functions that have no ret val. This +/// function takes the loop that it will act on, and then invokes the specified +/// callback in a situation where the task wil be immediately blocked +/// afterwards. The `FsCallback` yielded must be invoked to reschedule the task +/// (once the result of the operation is known). +fn uv_fs_helper(loop_: &mut Loop, + retfn: extern "Rust" fn(&mut FsRequest) -> T, + cb: &fn(&mut FsRequest, &mut Loop, FsCallback)) + -> Result { let result_cell = Cell::new_empty(); - let result_cell_ptr: *Cell> = &result_cell; - let path_cell = Cell::new(path); + let result_cell_ptr: *Cell> = &result_cell; do task::unkillable { // FIXME(#8674) let scheduler: ~Scheduler = Local::take(); let mut new_req = FsRequest::new(); do scheduler.deschedule_running_task_and_then |_, task| { let task_cell = Cell::new(task); - let path = path_cell.take(); - do cb(&mut new_req, loop_, path) |_, err| { + do cb(&mut new_req, loop_) |req, err| { let res = match err { - None => Ok(()), + None => Ok(retfn(req)), Some(err) => Err(uv_error_to_io_error(err)) }; unsafe { (*result_cell_ptr).put_back(res); } @@ -448,6 +440,43 @@ fn uv_fs_helper(loop_: &mut Loop, path: &CString, return result_cell.take(); } +fn unit(_: &mut FsRequest) {} + +fn fs_mkstat(f: &mut FsRequest) -> FileStat { + let path = unsafe { Path::new(CString::new(f.get_path(), false)) }; + let stat = f.get_stat(); + fn to_msec(stat: uvll::uv_timespec_t) -> u64 { + (stat.tv_sec * 1000 + stat.tv_nsec / 1000000) as u64 + } + 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, + }; + FileStat { + path: path, + size: stat.st_size as u64, + kind: kind, + perm: (stat.st_mode as io::FilePermission) & io::AllPermissions, + created: to_msec(stat.st_birthtim), + modified: to_msec(stat.st_mtim), + accessed: to_msec(stat.st_atim), + 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: stat.st_flags as u64, + gen: stat.st_gen as u64, + } +} + impl IoFactory for UvIoFactory { // Connect to an address and return a new stream // NB: This blocks the task waiting on the connection. @@ -552,6 +581,41 @@ impl IoFactory for UvIoFactory { Ok(~UvTimer::new(watcher, home) as ~RtioTimer) } + fn get_host_addresses(&mut self, host: Option<&str>, servname: Option<&str>, + hint: Option) -> Result<~[ai::Info], IoError> { + let result_cell = Cell::new_empty(); + let result_cell_ptr: *Cell> = &result_cell; + let host_ptr: *Option<&str> = &host; + let servname_ptr: *Option<&str> = &servname; + let hint_ptr: *Option = &hint; + let addrinfo_req = GetAddrInfoRequest::new(); + let addrinfo_req_cell = Cell::new(addrinfo_req); + + do task::unkillable { // FIXME(#8674) + let scheduler: ~Scheduler = Local::take(); + do scheduler.deschedule_running_task_and_then |_, task| { + let task_cell = Cell::new(task); + let mut addrinfo_req = addrinfo_req_cell.take(); + unsafe { + do addrinfo_req.getaddrinfo(self.uv_loop(), + *host_ptr, *servname_ptr, + *hint_ptr) |_, addrinfo, err| { + let res = match err { + None => Ok(accum_addrinfo(addrinfo)), + Some(err) => Err(uv_error_to_io_error(err)) + }; + (*result_cell_ptr).put_back(res); + let scheduler: ~Scheduler = Local::take(); + scheduler.resume_blocked_task_immediately(task_cell.take()); + } + } + } + } + addrinfo_req.delete(); + assert!(!result_cell.is_empty()); + return result_cell.take(); + } + fn fs_from_raw_fd(&mut self, fd: c_int, close: CloseBehavior) -> ~RtioFileStream { let loop_ = Loop {handle: self.uv_loop().native_handle()}; let home = get_handle_to_current_scheduler!(); @@ -560,35 +624,28 @@ impl IoFactory for UvIoFactory { fn fs_open(&mut self, path: &CString, fm: FileMode, fa: FileAccess) -> Result<~RtioFileStream, IoError> { - let mut flags = match fm { - Open => 0, - Create => O_CREAT, - OpenOrCreate => O_CREAT, - Append => O_APPEND, - Truncate => O_TRUNC, - CreateOrTruncate => O_TRUNC | O_CREAT - }; - flags = match fa { - Read => flags | O_RDONLY, - Write => flags | O_WRONLY, - ReadWrite => flags | O_RDWR + let flags = match fm { + io::Open => 0, + io::Append => libc::O_APPEND, + io::Truncate => libc::O_TRUNC, }; - let create_mode = match fm { - Create|OpenOrCreate|CreateOrTruncate => - S_IRUSR | S_IWUSR, - _ => 0 + // 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), }; let result_cell = Cell::new_empty(); let result_cell_ptr: *Cell> = &result_cell; - let path_cell = Cell::new(path); do task::unkillable { // FIXME(#8674) let scheduler: ~Scheduler = Local::take(); let open_req = file::FsRequest::new(); do scheduler.deschedule_running_task_and_then |_, task| { let task_cell = Cell::new(task); - let path = path_cell.take(); - do open_req.open(self.uv_loop(), path, flags as int, create_mode as int) + do open_req.open(self.uv_loop(), path, flags as int, mode as int) |req,err| { if err.is_none() { let loop_ = Loop {handle: req.get_loop().native_handle()}; @@ -614,125 +671,42 @@ impl IoFactory for UvIoFactory { } fn fs_unlink(&mut self, path: &CString) -> Result<(), IoError> { - do uv_fs_helper(self.uv_loop(), path) |unlink_req, l, p, cb| { - do unlink_req.unlink(l, p) |req, err| { - cb(req, err) - }; + do uv_fs_helper(self.uv_loop(), unit) |req, l, cb| { + req.unlink(l, path, cb) } } - fn fs_stat(&mut self, path: &CString) -> Result { - use str::StrSlice; - let result_cell = Cell::new_empty(); - let result_cell_ptr: *Cell> = &result_cell; - let path_cell = Cell::new(path); - do task::unkillable { // FIXME(#8674) - let scheduler: ~Scheduler = Local::take(); - let stat_req = file::FsRequest::new(); - do scheduler.deschedule_running_task_and_then |_, task| { - let task_cell = Cell::new(task); - let path = path_cell.take(); - // Don't pick up the null byte - let slice = path.as_bytes().slice(0, path.len()); - let path_instance = Cell::new(Path::new(slice)); - do stat_req.stat(self.uv_loop(), path) |req,err| { - let res = match err { - None => { - let stat = req.get_stat(); - Ok(FileStat { - path: path_instance.take(), - is_file: stat.is_file(), - is_dir: stat.is_dir(), - device: stat.st_dev, - mode: stat.st_mode, - inode: stat.st_ino, - size: stat.st_size, - created: stat.st_ctim.tv_sec as u64, - modified: stat.st_mtim.tv_sec as u64, - accessed: stat.st_atim.tv_sec as u64 - }) - }, - Some(e) => { - Err(uv_error_to_io_error(e)) - } - }; - unsafe { (*result_cell_ptr).put_back(res); } - let scheduler: ~Scheduler = Local::take(); - scheduler.resume_blocked_task_immediately(task_cell.take()); - }; - }; - }; - assert!(!result_cell.is_empty()); - return result_cell.take(); + fn fs_lstat(&mut self, path: &CString) -> Result { + do uv_fs_helper(self.uv_loop(), fs_mkstat) |req, l, cb| { + req.lstat(l, path, cb) + } } - - fn get_host_addresses(&mut self, host: Option<&str>, servname: Option<&str>, - hint: Option) -> Result<~[ai::Info], IoError> { - let result_cell = Cell::new_empty(); - let result_cell_ptr: *Cell> = &result_cell; - let host_ptr: *Option<&str> = &host; - let servname_ptr: *Option<&str> = &servname; - let hint_ptr: *Option = &hint; - let addrinfo_req = GetAddrInfoRequest::new(); - let addrinfo_req_cell = Cell::new(addrinfo_req); - - do task::unkillable { // FIXME(#8674) - let scheduler: ~Scheduler = Local::take(); - do scheduler.deschedule_running_task_and_then |_, task| { - let task_cell = Cell::new(task); - let mut addrinfo_req = addrinfo_req_cell.take(); - unsafe { - do addrinfo_req.getaddrinfo(self.uv_loop(), - *host_ptr, *servname_ptr, - *hint_ptr) |_, addrinfo, err| { - let res = match err { - None => Ok(accum_addrinfo(addrinfo)), - Some(err) => Err(uv_error_to_io_error(err)) - }; - (*result_cell_ptr).put_back(res); - let scheduler: ~Scheduler = Local::take(); - scheduler.resume_blocked_task_immediately(task_cell.take()); - } - } - } + fn fs_stat(&mut self, path: &CString) -> Result { + do uv_fs_helper(self.uv_loop(), fs_mkstat) |req, l, cb| { + req.stat(l, path, cb) } - addrinfo_req.delete(); - assert!(!result_cell.is_empty()); - return result_cell.take(); } fn fs_mkdir(&mut self, path: &CString, perm: io::FilePermission) -> Result<(), IoError> { - do uv_fs_helper(self.uv_loop(), path) |mkdir_req, l, p, cb| { - do mkdir_req.mkdir(l, p, perm as c_int) |req, err| { - cb(req, err) - }; + do uv_fs_helper(self.uv_loop(), unit) |req, l, cb| { + req.mkdir(l, path, perm as c_int, cb) } } fn fs_rmdir(&mut self, path: &CString) -> Result<(), IoError> { - do uv_fs_helper(self.uv_loop(), path) |rmdir_req, l, p, cb| { - do rmdir_req.rmdir(l, p) |req, err| { - cb(req, err) - }; + do uv_fs_helper(self.uv_loop(), unit) |req, l, cb| { + req.rmdir(l, path, cb) } } fn fs_rename(&mut self, path: &CString, to: &CString) -> Result<(), IoError> { - let to = to.with_ref(|p| p); - do uv_fs_helper(self.uv_loop(), path) |rename_req, l, p, cb| { - let to = unsafe { CString::new(to, false) }; - do rename_req.rename(l, p, &to) |req, err| { - cb(req, err) - }; + do uv_fs_helper(self.uv_loop(), unit) |req, l, cb| { + req.rename(l, path, to, cb) } } fn fs_chmod(&mut self, path: &CString, perm: io::FilePermission) -> Result<(), IoError> { - do uv_fs_helper(self.uv_loop(), path) |chmod_req, l, p, cb| { - do chmod_req.chmod(l, p, perm as c_int) |req, err| { - cb(req, err) - }; + do uv_fs_helper(self.uv_loop(), unit) |req, l, cb| { + req.chmod(l, path, perm as c_int, cb) } } ->>>>>>> Remove all blocking std::os blocking functions fn fs_readdir(&mut self, path: &CString, flags: c_int) -> Result<~[Path], IoError> { use str::StrSlice; @@ -773,6 +747,29 @@ impl IoFactory for UvIoFactory { assert!(!result_cell.is_empty()); return result_cell.take(); } + fn fs_link(&mut self, src: &CString, dst: &CString) -> Result<(), IoError> { + do uv_fs_helper(self.uv_loop(), unit) |req, l, cb| { + req.link(l, src, dst, cb) + } + } + fn fs_symlink(&mut self, src: &CString, dst: &CString) -> Result<(), IoError> { + do uv_fs_helper(self.uv_loop(), unit) |req, l, cb| { + req.symlink(l, src, dst, cb) + } + } + fn fs_chown(&mut self, path: &CString, uid: int, gid: int) -> Result<(), IoError> { + do uv_fs_helper(self.uv_loop(), unit) |req, l, cb| { + req.chown(l, path, uid, gid, cb) + } + } + fn fs_readlink(&mut self, path: &CString) -> Result { + fn getlink(f: &mut FsRequest) -> Path { + Path::new(unsafe { CString::new(f.get_path(), false) }) + } + do uv_fs_helper(self.uv_loop(), getlink) |req, l, cb| { + req.readlink(l, path, cb) + } + } fn spawn(&mut self, config: ProcessConfig) -> Result<(~RtioProcess, ~[Option<~RtioPipe>]), IoError> @@ -1581,26 +1578,9 @@ impl UvFileStream { result_cell.take() } fn base_write(&mut self, buf: &[u8], offset: i64) -> Result<(), IoError> { - let result_cell = Cell::new_empty(); - let result_cell_ptr: *Cell> = &result_cell; - let buf_ptr: *&[u8] = &buf; - do self.home_for_io_with_sched |self_, scheduler| { - do scheduler.deschedule_running_task_and_then |_, task| { - let buf = unsafe { slice_to_uv_buf(*buf_ptr) }; - let task_cell = Cell::new(task); - let write_req = file::FsRequest::new(); - do write_req.write(&self_.loop_, self_.fd, buf, offset) |_, uverr| { - let res = match uverr { - None => Ok(()), - Some(err) => Err(uv_error_to_io_error(err)) - }; - unsafe { (*result_cell_ptr).put_back(res); } - let scheduler: ~Scheduler = Local::take(); - scheduler.resume_blocked_task_immediately(task_cell.take()); - } - } + do self.nop_req |self_, req, cb| { + req.write(&self_.loop_, self_.fd, slice_to_uv_buf(buf), offset, cb) } - result_cell.take() } fn seek_common(&mut self, pos: i64, whence: c_int) -> Result{ @@ -1618,6 +1598,27 @@ impl UvFileStream { } } } + fn nop_req(&mut self, f: &fn(&mut UvFileStream, file::FsRequest, FsCallback)) + -> Result<(), IoError> { + let result_cell = Cell::new_empty(); + let result_cell_ptr: *Cell> = &result_cell; + do self.home_for_io_with_sched |self_, sched| { + do sched.deschedule_running_task_and_then |_, task| { + let task = Cell::new(task); + let req = file::FsRequest::new(); + do f(self_, req) |_, uverr| { + let res = match uverr { + None => Ok(()), + Some(err) => Err(uv_error_to_io_error(err)) + }; + unsafe { (*result_cell_ptr).put_back(res); } + let scheduler: ~Scheduler = Local::take(); + scheduler.resume_blocked_task_immediately(task.take()); + } + } + } + result_cell.take() + } } impl Drop for UvFileStream { @@ -1672,6 +1673,21 @@ impl RtioFileStream for UvFileStream { let self_ = unsafe { cast::transmute::<&UvFileStream, &mut UvFileStream>(self) }; self_.seek_common(0, SEEK_CUR) } + fn fsync(&mut self) -> Result<(), IoError> { + do self.nop_req |self_, req, cb| { + req.fsync(&self_.loop_, self_.fd, cb) + } + } + fn datasync(&mut self) -> Result<(), IoError> { + do self.nop_req |self_, req, cb| { + req.datasync(&self_.loop_, self_.fd, cb) + } + } + fn truncate(&mut self, offset: i64) -> Result<(), IoError> { + do self.nop_req |self_, req, cb| { + req.truncate(&self_.loop_, self_.fd, offset, cb) + } + } } pub struct UvProcess { @@ -2489,13 +2505,13 @@ fn test_timer_sleep_simple() { } fn file_test_uvio_full_simple_impl() { - use std::rt::io::{Open, Create, ReadWrite, Read}; + use std::rt::io::{Open, ReadWrite, Read}; unsafe { let io = local_io(); let write_val = "hello uvio!"; let path = "./tmp/file_test_uvio_full.txt"; { - let create_fm = Create; + let create_fm = Open; let create_fa = ReadWrite; let mut fd = io.fs_open(&path.to_c_str(), create_fm, create_fa).unwrap(); let write_buf = write_val.as_bytes(); diff --git a/src/librustuv/uvll.rs b/src/librustuv/uvll.rs index a2047ef98fa83..b8f16db1066dc 100644 --- a/src/librustuv/uvll.rs +++ b/src/librustuv/uvll.rs @@ -222,6 +222,7 @@ pub type uv_exit_cb = extern "C" fn(handle: *uv_process_t, term_signal: c_int); pub type uv_signal_cb = extern "C" fn(handle: *uv_signal_t, signum: c_int); +pub type uv_fs_cb = extern "C" fn(req: *uv_fs_t); pub type sockaddr = c_void; pub type sockaddr_in = c_void; @@ -886,6 +887,11 @@ pub unsafe fn get_ptr_from_fs_req(req: *uv_fs_t) -> *libc::c_void { rust_uv_get_ptr_from_fs_req(req) } +pub unsafe fn get_path_from_fs_req(req: *uv_fs_t) -> *c_char { + #[fixed_stack_segment]; #[inline(never)]; + + rust_uv_get_path_from_fs_req(req) +} pub unsafe fn get_loop_from_fs_req(req: *uv_fs_t) -> *uv_loop_t { #[fixed_stack_segment]; #[inline(never)]; @@ -1129,6 +1135,7 @@ extern { fn rust_uv_populate_uv_stat(req_in: *uv_fs_t, stat_out: *uv_stat_t); fn rust_uv_get_result_from_fs_req(req: *uv_fs_t) -> c_int; fn rust_uv_get_ptr_from_fs_req(req: *uv_fs_t) -> *libc::c_void; + fn rust_uv_get_path_from_fs_req(req: *uv_fs_t) -> *c_char; fn rust_uv_get_loop_from_fs_req(req: *uv_fs_t) -> *uv_loop_t; fn rust_uv_get_loop_from_getaddrinfo_req(req: *uv_fs_t) -> *uv_loop_t; @@ -1189,7 +1196,24 @@ extern { signal_cb: uv_signal_cb, signum: c_int) -> c_int; fn rust_uv_signal_stop(handle: *uv_signal_t) -> c_int; + } +externfn!(fn uv_fs_fsync(handle: *uv_loop_t, req: *uv_fs_t, file: c_int, + cb: *u8) -> c_int) +externfn!(fn uv_fs_fdatasync(handle: *uv_loop_t, req: *uv_fs_t, file: c_int, + cb: *u8) -> c_int) +externfn!(fn uv_fs_ftruncate(handle: *uv_loop_t, req: *uv_fs_t, file: c_int, + offset: i64, cb: *u8) -> c_int) +externfn!(fn uv_fs_readlink(handle: *uv_loop_t, req: *uv_fs_t, file: *c_char, + cb: *u8) -> c_int) +externfn!(fn uv_fs_symlink(handle: *uv_loop_t, req: *uv_fs_t, src: *c_char, + dst: *c_char, cb: *u8) -> c_int) +externfn!(fn uv_fs_link(handle: *uv_loop_t, req: *uv_fs_t, src: *c_char, + dst: *c_char, cb: *u8) -> c_int) +externfn!(fn uv_fs_chown(handle: *uv_loop_t, req: *uv_fs_t, src: *c_char, + uid: uv_uid_t, gid: uv_gid_t, cb: *u8) -> c_int) +externfn!(fn uv_fs_lstat(handle: *uv_loop_t, req: *uv_fs_t, file: *c_char, + cb: *u8) -> c_int) // libuv requires various system libraries to successfully link on some // platforms diff --git a/src/libstd/libc.rs b/src/libstd/libc.rs index d4df0e826f604..f992b327495b5 100644 --- a/src/libstd/libc.rs +++ b/src/libstd/libc.rs @@ -142,7 +142,7 @@ pub use libc::consts::os::c95::{SEEK_SET, TMP_MAX}; pub use libc::consts::os::posix88::{F_OK, O_APPEND, O_CREAT, O_EXCL}; pub use libc::consts::os::posix88::{O_RDONLY, O_RDWR, O_TRUNC, O_WRONLY}; pub use libc::consts::os::posix88::{R_OK, S_IEXEC, S_IFBLK, S_IFCHR}; -pub use libc::consts::os::posix88::{S_IFDIR, S_IFIFO, S_IFMT, S_IFREG}; +pub use libc::consts::os::posix88::{S_IFDIR, S_IFIFO, S_IFMT, S_IFREG, S_IFLNK}; pub use libc::consts::os::posix88::{S_IREAD, S_IRUSR, S_IRWXU, S_IWUSR}; pub use libc::consts::os::posix88::{STDERR_FILENO, STDIN_FILENO}; pub use libc::consts::os::posix88::{STDOUT_FILENO, W_OK, X_OK}; @@ -1168,6 +1168,7 @@ pub mod consts { pub static S_IFBLK : c_int = 12288; pub static S_IFDIR : c_int = 16384; pub static S_IFREG : c_int = 32768; + pub static S_IFLNK : c_int = 40960; pub static S_IFMT : c_int = 61440; pub static S_IEXEC : c_int = 64; pub static S_IWRITE : c_int = 128; @@ -1345,6 +1346,7 @@ pub mod consts { pub static S_IFBLK : c_int = 24576; pub static S_IFDIR : c_int = 16384; pub static S_IFREG : c_int = 32768; + pub static S_IFLNK : c_int = 40960; pub static S_IFMT : c_int = 61440; pub static S_IEXEC : c_int = 64; pub static S_IWRITE : c_int = 128; @@ -1555,6 +1557,7 @@ pub mod consts { pub static S_IFBLK : c_int = 24576; pub static S_IFDIR : c_int = 16384; pub static S_IFREG : c_int = 32768; + pub static S_IFLNK : c_int = 40960; pub static S_IFMT : c_int = 61440; pub static S_IEXEC : c_int = 64; pub static S_IWRITE : c_int = 128; @@ -1999,6 +2002,7 @@ pub mod consts { pub static S_IFBLK : c_int = 24576; pub static S_IFDIR : c_int = 16384; pub static S_IFREG : c_int = 32768; + pub static S_IFLNK : c_int = 40960; pub static S_IFMT : c_int = 61440; pub static S_IEXEC : c_int = 64; pub static S_IWRITE : c_int = 128; @@ -2341,6 +2345,7 @@ pub mod consts { pub static S_IFBLK : c_int = 24576; pub static S_IFDIR : c_int = 16384; pub static S_IFREG : c_int = 32768; + pub static S_IFLNK : c_int = 40960; pub static S_IFMT : c_int = 61440; pub static S_IEXEC : c_int = 64; pub static S_IWRITE : c_int = 128; diff --git a/src/libstd/os.rs b/src/libstd/os.rs index 12281f06005a7..f461781e13251 100644 --- a/src/libstd/os.rs +++ b/src/libstd/os.rs @@ -1495,7 +1495,7 @@ mod tests { use result::{Ok, Err}; use os::*; use libc::*; - use rt::io::file; + use rt::io::File; #[cfg(unix)] #[fixed_stack_segment] @@ -1544,7 +1544,7 @@ mod tests { assert!(*chunk.data == 0xbe); close(fd); } - file::unlink(&path); + File::unlink(&path); } // More recursive_mkdir tests are in extra::tempfile diff --git a/src/libstd/path/windows.rs b/src/libstd/path/windows.rs index dfd654ac13c73..8483b504c0137 100644 --- a/src/libstd/path/windows.rs +++ b/src/libstd/path/windows.rs @@ -23,9 +23,6 @@ use to_bytes::IterBytes; use vec::Vector; use super::{contains_nul, BytesContainer, GenericPath, GenericPathUnsafe}; -#[cfg(target_os = "win32")] -use rt::io::{FileStat, file, io_error}; - /// Iterator that yields successive components of a Path as &str /// /// Each component is yielded as Option<&str> for compatibility with PosixPath, but @@ -1056,67 +1053,6 @@ fn prefix_is_sep(p: Option, c: u8) -> bool { else { is_sep_verbatim(c as char) } } -// Stat support -#[cfg(target_os = "win32")] -impl Path { - /// Calls stat() on the represented file and returns the resulting rt::io::FileStat - pub fn stat(&self) -> Option { - let mut file_stat: Option = None; - do io_error::cond.trap(|_| { /* Ignore error, will return None */ }).inside { - file_stat = file::stat(self); - } - file_stat - } - - /// Returns whether the represented file exists - pub fn exists(&self) -> bool { - match self.stat() { - None => false, - Some(_) => true - } - } - - /// Returns the filesize of the represented file - pub fn get_size(&self) -> Option { - match self.stat() { - None => None, - Some(st) => Some(st.size) - } - } - - /// Returns the mode of the represented file - pub fn get_mode(&self) -> Option { - match self.stat() { - None => None, - Some(st) => Some(st.mode as uint) - } - } - - /// Returns the atime of the represented file, as msecs - pub fn get_atime(&self) -> Option { - match self.stat() { - None => None, - Some(st) => Some(st.accessed) - } - } - - /// Returns the mtime of the represented file, as msecs - pub fn get_mtime(&self) -> Option { - match self.stat() { - None => None, - Some(st) => Some(st.modified) - } - } - - /// Returns the ctime of the represented file, as msecs - pub fn get_ctime(&self) -> Option { - match self.stat() { - None => None, - Some(st) => Some(st.created) - } - } -} - #[cfg(test)] mod tests { use super::*; diff --git a/src/libstd/rand/os.rs b/src/libstd/rand/os.rs index c9499bb4aa8e6..a6d05ea307cdb 100644 --- a/src/libstd/rand/os.rs +++ b/src/libstd/rand/os.rs @@ -13,12 +13,11 @@ use rand::Rng; use ops::Drop; -use path::Path; #[cfg(unix)] use rand::reader::ReaderRng; #[cfg(unix)] -use rt::io::file; +use rt::io::File; #[cfg(windows)] use cast; @@ -41,7 +40,7 @@ type HCRYPTPROV = c_long; /// This does not block. #[cfg(unix)] pub struct OSRng { - priv inner: ReaderRng + priv inner: ReaderRng } /// A random number generator that retrieves randomness straight from /// the operating system. Platform sources: @@ -61,7 +60,8 @@ impl OSRng { /// Create a new `OSRng`. #[cfg(unix)] pub fn new() -> OSRng { - let reader = file::open(&Path::new("/dev/urandom")); + use path::Path; + let reader = File::open(&Path::new("/dev/urandom")); let reader = reader.expect("Error opening /dev/urandom"); let reader_rng = ReaderRng::new(reader); diff --git a/src/libstd/rt/io/file.rs b/src/libstd/rt/io/file.rs index b6c0b58434f1a..c3f5f38721151 100644 --- a/src/libstd/rt/io/file.rs +++ b/src/libstd/rt/io/file.rs @@ -16,7 +16,7 @@ with regular files & directories on a filesystem. At the top-level of the module are a set of freestanding functions, associated with various filesystem operations. They all operate on a `Path` object. -All operations in this module, including those as part of `FileStream` et al +All operations in this module, including those as part of `File` et al block the task during execution. Most will raise `std::rt::io::io_error` conditions in the event of failure. @@ -28,66 +28,40 @@ particular bits of it, etc. */ use c_str::ToCStr; +use iter::Iterator; use super::{Reader, Writer, Seek}; -use super::{SeekStyle, Read, Write, Open, CreateOrTruncate, +use super::{SeekStyle, Read, Write, Open, IoError, Truncate, FileMode, FileAccess, FileStat, io_error, FilePermission}; use rt::rtio::{RtioFileStream, IoFactory, with_local_io}; use rt::io; use option::{Some, None, Option}; -use result::{Ok, Err}; +use result::{Ok, Err, Result}; use path; use path::{Path, GenericPath}; +use vec::OwnedVector; -/// Open a file for reading/writing, as indicated by `path`. -/// -/// # Example -/// -/// use std::rt::{io, file, io_error}; -/// -/// let p = Path::new("/some/file/path.txt"); -/// -/// do io_error::cond.trap(|_| { -/// // hoo-boy... -/// }).inside { -/// let stream = match file::open_stream(&p, io::Create, io::ReadWrite) { -/// Some(s) => s, -/// None => fail!("whoops! I'm sure this raised, anyways..") -/// }; -/// // do some stuff with that stream -/// -/// // the file stream will be closed at the end of this block -/// } -/// // .. -/// -/// `FileMode` and `FileAccess` provide information about the permissions -/// context in which a given stream is created. More information about them -/// can be found in `std::rt::io`'s docs. +/// Unconstrained file access type that exposes read and write operations /// -/// Note that, with this function, a `FileStream` is returned regardless of -/// the access-limitations indicated by `FileAccess` (e.g. calling `write` on a -/// `FileStream` opened as `ReadOnly` will raise an `io_error` condition at -/// runtime). If you desire a more-correctly-constrained interface to files, -/// use the `{open_stream, open, create}` methods that are a part of `Path`. +/// Can be retreived via `File::open()` and `Path.File::open_mode()`. /// /// # Errors /// -/// This function will raise an `io_error` condition under a number of different -/// circumstances, to include but not limited to: +/// This type will raise an io_error condition if operations are attempted against +/// it for which its underlying file descriptor was not configured at creation +/// time, via the `FileAccess` parameter to `file::open()`. /// -/// * Opening a file that already exists with `FileMode` of `Create` or vice -/// versa (e.g. opening a non-existant file with `FileMode` or `Open`) -/// * Attempting to open a file with a `FileAccess` that the user lacks -/// permissions for -/// * Filesystem-level errors (full disk, etc) -pub fn open_stream(path: &Path, - mode: FileMode, - access: FileAccess) -> Option { +/// For this reason, it is best to use the access-constrained wrappers that are +/// exposed via `Path.open()` and `Path.create()`. +pub struct File { + priv fd: ~RtioFileStream, + priv path: Path, + priv last_nread: int, +} + +fn io_raise(f: &fn(io: &mut IoFactory) -> Result) -> Option { do with_local_io |io| { - match io.fs_open(&path.to_c_str(), mode, access) { - Ok(fd) => Some(FileStream { - fd: fd, - last_nread: -1 - }), + match f(io) { + Ok(t) => Some(t), Err(ioerr) => { io_error::cond.raise(ioerr); None @@ -96,54 +70,367 @@ pub fn open_stream(path: &Path, } } -/// Attempts to open a file in read-only mode. This function is equivalent to -/// `open_stream(path, Open, Read)`, and will raise all of the same errors that -/// `open_stream` does. -/// -/// For more information, see the `open_stream` function. -pub fn open(path: &Path) -> Option { - open_stream(path, Open, Read).map(|s| FileReader { stream: s }) -} +impl File { + /// Open a file at `path` in the mode specified by the `mode` and `access` + /// arguments + /// + /// # Example + /// + /// use std::rt::io::{File, io_error, Open, ReadWrite}; + /// + /// let p = Path::new("/some/file/path.txt"); + /// + /// do io_error::cond.trap(|_| { + /// // hoo-boy... + /// }).inside { + /// let file = match File::open_mode(&p, Open, ReadWrite) { + /// Some(s) => s, + /// None => fail!("whoops! I'm sure this raised, anyways..") + /// }; + /// // do some stuff with that file + /// + /// // the file will be closed at the end of this block + /// } + /// // .. + /// + /// `FileMode` and `FileAccess` provide information about the permissions + /// context in which a given stream is created. More information about them + /// can be found in `std::rt::io`'s docs. If a file is opened with `Write` + /// or `ReadWrite` access, then it will be created it it does not already + /// exist. + /// + /// Note that, with this function, a `File` is returned regardless of the + /// access-limitations indicated by `FileAccess` (e.g. calling `write` on a + /// `File` opened as `Read` will raise an `io_error` condition at runtime). + /// + /// # Errors + /// + /// This function will raise an `io_error` condition under a number of + /// different circumstances, to include but not limited to: + /// + /// * Opening a file that does not exist with `Read` access. + /// * Attempting to open a file with a `FileAccess` that the user lacks + /// permissions for + /// * Filesystem-level errors (full disk, etc) + pub fn open_mode(path: &Path, + mode: FileMode, + access: FileAccess) -> Option { + do with_local_io |io| { + match io.fs_open(&path.to_c_str(), mode, access) { + Ok(fd) => Some(File { + path: path.clone(), + fd: fd, + last_nread: -1 + }), + Err(ioerr) => { + io_error::cond.raise(ioerr); + None + } + } + } + } -/// Attempts to create a file in write-only mode. This function is equivalent to -/// `open_stream(path, CreateOrTruncate, Write)`, and will raise all of the -/// same errors that `open_stream` does. -/// -/// For more information, see the `open_stream` function. -pub fn create(path: &Path) -> Option { - open_stream(path, CreateOrTruncate, Write).map(|s| FileWriter { stream: s }) -} + /// Attempts to open a file in read-only mode. This function is equivalent to + /// `File::open_mode(path, Open, Read)`, and will raise all of the same + /// errors that `File::open_mode` does. + /// + /// For more information, see the `File::open_mode` function. + /// + /// # Example + /// + /// use std::rt::io::File; + /// + /// let contents = File::open("foo.txt").read_to_end(); + pub fn open(path: &Path) -> Option { + File::open_mode(path, Open, Read) + } -/// Unlink a file from the underlying filesystem. -/// -/// # Example -/// -/// use std::rt::io::file; -/// -/// let p = Path::new("/some/file/path.txt"); -/// file::unlink(&p); -/// // if we made it here without failing, then the -/// // unlink operation was successful -/// -/// Note that, just because an unlink call was successful, it is not -/// guaranteed that a file is immediately deleted (e.g. depending on -/// platform, other open file descriptors may prevent immediate removal) -/// -/// # Errors -/// -/// This function will raise an `io_error` condition if the path points to a -/// directory, the user lacks permissions to remove the file, or if some other -/// filesystem-level error occurs. -pub fn unlink(path: &Path) { - do with_local_io |io| { - match io.fs_unlink(&path.to_c_str()) { - Ok(()) => Some(()), - Err(ioerr) => { - io_error::cond.raise(ioerr); - None + /// Attempts to create a file in write-only mode. This function is + /// equivalent to `File::open_mode(path, Truncate, Write)`, and will + /// raise all of the same errors that `File::open_mode` does. + /// + /// For more information, see the `File::open_mode` function. + /// + /// # Example + /// + /// use std::rt::io::File; + /// + /// File::create("foo.txt").write(bytes!("This is a sample file")); + pub fn create(path: &Path) -> Option { + File::open_mode(path, Truncate, Write) + } + + /// Unlink a file from the underlying filesystem. + /// + /// # Example + /// + /// use std::rt::io::File; + /// + /// let p = Path::new("/some/file/path.txt"); + /// File::unlink(&p); + /// // if we made it here without failing, then the + /// // unlink operation was successful + /// + /// Note that, just because an unlink call was successful, it is not + /// guaranteed that a file is immediately deleted (e.g. depending on + /// platform, other open file descriptors may prevent immediate removal) + /// + /// # Errors + /// + /// This function will raise an `io_error` condition if the path points to a + /// directory, the user lacks permissions to remove the file, or if some + /// other filesystem-level error occurs. + pub fn unlink(path: &Path) { + do io_raise |io| { io.fs_unlink(&path.to_c_str()) }; + } + + /// Given a path, query the file system to get information about a file, + /// directory, etc. This function will traverse symlinks to query + /// information about the destination file. + /// + /// Returns a fully-filled out stat structure on succes, and on failure it + /// will return a dummy stat structure (it is expected that the condition + /// raised is handled as well). + /// + /// # Example + /// + /// use std::rt::io::{File, io_error}; + /// + /// let p = Path::new("/some/file/path.txt"); + /// + /// do io_error::cond.trap(|_| { + /// // hoo-boy... + /// }).inside { + /// let info = File::stat(p); + /// if info.is_file { + /// // just imagine the possibilities ... + /// } + /// } + /// + /// # Errors + /// + /// This call will raise an `io_error` condition if the user lacks the + /// requisite permissions to perform a `stat` call on the given path or if + /// there is no entry in the filesystem at the provided path. + pub fn stat(path: &Path) -> FileStat { + do io_raise |io| { + io.fs_stat(&path.to_c_str()) + }.unwrap_or_else(File::dummystat) + } + + fn dummystat() -> FileStat { + FileStat { + path: Path::new(""), + size: 0, + kind: io::TypeFile, + perm: 0, + created: 0, + modified: 0, + accessed: 0, + device: 0, + inode: 0, + rdev: 0, + nlink: 0, + uid: 0, + gid: 0, + blksize: 0, + blocks: 0, + flags: 0, + gen: 0, + } + } + + /// Perform the same operation as the `stat` function, except that this + /// function does not traverse through symlinks. This will return + /// information about the symlink file instead of the file that it points + /// to. + /// + /// # Errors + /// + /// See `stat` + pub fn lstat(path: &Path) -> FileStat { + do io_raise |io| { + io.fs_lstat(&path.to_c_str()) + }.unwrap_or_else(File::dummystat) + } + + /// Rename a file or directory to a new name. + /// + /// # Example + /// + /// use std::rt::io::File; + /// + /// File::rename(Path::new("foo"), Path::new("bar")); + /// // Oh boy, nothing was raised! + /// + /// # Errors + /// + /// Will raise an `io_error` condition if the provided `path` doesn't exist, + /// the process lacks permissions to view the contents, or if some other + /// intermittent I/O error occurs. + pub fn rename(from: &Path, to: &Path) { + do io_raise |io| { + io.fs_rename(&from.to_c_str(), &to.to_c_str()) + }; + } + + /// Copies the contents of one file to another. This function will also + /// copy the permission bits of the original file to the destination file. + /// + /// Note that if `from` and `to` both point to the same file, then the file + /// will likely get truncated by this operation. + /// + /// # Example + /// + /// use std::rt::io::File; + /// + /// File::copy(Path::new("foo.txt"), Path::new("bar.txt")); + /// // Oh boy, nothing was raised! + /// + /// # Errors + /// + /// Will raise an `io_error` condition is the following situtations, but is + /// not limited to just these cases: + /// + /// * The `from` path is not a file + /// * The `from` file does not exist + /// * The current process does not have the permission rights to access + /// `from` or write `to` + /// + /// Note that this copy is not atomic in that once the destination is + /// ensured to not exist, the is nothing preventing the destination from + /// being created and then destroyed by this operation. + pub fn copy(from: &Path, to: &Path) { + if !from.is_file() { + return io_error::cond.raise(IoError { + kind: io::MismatchedFileTypeForOperation, + desc: "the source path is not an existing file", + detail: None, + }); + } + + let mut reader = match File::open(from) { Some(f) => f, None => return }; + let mut writer = match File::create(to) { Some(f) => f, None => return }; + let mut buf = [0, ..io::DEFAULT_BUF_SIZE]; + + loop { + match reader.read(buf) { + Some(amt) => writer.write(buf.slice_to(amt)), + None => break } } - }; + + File::chmod(to, from.stat().perm) + } + + /// Changes the permission mode bits found on a file or a directory. This + /// function takes a mask from the `io` module + /// + /// # Example + /// + /// use std::rt::io; + /// use std::rt::io::File; + /// + /// File::chmod(&Path::new("file.txt"), io::UserFile); + /// File::chmod(&Path::new("file.txt"), io::UserRead | io::UserWrite); + /// File::chmod(&Path::new("dir"), io::UserDir); + /// File::chmod(&Path::new("file.exe"), io::UserExec); + /// + /// # Errors + /// + /// If this funciton encounters an I/O error, it will raise on the `io_error` + /// condition. Some possible error situations are not having the permission to + /// change the attributes of a file or the file not existing. + pub fn chmod(path: &Path, mode: io::FilePermission) { + do io_raise |io| { + io.fs_chmod(&path.to_c_str(), mode) + }; + } + + /// Change the user and group owners of a file at the specified path. + /// + /// # Errors + /// + /// This funtion will raise on the `io_error` condition on failure. + pub fn chown(path: &Path, uid: int, gid: int) { + do io_raise |io| { io.fs_chown(&path.to_c_str(), uid, gid) }; + } + + /// Creates a new hard link on the filesystem. The `dst` path will be a + /// link pointing to the `src` path. Note that systems often require these + /// two paths to both be located on the same filesystem. + /// + /// # Errors + /// + /// This function will raise on the `io_error` condition on failure. + pub fn link(src: &Path, dst: &Path) { + do io_raise |io| { io.fs_link(&src.to_c_str(), &dst.to_c_str()) }; + } + + /// Creates a new symbolic link on the filesystem. The `dst` path will be a + /// symlink pointing to the `src` path. + /// + /// # Errors + /// + /// This function will raise on the `io_error` condition on failure. + pub fn symlink(src: &Path, dst: &Path) { + do io_raise |io| { io.fs_symlink(&src.to_c_str(), &dst.to_c_str()) }; + } + + /// Reads a symlink, returning the file that the symlink points to. + /// + /// # Errors + /// + /// This function will raise on the `io_error` condition on failure. + /// + /// XXX: does this fail if called on files. + pub fn readlink(path: &Path) -> Option { + do io_raise |io| { io.fs_readlink(&path.to_c_str()) } + } + + /// Returns the original path which was used to open this file. + pub fn path<'a>(&'a self) -> &'a Path { + &self.path + } + + /// Synchronizes all modifications to this file to its permanent storage + /// device. This will flush any internal buffers necessary to perform this + /// operation. + /// + /// # Errors + /// + /// This function will raise on the `io_error` condition on failure. + pub fn fsync(&mut self) { + self.fd.fsync(); + } + + /// This function is similar to `fsync`, except that it may not synchronize + /// file metadata to the filesystem. This is intended for use case which + /// must synchronize content, but don't need the metadata on disk. The goal + /// of this method is to reduce disk operations. + /// + /// # Errors + /// + /// This function will raise on the `io_error` condition on failure. + pub fn datasync(&mut self) { + self.fd.datasync(); + } + + /// Either truncates or extends the underlying file, as extended from the + /// file's current position. This is equivalent to the unix `truncate` + /// function. + /// + /// The offset given is added to the file's current position and the result + /// is the new size of the file. If the new size is less than the current + /// size, then the file is truncated. If the new size is greater than the + /// current size, then the file is expanded to be filled with 0s. + /// + /// # Errors + /// + /// On error, this function will raise on the `io_error` condition. + pub fn truncate(&mut self, offset: i64) { + self.fd.truncate(offset); + } } /// Create a new, empty directory at the provided path @@ -163,14 +450,8 @@ pub fn unlink(path: &Path) { /// to make a new directory at the provided path, or if the directory already /// exists. pub fn mkdir(path: &Path, mode: FilePermission) { - do with_local_io |io| { - match io.fs_mkdir(&path.to_c_str(), mode) { - Ok(_) => Some(()), - Err(ioerr) => { - io_error::cond.raise(ioerr); - None - } - } + do io_raise |io| { + io.fs_mkdir(&path.to_c_str(), mode) }; } @@ -190,71 +471,11 @@ pub fn mkdir(path: &Path, mode: FilePermission) { /// to remove the directory at the provided path, or if the directory isn't /// empty. pub fn rmdir(path: &Path) { - do with_local_io |io| { - match io.fs_rmdir(&path.to_c_str()) { - Ok(_) => Some(()), - Err(ioerr) => { - io_error::cond.raise(ioerr); - None - } - } + do io_raise |io| { + io.fs_rmdir(&path.to_c_str()) }; } -/// Get information on the file, directory, etc at the provided path -/// -/// Given a path, query the file system to get information about a file, -/// directory, etc. -/// -/// Returns a fully-filled out stat structure on succes, and on failure it will -/// return a dummy stat structure (it is expected that the condition raised is -/// handled as well). -/// -/// # Example -/// -/// use std::rt::io::{file, io_error}; -/// -/// let p = Path::new("/some/file/path.txt"); -/// -/// do io_error::cond.trap(|_| { -/// // hoo-boy... -/// }).inside { -/// let info = file::stat(p); -/// if info.is_file { -/// // just imagine the possibilities ... -/// } -/// } -/// -/// # Errors -/// -/// This call will raise an `io_error` condition if the user lacks the requisite -/// permissions to perform a `stat` call on the given path or if there is no -/// entry in the filesystem at the provided path. -pub fn stat(path: &Path) -> FileStat { - do with_local_io |io| { - match io.fs_stat(&path.to_c_str()) { - Ok(p) => Some(p), - Err(ioerr) => { - io_error::cond.raise(ioerr); - None - } - } - }.unwrap_or_else(|| { - FileStat { - path: Path::new(path.to_c_str()), - is_file: false, - is_dir: false, - device: 0, - mode: 0, - inode: 0, - size: 0, - created: 0, - modified: 0, - accessed: 0, - } - }) -} - /// Retrieve a vector containing all entries within a provided directory /// /// # Example @@ -278,105 +499,41 @@ pub fn stat(path: &Path) -> FileStat { /// the process lacks permissions to view the contents or if the `path` points /// at a non-directory file pub fn readdir(path: &Path) -> ~[Path] { - do with_local_io |io| { - match io.fs_readdir(&path.to_c_str(), 0) { - Ok(p) => Some(p), - Err(ioerr) => { - io_error::cond.raise(ioerr); - None - } - } + do io_raise |io| { + io.fs_readdir(&path.to_c_str(), 0) }.unwrap_or_else(|| ~[]) } -/// Rename a file or directory to a new name. -/// -/// # Example -/// -/// use std::rt::io::file; -/// -/// file::rename(Path::new("foo"), Path::new("bar")); -/// // Oh boy, nothing was raised! -/// -/// # Errors -/// -/// Will raise an `io_error` condition if the provided `path` doesn't exist, -/// the process lacks permissions to view the contents, or if some other -/// intermittent I/O error occurs. -pub fn rename(from: &Path, to: &Path) { - do with_local_io |io| { - match io.fs_rename(&from.to_c_str(), &to.to_c_str()) { - Ok(()) => Some(()), - Err(ioerr) => { - io_error::cond.raise(ioerr); - None - } - } - }; +/// Returns an iterator which will recursively walk the directory structure +/// rooted at `path`. The path given will not be iterated over, and this will +/// perform iteration in a top-down order. +pub fn walk_dir(path: &Path) -> WalkIterator { + WalkIterator { stack: readdir(path) } } -/// Copies the contents of one file to another. -/// -/// # Example -/// -/// use std::rt::io::file; -/// -/// file::copy(Path::new("foo.txt"), Path::new("bar.txt")); -/// // Oh boy, nothing was raised! -/// -/// # Errors -/// -/// Will raise an `io_error` condition if the provided `from` doesn't exist, -/// the process lacks permissions to view the contents, or if some other -/// intermittent I/O error occurs (such as `to` couldn't be created). -pub fn copy(from: &Path, to: &Path) { - let mut reader = match open(from) { Some(f) => f, None => return }; - let mut writer = match create(to) { Some(f) => f, None => return }; - let mut buf = [0, ..io::DEFAULT_BUF_SIZE]; - - loop { - match reader.read(buf) { - Some(amt) => writer.write(buf.slice_to(amt)), - None => break - } - } - - // FIXME(#10131) this is an awful way to pull out the permission bits. - // If this comment is removed, then there should be a test - // asserting that permission bits are maintained using the - // permission interface created. - chmod(to, (from.stat().mode & 0xfff) as u32); +/// An iterator which walks over a directory +pub struct WalkIterator { + priv stack: ~[Path], } -// This function is not public because it's got a terrible interface for `mode` -// FIXME(#10131) -fn chmod(path: &Path, mode: u32) { - do with_local_io |io| { - match io.fs_chmod(&path.to_c_str(), mode) { - Ok(()) => Some(()), - Err(ioerr) => { - io_error::cond.raise(ioerr); - None +impl Iterator for WalkIterator { + fn next(&mut self) -> Option { + match self.stack.shift_opt() { + Some(path) => { + if path.is_dir() { + self.stack.push_all_move(readdir(&path)); + } + Some(path) } + None => None } - }; -} - -/// Recursively walk a directory structure. This function will call the -/// provided closure on all directories and files found inside the path -/// pointed to by `self`. If the closure returns `false`, then the iteration -/// will be short-circuited. -pub fn walk_dir(path: &Path, f: &fn(&Path) -> bool) -> bool { - let files = readdir(path); - files.iter().advance(|q| { - f(q) && (!q.is_dir() || walk_dir(q, |p| f(p))) - }) + } } /// Recursively create a directory and all of its parent components if they /// are missing. /// -/// # Failure +/// # Errors /// /// This function will raise on the `io_error` condition if an error /// happens, see `file::mkdir` for more information about error conditions @@ -396,74 +553,25 @@ pub fn mkdir_recursive(path: &Path, mode: FilePermission) { /// Removes a directory at this path, after removing all its contents. Use /// carefully! /// -/// # Failure +/// # Errors /// /// This function will raise on the `io_error` condition if an error /// happens. See `file::unlink` and `file::readdir` for possible error /// conditions. pub fn rmdir_recursive(path: &Path) { - do walk_dir(path) |inner| { - if inner.is_dir() { - rmdir_recursive(inner); + let children = readdir(path); + for child in children.iter() { + if child.is_dir() { + rmdir_recursive(child); } else { - unlink(inner); + File::unlink(child); } - true - }; + } // Directory should now be empty rmdir(path); } -/// Constrained version of `FileStream` that only exposes read-specific -/// operations. -/// -/// Can be retreived via `Path.open()` or `file::open`. -pub struct FileReader { priv stream: FileStream } - -impl Reader for FileReader { - fn read(&mut self, buf: &mut [u8]) -> Option { self.stream.read(buf) } - fn eof(&mut self) -> bool { self.stream.eof() } -} - -impl Seek for FileReader { - fn tell(&self) -> u64 { self.stream.tell() } - fn seek(&mut self, p: i64, s: SeekStyle) { self.stream.seek(p, s) } -} - -/// Constrained version of `FileStream` that only exposes write-specific -/// operations. -/// -/// Can be retreived via `Path.create()` or `file::create`. -pub struct FileWriter { priv stream: FileStream } - -impl Writer for FileWriter { - fn write(&mut self, buf: &[u8]) { self.stream.write(buf); } - fn flush(&mut self) { self.stream.flush(); } -} - -impl Seek for FileWriter { - fn tell(&self) -> u64 { self.stream.tell() } - fn seek(&mut self, p: i64, s: SeekStyle) { self.stream.seek(p, s); } -} - -/// Unconstrained file access type that exposes read and write operations -/// -/// Can be retreived via `file::open()` and `Path.open_stream()`. -/// -/// # Errors -/// -/// This type will raise an io_error condition if operations are attempted against -/// it for which its underlying file descriptor was not configured at creation -/// time, via the `FileAccess` parameter to `file::open()`. -/// -/// For this reason, it is best to use the access-constrained wrappers that are -/// exposed via `Path.open()` and `Path.create()`. -pub struct FileStream { - priv fd: ~RtioFileStream, - priv last_nread: int, -} - -impl Reader for FileStream { +impl Reader for File { fn read(&mut self, buf: &mut [u8]) -> Option { match self.fd.read(buf) { Ok(read) => { @@ -486,10 +594,10 @@ impl Reader for FileStream { fn eof(&mut self) -> bool { self.last_nread == 0 } } -impl Writer for FileStream { +impl Writer for File { fn write(&mut self, buf: &[u8]) { match self.fd.write(buf) { - Ok(_) => (), + Ok(()) => (), Err(ioerr) => { io_error::cond.raise(ioerr); } @@ -497,7 +605,7 @@ impl Writer for FileStream { } } -impl Seek for FileStream { +impl Seek for File { fn tell(&self) -> u64 { let res = self.fd.tell(); match res { @@ -529,7 +637,7 @@ impl path::Path { /// Consult the `file::stat` documentation for more info. /// /// This call preserves identical runtime/error semantics with `file::stat`. - pub fn stat(&self) -> FileStat { stat(self) } + pub fn stat(&self) -> FileStat { File::stat(self) } /// Boolean value indicator whether the underlying file exists on the local /// filesystem. This will return true if the path points to either a @@ -552,7 +660,7 @@ impl path::Path { /// Will not raise a condition pub fn is_file(&self) -> bool { match io::result(|| self.stat()) { - Ok(s) => s.is_file, + Ok(s) => s.kind == io::TypeFile, Err(*) => false } } @@ -567,7 +675,7 @@ impl path::Path { /// Will not raise a condition pub fn is_dir(&self) -> bool { match io::result(|| self.stat()) { - Ok(s) => s.is_dir, + Ok(s) => s.kind == io::TypeDirectory, Err(*) => false } } @@ -575,19 +683,11 @@ impl path::Path { #[cfg(test)] mod test { - use path::{Path, GenericPath}; - use result::{Ok, Err}; - use option::{Some, None}; - use iter::range; - use rt::test::run_in_mt_newsched_task; - use super::{open_stream, unlink, stat, copy, rmdir, mkdir, readdir, - open, create, rmdir_recursive, mkdir_recursive}; - + use prelude::*; + use rt::io::{SeekSet, SeekCur, SeekEnd, io_error, Read, Open, ReadWrite}; use rt::io; - use rt::io::Reader; - use super::super::{SeekSet, SeekCur, SeekEnd, - io_error, Read, Create, Open, ReadWrite}; - use vec::Vector; + use str; + use super::{File, rmdir, mkdir, readdir, rmdir_recursive, mkdir_recursive}; fn tmpdir() -> Path { use os; @@ -599,266 +699,236 @@ mod test { #[test] fn file_test_io_smoke_test() { - do run_in_mt_newsched_task { - let message = "it's alright. have a good time"; - let filename = &Path::new("./tmp/file_rt_io_file_test.txt"); - { - let mut write_stream = open_stream(filename, Create, ReadWrite); - write_stream.write(message.as_bytes()); - } - { - use str; - let mut read_stream = open_stream(filename, Open, Read); - let mut read_buf = [0, .. 1028]; - let read_str = match read_stream.read(read_buf).unwrap() { - -1|0 => fail!("shouldn't happen"), - n => str::from_utf8(read_buf.slice_to(n)) - }; - assert!(read_str == message.to_owned()); - } - unlink(filename); + let message = "it's alright. have a good time"; + let filename = &Path::new("./tmp/file_rt_io_file_test.txt"); + { + let mut write_stream = File::open_mode(filename, Open, ReadWrite); + write_stream.write(message.as_bytes()); } + { + let mut read_stream = File::open_mode(filename, Open, Read); + let mut read_buf = [0, .. 1028]; + let read_str = match read_stream.read(read_buf).unwrap() { + -1|0 => fail!("shouldn't happen"), + n => str::from_utf8(read_buf.slice_to(n)) + }; + assert!(read_str == message.to_owned()); + } + File::unlink(filename); } #[test] fn file_test_io_invalid_path_opened_without_create_should_raise_condition() { - do run_in_mt_newsched_task { - let filename = &Path::new("./tmp/file_that_does_not_exist.txt"); - let mut called = false; - do io_error::cond.trap(|_| { - called = true; - }).inside { - let result = open_stream(filename, Open, Read); - assert!(result.is_none()); - } - assert!(called); + let filename = &Path::new("./tmp/file_that_does_not_exist.txt"); + let mut called = false; + do io_error::cond.trap(|_| { + called = true; + }).inside { + let result = File::open_mode(filename, Open, Read); + assert!(result.is_none()); } + assert!(called); } #[test] fn file_test_iounlinking_invalid_path_should_raise_condition() { - do run_in_mt_newsched_task { - let filename = &Path::new("./tmp/file_another_file_that_does_not_exist.txt"); - let mut called = false; - do io_error::cond.trap(|_| { - called = true; - }).inside { - unlink(filename); - } - assert!(called); + let filename = &Path::new("./tmp/file_another_file_that_does_not_exist.txt"); + let mut called = false; + do io_error::cond.trap(|_| { + called = true; + }).inside { + File::unlink(filename); } + assert!(called); } #[test] fn file_test_io_non_positional_read() { - do run_in_mt_newsched_task { - use str; - let message = "ten-four"; - let mut read_mem = [0, .. 8]; - let filename = &Path::new("./tmp/file_rt_io_file_test_positional.txt"); + let message = "ten-four"; + let mut read_mem = [0, .. 8]; + let filename = &Path::new("./tmp/file_rt_io_file_test_positional.txt"); + { + let mut rw_stream = File::open_mode(filename, Open, ReadWrite); + rw_stream.write(message.as_bytes()); + } + { + let mut read_stream = File::open_mode(filename, Open, Read); { - let mut rw_stream = open_stream(filename, Create, ReadWrite); - rw_stream.write(message.as_bytes()); + let read_buf = read_mem.mut_slice(0, 4); + read_stream.read(read_buf); } { - let mut read_stream = open_stream(filename, Open, Read); - { - let read_buf = read_mem.mut_slice(0, 4); - read_stream.read(read_buf); - } - { - let read_buf = read_mem.mut_slice(4, 8); - read_stream.read(read_buf); - } + let read_buf = read_mem.mut_slice(4, 8); + read_stream.read(read_buf); } - unlink(filename); - let read_str = str::from_utf8(read_mem); - assert!(read_str == message.to_owned()); } + File::unlink(filename); + let read_str = str::from_utf8(read_mem); + assert!(read_str == message.to_owned()); } #[test] fn file_test_io_seek_and_tell_smoke_test() { - do run_in_mt_newsched_task { - use str; - let message = "ten-four"; - let mut read_mem = [0, .. 4]; - let set_cursor = 4 as u64; - let mut tell_pos_pre_read; - let mut tell_pos_post_read; - let filename = &Path::new("./tmp/file_rt_io_file_test_seeking.txt"); - { - let mut rw_stream = open_stream(filename, Create, ReadWrite); - rw_stream.write(message.as_bytes()); - } - { - let mut read_stream = open_stream(filename, Open, Read); - read_stream.seek(set_cursor as i64, SeekSet); - tell_pos_pre_read = read_stream.tell(); - read_stream.read(read_mem); - tell_pos_post_read = read_stream.tell(); - } - unlink(filename); - let read_str = str::from_utf8(read_mem); - assert!(read_str == message.slice(4, 8).to_owned()); - assert!(tell_pos_pre_read == set_cursor); - assert!(tell_pos_post_read == message.len() as u64); + let message = "ten-four"; + let mut read_mem = [0, .. 4]; + let set_cursor = 4 as u64; + let mut tell_pos_pre_read; + let mut tell_pos_post_read; + let filename = &Path::new("./tmp/file_rt_io_file_test_seeking.txt"); + { + let mut rw_stream = File::open_mode(filename, Open, ReadWrite); + rw_stream.write(message.as_bytes()); + } + { + let mut read_stream = File::open_mode(filename, Open, Read); + read_stream.seek(set_cursor as i64, SeekSet); + tell_pos_pre_read = read_stream.tell(); + read_stream.read(read_mem); + tell_pos_post_read = read_stream.tell(); } + File::unlink(filename); + let read_str = str::from_utf8(read_mem); + assert!(read_str == message.slice(4, 8).to_owned()); + assert!(tell_pos_pre_read == set_cursor); + assert!(tell_pos_post_read == message.len() as u64); } #[test] fn file_test_io_seek_and_write() { - do run_in_mt_newsched_task { - use str; - let initial_msg = "food-is-yummy"; - let overwrite_msg = "-the-bar!!"; - let final_msg = "foo-the-bar!!"; - let seek_idx = 3; - let mut read_mem = [0, .. 13]; - let filename = &Path::new("./tmp/file_rt_io_file_test_seek_and_write.txt"); - { - let mut rw_stream = open_stream(filename, Create, ReadWrite); - rw_stream.write(initial_msg.as_bytes()); - rw_stream.seek(seek_idx as i64, SeekSet); - rw_stream.write(overwrite_msg.as_bytes()); - } - { - let mut read_stream = open_stream(filename, Open, Read); - read_stream.read(read_mem); - } - unlink(filename); - let read_str = str::from_utf8(read_mem); - assert!(read_str == final_msg.to_owned()); + let initial_msg = "food-is-yummy"; + let overwrite_msg = "-the-bar!!"; + let final_msg = "foo-the-bar!!"; + let seek_idx = 3; + let mut read_mem = [0, .. 13]; + let filename = &Path::new("./tmp/file_rt_io_file_test_seek_and_write.txt"); + { + let mut rw_stream = File::open_mode(filename, Open, ReadWrite); + rw_stream.write(initial_msg.as_bytes()); + rw_stream.seek(seek_idx as i64, SeekSet); + rw_stream.write(overwrite_msg.as_bytes()); } + { + let mut read_stream = File::open_mode(filename, Open, Read); + read_stream.read(read_mem); + } + File::unlink(filename); + let read_str = str::from_utf8(read_mem); + assert!(read_str == final_msg.to_owned()); } #[test] fn file_test_io_seek_shakedown() { - do run_in_mt_newsched_task { - use str; // 01234567890123 - let initial_msg = "qwer-asdf-zxcv"; - let chunk_one = "qwer"; - let chunk_two = "asdf"; - let chunk_three = "zxcv"; - let mut read_mem = [0, .. 4]; - let filename = &Path::new("./tmp/file_rt_io_file_test_seek_shakedown.txt"); - { - let mut rw_stream = open_stream(filename, Create, ReadWrite); - rw_stream.write(initial_msg.as_bytes()); - } - { - let mut read_stream = open_stream(filename, Open, Read); - - read_stream.seek(-4, SeekEnd); - read_stream.read(read_mem); - let read_str = str::from_utf8(read_mem); - assert!(read_str == chunk_three.to_owned()); - - read_stream.seek(-9, SeekCur); - read_stream.read(read_mem); - let read_str = str::from_utf8(read_mem); - assert!(read_str == chunk_two.to_owned()); - - read_stream.seek(0, SeekSet); - read_stream.read(read_mem); - let read_str = str::from_utf8(read_mem); - assert!(read_str == chunk_one.to_owned()); - } - unlink(filename); + use std::str; // 01234567890123 + let initial_msg = "qwer-asdf-zxcv"; + let chunk_one = "qwer"; + let chunk_two = "asdf"; + let chunk_three = "zxcv"; + let mut read_mem = [0, .. 4]; + let filename = &Path::new("./tmp/file_rt_io_file_test_seek_shakedown.txt"); + { + let mut rw_stream = File::open_mode(filename, Open, ReadWrite); + rw_stream.write(initial_msg.as_bytes()); } + { + let mut read_stream = File::open_mode(filename, Open, Read); + + read_stream.seek(-4, SeekEnd); + read_stream.read(read_mem); + let read_str = str::from_utf8(read_mem); + assert!(read_str == chunk_three.to_owned()); + + read_stream.seek(-9, SeekCur); + read_stream.read(read_mem); + let read_str = str::from_utf8(read_mem); + assert!(read_str == chunk_two.to_owned()); + + read_stream.seek(0, SeekSet); + read_stream.read(read_mem); + let read_str = str::from_utf8(read_mem); + assert!(read_str == chunk_one.to_owned()); + } + File::unlink(filename); } #[test] fn file_test_stat_is_correct_on_is_file() { - do run_in_mt_newsched_task { - let filename = &Path::new("./tmp/file_stat_correct_on_is_file.txt"); - { - let mut fs = open_stream(filename, Create, ReadWrite); - let msg = "hw"; - fs.write(msg.as_bytes()); - } - let stat_res = stat(filename); - assert!(stat_res.is_file); - unlink(filename); + let filename = &Path::new("./tmp/file_stat_correct_on_is_file.txt"); + { + let mut fs = File::open_mode(filename, Open, ReadWrite); + let msg = "hw"; + fs.write(msg.as_bytes()); } + let stat_res = File::stat(filename); + assert_eq!(stat_res.kind, io::TypeFile); + File::unlink(filename); } #[test] fn file_test_stat_is_correct_on_is_dir() { - do run_in_mt_newsched_task { - let filename = &Path::new("./tmp/file_stat_correct_on_is_dir"); - mkdir(filename, io::UserRWX); - let stat_res = filename.stat(); - assert!(stat_res.is_dir); - rmdir(filename); - } + let filename = &Path::new("./tmp/file_stat_correct_on_is_dir"); + mkdir(filename, io::UserRWX); + let stat_res = filename.stat(); + assert!(stat_res.kind == io::TypeDirectory); + rmdir(filename); } #[test] fn file_test_fileinfo_false_when_checking_is_file_on_a_directory() { - do run_in_mt_newsched_task { - let dir = &Path::new("./tmp/fileinfo_false_on_dir"); - mkdir(dir, io::UserRWX); - assert!(dir.is_file() == false); - rmdir(dir); - } + let dir = &Path::new("./tmp/fileinfo_false_on_dir"); + mkdir(dir, io::UserRWX); + assert!(dir.is_file() == false); + rmdir(dir); } #[test] fn file_test_fileinfo_check_exists_before_and_after_file_creation() { - do run_in_mt_newsched_task { - let file = &Path::new("./tmp/fileinfo_check_exists_b_and_a.txt"); - create(file).write(bytes!("foo")); - assert!(file.exists()); - unlink(file); - assert!(!file.exists()); - } + let file = &Path::new("./tmp/fileinfo_check_exists_b_and_a.txt"); + File::create(file).write(bytes!("foo")); + assert!(file.exists()); + File::unlink(file); + assert!(!file.exists()); } #[test] fn file_test_directoryinfo_check_exists_before_and_after_mkdir() { - do run_in_mt_newsched_task { - let dir = &Path::new("./tmp/before_and_after_dir"); - assert!(!dir.exists()); - mkdir(dir, io::UserRWX); - assert!(dir.exists()); - assert!(dir.is_dir()); - rmdir(dir); - assert!(!dir.exists()); - } + let dir = &Path::new("./tmp/before_and_after_dir"); + assert!(!dir.exists()); + mkdir(dir, io::UserRWX); + assert!(dir.exists()); + assert!(dir.is_dir()); + rmdir(dir); + assert!(!dir.exists()); } #[test] fn file_test_directoryinfo_readdir() { - use str; - do run_in_mt_newsched_task { - let dir = &Path::new("./tmp/di_readdir"); - mkdir(dir, io::UserRWX); - let prefix = "foo"; - for n in range(0,3) { - let f = dir.join(format!("{}.txt", n)); - let mut w = create(&f); - let msg_str = (prefix + n.to_str().to_owned()).to_owned(); - let msg = msg_str.as_bytes(); - w.write(msg); - } - let files = readdir(dir); - let mut mem = [0u8, .. 4]; - for f in files.iter() { - { - let n = f.filestem_str(); - open(f).read(mem); - let read_str = str::from_utf8(mem); - let expected = match n { - None|Some("") => fail!("really shouldn't happen.."), - Some(n) => prefix+n - }; - assert!(expected == read_str); - } - unlink(f); + use std::str; + let dir = &Path::new("./tmp/di_readdir"); + mkdir(dir, io::UserRWX); + let prefix = "foo"; + for n in range(0,3) { + let f = dir.join(format!("{}.txt", n)); + let mut w = File::create(&f); + let msg_str = (prefix + n.to_str().to_owned()).to_owned(); + let msg = msg_str.as_bytes(); + w.write(msg); + } + let files = readdir(dir); + let mut mem = [0u8, .. 4]; + for f in files.iter() { + { + let n = f.filestem_str(); + File::open(f).read(mem); + let read_str = str::from_utf8(mem); + let expected = match n { + None|Some("") => fail!("really shouldn't happen.."), + Some(n) => prefix+n + }; + assert!(expected == read_str); } - rmdir(dir); + File::unlink(f); } + rmdir(dir); } #[test] @@ -880,7 +950,7 @@ mod test { let mut filepath = dirpath; filepath.push("unicode-file-\uac00\u4e00\u30fc\u4f60\u597d.rs"); - create(&filepath); // ignore return; touch only + File::create(&filepath); // ignore return; touch only assert!(!filepath.is_dir()); assert!(filepath.exists()); @@ -905,7 +975,7 @@ mod 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)) { + match io::result(|| File::copy(&from, &to)) { Ok(*) => fail!(), Err(*) => { assert!(!from.exists()); @@ -920,12 +990,226 @@ mod test { let input = tmpdir.join("in.txt"); let out = tmpdir.join("out.txt"); - create(&input).write(bytes!("hello")); - copy(&input, &out); - let contents = open(&out).read_to_end(); + File::create(&input).write(bytes!("hello")); + File::copy(&input, &out); + let contents = File::open(&out).read_to_end(); assert_eq!(contents.as_slice(), bytes!("hello")); - assert_eq!(input.stat().mode, out.stat().mode); + assert_eq!(input.stat().perm, out.stat().perm); + rmdir_recursive(&tmpdir); + } + + #[test] + fn copy_file_dst_dir() { + let tmpdir = tmpdir(); + let out = tmpdir.join("out"); + + File::create(&out); + match io::result(|| File::copy(&out, &tmpdir)) { + Ok(*) => fail!(), Err(*) => {} + } + rmdir_recursive(&tmpdir); + } + + #[test] + fn copy_file_dst_exists() { + let tmpdir = tmpdir(); + let input = tmpdir.join("in"); + let output = tmpdir.join("out"); + + File::create(&input).write("foo".as_bytes()); + File::create(&output).write("bar".as_bytes()); + File::copy(&input, &output); + + assert_eq!(File::open(&output).read_to_end(), + (bytes!("foo")).to_owned()); + + rmdir_recursive(&tmpdir); + } + + #[test] + fn copy_file_src_dir() { + let tmpdir = tmpdir(); + let out = tmpdir.join("out"); + + match io::result(|| File::copy(&tmpdir, &out)) { + Ok(*) => fail!(), Err(*) => {} + } + assert!(!out.exists()); + rmdir_recursive(&tmpdir); + } + + #[test] + fn copy_file_preserves_perm_bits() { + let tmpdir = tmpdir(); + let input = tmpdir.join("in.txt"); + let out = tmpdir.join("out.txt"); + + File::create(&input); + File::chmod(&input, io::UserExec); + File::copy(&input, &out); + assert_eq!(out.stat().perm, io::UserExec); + + rmdir_recursive(&tmpdir); + } + + #[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()); + File::symlink(&input, &out); + assert_eq!(File::lstat(&out).kind, io::TypeSymlink); + assert_eq!(File::stat(&out).size, File::stat(&input).size); + assert_eq!(File::open(&out).read_to_end(), (bytes!("foobar")).to_owned()); + + // can't link to yourself + match io::result(|| File::symlink(&input, &input)) { + Ok(*) => fail!("wanted a failure"), + Err(*) => {} + } + // symlinks can point to things that don't exist + File::symlink(&tmpdir.join("foo"), &tmpdir.join("bar")); + + assert!(File::readlink(&tmpdir.join("bar")).unwrap() == tmpdir.join("bar")); + + match io::result(|| File::readlink(&tmpdir)) { + Ok(*) => fail!("wanted a failure"), + Err(*) => {} + } + + rmdir_recursive(&tmpdir); + } + + #[test] + fn links_work() { + let tmpdir = tmpdir(); + let input = tmpdir.join("in.txt"); + let out = tmpdir.join("out.txt"); + + File::create(&input).write("foobar".as_bytes()); + File::link(&input, &out); + assert_eq!(File::lstat(&out).kind, io::TypeFile); + assert_eq!(File::stat(&out).size, File::stat(&input).size); + assert_eq!(File::stat(&out).nlink, 2); + assert_eq!(File::open(&out).read_to_end(), (bytes!("foobar")).to_owned()); + + // can't link to yourself + match io::result(|| File::link(&input, &input)) { + Ok(*) => fail!("wanted a failure"), + Err(*) => {} + } + // can't link to something that doesn't exist + match io::result(|| File::link(&tmpdir.join("foo"), &tmpdir.join("bar"))) { + Ok(*) => fail!("wanted a failure"), + Err(*) => {} + } + + rmdir_recursive(&tmpdir); + } + + #[test] + fn chmod_works() { + let tmpdir = tmpdir(); + let file = tmpdir.join("in.txt"); + + File::create(&file); + File::chmod(&file, io::UserRWX); + assert_eq!(File::stat(&file).perm, io::UserRWX); + + match io::result(|| File::chmod(&tmpdir.join("foo"), io::UserRWX)) { + Ok(*) => fail!("wanted a failure"), + Err(*) => {} + } + + rmdir_recursive(&tmpdir); + } + + #[test] + fn sync_doesnt_kill_anything() { + let tmpdir = tmpdir(); + let path = tmpdir.join("in.txt"); + + let mut file = File::open_mode(&path, io::Open, io::ReadWrite).unwrap(); + file.fsync(); + file.datasync(); + file.write(bytes!("foo")); + file.fsync(); + file.datasync(); + + rmdir_recursive(&tmpdir); + } + + #[test] + fn truncate_works() { + let tmpdir = tmpdir(); + let path = tmpdir.join("in.txt"); + + let mut file = File::open_mode(&path, io::Open, io::ReadWrite).unwrap(); + file.write(bytes!("foo")); + + // Do some simple things with truncation + assert_eq!(File::stat(&path).size, 3); + file.truncate(10); + assert_eq!(File::stat(&path).size, 10); + file.write(bytes!("bar")); + assert_eq!(File::stat(&path).size, 10); + assert_eq!(File::open(&path).read_to_end(), + (bytes!("foobar", 0, 0, 0, 0)).to_owned()); + + // Truncate to a smaller length, don't seek, and then write something. + // Ensure that the intermediate zeroes are all filled in (we're seeked + // past the end of the file). + file.truncate(2); + assert_eq!(File::stat(&path).size, 2); + file.write(bytes!("wut")); + assert_eq!(File::stat(&path).size, 9); + assert_eq!(File::open(&path).read_to_end(), + (bytes!("fo", 0, 0, 0, 0, "wut")).to_owned()); + + rmdir_recursive(&tmpdir); + } + + #[test] + fn open_flavors() { + let tmpdir = tmpdir(); + + match io::result(|| File::open_mode(&tmpdir.join("a"), io::Open, + io::Read)) { + Ok(*) => fail!(), Err(*) => {} + } + File::open_mode(&tmpdir.join("b"), io::Open, io::Write).unwrap(); + File::open_mode(&tmpdir.join("c"), io::Open, io::ReadWrite).unwrap(); + File::open_mode(&tmpdir.join("d"), io::Append, io::Write).unwrap(); + File::open_mode(&tmpdir.join("e"), io::Append, io::ReadWrite).unwrap(); + File::open_mode(&tmpdir.join("f"), io::Truncate, io::Write).unwrap(); + File::open_mode(&tmpdir.join("g"), io::Truncate, io::ReadWrite).unwrap(); + + File::create(&tmpdir.join("h")).write("foo".as_bytes()); + File::open_mode(&tmpdir.join("h"), io::Open, io::Read).unwrap(); + { + let mut f = File::open_mode(&tmpdir.join("h"), io::Open, + io::Read).unwrap(); + match io::result(|| f.write("wut".as_bytes())) { + Ok(*) => fail!(), Err(*) => {} + } + } + assert_eq!(File::stat(&tmpdir.join("h")).size, 3); + { + let mut f = File::open_mode(&tmpdir.join("h"), io::Append, + io::Write).unwrap(); + f.write("bar".as_bytes()); + } + assert_eq!(File::stat(&tmpdir.join("h")).size, 6); + { + let mut f = File::open_mode(&tmpdir.join("h"), io::Truncate, + io::Write).unwrap(); + f.write("bar".as_bytes()); + } + assert_eq!(File::stat(&tmpdir.join("h")).size, 3); + rmdir_recursive(&tmpdir); } } diff --git a/src/libstd/rt/io/mod.rs b/src/libstd/rt/io/mod.rs index 51204ca73b94b..510c3470d06ae 100644 --- a/src/libstd/rt/io/mod.rs +++ b/src/libstd/rt/io/mod.rs @@ -231,8 +231,6 @@ Out of scope * Trait for things that are both readers and writers, Stream? * How to handle newline conversion * String conversion -* File vs. FileStream? File is shorter but could also be used for getting file info - - maybe File is for general file querying and *also* has a static `open` method * open vs. connect for generic stream opening * Do we need `close` at all? dtors might be good enough * How does I/O relate to the Iterator trait? @@ -244,7 +242,6 @@ Out of scope use cast; use int; -use libc; use path::Path; use str::{StrSlice, OwnedStr}; use option::{Option, Some, None}; @@ -262,7 +259,7 @@ pub use self::stdio::stderr; pub use self::stdio::print; pub use self::stdio::println; -pub use self::file::FileStream; +pub use self::file::File; pub use self::timer::Timer; pub use self::net::ip::IpAddr; pub use self::net::tcp::TcpListener; @@ -465,7 +462,7 @@ pub trait Reader { /// /// # Example /// - /// let reader = FileStream::new() + /// let reader = File::open(&Path::new("foo.txt")) /// while !reader.eof() { /// println(reader.read_line()); /// } @@ -1104,55 +1101,103 @@ pub fn placeholder_error() -> IoError { } } -/// Instructions on how to open a file and return a `FileStream`. +/// A mode specifies how a file should be opened or created. These modes are +/// passed to `File::open_mode` and are used to control where the file is +/// positioned when it is initially opened. pub enum FileMode { - /// Opens an existing file. IoError if file does not exist. + /// Opens a file positioned at the beginning. Open, - /// Creates a file. IoError if file exists. - Create, - /// Opens an existing file or creates a new one. - OpenOrCreate, - /// Opens an existing file or creates a new one, positioned at EOF. + /// Opens a file positioned at EOF. Append, - /// Opens an existing file, truncating it to 0 bytes. + /// Opens a file, truncating it if it already exists. Truncate, - /// Opens an existing file or creates a new one, truncating it to 0 bytes. - CreateOrTruncate, } -/// Access permissions with which the file should be opened. -/// `FileStream`s opened with `Read` will raise an `io_error` condition if written to. +/// Access permissions with which the file should be opened. `File`s +/// opened with `Read` will raise an `io_error` condition if written to. pub enum FileAccess { Read, Write, - ReadWrite + ReadWrite, +} + +/// Different kinds of files which can be identified by a call to stat +#[deriving(Eq)] +pub enum FileType { + TypeFile, + TypeDirectory, + TypeNamedPipe, + TypeBlockSpecial, + TypeSymlink, + TypeUnknown, } pub struct FileStat { - /// A `Path` object containing information about the `PathInfo`'s location + /// The path that this stat structure is describing path: Path, - /// `true` if the file pointed at by the `PathInfo` is a regular file - is_file: bool, - /// `true` if the file pointed at by the `PathInfo` is a directory - is_dir: bool, - /// The file pointed at by the `PathInfo`'s device - device: u64, - /// The file pointed at by the `PathInfo`'s mode - mode: u64, - /// The file pointed at by the `PathInfo`'s inode - inode: u64, - /// The file pointed at by the `PathInfo`'s size in bytes + /// The size of the file, in bytes size: u64, - /// The file pointed at by the `PathInfo`'s creation time + /// The kind of file this path points to (directory, file, pipe, etc.) + kind: FileType, + /// The file permissions currently on the file + perm: FilePermission, + + // XXX: These time fields are pretty useless without an actual time + // representation, what are the milliseconds relative to? + + /// The time that the file was created at, in platform-dependent + /// milliseconds created: u64, - /// The file pointed at by the `PathInfo`'s last-modification time in - /// platform-dependent msecs + /// The time that this file was last modified, in platform-dependent + /// milliseconds modified: u64, - /// The file pointed at by the `PathInfo`'s last-accessd time (e.g. read) in - /// platform-dependent msecs + /// The time that this file was last accessed, in platform-dependent + /// milliseconds accessed: u64, + + // Various filesytem info + device: u64, + inode: u64, + rdev: u64, + nlink: u64, + uid: u64, + gid: u64, + blksize: u64, + blocks: u64, + flags: u64, + gen: u64, } -// FIXME(#10131): this needs to get designed for real +/// A set of permissions for a file or directory is represented by a set of +/// flags which are or'd together. pub type FilePermission = u32; -pub static UserRWX: FilePermission = libc::S_IRWXU as FilePermission; + +// Each permission bit +pub static UserRead: FilePermission = 0x100; +pub static UserWrite: FilePermission = 0x080; +pub static UserExecute: FilePermission = 0x040; +pub static GroupRead: FilePermission = 0x020; +pub static GroupWrite: FilePermission = 0x010; +pub static GroupExecute: FilePermission = 0x008; +pub static OtherRead: FilePermission = 0x004; +pub static OtherWrite: FilePermission = 0x002; +pub static OtherExecute: FilePermission = 0x001; + +// Common combinations of these bits +pub static UserRWX: FilePermission = UserRead | UserWrite | UserExecute; +pub static GroupRWX: FilePermission = GroupRead | GroupWrite | GroupExecute; +pub static OtherRWX: FilePermission = OtherRead | OtherWrite | OtherExecute; + +/// A set of permissions for user owned files, this is equivalent to 0644 on +/// unix-like systems. +pub static UserFile: FilePermission = UserRead | UserWrite | GroupRead | OtherRead; +/// A set of permissions for user owned directories, this is equivalent to 0755 +/// on unix-like systems. +pub static UserDir: FilePermission = UserRWX | GroupRead | GroupExecute | + OtherRead | OtherExecute; +/// A set of permissions for user owned executables, this is equivalent to 0755 +/// on unix-like systems. +pub static UserExec: FilePermission = UserDir; + +/// A mask for all possible permission bits +pub static AllPermissions: FilePermission = 0x1ff; diff --git a/src/libstd/rt/io/native/file.rs b/src/libstd/rt/io/native/file.rs index e26cc166c8da4..4eb473a73a6a3 100644 --- a/src/libstd/rt/io/native/file.rs +++ b/src/libstd/rt/io/native/file.rs @@ -309,14 +309,16 @@ mod tests { // get bitrotted instantaneously. mod old_os { use prelude::*; - use c_str::CString; - use libc::fclose; use libc::{size_t, c_void, c_int}; use libc; use vec; - #[cfg(test)] use os; + #[cfg(not(windows))] use c_str::CString; + #[cfg(not(windows))] use libc::fclose; + #[cfg(test)] #[cfg(windows)] use os; #[cfg(test)] use rand; + #[cfg(windows)] use str; + #[cfg(windows)] use ptr; // On Windows, wide character version of function must be used to support // unicode, so functions should be split into at least two versions, @@ -651,7 +653,7 @@ mod old_os { return false; } // Preserve permissions - let from_mode = from.stat().mode; + let from_mode = from.stat().perm; let ostream = do to.with_c_str |top| { do "w+b".with_c_str |modebuf| { @@ -735,8 +737,8 @@ mod old_os { #[test] fn test_path_is_dir() { - use rt::io::file::{open_stream, mkdir_recursive}; - use rt::io::{OpenOrCreate, Read, UserRWX}; + use rt::io::file::{mkdir_recursive}; + use rt::io::{File, UserRWX}; assert!((path_is_dir(&Path::new(".")))); assert!((!path_is_dir(&Path::new("test/stdtest/fs.rs")))); @@ -754,7 +756,7 @@ mod old_os { filepath.push("unicode-file-\uac00\u4e00\u30fc\u4f60\u597d.rs"); debug!("path_is_dir filepath: {}", filepath.display()); - open_stream(&filepath, OpenOrCreate, Read); // ignore return; touch only + File::create(&filepath); // ignore return; touch only assert!((!path_is_dir(&filepath))); assert!((!path_is_dir(&Path::new( diff --git a/src/libstd/rt/io/option.rs b/src/libstd/rt/io/option.rs index 234b46458b458..5938252571f51 100644 --- a/src/libstd/rt/io/option.rs +++ b/src/libstd/rt/io/option.rs @@ -11,7 +11,7 @@ //! Implementations of I/O traits for the Option type //! //! I/O constructors return option types to allow errors to be handled. -//! These implementations allow e.g. `Option` to be used +//! These implementations allow e.g. `Option` to be used //! as a `Reader` without unwrapping the option first. use option::*; diff --git a/src/libstd/rt/rtio.rs b/src/libstd/rt/rtio.rs index a0db1f1df000c..d24de7cbfee51 100644 --- a/src/libstd/rt/rtio.rs +++ b/src/libstd/rt/rtio.rs @@ -91,12 +91,17 @@ pub fn with_local_io(f: &fn(&mut IoFactory) -> Option) -> Option { } pub trait IoFactory { + // networking fn tcp_connect(&mut self, addr: SocketAddr) -> Result<~RtioTcpStream, IoError>; fn tcp_bind(&mut self, addr: SocketAddr) -> Result<~RtioTcpListener, IoError>; fn udp_bind(&mut self, addr: SocketAddr) -> Result<~RtioUdpSocket, IoError>; + fn unix_bind(&mut self, path: &CString) -> + Result<~RtioUnixListener, IoError>; + fn unix_connect(&mut self, path: &CString) -> Result<~RtioPipe, IoError>; fn get_host_addresses(&mut self, host: Option<&str>, servname: Option<&str>, hint: Option) -> Result<~[ai::Info], IoError>; - fn timer_init(&mut self) -> Result<~RtioTimer, IoError>; + + // filesystem operations fn fs_from_raw_fd(&mut self, fd: c_int, close: CloseBehavior) -> ~RtioFileStream; fn fs_open(&mut self, path: &CString, fm: FileMode, fa: FileAccess) -> Result<~RtioFileStream, IoError>; @@ -110,13 +115,18 @@ pub trait IoFactory { fn fs_rename(&mut self, path: &CString, to: &CString) -> Result<(), IoError>; fn fs_readdir(&mut self, path: &CString, flags: c_int) -> Result<~[Path], IoError>; + fn fs_lstat(&mut self, path: &CString) -> Result; + fn fs_chown(&mut self, path: &CString, uid: int, gid: int) -> + Result<(), IoError>; + fn fs_readlink(&mut self, path: &CString) -> Result; + fn fs_symlink(&mut self, src: &CString, dst: &CString) -> Result<(), IoError>; + fn fs_link(&mut self, src: &CString, dst: &CString) -> Result<(), IoError>; + + // misc + fn timer_init(&mut self) -> Result<~RtioTimer, IoError>; fn spawn(&mut self, config: ProcessConfig) -> Result<(~RtioProcess, ~[Option<~RtioPipe>]), IoError>; - fn pipe_open(&mut self, fd: c_int) -> Result<~RtioPipe, IoError>; - fn unix_bind(&mut self, path: &CString) -> - Result<~RtioUnixListener, IoError>; - fn unix_connect(&mut self, path: &CString) -> Result<~RtioPipe, IoError>; fn tty_open(&mut self, fd: c_int, readable: bool) -> Result<~RtioTTY, IoError>; fn signal(&mut self, signal: Signum, channel: SharedChan) @@ -177,6 +187,9 @@ pub trait RtioFileStream { fn pwrite(&mut self, buf: &[u8], offset: u64) -> Result<(), IoError>; fn seek(&mut self, pos: i64, whence: SeekStyle) -> Result; fn tell(&self) -> Result; + fn fsync(&mut self) -> Result<(), IoError>; + fn datasync(&mut self) -> Result<(), IoError>; + fn truncate(&mut self, offset: i64) -> Result<(), IoError>; } pub trait RtioProcess { diff --git a/src/libsyntax/ext/source_util.rs b/src/libsyntax/ext/source_util.rs index 876adf401862f..75b5ab81f9bb3 100644 --- a/src/libsyntax/ext/source_util.rs +++ b/src/libsyntax/ext/source_util.rs @@ -20,8 +20,7 @@ use parse::token::{get_ident_interner}; use print::pprust; use std::rt::io; -use std::rt::io::Reader; -use std::rt::io::file; +use std::rt::io::File; use std::str; // These macros all relate to the file system; they either return @@ -92,7 +91,7 @@ pub fn expand_include_str(cx: @ExtCtxt, sp: Span, tts: &[ast::token_tree]) -> base::MacResult { let file = get_single_str_from_tts(cx, sp, tts, "include_str!"); let file = res_rel_file(cx, sp, &Path::new(file)); - let bytes = match io::result(|| file::open(&file).read_to_end()) { + let bytes = match io::result(|| File::open(&file).read_to_end()) { Err(e) => { cx.span_fatal(sp, format!("couldn't read {}: {}", file.display(), e.desc)); @@ -114,7 +113,7 @@ pub fn expand_include_bin(cx: @ExtCtxt, sp: Span, tts: &[ast::token_tree]) let file = get_single_str_from_tts(cx, sp, tts, "include_bin!"); let file = res_rel_file(cx, sp, &Path::new(file)); - match io::result(|| file::open(&file).read_to_end()) { + match io::result(|| File::open(&file).read_to_end()) { Err(e) => { cx.span_fatal(sp, format!("couldn't read {}: {}", file.display(), e.desc)); diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index cd1be9a3c1615..fbe711b5efe9e 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -19,9 +19,8 @@ use parse::attr::parser_attr; use parse::lexer::reader; use parse::parser::Parser; -use std::path::Path; use std::rt::io; -use std::rt::io::file; +use std::rt::io::File; use std::str; pub mod lexer; @@ -268,7 +267,7 @@ pub fn file_to_filemap(sess: @mut ParseSess, path: &Path, spanopt: Option) None => sess.span_diagnostic.handler().fatal(msg), } }; - let bytes = match io::result(|| file::open(path).read_to_end()) { + let bytes = match io::result(|| File::open(path).read_to_end()) { Ok(bytes) => bytes, Err(e) => { err(format!("couldn't read {}: {}", path.display(), e.desc)); diff --git a/src/rt/rust_uv.cpp b/src/rt/rust_uv.cpp index 2b63325f931e7..a4361f14f69b2 100644 --- a/src/rt/rust_uv.cpp +++ b/src/rt/rust_uv.cpp @@ -532,6 +532,10 @@ extern "C" int rust_uv_get_result_from_fs_req(uv_fs_t* req) { return req->result; } +extern "C" const char* +rust_uv_get_path_from_fs_req(uv_fs_t* req) { + return req->path; +} extern "C" void* rust_uv_get_ptr_from_fs_req(uv_fs_t* req) { return req->ptr; diff --git a/src/test/bench/core-std.rs b/src/test/bench/core-std.rs index 531f01c199562..2c86fdfe6ad72 100644 --- a/src/test/bench/core-std.rs +++ b/src/test/bench/core-std.rs @@ -21,7 +21,7 @@ use std::rand; use std::str; use std::util; use std::vec; -use std::rt::io::file; +use std::rt::io::File; macro_rules! bench ( ($argv:expr, $id:ident) => (maybe_run_test($argv, stringify!($id).to_owned(), $id)) @@ -76,7 +76,7 @@ fn read_line() { path.push("src/test/bench/shootout-k-nucleotide.data"); for _ in range(0, 3) { - let mut reader = BufferedReader::new(file::open(&path).unwrap()); + let mut reader = BufferedReader::new(File::open(&path).unwrap()); while !reader.eof() { reader.read_line(); } diff --git a/src/test/bench/shootout-fasta.rs b/src/test/bench/shootout-fasta.rs index 7d3fa6104e5c3..d7d7e9a58f3ca 100644 --- a/src/test/bench/shootout-fasta.rs +++ b/src/test/bench/shootout-fasta.rs @@ -19,7 +19,7 @@ extern mod extra; use std::int; use std::rt::io; -use std::rt::io::file; +use std::rt::io::File; use std::os; use std::rand::Rng; use std::rand; @@ -123,7 +123,7 @@ fn main() { }; let writer = if os::getenv("RUST_BENCH").is_some() { - let file = file::create(&Path::new("./shootout-fasta.data")); + let file = File::create(&Path::new("./shootout-fasta.data")); @mut file as @mut io::Writer } else { @mut io::stdout() as @mut io::Writer diff --git a/src/test/run-pass/glob-std.rs b/src/test/run-pass/glob-std.rs index 56bcd24f1cb4e..7f684e41c75a9 100644 --- a/src/test/run-pass/glob-std.rs +++ b/src/test/run-pass/glob-std.rs @@ -23,7 +23,7 @@ pub fn main() { if directory { io::file::mkdir(&Path::new(path), io::UserRWX); } else { - io::file::create(&Path::new(path)); + io::File::create(&Path::new(path)); } } diff --git a/src/test/run-pass/rename-directory.rs b/src/test/run-pass/rename-directory.rs index 2f6de7e4472bd..0aa4ae40f9e5d 100644 --- a/src/test/run-pass/rename-directory.rs +++ b/src/test/run-pass/rename-directory.rs @@ -19,6 +19,7 @@ use std::os; use std::libc; use std::rt::io; use std::rt::io::file; +use std::rt::io::File; fn rename_directory() { #[fixed_stack_segment]; @@ -50,7 +51,7 @@ fn rename_directory() { let new_path = tmpdir.join_many(["quux", "blat"]); file::mkdir_recursive(&new_path, io::UserRWX); - file::rename(&old_path, &new_path.join("newdir")); + File::rename(&old_path, &new_path.join("newdir")); assert!(new_path.join("newdir").is_dir()); assert!(new_path.join_many(["newdir", "temp.txt"]).exists()); } diff --git a/src/test/run-pass/stat.rs b/src/test/run-pass/stat.rs index d46c8a64f5a4e..9ce3d318064c9 100644 --- a/src/test/run-pass/stat.rs +++ b/src/test/run-pass/stat.rs @@ -13,14 +13,14 @@ extern mod extra; use extra::tempfile; -use std::rt::io::file; +use std::rt::io::File; pub fn main() { let dir = tempfile::TempDir::new_in(&Path::new("."), "").unwrap(); let path = dir.path().join("file"); { - match file::create(&path) { + match File::create(&path) { None => unreachable!(), Some(f) => { let mut f = f; From 3c3ed1499a9b9e23d4a2d2243a7b0b1c9015f34b Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 31 Oct 2013 15:15:30 -0700 Subject: [PATCH 5/5] Move io::file to io::fs and fns out of File This renames the `file` module to `fs` because that more accurately describes its current purpose (manipulating the filesystem, not just files). Additionally, this adds an UnstableFileStat structure as a nested structure of FileStat to signify that the fields should not be depended on. The structure is currently flagged with #[unstable], but it's unlikely that it has much meaning. Closes #10241 --- src/compiletest/compiletest.rs | 4 +- src/compiletest/runtest.rs | 35 +- src/libextra/glob.rs | 4 +- src/libextra/tempfile.rs | 6 +- src/libextra/terminfo/parser/compiled.rs | 2 +- src/libextra/workcache.rs | 6 +- src/librustc/back/link.rs | 4 +- src/librustc/driver/driver.rs | 4 +- src/librustc/metadata/filesearch.rs | 4 +- src/librustdoc/html/render.rs | 4 +- src/librustpkg/installed_packages.rs | 8 +- src/librustpkg/lib.rs | 21 +- src/librustpkg/package_source.rs | 7 +- src/librustpkg/path_util.rs | 21 +- src/librustpkg/source_control.rs | 4 +- src/librustpkg/tests.rs | 74 +-- .../testsuite/pass/src/c-dependencies/foo.rs | 2 +- src/librustpkg/util.rs | 6 +- src/librustuv/file.rs | 1 + src/librustuv/uvio.rs | 24 +- src/librustuv/uvll.rs | 2 +- src/libstd/os.rs | 29 +- src/libstd/rt/io/{file.rs => fs.rs} | 620 +++++++++--------- src/libstd/rt/io/mod.rs | 24 +- src/libstd/rt/io/native/file.rs | 4 +- src/libstd/rt/io/signal.rs | 1 + src/libstd/rt/sched.rs | 2 +- src/libstd/run.rs | 8 +- src/test/run-pass/glob-std.rs | 2 +- src/test/run-pass/rename-directory.rs | 9 +- src/test/run-pass/tempfile.rs | 26 +- 31 files changed, 491 insertions(+), 477 deletions(-) rename src/libstd/rt/io/{file.rs => fs.rs} (73%) diff --git a/src/compiletest/compiletest.rs b/src/compiletest/compiletest.rs index a354bc84e52b5..f4bd668690eef 100644 --- a/src/compiletest/compiletest.rs +++ b/src/compiletest/compiletest.rs @@ -17,7 +17,7 @@ extern mod extra; use std::os; use std::rt; -use std::rt::io::file; +use std::rt::io::fs; use extra::getopts; use extra::getopts::groups::{optopt, optflag, reqopt}; @@ -248,7 +248,7 @@ pub fn make_tests(config: &config) -> ~[test::TestDescAndFn] { debug!("making tests from {}", config.src_base.display()); let mut tests = ~[]; - let dirs = file::readdir(&config.src_base); + let dirs = fs::readdir(&config.src_base); for file in dirs.iter() { let file = file.clone(); debug!("inspecting file {}", file.display()); diff --git a/src/compiletest/runtest.rs b/src/compiletest/runtest.rs index d55bdc2370327..1b3e34ad81934 100644 --- a/src/compiletest/runtest.rs +++ b/src/compiletest/runtest.rs @@ -20,43 +20,18 @@ use procsrv; use util; use util::logv; -use std::cell::Cell; use std::rt::io; -use std::rt::io::file; +use std::rt::io::fs; use std::rt::io::File; use std::os; use std::str; -use std::task::{spawn_sched, SingleThreaded}; use std::vec; -use std::unstable::running_on_valgrind; use extra::test::MetricMap; pub fn run(config: config, testfile: ~str) { - let config = Cell::new(config); - let testfile = Cell::new(testfile); - // FIXME #6436: Creating another thread to run the test because this - // is going to call waitpid. The new scheduler has some strange - // interaction between the blocking tasks and 'friend' schedulers - // that destroys parallelism if we let normal schedulers block. - // It should be possible to remove this spawn once std::run is - // rewritten to be non-blocking. - // - // We do _not_ create another thread if we're running on V because - // it serializes all threads anyways. - if running_on_valgrind() { - let config = config.take(); - let testfile = testfile.take(); - let mut _mm = MetricMap::new(); - run_metrics(config, testfile, &mut _mm); - } else { - do spawn_sched(SingleThreaded) { - let config = config.take(); - let testfile = testfile.take(); - let mut _mm = MetricMap::new(); - run_metrics(config, testfile, &mut _mm); - } - } + let mut _mm = MetricMap::new(); + run_metrics(config, testfile, &mut _mm); } pub fn run_metrics(config: config, testfile: ~str, mm: &mut MetricMap) { @@ -651,7 +626,7 @@ fn compose_and_run_compiler( fn ensure_dir(path: &Path) { if path.is_dir() { return; } - file::mkdir(path, io::UserRWX); + fs::mkdir(path, io::UserRWX); } fn compose_and_run(config: &config, testfile: &Path, @@ -921,7 +896,7 @@ fn _dummy_exec_compiled_test(config: &config, props: &TestProps, fn _arm_push_aux_shared_library(config: &config, testfile: &Path) { let tdir = aux_output_dir_name(config, testfile); - let dirs = file::readdir(&tdir); + let dirs = fs::readdir(&tdir); for file in dirs.iter() { if file.extension_str() == Some("so") { // FIXME (#9639): This needs to handle non-utf8 paths diff --git a/src/libextra/glob.rs b/src/libextra/glob.rs index a7742f771da3c..1edef5ddbe1b4 100644 --- a/src/libextra/glob.rs +++ b/src/libextra/glob.rs @@ -25,7 +25,7 @@ use std::{os, path}; use std::rt::io; -use std::rt::io::file; +use std::rt::io::fs; use std::path::is_sep; use sort; @@ -148,7 +148,7 @@ impl Iterator for GlobIterator { } fn list_dir_sorted(path: &Path) -> ~[Path] { - match io::result(|| file::readdir(path)) { + match io::result(|| fs::readdir(path)) { Ok(children) => { let mut children = children; sort::quick_sort(children, |p1, p2| p2.filename() <= p1.filename()); diff --git a/src/libextra/tempfile.rs b/src/libextra/tempfile.rs index 4affe7c1cde8a..fbd65cab98ca7 100644 --- a/src/libextra/tempfile.rs +++ b/src/libextra/tempfile.rs @@ -15,7 +15,7 @@ use std::os; use std::rand::Rng; use std::rand; use std::rt::io; -use std::rt::io::file; +use std::rt::io::fs; /// A wrapper for a path to temporary directory implementing automatic /// scope-pased deletion. @@ -38,7 +38,7 @@ impl TempDir { let mut r = rand::rng(); for _ in range(0u, 1000) { let p = tmpdir.join(r.gen_ascii_str(16) + suffix); - match io::result(|| file::mkdir(&p, io::UserRWX)) { + match io::result(|| fs::mkdir(&p, io::UserRWX)) { Err(*) => {} Ok(()) => return Some(TempDir { path: Some(p) }) } @@ -73,7 +73,7 @@ impl Drop for TempDir { fn drop(&mut self) { for path in self.path.iter() { if path.exists() { - file::rmdir_recursive(path); + fs::rmdir_recursive(path); } } } diff --git a/src/libextra/terminfo/parser/compiled.rs b/src/libextra/terminfo/parser/compiled.rs index b530c1b6334ed..04b30e5ef7474 100644 --- a/src/libextra/terminfo/parser/compiled.rs +++ b/src/libextra/terminfo/parser/compiled.rs @@ -329,6 +329,6 @@ mod test { #[ignore(reason = "no ncurses on buildbots, needs a bundled terminfo file to test against")] fn test_parse() { // FIXME #6870: Distribute a compiled file in src/tests and test there - // parse(io::file_reader(&p("/usr/share/terminfo/r/rxvt-256color")).unwrap(), false); + // parse(io::fs_reader(&p("/usr/share/terminfo/r/rxvt-256color")).unwrap(), false); } } diff --git a/src/libextra/workcache.rs b/src/libextra/workcache.rs index 09d9dd828d4e5..eed37a426be2d 100644 --- a/src/libextra/workcache.rs +++ b/src/libextra/workcache.rs @@ -19,8 +19,7 @@ use std::cell::Cell; use std::comm::{PortOne, oneshot}; use std::{str, task}; use std::rt::io; -use std::rt::io::File; -use std::rt::io::Decorator; +use std::rt::io::{File, Decorator}; use std::rt::io::mem::MemWriter; /** @@ -480,6 +479,7 @@ impl<'self, T:Send + #[test] fn test() { use std::{os, run}; + use std::rt::io::fs; use std::str::from_utf8_owned; // Create a path to a new file 'filename' in the directory in which @@ -487,7 +487,7 @@ fn test() { fn make_path(filename: ~str) -> Path { let pth = os::self_exe_path().expect("workcache::test failed").with_filename(filename); if pth.exists() { - File::unlink(&pth); + fs::unlink(&pth); } return pth; } diff --git a/src/librustc/back/link.rs b/src/librustc/back/link.rs index 81a205228073e..5b0f424360b1e 100644 --- a/src/librustc/back/link.rs +++ b/src/librustc/back/link.rs @@ -31,7 +31,7 @@ use std::ptr; use std::run; use std::str; use std::vec; -use std::rt::io::File; +use std::rt::io::fs; use syntax::ast; use syntax::ast_map::{path, path_mod, path_name, path_pretty_name}; use syntax::attr; @@ -950,7 +950,7 @@ pub fn link_binary(sess: Session, // Remove the temporary object file if we aren't saving temps if !sess.opts.save_temps { - File::unlink(obj_filename); + fs::unlink(obj_filename); } } diff --git a/src/librustc/driver/driver.rs b/src/librustc/driver/driver.rs index 01035385f97c7..744e192095bb2 100644 --- a/src/librustc/driver/driver.rs +++ b/src/librustc/driver/driver.rs @@ -27,7 +27,7 @@ use util::ppaux; use std::hashmap::{HashMap,HashSet}; use std::rt::io; -use std::rt::io::File; +use std::rt::io::fs; use std::rt::io::mem::MemReader; use std::os; use std::vec; @@ -370,7 +370,7 @@ pub fn phase_5_run_llvm_passes(sess: Session, // Remove assembly source unless --save-temps was specified if !sess.opts.save_temps { - File::unlink(&asm_filename); + fs::unlink(&asm_filename); } } else { time(sess.time_passes(), "LLVM passes", (), |_| diff --git a/src/librustc/metadata/filesearch.rs b/src/librustc/metadata/filesearch.rs index 44e43bd4ef3a6..c9bd5eff4a771 100644 --- a/src/librustc/metadata/filesearch.rs +++ b/src/librustc/metadata/filesearch.rs @@ -12,7 +12,7 @@ use std::option; use std::os; use std::rt::io; -use std::rt::io::file; +use std::rt::io::fs; use std::hashmap::HashSet; pub enum FileMatch { FileMatches, FileDoesntMatch } @@ -119,7 +119,7 @@ pub fn mk_filesearch(maybe_sysroot: &Option<@Path>, pub fn search(filesearch: @FileSearch, pick: pick) { do filesearch.for_each_lib_search_path() |lib_search_path| { debug!("searching {}", lib_search_path.display()); - match io::result(|| file::readdir(lib_search_path)) { + match io::result(|| fs::readdir(lib_search_path)) { Ok(files) => { let mut rslt = FileDoesntMatch; for path in files.iter() { diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index d0e01d1f42322..0efc52bbe4a67 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -41,7 +41,7 @@ use std::hashmap::{HashMap, HashSet}; use std::local_data; use std::rt::io::buffered::BufferedWriter; use std::rt::io; -use std::rt::io::file; +use std::rt::io::fs; use std::rt::io::File; use std::os; use std::str; @@ -326,7 +326,7 @@ fn mkdir(path: &Path) { fail!() }).inside { if !path.is_dir() { - file::mkdir(path, io::UserRWX); + fs::mkdir(path, io::UserRWX); } } } diff --git a/src/librustpkg/installed_packages.rs b/src/librustpkg/installed_packages.rs index 09b58e6e94cce..576d5abe8bdad 100644 --- a/src/librustpkg/installed_packages.rs +++ b/src/librustpkg/installed_packages.rs @@ -14,12 +14,12 @@ use rustc::metadata::filesearch::rust_path; use path_util::*; use std::os; use std::rt::io; -use std::rt::io::file; +use std::rt::io::fs; pub fn list_installed_packages(f: &fn(&PkgId) -> bool) -> bool { let workspaces = rust_path(); for p in workspaces.iter() { - let binfiles = do io::ignore_io_error { file::readdir(&p.join("bin")) }; + let binfiles = do io::ignore_io_error { fs::readdir(&p.join("bin")) }; for exec in binfiles.iter() { // FIXME (#9639): This needs to handle non-utf8 paths match exec.filestem_str() { @@ -31,7 +31,7 @@ pub fn list_installed_packages(f: &fn(&PkgId) -> bool) -> bool { } } } - let libfiles = do io::ignore_io_error { file::readdir(&p.join("lib")) }; + let libfiles = do io::ignore_io_error { fs::readdir(&p.join("lib")) }; for lib in libfiles.iter() { debug!("Full name: {}", lib.display()); match has_library(lib) { @@ -55,7 +55,7 @@ pub fn list_installed_packages(f: &fn(&PkgId) -> bool) -> bool { } pub fn has_library(p: &Path) -> Option<~str> { - let files = do io::ignore_io_error { file::readdir(p) }; + let files = do io::ignore_io_error { fs::readdir(p) }; for path in files.iter() { if path.extension_str() == Some(os::consts::DLL_EXTENSION) { let stuff : &str = path.filestem_str().expect("has_library: weird path"); diff --git a/src/librustpkg/lib.rs b/src/librustpkg/lib.rs index cc10f15ffb101..d69c8db52c690 100644 --- a/src/librustpkg/lib.rs +++ b/src/librustpkg/lib.rs @@ -27,8 +27,7 @@ extern mod syntax; use std::{os, result, run, str, task}; use std::hashmap::HashSet; use std::rt::io; -use std::rt::io::file; -use std::rt::io::File; +use std::rt::io::fs; pub use std::path::Path; use extra::workcache; @@ -545,7 +544,7 @@ impl CtxMethods for BuildContext { note(format!("Cleaning package {} (removing directory {})", id.to_str(), dir.display())); if dir.exists() { - file::rmdir_recursive(&dir); + fs::rmdir_recursive(&dir); note(format!("Removed directory {}", dir.display())); } @@ -661,8 +660,8 @@ impl CtxMethods for BuildContext { for exec in subex.iter() { debug!("Copying: {} -> {}", exec.display(), sub_target_ex.display()); - file::mkdir_recursive(&sub_target_ex.dir_path(), io::UserRWX); - File::copy(exec, &sub_target_ex); + fs::mkdir_recursive(&sub_target_ex.dir_path(), io::UserRWX); + fs::copy(exec, &sub_target_ex); // FIXME (#9639): This needs to handle non-utf8 paths exe_thing.discover_output("binary", sub_target_ex.as_str().unwrap(), @@ -674,8 +673,8 @@ impl CtxMethods for BuildContext { .clone().expect(format!("I built {} but apparently \ didn't install it!", lib.display())); target_lib.set_filename(lib.filename().expect("weird target lib")); - file::mkdir_recursive(&target_lib.dir_path(), io::UserRWX); - File::copy(lib, &target_lib); + fs::mkdir_recursive(&target_lib.dir_path(), io::UserRWX); + fs::copy(lib, &target_lib); debug!("3. discovering output {}", target_lib.display()); exe_thing.discover_output("binary", target_lib.as_str().unwrap(), @@ -708,10 +707,10 @@ impl CtxMethods for BuildContext { } fn init(&self) { - file::mkdir_recursive(&Path::new("src"), io::UserRWX); - file::mkdir_recursive(&Path::new("bin"), io::UserRWX); - file::mkdir_recursive(&Path::new("lib"), io::UserRWX); - file::mkdir_recursive(&Path::new("build"), io::UserRWX); + fs::mkdir_recursive(&Path::new("src"), io::UserRWX); + fs::mkdir_recursive(&Path::new("bin"), io::UserRWX); + fs::mkdir_recursive(&Path::new("lib"), io::UserRWX); + fs::mkdir_recursive(&Path::new("build"), io::UserRWX); } fn uninstall(&self, _id: &str, _vers: Option<~str>) { diff --git a/src/librustpkg/package_source.rs b/src/librustpkg/package_source.rs index 5e3a90bbf58f7..3023f3ed60c5c 100644 --- a/src/librustpkg/package_source.rs +++ b/src/librustpkg/package_source.rs @@ -13,8 +13,7 @@ extern mod extra; use target::*; use package_id::PkgId; use std::rt::io; -use std::rt::io::file; -use std::rt::io::File; +use std::rt::io::fs; use std::os; use context::*; use crate::Crate; @@ -302,7 +301,7 @@ impl PkgSrc { // Move clone_target to local. // First, create all ancestor directories. let moved = make_dir_rwx_recursive(&local.dir_path()) - && io::result(|| File::rename(&clone_target, local)).is_ok(); + && io::result(|| fs::rename(&clone_target, local)).is_ok(); if moved { Some(local.clone()) } else { None } } @@ -351,7 +350,7 @@ impl PkgSrc { let prefix = self.start_dir.component_iter().len(); debug!("Matching against {}", self.id.short_name); - for pth in file::walk_dir(&self.start_dir) { + for pth in fs::walk_dir(&self.start_dir) { let maybe_known_crate_set = match pth.filename_str() { Some(filename) if filter(filename) => match filename { "lib.rs" => Some(&mut self.libs), diff --git a/src/librustpkg/path_util.rs b/src/librustpkg/path_util.rs index e8f1b2300c737..949efacaa1196 100644 --- a/src/librustpkg/path_util.rs +++ b/src/librustpkg/path_util.rs @@ -20,8 +20,7 @@ use std::libc; use std::libc::consts::os::posix88::{S_IRUSR, S_IWUSR, S_IXUSR}; use std::os; use std::rt::io; -use std::rt::io::file; -use std::rt::io::File; +use std::rt::io::fs; use messages::*; pub fn default_workspace() -> Path { @@ -31,7 +30,7 @@ pub fn default_workspace() -> Path { } let result = p[0]; if !result.is_dir() { - file::mkdir_recursive(&result, io::UserRWX); + fs::mkdir_recursive(&result, io::UserRWX); } result } @@ -46,11 +45,11 @@ pub static U_RWX: i32 = (S_IRUSR | S_IWUSR | S_IXUSR) as i32; /// and executable by the user. Returns true iff creation /// succeeded. pub fn make_dir_rwx(p: &Path) -> bool { - io::result(|| file::mkdir(p, io::UserRWX)).is_ok() + io::result(|| fs::mkdir(p, io::UserRWX)).is_ok() } pub fn make_dir_rwx_recursive(p: &Path) -> bool { - io::result(|| file::mkdir_recursive(p, io::UserRWX)).is_ok() + io::result(|| fs::mkdir_recursive(p, io::UserRWX)).is_ok() } // n.b. The next three functions ignore the package version right @@ -73,7 +72,7 @@ pub fn workspace_contains_package_id_(pkgid: &PkgId, workspace: &Path, if !src_dir.is_dir() { return None } let mut found = None; - for p in file::walk_dir(&src_dir) { + for p in fs::walk_dir(&src_dir) { if p.is_dir() { if p == src_dir.join(&pkgid.path) || { let pf = p.filename_str(); @@ -216,7 +215,7 @@ pub fn system_library(sysroot: &Path, lib_name: &str) -> Option { fn library_in(short_name: &str, version: &Version, dir_to_search: &Path) -> Option { debug!("Listing directory {}", dir_to_search.display()); - let dir_contents = do io::ignore_io_error { file::readdir(dir_to_search) }; + let dir_contents = do io::ignore_io_error { fs::readdir(dir_to_search) }; debug!("dir has {:?} entries", dir_contents.len()); let lib_prefix = format!("{}{}", os::consts::DLL_PREFIX, short_name); @@ -339,7 +338,7 @@ fn target_file_in_workspace(pkgid: &PkgId, workspace: &Path, (Install, Lib) => target_lib_dir(workspace), (Install, _) => target_bin_dir(workspace) }; - if io::result(|| file::mkdir_recursive(&result, io::UserRWX)).is_err() { + if io::result(|| fs::mkdir_recursive(&result, io::UserRWX)).is_err() { cond.raise((result.clone(), format!("target_file_in_workspace couldn't \ create the {} dir (pkgid={}, workspace={}, what={:?}, where={:?}", subdir, pkgid.to_str(), workspace.display(), what, where))); @@ -354,7 +353,7 @@ pub fn build_pkg_id_in_workspace(pkgid: &PkgId, workspace: &Path) -> Path { result.push(&pkgid.path); debug!("Creating build dir {} for package id {}", result.display(), pkgid.to_str()); - file::mkdir_recursive(&result, io::UserRWX); + fs::mkdir_recursive(&result, io::UserRWX); return result; } @@ -399,12 +398,12 @@ pub fn uninstall_package_from(workspace: &Path, pkgid: &PkgId) { let mut did_something = false; let installed_bin = target_executable_in_workspace(pkgid, workspace); if installed_bin.exists() { - File::unlink(&installed_bin); + fs::unlink(&installed_bin); did_something = true; } let installed_lib = target_library_in_workspace(pkgid, workspace); if installed_lib.exists() { - File::unlink(&installed_lib); + fs::unlink(&installed_lib); did_something = true; } if !did_something { diff --git a/src/librustpkg/source_control.rs b/src/librustpkg/source_control.rs index e5d1c9b597ffc..bcda3168bd855 100644 --- a/src/librustpkg/source_control.rs +++ b/src/librustpkg/source_control.rs @@ -12,7 +12,7 @@ use std::{run, str}; use std::run::{ProcessOutput, ProcessOptions, Process}; -use std::rt::io::file; +use std::rt::io::fs; use extra::tempfile::TempDir; use version::*; use path_util::chmod_read_only; @@ -96,7 +96,7 @@ pub enum CloneResult { pub fn make_read_only(target: &Path) { // Now, make all the files in the target dir read-only - for p in file::walk_dir(target) { + for p in fs::walk_dir(target) { if !p.is_dir() { assert!(chmod_read_only(&p)); } diff --git a/src/librustpkg/tests.rs b/src/librustpkg/tests.rs index a2ef80db6d684..fc46346a35eab 100644 --- a/src/librustpkg/tests.rs +++ b/src/librustpkg/tests.rs @@ -13,7 +13,7 @@ use context::{BuildContext, Context, RustcFlags}; use std::{os, run, str, task}; use std::rt::io; -use std::rt::io::file; +use std::rt::io::fs; use std::rt::io::File; use extra::arc::Arc; use extra::arc::RWArc; @@ -92,7 +92,7 @@ fn writeFile(file_path: &Path, contents: &str) { fn mk_emptier_workspace(tag: &str) -> TempDir { let workspace = TempDir::new(tag).expect("couldn't create temp dir"); let package_dir = workspace.path().join("src"); - file::mkdir_recursive(&package_dir, io::UserRWX); + fs::mkdir_recursive(&package_dir, io::UserRWX); workspace } @@ -107,7 +107,7 @@ fn mk_workspace(workspace: &Path, short_name: &Path, version: &Version) -> Path // FIXME (#9639): This needs to handle non-utf8 paths let package_dir = workspace.join_many([~"src", format!("{}-{}", short_name.as_str().unwrap(), version.to_str())]); - file::mkdir_recursive(&package_dir, io::UserRWX); + fs::mkdir_recursive(&package_dir, io::UserRWX); package_dir } @@ -123,7 +123,7 @@ fn mk_temp_workspace(short_name: &Path, version: &Version) -> (TempDir, Path) { package_dir.is_dir()); // Create main, lib, test, and bench files debug!("mk_workspace: creating {}", package_dir.display()); - file::mkdir_recursive(&package_dir, io::UserRWX); + fs::mkdir_recursive(&package_dir, io::UserRWX); debug!("Created {} and does it exist? {:?}", package_dir.display(), package_dir.is_dir()); // Create main, lib, test, and bench files @@ -162,7 +162,7 @@ fn init_git_repo(p: &Path) -> TempDir { let tmp = TempDir::new("git_local").expect("couldn't create temp dir"); let work_dir = tmp.path().join(p); let work_dir_for_opts = work_dir.clone(); - file::mkdir_recursive(&work_dir, io::UserRWX); + fs::mkdir_recursive(&work_dir, io::UserRWX); debug!("Running: git init in {}", work_dir.display()); run_git([~"init"], None, &work_dir_for_opts, format!("Couldn't initialize git repository in {}", work_dir.display())); @@ -311,7 +311,7 @@ fn create_local_package_in(pkgid: &PkgId, pkgdir: &Path) -> Path { let package_dir = pkgdir.join_many([~"src", pkgid.to_str()]); // Create main, lib, test, and bench files - file::mkdir_recursive(&package_dir, io::UserRWX); + fs::mkdir_recursive(&package_dir, io::UserRWX); debug!("Created {} and does it exist? {:?}", package_dir.display(), package_dir.is_dir()); // Create main, lib, test, and bench files @@ -389,7 +389,7 @@ fn test_executable_exists(repo: &Path, short_name: &str) -> bool { fn remove_executable_file(p: &PkgId, workspace: &Path) { let exec = target_executable_in_workspace(&PkgId::new(p.short_name), workspace); if exec.exists() { - File::unlink(&exec); + fs::unlink(&exec); } } @@ -410,7 +410,7 @@ fn built_executable_exists(repo: &Path, short_name: &str) -> bool { fn remove_built_executable_file(p: &PkgId, workspace: &Path) { let exec = built_executable_in_workspace(&PkgId::new(p.short_name), workspace); match exec { - Some(r) => File::unlink(&r), + Some(r) => fs::unlink(&r), None => () } } @@ -495,7 +495,7 @@ fn output_file_name(workspace: &Path, short_name: ~str) -> Path { fn touch_source_file(workspace: &Path, pkgid: &PkgId) { use conditions::bad_path::cond; let pkg_src_dir = workspace.join_many([~"src", pkgid.to_str()]); - let contents = file::readdir(&pkg_src_dir); + let contents = fs::readdir(&pkg_src_dir); for p in contents.iter() { if p.extension_str() == Some("rs") { // should be able to do this w/o a process @@ -514,7 +514,7 @@ fn touch_source_file(workspace: &Path, pkgid: &PkgId) { fn touch_source_file(workspace: &Path, pkgid: &PkgId) { use conditions::bad_path::cond; let pkg_src_dir = workspace.join_many([~"src", pkgid.to_str()]); - let contents = file::readdir(&pkg_src_dir); + let contents = fs::readdir(&pkg_src_dir); for p in contents.iter() { if p.extension_str() == Some("rs") { // should be able to do this w/o a process @@ -558,13 +558,13 @@ fn test_make_dir_rwx() { let temp = &os::tmpdir(); let dir = temp.join("quux"); if dir.exists() { - file::rmdir_recursive(&dir); + fs::rmdir_recursive(&dir); } debug!("Trying to make {}", dir.display()); assert!(make_dir_rwx(&dir)); assert!(dir.is_dir()); assert!(is_rwx(&dir)); - file::rmdir_recursive(&dir); + fs::rmdir_recursive(&dir); } // n.b. I ignored the next two tests for now because something funny happens on linux @@ -771,7 +771,7 @@ fn test_package_version() { let repo = repo.path(); let repo_subdir = repo.join_many(["mockgithub.com", "catamorphism", "test_pkg_version"]); debug!("Writing files in: {}", repo_subdir.display()); - file::mkdir_recursive(&repo_subdir, io::UserRWX); + fs::mkdir_recursive(&repo_subdir, io::UserRWX); writeFile(&repo_subdir.join("main.rs"), "fn main() { let _x = (); }"); writeFile(&repo_subdir.join("lib.rs"), @@ -893,7 +893,7 @@ fn package_script_with_default_build() { let source = Path::new(file!()).dir_path().join_many( [~"testsuite", ~"pass", ~"src", ~"fancy-lib", ~"pkg.rs"]); debug!("package_script_with_default_build: {}", source.display()); - File::copy(&source, &dir.join_many(["src", "fancy-lib-0.1", "pkg.rs"])); + fs::copy(&source, &dir.join_many(["src", "fancy-lib-0.1", "pkg.rs"])); command_line_test([~"install", ~"fancy-lib"], dir); assert_lib_exists(dir, &Path::new("fancy-lib"), NoVersion); assert!(target_build_dir(dir).join_many([~"fancy-lib", ~"generated.rs"]).exists()); @@ -907,7 +907,7 @@ fn rustpkg_build_no_arg() { let tmp = TempDir::new("rustpkg_build_no_arg").expect("rustpkg_build_no_arg failed"); let tmp = tmp.path().join(".rust"); let package_dir = tmp.join_many(["src", "foo"]); - file::mkdir_recursive(&package_dir, io::UserRWX); + fs::mkdir_recursive(&package_dir, io::UserRWX); writeFile(&package_dir.join("main.rs"), "fn main() { let _x = (); }"); @@ -921,7 +921,7 @@ fn rustpkg_install_no_arg() { let tmp = TempDir::new("rustpkg_install_no_arg").expect("rustpkg_install_no_arg failed"); let tmp = tmp.path().join(".rust"); let package_dir = tmp.join_many(["src", "foo"]); - file::mkdir_recursive(&package_dir, io::UserRWX); + fs::mkdir_recursive(&package_dir, io::UserRWX); writeFile(&package_dir.join("lib.rs"), "fn main() { let _x = (); }"); debug!("install_no_arg: dir = {}", package_dir.display()); @@ -934,7 +934,7 @@ fn rustpkg_clean_no_arg() { let tmp = TempDir::new("rustpkg_clean_no_arg").expect("rustpkg_clean_no_arg failed"); let tmp = tmp.path().join(".rust"); let package_dir = tmp.join_many(["src", "foo"]); - file::mkdir_recursive(&package_dir, io::UserRWX); + fs::mkdir_recursive(&package_dir, io::UserRWX); writeFile(&package_dir.join("main.rs"), "fn main() { let _x = (); }"); @@ -969,9 +969,9 @@ fn rust_path_test() { fn rust_path_contents() { let dir = TempDir::new("rust_path").expect("rust_path_contents failed"); let abc = &dir.path().join_many(["A", "B", "C"]); - file::mkdir_recursive(&abc.join(".rust"), io::UserRWX); - file::mkdir_recursive(&abc.with_filename(".rust"), io::UserRWX); - file::mkdir_recursive(&abc.dir_path().with_filename(".rust"), io::UserRWX); + fs::mkdir_recursive(&abc.join(".rust"), io::UserRWX); + fs::mkdir_recursive(&abc.with_filename(".rust"), io::UserRWX); + fs::mkdir_recursive(&abc.dir_path().with_filename(".rust"), io::UserRWX); assert!(os::change_dir(abc)); let p = rust_path(); @@ -1223,7 +1223,7 @@ fn test_extern_mod() { let lib_depend_dir = TempDir::new("foo").expect("test_extern_mod"); let lib_depend_dir = lib_depend_dir.path(); let aux_dir = lib_depend_dir.join_many(["src", "mockgithub.com", "catamorphism", "test_pkg"]); - file::mkdir_recursive(&aux_dir, io::UserRWX); + fs::mkdir_recursive(&aux_dir, io::UserRWX); let aux_pkg_file = aux_dir.join("lib.rs"); writeFile(&aux_pkg_file, "pub mod bar { pub fn assert_true() { assert!(true); } }\n"); @@ -1272,7 +1272,7 @@ fn test_extern_mod_simpler() { let lib_depend_dir = TempDir::new("foo").expect("test_extern_mod_simpler"); let lib_depend_dir = lib_depend_dir.path(); let aux_dir = lib_depend_dir.join_many(["src", "rust-awesomeness"]); - file::mkdir_recursive(&aux_dir, io::UserRWX); + fs::mkdir_recursive(&aux_dir, io::UserRWX); let aux_pkg_file = aux_dir.join("lib.rs"); writeFile(&aux_pkg_file, "pub mod bar { pub fn assert_true() { assert!(true); } }\n"); @@ -1422,7 +1422,7 @@ fn rust_path_hack_cwd() { // Same as rust_path_hack_test, but the CWD is the dir to build out of let cwd = TempDir::new("foo").expect("rust_path_hack_cwd"); let cwd = cwd.path().join("foo"); - file::mkdir_recursive(&cwd, io::UserRWX); + fs::mkdir_recursive(&cwd, io::UserRWX); writeFile(&cwd.join("lib.rs"), "pub fn f() { }"); let dest_workspace = mk_empty_workspace(&Path::new("bar"), &NoVersion, "dest_workspace"); @@ -1442,7 +1442,7 @@ fn rust_path_hack_multi_path() { // Same as rust_path_hack_test, but with a more complex package ID let cwd = TempDir::new("pkg_files").expect("rust_path_hack_cwd"); let subdir = cwd.path().join_many(["foo", "bar", "quux"]); - file::mkdir_recursive(&subdir, io::UserRWX); + fs::mkdir_recursive(&subdir, io::UserRWX); writeFile(&subdir.join("lib.rs"), "pub fn f() { }"); let name = ~"foo/bar/quux"; @@ -1856,7 +1856,7 @@ fn pkgid_pointing_to_subdir() { // rustpkg should recognize that and treat the part after some_repo/ as a subdir let workspace = TempDir::new("parent_repo").expect("Couldn't create temp dir"); let workspace = workspace.path(); - file::mkdir_recursive(&workspace.join_many(["src", "mockgithub.com", + fs::mkdir_recursive(&workspace.join_many(["src", "mockgithub.com", "mozilla", "some_repo"]), io::UserRWX); @@ -1864,14 +1864,14 @@ fn pkgid_pointing_to_subdir() { "extras", "foo"]); let bar_dir = workspace.join_many(["src", "mockgithub.com", "mozilla", "some_repo", "extras", "bar"]); - file::mkdir_recursive(&foo_dir, io::UserRWX); - file::mkdir_recursive(&bar_dir, io::UserRWX); + fs::mkdir_recursive(&foo_dir, io::UserRWX); + fs::mkdir_recursive(&bar_dir, io::UserRWX); writeFile(&foo_dir.join("lib.rs"), "pub fn f() {}"); writeFile(&bar_dir.join("lib.rs"), "pub fn g() {}"); debug!("Creating a file in {}", workspace.display()); let testpkg_dir = workspace.join_many(["src", "testpkg-0.1"]); - file::mkdir_recursive(&testpkg_dir, io::UserRWX); + fs::mkdir_recursive(&testpkg_dir, io::UserRWX); writeFile(&testpkg_dir.join("main.rs"), "extern mod foo = \"mockgithub.com/mozilla/some_repo/extras/foo\";\n @@ -1946,7 +1946,7 @@ fn test_target_specific_build_dir() { workspace); assert!(target_build_dir(workspace).is_dir()); assert!(built_executable_exists(workspace, "foo")); - assert!(file::readdir(&workspace.join("build")).len() == 1); + assert!(fs::readdir(&workspace.join("build")).len() == 1); } #[test] @@ -1962,7 +1962,7 @@ fn test_target_specific_install_dir() { workspace); assert!(workspace.join_many([~"lib", host_triple()]).is_dir()); assert_lib_exists(workspace, &Path::new("foo"), NoVersion); - assert!(file::readdir(&workspace.join("lib")).len() == 1); + assert!(fs::readdir(&workspace.join("lib")).len() == 1); assert!(workspace.join("bin").is_dir()); assert_executable_exists(workspace, "foo"); } @@ -1975,7 +1975,7 @@ fn test_dependencies_terminate() { let workspace = workspace.path(); let b_dir = workspace.join_many(["src", "b-0.1"]); let b_subdir = b_dir.join("test"); - file::mkdir_recursive(&b_subdir, io::UserRWX); + fs::mkdir_recursive(&b_subdir, io::UserRWX); writeFile(&b_subdir.join("test.rs"), "extern mod b; use b::f; #[test] fn g() { f() }"); command_line_test([~"install", ~"b"], workspace); @@ -2173,7 +2173,7 @@ fn test_installed_local_changes() { debug!("repo = {}", repo.display()); let repo_subdir = repo.join_many(["mockgithub.com", "catamorphism", "test-pkg"]); debug!("repo_subdir = {}", repo_subdir.display()); - file::mkdir_recursive(&repo.join_many([".rust", "src"]), io::UserRWX); + fs::mkdir_recursive(&repo.join_many([".rust", "src"]), io::UserRWX); writeFile(&repo_subdir.join("main.rs"), "fn main() { let _x = (); }"); @@ -2256,7 +2256,7 @@ fn find_sources_in_cwd() { let temp_dir = TempDir::new("sources").expect("find_sources_in_cwd failed"); let temp_dir = temp_dir.path(); let source_dir = temp_dir.join("foo"); - file::mkdir_recursive(&source_dir, io::UserRWX); + fs::mkdir_recursive(&source_dir, io::UserRWX); writeFile(&source_dir.join("main.rs"), "fn main() { let _x = (); }"); command_line_test([~"install", ~"foo"], &source_dir); @@ -2279,7 +2279,7 @@ fn test_c_dependency_ok() { debug!("dir = {}", dir.display()); let source = Path::new(file!()).dir_path().join_many( [~"testsuite", ~"pass", ~"src", ~"c-dependencies", ~"pkg.rs"]); - File::copy(&source, &dir.join_many([~"src", ~"cdep-0.1", ~"pkg.rs"])); + fs::copy(&source, &dir.join_many([~"src", ~"cdep-0.1", ~"pkg.rs"])); command_line_test([~"build", ~"cdep"], dir); assert_executable_exists(dir, "cdep"); let out_dir = target_build_dir(dir).join("cdep"); @@ -2300,7 +2300,7 @@ fn test_c_dependency_no_rebuilding() { debug!("dir = {}", dir.display()); let source = Path::new(file!()).dir_path().join_many( [~"testsuite", ~"pass", ~"src", ~"c-dependencies", ~"pkg.rs"]); - File::copy(&source, &dir.join_many([~"src", ~"cdep-0.1", ~"pkg.rs"])); + fs::copy(&source, &dir.join_many([~"src", ~"cdep-0.1", ~"pkg.rs"])); command_line_test([~"build", ~"cdep"], dir); assert_executable_exists(dir, "cdep"); let out_dir = target_build_dir(dir).join("cdep"); @@ -2333,7 +2333,7 @@ fn test_c_dependency_yes_rebuilding() { [~"testsuite", ~"pass", ~"src", ~"c-dependencies", ~"pkg.rs"]); let target = dir.join_many([~"src", ~"cdep-0.1", ~"pkg.rs"]); debug!("Copying {} -> {}", source.display(), target.display()); - File::copy(&source, &target); + fs::copy(&source, &target); command_line_test([~"build", ~"cdep"], dir); assert_executable_exists(dir, "cdep"); let out_dir = target_build_dir(dir).join("cdep"); @@ -2357,5 +2357,5 @@ fn test_c_dependency_yes_rebuilding() { /// Returns true if p exists and is executable fn is_executable(p: &Path) -> bool { - p.exists() && p.stat().perm & io::UserExec == io::UserExec + p.exists() && p.stat().perm & io::UserExecute == io::UserExecute } diff --git a/src/librustpkg/testsuite/pass/src/c-dependencies/foo.rs b/src/librustpkg/testsuite/pass/src/c-dependencies/foo.rs index 542a6af402d05..3b233c9f6a88a 100644 --- a/src/librustpkg/testsuite/pass/src/c-dependencies/foo.rs +++ b/src/librustpkg/testsuite/pass/src/c-dependencies/foo.rs @@ -9,4 +9,4 @@ // except according to those terms. pub fn do_nothing() { -} \ No newline at end of file +} diff --git a/src/librustpkg/util.rs b/src/librustpkg/util.rs index d0ba5ce368fcd..ec7771c2ab5e4 100644 --- a/src/librustpkg/util.rs +++ b/src/librustpkg/util.rs @@ -11,7 +11,7 @@ use std::libc; use std::os; use std::rt::io; -use std::rt::io::file; +use std::rt::io::fs; use extra::workcache; use rustc::driver::{driver, session}; use extra::getopts::groups::getopts; @@ -185,7 +185,7 @@ pub fn compile_input(context: &BuildContext, let mut out_dir = target_build_dir(workspace); out_dir.push(&pkg_id.path); // Make the output directory if it doesn't exist already - file::mkdir_recursive(&out_dir, io::UserRWX); + fs::mkdir_recursive(&out_dir, io::UserRWX); let binary = os::args()[0].to_managed(); @@ -261,7 +261,7 @@ pub fn compile_input(context: &BuildContext, assert!(p.is_dir()) } else { - file::mkdir_recursive(p, io::UserRWX); + fs::mkdir_recursive(p, io::UserRWX); } } diff --git a/src/librustuv/file.rs b/src/librustuv/file.rs index 99060de1d2dd2..8c9302e123815 100644 --- a/src/librustuv/file.rs +++ b/src/librustuv/file.rs @@ -257,6 +257,7 @@ impl FsRequest { uvll::uv_fs_symlink(loop_.native_handle(), self.native_handle(), src.with_ref(|p| p), dst.with_ref(|p| p), + 0, complete_cb_ptr) }, 0); } diff --git a/src/librustuv/uvio.rs b/src/librustuv/uvio.rs index 25839c429da6a..15d5fe702a536 100644 --- a/src/librustuv/uvio.rs +++ b/src/librustuv/uvio.rs @@ -464,16 +464,18 @@ fn fs_mkstat(f: &mut FsRequest) -> FileStat { created: to_msec(stat.st_birthtim), modified: to_msec(stat.st_mtim), accessed: to_msec(stat.st_atim), - 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: stat.st_flags as u64, - gen: stat.st_gen 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: stat.st_flags as u64, + gen: stat.st_gen as u64, + } } } @@ -764,7 +766,7 @@ impl IoFactory for UvIoFactory { } fn fs_readlink(&mut self, path: &CString) -> Result { fn getlink(f: &mut FsRequest) -> Path { - Path::new(unsafe { CString::new(f.get_path(), false) }) + Path::new(unsafe { CString::new(f.get_ptr() as *libc::c_char, false) }) } do uv_fs_helper(self.uv_loop(), getlink) |req, l, cb| { req.readlink(l, path, cb) diff --git a/src/librustuv/uvll.rs b/src/librustuv/uvll.rs index b8f16db1066dc..2d850383766f5 100644 --- a/src/librustuv/uvll.rs +++ b/src/librustuv/uvll.rs @@ -1207,7 +1207,7 @@ externfn!(fn uv_fs_ftruncate(handle: *uv_loop_t, req: *uv_fs_t, file: c_int, externfn!(fn uv_fs_readlink(handle: *uv_loop_t, req: *uv_fs_t, file: *c_char, cb: *u8) -> c_int) externfn!(fn uv_fs_symlink(handle: *uv_loop_t, req: *uv_fs_t, src: *c_char, - dst: *c_char, cb: *u8) -> c_int) + dst: *c_char, flags: c_int, cb: *u8) -> c_int) externfn!(fn uv_fs_link(handle: *uv_loop_t, req: *uv_fs_t, src: *c_char, dst: *c_char, cb: *u8) -> c_int) externfn!(fn uv_fs_chown(handle: *uv_loop_t, req: *uv_fs_t, src: *c_char, diff --git a/src/libstd/os.rs b/src/libstd/os.rs index f461781e13251..b066685f6ef64 100644 --- a/src/libstd/os.rs +++ b/src/libstd/os.rs @@ -42,7 +42,6 @@ use ptr; use str; use to_str; use unstable::finally::Finally; -use vec; pub use os::consts::*; @@ -382,6 +381,7 @@ pub fn self_exe_path() -> Option { unsafe { use libc::funcs::bsd44::*; use libc::consts::os::extra::*; + use vec; let mib = ~[CTL_KERN as c_int, KERN_PROC as c_int, KERN_PROC_PATHNAME as c_int, -1 as c_int]; @@ -405,23 +405,11 @@ pub fn self_exe_path() -> Option { #[cfg(target_os = "linux")] #[cfg(target_os = "android")] fn load_self() -> Option<~[u8]> { - #[fixed_stack_segment]; #[inline(never)]; - unsafe { - use libc::funcs::posix01::unistd::readlink; - - let mut path: ~[u8] = vec::with_capacity(TMPBUF_SZ); + use std::rt::io; - let len = do path.as_mut_buf |buf, _| { - do "/proc/self/exe".with_c_str |proc_self_buf| { - readlink(proc_self_buf, buf as *mut c_char, TMPBUF_SZ as size_t) as uint - } - }; - if len == -1 { - None - } else { - vec::raw::set_len(&mut path, len as uint); - Some(path) - } + match io::result(|| io::fs::readlink(&Path::new("/proc/self/exe"))) { + Ok(Some(path)) => Some(path.as_vec().to_owned()), + Ok(None) | Err(*) => None } } @@ -430,6 +418,7 @@ pub fn self_exe_path() -> Option { #[fixed_stack_segment]; #[inline(never)]; unsafe { use libc::funcs::extra::_NSGetExecutablePath; + use vec; let mut sz: u32 = 0; _NSGetExecutablePath(ptr::mut_null(), &mut sz); if sz == 0 { return None; } @@ -814,6 +803,7 @@ fn real_args() -> ~[~str] { #[cfg(windows)] fn real_args() -> ~[~str] { #[fixed_stack_segment]; #[inline(never)]; + use vec; let mut nArgs: c_int = 0; let lpArgCount: *mut c_int = &mut nArgs; @@ -1495,7 +1485,8 @@ mod tests { use result::{Ok, Err}; use os::*; use libc::*; - use rt::io::File; + use rt::io; + use rt::io::fs; #[cfg(unix)] #[fixed_stack_segment] @@ -1544,7 +1535,7 @@ mod tests { assert!(*chunk.data == 0xbe); close(fd); } - File::unlink(&path); + do io::ignore_io_error { fs::unlink(&path); } } // More recursive_mkdir tests are in extra::tempfile diff --git a/src/libstd/rt/io/file.rs b/src/libstd/rt/io/fs.rs similarity index 73% rename from src/libstd/rt/io/file.rs rename to src/libstd/rt/io/fs.rs index c3f5f38721151..22d7ea55f3b45 100644 --- a/src/libstd/rt/io/file.rs +++ b/src/libstd/rt/io/fs.rs @@ -25,6 +25,24 @@ defined in `std::path::Path`. The impl adds useful methods about inspecting the metadata of a file. This includes getting the `stat` information, reading off particular bits of it, etc. +# Example + + use std::rt::io::{File, fs}; + + let path = Path::new("foo.txt"); + + // create the file, whether it exists or not + let mut file = File::create(&path); + file.write(bytes!("foobar")); + + // open the file in read-only mode + let mut file = File::open(&path); + file.read_to_end(); + + println!("{}", path.stat().size); + fs::symlink(&path, &Path::new("bar.txt")); + fs::unlink(&path); + */ use c_str::ToCStr; @@ -42,16 +60,14 @@ use vec::OwnedVector; /// Unconstrained file access type that exposes read and write operations /// -/// Can be retreived via `File::open()` and `Path.File::open_mode()`. +/// Can be constructed via `File::open()`, `File::create()`, and +/// `File::open_mode()`. /// /// # Errors /// /// This type will raise an io_error condition if operations are attempted against /// it for which its underlying file descriptor was not configured at creation -/// time, via the `FileAccess` parameter to `file::open()`. -/// -/// For this reason, it is best to use the access-constrained wrappers that are -/// exposed via `Path.open()` and `Path.create()`. +/// time, via the `FileAccess` parameter to `File::open_mode()`. pub struct File { priv fd: ~RtioFileStream, priv path: Path, @@ -140,7 +156,7 @@ impl File { /// /// use std::rt::io::File; /// - /// let contents = File::open("foo.txt").read_to_end(); + /// let contents = File::open(&Path::new("foo.txt")).read_to_end(); pub fn open(path: &Path) -> Option { File::open_mode(path, Open, Read) } @@ -155,239 +171,12 @@ impl File { /// /// use std::rt::io::File; /// - /// File::create("foo.txt").write(bytes!("This is a sample file")); + /// let mut f = File::create(&Path::new("foo.txt")); + /// f.write(bytes!("This is a sample file")); pub fn create(path: &Path) -> Option { File::open_mode(path, Truncate, Write) } - /// Unlink a file from the underlying filesystem. - /// - /// # Example - /// - /// use std::rt::io::File; - /// - /// let p = Path::new("/some/file/path.txt"); - /// File::unlink(&p); - /// // if we made it here without failing, then the - /// // unlink operation was successful - /// - /// Note that, just because an unlink call was successful, it is not - /// guaranteed that a file is immediately deleted (e.g. depending on - /// platform, other open file descriptors may prevent immediate removal) - /// - /// # Errors - /// - /// This function will raise an `io_error` condition if the path points to a - /// directory, the user lacks permissions to remove the file, or if some - /// other filesystem-level error occurs. - pub fn unlink(path: &Path) { - do io_raise |io| { io.fs_unlink(&path.to_c_str()) }; - } - - /// Given a path, query the file system to get information about a file, - /// directory, etc. This function will traverse symlinks to query - /// information about the destination file. - /// - /// Returns a fully-filled out stat structure on succes, and on failure it - /// will return a dummy stat structure (it is expected that the condition - /// raised is handled as well). - /// - /// # Example - /// - /// use std::rt::io::{File, io_error}; - /// - /// let p = Path::new("/some/file/path.txt"); - /// - /// do io_error::cond.trap(|_| { - /// // hoo-boy... - /// }).inside { - /// let info = File::stat(p); - /// if info.is_file { - /// // just imagine the possibilities ... - /// } - /// } - /// - /// # Errors - /// - /// This call will raise an `io_error` condition if the user lacks the - /// requisite permissions to perform a `stat` call on the given path or if - /// there is no entry in the filesystem at the provided path. - pub fn stat(path: &Path) -> FileStat { - do io_raise |io| { - io.fs_stat(&path.to_c_str()) - }.unwrap_or_else(File::dummystat) - } - - fn dummystat() -> FileStat { - FileStat { - path: Path::new(""), - size: 0, - kind: io::TypeFile, - perm: 0, - created: 0, - modified: 0, - accessed: 0, - device: 0, - inode: 0, - rdev: 0, - nlink: 0, - uid: 0, - gid: 0, - blksize: 0, - blocks: 0, - flags: 0, - gen: 0, - } - } - - /// Perform the same operation as the `stat` function, except that this - /// function does not traverse through symlinks. This will return - /// information about the symlink file instead of the file that it points - /// to. - /// - /// # Errors - /// - /// See `stat` - pub fn lstat(path: &Path) -> FileStat { - do io_raise |io| { - io.fs_lstat(&path.to_c_str()) - }.unwrap_or_else(File::dummystat) - } - - /// Rename a file or directory to a new name. - /// - /// # Example - /// - /// use std::rt::io::File; - /// - /// File::rename(Path::new("foo"), Path::new("bar")); - /// // Oh boy, nothing was raised! - /// - /// # Errors - /// - /// Will raise an `io_error` condition if the provided `path` doesn't exist, - /// the process lacks permissions to view the contents, or if some other - /// intermittent I/O error occurs. - pub fn rename(from: &Path, to: &Path) { - do io_raise |io| { - io.fs_rename(&from.to_c_str(), &to.to_c_str()) - }; - } - - /// Copies the contents of one file to another. This function will also - /// copy the permission bits of the original file to the destination file. - /// - /// Note that if `from` and `to` both point to the same file, then the file - /// will likely get truncated by this operation. - /// - /// # Example - /// - /// use std::rt::io::File; - /// - /// File::copy(Path::new("foo.txt"), Path::new("bar.txt")); - /// // Oh boy, nothing was raised! - /// - /// # Errors - /// - /// Will raise an `io_error` condition is the following situtations, but is - /// not limited to just these cases: - /// - /// * The `from` path is not a file - /// * The `from` file does not exist - /// * The current process does not have the permission rights to access - /// `from` or write `to` - /// - /// Note that this copy is not atomic in that once the destination is - /// ensured to not exist, the is nothing preventing the destination from - /// being created and then destroyed by this operation. - pub fn copy(from: &Path, to: &Path) { - if !from.is_file() { - return io_error::cond.raise(IoError { - kind: io::MismatchedFileTypeForOperation, - desc: "the source path is not an existing file", - detail: None, - }); - } - - let mut reader = match File::open(from) { Some(f) => f, None => return }; - let mut writer = match File::create(to) { Some(f) => f, None => return }; - let mut buf = [0, ..io::DEFAULT_BUF_SIZE]; - - loop { - match reader.read(buf) { - Some(amt) => writer.write(buf.slice_to(amt)), - None => break - } - } - - File::chmod(to, from.stat().perm) - } - - /// Changes the permission mode bits found on a file or a directory. This - /// function takes a mask from the `io` module - /// - /// # Example - /// - /// use std::rt::io; - /// use std::rt::io::File; - /// - /// File::chmod(&Path::new("file.txt"), io::UserFile); - /// File::chmod(&Path::new("file.txt"), io::UserRead | io::UserWrite); - /// File::chmod(&Path::new("dir"), io::UserDir); - /// File::chmod(&Path::new("file.exe"), io::UserExec); - /// - /// # Errors - /// - /// If this funciton encounters an I/O error, it will raise on the `io_error` - /// condition. Some possible error situations are not having the permission to - /// change the attributes of a file or the file not existing. - pub fn chmod(path: &Path, mode: io::FilePermission) { - do io_raise |io| { - io.fs_chmod(&path.to_c_str(), mode) - }; - } - - /// Change the user and group owners of a file at the specified path. - /// - /// # Errors - /// - /// This funtion will raise on the `io_error` condition on failure. - pub fn chown(path: &Path, uid: int, gid: int) { - do io_raise |io| { io.fs_chown(&path.to_c_str(), uid, gid) }; - } - - /// Creates a new hard link on the filesystem. The `dst` path will be a - /// link pointing to the `src` path. Note that systems often require these - /// two paths to both be located on the same filesystem. - /// - /// # Errors - /// - /// This function will raise on the `io_error` condition on failure. - pub fn link(src: &Path, dst: &Path) { - do io_raise |io| { io.fs_link(&src.to_c_str(), &dst.to_c_str()) }; - } - - /// Creates a new symbolic link on the filesystem. The `dst` path will be a - /// symlink pointing to the `src` path. - /// - /// # Errors - /// - /// This function will raise on the `io_error` condition on failure. - pub fn symlink(src: &Path, dst: &Path) { - do io_raise |io| { io.fs_symlink(&src.to_c_str(), &dst.to_c_str()) }; - } - - /// Reads a symlink, returning the file that the symlink points to. - /// - /// # Errors - /// - /// This function will raise on the `io_error` condition on failure. - /// - /// XXX: does this fail if called on files. - pub fn readlink(path: &Path) -> Option { - do io_raise |io| { io.fs_readlink(&path.to_c_str()) } - } - /// Returns the original path which was used to open this file. pub fn path<'a>(&'a self) -> &'a Path { &self.path @@ -433,15 +222,241 @@ impl File { } } +/// Unlink a file from the underlying filesystem. +/// +/// # Example +/// +/// use std::rt::io::fs; +/// +/// let p = Path::new("/some/file/path.txt"); +/// fs::unlink(&p); +/// // if we made it here without failing, then the +/// // unlink operation was successful +/// +/// Note that, just because an unlink call was successful, it is not +/// guaranteed that a file is immediately deleted (e.g. depending on +/// platform, other open file descriptors may prevent immediate removal) +/// +/// # Errors +/// +/// This function will raise an `io_error` condition if the path points to a +/// directory, the user lacks permissions to remove the file, or if some +/// other filesystem-level error occurs. +pub fn unlink(path: &Path) { + do io_raise |io| { io.fs_unlink(&path.to_c_str()) }; +} + +/// Given a path, query the file system to get information about a file, +/// directory, etc. This function will traverse symlinks to query +/// information about the destination file. +/// +/// Returns a fully-filled out stat structure on succes, and on failure it +/// will return a dummy stat structure (it is expected that the condition +/// raised is handled as well). +/// +/// # Example +/// +/// use std::rt::io; +/// use std::rt::io::fs; +/// +/// let p = Path::new("/some/file/path.txt"); +/// match io::result(|| fs::stat(&p)) { +/// Ok(stat) => { /* ... */ } +/// Err(e) => { /* handle error */ } +/// } +/// +/// # Errors +/// +/// This call will raise an `io_error` condition if the user lacks the +/// requisite permissions to perform a `stat` call on the given path or if +/// there is no entry in the filesystem at the provided path. +pub fn stat(path: &Path) -> FileStat { + do io_raise |io| { + io.fs_stat(&path.to_c_str()) + }.unwrap_or_else(dummystat) +} + +fn dummystat() -> FileStat { + FileStat { + path: Path::new(""), + size: 0, + kind: io::TypeFile, + perm: 0, + created: 0, + modified: 0, + accessed: 0, + unstable: io::UnstableFileStat { + device: 0, + inode: 0, + rdev: 0, + nlink: 0, + uid: 0, + gid: 0, + blksize: 0, + blocks: 0, + flags: 0, + gen: 0, + } + } +} + +/// Perform the same operation as the `stat` function, except that this +/// function does not traverse through symlinks. This will return +/// information about the symlink file instead of the file that it points +/// to. +/// +/// # Errors +/// +/// See `stat` +pub fn lstat(path: &Path) -> FileStat { + do io_raise |io| { + io.fs_lstat(&path.to_c_str()) + }.unwrap_or_else(dummystat) +} + +/// Rename a file or directory to a new name. +/// +/// # Example +/// +/// use std::rt::io::fs; +/// +/// fs::rename(&Path::new("foo"), &Path::new("bar")); +/// // Oh boy, nothing was raised! +/// +/// # Errors +/// +/// Will raise an `io_error` condition if the provided `path` doesn't exist, +/// the process lacks permissions to view the contents, or if some other +/// intermittent I/O error occurs. +pub fn rename(from: &Path, to: &Path) { + do io_raise |io| { + io.fs_rename(&from.to_c_str(), &to.to_c_str()) + }; +} + +/// Copies the contents of one file to another. This function will also +/// copy the permission bits of the original file to the destination file. +/// +/// Note that if `from` and `to` both point to the same file, then the file +/// will likely get truncated by this operation. +/// +/// # Example +/// +/// use std::rt::io::fs; +/// +/// fs::copy(&Path::new("foo.txt"), &Path::new("bar.txt")); +/// // Oh boy, nothing was raised! +/// +/// # Errors +/// +/// Will raise an `io_error` condition is the following situtations, but is +/// not limited to just these cases: +/// +/// * The `from` path is not a file +/// * The `from` file does not exist +/// * The current process does not have the permission rights to access +/// `from` or write `to` +/// +/// Note that this copy is not atomic in that once the destination is +/// ensured to not exist, there is nothing preventing the destination from +/// being created and then destroyed by this operation. +pub fn copy(from: &Path, to: &Path) { + if !from.is_file() { + return io_error::cond.raise(IoError { + kind: io::MismatchedFileTypeForOperation, + desc: "the source path is not an existing file", + detail: None, + }); + } + + let mut reader = match File::open(from) { Some(f) => f, None => return }; + let mut writer = match File::create(to) { Some(f) => f, None => return }; + let mut buf = [0, ..io::DEFAULT_BUF_SIZE]; + + loop { + match reader.read(buf) { + Some(amt) => writer.write(buf.slice_to(amt)), + None => break + } + } + + chmod(to, from.stat().perm) +} + +/// Changes the permission mode bits found on a file or a directory. This +/// function takes a mask from the `io` module +/// +/// # Example +/// +/// use std::rt::io; +/// use std::rt::io::fs; +/// +/// fs::chmod(&Path::new("file.txt"), io::UserFile); +/// fs::chmod(&Path::new("file.txt"), io::UserRead | io::UserWrite); +/// fs::chmod(&Path::new("dir"), io::UserDir); +/// fs::chmod(&Path::new("file.exe"), io::UserExec); +/// +/// # Errors +/// +/// If this funciton encounters an I/O error, it will raise on the `io_error` +/// condition. Some possible error situations are not having the permission to +/// change the attributes of a file or the file not existing. +pub fn chmod(path: &Path, mode: io::FilePermission) { + do io_raise |io| { + io.fs_chmod(&path.to_c_str(), mode) + }; +} + +/// Change the user and group owners of a file at the specified path. +/// +/// # Errors +/// +/// This funtion will raise on the `io_error` condition on failure. +pub fn chown(path: &Path, uid: int, gid: int) { + do io_raise |io| { io.fs_chown(&path.to_c_str(), uid, gid) }; +} + +/// Creates a new hard link on the filesystem. The `dst` path will be a +/// link pointing to the `src` path. Note that systems often require these +/// two paths to both be located on the same filesystem. +/// +/// # Errors +/// +/// This function will raise on the `io_error` condition on failure. +pub fn link(src: &Path, dst: &Path) { + do io_raise |io| { io.fs_link(&src.to_c_str(), &dst.to_c_str()) }; +} + +/// Creates a new symbolic link on the filesystem. The `dst` path will be a +/// symlink pointing to the `src` path. +/// +/// # Errors +/// +/// This function will raise on the `io_error` condition on failure. +pub fn symlink(src: &Path, dst: &Path) { + do io_raise |io| { io.fs_symlink(&src.to_c_str(), &dst.to_c_str()) }; +} + +/// Reads a symlink, returning the file that the symlink points to. +/// +/// # Errors +/// +/// This function will raise on the `io_error` condition on failure. Failure +/// conditions include reading a file that does not exist or reading a file +/// which is not a symlink. +pub fn readlink(path: &Path) -> Option { + do io_raise |io| { io.fs_readlink(&path.to_c_str()) } +} + /// Create a new, empty directory at the provided path /// /// # Example /// /// use std::libc::S_IRWXU; -/// use std::rt::io::file; +/// use std::rt::io::fs; /// /// let p = Path::new("/some/dir"); -/// file::mkdir(&p, S_IRWXU as int); +/// fs::mkdir(&p, S_IRWXU as int); /// // If we got here, our directory exists! Horray! /// /// # Errors @@ -459,10 +474,10 @@ pub fn mkdir(path: &Path, mode: FilePermission) { /// /// # Example /// -/// use std::rt::io::file; +/// use std::rt::io::fs; /// /// let p = Path::new("/some/dir"); -/// file::rmdir(&p); +/// fs::rmdir(&p); /// // good riddance, you mean ol' directory /// /// # Errors @@ -480,11 +495,12 @@ pub fn rmdir(path: &Path) { /// /// # Example /// -/// use std::rt::io::file; +/// use std::rt::io::fs; /// +/// // one possible implementation of fs::walk_dir only visiting files /// fn visit_dirs(dir: &Path, cb: &fn(&Path)) { /// if dir.is_dir() { -/// let contents = file::readdir(dir).unwrap(); +/// let contents = fs::readdir(dir).unwrap(); /// for entry in contents.iter() { /// if entry.is_dir() { visit_dirs(entry, cb); } /// else { cb(entry); } @@ -536,7 +552,7 @@ impl Iterator for WalkIterator { /// # Errors /// /// This function will raise on the `io_error` condition if an error -/// happens, see `file::mkdir` for more information about error conditions +/// happens, see `fs::mkdir` for more information about error conditions /// and performance. pub fn mkdir_recursive(path: &Path, mode: FilePermission) { // tjc: if directory exists but with different permissions, @@ -556,7 +572,7 @@ pub fn mkdir_recursive(path: &Path, mode: FilePermission) { /// # Errors /// /// This function will raise on the `io_error` condition if an error -/// happens. See `file::unlink` and `file::readdir` for possible error +/// happens. See `file::unlink` and `fs::readdir` for possible error /// conditions. pub fn rmdir_recursive(path: &Path) { let children = readdir(path); @@ -564,7 +580,7 @@ pub fn rmdir_recursive(path: &Path) { if child.is_dir() { rmdir_recursive(child); } else { - File::unlink(child); + unlink(child); } } // Directory should now be empty @@ -637,7 +653,7 @@ impl path::Path { /// Consult the `file::stat` documentation for more info. /// /// This call preserves identical runtime/error semantics with `file::stat`. - pub fn stat(&self) -> FileStat { File::stat(self) } + pub fn stat(&self) -> FileStat { stat(self) } /// Boolean value indicator whether the underlying file exists on the local /// filesystem. This will return true if the path points to either a @@ -687,7 +703,9 @@ mod test { use rt::io::{SeekSet, SeekCur, SeekEnd, io_error, Read, Open, ReadWrite}; use rt::io; use str; - use super::{File, rmdir, mkdir, readdir, rmdir_recursive, mkdir_recursive}; + use super::{File, rmdir, mkdir, readdir, rmdir_recursive, mkdir_recursive, + copy, unlink, stat, symlink, link, readlink, chmod, chown, + lstat}; fn tmpdir() -> Path { use os; @@ -697,6 +715,8 @@ mod test { ret } + fn free(_: T) {} + #[test] fn file_test_io_smoke_test() { let message = "it's alright. have a good time"; @@ -714,7 +734,7 @@ mod test { }; assert!(read_str == message.to_owned()); } - File::unlink(filename); + unlink(filename); } #[test] @@ -737,7 +757,7 @@ mod test { do io_error::cond.trap(|_| { called = true; }).inside { - File::unlink(filename); + unlink(filename); } assert!(called); } @@ -762,7 +782,7 @@ mod test { read_stream.read(read_buf); } } - File::unlink(filename); + unlink(filename); let read_str = str::from_utf8(read_mem); assert!(read_str == message.to_owned()); } @@ -786,7 +806,7 @@ mod test { read_stream.read(read_mem); tell_pos_post_read = read_stream.tell(); } - File::unlink(filename); + unlink(filename); let read_str = str::from_utf8(read_mem); assert!(read_str == message.slice(4, 8).to_owned()); assert!(tell_pos_pre_read == set_cursor); @@ -811,7 +831,7 @@ mod test { let mut read_stream = File::open_mode(filename, Open, Read); read_stream.read(read_mem); } - File::unlink(filename); + unlink(filename); let read_str = str::from_utf8(read_mem); assert!(read_str == final_msg.to_owned()); } @@ -847,7 +867,7 @@ mod test { let read_str = str::from_utf8(read_mem); assert!(read_str == chunk_one.to_owned()); } - File::unlink(filename); + unlink(filename); } #[test] @@ -858,9 +878,9 @@ mod test { let msg = "hw"; fs.write(msg.as_bytes()); } - let stat_res = File::stat(filename); + let stat_res = stat(filename); assert_eq!(stat_res.kind, io::TypeFile); - File::unlink(filename); + unlink(filename); } #[test] @@ -885,7 +905,7 @@ mod test { let file = &Path::new("./tmp/fileinfo_check_exists_b_and_a.txt"); File::create(file).write(bytes!("foo")); assert!(file.exists()); - File::unlink(file); + unlink(file); assert!(!file.exists()); } @@ -926,7 +946,7 @@ mod test { }; assert!(expected == read_str); } - File::unlink(f); + unlink(f); } rmdir(dir); } @@ -975,7 +995,7 @@ mod 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(|| File::copy(&from, &to)) { + match io::result(|| copy(&from, &to)) { Ok(*) => fail!(), Err(*) => { assert!(!from.exists()); @@ -991,7 +1011,7 @@ mod test { let out = tmpdir.join("out.txt"); File::create(&input).write(bytes!("hello")); - File::copy(&input, &out); + copy(&input, &out); let contents = File::open(&out).read_to_end(); assert_eq!(contents.as_slice(), bytes!("hello")); @@ -1005,7 +1025,7 @@ mod test { let out = tmpdir.join("out"); File::create(&out); - match io::result(|| File::copy(&out, &tmpdir)) { + match io::result(|| copy(&out, &tmpdir)) { Ok(*) => fail!(), Err(*) => {} } rmdir_recursive(&tmpdir); @@ -1019,7 +1039,7 @@ mod test { File::create(&input).write("foo".as_bytes()); File::create(&output).write("bar".as_bytes()); - File::copy(&input, &output); + copy(&input, &output); assert_eq!(File::open(&output).read_to_end(), (bytes!("foo")).to_owned()); @@ -1032,7 +1052,7 @@ mod test { let tmpdir = tmpdir(); let out = tmpdir.join("out"); - match io::result(|| File::copy(&tmpdir, &out)) { + match io::result(|| copy(&tmpdir, &out)) { Ok(*) => fail!(), Err(*) => {} } assert!(!out.exists()); @@ -1046,40 +1066,48 @@ mod test { let out = tmpdir.join("out.txt"); File::create(&input); - File::chmod(&input, io::UserExec); - File::copy(&input, &out); - assert_eq!(out.stat().perm, io::UserExec); + chmod(&input, io::UserRead); + copy(&input, &out); + assert!(out.stat().perm & io::UserWrite == 0); + chmod(&input, io::UserFile); + chmod(&out, io::UserFile); rmdir_recursive(&tmpdir); } #[test] + #[ignore(cfg(windows))] // FIXME(#10264) operation not permitted? fn symlinks_work() { let tmpdir = tmpdir(); let input = tmpdir.join("in.txt"); let out = tmpdir.join("out.txt"); File::create(&input).write("foobar".as_bytes()); - File::symlink(&input, &out); - assert_eq!(File::lstat(&out).kind, io::TypeSymlink); - assert_eq!(File::stat(&out).size, File::stat(&input).size); + symlink(&input, &out); + assert_eq!(lstat(&out).kind, io::TypeSymlink); + assert_eq!(stat(&out).size, stat(&input).size); assert_eq!(File::open(&out).read_to_end(), (bytes!("foobar")).to_owned()); - // can't link to yourself - match io::result(|| File::symlink(&input, &input)) { - Ok(*) => fail!("wanted a failure"), - Err(*) => {} - } - // symlinks can point to things that don't exist - File::symlink(&tmpdir.join("foo"), &tmpdir.join("bar")); + rmdir_recursive(&tmpdir); + } - assert!(File::readlink(&tmpdir.join("bar")).unwrap() == tmpdir.join("bar")); + #[test] + #[ignore(cfg(windows))] // apparently windows doesn't like symlinks + fn symlink_noexist() { + let tmpdir = tmpdir(); + // symlinks can point to things that don't exist + symlink(&tmpdir.join("foo"), &tmpdir.join("bar")); + assert!(readlink(&tmpdir.join("bar")).unwrap() == tmpdir.join("foo")); + rmdir_recursive(&tmpdir); + } - match io::result(|| File::readlink(&tmpdir)) { + #[test] + fn readlink_not_symlink() { + let tmpdir = tmpdir(); + match io::result(|| readlink(&tmpdir)) { Ok(*) => fail!("wanted a failure"), Err(*) => {} } - rmdir_recursive(&tmpdir); } @@ -1090,19 +1118,19 @@ mod test { let out = tmpdir.join("out.txt"); File::create(&input).write("foobar".as_bytes()); - File::link(&input, &out); - assert_eq!(File::lstat(&out).kind, io::TypeFile); - assert_eq!(File::stat(&out).size, File::stat(&input).size); - assert_eq!(File::stat(&out).nlink, 2); + link(&input, &out); + assert_eq!(lstat(&out).kind, io::TypeFile); + assert_eq!(stat(&out).size, stat(&input).size); + assert_eq!(stat(&out).unstable.nlink, 2); assert_eq!(File::open(&out).read_to_end(), (bytes!("foobar")).to_owned()); // can't link to yourself - match io::result(|| File::link(&input, &input)) { + match io::result(|| link(&input, &input)) { Ok(*) => fail!("wanted a failure"), Err(*) => {} } // can't link to something that doesn't exist - match io::result(|| File::link(&tmpdir.join("foo"), &tmpdir.join("bar"))) { + match io::result(|| link(&tmpdir.join("foo"), &tmpdir.join("bar"))) { Ok(*) => fail!("wanted a failure"), Err(*) => {} } @@ -1116,14 +1144,16 @@ mod test { let file = tmpdir.join("in.txt"); File::create(&file); - File::chmod(&file, io::UserRWX); - assert_eq!(File::stat(&file).perm, io::UserRWX); + assert!(stat(&file).perm & io::UserWrite == io::UserWrite); + chmod(&file, io::UserRead); + assert!(stat(&file).perm & io::UserWrite == 0); - match io::result(|| File::chmod(&tmpdir.join("foo"), io::UserRWX)) { + match io::result(|| chmod(&tmpdir.join("foo"), io::UserRWX)) { Ok(*) => fail!("wanted a failure"), Err(*) => {} } + chmod(&file, io::UserFile); rmdir_recursive(&tmpdir); } @@ -1138,6 +1168,7 @@ mod test { file.write(bytes!("foo")); file.fsync(); file.datasync(); + free(file); rmdir_recursive(&tmpdir); } @@ -1151,11 +1182,11 @@ mod test { file.write(bytes!("foo")); // Do some simple things with truncation - assert_eq!(File::stat(&path).size, 3); + assert_eq!(stat(&path).size, 3); file.truncate(10); - assert_eq!(File::stat(&path).size, 10); + assert_eq!(stat(&path).size, 10); file.write(bytes!("bar")); - assert_eq!(File::stat(&path).size, 10); + assert_eq!(stat(&path).size, 10); assert_eq!(File::open(&path).read_to_end(), (bytes!("foobar", 0, 0, 0, 0)).to_owned()); @@ -1163,11 +1194,12 @@ mod test { // Ensure that the intermediate zeroes are all filled in (we're seeked // past the end of the file). file.truncate(2); - assert_eq!(File::stat(&path).size, 2); + assert_eq!(stat(&path).size, 2); file.write(bytes!("wut")); - assert_eq!(File::stat(&path).size, 9); + 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); } @@ -1196,19 +1228,19 @@ mod test { Ok(*) => fail!(), Err(*) => {} } } - assert_eq!(File::stat(&tmpdir.join("h")).size, 3); + assert_eq!(stat(&tmpdir.join("h")).size, 3); { let mut f = File::open_mode(&tmpdir.join("h"), io::Append, io::Write).unwrap(); f.write("bar".as_bytes()); } - assert_eq!(File::stat(&tmpdir.join("h")).size, 6); + assert_eq!(stat(&tmpdir.join("h")).size, 6); { let mut f = File::open_mode(&tmpdir.join("h"), io::Truncate, io::Write).unwrap(); f.write("bar".as_bytes()); } - assert_eq!(File::stat(&tmpdir.join("h")).size, 3); + assert_eq!(stat(&tmpdir.join("h")).size, 3); rmdir_recursive(&tmpdir); } diff --git a/src/libstd/rt/io/mod.rs b/src/libstd/rt/io/mod.rs index 510c3470d06ae..f01ce5012eb25 100644 --- a/src/libstd/rt/io/mod.rs +++ b/src/libstd/rt/io/mod.rs @@ -259,7 +259,7 @@ pub use self::stdio::stderr; pub use self::stdio::print; pub use self::stdio::println; -pub use self::file::File; +pub use self::fs::File; pub use self::timer::Timer; pub use self::net::ip::IpAddr; pub use self::net::tcp::TcpListener; @@ -268,8 +268,8 @@ pub use self::net::udp::UdpStream; pub use self::pipe::PipeStream; pub use self::process::Process; -/// Synchronous, non-blocking file I/O. -pub mod file; +/// Synchronous, non-blocking filesystem operations. +pub mod fs; /// Synchronous, in-memory I/O. pub mod pipe; @@ -1155,7 +1155,23 @@ pub struct FileStat { /// milliseconds accessed: u64, - // Various filesytem info + /// Information returned by stat() which is not guaranteed to be + /// platform-independent. This information may be useful on some platforms, + /// but it may have different meanings or no meaning at all on other + /// platforms. + /// + /// Usage of this field is discouraged, but if access is desired then the + /// fields are located here. + #[unstable] + unstable: UnstableFileStat, +} + +/// This structure represents all of the possible information which can be +/// returned from a `stat` syscall which is not contained in the `FileStat` +/// structure. This information is not necessarily platform independent, and may +/// have different meanings or no meaning at all on some platforms. +#[unstable] +pub struct UnstableFileStat { device: u64, inode: u64, rdev: u64, diff --git a/src/libstd/rt/io/native/file.rs b/src/libstd/rt/io/native/file.rs index 4eb473a73a6a3..35057f475cf5a 100644 --- a/src/libstd/rt/io/native/file.rs +++ b/src/libstd/rt/io/native/file.rs @@ -737,7 +737,7 @@ mod old_os { #[test] fn test_path_is_dir() { - use rt::io::file::{mkdir_recursive}; + use rt::io::fs::{mkdir_recursive}; use rt::io::{File, UserRWX}; assert!((path_is_dir(&Path::new(".")))); @@ -765,7 +765,7 @@ mod old_os { #[test] fn test_path_exists() { - use rt::io::file::mkdir_recursive; + use rt::io::fs::mkdir_recursive; use rt::io::UserRWX; assert!((path_exists(&Path::new(".")))); diff --git a/src/libstd/rt/io/signal.rs b/src/libstd/rt/io/signal.rs index 1b856ab07550c..0f48f83a57e0e 100644 --- a/src/libstd/rt/io/signal.rs +++ b/src/libstd/rt/io/signal.rs @@ -208,6 +208,7 @@ mod test { #[cfg(windows)] #[test] fn test_io_signal_invalid_signum() { + use rt::io; use super::User1; let mut s = Listener::new(); let mut called = false; diff --git a/src/libstd/rt/sched.rs b/src/libstd/rt/sched.rs index fd4dab60ff36f..e71cd92589c33 100644 --- a/src/libstd/rt/sched.rs +++ b/src/libstd/rt/sched.rs @@ -836,7 +836,7 @@ impl ClosureConverter for UnsafeTaskReceiver { } // On unix, we read randomness straight from /dev/urandom, but the -// default constructor of an XorShiftRng does this via io::file, which +// default constructor of an XorShiftRng does this via io::fs, which // relies on the scheduler existing, so we have to manually load // randomness. Windows has its own C API for this, so we don't need to // worry there. diff --git a/src/libstd/run.rs b/src/libstd/run.rs index 89784acec8ebb..74f4ed3d55e4b 100644 --- a/src/libstd/run.rs +++ b/src/libstd/run.rs @@ -607,8 +607,8 @@ mod tests { let parent_stat = parent_dir.stat(); let child_stat = child_dir.stat(); - assert_eq!(parent_stat.device, child_stat.device); - assert_eq!(parent_stat.inode, child_stat.inode); + assert_eq!(parent_stat.unstable.device, child_stat.unstable.device); + assert_eq!(parent_stat.unstable.inode, child_stat.unstable.inode); } #[test] @@ -624,8 +624,8 @@ mod tests { let parent_stat = parent_dir.stat(); let child_stat = child_dir.stat(); - assert_eq!(parent_stat.device, child_stat.device); - assert_eq!(parent_stat.inode, child_stat.inode); + assert_eq!(parent_stat.unstable.device, child_stat.unstable.device); + assert_eq!(parent_stat.unstable.inode, child_stat.unstable.inode); } #[cfg(unix,not(target_os="android"))] diff --git a/src/test/run-pass/glob-std.rs b/src/test/run-pass/glob-std.rs index 7f684e41c75a9..897ee9cb88b06 100644 --- a/src/test/run-pass/glob-std.rs +++ b/src/test/run-pass/glob-std.rs @@ -21,7 +21,7 @@ use std::rt::io; pub fn main() { fn mk_file(path: &str, directory: bool) { if directory { - io::file::mkdir(&Path::new(path), io::UserRWX); + io::fs::mkdir(&Path::new(path), io::UserRWX); } else { io::File::create(&Path::new(path)); } diff --git a/src/test/run-pass/rename-directory.rs b/src/test/run-pass/rename-directory.rs index 0aa4ae40f9e5d..fcb57152daa5f 100644 --- a/src/test/run-pass/rename-directory.rs +++ b/src/test/run-pass/rename-directory.rs @@ -18,8 +18,7 @@ use extra::tempfile::TempDir; use std::os; use std::libc; use std::rt::io; -use std::rt::io::file; -use std::rt::io::File; +use std::rt::io::fs; fn rename_directory() { #[fixed_stack_segment]; @@ -29,7 +28,7 @@ fn rename_directory() { let tmpdir = TempDir::new("rename_directory").expect("rename_directory failed"); let tmpdir = tmpdir.path(); let old_path = tmpdir.join_many(["foo", "bar", "baz"]); - file::mkdir_recursive(&old_path, io::UserRWX); + fs::mkdir_recursive(&old_path, io::UserRWX); let test_file = &old_path.join("temp.txt"); /* Write the temp input file */ @@ -50,8 +49,8 @@ fn rename_directory() { assert_eq!(libc::fclose(ostream), (0u as libc::c_int)); let new_path = tmpdir.join_many(["quux", "blat"]); - file::mkdir_recursive(&new_path, io::UserRWX); - File::rename(&old_path, &new_path.join("newdir")); + fs::mkdir_recursive(&new_path, io::UserRWX); + fs::rename(&old_path, &new_path.join("newdir")); assert!(new_path.join("newdir").is_dir()); assert!(new_path.join_many(["newdir", "temp.txt"]).exists()); } diff --git a/src/test/run-pass/tempfile.rs b/src/test/run-pass/tempfile.rs index 9ac144f5fb5e5..3a115ab29cf54 100644 --- a/src/test/run-pass/tempfile.rs +++ b/src/test/run-pass/tempfile.rs @@ -25,7 +25,7 @@ use std::os; use std::task; use std::cell::Cell; use std::rt::io; -use std::rt::io::file; +use std::rt::io::fs; fn test_tempdir() { let path = { @@ -75,7 +75,7 @@ fn test_rm_tempdir() { path = tmp.unwrap(); } assert!(path.exists()); - file::rmdir_recursive(&path); + fs::rmdir_recursive(&path); assert!(!path.exists()); } @@ -86,17 +86,17 @@ fn recursive_mkdir_rel() { let cwd = os::getcwd(); debug!("recursive_mkdir_rel: Making: {} in cwd {} [{:?}]", path.display(), cwd.display(), path.exists()); - file::mkdir_recursive(&path, io::UserRWX); + fs::mkdir_recursive(&path, io::UserRWX); assert!(path.is_dir()); - file::mkdir_recursive(&path, io::UserRWX); + fs::mkdir_recursive(&path, io::UserRWX); assert!(path.is_dir()); } fn recursive_mkdir_dot() { let dot = Path::new("."); - file::mkdir_recursive(&dot, io::UserRWX); + fs::mkdir_recursive(&dot, io::UserRWX); let dotdot = Path::new(".."); - file::mkdir_recursive(&dotdot, io::UserRWX); + fs::mkdir_recursive(&dotdot, io::UserRWX); } fn recursive_mkdir_rel_2() { @@ -104,13 +104,13 @@ fn recursive_mkdir_rel_2() { let cwd = os::getcwd(); debug!("recursive_mkdir_rel_2: Making: {} in cwd {} [{:?}]", path.display(), cwd.display(), path.exists()); - file::mkdir_recursive(&path, io::UserRWX); + fs::mkdir_recursive(&path, io::UserRWX); assert!(path.is_dir()); assert!(path.dir_path().is_dir()); let path2 = Path::new("quux/blat"); debug!("recursive_mkdir_rel_2: Making: {} in cwd {}", path2.display(), cwd.display()); - file::mkdir_recursive(&path2, io::UserRWX); + fs::mkdir_recursive(&path2, io::UserRWX); assert!(path2.is_dir()); assert!(path2.dir_path().is_dir()); } @@ -125,11 +125,11 @@ pub fn test_rmdir_recursive_ok() { let root = tmpdir.join("foo"); debug!("making {}", root.display()); - file::mkdir(&root, rwx); - file::mkdir(&root.join("foo"), rwx); - file::mkdir(&root.join("foo").join("bar"), rwx); - file::mkdir(&root.join("foo").join("bar").join("blat"), rwx); - file::rmdir_recursive(&root); + fs::mkdir(&root, rwx); + fs::mkdir(&root.join("foo"), rwx); + fs::mkdir(&root.join("foo").join("bar"), rwx); + fs::mkdir(&root.join("foo").join("bar").join("blat"), rwx); + fs::rmdir_recursive(&root); assert!(!root.exists()); assert!(!root.join("bar").exists()); assert!(!root.join("bar").join("blat").exists());