cap-async-std-3.4.1/.cargo_vcs_info.json0000644000000001530000000000100135060ustar { "git": { "sha1": "c461c0799f831df5d8ca2e121b7f541d9e8143af" }, "path_in_vcs": "cap-async-std" }cap-async-std-3.4.1/COPYRIGHT000064400000000000000000000015611046102023000135750ustar 00000000000000Short version for non-lawyers: `cap-async-std` is triple-licensed under Apache 2.0 with the LLVM Exception, Apache 2.0, and MIT terms. Longer version: Copyrights in the `cap-async-std` project are retained by their contributors. No copyright assignment is required to contribute to the `cap-async-std` project. Some files include code derived from Rust's `libstd`; see the comments in the code for details. Except as otherwise noted (below and/or in individual files), `cap-async-std` is licensed under: - the Apache License, Version 2.0, with the LLVM Exception or - the Apache License, Version 2.0 or , - or the MIT license or , at your option. cap-async-std-3.4.1/Cargo.toml0000644000000034230000000000100115070ustar # 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 = "2021" name = "cap-async-std" version = "3.4.1" authors = [ "Dan Gohman ", "Jakub Konka ", ] build = "build.rs" autobins = false autoexamples = false autotests = false autobenches = false description = "Capability-based version of async-std" readme = "README.md" keywords = [ "network", "file", "async", "future", "await", ] categories = [ "filesystem", "network-programming", "asynchronous", "concurrency", ] license = "Apache-2.0 WITH LLVM-exception OR Apache-2.0 OR MIT" repository = "https://github.com/bytecodealliance/cap-std" [lib] name = "cap_async_std" path = "src/lib.rs" [dependencies.arf-strings] version = "0.7.0" optional = true [dependencies.async-std] version = "1.13.0" features = [ "attributes", "io_safety", ] [dependencies.camino] version = "1.0.5" optional = true [dependencies.cap-primitives] version = "^3.4.1" [dependencies.io-extras] version = "0.18.3" features = ["use_async_std"] [dependencies.io-lifetimes] version = "2.0.0" features = ["async-std"] default-features = false [features] arf_strings = [ "fs_utf8", "arf-strings", ] default = [] fs_utf8 = ["camino"] tokio1 = ["async-std/tokio1"] [target."cfg(not(windows))".dependencies.rustix] version = "0.38.0" features = ["fs"] cap-async-std-3.4.1/Cargo.toml.orig000064400000000000000000000021271046102023000151700ustar 00000000000000[package] name = "cap-async-std" version = "3.4.1" description = "Capability-based version of async-std" authors = [ "Dan Gohman ", "Jakub Konka ", ] license = "Apache-2.0 WITH LLVM-exception OR Apache-2.0 OR MIT" keywords = ["network", "file", "async", "future", "await"] categories = ["filesystem", "network-programming", "asynchronous", "concurrency"] repository = "https://github.com/bytecodealliance/cap-std" edition = "2021" [dependencies] arf-strings = { version = "0.7.0", optional = true } async-std = { version = "1.13.0", features = ["attributes", "io_safety"] } cap-primitives = { path = "../cap-primitives", version = "^3.4.1" } io-lifetimes = { version = "2.0.0", default-features = false, features = ["async-std"] } io-extras = { version = "0.18.3", features = ["use_async_std"] } camino = { version = "1.0.5", optional = true } [target.'cfg(not(windows))'.dependencies] rustix = { version = "0.38.0", features = ["fs"] } [features] default = [] fs_utf8 = ["camino"] arf_strings = ["fs_utf8", "arf-strings"] tokio1 = ["async-std/tokio1"] cap-async-std-3.4.1/LICENSE-APACHE000064400000000000000000000251371046102023000142330ustar 00000000000000 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. cap-async-std-3.4.1/LICENSE-Apache-2.0_WITH_LLVM-exception000064400000000000000000000277231046102023000204540ustar 00000000000000 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. --- LLVM Exceptions to the Apache 2.0 License ---- As an exception, if, as a result of your compiling your source code, portions of this Software are embedded into an Object form of such source code, you may redistribute such embedded portions in such Object form without complying with the conditions of Sections 4(a), 4(b) and 4(d) of the License. In addition, if you combine or link compiled forms of this Software with software that is licensed under the GPLv2 ("Combined Software") and if a court of competent jurisdiction determines that the patent provision (Section 3), the indemnity provision (Section 9) or other Section of the License conflicts with the conditions of the GPLv2, you may retroactively and prospectively choose to deem waived or otherwise exclude such Section(s) of the License, but only in their entirety and only with respect to the Combined Software. cap-async-std-3.4.1/LICENSE-MIT000064400000000000000000000017771046102023000137470ustar 00000000000000Permission 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. cap-async-std-3.4.1/README.md000064400000000000000000000016121046102023000135560ustar 00000000000000

cap-async-std

Capability-based version of `async-std`

Github Actions CI Status crates.io page docs.rs docs

This crate provides a capability-based version of [`async-std`]. See the [toplevel README.md] for more information about capability-based security. [`async-std`]: https://crates.io/crates/async-std [toplevel README.md]: https://github.com/bytecodealliance/cap-std/blob/main/README.md cap-async-std-3.4.1/build.rs000064400000000000000000000051061046102023000137460ustar 00000000000000use std::env::var; use std::io::Write; fn main() { use_feature_or_nothing("windows_file_type_ext"); // Cfgs that users may set. println!("cargo:rustc-check-cfg=cfg(io_lifetimes_use_std)"); // Don't rerun this on changes other than build.rs, as we only depend on // the rustc version. println!("cargo:rerun-if-changed=build.rs"); } fn use_feature_or_nothing(feature: &str) { if has_feature(feature) { use_feature(feature); } println!("cargo:rustc-check-cfg=cfg({})", feature); } fn use_feature(feature: &str) { println!("cargo:rustc-cfg={}", feature); } /// Test whether the rustc at `var("RUSTC")` supports the given feature. fn has_feature(feature: &str) -> bool { can_compile(&format!( "#![allow(stable_features)]\n#![feature({})]", feature )) } /// Test whether the rustc at `var("RUSTC")` can compile the given code. fn can_compile>(test: T) -> bool { use std::process::Stdio; let out_dir = var("OUT_DIR").unwrap(); let rustc = var("RUSTC").unwrap(); let target = var("TARGET").unwrap(); // Use `RUSTC_WRAPPER` if it's set, unless it's set to an empty string, // as documented [here]. // [here]: https://doc.rust-lang.org/cargo/reference/environment-variables.html#environment-variables-cargo-reads let wrapper = var("RUSTC_WRAPPER") .ok() .and_then(|w| if w.is_empty() { None } else { Some(w) }); let mut cmd = if let Some(wrapper) = wrapper { let mut cmd = std::process::Command::new(wrapper); // The wrapper's first argument is supposed to be the path to rustc. cmd.arg(rustc); cmd } else { std::process::Command::new(rustc) }; cmd.arg("--crate-type=rlib") // Don't require `main`. .arg("--emit=metadata") // Do as little as possible but still parse. .arg("--target") .arg(target) .arg("--out-dir") .arg(out_dir); // Put the output somewhere inconsequential. // If Cargo wants to set RUSTFLAGS, use that. if let Ok(rustflags) = var("CARGO_ENCODED_RUSTFLAGS") { if !rustflags.is_empty() { for arg in rustflags.split('\x1f') { cmd.arg(arg); } } } let mut child = cmd .arg("-") // Read from stdin. .stdin(Stdio::piped()) // Stdin is a pipe. .stderr(Stdio::null()) // Errors from feature detection aren't interesting and can be confusing. .spawn() .unwrap(); writeln!(child.stdin.take().unwrap(), "{}", test.as_ref()).unwrap(); child.wait().unwrap().success() } cap-async-std-3.4.1/src/fs/dir.rs000064400000000000000000001064021046102023000146250ustar 00000000000000use crate::fs::{DirBuilder, File, Metadata, OpenOptions, ReadDir}; #[cfg(target_os = "wasi")] use async_std::os::wasi::{ fs::OpenOptionsExt, io::{AsRawFd, IntoRawFd}, }; use async_std::path::{Path, PathBuf}; use async_std::task::spawn_blocking; use async_std::{fs, io}; use cap_primitives::fs::{ canonicalize, copy, create_dir, hard_link, open, open_ambient_dir, open_dir, open_parent_dir, read_base_dir, read_dir, read_link, remove_dir, remove_dir_all, remove_file, remove_open_dir, remove_open_dir_all, rename, set_permissions, stat, DirOptions, FollowSymlinks, Permissions, }; use cap_primitives::AmbientAuthority; use io_lifetimes::raw::{AsRawFilelike, FromRawFilelike}; #[cfg(not(windows))] use io_lifetimes::{AsFd, BorrowedFd, OwnedFd}; use io_lifetimes::{AsFilelike, FromFilelike}; #[cfg(windows)] use io_lifetimes::{AsHandle, BorrowedHandle, OwnedHandle}; use std::fmt; use std::mem::ManuallyDrop; #[cfg(unix)] use { crate::os::unix::net::{UnixDatagram, UnixListener, UnixStream}, async_std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd}, cap_primitives::fs::symlink, }; #[cfg(windows)] use { async_std::os::windows::io::{AsRawHandle, FromRawHandle, IntoRawHandle, RawHandle}, cap_primitives::fs::{symlink_dir, symlink_file}, io_extras::os::windows::{ AsHandleOrSocket, AsRawHandleOrSocket, BorrowedHandleOrSocket, IntoRawHandleOrSocket, OwnedHandleOrSocket, RawHandleOrSocket, }, }; /// A reference to an open directory on a filesystem. /// /// This does not directly correspond to anything in `async_std`, however its /// methods correspond to the [functions in `async_std::fs`] and the /// constructor methods for [`async_std::fs::File`]. /// /// Unlike `async_std::fs`, this API's `canonicalize` returns a relative path /// since absolute paths don't interoperate well with the capability model. /// /// [functions in `async_std::fs`]: https://docs.rs/async-std/latest/async_std/fs/index.html#functions #[derive(Clone)] pub struct Dir { std_file: fs::File, } impl Dir { /// Constructs a new instance of `Self` from the given /// `async_std::fs::File`. /// /// To prevent race conditions on Windows, the file must be opened without /// `FILE_SHARE_DELETE`. /// /// This grants access the resources the `async_std::fs::File` instance /// already has access to. #[inline] pub fn from_std_file(std_file: fs::File) -> Self { Self { std_file } } /// Consumes `self` and returns an `async_std::fs::File`. #[inline] pub fn into_std_file(self) -> fs::File { self.std_file } /// Attempts to open a file in read-only mode. /// /// This corresponds to [`async_std::fs::File::open`], but only accesses /// paths relative to `self`. #[inline] pub async fn open>(&self, path: P) -> io::Result { self.open_with(path, OpenOptions::new().read(true)).await } /// Opens a file at `path` with the options specified by `options`. /// /// This corresponds to [`async_std::fs::OpenOptions::open`]. /// /// Instead of being a method on `OpenOptions`, this is a method on `Dir`, /// and it only accesses paths relative to `self`. #[inline] pub async fn open_with>( &self, path: P, options: &OpenOptions, ) -> io::Result { self._open_with(path.as_ref(), options).await } #[cfg(not(target_os = "wasi"))] async fn _open_with(&self, path: &Path, options: &OpenOptions) -> io::Result { let path = path.to_path_buf(); let clone = self.clone(); let options = options.clone(); let file = spawn_blocking(move || { open( &*clone.as_filelike_view::(), path.as_ref(), &options, ) }) .await? .into(); Ok(File::from_std(file)) } #[cfg(target_os = "wasi")] async fn _open_with( file: &std::fs::File, path: &Path, options: &OpenOptions, ) -> io::Result { let file = options.open_at(&self.std_file, path)?.into(); Ok(File::from_std(file)) } /// Attempts to open a directory. #[inline] pub async fn open_dir>(&self, path: P) -> io::Result { let path = path.as_ref().to_path_buf(); let clone = self.clone(); let dir = spawn_blocking(move || { open_dir(&clone.as_filelike_view::(), path.as_ref()) }) .await? .into(); Ok(Self::from_std_file(dir)) } /// Creates a new, empty directory at the provided path. /// /// This corresponds to [`async_std::fs::create_dir`], but only accesses /// paths relative to `self`. /// /// TODO: async: fix this when we fix #[inline] pub fn create_dir>(&self, path: P) -> io::Result<()> { self._create_dir_one(path.as_ref(), &DirOptions::new()) } /// Recursively create a directory and all of its parent components if they /// are missing. /// /// This corresponds to [`async_std::fs::create_dir_all`], but only /// accesses paths relative to `self`. /// /// TODO: async: fix this when we fix #[inline] pub fn create_dir_all>(&self, path: P) -> io::Result<()> { self._create_dir_all(path.as_ref(), &DirOptions::new()) } /// Creates the specified directory with the options configured in this /// builder. /// /// This corresponds to [`async_std::fs::DirBuilder::create`]. /// /// TODO: async: fix this when we fix #[inline] pub fn create_dir_with>( &self, path: P, dir_builder: &DirBuilder, ) -> io::Result<()> { let options = dir_builder.options(); if dir_builder.is_recursive() { self._create_dir_all(path.as_ref(), options) } else { self._create_dir_one(path.as_ref(), options) } } #[inline] fn _create_dir_one(&self, path: &Path, dir_options: &DirOptions) -> io::Result<()> { create_dir( &self.as_filelike_view::(), path.as_ref(), dir_options, ) } fn _create_dir_all(&self, path: &Path, dir_options: &DirOptions) -> io::Result<()> { if path == Path::new("") { return Ok(()); } match self._create_dir_one(path, dir_options) { Ok(()) => return Ok(()), Err(ref e) if e.kind() == io::ErrorKind::NotFound => {} Err(_) if self.is_dir_blocking(path) => return Ok(()), Err(e) => return Err(e), } match path.parent() { Some(p) => self._create_dir_all(p, dir_options)?, None => { return Err(io::Error::new( io::ErrorKind::Other, "failed to create whole tree", )) } } match self._create_dir_one(path, dir_options) { Ok(()) => Ok(()), Err(_) if self.is_dir_blocking(path) => Ok(()), Err(e) => Err(e), } } /// Opens a file in write-only mode. /// /// This corresponds to [`async_std::fs::File::create`], but only accesses /// paths relative to `self`. #[inline] pub async fn create>(&self, path: P) -> io::Result { self.open_with( path, OpenOptions::new().write(true).create(true).truncate(true), ) .await } /// Returns the canonical form of a path with all intermediate components /// normalized and symbolic links resolved. /// /// This corresponds to [`async_std::fs::canonicalize`], but instead of /// returning an absolute path, returns a path relative to the /// directory represented by `self`. #[inline] pub async fn canonicalize>(&self, path: P) -> io::Result { let path = path.as_ref().to_path_buf(); let clone = self.clone(); spawn_blocking(move || { canonicalize(&clone.as_filelike_view::(), path.as_ref()) }) .await .map(PathBuf::from) } /// Copies the contents of one file to another. This function will also /// copy the permission bits of the original file to the destination /// file. /// /// This corresponds to [`async_std::fs::copy`], but only accesses paths /// relative to `self`. #[inline] pub async fn copy, Q: AsRef>( &self, from: P, to_dir: &Self, to: Q, ) -> io::Result { let from = from.as_ref().to_path_buf(); let to = to.as_ref().to_path_buf(); let from_clone = self.clone(); let to_clone = to_dir.clone(); spawn_blocking(move || { copy( &from_clone.as_filelike_view::(), from.as_ref(), &to_clone.as_filelike_view::(), to.as_ref(), ) }) .await } /// Creates a new hard link on a filesystem. /// /// This corresponds to [`async_std::fs::hard_link`], but only accesses /// paths relative to `self`. #[inline] pub async fn hard_link, Q: AsRef>( &self, src: P, dst_dir: &Self, dst: Q, ) -> io::Result<()> { let dst = dst.as_ref().to_path_buf(); let src = src.as_ref().to_path_buf(); let src_clone = self.clone(); let dst_clone = dst_dir.clone(); spawn_blocking(move || { hard_link( &src_clone.as_filelike_view::(), src.as_ref(), &dst_clone.as_filelike_view::(), dst.as_ref(), ) }) .await } /// Given a path, query the file system to get information about a file, /// directory, etc. /// /// This corresponds to [`async_std::fs::metadata`], but only accesses /// paths relative to `self`. #[inline] pub async fn metadata>(&self, path: P) -> io::Result { let path = path.as_ref().to_path_buf(); let clone = self.clone(); spawn_blocking(move || { stat( &clone.as_filelike_view::(), path.as_ref(), FollowSymlinks::Yes, ) }) .await } /// TODO: Remove this once `create_dir` and friends are async. #[inline] fn metadata_blocking>(&self, path: P) -> io::Result { let path = path.as_ref().to_path_buf(); stat( &self.as_filelike_view::(), path.as_ref(), FollowSymlinks::Yes, ) } /// Queries metadata about the underlying directory. /// /// This is similar to [`std::fs::File::metadata`], but for `Dir` rather /// than for `File`. #[inline] pub async fn dir_metadata(&self) -> io::Result { let clone = self.clone(); spawn_blocking(move || metadata_from(&*clone.as_filelike_view::())).await } /// Returns an iterator over the entries within `self`. #[inline] pub async fn entries(&self) -> io::Result { let clone = self.clone(); spawn_blocking(move || read_base_dir(&clone.as_filelike_view::())) .await .map(|inner| ReadDir { inner }) } /// Returns an iterator over the entries within a directory. /// /// This corresponds to [`async_std::fs::read_dir`], but only accesses /// paths relative to `self`. #[inline] pub async fn read_dir>(&self, path: P) -> io::Result { let path = path.as_ref().to_path_buf(); let clone = self.clone(); spawn_blocking(move || read_dir(&clone.as_filelike_view::(), path.as_ref())) .await .map(|inner| ReadDir { inner }) } /// Read the entire contents of a file into a bytes vector. /// /// This corresponds to [`async_std::fs::read`], but only accesses paths /// relative to `self`. #[inline] pub async fn read>(&self, path: P) -> io::Result> { use async_std::prelude::*; let mut file = self.open(path).await?; let mut bytes = Vec::with_capacity(initial_buffer_size(&file).await); file.read_to_end(&mut bytes).await?; Ok(bytes) } /// Reads a symbolic link, returning the file that the link points to. /// /// This corresponds to [`async_std::fs::read_link`], but only accesses /// paths relative to `self`. #[inline] pub async fn read_link>(&self, path: P) -> io::Result { let path = path.as_ref().to_path_buf(); let clone = self.clone(); spawn_blocking(move || read_link(&clone.as_filelike_view::(), path.as_ref())) .await .map(PathBuf::from) } /// Read the entire contents of a file into a string. /// /// This corresponds to [`async_std::fs::read_to_string`], but only /// accesses paths relative to `self`. #[inline] pub async fn read_to_string>(&self, path: P) -> io::Result { use async_std::prelude::*; let mut s = String::new(); self.open(path).await?.read_to_string(&mut s).await?; Ok(s) } /// Removes an empty directory. /// /// This corresponds to [`async_std::fs::remove_dir`], but only accesses /// paths relative to `self`. #[inline] pub async fn remove_dir>(&self, path: P) -> io::Result<()> { let path = path.as_ref().to_path_buf(); let clone = self.clone(); spawn_blocking(move || { remove_dir(&clone.as_filelike_view::(), path.as_ref()) }) .await } /// Removes a directory at this path, after removing all its contents. Use /// carefully! /// /// This corresponds to [`async_std::fs::remove_dir_all`], but only /// accesses paths relative to `self`. #[inline] pub async fn remove_dir_all>(&self, path: P) -> io::Result<()> { let path = path.as_ref().to_path_buf(); let clone = self.clone(); spawn_blocking(move || { remove_dir_all(&clone.as_filelike_view::(), path.as_ref()) }) .await } /// Remove the directory referenced by `self` and consume `self`. /// /// Even though this implementation works in terms of handles as much as /// possible, removal is not guaranteed to be atomic with respect to a /// concurrent rename of the directory. #[inline] pub async fn remove_open_dir(self) -> io::Result<()> { let file = std::fs::File::from_into_filelike(self.std_file); spawn_blocking(move || remove_open_dir(file)).await } /// Removes the directory referenced by `self`, after removing all its /// contents, and consume `self`. Use carefully! /// /// Even though this implementation works in terms of handles as much as /// possible, removal is not guaranteed to be atomic with respect to a /// concurrent rename of the directory. #[inline] pub async fn remove_open_dir_all(self) -> io::Result<()> { let file = std::fs::File::from_into_filelike(self.std_file); spawn_blocking(move || remove_open_dir_all(file)).await } /// Removes a file from a filesystem. /// /// This corresponds to [`async_std::fs::remove_file`], but only accesses /// paths relative to `self`. #[inline] pub async fn remove_file>(&self, path: P) -> io::Result<()> { let path = path.as_ref().to_path_buf(); let clone = self.clone(); spawn_blocking(move || { remove_file(&clone.as_filelike_view::(), path.as_ref()) }) .await } /// Rename a file or directory to a new name, replacing the original file /// if to already exists. /// /// This corresponds to [`async_std::fs::rename`], but only accesses paths /// relative to `self`. #[inline] pub async fn rename, Q: AsRef>( &self, from: P, to_dir: &Self, to: Q, ) -> io::Result<()> { let from = from.as_ref().to_path_buf(); let to = to.as_ref().to_path_buf(); let clone = self.clone(); let to_clone = to_dir.clone(); spawn_blocking(move || { rename( &clone.as_filelike_view::(), from.as_ref(), &to_clone.as_filelike_view::(), to.as_ref(), ) }) .await } /// Changes the permissions found on a file or a directory. /// /// This corresponds to [`async_std::fs::set_permissions`], but only /// accesses paths relative to `self`. Also, on some platforms, this /// function may fail if the file or directory cannot be opened for /// reading or writing first. pub async fn set_permissions>( &self, path: P, perm: Permissions, ) -> io::Result<()> { let path = path.as_ref().to_path_buf(); let clone = self.clone(); spawn_blocking(move || { set_permissions( &clone.as_filelike_view::(), path.as_ref(), perm, ) }) .await } /// Query the metadata about a file without following symlinks. /// /// This corresponds to [`async_std::fs::symlink_metadata`], but only /// accesses paths relative to `self`. #[inline] pub async fn symlink_metadata>(&self, path: P) -> io::Result { let path = path.as_ref().to_path_buf(); let clone = self.clone(); spawn_blocking(move || { stat( &clone.as_filelike_view::(), path.as_ref(), FollowSymlinks::No, ) }) .await } /// Write a slice as the entire contents of a file. /// /// This corresponds to [`async_std::fs::write`], but only accesses paths /// relative to `self`. #[inline] pub async fn write, C: AsRef<[u8]>>( &self, path: P, contents: C, ) -> io::Result<()> { use async_std::prelude::*; let mut file = self.create(path).await?; file.write_all(contents.as_ref()).await } /// Creates a new symbolic link on a filesystem. /// /// The `original` argument provides the target of the symlink. The `link` /// argument provides the name of the created symlink. /// /// Despite the argument ordering, `original` is not resolved relative to /// `self` here. `link` is resolved relative to `self`, and `original` is /// not resolved within this function. /// /// The `link` path is resolved when the symlink is dereferenced, relative /// to the directory that contains it. /// /// This corresponds to [`async_std::os::unix::fs::symlink`], but only /// accesses paths relative to `self`. /// /// [`async_std::os::unix::fs::symlink`]: https://docs.rs/async-std/latest/async_std/os/unix/fs/fn.symlink.html #[cfg(not(windows))] #[inline] pub async fn symlink, Q: AsRef>( &self, original: P, link: Q, ) -> io::Result<()> { let original = original.as_ref().to_path_buf(); let link = link.as_ref().to_path_buf(); let clone = self.clone(); spawn_blocking(move || { symlink( original.as_ref(), &clone.as_filelike_view::(), link.as_ref(), ) }) .await } /// Creates a new file symbolic link on a filesystem. /// /// The `original` argument provides the target of the symlink. The `link` /// argument provides the name of the created symlink. /// /// Despite the argument ordering, `original` is not resolved relative to /// `self` here. `link` is resolved relative to `self`, and `original` is /// not resolved within this function. /// /// The `link` path is resolved when the symlink is dereferenced, relative /// to the directory that contains it. /// /// This corresponds to [`async_std::os::windows::fs::symlink_file`], but /// only accesses paths relative to `self`. /// /// [`async_std::os::windows::fs::symlink_file`]: https://docs.rs/async-std/latest/async_std/os/windows/fs/fn.symlink_file.html #[cfg(windows)] #[inline] pub async fn symlink_file, Q: AsRef>( &self, original: P, link: Q, ) -> io::Result<()> { let original = original.as_ref().to_path_buf(); let link = link.as_ref().to_path_buf(); let clone = self.clone(); spawn_blocking(move || { symlink_file( original.as_ref(), &clone.as_filelike_view::(), link.as_ref(), ) }) .await } /// Creates a new directory symlink on a filesystem. /// /// The `original` argument provides the target of the symlink. The `link` /// argument provides the name of the created symlink. /// /// Despite the argument ordering, `original` is not resolved relative to /// `self` here. `link` is resolved relative to `self`, and `original` is /// not resolved within this function. /// /// The `link` path is resolved when the symlink is dereferenced, relative /// to the directory that contains it. /// /// This corresponds to [`async_std::os::windows::fs::symlink_dir`], but /// only accesses paths relative to `self`. /// /// [`async_std::os::windows::fs::symlink_dir`]: https://docs.rs/async-std/latest/async_std/os/windows/fs/fn.symlink_dir.html #[cfg(windows)] #[inline] pub async fn symlink_dir, Q: AsRef>( &self, original: P, link: Q, ) -> io::Result<()> { let original = original.as_ref().to_path_buf(); let link = link.as_ref().to_path_buf(); let clone = self.clone(); spawn_blocking(move || { symlink_dir( original.as_ref(), &clone.as_filelike_view::(), link.as_ref(), ) }) .await } /// Creates a new `UnixListener` bound to the specified socket. /// /// This corresponds to [`async_std::os::unix::net::UnixListener::bind`], /// but only accesses paths relative to `self`. /// /// XXX: This function is not yet implemented. /// /// [`async_std::os::unix::net::UnixListener::bind`]: https://docs.rs/async-std/latest/async_std/os/unix/net/struct.UnixListener.html#method.bind #[doc(alias = "bind")] #[cfg(unix)] #[inline] pub async fn bind_unix_listener>(&self, path: P) -> io::Result { todo!( "Dir::bind_unix_listener({:?}, {})", self.std_file, path.as_ref().display() ) } /// Connects to the socket named by path. /// /// This corresponds to [`async_std::os::unix::net::UnixStream::connect`], /// but only accesses paths relative to `self`. /// /// XXX: This function is not yet implemented. /// /// [`async_std::os::unix::net::UnixStream::connect`]: https://docs.rs/async-std/latest/async_std/os/unix/net/struct.UnixStream.html#method.connect #[doc(alias = "connect")] #[cfg(unix)] #[inline] pub async fn connect_unix_stream>(&self, path: P) -> io::Result { todo!( "Dir::connect_unix_stream({:?}, {})", self.std_file, path.as_ref().display() ) } /// Creates a Unix datagram socket bound to the given path. /// /// This corresponds to [`async_std::os::unix::net::UnixDatagram::bind`], /// but only accesses paths relative to `self`. /// /// XXX: This function is not yet implemented. /// /// [`async_std::os::unix::net::UnixDatagram::bind`]: https://docs.rs/async-std/latest/async_std/os/unix/net/struct.UnixDatagram.html#method.bind #[doc(alias = "bind")] #[cfg(unix)] #[inline] pub async fn bind_unix_datagram>(&self, path: P) -> io::Result { todo!( "Dir::bind_unix_datagram({:?}, {})", self.std_file, path.as_ref().display() ) } /// Connects the socket to the specified address. /// /// This corresponds to /// [`async_std::os::unix::net::UnixDatagram::connect`], but only /// accesses paths relative to `self`. /// /// XXX: This function is not yet implemented. /// /// [`async_std::os::unix::net::UnixDatagram::connect`]: https://docs.rs/async-std/latest/async_std/os/unix/net/struct.UnixDatagram.html#method.connect #[doc(alias = "connect")] #[cfg(unix)] #[inline] pub async fn connect_unix_datagram>( &self, _unix_datagram: &UnixDatagram, path: P, ) -> io::Result<()> { todo!( "Dir::connect_unix_datagram({:?}, {})", self.std_file, path.as_ref().display() ) } /// Sends data on the socket to the specified address. /// /// This corresponds to /// [`async_std::os::unix::net::UnixDatagram::send_to`], but only /// accesses paths relative to `self`. /// /// XXX: This function is not yet implemented. /// /// [`async_std::os::unix::net::UnixDatagram::send_to`]: https://docs.rs/async-std/latest/async_std/os/unix/net/struct.UnixDatagram.html#method.send_to #[doc(alias = "send_to")] #[cfg(unix)] #[inline] pub async fn send_to_unix_datagram_addr>( &self, _unix_datagram: &UnixDatagram, buf: &[u8], path: P, ) -> io::Result { todo!( "Dir::send_to_unix_datagram_addr({:?}, {:?}, {})", self.std_file, buf, path.as_ref().display() ) } // async_std doesn't have `try_clone`. /// Returns `true` if the path points at an existing entity. /// /// This corresponds to [`async_std::path::Path::exists`], but only /// accesses paths relative to `self`. #[inline] pub async fn exists>(&self, path: P) -> bool { self.metadata(path).await.is_ok() } /// Returns `true` if the path points at an existing entity. /// /// This is an asynchronous version of [`std::fs::try_exists`], and also /// only accesses paths relative to `self`. /// /// NOTE: This API is not yet part of `async_std`. #[inline] pub async fn try_exists>(&self, path: P) -> io::Result { match self.metadata(path.as_ref()).await { Ok(_) => Ok(true), Err(error) if error.kind() == io::ErrorKind::NotFound => Ok(false), Err(e) => Err(e), } } /// Returns `true` if the path exists on disk and is pointing at a regular /// file. /// /// This corresponds to [`async_std::path::Path::is_file`], but only /// accesses paths relative to `self`. #[inline] pub async fn is_file>(&self, path: P) -> bool { self.metadata(path) .await .map(|m| m.is_file()) .unwrap_or(false) } /// Checks if `path` is a directory. /// /// This is similar to [`async_std::path::Path::is_dir`] in that it checks /// if `path` relative to `Dir` is a directory. This function will traverse /// symbolic links to query information about the destination file. In case /// of broken symbolic links, this will return `false`. #[inline] pub async fn is_dir>(&self, path: P) -> bool { self.metadata(path) .await .map(|m| m.is_dir()) .unwrap_or(false) } /// TODO: Remove this once `create_dir` and friends are async. #[inline] fn is_dir_blocking>(&self, path: P) -> bool { self.metadata_blocking(path) .map(|m| m.is_dir()) .unwrap_or(false) } /// Constructs a new instance of `Self` by opening the given path as a /// directory using the host process' ambient authority. /// /// # Ambient Authority /// /// This function is not sandboxed and may access any path that the host /// process has access to. #[inline] pub async fn open_ambient_dir>( path: P, ambient_authority: AmbientAuthority, ) -> io::Result { let path = path.as_ref().to_path_buf(); spawn_blocking(move || open_ambient_dir(path.as_ref(), ambient_authority)) .await .map(|f| Self::from_std_file(f.into())) } /// Constructs a new instance of `Self` by opening the parent directory /// (aka "..") of `self`, using the host process' ambient authority. /// /// # Ambient Authority /// /// This function accesses a directory outside of the `self` subtree. #[inline] pub async fn open_parent_dir(&self, ambient_authority: AmbientAuthority) -> io::Result { let clone = self.clone(); let dir = spawn_blocking(move || { open_parent_dir( &*clone.as_filelike_view::(), ambient_authority, ) }) .await? .into(); Ok(Self::from_std_file(dir)) } /// Recursively create a directory and all of its parent components if they /// are missing, using the host process' ambient authority. /// /// # Ambient Authority /// /// This function is not sandboxed and may access any path that the host /// process has access to. #[inline] pub async fn create_ambient_dir_all>( path: P, ambient_authority: AmbientAuthority, ) -> io::Result<()> { let _ = ambient_authority; let path = path.as_ref().to_path_buf(); fs::create_dir_all(path).await } /// Construct a new instance of `Self` from existing directory file /// descriptor. /// /// This can be useful when interacting with other libraries and or C/C++ /// code which has invoked `openat(..., O_DIRECTORY)` external to this /// crate. pub async fn reopen_dir(dir: &Filelike) -> io::Result { // Our public API has a `&Filelike` here, which prevents us from doing // a `clone` as we usually do. So instead, we use the raw filelike, which // we can clone and depend on it remaining open until we return. let raw_filelike = dir.as_filelike_view::().as_raw_filelike(); // SAFETY: `raw_filelike` remains open for the duration of the // `reopen_dir` call. let file = ManuallyDrop::new(unsafe { std::fs::File::from_raw_filelike(raw_filelike) }); let dir = spawn_blocking(move || { cap_primitives::fs::open_dir(&*file, std::path::Component::CurDir.as_ref()) }) .await? .into(); Ok(Self::from_std_file(dir)) } } #[cfg(not(target_os = "wasi"))] #[inline] fn metadata_from(file: &std::fs::File) -> io::Result { Metadata::from_file(file) } #[cfg(target_os = "wasi")] #[inline] fn metadata_from(file: &std::fs::File) -> io::Result { file.metadata() } // Safety: `FilelikeViewType` is implemented for `std::fs::File`. unsafe impl io_lifetimes::views::FilelikeViewType for Dir {} #[cfg(not(windows))] impl FromRawFd for Dir { #[inline] unsafe fn from_raw_fd(fd: RawFd) -> Self { Self::from_std_file(fs::File::from_raw_fd(fd)) } } #[cfg(not(windows))] impl From for Dir { #[inline] fn from(fd: OwnedFd) -> Self { Self::from_std_file(fs::File::from(fd)) } } #[cfg(windows)] impl FromRawHandle for Dir { /// To prevent race conditions on Windows, the handle must be opened /// without `FILE_SHARE_DELETE`. #[inline] unsafe fn from_raw_handle(handle: RawHandle) -> Self { Self::from_std_file(fs::File::from_raw_handle(handle)) } } #[cfg(windows)] impl From for Dir { #[inline] fn from(handle: OwnedHandle) -> Self { Self::from_std_file(fs::File::from(handle)) } } #[cfg(not(windows))] impl AsRawFd for Dir { #[inline] fn as_raw_fd(&self) -> RawFd { self.std_file.as_raw_fd() } } #[cfg(not(windows))] impl AsFd for Dir { #[inline] fn as_fd(&self) -> BorrowedFd<'_> { self.std_file.as_fd() } } #[cfg(windows)] impl AsRawHandle for Dir { #[inline] fn as_raw_handle(&self) -> RawHandle { self.std_file.as_raw_handle() } } #[cfg(windows)] impl AsHandle for Dir { #[inline] fn as_handle(&self) -> BorrowedHandle<'_> { self.std_file.as_handle() } } #[cfg(windows)] impl AsRawHandleOrSocket for Dir { #[inline] fn as_raw_handle_or_socket(&self) -> RawHandleOrSocket { self.std_file.as_raw_handle_or_socket() } } #[cfg(windows)] impl AsHandleOrSocket for Dir { #[inline] fn as_handle_or_socket(&self) -> BorrowedHandleOrSocket<'_> { self.std_file.as_handle_or_socket() } } #[cfg(not(windows))] impl IntoRawFd for Dir { #[inline] fn into_raw_fd(self) -> RawFd { self.std_file.into_raw_fd() } } #[cfg(not(windows))] impl From for OwnedFd { #[inline] fn from(dir: Dir) -> OwnedFd { dir.std_file.into() } } #[cfg(windows)] impl IntoRawHandle for Dir { #[inline] fn into_raw_handle(self) -> RawHandle { self.std_file.into_raw_handle() } } #[cfg(windows)] impl From for OwnedHandle { #[inline] fn from(dir: Dir) -> OwnedHandle { dir.std_file.into() } } #[cfg(windows)] impl IntoRawHandleOrSocket for Dir { #[inline] fn into_raw_handle_or_socket(self) -> RawHandleOrSocket { self.std_file.into_raw_handle_or_socket() } } #[cfg(windows)] impl From for OwnedHandleOrSocket { #[inline] fn from(dir: Dir) -> Self { dir.std_file.into() } } /// Indicates how large a buffer to pre-allocate before reading the entire /// file. /// /// Derived from the function of the same name in Rust's library/std/src/fs.rs /// at revision 108e90ca78f052c0c1c49c42a22c85620be19712. async fn initial_buffer_size(file: &File) -> usize { // Allocate one extra byte so the buffer doesn't need to grow before the // final `read` call at the end of the file. Don't worry about `usize` // overflow because reading will fail regardless in that case. file.metadata() .await .map(|m| m.len() as usize + 1) .unwrap_or(0) } impl fmt::Debug for Dir { // Like libstd's version, but doesn't print the path. fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let mut b = f.debug_struct("Dir"); #[cfg(not(windows))] b.field("fd", &self.std_file.as_raw_fd()); #[cfg(windows)] b.field("handle", &self.std_file.as_raw_handle()); b.finish() } } cap-async-std-3.4.1/src/fs/dir_entry.rs000064400000000000000000000062701046102023000160500ustar 00000000000000use crate::fs::{Dir, File, FileType, Metadata, OpenOptions}; use async_std::io; #[cfg(unix)] use async_std::os::unix::fs::DirEntryExt; #[cfg(target_os = "wasi")] use async_std::os::wasi::fs::DirEntryExt; use std::ffi::OsString; use std::fmt; /// Entries returned by the `ReadDir` iterator. /// /// This corresponds to [`async_std::fs::DirEntry`]. /// /// Unlike `async_std::fs::DirEntry`, this API has no `DirEntry::path`, because /// absolute paths don't interoperate well with the capability model. /// /// There is a `file_name` function, however there are also `open`, /// `open_with`, `open_dir`, `remove_file`, and `remove_dir` functions for /// opening or removing the entry directly, which can be more efficient and /// convenient. /// /// There is no `from_std` method, as `async_std::fs::DirEntry` doesn't provide /// a way to construct a `DirEntry` without opening directories by ambient /// paths. /// /// TODO: async pub struct DirEntry { pub(crate) inner: cap_primitives::fs::DirEntry, } impl DirEntry { /// Open the file for reading. #[inline] pub fn open(&self) -> io::Result { let file = self.inner.open()?.into(); Ok(File::from_std(file)) } /// Open the file with the given options. #[inline] pub fn open_with(&self, options: &OpenOptions) -> io::Result { let file = self.inner.open_with(options)?.into(); Ok(File::from_std(file)) } /// Open the entry as a directory. #[inline] pub fn open_dir(&self) -> io::Result { let file = self.inner.open_dir()?.into(); Ok(Dir::from_std_file(file)) } /// Removes the file from its filesystem. #[inline] pub fn remove_file(&self) -> io::Result<()> { self.inner.remove_file() } /// Removes the directory from its filesystem. #[inline] pub fn remove_dir(&self) -> io::Result<()> { self.inner.remove_dir() } /// Returns the metadata for the file that this entry points at. /// /// This corresponds to [`async_std::fs::DirEntry::metadata`]. #[inline] pub fn metadata(&self) -> io::Result { // TODO: Make this async. self.inner.metadata() } /// Returns the file type for the file that this entry points at. /// /// This corresponds to [`async_std::fs::DirEntry::file_type`]. #[inline] pub async fn file_type(&self) -> io::Result { // TODO: Make this actually async. self.inner.file_type() } /// Returns the bare file name of this directory entry without any other /// leading path component. /// /// This corresponds to [`async_std::fs::DirEntry::file_name`]. #[inline] pub fn file_name(&self) -> OsString { self.inner.file_name() } } #[cfg(not(windows))] impl DirEntryExt for DirEntry { #[inline] fn ino(&self) -> u64 { self.inner.ino() } } #[cfg(windows)] #[doc(hidden)] impl cap_primitives::fs::_WindowsDirEntryExt for DirEntry { #[inline] fn full_metadata(&self) -> io::Result { self.inner.full_metadata() } } impl fmt::Debug for DirEntry { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.inner.fmt(f) } } cap-async-std-3.4.1/src/fs/file.rs000064400000000000000000000320561046102023000147710ustar 00000000000000use crate::fs::{Metadata, OpenOptions, Permissions}; use async_std::fs; use async_std::io::{self, IoSlice, IoSliceMut, Read, Seek, SeekFrom, Write}; #[cfg(unix)] use async_std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd}; #[cfg(target_os = "wasi")] use async_std::os::wasi::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd}; use async_std::task::{spawn_blocking, Context, Poll}; use cap_primitives::fs::{is_file_read_write, open_ambient}; use cap_primitives::AmbientAuthority; use io_lifetimes::AsFilelike; #[cfg(not(windows))] use io_lifetimes::{AsFd, BorrowedFd, OwnedFd}; #[cfg(windows)] use io_lifetimes::{AsHandle, BorrowedHandle, OwnedHandle}; use std::fmt; use std::path::Path; use std::pin::Pin; #[cfg(windows)] use { async_std::os::windows::io::{AsRawHandle, FromRawHandle, IntoRawHandle, RawHandle}, io_extras::os::windows::{ AsHandleOrSocket, AsRawHandleOrSocket, BorrowedHandleOrSocket, IntoRawHandleOrSocket, OwnedHandleOrSocket, RawHandleOrSocket, }, }; /// A reference to an open file on a filesystem. /// /// This corresponds to [`async_std::fs::File`]. /// /// This `File` has no `open` or `create` methods. To open or create a file, /// first obtain a [`Dir`] containing the path, and then call [`Dir::open`] or /// [`Dir::create`]. /// /// [`Dir`]: crate::fs::Dir /// [`Dir::open`]: crate::fs::Dir::open /// [`Dir::create`]: crate::fs::Dir::create #[derive(Clone)] pub struct File { pub(crate) std: fs::File, } impl File { /// Constructs a new instance of `Self` from the given /// `async_std::fs::File`. /// /// This grants access the resources the `async_std::fs::File` instance /// already has access to. #[inline] pub fn from_std(std: fs::File) -> Self { Self { std } } /// Consumes `self` and returns an `async_std::fs::File`. #[inline] pub fn into_std(self) -> fs::File { self.std } /// Attempts to sync all OS-internal metadata to disk. /// /// This corresponds to [`async_std::fs::File::sync_all`]. #[inline] pub async fn sync_all(&self) -> io::Result<()> { self.std.sync_all().await } /// This function is similar to `sync_all`, except that it may not /// synchronize file metadata to a filesystem. /// /// This corresponds to [`async_std::fs::File::sync_data`]. #[inline] pub async fn sync_data(&self) -> io::Result<()> { self.std.sync_data().await } /// Truncates or extends the underlying file, updating the size of this /// file to become size. /// /// This corresponds to [`async_std::fs::File::set_len`]. #[inline] pub async fn set_len(&self, size: u64) -> io::Result<()> { self.std.set_len(size).await } /// Queries metadata about the underlying file. /// /// This corresponds to [`async_std::fs::File::metadata`]. #[inline] pub async fn metadata(&self) -> io::Result { let clone = self.clone(); spawn_blocking(move || metadata_from(&*clone.std.as_filelike_view::())).await } // async_std doesn't have `try_clone`. /// Changes the permissions on the underlying file. /// /// This corresponds to [`async_std::fs::File::set_permissions`]. #[inline] pub async fn set_permissions(&self, perm: Permissions) -> io::Result<()> { let sync = self.std.as_filelike_view::(); self.std .set_permissions(permissions_into_std(&sync, perm)?) .await } /// Constructs a new instance of `Self` in read-only mode by opening the /// given path as a file using the host process' ambient authority. /// /// # Ambient Authority /// /// This function is not sandboxed and may access any path that the host /// process has access to. #[inline] pub async fn open_ambient>( path: P, ambient_authority: AmbientAuthority, ) -> io::Result { let path = path.as_ref().to_path_buf(); spawn_blocking(move || { open_ambient( path.as_ref(), OpenOptions::new().read(true), ambient_authority, ) }) .await .map(|f| Self::from_std(f.into())) } /// Constructs a new instance of `Self` in write-only mode by opening, /// creating or truncating, the given path as a file using the host /// process' ambient authority. /// /// # Ambient Authority /// /// This function is not sandboxed and may access any path that the host /// process has access to. #[inline] pub async fn create_ambient>( path: P, ambient_authority: AmbientAuthority, ) -> io::Result { let path = path.as_ref().to_path_buf(); spawn_blocking(move || { open_ambient( path.as_ref(), OpenOptions::new().write(true).create(true).truncate(true), ambient_authority, ) }) .await .map(|f| Self::from_std(f.into())) } /// Constructs a new instance of `Self` with the options specified by /// `options` by opening the given path as a file using the host process' /// ambient authority. /// /// # Ambient Authority /// /// This function is not sandboxed and may access any path that the host /// process has access to. #[inline] pub async fn open_ambient_with>( path: P, options: &OpenOptions, ambient_authority: AmbientAuthority, ) -> io::Result { let path = path.as_ref().to_path_buf(); let options = options.clone(); spawn_blocking(move || open_ambient(path.as_ref(), &options, ambient_authority)) .await .map(|f| Self::from_std(f.into())) } /// Returns a new `OpenOptions` object. /// /// This corresponds to [`async_std::fs::File::options`]. #[must_use] #[inline] pub fn options() -> OpenOptions { OpenOptions::new() } } #[cfg(not(target_os = "wasi"))] #[inline] fn metadata_from(file: &std::fs::File) -> io::Result { Metadata::from_file(file) } #[cfg(target_os = "wasi")] #[inline] fn metadata_from(file: &std::fs::File) -> io::Result { file.metadata() } #[cfg(not(target_os = "wasi"))] #[inline] fn permissions_into_std( file: &std::fs::File, permissions: Permissions, ) -> io::Result { permissions.into_std(file) } #[cfg(target_os = "wasi")] #[inline] fn permissions_into_std( _file: &std::fs::File, permissions: Permissions, ) -> io::Result { permissions } // Safety: `FilelikeViewType` is implemented for `std::fs::File`. unsafe impl io_lifetimes::views::FilelikeViewType for File {} #[cfg(not(windows))] impl FromRawFd for File { #[inline] unsafe fn from_raw_fd(fd: RawFd) -> Self { Self::from_std(fs::File::from_raw_fd(fd)) } } #[cfg(not(windows))] impl From for File { #[inline] fn from(fd: OwnedFd) -> Self { Self::from_std(fs::File::from(fd)) } } #[cfg(windows)] impl FromRawHandle for File { #[inline] unsafe fn from_raw_handle(handle: RawHandle) -> Self { Self::from_std(fs::File::from_raw_handle(handle)) } } #[cfg(windows)] impl From for File { #[inline] fn from(handle: OwnedHandle) -> Self { Self::from_std(fs::File::from(handle)) } } #[cfg(not(windows))] impl AsRawFd for File { #[inline] fn as_raw_fd(&self) -> RawFd { self.std.as_raw_fd() } } #[cfg(not(windows))] impl AsFd for File { #[inline] fn as_fd(&self) -> BorrowedFd<'_> { self.std.as_fd() } } #[cfg(windows)] impl AsRawHandle for File { #[inline] fn as_raw_handle(&self) -> RawHandle { self.std.as_raw_handle() } } #[cfg(windows)] impl AsHandle for File { #[inline] fn as_handle(&self) -> BorrowedHandle<'_> { self.std.as_handle() } } #[cfg(windows)] impl AsRawHandleOrSocket for File { #[inline] fn as_raw_handle_or_socket(&self) -> RawHandleOrSocket { self.std.as_raw_handle_or_socket() } } #[cfg(windows)] impl AsHandleOrSocket for File { #[inline] fn as_handle_or_socket(&self) -> BorrowedHandleOrSocket<'_> { self.std.as_handle_or_socket() } } #[cfg(not(windows))] impl IntoRawFd for File { #[inline] fn into_raw_fd(self) -> RawFd { self.std.into_raw_fd() } } #[cfg(not(windows))] impl From for OwnedFd { #[inline] fn from(file: File) -> OwnedFd { file.std.into() } } #[cfg(windows)] impl IntoRawHandle for File { #[inline] fn into_raw_handle(self) -> RawHandle { self.std.into_raw_handle() } } #[cfg(windows)] impl From for OwnedHandle { #[inline] fn from(file: File) -> OwnedHandle { file.std.into() } } #[cfg(windows)] impl IntoRawHandleOrSocket for File { #[inline] fn into_raw_handle_or_socket(self) -> RawHandleOrSocket { self.std.into_raw_handle_or_socket() } } #[cfg(windows)] impl From for OwnedHandleOrSocket { #[inline] fn from(file: File) -> Self { file.std.into() } } impl Read for File { #[inline] fn poll_read( mut self: Pin<&mut Self>, cx: &mut Context, buf: &mut [u8], ) -> Poll> { Read::poll_read(Pin::new(&mut self.std), cx, buf) } #[inline] fn poll_read_vectored( mut self: Pin<&mut Self>, cx: &mut Context, bufs: &mut [IoSliceMut], ) -> Poll> { Read::poll_read_vectored(Pin::new(&mut self.std), cx, bufs) } // async_std doesn't have `is_read_vectored`. // async_std doesn't have `initializer`. } impl Read for &File { #[inline] fn poll_read( self: Pin<&mut Self>, cx: &mut Context, buf: &mut [u8], ) -> Poll> { Read::poll_read(Pin::new(&mut &self.std), cx, buf) } #[inline] fn poll_read_vectored( self: Pin<&mut Self>, cx: &mut Context, bufs: &mut [IoSliceMut], ) -> Poll> { Read::poll_read_vectored(Pin::new(&mut &self.std), cx, bufs) } // async_std doesn't have `is_read_vectored`. // async_std doesn't have `initializer`. } impl Write for File { #[inline] fn poll_write( mut self: Pin<&mut Self>, cx: &mut Context, buf: &[u8], ) -> Poll> { Write::poll_write(Pin::new(&mut self.std), cx, buf) } #[inline] fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll> { Write::poll_flush(Pin::new(&mut self.std), cx) } #[inline] fn poll_close(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll> { Write::poll_close(Pin::new(&mut self.std), cx) } #[inline] fn poll_write_vectored( mut self: Pin<&mut Self>, cx: &mut Context, bufs: &[IoSlice], ) -> Poll> { Write::poll_write_vectored(Pin::new(&mut self.std), cx, bufs) } // async_std doesn't have `is_write_vectored`. // async_std doesn't have `write_all_vectored`. } impl Write for &File { #[inline] fn poll_write(self: Pin<&mut Self>, cx: &mut Context, buf: &[u8]) -> Poll> { Write::poll_write(Pin::new(&mut &self.std), cx, buf) } #[inline] fn poll_flush(self: Pin<&mut Self>, cx: &mut Context) -> Poll> { Write::poll_flush(Pin::new(&mut &self.std), cx) } #[inline] fn poll_close(self: Pin<&mut Self>, cx: &mut Context) -> Poll> { Write::poll_close(Pin::new(&mut &self.std), cx) } #[inline] fn poll_write_vectored( self: Pin<&mut Self>, cx: &mut Context, bufs: &[IoSlice], ) -> Poll> { Write::poll_write_vectored(Pin::new(&mut &self.std), cx, bufs) } // async_std doesn't have `is_write_vectored`. // async_std doesn't have `write_all_vectored`. } impl Seek for File { #[inline] fn poll_seek( mut self: Pin<&mut Self>, cx: &mut Context, pos: SeekFrom, ) -> Poll> { Seek::poll_seek(Pin::new(&mut self.std), cx, pos) } } impl Seek for &File { #[inline] fn poll_seek(self: Pin<&mut Self>, cx: &mut Context, pos: SeekFrom) -> Poll> { Seek::poll_seek(Pin::new(&mut &self.std), cx, pos) } } // TODO: Can async_std implement `From` for `process::Stdio`? // async_std doesn't have `FileExt`. impl fmt::Debug for File { // Like libstd's version, but doesn't print the path. fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let mut b = f.debug_struct("File"); let file = self.std.as_filelike_view::(); #[cfg(not(windows))] b.field("fd", &file.as_raw_fd()); #[cfg(windows)] b.field("handle", &file.as_raw_handle()); if let Ok((read, write)) = is_file_read_write(&file) { b.field("read", &read).field("write", &write); } b.finish() } } cap-async-std-3.4.1/src/fs/mod.rs000064400000000000000000000040521046102023000146240ustar 00000000000000//! A capability-based filesystem API modeled after [`async_std::fs`]. //! //! This corresponds to [`async_std::fs`]. //! //! Instead of [`async_std::fs`'s free functions] and [`async_std::fs::File`]'s //! constructors which operate on bare paths, this crate has methods on [`Dir`] //! which operate on paths which must be relative to the directory. //! //! Where `async_std` says "the filesystem", this API says "a filesystem", as //! it doesn't assume that there's a single global filesystem namespace. //! //! Since all functions which expose raw file descriptors are `unsafe`, I/O //! handles in this API are unforgeable (unsafe code notwithstanding). This //! combined with a lack of absolute paths provides a natural capability-based //! interface. //! //! This crate uses the existing `async_std::path::Path` rather than having its //! own path type, however while `async_std::path::Path` is mostly just a pure //! datatype, it includes aliases for several `async_std::fs` functions. To //! preserve the capability-based interface, avoid using //! `async_std::path::Path`'s `canonicalize`, `read_link`, `read_dir`, //! `metadata`, and `symlink_metadata` functions. //! //! [`async_std::fs`'s free functions]: https://docs.rs/async-std/latest/async_std/fs/#functions mod dir; mod dir_entry; mod file; mod read_dir; pub use dir::Dir; pub use dir_entry::DirEntry; pub use file::File; pub use read_dir::ReadDir; // Re-export things from `cap_primitives` that we can use as-is. #[cfg(not(target_os = "wasi"))] pub use cap_primitives::fs::{DirBuilder, FileType, Metadata, OpenOptions, Permissions}; // Re-export conditional types from `cap_primitives`. #[cfg(any(unix, target_os = "vxworks", all(windows, windows_file_type_ext)))] pub use cap_primitives::fs::FileTypeExt; #[cfg(unix)] pub use cap_primitives::fs::{DirBuilderExt, PermissionsExt}; pub use cap_primitives::fs::{FileExt, MetadataExt, OpenOptionsExt}; // Re-export things from `async_std` that we can use as-is. #[cfg(target_os = "wasi")] pub use async_std::fs::{DirBuilder, FileType, Metadata, OpenOptions, Permissions}; cap-async-std-3.4.1/src/fs/read_dir.rs000064400000000000000000000014031046102023000156130ustar 00000000000000use crate::fs::DirEntry; use async_std::io; use std::fmt; /// Iterator over the entries in a directory. /// /// This corresponds to [`async_std::fs::ReadDir`]. /// /// There is no `from_std` method, as `async_std::fs::ReadDir` doesn't provide /// a way to construct a `ReadDir` without opening directories by ambient /// paths. pub struct ReadDir { pub(crate) inner: cap_primitives::fs::ReadDir, } impl Iterator for ReadDir { type Item = io::Result; #[inline] fn next(&mut self) -> Option { self.inner .next() .map(|inner| inner.map(|inner| DirEntry { inner })) } } impl fmt::Debug for ReadDir { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.inner.fmt(f) } } cap-async-std-3.4.1/src/fs_utf8/dir.rs000064400000000000000000000665151046102023000156050ustar 00000000000000use crate::fs::{OpenOptions, Permissions}; use crate::fs_utf8::{from_utf8, to_utf8, DirBuilder, File, Metadata, ReadDir}; use async_std::{fs, io}; use camino::{Utf8Path, Utf8PathBuf}; use cap_primitives::AmbientAuthority; use io_lifetimes::raw::{AsRawFilelike, FromRawFilelike}; use io_lifetimes::AsFilelike; #[cfg(not(windows))] use io_lifetimes::{AsFd, BorrowedFd, OwnedFd}; #[cfg(windows)] use io_lifetimes::{AsHandle, BorrowedHandle, OwnedHandle}; use std::fmt; use std::mem::ManuallyDrop; #[cfg(unix)] use { crate::os::unix::net::{UnixDatagram, UnixListener, UnixStream}, async_std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd}, }; #[cfg(windows)] use { async_std::os::windows::io::{AsRawHandle, FromRawHandle, IntoRawHandle, RawHandle}, io_extras::os::windows::{ AsHandleOrSocket, AsRawHandleOrSocket, BorrowedHandleOrSocket, IntoRawHandleOrSocket, OwnedHandleOrSocket, RawHandleOrSocket, }, }; /// A reference to an open directory on a filesystem. /// /// This does not directly correspond to anything in `async_std`, however its /// methods correspond to the [functions in `async_std::fs`] and the /// constructor methods for [`async_std::fs::File`]. /// /// Unlike `async_std::fs`, this API's `canonicalize` returns a relative path /// since absolute paths don't interoperate well with the capability model. /// /// [functions in `async_std::fs`]: https://docs.rs/async-std/latest/async_std/fs/index.html#functions #[derive(Clone)] pub struct Dir { cap_std: crate::fs::Dir, } impl Dir { /// Constructs a new instance of `Self` from the given /// `async_std::fs::File`. /// /// To prevent race conditions on Windows, the file must be opened without /// `FILE_SHARE_DELETE`. /// /// This grants access the resources the `async_std::fs::File` instance /// already has access to. #[inline] pub fn from_std_file(std_file: fs::File) -> Self { Self::from_cap_std(crate::fs::Dir::from_std_file(std_file)) } /// Constructs a new instance of `Self` from the given `cap_std::fs::Dir`. #[inline] pub fn from_cap_std(cap_std: crate::fs::Dir) -> Self { Self { cap_std } } /// Attempts to open a file in read-only mode. /// /// This corresponds to [`async_std::fs::File::open`], but only accesses /// paths relative to `self`. #[inline] pub async fn open>(&self, path: P) -> io::Result { let path = from_utf8(path.as_ref())?; self.cap_std.open(path).await.map(File::from_cap_std) } /// Opens a file at `path` with the options specified by `options`. /// /// This corresponds to [`async_std::fs::OpenOptions::open`]. /// /// Instead of being a method on `OpenOptions`, this is a method on `Dir`, /// and it only accesses paths relative to `self`. #[inline] pub async fn open_with>( &self, path: P, options: &OpenOptions, ) -> io::Result { let path = from_utf8(path.as_ref())?; self.cap_std .open_with(path, options) .await .map(File::from_cap_std) } /// Attempts to open a directory. #[inline] pub async fn open_dir>(&self, path: P) -> io::Result { let path = from_utf8(path.as_ref())?; self.cap_std.open_dir(path).await.map(Self::from_cap_std) } /// Creates a new, empty directory at the provided path. /// /// This corresponds to [`async_std::fs::create_dir`], but only accesses /// paths relative to `self`. /// /// TODO: async: fix this when we fix https://github.com/bytecodealliance/cap-std/issues/51 #[inline] pub fn create_dir>(&self, path: P) -> io::Result<()> { let path = from_utf8(path.as_ref())?; self.cap_std.create_dir(path) } /// Recursively create a directory and all of its parent components if they /// are missing. /// /// This corresponds to [`async_std::fs::create_dir_all`], but only /// accesses paths relative to `self`. /// /// TODO: async: fix this when we fix https://github.com/bytecodealliance/cap-std/issues/51 #[inline] pub fn create_dir_all>(&self, path: P) -> io::Result<()> { let path = from_utf8(path.as_ref())?; self.cap_std.create_dir_all(path) } /// Creates the specified directory with the options configured in this /// builder. /// /// This corresponds to [`async_std::fs::DirBuilder::create`]. /// /// TODO: async: fix this when we fix https://github.com/bytecodealliance/cap-std/issues/51 #[inline] pub fn create_dir_with>( &self, path: P, dir_builder: &DirBuilder, ) -> io::Result<()> { let path = from_utf8(path.as_ref())?; self.cap_std.create_dir_with(path, dir_builder) } /// Opens a file in write-only mode. /// /// This corresponds to [`async_std::fs::File::create`], but only accesses /// paths relative to `self`. #[inline] pub async fn create>(&self, path: P) -> io::Result { let path = from_utf8(path.as_ref())?; self.cap_std.create(path).await.map(File::from_cap_std) } /// Returns the canonical form of a path with all intermediate components /// normalized and symbolic links resolved. /// /// This corresponds to [`async_std::fs::canonicalize`], but instead of /// returning an absolute path, returns a path relative to the /// directory represented by `self`. #[inline] pub async fn canonicalize>(&self, path: P) -> io::Result { let path = from_utf8(path.as_ref())?; self.cap_std.canonicalize(path).await.and_then(to_utf8) } /// Copies the contents of one file to another. This function will also /// copy the permission bits of the original file to the destination /// file. /// /// This corresponds to [`async_std::fs::copy`], but only accesses paths /// relative to `self`. #[inline] pub async fn copy, Q: AsRef>( &self, from: P, to_dir: &Self, to: Q, ) -> io::Result { let from = from_utf8(from.as_ref())?; let to = from_utf8(to.as_ref())?; self.cap_std.copy(from, &to_dir.cap_std, to).await } /// Creates a new hard link on a filesystem. /// /// This corresponds to [`async_std::fs::hard_link`], but only accesses /// paths relative to `self`. #[inline] pub async fn hard_link, Q: AsRef>( &self, src: P, dst_dir: &Self, dst: Q, ) -> io::Result<()> { let src = from_utf8(src.as_ref())?; let dst = from_utf8(dst.as_ref())?; self.cap_std.hard_link(src, &dst_dir.cap_std, dst).await } /// Given a path, query the file system to get information about a file, /// directory, etc. /// /// This corresponds to [`async_std::fs::metadata`], but only accesses /// paths relative to `self`. #[inline] pub async fn metadata>(&self, path: P) -> io::Result { let path = from_utf8(path.as_ref())?; self.cap_std.metadata(path).await } /// Queries metadata about the underlying directory. /// /// This is similar to [`std::fs::File::metadata`], but for `Dir` rather /// than for `File`. #[inline] pub async fn dir_metadata(&self) -> io::Result { self.cap_std.dir_metadata().await } /// Returns an iterator over the entries within `self`. #[inline] pub async fn entries(&self) -> io::Result { self.cap_std.entries().await.map(ReadDir::from_cap_std) } /// Returns an iterator over the entries within a directory. /// /// This corresponds to [`async_std::fs::read_dir`], but only accesses /// paths relative to `self`. #[inline] pub async fn read_dir>(&self, path: P) -> io::Result { let path = from_utf8(path.as_ref())?; self.cap_std.read_dir(path).await.map(ReadDir::from_cap_std) } /// Read the entire contents of a file into a bytes vector. /// /// This corresponds to [`async_std::fs::read`], but only accesses paths /// relative to `self`. #[inline] pub async fn read>(&self, path: P) -> io::Result> { let path = from_utf8(path.as_ref())?; self.cap_std.read(path).await } /// Reads a symbolic link, returning the file that the link points to. /// /// This corresponds to [`async_std::fs::read_link`], but only accesses /// paths relative to `self`. #[inline] pub async fn read_link>(&self, path: P) -> io::Result { let path = from_utf8(path.as_ref())?; self.cap_std.read_link(path).await.and_then(to_utf8) } /// Read the entire contents of a file into a string. /// /// This corresponds to [`async_std::fs::read_to_string`], but only /// accesses paths relative to `self`. #[inline] pub async fn read_to_string>(&self, path: P) -> io::Result { let path = from_utf8(path.as_ref())?; self.cap_std.read_to_string(path).await } /// Removes an empty directory. /// /// This corresponds to [`async_std::fs::remove_dir`], but only accesses /// paths relative to `self`. #[inline] pub async fn remove_dir>(&self, path: P) -> io::Result<()> { let path = from_utf8(path.as_ref())?; self.cap_std.remove_dir(path).await } /// Removes a directory at this path, after removing all its contents. Use /// carefully! /// /// This corresponds to [`async_std::fs::remove_dir_all`], but only /// accesses paths relative to `self`. #[inline] pub async fn remove_dir_all>(&self, path: P) -> io::Result<()> { let path = from_utf8(path.as_ref())?; self.cap_std.remove_dir_all(path).await } /// Remove the directory referenced by `self` and consume `self`. /// /// Even though this implementation works in terms of handles as much as /// possible, removal is not guaranteed to be atomic with respect to a /// concurrent rename of the directory. #[inline] pub async fn remove_open_dir(self) -> io::Result<()> { self.cap_std.remove_open_dir().await } /// Removes the directory referenced by `self`, after removing all its /// contents, and consume `self`. Use carefully! /// /// Even though this implementation works in terms of handles as much as /// possible, removal is not guaranteed to be atomic with respect to a /// concurrent rename of the directory. #[inline] pub async fn remove_open_dir_all(self) -> io::Result<()> { self.cap_std.remove_open_dir_all().await } /// Removes a file from a filesystem. /// /// This corresponds to [`async_std::fs::remove_file`], but only accesses /// paths relative to `self`. #[inline] pub async fn remove_file>(&self, path: P) -> io::Result<()> { let path = from_utf8(path.as_ref())?; self.cap_std.remove_file(path).await } /// Rename a file or directory to a new name, replacing the original file /// if to already exists. /// /// This corresponds to [`async_std::fs::rename`], but only accesses paths /// relative to `self`. #[inline] pub async fn rename, Q: AsRef>( &self, from: P, to_dir: &Self, to: Q, ) -> io::Result<()> { let from = from_utf8(from.as_ref())?; let to = from_utf8(to.as_ref())?; self.cap_std.rename(from, &to_dir.cap_std, to).await } /// Changes the permissions found on a file or a directory. /// /// This corresponds to [`async_std::fs::set_permissions`], but only /// accesses paths relative to `self`. Also, on some platforms, this /// function may fail if the file or directory cannot be opened for /// reading or writing first. pub async fn set_permissions>( &self, path: P, perm: Permissions, ) -> io::Result<()> { let path = from_utf8(path.as_ref())?; self.cap_std.set_permissions(path, perm).await } /// Query the metadata about a file without following symlinks. /// /// This corresponds to [`async_std::fs::symlink_metadata`], but only /// accesses paths relative to `self`. #[inline] pub async fn symlink_metadata>(&self, path: P) -> io::Result { let path = from_utf8(path.as_ref())?; self.cap_std.symlink_metadata(path).await } /// Write a slice as the entire contents of a file. /// /// This corresponds to [`async_std::fs::write`], but only accesses paths /// relative to `self`. #[inline] pub async fn write, C: AsRef<[u8]>>( &self, path: P, contents: C, ) -> io::Result<()> { let path = from_utf8(path.as_ref())?; self.cap_std.write(path, contents).await } /// Creates a new symbolic link on a filesystem. /// /// The `original` argument provides the target of the symlink. The `link` /// argument provides the name of the created symlink. /// /// Despite the argument ordering, `original` is not resolved relative to /// `self` here. `link` is resolved relative to `self`, and `original` is /// not resolved within this function. /// /// The `link` path is resolved when the symlink is dereferenced, relative /// to the directory that contains it. /// /// This corresponds to [`async_std::os::unix::fs::symlink`], but only /// accesses paths relative to `self`. /// /// [`async_std::os::unix::fs::symlink`]: https://docs.rs/async-std/latest/async_std/os/unix/fs/fn.symlink.html #[cfg(not(windows))] #[inline] pub async fn symlink, Q: AsRef>( &self, original: P, link: Q, ) -> io::Result<()> { let original = from_utf8(original.as_ref())?; let link = from_utf8(link.as_ref())?; self.cap_std.symlink(original, link).await } /// Creates a new file symbolic link on a filesystem. /// /// The `original` argument provides the target of the symlink. The `link` /// argument provides the name of the created symlink. /// /// Despite the argument ordering, `original` is not resolved relative to /// `self` here. `link` is resolved relative to `self`, and `original` is /// not resolved within this function. /// /// The `link` path is resolved when the symlink is dereferenced, relative /// to the directory that contains it. /// /// This corresponds to [`async_std::os::windows::fs::symlink_file`], but /// only accesses paths relative to `self`. /// /// [`async_std::os::windows::fs::symlink_file`]: https://docs.rs/async-std/latest/async_std/os/windows/fs/fn.symlink_file.html #[cfg(windows)] #[inline] pub async fn symlink_file, Q: AsRef>( &self, original: P, link: Q, ) -> io::Result<()> { let original = from_utf8(original.as_ref())?; let link = from_utf8(link.as_ref())?; self.cap_std.symlink_file(original, link).await } /// Creates a new directory symlink on a filesystem. /// /// The `original` argument provides the target of the symlink. The `link` /// argument provides the name of the created symlink. /// /// Despite the argument ordering, `original` is not resolved relative to /// `self` here. `link` is resolved relative to `self`, and `original` is /// not resolved within this function. /// /// The `link` path is resolved when the symlink is dereferenced, relative /// to the directory that contains it. /// /// This corresponds to [`async_std::os::windows::fs::symlink_dir`], but /// only accesses paths relative to `self`. /// /// [`async_std::os::windows::fs::symlink_dir`]: https://docs.rs/async-std/latest/async_std/os/windows/fs/fn.symlink_dir.html #[cfg(windows)] #[inline] pub async fn symlink_dir, Q: AsRef>( &self, original: P, link: Q, ) -> io::Result<()> { let original = from_utf8(original.as_ref())?; let link = from_utf8(link.as_ref())?; self.cap_std.symlink_dir(original, link).await } /// Creates a new `UnixListener` bound to the specified socket. /// /// This corresponds to [`async_std::os::unix::net::UnixListener::bind`], /// but only accesses paths relative to `self`. /// /// XXX: This function is not yet implemented. /// /// [`async_std::os::unix::net::UnixListener::bind`]: https://docs.rs/async-std/latest/async_std/os/unix/net/struct.UnixListener.html#method.bind #[doc(alias = "bind")] #[cfg(unix)] #[inline] pub async fn bind_unix_listener>( &self, path: P, ) -> io::Result { let path = from_utf8(path.as_ref())?; self.cap_std.bind_unix_listener(path).await } /// Connects to the socket named by path. /// /// This corresponds to [`async_std::os::unix::net::UnixStream::connect`], /// but only accesses paths relative to `self`. /// /// XXX: This function is not yet implemented. /// /// [`async_std::os::unix::net::UnixStream::connect`]: https://docs.rs/async-std/latest/async_std/os/unix/net/struct.UnixStream.html#method.connect #[doc(alias = "connect")] #[cfg(unix)] #[inline] pub async fn connect_unix_stream>(&self, path: P) -> io::Result { let path = from_utf8(path.as_ref())?; self.cap_std.connect_unix_stream(path).await } /// Creates a Unix datagram socket bound to the given path. /// /// This corresponds to [`async_std::os::unix::net::UnixDatagram::bind`], /// but only accesses paths relative to `self`. /// /// XXX: This function is not yet implemented. /// /// [`async_std::os::unix::net::UnixDatagram::bind`]: https://docs.rs/async-std/latest/async_std/os/unix/net/struct.UnixDatagram.html#method.bind #[doc(alias = "bind")] #[cfg(unix)] #[inline] pub async fn bind_unix_datagram>( &self, path: P, ) -> io::Result { let path = from_utf8(path.as_ref())?; self.cap_std.bind_unix_datagram(path).await } /// Connects the socket to the specified address. /// /// This corresponds to /// [`async_std::os::unix::net::UnixDatagram::connect`], but only /// accesses paths relative to `self`. /// /// XXX: This function is not yet implemented. /// /// [`async_std::os::unix::net::UnixDatagram::connect`]: https://docs.rs/async-std/latest/async_std/os/unix/net/struct.UnixDatagram.html#method.connect #[doc(alias = "connect")] #[cfg(unix)] #[inline] pub async fn connect_unix_datagram>( &self, unix_datagram: &UnixDatagram, path: P, ) -> io::Result<()> { let path = from_utf8(path.as_ref())?; self.cap_std .connect_unix_datagram(unix_datagram, path) .await } /// Sends data on the socket to the specified address. /// /// This corresponds to /// [`async_std::os::unix::net::UnixDatagram::send_to`], but only /// accesses paths relative to `self`. /// /// XXX: This function is not yet implemented. /// /// [`async_std::os::unix::net::UnixDatagram::send_to`]: https://docs.rs/async-std/latest/async_std/os/unix/net/struct.UnixDatagram.html#method.send_to #[doc(alias = "send_to")] #[cfg(unix)] #[inline] pub async fn send_to_unix_datagram_addr>( &self, unix_datagram: &UnixDatagram, buf: &[u8], path: P, ) -> io::Result { let path = from_utf8(path.as_ref())?; self.cap_std .send_to_unix_datagram_addr(unix_datagram, buf, path) .await } // async_std doesn't have `try_clone`. /// Returns `true` if the path points at an existing entity. /// /// This corresponds to [`async_std::path::Path::exists`], but only /// accesses paths relative to `self`. #[inline] pub async fn exists>(&self, path: P) -> bool { match from_utf8(path.as_ref()) { Ok(path) => self.cap_std.exists(path).await, Err(_) => false, } } /// Returns `true` if the path points at an existing entity. /// /// This corresponds to [`async_std::path::Path::exists`], but only /// accesses paths relative to `self`. #[inline] pub async fn try_exists>(&self, path: P) -> io::Result { self.cap_std.try_exists(from_utf8(path.as_ref())?).await } /// Returns `true` if the path exists on disk and is pointing at a regular /// file. /// /// This corresponds to [`async_std::path::Path::is_file`], but only /// accesses paths relative to `self`. #[inline] pub async fn is_file>(&self, path: P) -> bool { match from_utf8(path.as_ref()) { Ok(path) => self.cap_std.is_file(path).await, Err(_) => false, } } /// Checks if `path` is a directory. /// /// This is similar to [`async_std::path::Path::is_dir`] in that it checks /// if `path` relative to `Dir` is a directory. This function will traverse /// symbolic links to query information about the destination file. In case /// of broken symbolic links, this will return `false`. #[inline] pub async fn is_dir>(&self, path: P) -> bool { match from_utf8(path.as_ref()) { Ok(path) => self.cap_std.is_dir(path).await, Err(_) => false, } } /// Constructs a new instance of `Self` by opening the given path as a /// directory using the host process' ambient authority. /// /// # Ambient Authority /// /// This function is not sandboxed and may access any path that the host /// process has access to. #[inline] pub async fn open_ambient_dir>( path: P, ambient_authority: AmbientAuthority, ) -> io::Result { let path = from_utf8(path.as_ref())?; crate::fs::Dir::open_ambient_dir(path, ambient_authority) .await .map(Self::from_cap_std) } /// Constructs a new instance of `Self` by opening the parent directory /// (aka "..") of `self`, using the host process' ambient authority. /// /// # Ambient Authority /// /// This function accesses a directory outside of the `self` subtree. #[inline] pub async fn open_parent_dir(&self, ambient_authority: AmbientAuthority) -> io::Result { self.cap_std .open_parent_dir(ambient_authority) .await .map(Self::from_cap_std) } /// Recursively create a directory and all of its parent components if they /// are missing, using the host process' ambient authority. /// /// # Ambient Authority /// /// This function is not sandboxed and may access any path that the host /// process has access to. #[inline] pub async fn create_ambient_dir_all>( path: P, ambient_authority: AmbientAuthority, ) -> io::Result<()> { let _ = ambient_authority; let path = from_utf8(path.as_ref())?; fs::create_dir_all(path).await } /// Construct a new instance of `Self` from existing directory file /// descriptor. /// /// This can be useful when interacting with other libraries and or C/C++ /// code which has invoked `openat(..., O_DIRECTORY)` external to this /// crate. pub async fn reopen_dir(dir: &Filelike) -> io::Result { // Our public API has a `&Filelike` here, which prevents us from doing // a `clone` as we usually do. So instead, we use the raw fd, which we // can clone and depend on it remaining open until we return. let raw_filelike = dir.as_filelike_view::().as_raw_filelike(); // SAFETY: `raw_filelike` remains open for the duration of the `reopen_dir` // call. let file = ManuallyDrop::new(unsafe { std::fs::File::from_raw_filelike(raw_filelike) }); crate::fs::Dir::reopen_dir(&*file) .await .map(Self::from_cap_std) } } // Safety: `FilelikeViewType` is implemented for `std::fs::File`. unsafe impl io_lifetimes::views::FilelikeViewType for Dir {} #[cfg(not(windows))] impl FromRawFd for Dir { #[inline] unsafe fn from_raw_fd(fd: RawFd) -> Self { Self::from_std_file(fs::File::from_raw_fd(fd)) } } #[cfg(not(windows))] impl From for Dir { #[inline] fn from(fd: OwnedFd) -> Self { Self::from_std_file(fs::File::from(fd)) } } #[cfg(windows)] impl FromRawHandle for Dir { /// To prevent race conditions on Windows, the handle must be opened /// without `FILE_SHARE_DELETE`. #[inline] unsafe fn from_raw_handle(handle: RawHandle) -> Self { Self::from_std_file(fs::File::from_raw_handle(handle)) } } #[cfg(windows)] impl From for Dir { #[inline] fn from(handle: OwnedHandle) -> Self { Self::from_std_file(fs::File::from(handle)) } } #[cfg(not(windows))] impl AsRawFd for Dir { #[inline] fn as_raw_fd(&self) -> RawFd { self.cap_std.as_raw_fd() } } #[cfg(not(windows))] impl AsFd for Dir { #[inline] fn as_fd(&self) -> BorrowedFd<'_> { self.cap_std.as_fd() } } #[cfg(windows)] impl AsRawHandle for Dir { #[inline] fn as_raw_handle(&self) -> RawHandle { self.cap_std.as_raw_handle() } } #[cfg(windows)] impl AsHandle for Dir { #[inline] fn as_handle(&self) -> BorrowedHandle<'_> { self.cap_std.as_handle() } } #[cfg(windows)] impl AsHandleOrSocket for Dir { #[inline] fn as_handle_or_socket(&self) -> BorrowedHandleOrSocket<'_> { self.cap_std.as_handle_or_socket() } } #[cfg(windows)] impl AsRawHandleOrSocket for Dir { #[inline] fn as_raw_handle_or_socket(&self) -> RawHandleOrSocket { self.cap_std.as_raw_handle_or_socket() } } #[cfg(not(windows))] impl IntoRawFd for Dir { #[inline] fn into_raw_fd(self) -> RawFd { self.cap_std.into_raw_fd() } } #[cfg(not(windows))] impl From for OwnedFd { #[inline] fn from(dir: Dir) -> OwnedFd { dir.cap_std.into() } } #[cfg(windows)] impl IntoRawHandle for Dir { #[inline] fn into_raw_handle(self) -> RawHandle { self.cap_std.into_raw_handle() } } #[cfg(windows)] impl From for OwnedHandle { #[inline] fn from(dir: Dir) -> OwnedHandle { dir.cap_std.into() } } #[cfg(windows)] impl IntoRawHandleOrSocket for Dir { #[inline] fn into_raw_handle_or_socket(self) -> RawHandleOrSocket { self.cap_std.into_raw_handle_or_socket() } } #[cfg(windows)] impl From for OwnedHandleOrSocket { #[inline] fn from(dir: Dir) -> Self { dir.cap_std.into() } } impl fmt::Debug for Dir { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.cap_std.fmt(f) } } cap-async-std-3.4.1/src/fs_utf8/dir_entry.rs000064400000000000000000000066421046102023000170210ustar 00000000000000use crate::fs::{FileType, Metadata, OpenOptions}; use crate::fs_utf8::{to_utf8, Dir, File}; #[cfg(not(windows))] use rustix::fs::DirEntryExt; use std::{fmt, io}; /// Entries returned by the `ReadDir` iterator. /// /// This corresponds to [`async_std::fs::DirEntry`]. /// /// Unlike `async_std::fs::DirEntry`, this API has no `DirEntry::path`, because /// absolute paths don't interoperate well with the capability model. /// /// There is a `file_name` function, however there are also `open`, /// `open_with`, `open_dir`, `remove_file`, and `remove_dir` functions for /// opening or removing the entry directly, which can be more efficient and /// convenient. /// /// There is no `from_std` method, as `async_std::fs::DirEntry` doesn't provide /// a way to construct a `DirEntry` without opening directories by ambient /// paths. /// /// TODO: async pub struct DirEntry { cap_std: crate::fs::DirEntry, } impl DirEntry { /// Constructs a new instance of `Self` from the given /// `cap_std::fs::DirEntry`. #[inline] pub fn from_cap_std(cap_std: crate::fs::DirEntry) -> Self { Self { cap_std } } /// Open the file for reading. #[inline] pub fn open(&self) -> io::Result { self.cap_std.open().map(File::from_cap_std) } /// Open the file with the given options. #[inline] pub fn open_with(&self, options: &OpenOptions) -> io::Result { self.cap_std.open_with(options).map(File::from_cap_std) } /// Open the entry as a directory. #[inline] pub fn open_dir(&self) -> io::Result { self.cap_std.open_dir().map(Dir::from_cap_std) } /// Removes the file from its filesystem. #[inline] pub fn remove_file(&self) -> io::Result<()> { self.cap_std.remove_file() } /// Removes the directory from its filesystem. #[inline] pub fn remove_dir(&self) -> io::Result<()> { self.cap_std.remove_dir() } /// Returns the metadata for the file that this entry points at. /// /// This corresponds to [`async_std::fs::DirEntry::metadata`]. #[inline] pub fn metadata(&self) -> io::Result { self.cap_std.metadata() } /// Returns the file type for the file that this entry points at. /// /// This corresponds to [`async_std::fs::DirEntry::file_type`]. #[inline] pub async fn file_type(&self) -> io::Result { self.cap_std.file_type().await } /// Returns the bare file name of this directory entry without any other /// leading path component. /// /// This function returns an `Err` in the case that the file name isn't /// encodable as UTF-8. /// /// If the `arf_strings` feature is enabled, unencodable names are /// translated to UTF-8 using `arf-strings`. /// /// This corresponds to [`async_std::fs::DirEntry::file_name`]. #[inline] pub fn file_name(&self) -> io::Result { Ok(to_utf8(self.cap_std.file_name())?.into()) } } #[cfg(not(windows))] impl DirEntryExt for DirEntry { #[inline] fn ino(&self) -> u64 { self.cap_std.ino() } } #[cfg(windows)] #[doc(hidden)] impl cap_primitives::fs::_WindowsDirEntryExt for DirEntry { #[inline] fn full_metadata(&self) -> io::Result { self.cap_std.full_metadata() } } impl fmt::Debug for DirEntry { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.cap_std.fmt(f) } } cap-async-std-3.4.1/src/fs_utf8/file.rs000064400000000000000000000274531046102023000157440ustar 00000000000000use crate::fs::{Metadata, OpenOptions, Permissions}; use crate::fs_utf8::from_utf8; use async_std::fs; use async_std::io::{self, IoSlice, IoSliceMut, Read, Seek, SeekFrom, Write}; #[cfg(unix)] use async_std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd}; #[cfg(target_os = "wasi")] use async_std::os::wasi::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd}; use async_std::task::{Context, Poll}; use camino::Utf8Path; use cap_primitives::AmbientAuthority; #[cfg(not(windows))] use io_lifetimes::{AsFd, BorrowedFd, OwnedFd}; #[cfg(windows)] use io_lifetimes::{AsHandle, BorrowedHandle, OwnedHandle}; use std::fmt; use std::pin::Pin; #[cfg(windows)] use { async_std::os::windows::io::{AsRawHandle, FromRawHandle, IntoRawHandle, RawHandle}, io_extras::os::windows::{ AsHandleOrSocket, AsRawHandleOrSocket, BorrowedHandleOrSocket, IntoRawHandleOrSocket, OwnedHandleOrSocket, RawHandleOrSocket, }, }; /// A reference to an open file on a filesystem. /// /// This corresponds to [`async_std::fs::File`]. /// /// This `File` has no `open` or `create` methods. To open or create a file, /// first obtain a [`Dir`] containing the path, and then call [`Dir::open`] or /// [`Dir::create`]. /// /// [`Dir`]: crate::fs::Dir /// [`Dir::open`]: crate::fs::Dir::open /// [`Dir::create`]: crate::fs::Dir::create pub struct File { cap_std: crate::fs::File, } impl File { /// Constructs a new instance of `Self` from the given /// `async_std::fs::File`. /// /// This grants access the resources the `async_std::fs::File` instance /// already has access to. #[inline] pub fn from_std(std: fs::File) -> Self { Self::from_cap_std(crate::fs::File::from_std(std)) } /// Constructs a new instance of `Self` from the given `cap_std::fs::File`. #[inline] pub fn from_cap_std(cap_std: crate::fs::File) -> Self { Self { cap_std } } /// Consumes `self` and returns an `async_std::fs::File`. #[inline] pub fn into_std(self) -> fs::File { self.cap_std.into_std() } /// Attempts to sync all OS-internal metadata to disk. /// /// This corresponds to [`async_std::fs::File::sync_all`]. #[inline] pub async fn sync_all(&self) -> io::Result<()> { self.cap_std.sync_all().await } /// This function is similar to `sync_all`, except that it may not /// synchronize file metadata to a filesystem. /// /// This corresponds to [`async_std::fs::File::sync_data`]. #[inline] pub async fn sync_data(&self) -> io::Result<()> { self.cap_std.sync_data().await } /// Truncates or extends the underlying file, updating the size of this /// file to become size. /// /// This corresponds to [`async_std::fs::File::set_len`]. #[inline] pub async fn set_len(&self, size: u64) -> io::Result<()> { self.cap_std.set_len(size).await } /// Queries metadata about the underlying file. /// /// This corresponds to [`async_std::fs::File::metadata`]. #[inline] pub async fn metadata(&self) -> io::Result { self.cap_std.metadata().await } // async_std doesn't have `try_clone`. /// Changes the permissions on the underlying file. /// /// This corresponds to [`async_std::fs::File::set_permissions`]. #[inline] pub async fn set_permissions(&self, perm: Permissions) -> io::Result<()> { self.cap_std.set_permissions(perm).await } /// Constructs a new instance of `Self` in read-only mode by opening the /// given path as a file using the host process' ambient authority. /// /// # Ambient Authority /// /// This function is not sandboxed and may access any path that the host /// process has access to. #[inline] pub async fn open_ambient>( path: P, ambient_authority: AmbientAuthority, ) -> io::Result { let path = from_utf8(path.as_ref())?; crate::fs::File::open_ambient(path, ambient_authority) .await .map(Self::from_cap_std) } /// Constructs a new instance of `Self` in write-only mode by opening, /// creating or truncating, the given path as a file using the host /// process' ambient authority. /// /// # Ambient Authority /// /// This function is not sandboxed and may access any path that the host /// process has access to. #[inline] pub async fn create_ambient>( path: P, ambient_authority: AmbientAuthority, ) -> io::Result { let path = from_utf8(path.as_ref())?; crate::fs::File::create_ambient(path, ambient_authority) .await .map(Self::from_cap_std) } /// Constructs a new instance of `Self` with the options specified by /// `options` by opening the given path as a file using the host process' /// ambient authority. /// /// # Ambient Authority /// /// This function is not sandboxed and may access any path that the host /// process has access to. #[inline] pub async fn open_ambient_with>( path: P, options: &OpenOptions, ambient_authority: AmbientAuthority, ) -> io::Result { let path = from_utf8(path.as_ref())?; crate::fs::File::open_ambient_with(path, options, ambient_authority) .await .map(Self::from_cap_std) } /// Returns a new `OpenOptions` object. /// /// This corresponds to [`async_std::fs::File::options`]. #[must_use] #[inline] pub fn options() -> OpenOptions { OpenOptions::new() } } // Safety: `FilelikeViewType` is implemented for `std::fs::File`. unsafe impl io_lifetimes::views::FilelikeViewType for File {} #[cfg(not(windows))] impl FromRawFd for File { #[inline] unsafe fn from_raw_fd(fd: RawFd) -> Self { Self::from_std(fs::File::from_raw_fd(fd)) } } #[cfg(not(windows))] impl From for File { #[inline] fn from(fd: OwnedFd) -> Self { Self::from_std(fs::File::from(fd)) } } #[cfg(windows)] impl FromRawHandle for File { #[inline] unsafe fn from_raw_handle(handle: RawHandle) -> Self { Self::from_std(fs::File::from_raw_handle(handle)) } } #[cfg(windows)] impl From for File { #[inline] fn from(handle: OwnedHandle) -> Self { Self::from_std(fs::File::from(handle)) } } #[cfg(not(windows))] impl AsRawFd for File { #[inline] fn as_raw_fd(&self) -> RawFd { self.cap_std.as_raw_fd() } } #[cfg(not(windows))] impl AsFd for File { #[inline] fn as_fd(&self) -> BorrowedFd<'_> { self.cap_std.as_fd() } } #[cfg(windows)] impl AsRawHandle for File { #[inline] fn as_raw_handle(&self) -> RawHandle { self.cap_std.as_raw_handle() } } #[cfg(windows)] impl AsHandle for File { #[inline] fn as_handle(&self) -> BorrowedHandle<'_> { self.cap_std.as_handle() } } #[cfg(windows)] impl AsRawHandleOrSocket for File { #[inline] fn as_raw_handle_or_socket(&self) -> RawHandleOrSocket { self.cap_std.as_raw_handle_or_socket() } } #[cfg(windows)] impl AsHandleOrSocket for File { #[inline] fn as_handle_or_socket(&self) -> BorrowedHandleOrSocket<'_> { self.cap_std.as_handle_or_socket() } } #[cfg(not(windows))] impl IntoRawFd for File { #[inline] fn into_raw_fd(self) -> RawFd { self.cap_std.into_raw_fd() } } #[cfg(not(windows))] impl From for OwnedFd { #[inline] fn from(file: File) -> OwnedFd { file.cap_std.into() } } #[cfg(windows)] impl IntoRawHandle for File { #[inline] fn into_raw_handle(self) -> RawHandle { self.cap_std.into_raw_handle() } } #[cfg(windows)] impl From for OwnedHandle { #[inline] fn from(file: File) -> OwnedHandle { file.cap_std.into() } } #[cfg(windows)] impl IntoRawHandleOrSocket for File { #[inline] fn into_raw_handle_or_socket(self) -> RawHandleOrSocket { self.cap_std.into_raw_handle_or_socket() } } #[cfg(windows)] impl From for OwnedHandleOrSocket { #[inline] fn from(file: File) -> Self { file.cap_std.into() } } impl Read for File { #[inline] fn poll_read( mut self: Pin<&mut Self>, cx: &mut Context, buf: &mut [u8], ) -> Poll> { Read::poll_read(Pin::new(&mut self.cap_std), cx, buf) } #[inline] fn poll_read_vectored( mut self: Pin<&mut Self>, cx: &mut Context, bufs: &mut [IoSliceMut], ) -> Poll> { Read::poll_read_vectored(Pin::new(&mut self.cap_std), cx, bufs) } // async_std doesn't have `is_read_vectored`. // async_std doesn't have `initializer`. } impl Read for &File { #[inline] fn poll_read( self: Pin<&mut Self>, cx: &mut Context, buf: &mut [u8], ) -> Poll> { Read::poll_read(Pin::new(&mut &self.cap_std), cx, buf) } #[inline] fn poll_read_vectored( self: Pin<&mut Self>, cx: &mut Context, bufs: &mut [IoSliceMut], ) -> Poll> { Read::poll_read_vectored(Pin::new(&mut &self.cap_std), cx, bufs) } // async_std doesn't have `is_read_vectored`. // async_std doesn't have `initializer`. } impl Write for File { #[inline] fn poll_write( mut self: Pin<&mut Self>, cx: &mut Context, buf: &[u8], ) -> Poll> { Write::poll_write(Pin::new(&mut self.cap_std), cx, buf) } #[inline] fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll> { Write::poll_flush(Pin::new(&mut self.cap_std), cx) } #[inline] fn poll_close(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll> { Write::poll_close(Pin::new(&mut self.cap_std), cx) } #[inline] fn poll_write_vectored( mut self: Pin<&mut Self>, cx: &mut Context, bufs: &[IoSlice], ) -> Poll> { Write::poll_write_vectored(Pin::new(&mut self.cap_std), cx, bufs) } // async_std doesn't have `can_vector`. // async_std doesn't have `write_all_vectored`. } impl Write for &File { #[inline] fn poll_write(self: Pin<&mut Self>, cx: &mut Context, buf: &[u8]) -> Poll> { Write::poll_write(Pin::new(&mut &self.cap_std), cx, buf) } #[inline] fn poll_flush(self: Pin<&mut Self>, cx: &mut Context) -> Poll> { Write::poll_flush(Pin::new(&mut &self.cap_std), cx) } #[inline] fn poll_close(self: Pin<&mut Self>, cx: &mut Context) -> Poll> { Write::poll_close(Pin::new(&mut &self.cap_std), cx) } #[inline] fn poll_write_vectored( self: Pin<&mut Self>, cx: &mut Context, bufs: &[IoSlice], ) -> Poll> { Write::poll_write_vectored(Pin::new(&mut &self.cap_std), cx, bufs) } // async_std doesn't have `can_vector`. // async_std doesn't have `write_all_vectored`. } impl Seek for File { #[inline] fn poll_seek( mut self: Pin<&mut Self>, cx: &mut Context, pos: SeekFrom, ) -> Poll> { Seek::poll_seek(Pin::new(&mut self.cap_std), cx, pos) } // async_std doesn't have `stream_position`. } impl Seek for &File { #[inline] fn poll_seek(self: Pin<&mut Self>, cx: &mut Context, pos: SeekFrom) -> Poll> { Seek::poll_seek(Pin::new(&mut &self.cap_std), cx, pos) } // async_std doesn't have `stream_position`. } // TODO: Can async_std implement `From` for `process::Stdio`? // async_std doesn't have `FileExt`. impl fmt::Debug for File { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.cap_std.fmt(f) } } cap-async-std-3.4.1/src/fs_utf8/mod.rs000064400000000000000000000057671046102023000156100ustar 00000000000000//! A fully UTF-8 filesystem API modeled after [`cap_async_std::fs`]. //! //! Where `cap_async_std::fs` would use `Path` and `PathBuf`, this `fs_utf8` //! module uses [`Utf8Path`] and [`Utf8PathBuf`], meaning that all paths are //! valid UTF-8. //! //! If you don't want this, use the regular [`cap_async_std::fs`] module //! instead. //! //! [`cap_async_std::fs`]: ../fs/ mod dir; mod dir_entry; mod file; mod read_dir; pub use dir::Dir; pub use dir_entry::DirEntry; pub use file::File; pub use read_dir::ReadDir; // Re-export things from `cap_std::fs` that we can use as-is. pub use crate::fs::{DirBuilder, FileType, Metadata, OpenOptions, Permissions}; // Re-export conditional types from `cap_primitives`. #[cfg(any(unix, target_os = "vxworks", all(windows, windows_file_type_ext)))] pub use cap_primitives::fs::FileTypeExt; #[cfg(unix)] pub use cap_primitives::fs::{DirBuilderExt, PermissionsExt}; pub use cap_primitives::fs::{FileExt, MetadataExt, OpenOptionsExt}; // Re-export `camino` to make it easy for users to depend on the same // version we do, because we use its types in our public API. pub use camino; use camino::{Utf8Path, Utf8PathBuf}; #[cfg(not(feature = "arf_strings"))] fn from_utf8<'a>(path: &'a Utf8Path) -> std::io::Result<&'a async_std::path::Path> { Ok(path.as_std_path().into()) } #[cfg(feature = "arf_strings")] fn from_utf8<'a>(path: &'a Utf8Path) -> std::io::Result { #[cfg(not(windows))] let path = { #[cfg(unix)] use std::{ffi::OsString, os::unix::ffi::OsStringExt}; #[cfg(target_os = "wasi")] use std::{ffi::OsString, os::wasi::ffi::OsStringExt}; let string = arf_strings::str_to_host(path.as_str())?; OsString::from_vec(string.into_bytes()) }; #[cfg(windows)] let path = arf_strings::str_to_host(path.as_str())?; Ok(path.into()) } fn to_utf8>(path: P) -> std::io::Result { #[cfg(not(feature = "arf_strings"))] #[cfg(not(windows))] { Ok(Utf8Path::from_path(path.as_ref().into()) .ok_or_else(|| ::rustix::io::Errno::ILSEQ)? .to_path_buf()) } #[cfg(not(feature = "arf_strings"))] #[cfg(windows)] { Ok(Utf8Path::from_path(path.as_ref().into()) .ok_or_else(|| { std::io::Error::new( std::io::ErrorKind::InvalidData, "filesystem path is not valid UTF-8", ) })? .to_path_buf()) } #[cfg(feature = "arf_strings")] { // For now, for WASI use the same logic as other OS's, but // in the future, the idea is we could avoid this. let osstr = path.as_ref().as_os_str(); #[cfg(not(windows))] { arf_strings::host_os_str_to_str(osstr) .map(std::borrow::Cow::into_owned) .map(Into::into) } #[cfg(windows)] { arf_strings::host_to_str(osstr).map(Into::into) } } } cap-async-std-3.4.1/src/fs_utf8/read_dir.rs000064400000000000000000000016711046102023000165700ustar 00000000000000use crate::fs_utf8::DirEntry; use std::{fmt, io}; /// Iterator over the entries in a directory. /// /// This corresponds to [`async_std::fs::ReadDir`]. /// /// There is no `from_std` method, as `async_std::fs::ReadDir` doesn't provide /// a way to construct a `ReadDir` without opening directories by ambient /// paths. pub struct ReadDir { cap_std: crate::fs::ReadDir, } impl ReadDir { /// Constructs a new instance of `Self` from the given `cap_std::fs::File`. #[inline] pub fn from_cap_std(cap_std: crate::fs::ReadDir) -> Self { Self { cap_std } } } impl Iterator for ReadDir { type Item = io::Result; #[inline] fn next(&mut self) -> Option { self.cap_std .next() .map(|result| result.map(DirEntry::from_cap_std)) } } impl fmt::Debug for ReadDir { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.cap_std.fmt(f) } } cap-async-std-3.4.1/src/lib.rs000064400000000000000000000041231046102023000142020ustar 00000000000000//! A capability-based API modeled after [`async_std`]. //! //! This corresponds to [`async_std`]. //! //! Capability-based APIs represent access to external resources as values //! which can be passed around between different parts of a program. //! //! Two notable features are the [`Dir`] and [`Pool`] types: //! - `Dir` represents an open directory in a filesystem. Instead of opening //! files by absolute paths or paths relative to the current working //! directory, files are opened via paths relative to a `Dir`. The concepts //! of a process-wide "current working directory" and a single global //! filesystem namespace are de-emphasized. //! - `Pool` represents a set of network addresses. Instead of allowing //! applications to request access to any address and then applying //! process-wide filtering rules, filtering rules are built into pools which //! may be passed through the program. //! //! On WASI, use of this library closely reflects the underlying system //! API, so it avoids compatibility layers. //! //! [`Dir`]: fs::Dir //! [`Pool`]: net::Pool #![deny(missing_docs)] #![cfg_attr(target_os = "wasi", feature(wasi_ext))] // async_std doesn't have "can_vector". // async_std doesn't have "write_all_vectored". #![doc( html_logo_url = "https://raw.githubusercontent.com/bytecodealliance/cap-std/main/media/cap-std.svg" )] #![doc( html_favicon_url = "https://raw.githubusercontent.com/bytecodealliance/cap-std/main/media/cap-std.ico" )] #![cfg_attr(io_lifetimes_use_std, feature(io_safety))] pub mod fs; #[cfg(feature = "fs_utf8")] pub mod fs_utf8; #[cfg(not(target_os = "wasi"))] // Disable `net` on WASI until it has networking support. pub mod net; pub mod os; pub mod time; #[doc(hidden)] pub use cap_primitives::ambient_authority_known_at_compile_time; pub use cap_primitives::{ambient_authority, AmbientAuthority}; // Re-export `async_std` to make it easy for users to depend on the same // version we do, because we use its types in our public API. pub use async_std; // And these are also part of our public API pub use cap_primitives::ipnet; pub use io_lifetimes; cap-async-std-3.4.1/src/net/incoming.rs000064400000000000000000000025421046102023000160300ustar 00000000000000use crate::net::TcpStream; use async_std::stream::Stream; use async_std::task::{Context, Poll}; use async_std::{io, net}; use std::fmt; use std::pin::Pin; /// An iterator that infinitely `accept`s connections on a [`TcpListener`]. /// /// This corresponds to [`async_std::net::Incoming`]. /// /// [`TcpListener`]: struct.TcpListener.html pub struct Incoming<'a> { std: net::Incoming<'a>, } impl<'a> Incoming<'a> { /// Constructs a new instance of `Self` from the given /// `async_std::net::Incoming`. /// /// This grants access the resources the `async_std::net::Incoming` /// instance already has access to. #[inline] pub fn from_std(std: net::Incoming<'a>) -> Self { Self { std } } } impl<'a> Stream for Incoming<'a> { type Item = io::Result; #[inline] fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll> { Stream::poll_next(Pin::new(&mut self.std), cx).map(|poll| { poll.map(|result| { let tcp_stream = result?; Ok(TcpStream::from_std(tcp_stream)) }) }) } #[inline] fn size_hint(&self) -> (usize, Option) { self.std.size_hint() } } impl<'a> fmt::Debug for Incoming<'a> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.std.fmt(f) } } cap-async-std-3.4.1/src/net/mod.rs000064400000000000000000000014451046102023000150050ustar 00000000000000//! A capability-based network API modeled after [`async_std::net`]. //! //! This corresponds to [`async_std::net`]. //! //! Instead of [`async_std::net`]'s constructor methods which take an address //! to connect to, this crates has methods on [`Pool`] which operate on //! addresses which must be present in the pool. //! //! [`Pool`]: struct.Pool.html mod incoming; mod pool; mod tcp_listener; mod tcp_stream; mod udp_socket; pub use incoming::*; pub use pool::*; pub use tcp_listener::*; pub use tcp_stream::*; pub use udp_socket::*; // Re-export things from `async_std::net` that we can use as-is. pub use async_std::net::{ AddrParseError, IpAddr, Ipv4Addr, Ipv6Addr, Shutdown, SocketAddr, SocketAddrV4, SocketAddrV6, ToSocketAddrs, }; // TODO: re-export experimental Ipv6MulticastScope? cap-async-std-3.4.1/src/net/pool.rs000064400000000000000000000164021046102023000151760ustar 00000000000000use crate::net::{TcpListener, TcpStream, ToSocketAddrs, UdpSocket}; use async_std::{io, net}; use cap_primitives::net::no_socket_addrs; use cap_primitives::{ipnet, AmbientAuthority}; /// A pool of network addresses. /// /// This does not directly correspond to anything in `async_std`, however its /// methods correspond to the several functions in [`async_std::net`]. /// /// `Pool` implements `Clone`, which creates new independent entities that /// carry the full authority of the originals. This means that in a borrow /// of a `Pool`, the scope of the authority is not necessarily limited to /// the scope of the borrow. /// /// Similarly, the [`cap_net_ext::PoolExt`] class allows creating "binder" /// and "connecter" objects which represent capabilities to bind and /// connect to addresses. /// /// [`cap_net_ext::PoolExt`]: https://docs.rs/cap-net-ext/latest/cap_net_ext/trait.PoolExt.html #[derive(Clone, Default)] pub struct Pool { cap: cap_primitives::net::Pool, } impl Pool { /// Construct a new empty pool. pub fn new() -> Self { Self { cap: cap_primitives::net::Pool::new(), } } /// Add addresses to the pool. /// /// # Ambient Authority /// /// This function allows ambient access to any IP address. pub async fn insert( &mut self, addrs: A, ambient_authority: AmbientAuthority, ) -> io::Result<()> { for addr in addrs.to_socket_addrs().await? { self.cap.insert(addr, ambient_authority)?; } Ok(()) } /// Add a specific [`net::SocketAddr`] to the pool. /// /// # Ambient Authority /// /// This function allows ambient access to any IP address. pub fn insert_socket_addr( &mut self, addr: net::SocketAddr, ambient_authority: AmbientAuthority, ) { self.cap.insert_socket_addr(addr, ambient_authority) } /// Add a range of network addresses, accepting any port, to the pool. /// /// Unlike `insert_ip_net`, this function grants access to any requested /// port. /// /// # Ambient Authority /// /// This function allows ambient access to any IP address. pub fn insert_ip_net_port_any( &mut self, ip_net: ipnet::IpNet, ambient_authority: AmbientAuthority, ) { self.cap.insert_ip_net_port_any(ip_net, ambient_authority) } /// Add a range of network addresses, accepting a range of ports, to the /// pool. /// /// This grants access to the port range starting at `ports_start` and, /// if `ports_end` is provided, ending before `ports_end`. /// /// # Ambient Authority /// /// This function allows ambient access to any IP address. pub fn insert_ip_net_port_range( &mut self, ip_net: ipnet::IpNet, ports_start: u16, ports_end: Option, ambient_authority: AmbientAuthority, ) { self.cap .insert_ip_net_port_range(ip_net, ports_start, ports_end, ambient_authority) } /// Add a range of network addresses with a specific port to the pool. /// /// # Ambient Authority /// /// This function allows ambient access to any IP address. pub fn insert_ip_net( &mut self, ip_net: ipnet::IpNet, port: u16, ambient_authority: AmbientAuthority, ) { self.cap.insert_ip_net(ip_net, port, ambient_authority) } /// Creates a new `TcpListener` which will be bound to the specified /// address. /// /// This corresponds to [`async_std::net::TcpListener::bind`]. #[doc(alias = "bind")] #[inline] pub async fn bind_tcp_listener(&self, addr: A) -> io::Result { let addrs = addr.to_socket_addrs().await?; let mut last_err = None; for addr in addrs { self.cap.check_addr(&addr)?; // TODO: when compiling for WASI, use WASI-specific methods instead match net::TcpListener::bind(addr).await { Ok(tcp_listener) => return Ok(TcpListener::from_std(tcp_listener)), Err(e) => last_err = Some(e), } } match last_err { Some(e) => Err(e), None => Err(no_socket_addrs()), } } /// Creates a new TCP stream connected to the specified address. /// /// This corresponds to [`async_std::net::TcpStream::connect`]. #[doc(alias = "connect")] #[inline] pub async fn connect_tcp_stream(&self, addr: A) -> io::Result { let addrs = addr.to_socket_addrs().await?; let mut last_err = None; for addr in addrs { self.cap.check_addr(&addr)?; // TODO: when compiling for WASI, use WASI-specific methods instead match net::TcpStream::connect(addr).await { Ok(tcp_stream) => return Ok(TcpStream::from_std(tcp_stream)), Err(e) => last_err = Some(e), } } match last_err { Some(e) => Err(e), None => Err(no_socket_addrs()), } } // async_std doesn't have `connect_timeout`. /// Creates a UDP socket from the given address. /// /// This corresponds to [`async_std::net::UdpSocket::bind`]. #[doc(alias = "bind")] #[inline] pub async fn bind_udp_socket(&self, addr: A) -> io::Result { let addrs = addr.to_socket_addrs().await?; let mut last_err = None; for addr in addrs { self.cap.check_addr(&addr)?; match net::UdpSocket::bind(addr).await { Ok(udp_socket) => return Ok(UdpSocket::from_std(udp_socket)), Err(e) => last_err = Some(e), } } match last_err { Some(e) => Err(e), None => Err(no_socket_addrs()), } } /// Sends data on the socket to the given address. /// /// This corresponds to [`async_std::net::UdpSocket::send_to`]. #[doc(alias = "send_to")] #[inline] pub async fn send_to_udp_socket_addr( &self, udp_socket: &UdpSocket, buf: &[u8], addr: A, ) -> io::Result { let mut addrs = addr.to_socket_addrs().await?; // `UdpSocket::send_to` only sends to the first address. let addr = match addrs.next() { None => return Err(no_socket_addrs()), Some(addr) => addr, }; self.cap.check_addr(&addr)?; udp_socket.std.send_to(buf, addr).await } /// Connects the UDP socket to a remote address. /// /// This corresponds to [`async_std::net::UdpSocket::connect`]. #[doc(alias = "connect")] #[inline] pub async fn connect_udp_socket( &self, udp_socket: &UdpSocket, addr: A, ) -> io::Result<()> { let addrs = addr.to_socket_addrs().await?; let mut last_err = None; for addr in addrs { self.cap.check_addr(&addr)?; match udp_socket.std.connect(addr).await { Ok(()) => return Ok(()), Err(e) => last_err = Some(e), } } match last_err { Some(e) => Err(e), None => Err(no_socket_addrs()), } } } cap-async-std-3.4.1/src/net/tcp_listener.rs000064400000000000000000000126151046102023000167220ustar 00000000000000use crate::net::{Incoming, SocketAddr, TcpStream}; #[cfg(unix)] use async_std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd}; use async_std::{io, net}; #[cfg(not(windows))] use io_lifetimes::{AsFd, BorrowedFd, OwnedFd}; #[cfg(windows)] use io_lifetimes::{AsSocket, BorrowedSocket, OwnedSocket}; use std::fmt; #[cfg(windows)] use { async_std::os::windows::io::{AsRawSocket, FromRawSocket, IntoRawSocket, RawSocket}, io_extras::os::windows::{ AsHandleOrSocket, AsRawHandleOrSocket, BorrowedHandleOrSocket, IntoRawHandleOrSocket, OwnedHandleOrSocket, RawHandleOrSocket, }, }; /// A TCP socket server, listening for connections. /// /// This corresponds to [`async_std::net::TcpListener`]. /// /// This `TcpListener` has no `bind` method. To bind it to a socket address, /// first obtain a [`Pool`] permitting the address, and then call /// [`Pool::bind_tcp_listener`]. /// /// [`Pool`]: struct.Pool.html /// [`Pool::bind_tcp_listener`]: struct.Pool.html#method.bind_tcp_listener pub struct TcpListener { std: net::TcpListener, } impl TcpListener { /// Constructs a new instance of `Self` from the given /// `async_std::net::TcpListener`. /// /// This grants access the resources the `async_std::net::TcpListener` /// instance already has access to. #[inline] pub fn from_std(std: net::TcpListener) -> Self { Self { std } } /// Returns the local socket address of this listener. /// /// This corresponds to [`async_std::net::TcpListener::local_addr`]. #[inline] pub fn local_addr(&self) -> io::Result { self.std.local_addr() } // async_std doesn't have `try_clone`. /// Accept a new incoming connection from this listener. /// /// This corresponds to [`async_std::net::TcpListener::accept`]. #[inline] pub async fn accept(&self) -> io::Result<(TcpStream, SocketAddr)> { self.std .accept() .await .map(|(tcp_stream, addr)| (TcpStream::from_std(tcp_stream), addr)) } /// Returns an iterator over the connections being received on this /// listener. /// /// This corresponds to [`async_std::net::TcpListener::incoming`]. #[inline] pub fn incoming(&self) -> Incoming { let incoming = self.std.incoming(); Incoming::from_std(incoming) } // async_std doesn't have `TcpListener::set_ttl`. // async_std doesn't have `TcpListener::ttl`. // async_std doesn't have `TcpListener::take_error`. // async_std doesn't have `TcpListener::set_nonblocking`. } // Safety: `SocketlikeViewType` is implemented for `std`'s socket types. unsafe impl io_lifetimes::views::SocketlikeViewType for TcpListener {} #[cfg(not(windows))] impl FromRawFd for TcpListener { #[inline] unsafe fn from_raw_fd(fd: RawFd) -> Self { Self::from_std(net::TcpListener::from_raw_fd(fd)) } } #[cfg(not(windows))] impl From for TcpListener { #[inline] fn from(fd: OwnedFd) -> Self { Self::from_std(net::TcpListener::from(fd)) } } #[cfg(windows)] impl FromRawSocket for TcpListener { #[inline] unsafe fn from_raw_socket(socket: RawSocket) -> Self { Self::from_std(net::TcpListener::from_raw_socket(socket)) } } #[cfg(windows)] impl From for TcpListener { #[inline] fn from(socket: OwnedSocket) -> Self { Self::from_std(net::TcpListener::from(socket)) } } #[cfg(not(windows))] impl AsRawFd for TcpListener { #[inline] fn as_raw_fd(&self) -> RawFd { self.std.as_raw_fd() } } #[cfg(not(windows))] impl AsFd for TcpListener { #[inline] fn as_fd(&self) -> BorrowedFd<'_> { self.std.as_fd() } } #[cfg(windows)] impl AsRawSocket for TcpListener { #[inline] fn as_raw_socket(&self) -> RawSocket { self.std.as_raw_socket() } } #[cfg(windows)] impl AsSocket for TcpListener { #[inline] fn as_socket(&self) -> BorrowedSocket<'_> { self.std.as_socket() } } #[cfg(windows)] impl AsRawHandleOrSocket for TcpListener { #[inline] fn as_raw_handle_or_socket(&self) -> RawHandleOrSocket { self.std.as_raw_handle_or_socket() } } #[cfg(windows)] impl AsHandleOrSocket for TcpListener { #[inline] fn as_handle_or_socket(&self) -> BorrowedHandleOrSocket<'_> { self.std.as_handle_or_socket() } } #[cfg(not(windows))] impl IntoRawFd for TcpListener { #[inline] fn into_raw_fd(self) -> RawFd { self.std.into_raw_fd() } } #[cfg(not(windows))] impl From for OwnedFd { #[inline] fn from(listener: TcpListener) -> OwnedFd { listener.std.into() } } #[cfg(windows)] impl IntoRawSocket for TcpListener { #[inline] fn into_raw_socket(self) -> RawSocket { self.std.into_raw_socket() } } #[cfg(windows)] impl From for OwnedSocket { #[inline] fn from(listener: TcpListener) -> OwnedSocket { listener.std.into() } } #[cfg(windows)] impl IntoRawHandleOrSocket for TcpListener { #[inline] fn into_raw_handle_or_socket(self) -> RawHandleOrSocket { self.std.into_raw_handle_or_socket() } } #[cfg(windows)] impl From for OwnedHandleOrSocket { #[inline] fn from(listener: TcpListener) -> Self { listener.std.into() } } impl fmt::Debug for TcpListener { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.std.fmt(f) } } cap-async-std-3.4.1/src/net/tcp_stream.rs000064400000000000000000000227741046102023000163770ustar 00000000000000use crate::net::{Shutdown, SocketAddr}; use async_std::io::{self, IoSlice, IoSliceMut, Read, Write}; use async_std::net; #[cfg(unix)] use async_std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd}; use async_std::task::{Context, Poll}; #[cfg(not(windows))] use io_lifetimes::{AsFd, BorrowedFd, OwnedFd}; #[cfg(windows)] use io_lifetimes::{AsSocket, BorrowedSocket, OwnedSocket}; use std::fmt; use std::pin::Pin; #[cfg(windows)] use { async_std::os::windows::io::{AsRawSocket, FromRawSocket, IntoRawSocket, RawSocket}, io_extras::os::windows::{ AsHandleOrSocket, AsRawHandleOrSocket, BorrowedHandleOrSocket, IntoRawHandleOrSocket, OwnedHandleOrSocket, RawHandleOrSocket, }, }; /// A TCP stream between a local and a remote socket. /// /// This corresponds to [`async_std::net::TcpStream`]. /// /// This `TcpStream` has no `connect` method. To create a `TcpStream`, first /// obtain a [`Pool`] permitting the address, and then call /// [`Pool::connect_tcp_stream`]. /// /// [`Pool`]: struct.Pool.html /// [`Pool::connect_tcp_stream`]: struct.Pool.html#method.connect_tcp_stream #[derive(Clone)] pub struct TcpStream { std: net::TcpStream, } impl TcpStream { /// Constructs a new instance of `Self` from the given /// `async_std::net::TcpStream`. /// /// This grants access the resources the `async_std::net::TcpStream` /// instance already has access to. #[inline] pub fn from_std(std: net::TcpStream) -> Self { Self { std } } /// Returns the remote address that this stream is connected to. /// /// This corresponds to [`async_std::net::TcpStream::peer_addr`]. #[inline] pub fn peer_addr(&self) -> io::Result { self.std.peer_addr() } /// Returns the local socket address of this listener. /// /// This corresponds to [`async_std::net::TcpStream::local_addr`]. #[inline] pub fn local_addr(&self) -> io::Result { self.std.local_addr() } /// Shuts down the read, write, or both halves of this connection. /// /// This corresponds to [`async_std::net::TcpStream::shutdown`]. #[inline] pub fn shutdown(&self, how: Shutdown) -> io::Result<()> { self.std.shutdown(how) } // async_std doesn't have `try_clone`. // async_std doesn't have `set_read_timeout`. // async_std doesn't have `set_write_timeout`. // async_std doesn't have `read_timeout`. // async_std doesn't have `write_timeout`. /// Receives data on the socket from the remote address to which it is /// connected, without removing that data from the queue. /// /// This corresponds to [`async_std::net::TcpStream::peek`]. #[inline] pub async fn peek(&self, buf: &mut [u8]) -> io::Result { self.std.peek(buf).await } /// Sets the value of the `TCP_NODELAY` option on this socket. /// /// This corresponds to [`async_std::net::TcpStream::set_nodelay`]. #[inline] pub fn set_nodelay(&self, nodelay: bool) -> io::Result<()> { self.std.set_nodelay(nodelay) } /// Gets the value of the `TCP_NODELAY` option on this socket. /// /// This corresponds to [`async_std::net::TcpStream::nodelay`]. #[inline] pub fn nodelay(&self) -> io::Result { self.std.nodelay() } /// Sets the value for the `IP_TTL` option on this socket. /// /// This corresponds to [`async_std::net::TcpStream::set_ttl`]. #[inline] pub fn set_ttl(&self, ttl: u32) -> io::Result<()> { self.std.set_ttl(ttl) } /// Gets the value of the `IP_TTL` option for this socket. /// /// This corresponds to [`async_std::net::TcpStream::ttl`]. #[inline] pub fn ttl(&self) -> io::Result { self.std.ttl() } // async_std doesn't have `take_error`. // async_std doesn't have `set_nonblocking`. } // Safety: `SocketlikeViewType` is implemented for `std`'s socket types. unsafe impl io_lifetimes::views::SocketlikeViewType for TcpStream {} #[cfg(not(windows))] impl FromRawFd for TcpStream { #[inline] unsafe fn from_raw_fd(fd: RawFd) -> Self { Self::from_std(net::TcpStream::from_raw_fd(fd)) } } #[cfg(not(windows))] impl From for TcpStream { #[inline] fn from(fd: OwnedFd) -> Self { Self::from_std(net::TcpStream::from(fd)) } } #[cfg(windows)] impl FromRawSocket for TcpStream { #[inline] unsafe fn from_raw_socket(socket: RawSocket) -> Self { Self::from_std(net::TcpStream::from_raw_socket(socket)) } } #[cfg(windows)] impl From for TcpStream { #[inline] fn from(socket: OwnedSocket) -> Self { Self::from_std(net::TcpStream::from(socket)) } } #[cfg(not(windows))] impl AsRawFd for TcpStream { #[inline] fn as_raw_fd(&self) -> RawFd { self.std.as_raw_fd() } } #[cfg(not(windows))] impl AsFd for TcpStream { #[inline] fn as_fd(&self) -> BorrowedFd<'_> { self.std.as_fd() } } #[cfg(windows)] impl AsRawSocket for TcpStream { #[inline] fn as_raw_socket(&self) -> RawSocket { self.std.as_raw_socket() } } #[cfg(windows)] impl AsSocket for TcpStream { #[inline] fn as_socket(&self) -> BorrowedSocket<'_> { self.std.as_socket() } } #[cfg(windows)] impl AsRawHandleOrSocket for TcpStream { #[inline] fn as_raw_handle_or_socket(&self) -> RawHandleOrSocket { self.std.as_raw_handle_or_socket() } } #[cfg(windows)] impl AsHandleOrSocket for TcpStream { #[inline] fn as_handle_or_socket(&self) -> BorrowedHandleOrSocket<'_> { self.std.as_handle_or_socket() } } #[cfg(not(windows))] impl IntoRawFd for TcpStream { #[inline] fn into_raw_fd(self) -> RawFd { self.std.into_raw_fd() } } #[cfg(not(windows))] impl From for OwnedFd { #[inline] fn from(stream: TcpStream) -> OwnedFd { stream.std.into() } } #[cfg(windows)] impl IntoRawSocket for TcpStream { #[inline] fn into_raw_socket(self) -> RawSocket { self.std.into_raw_socket() } } #[cfg(windows)] impl From for OwnedSocket { #[inline] fn from(stream: TcpStream) -> OwnedSocket { stream.std.into() } } #[cfg(windows)] impl IntoRawHandleOrSocket for TcpStream { #[inline] fn into_raw_handle_or_socket(self) -> RawHandleOrSocket { self.std.into_raw_handle_or_socket() } } #[cfg(windows)] impl From for OwnedHandleOrSocket { #[inline] fn from(stream: TcpStream) -> Self { stream.std.into() } } impl Read for TcpStream { #[inline] fn poll_read( mut self: Pin<&mut Self>, cx: &mut Context, buf: &mut [u8], ) -> Poll> { Read::poll_read(Pin::new(&mut self.std), cx, buf) } #[inline] fn poll_read_vectored( mut self: Pin<&mut Self>, cx: &mut Context, bufs: &mut [IoSliceMut], ) -> Poll> { Read::poll_read_vectored(Pin::new(&mut self.std), cx, bufs) } // async_std doesn't have `is_read_vectored`. // async_std doesn't have `initializer`. } impl Read for &TcpStream { #[inline] fn poll_read( self: Pin<&mut Self>, cx: &mut Context, buf: &mut [u8], ) -> Poll> { Read::poll_read(Pin::new(&mut &self.std), cx, buf) } #[inline] fn poll_read_vectored( self: Pin<&mut Self>, cx: &mut Context, bufs: &mut [IoSliceMut], ) -> Poll> { Read::poll_read_vectored(Pin::new(&mut &self.std), cx, bufs) } // async_std doesn't have `is_read_vectored`. // async_std doesn't have `initializer`. } impl Write for TcpStream { #[inline] fn poll_write( mut self: Pin<&mut Self>, cx: &mut Context, buf: &[u8], ) -> Poll> { Write::poll_write(Pin::new(&mut self.std), cx, buf) } #[inline] fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll> { Write::poll_flush(Pin::new(&mut self.std), cx) } #[inline] fn poll_close(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll> { Write::poll_close(Pin::new(&mut self.std), cx) } #[inline] fn poll_write_vectored( mut self: Pin<&mut Self>, cx: &mut Context, bufs: &[IoSlice], ) -> Poll> { Write::poll_write_vectored(Pin::new(&mut self.std), cx, bufs) } // async_std doesn't have `is_write_vectored`. // async_std doesn't have `write_all_vectored`. } impl Write for &TcpStream { #[inline] fn poll_write(self: Pin<&mut Self>, cx: &mut Context, buf: &[u8]) -> Poll> { Write::poll_write(Pin::new(&mut &self.std), cx, buf) } #[inline] fn poll_flush(self: Pin<&mut Self>, cx: &mut Context) -> Poll> { Write::poll_flush(Pin::new(&mut &self.std), cx) } #[inline] fn poll_close(self: Pin<&mut Self>, cx: &mut Context) -> Poll> { Write::poll_close(Pin::new(&mut &self.std), cx) } #[inline] fn poll_write_vectored( self: Pin<&mut Self>, cx: &mut Context, bufs: &[IoSlice], ) -> Poll> { Write::poll_write_vectored(Pin::new(&mut &self.std), cx, bufs) } // async_std doesn't have `is_write_vectored`. // async_std doesn't have `write_all_vectored`. } impl fmt::Debug for TcpStream { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.std.fmt(f) } } cap-async-std-3.4.1/src/net/udp_socket.rs000064400000000000000000000247011046102023000163660ustar 00000000000000use crate::net::{Ipv4Addr, Ipv6Addr, SocketAddr}; #[cfg(unix)] use async_std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd}; use async_std::{io, net}; #[cfg(not(windows))] use io_lifetimes::{AsFd, BorrowedFd, OwnedFd}; #[cfg(windows)] use io_lifetimes::{AsSocket, BorrowedSocket, OwnedSocket}; use std::fmt; #[cfg(windows)] use { async_std::os::windows::io::{AsRawSocket, FromRawSocket, IntoRawSocket, RawSocket}, io_extras::os::windows::{ AsHandleOrSocket, AsRawHandleOrSocket, BorrowedHandleOrSocket, IntoRawHandleOrSocket, OwnedHandleOrSocket, RawHandleOrSocket, }, }; /// A UDP socket. /// /// This corresponds to [`async_std::net::UdpSocket`]. /// /// This `UdpSocket` has no `bind`, `connect`, or `send_to` methods. To create /// a `UdpSocket` bound to an address or to send a message to an address, first /// obtain a [`Pool`] permitting the address, and then call /// [`Pool::bind_udp_socket`], or [`Pool::connect_udp_socket`], or /// [`Pool::send_to_udp_socket_addr`]. /// /// [`Pool`]: struct.Pool.html /// [`Pool::bind_udp_socket`]: struct.Pool.html#method.bind_udp_socket /// [`Pool::connect_udp_socket`]: struct.Pool.html#method.connect_udp_socket /// [`Pool::send_to_udp_socket_addr`]: struct.Pool.html#method.send_to_udp_socket_addr pub struct UdpSocket { pub(crate) std: net::UdpSocket, } impl UdpSocket { /// Constructs a new instance of `Self` from the given /// `async_std::net::UdpSocket`. /// /// This grants access the resources the `async_std::net::UdpSocket` /// instance already has access to. #[inline] pub fn from_std(std: net::UdpSocket) -> Self { Self { std } } /// Receives a single datagram message on the socket. /// /// This corresponds to [`async_std::net::UdpSocket::recv_from`]. #[inline] pub async fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> { self.std.recv_from(buf).await } // async_std doesn't have `peek_from`. /// Returns the socket address of the remote peer this socket was connected /// to. /// /// This corresponds to [`async_std::net::UdpSocket::peer_addr`]. #[inline] pub fn peer_addr(&self) -> io::Result { self.std.peer_addr() } /// Returns the socket address that this socket was created from. /// /// This corresponds to [`async_std::net::UdpSocket::local_addr`]. #[inline] pub fn local_addr(&self) -> io::Result { self.std.local_addr() } // async_std doesn't have `try_clone`. // async_std doesn't have `set_read_timeout`. // async_std doesn't have `set_write_timeout`. // async_std doesn't have `read_timeout`. // async_std doesn't have `write_timeout`. /// Sets the value of the `SO_BROADCAST` option for this socket. /// /// This corresponds to [`async_std::net::UdpSocket::set_broadcast`]. #[inline] pub fn set_broadcast(&self, broadcast: bool) -> io::Result<()> { self.std.set_broadcast(broadcast) } /// Gets the value of the `SO_BROADCAST` option for this socket. /// /// This corresponds to [`async_std::net::UdpSocket::broadcast`]. #[inline] pub fn broadcast(&self) -> io::Result { self.std.broadcast() } /// Sets the value of the `IP_MULTICAST_LOOP` option for this socket. /// /// This corresponds to /// [`async_std::net::UdpSocket::set_multicast_loop_v4`]. #[inline] pub fn set_multicast_loop_v4(&self, multicast_loop_v4: bool) -> io::Result<()> { self.std.set_multicast_loop_v4(multicast_loop_v4) } /// Gets the value of the `IP_MULTICAST_LOOP` option for this socket. /// /// This corresponds to [`async_std::net::UdpSocket::multicast_loop_v4`]. #[inline] pub fn multicast_loop_v4(&self) -> io::Result { self.std.multicast_loop_v4() } /// Sets the value of the `IP_MULTICAST_TTL` option for this socket. /// /// This corresponds to /// [`async_std::net::UdpSocket::set_multicast_ttl_v4`]. #[inline] pub fn set_multicast_ttl_v4(&self, multicast_ttl_v4: u32) -> io::Result<()> { self.std.set_multicast_ttl_v4(multicast_ttl_v4) } /// Gets the value of the `IP_MULTICAST_TTL` option for this socket. /// /// This corresponds to [`async_std::net::UdpSocket::multicast_ttl_v4`]. #[inline] pub fn multicast_ttl_v4(&self) -> io::Result { self.std.multicast_ttl_v4() } /// Sets the value of the `IPV6_MULTICAST_LOOP` option for this socket. /// /// This corresponds to /// [`async_std::net::UdpSocket::set_multicast_loop_v6`]. #[inline] pub fn set_multicast_loop_v6(&self, multicast_loop_v6: bool) -> io::Result<()> { self.std.set_multicast_loop_v6(multicast_loop_v6) } /// Gets the value of the `IPV6_MULTICAST_LOOP` option for this socket. /// /// This corresponds to [`async_std::net::UdpSocket::multicast_loop_v6`]. #[inline] pub fn multicast_loop_v6(&self) -> io::Result { self.std.multicast_loop_v6() } /// Sets the value for the `IP_TTL` option on this socket. /// /// This corresponds to [`async_std::net::UdpSocket::set_ttl`]. #[inline] pub fn set_ttl(&self, ttl: u32) -> io::Result<()> { self.std.set_ttl(ttl) } /// Gets the value of the `IP_TTL` option for this socket. /// /// This corresponds to [`async_std::net::UdpSocket::ttl`]. #[inline] pub fn ttl(&self) -> io::Result { self.std.ttl() } /// Executes an operation of the `IP_ADD_MEMBERSHIP` type. /// /// This corresponds to [`async_std::net::UdpSocket::join_multicast_v4`]. #[allow(clippy::trivially_copy_pass_by_ref)] #[inline] pub fn join_multicast_v4(&self, multiaddr: Ipv4Addr, interface: Ipv4Addr) -> io::Result<()> { self.std.join_multicast_v4(multiaddr, interface) } /// Executes an operation of the `IPV6_ADD_MEMBERSHIP` type. /// /// This corresponds to [`async_std::net::UdpSocket::join_multicast_v6`]. #[allow(clippy::trivially_copy_pass_by_ref)] #[inline] pub fn join_multicast_v6(&self, multiaddr: &Ipv6Addr, interface: u32) -> io::Result<()> { self.std.join_multicast_v6(multiaddr, interface) } /// Executes an operation of the `IP_DROP_MEMBERSHIP` type. /// /// This corresponds to [`async_std::net::UdpSocket::leave_multicast_v4`]. #[allow(clippy::trivially_copy_pass_by_ref)] #[inline] pub fn leave_multicast_v4(&self, multiaddr: Ipv4Addr, interface: Ipv4Addr) -> io::Result<()> { self.std.leave_multicast_v4(multiaddr, interface) } /// Executes an operation of the `IPV6_DROP_MEMBERSHIP` type. /// /// This corresponds to [`async_std::net::UdpSocket::leave_multicast_v6`]. #[allow(clippy::trivially_copy_pass_by_ref)] #[inline] pub fn leave_multicast_v6(&self, multiaddr: &Ipv6Addr, interface: u32) -> io::Result<()> { self.std.leave_multicast_v6(multiaddr, interface) } // async_std doesn't have `take_error`. /// Sends data on the socket to the remote address to which it is /// connected. /// /// This corresponds to [`async_std::net::UdpSocket::send`]. #[inline] pub async fn send(&self, buf: &[u8]) -> io::Result { self.std.send(buf).await } /// Receives a single datagram message on the socket from the remote /// address to which it is connected. /// /// This corresponds to [`async_std::net::UdpSocket::recv`]. #[inline] pub async fn recv(&self, buf: &mut [u8]) -> io::Result { self.std.recv(buf).await } // async_std doesn't have `UdpSocket::peek`. // async_std doesn't have `set_nonblocking`. } // Safety: `SocketlikeViewType` is implemented for `std`'s socket types. unsafe impl io_lifetimes::views::SocketlikeViewType for UdpSocket {} #[cfg(not(windows))] impl FromRawFd for UdpSocket { #[inline] unsafe fn from_raw_fd(fd: RawFd) -> Self { Self::from_std(net::UdpSocket::from_raw_fd(fd)) } } #[cfg(not(windows))] impl From for UdpSocket { #[inline] fn from(fd: OwnedFd) -> Self { Self::from_std(net::UdpSocket::from(fd)) } } #[cfg(windows)] impl FromRawSocket for UdpSocket { #[inline] unsafe fn from_raw_socket(socket: RawSocket) -> Self { Self::from_std(net::UdpSocket::from_raw_socket(socket)) } } #[cfg(windows)] impl From for UdpSocket { #[inline] fn from(socket: OwnedSocket) -> Self { Self::from_std(net::UdpSocket::from(socket)) } } #[cfg(not(windows))] impl AsRawFd for UdpSocket { #[inline] fn as_raw_fd(&self) -> RawFd { self.std.as_raw_fd() } } #[cfg(not(windows))] impl AsFd for UdpSocket { #[inline] fn as_fd(&self) -> BorrowedFd<'_> { self.std.as_fd() } } #[cfg(windows)] impl AsRawSocket for UdpSocket { #[inline] fn as_raw_socket(&self) -> RawSocket { self.std.as_raw_socket() } } #[cfg(windows)] impl AsSocket for UdpSocket { #[inline] fn as_socket(&self) -> BorrowedSocket<'_> { self.std.as_socket() } } #[cfg(windows)] impl AsRawHandleOrSocket for UdpSocket { #[inline] fn as_raw_handle_or_socket(&self) -> RawHandleOrSocket { self.std.as_raw_handle_or_socket() } } #[cfg(windows)] impl AsHandleOrSocket for UdpSocket { #[inline] fn as_handle_or_socket(&self) -> BorrowedHandleOrSocket<'_> { self.std.as_handle_or_socket() } } #[cfg(not(windows))] impl IntoRawFd for UdpSocket { #[inline] fn into_raw_fd(self) -> RawFd { self.std.into_raw_fd() } } #[cfg(not(windows))] impl From for OwnedFd { #[inline] fn from(socket: UdpSocket) -> OwnedFd { socket.std.into() } } #[cfg(windows)] impl IntoRawSocket for UdpSocket { #[inline] fn into_raw_socket(self) -> RawSocket { self.std.into_raw_socket() } } #[cfg(windows)] impl From for OwnedSocket { #[inline] fn from(socket: UdpSocket) -> OwnedSocket { socket.std.into() } } #[cfg(windows)] impl IntoRawHandleOrSocket for UdpSocket { #[inline] fn into_raw_handle_or_socket(self) -> RawHandleOrSocket { self.std.into_raw_handle_or_socket() } } #[cfg(windows)] impl From for OwnedHandleOrSocket { #[inline] fn from(socket: UdpSocket) -> Self { socket.std.into() } } impl fmt::Debug for UdpSocket { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.std.fmt(f) } } cap-async-std-3.4.1/src/os/mod.rs000064400000000000000000000001471046102023000146360ustar 00000000000000//! OS-specific extensions. //! //! This corresponds to [`async_std::os`]. #[cfg(unix)] pub mod unix; cap-async-std-3.4.1/src/os/unix/mod.rs000064400000000000000000000003151046102023000156160ustar 00000000000000//! Platform-specific extensions for Unix platforms. //! //! This corresponds to [`async_std::os::unix`]. //! //! [`async_std::os::unix`]: https://docs.rs/async-std/latest/async_std/os/unix/ pub mod net; cap-async-std-3.4.1/src/os/unix/net/incoming.rs000064400000000000000000000030741046102023000174350ustar 00000000000000use crate::os::unix::net::UnixStream; use async_std::io; use async_std::os::unix; use async_std::stream::Stream; use async_std::task::{Context, Poll}; use std::fmt; use std::pin::Pin; /// An iterator over incoming connections to a [`UnixListener`]. /// /// This corresponds to [`async_std::os::unix::net::Incoming`]. /// /// [`async_std::os::unix::net::Incoming`]: https://docs.rs/async-std/latest/async_std/os/unix/net/struct.Incoming.html /// [`UnixListener`]: struct.UnixListener.html pub struct Incoming<'a> { std: unix::net::Incoming<'a>, } impl<'a> Incoming<'a> { /// Constructs a new instance of `Self` from the given /// `async_std::os::unix::net::Incoming`. /// /// This grants access the resources the /// `async_std::os::unix::net::Incoming` instance already has access to, /// without any sandboxing. #[inline] pub fn from_std(std: unix::net::Incoming<'a>) -> Self { Self { std } } } impl<'a> Stream for Incoming<'a> { type Item = io::Result; #[inline] fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll> { Stream::poll_next(Pin::new(&mut self.std), cx).map(|poll| { poll.map(|result| { let unix_stream = result?; Ok(UnixStream::from_std(unix_stream)) }) }) } #[inline] fn size_hint(&self) -> (usize, Option) { self.std.size_hint() } } impl<'a> fmt::Debug for Incoming<'a> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.std.fmt(f) } } cap-async-std-3.4.1/src/os/unix/net/mod.rs000064400000000000000000000006321046102023000164060ustar 00000000000000//! Unix-specific networking functionality //! //! This corresponds to [`async_std::os::unix::net`]. //! //! [`async_std::os::unix::net`]: https://docs.rs/async-std/latest/async_std/os/unix/net/ mod incoming; mod unix_datagram; mod unix_listener; mod unix_stream; pub use incoming::*; pub use unix_datagram::*; pub use unix_listener::*; pub use unix_stream::*; pub use async_std::os::unix::net::SocketAddr; cap-async-std-3.4.1/src/os/unix/net/unix_datagram.rs000064400000000000000000000143721046102023000204600ustar 00000000000000use crate::net::Shutdown; use crate::os::unix::net::SocketAddr; use async_std::io; use async_std::os::unix; use async_std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd}; use io_lifetimes::{AsFd, BorrowedFd, OwnedFd}; use std::fmt; /// A Unix datagram socket. /// /// This corresponds to [`async_std::os::unix::net::UnixDatagram`]. /// /// This `UnixDatagram` has no `bind`, `connect`, or `send_to` methods. To /// create a `UnixDatagram`, first obtain a [`Dir`] containing the path, and /// then call [`Dir::bind_unix_datagram`], [`Dir::connect_unix_datagram`], or /// [`Dir::send_to_unix_datagram_addr`]. /// /// [`async_std::os::unix::net::UnixDatagram`]: https://docs.rs/async-std/latest/async_std/os/unix/net/struct.UnixDatagram.html /// [`Dir`]: struct.Dir.html /// [`Dir::connect_unix_datagram`]: struct.Dir.html#method.connect_unix_datagram /// [`Dir::bind_unix_datagram`]: struct.Dir.html#method.bind_unix_datagram /// [`Dir::send_to_unix_datagram_addr`]: struct.Dir.html#method.send_to_unix_datagram_addr pub struct UnixDatagram { std: unix::net::UnixDatagram, } impl UnixDatagram { /// Constructs a new instance of `Self` from the given /// `async_std::os::unix::net::UnixDatagram`. /// /// This grants access the resources the /// `async_std::os::unix::net::UnixDatagram` instance already has access /// to. #[inline] pub fn from_std(std: unix::net::UnixDatagram) -> Self { Self { std } } /// Creates a Unix Datagram socket which is not bound to any address. /// /// This corresponds to /// [`async_std::os::unix::net::UnixDatagram::unbound`]. /// /// TODO: should this require a capability? /// /// [`async_std::os::unix::net::UnixDatagram::unbound`]: https://docs.rs/async-std/latest/async_std/os/unix/net/struct.UnixDatagram.html#method.unbound #[inline] pub fn unbound() -> io::Result { let unix_datagram = unix::net::UnixDatagram::unbound()?; Ok(Self::from_std(unix_datagram)) } /// Creates an unnamed pair of connected sockets. /// /// This corresponds to [`async_std::os::unix::net::UnixDatagram::pair`]. /// /// TODO: should this require a capability? /// /// [`async_std::os::unix::net::UnixDatagram::pair`]: https://docs.rs/async-std/latest/async_std/os/unix/net/struct.UnixDatagram.html#method.pair #[inline] pub fn pair() -> io::Result<(Self, Self)> { unix::net::UnixDatagram::pair().map(|(a, b)| (Self::from_std(a), Self::from_std(b))) } // async_std doesn't have `try_clone`. /// Returns the address of this socket. /// /// This corresponds to /// [`async_std::os::unix::net::UnixDatagram::local_addr`]. /// /// [`async_std::os::unix::net::UnixDatagram::local_addr`]: https://docs.rs/async-std/latest/async_std/os/unix/net/struct.UnixDatagram.html#method.local_addr #[inline] pub fn local_addr(&self) -> io::Result { self.std.local_addr() } /// Returns the address of this socket's peer. /// /// This corresponds to /// [`async_std::os::unix::net::UnixDatagram::peer_addr`]. /// /// [`async_std::os::unix::net::UnixDatagram::peer_addr`]: https://docs.rs/async-std/latest/async_std/os/unix/net/struct.UnixDatagram.html#method.peer_addr #[inline] pub fn peer_addr(&self) -> io::Result { self.std.peer_addr() } /// Receives data from the socket. /// /// This corresponds to /// [`async_std::os::unix::net::UnixDatagram::recv_from`]. /// /// [`async_std::os::unix::net::UnixDatagram::recv_from`]: https://docs.rs/async-std/latest/async_std/os/unix/net/struct.UnixDatagram.html#method.recv_from #[inline] pub async fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> { self.std.recv_from(buf).await } /// Receives data from the socket. /// /// This corresponds to [`async_std::os::unix::net::UnixDatagram::recv`]. /// /// [`async_std::os::unix::net::UnixDatagram::recv`]: https://docs.rs/async-std/latest/async_std/os/unix/net/struct.UnixDatagram.html#method.recv #[inline] pub async fn recv(&self, buf: &mut [u8]) -> io::Result { self.std.recv(buf).await } /// Sends data on the socket to the socket's peer. /// /// This corresponds to [`async_std::os::unix::net::UnixDatagram::send`]. /// /// [`async_std::os::unix::net::UnixDatagram::send`]: https://docs.rs/async-std/latest/async_std/os/unix/net/struct.UnixDatagram.html#method.send #[inline] pub async fn send(&self, buf: &[u8]) -> io::Result { self.std.send(buf).await } // async_std doesn't have `set_read_timeout`. // async_std doesn't have `set_write_timeout`. // async_std doesn't have `read_timeout`. // async_std doesn't have `write_timeout`. // async_std doesn't have `set_nonblocking`. // async_std doesn't have `take_error`. /// Shut down the read, write, or both halves of this connection. /// /// This corresponds to /// [`async_std::os::unix::net::UnixDatagram::shutdown`]. /// /// [`async_std::os::unix::net::UnixDatagram::shutdown`]: https://docs.rs/async-std/latest/async_std/os/unix/net/struct.UnixDatagram.html#method.shutdown #[inline] pub fn shutdown(&self, how: Shutdown) -> io::Result<()> { self.std.shutdown(how) } } impl FromRawFd for UnixDatagram { #[inline] unsafe fn from_raw_fd(fd: RawFd) -> Self { Self::from_std(unix::net::UnixDatagram::from_raw_fd(fd)) } } impl From for UnixDatagram { #[inline] fn from(fd: OwnedFd) -> Self { Self::from_std(unix::net::UnixDatagram::from(fd)) } } impl AsRawFd for UnixDatagram { #[inline] fn as_raw_fd(&self) -> RawFd { self.std.as_raw_fd() } } impl AsFd for UnixDatagram { #[inline] fn as_fd(&self) -> BorrowedFd<'_> { self.std.as_fd() } } impl IntoRawFd for UnixDatagram { #[inline] fn into_raw_fd(self) -> RawFd { self.std.into_raw_fd() } } impl From for OwnedFd { #[inline] fn from(datagram: UnixDatagram) -> OwnedFd { datagram.std.into() } } impl fmt::Debug for UnixDatagram { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.std.fmt(f) } } cap-async-std-3.4.1/src/os/unix/net/unix_listener.rs000064400000000000000000000073211046102023000205210ustar 00000000000000use crate::os::unix::net::{Incoming, SocketAddr, UnixStream}; use async_std::io; use async_std::os::unix; use async_std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd}; use io_lifetimes::{AsFd, BorrowedFd, OwnedFd}; use std::fmt; /// A structure representing a Unix domain socket server. /// /// This corresponds to [`async_std::os::unix::net::UnixListener`]. /// /// This `UnixListener` has no `bind` method. To bind it to a socket address, /// first obtain a [`Dir`] containing the path, and then call /// [`Dir::bind_unix_listener`]. /// /// [`async_std::os::unix::net::UnixListener`]: https://docs.rs/async-std/latest/async_std/os/unix/net/struct.UnixListener.html /// [`Dir`]: struct.Dir.html /// [`Dir::bind_unix_listener`]: struct.Dir.html#method.bind_unix_listener pub struct UnixListener { std: unix::net::UnixListener, } impl UnixListener { /// Constructs a new instance of `Self` from the given /// `async_std::os::unix::net::UnixListener`. /// /// This grants access the resources the /// `async_std::os::unix::net::UnixListener` instance already has access /// to. #[inline] pub fn from_std(std: unix::net::UnixListener) -> Self { Self { std } } /// Accepts a new incoming connection to this listener. /// /// This corresponds to [`async_std::os::unix::net::UnixListener::accept`]. /// /// [`async_std::os::unix::net::UnixListener::accept`]: https://docs.rs/async-std/latest/async_std/os/unix/net/struct.UnixListener.html#method.accept #[inline] pub async fn accept(&self) -> io::Result<(UnixStream, SocketAddr)> { self.std .accept() .await .map(|(unix_stream, addr)| (UnixStream::from_std(unix_stream), addr)) } // async_std doesn't have `try_clone`. /// Returns the local socket address of this listener. /// /// This corresponds to /// [`async_std::os::unix::net::UnixListener::local_addr`]. /// /// [`async_std::os::unix::net::UnixListener::local_addr`]: https://docs.rs/async-std/latest/async_std/os/unix/net/struct.UnixListener.html#method.local_addr #[inline] pub fn local_addr(&self) -> io::Result { self.std.local_addr() } // async_std doesn't have `set_nonblocking`. // async_std doesn't have `take_error`. /// Returns an iterator over incoming connections. /// /// This corresponds to /// [`async_std::os::unix::net::UnixListener::incoming`]. /// /// [`async_std::os::unix::net::UnixListener::incoming`]: https://docs.rs/async-std/latest/async_std/os/unix/net/struct.UnixListener.html#method.incoming #[inline] pub fn incoming(&self) -> Incoming { let incoming = self.std.incoming(); Incoming::from_std(incoming) } } impl FromRawFd for UnixListener { #[inline] unsafe fn from_raw_fd(fd: RawFd) -> Self { Self::from_std(unix::net::UnixListener::from_raw_fd(fd)) } } impl From for UnixListener { #[inline] fn from(fd: OwnedFd) -> Self { Self::from_std(unix::net::UnixListener::from(fd)) } } impl AsRawFd for UnixListener { #[inline] fn as_raw_fd(&self) -> RawFd { self.std.as_raw_fd() } } impl AsFd for UnixListener { #[inline] fn as_fd(&self) -> BorrowedFd<'_> { self.std.as_fd() } } impl IntoRawFd for UnixListener { #[inline] fn into_raw_fd(self) -> RawFd { self.std.into_raw_fd() } } impl From for OwnedFd { #[inline] fn from(listener: UnixListener) -> OwnedFd { listener.std.into() } } // async_std's `IntoStream` is unstable. impl fmt::Debug for UnixListener { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.std.fmt(f) } } cap-async-std-3.4.1/src/os/unix/net/unix_stream.rs000064400000000000000000000162521046102023000201720ustar 00000000000000use crate::net::Shutdown; use crate::os::unix::net::SocketAddr; use async_std::io::{self, IoSlice, IoSliceMut, Read, Write}; use async_std::os::unix; use async_std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd}; use async_std::task::{Context, Poll}; use io_lifetimes::{AsFd, BorrowedFd, OwnedFd}; use std::fmt; use std::pin::Pin; /// A Unix stream socket. /// /// This corresponds to [`async_std::os::unix::net::UnixStream`]. /// /// This `UnixStream` has no `connect` method. To create a `UnixStream`, first /// obtain a [`Dir`] containing the path, and then call /// [`Dir::connect_unix_stream`]. /// /// [`async_std::os::unix::net::UnixStream`]: https://docs.rs/async-std/latest/async_std/os/unix/net/struct.UnixStream.html /// [`Dir`]: struct.Dir.html /// [`Dir::connect_unix_stream`]: struct.Dir.html#method.connect_unix_stream #[derive(Clone)] pub struct UnixStream { std: unix::net::UnixStream, } impl UnixStream { /// Constructs a new instance of `Self` from the given /// `async_std::os::unix::net::UnixStream`. /// /// This grants access the resources the /// `async_std::os::unix::net::UnixStream` instance already has access /// to. #[inline] pub fn from_std(std: unix::net::UnixStream) -> Self { Self { std } } /// Creates an unnamed pair of connected sockets. /// /// This corresponds to [`async_std::os::unix::net::UnixStream::pair`]. /// /// TODO: should this require a capability? /// /// [`async_std::os::unix::net::UnixStream::pair`]: https://docs.rs/async-std/latest/async_std/os/unix/net/struct.UnixStream.html#method.pair #[inline] pub fn pair() -> io::Result<(Self, Self)> { unix::net::UnixStream::pair().map(|(a, b)| (Self::from_std(a), Self::from_std(b))) } // async_std doesn't have `try_clone`. /// Returns the socket address of the local half of this connection. /// /// This corresponds to /// [`async_std::os::unix::net::UnixStream::local_addr`]. /// /// [`async_std::os::unix::net::UnixStream::local_addr`]: https://docs.rs/async-std/latest/async_std/os/unix/net/struct.UnixStream.html#method.local_addr #[inline] pub fn local_addr(&self) -> io::Result { self.std.local_addr() } /// Returns the socket address of the remote half of this connection. /// /// This corresponds to /// [`async_std::os::unix::net::UnixStream::peer_addr`]. /// /// [`async_std::os::unix::net::UnixStream::peer_addr`]: https://docs.rs/async-std/latest/async_std/os/unix/net/struct.UnixStream.html#method.peer_addr #[inline] pub fn peer_addr(&self) -> io::Result { self.std.peer_addr() } // async_std doesn't have `set_read_timeout`. // async_std doesn't have `set_write_timeout`. // async_std doesn't have `read_timeout`. // async_std doesn't have `write_timeout`. // async_std doesn't have `set_nonblocking`. // async_std doesn't have `take_error`. /// Shuts down the read, write, or both halves of this connection. /// /// This corresponds to [`async_std::os::unix::net::UnixStream::shutdown`]. /// /// [`async_std::os::unix::net::UnixStream::shutdown`]: https://docs.rs/async-std/latest/async_std/os/unix/net/struct.UnixStream.html#method.shutdown #[inline] pub fn shutdown(&self, how: Shutdown) -> io::Result<()> { self.std.shutdown(how) } } impl FromRawFd for UnixStream { #[inline] unsafe fn from_raw_fd(fd: RawFd) -> Self { Self::from_std(unix::net::UnixStream::from_raw_fd(fd)) } } impl From for UnixStream { #[inline] fn from(fd: OwnedFd) -> Self { Self::from_std(unix::net::UnixStream::from(fd)) } } impl AsRawFd for UnixStream { #[inline] fn as_raw_fd(&self) -> RawFd { self.std.as_raw_fd() } } impl AsFd for UnixStream { #[inline] fn as_fd(&self) -> BorrowedFd<'_> { self.std.as_fd() } } impl IntoRawFd for UnixStream { #[inline] fn into_raw_fd(self) -> RawFd { self.std.into_raw_fd() } } impl From for OwnedFd { #[inline] fn from(stream: UnixStream) -> OwnedFd { stream.std.into() } } impl Read for UnixStream { #[inline] fn poll_read( mut self: Pin<&mut Self>, cx: &mut Context, buf: &mut [u8], ) -> Poll> { Read::poll_read(Pin::new(&mut self.std), cx, buf) } #[inline] fn poll_read_vectored( mut self: Pin<&mut Self>, cx: &mut Context, bufs: &mut [IoSliceMut], ) -> Poll> { Read::poll_read_vectored(Pin::new(&mut self.std), cx, bufs) } // async_std doesn't have `is_read_vectored`. // async_std doesn't have `initializer`. } impl Read for &UnixStream { #[inline] fn poll_read( self: Pin<&mut Self>, cx: &mut Context, buf: &mut [u8], ) -> Poll> { Read::poll_read(Pin::new(&mut &self.std), cx, buf) } #[inline] fn poll_read_vectored( self: Pin<&mut Self>, cx: &mut Context, bufs: &mut [IoSliceMut], ) -> Poll> { Read::poll_read_vectored(Pin::new(&mut &self.std), cx, bufs) } // async_std doesn't have `is_read_vectored`. // async_std doesn't have `initializer`. } impl Write for UnixStream { #[inline] fn poll_write( mut self: Pin<&mut Self>, cx: &mut Context, buf: &[u8], ) -> Poll> { Write::poll_write(Pin::new(&mut self.std), cx, buf) } #[inline] fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll> { Write::poll_flush(Pin::new(&mut self.std), cx) } #[inline] fn poll_close(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll> { Write::poll_close(Pin::new(&mut self.std), cx) } #[inline] fn poll_write_vectored( mut self: Pin<&mut Self>, cx: &mut Context, bufs: &[IoSlice], ) -> Poll> { Write::poll_write_vectored(Pin::new(&mut self.std), cx, bufs) } // async_std doesn't have `is_write_vectored`. // async_std doesn't have `write_all_vectored`. } impl Write for &UnixStream { #[inline] fn poll_write(self: Pin<&mut Self>, cx: &mut Context, buf: &[u8]) -> Poll> { Write::poll_write(Pin::new(&mut &self.std), cx, buf) } #[inline] fn poll_flush(self: Pin<&mut Self>, cx: &mut Context) -> Poll> { Write::poll_flush(Pin::new(&mut &self.std), cx) } #[inline] fn poll_close(self: Pin<&mut Self>, cx: &mut Context) -> Poll> { Write::poll_close(Pin::new(&mut &self.std), cx) } #[inline] fn poll_write_vectored( self: Pin<&mut Self>, cx: &mut Context, bufs: &[IoSlice], ) -> Poll> { Write::poll_write_vectored(Pin::new(&mut &self.std), cx, bufs) } // async_std doesn't have `is_write_vectored`. // async_std doesn't have `write_all_vectored`. } impl fmt::Debug for UnixStream { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.std.fmt(f) } } cap-async-std-3.4.1/src/time/mod.rs000064400000000000000000000005561046102023000151570ustar 00000000000000//! A capability-based clock API modeled after [`std::time`]. //! //! This corresponds to [`std::time`]. //! //! Instead of [`std::time`]'s methods which return the current time, this //! crate has methods on [`SystemClock`] and [`MonotonicClock`]. pub use cap_primitives::time::{ Duration, Instant, MonotonicClock, SystemClock, SystemTime, SystemTimeError, };