Import async-fs 1.6.0 upstream upstream/1.6.0
authorDongHun Kwak <dh0128.kwak@samsung.com>
Wed, 12 Apr 2023 06:57:32 +0000 (15:57 +0900)
committerDongHun Kwak <dh0128.kwak@samsung.com>
Wed, 12 Apr 2023 06:57:32 +0000 (15:57 +0900)
.cargo_vcs_info.json [new file with mode: 0644]
CHANGELOG.md [new file with mode: 0644]
Cargo.toml [new file with mode: 0644]
Cargo.toml.orig [new file with mode: 0644]
LICENSE-APACHE [new file with mode: 0644]
LICENSE-MIT [new file with mode: 0644]
README.md [new file with mode: 0644]
build.rs [new file with mode: 0644]
src/lib.rs [new file with mode: 0644]

diff --git a/.cargo_vcs_info.json b/.cargo_vcs_info.json
new file mode 100644 (file)
index 0000000..ca479d0
--- /dev/null
@@ -0,0 +1,6 @@
+{
+  "git": {
+    "sha1": "92868805ac261d14912e42893a4a1c5c01505d96"
+  },
+  "path_in_vcs": ""
+}
\ No newline at end of file
diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644 (file)
index 0000000..7df849a
--- /dev/null
@@ -0,0 +1,48 @@
+# Version 1.6.0
+
+- Implement I/O safety traits on Rust 1.63+ (#13)
+
+# Version 1.5.0
+
+- Replace `&mut self` with `&self` on the following methods:
+    - `File::sync_data()`
+    - `File::sync_all()`
+    - `File::set_len()`
+
+# Version 1.4.0
+
+- Define new extension traits instead of implementing those from `std`.
+
+# Version 1.3.0
+
+- Implement `FromRawFd`/`FromRawHandle` for `File`.
+- Implement `OpenOptionsExt` for `OpenOptions` on Windows.
+- Re-export some extension traits into OS-specific modules.
+
+# Version 1.2.1
+
+- Optimization: Don't flush if the file is already flushed.
+
+# Version 1.2.0
+
+- Update `blocking` to v1.0
+
+# Version 1.1.2
+
+- Do not reposition the cursor if the file is not seekable.
+
+# Version 1.1.1
+
+- Update dependencies.
+
+# Version 1.1.0
+
+- Implement `From<std::fs::File>` for `File`.
+
+# Version 1.0.1
+
+- Fix build error on https://docs.rs
+
+# Version 1.0.0
+
+- Initial version
diff --git a/Cargo.toml b/Cargo.toml
new file mode 100644 (file)
index 0000000..d108247
--- /dev/null
@@ -0,0 +1,53 @@
+# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
+#
+# When uploading crates to the registry Cargo will automatically
+# "normalize" Cargo.toml files for maximal compatibility
+# with all versions of Cargo and also rewrite `path` dependencies
+# to registry (e.g., crates.io) dependencies.
+#
+# If you are reading this file be aware that the original Cargo.toml
+# will likely look very different (and much more reasonable).
+# See Cargo.toml.orig for the original contents.
+
+[package]
+edition = "2018"
+rust-version = "1.47"
+name = "async-fs"
+version = "1.6.0"
+authors = ["Stjepan Glavina <stjepang@gmail.com>"]
+exclude = ["/.*"]
+description = "Async filesystem primitives"
+homepage = "https://github.com/smol-rs/async-fs"
+documentation = "https://docs.rs/async-fs"
+readme = "README.md"
+keywords = [
+    "asynchronous",
+    "file",
+    "filesystem",
+    "io",
+]
+categories = [
+    "asynchronous",
+    "concurrency",
+]
+license = "Apache-2.0 OR MIT"
+repository = "https://github.com/smol-rs/async-fs"
+
+[dependencies.async-lock]
+version = "2.3.0"
+
+[dependencies.blocking]
+version = "1.0.0"
+
+[dependencies.futures-lite]
+version = "1.2.0"
+
+[build-dependencies.autocfg]
+version = "1"
+
+[target."cfg(unix)".dev-dependencies.libc]
+version = "0.2.78"
+
+[target."cfg(windows)".dev-dependencies.winapi]
+version = "0.3.9"
+features = ["winbase"]
diff --git a/Cargo.toml.orig b/Cargo.toml.orig
new file mode 100644 (file)
index 0000000..fd63870
--- /dev/null
@@ -0,0 +1,31 @@
+[package]
+name = "async-fs"
+# When publishing a new version:
+# - Update CHANGELOG.md
+# - Create "v1.x.y" git tag
+version = "1.6.0"
+authors = ["Stjepan Glavina <stjepang@gmail.com>"]
+edition = "2018"
+rust-version = "1.47"
+description = "Async filesystem primitives"
+license = "Apache-2.0 OR MIT"
+repository = "https://github.com/smol-rs/async-fs"
+homepage = "https://github.com/smol-rs/async-fs"
+documentation = "https://docs.rs/async-fs"
+keywords = ["asynchronous", "file", "filesystem", "io"]
+categories = ["asynchronous", "concurrency"]
+exclude = ["/.*"]
+
+[dependencies]
+async-lock = "2.3.0"
+blocking = "1.0.0"
+futures-lite = "1.2.0"
+
+[build-dependencies]
+autocfg = "1"
+
+[target.'cfg(unix)'.dev-dependencies]
+libc = "0.2.78"
+
+[target.'cfg(windows)'.dev-dependencies]
+winapi = { version = "0.3.9", features = ["winbase"] }
diff --git a/LICENSE-APACHE b/LICENSE-APACHE
new file mode 100644 (file)
index 0000000..16fe87b
--- /dev/null
@@ -0,0 +1,201 @@
+                              Apache License
+                        Version 2.0, January 2004
+                     http://www.apache.org/licenses/
+
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+1. Definitions.
+
+   "License" shall mean the terms and conditions for use, reproduction,
+   and distribution as defined by Sections 1 through 9 of this document.
+
+   "Licensor" shall mean the copyright owner or entity authorized by
+   the copyright owner that is granting the License.
+
+   "Legal Entity" shall mean the union of the acting entity and all
+   other entities that control, are controlled by, or are under common
+   control with that entity. For the purposes of this definition,
+   "control" means (i) the power, direct or indirect, to cause the
+   direction or management of such entity, whether by contract or
+   otherwise, or (ii) ownership of fifty percent (50%) or more of the
+   outstanding shares, or (iii) beneficial ownership of such entity.
+
+   "You" (or "Your") shall mean an individual or Legal Entity
+   exercising permissions granted by this License.
+
+   "Source" form shall mean the preferred form for making modifications,
+   including but not limited to software source code, documentation
+   source, and configuration files.
+
+   "Object" form shall mean any form resulting from mechanical
+   transformation or translation of a Source form, including but
+   not limited to compiled object code, generated documentation,
+   and conversions to other media types.
+
+   "Work" shall mean the work of authorship, whether in Source or
+   Object form, made available under the License, as indicated by a
+   copyright notice that is included in or attached to the work
+   (an example is provided in the Appendix below).
+
+   "Derivative Works" shall mean any work, whether in Source or Object
+   form, that is based on (or derived from) the Work and for which the
+   editorial revisions, annotations, elaborations, or other modifications
+   represent, as a whole, an original work of authorship. For the purposes
+   of this License, Derivative Works shall not include works that remain
+   separable from, or merely link (or bind by name) to the interfaces of,
+   the Work and Derivative Works thereof.
+
+   "Contribution" shall mean any work of authorship, including
+   the original version of the Work and any modifications or additions
+   to that Work or Derivative Works thereof, that is intentionally
+   submitted to Licensor for inclusion in the Work by the copyright owner
+   or by an individual or Legal Entity authorized to submit on behalf of
+   the copyright owner. For the purposes of this definition, "submitted"
+   means any form of electronic, verbal, or written communication sent
+   to the Licensor or its representatives, including but not limited to
+   communication on electronic mailing lists, source code control systems,
+   and issue tracking systems that are managed by, or on behalf of, the
+   Licensor for the purpose of discussing and improving the Work, but
+   excluding communication that is conspicuously marked or otherwise
+   designated in writing by the copyright owner as "Not a Contribution."
+
+   "Contributor" shall mean Licensor and any individual or Legal Entity
+   on behalf of whom a Contribution has been received by Licensor and
+   subsequently incorporated within the Work.
+
+2. Grant of Copyright License. Subject to the terms and conditions of
+   this License, each Contributor hereby grants to You a perpetual,
+   worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+   copyright license to reproduce, prepare Derivative Works of,
+   publicly display, publicly perform, sublicense, and distribute the
+   Work and such Derivative Works in Source or Object form.
+
+3. Grant of Patent License. Subject to the terms and conditions of
+   this License, each Contributor hereby grants to You a perpetual,
+   worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+   (except as stated in this section) patent license to make, have made,
+   use, offer to sell, sell, import, and otherwise transfer the Work,
+   where such license applies only to those patent claims licensable
+   by such Contributor that are necessarily infringed by their
+   Contribution(s) alone or by combination of their Contribution(s)
+   with the Work to which such Contribution(s) was submitted. If You
+   institute patent litigation against any entity (including a
+   cross-claim or counterclaim in a lawsuit) alleging that the Work
+   or a Contribution incorporated within the Work constitutes direct
+   or contributory patent infringement, then any patent licenses
+   granted to You under this License for that Work shall terminate
+   as of the date such litigation is filed.
+
+4. Redistribution. You may reproduce and distribute copies of the
+   Work or Derivative Works thereof in any medium, with or without
+   modifications, and in Source or Object form, provided that You
+   meet the following conditions:
+
+   (a) You must give any other recipients of the Work or
+       Derivative Works a copy of this License; and
+
+   (b) You must cause any modified files to carry prominent notices
+       stating that You changed the files; and
+
+   (c) You must retain, in the Source form of any Derivative Works
+       that You distribute, all copyright, patent, trademark, and
+       attribution notices from the Source form of the Work,
+       excluding those notices that do not pertain to any part of
+       the Derivative Works; and
+
+   (d) If the Work includes a "NOTICE" text file as part of its
+       distribution, then any Derivative Works that You distribute must
+       include a readable copy of the attribution notices contained
+       within such NOTICE file, excluding those notices that do not
+       pertain to any part of the Derivative Works, in at least one
+       of the following places: within a NOTICE text file distributed
+       as part of the Derivative Works; within the Source form or
+       documentation, if provided along with the Derivative Works; or,
+       within a display generated by the Derivative Works, if and
+       wherever such third-party notices normally appear. The contents
+       of the NOTICE file are for informational purposes only and
+       do not modify the License. You may add Your own attribution
+       notices within Derivative Works that You distribute, alongside
+       or as an addendum to the NOTICE text from the Work, provided
+       that such additional attribution notices cannot be construed
+       as modifying the License.
+
+   You may add Your own copyright statement to Your modifications and
+   may provide additional or different license terms and conditions
+   for use, reproduction, or distribution of Your modifications, or
+   for any such Derivative Works as a whole, provided Your use,
+   reproduction, and distribution of the Work otherwise complies with
+   the conditions stated in this License.
+
+5. Submission of Contributions. Unless You explicitly state otherwise,
+   any Contribution intentionally submitted for inclusion in the Work
+   by You to the Licensor shall be under the terms and conditions of
+   this License, without any additional terms or conditions.
+   Notwithstanding the above, nothing herein shall supersede or modify
+   the terms of any separate license agreement you may have executed
+   with Licensor regarding such Contributions.
+
+6. Trademarks. This License does not grant permission to use the trade
+   names, trademarks, service marks, or product names of the Licensor,
+   except as required for reasonable and customary use in describing the
+   origin of the Work and reproducing the content of the NOTICE file.
+
+7. Disclaimer of Warranty. Unless required by applicable law or
+   agreed to in writing, Licensor provides the Work (and each
+   Contributor provides its Contributions) on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+   implied, including, without limitation, any warranties or conditions
+   of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+   PARTICULAR PURPOSE. You are solely responsible for determining the
+   appropriateness of using or redistributing the Work and assume any
+   risks associated with Your exercise of permissions under this License.
+
+8. Limitation of Liability. In no event and under no legal theory,
+   whether in tort (including negligence), contract, or otherwise,
+   unless required by applicable law (such as deliberate and grossly
+   negligent acts) or agreed to in writing, shall any Contributor be
+   liable to You for damages, including any direct, indirect, special,
+   incidental, or consequential damages of any character arising as a
+   result of this License or out of the use or inability to use the
+   Work (including but not limited to damages for loss of goodwill,
+   work stoppage, computer failure or malfunction, or any and all
+   other commercial damages or losses), even if such Contributor
+   has been advised of the possibility of such damages.
+
+9. Accepting Warranty or Additional Liability. While redistributing
+   the Work or Derivative Works thereof, You may choose to offer,
+   and charge a fee for, acceptance of support, warranty, indemnity,
+   or other liability obligations and/or rights consistent with this
+   License. However, in accepting such obligations, You may act only
+   on Your own behalf and on Your sole responsibility, not on behalf
+   of any other Contributor, and only if You agree to indemnify,
+   defend, and hold each Contributor harmless for any liability
+   incurred by, or claims asserted against, such Contributor by reason
+   of your accepting any such warranty or additional liability.
+
+END OF TERMS AND CONDITIONS
+
+APPENDIX: How to apply the Apache License to your work.
+
+   To apply the Apache License to your work, attach the following
+   boilerplate notice, with the fields enclosed by brackets "[]"
+   replaced with your own identifying information. (Don't include
+   the brackets!)  The text should be enclosed in the appropriate
+   comment syntax for the file format. We also recommend that a
+   file or class name and description of purpose be included on the
+   same "printed page" as the copyright notice for easier
+   identification within third-party archives.
+
+Copyright [yyyy] [name of copyright owner]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
diff --git a/LICENSE-MIT b/LICENSE-MIT
new file mode 100644 (file)
index 0000000..31aa793
--- /dev/null
@@ -0,0 +1,23 @@
+Permission is hereby granted, free of charge, to any
+person obtaining a copy of this software and associated
+documentation files (the "Software"), to deal in the
+Software without restriction, including without
+limitation the rights to use, copy, modify, merge,
+publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software
+is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice
+shall be included in all copies or substantial portions
+of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
+ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
+TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
+SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
+IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
diff --git a/README.md b/README.md
new file mode 100644 (file)
index 0000000..35013d5
--- /dev/null
+++ b/README.md
@@ -0,0 +1,48 @@
+# async-fs
+
+[![Build](https://github.com/smol-rs/async-fs/workflows/Build%20and%20test/badge.svg)](
+https://github.com/smol-rs/async-fs/actions)
+[![License](https://img.shields.io/badge/license-Apache--2.0_OR_MIT-blue.svg)](
+https://github.com/smol-rs/async-fs)
+[![Cargo](https://img.shields.io/crates/v/async-fs.svg)](
+https://crates.io/crates/async-fs)
+[![Documentation](https://docs.rs/async-fs/badge.svg)](
+https://docs.rs/async-fs)
+
+Async filesystem primitives.
+
+This crate is an async version of `std::fs`.
+
+## Implementation
+
+This crate uses [`blocking`] to offload blocking I/O onto a thread pool.
+
+[`blocking`]: https://docs.rs/blocking
+
+## Examples
+
+Create a new file and write some bytes to it:
+
+```rust
+use async_fs::File;
+use futures_lite::io::AsyncWriteExt;
+
+let mut file = File::create("a.txt").await?;
+file.write_all(b"Hello, world!").await?;
+file.flush().await?;
+```
+
+## License
+
+Licensed under either of
+
+ * Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0)
+ * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)
+
+at your option.
+
+#### Contribution
+
+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.
diff --git a/build.rs b/build.rs
new file mode 100644 (file)
index 0000000..10a25b1
--- /dev/null
+++ b/build.rs
@@ -0,0 +1,16 @@
+fn main() {
+    let cfg = match autocfg::AutoCfg::new() {
+        Ok(cfg) => cfg,
+        Err(e) => {
+            println!(
+                "cargo:warning=async-fs: failed to detect compiler features: {}",
+                e
+            );
+            return;
+        }
+    };
+
+    if !cfg.probe_rustc_version(1, 63) {
+        autocfg::emit("async_fs_no_io_safety");
+    }
+}
diff --git a/src/lib.rs b/src/lib.rs
new file mode 100644 (file)
index 0000000..c524789
--- /dev/null
@@ -0,0 +1,1812 @@
+//! Async filesystem primitives.
+//!
+//! This crate is an async version of [`std::fs`].
+//!
+//! # Implementation
+//!
+//! This crate uses [`blocking`] to offload blocking I/O onto a thread pool.
+//!
+//! [`blocking`]: https://docs.rs/blocking
+//!
+//! # Examples
+//!
+//! Create a new file and write some bytes to it:
+//!
+//! ```no_run
+//! use async_fs::File;
+//! use futures_lite::io::AsyncWriteExt;
+//!
+//! # futures_lite::future::block_on(async {
+//! let mut file = File::create("a.txt").await?;
+//! file.write_all(b"Hello, world!").await?;
+//! file.flush().await?;
+//! # std::io::Result::Ok(()) });
+//! ```
+
+#![warn(missing_docs, missing_debug_implementations, rust_2018_idioms)]
+
+use std::ffi::OsString;
+use std::fmt;
+use std::future::Future;
+use std::io::{self, SeekFrom};
+use std::path::{Path, PathBuf};
+use std::pin::Pin;
+use std::sync::Arc;
+use std::task::{Context, Poll};
+
+#[cfg(unix)]
+use std::os::unix::fs::{DirEntryExt as _, OpenOptionsExt as _};
+
+#[cfg(windows)]
+use std::os::windows::fs::OpenOptionsExt as _;
+
+use async_lock::Mutex;
+use blocking::{unblock, Unblock};
+use futures_lite::io::{AsyncRead, AsyncSeek, AsyncWrite, AsyncWriteExt};
+use futures_lite::stream::Stream;
+use futures_lite::{future, ready};
+
+#[doc(no_inline)]
+pub use std::fs::{FileType, Metadata, Permissions};
+
+/// Returns the canonical form of a path.
+///
+/// The returned path is in absolute form with all intermediate components normalized and symbolic
+/// links resolved.
+///
+/// # Errors
+///
+/// An error will be returned in the following situations:
+///
+/// * `path` does not point to an existing file or directory.
+/// * A non-final component in `path` is not a directory.
+/// * Some other I/O error occurred.
+///
+/// # Examples
+///
+/// ```no_run
+/// # futures_lite::future::block_on(async {
+/// let path = async_fs::canonicalize(".").await?;
+/// # std::io::Result::Ok(()) });
+/// ```
+pub async fn canonicalize<P: AsRef<Path>>(path: P) -> io::Result<PathBuf> {
+    let path = path.as_ref().to_owned();
+    unblock(move || std::fs::canonicalize(&path)).await
+}
+
+/// Copies a file to a new location.
+///
+/// On success, the total number of bytes copied is returned and equals the length of the `dst`
+/// file after this operation.
+///
+/// The old contents of `dst` will be overwritten. If `src` and `dst` both point to the same
+/// file, then the file will likely get truncated as a result of this operation.
+///
+/// If you're working with open [`File`]s and want to copy contents through those types, use
+/// [`futures_lite::io::copy()`] instead.
+///
+/// # Errors
+///
+/// An error will be returned in the following situations:
+///
+/// * `src` does not point to an existing file.
+/// * The current process lacks permissions to read `src` or write `dst`.
+/// * Some other I/O error occurred.
+///
+/// # Examples
+///
+/// ```no_run
+/// # futures_lite::future::block_on(async {
+/// let num_bytes = async_fs::copy("a.txt", "b.txt").await?;
+/// # std::io::Result::Ok(()) });
+/// ```
+pub async fn copy<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dst: Q) -> io::Result<u64> {
+    let src = src.as_ref().to_owned();
+    let dst = dst.as_ref().to_owned();
+    unblock(move || std::fs::copy(&src, &dst)).await
+}
+
+/// Creates a directory.
+///
+/// Note that this function will only create the final directory in `path`. If you want to create
+/// all of its missing parent directories too, use [`create_dir_all()`] instead.
+///
+/// # Errors
+///
+/// An error will be returned in the following situations:
+///
+/// * `path` already points to an existing file or directory.
+/// * A parent directory in `path` does not exist.
+/// * The current process lacks permissions to create the directory.
+/// * Some other I/O error occurred.
+///
+/// # Examples
+///
+/// ```no_run
+/// # futures_lite::future::block_on(async {
+/// async_fs::create_dir("./some/directory").await?;
+/// # std::io::Result::Ok(()) });
+/// ```
+pub async fn create_dir<P: AsRef<Path>>(path: P) -> io::Result<()> {
+    let path = path.as_ref().to_owned();
+    unblock(move || std::fs::create_dir(&path)).await
+}
+
+/// Creates a directory and its parent directories if they are missing.
+///
+/// # Errors
+///
+/// An error will be returned in the following situations:
+///
+/// * `path` already points to an existing file or directory.
+/// * The current process lacks permissions to create the directory or its missing parents.
+/// * Some other I/O error occurred.
+///
+/// # Examples
+///
+/// ```no_run
+/// # futures_lite::future::block_on(async {
+/// async_fs::create_dir_all("./some/directory").await?;
+/// # std::io::Result::Ok(()) });
+/// ```
+pub async fn create_dir_all<P: AsRef<Path>>(path: P) -> io::Result<()> {
+    let path = path.as_ref().to_owned();
+    unblock(move || std::fs::create_dir_all(&path)).await
+}
+
+/// Creates a hard link on the filesystem.
+///
+/// The `dst` path will be a link pointing to the `src` path. Note that operating systems often
+/// require these two paths to be located on the same filesystem.
+///
+/// # Errors
+///
+/// An error will be returned in the following situations:
+///
+/// * `src` does not point to an existing file.
+/// * Some other I/O error occurred.
+///
+/// # Examples
+///
+/// ```no_run
+/// # futures_lite::future::block_on(async {
+/// async_fs::hard_link("a.txt", "b.txt").await?;
+/// # std::io::Result::Ok(()) });
+/// ```
+pub async fn hard_link<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dst: Q) -> io::Result<()> {
+    let src = src.as_ref().to_owned();
+    let dst = dst.as_ref().to_owned();
+    unblock(move || std::fs::hard_link(&src, &dst)).await
+}
+
+/// Reads metadata for a path.
+///
+/// This function will traverse symbolic links to read metadata for the target file or directory.
+/// If you want to read metadata without following symbolic links, use [`symlink_metadata()`]
+/// instead.
+///
+/// # Errors
+///
+/// An error will be returned in the following situations:
+///
+/// * `path` does not point to an existing file or directory.
+/// * The current process lacks permissions to read metadata for the path.
+/// * Some other I/O error occurred.
+///
+/// # Examples
+///
+/// ```no_run
+/// # futures_lite::future::block_on(async {
+/// let perm = async_fs::metadata("a.txt").await?.permissions();
+/// # std::io::Result::Ok(()) });
+/// ```
+pub async fn metadata<P: AsRef<Path>>(path: P) -> io::Result<Metadata> {
+    let path = path.as_ref().to_owned();
+    unblock(move || std::fs::metadata(path)).await
+}
+
+/// Reads the entire contents of a file as raw bytes.
+///
+/// This is a convenience function for reading entire files. It pre-allocates a buffer based on the
+/// file size when available, so it is typically faster than manually opening a file and reading
+/// from it.
+///
+/// If you want to read the contents as a string, use [`read_to_string()`] instead.
+///
+/// # Errors
+///
+/// An error will be returned in the following situations:
+///
+/// * `path` does not point to an existing file.
+/// * The current process lacks permissions to read the file.
+/// * Some other I/O error occurred.
+///
+/// # Examples
+///
+/// ```no_run
+/// # futures_lite::future::block_on(async {
+/// let contents = async_fs::read("a.txt").await?;
+/// # std::io::Result::Ok(()) });
+/// ```
+pub async fn read<P: AsRef<Path>>(path: P) -> io::Result<Vec<u8>> {
+    let path = path.as_ref().to_owned();
+    unblock(move || std::fs::read(&path)).await
+}
+
+/// Returns a stream of entries in a directory.
+///
+/// The stream yields items of type [`io::Result`]`<`[`DirEntry`]`>`. Note that I/O errors can
+/// occur while reading from the stream.
+///
+/// # Errors
+///
+/// An error will be returned in the following situations:
+///
+/// * `path` does not point to an existing directory.
+/// * The current process lacks permissions to read the contents of the directory.
+/// * Some other I/O error occurred.
+///
+/// # Examples
+///
+/// ```no_run
+/// # futures_lite::future::block_on(async {
+/// use futures_lite::stream::StreamExt;
+///
+/// let mut entries = async_fs::read_dir(".").await?;
+///
+/// while let Some(entry) = entries.try_next().await? {
+///     println!("{}", entry.file_name().to_string_lossy());
+/// }
+/// # std::io::Result::Ok(()) });
+/// ```
+pub async fn read_dir<P: AsRef<Path>>(path: P) -> io::Result<ReadDir> {
+    let path = path.as_ref().to_owned();
+    unblock(move || std::fs::read_dir(&path).map(|inner| ReadDir(State::Idle(Some(inner))))).await
+}
+
+/// A stream of entries in a directory.
+///
+/// This stream is returned by [`read_dir()`] and yields items of type
+/// [`io::Result`]`<`[`DirEntry`]`>`. Each [`DirEntry`] can then retrieve information like entry's
+/// path or metadata.
+pub struct ReadDir(State);
+
+/// The state of an asynchronous `ReadDir`.
+///
+/// The `ReadDir` can be either idle or busy performing an asynchronous operation.
+enum State {
+    Idle(Option<std::fs::ReadDir>),
+    Busy(future::Boxed<(std::fs::ReadDir, Option<io::Result<std::fs::DirEntry>>)>),
+}
+
+impl fmt::Debug for ReadDir {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.debug_struct("ReadDir").finish()
+    }
+}
+
+impl Stream for ReadDir {
+    type Item = io::Result<DirEntry>;
+
+    fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
+        loop {
+            match &mut self.0 {
+                State::Idle(opt) => {
+                    let mut inner = opt.take().unwrap();
+
+                    // Start the operation asynchronously.
+                    self.0 = State::Busy(Box::pin(unblock(move || {
+                        let next = inner.next();
+                        (inner, next)
+                    })));
+                }
+                // Poll the asynchronous operation the file is currently blocked on.
+                State::Busy(task) => {
+                    let (inner, opt) = ready!(task.as_mut().poll(cx));
+                    self.0 = State::Idle(Some(inner));
+                    return Poll::Ready(opt.map(|res| res.map(|inner| DirEntry(Arc::new(inner)))));
+                }
+            }
+        }
+    }
+}
+
+/// An entry in a directory.
+///
+/// A stream of entries in a directory is returned by [`read_dir()`].
+///
+/// For Unix-specific options, import the [`DirEntryExt`][`std::os::unix::fs::DirEntryExt`] trait.
+pub struct DirEntry(Arc<std::fs::DirEntry>);
+
+impl DirEntry {
+    /// Returns the full path to this entry.
+    ///
+    /// The full path is created by joining the original path passed to [`read_dir()`] with the
+    /// name of this entry.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use futures_lite::stream::StreamExt;
+    ///
+    /// # futures_lite::future::block_on(async {
+    /// let mut dir = async_fs::read_dir(".").await?;
+    ///
+    /// while let Some(entry) = dir.try_next().await? {
+    ///     println!("{:?}", entry.path());
+    /// }
+    /// # std::io::Result::Ok(()) });
+    /// ```
+    pub fn path(&self) -> PathBuf {
+        self.0.path()
+    }
+
+    /// Reads the metadata for this entry.
+    ///
+    /// This function will traverse symbolic links to read the metadata.
+    ///
+    /// If you want to read metadata without following symbolic links, use [`symlink_metadata()`]
+    /// instead.
+    ///
+    /// # Errors
+    ///
+    /// An error will be returned in the following situations:
+    ///
+    /// * This entry does not point to an existing file or directory anymore.
+    /// * The current process lacks permissions to read the metadata.
+    /// * Some other I/O error occurred.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use futures_lite::stream::StreamExt;
+    ///
+    /// # futures_lite::future::block_on(async {
+    /// let mut dir = async_fs::read_dir(".").await?;
+    ///
+    /// while let Some(entry) = dir.try_next().await? {
+    ///     println!("{:?}", entry.metadata().await?);
+    /// }
+    /// # std::io::Result::Ok(()) });
+    /// ```
+    pub async fn metadata(&self) -> io::Result<Metadata> {
+        let inner = self.0.clone();
+        unblock(move || inner.metadata()).await
+    }
+
+    /// Reads the file type for this entry.
+    ///
+    /// This function will not traverse symbolic links if this entry points at one.
+    ///
+    /// If you want to read metadata with following symbolic links, use [`metadata()`] instead.
+    ///
+    /// # Errors
+    ///
+    /// An error will be returned in the following situations:
+    ///
+    /// * This entry does not point to an existing file or directory anymore.
+    /// * The current process lacks permissions to read this entry's metadata.
+    /// * Some other I/O error occurred.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use futures_lite::stream::StreamExt;
+    ///
+    /// # futures_lite::future::block_on(async {
+    /// let mut dir = async_fs::read_dir(".").await?;
+    ///
+    /// while let Some(entry) = dir.try_next().await? {
+    ///     println!("{:?}", entry.file_type().await?);
+    /// }
+    /// # std::io::Result::Ok(()) });
+    /// ```
+    pub async fn file_type(&self) -> io::Result<FileType> {
+        let inner = self.0.clone();
+        unblock(move || inner.file_type()).await
+    }
+
+    /// Returns the bare name of this entry without the leading path.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use futures_lite::stream::StreamExt;
+    ///
+    /// # futures_lite::future::block_on(async {
+    /// let mut dir = async_fs::read_dir(".").await?;
+    ///
+    /// while let Some(entry) = dir.try_next().await? {
+    ///     println!("{}", entry.file_name().to_string_lossy());
+    /// }
+    /// # std::io::Result::Ok(()) });
+    /// ```
+    pub fn file_name(&self) -> OsString {
+        self.0.file_name()
+    }
+}
+
+impl fmt::Debug for DirEntry {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.debug_tuple("DirEntry").field(&self.path()).finish()
+    }
+}
+
+impl Clone for DirEntry {
+    fn clone(&self) -> Self {
+        DirEntry(self.0.clone())
+    }
+}
+
+#[cfg(unix)]
+impl unix::DirEntryExt for DirEntry {
+    fn ino(&self) -> u64 {
+        self.0.ino()
+    }
+}
+
+/// Reads a symbolic link and returns the path it points to.
+///
+/// # Errors
+///
+/// An error will be returned in the following situations:
+///
+/// * `path` does not point to an existing link.
+/// * Some other I/O error occurred.
+///
+/// # Examples
+///
+/// ```no_run
+/// # futures_lite::future::block_on(async {
+/// let path = async_fs::read_link("a.txt").await?;
+/// # std::io::Result::Ok(()) });
+/// ```
+pub async fn read_link<P: AsRef<Path>>(path: P) -> io::Result<PathBuf> {
+    let path = path.as_ref().to_owned();
+    unblock(move || std::fs::read_link(&path)).await
+}
+
+/// Reads the entire contents of a file as a string.
+///
+/// This is a convenience function for reading entire files. It pre-allocates a string based on the
+/// file size when available, so it is typically faster than manually opening a file and reading
+/// from it.
+///
+/// If you want to read the contents as raw bytes, use [`read()`] instead.
+///
+/// # Errors
+///
+/// An error will be returned in the following situations:
+///
+/// * `path` does not point to an existing file.
+/// * The current process lacks permissions to read the file.
+/// * The contents of the file cannot be read as a UTF-8 string.
+/// * Some other I/O error occurred.
+///
+/// # Examples
+///
+/// ```no_run
+/// # futures_lite::future::block_on(async {
+/// let contents = async_fs::read_to_string("a.txt").await?;
+/// # std::io::Result::Ok(()) });
+/// ```
+pub async fn read_to_string<P: AsRef<Path>>(path: P) -> io::Result<String> {
+    let path = path.as_ref().to_owned();
+    unblock(move || std::fs::read_to_string(&path)).await
+}
+
+/// Removes an empty directory.
+///
+/// Note that this function can only delete an empty directory. If you want to delete a directory
+/// and all of its contents, use [`remove_dir_all()`] instead.
+///
+/// # Errors
+///
+/// An error will be returned in the following situations:
+///
+/// * `path` is not an existing and empty directory.
+/// * The current process lacks permissions to remove the directory.
+/// * Some other I/O error occurred.
+///
+/// # Examples
+///
+/// ```no_run
+/// # futures_lite::future::block_on(async {
+/// async_fs::remove_dir("./some/directory").await?;
+/// # std::io::Result::Ok(()) });
+/// ```
+pub async fn remove_dir<P: AsRef<Path>>(path: P) -> io::Result<()> {
+    let path = path.as_ref().to_owned();
+    unblock(move || std::fs::remove_dir(&path)).await
+}
+
+/// Removes a directory and all of its contents.
+///
+/// # Errors
+///
+/// An error will be returned in the following situations:
+///
+/// * `path` is not an existing and empty directory.
+/// * The current process lacks permissions to remove the directory.
+/// * Some other I/O error occurred.
+///
+/// # Examples
+///
+/// ```no_run
+/// # futures_lite::future::block_on(async {
+/// async_fs::remove_dir_all("./some/directory").await?;
+/// # std::io::Result::Ok(()) });
+/// ```
+pub async fn remove_dir_all<P: AsRef<Path>>(path: P) -> io::Result<()> {
+    let path = path.as_ref().to_owned();
+    unblock(move || std::fs::remove_dir_all(&path)).await
+}
+
+/// Removes a file.
+///
+/// # Errors
+///
+/// An error will be returned in the following situations:
+///
+/// * `path` does not point to an existing file.
+/// * The current process lacks permissions to remove the file.
+/// * Some other I/O error occurred.
+///
+/// # Examples
+///
+/// ```no_run
+/// # futures_lite::future::block_on(async {
+/// async_fs::remove_file("a.txt").await?;
+/// # std::io::Result::Ok(()) });
+/// ```
+pub async fn remove_file<P: AsRef<Path>>(path: P) -> io::Result<()> {
+    let path = path.as_ref().to_owned();
+    unblock(move || std::fs::remove_file(&path)).await
+}
+
+/// Renames a file or directory to a new location.
+///
+/// If a file or directory already exists at the target location, it will be overwritten by this
+/// operation.
+///
+/// # Errors
+///
+/// An error will be returned in the following situations:
+///
+/// * `src` does not point to an existing file or directory.
+/// * `src` and `dst` are on different filesystems.
+/// * The current process lacks permissions to do the rename operation.
+/// * Some other I/O error occurred.
+///
+/// # Examples
+///
+/// ```no_run
+/// # futures_lite::future::block_on(async {
+/// async_fs::rename("a.txt", "b.txt").await?;
+/// # std::io::Result::Ok(()) });
+/// ```
+pub async fn rename<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dst: Q) -> io::Result<()> {
+    let src = src.as_ref().to_owned();
+    let dst = dst.as_ref().to_owned();
+    unblock(move || std::fs::rename(&src, &dst)).await
+}
+
+/// Changes the permissions of a file or directory.
+///
+/// # Errors
+///
+/// An error will be returned in the following situations:
+///
+/// * `path` does not point to an existing file or directory.
+/// * The current process lacks permissions to change attributes on the file or directory.
+/// * Some other I/O error occurred.
+///
+/// # Examples
+///
+/// ```no_run
+/// # futures_lite::future::block_on(async {
+/// let mut perm = async_fs::metadata("a.txt").await?.permissions();
+/// perm.set_readonly(true);
+/// async_fs::set_permissions("a.txt", perm).await?;
+/// # std::io::Result::Ok(()) });
+/// ```
+pub async fn set_permissions<P: AsRef<Path>>(path: P, perm: Permissions) -> io::Result<()> {
+    let path = path.as_ref().to_owned();
+    unblock(move || std::fs::set_permissions(path, perm)).await
+}
+
+/// Reads metadata for a path without following symbolic links.
+///
+/// If you want to follow symbolic links before reading metadata of the target file or directory,
+/// use [`metadata()`] instead.
+///
+/// # Errors
+///
+/// An error will be returned in the following situations:
+///
+/// * `path` does not point to an existing file or directory.
+/// * The current process lacks permissions to read metadata for the path.
+/// * Some other I/O error occurred.
+///
+/// # Examples
+///
+/// ```no_run
+/// # futures_lite::future::block_on(async {
+/// let perm = async_fs::symlink_metadata("a.txt").await?.permissions();
+/// # std::io::Result::Ok(()) });
+/// ```
+pub async fn symlink_metadata<P: AsRef<Path>>(path: P) -> io::Result<Metadata> {
+    let path = path.as_ref().to_owned();
+    unblock(move || std::fs::symlink_metadata(path)).await
+}
+
+/// Writes a slice of bytes as the new contents of a file.
+///
+/// This function will create a file if it does not exist, and will entirely replace its contents
+/// if it does.
+///
+/// # Errors
+///
+/// An error will be returned in the following situations:
+///
+/// * The file's parent directory does not exist.
+/// * The current process lacks permissions to write to the file.
+/// * Some other I/O error occurred.
+///
+/// # Examples
+///
+/// ```no_run
+/// # futures_lite::future::block_on(async {
+/// async_fs::write("a.txt", b"Hello world!").await?;
+/// # std::io::Result::Ok(()) });
+/// ```
+pub async fn write<P: AsRef<Path>, C: AsRef<[u8]>>(path: P, contents: C) -> io::Result<()> {
+    let path = path.as_ref().to_owned();
+    let contents = contents.as_ref().to_owned();
+    unblock(move || std::fs::write(&path, contents)).await
+}
+
+/// A builder for creating directories with configurable options.
+///
+/// For Unix-specific options, import the [`DirBuilderExt`][`std::os::unix::fs::DirBuilderExt`]
+/// trait.
+#[derive(Debug, Default)]
+pub struct DirBuilder {
+    /// Set to `true` if non-existent parent directories should be created.
+    recursive: bool,
+
+    /// Unix mode for newly created directories.
+    #[cfg(unix)]
+    mode: Option<u32>,
+}
+
+impl DirBuilder {
+    /// Creates a blank set of options.
+    ///
+    /// The [`recursive()`][`DirBuilder::recursive()`] option is initially set to `false`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use async_fs::DirBuilder;
+    ///
+    /// let builder = DirBuilder::new();
+    /// ```
+    pub fn new() -> DirBuilder {
+        #[cfg(not(unix))]
+        let builder = DirBuilder { recursive: false };
+
+        #[cfg(unix)]
+        let builder = DirBuilder {
+            recursive: false,
+            mode: None,
+        };
+
+        builder
+    }
+
+    /// Sets the option for recursive mode.
+    ///
+    /// When set to `true`, this option means all parent directories should be created recursively
+    /// if they don't exist. Parents are created with the same permissions as the final directory.
+    ///
+    /// This option is initially set to `false`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use async_fs::DirBuilder;
+    ///
+    /// let mut builder = DirBuilder::new();
+    /// builder.recursive(true);
+    /// ```
+    pub fn recursive(&mut self, recursive: bool) -> &mut Self {
+        self.recursive = recursive;
+        self
+    }
+
+    /// Creates a directory with the configured options.
+    ///
+    /// It is considered an error if the directory already exists unless recursive mode is enabled.
+    ///
+    /// # Errors
+    ///
+    /// An error will be returned in the following situations:
+    ///
+    /// * `path` already points to an existing file or directory.
+    /// * The current process lacks permissions to create the directory or its missing parents.
+    /// * Some other I/O error occurred.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use async_fs::DirBuilder;
+    ///
+    /// # futures_lite::future::block_on(async {
+    /// DirBuilder::new()
+    ///     .recursive(true)
+    ///     .create("./some/directory")
+    ///     .await?;
+    /// # std::io::Result::Ok(()) });
+    /// ```
+    pub fn create<P: AsRef<Path>>(&self, path: P) -> impl Future<Output = io::Result<()>> {
+        let mut builder = std::fs::DirBuilder::new();
+        builder.recursive(self.recursive);
+
+        #[cfg(unix)]
+        {
+            if let Some(mode) = self.mode {
+                std::os::unix::fs::DirBuilderExt::mode(&mut builder, mode);
+            }
+        }
+
+        let path = path.as_ref().to_owned();
+        unblock(move || builder.create(path))
+    }
+}
+
+#[cfg(unix)]
+impl unix::DirBuilderExt for DirBuilder {
+    fn mode(&mut self, mode: u32) -> &mut Self {
+        self.mode = Some(mode);
+        self
+    }
+}
+
+/// An open file on the filesystem.
+///
+/// Depending on what options the file was opened with, this type can be used for reading and/or
+/// writing.
+///
+/// Files are automatically closed when they get dropped and any errors detected on closing are
+/// ignored. Use the [`sync_all()`][`File::sync_all()`] method before dropping a file if such
+/// errors need to be handled.
+///
+/// **NOTE:** If writing to a file, make sure to call
+/// [`flush()`][`futures_lite::io::AsyncWriteExt::flush()`], [`sync_data()`][`File::sync_data()`],
+/// or [`sync_all()`][`File::sync_all()`] before dropping the file or else some written data
+/// might get lost!
+///
+/// # Examples
+///
+/// Create a new file and write some bytes to it:
+///
+/// ```no_run
+/// use async_fs::File;
+/// use futures_lite::io::AsyncWriteExt;
+///
+/// # futures_lite::future::block_on(async {
+/// let mut file = File::create("a.txt").await?;
+///
+/// file.write_all(b"Hello, world!").await?;
+/// file.flush().await?;
+/// # std::io::Result::Ok(()) });
+/// ```
+///
+/// Read the contents of a file into a vector of bytes:
+///
+/// ```no_run
+/// use async_fs::File;
+/// use futures_lite::io::AsyncReadExt;
+///
+/// # futures_lite::future::block_on(async {
+/// let mut file = File::open("a.txt").await?;
+///
+/// let mut contents = Vec::new();
+/// file.read_to_end(&mut contents).await?;
+/// # std::io::Result::Ok(()) });
+/// ```
+pub struct File {
+    /// Always accessible reference to the file.
+    file: Arc<std::fs::File>,
+
+    /// Performs blocking I/O operations on a thread pool.
+    unblock: Mutex<Unblock<ArcFile>>,
+
+    /// Logical file cursor, tracked when reading from the file.
+    ///
+    /// This will be set to an error if the file is not seekable.
+    read_pos: Option<io::Result<u64>>,
+
+    /// Set to `true` if the file needs flushing.
+    is_dirty: bool,
+}
+
+impl File {
+    /// Creates an async file from a blocking file.
+    fn new(inner: std::fs::File, is_dirty: bool) -> File {
+        let file = Arc::new(inner);
+        let unblock = Mutex::new(Unblock::new(ArcFile(file.clone())));
+        let read_pos = None;
+        File {
+            file,
+            unblock,
+            read_pos,
+            is_dirty,
+        }
+    }
+
+    /// Opens a file in read-only mode.
+    ///
+    /// See the [`OpenOptions::open()`] function for more options.
+    ///
+    /// # Errors
+    ///
+    /// An error will be returned in the following situations:
+    ///
+    /// * `path` does not point to an existing file.
+    /// * The current process lacks permissions to read the file.
+    /// * Some other I/O error occurred.
+    ///
+    /// For more details, see the list of errors documented by [`OpenOptions::open()`].
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use async_fs::File;
+    ///
+    /// # futures_lite::future::block_on(async {
+    /// let file = File::open("a.txt").await?;
+    /// # std::io::Result::Ok(()) });
+    /// ```
+    pub async fn open<P: AsRef<Path>>(path: P) -> io::Result<File> {
+        let path = path.as_ref().to_owned();
+        let file = unblock(move || std::fs::File::open(&path)).await?;
+        Ok(File::new(file, false))
+    }
+
+    /// Opens a file in write-only mode.
+    ///
+    /// This method will create a file if it does not exist, and will truncate it if it does.
+    ///
+    /// See the [`OpenOptions::open`] function for more options.
+    ///
+    /// # Errors
+    ///
+    /// An error will be returned in the following situations:
+    ///
+    /// * The file's parent directory does not exist.
+    /// * The current process lacks permissions to write to the file.
+    /// * Some other I/O error occurred.
+    ///
+    /// For more details, see the list of errors documented by [`OpenOptions::open()`].
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use async_fs::File;
+    ///
+    /// # futures_lite::future::block_on(async {
+    /// let file = File::create("a.txt").await?;
+    /// # std::io::Result::Ok(()) });
+    /// ```
+    pub async fn create<P: AsRef<Path>>(path: P) -> io::Result<File> {
+        let path = path.as_ref().to_owned();
+        let file = unblock(move || std::fs::File::create(&path)).await?;
+        Ok(File::new(file, false))
+    }
+
+    /// Synchronizes OS-internal buffered contents and metadata to disk.
+    ///
+    /// This function will ensure that all in-memory data reaches the filesystem.
+    ///
+    /// This can be used to handle errors that would otherwise only be caught by closing the file.
+    /// When a file is dropped, errors in synchronizing this in-memory data are ignored.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use async_fs::File;
+    /// use futures_lite::io::AsyncWriteExt;
+    ///
+    /// # futures_lite::future::block_on(async {
+    /// let mut file = File::create("a.txt").await?;
+    ///
+    /// file.write_all(b"Hello, world!").await?;
+    /// file.sync_all().await?;
+    /// # std::io::Result::Ok(()) });
+    /// ```
+    pub async fn sync_all(&self) -> io::Result<()> {
+        let mut inner = self.unblock.lock().await;
+        inner.flush().await?;
+        let file = self.file.clone();
+        unblock(move || file.sync_all()).await
+    }
+
+    /// Synchronizes OS-internal buffered contents to disk.
+    ///
+    /// This is similar to [`sync_all()`][`File::sync_data()`], except that file metadata may not
+    /// be synchronized.
+    ///
+    /// This is intended for use cases that must synchronize the contents of the file, but don't
+    /// need the file metadata synchronized to disk.
+    ///
+    /// Note that some platforms may simply implement this in terms of
+    /// [`sync_all()`][`File::sync_data()`].
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use async_fs::File;
+    /// use futures_lite::io::AsyncWriteExt;
+    ///
+    /// # futures_lite::future::block_on(async {
+    /// let mut file = File::create("a.txt").await?;
+    ///
+    /// file.write_all(b"Hello, world!").await?;
+    /// file.sync_data().await?;
+    /// # std::io::Result::Ok(()) });
+    /// ```
+    pub async fn sync_data(&self) -> io::Result<()> {
+        let mut inner = self.unblock.lock().await;
+        inner.flush().await?;
+        let file = self.file.clone();
+        unblock(move || file.sync_data()).await
+    }
+
+    /// Truncates or extends the file.
+    ///
+    /// If `size` is less than the current file size, then the file will be truncated. If it is
+    /// greater than the current file size, then the file will be extended to `size` and have all
+    /// intermediate data filled with zeros.
+    ///
+    /// The file's cursor stays at the same position, even if the cursor ends up being past the end
+    /// of the file after this operation.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use async_fs::File;
+    ///
+    /// # futures_lite::future::block_on(async {
+    /// let mut file = File::create("a.txt").await?;
+    /// file.set_len(10).await?;
+    /// # std::io::Result::Ok(()) });
+    /// ```
+    pub async fn set_len(&self, size: u64) -> io::Result<()> {
+        let mut inner = self.unblock.lock().await;
+        inner.flush().await?;
+        let file = self.file.clone();
+        unblock(move || file.set_len(size)).await
+    }
+
+    /// Reads the file's metadata.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use async_fs::File;
+    ///
+    /// # futures_lite::future::block_on(async {
+    /// let file = File::open("a.txt").await?;
+    /// let metadata = file.metadata().await?;
+    /// # std::io::Result::Ok(()) });
+    /// ```
+    pub async fn metadata(&self) -> io::Result<Metadata> {
+        let file = self.file.clone();
+        unblock(move || file.metadata()).await
+    }
+
+    /// Changes the permissions on the file.
+    ///
+    /// # Errors
+    ///
+    /// An error will be returned in the following situations:
+    ///
+    /// * The current process lacks permissions to change attributes on the file.
+    /// * Some other I/O error occurred.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use async_fs::File;
+    ///
+    /// # futures_lite::future::block_on(async {
+    /// let file = File::create("a.txt").await?;
+    ///
+    /// let mut perms = file.metadata().await?.permissions();
+    /// perms.set_readonly(true);
+    /// file.set_permissions(perms).await?;
+    /// # std::io::Result::Ok(()) });
+    /// ```
+    pub async fn set_permissions(&self, perm: Permissions) -> io::Result<()> {
+        let file = self.file.clone();
+        unblock(move || file.set_permissions(perm)).await
+    }
+
+    /// Repositions the cursor after reading.
+    ///
+    /// When reading from a file, actual file reads run asynchronously in the background, which
+    /// means the real file cursor is usually ahead of the logical cursor, and the data between
+    /// them is buffered in memory. This kind of buffering is an important optimization.
+    ///
+    /// After reading ends, if we decide to perform a write or a seek operation, the real file
+    /// cursor must first be repositioned back to the correct logical position.
+    fn poll_reposition(&mut self, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
+        if let Some(Ok(read_pos)) = self.read_pos {
+            ready!(Pin::new(self.unblock.get_mut()).poll_seek(cx, SeekFrom::Start(read_pos)))?;
+        }
+        self.read_pos = None;
+        Poll::Ready(Ok(()))
+    }
+}
+
+impl fmt::Debug for File {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        self.file.fmt(f)
+    }
+}
+
+impl From<std::fs::File> for File {
+    fn from(inner: std::fs::File) -> File {
+        File::new(inner, true)
+    }
+}
+
+#[cfg(unix)]
+impl std::os::unix::io::FromRawFd for File {
+    unsafe fn from_raw_fd(raw: std::os::unix::io::RawFd) -> File {
+        File::from(std::fs::File::from_raw_fd(raw))
+    }
+}
+
+#[cfg(windows)]
+impl std::os::windows::io::FromRawHandle for File {
+    unsafe fn from_raw_handle(raw: std::os::windows::io::RawHandle) -> File {
+        File::from(std::fs::File::from_raw_handle(raw))
+    }
+}
+
+#[cfg(unix)]
+impl std::os::unix::io::AsRawFd for File {
+    fn as_raw_fd(&self) -> std::os::unix::io::RawFd {
+        self.file.as_raw_fd()
+    }
+}
+
+#[cfg(windows)]
+impl std::os::windows::io::AsRawHandle for File {
+    fn as_raw_handle(&self) -> std::os::windows::io::RawHandle {
+        self.file.as_raw_handle()
+    }
+}
+
+#[cfg(all(not(async_fs_no_io_safety), unix))]
+impl From<std::os::unix::io::OwnedFd> for File {
+    fn from(fd: std::os::unix::io::OwnedFd) -> Self {
+        File::from(std::fs::File::from(fd))
+    }
+}
+
+#[cfg(all(not(async_fs_no_io_safety), windows))]
+impl From<std::os::windows::io::OwnedHandle> for File {
+    fn from(fd: std::os::windows::io::OwnedHandle) -> Self {
+        File::from(std::fs::File::from(fd))
+    }
+}
+
+#[cfg(all(not(async_fs_no_io_safety), unix))]
+impl std::os::unix::io::AsFd for File {
+    fn as_fd(&self) -> std::os::unix::io::BorrowedFd<'_> {
+        self.file.as_fd()
+    }
+}
+
+#[cfg(all(not(async_fs_no_io_safety), windows))]
+impl std::os::windows::io::AsHandle for File {
+    fn as_handle(&self) -> std::os::windows::io::BorrowedHandle<'_> {
+        self.file.as_handle()
+    }
+}
+
+impl AsyncRead for File {
+    fn poll_read(
+        mut self: Pin<&mut Self>,
+        cx: &mut Context<'_>,
+        buf: &mut [u8],
+    ) -> Poll<io::Result<usize>> {
+        // Before reading begins, remember the current cursor position.
+        if self.read_pos.is_none() {
+            // Initialize the logical cursor to the current position in the file.
+            self.read_pos = Some(ready!(self.as_mut().poll_seek(cx, SeekFrom::Current(0))));
+        }
+
+        let n = ready!(Pin::new(self.unblock.get_mut()).poll_read(cx, buf))?;
+
+        // Update the logical cursor if the file is seekable.
+        if let Some(Ok(pos)) = self.read_pos.as_mut() {
+            *pos += n as u64;
+        }
+
+        Poll::Ready(Ok(n))
+    }
+}
+
+impl AsyncWrite for File {
+    fn poll_write(
+        mut self: Pin<&mut Self>,
+        cx: &mut Context<'_>,
+        buf: &[u8],
+    ) -> Poll<io::Result<usize>> {
+        ready!(self.poll_reposition(cx))?;
+        self.is_dirty = true;
+        Pin::new(self.unblock.get_mut()).poll_write(cx, buf)
+    }
+
+    fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
+        if self.is_dirty {
+            ready!(Pin::new(self.unblock.get_mut()).poll_flush(cx))?;
+            self.is_dirty = false;
+        }
+        Poll::Ready(Ok(()))
+    }
+
+    fn poll_close(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
+        Pin::new(self.unblock.get_mut()).poll_close(cx)
+    }
+}
+
+impl AsyncSeek for File {
+    fn poll_seek(
+        mut self: Pin<&mut Self>,
+        cx: &mut Context<'_>,
+        pos: SeekFrom,
+    ) -> Poll<io::Result<u64>> {
+        ready!(self.poll_reposition(cx))?;
+        Pin::new(self.unblock.get_mut()).poll_seek(cx, pos)
+    }
+}
+
+/// A wrapper around `Arc<std::fs::File>` that implements `Read`, `Write`, and `Seek`.
+struct ArcFile(Arc<std::fs::File>);
+
+impl io::Read for ArcFile {
+    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
+        (&*self.0).read(buf)
+    }
+}
+
+impl io::Write for ArcFile {
+    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+        (&*self.0).write(buf)
+    }
+
+    fn flush(&mut self) -> io::Result<()> {
+        (&*self.0).flush()
+    }
+}
+
+impl io::Seek for ArcFile {
+    fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
+        (&*self.0).seek(pos)
+    }
+}
+
+/// A builder for opening files with configurable options.
+///
+/// Files can be opened in [`read`][`OpenOptions::read()`] and/or
+/// [`write`][`OpenOptions::write()`] mode.
+///
+/// The [`append`][`OpenOptions::append()`] option opens files in a special writing mode that
+/// moves the file cursor to the end of file before every write operation.
+///
+/// It is also possible to [`truncate`][`OpenOptions::truncate()`] the file right after opening,
+/// to [`create`][`OpenOptions::create()`] a file if it doesn't exist yet, or to always create a
+/// new file with [`create_new`][`OpenOptions::create_new()`].
+///
+/// # Examples
+///
+/// Open a file for reading:
+///
+/// ```no_run
+/// use async_fs::OpenOptions;
+///
+/// # futures_lite::future::block_on(async {
+/// let file = OpenOptions::new()
+///     .read(true)
+///     .open("a.txt")
+///     .await?;
+/// # std::io::Result::Ok(()) });
+/// ```
+///
+/// Open a file for both reading and writing, and create it if it doesn't exist yet:
+///
+/// ```no_run
+/// use async_fs::OpenOptions;
+///
+/// # futures_lite::future::block_on(async {
+/// let file = OpenOptions::new()
+///     .read(true)
+///     .write(true)
+///     .create(true)
+///     .open("a.txt")
+///     .await?;
+/// # std::io::Result::Ok(()) });
+/// ```
+#[derive(Clone, Debug)]
+pub struct OpenOptions(std::fs::OpenOptions);
+
+impl OpenOptions {
+    /// Creates a blank set of options.
+    ///
+    /// All options are initially set to `false`.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use async_fs::OpenOptions;
+    ///
+    /// # futures_lite::future::block_on(async {
+    /// let file = OpenOptions::new()
+    ///     .read(true)
+    ///     .open("a.txt")
+    ///     .await?;
+    /// # std::io::Result::Ok(()) });
+    /// ```
+    pub fn new() -> OpenOptions {
+        OpenOptions(std::fs::OpenOptions::new())
+    }
+
+    /// Configures the option for read mode.
+    ///
+    /// When set to `true`, this option means the file will be readable after opening.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use async_fs::OpenOptions;
+    ///
+    /// # futures_lite::future::block_on(async {
+    /// let file = OpenOptions::new()
+    ///     .read(true)
+    ///     .open("a.txt")
+    ///     .await?;
+    /// # std::io::Result::Ok(()) });
+    /// ```
+    pub fn read(&mut self, read: bool) -> &mut OpenOptions {
+        self.0.read(read);
+        self
+    }
+
+    /// Configures the option for write mode.
+    ///
+    /// When set to `true`, this option means the file will be writable after opening.
+    ///
+    /// If the file already exists, write calls on it will overwrite the previous contents without
+    /// truncating it.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use async_fs::OpenOptions;
+    ///
+    /// # futures_lite::future::block_on(async {
+    /// let file = OpenOptions::new()
+    ///     .write(true)
+    ///     .open("a.txt")
+    ///     .await?;
+    /// # std::io::Result::Ok(()) });
+    /// ```
+    pub fn write(&mut self, write: bool) -> &mut OpenOptions {
+        self.0.write(write);
+        self
+    }
+
+    /// Configures the option for append mode.
+    ///
+    /// When set to `true`, this option means the file will be writable after opening and the file
+    /// cursor will be moved to the end of file before every write operaiton.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use async_fs::OpenOptions;
+    ///
+    /// # futures_lite::future::block_on(async {
+    /// let file = OpenOptions::new()
+    ///     .append(true)
+    ///     .open("a.txt")
+    ///     .await?;
+    /// # std::io::Result::Ok(()) });
+    /// ```
+    pub fn append(&mut self, append: bool) -> &mut OpenOptions {
+        self.0.append(append);
+        self
+    }
+
+    /// Configures the option for truncating the previous file.
+    ///
+    /// When set to `true`, the file will be truncated to the length of 0 bytes.
+    ///
+    /// The file must be opened in [`write`][`OpenOptions::write()`] or
+    /// [`append`][`OpenOptions::append()`] mode for truncation to work.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use async_fs::OpenOptions;
+    ///
+    /// # futures_lite::future::block_on(async {
+    /// let file = OpenOptions::new()
+    ///     .write(true)
+    ///     .truncate(true)
+    ///     .open("a.txt")
+    ///     .await?;
+    /// # std::io::Result::Ok(()) });
+    /// ```
+    pub fn truncate(&mut self, truncate: bool) -> &mut OpenOptions {
+        self.0.truncate(truncate);
+        self
+    }
+
+    /// Configures the option for creating a new file if it doesn't exist.
+    ///
+    /// When set to `true`, this option means a new file will be created if it doesn't exist.
+    ///
+    /// The file must be opened in [`write`][`OpenOptions::write()`] or
+    /// [`append`][`OpenOptions::append()`] mode for file creation to work.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use async_fs::OpenOptions;
+    ///
+    /// # futures_lite::future::block_on(async {
+    /// let file = OpenOptions::new()
+    ///     .write(true)
+    ///     .create(true)
+    ///     .open("a.txt")
+    ///     .await?;
+    /// # std::io::Result::Ok(()) });
+    /// ```
+    pub fn create(&mut self, create: bool) -> &mut OpenOptions {
+        self.0.create(create);
+        self
+    }
+
+    /// Configures the option for creating a new file or failing if it already exists.
+    ///
+    /// When set to `true`, this option means a new file will be created, or the open operation
+    /// will fail if the file already exists.
+    ///
+    /// The file must be opened in [`write`][`OpenOptions::write()`] or
+    /// [`append`][`OpenOptions::append()`] mode for file creation to work.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use async_fs::OpenOptions;
+    ///
+    /// # futures_lite::future::block_on(async {
+    /// let file = OpenOptions::new()
+    ///     .write(true)
+    ///     .create_new(true)
+    ///     .open("a.txt")
+    ///     .await?;
+    /// # std::io::Result::Ok(()) });
+    /// ```
+    pub fn create_new(&mut self, create_new: bool) -> &mut OpenOptions {
+        self.0.create_new(create_new);
+        self
+    }
+
+    /// Opens a file with the configured options.
+    ///
+    /// # Errors
+    ///
+    /// An error will be returned in the following situations:
+    ///
+    /// * The file does not exist and neither [`create`] nor [`create_new`] were set.
+    /// * The file's parent directory does not exist.
+    /// * The current process lacks permissions to open the file in the configured mode.
+    /// * The file already exists and [`create_new`] was set.
+    /// * Invalid combination of options was used, like [`truncate`] was set but [`write`] wasn't,
+    ///   or none of [`read`], [`write`], and [`append`] modes was set.
+    /// * An OS-level occurred, like too many files are open or the file name is too long.
+    /// * Some other I/O error occurred.
+    ///
+    /// [`read`]: `OpenOptions::read()`
+    /// [`write`]: `OpenOptions::write()`
+    /// [`append`]: `OpenOptions::append()`
+    /// [`truncate`]: `OpenOptions::truncate()`
+    /// [`create`]: `OpenOptions::create()`
+    /// [`create_new`]: `OpenOptions::create_new()`
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use async_fs::OpenOptions;
+    ///
+    /// # futures_lite::future::block_on(async {
+    /// let file = OpenOptions::new()
+    ///     .read(true)
+    ///     .open("a.txt")
+    ///     .await?;
+    /// # std::io::Result::Ok(()) });
+    /// ```
+    pub fn open<P: AsRef<Path>>(&self, path: P) -> impl Future<Output = io::Result<File>> {
+        let path = path.as_ref().to_owned();
+        let options = self.0.clone();
+        async move {
+            let file = unblock(move || options.open(path)).await?;
+            Ok(File::new(file, false))
+        }
+    }
+}
+
+impl Default for OpenOptions {
+    fn default() -> Self {
+        Self::new()
+    }
+}
+
+#[cfg(unix)]
+impl unix::OpenOptionsExt for OpenOptions {
+    fn mode(&mut self, mode: u32) -> &mut Self {
+        self.0.mode(mode);
+        self
+    }
+
+    fn custom_flags(&mut self, flags: i32) -> &mut Self {
+        self.0.custom_flags(flags);
+        self
+    }
+}
+
+#[cfg(windows)]
+impl windows::OpenOptionsExt for OpenOptions {
+    fn access_mode(&mut self, access: u32) -> &mut Self {
+        self.0.access_mode(access);
+        self
+    }
+
+    fn share_mode(&mut self, val: u32) -> &mut Self {
+        self.0.share_mode(val);
+        self
+    }
+
+    fn custom_flags(&mut self, flags: u32) -> &mut Self {
+        self.0.custom_flags(flags);
+        self
+    }
+
+    fn attributes(&mut self, val: u32) -> &mut Self {
+        self.0.attributes(val);
+        self
+    }
+
+    fn security_qos_flags(&mut self, flags: u32) -> &mut Self {
+        self.0.security_qos_flags(flags);
+        self
+    }
+}
+
+/// Unix-specific extensions.
+#[cfg(unix)]
+pub mod unix {
+    use super::*;
+
+    #[doc(no_inline)]
+    pub use std::os::unix::fs::{FileTypeExt, MetadataExt, PermissionsExt};
+
+    /// Creates a new symbolic link on the filesystem.
+    ///
+    /// The `dst` path will be a symbolic link pointing to the `src` path.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// # futures_lite::future::block_on(async {
+    /// async_fs::unix::symlink("a.txt", "b.txt").await?;
+    /// # std::io::Result::Ok(()) });
+    /// ```
+    pub async fn symlink<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dst: Q) -> io::Result<()> {
+        let src = src.as_ref().to_owned();
+        let dst = dst.as_ref().to_owned();
+        unblock(move || std::os::unix::fs::symlink(&src, &dst)).await
+    }
+
+    /// Unix-specific extensions to [`DirBuilder`].
+    pub trait DirBuilderExt {
+        /// Sets the mode to create new directories with.
+        ///
+        /// This option defaults to `0o777`.
+        ///
+        /// # Examples
+        ///
+        /// ```no_run
+        /// use async_fs::{DirBuilder, unix::DirBuilderExt};
+        ///
+        /// let mut builder = DirBuilder::new();
+        /// builder.mode(0o755);
+        /// ```
+        fn mode(&mut self, mode: u32) -> &mut Self;
+    }
+
+    /// Unix-specific extension methods for [`DirEntry`].
+    pub trait DirEntryExt {
+        /// Returns the underlying `d_ino` field in the contained `dirent` structure.
+        ///
+        /// # Examples
+        ///
+        /// ```no_run
+        /// use async_fs::unix::DirEntryExt;
+        /// use futures_lite::stream::StreamExt;
+        ///
+        /// # futures_lite::future::block_on(async {
+        /// let mut entries = async_fs::read_dir(".").await?;
+        ///
+        /// while let Some(entry) = entries.try_next().await? {
+        ///     println!("{:?}: {}", entry.file_name(), entry.ino());
+        /// }
+        /// # std::io::Result::Ok(()) });
+        /// ```
+        fn ino(&self) -> u64;
+    }
+
+    /// Unix-specific extensions to [`OpenOptions`].
+    pub trait OpenOptionsExt {
+        /// Sets the mode bits that a new file will be created with.
+        ///
+        /// If a new file is created as part of an [`OpenOptions::open()`] call then this
+        /// specified `mode` will be used as the permission bits for the new file.
+        ///
+        /// If no `mode` is set, the default of `0o666` will be used.
+        /// The operating system masks out bits with the system's `umask`, to produce
+        /// the final permissions.
+        ///
+        /// # Examples
+        ///
+        /// ```no_run
+        /// use async_fs::{OpenOptions, unix::OpenOptionsExt};
+        ///
+        /// # futures_lite::future::block_on(async {
+        /// let mut options = OpenOptions::new();
+        /// // Read/write permissions for owner and read permissions for others.
+        /// options.mode(0o644);
+        /// let file = options.open("foo.txt").await?;
+        /// # std::io::Result::Ok(()) });
+        /// ```
+        fn mode(&mut self, mode: u32) -> &mut Self;
+
+        /// Passes custom flags to the `flags` argument of `open`.
+        ///
+        /// The bits that define the access mode are masked out with `O_ACCMODE`, to
+        /// ensure they do not interfere with the access mode set by Rust's options.
+        ///
+        /// Custom flags can only set flags, not remove flags set by Rust's options.
+        /// This options overwrites any previously set custom flags.
+        ///
+        /// # Examples
+        ///
+        /// ```no_run
+        /// use async_fs::{OpenOptions, unix::OpenOptionsExt};
+        ///
+        /// # futures_lite::future::block_on(async {
+        /// let mut options = OpenOptions::new();
+        /// options.write(true);
+        /// options.custom_flags(libc::O_NOFOLLOW);
+        /// let file = options.open("foo.txt").await?;
+        /// # std::io::Result::Ok(()) });
+        /// ```
+        fn custom_flags(&mut self, flags: i32) -> &mut Self;
+    }
+}
+
+/// Windows-specific extensions.
+#[cfg(windows)]
+pub mod windows {
+    use super::*;
+
+    #[doc(no_inline)]
+    pub use std::os::windows::fs::MetadataExt;
+
+    /// Creates a new directory symbolic link on the filesystem.
+    ///
+    /// The `dst` path will be a directory symbolic link pointing to the `src` path.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// # futures_lite::future::block_on(async {
+    /// async_fs::windows::symlink_dir("a", "b").await?;
+    /// # std::io::Result::Ok(()) });
+    /// ```
+    pub async fn symlink_dir<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dst: Q) -> io::Result<()> {
+        let src = src.as_ref().to_owned();
+        let dst = dst.as_ref().to_owned();
+        unblock(move || std::os::windows::fs::symlink_dir(&src, &dst)).await
+    }
+
+    /// Creates a new file symbolic link on the filesystem.
+    ///
+    /// The `dst` path will be a file symbolic link pointing to the `src` path.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// # futures_lite::future::block_on(async {
+    /// async_fs::windows::symlink_file("a.txt", "b.txt").await?;
+    /// # std::io::Result::Ok(()) });
+    /// ```
+    pub async fn symlink_file<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dst: Q) -> io::Result<()> {
+        let src = src.as_ref().to_owned();
+        let dst = dst.as_ref().to_owned();
+        unblock(move || std::os::windows::fs::symlink_file(&src, &dst)).await
+    }
+
+    /// Windows-specific extensions to [`OpenOptions`].
+    pub trait OpenOptionsExt {
+        /// Overrides the `dwDesiredAccess` argument to the call to [`CreateFile`]
+        /// with the specified value.
+        ///
+        /// This will override the `read`, `write`, and `append` flags on the
+        /// [`OpenOptions`] structure. This method provides fine-grained control over
+        /// the permissions to read, write and append data, attributes (like hidden
+        /// and system), and extended attributes.
+        ///
+        /// # Examples
+        ///
+        /// ```no_run
+        /// use async_fs::{OpenOptions, windows::OpenOptionsExt};
+        ///
+        /// # futures_lite::future::block_on(async {
+        /// // Open without read and write permission, for example if you only need
+        /// // to call `stat` on the file
+        /// let file = OpenOptions::new().access_mode(0).open("foo.txt").await?;
+        /// # std::io::Result::Ok(()) });
+        /// ```
+        ///
+        /// [`CreateFile`]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilea
+        fn access_mode(&mut self, access: u32) -> &mut Self;
+
+        /// Overrides the `dwShareMode` argument to the call to [`CreateFile`] with
+        /// the specified value.
+        ///
+        /// By default `share_mode` is set to
+        /// `FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE`. This allows
+        /// other processes to read, write, and delete/rename the same file
+        /// while it is open. Removing any of the flags will prevent other
+        /// processes from performing the corresponding operation until the file
+        /// handle is closed.
+        ///
+        /// # Examples
+        ///
+        /// ```no_run
+        /// use async_fs::{OpenOptions, windows::OpenOptionsExt};
+        ///
+        /// # futures_lite::future::block_on(async {
+        /// // Do not allow others to read or modify this file while we have it open
+        /// // for writing.
+        /// let file = OpenOptions::new()
+        ///     .write(true)
+        ///     .share_mode(0)
+        ///     .open("foo.txt")
+        ///     .await?;
+        /// # std::io::Result::Ok(()) });
+        /// ```
+        ///
+        /// [`CreateFile`]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilea
+        fn share_mode(&mut self, val: u32) -> &mut Self;
+
+        /// Sets extra flags for the `dwFileFlags` argument to the call to
+        /// [`CreateFile2`] to the specified value (or combines it with
+        /// `attributes` and `security_qos_flags` to set the `dwFlagsAndAttributes`
+        /// for [`CreateFile`]).
+        ///
+        /// Custom flags can only set flags, not remove flags set by Rust's options.
+        /// This option overwrites any previously set custom flags.
+        ///
+        /// # Examples
+        ///
+        /// ```no_run
+        /// use async_fs::{OpenOptions, windows::OpenOptionsExt};
+        ///
+        /// # futures_lite::future::block_on(async {
+        /// let file = OpenOptions::new()
+        ///     .create(true)
+        ///     .write(true)
+        ///     .custom_flags(winapi::um::winbase::FILE_FLAG_DELETE_ON_CLOSE)
+        ///     .open("foo.txt")
+        ///     .await?;
+        /// # std::io::Result::Ok(()) });
+        /// ```
+        ///
+        /// [`CreateFile`]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilea
+        /// [`CreateFile2`]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfile2
+        fn custom_flags(&mut self, flags: u32) -> &mut Self;
+
+        /// Sets the `dwFileAttributes` argument to the call to [`CreateFile2`] to
+        /// the specified value (or combines it with `custom_flags` and
+        /// `security_qos_flags` to set the `dwFlagsAndAttributes` for
+        /// [`CreateFile`]).
+        ///
+        /// If a _new_ file is created because it does not yet exist and
+        /// `.create(true)` or `.create_new(true)` are specified, the new file is
+        /// given the attributes declared with `.attributes()`.
+        ///
+        /// If an _existing_ file is opened with `.create(true).truncate(true)`, its
+        /// existing attributes are preserved and combined with the ones declared
+        /// with `.attributes()`.
+        ///
+        /// In all other cases the attributes get ignored.
+        ///
+        /// # Examples
+        ///
+        /// ```no_run
+        /// use async_fs::{OpenOptions, windows::OpenOptionsExt};
+        ///
+        /// # futures_lite::future::block_on(async {
+        /// let file = OpenOptions::new()
+        ///     .write(true)
+        ///     .create(true)
+        ///     .attributes(winapi::um::winnt::FILE_ATTRIBUTE_HIDDEN)
+        ///     .open("foo.txt")
+        ///     .await?;
+        /// # std::io::Result::Ok(()) });
+        /// ```
+        ///
+        /// [`CreateFile`]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilea
+        /// [`CreateFile2`]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfile2
+        fn attributes(&mut self, val: u32) -> &mut Self;
+
+        /// Sets the `dwSecurityQosFlags` argument to the call to [`CreateFile2`] to
+        /// the specified value (or combines it with `custom_flags` and `attributes`
+        /// to set the `dwFlagsAndAttributes` for [`CreateFile`]).
+        ///
+        /// By default `security_qos_flags` is not set. It should be specified when
+        /// opening a named pipe, to control to which degree a server process can
+        /// act on behalf of a client process (security impersonation level).
+        ///
+        /// When `security_qos_flags` is not set, a malicious program can gain the
+        /// elevated privileges of a privileged Rust process when it allows opening
+        /// user-specified paths, by tricking it into opening a named pipe. So
+        /// arguably `security_qos_flags` should also be set when opening arbitrary
+        /// paths. However the bits can then conflict with other flags, specifically
+        /// `FILE_FLAG_OPEN_NO_RECALL`.
+        ///
+        /// For information about possible values, see [Impersonation Levels] on the
+        /// Windows Dev Center site. The `SECURITY_SQOS_PRESENT` flag is set
+        /// automatically when using this method.
+        ///
+        /// # Examples
+        ///
+        /// ```no_run
+        /// use async_fs::{OpenOptions, windows::OpenOptionsExt};
+        ///
+        /// # futures_lite::future::block_on(async {
+        /// let file = OpenOptions::new()
+        ///     .write(true)
+        ///     .create(true)
+        ///     .security_qos_flags(winapi::um::winbase::SECURITY_IDENTIFICATION)
+        ///     .open(r"\\.\pipe\MyPipe")
+        ///     .await?;
+        /// # std::io::Result::Ok(()) });
+        /// ```
+        ///
+        /// [`CreateFile`]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilea
+        /// [`CreateFile2`]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfile2
+        /// [Impersonation Levels]: https://docs.microsoft.com/en-us/windows/win32/api/winnt/ne-winnt-security_impersonation_level
+        fn security_qos_flags(&mut self, flags: u32) -> &mut Self;
+    }
+}