File tree Expand file tree Collapse file tree 3 files changed +81
-0
lines changed Expand file tree Collapse file tree 3 files changed +81
-0
lines changed Original file line number Diff line number Diff line change @@ -102,6 +102,9 @@ pub use self::write::write;
102102mod copy;
103103pub use self :: copy:: copy;
104104
105+ mod try_exists;
106+ pub use self :: try_exists:: try_exists;
107+
105108#[ cfg( test) ]
106109mod mocks;
107110
Original file line number Diff line number Diff line change 1+ use crate :: fs:: asyncify;
2+
3+ use std:: io;
4+ use std:: path:: Path ;
5+
6+ /// Returns `Ok(true)` if the path points at an existing entity.
7+ ///
8+ /// This function will traverse symbolic links to query information about the
9+ /// destination file. In case of broken symbolic links this will return `Ok(false)`.
10+ ///
11+ /// This is the async equivalent of [`std::path::Path::try_exists`][std].
12+ ///
13+ /// [std]: fn@std::path::Path::try_exists
14+ ///
15+ /// # Examples
16+ ///
17+ /// ```no_run
18+ /// use tokio::fs;
19+ ///
20+ /// # async fn dox() -> std::io::Result<()> {
21+ /// fs::try_exists("foo.txt").await?;
22+ /// # Ok(())
23+ /// # }
24+ /// ```
25+ pub async fn try_exists ( path : impl AsRef < Path > ) -> io:: Result < bool > {
26+ let path = path. as_ref ( ) . to_owned ( ) ;
27+ // std's Path::try_exists is not available for current Rust min supported version.
28+ // Current implementation is based on its internal implementation instead.
29+ match asyncify ( move || std:: fs:: metadata ( path) ) . await {
30+ Ok ( _) => Ok ( true ) ,
31+ Err ( error) if error. kind ( ) == std:: io:: ErrorKind :: NotFound => Ok ( false ) ,
32+ Err ( error) => Err ( error) ,
33+ }
34+ }
Original file line number Diff line number Diff line change 1+ #![ warn( rust_2018_idioms) ]
2+ #![ cfg( all( feature = "full" , not( tokio_wasi) ) ) ] // Wasi does not support file operations
3+
4+ use tempfile:: tempdir;
5+ use tokio:: fs;
6+
7+ #[ tokio:: test]
8+ async fn try_exists ( ) {
9+ let dir = tempdir ( ) . unwrap ( ) ;
10+
11+ let existing_path = dir. path ( ) . join ( "foo.txt" ) ;
12+ fs:: write ( & existing_path, b"Hello File!" ) . await . unwrap ( ) ;
13+ let nonexisting_path = dir. path ( ) . join ( "bar.txt" ) ;
14+
15+ assert ! ( fs:: try_exists( existing_path) . await . unwrap( ) ) ;
16+ assert ! ( !fs:: try_exists( nonexisting_path) . await . unwrap( ) ) ;
17+ // FreeBSD root user always has permission to stat.
18+ #[ cfg( all( unix, not( target_os = "freebsd" ) ) ) ]
19+ {
20+ use std:: os:: unix:: prelude:: PermissionsExt ;
21+ let permission_denied_directory_path = dir. path ( ) . join ( "baz" ) ;
22+ fs:: create_dir ( & permission_denied_directory_path)
23+ . await
24+ . unwrap ( ) ;
25+ let permission_denied_file_path = permission_denied_directory_path. join ( "baz.txt" ) ;
26+ fs:: write ( & permission_denied_file_path, b"Hello File!" )
27+ . await
28+ . unwrap ( ) ;
29+ let mut perms = tokio:: fs:: metadata ( & permission_denied_directory_path)
30+ . await
31+ . unwrap ( )
32+ . permissions ( ) ;
33+
34+ perms. set_mode ( 0o244 ) ;
35+ fs:: set_permissions ( & permission_denied_directory_path, perms)
36+ . await
37+ . unwrap ( ) ;
38+ let permission_denied_result = fs:: try_exists ( permission_denied_file_path) . await ;
39+ assert_eq ! (
40+ permission_denied_result. err( ) . unwrap( ) . kind( ) ,
41+ std:: io:: ErrorKind :: PermissionDenied
42+ ) ;
43+ }
44+ }
You can’t perform that action at this time.
0 commit comments