From 9c1851019f1ef9511fa8731b8f1acb0796d1e97f Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 25 Oct 2013 17:04:37 -0700 Subject: 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 --- 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 +- src/librustpkg/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 +- 15 files changed, 204 insertions(+), 229 deletions(-) (limited to 'src/librustpkg') diff --git a/src/librustpkg/api.rs b/src/librustpkg/api.rs index c67b6f52c7e..c0ffd66d22e 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 77fe2ae8f70..0ae08731546 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 767a31ed785..09b58e6e94c 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 517d43432ec..bb6088adee1 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 0fc614d7f3c..0da343a27bf 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 797ea3372cc..a52aa68e1e4 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 a48ef23115c..75f03533d58 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 c3e4205dfc9..a0e50ff0f9e 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 8f1b269f1ca..60e99f242ef 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 016635339a9..f5d6317e7a6 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 f82c585b1d1..e5fb6889ae0 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 9d835dcc20b..d0ba5ce368f 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 6ca19562724..eff16cb9996 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 2e4894b854d..c16224afbf4 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 a3550037246..e65f3ce5bb6 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. -- cgit 1.4.1-3-g733a5 From f19d0833625c382c5d0a8868924cd4620335e659 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 29 Oct 2013 23:31:07 -0700 Subject: 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 +- src/librustpkg/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(-) (limited to 'src/librustpkg') diff --git a/src/compiletest/errors.rs b/src/compiletest/errors.rs index dfadea37cd0..8bfef9da805 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 68e8fd76735..5571e159ee3 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 7fc13467217..d55bdc23703 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 e341f495eeb..d86ed510361 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 c5509f8aec7..09ceae66bb1 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 497d4206fe3..4cdb3841acf 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 b2be4cf811b..09d9dd828d4 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 7d044ba998f..81a20522807 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 1526b5ad9c6..01035385f97 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 fd7ba7c0452..d0e01d1f423 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 7a64ca6d6fc..c69fd9879ce 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 bb6088adee1..cc10f15ffb1 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 a52aa68e1e4..5e3a90bbf58 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 75f03533d58..e8f1b2300c7 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 a0e50ff0f9e..e5d1c9b597f 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 60e99f242ef..a2ef80db6d6 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 e5fb6889ae0..1c3bf897bec 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 c16224afbf4..d8b35f2c033 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 15df189edcd..99060de1d2d 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 ae8546af4b4..25839c429da 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 a2047ef98fa..b8f16db1066 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 d4df0e826f6..f992b327495 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 12281f06005..f461781e132 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 dfd654ac13c..8483b504c01 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 c9499bb4aa8..a6d05ea307c 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 b6c0b58434f..c3f5f387211 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 51204ca73b9..510c3470d06 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 e26cc166c8d..4eb473a73a6 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 234b46458b4..5938252571f 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 a0db1f1df00..d24de7cbfee 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 876adf40186..75b5ab81f9b 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 cd1be9a3c16..fbe711b5efe 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 2b63325f931..a4361f14f69 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 531f01c1995..2c86fdfe6ad 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 7d3fa6104e5..d7d7e9a58f3 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 56bcd24f1cb..7f684e41c75 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 2f6de7e4472..0aa4ae40f9e 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 d46c8a64f5a..9ce3d318064 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; -- cgit 1.4.1-3-g733a5 From 3c3ed1499a9b9e23d4a2d2243a7b0b1c9015f34b Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 31 Oct 2013 15:15:30 -0700 Subject: 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 | 1215 ------------------- src/libstd/rt/io/fs.rs | 1247 ++++++++++++++++++++ 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 +- 32 files changed, 1412 insertions(+), 1398 deletions(-) delete mode 100644 src/libstd/rt/io/file.rs create mode 100644 src/libstd/rt/io/fs.rs (limited to 'src/librustpkg') diff --git a/src/compiletest/compiletest.rs b/src/compiletest/compiletest.rs index a354bc84e52..f4bd668690e 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 d55bdc23703..1b3e34ad819 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 a7742f771da..1edef5ddbe1 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 4affe7c1cde..fbd65cab98c 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 b530c1b6334..04b30e5ef74 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 09d9dd828d4..eed37a426be 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 81a20522807..5b0f424360b 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 01035385f97..744e192095b 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 44e43bd4ef3..c9bd5eff4a7 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 d0e01d1f423..0efc52bbe4a 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 09b58e6e94c..576d5abe8bd 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 cc10f15ffb1..d69c8db52c6 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 5e3a90bbf58..3023f3ed60c 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 e8f1b2300c7..949efacaa11 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 e5d1c9b597f..bcda3168bd8 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 a2ef80db6d6..fc46346a35e 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 542a6af402d..3b233c9f6a8 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 d0ba5ce368f..ec7771c2ab5 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 99060de1d2d..8c9302e1238 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 25839c429da..15d5fe702a5 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 b8f16db1066..2d850383766 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 f461781e132..b066685f6ef 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/file.rs deleted file mode 100644 index c3f5f387211..00000000000 --- a/src/libstd/rt/io/file.rs +++ /dev/null @@ -1,1215 +0,0 @@ -// Copyright 2013 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -/*! Synchronous File I/O - -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 `Path` object. - -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. - -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 c_str::ToCStr; -use iter::Iterator; -use super::{Reader, Writer, Seek}; -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, Result}; -use path; -use path::{Path, GenericPath}; -use vec::OwnedVector; - -/// Unconstrained file access type that exposes read and write operations -/// -/// Can be retreived via `File::open()` and `Path.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()`. -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 f(io) { - Ok(t) => Some(t), - Err(ioerr) => { - io_error::cond.raise(ioerr); - None - } - } - } -} - -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 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) - } - - /// 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 -/// -/// # Example -/// -/// use std::libc::S_IRWXU; -/// use std::rt::io::file; -/// -/// 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: &Path, mode: FilePermission) { - do io_raise |io| { - io.fs_mkdir(&path.to_c_str(), mode) - }; -} - -/// Remove an existing, empty directory -/// -/// # Example -/// -/// use std::rt::io::file; -/// -/// 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: &Path) { - do io_raise |io| { - io.fs_rmdir(&path.to_c_str()) - }; -} - -/// Retrieve a vector containing all entries within a provided directory -/// -/// # Example -/// -/// use std::rt::io::file; -/// -/// fn visit_dirs(dir: &Path, cb: &fn(&Path)) { -/// if dir.is_dir() { -/// let contents = file::readdir(dir).unwrap(); -/// for entry in contents.iter() { -/// if entry.is_dir() { visit_dirs(entry, cb); } -/// else { cb(entry); } -/// } -/// } -/// else { fail!("nope"); } -/// } -/// -/// # Errors -/// -/// 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: &Path) -> ~[Path] { - do io_raise |io| { - io.fs_readdir(&path.to_c_str(), 0) - }.unwrap_or_else(|| ~[]) -} - -/// 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) } -} - -/// An iterator which walks over a directory -pub struct WalkIterator { - priv stack: ~[Path], -} - -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 create a directory and all of its parent components if they -/// are missing. -/// -/// # Errors -/// -/// 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) -} - -/// Removes a directory at this path, after removing all its contents. Use -/// carefully! -/// -/// # 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) { - let children = readdir(path); - for child in children.iter() { - if child.is_dir() { - rmdir_recursive(child); - } else { - File::unlink(child); - } - } - // Directory should now be empty - rmdir(path); -} - -impl Reader for File { - fn read(&mut self, buf: &mut [u8]) -> Option { - match self.fd.read(buf) { - Ok(read) => { - self.last_nread = read; - match read { - 0 => None, - _ => Some(read as uint) - } - }, - Err(ioerr) => { - // EOF is indicated by returning None - if ioerr.kind != io::EndOfFile { - io_error::cond.raise(ioerr); - } - return None; - } - } - } - - fn eof(&mut self) -> bool { self.last_nread == 0 } -} - -impl Writer for File { - fn write(&mut self, buf: &[u8]) { - match self.fd.write(buf) { - Ok(()) => (), - Err(ioerr) => { - io_error::cond.raise(ioerr); - } - } - } -} - -impl Seek for File { - fn tell(&self) -> u64 { - let res = self.fd.tell(); - match res { - Ok(cursor) => cursor, - Err(ioerr) => { - io_error::cond.raise(ioerr); - return -1; - } - } - } - - fn seek(&mut self, pos: i64, style: SeekStyle) { - match self.fd.seek(pos, style) { - Ok(_) => { - // successful seek resets EOF indicator - self.last_nread = -1; - () - }, - Err(ioerr) => { - io_error::cond.raise(ioerr); - } - } - } -} - -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`. - 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 - /// directory or a file. - /// - /// # Errors - /// - /// Will not raise a condition - pub fn exists(&self) -> bool { - io::result(|| self.stat()).is_ok() - } - - /// 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 - pub fn is_file(&self) -> bool { - match io::result(|| self.stat()) { - Ok(s) => s.kind == io::TypeFile, - Err(*) => false - } - } - - /// 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 - /// not a directory (eg files, named pipes, links, etc) - /// - /// # Errors - /// - /// Will not raise a condition - pub fn is_dir(&self) -> bool { - match io::result(|| self.stat()) { - Ok(s) => s.kind == io::TypeDirectory, - Err(*) => false - } - } -} - -#[cfg(test)] -mod test { - use prelude::*; - 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}; - - 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() { - 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() { - 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() { - 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() { - 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 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); - } - } - 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() { - 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() { - 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() { - 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() { - 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() { - 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() { - 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() { - 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() { - 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 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); - } - File::unlink(f); - } - 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"); - File::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(|| File::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"); - - 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().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/fs.rs b/src/libstd/rt/io/fs.rs new file mode 100644 index 00000000000..22d7ea55f3b --- /dev/null +++ b/src/libstd/rt/io/fs.rs @@ -0,0 +1,1247 @@ +// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +/*! Synchronous File I/O + +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 `Path` object. + +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. + +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. + +# 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; +use iter::Iterator; +use super::{Reader, Writer, Seek}; +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, Result}; +use path; +use path::{Path, GenericPath}; +use vec::OwnedVector; + +/// Unconstrained file access type that exposes read and write operations +/// +/// 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_mode()`. +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 f(io) { + Ok(t) => Some(t), + Err(ioerr) => { + io_error::cond.raise(ioerr); + None + } + } + } +} + +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 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(&Path::new("foo.txt")).read_to_end(); + pub fn open(path: &Path) -> Option { + File::open_mode(path, Open, Read) + } + + /// 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; + /// + /// 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) + } + + /// 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); + } +} + +/// 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::fs; +/// +/// let p = Path::new("/some/dir"); +/// fs::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: &Path, mode: FilePermission) { + do io_raise |io| { + io.fs_mkdir(&path.to_c_str(), mode) + }; +} + +/// Remove an existing, empty directory +/// +/// # Example +/// +/// use std::rt::io::fs; +/// +/// let p = Path::new("/some/dir"); +/// fs::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: &Path) { + do io_raise |io| { + io.fs_rmdir(&path.to_c_str()) + }; +} + +/// Retrieve a vector containing all entries within a provided directory +/// +/// # Example +/// +/// 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 = fs::readdir(dir).unwrap(); +/// for entry in contents.iter() { +/// if entry.is_dir() { visit_dirs(entry, cb); } +/// else { cb(entry); } +/// } +/// } +/// else { fail!("nope"); } +/// } +/// +/// # Errors +/// +/// 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: &Path) -> ~[Path] { + do io_raise |io| { + io.fs_readdir(&path.to_c_str(), 0) + }.unwrap_or_else(|| ~[]) +} + +/// 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) } +} + +/// An iterator which walks over a directory +pub struct WalkIterator { + priv stack: ~[Path], +} + +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 create a directory and all of its parent components if they +/// are missing. +/// +/// # Errors +/// +/// This function will raise on the `io_error` condition if an error +/// 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, + // should we return false? + if path.is_dir() { + return + } + if path.filename().is_some() { + mkdir_recursive(&path.dir_path(), mode); + } + mkdir(path, mode) +} + +/// Removes a directory at this path, after removing all its contents. Use +/// carefully! +/// +/// # Errors +/// +/// This function will raise on the `io_error` condition if an error +/// happens. See `file::unlink` and `fs::readdir` for possible error +/// conditions. +pub fn rmdir_recursive(path: &Path) { + let children = readdir(path); + for child in children.iter() { + if child.is_dir() { + rmdir_recursive(child); + } else { + unlink(child); + } + } + // Directory should now be empty + rmdir(path); +} + +impl Reader for File { + fn read(&mut self, buf: &mut [u8]) -> Option { + match self.fd.read(buf) { + Ok(read) => { + self.last_nread = read; + match read { + 0 => None, + _ => Some(read as uint) + } + }, + Err(ioerr) => { + // EOF is indicated by returning None + if ioerr.kind != io::EndOfFile { + io_error::cond.raise(ioerr); + } + return None; + } + } + } + + fn eof(&mut self) -> bool { self.last_nread == 0 } +} + +impl Writer for File { + fn write(&mut self, buf: &[u8]) { + match self.fd.write(buf) { + Ok(()) => (), + Err(ioerr) => { + io_error::cond.raise(ioerr); + } + } + } +} + +impl Seek for File { + fn tell(&self) -> u64 { + let res = self.fd.tell(); + match res { + Ok(cursor) => cursor, + Err(ioerr) => { + io_error::cond.raise(ioerr); + return -1; + } + } + } + + fn seek(&mut self, pos: i64, style: SeekStyle) { + match self.fd.seek(pos, style) { + Ok(_) => { + // successful seek resets EOF indicator + self.last_nread = -1; + () + }, + Err(ioerr) => { + io_error::cond.raise(ioerr); + } + } + } +} + +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`. + 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 + /// directory or a file. + /// + /// # Errors + /// + /// Will not raise a condition + pub fn exists(&self) -> bool { + io::result(|| self.stat()).is_ok() + } + + /// 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 + pub fn is_file(&self) -> bool { + match io::result(|| self.stat()) { + Ok(s) => s.kind == io::TypeFile, + Err(*) => false + } + } + + /// 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 + /// not a directory (eg files, named pipes, links, etc) + /// + /// # Errors + /// + /// Will not raise a condition + pub fn is_dir(&self) -> bool { + match io::result(|| self.stat()) { + Ok(s) => s.kind == io::TypeDirectory, + Err(*) => false + } + } +} + +#[cfg(test)] +mod test { + use prelude::*; + 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, + copy, unlink, stat, symlink, link, readlink, chmod, chown, + lstat}; + + fn tmpdir() -> Path { + use os; + use rand; + let ret = os::tmpdir().join(format!("rust-{}", rand::random::())); + mkdir(&ret, io::UserRWX); + ret + } + + fn free(_: T) {} + + #[test] + fn file_test_io_smoke_test() { + let message = "it's alright. have a good time"; + let filename = &Path::new("./tmp/file_rt_io_file_test.txt"); + { + let 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()); + } + unlink(filename); + } + + #[test] + fn file_test_io_invalid_path_opened_without_create_should_raise_condition() { + let filename = &Path::new("./tmp/file_that_does_not_exist.txt"); + 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() { + 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); + } + + #[test] + fn file_test_io_non_positional_read() { + let message = "ten-four"; + let mut read_mem = [0, .. 8]; + let filename = &Path::new("./tmp/file_rt_io_file_test_positional.txt"); + { + let 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 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); + } + } + 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() { + 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(); + } + 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() { + 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); + } + unlink(filename); + let read_str = str::from_utf8(read_mem); + assert!(read_str == final_msg.to_owned()); + } + + #[test] + fn file_test_io_seek_shakedown() { + use std::str; // 01234567890123 + let initial_msg = "qwer-asdf-zxcv"; + let chunk_one = "qwer"; + let chunk_two = "asdf"; + let chunk_three = "zxcv"; + let mut read_mem = [0, .. 4]; + let filename = &Path::new("./tmp/file_rt_io_file_test_seek_shakedown.txt"); + { + let 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()); + } + unlink(filename); + } + + #[test] + fn file_test_stat_is_correct_on_is_file() { + 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 = stat(filename); + assert_eq!(stat_res.kind, io::TypeFile); + unlink(filename); + } + + #[test] + fn file_test_stat_is_correct_on_is_dir() { + let filename = &Path::new("./tmp/file_stat_correct_on_is_dir"); + mkdir(filename, io::UserRWX); + let stat_res = filename.stat(); + assert!(stat_res.kind == io::TypeDirectory); + rmdir(filename); + } + + #[test] + fn file_test_fileinfo_false_when_checking_is_file_on_a_directory() { + let dir = &Path::new("./tmp/fileinfo_false_on_dir"); + mkdir(dir, io::UserRWX); + assert!(dir.is_file() == false); + rmdir(dir); + } + + #[test] + fn file_test_fileinfo_check_exists_before_and_after_file_creation() { + let file = &Path::new("./tmp/fileinfo_check_exists_b_and_a.txt"); + File::create(file).write(bytes!("foo")); + assert!(file.exists()); + unlink(file); + assert!(!file.exists()); + } + + #[test] + fn file_test_directoryinfo_check_exists_before_and_after_mkdir() { + let dir = &Path::new("./tmp/before_and_after_dir"); + 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 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); + } + unlink(f); + } + 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"); + File::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"); + + File::create(&input).write(bytes!("hello")); + copy(&input, &out); + let contents = File::open(&out).read_to_end(); + assert_eq!(contents.as_slice(), bytes!("hello")); + + 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(|| 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()); + 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(|| 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); + 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()); + 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()); + + rmdir_recursive(&tmpdir); + } + + #[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); + } + + #[test] + fn readlink_not_symlink() { + let tmpdir = tmpdir(); + match io::result(|| 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()); + 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(|| link(&input, &input)) { + Ok(*) => fail!("wanted a failure"), + Err(*) => {} + } + // can't link to something that doesn't exist + match io::result(|| 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); + assert!(stat(&file).perm & io::UserWrite == io::UserWrite); + chmod(&file, io::UserRead); + assert!(stat(&file).perm & io::UserWrite == 0); + + match io::result(|| chmod(&tmpdir.join("foo"), io::UserRWX)) { + Ok(*) => fail!("wanted a failure"), + Err(*) => {} + } + + chmod(&file, io::UserFile); + 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(); + free(file); + + 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!(stat(&path).size, 3); + file.truncate(10); + assert_eq!(stat(&path).size, 10); + file.write(bytes!("bar")); + assert_eq!(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!(stat(&path).size, 2); + file.write(bytes!("wut")); + 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); + } + + #[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!(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!(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!(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 510c3470d06..f01ce5012eb 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 4eb473a73a6..35057f475cf 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 1b856ab0755..0f48f83a57e 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 fd4dab60ff3..e71cd92589c 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 89784acec8e..74f4ed3d55e 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 7f684e41c75..897ee9cb88b 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 0aa4ae40f9e..fcb57152daa 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 9ac144f5fb5..3a115ab29cf 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()); -- cgit 1.4.1-3-g733a5