Skip to main content

tokio/fs/
try_exists.rs

1use crate::fs::asyncify;
2
3use std::io;
4use 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/// ```
25pub async fn try_exists(path: impl AsRef<Path>) -> io::Result<bool> {
26    let path = path.as_ref();
27
28    #[cfg(all(
29        tokio_unstable,
30        feature = "io-uring",
31        feature = "rt",
32        feature = "fs",
33        // libc::statx is only supported on these platforms
34        // FIXME: Add musl target env when our minimum supported
35        // rust version is 1.93. To clarify, statx support is
36        // introduced to musl in 1.25 as mentioned officially here:
37        // https://musl.libc.org/releases.html.
38        // However, rustup target_env building for *-linux-musl
39        // uses 1.25 musl on all *-linux-musl platforms starting
40        // in 1.93 stable rust version.
41        // https://blog.rust-lang.org/2025/12/05/Updating-musl-1.2.5/
42        any(target_env = "gnu", target_os = "android")
43    ))]
44    {
45        if let Ok(handle) = crate::runtime::Handle::try_current() {
46            if let Some(driver_handle) = handle.inner.driver().io.as_ref() {
47                if driver_handle
48                    .check_and_init(io_uring::opcode::Statx::CODE)
49                    .await?
50                {
51                    return try_exists_uring(path).await;
52                }
53            }
54        }
55    }
56
57    try_exists_spawn_blocking(path).await
58}
59
60cfg_io_uring! {
61    #[inline]
62    #[cfg(
63        // libc::statx is only supported on these platforms
64        // FIXME: Add musl target env when our minimum supported
65        // rust version is 1.93. To clarify, statx support is
66        // introduced to musl in 1.25 as mentioned officially here:
67        // https://musl.libc.org/releases.html.
68        // However, rustup target_env building for *-linux-musl
69        // uses 1.25 musl on all *-linux-musl platforms starting
70        // in 1.93 stable rust version.
71        // https://blog.rust-lang.org/2025/12/05/Updating-musl-1.2.5/
72        any(target_env = "gnu", target_os = "android")
73    )]
74    async fn try_exists_uring(path: &Path) -> io::Result<bool> {
75        use crate::runtime::driver::op::Op;
76
77        match Op::metadata(path)?.await {
78            Ok(_) => Ok(true),
79            Err(error) if error.kind() == io::ErrorKind::NotFound => Ok(false),
80            Err(error) => Err(error),
81        }
82    }
83}
84
85async fn try_exists_spawn_blocking(path: &Path) -> io::Result<bool> {
86    let path = path.to_owned();
87    // FIXME: When MSRV is 1.81, change this to
88    // std::fs::exists() to be consistent with
89    // all other tokio::fs operations
90    asyncify(move || path.try_exists()).await
91}