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        let handle = crate::runtime::Handle::current();
46        let driver_handle = handle.inner.driver().io();
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    try_exists_spawn_blocking(path).await
56}
57
58cfg_io_uring! {
59    #[inline]
60    #[cfg(
61        // libc::statx is only supported on these platforms
62        // FIXME: Add musl target env when our minimum supported
63        // rust version is 1.93. To clarify, statx support is
64        // introduced to musl in 1.25 as mentioned officially here:
65        // https://musl.libc.org/releases.html.
66        // However, rustup target_env building for *-linux-musl
67        // uses 1.25 musl on all *-linux-musl platforms starting
68        // in 1.93 stable rust version.
69        // https://blog.rust-lang.org/2025/12/05/Updating-musl-1.2.5/
70        any(target_env = "gnu", target_os = "android")
71    )]
72    async fn try_exists_uring(path: &Path) -> io::Result<bool> {
73        use crate::runtime::driver::op::Op;
74
75        match Op::metadata(path)?.await {
76            Ok(_) => Ok(true),
77            Err(error) if error.kind() == io::ErrorKind::NotFound => Ok(false),
78            Err(error) => Err(error),
79        }
80    }
81}
82
83async fn try_exists_spawn_blocking(path: &Path) -> io::Result<bool> {
84    let path = path.to_owned();
85    // FIXME: When MSRV is 1.81, change this to
86    // std::fs::exists() to be consistent with
87    // all other tokio::fs operations
88    asyncify(move || path.try_exists()).await
89}