From 9d3c2288a3ced56816c9406aada8e98dba766396 Mon Sep 17 00:00:00 2001 From: Mike Hommey Date: Fri, 23 Dec 2022 20:51:18 +0000 Subject: [PATCH] Bug 1806766 - Update fs-err to 2.9.0. r=emilio,supply-chain-reviewers Differential Revision: https://phabricator.services.mozilla.com/D165361 --- Cargo.lock | 4 +- supply-chain/audits.toml | 5 + third_party/rust/fs-err/.cargo-checksum.json | 2 +- third_party/rust/fs-err/CHANGELOG.md | 4 + third_party/rust/fs-err/Cargo.toml | 8 +- third_party/rust/fs-err/src/lib.rs | 5 +- .../rust/fs-err/src/tokio/dir_builder.rs | 54 ++++ third_party/rust/fs-err/src/tokio/file.rs | 243 ++++++++++++++++++ third_party/rust/fs-err/src/tokio/mod.rs | 189 ++++++++++++++ .../rust/fs-err/src/tokio/open_options.rs | 109 ++++++++ third_party/rust/fs-err/src/tokio/read_dir.rs | 94 +++++++ 11 files changed, 711 insertions(+), 6 deletions(-) create mode 100644 third_party/rust/fs-err/src/tokio/dir_builder.rs create mode 100644 third_party/rust/fs-err/src/tokio/file.rs create mode 100644 third_party/rust/fs-err/src/tokio/mod.rs create mode 100644 third_party/rust/fs-err/src/tokio/open_options.rs create mode 100644 third_party/rust/fs-err/src/tokio/read_dir.rs diff --git a/Cargo.lock b/Cargo.lock index 0eda564814bf..db0c7aef62d1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1872,9 +1872,9 @@ dependencies = [ [[package]] name = "fs-err" -version = "2.8.1" +version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64db3e262960f0662f43a6366788d5f10f7f244b8f7d7d987f560baf5ded5c50" +checksum = "0845fa252299212f0389d64ba26f34fa32cfe41588355f21ed507c59a0f64541" [[package]] name = "fuchsia-zircon" diff --git a/supply-chain/audits.toml b/supply-chain/audits.toml index 735010df33a0..b32b608fa3ee 100644 --- a/supply-chain/audits.toml +++ b/supply-chain/audits.toml @@ -607,6 +607,11 @@ who = "Mike Hommey " criteria = "safe-to-deploy" delta = "2.7.0 -> 2.8.1" +[[audits.fs-err]] +who = "Mike Hommey " +criteria = "safe-to-deploy" +delta = "2.8.1 -> 2.9.0" + [[audits.futures]] who = "Mike Hommey " criteria = "safe-to-deploy" diff --git a/third_party/rust/fs-err/.cargo-checksum.json b/third_party/rust/fs-err/.cargo-checksum.json index 0cafc2baec7c..234187bec994 100644 --- a/third_party/rust/fs-err/.cargo-checksum.json +++ b/third_party/rust/fs-err/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"CHANGELOG.md":"fb2609e5837d71e923def1765b6addc4d11b0b5040e7eb9bdbf50d59a4a5cd42","Cargo.toml":"b468e8d560ea6e30277c2ee438ac650bbb2397f5b62da911126c180921aa5d29","LICENSE-APACHE":"7cfd738c53d61c79f07e348f622bf7707c9084237054d37fbe07788a75f5881c","LICENSE-MIT":"36516aefdc84c5d5a1e7485425913a22dbda69eb1930c5e84d6ae4972b5194b9","README.md":"adbf428f33a04028cc8db98d7b75bdcf28d0edb5e792867578bcb93f1784abec","src/dir.rs":"c5255382d7357f2fbcb0b45325a343277d347f0dd0b5f0e5ff74cb808020795d","src/errors.rs":"f04771790f55627fdc39de43a1d16f7d0125bbf48d4a1c8a70921f2670dd3eaa","src/file.rs":"4516834bc52f1219f10e369bf570fd432493ceaf5d52d239d93a5e69ceaed0aa","src/lib.rs":"1a10c04bde2bc3ae30cc328afb0aa00ac98ab80c6bfff5ae94ee7e5bdbe86ec8","src/open_options.rs":"304c5be36b5a6c5ecc2c731e2956627494945d093952c879d8f3c5b15216b1d0","src/os.rs":"54fe6cb71a24592de1cb4e1fcebdeaba5e58b26925dbf2dc868e8dd0b0a7bef7","src/os/unix.rs":"21ab862305b9e1034c41bb4be31b1f3d43e3d208ca3e622211b6b54d1bbd9acc","src/os/windows.rs":"4cf0530becb6fed439f469e1f22f57de9ae2ac15e39f2a973f4734aee6267ed0","src/path.rs":"a026ae234184ed1bbadd9051099e201c3ac6309b1fd939d1b2d2b2a7cb82230d"},"package":"64db3e262960f0662f43a6366788d5f10f7f244b8f7d7d987f560baf5ded5c50"} \ No newline at end of file +{"files":{"CHANGELOG.md":"b17b12bee003d65ea5f1593ffd57faf8d8f98b036137cca857b5c203d1c2ae0b","Cargo.toml":"4ee30dec20735529b07d148071ecbe148d34a9fe1f83ed9f6d820230f41034bb","LICENSE-APACHE":"7cfd738c53d61c79f07e348f622bf7707c9084237054d37fbe07788a75f5881c","LICENSE-MIT":"36516aefdc84c5d5a1e7485425913a22dbda69eb1930c5e84d6ae4972b5194b9","README.md":"adbf428f33a04028cc8db98d7b75bdcf28d0edb5e792867578bcb93f1784abec","src/dir.rs":"c5255382d7357f2fbcb0b45325a343277d347f0dd0b5f0e5ff74cb808020795d","src/errors.rs":"f04771790f55627fdc39de43a1d16f7d0125bbf48d4a1c8a70921f2670dd3eaa","src/file.rs":"4516834bc52f1219f10e369bf570fd432493ceaf5d52d239d93a5e69ceaed0aa","src/lib.rs":"9cdc8a3cac73976d7c121a1b9eb63a3a2bebdd6533a67b22bc3628952578fde2","src/open_options.rs":"304c5be36b5a6c5ecc2c731e2956627494945d093952c879d8f3c5b15216b1d0","src/os.rs":"54fe6cb71a24592de1cb4e1fcebdeaba5e58b26925dbf2dc868e8dd0b0a7bef7","src/os/unix.rs":"21ab862305b9e1034c41bb4be31b1f3d43e3d208ca3e622211b6b54d1bbd9acc","src/os/windows.rs":"4cf0530becb6fed439f469e1f22f57de9ae2ac15e39f2a973f4734aee6267ed0","src/path.rs":"a026ae234184ed1bbadd9051099e201c3ac6309b1fd939d1b2d2b2a7cb82230d","src/tokio/dir_builder.rs":"b004b6b5aeda08201dbc0ecda841f60cf06361e709cfef891356980543509b87","src/tokio/file.rs":"fb59dd43133f22b85314d28a098dc68281f4dc29a109d79fcbf2e76224830ad8","src/tokio/mod.rs":"cedd71363c524436ddae1e3dacc5ce16959b480c4f1c470ca44b2a5b59a9b1a2","src/tokio/open_options.rs":"c6ccc8f9c89ea7f8a1b96ad927a8dfcb169e77d9f40b01f0cfdccd4e1869a9c6","src/tokio/read_dir.rs":"8f3a2aaa029354420563ff621f72defb228f196a32bc113d89c99944fac56086"},"package":"0845fa252299212f0389d64ba26f34fa32cfe41588355f21ed507c59a0f64541"} \ No newline at end of file diff --git a/third_party/rust/fs-err/CHANGELOG.md b/third_party/rust/fs-err/CHANGELOG.md index ee7e4be32279..aa4079e1a0a2 100644 --- a/third_party/rust/fs-err/CHANGELOG.md +++ b/third_party/rust/fs-err/CHANGELOG.md @@ -1,5 +1,9 @@ # fs-err Changelog +## 2.9.0 + +* Add wrappers for [`tokio::fs`](https://docs.rs/tokio/latest/tokio/fs/index.html) ([#40](https://github.com/andrewhickman/fs-err/pull/40)). + ## 2.8.1 * Fixed docs.rs build diff --git a/third_party/rust/fs-err/Cargo.toml b/third_party/rust/fs-err/Cargo.toml index 07bada50a942..f7a7194fb436 100644 --- a/third_party/rust/fs-err/Cargo.toml +++ b/third_party/rust/fs-err/Cargo.toml @@ -12,7 +12,7 @@ [package] edition = "2018" name = "fs-err" -version = "2.8.1" +version = "2.9.0" authors = ["Andrew Hickman "] exclude = [ ".github", @@ -46,7 +46,11 @@ rustdoc-args = [ "docsrs", ] -[dependencies] +[dependencies.tokio] +version = "1.21" +features = ["fs"] +optional = true +default_features = false [dev-dependencies.serde_json] version = "1.0.64" diff --git a/third_party/rust/fs-err/src/lib.rs b/third_party/rust/fs-err/src/lib.rs index 777db9535338..b1ceae529aa0 100644 --- a/third_party/rust/fs-err/src/lib.rs +++ b/third_party/rust/fs-err/src/lib.rs @@ -66,7 +66,7 @@ println!("Program config: {:?}", decoded); [serde_json]: https://crates.io/crates/serde_json */ -#![doc(html_root_url = "https://docs.rs/fs-err/2.8.1")] +#![doc(html_root_url = "https://docs.rs/fs-err/2.9.0")] #![deny(missing_debug_implementations, missing_docs)] #![cfg_attr(docsrs, feature(doc_cfg))] @@ -76,6 +76,9 @@ mod file; mod open_options; pub mod os; mod path; +#[cfg(feature = "tokio")] +#[cfg_attr(docsrs, doc(cfg(feature = "tokio")))] +pub mod tokio; use std::fs; use std::io::{self, Read, Write}; diff --git a/third_party/rust/fs-err/src/tokio/dir_builder.rs b/third_party/rust/fs-err/src/tokio/dir_builder.rs new file mode 100644 index 000000000000..0615999ee1b1 --- /dev/null +++ b/third_party/rust/fs-err/src/tokio/dir_builder.rs @@ -0,0 +1,54 @@ +use crate::errors::{Error, ErrorKind}; +use std::io; +use std::path::Path; + +/// A builder for creating directories in various manners. +/// +/// This is a wrapper around [`tokio::fs::DirBuilder`]. +#[derive(Debug, Default)] +#[cfg_attr(docsrs, doc(cfg(feature = "tokio")))] +pub struct DirBuilder { + inner: tokio::fs::DirBuilder, +} + +impl DirBuilder { + /// Creates a new set of options with default mode/security settings for all + /// platforms and also non-recursive. + /// + /// This is a wrapper version of [`tokio::fs::DirBuilder::new`] + /// + /// # Examples + /// + /// ```no_run + /// use fs_err::tokio::DirBuilder; + /// + /// let builder = DirBuilder::new(); + /// ``` + pub fn new() -> Self { + Default::default() + } + + /// Wrapper around [`tokio::fs::DirBuilder::recursive`]. + pub fn recursive(&mut self, recursive: bool) -> &mut Self { + self.inner.recursive(recursive); + self + } + + /// Wrapper around [`tokio::fs::DirBuilder::create`]. + pub async fn create(&self, path: impl AsRef) -> io::Result<()> { + let path = path.as_ref(); + self.inner + .create(path) + .await + .map_err(|err| Error::build(err, ErrorKind::CreateDir, path)) + } +} + +#[cfg(unix)] +impl DirBuilder { + /// Wrapper around [`tokio::fs::DirBuilder::mode`]. + pub fn mode(&mut self, mode: u32) -> &mut Self { + self.inner.mode(mode); + self + } +} diff --git a/third_party/rust/fs-err/src/tokio/file.rs b/third_party/rust/fs-err/src/tokio/file.rs new file mode 100644 index 000000000000..c0dac4ca47ac --- /dev/null +++ b/third_party/rust/fs-err/src/tokio/file.rs @@ -0,0 +1,243 @@ +use crate::errors::{Error, ErrorKind}; +use std::fs::{Metadata, Permissions}; +use std::io; +use std::io::{IoSlice, SeekFrom}; +use std::path::{Path, PathBuf}; +use std::pin::Pin; +use std::task::{ready, Context, Poll}; +use tokio::fs; +use tokio::fs::File as TokioFile; +use tokio::io::{AsyncRead, AsyncSeek, AsyncWrite, ReadBuf}; + +/// Wrapper around [`tokio::fs::File`] which adds more helpful +/// information to all errors. +#[derive(Debug)] +#[cfg_attr(docsrs, doc(cfg(feature = "tokio")))] +pub struct File { + tokio: fs::File, + path: PathBuf, +} + +impl File { + /// Wrapper for [`tokio::fs::File::open`]. + pub async fn open(path: impl Into) -> io::Result { + let path = path.into(); + let f = TokioFile::open(&path) + .await + .map_err(|err| Error::build(err, ErrorKind::OpenFile, &path))?; + Ok(File::from_parts(f, path)) + } + + /// Wrapper for [`tokio::fs::File::create`]. + pub async fn create(path: impl Into) -> io::Result { + let path = path.into(); + match TokioFile::create(&path).await { + Ok(f) => Ok(File::from_parts(f, path)), + Err(err) => Err(Error::build(err, ErrorKind::CreateFile, &path)), + } + } + + /// Wrapper for [`tokio::fs::File::from_std`]. + pub fn from_std(std: crate::File) -> File { + let (std, path) = std.into_parts(); + File::from_parts(TokioFile::from_std(std), path) + } + + /// Wrapper for [`tokio::fs::File::sync_all`]. + pub async fn sync_all(&self) -> io::Result<()> { + self.tokio + .sync_all() + .await + .map_err(|err| self.error(err, ErrorKind::SyncFile)) + } + + /// Wrapper for [`tokio::fs::File::sync_data`]. + pub async fn sync_data(&self) -> io::Result<()> { + self.tokio + .sync_data() + .await + .map_err(|err| self.error(err, ErrorKind::SyncFile)) + } + + /// Wrapper for [`tokio::fs::File::set_len`]. + pub async fn set_len(&self, size: u64) -> io::Result<()> { + self.tokio + .set_len(size) + .await + .map_err(|err| self.error(err, ErrorKind::SetLen)) + } + + /// Wrapper for [`tokio::fs::File::metadata`]. + pub async fn metadata(&self) -> io::Result { + self.tokio + .metadata() + .await + .map_err(|err| self.error(err, ErrorKind::Metadata)) + } + + /// Wrapper for [`tokio::fs::File::try_clone`]. + pub async fn try_clone(&self) -> io::Result { + match self.tokio.try_clone().await { + Ok(file) => Ok(File::from_parts(file, self.path.clone())), + Err(err) => Err(self.error(err, ErrorKind::Clone)), + } + } + + /// Wrapper for [`tokio::fs::File::into_std`]. + pub async fn into_std(self) -> crate::File { + crate::File::from_parts(self.tokio.into_std().await, self.path) + } + + /// Wrapper for [`tokio::fs::File::try_into_std`]. + pub fn try_into_std(self) -> Result { + match self.tokio.try_into_std() { + Ok(f) => Ok(crate::File::from_parts(f, self.path)), + Err(f) => Err(File::from_parts(f, self.path)), + } + } + + /// Wrapper for [`tokio::fs::File::set_permissions`]. + pub async fn set_permissions(&self, perm: Permissions) -> io::Result<()> { + self.tokio + .set_permissions(perm) + .await + .map_err(|err| self.error(err, ErrorKind::SetPermissions)) + } +} + +/// Methods added by fs-err that are not available on +/// [`tokio::fs::File`]. +impl File { + /// Creates a [`File`](struct.File.html) from a raw file and its path. + pub fn from_parts

(file: TokioFile, path: P) -> Self + where + P: Into, + { + File { + tokio: file, + path: path.into(), + } + } + + /// Extract the raw file and its path from this [`File`](struct.File.html). + pub fn into_parts(self) -> (TokioFile, PathBuf) { + (self.tokio, self.path) + } + + /// Returns a reference to the underlying [`tokio::fs::File`]. + pub fn file(&self) -> &TokioFile { + &self.tokio + } + + /// Returns a mutable reference to the underlying [`tokio::fs::File`]. + pub fn file_mut(&mut self) -> &mut TokioFile { + &mut self.tokio + } + + /// Returns a reference to the path that this file was created with. + pub fn path(&self) -> &Path { + &self.path + } + + /// Wrap the error in information specific to this `File` object. + fn error(&self, source: io::Error, kind: ErrorKind) -> io::Error { + Error::build(source, kind, &self.path) + } +} + +impl From for File { + fn from(f: crate::File) -> Self { + let (f, path) = f.into_parts(); + File::from_parts(f.into(), path) + } +} + +impl From for TokioFile { + fn from(f: File) -> Self { + f.into_parts().0 + } +} + +#[cfg(unix)] +impl std::os::unix::io::AsRawFd for File { + fn as_raw_fd(&self) -> std::os::unix::io::RawFd { + self.tokio.as_raw_fd() + } +} + +#[cfg(windows)] +impl std::os::windows::io::AsRawHandle for File { + fn as_raw_handle(&self) -> std::os::windows::io::RawHandle { + self.tokio.as_raw_handle() + } +} + +impl AsyncRead for File { + fn poll_read( + mut self: Pin<&mut Self>, + cx: &mut Context<'_>, + buf: &mut ReadBuf<'_>, + ) -> Poll> { + Poll::Ready( + ready!(Pin::new(&mut self.tokio).poll_read(cx, buf)) + .map_err(|err| self.error(err, ErrorKind::Read)), + ) + } +} + +impl AsyncSeek for File { + fn start_seek(mut self: Pin<&mut Self>, position: SeekFrom) -> io::Result<()> { + Pin::new(&mut self.tokio) + .start_seek(position) + .map_err(|err| self.error(err, ErrorKind::Seek)) + } + + fn poll_complete(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { + Poll::Ready( + ready!(Pin::new(&mut self.tokio).poll_complete(cx)) + .map_err(|err| self.error(err, ErrorKind::Seek)), + ) + } +} + +impl AsyncWrite for File { + fn poll_write( + mut self: Pin<&mut Self>, + cx: &mut Context<'_>, + buf: &[u8], + ) -> Poll> { + Poll::Ready( + ready!(Pin::new(&mut self.tokio).poll_write(cx, buf)) + .map_err(|err| self.error(err, ErrorKind::Write)), + ) + } + + fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { + Poll::Ready( + ready!(Pin::new(&mut self.tokio).poll_flush(cx)) + .map_err(|err| self.error(err, ErrorKind::Flush)), + ) + } + + fn poll_shutdown(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { + Poll::Ready( + ready!(Pin::new(&mut self.tokio).poll_shutdown(cx)) + .map_err(|err| self.error(err, ErrorKind::Flush)), + ) + } + + fn poll_write_vectored( + mut self: Pin<&mut Self>, + cx: &mut Context<'_>, + bufs: &[IoSlice<'_>], + ) -> Poll> { + Poll::Ready( + ready!(Pin::new(&mut self.tokio).poll_write_vectored(cx, bufs)) + .map_err(|err| self.error(err, ErrorKind::Write)), + ) + } + + fn is_write_vectored(&self) -> bool { + self.tokio.is_write_vectored() + } +} diff --git a/third_party/rust/fs-err/src/tokio/mod.rs b/third_party/rust/fs-err/src/tokio/mod.rs new file mode 100644 index 000000000000..bf4ac94ad269 --- /dev/null +++ b/third_party/rust/fs-err/src/tokio/mod.rs @@ -0,0 +1,189 @@ +//! Tokio-specific wrappers that use `fs_err` error messages. + +use crate::errors::{Error, ErrorKind, SourceDestError, SourceDestErrorKind}; +use std::fs::{Metadata, Permissions}; +use std::path::{Path, PathBuf}; +use tokio::io; +mod dir_builder; +mod file; +mod open_options; +mod read_dir; + +pub use self::open_options::OpenOptions; +pub use self::read_dir::{read_dir, DirEntry, ReadDir}; +pub use dir_builder::DirBuilder; +pub use file::File; + +/// Wrapper for [`tokio::fs::canonicalize`]. +#[cfg_attr(docsrs, doc(cfg(feature = "tokio")))] +pub async fn canonicalize(path: impl AsRef) -> io::Result { + let path = path.as_ref(); + tokio::fs::canonicalize(path) + .await + .map_err(|err| Error::build(err, ErrorKind::Canonicalize, path)) +} + +/// Wrapper for [`tokio::fs::copy`]. +#[cfg_attr(docsrs, doc(cfg(feature = "tokio")))] +pub async fn copy(from: impl AsRef, to: impl AsRef) -> Result { + let (from, to) = (from.as_ref(), to.as_ref()); + tokio::fs::copy(from, to) + .await + .map_err(|err| SourceDestError::build(err, SourceDestErrorKind::Copy, from, to)) +} + +/// Wrapper for [`tokio::fs::create_dir`]. +#[cfg_attr(docsrs, doc(cfg(feature = "tokio")))] +pub async fn create_dir(path: impl AsRef) -> io::Result<()> { + let path = path.as_ref(); + tokio::fs::create_dir(path) + .await + .map_err(|err| Error::build(err, ErrorKind::CreateDir, path)) +} + +/// Wrapper for [`tokio::fs::create_dir_all`]. +#[cfg_attr(docsrs, doc(cfg(feature = "tokio")))] +pub async fn create_dir_all(path: impl AsRef) -> io::Result<()> { + let path = path.as_ref(); + tokio::fs::create_dir_all(path) + .await + .map_err(|err| Error::build(err, ErrorKind::CreateDir, path)) +} + +/// Wrapper for [`tokio::fs::hard_link`]. +#[cfg_attr(docsrs, doc(cfg(feature = "tokio")))] +pub async fn hard_link(src: impl AsRef, dst: impl AsRef) -> io::Result<()> { + let (src, dst) = (src.as_ref(), dst.as_ref()); + tokio::fs::hard_link(src, dst) + .await + .map_err(|err| SourceDestError::build(err, SourceDestErrorKind::HardLink, src, dst)) +} + +/// Wrapper for [`tokio::fs::metadata`]. +#[cfg_attr(docsrs, doc(cfg(feature = "tokio")))] +pub async fn metadata(path: impl AsRef) -> io::Result { + let path = path.as_ref(); + tokio::fs::metadata(path) + .await + .map_err(|err| Error::build(err, ErrorKind::Metadata, path)) +} + +/// Wrapper for [`tokio::fs::read`]. +#[cfg_attr(docsrs, doc(cfg(feature = "tokio")))] +pub async fn read(path: impl AsRef) -> io::Result> { + let path = path.as_ref(); + tokio::fs::read(path) + .await + .map_err(|err| Error::build(err, ErrorKind::Read, path)) +} + +/// Wrapper for [`tokio::fs::read_link`]. +#[cfg_attr(docsrs, doc(cfg(feature = "tokio")))] +pub async fn read_link(path: impl AsRef) -> io::Result { + let path = path.as_ref(); + tokio::fs::read_link(path) + .await + .map_err(|err| Error::build(err, ErrorKind::ReadLink, path)) +} + +/// Wrapper for [`tokio::fs::read_to_string`]. +#[cfg_attr(docsrs, doc(cfg(feature = "tokio")))] +pub async fn read_to_string(path: impl AsRef) -> io::Result { + let path = path.as_ref(); + tokio::fs::read_to_string(path) + .await + .map_err(|err| Error::build(err, ErrorKind::Read, path)) +} + +/// Wrapper for [`tokio::fs::remove_dir`]. +#[cfg_attr(docsrs, doc(cfg(feature = "tokio")))] +pub async fn remove_dir(path: impl AsRef) -> io::Result<()> { + let path = path.as_ref(); + tokio::fs::remove_dir(path) + .await + .map_err(|err| Error::build(err, ErrorKind::RemoveDir, path)) +} + +/// Wrapper for [`tokio::fs::remove_dir_all`]. +#[cfg_attr(docsrs, doc(cfg(feature = "tokio")))] +pub async fn remove_dir_all(path: impl AsRef) -> io::Result<()> { + let path = path.as_ref(); + tokio::fs::remove_dir_all(path) + .await + .map_err(|err| Error::build(err, ErrorKind::RemoveDir, path)) +} + +/// Wrapper for [`tokio::fs::remove_file`]. +#[cfg_attr(docsrs, doc(cfg(feature = "tokio")))] +pub async fn remove_file(path: impl AsRef) -> io::Result<()> { + let path = path.as_ref(); + tokio::fs::remove_file(path) + .await + .map_err(|err| Error::build(err, ErrorKind::RemoveFile, path)) +} + +/// Wrapper for [`tokio::fs::rename`]. +#[cfg_attr(docsrs, doc(cfg(feature = "tokio")))] +pub async fn rename(from: impl AsRef, to: impl AsRef) -> io::Result<()> { + let (from, to) = (from.as_ref(), to.as_ref()); + tokio::fs::rename(from, to) + .await + .map_err(|err| SourceDestError::build(err, SourceDestErrorKind::Rename, from, to)) +} + +/// Wrapper for [`tokio::fs::set_permissions`]. +#[cfg_attr(docsrs, doc(cfg(feature = "tokio")))] +pub async fn set_permissions(path: impl AsRef, perm: Permissions) -> io::Result<()> { + let path = path.as_ref(); + tokio::fs::set_permissions(path, perm) + .await + .map_err(|err| Error::build(err, ErrorKind::SetPermissions, path)) +} + +/// Wrapper for [`tokio::fs::symlink_metadata`]. +#[cfg_attr(docsrs, doc(cfg(feature = "tokio")))] +pub async fn symlink_metadata(path: impl AsRef) -> io::Result { + let path = path.as_ref(); + tokio::fs::symlink_metadata(path) + .await + .map_err(|err| Error::build(err, ErrorKind::SymlinkMetadata, path)) +} + +/// Wrapper for [`tokio::fs::symlink`]. +#[cfg(unix)] +#[cfg_attr(docsrs, doc(cfg(feature = "tokio")))] +pub async fn symlink(src: impl AsRef, dst: impl AsRef) -> io::Result<()> { + let (src, dst) = (src.as_ref(), dst.as_ref()); + tokio::fs::symlink(src, dst) + .await + .map_err(|err| SourceDestError::build(err, SourceDestErrorKind::Symlink, src, dst)) +} + +/// Wrapper for [`tokio::fs::symlink_dir`]. +#[cfg(windows)] +#[cfg_attr(docsrs, doc(cfg(feature = "tokio")))] +pub async fn symlink(src: impl AsRef, dst: impl AsRef) -> io::Result<()> { + let (src, dst) = (src.as_ref(), dst.as_ref()); + tokio::fs::symlink_dir(src, dst) + .await + .map_err(|err| SourceDestError::build(err, SourceDestErrorKind::SymlinkDir, src, dst)) +} + +/// Wrapper for [`tokio::fs::symlink_file`]. +#[cfg(windows)] +#[cfg_attr(docsrs, doc(cfg(feature = "tokio")))] +pub async fn symlink_file(src: impl AsRef, dst: impl AsRef) -> io::Result<()> { + let (src, dst) = (src.as_ref(), dst.as_ref()); + tokio::fs::symlink_file(src, dst) + .await + .map_err(|err| SourceDestError::build(err, SourceDestErrorKind::SymlinkFile, src, dst)) +} + +/// Wrapper for [`tokio::fs::write`]. +#[cfg_attr(docsrs, doc(cfg(feature = "tokio")))] +pub async fn write(path: impl AsRef, contents: impl AsRef<[u8]>) -> io::Result<()> { + let (path, contents) = (path.as_ref(), contents.as_ref()); + tokio::fs::write(path, contents) + .await + .map_err(|err| Error::build(err, ErrorKind::Write, path)) +} diff --git a/third_party/rust/fs-err/src/tokio/open_options.rs b/third_party/rust/fs-err/src/tokio/open_options.rs new file mode 100644 index 000000000000..6a2b5bf35dab --- /dev/null +++ b/third_party/rust/fs-err/src/tokio/open_options.rs @@ -0,0 +1,109 @@ +use crate::errors::{Error, ErrorKind}; +use crate::tokio::File; +use std::io; +use std::path::Path; +use tokio::fs::OpenOptions as TokioOpenOptions; + +/// Options and flags which can be used to configure how a file is opened. +/// +/// This is a wrapper around [`tokio::fs::OpenOptions`]. +#[derive(Clone, Debug, Default)] +#[cfg_attr(docsrs, doc(cfg(feature = "tokio")))] +pub struct OpenOptions { + tokio: TokioOpenOptions, +} + +impl OpenOptions { + /// Creates a blank new set of options ready for configuration. + /// + /// All options are initially set to `false`. + /// + /// This is a wrapped version of [`tokio::fs::OpenOptions::new`] + /// + /// # Examples + /// + /// ```no_run + /// use fs_err::tokio::OpenOptions; + /// + /// let mut options = OpenOptions::new(); + /// let future = options.read(true).open("foo.txt"); + /// ``` + pub fn new() -> OpenOptions { + OpenOptions { + tokio: TokioOpenOptions::new(), + } + } + + /// Wrapper for [`tokio::fs::OpenOptions::read`]. + pub fn read(&mut self, read: bool) -> &mut OpenOptions { + self.tokio.read(read); + self + } + + /// Wrapper for [`tokio::fs::OpenOptions::write`]. + pub fn write(&mut self, write: bool) -> &mut OpenOptions { + self.tokio.write(write); + self + } + + /// Wrapper for [`tokio::fs::OpenOptions::append`]. + pub fn append(&mut self, append: bool) -> &mut OpenOptions { + self.tokio.append(append); + self + } + + /// Wrapper for [`tokio::fs::OpenOptions::truncate`]. + pub fn truncate(&mut self, truncate: bool) -> &mut OpenOptions { + self.tokio.truncate(truncate); + self + } + + /// Wrapper for [`tokio::fs::OpenOptions::create`]. + pub fn create(&mut self, create: bool) -> &mut OpenOptions { + self.tokio.create(create); + self + } + + /// Wrapper for [`tokio::fs::OpenOptions::create_new`]. + pub fn create_new(&mut self, create_new: bool) -> &mut OpenOptions { + self.tokio.create_new(create_new); + self + } + + /// Wrapper for [`tokio::fs::OpenOptions::open`]. + pub async fn open(&self, path: impl AsRef) -> io::Result { + let path = path.as_ref(); + self.tokio + .open(path) + .await + .map(|f| File::from_parts(f, path)) + .map_err(|err| Error::build(err, ErrorKind::OpenFile, path)) + } +} + +#[cfg(unix)] +impl OpenOptions { + /// Wrapper for [`tokio::fs::OpenOptions::mode`]. + pub fn mode(&mut self, mode: u32) -> &mut OpenOptions { + self.tokio.mode(mode); + self + } + + /// Wrapper for [`tokio::fs::OpenOptions::custom_flags`]. + pub fn custom_flags(&mut self, flags: i32) -> &mut OpenOptions { + self.tokio.custom_flags(flags); + self + } +} + +impl From for OpenOptions { + fn from(std: std::fs::OpenOptions) -> Self { + OpenOptions { tokio: std.into() } + } +} + +impl From for OpenOptions { + fn from(tokio: TokioOpenOptions) -> Self { + OpenOptions { tokio } + } +} diff --git a/third_party/rust/fs-err/src/tokio/read_dir.rs b/third_party/rust/fs-err/src/tokio/read_dir.rs new file mode 100644 index 000000000000..2594edfa92a2 --- /dev/null +++ b/third_party/rust/fs-err/src/tokio/read_dir.rs @@ -0,0 +1,94 @@ +use crate::errors::{Error, ErrorKind}; +use std::ffi::OsString; +use std::fs::{FileType, Metadata}; +use std::io; +use std::path::{Path, PathBuf}; +use std::task::{ready, Context, Poll}; +use tokio::fs; + +/// Wrapper for [`tokio::fs::read_dir`]. +#[cfg_attr(docsrs, doc(cfg(feature = "tokio")))] +pub async fn read_dir(path: impl AsRef) -> io::Result { + let path = path.as_ref(); + let tokio = fs::read_dir(path) + .await + .map_err(|err| Error::build(err, ErrorKind::ReadDir, path))?; + Ok(ReadDir { + tokio, + path: path.to_owned(), + }) +} + +/// Reads the entries in a directory. +/// +/// This is a wrapper around [`tokio::fs::ReadDir`]. +#[derive(Debug)] +#[must_use = "streams do nothing unless polled"] +#[cfg_attr(docsrs, doc(cfg(feature = "tokio")))] +pub struct ReadDir { + tokio: fs::ReadDir, + path: PathBuf, +} + +impl ReadDir { + /// Wrapper around [`tokio::fs::ReadDir::next_entry`]. + pub async fn next_entry(&mut self) -> io::Result> { + match self.tokio.next_entry().await { + Ok(entry) => Ok(entry.map(|e| DirEntry { tokio: e })), + Err(err) => Err(Error::build(err, ErrorKind::ReadDir, &self.path)), + } + } + + /// Wrapper around [`tokio::fs::ReadDir::poll_next_entry`]. + pub fn poll_next_entry(&mut self, cx: &mut Context<'_>) -> Poll>> { + Poll::Ready(match ready!(self.tokio.poll_next_entry(cx)) { + Ok(entry) => Ok(entry.map(|e| DirEntry { tokio: e })), + Err(err) => Err(Error::build(err, ErrorKind::ReadDir, &self.path)), + }) + } +} + +/// Entries returned by the [`ReadDir`] stream. +/// +/// This is a wrapper around [`tokio::fs::DirEntry`]. +#[derive(Debug)] +#[cfg_attr(docsrs, doc(cfg(feature = "tokio")))] +pub struct DirEntry { + tokio: fs::DirEntry, +} + +impl DirEntry { + /// Wrapper around [`tokio::fs::DirEntry::path`]. + pub fn path(&self) -> PathBuf { + self.tokio.path() + } + + /// Wrapper around [`tokio::fs::DirEntry::file_name`]. + pub fn file_name(&self) -> OsString { + self.tokio.file_name() + } + + /// Wrapper around [`tokio::fs::DirEntry::metadata`]. + pub async fn metadata(&self) -> io::Result { + self.tokio + .metadata() + .await + .map_err(|err| Error::build(err, ErrorKind::Metadata, self.path())) + } + + /// Wrapper around [`tokio::fs::DirEntry::file_type`]. + pub async fn file_type(&self) -> io::Result { + self.tokio + .file_type() + .await + .map_err(|err| Error::build(err, ErrorKind::Metadata, self.path())) + } +} + +#[cfg(unix)] +impl DirEntry { + /// Wrapper around [`tokio::fs::DirEntry::ino`]. + pub fn ino(&self) -> u64 { + self.tokio.ino() + } +}