Merge "Update fs-err to 3.1.0" into main
diff --git a/crates/fs-err/.android-checksum.json b/crates/fs-err/.android-checksum.json
index 4fa6903..0efaf8c 100644
--- a/crates/fs-err/.android-checksum.json
+++ b/crates/fs-err/.android-checksum.json
@@ -1 +1 @@
-{"package":null,"files":{".cargo-checksum.json":"c54f34e3f4b1d64848e6da90d966b117bdef12576cf6b066dc6b5c624b56d8be","Android.bp":"0f2feb7fd5a76caac208f8b777aba0d7a12ffff3d6e5ca95a0513befb431240c","CHANGELOG.md":"ba225e2e4a163959c7f47c7d44dcc576d3d7ebf4dada88b2cbec8fc84353bbe4","Cargo.toml":"5dabbf8ed505b7dc761147e8332894e89777896d7c0b6d8217c73e0da7001f8d","LICENSE":"72683dc236dc9b1a88efcc4b5cf18c78f2149c21c9729fba58750a233b93fe47","LICENSE-APACHE":"72683dc236dc9b1a88efcc4b5cf18c78f2149c21c9729fba58750a233b93fe47","LICENSE-MIT":"233fd6bd2767911ab144db38ed781bbf1251e15eaad26b0b53db7b3dc324d255","METADATA":"11d09f7593494c0c059ded191c42fb35ef2a7c3244a2e9fde88d1c9a3134a600","MODULE_LICENSE_APACHE2":"0d6f8afa3940b7f06bebee651376d43bc8b0d5b437337be2696d30377451e93a","README.md":"7065f8d5aa3f62ca4d065acde95377882bc5351093a08e63a77fd88caafd98ae","build.rs":"3f306eb75e4fe2dcf1f10192acdb35127dea3d91e70c032bb8b15f420911a82a","cargo_embargo.json":"651827b0be315dc6c3973d2a32e15065ce98eb06fe43e132de89c8885c120ddd","src/dir.rs":"ecd7c0bee824830a8cf2cc8737d7f03a093315e2c14454ea41b739fb99c9a48d","src/errors.rs":"4220b09455f8a7bd539003975df2841ae54a3f8907ff34691fe67c222a510d98","src/file.rs":"8c9ab40a18e0aee1ced955c510ea1ee941bdcf87abd911b06b1a13a16c177ce5","src/lib.rs":"a2d3626cd71652228fa83b9b5312ca429343774dec44975876b296deb0da29d8","src/open_options.rs":"86e4290023672f9eafbb6f9c13b9b9f7e385b0d70d8bff41ef3e7eaa2f162e05","src/os.rs":"ffb7e398c586997868776af2325ac798525753ae171ac88e87a36d994f519f38","src/os/unix.rs":"f793f46d29e6354be2e7726e475cce3862ed1d02e30f5219890b76d522f22e6a","src/os/windows.rs":"bb74c318777b1d429c07e80f739d689260da47564dac991b72fde447a8ab1d9b","src/path.rs":"a1f22cc73fe7a2c370566a2d830c8e38847b763c600ceb3d6d8345c687f1964c","src/tokio/dir_builder.rs":"5cbed6d1f1cc9eab8f2d41e8f924279675c9eae8c18380c3cc3f591e194747d9","src/tokio/file.rs":"848eca9921df0fc40ab4d300d1682fdabd000d7f6207ae87cf5f1c51714bb6be","src/tokio/mod.rs":"1cbd8f3990bd7b10fc7a46ace89cb73c63525c13ea48c95f794f060e0cbaddb3","src/tokio/open_options.rs":"b47e8bd98bce103e5d41fdf0ff289b211f29a1ac64fa170602e965dad3784bd6","src/tokio/read_dir.rs":"e6e94f8b22a3ff02a982c6394ab41701cccd8cb8099090905545970eaf7c8c7e"}}
\ No newline at end of file
+{"package":null,"files":{".cargo-checksum.json":"6cbfbcdc6fec6b8899f08bde09fd7ce428168c370e39a3a66f4e2c3a5ce8e3c5","Android.bp":"0119a6e10d1dca33b1da5c538080be59b918096412e70a9130d80577f42207ba","CHANGELOG.md":"330a5c58566439bcd7f18a9c6042420f7ea5020f2260a70990a7f3bc7a40f7a8","Cargo.toml":"60aacbb01e2de5c4b6f5d33056475d7a797194ee3cd0dc6d5fbc5c61c28916f9","LICENSE":"72683dc236dc9b1a88efcc4b5cf18c78f2149c21c9729fba58750a233b93fe47","LICENSE-APACHE":"72683dc236dc9b1a88efcc4b5cf18c78f2149c21c9729fba58750a233b93fe47","LICENSE-MIT":"233fd6bd2767911ab144db38ed781bbf1251e15eaad26b0b53db7b3dc324d255","METADATA":"69757f385995432041d415239977f9a20bd2a9b95d432e87b68758cd2f31e6ef","MODULE_LICENSE_APACHE2":"0d6f8afa3940b7f06bebee651376d43bc8b0d5b437337be2696d30377451e93a","README.md":"6146d75312f08a8d8e710f9c3019d49b8f593c0adfaefbfb31e40609007a820b","build.rs":"063693fbd5587847ab073aab7e087cecdf944aa514b3088c27dc55136ac427b3","cargo_embargo.json":"651827b0be315dc6c3973d2a32e15065ce98eb06fe43e132de89c8885c120ddd","src/dir.rs":"ecd7c0bee824830a8cf2cc8737d7f03a093315e2c14454ea41b739fb99c9a48d","src/errors.rs":"61936d4341c9afa77158b0233837ed50bc2425d0026ec8daba1c83543a84bfd2","src/file.rs":"c1ecbd1bde7a380a43b38e0083271b18edb9aa989e1235699486e9f019a66d8e","src/lib.rs":"da6f098deec068b8450b1585a36580d1f4cb671b0d50b4d57ddddfe564f1f3fb","src/open_options.rs":"c456cc8308706a0778a857159899bb89ee712380e77e1f56076b2f5f3c1851e9","src/os.rs":"ffb7e398c586997868776af2325ac798525753ae171ac88e87a36d994f519f38","src/os/unix.rs":"f793f46d29e6354be2e7726e475cce3862ed1d02e30f5219890b76d522f22e6a","src/os/windows.rs":"bb74c318777b1d429c07e80f739d689260da47564dac991b72fde447a8ab1d9b","src/path.rs":"a1f22cc73fe7a2c370566a2d830c8e38847b763c600ceb3d6d8345c687f1964c","src/tokio/dir_builder.rs":"5cbed6d1f1cc9eab8f2d41e8f924279675c9eae8c18380c3cc3f591e194747d9","src/tokio/file.rs":"07203622146c198a06a47dbd51558d5b884576a59766436c4743f43e8301f15f","src/tokio/mod.rs":"12b6bc3d0ead2a075cb098086affe7a08dd2b877793c4d7cc93d470ba4767861","src/tokio/open_options.rs":"b47e8bd98bce103e5d41fdf0ff289b211f29a1ac64fa170602e965dad3784bd6","src/tokio/read_dir.rs":"e6e94f8b22a3ff02a982c6394ab41701cccd8cb8099090905545970eaf7c8c7e"}}
\ No newline at end of file
diff --git a/crates/fs-err/.cargo-checksum.json b/crates/fs-err/.cargo-checksum.json
index 8d549a9..ca49dd3 100644
--- a/crates/fs-err/.cargo-checksum.json
+++ b/crates/fs-err/.cargo-checksum.json
@@ -1 +1 @@
-{"files":{"CHANGELOG.md":"10773f5a450b13fcafece2790a2f061479ecaae87ef48c9b10052c5bdeeb5f70","Cargo.toml":"e5c911a423edc6acbe06979b3a1c91a81a33aca3ba19be638c5a121729552725","LICENSE-APACHE":"7cfd738c53d61c79f07e348f622bf7707c9084237054d37fbe07788a75f5881c","LICENSE-MIT":"36516aefdc84c5d5a1e7485425913a22dbda69eb1930c5e84d6ae4972b5194b9","README.md":"80a833a373a9ba25fbf8ff6e6f93806fce48c39b38c453ada025429a592d490d","build.rs":"f1d5a299d68f91e26fbe9dd642dfcd00e122ec9cb999d4a4b38c6d7200fb9763","src/dir.rs":"07d484f2f9efbfcc67846eb05d687813903f9007bd55aef2d2c7d3b4e7cadd96","src/errors.rs":"80184ce74d67b1d197530eaa56d071bc3df1856bf12bbaa04dee270a6388b0d0","src/file.rs":"75bb885b440f31a067870acdf5fc6080158bf82e31a8cd79536fbc0b2cf1c49f","src/lib.rs":"491160d092e9525d754ac4c7849294cbefe14ef6949363fa644f364e3d6f1c03","src/open_options.rs":"2d93a5431294880b4eab925a752e3f3999e14bdc4a79a26d5516e43c82c42675","src/os.rs":"54fe6cb71a24592de1cb4e1fcebdeaba5e58b26925dbf2dc868e8dd0b0a7bef7","src/os/unix.rs":"e94dd4043babe183f5d77146ca6fef9fe11ecc1e4b572e7eac9814d87c86ba26","src/os/windows.rs":"5f9da192f8f4442fe9656432bf994d7996d4ee1e757ced446bbdc5d057332456","src/path.rs":"13538c226e689b3e5a50e5c39009df665685fafa3a693cc426fd207efb79bf29","src/tokio/dir_builder.rs":"855460e182ebc6a35ff0b381bac4fc5ac1270bab27daa41244211248c9bc316f","src/tokio/file.rs":"4988a9bae3246364c7a8fbb5bbf87ddade75346728d3e8255b5d7d19f51a1068","src/tokio/mod.rs":"bacbe3ceaaefc3a68838d1067ef04981c31be42e34ffcb13d8d2f1f43b5c85d8","src/tokio/open_options.rs":"ec65d13e9b1cf87dc600912749fb3d646b162144ee37b530b96d7705130fef84","src/tokio/read_dir.rs":"be4a567caf7ae253fd4f4925964d65e4b3afa119204156166879afc26e6c548e"},"package":"88a41f105fe1d5b6b34b2055e3dc59bb79b46b48b2040b9e6c7b4b5de097aa41"}
\ No newline at end of file
+{"files":{"CHANGELOG.md":"5072579891e1c6cd05d4909819519be07217e124c29f18eb2fd4f71184800c93","Cargo.toml":"75b3f41f5452a60699e12645f919bc6232d03bd8c1a1a4a8e22cfaab6ce0904c","LICENSE-APACHE":"7cfd738c53d61c79f07e348f622bf7707c9084237054d37fbe07788a75f5881c","LICENSE-MIT":"36516aefdc84c5d5a1e7485425913a22dbda69eb1930c5e84d6ae4972b5194b9","README.md":"2336f74decead21e0d3f6a3122082d2a2ee28a27ed1f05e6cd9f74396dd5e315","build.rs":"11095b891b5601e6a6992df9c65d6385247103d59ceef22c919d351a4ce09f2d","src/dir.rs":"07d484f2f9efbfcc67846eb05d687813903f9007bd55aef2d2c7d3b4e7cadd96","src/errors.rs":"bad82faaf17d505b1faf44f9e5680d97ad3b23b413c2a7987fe715f30e78347e","src/file.rs":"1b4a7bd82a3e06e9ca2286cc8018fb1ed8b65a74b08a4a17c3eca702ecc0acdf","src/lib.rs":"2e9c9871194d19b6b24e03ba119317a93b16bfa5ec29e65cdd896d93c10314ab","src/open_options.rs":"64213c8fe66a42409d2175c56c10fb380d196edac3fe30e33507c87e13c2a703","src/os.rs":"54fe6cb71a24592de1cb4e1fcebdeaba5e58b26925dbf2dc868e8dd0b0a7bef7","src/os/unix.rs":"e94dd4043babe183f5d77146ca6fef9fe11ecc1e4b572e7eac9814d87c86ba26","src/os/windows.rs":"5f9da192f8f4442fe9656432bf994d7996d4ee1e757ced446bbdc5d057332456","src/path.rs":"13538c226e689b3e5a50e5c39009df665685fafa3a693cc426fd207efb79bf29","src/tokio/dir_builder.rs":"855460e182ebc6a35ff0b381bac4fc5ac1270bab27daa41244211248c9bc316f","src/tokio/file.rs":"e24ee167b34cb2ee21f3ab600ef111727cd7f749303bd8fbf5f2fd0a01b871fb","src/tokio/mod.rs":"77075f7d90b14e1b2df32549de698e8d986dbd1e2c26716a7c4e4bdb2940e3e1","src/tokio/open_options.rs":"ec65d13e9b1cf87dc600912749fb3d646b162144ee37b530b96d7705130fef84","src/tokio/read_dir.rs":"be4a567caf7ae253fd4f4925964d65e4b3afa119204156166879afc26e6c548e"},"package":"1f89bda4c2a21204059a977ed3bfe746677dfd137b83c339e702b0ac91d482aa"}
\ No newline at end of file
diff --git a/crates/fs-err/Android.bp b/crates/fs-err/Android.bp
index 046d511..d636f9e 100644
--- a/crates/fs-err/Android.bp
+++ b/crates/fs-err/Android.bp
@@ -18,7 +18,7 @@
host_supported: true,
crate_name: "fs_err",
cargo_env_compat: true,
- cargo_pkg_version: "2.11.0",
+ cargo_pkg_version: "3.1.0",
crate_root: "src/lib.rs",
edition: "2018",
cfgs: ["rustc_1_63"],
diff --git a/crates/fs-err/CHANGELOG.md b/crates/fs-err/CHANGELOG.md
index c2a5d0e..0311ac4 100644
--- a/crates/fs-err/CHANGELOG.md
+++ b/crates/fs-err/CHANGELOG.md
@@ -1,5 +1,29 @@
# fs-err Changelog
+## 3.1.0
+
+* Added new wrappers for `create_new` and `options` functions on `File` ([#69](https://github.com/andrewhickman/fs-err/pull/69))
+
+## 3.0.0
+
+* Error messages now include the original message from `std::io::Error` by default ([#60](https://github.com/andrewhickman/fs-err/pull/60)). Previously this was exposed through the [`Error::source()`](https://doc.rust-lang.org/stable/std/error/trait.Error.html#method.source) method. For example, previously a message would look like:
+
+ ```
+ failed to open file `file.txt`
+ ```
+
+ and you would have to remember to print the source, or use a library like `anyhow` to print the full chain of source errors. The new error message includes the cause by default
+
+ ```
+ failed to open file `file.txt`: The system cannot find the file specified. (os error 2)
+ ```
+
+ Note that the original error is no longer exposed though [`Error::source()`](https://doc.rust-lang.org/stable/std/error/trait.Error.html#method.source) by default. If you need access to it, you can restore the previous behaviour with the `expose_original_error` feature flag.
+
+* The `io_safety` feature flag has been removed, and this functionality is now always enabled on Rust versions which support it (1.63.0 and greater).
+
+* Removed deprecated APIs: `File::from_options`, `tokio::symlink`
+
## 2.11.0
* Added the first line of the standard library documentation to each function's rustdocs, to make them more useful in IDEs ([#50](https://github.com/andrewhickman/fs-err/issues/45))
diff --git a/crates/fs-err/Cargo.toml b/crates/fs-err/Cargo.toml
index f2ea497..b2282b7 100644
--- a/crates/fs-err/Cargo.toml
+++ b/crates/fs-err/Cargo.toml
@@ -12,13 +12,19 @@
[package]
edition = "2018"
name = "fs-err"
-version = "2.11.0"
+version = "3.1.0"
authors = ["Andrew Hickman <[email protected]>"]
+build = "build.rs"
exclude = [
".github",
".gitignore",
"README.tpl",
]
+autolib = false
+autobins = false
+autoexamples = false
+autotests = false
+autobenches = false
description = "A drop-in replacement for std::fs with more helpful error messages."
documentation = "https://docs.rs/fs-err"
readme = "README.md"
@@ -43,14 +49,18 @@
[[package.metadata.release.pre-release-replacements]]
exactly = 1
file = "src/lib.rs"
-replace = "html_root_url = \"https://docs.rs/fs-err/{{version}}\""
+replace = 'html_root_url = "https://docs.rs/fs-err/{{version}}"'
search = 'html_root_url = "https://docs\.rs/fs-err/.*?"'
+[lib]
+name = "fs_err"
+path = "src/lib.rs"
+
[dependencies.tokio]
version = "1.21"
features = ["fs"]
optional = true
-default_features = false
+default-features = false
[dev-dependencies.serde_json]
version = "1.0.64"
@@ -59,4 +69,4 @@
version = "1"
[features]
-io_safety = []
+expose_original_error = []
diff --git a/crates/fs-err/METADATA b/crates/fs-err/METADATA
index e238e59..88210b1 100644
--- a/crates/fs-err/METADATA
+++ b/crates/fs-err/METADATA
@@ -1,17 +1,17 @@
name: "fs-err"
description: "A drop-in replacement for std::fs with more helpful error messages."
third_party {
- version: "2.11.0"
+ version: "3.1.0"
license_type: NOTICE
last_upgrade_date {
- year: 2024
- month: 3
- day: 21
+ year: 2025
+ month: 1
+ day: 22
}
homepage: "https://crates.io/crates/fs-err"
identifier {
type: "Archive"
- value: "https://static.crates.io/crates/fs-err/fs-err-2.11.0.crate"
- version: "2.11.0"
+ value: "https://static.crates.io/crates/fs-err/fs-err-3.1.0.crate"
+ version: "3.1.0"
}
}
diff --git a/crates/fs-err/README.md b/crates/fs-err/README.md
index a0f63ea..d36dc35 100644
--- a/crates/fs-err/README.md
+++ b/crates/fs-err/README.md
@@ -9,76 +9,81 @@
[](https://crates.io/crates/fs-err)
[](https://github.com/andrewhickman/fs-err/actions?query=workflow%3ACI)
-fs-err is a drop-in replacement for [`std::fs`][std::fs] that provides more
-helpful messages on errors. Extra information includes which operations was
-attempted and any involved paths.
-
-## Error Messages
-
-Using [`std::fs`][std::fs], if this code fails:
-
-```rust
-let file = File::open("does not exist.txt")?;
-```
-
-The error message that Rust gives you isn't very useful:
-
-```txt
-The system cannot find the file specified. (os error 2)
-```
-
-...but if we use fs-err instead, our error contains more actionable information:
-
-```txt
-failed to open file `does not exist.txt`
- caused by: The system cannot find the file specified. (os error 2)
-```
-
-## Usage
-
-fs-err's API is the same as [`std::fs`][std::fs], so migrating code to use it is easy.
-
-```rust
-// use std::fs;
-use fs_err as fs;
-
-let contents = fs::read_to_string("foo.txt")?;
-
-println!("Read foo.txt: {}", contents);
-
-```
-
-fs-err uses [`std::io::Error`][std::io::Error] for all errors. This helps fs-err
-compose well with traits from the standard library like
-[`std::io::Read`][std::io::Read] and crates that use them like
-[`serde_json`][serde_json]:
-
-```rust
-use fs_err::File;
-
-let file = File::open("my-config.json")?;
-
-// If an I/O error occurs inside serde_json, the error will include a file path
-// as well as what operation was being performed.
-let decoded: Vec<String> = serde_json::from_reader(file)?;
-
-println!("Program config: {:?}", decoded);
-
-```
-
-[std::fs]: https://doc.rust-lang.org/stable/std/fs/
-[std::io::Error]: https://doc.rust-lang.org/stable/std/io/struct.Error.html
-[std::io::Read]: https://doc.rust-lang.org/stable/std/io/trait.Read.html
+fs-err is a drop-in replacement for [`std::fs`][std::fs] that provides more
+helpful messages on errors. Extra information includes which operations was
+attempted and any involved paths.
+
+## Error Messages
+
+Using [`std::fs`][std::fs], if this code fails:
+
+```rust
+let file = File::open("does not exist.txt")?;
+```
+
+The error message that Rust gives you isn't very useful:
+
+```txt
+The system cannot find the file specified. (os error 2)
+```
+
+...but if we use fs-err instead, our error contains more actionable information:
+
+```txt
+failed to open file `does not exist.txt`: The system cannot find the file specified. (os error 2)
+```
+
+## Usage
+
+fs-err's API is the same as [`std::fs`][std::fs], so migrating code to use it is easy.
+
+```rust
+// use std::fs;
+use fs_err as fs;
+
+let contents = fs::read_to_string("foo.txt")?;
+
+println!("Read foo.txt: {}", contents);
+
+```
+
+fs-err uses [`std::io::Error`][std::io::Error] for all errors. This helps fs-err
+compose well with traits from the standard library like
+[`std::io::Read`][std::io::Read] and crates that use them like
+[`serde_json`][serde_json]:
+
+```rust
+use fs_err::File;
+
+let file = File::open("my-config.json")?;
+
+// If an I/O error occurs inside serde_json, the error will include a file path
+// as well as what operation was being performed.
+let decoded: Vec<String> = serde_json::from_reader(file)?;
+
+println!("Program config: {:?}", decoded);
+
+```
+
+## Feature flags
+
+* `expose_original_error`: when enabled, the [`Error::source()`](https://doc.rust-lang.org/stable/std/error/trait.Error.html#method.source) method of errors returned by this crate return the original `io::Error`. To avoid duplication in error messages,
+ this also suppresses printing its message in their `Display` implementation, so make sure that you are printing the full error chain.
+
+
+## Minimum Supported Rust Version
+
+The oldest rust version this crate is tested on is **1.40**.
+
+This crate will generally be conservative with rust version updates. It uses the [`autocfg`](https://crates.io/crates/autocfg) crate to allow wrapping new APIs without incrementing the MSRV.
+
+If the `tokio` feature is enabled, this crate will inherit the MSRV of the selected [`tokio`](https://crates.io/crates/tokio) version.
+
+[std::fs]: https://doc.rust-lang.org/stable/std/fs/
+[std::io::Error]: https://doc.rust-lang.org/stable/std/io/struct.Error.html
+[std::io::Read]: https://doc.rust-lang.org/stable/std/io/trait.Read.html
[serde_json]: https://crates.io/crates/serde_json
-## Minimum Supported Rust Version
-
-The oldest rust version this crate is tested on is **1.40**.
-
-This crate will generally be conservative with rust version updates. It uses the [`autocfg`](https://crates.io/crates/autocfg) crate to allow wrapping new APIs without incrementing the MSRV.
-
-If the `tokio` feature is enabled, this crate will inherit the MSRV of the selected [`tokio`](https://crates.io/crates/tokio) version.
-
## License
Licensed under either of
@@ -93,4 +98,4 @@
Unless you explicitly state otherwise, any contribution intentionally
submitted for inclusion in the work by you, as defined in the Apache-2.0
license, shall be dual licensed as above, without any additional terms or
-conditions.
+conditions.
diff --git a/crates/fs-err/build.rs b/crates/fs-err/build.rs
index 954dd27..0879439 100644
--- a/crates/fs-err/build.rs
+++ b/crates/fs-err/build.rs
@@ -4,4 +4,7 @@
let ac = autocfg::new();
// Allows `#[cfg(rustc_1_63)]` to be used in code
ac.emit_rustc_version(1, 63);
+
+ // Re-run if this file changes
+ autocfg::rerun_path("build.rs");
}
diff --git a/crates/fs-err/src/errors.rs b/crates/fs-err/src/errors.rs
index d732c0e..906be14 100644
--- a/crates/fs-err/src/errors.rs
+++ b/crates/fs-err/src/errors.rs
@@ -63,41 +63,49 @@
impl fmt::Display for Error {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
- use ErrorKind::*;
+ use ErrorKind as E;
let path = self.path.display();
match self.kind {
- OpenFile => write!(formatter, "failed to open file `{}`", path),
- CreateFile => write!(formatter, "failed to create file `{}`", path),
- CreateDir => write!(formatter, "failed to create directory `{}`", path),
- SyncFile => write!(formatter, "failed to sync file `{}`", path),
- SetLen => write!(formatter, "failed to set length of file `{}`", path),
- Metadata => write!(formatter, "failed to query metadata of file `{}`", path),
- Clone => write!(formatter, "failed to clone handle for file `{}`", path),
- SetPermissions => write!(formatter, "failed to set permissions for file `{}`", path),
- Read => write!(formatter, "failed to read from file `{}`", path),
- Seek => write!(formatter, "failed to seek in file `{}`", path),
- Write => write!(formatter, "failed to write to file `{}`", path),
- Flush => write!(formatter, "failed to flush file `{}`", path),
- ReadDir => write!(formatter, "failed to read directory `{}`", path),
- RemoveFile => write!(formatter, "failed to remove file `{}`", path),
- RemoveDir => write!(formatter, "failed to remove directory `{}`", path),
- Canonicalize => write!(formatter, "failed to canonicalize path `{}`", path),
- ReadLink => write!(formatter, "failed to read symbolic link `{}`", path),
- SymlinkMetadata => write!(formatter, "failed to query metadata of symlink `{}`", path),
- FileExists => write!(formatter, "failed to check file existance `{}`", path),
+ E::OpenFile => write!(formatter, "failed to open file `{}`", path),
+ E::CreateFile => write!(formatter, "failed to create file `{}`", path),
+ E::CreateDir => write!(formatter, "failed to create directory `{}`", path),
+ E::SyncFile => write!(formatter, "failed to sync file `{}`", path),
+ E::SetLen => write!(formatter, "failed to set length of file `{}`", path),
+ E::Metadata => write!(formatter, "failed to query metadata of file `{}`", path),
+ E::Clone => write!(formatter, "failed to clone handle for file `{}`", path),
+ E::SetPermissions => write!(formatter, "failed to set permissions for file `{}`", path),
+ E::Read => write!(formatter, "failed to read from file `{}`", path),
+ E::Seek => write!(formatter, "failed to seek in file `{}`", path),
+ E::Write => write!(formatter, "failed to write to file `{}`", path),
+ E::Flush => write!(formatter, "failed to flush file `{}`", path),
+ E::ReadDir => write!(formatter, "failed to read directory `{}`", path),
+ E::RemoveFile => write!(formatter, "failed to remove file `{}`", path),
+ E::RemoveDir => write!(formatter, "failed to remove directory `{}`", path),
+ E::Canonicalize => write!(formatter, "failed to canonicalize path `{}`", path),
+ E::ReadLink => write!(formatter, "failed to read symbolic link `{}`", path),
+ E::SymlinkMetadata => {
+ write!(formatter, "failed to query metadata of symlink `{}`", path)
+ }
+ E::FileExists => write!(formatter, "failed to check file existence `{}`", path),
#[cfg(windows)]
- SeekRead => write!(formatter, "failed to seek and read from `{}`", path),
+ E::SeekRead => write!(formatter, "failed to seek and read from `{}`", path),
#[cfg(windows)]
- SeekWrite => write!(formatter, "failed to seek and write to `{}`", path),
+ E::SeekWrite => write!(formatter, "failed to seek and write to `{}`", path),
#[cfg(unix)]
- ReadAt => write!(formatter, "failed to read with offset from `{}`", path),
+ E::ReadAt => write!(formatter, "failed to read with offset from `{}`", path),
#[cfg(unix)]
- WriteAt => write!(formatter, "failed to write with offset to `{}`", path),
- }
+ E::WriteAt => write!(formatter, "failed to write with offset to `{}`", path),
+ }?;
+
+ // The `expose_original_error` feature indicates the caller should display the original error
+ #[cfg(not(feature = "expose_original_error"))]
+ write!(formatter, ": {}", self.source)?;
+
+ Ok(())
}
}
@@ -106,6 +114,12 @@
self.source()
}
+ #[cfg(not(feature = "expose_original_error"))]
+ fn source(&self) -> Option<&(dyn StdError + 'static)> {
+ None
+ }
+
+ #[cfg(feature = "expose_original_error")]
fn source(&self) -> Option<&(dyn StdError + 'static)> {
Some(&self.source)
}
@@ -186,7 +200,13 @@
SourceDestErrorKind::SymlinkDir => {
write!(formatter, "failed to symlink dir from {} to {}", from, to)
}
- }
+ }?;
+
+ // The `expose_original_error` feature indicates the caller should display the original error
+ #[cfg(not(feature = "expose_original_error"))]
+ write!(formatter, ": {}", self.source)?;
+
+ Ok(())
}
}
@@ -195,6 +215,12 @@
self.source()
}
+ #[cfg(not(feature = "expose_original_error"))]
+ fn source(&self) -> Option<&(dyn StdError + 'static)> {
+ None
+ }
+
+ #[cfg(feature = "expose_original_error")]
fn source(&self) -> Option<&(dyn StdError + 'static)> {
Some(&self.source)
}
diff --git a/crates/fs-err/src/file.rs b/crates/fs-err/src/file.rs
index acdb3c2..f8c5ad1 100644
--- a/crates/fs-err/src/file.rs
+++ b/crates/fs-err/src/file.rs
@@ -3,6 +3,7 @@
use std::path::{Path, PathBuf};
use crate::errors::{Error, ErrorKind};
+use crate::OpenOptions;
/// Wrapper around [`std::fs::File`][std::fs::File] which adds more helpful
/// information to all errors.
@@ -57,22 +58,33 @@
}
}
- /// Wrapper for [`OpenOptions::open`](https://doc.rust-lang.org/stable/std/fs/struct.OpenOptions.html#method.open).
+ /// Opens a file in read-write mode.
///
- /// This takes [`&std::fs::OpenOptions`](https://doc.rust-lang.org/stable/std/fs/struct.OpenOptions.html),
- /// not [`crate::OpenOptions`].
- #[deprecated = "use fs_err::OpenOptions::open instead"]
- pub fn from_options<P>(path: P, options: &fs::OpenOptions) -> Result<Self, io::Error>
+ /// Wrapper for [`File::create_new`](https://doc.rust-lang.org/stable/std/fs/struct.File.html#method.create_new).
+ pub fn create_new<P>(path: P) -> Result<Self, io::Error>
where
P: Into<PathBuf>,
{
let path = path.into();
- match options.open(&path) {
+ // TODO: Use fs::File::create_new once MSRV is at least 1.77
+ match fs::OpenOptions::new()
+ .read(true)
+ .write(true)
+ .create_new(true)
+ .open(&path)
+ {
Ok(file) => Ok(File::from_parts(file, path)),
- Err(source) => Err(Error::build(source, ErrorKind::OpenFile, path)),
+ Err(err) => Err(Error::build(err, ErrorKind::CreateFile, path)),
}
}
+ /// Returns a new `OpenOptions` object.
+ ///
+ /// Wrapper for [`File::options`](https://doc.rust-lang.org/stable/std/fs/struct.File.html#method.options).
+ pub fn options() -> OpenOptions {
+ OpenOptions::new()
+ }
+
/// Attempts to sync all OS-internal metadata to disk.
///
/// Wrapper for [`File::sync_all`](https://doc.rust-lang.org/stable/std/fs/struct.File.html#method.sync_all).
@@ -194,7 +206,7 @@
}
}
-impl<'a> Read for &'a File {
+impl Read for &File {
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
(&self.file)
.read(buf)
@@ -222,7 +234,7 @@
}
}
-impl<'a> Seek for &'a File {
+impl Seek for &File {
fn seek(&mut self, pos: std::io::SeekFrom) -> std::io::Result<u64> {
(&self.file)
.seek(pos)
@@ -250,7 +262,7 @@
}
}
-impl<'a> Write for &'a File {
+impl Write for &File {
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
(&self.file)
.write(buf)
@@ -303,18 +315,16 @@
}
}
- #[cfg(feature = "io_safety")]
+ #[cfg(rustc_1_63)]
mod io_safety {
use std::os::unix::io::{AsFd, BorrowedFd, OwnedFd};
- #[cfg_attr(docsrs, doc(cfg(feature = "io_safety")))]
impl AsFd for crate::File {
fn as_fd(&self) -> BorrowedFd<'_> {
self.file().as_fd()
}
}
- #[cfg_attr(docsrs, doc(cfg(feature = "io_safety")))]
impl From<crate::File> for OwnedFd {
fn from(file: crate::File) -> Self {
file.into_parts().0.into()
@@ -363,18 +373,16 @@
}
}
- #[cfg(feature = "io_safety")]
+ #[cfg(rustc_1_63)]
mod io_safety {
use std::os::windows::io::{AsHandle, BorrowedHandle, OwnedHandle};
- #[cfg_attr(docsrs, doc(cfg(feature = "io_safety")))]
impl AsHandle for crate::File {
fn as_handle(&self) -> BorrowedHandle<'_> {
self.file().as_handle()
}
}
- #[cfg_attr(docsrs, doc(cfg(feature = "io_safety")))]
impl From<crate::File> for OwnedHandle {
fn from(file: crate::File) -> Self {
file.into_parts().0.into()
diff --git a/crates/fs-err/src/lib.rs b/crates/fs-err/src/lib.rs
index b1ef0d5..51b64fa 100644
--- a/crates/fs-err/src/lib.rs
+++ b/crates/fs-err/src/lib.rs
@@ -22,8 +22,7 @@
...but if we use fs-err instead, our error contains more actionable information:
```txt
-failed to open file `does not exist.txt`
- caused by: The system cannot find the file specified. (os error 2)
+failed to open file `does not exist.txt`: The system cannot find the file specified. (os error 2)
```
# Usage
@@ -60,13 +59,27 @@
# Ok::<(), Box<dyn std::error::Error>>(())
```
+# Feature flags
+
+* `expose_original_error`: when enabled, the [`Error::source()`](https://doc.rust-lang.org/stable/std/error/trait.Error.html#method.source) method of errors returned by this crate return the original `io::Error`. To avoid duplication in error messages,
+ this also suppresses printing its message in their `Display` implementation, so make sure that you are printing the full error chain.
+
+
+# Minimum Supported Rust Version
+
+The oldest rust version this crate is tested on is **1.40**.
+
+This crate will generally be conservative with rust version updates. It uses the [`autocfg`](https://crates.io/crates/autocfg) crate to allow wrapping new APIs without incrementing the MSRV.
+
+If the `tokio` feature is enabled, this crate will inherit the MSRV of the selected [`tokio`](https://crates.io/crates/tokio) version.
+
[std::fs]: https://doc.rust-lang.org/stable/std/fs/
[std::io::Error]: https://doc.rust-lang.org/stable/std/io/struct.Error.html
[std::io::Read]: https://doc.rust-lang.org/stable/std/io/trait.Read.html
[serde_json]: https://crates.io/crates/serde_json
*/
-#![doc(html_root_url = "https://docs.rs/fs-err/2.11.0")]
+#![doc(html_root_url = "https://docs.rs/fs-err/3.1.0")]
#![deny(missing_debug_implementations, missing_docs)]
#![cfg_attr(docsrs, feature(doc_cfg))]
diff --git a/crates/fs-err/src/open_options.rs b/crates/fs-err/src/open_options.rs
index 08c3562..66f006c 100644
--- a/crates/fs-err/src/open_options.rs
+++ b/crates/fs-err/src/open_options.rs
@@ -1,4 +1,7 @@
use std::{fs, io, path::PathBuf};
+
+use crate::errors::{Error, ErrorKind};
+
#[derive(Clone, Debug)]
/// Wrapper around [`std::fs::OpenOptions`](https://doc.rust-lang.org/std/fs/struct.OpenOptions.html)
pub struct OpenOptions(fs::OpenOptions);
@@ -67,12 +70,11 @@
where
P: Into<PathBuf>,
{
- // We have to either duplicate the logic or call the deprecated method here.
- // We can't let the deprecated function call this method, because we can't construct
- // `&fs_err::OpenOptions` from `&fs::OpenOptions` without cloning
- // (although cloning would probably be cheap).
- #[allow(deprecated)]
- crate::File::from_options(path.into(), self.options())
+ let path = path.into();
+ match self.0.open(&path) {
+ Ok(file) => Ok(crate::File::from_parts(file, path)),
+ Err(source) => Err(Error::build(source, ErrorKind::OpenFile, path)),
+ }
}
}
diff --git a/crates/fs-err/src/tokio/file.rs b/crates/fs-err/src/tokio/file.rs
index 2a005ba..7e73ba7 100644
--- a/crates/fs-err/src/tokio/file.rs
+++ b/crates/fs-err/src/tokio/file.rs
@@ -9,6 +9,8 @@
use tokio::fs::File as TokioFile;
use tokio::io::{AsyncRead, AsyncSeek, AsyncWrite, ReadBuf};
+use super::OpenOptions;
+
/// Wrapper around [`tokio::fs::File`] which adds more helpful
/// information to all errors.
#[derive(Debug)]
@@ -41,6 +43,24 @@
}
}
+ /// Opens a file in read-write mode.
+ ///
+ /// Wrapper for [`tokio::fs::File::create_new`].
+ pub async fn create_new(path: impl Into<PathBuf>) -> Result<Self, io::Error> {
+ let path = path.into();
+ match fs::File::create_new(&path).await {
+ Ok(file) => Ok(File::from_parts(file, path)),
+ Err(err) => Err(Error::build(err, ErrorKind::CreateFile, path)),
+ }
+ }
+
+ /// Returns a new `OpenOptions` object.
+ ///
+ /// Wrapper for [`tokio::fs::File::options`].
+ pub fn options() -> OpenOptions {
+ OpenOptions::new()
+ }
+
/// Converts a [`crate::File`] to a [`tokio::fs::File`].
///
/// Wrapper for [`tokio::fs::File::from_std`].
diff --git a/crates/fs-err/src/tokio/mod.rs b/crates/fs-err/src/tokio/mod.rs
index 1a56532..e34f514 100644
--- a/crates/fs-err/src/tokio/mod.rs
+++ b/crates/fs-err/src/tokio/mod.rs
@@ -203,16 +203,6 @@
/// Wrapper for [`tokio::fs::symlink_dir`].
#[cfg(windows)]
#[cfg_attr(docsrs, doc(cfg(feature = "tokio")))]
-#[deprecated = "use fs_err::tokio::symlink_dir instead"]
-pub async fn symlink(src: impl AsRef<Path>, dst: impl AsRef<Path>) -> io::Result<()> {
- symlink_dir(src, dst).await
-}
-
-/// Creates a new directory symlink on the filesystem.
-///
-/// Wrapper for [`tokio::fs::symlink_dir`].
-#[cfg(windows)]
-#[cfg_attr(docsrs, doc(cfg(feature = "tokio")))]
pub async fn symlink_dir(src: impl AsRef<Path>, dst: impl AsRef<Path>) -> io::Result<()> {
let (src, dst) = (src.as_ref(), dst.as_ref());
tokio::fs::symlink_dir(src, dst)
diff --git a/pseudo_crate/Cargo.lock b/pseudo_crate/Cargo.lock
index 6e7ff72..b75a369 100644
--- a/pseudo_crate/Cargo.lock
+++ b/pseudo_crate/Cargo.lock
@@ -2122,9 +2122,9 @@
[[package]]
name = "fs-err"
-version = "2.11.0"
+version = "3.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "88a41f105fe1d5b6b34b2055e3dc59bb79b46b48b2040b9e6c7b4b5de097aa41"
+checksum = "1f89bda4c2a21204059a977ed3bfe746677dfd137b83c339e702b0ac91d482aa"
dependencies = [
"autocfg",
]
diff --git a/pseudo_crate/Cargo.toml b/pseudo_crate/Cargo.toml
index 0b5ce4f..8523bc5 100644
--- a/pseudo_crate/Cargo.toml
+++ b/pseudo_crate/Cargo.toml
@@ -114,7 +114,7 @@
foreign-types-shared = "=0.1.1"
form_urlencoded = "=1.2.1"
fragile = "=2.0.0"
-fs-err = "=2.11.0"
+fs-err = "=3.1.0"
futures = "=0.3.31"
futures-channel = "=0.3.31"
futures-core = "=0.3.31"