cap_std/fs_utf8/
mod.rs

1//! A fully UTF-8 filesystem API modeled after [`cap_std::fs`].
2//!
3//! Where `cap_std::fs` would use `Path` and `PathBuf`, this `fs_utf8` module
4//! uses [`Utf8Path`] and [`Utf8PathBuf`], meaning that all paths are valid
5//! UTF-8.
6//!
7//! To use this module, enable the `fs_utf8` cargo feature.
8//!
9//! If you don't want to restrict paths to UTF-8, use the regular
10//! [`cap_std::fs`] module instead.
11//!
12//! [`cap_std::fs`]: ../fs/
13
14mod dir;
15mod dir_entry;
16mod file;
17mod read_dir;
18
19pub use dir::Dir;
20pub use dir_entry::DirEntry;
21pub use file::File;
22pub use read_dir::ReadDir;
23
24// Re-export things from `cap_std::fs` that we can use as-is.
25pub use crate::fs::{DirBuilder, FileType, Metadata, OpenOptions, Permissions};
26
27// Re-export conditional types from `cap_primitives`.
28#[cfg(any(unix, target_os = "vxworks", all(windows, windows_file_type_ext)))]
29pub use cap_primitives::fs::FileTypeExt;
30#[cfg(unix)]
31pub use cap_primitives::fs::{DirBuilderExt, PermissionsExt};
32pub use cap_primitives::fs::{FileExt, MetadataExt, OpenOptionsExt};
33
34// Re-export `camino` to make it easy for users to depend on the same
35// version we do, because we use its types in our public API.
36pub use camino;
37
38use camino::{Utf8Path, Utf8PathBuf};
39
40#[cfg(not(feature = "arf_strings"))]
41pub(crate) fn from_utf8<'a>(path: &'a Utf8Path) -> std::io::Result<&'a std::path::Path> {
42    Ok(path.as_std_path())
43}
44
45#[cfg(feature = "arf_strings")]
46pub(crate) fn from_utf8<'a>(path: &'a Utf8Path) -> std::io::Result<std::path::PathBuf> {
47    #[cfg(not(windows))]
48    let path = {
49        #[cfg(unix)]
50        use std::{ffi::OsString, os::unix::ffi::OsStringExt};
51        #[cfg(target_os = "wasi")]
52        use std::{ffi::OsString, os::wasi::ffi::OsStringExt};
53
54        let string = arf_strings::str_to_host(path.as_str())?;
55        OsString::from_vec(string.into_bytes())
56    };
57
58    #[cfg(windows)]
59    let path = arf_strings::str_to_host(path.as_str())?;
60
61    Ok(path.into())
62}
63
64fn to_utf8<P: AsRef<std::path::Path>>(path: P) -> std::io::Result<Utf8PathBuf> {
65    #[cfg(not(feature = "arf_strings"))]
66    #[cfg(not(windows))]
67    {
68        Ok(Utf8Path::from_path(path.as_ref())
69            .ok_or(::rustix::io::Errno::ILSEQ)?
70            .to_path_buf())
71    }
72
73    #[cfg(not(feature = "arf_strings"))]
74    #[cfg(windows)]
75    {
76        Ok(Utf8Path::from_path(path.as_ref())
77            .ok_or_else(|| {
78                std::io::Error::new(
79                    std::io::ErrorKind::InvalidData,
80                    "filesystem path is not valid UTF-8",
81                )
82            })?
83            .to_path_buf())
84    }
85
86    #[cfg(feature = "arf_strings")]
87    {
88        // For now, for WASI use the same logic as other OS's, but
89        // in the future, the idea is we could avoid this.
90        let osstr = path.as_ref().as_os_str();
91
92        #[cfg(not(windows))]
93        {
94            arf_strings::host_os_str_to_str(osstr)
95                .map(std::borrow::Cow::into_owned)
96                .map(Into::into)
97        }
98
99        #[cfg(windows)]
100        {
101            arf_strings::host_to_str(osstr).map(Into::into)
102        }
103    }
104}