mirror of
https://github.com/tokio-rs/tokio.git
synced 2026-08-28 00:00:11 +02:00
fs: add fs::try_exists (#4299)
This commit is contained in:
@@ -102,6 +102,9 @@ pub use self::write::write;
|
|||||||
mod copy;
|
mod copy;
|
||||||
pub use self::copy::copy;
|
pub use self::copy::copy;
|
||||||
|
|
||||||
|
mod try_exists;
|
||||||
|
pub use self::try_exists::try_exists;
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod mocks;
|
mod mocks;
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,34 @@
|
|||||||
|
use crate::fs::asyncify;
|
||||||
|
|
||||||
|
use std::io;
|
||||||
|
use std::path::Path;
|
||||||
|
|
||||||
|
/// Returns `Ok(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 `Ok(false)`.
|
||||||
|
///
|
||||||
|
/// This is the async equivalent of [`std::path::Path::try_exists`][std].
|
||||||
|
///
|
||||||
|
/// [std]: fn@std::path::Path::try_exists
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```no_run
|
||||||
|
/// use tokio::fs;
|
||||||
|
///
|
||||||
|
/// # async fn dox() -> std::io::Result<()> {
|
||||||
|
/// fs::try_exists("foo.txt").await?;
|
||||||
|
/// # Ok(())
|
||||||
|
/// # }
|
||||||
|
/// ```
|
||||||
|
pub async fn try_exists(path: impl AsRef<Path>) -> io::Result<bool> {
|
||||||
|
let path = path.as_ref().to_owned();
|
||||||
|
// std's Path::try_exists is not available for current Rust min supported version.
|
||||||
|
// Current implementation is based on its internal implementation instead.
|
||||||
|
match asyncify(move || std::fs::metadata(path)).await {
|
||||||
|
Ok(_) => Ok(true),
|
||||||
|
Err(error) if error.kind() == std::io::ErrorKind::NotFound => Ok(false),
|
||||||
|
Err(error) => Err(error),
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
#![warn(rust_2018_idioms)]
|
||||||
|
#![cfg(all(feature = "full", not(tokio_wasi)))] // Wasi does not support file operations
|
||||||
|
|
||||||
|
use tempfile::tempdir;
|
||||||
|
use tokio::fs;
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn try_exists() {
|
||||||
|
let dir = tempdir().unwrap();
|
||||||
|
|
||||||
|
let existing_path = dir.path().join("foo.txt");
|
||||||
|
fs::write(&existing_path, b"Hello File!").await.unwrap();
|
||||||
|
let nonexisting_path = dir.path().join("bar.txt");
|
||||||
|
|
||||||
|
assert!(fs::try_exists(existing_path).await.unwrap());
|
||||||
|
assert!(!fs::try_exists(nonexisting_path).await.unwrap());
|
||||||
|
// FreeBSD root user always has permission to stat.
|
||||||
|
#[cfg(all(unix, not(target_os = "freebsd")))]
|
||||||
|
{
|
||||||
|
use std::os::unix::prelude::PermissionsExt;
|
||||||
|
let permission_denied_directory_path = dir.path().join("baz");
|
||||||
|
fs::create_dir(&permission_denied_directory_path)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
let permission_denied_file_path = permission_denied_directory_path.join("baz.txt");
|
||||||
|
fs::write(&permission_denied_file_path, b"Hello File!")
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
let mut perms = tokio::fs::metadata(&permission_denied_directory_path)
|
||||||
|
.await
|
||||||
|
.unwrap()
|
||||||
|
.permissions();
|
||||||
|
|
||||||
|
perms.set_mode(0o244);
|
||||||
|
fs::set_permissions(&permission_denied_directory_path, perms)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
let permission_denied_result = fs::try_exists(permission_denied_file_path).await;
|
||||||
|
assert_eq!(
|
||||||
|
permission_denied_result.err().unwrap().kind(),
|
||||||
|
std::io::ErrorKind::PermissionDenied
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user