From de4fdd3ccc4637188d2fc1f14fc640ae50ac440d Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Tue, 5 Jan 2021 16:49:09 -0800 Subject: [PATCH 1/9] Deprecate std::path::Path's aliases of `std::fs` functions. `std::path::Path` has several functions which are trivial aliases for `std::fs` functions (eg. [`metadata`]) and a few which are minor convenience wrappers for `std::fs` functions (eg. [`is_file`]). [`metadata`]: https://doc.rust-lang.org/std/path/struct.Path.html#method.metadata [`is_file`]: https://doc.rust-lang.org/std/path/struct.Path.html#method.is_file This PR deprecates these functions, so that `std` only has one preferred name for these operations. And it clarifies the role of the `std::path` module, which otherwise just has pure data structures and algorithms. The convenience wrappers, `is_file`, `is_dir`, and `exists`, are operations for which seemingly obvious uses are prone to TOCTTOU errors. So while it would be straightforward to add corresponding similar convenience functions to `std::fs`, this PR does not propose doing so. Specifically, this PR deprecates the 5 functions in `std::path::Path` which are trivial aliases of functions in `std::fs`: - [`metadata`](https://doc.rust-lang.org/std/path/struct.Path.html#method.metadata) - [`symlink_metadata`](https://doc.rust-lang.org/std/path/struct.Path.html#method.symlink_metadata) - [`canonicalize`](https://doc.rust-lang.org/std/path/struct.Path.html#method.canonicalize) - [`read_link`](https://doc.rust-lang.org/std/path/struct.Path.html#method.read_link) - [`read_dir`](https://doc.rust-lang.org/std/path/struct.Path.html#method.read_dir) and the 3 which are convenience wrappers around `std::fs::metadata`: - [`is_file`](https://doc.rust-lang.org/std/path/struct.Path.html#method.is_file) - [`is_dir`](https://doc.rust-lang.org/std/path/struct.Path.html#method.is_dir) - [`exists`](https://doc.rust-lang.org/std/path/struct.Path.html#method.exists) --- library/std/src/path.rs | 44 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/library/std/src/path.rs b/library/std/src/path.rs index 243761e389784..c38648e3c49a8 100644 --- a/library/std/src/path.rs +++ b/library/std/src/path.rs @@ -2305,6 +2305,11 @@ impl Path { /// println!("{:?}", metadata.file_type()); /// ``` #[stable(feature = "path_ext", since = "1.5.0")] + #[rustc_deprecated( + since = "1.51.0", + reason = "the `std::fs::metadata` function is now preferred", + suggestion = "std::fs::metadata" + )] pub fn metadata(&self) -> io::Result { fs::metadata(self) } @@ -2323,6 +2328,11 @@ impl Path { /// println!("{:?}", metadata.file_type()); /// ``` #[stable(feature = "path_ext", since = "1.5.0")] + #[rustc_deprecated( + since = "1.51.0", + reason = "the `std::fs::symlink_metadata` function is now preferred", + suggestion = "std::fs::symlink_metadata" + )] pub fn symlink_metadata(&self) -> io::Result { fs::symlink_metadata(self) } @@ -2341,6 +2351,11 @@ impl Path { /// assert_eq!(path.canonicalize().unwrap(), PathBuf::from("/foo/test/bar.rs")); /// ``` #[stable(feature = "path_ext", since = "1.5.0")] + #[rustc_deprecated( + since = "1.51.0", + reason = "the `std::fs::canonicalize` function is now preferred", + suggestion = "std::fs::canonicalize" + )] pub fn canonicalize(&self) -> io::Result { fs::canonicalize(self) } @@ -2358,6 +2373,11 @@ impl Path { /// let path_link = path.read_link().expect("read_link call failed"); /// ``` #[stable(feature = "path_ext", since = "1.5.0")] + #[rustc_deprecated( + since = "1.51.0", + reason = "the `std::fs::read_link` function is now preferred", + suggestion = "std::fs::read_link" + )] pub fn read_link(&self) -> io::Result { fs::read_link(self) } @@ -2382,6 +2402,11 @@ impl Path { /// } /// ``` #[stable(feature = "path_ext", since = "1.5.0")] + #[rustc_deprecated( + since = "1.51.0", + reason = "the `std::fs::read_dir` function is now preferred", + suggestion = "std::fs::read_dir" + )] pub fn read_dir(&self) -> io::Result { fs::read_dir(self) } @@ -2406,6 +2431,11 @@ impl Path { /// This is a convenience function that coerces errors to false. If you want to /// check errors, call [`fs::metadata`]. #[stable(feature = "path_ext", since = "1.5.0")] + #[rustc_deprecated( + since = "1.51.0", + reason = "other processes may remove or rename files at any time", + suggestion = "use `std::fs::metadata`" + )] pub fn exists(&self) -> bool { fs::metadata(self).is_ok() } @@ -2438,6 +2468,11 @@ impl Path { /// a Unix-like system for example. See [`fs::File::open`] or /// [`fs::OpenOptions::open`] for more information. #[stable(feature = "path_ext", since = "1.5.0")] + #[rustc_deprecated( + since = "1.51.0", + reason = "other processes may remove, rename, or replace files at any time", + suggestion = "use `std::fs::File::open` or `std::fs::metadata`" + )] pub fn is_file(&self) -> bool { fs::metadata(self).map(|m| m.is_file()).unwrap_or(false) } @@ -2463,7 +2498,16 @@ impl Path { /// This is a convenience function that coerces errors to false. If you want to /// check errors, call [`fs::metadata`] and handle its [`Result`]. Then call /// [`fs::Metadata::is_dir`] if it was [`Ok`]. + /// + /// When the goal is simply to read from the source, the most reliable way to + /// test the source can be read is to open it. See [`fs::read_dir`] for more + /// information. #[stable(feature = "path_ext", since = "1.5.0")] + #[rustc_deprecated( + since = "1.51.0", + reason = "other processes may remove, rename, or replace directories at any time", + suggestion = "use `std::fs::read_dir` or `std::fs::metadata`" + )] pub fn is_dir(&self) -> bool { fs::metadata(self).map(|m| m.is_dir()).unwrap_or(false) } From ccf2dadb6c2bf13ce18ee862592b5f6d851e70e5 Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Tue, 5 Jan 2021 18:00:38 -0800 Subject: [PATCH 2/9] Avoid using `Path::metadata` in the generic `fs::copy`. This also eliminates one of the two path lookups on the input. --- library/std/src/sys_common/fs.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/library/std/src/sys_common/fs.rs b/library/std/src/sys_common/fs.rs index e30e8018a31fe..54fbf68c9cb5a 100644 --- a/library/std/src/sys_common/fs.rs +++ b/library/std/src/sys_common/fs.rs @@ -5,14 +5,16 @@ use crate::io::{self, Error, ErrorKind}; use crate::path::Path; pub fn copy(from: &Path, to: &Path) -> io::Result { - if !from.is_file() { + let mut reader = fs::File::open(from)?; + let metadata = reader.metadata()?; + + if !metadata.is_file() { return Err(Error::new( ErrorKind::InvalidInput, "the source path is not an existing regular file", )); } - let mut reader = fs::File::open(from)?; let mut writer = fs::File::create(to)?; let perm = reader.metadata()?.permissions(); From f7a6c3e05d8c86804f8fd36de87c4b6f8156770f Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Tue, 5 Jan 2021 18:02:21 -0800 Subject: [PATCH 3/9] Avoid using `Path::is_dir`, which is now deprecated. --- library/std/src/fs.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs index e2d4f2e6a56af..58c01325e7064 100644 --- a/library/std/src/fs.rs +++ b/library/std/src/fs.rs @@ -2179,7 +2179,7 @@ impl DirBuilder { match self.inner.mkdir(path) { Ok(()) => return Ok(()), Err(ref e) if e.kind() == io::ErrorKind::NotFound => {} - Err(_) if path.is_dir() => return Ok(()), + Err(_) if metadata(path).map(|m| m.is_dir()).unwrap_or(false) => return Ok(()), Err(e) => return Err(e), } match path.parent() { @@ -2190,7 +2190,7 @@ impl DirBuilder { } match self.inner.mkdir(path) { Ok(()) => Ok(()), - Err(_) if path.is_dir() => Ok(()), + Err(_) if metadata(path).map(|m| m.is_dir()).unwrap_or(false) => Ok(()), Err(e) => Err(e), } } From 77c9f115f735062e9cbc46d6dab284df284f4f2c Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Tue, 5 Jan 2021 18:40:18 -0800 Subject: [PATCH 4/9] Update library/std/src/path.rs Co-authored-by: Ivan Tham --- library/std/src/path.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/std/src/path.rs b/library/std/src/path.rs index c38648e3c49a8..9680ff41ff1ac 100644 --- a/library/std/src/path.rs +++ b/library/std/src/path.rs @@ -2307,7 +2307,7 @@ impl Path { #[stable(feature = "path_ext", since = "1.5.0")] #[rustc_deprecated( since = "1.51.0", - reason = "the `std::fs::metadata` function is now preferred", + reason = "use `std::fs::metadata` instead", suggestion = "std::fs::metadata" )] pub fn metadata(&self) -> io::Result { From ac0edef32d5e061af4d8d0a190362bb896b5f37c Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Tue, 5 Jan 2021 18:41:17 -0800 Subject: [PATCH 5/9] Apply similar wording to several more suggestions. --- library/std/src/path.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/library/std/src/path.rs b/library/std/src/path.rs index 9680ff41ff1ac..38a2b2bdfa4b2 100644 --- a/library/std/src/path.rs +++ b/library/std/src/path.rs @@ -2330,7 +2330,7 @@ impl Path { #[stable(feature = "path_ext", since = "1.5.0")] #[rustc_deprecated( since = "1.51.0", - reason = "the `std::fs::symlink_metadata` function is now preferred", + reason = "use `std::fs::symlink_metadata` instead", suggestion = "std::fs::symlink_metadata" )] pub fn symlink_metadata(&self) -> io::Result { @@ -2353,7 +2353,7 @@ impl Path { #[stable(feature = "path_ext", since = "1.5.0")] #[rustc_deprecated( since = "1.51.0", - reason = "the `std::fs::canonicalize` function is now preferred", + reason = "use `std::fs::canonicalize` instead", suggestion = "std::fs::canonicalize" )] pub fn canonicalize(&self) -> io::Result { @@ -2375,7 +2375,7 @@ impl Path { #[stable(feature = "path_ext", since = "1.5.0")] #[rustc_deprecated( since = "1.51.0", - reason = "the `std::fs::read_link` function is now preferred", + reason = "use `std::fs::read_link` instead", suggestion = "std::fs::read_link" )] pub fn read_link(&self) -> io::Result { @@ -2404,7 +2404,7 @@ impl Path { #[stable(feature = "path_ext", since = "1.5.0")] #[rustc_deprecated( since = "1.51.0", - reason = "the `std::fs::read_dir` function is now preferred", + reason = "use `std::fs::read_dir` instead", suggestion = "std::fs::read_dir" )] pub fn read_dir(&self) -> io::Result { From 42e4189be3c3ba0117a610070beffc5cc799217c Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Tue, 5 Jan 2021 18:38:28 -0800 Subject: [PATCH 6/9] Avoid using now-deprecated functions. --- compiler/rustc_codegen_llvm/src/back/lto.rs | 9 +- .../rustc_codegen_ssa/src/back/archive.rs | 5 +- compiler/rustc_codegen_ssa/src/back/link.rs | 12 +-- compiler/rustc_fs_util/src/lib.rs | 6 +- .../src/persist/file_format.rs | 10 +-- compiler/rustc_incremental/src/persist/fs.rs | 41 ++++----- .../rustc_incremental/src/persist/load.rs | 3 +- .../rustc_incremental/src/persist/save.rs | 37 ++++---- compiler/rustc_interface/src/passes.rs | 8 +- compiler/rustc_interface/src/util.rs | 9 +- compiler/rustc_llvm/build.rs | 3 +- compiler/rustc_metadata/src/locator.rs | 6 +- compiler/rustc_session/src/filesearch.rs | 2 +- compiler/rustc_session/src/output.rs | 3 +- compiler/rustc_session/src/session.rs | 14 ++- compiler/rustc_target/src/spec/mod.rs | 6 +- library/std/src/fs/tests.rs | 87 +++++++++---------- src/build_helper/lib.rs | 7 +- .../ui-fulldeps/mod_dir_path_canonicalized.rs | 3 +- src/test/ui-fulldeps/rename-directory.rs | 4 +- 20 files changed, 144 insertions(+), 131 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/back/lto.rs b/compiler/rustc_codegen_llvm/src/back/lto.rs index 29415973ed073..9ccfb781b9f16 100644 --- a/compiler/rustc_codegen_llvm/src/back/lto.rs +++ b/compiler/rustc_codegen_llvm/src/back/lto.rs @@ -22,7 +22,7 @@ use rustc_session::config::{self, CrateType, Lto}; use tracing::{debug, info}; use std::ffi::{CStr, CString}; -use std::fs::File; +use std::fs::{self, File}; use std::io; use std::path::Path; use std::ptr; @@ -496,8 +496,11 @@ fn thin_lto( // If the previous file was deleted, or we get an IO error // reading the file, then we'll just use `None` as the // prev_key_map, which will force the code to be recompiled. - let prev = - if path.exists() { ThinLTOKeysMap::load_from_file(&path).ok() } else { None }; + let prev = if fs::metadata(&path).is_ok() { + ThinLTOKeysMap::load_from_file(&path).ok() + } else { + None + }; let curr = ThinLTOKeysMap::from_thin_lto_modules(&data, &thin_modules, &module_names); (Some(path), prev, curr) } else { diff --git a/compiler/rustc_codegen_ssa/src/back/archive.rs b/compiler/rustc_codegen_ssa/src/back/archive.rs index c477ac6462acb..73465e2196444 100644 --- a/compiler/rustc_codegen_ssa/src/back/archive.rs +++ b/compiler/rustc_codegen_ssa/src/back/archive.rs @@ -1,6 +1,7 @@ use rustc_session::Session; use rustc_span::symbol::Symbol; +use std::fs; use std::io; use std::path::{Path, PathBuf}; @@ -14,12 +15,12 @@ pub fn find_library(name: Symbol, search_paths: &[PathBuf], sess: &Session) -> P for path in search_paths { debug!("looking for {} inside {:?}", name, path); let test = path.join(&oslibname); - if test.exists() { + if fs::metadata(&test).is_ok() { return test; } if oslibname != unixlibname { let test = path.join(&unixlibname); - if test.exists() { + if fs::metadata(&test).is_ok() { return test; } } diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index 55fddb38e10be..6b765334e0f76 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -1110,19 +1110,19 @@ fn print_native_static_libs(sess: &Session, all_native_libs: &[NativeLib]) { fn get_object_file_path(sess: &Session, name: &str, self_contained: bool) -> PathBuf { let fs = sess.target_filesearch(PathKind::Native); let file_path = fs.get_lib_path().join(name); - if file_path.exists() { + if fs::metadata(&file_path).is_ok() { return file_path; } // Special directory with objects used only in self-contained linkage mode if self_contained { let file_path = fs.get_self_contained_lib_path().join(name); - if file_path.exists() { + if fs::metadata(&file_path).is_ok() { return file_path; } } for search_path in fs.search_paths() { let file_path = search_path.dir.join(name); - if file_path.exists() { + if fs::metadata(&file_path).is_ok() { return file_path; } } @@ -1312,7 +1312,9 @@ fn detect_self_contained_mingw(sess: &Session) -> bool { for dir in env::split_paths(&env::var_os("PATH").unwrap_or_default()) { let full_path = dir.join(&linker_with_extension); // If linker comes from sysroot assume self-contained mode - if full_path.is_file() && !full_path.starts_with(&sess.sysroot) { + if fs::metadata(&full_path).map(|m| m.is_file()).unwrap_or(false) + && !full_path.starts_with(&sess.sysroot) + { return false; } } @@ -2228,7 +2230,7 @@ fn get_apple_sdk_root(sdk_name: &str) -> Result { if sdkroot.contains("iPhoneOS.platform") || sdkroot.contains("iPhoneSimulator.platform") => {} // Ignore `SDKROOT` if it's not a valid path. - _ if !p.is_absolute() || p == Path::new("/") || !p.exists() => {} + _ if !p.is_absolute() || p == Path::new("/") || fs::metadata(p).is_err() => {} _ => return Ok(sdkroot), } } diff --git a/compiler/rustc_fs_util/src/lib.rs b/compiler/rustc_fs_util/src/lib.rs index 7742961e65dbb..87e97c746ef56 100644 --- a/compiler/rustc_fs_util/src/lib.rs +++ b/compiler/rustc_fs_util/src/lib.rs @@ -62,8 +62,10 @@ pub enum LinkOrCopy { pub fn link_or_copy, Q: AsRef>(p: P, q: Q) -> io::Result { let p = p.as_ref(); let q = q.as_ref(); - if q.exists() { - fs::remove_file(&q)?; + match fs::remove_file(&q) { + Ok(()) => (), + Err(err) if err.kind() == io::ErrorKind::NotFound => (), + Err(err) => return Err(err), } match fs::hard_link(p, q) { diff --git a/compiler/rustc_incremental/src/persist/file_format.rs b/compiler/rustc_incremental/src/persist/file_format.rs index e185ee24d171b..c86122f89392d 100644 --- a/compiler/rustc_incremental/src/persist/file_format.rs +++ b/compiler/rustc_incremental/src/persist/file_format.rs @@ -52,11 +52,11 @@ pub fn read_file( path: &Path, nightly_build: bool, ) -> io::Result, usize)>> { - if !path.exists() { - return Ok(None); - } - - let data = fs::read(path)?; + let data = match fs::read(path) { + Ok(data) => data, + Err(err) if err.kind() == io::ErrorKind::NotFound => return Ok(None), + Err(err) => return Err(err), + }; let mut file = io::Cursor::new(data); diff --git a/compiler/rustc_incremental/src/persist/fs.rs b/compiler/rustc_incremental/src/persist/fs.rs index 9fdf0a56d9de1..45c2bbe7ad5bb 100644 --- a/compiler/rustc_incremental/src/persist/fs.rs +++ b/compiler/rustc_incremental/src/persist/fs.rs @@ -205,7 +205,7 @@ pub fn prepare_session_directory( // because, on windows, long paths can cause problems; // canonicalization inserts this weird prefix that makes windows // tolerate long paths. - let crate_dir = match crate_dir.canonicalize() { + let crate_dir = match std_fs::canonicalize(&crate_dir) { Ok(v) => v, Err(err) => { sess.err(&format!( @@ -387,7 +387,7 @@ pub fn finalize_session_directory(sess: &Session, svh: Svh) { } pub fn delete_all_session_dir_contents(sess: &Session) -> io::Result<()> { - let sess_dir_iterator = sess.incr_comp_session_dir().read_dir()?; + let sess_dir_iterator = std_fs::read_dir(&*sess.incr_comp_session_dir())?; for entry in sess_dir_iterator { let entry = entry?; safe_remove_file(&entry.path())? @@ -412,7 +412,7 @@ fn copy_files(sess: &Session, target_dir: &Path, source_dir: &Path) -> Result it, Err(_) => return Err(()), }; @@ -534,8 +534,7 @@ fn find_source_directory( crate_dir: &Path, source_directories_already_tried: &FxHashSet, ) -> Option { - let iter = crate_dir - .read_dir() + let iter = std_fs::read_dir(crate_dir) .unwrap() // FIXME .filter_map(|e| e.ok().map(|e| e.path())); @@ -670,7 +669,7 @@ pub fn garbage_collect_session_directories(sess: &Session) -> io::Result<()> { let mut session_directories = FxHashSet::default(); let mut lock_files = FxHashSet::default(); - for dir_entry in crate_directory.read_dir()? { + for dir_entry in std_fs::read_dir(crate_directory)? { let dir_entry = match dir_entry { Ok(dir_entry) => dir_entry, _ => { @@ -922,22 +921,24 @@ fn all_except_most_recent( /// before passing it to std::fs::remove_dir_all(). This will convert the path /// into the '\\?\' format, which supports much longer paths. fn safe_remove_dir_all(p: &Path) -> io::Result<()> { - if p.exists() { - let canonicalized = p.canonicalize()?; - std_fs::remove_dir_all(canonicalized) - } else { - Ok(()) - } + let canonicalized = match std_fs::canonicalize(p) { + Ok(canonicalized) => canonicalized, + Err(err) if err.kind() == io::ErrorKind::NotFound => return Ok(()), + Err(err) => return Err(err), + }; + + std_fs::remove_dir_all(canonicalized) } fn safe_remove_file(p: &Path) -> io::Result<()> { - if p.exists() { - let canonicalized = p.canonicalize()?; - match std_fs::remove_file(canonicalized) { - Err(ref err) if err.kind() == io::ErrorKind::NotFound => Ok(()), - result => result, - } - } else { - Ok(()) + let canonicalized = match std_fs::canonicalize(p) { + Ok(canonicalized) => canonicalized, + Err(err) if err.kind() == io::ErrorKind::NotFound => return Ok(()), + Err(err) => return Err(err), + }; + + match std_fs::remove_file(canonicalized) { + Err(err) if err.kind() == io::ErrorKind::NotFound => Ok(()), + result => result, } } diff --git a/compiler/rustc_incremental/src/persist/load.rs b/compiler/rustc_incremental/src/persist/load.rs index 35428dc8d84e5..ba2be6c4917f0 100644 --- a/compiler/rustc_incremental/src/persist/load.rs +++ b/compiler/rustc_incremental/src/persist/load.rs @@ -8,6 +8,7 @@ use rustc_middle::ty::TyCtxt; use rustc_serialize::opaque::Decoder; use rustc_serialize::Decodable as RustcDecodable; use rustc_session::Session; +use std::fs; use std::path::Path; use super::data::*; @@ -142,7 +143,7 @@ pub fn load_dep_graph(sess: &Session) -> DepGraphFuture { let mut all_files_exist = true; if let Some(ref file_name) = swp.work_product.saved_file { let path = in_incr_comp_dir_sess(sess, file_name); - if !path.exists() { + if fs::metadata(&path).is_err() { all_files_exist = false; if sess.opts.debugging_opts.incremental_info { diff --git a/compiler/rustc_incremental/src/persist/save.rs b/compiler/rustc_incremental/src/persist/save.rs index 102a77e8e79a7..4a1f0fd3d081d 100644 --- a/compiler/rustc_incremental/src/persist/save.rs +++ b/compiler/rustc_incremental/src/persist/save.rs @@ -5,8 +5,8 @@ use rustc_middle::ty::TyCtxt; use rustc_serialize::opaque::Encoder; use rustc_serialize::Encodable as RustcEncodable; use rustc_session::Session; -use std::fs; use std::path::PathBuf; +use std::{fs, io}; use super::data::*; use super::dirty_clean; @@ -73,11 +73,9 @@ pub fn save_work_product_index( for (id, wp) in previous_work_products.iter() { if !new_work_products.contains_key(id) { work_product::delete_workproduct_files(sess, wp); - debug_assert!( - wp.saved_file.as_ref().map_or(true, |file_name| { - !in_incr_comp_dir_sess(sess, &file_name).exists() - }) - ); + debug_assert!(wp.saved_file.as_ref().map_or(true, |file_name| { + fs::metadata(in_incr_comp_dir_sess(sess, &file_name)).is_err() + })); } } @@ -87,7 +85,7 @@ pub fn save_work_product_index( .iter() .flat_map(|(_, wp)| wp.saved_file.iter()) .map(|name| in_incr_comp_dir_sess(sess, name)) - .all(|path| path.exists()) + .all(|path| fs::metadata(path).is_ok()) }); } @@ -101,19 +99,18 @@ where // Note: It's important that we actually delete the old file and not just // truncate and overwrite it, since it might be a shared hard-link, the // underlying data of which we don't want to modify - if path_buf.exists() { - match fs::remove_file(&path_buf) { - Ok(()) => { - debug!("save: remove old file"); - } - Err(err) => { - sess.err(&format!( - "unable to delete old dep-graph at `{}`: {}", - path_buf.display(), - err - )); - return; - } + match fs::remove_file(&path_buf) { + Ok(()) => { + debug!("save: remove old file"); + } + Err(err) if err.kind() == io::ErrorKind::NotFound => (), + Err(err) => { + sess.err(&format!( + "unable to delete old dep-graph at `{}`: {}", + path_buf.display(), + err + )); + return; } } diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index 461ee08592275..8997aff631585 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -506,18 +506,20 @@ where } fn output_contains_path(output_paths: &[PathBuf], input_path: &PathBuf) -> bool { - let input_path = input_path.canonicalize().ok(); + let input_path = fs::canonicalize(input_path).ok(); if input_path.is_none() { return false; } let check = |output_path: &PathBuf| { - if output_path.canonicalize().ok() == input_path { Some(()) } else { None } + if fs::canonicalize(output_path).ok() == input_path { Some(()) } else { None } }; check_output(output_paths, check).is_some() } fn output_conflicts_with_dir(output_paths: &[PathBuf]) -> Option { - let check = |output_path: &PathBuf| output_path.is_dir().then(|| output_path.clone()); + let check = |output_path: &PathBuf| { + fs::metadata(output_path).map(|m| m.is_dir()).unwrap_or(false).then(|| output_path.clone()) + }; check_output(output_paths, check) } diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs index f34990a1a1037..dadaa5a823ede 100644 --- a/compiler/rustc_interface/src/util.rs +++ b/compiler/rustc_interface/src/util.rs @@ -25,6 +25,7 @@ use rustc_span::symbol::{sym, Symbol}; use smallvec::SmallVec; use std::env; use std::env::consts::{DLL_PREFIX, DLL_SUFFIX}; +use std::fs; use std::io; use std::lazy::SyncOnceCell; use std::mem; @@ -269,14 +270,14 @@ fn get_rustc_path_inner(bin_path: &str) -> Option { } else { "rustc" }); - candidate.exists().then_some(candidate) + fs::metadata(&candidate).is_ok().then_some(candidate) }) } fn sysroot_candidates() -> Vec { let target = session::config::host_triple(); let mut sysroot_candidates = vec![filesearch::get_or_default_sysroot()]; - let path = current_dll_path().and_then(|s| s.canonicalize().ok()); + let path = current_dll_path().and_then(|s| fs::canonicalize(s).ok()); if let Some(dll) = path { // use `parent` twice to chop off the file name and then also the // directory containing the dll which should be either `lib` or `bin`. @@ -397,7 +398,7 @@ pub fn get_codegen_sysroot(backend_name: &str) -> fn() -> Box fn() -> Box CrateLocator<'a> { // as well. if let Some((prev, _)) = &ret { let sysroot = &self.sess.sysroot; - let sysroot = sysroot.canonicalize().unwrap_or_else(|_| sysroot.to_path_buf()); + let sysroot = fs::canonicalize(sysroot).unwrap_or_else(|_| sysroot.to_path_buf()); if prev.starts_with(&sysroot) { continue; } @@ -664,7 +664,7 @@ impl<'a> CrateLocator<'a> { let mut rmetas = FxHashMap::default(); let mut dylibs = FxHashMap::default(); for loc in &self.exact_paths { - if !loc.exists() { + if fs::metadata(loc).is_err() { return Err(CrateError::ExternLocationNotExist(self.crate_name, loc.clone())); } let file = match loc.file_name().and_then(|s| s.to_str()) { @@ -738,7 +738,7 @@ fn get_metadata_section( filename: &Path, loader: &dyn MetadataLoader, ) -> Result { - if !filename.exists() { + if fs::metadata(filename).is_err() { return Err(format!("no such file: '{}'", filename.display())); } let raw_bytes: MetadataRef = match flavor { diff --git a/compiler/rustc_session/src/filesearch.rs b/compiler/rustc_session/src/filesearch.rs index 3a757e5f0075d..1756720964c1d 100644 --- a/compiler/rustc_session/src/filesearch.rs +++ b/compiler/rustc_session/src/filesearch.rs @@ -154,7 +154,7 @@ fn find_libdir(sysroot: &Path) -> Cow<'static, str> { match option_env!("CFG_LIBDIR_RELATIVE") { None | Some("lib") => { - if sysroot.join(PRIMARY_LIB_DIR).join(RUST_LIB_DIR).exists() { + if fs::metadata(sysroot.join(PRIMARY_LIB_DIR).join(RUST_LIB_DIR)).is_ok() { PRIMARY_LIB_DIR.into() } else { SECONDARY_LIB_DIR.into() diff --git a/compiler/rustc_session/src/output.rs b/compiler/rustc_session/src/output.rs index 777eea3f68d02..0d58d8357e10c 100644 --- a/compiler/rustc_session/src/output.rs +++ b/compiler/rustc_session/src/output.rs @@ -4,6 +4,7 @@ use crate::Session; use rustc_ast as ast; use rustc_span::symbol::sym; use rustc_span::Span; +use std::fs; use std::path::{Path, PathBuf}; pub fn out_filename( @@ -39,7 +40,7 @@ pub fn check_file_is_writeable(file: &Path, sess: &Session) { } fn is_writeable(p: &Path) -> bool { - match p.metadata() { + match fs::metadata(p) { Err(..) => true, Ok(m) => !m.permissions().readonly(), } diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index 509e583eca21d..38c65ad684ca5 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -33,6 +33,7 @@ use rustc_target::spec::{Target, TargetTriple, TlsModel}; use std::cell::{self, RefCell}; use std::env; use std::fmt; +use std::fs; use std::io::Write; use std::num::NonZeroU32; use std::ops::{Div, Mul}; @@ -1384,7 +1385,7 @@ pub fn build_session( let real_rust_source_base_dir = { // This is the location used by the `rust-src` `rustup` component. let mut candidate = sysroot.join("lib/rustlib/src/rust"); - if let Ok(metadata) = candidate.symlink_metadata() { + if let Ok(metadata) = fs::symlink_metadata(&candidate) { // Replace the symlink rustbuild creates, with its destination. // We could try to use `fs::canonicalize` instead, but that might // produce unnecessarily verbose path. @@ -1396,7 +1397,14 @@ pub fn build_session( } // Only use this directory if it has a file we can expect to always find. - if candidate.join("library/std/src/lib.rs").is_file() { Some(candidate) } else { None } + if fs::metadata(candidate.join("library/std/src/lib.rs")) + .map(|m| m.is_file()) + .unwrap_or(false) + { + Some(candidate) + } else { + None + } }; let asm_arch = @@ -1477,7 +1485,7 @@ fn validate_commandline_args_with_session_available(sess: &Session) { // Make sure that any given profiling data actually exists so LLVM can't // decide to silently skip PGO. if let Some(ref path) = sess.opts.cg.profile_use { - if !path.exists() { + if fs::metadata(path).is_err() { sess.err(&format!( "File `{}` passed to `-C profile-use` does not exist.", path.display() diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index 8d72df6850fc2..48780edd23368 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -1600,14 +1600,14 @@ impl Target { for dir in env::split_paths(&target_path) { let p = dir.join(&path); - if p.is_file() { + if fs::metadata(&p).map(|m| m.is_file()).unwrap_or(false) { return load_file(&p); } } Err(format!("Could not find specification for target {:?}", target_triple)) } TargetTriple::TargetPath(ref target_path) => { - if target_path.is_file() { + if fs::metadata(target_path).map(|m| m.is_file()).unwrap_or(false) { return load_file(&target_path); } Err(format!("Target path {:?} is not a valid file", target_path)) @@ -1796,7 +1796,7 @@ impl TargetTriple { /// Creates a target triple from the passed target path. pub fn from_path(path: &Path) -> Result { - let canonicalized_path = path.canonicalize()?; + let canonicalized_path = std::fs::canonicalize(path)?; Ok(TargetTriple::TargetPath(canonicalized_path)) } diff --git a/library/std/src/fs/tests.rs b/library/std/src/fs/tests.rs index 5c969741592e6..4dfaf35b671a5 100644 --- a/library/std/src/fs/tests.rs +++ b/library/std/src/fs/tests.rs @@ -397,10 +397,8 @@ fn file_test_stat_is_correct_on_is_file() { let fstat_res = check!(fs.metadata()); assert!(fstat_res.is_file()); } - let stat_res_fn = check!(fs::metadata(filename)); - assert!(stat_res_fn.is_file()); - let stat_res_meth = check!(filename.metadata()); - assert!(stat_res_meth.is_file()); + let stat_res = check!(fs::metadata(filename)); + assert!(stat_res.is_file()); check!(fs::remove_file(filename)); } @@ -409,10 +407,8 @@ fn file_test_stat_is_correct_on_is_dir() { let tmpdir = tmpdir(); let filename = &tmpdir.join("file_stat_correct_on_is_dir"); check!(fs::create_dir(filename)); - let stat_res_fn = check!(fs::metadata(filename)); - assert!(stat_res_fn.is_dir()); - let stat_res_meth = check!(filename.metadata()); - assert!(stat_res_meth.is_dir()); + let stat_res = check!(fs::metadata(filename)); + assert!(stat_res.is_dir()); check!(fs::remove_dir(filename)); } @@ -421,7 +417,7 @@ fn file_test_fileinfo_false_when_checking_is_file_on_a_directory() { let tmpdir = tmpdir(); let dir = &tmpdir.join("fileinfo_false_on_dir"); check!(fs::create_dir(dir)); - assert!(!dir.is_file()); + assert!(!fs::metadata(dir).unwrap().is_file()); check!(fs::remove_dir(dir)); } @@ -430,21 +426,20 @@ fn file_test_fileinfo_check_exists_before_and_after_file_creation() { let tmpdir = tmpdir(); let file = &tmpdir.join("fileinfo_check_exists_b_and_a.txt"); check!(check!(File::create(file)).write(b"foo")); - assert!(file.exists()); + assert!(fs::metadata(file).is_ok()); check!(fs::remove_file(file)); - assert!(!file.exists()); + assert!(fs::metadata(file).is_err()); } #[test] fn file_test_directoryinfo_check_exists_before_and_after_mkdir() { let tmpdir = tmpdir(); let dir = &tmpdir.join("before_and_after_dir"); - assert!(!dir.exists()); + assert!(fs::metadata(dir).is_err()); check!(fs::create_dir(dir)); - assert!(dir.exists()); - assert!(dir.is_dir()); + assert!(fs::metadata(dir).unwrap().is_dir()); check!(fs::remove_dir(dir)); - assert!(!dir.exists()); + assert!(fs::metadata(dir).is_err()); } #[test] @@ -499,7 +494,7 @@ fn recursive_mkdir() { let tmpdir = tmpdir(); let dir = tmpdir.join("d1/d2"); check!(fs::create_dir_all(&dir)); - assert!(dir.is_dir()) + assert!(fs::metadata(dir).unwrap().is_dir()); } #[test] @@ -567,8 +562,8 @@ fn recursive_rmdir() { let _ = symlink_file(&canary, &d1.join("canary")); check!(fs::remove_dir_all(&d1)); - assert!(!d1.is_dir()); - assert!(canary.exists()); + assert!(!fs::metadata(d1).unwrap().is_dir()); + assert!(fs::metadata(canary).is_ok()); } #[test] @@ -583,8 +578,8 @@ fn recursive_rmdir_of_symlink() { check!(symlink_junction(&dir, &link)); check!(fs::remove_dir_all(&link)); - assert!(!link.is_dir()); - assert!(canary.exists()); + assert!(!fs::metadata(link).unwrap().is_dir()); + assert!(fs::metadata(canary).is_ok()); } #[test] @@ -608,34 +603,33 @@ fn recursive_rmdir_of_file_symlink() { #[test] fn unicode_path_is_dir() { - assert!(Path::new(".").is_dir()); - assert!(!Path::new("test/stdtest/fs.rs").is_dir()); + assert!(fs::metadata(Path::new(".")).unwrap().is_dir()); + assert!(!fs::metadata(Path::new("test/stdtest/fs.rs")).unwrap().is_dir()); let tmpdir = tmpdir(); let mut dirpath = tmpdir.path().to_path_buf(); dirpath.push("test-가一ー你好"); check!(fs::create_dir(&dirpath)); - assert!(dirpath.is_dir()); + assert!(fs::metadata(&dirpath).unwrap().is_dir()); let mut filepath = dirpath; filepath.push("unicode-file-\u{ac00}\u{4e00}\u{30fc}\u{4f60}\u{597d}.rs"); check!(File::create(&filepath)); // ignore return; touch only - assert!(!filepath.is_dir()); - assert!(filepath.exists()); + assert!(!fs::metadata(filepath).unwrap().is_dir()); } #[test] fn unicode_path_exists() { - assert!(Path::new(".").exists()); - assert!(!Path::new("test/nonexistent-bogus-path").exists()); + assert!(fs::metadata(Path::new(".")).is_ok()); + assert!(fs::metadata(Path::new("test/nonexistent-bogus-path")).is_err()); let tmpdir = tmpdir(); let unicode = tmpdir.path(); let unicode = unicode.join("test-각丁ー再见"); check!(fs::create_dir(&unicode)); - assert!(unicode.exists()); - assert!(!Path::new("test/unicode-bogus-path-각丁ー再见").exists()); + assert!(fs::metadata(unicode).is_ok()); + assert!(fs::metadata(Path::new("test/unicode-bogus-path-각丁ー再见")).is_err()); } #[test] @@ -646,8 +640,8 @@ fn copy_file_does_not_exist() { match fs::copy(&from, &to) { Ok(..) => panic!(), Err(..) => { - assert!(!from.exists()); - assert!(!to.exists()); + assert!(fs::metadata(from).is_err()); + assert!(fs::metadata(to).is_err()); } } } @@ -659,7 +653,7 @@ fn copy_src_does_not_exist() { let to = tmpdir.join("out.txt"); check!(check!(File::create(&to)).write(b"hello")); assert!(fs::copy(&from, &to).is_err()); - assert!(!from.exists()); + assert!(fs::metadata(from).is_err()); let mut v = Vec::new(); check!(check!(File::open(&to)).read_to_end(&mut v)); assert_eq!(v, b"hello"); @@ -677,7 +671,7 @@ fn copy_file_ok() { check!(check!(File::open(&out)).read_to_end(&mut v)); assert_eq!(v, b"hello"); - assert_eq!(check!(input.metadata()).permissions(), check!(out.metadata()).permissions()); + assert_eq!(check!(fs::metadata(input)).permissions(), check!(fs::metadata(out)).permissions()); } #[test] @@ -716,7 +710,7 @@ fn copy_file_src_dir() { Ok(..) => panic!(), Err(..) => {} } - assert!(!out.exists()); + assert!(fs::metadata(out).is_err()); } #[test] @@ -730,7 +724,7 @@ fn copy_file_preserves_perm_bits() { p.set_readonly(true); check!(fs::set_permissions(&input, p)); check!(fs::copy(&input, &out)); - assert!(check!(out.metadata()).permissions().readonly()); + assert!(check!(fs::metadata(&out)).permissions().readonly()); check!(fs::set_permissions(&input, attr.permissions())); check!(fs::set_permissions(&out, attr.permissions())); } @@ -741,7 +735,7 @@ fn copy_file_preserves_streams() { let tmp = tmpdir(); check!(check!(File::create(tmp.join("in.txt:bunny"))).write("carrot".as_bytes())); assert_eq!(check!(fs::copy(tmp.join("in.txt"), tmp.join("out.txt"))), 0); - assert_eq!(check!(tmp.join("out.txt").metadata()).len(), 0); + assert_eq!(check!(fs::metadata(tmp.join("out.txt"))).len(), 0); let mut v = Vec::new(); check!(check!(File::open(tmp.join("out.txt:bunny"))).read_to_end(&mut v)); assert_eq!(v, b"carrot".to_vec()); @@ -756,7 +750,7 @@ fn copy_file_returns_metadata_len() { #[cfg(windows)] check!(check!(File::create(tmp.join("in.txt:bunny"))).write(b"carrot")); let copied_len = check!(fs::copy(&in_path, &out_path)); - assert_eq!(check!(out_path.metadata()).len(), copied_len); + assert_eq!(check!(fs::metadata(out_path)).len(), copied_len); } #[test] @@ -776,7 +770,7 @@ fn copy_file_follows_dst_symlink() { check!(fs::copy(&in_path, &out_path_symlink)); - assert!(check!(out_path_symlink.symlink_metadata()).file_type().is_symlink()); + assert!(check!(fs::symlink_metadata(&out_path_symlink)).file_type().is_symlink()); assert_eq!(check!(fs::read(&out_path_symlink)), b"foo".to_vec()); assert_eq!(check!(fs::read(&out_path)), b"foo".to_vec()); } @@ -793,7 +787,7 @@ fn symlinks_work() { check!(check!(File::create(&input)).write("foobar".as_bytes())); check!(symlink_file(&input, &out)); - assert!(check!(out.symlink_metadata()).file_type().is_symlink()); + assert!(check!(fs::symlink_metadata(&out)).file_type().is_symlink()); assert_eq!(check!(fs::metadata(&out)).len(), check!(fs::metadata(&input)).len()); let mut v = Vec::new(); check!(check!(File::open(&out)).read_to_end(&mut v)); @@ -860,7 +854,6 @@ fn links_work() { check!(check!(File::create(&input)).write("foobar".as_bytes())); check!(fs::hard_link(&input, &out)); assert_eq!(check!(fs::metadata(&out)).len(), check!(fs::metadata(&input)).len()); - assert_eq!(check!(fs::metadata(&out)).len(), check!(input.metadata()).len()); let mut v = Vec::new(); check!(check!(File::open(&out)).read_to_end(&mut v)); assert_eq!(v, b"foobar".to_vec()); @@ -1196,7 +1189,7 @@ fn realpath_works() { symlink_file(&file, &link).unwrap(); symlink_dir(&dir, &linkdir).unwrap(); - assert!(link.symlink_metadata().unwrap().file_type().is_symlink()); + assert!(fs::symlink_metadata(&link).unwrap().file_type().is_symlink()); assert_eq!(fs::canonicalize(&tmpdir).unwrap(), tmpdir); assert_eq!(fs::canonicalize(&file).unwrap(), file); @@ -1243,7 +1236,7 @@ fn dir_entry_methods() { fs::create_dir_all(&tmpdir.join("a")).unwrap(); File::create(&tmpdir.join("b")).unwrap(); - for file in tmpdir.path().read_dir().unwrap().map(|f| f.unwrap()) { + for file in fs::read_dir(tmpdir.path()).unwrap().map(|f| f.unwrap()) { let fname = file.file_name(); match fname.to_str() { Some("a") => { @@ -1263,7 +1256,7 @@ fn dir_entry_methods() { fn dir_entry_debug() { let tmpdir = tmpdir(); File::create(&tmpdir.join("b")).unwrap(); - let mut read_dir = tmpdir.path().read_dir().unwrap(); + let mut read_dir = fs::read_dir(tmpdir.path()).unwrap(); let dir_entry = read_dir.next().unwrap().unwrap(); let actual = format!("{:?}", dir_entry); let expected = format!("DirEntry({:?})", dir_entry.0.path()); @@ -1293,16 +1286,16 @@ fn create_dir_all_with_junctions() { check!(fs::create_dir_all(&b)); // the junction itself is not a directory, but `is_dir()` on a Path // follows links - assert!(junction.is_dir()); - assert!(b.exists()); + assert!(fs::metadata(junction).unwrap().is_dir()); + assert!(fs::metadata(b).is_ok()); if !got_symlink_permission(&tmpdir) { return; }; check!(symlink_dir(&target, &link)); check!(fs::create_dir_all(&d)); - assert!(link.is_dir()); - assert!(d.exists()); + assert!(fs::metadata(link).unwrap().is_dir()); + assert!(fs::metadata(d).is_ok()); } #[test] diff --git a/src/build_helper/lib.rs b/src/build_helper/lib.rs index 80f804174ed08..80406881d62da 100644 --- a/src/build_helper/lib.rs +++ b/src/build_helper/lib.rs @@ -146,8 +146,7 @@ pub fn output(cmd: &mut Command) -> String { } pub fn rerun_if_changed_anything_in_dir(dir: &Path) { - let mut stack = dir - .read_dir() + let mut stack = fs::read_dir(dir) .unwrap() .map(|e| e.unwrap()) .filter(|e| &*e.file_name() != ".git") @@ -155,7 +154,7 @@ pub fn rerun_if_changed_anything_in_dir(dir: &Path) { while let Some(entry) = stack.pop() { let path = entry.path(); if entry.file_type().unwrap().is_dir() { - stack.extend(path.read_dir().unwrap().map(|e| e.unwrap())); + stack.extend(fs::read_dir(path).unwrap().map(|e| e.unwrap())); } else { println!("cargo:rerun-if-changed={}", path.display()); } @@ -172,7 +171,7 @@ pub fn mtime(path: &Path) -> SystemTime { /// /// Uses last-modified time checks to verify this. pub fn up_to_date(src: &Path, dst: &Path) -> bool { - if !dst.exists() { + if fs::metadata(dst).is_err() { return false; } let threshold = mtime(dst); diff --git a/src/test/ui-fulldeps/mod_dir_path_canonicalized.rs b/src/test/ui-fulldeps/mod_dir_path_canonicalized.rs index 448c57da754a0..23e6d6ca4c383 100644 --- a/src/test/ui-fulldeps/mod_dir_path_canonicalized.rs +++ b/src/test/ui-fulldeps/mod_dir_path_canonicalized.rs @@ -13,6 +13,7 @@ extern crate rustc_span; use rustc_parse::new_parser_from_file; use rustc_session::parse::ParseSess; use rustc_span::source_map::FilePathMapping; +use std::fs; use std::path::Path; #[path = "mod_dir_simple/test.rs"] @@ -28,7 +29,7 @@ fn parse() { let parse_session = ParseSess::new(FilePathMapping::empty()); let path = Path::new(file!()); - let path = path.canonicalize().unwrap(); + let path = fs::canonicalize(path).unwrap(); let mut parser = new_parser_from_file(&parse_session, &path, None); let _ = parser.parse_crate_mod(); } diff --git a/src/test/ui-fulldeps/rename-directory.rs b/src/test/ui-fulldeps/rename-directory.rs index 8fc340cb91872..26bd8d13b67be 100644 --- a/src/test/ui-fulldeps/rename-directory.rs +++ b/src/test/ui-fulldeps/rename-directory.rs @@ -23,8 +23,8 @@ fn rename_directory() { let new_path = tmpdir.join("quux/blat"); fs::create_dir_all(&new_path).unwrap(); fs::rename(&old_path, &new_path.join("newdir")); - assert!(new_path.join("newdir").is_dir()); - assert!(new_path.join("newdir/temp.txt").exists()); + assert!(fs::metadata(new_path.join("newdir")).map(|m| m.is_dir()).unwrap_or(false)); + assert!(fs::metadata(new_path.join("newdir/temp.txt")).is_ok()); } pub fn main() { rename_directory() } From e33dbc0c2df38fb287c5f53b2c8285bee9c860d8 Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Wed, 6 Jan 2021 00:26:48 -0800 Subject: [PATCH 7/9] Simplify this code to call `metadata` once. --- src/build_helper/lib.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/build_helper/lib.rs b/src/build_helper/lib.rs index 80406881d62da..cd4dac6489689 100644 --- a/src/build_helper/lib.rs +++ b/src/build_helper/lib.rs @@ -171,10 +171,11 @@ pub fn mtime(path: &Path) -> SystemTime { /// /// Uses last-modified time checks to verify this. pub fn up_to_date(src: &Path, dst: &Path) -> bool { - if fs::metadata(dst).is_err() { - return false; - } - let threshold = mtime(dst); + let dst_meta = match fs::metadata(dst) { + Ok(meta) => meta, + Err(_) => return false, + }; + let threshold = dst_meta.modified().unwrap_or(UNIX_EPOCH); let meta = match fs::metadata(src) { Ok(meta) => meta, Err(e) => panic!("source {:?} failed to get metadata: {}", src, e), From 5dfd1c105b4587eb7fefa22877c9a20dccd68ab3 Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Wed, 6 Jan 2021 02:08:53 -0800 Subject: [PATCH 8/9] Optimize away another path lookup. --- library/std/src/sys_common/fs.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/std/src/sys_common/fs.rs b/library/std/src/sys_common/fs.rs index 54fbf68c9cb5a..5b0c960f2a437 100644 --- a/library/std/src/sys_common/fs.rs +++ b/library/std/src/sys_common/fs.rs @@ -19,7 +19,7 @@ pub fn copy(from: &Path, to: &Path) -> io::Result { let perm = reader.metadata()?.permissions(); let ret = io::copy(&mut reader, &mut writer)?; - fs::set_permissions(to, perm)?; + writer.set_permissions(perm)?; Ok(ret) } From b7aae1b68e0556a5d840cdcfc00459da030ca3af Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Wed, 6 Jan 2021 02:53:24 -0800 Subject: [PATCH 9/9] Provide convenience functions `exists`, `is_file`, and `is_dir`, in `fs`. --- compiler/rustc_codegen_llvm/src/back/lto.rs | 7 +- .../rustc_codegen_ssa/src/back/archive.rs | 4 +- compiler/rustc_codegen_ssa/src/back/link.rs | 12 +-- compiler/rustc_codegen_ssa/src/back/linker.rs | 2 +- .../rustc_incremental/src/persist/load.rs | 2 +- .../rustc_incremental/src/persist/save.rs | 4 +- compiler/rustc_interface/src/passes.rs | 4 +- compiler/rustc_interface/src/util.rs | 4 +- compiler/rustc_llvm/build.rs | 2 +- compiler/rustc_metadata/src/locator.rs | 4 +- compiler/rustc_session/src/filesearch.rs | 2 +- compiler/rustc_session/src/session.rs | 2 +- compiler/rustc_span/src/source_map.rs | 2 +- compiler/rustc_target/src/spec/mod.rs | 4 +- library/std/src/fs.rs | 92 ++++++++++++++++++- library/std/src/fs/tests.rs | 54 +++++------ library/std/src/path.rs | 18 ++-- library/std/src/sys/windows/process.rs | 2 +- library/term/src/terminfo/searcher.rs | 6 +- src/test/ui-fulldeps/rename-directory.rs | 4 +- 20 files changed, 158 insertions(+), 73 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/back/lto.rs b/compiler/rustc_codegen_llvm/src/back/lto.rs index 9ccfb781b9f16..ec36c642733fb 100644 --- a/compiler/rustc_codegen_llvm/src/back/lto.rs +++ b/compiler/rustc_codegen_llvm/src/back/lto.rs @@ -496,11 +496,8 @@ fn thin_lto( // If the previous file was deleted, or we get an IO error // reading the file, then we'll just use `None` as the // prev_key_map, which will force the code to be recompiled. - let prev = if fs::metadata(&path).is_ok() { - ThinLTOKeysMap::load_from_file(&path).ok() - } else { - None - }; + let prev = + if fs::exists(&path) { ThinLTOKeysMap::load_from_file(&path).ok() } else { None }; let curr = ThinLTOKeysMap::from_thin_lto_modules(&data, &thin_modules, &module_names); (Some(path), prev, curr) } else { diff --git a/compiler/rustc_codegen_ssa/src/back/archive.rs b/compiler/rustc_codegen_ssa/src/back/archive.rs index 73465e2196444..50519e93bf6e4 100644 --- a/compiler/rustc_codegen_ssa/src/back/archive.rs +++ b/compiler/rustc_codegen_ssa/src/back/archive.rs @@ -15,12 +15,12 @@ pub fn find_library(name: Symbol, search_paths: &[PathBuf], sess: &Session) -> P for path in search_paths { debug!("looking for {} inside {:?}", name, path); let test = path.join(&oslibname); - if fs::metadata(&test).is_ok() { + if fs::exists(&test) { return test; } if oslibname != unixlibname { let test = path.join(&unixlibname); - if fs::metadata(&test).is_ok() { + if fs::exists(&test) { return test; } } diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index 6b765334e0f76..0cd126996b4d2 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -1110,19 +1110,19 @@ fn print_native_static_libs(sess: &Session, all_native_libs: &[NativeLib]) { fn get_object_file_path(sess: &Session, name: &str, self_contained: bool) -> PathBuf { let fs = sess.target_filesearch(PathKind::Native); let file_path = fs.get_lib_path().join(name); - if fs::metadata(&file_path).is_ok() { + if fs::exists(&file_path) { return file_path; } // Special directory with objects used only in self-contained linkage mode if self_contained { let file_path = fs.get_self_contained_lib_path().join(name); - if fs::metadata(&file_path).is_ok() { + if fs::exists(&file_path) { return file_path; } } for search_path in fs.search_paths() { let file_path = search_path.dir.join(name); - if fs::metadata(&file_path).is_ok() { + if fs::exists(&file_path) { return file_path; } } @@ -1312,9 +1312,7 @@ fn detect_self_contained_mingw(sess: &Session) -> bool { for dir in env::split_paths(&env::var_os("PATH").unwrap_or_default()) { let full_path = dir.join(&linker_with_extension); // If linker comes from sysroot assume self-contained mode - if fs::metadata(&full_path).map(|m| m.is_file()).unwrap_or(false) - && !full_path.starts_with(&sess.sysroot) - { + if fs::is_file(&full_path) && !full_path.starts_with(&sess.sysroot) { return false; } } @@ -2230,7 +2228,7 @@ fn get_apple_sdk_root(sdk_name: &str) -> Result { if sdkroot.contains("iPhoneOS.platform") || sdkroot.contains("iPhoneSimulator.platform") => {} // Ignore `SDKROOT` if it's not a valid path. - _ if !p.is_absolute() || p == Path::new("/") || fs::metadata(p).is_err() => {} + _ if !p.is_absolute() || p == Path::new("/") || !fs::exists(p) => {} _ => return Ok(sdkroot), } } diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs index 3df956c465e5e..a3cc116c29318 100644 --- a/compiler/rustc_codegen_ssa/src/back/linker.rs +++ b/compiler/rustc_codegen_ssa/src/back/linker.rs @@ -695,7 +695,7 @@ impl<'a> Linker for MsvcLinker<'a> { // check to see if the file is there and just omit linking to it if it's // not present. let name = format!("{}.dll.lib", lib); - if fs::metadata(&path.join(&name)).is_ok() { + if fs::exists(&path.join(&name)) { self.cmd.arg(name); } } diff --git a/compiler/rustc_incremental/src/persist/load.rs b/compiler/rustc_incremental/src/persist/load.rs index ba2be6c4917f0..c6319599b5692 100644 --- a/compiler/rustc_incremental/src/persist/load.rs +++ b/compiler/rustc_incremental/src/persist/load.rs @@ -143,7 +143,7 @@ pub fn load_dep_graph(sess: &Session) -> DepGraphFuture { let mut all_files_exist = true; if let Some(ref file_name) = swp.work_product.saved_file { let path = in_incr_comp_dir_sess(sess, file_name); - if fs::metadata(&path).is_err() { + if !fs::exists(&path) { all_files_exist = false; if sess.opts.debugging_opts.incremental_info { diff --git a/compiler/rustc_incremental/src/persist/save.rs b/compiler/rustc_incremental/src/persist/save.rs index 4a1f0fd3d081d..1d2219af42db0 100644 --- a/compiler/rustc_incremental/src/persist/save.rs +++ b/compiler/rustc_incremental/src/persist/save.rs @@ -74,7 +74,7 @@ pub fn save_work_product_index( if !new_work_products.contains_key(id) { work_product::delete_workproduct_files(sess, wp); debug_assert!(wp.saved_file.as_ref().map_or(true, |file_name| { - fs::metadata(in_incr_comp_dir_sess(sess, &file_name)).is_err() + !fs::exists(in_incr_comp_dir_sess(sess, &file_name)) })); } } @@ -85,7 +85,7 @@ pub fn save_work_product_index( .iter() .flat_map(|(_, wp)| wp.saved_file.iter()) .map(|name| in_incr_comp_dir_sess(sess, name)) - .all(|path| fs::metadata(path).is_ok()) + .all(|path| fs::exists(path)) }); } diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index 8997aff631585..4994d62fd3389 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -517,9 +517,7 @@ fn output_contains_path(output_paths: &[PathBuf], input_path: &PathBuf) -> bool } fn output_conflicts_with_dir(output_paths: &[PathBuf]) -> Option { - let check = |output_path: &PathBuf| { - fs::metadata(output_path).map(|m| m.is_dir()).unwrap_or(false).then(|| output_path.clone()) - }; + let check = |output_path: &PathBuf| fs::is_dir(output_path).then(|| output_path.clone()); check_output(output_paths, check) } diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs index dadaa5a823ede..533534aa57285 100644 --- a/compiler/rustc_interface/src/util.rs +++ b/compiler/rustc_interface/src/util.rs @@ -270,7 +270,7 @@ fn get_rustc_path_inner(bin_path: &str) -> Option { } else { "rustc" }); - fs::metadata(&candidate).is_ok().then_some(candidate) + fs::exists(&candidate).then_some(candidate) }) } @@ -398,7 +398,7 @@ pub fn get_codegen_sysroot(backend_name: &str) -> fn() -> Box CrateLocator<'a> { let mut rmetas = FxHashMap::default(); let mut dylibs = FxHashMap::default(); for loc in &self.exact_paths { - if fs::metadata(loc).is_err() { + if !fs::exists(loc) { return Err(CrateError::ExternLocationNotExist(self.crate_name, loc.clone())); } let file = match loc.file_name().and_then(|s| s.to_str()) { @@ -738,7 +738,7 @@ fn get_metadata_section( filename: &Path, loader: &dyn MetadataLoader, ) -> Result { - if fs::metadata(filename).is_err() { + if !fs::exists(filename) { return Err(format!("no such file: '{}'", filename.display())); } let raw_bytes: MetadataRef = match flavor { diff --git a/compiler/rustc_session/src/filesearch.rs b/compiler/rustc_session/src/filesearch.rs index 1756720964c1d..f1eb464f7eb57 100644 --- a/compiler/rustc_session/src/filesearch.rs +++ b/compiler/rustc_session/src/filesearch.rs @@ -154,7 +154,7 @@ fn find_libdir(sysroot: &Path) -> Cow<'static, str> { match option_env!("CFG_LIBDIR_RELATIVE") { None | Some("lib") => { - if fs::metadata(sysroot.join(PRIMARY_LIB_DIR).join(RUST_LIB_DIR)).is_ok() { + if fs::exists(sysroot.join(PRIMARY_LIB_DIR).join(RUST_LIB_DIR)) { PRIMARY_LIB_DIR.into() } else { SECONDARY_LIB_DIR.into() diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index 38c65ad684ca5..d2ea09b96287d 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -1485,7 +1485,7 @@ fn validate_commandline_args_with_session_available(sess: &Session) { // Make sure that any given profiling data actually exists so LLVM can't // decide to silently skip PGO. if let Some(ref path) = sess.opts.cg.profile_use { - if fs::metadata(path).is_err() { + if !fs::exists(path) { sess.err(&format!( "File `{}` passed to `-C profile-use` does not exist.", path.display() diff --git a/compiler/rustc_span/src/source_map.rs b/compiler/rustc_span/src/source_map.rs index fefc0cb48ddd8..7fa9b59c096f7 100644 --- a/compiler/rustc_span/src/source_map.rs +++ b/compiler/rustc_span/src/source_map.rs @@ -109,7 +109,7 @@ pub struct RealFileLoader; impl FileLoader for RealFileLoader { fn file_exists(&self, path: &Path) -> bool { - fs::metadata(path).is_ok() + fs::exists(path) } fn read_file(&self, path: &Path) -> io::Result { diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index 48780edd23368..920b3590bc1a1 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -1600,14 +1600,14 @@ impl Target { for dir in env::split_paths(&target_path) { let p = dir.join(&path); - if fs::metadata(&p).map(|m| m.is_file()).unwrap_or(false) { + if fs::is_file(&p) { return load_file(&p); } } Err(format!("Could not find specification for target {:?}", target_triple)) } TargetTriple::TargetPath(ref target_path) => { - if fs::metadata(target_path).map(|m| m.is_file()).unwrap_or(false) { + if fs::is_file(target_path) { return load_file(&target_path); } Err(format!("Target path {:?} is not a valid file", target_path)) diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs index 58c01325e7064..00e8e2a6dfdf9 100644 --- a/library/std/src/fs.rs +++ b/library/std/src/fs.rs @@ -2108,6 +2108,92 @@ pub fn set_permissions>(path: P, perm: Permissions) -> io::Result fs_imp::set_perm(path.as_ref(), perm.0) } +/// Returns `true` if the path points at an existing entity. +/// +/// This function will traverse symbolic links to query information about the +/// destination file. In case of broken symbolic links this will return `false`. +/// +/// If you cannot access the directory containing the file, e.g., because of a +/// permission error, this will return `false`. +/// +/// # Examples +/// +/// ```no_run +/// use std::path::Path; +/// assert!(!Path::new("does_not_exist.txt").exists()); +/// ``` +/// +/// # See Also +/// +/// This is a convenience function that coerces errors to false. If you want to +/// check errors, call [`metadata`]. +#[stable(feature = "fs_path_convenience", since = "1.51.0")] +pub fn exists>(path: P) -> bool { + metadata(path).is_ok() +} + +/// Returns `true` if the path exists on disk and is pointing at a regular file. +/// +/// This function will traverse symbolic links to query information about the +/// destination file. In case of broken symbolic links this will return `false`. +/// +/// If you cannot access the directory containing the file, e.g., because of a +/// permission error, this will return `false`. +/// +/// # Examples +/// +/// ```no_run +/// use std::path::Path; +/// assert_eq!(Path::new("./is_a_directory/").is_file(), false); +/// assert_eq!(Path::new("a_file.txt").is_file(), true); +/// ``` +/// +/// # See Also +/// +/// This is a convenience function that coerces errors to false. If you want to +/// check errors, call [`metadata`] and handle its [`Result`]. Then call +/// [`Metadata::is_file`] if it was [`Ok`]. +/// +/// When the goal is simply to read from (or write to) the source, the most +/// reliable way to test the source can be read (or written to) is to open +/// it. Only using `is_file` can break workflows like `diff <( prog_a )` on +/// a Unix-like system for example. See [`File::open`] or +/// [`OpenOptions::open`] for more information. +#[stable(feature = "fs_path_convenience", since = "1.51.0")] +pub fn is_file>(path: P) -> bool { + metadata(path).map(|m| m.is_file()).unwrap_or(false) +} + +/// Returns `true` if the path exists on disk and is pointing at a directory. +/// +/// This function will traverse symbolic links to query information about the +/// destination file. In case of broken symbolic links this will return `false`. +/// +/// If you cannot access the directory containing the file, e.g., because of a +/// permission error, this will return `false`. +/// +/// # Examples +/// +/// ```no_run +/// use std::path::Path; +/// assert_eq!(Path::new("./is_a_directory/").is_dir(), true); +/// assert_eq!(Path::new("a_file.txt").is_dir(), false); +/// ``` +/// +/// # See Also +/// +/// This is a convenience function that coerces errors to false. If you want to +/// check errors, call [`metadata`] and handle its [`Result`]. Then call +/// [`Metadata::is_dir`] if it was [`Ok`]. +/// +/// When the goal is simply to read from the source, the most reliable way to +/// test the source can be read is to open it. See [`read_dir`] for more +/// information. +#[stable(feature = "fs_path_convenience", since = "1.51.0")] +pub fn is_dir>(path: P) -> bool { + metadata(path).map(|m| m.is_dir()).unwrap_or(false) +} + impl DirBuilder { /// Creates a new set of options with default mode/security settings for all /// platforms and also non-recursive. @@ -2160,7 +2246,7 @@ impl DirBuilder { /// .recursive(true) /// .create(path).unwrap(); /// - /// assert!(fs::metadata(path).unwrap().is_dir()); + /// assert!(fs::is_dir(path)); /// ``` #[stable(feature = "dir_builder", since = "1.6.0")] pub fn create>(&self, path: P) -> io::Result<()> { @@ -2179,7 +2265,7 @@ impl DirBuilder { match self.inner.mkdir(path) { Ok(()) => return Ok(()), Err(ref e) if e.kind() == io::ErrorKind::NotFound => {} - Err(_) if metadata(path).map(|m| m.is_dir()).unwrap_or(false) => return Ok(()), + Err(_) if is_dir(path) => return Ok(()), Err(e) => return Err(e), } match path.parent() { @@ -2190,7 +2276,7 @@ impl DirBuilder { } match self.inner.mkdir(path) { Ok(()) => Ok(()), - Err(_) if metadata(path).map(|m| m.is_dir()).unwrap_or(false) => Ok(()), + Err(_) if is_dir(path) => Ok(()), Err(e) => Err(e), } } diff --git a/library/std/src/fs/tests.rs b/library/std/src/fs/tests.rs index 4dfaf35b671a5..34eda393dbae5 100644 --- a/library/std/src/fs/tests.rs +++ b/library/std/src/fs/tests.rs @@ -417,7 +417,7 @@ fn file_test_fileinfo_false_when_checking_is_file_on_a_directory() { let tmpdir = tmpdir(); let dir = &tmpdir.join("fileinfo_false_on_dir"); check!(fs::create_dir(dir)); - assert!(!fs::metadata(dir).unwrap().is_file()); + assert!(!fs::is_file(dir)); check!(fs::remove_dir(dir)); } @@ -426,20 +426,20 @@ fn file_test_fileinfo_check_exists_before_and_after_file_creation() { let tmpdir = tmpdir(); let file = &tmpdir.join("fileinfo_check_exists_b_and_a.txt"); check!(check!(File::create(file)).write(b"foo")); - assert!(fs::metadata(file).is_ok()); + assert!(fs::exists(file)); check!(fs::remove_file(file)); - assert!(fs::metadata(file).is_err()); + assert!(!fs::exists(file)); } #[test] fn file_test_directoryinfo_check_exists_before_and_after_mkdir() { let tmpdir = tmpdir(); let dir = &tmpdir.join("before_and_after_dir"); - assert!(fs::metadata(dir).is_err()); + assert!(!fs::exists(dir)); check!(fs::create_dir(dir)); - assert!(fs::metadata(dir).unwrap().is_dir()); + assert!(fs::is_dir(dir)); check!(fs::remove_dir(dir)); - assert!(fs::metadata(dir).is_err()); + assert!(!fs::exists(dir)); } #[test] @@ -494,7 +494,7 @@ fn recursive_mkdir() { let tmpdir = tmpdir(); let dir = tmpdir.join("d1/d2"); check!(fs::create_dir_all(&dir)); - assert!(fs::metadata(dir).unwrap().is_dir()); + assert!(fs::is_dir(dir)); } #[test] @@ -562,8 +562,8 @@ fn recursive_rmdir() { let _ = symlink_file(&canary, &d1.join("canary")); check!(fs::remove_dir_all(&d1)); - assert!(!fs::metadata(d1).unwrap().is_dir()); - assert!(fs::metadata(canary).is_ok()); + assert!(!fs::is_dir(d1)); + assert!(fs::exists(canary)); } #[test] @@ -578,8 +578,8 @@ fn recursive_rmdir_of_symlink() { check!(symlink_junction(&dir, &link)); check!(fs::remove_dir_all(&link)); - assert!(!fs::metadata(link).unwrap().is_dir()); - assert!(fs::metadata(canary).is_ok()); + assert!(!fs::is_dir(link)); + assert!(fs::exists(canary)); } #[test] @@ -603,33 +603,33 @@ fn recursive_rmdir_of_file_symlink() { #[test] fn unicode_path_is_dir() { - assert!(fs::metadata(Path::new(".")).unwrap().is_dir()); - assert!(!fs::metadata(Path::new("test/stdtest/fs.rs")).unwrap().is_dir()); + assert!(fs::is_dir(Path::new("."))); + assert!(!fs::is_dir(Path::new("test/stdtest/fs.rs"))); let tmpdir = tmpdir(); let mut dirpath = tmpdir.path().to_path_buf(); dirpath.push("test-가一ー你好"); check!(fs::create_dir(&dirpath)); - assert!(fs::metadata(&dirpath).unwrap().is_dir()); + assert!(fs::is_dir(&dirpath)); let mut filepath = dirpath; filepath.push("unicode-file-\u{ac00}\u{4e00}\u{30fc}\u{4f60}\u{597d}.rs"); check!(File::create(&filepath)); // ignore return; touch only - assert!(!fs::metadata(filepath).unwrap().is_dir()); + assert!(!fs::is_dir(filepath)); } #[test] fn unicode_path_exists() { - assert!(fs::metadata(Path::new(".")).is_ok()); - assert!(fs::metadata(Path::new("test/nonexistent-bogus-path")).is_err()); + assert!(fs::exists(Path::new("."))); + assert!(!fs::exists(Path::new("test/nonexistent-bogus-path"))); let tmpdir = tmpdir(); let unicode = tmpdir.path(); let unicode = unicode.join("test-각丁ー再见"); check!(fs::create_dir(&unicode)); - assert!(fs::metadata(unicode).is_ok()); - assert!(fs::metadata(Path::new("test/unicode-bogus-path-각丁ー再见")).is_err()); + assert!(fs::exists(unicode)); + assert!(!fs::exists(Path::new("test/unicode-bogus-path-각丁ー再见"))); } #[test] @@ -640,8 +640,8 @@ fn copy_file_does_not_exist() { match fs::copy(&from, &to) { Ok(..) => panic!(), Err(..) => { - assert!(fs::metadata(from).is_err()); - assert!(fs::metadata(to).is_err()); + assert!(!fs::exists(from)); + assert!(!fs::exists(to)); } } } @@ -653,7 +653,7 @@ fn copy_src_does_not_exist() { let to = tmpdir.join("out.txt"); check!(check!(File::create(&to)).write(b"hello")); assert!(fs::copy(&from, &to).is_err()); - assert!(fs::metadata(from).is_err()); + assert!(!fs::exists(from)); let mut v = Vec::new(); check!(check!(File::open(&to)).read_to_end(&mut v)); assert_eq!(v, b"hello"); @@ -710,7 +710,7 @@ fn copy_file_src_dir() { Ok(..) => panic!(), Err(..) => {} } - assert!(fs::metadata(out).is_err()); + assert!(!fs::exists(out)); } #[test] @@ -1286,16 +1286,16 @@ fn create_dir_all_with_junctions() { check!(fs::create_dir_all(&b)); // the junction itself is not a directory, but `is_dir()` on a Path // follows links - assert!(fs::metadata(junction).unwrap().is_dir()); - assert!(fs::metadata(b).is_ok()); + assert!(fs::is_dir(junction)); + assert!(fs::exists(b)); if !got_symlink_permission(&tmpdir) { return; }; check!(symlink_dir(&target, &link)); check!(fs::create_dir_all(&d)); - assert!(fs::metadata(link).unwrap().is_dir()); - assert!(fs::metadata(d).is_ok()); + assert!(fs::is_dir(link)); + assert!(fs::exists(d)); } #[test] diff --git a/library/std/src/path.rs b/library/std/src/path.rs index 38a2b2bdfa4b2..522802d49ea2d 100644 --- a/library/std/src/path.rs +++ b/library/std/src/path.rs @@ -2419,6 +2419,8 @@ impl Path { /// If you cannot access the directory containing the file, e.g., because of a /// permission error, this will return `false`. /// + /// This is an alias to [`fs::exists`]. + /// /// # Examples /// /// ```no_run @@ -2434,10 +2436,10 @@ impl Path { #[rustc_deprecated( since = "1.51.0", reason = "other processes may remove or rename files at any time", - suggestion = "use `std::fs::metadata`" + suggestion = "use `std::fs::exists`" )] pub fn exists(&self) -> bool { - fs::metadata(self).is_ok() + fs::exists(self) } /// Returns `true` if the path exists on disk and is pointing at a regular file. @@ -2456,6 +2458,8 @@ impl Path { /// assert_eq!(Path::new("a_file.txt").is_file(), true); /// ``` /// + /// This is an alias to [`fs::is_file`]. + /// /// # See Also /// /// This is a convenience function that coerces errors to false. If you want to @@ -2471,10 +2475,10 @@ impl Path { #[rustc_deprecated( since = "1.51.0", reason = "other processes may remove, rename, or replace files at any time", - suggestion = "use `std::fs::File::open` or `std::fs::metadata`" + suggestion = "use `std::fs::File::open` or `std::fs::is_file`" )] pub fn is_file(&self) -> bool { - fs::metadata(self).map(|m| m.is_file()).unwrap_or(false) + fs::is_file(self) } /// Returns `true` if the path exists on disk and is pointing at a directory. @@ -2485,6 +2489,8 @@ impl Path { /// If you cannot access the directory containing the file, e.g., because of a /// permission error, this will return `false`. /// + /// This is an alias to [`fs::is_dir`]. + /// /// # Examples /// /// ```no_run @@ -2506,10 +2512,10 @@ impl Path { #[rustc_deprecated( since = "1.51.0", reason = "other processes may remove, rename, or replace directories at any time", - suggestion = "use `std::fs::read_dir` or `std::fs::metadata`" + suggestion = "use `std::fs::read_dir` or `std::fs::is_dir`" )] pub fn is_dir(&self) -> bool { - fs::metadata(self).map(|m| m.is_dir()).unwrap_or(false) + fs::is_dir(self) } /// Converts a [`Box`](Box) into a [`PathBuf`] without copying or diff --git a/library/std/src/sys/windows/process.rs b/library/std/src/sys/windows/process.rs index 243065b94b125..deca416915792 100644 --- a/library/std/src/sys/windows/process.rs +++ b/library/std/src/sys/windows/process.rs @@ -168,7 +168,7 @@ impl Command { let path = path .join(self.program.to_str().unwrap()) .with_extension(env::consts::EXE_EXTENSION); - if fs::metadata(&path).is_ok() { + if fs::exists(&path) { return Some(path.into_os_string()); } } diff --git a/library/term/src/terminfo/searcher.rs b/library/term/src/terminfo/searcher.rs index 5499e240e66e5..d45f76429ad60 100644 --- a/library/term/src/terminfo/searcher.rs +++ b/library/term/src/terminfo/searcher.rs @@ -47,10 +47,10 @@ pub fn get_dbpath_for_term(term: &str) -> Option { // Look for the terminal in all of the search directories for mut p in dirs_to_search { - if fs::metadata(&p).is_ok() { + if fs::exists(&p) { p.push(&first_char.to_string()); p.push(&term); - if fs::metadata(&p).is_ok() { + if fs::exists(&p) { return Some(p); } p.pop(); @@ -60,7 +60,7 @@ pub fn get_dbpath_for_term(term: &str) -> Option { // (e.g., macOS) p.push(&format!("{:x}", first_char as usize)); p.push(term); - if fs::metadata(&p).is_ok() { + if fs::exists(&p) { return Some(p); } } diff --git a/src/test/ui-fulldeps/rename-directory.rs b/src/test/ui-fulldeps/rename-directory.rs index 26bd8d13b67be..c06068d4b24bc 100644 --- a/src/test/ui-fulldeps/rename-directory.rs +++ b/src/test/ui-fulldeps/rename-directory.rs @@ -23,8 +23,8 @@ fn rename_directory() { let new_path = tmpdir.join("quux/blat"); fs::create_dir_all(&new_path).unwrap(); fs::rename(&old_path, &new_path.join("newdir")); - assert!(fs::metadata(new_path.join("newdir")).map(|m| m.is_dir()).unwrap_or(false)); - assert!(fs::metadata(new_path.join("newdir/temp.txt")).is_ok()); + assert!(fs::is_dir(new_path.join("newdir"))); + assert!(fs::exists(new_path.join("newdir/temp.txt"))); } pub fn main() { rename_directory() }