fs_err/tokio/
mod.rs

1//! Tokio-specific wrappers that use `fs_err` error messages.
2
3use crate::errors::{Error, ErrorKind, SourceDestError, SourceDestErrorKind};
4use std::fs::{Metadata, Permissions};
5use std::path::{Path, PathBuf};
6use tokio::io;
7mod dir_builder;
8mod file;
9mod open_options;
10mod read_dir;
11
12pub use self::open_options::OpenOptions;
13pub use self::read_dir::{read_dir, DirEntry, ReadDir};
14pub use dir_builder::DirBuilder;
15pub use file::File;
16
17/// Returns the canonical, absolute form of a path with all intermediate
18/// components normalized and symbolic links resolved.
19///
20/// Wrapper for [`tokio::fs::canonicalize`].
21#[cfg_attr(docsrs, doc(cfg(feature = "tokio")))]
22pub async fn canonicalize(path: impl AsRef<Path>) -> io::Result<PathBuf> {
23    let path = path.as_ref();
24    tokio::fs::canonicalize(path)
25        .await
26        .map_err(|err| Error::build(err, ErrorKind::Canonicalize, path))
27}
28
29/// Copies the contents of one file to another. This function will also copy the permission bits
30/// of the original file to the destination file.
31/// This function will overwrite the contents of to.
32///
33/// Wrapper for [`tokio::fs::copy`].
34#[cfg_attr(docsrs, doc(cfg(feature = "tokio")))]
35pub async fn copy(from: impl AsRef<Path>, to: impl AsRef<Path>) -> Result<u64, io::Error> {
36    let (from, to) = (from.as_ref(), to.as_ref());
37    tokio::fs::copy(from, to)
38        .await
39        .map_err(|err| SourceDestError::build(err, SourceDestErrorKind::Copy, from, to))
40}
41
42/// Creates a new, empty directory at the provided path.
43///
44/// Wrapper for [`tokio::fs::create_dir`].
45#[cfg_attr(docsrs, doc(cfg(feature = "tokio")))]
46pub async fn create_dir(path: impl AsRef<Path>) -> io::Result<()> {
47    let path = path.as_ref();
48    tokio::fs::create_dir(path)
49        .await
50        .map_err(|err| Error::build(err, ErrorKind::CreateDir, path))
51}
52
53/// Recursively creates a directory and all of its parent components if they
54/// are missing.
55///
56/// Wrapper for [`tokio::fs::create_dir_all`].
57#[cfg_attr(docsrs, doc(cfg(feature = "tokio")))]
58pub async fn create_dir_all(path: impl AsRef<Path>) -> io::Result<()> {
59    let path = path.as_ref();
60    tokio::fs::create_dir_all(path)
61        .await
62        .map_err(|err| Error::build(err, ErrorKind::CreateDir, path))
63}
64
65/// Creates a new hard link on the filesystem.
66///
67/// The `link` path will be a link pointing to the `original` path. Note that
68/// systems often require these two paths to both be located on the same
69/// filesystem.
70///
71/// Wrapper for [`tokio::fs::hard_link`].
72#[cfg_attr(docsrs, doc(cfg(feature = "tokio")))]
73pub async fn hard_link(original: impl AsRef<Path>, link: impl AsRef<Path>) -> io::Result<()> {
74    let (original, link) = (original.as_ref(), link.as_ref());
75    tokio::fs::hard_link(original, link)
76        .await
77        .map_err(|err| SourceDestError::build(err, SourceDestErrorKind::HardLink, link, original))
78}
79
80/// Given a path, queries the file system to get information about a file,
81/// directory, etc.
82///
83/// Wrapper for [`tokio::fs::metadata`].
84#[cfg_attr(docsrs, doc(cfg(feature = "tokio")))]
85pub async fn metadata(path: impl AsRef<Path>) -> io::Result<Metadata> {
86    let path = path.as_ref();
87    tokio::fs::metadata(path)
88        .await
89        .map_err(|err| Error::build(err, ErrorKind::Metadata, path))
90}
91
92/// Returns `Ok(true)` if the path points at an existing entity.
93///
94/// Wrapper for [`tokio::fs::try_exists`].
95#[cfg_attr(docsrs, doc(cfg(feature = "tokio")))]
96pub async fn try_exists(path: impl AsRef<Path>) -> io::Result<bool> {
97    let path = path.as_ref();
98    tokio::fs::try_exists(path)
99        .await
100        .map_err(|err| Error::build(err, ErrorKind::FileExists, path))
101}
102
103/// Reads the entire contents of a file into a bytes vector.
104///
105/// Wrapper for [`tokio::fs::read`].
106#[cfg_attr(docsrs, doc(cfg(feature = "tokio")))]
107pub async fn read(path: impl AsRef<Path>) -> io::Result<Vec<u8>> {
108    let path = path.as_ref();
109    tokio::fs::read(path)
110        .await
111        .map_err(|err| Error::build(err, ErrorKind::Read, path))
112}
113
114/// Reads a symbolic link, returning the file that the link points to.
115///
116/// Wrapper for [`tokio::fs::read_link`].
117#[cfg_attr(docsrs, doc(cfg(feature = "tokio")))]
118pub async fn read_link(path: impl AsRef<Path>) -> io::Result<PathBuf> {
119    let path = path.as_ref();
120    tokio::fs::read_link(path)
121        .await
122        .map_err(|err| Error::build(err, ErrorKind::ReadLink, path))
123}
124
125/// Creates a future which will open a file for reading and read the entire
126/// contents into a string and return said string.
127///
128/// Wrapper for [`tokio::fs::read_to_string`].
129#[cfg_attr(docsrs, doc(cfg(feature = "tokio")))]
130pub async fn read_to_string(path: impl AsRef<Path>) -> io::Result<String> {
131    let path = path.as_ref();
132    tokio::fs::read_to_string(path)
133        .await
134        .map_err(|err| Error::build(err, ErrorKind::Read, path))
135}
136
137/// Removes an existing, empty directory.
138///
139/// Wrapper for [`tokio::fs::remove_dir`].
140#[cfg_attr(docsrs, doc(cfg(feature = "tokio")))]
141pub async fn remove_dir(path: impl AsRef<Path>) -> io::Result<()> {
142    let path = path.as_ref();
143    tokio::fs::remove_dir(path)
144        .await
145        .map_err(|err| Error::build(err, ErrorKind::RemoveDir, path))
146}
147
148/// Removes a directory at this path, after removing all its contents. Use carefully!
149///
150/// Wrapper for [`tokio::fs::remove_dir_all`].
151#[cfg_attr(docsrs, doc(cfg(feature = "tokio")))]
152pub async fn remove_dir_all(path: impl AsRef<Path>) -> io::Result<()> {
153    let path = path.as_ref();
154    tokio::fs::remove_dir_all(path)
155        .await
156        .map_err(|err| Error::build(err, ErrorKind::RemoveDir, path))
157}
158
159/// Removes a file from the filesystem.
160///
161/// Wrapper for [`tokio::fs::remove_file`].
162#[cfg_attr(docsrs, doc(cfg(feature = "tokio")))]
163pub async fn remove_file(path: impl AsRef<Path>) -> io::Result<()> {
164    let path = path.as_ref();
165    tokio::fs::remove_file(path)
166        .await
167        .map_err(|err| Error::build(err, ErrorKind::RemoveFile, path))
168}
169
170/// Renames a file or directory to a new name, replacing the original file if
171/// `to` already exists.
172///
173/// Wrapper for [`tokio::fs::rename`].
174#[cfg_attr(docsrs, doc(cfg(feature = "tokio")))]
175pub async fn rename(from: impl AsRef<Path>, to: impl AsRef<Path>) -> io::Result<()> {
176    let (from, to) = (from.as_ref(), to.as_ref());
177    tokio::fs::rename(from, to)
178        .await
179        .map_err(|err| SourceDestError::build(err, SourceDestErrorKind::Rename, from, to))
180}
181
182/// Changes the permissions found on a file or a directory.
183///
184/// Wrapper for [`tokio::fs::set_permissions`].
185#[cfg_attr(docsrs, doc(cfg(feature = "tokio")))]
186pub async fn set_permissions(path: impl AsRef<Path>, perm: Permissions) -> io::Result<()> {
187    let path = path.as_ref();
188    tokio::fs::set_permissions(path, perm)
189        .await
190        .map_err(|err| Error::build(err, ErrorKind::SetPermissions, path))
191}
192
193/// Queries the file system metadata for a path.
194///
195/// Wrapper for [`tokio::fs::symlink_metadata`].
196#[cfg_attr(docsrs, doc(cfg(feature = "tokio")))]
197pub async fn symlink_metadata(path: impl AsRef<Path>) -> io::Result<Metadata> {
198    let path = path.as_ref();
199    tokio::fs::symlink_metadata(path)
200        .await
201        .map_err(|err| Error::build(err, ErrorKind::SymlinkMetadata, path))
202}
203
204/// Creates a new symbolic link on the filesystem.
205///
206/// The `link` path will be a symbolic link pointing to the `original` path.
207///
208/// Wrapper for [`tokio::fs::symlink`].
209#[cfg(unix)]
210#[cfg_attr(docsrs, doc(cfg(feature = "tokio")))]
211pub async fn symlink(original: impl AsRef<Path>, link: impl AsRef<Path>) -> io::Result<()> {
212    let (original, link) = (original.as_ref(), link.as_ref());
213    tokio::fs::symlink(original, link)
214        .await
215        .map_err(|err| SourceDestError::build(err, SourceDestErrorKind::Symlink, link, original))
216}
217
218/// Creates a new directory symlink on the filesystem.
219///
220/// The `link` path will be a symbolic link pointing to the `original` path.
221///
222/// Wrapper for [`tokio::fs::symlink_dir`].
223#[cfg(windows)]
224#[cfg_attr(docsrs, doc(cfg(feature = "tokio")))]
225pub async fn symlink_dir(original: impl AsRef<Path>, link: impl AsRef<Path>) -> io::Result<()> {
226    let (original, link) = (original.as_ref(), link.as_ref());
227    tokio::fs::symlink_dir(original, link)
228        .await
229        .map_err(|err| SourceDestError::build(err, SourceDestErrorKind::SymlinkDir, link, original))
230}
231
232/// Creates a new file symbolic link on the filesystem.
233///
234/// The `link` path will be a symbolic link pointing to the `original` path.
235///
236/// Wrapper for [`tokio::fs::symlink_file`].
237#[cfg(windows)]
238#[cfg_attr(docsrs, doc(cfg(feature = "tokio")))]
239pub async fn symlink_file(original: impl AsRef<Path>, link: impl AsRef<Path>) -> io::Result<()> {
240    let (original, link) = (original.as_ref(), link.as_ref());
241    tokio::fs::symlink_file(original, link)
242        .await
243        .map_err(|err| {
244            SourceDestError::build(err, SourceDestErrorKind::SymlinkFile, link, original)
245        })
246}
247
248/// Creates a future that will open a file for writing and write the entire
249/// contents of `contents` to it.
250///
251/// Wrapper for [`tokio::fs::write`].
252#[cfg_attr(docsrs, doc(cfg(feature = "tokio")))]
253pub async fn write(path: impl AsRef<Path>, contents: impl AsRef<[u8]>) -> io::Result<()> {
254    let (path, contents) = (path.as_ref(), contents.as_ref());
255    tokio::fs::write(path, contents)
256        .await
257        .map_err(|err| Error::build(err, ErrorKind::Write, path))
258}