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/// Wrapper for [`tokio::fs::hard_link`].
68#[cfg_attr(docsrs, doc(cfg(feature = "tokio")))]
69pub async fn hard_link(src: impl AsRef<Path>, dst: impl AsRef<Path>) -> io::Result<()> {
70    let (src, dst) = (src.as_ref(), dst.as_ref());
71    tokio::fs::hard_link(src, dst)
72        .await
73        .map_err(|err| SourceDestError::build(err, SourceDestErrorKind::HardLink, src, dst))
74}
75
76/// Given a path, queries the file system to get information about a file,
77/// directory, etc.
78///
79/// Wrapper for [`tokio::fs::metadata`].
80#[cfg_attr(docsrs, doc(cfg(feature = "tokio")))]
81pub async fn metadata(path: impl AsRef<Path>) -> io::Result<Metadata> {
82    let path = path.as_ref();
83    tokio::fs::metadata(path)
84        .await
85        .map_err(|err| Error::build(err, ErrorKind::Metadata, path))
86}
87
88/// Returns `Ok(true)` if the path points at an existing entity.
89///
90/// Wrapper for [`tokio::fs::try_exists`].
91#[cfg_attr(docsrs, doc(cfg(feature = "tokio")))]
92pub async fn try_exists(path: impl AsRef<Path>) -> io::Result<bool> {
93    let path = path.as_ref();
94    tokio::fs::try_exists(path)
95        .await
96        .map_err(|err| Error::build(err, ErrorKind::FileExists, path))
97}
98
99/// Reads the entire contents of a file into a bytes vector.
100///
101/// Wrapper for [`tokio::fs::read`].
102#[cfg_attr(docsrs, doc(cfg(feature = "tokio")))]
103pub async fn read(path: impl AsRef<Path>) -> io::Result<Vec<u8>> {
104    let path = path.as_ref();
105    tokio::fs::read(path)
106        .await
107        .map_err(|err| Error::build(err, ErrorKind::Read, path))
108}
109
110/// Reads a symbolic link, returning the file that the link points to.
111///
112/// Wrapper for [`tokio::fs::read_link`].
113#[cfg_attr(docsrs, doc(cfg(feature = "tokio")))]
114pub async fn read_link(path: impl AsRef<Path>) -> io::Result<PathBuf> {
115    let path = path.as_ref();
116    tokio::fs::read_link(path)
117        .await
118        .map_err(|err| Error::build(err, ErrorKind::ReadLink, path))
119}
120
121/// Creates a future which will open a file for reading and read the entire
122/// contents into a string and return said string.
123///
124/// Wrapper for [`tokio::fs::read_to_string`].
125#[cfg_attr(docsrs, doc(cfg(feature = "tokio")))]
126pub async fn read_to_string(path: impl AsRef<Path>) -> io::Result<String> {
127    let path = path.as_ref();
128    tokio::fs::read_to_string(path)
129        .await
130        .map_err(|err| Error::build(err, ErrorKind::Read, path))
131}
132
133/// Removes an existing, empty directory.
134///
135/// Wrapper for [`tokio::fs::remove_dir`].
136#[cfg_attr(docsrs, doc(cfg(feature = "tokio")))]
137pub async fn remove_dir(path: impl AsRef<Path>) -> io::Result<()> {
138    let path = path.as_ref();
139    tokio::fs::remove_dir(path)
140        .await
141        .map_err(|err| Error::build(err, ErrorKind::RemoveDir, path))
142}
143
144/// Removes a directory at this path, after removing all its contents. Use carefully!
145///
146/// Wrapper for [`tokio::fs::remove_dir_all`].
147#[cfg_attr(docsrs, doc(cfg(feature = "tokio")))]
148pub async fn remove_dir_all(path: impl AsRef<Path>) -> io::Result<()> {
149    let path = path.as_ref();
150    tokio::fs::remove_dir_all(path)
151        .await
152        .map_err(|err| Error::build(err, ErrorKind::RemoveDir, path))
153}
154
155/// Removes a file from the filesystem.
156///
157/// Wrapper for [`tokio::fs::remove_file`].
158#[cfg_attr(docsrs, doc(cfg(feature = "tokio")))]
159pub async fn remove_file(path: impl AsRef<Path>) -> io::Result<()> {
160    let path = path.as_ref();
161    tokio::fs::remove_file(path)
162        .await
163        .map_err(|err| Error::build(err, ErrorKind::RemoveFile, path))
164}
165
166/// Renames a file or directory to a new name, replacing the original file if
167/// `to` already exists.
168///
169/// Wrapper for [`tokio::fs::rename`].
170#[cfg_attr(docsrs, doc(cfg(feature = "tokio")))]
171pub async fn rename(from: impl AsRef<Path>, to: impl AsRef<Path>) -> io::Result<()> {
172    let (from, to) = (from.as_ref(), to.as_ref());
173    tokio::fs::rename(from, to)
174        .await
175        .map_err(|err| SourceDestError::build(err, SourceDestErrorKind::Rename, from, to))
176}
177
178/// Changes the permissions found on a file or a directory.
179///
180/// Wrapper for [`tokio::fs::set_permissions`].
181#[cfg_attr(docsrs, doc(cfg(feature = "tokio")))]
182pub async fn set_permissions(path: impl AsRef<Path>, perm: Permissions) -> io::Result<()> {
183    let path = path.as_ref();
184    tokio::fs::set_permissions(path, perm)
185        .await
186        .map_err(|err| Error::build(err, ErrorKind::SetPermissions, path))
187}
188
189/// Queries the file system metadata for a path.
190///
191/// Wrapper for [`tokio::fs::symlink_metadata`].
192#[cfg_attr(docsrs, doc(cfg(feature = "tokio")))]
193pub async fn symlink_metadata(path: impl AsRef<Path>) -> io::Result<Metadata> {
194    let path = path.as_ref();
195    tokio::fs::symlink_metadata(path)
196        .await
197        .map_err(|err| Error::build(err, ErrorKind::SymlinkMetadata, path))
198}
199
200/// Creates a new symbolic link on the filesystem.
201///
202/// Wrapper for [`tokio::fs::symlink`].
203#[cfg(unix)]
204#[cfg_attr(docsrs, doc(cfg(feature = "tokio")))]
205pub async fn symlink(src: impl AsRef<Path>, dst: impl AsRef<Path>) -> io::Result<()> {
206    let (src, dst) = (src.as_ref(), dst.as_ref());
207    tokio::fs::symlink(src, dst)
208        .await
209        .map_err(|err| SourceDestError::build(err, SourceDestErrorKind::Symlink, src, dst))
210}
211
212/// Creates a new directory symlink on the filesystem.
213///
214/// Wrapper for [`tokio::fs::symlink_dir`].
215#[cfg(windows)]
216#[cfg_attr(docsrs, doc(cfg(feature = "tokio")))]
217pub async fn symlink_dir(src: impl AsRef<Path>, dst: impl AsRef<Path>) -> io::Result<()> {
218    let (src, dst) = (src.as_ref(), dst.as_ref());
219    tokio::fs::symlink_dir(src, dst)
220        .await
221        .map_err(|err| SourceDestError::build(err, SourceDestErrorKind::SymlinkDir, src, dst))
222}
223
224/// Creates a new file symbolic link on the filesystem.
225///
226/// Wrapper for [`tokio::fs::symlink_file`].
227#[cfg(windows)]
228#[cfg_attr(docsrs, doc(cfg(feature = "tokio")))]
229pub async fn symlink_file(src: impl AsRef<Path>, dst: impl AsRef<Path>) -> io::Result<()> {
230    let (src, dst) = (src.as_ref(), dst.as_ref());
231    tokio::fs::symlink_file(src, dst)
232        .await
233        .map_err(|err| SourceDestError::build(err, SourceDestErrorKind::SymlinkFile, src, dst))
234}
235
236/// Creates a future that will open a file for writing and write the entire
237/// contents of `contents` to it.
238///
239/// Wrapper for [`tokio::fs::write`].
240#[cfg_attr(docsrs, doc(cfg(feature = "tokio")))]
241pub async fn write(path: impl AsRef<Path>, contents: impl AsRef<[u8]>) -> io::Result<()> {
242    let (path, contents) = (path.as_ref(), contents.as_ref());
243    tokio::fs::write(path, contents)
244        .await
245        .map_err(|err| Error::build(err, ErrorKind::Write, path))
246}