зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1773399 - Update tempfile to 3.3.0 and parking_lot to 0.11.2. r=emilio
Differential Revision: https://phabricator.services.mozilla.com/D148736
This commit is contained in:
Родитель
604213514b
Коммит
2aee1dac71
|
@ -1634,6 +1634,15 @@ dependencies = [
|
|||
"hashbrown",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fastrand"
|
||||
version = "1.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c3fcf0cee53519c866c09b5de1f6c56ff9d647101f81c1964fa632e148896cdf"
|
||||
dependencies = [
|
||||
"instant",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ffi-support"
|
||||
version = "0.4.4"
|
||||
|
@ -3954,9 +3963,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "parking_lot"
|
||||
version = "0.11.1"
|
||||
version = "0.11.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6d7744ac029df22dca6284efe4e898991d28e3085c706c972bcd7da4a27a15eb"
|
||||
checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99"
|
||||
dependencies = [
|
||||
"instant",
|
||||
"lock_api",
|
||||
|
@ -3967,14 +3976,14 @@ dependencies = [
|
|||
name = "parking_lot"
|
||||
version = "0.12.999"
|
||||
dependencies = [
|
||||
"parking_lot 0.11.1",
|
||||
"parking_lot 0.11.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot_core"
|
||||
version = "0.8.1"
|
||||
version = "0.8.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d7c6d9b8427445284a09c55be860a15855ab580a417ccad9da88f5a06787ced0"
|
||||
checksum = "d76e8e1493bcac0d2766c42737f34458f1c8c50c0d23bcb24ea953affb273216"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"instant",
|
||||
|
@ -4404,9 +4413,12 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.1.57"
|
||||
version = "0.2.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce"
|
||||
checksum = "62f25bc4c7e55e0b0b7a1d43fb893f4fa1361d0abe38b9ce4f323c2adfe6ef42"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_users"
|
||||
|
@ -4805,7 +4817,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "e0bccbcf40c8938196944a3da0e133e031a33f4d6b72db3bda3cc556e361905d"
|
||||
dependencies = [
|
||||
"lazy_static",
|
||||
"parking_lot 0.11.1",
|
||||
"parking_lot 0.11.2",
|
||||
"serial_test_derive",
|
||||
]
|
||||
|
||||
|
@ -5020,7 +5032,7 @@ dependencies = [
|
|||
"num-traits",
|
||||
"num_cpus",
|
||||
"owning_ref",
|
||||
"parking_lot 0.11.1",
|
||||
"parking_lot 0.11.2",
|
||||
"precomputed-hash",
|
||||
"rayon",
|
||||
"regex",
|
||||
|
@ -5160,13 +5172,13 @@ checksum = "c02424087780c9b71cc96799eaeddff35af2bc513278cda5c99fc1f5d026d3c1"
|
|||
|
||||
[[package]]
|
||||
name = "tempfile"
|
||||
version = "3.1.0"
|
||||
version = "3.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9"
|
||||
checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4"
|
||||
dependencies = [
|
||||
"cfg-if 0.1.999",
|
||||
"cfg-if 1.0.0",
|
||||
"fastrand",
|
||||
"libc",
|
||||
"rand 0.7.999",
|
||||
"redox_syscall",
|
||||
"remove_dir_all",
|
||||
"winapi",
|
||||
|
@ -6128,7 +6140,7 @@ version = "0.1.0"
|
|||
dependencies = [
|
||||
"bincode",
|
||||
"log",
|
||||
"parking_lot 0.11.1",
|
||||
"parking_lot 0.11.2",
|
||||
"serde",
|
||||
"wgpu-core",
|
||||
"wgpu-hal",
|
||||
|
|
|
@ -513,6 +513,10 @@ criteria = "safe-to-deploy"
|
|||
version = "0.4.4"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[unaudited.fastrand]]
|
||||
version = "1.7.0"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[unaudited.ffi-support]]
|
||||
version = "0.4.4"
|
||||
criteria = "safe-to-deploy"
|
||||
|
@ -1030,11 +1034,11 @@ version = "0.4.1"
|
|||
criteria = "safe-to-deploy"
|
||||
|
||||
[[unaudited.parking_lot]]
|
||||
version = "0.11.1"
|
||||
version = "0.11.2"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[unaudited.parking_lot_core]]
|
||||
version = "0.8.1"
|
||||
version = "0.8.5"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[unaudited.paste]]
|
||||
|
@ -1186,7 +1190,7 @@ version = "1.9.3"
|
|||
criteria = "safe-to-deploy"
|
||||
|
||||
[[unaudited.redox_syscall]]
|
||||
version = "0.1.57"
|
||||
version = "0.2.13"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[unaudited.regalloc]]
|
||||
|
@ -1410,7 +1414,7 @@ version = "0.12.4"
|
|||
criteria = "safe-to-deploy"
|
||||
|
||||
[[unaudited.tempfile]]
|
||||
version = "3.1.0"
|
||||
version = "3.3.0"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[unaudited.termcolor]]
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
{"files":{"CHANGELOG.md":"64b93943521b0ee7266f0d95d7ebdd0b8d1ff0bb4bebda9e445ec55dc641b232","Cargo.toml":"d4c2645fe37d1d484b8aa9cd64beb37e9c8a763f5b9e6c5ed775e6400745c7f8","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3","README.md":"dec6b96d3549746937d7e0e62e35e206e6f5b7e2d1886451281905f4edf096d4","benches/bench.rs":"8a8a38a032c4b0442aeccfeb5444e6824ad5e50143c9feec88803d6558312232","src/lib.rs":"6daab127f3f55166041c5a6f80384899597696e5bf12f80b87a0f3abaf1cf873","tests/char.rs":"a530b41837f5bf43701d983ef0267d9b44779d455f24cbf30b881cd348de9ee1","tests/smoke.rs":"10631fa1facee3243e12a8fc56856f2bddfc7090be17b3364edbbac9973692d9"},"package":"c3fcf0cee53519c866c09b5de1f6c56ff9d647101f81c1964fa632e148896cdf"}
|
|
@ -0,0 +1,77 @@
|
|||
# Version 1.7.0
|
||||
|
||||
- Add `char()` and `Rng::char()` (#25)
|
||||
|
||||
# Version 1.6.0
|
||||
|
||||
- Implement `PartialEq` and `Eq` for `Rng` (#23)
|
||||
|
||||
# Version 1.5.0
|
||||
|
||||
- Switch to Wyrand (#14)
|
||||
|
||||
# Version 1.4.1
|
||||
|
||||
- Fix bug when generating a signed integer within a range (#16)
|
||||
|
||||
# Version 1.4.0
|
||||
|
||||
- Add wasm support.
|
||||
|
||||
# Version 1.3.5
|
||||
|
||||
- Reword docs.
|
||||
- Add `Rng::with_seed()`.
|
||||
|
||||
# Version 1.3.4
|
||||
|
||||
- Implement `Clone` for `Rng`.
|
||||
|
||||
# Version 1.3.3
|
||||
|
||||
- Forbid unsafe code.
|
||||
|
||||
# Version 1.3.2
|
||||
|
||||
- Support older Rust versions.
|
||||
|
||||
# Version 1.3.1
|
||||
|
||||
- Tweak Cargo keywords.
|
||||
|
||||
# Version 1.3.0
|
||||
|
||||
- Add `f32()` and `f64()`.
|
||||
- Add `lowercase()`, `uppercase()`, `alphabetic()`, and `digit()`.
|
||||
|
||||
# Version 1.2.4
|
||||
|
||||
- Switch to PCG XSH RR 64/32.
|
||||
- Fix a bug in `gen_mod_u128`.
|
||||
- Fix bias in ranges.
|
||||
|
||||
# Version 1.2.3
|
||||
|
||||
- Support Rust 1.32.0
|
||||
|
||||
# Version 1.2.2
|
||||
|
||||
- Use `std::$t::MAX` rather than `$t::MAX` to support older Rust versions.
|
||||
|
||||
# Version 1.2.1
|
||||
|
||||
- Inline all functions.
|
||||
|
||||
# Version 1.2.0
|
||||
|
||||
- Add `Rng` struct.
|
||||
|
||||
# Version 1.1.0
|
||||
|
||||
- Switch to PCG implementation.
|
||||
- Add `alphanumeric()`.
|
||||
- Add `seed()`.
|
||||
|
||||
# Version 1.0.0
|
||||
|
||||
- Initial version
|
|
@ -0,0 +1,43 @@
|
|||
# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
|
||||
#
|
||||
# When uploading crates to the registry Cargo will automatically
|
||||
# "normalize" Cargo.toml files for maximal compatibility
|
||||
# with all versions of Cargo and also rewrite `path` dependencies
|
||||
# to registry (e.g., crates.io) dependencies.
|
||||
#
|
||||
# If you are reading this file be aware that the original Cargo.toml
|
||||
# will likely look very different (and much more reasonable).
|
||||
# See Cargo.toml.orig for the original contents.
|
||||
|
||||
[package]
|
||||
edition = "2018"
|
||||
rust-version = "1.34"
|
||||
name = "fastrand"
|
||||
version = "1.7.0"
|
||||
authors = ["Stjepan Glavina <stjepang@gmail.com>"]
|
||||
exclude = ["/.*"]
|
||||
description = "A simple and fast random number generator"
|
||||
keywords = ["simple", "fast", "rand", "random", "wyrand"]
|
||||
categories = ["algorithms"]
|
||||
license = "Apache-2.0 OR MIT"
|
||||
repository = "https://github.com/smol-rs/fastrand"
|
||||
[dev-dependencies.getrandom]
|
||||
version = "0.2"
|
||||
|
||||
[dev-dependencies.rand]
|
||||
version = "0.8"
|
||||
|
||||
[dev-dependencies.wyhash]
|
||||
version = "0.5"
|
||||
[target."cfg(target_arch = \"wasm32\")".dependencies.instant]
|
||||
version = "0.1"
|
||||
[target."cfg(target_arch = \"wasm32\")".dev-dependencies.getrandom]
|
||||
version = "0.2"
|
||||
features = ["js"]
|
||||
|
||||
[target."cfg(target_arch = \"wasm32\")".dev-dependencies.instant]
|
||||
version = "0.1"
|
||||
features = ["wasm-bindgen"]
|
||||
|
||||
[target."cfg(target_arch = \"wasm32\")".dev-dependencies.wasm-bindgen-test]
|
||||
version = "0.3"
|
|
@ -0,0 +1,201 @@
|
|||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
|
@ -0,0 +1,23 @@
|
|||
Permission is hereby granted, free of charge, to any
|
||||
person obtaining a copy of this software and associated
|
||||
documentation files (the "Software"), to deal in the
|
||||
Software without restriction, including without
|
||||
limitation the rights to use, copy, modify, merge,
|
||||
publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software
|
||||
is furnished to do so, subject to the following
|
||||
conditions:
|
||||
|
||||
The above copyright notice and this permission notice
|
||||
shall be included in all copies or substantial portions
|
||||
of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
|
||||
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
|
||||
TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
|
||||
SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
|
||||
IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
|
@ -0,0 +1,92 @@
|
|||
# fastrand
|
||||
|
||||
[![Build](https://github.com/smol-rs/fastrand/workflows/Build%20and%20test/badge.svg)](
|
||||
https://github.com/smol-rs/fastrand/actions)
|
||||
[![License](https://img.shields.io/badge/license-Apache--2.0_OR_MIT-blue.svg)](
|
||||
https://github.com/smol-rs/fastrand)
|
||||
[![Cargo](https://img.shields.io/crates/v/fastrand.svg)](
|
||||
https://crates.io/crates/fastrand)
|
||||
[![Documentation](https://docs.rs/fastrand/badge.svg)](
|
||||
https://docs.rs/fastrand)
|
||||
|
||||
A simple and fast random number generator.
|
||||
|
||||
The implementation uses [Wyrand](https://github.com/wangyi-fudan/wyhash), a simple and fast
|
||||
generator but **not** cryptographically secure.
|
||||
|
||||
## Examples
|
||||
|
||||
Flip a coin:
|
||||
|
||||
```rust
|
||||
if fastrand::bool() {
|
||||
println!("heads");
|
||||
} else {
|
||||
println!("tails");
|
||||
}
|
||||
```
|
||||
|
||||
Generate a random `i32`:
|
||||
|
||||
```rust
|
||||
let num = fastrand::i32(..);
|
||||
```
|
||||
|
||||
Choose a random element in an array:
|
||||
|
||||
```rust
|
||||
let v = vec![1, 2, 3, 4, 5];
|
||||
let i = fastrand::usize(..v.len());
|
||||
let elem = v[i];
|
||||
```
|
||||
|
||||
Shuffle an array:
|
||||
|
||||
```rust
|
||||
let mut v = vec![1, 2, 3, 4, 5];
|
||||
fastrand::shuffle(&mut v);
|
||||
```
|
||||
|
||||
Generate a random `Vec` or `String`:
|
||||
|
||||
```rust
|
||||
use std::iter::repeat_with;
|
||||
|
||||
let v: Vec<i32> = repeat_with(|| fastrand::i32(..)).take(10).collect();
|
||||
let s: String = repeat_with(fastrand::alphanumeric).take(10).collect();
|
||||
```
|
||||
|
||||
To get reproducible results on every run, initialize the generator with a seed:
|
||||
|
||||
```rust
|
||||
// Pick an arbitrary number as seed.
|
||||
fastrand::seed(7);
|
||||
|
||||
// Now this prints the same number on every run:
|
||||
println!("{}", fastrand::u32(..));
|
||||
```
|
||||
|
||||
To be more efficient, create a new `Rng` instance instead of using the thread-local
|
||||
generator:
|
||||
|
||||
```rust
|
||||
use std::iter::repeat_with;
|
||||
|
||||
let rng = fastrand::Rng::new();
|
||||
let mut bytes: Vec<u8> = repeat_with(|| rng.u8(..)).take(10_000).collect();
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
Licensed under either of
|
||||
|
||||
* Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0)
|
||||
* MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)
|
||||
|
||||
at your option.
|
||||
|
||||
#### Contribution
|
||||
|
||||
Unless you explicitly state otherwise, any contribution intentionally submitted
|
||||
for inclusion in the work by you, as defined in the Apache-2.0 license, shall be
|
||||
dual licensed as above, without any additional terms or conditions.
|
|
@ -0,0 +1,75 @@
|
|||
#![feature(test)]
|
||||
|
||||
extern crate test;
|
||||
|
||||
use rand::prelude::*;
|
||||
use test::Bencher;
|
||||
use wyhash::WyRng;
|
||||
|
||||
#[bench]
|
||||
fn shuffle_wyhash(b: &mut Bencher) {
|
||||
let mut rng = WyRng::from_rng(thread_rng()).unwrap();
|
||||
let mut x = (0..100).collect::<Vec<usize>>();
|
||||
b.iter(|| {
|
||||
x.shuffle(&mut rng);
|
||||
x[0]
|
||||
})
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn shuffle_fastrand(b: &mut Bencher) {
|
||||
let rng = fastrand::Rng::new();
|
||||
let mut x = (0..100).collect::<Vec<usize>>();
|
||||
b.iter(|| {
|
||||
rng.shuffle(&mut x);
|
||||
x[0]
|
||||
})
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn u8_wyhash(b: &mut Bencher) {
|
||||
let mut rng = WyRng::from_rng(thread_rng()).unwrap();
|
||||
b.iter(|| {
|
||||
let mut sum = 0u8;
|
||||
for _ in 0..10_000 {
|
||||
sum = sum.wrapping_add(rng.gen::<u8>());
|
||||
}
|
||||
sum
|
||||
})
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn u8_fastrand(b: &mut Bencher) {
|
||||
let rng = fastrand::Rng::new();
|
||||
b.iter(|| {
|
||||
let mut sum = 0u8;
|
||||
for _ in 0..10_000 {
|
||||
sum = sum.wrapping_add(rng.u8(..));
|
||||
}
|
||||
sum
|
||||
})
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn u32_wyhash(b: &mut Bencher) {
|
||||
let mut rng = WyRng::from_rng(thread_rng()).unwrap();
|
||||
b.iter(|| {
|
||||
let mut sum = 0u32;
|
||||
for _ in 0..10_000 {
|
||||
sum = sum.wrapping_add(rng.gen::<u32>());
|
||||
}
|
||||
sum
|
||||
})
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn u32_fastrand(b: &mut Bencher) {
|
||||
let rng = fastrand::Rng::new();
|
||||
b.iter(|| {
|
||||
let mut sum = 0u32;
|
||||
for _ in 0..10_000 {
|
||||
sum = sum.wrapping_add(rng.u32(..));
|
||||
}
|
||||
sum
|
||||
})
|
||||
}
|
|
@ -0,0 +1,668 @@
|
|||
//! A simple and fast random number generator.
|
||||
//!
|
||||
//! The implementation uses [Wyrand](https://github.com/wangyi-fudan/wyhash), a simple and fast
|
||||
//! generator but **not** cryptographically secure.
|
||||
//!
|
||||
//! # Examples
|
||||
//!
|
||||
//! Flip a coin:
|
||||
//!
|
||||
//! ```
|
||||
//! if fastrand::bool() {
|
||||
//! println!("heads");
|
||||
//! } else {
|
||||
//! println!("tails");
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! Generate a random `i32`:
|
||||
//!
|
||||
//! ```
|
||||
//! let num = fastrand::i32(..);
|
||||
//! ```
|
||||
//!
|
||||
//! Choose a random element in an array:
|
||||
//!
|
||||
//! ```
|
||||
//! let v = vec![1, 2, 3, 4, 5];
|
||||
//! let i = fastrand::usize(..v.len());
|
||||
//! let elem = v[i];
|
||||
//! ```
|
||||
//!
|
||||
//! Shuffle an array:
|
||||
//!
|
||||
//! ```
|
||||
//! let mut v = vec![1, 2, 3, 4, 5];
|
||||
//! fastrand::shuffle(&mut v);
|
||||
//! ```
|
||||
//!
|
||||
//! Generate a random [`Vec`] or [`String`]:
|
||||
//!
|
||||
//! ```
|
||||
//! use std::iter::repeat_with;
|
||||
//!
|
||||
//! let v: Vec<i32> = repeat_with(|| fastrand::i32(..)).take(10).collect();
|
||||
//! let s: String = repeat_with(fastrand::alphanumeric).take(10).collect();
|
||||
//! ```
|
||||
//!
|
||||
//! To get reproducible results on every run, initialize the generator with a seed:
|
||||
//!
|
||||
//! ```
|
||||
//! // Pick an arbitrary number as seed.
|
||||
//! fastrand::seed(7);
|
||||
//!
|
||||
//! // Now this prints the same number on every run:
|
||||
//! println!("{}", fastrand::u32(..));
|
||||
//! ```
|
||||
//!
|
||||
//! To be more efficient, create a new [`Rng`] instance instead of using the thread-local
|
||||
//! generator:
|
||||
//!
|
||||
//! ```
|
||||
//! use std::iter::repeat_with;
|
||||
//!
|
||||
//! let rng = fastrand::Rng::new();
|
||||
//! let mut bytes: Vec<u8> = repeat_with(|| rng.u8(..)).take(10_000).collect();
|
||||
//! ```
|
||||
|
||||
#![forbid(unsafe_code)]
|
||||
#![warn(missing_docs, missing_debug_implementations, rust_2018_idioms)]
|
||||
|
||||
use std::cell::Cell;
|
||||
use std::collections::hash_map::DefaultHasher;
|
||||
use std::hash::{Hash, Hasher};
|
||||
use std::ops::{Bound, RangeBounds};
|
||||
use std::thread;
|
||||
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
use instant::Instant;
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
use std::time::Instant;
|
||||
|
||||
/// A random number generator.
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub struct Rng(Cell<u64>);
|
||||
|
||||
impl Default for Rng {
|
||||
#[inline]
|
||||
fn default() -> Rng {
|
||||
Rng::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl Clone for Rng {
|
||||
/// Clones the generator by deterministically deriving a new generator based on the initial
|
||||
/// seed.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// // Seed two generators equally, and clone both of them.
|
||||
/// let base1 = fastrand::Rng::new();
|
||||
/// base1.seed(0x4d595df4d0f33173);
|
||||
/// base1.bool(); // Use the generator once.
|
||||
///
|
||||
/// let base2 = fastrand::Rng::new();
|
||||
/// base2.seed(0x4d595df4d0f33173);
|
||||
/// base2.bool(); // Use the generator once.
|
||||
///
|
||||
/// let rng1 = base1.clone();
|
||||
/// let rng2 = base2.clone();
|
||||
///
|
||||
/// assert_eq!(rng1.u64(..), rng2.u64(..), "the cloned generators are identical");
|
||||
/// ```
|
||||
fn clone(&self) -> Rng {
|
||||
Rng::with_seed(self.gen_u64())
|
||||
}
|
||||
}
|
||||
|
||||
impl Rng {
|
||||
/// Generates a random `u32`.
|
||||
#[inline]
|
||||
fn gen_u32(&self) -> u32 {
|
||||
self.gen_u64() as u32
|
||||
}
|
||||
|
||||
/// Generates a random `u64`.
|
||||
#[inline]
|
||||
fn gen_u64(&self) -> u64 {
|
||||
let s = self.0.get().wrapping_add(0xA0761D6478BD642F);
|
||||
self.0.set(s);
|
||||
let t = u128::from(s) * u128::from(s ^ 0xE7037ED1A0B428DB);
|
||||
(t as u64) ^ (t >> 64) as u64
|
||||
}
|
||||
|
||||
/// Generates a random `u128`.
|
||||
#[inline]
|
||||
fn gen_u128(&self) -> u128 {
|
||||
(u128::from(self.gen_u64()) << 64) | u128::from(self.gen_u64())
|
||||
}
|
||||
|
||||
/// Generates a random `u32` in `0..n`.
|
||||
#[inline]
|
||||
fn gen_mod_u32(&self, n: u32) -> u32 {
|
||||
// Adapted from: https://lemire.me/blog/2016/06/30/fast-random-shuffling/
|
||||
let mut r = self.gen_u32();
|
||||
let mut hi = mul_high_u32(r, n);
|
||||
let mut lo = r.wrapping_mul(n);
|
||||
if lo < n {
|
||||
let t = n.wrapping_neg() % n;
|
||||
while lo < t {
|
||||
r = self.gen_u32();
|
||||
hi = mul_high_u32(r, n);
|
||||
lo = r.wrapping_mul(n);
|
||||
}
|
||||
}
|
||||
hi
|
||||
}
|
||||
|
||||
/// Generates a random `u64` in `0..n`.
|
||||
#[inline]
|
||||
fn gen_mod_u64(&self, n: u64) -> u64 {
|
||||
// Adapted from: https://lemire.me/blog/2016/06/30/fast-random-shuffling/
|
||||
let mut r = self.gen_u64();
|
||||
let mut hi = mul_high_u64(r, n);
|
||||
let mut lo = r.wrapping_mul(n);
|
||||
if lo < n {
|
||||
let t = n.wrapping_neg() % n;
|
||||
while lo < t {
|
||||
r = self.gen_u64();
|
||||
hi = mul_high_u64(r, n);
|
||||
lo = r.wrapping_mul(n);
|
||||
}
|
||||
}
|
||||
hi
|
||||
}
|
||||
|
||||
/// Generates a random `u128` in `0..n`.
|
||||
#[inline]
|
||||
fn gen_mod_u128(&self, n: u128) -> u128 {
|
||||
// Adapted from: https://lemire.me/blog/2016/06/30/fast-random-shuffling/
|
||||
let mut r = self.gen_u128();
|
||||
let mut hi = mul_high_u128(r, n);
|
||||
let mut lo = r.wrapping_mul(n);
|
||||
if lo < n {
|
||||
let t = n.wrapping_neg() % n;
|
||||
while lo < t {
|
||||
r = self.gen_u128();
|
||||
hi = mul_high_u128(r, n);
|
||||
lo = r.wrapping_mul(n);
|
||||
}
|
||||
}
|
||||
hi
|
||||
}
|
||||
}
|
||||
|
||||
thread_local! {
|
||||
static RNG: Rng = Rng(Cell::new({
|
||||
let mut hasher = DefaultHasher::new();
|
||||
Instant::now().hash(&mut hasher);
|
||||
thread::current().id().hash(&mut hasher);
|
||||
let hash = hasher.finish();
|
||||
(hash << 1) | 1
|
||||
}));
|
||||
}
|
||||
|
||||
/// Computes `(a * b) >> 32`.
|
||||
#[inline]
|
||||
fn mul_high_u32(a: u32, b: u32) -> u32 {
|
||||
(((a as u64) * (b as u64)) >> 32) as u32
|
||||
}
|
||||
|
||||
/// Computes `(a * b) >> 64`.
|
||||
#[inline]
|
||||
fn mul_high_u64(a: u64, b: u64) -> u64 {
|
||||
(((a as u128) * (b as u128)) >> 64) as u64
|
||||
}
|
||||
|
||||
/// Computes `(a * b) >> 128`.
|
||||
#[inline]
|
||||
fn mul_high_u128(a: u128, b: u128) -> u128 {
|
||||
// Adapted from: https://stackoverflow.com/a/28904636
|
||||
let a_lo = a as u64 as u128;
|
||||
let a_hi = (a >> 64) as u64 as u128;
|
||||
let b_lo = b as u64 as u128;
|
||||
let b_hi = (b >> 64) as u64 as u128;
|
||||
let carry = (a_lo * b_lo) >> 64;
|
||||
let carry = ((a_hi * b_lo) as u64 as u128 + (a_lo * b_hi) as u64 as u128 + carry) >> 64;
|
||||
a_hi * b_hi + ((a_hi * b_lo) >> 64) + ((a_lo * b_hi) >> 64) + carry
|
||||
}
|
||||
|
||||
macro_rules! rng_integer {
|
||||
($t:tt, $unsigned_t:tt, $gen:tt, $mod:tt, $doc:tt) => {
|
||||
#[doc = $doc]
|
||||
///
|
||||
/// Panics if the range is empty.
|
||||
#[inline]
|
||||
pub fn $t(&self, range: impl RangeBounds<$t>) -> $t {
|
||||
let panic_empty_range = || {
|
||||
panic!(
|
||||
"empty range: {:?}..{:?}",
|
||||
range.start_bound(),
|
||||
range.end_bound()
|
||||
)
|
||||
};
|
||||
|
||||
let low = match range.start_bound() {
|
||||
Bound::Unbounded => std::$t::MIN,
|
||||
Bound::Included(&x) => x,
|
||||
Bound::Excluded(&x) => x.checked_add(1).unwrap_or_else(panic_empty_range),
|
||||
};
|
||||
|
||||
let high = match range.end_bound() {
|
||||
Bound::Unbounded => std::$t::MAX,
|
||||
Bound::Included(&x) => x,
|
||||
Bound::Excluded(&x) => x.checked_sub(1).unwrap_or_else(panic_empty_range),
|
||||
};
|
||||
|
||||
if low > high {
|
||||
panic_empty_range();
|
||||
}
|
||||
|
||||
if low == std::$t::MIN && high == std::$t::MAX {
|
||||
self.$gen() as $t
|
||||
} else {
|
||||
let len = high.wrapping_sub(low).wrapping_add(1);
|
||||
low.wrapping_add(self.$mod(len as $unsigned_t as _) as $t)
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
impl Rng {
|
||||
/// Creates a new random number generator.
|
||||
#[inline]
|
||||
pub fn new() -> Rng {
|
||||
Rng::with_seed(
|
||||
RNG.try_with(|rng| rng.u64(..))
|
||||
.unwrap_or(0x4d595df4d0f33173),
|
||||
)
|
||||
}
|
||||
|
||||
/// Creates a new random number generator with the initial seed.
|
||||
#[inline]
|
||||
pub fn with_seed(seed: u64) -> Self {
|
||||
let rng = Rng(Cell::new(0));
|
||||
|
||||
rng.seed(seed);
|
||||
rng
|
||||
}
|
||||
|
||||
/// Generates a random `char` in ranges a-z and A-Z.
|
||||
#[inline]
|
||||
pub fn alphabetic(&self) -> char {
|
||||
const CHARS: &[u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
|
||||
let len = CHARS.len() as u8;
|
||||
let i = self.u8(..len);
|
||||
CHARS[i as usize] as char
|
||||
}
|
||||
|
||||
/// Generates a random `char` in ranges a-z, A-Z and 0-9.
|
||||
#[inline]
|
||||
pub fn alphanumeric(&self) -> char {
|
||||
const CHARS: &[u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
|
||||
let len = CHARS.len() as u8;
|
||||
let i = self.u8(..len);
|
||||
CHARS[i as usize] as char
|
||||
}
|
||||
|
||||
/// Generates a random `bool`.
|
||||
#[inline]
|
||||
pub fn bool(&self) -> bool {
|
||||
self.u8(..) % 2 == 0
|
||||
}
|
||||
|
||||
/// Generates a random digit in the given `base`.
|
||||
///
|
||||
/// Digits are represented by `char`s in ranges 0-9 and a-z.
|
||||
///
|
||||
/// Panics if the base is zero or greater than 36.
|
||||
#[inline]
|
||||
pub fn digit(&self, base: u32) -> char {
|
||||
if base == 0 {
|
||||
panic!("base cannot be zero");
|
||||
}
|
||||
if base > 36 {
|
||||
panic!("base cannot be larger than 36");
|
||||
}
|
||||
let num = self.u8(..base as u8);
|
||||
if num < 10 {
|
||||
(b'0' + num) as char
|
||||
} else {
|
||||
(b'a' + num - 10) as char
|
||||
}
|
||||
}
|
||||
|
||||
/// Generates a random `f32` in range `0..1`.
|
||||
pub fn f32(&self) -> f32 {
|
||||
let b = 32;
|
||||
let f = std::f32::MANTISSA_DIGITS - 1;
|
||||
f32::from_bits((1 << (b - 2)) - (1 << f) + (self.u32(..) >> (b - f))) - 1.0
|
||||
}
|
||||
|
||||
/// Generates a random `f64` in range `0..1`.
|
||||
pub fn f64(&self) -> f64 {
|
||||
let b = 64;
|
||||
let f = std::f64::MANTISSA_DIGITS - 1;
|
||||
f64::from_bits((1 << (b - 2)) - (1 << f) + (self.u64(..) >> (b - f))) - 1.0
|
||||
}
|
||||
|
||||
rng_integer!(
|
||||
i8,
|
||||
u8,
|
||||
gen_u32,
|
||||
gen_mod_u32,
|
||||
"Generates a random `i8` in the given range."
|
||||
);
|
||||
|
||||
rng_integer!(
|
||||
i16,
|
||||
u16,
|
||||
gen_u32,
|
||||
gen_mod_u32,
|
||||
"Generates a random `i16` in the given range."
|
||||
);
|
||||
|
||||
rng_integer!(
|
||||
i32,
|
||||
u32,
|
||||
gen_u32,
|
||||
gen_mod_u32,
|
||||
"Generates a random `i32` in the given range."
|
||||
);
|
||||
|
||||
rng_integer!(
|
||||
i64,
|
||||
u64,
|
||||
gen_u64,
|
||||
gen_mod_u64,
|
||||
"Generates a random `i64` in the given range."
|
||||
);
|
||||
|
||||
rng_integer!(
|
||||
i128,
|
||||
u128,
|
||||
gen_u128,
|
||||
gen_mod_u128,
|
||||
"Generates a random `i128` in the given range."
|
||||
);
|
||||
|
||||
#[cfg(target_pointer_width = "16")]
|
||||
rng_integer!(
|
||||
isize,
|
||||
usize,
|
||||
gen_u32,
|
||||
gen_mod_u32,
|
||||
"Generates a random `isize` in the given range."
|
||||
);
|
||||
#[cfg(target_pointer_width = "32")]
|
||||
rng_integer!(
|
||||
isize,
|
||||
usize,
|
||||
gen_u32,
|
||||
gen_mod_u32,
|
||||
"Generates a random `isize` in the given range."
|
||||
);
|
||||
#[cfg(target_pointer_width = "64")]
|
||||
rng_integer!(
|
||||
isize,
|
||||
usize,
|
||||
gen_u64,
|
||||
gen_mod_u64,
|
||||
"Generates a random `isize` in the given range."
|
||||
);
|
||||
|
||||
/// Generates a random `char` in range a-z.
|
||||
#[inline]
|
||||
pub fn lowercase(&self) -> char {
|
||||
const CHARS: &[u8] = b"abcdefghijklmnopqrstuvwxyz";
|
||||
let len = CHARS.len() as u8;
|
||||
let i = self.u8(..len);
|
||||
CHARS[i as usize] as char
|
||||
}
|
||||
|
||||
/// Initializes this generator with the given seed.
|
||||
#[inline]
|
||||
pub fn seed(&self, seed: u64) {
|
||||
self.0.set(seed);
|
||||
}
|
||||
|
||||
/// Shuffles a slice randomly.
|
||||
#[inline]
|
||||
pub fn shuffle<T>(&self, slice: &mut [T]) {
|
||||
for i in 1..slice.len() {
|
||||
slice.swap(i, self.usize(..=i));
|
||||
}
|
||||
}
|
||||
|
||||
rng_integer!(
|
||||
u8,
|
||||
u8,
|
||||
gen_u32,
|
||||
gen_mod_u32,
|
||||
"Generates a random `u8` in the given range."
|
||||
);
|
||||
|
||||
rng_integer!(
|
||||
u16,
|
||||
u16,
|
||||
gen_u32,
|
||||
gen_mod_u32,
|
||||
"Generates a random `u16` in the given range."
|
||||
);
|
||||
|
||||
rng_integer!(
|
||||
u32,
|
||||
u32,
|
||||
gen_u32,
|
||||
gen_mod_u32,
|
||||
"Generates a random `u32` in the given range."
|
||||
);
|
||||
|
||||
rng_integer!(
|
||||
u64,
|
||||
u64,
|
||||
gen_u64,
|
||||
gen_mod_u64,
|
||||
"Generates a random `u64` in the given range."
|
||||
);
|
||||
|
||||
rng_integer!(
|
||||
u128,
|
||||
u128,
|
||||
gen_u128,
|
||||
gen_mod_u128,
|
||||
"Generates a random `u128` in the given range."
|
||||
);
|
||||
|
||||
#[cfg(target_pointer_width = "16")]
|
||||
rng_integer!(
|
||||
usize,
|
||||
usize,
|
||||
gen_u32,
|
||||
gen_mod_u32,
|
||||
"Generates a random `usize` in the given range."
|
||||
);
|
||||
#[cfg(target_pointer_width = "32")]
|
||||
rng_integer!(
|
||||
usize,
|
||||
usize,
|
||||
gen_u32,
|
||||
gen_mod_u32,
|
||||
"Generates a random `usize` in the given range."
|
||||
);
|
||||
#[cfg(target_pointer_width = "64")]
|
||||
rng_integer!(
|
||||
usize,
|
||||
usize,
|
||||
gen_u64,
|
||||
gen_mod_u64,
|
||||
"Generates a random `usize` in the given range."
|
||||
);
|
||||
#[cfg(target_pointer_width = "128")]
|
||||
rng_integer!(
|
||||
usize,
|
||||
usize,
|
||||
gen_u128,
|
||||
gen_mod_u128,
|
||||
"Generates a random `usize` in the given range."
|
||||
);
|
||||
|
||||
/// Generates a random `char` in range A-Z.
|
||||
#[inline]
|
||||
pub fn uppercase(&self) -> char {
|
||||
const CHARS: &[u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
||||
let len = CHARS.len() as u8;
|
||||
let i = self.u8(..len);
|
||||
CHARS[i as usize] as char
|
||||
}
|
||||
|
||||
/// Generates a random `char` in the given range.
|
||||
///
|
||||
/// Panics if the range is empty.
|
||||
#[inline]
|
||||
pub fn char(&self, range: impl RangeBounds<char>) -> char {
|
||||
use std::convert::{TryFrom, TryInto};
|
||||
|
||||
let panic_empty_range = || {
|
||||
panic!(
|
||||
"empty range: {:?}..{:?}",
|
||||
range.start_bound(),
|
||||
range.end_bound()
|
||||
)
|
||||
};
|
||||
|
||||
let surrogate_start = 0xd800u32;
|
||||
let surrogate_len = 0x800u32;
|
||||
|
||||
let low = match range.start_bound() {
|
||||
Bound::Unbounded => 0u8 as char,
|
||||
Bound::Included(&x) => x,
|
||||
Bound::Excluded(&x) => {
|
||||
let scalar = if x as u32 == surrogate_start - 1 {
|
||||
surrogate_start + surrogate_len
|
||||
} else {
|
||||
x as u32 + 1
|
||||
};
|
||||
char::try_from(scalar).unwrap_or_else(|_| panic_empty_range())
|
||||
}
|
||||
};
|
||||
|
||||
let high = match range.end_bound() {
|
||||
Bound::Unbounded => std::char::MAX,
|
||||
Bound::Included(&x) => x,
|
||||
Bound::Excluded(&x) => {
|
||||
let scalar = if x as u32 == surrogate_start + surrogate_len {
|
||||
surrogate_start - 1
|
||||
} else {
|
||||
(x as u32).wrapping_sub(1)
|
||||
};
|
||||
char::try_from(scalar).unwrap_or_else(|_| panic_empty_range())
|
||||
}
|
||||
};
|
||||
|
||||
if low > high {
|
||||
panic_empty_range();
|
||||
}
|
||||
|
||||
let gap = if (low as u32) < surrogate_start && (high as u32) >= surrogate_start {
|
||||
surrogate_len
|
||||
} else {
|
||||
0
|
||||
};
|
||||
let range = high as u32 - low as u32 - gap;
|
||||
let mut val = self.u32(0..=range) + low as u32;
|
||||
if val >= surrogate_start {
|
||||
val += gap;
|
||||
}
|
||||
val.try_into().unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
/// Initializes the thread-local generator with the given seed.
|
||||
#[inline]
|
||||
pub fn seed(seed: u64) {
|
||||
RNG.with(|rng| rng.seed(seed))
|
||||
}
|
||||
|
||||
/// Generates a random `bool`.
|
||||
#[inline]
|
||||
pub fn bool() -> bool {
|
||||
RNG.with(|rng| rng.bool())
|
||||
}
|
||||
|
||||
/// Generates a random `char` in ranges a-z and A-Z.
|
||||
#[inline]
|
||||
pub fn alphabetic() -> char {
|
||||
RNG.with(|rng| rng.alphabetic())
|
||||
}
|
||||
|
||||
/// Generates a random `char` in ranges a-z, A-Z and 0-9.
|
||||
#[inline]
|
||||
pub fn alphanumeric() -> char {
|
||||
RNG.with(|rng| rng.alphanumeric())
|
||||
}
|
||||
|
||||
/// Generates a random `char` in range a-z.
|
||||
#[inline]
|
||||
pub fn lowercase() -> char {
|
||||
RNG.with(|rng| rng.lowercase())
|
||||
}
|
||||
|
||||
/// Generates a random `char` in range A-Z.
|
||||
#[inline]
|
||||
pub fn uppercase() -> char {
|
||||
RNG.with(|rng| rng.uppercase())
|
||||
}
|
||||
|
||||
/// Generates a random digit in the given `base`.
|
||||
///
|
||||
/// Digits are represented by `char`s in ranges 0-9 and a-z.
|
||||
///
|
||||
/// Panics if the base is zero or greater than 36.
|
||||
#[inline]
|
||||
pub fn digit(base: u32) -> char {
|
||||
RNG.with(|rng| rng.digit(base))
|
||||
}
|
||||
|
||||
/// Shuffles a slice randomly.
|
||||
#[inline]
|
||||
pub fn shuffle<T>(slice: &mut [T]) {
|
||||
RNG.with(|rng| rng.shuffle(slice))
|
||||
}
|
||||
|
||||
macro_rules! integer {
|
||||
($t:tt, $doc:tt) => {
|
||||
#[doc = $doc]
|
||||
///
|
||||
/// Panics if the range is empty.
|
||||
#[inline]
|
||||
pub fn $t(range: impl RangeBounds<$t>) -> $t {
|
||||
RNG.with(|rng| rng.$t(range))
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
integer!(u8, "Generates a random `u8` in the given range.");
|
||||
integer!(i8, "Generates a random `i8` in the given range.");
|
||||
integer!(u16, "Generates a random `u16` in the given range.");
|
||||
integer!(i16, "Generates a random `i16` in the given range.");
|
||||
integer!(u32, "Generates a random `u32` in the given range.");
|
||||
integer!(i32, "Generates a random `i32` in the given range.");
|
||||
integer!(u64, "Generates a random `u64` in the given range.");
|
||||
integer!(i64, "Generates a random `i64` in the given range.");
|
||||
integer!(u128, "Generates a random `u128` in the given range.");
|
||||
integer!(i128, "Generates a random `i128` in the given range.");
|
||||
integer!(usize, "Generates a random `usize` in the given range.");
|
||||
integer!(isize, "Generates a random `isize` in the given range.");
|
||||
integer!(char, "Generates a random `char` in the given range.");
|
||||
|
||||
/// Generates a random `f32` in range `0..1`.
|
||||
pub fn f32() -> f32 {
|
||||
RNG.with(|rng| rng.f32())
|
||||
}
|
||||
|
||||
/// Generates a random `f64` in range `0..1`.
|
||||
pub fn f64() -> f64 {
|
||||
RNG.with(|rng| rng.f64())
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
use std::convert::TryFrom;
|
||||
use std::ops::RangeBounds;
|
||||
|
||||
fn test_char_coverage<R>(n: usize, range: R)
|
||||
where
|
||||
R: Iterator<Item = char> + RangeBounds<char> + Clone,
|
||||
{
|
||||
use std::collections::HashSet;
|
||||
|
||||
let all: HashSet<char> = range.clone().collect();
|
||||
let mut covered = HashSet::new();
|
||||
for _ in 0..n {
|
||||
let c = fastrand::char(range.clone());
|
||||
assert!(all.contains(&c));
|
||||
covered.insert(c);
|
||||
}
|
||||
assert_eq!(covered, all);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_char() {
|
||||
// ASCII control chars.
|
||||
let nul = 0u8 as char;
|
||||
let soh = 1u8 as char;
|
||||
let stx = 2u8 as char;
|
||||
// Some undefined Hangul Jamo codepoints just before
|
||||
// the surrogate area.
|
||||
let last_jamo = char::try_from(0xd7ffu32).unwrap();
|
||||
let penultimate_jamo = char::try_from(last_jamo as u32 - 1).unwrap();
|
||||
// Private-use codepoints just after the surrogate area.
|
||||
let first_private = char::try_from(0xe000u32).unwrap();
|
||||
let second_private = char::try_from(first_private as u32 + 1).unwrap();
|
||||
// Private-use codepoints at the end of Unicode space.
|
||||
let last_private = std::char::MAX;
|
||||
let penultimate_private = char::try_from(last_private as u32 - 1).unwrap();
|
||||
|
||||
test_char_coverage(100, nul..stx);
|
||||
test_char_coverage(100, nul..=soh);
|
||||
|
||||
test_char_coverage(400, penultimate_jamo..second_private);
|
||||
test_char_coverage(400, penultimate_jamo..=second_private);
|
||||
|
||||
test_char_coverage(100, penultimate_private..=last_private);
|
||||
}
|
|
@ -0,0 +1,117 @@
|
|||
#[cfg(target_arch = "wasm32")]
|
||||
use wasm_bindgen_test::*;
|
||||
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_browser);
|
||||
|
||||
#[test]
|
||||
#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
|
||||
fn bool() {
|
||||
for x in &[false, true] {
|
||||
while fastrand::bool() != *x {}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
|
||||
fn u8() {
|
||||
for x in 0..10 {
|
||||
while fastrand::u8(..10) != x {}
|
||||
}
|
||||
|
||||
for x in 200..=u8::MAX {
|
||||
while fastrand::u8(200..) != x {}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
|
||||
fn i8() {
|
||||
for x in -128..-120 {
|
||||
while fastrand::i8(..-120) != x {}
|
||||
}
|
||||
|
||||
for x in 120..=127 {
|
||||
while fastrand::i8(120..) != x {}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
|
||||
fn u32() {
|
||||
for n in 1u32..10_000 {
|
||||
let n = n.wrapping_mul(n);
|
||||
let n = n.wrapping_mul(n);
|
||||
if n != 0 {
|
||||
for _ in 0..1000 {
|
||||
assert!(fastrand::u32(..n) < n);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
|
||||
fn u64() {
|
||||
for n in 1u64..10_000 {
|
||||
let n = n.wrapping_mul(n);
|
||||
let n = n.wrapping_mul(n);
|
||||
let n = n.wrapping_mul(n);
|
||||
if n != 0 {
|
||||
for _ in 0..1000 {
|
||||
assert!(fastrand::u64(..n) < n);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
|
||||
fn u128() {
|
||||
for n in 1u128..10_000 {
|
||||
let n = n.wrapping_mul(n);
|
||||
let n = n.wrapping_mul(n);
|
||||
let n = n.wrapping_mul(n);
|
||||
let n = n.wrapping_mul(n);
|
||||
if n != 0 {
|
||||
for _ in 0..1000 {
|
||||
assert!(fastrand::u128(..n) < n);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
|
||||
fn rng() {
|
||||
let r = fastrand::Rng::new();
|
||||
|
||||
assert_ne!(r.u64(..), r.u64(..));
|
||||
|
||||
r.seed(7);
|
||||
let a = r.u64(..);
|
||||
r.seed(7);
|
||||
let b = r.u64(..);
|
||||
assert_eq!(a, b);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
|
||||
fn rng_init() {
|
||||
let a = fastrand::Rng::new();
|
||||
let b = fastrand::Rng::new();
|
||||
assert_ne!(a.u64(..), b.u64(..));
|
||||
|
||||
a.seed(7);
|
||||
b.seed(7);
|
||||
assert_eq!(a.u64(..), b.u64(..));
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
|
||||
fn with_seed() {
|
||||
let a = fastrand::Rng::with_seed(7);
|
||||
let b = fastrand::Rng::new();
|
||||
b.seed(7);
|
||||
assert_eq!(a.u64(..), b.u64(..));
|
||||
}
|
|
@ -1 +1 @@
|
|||
{"files":{"CHANGELOG.md":"f9559e40e966a870d64367a75e41b233ee1bc1746f6f242501b9462e69b4db12","Cargo.toml":"a7cce7f9fbc2cb0a5c388384073f9b2e820d6b47f314ef0dcccb5613741b8202","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"c9a75f18b9ab2927829a208fc6aa2cf4e63b8420887ba29cdb265d6619ae82d5","README.md":"93e21ceae3fe1b6cf9f6c2ebcbf09211a08b446f849048900d8d7efe52751614","bors.toml":"938b40da0516dd1e18f6ab893d43a3c6a011836124696157568380f3ce784958","src/condvar.rs":"bace2ee6e97eab088833a22a511029fb188e5f6bc9289bfcd5d41e3915de921d","src/deadlock.rs":"7d3ebb5b4f63658435df277bb983e352e4bc651a92c4fd48ae68bf103e452d0d","src/elision.rs":"9aceb0b27fd3cdaf4ef76bda63435a96ec2fdef24be098b9e4edbc39db000765","src/fair_mutex.rs":"d0a032e8207919da04b85f1422dfb14aa2af7aad78843c708d2fe3e0478e401a","src/lib.rs":"d83b9e6c70d2c6167d55dc2c4cf2b02abf4b11bfa092949750bc0cdafd38a45c","src/mutex.rs":"9fff878238ef798bfe2f48b410ca3074914826005a12df4f9b96619b2d3e6409","src/once.rs":"a1c38a5d87077e3d112d57e065ee126a24ab19f04fba9cb1f2cb43bc82caf33c","src/raw_fair_mutex.rs":"316f954d9673ac5b8d6bf4c19f2444800f63daf801c224d986e2d6dac810643c","src/raw_mutex.rs":"a24262800d61b8486ef0cfb1b72ead748c544ca2a551ec48346036ebb4fc385b","src/raw_rwlock.rs":"d0d93b096e68da3213da49d51849baf4ec241552eaa9b791f38314eb36c4e1a9","src/remutex.rs":"7a0de55161cd57497bb52d3aecca69a89eff2e71cdb2d762df53579e0607b489","src/rwlock.rs":"68584dffeb4368839774c0ee987481affc0547c38977a17970514f072a582d61","src/util.rs":"26325483bcd23ab8ceb16bf47541152c5eb0bc394f247795c14698fa7b586692","tests/issue_203.rs":"5fbdf6ec63f391d86457df949678c203a1e81e8aa32d4e10037fa76e768702c0"},"package":"6d7744ac029df22dca6284efe4e898991d28e3085c706c972bcd7da4a27a15eb"}
|
||||
{"files":{"CHANGELOG.md":"3ea666453fd8eae4b1b8d81f675f45e627115201a368890f0828cf895c58790f","Cargo.toml":"6217caca78eb5e8c0bb41beed960b735bde774ae60e752e584d7265a2e19f079","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"c9a75f18b9ab2927829a208fc6aa2cf4e63b8420887ba29cdb265d6619ae82d5","README.md":"93e21ceae3fe1b6cf9f6c2ebcbf09211a08b446f849048900d8d7efe52751614","bors.toml":"938b40da0516dd1e18f6ab893d43a3c6a011836124696157568380f3ce784958","src/condvar.rs":"bace2ee6e97eab088833a22a511029fb188e5f6bc9289bfcd5d41e3915de921d","src/deadlock.rs":"7d3ebb5b4f63658435df277bb983e352e4bc651a92c4fd48ae68bf103e452d0d","src/elision.rs":"9aceb0b27fd3cdaf4ef76bda63435a96ec2fdef24be098b9e4edbc39db000765","src/fair_mutex.rs":"d0a032e8207919da04b85f1422dfb14aa2af7aad78843c708d2fe3e0478e401a","src/lib.rs":"d83b9e6c70d2c6167d55dc2c4cf2b02abf4b11bfa092949750bc0cdafd38a45c","src/mutex.rs":"9fff878238ef798bfe2f48b410ca3074914826005a12df4f9b96619b2d3e6409","src/once.rs":"a1c38a5d87077e3d112d57e065ee126a24ab19f04fba9cb1f2cb43bc82caf33c","src/raw_fair_mutex.rs":"316f954d9673ac5b8d6bf4c19f2444800f63daf801c224d986e2d6dac810643c","src/raw_mutex.rs":"a24262800d61b8486ef0cfb1b72ead748c544ca2a551ec48346036ebb4fc385b","src/raw_rwlock.rs":"f23b9d68b7048278f9987d81551ae9551894e5af47bbaaf8d86b8ee42cb7ed74","src/remutex.rs":"7a0de55161cd57497bb52d3aecca69a89eff2e71cdb2d762df53579e0607b489","src/rwlock.rs":"68584dffeb4368839774c0ee987481affc0547c38977a17970514f072a582d61","src/util.rs":"26325483bcd23ab8ceb16bf47541152c5eb0bc394f247795c14698fa7b586692","tests/issue_203.rs":"5fbdf6ec63f391d86457df949678c203a1e81e8aa32d4e10037fa76e768702c0"},"package":"7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99"}
|
|
@ -1,3 +1,31 @@
|
|||
## parking_lot 0.11.2, parking_lot_core 0.8.4, lock_api 0.4.5 (2021-08-28)
|
||||
|
||||
- Fixed incorrect memory orderings on `RwLock` and `WordLock`. (#294, #292)
|
||||
- Added `Arc`-based lock guards. (#291)
|
||||
- Added workaround for TSan's lack of support for `fence`. (#292)
|
||||
|
||||
## lock_api 0.4.4 (2021-05-01)
|
||||
|
||||
- Update for latest nightly. (#281)
|
||||
|
||||
## lock_api 0.4.3 (2021-04-03)
|
||||
|
||||
- Added `[Raw]ReentrantMutex::is_owned`. (#280)
|
||||
|
||||
## parking_lot_core 0.8.3 (2021-02-12)
|
||||
|
||||
- Updated smallvec to 1.6. (#276)
|
||||
|
||||
## parking_lot_core 0.8.2 (2020-12-21)
|
||||
|
||||
- Fixed assertion failure on OpenBSD. (#270)
|
||||
|
||||
## parking_lot_core 0.8.1 (2020-12-04)
|
||||
|
||||
- Removed deprecated CloudABI support. (#263)
|
||||
- Fixed build on wasm32-unknown-unknown. (#265)
|
||||
- Relaxed dependency on `smallvec`. (#266)
|
||||
|
||||
## parking_lot 0.11.1, lock_api 0.4.2 (2020-11-18)
|
||||
|
||||
- Fix bounds on Send and Sync impls for lock guards. (#262)
|
||||
|
|
|
@ -3,17 +3,16 @@
|
|||
# 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
|
||||
# to registry (e.g., crates.io) dependencies.
|
||||
#
|
||||
# If you believe there's an error in this file please file an
|
||||
# issue against the rust-lang/cargo repository. If you're
|
||||
# editing this file be aware that the upstream Cargo.toml
|
||||
# will likely look very different (and much more reasonable)
|
||||
# If you are reading this file be aware that the original Cargo.toml
|
||||
# will likely look very different (and much more reasonable).
|
||||
# See Cargo.toml.orig for the original contents.
|
||||
|
||||
[package]
|
||||
edition = "2018"
|
||||
name = "parking_lot"
|
||||
version = "0.11.1"
|
||||
version = "0.11.2"
|
||||
authors = ["Amanieu d'Antras <amanieu@gmail.com>"]
|
||||
description = "More compact and efficient implementations of the standard synchronization primitives."
|
||||
readme = "README.md"
|
||||
|
@ -22,20 +21,21 @@ categories = ["concurrency"]
|
|||
license = "Apache-2.0/MIT"
|
||||
repository = "https://github.com/Amanieu/parking_lot"
|
||||
[dependencies.instant]
|
||||
version = "0.1.4"
|
||||
version = "0.1.9"
|
||||
|
||||
[dependencies.lock_api]
|
||||
version = "0.4.0"
|
||||
version = "0.4.5"
|
||||
|
||||
[dependencies.parking_lot_core]
|
||||
version = "0.8.0"
|
||||
version = "0.8.4"
|
||||
[dev-dependencies.bincode]
|
||||
version = "1.3.0"
|
||||
version = "1.3.3"
|
||||
|
||||
[dev-dependencies.rand]
|
||||
version = "0.7.3"
|
||||
version = "0.8.3"
|
||||
|
||||
[features]
|
||||
arc_lock = ["lock_api/arc_lock"]
|
||||
deadlock_detection = ["parking_lot_core/deadlock_detection"]
|
||||
default = []
|
||||
nightly = ["parking_lot_core/nightly", "lock_api/nightly"]
|
||||
|
|
|
@ -362,7 +362,7 @@ unsafe impl lock_api::RawRwLockUpgrade for RawRwLock {
|
|||
unsafe fn upgrade(&self) {
|
||||
let state = self.state.fetch_sub(
|
||||
(ONE_READER | UPGRADABLE_BIT) - WRITER_BIT,
|
||||
Ordering::Relaxed,
|
||||
Ordering::Acquire,
|
||||
);
|
||||
if state & READERS_MASK != ONE_READER {
|
||||
let result = self.upgrade_slow(None);
|
||||
|
@ -377,7 +377,7 @@ unsafe impl lock_api::RawRwLockUpgrade for RawRwLock {
|
|||
.compare_exchange_weak(
|
||||
ONE_READER | UPGRADABLE_BIT,
|
||||
WRITER_BIT,
|
||||
Ordering::Relaxed,
|
||||
Ordering::Acquire,
|
||||
Ordering::Relaxed,
|
||||
)
|
||||
.is_ok()
|
||||
|
|
|
@ -1 +1 @@
|
|||
{"files":{"Cargo.toml":"5c6baed932139022eb9544cb9b2ea8434bd1dc4add567257bbc0245f52efaa85","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"c9a75f18b9ab2927829a208fc6aa2cf4e63b8420887ba29cdb265d6619ae82d5","src/lib.rs":"7baf09034aafc28f7dbb1550cdde89221e4eb5dfda51b55aeb652ee8710c715d","src/parking_lot.rs":"58125667bd78399e8753b6bd8acef84f180f369f0bc174c573887176bab9f9d3","src/spinwait.rs":"d568d8a81f9144ec4c4a139dc934d7d04ee1656a4a221eb548742fe7aba09ab1","src/thread_parker/generic.rs":"574aecb3c325012b683eca4135441ec73f44c33cc9955aa05db24d7e4c991cd7","src/thread_parker/linux.rs":"4a2c76b3dc09301ceb73d904460f49d91bc1a2492cc123ee26ca22ece3faae79","src/thread_parker/mod.rs":"9c675b7690bbde62e88d946fad218623d423edccff4e01e8e52b116d815c695c","src/thread_parker/redox.rs":"91ca107c4edffa57e87294cadec3b6010b584fb272c044e2557c925dbcb90f6a","src/thread_parker/sgx.rs":"898ced116fb7b0ac077b5977b5bcac610f1d55beffb613ec73e083b1ef09cc28","src/thread_parker/unix.rs":"8ff84ab0a629e8891b663226c8867ae4bb0fc63f0b3504e85b4583e7bf73a589","src/thread_parker/wasm.rs":"903b7eec240cdbe8a23467f6b41d042d93b35755bd1763be02f9cc55756c4aec","src/thread_parker/wasm_atomic.rs":"cf761157803256b18205e747bc99e30b18d5410c27121fa9595e12cb51bb6bef","src/thread_parker/windows/keyed_event.rs":"fc1cf4e592d814c4c949217d91317ec2afb6048430abebb3cea2e8487b369734","src/thread_parker/windows/mod.rs":"c99a3871e69800452a56928a9e870530b7f48a563a4d3efe6184103147899f0c","src/thread_parker/windows/waitaddress.rs":"8e037df2a5692905e2bc2d4ea955295ab92bcc7e26eea0bb7a4eaac9ce657321","src/util.rs":"285e6133150645525f2ca1ece41f6d35bad4e7c5e08b42b20c99d2a97e04a974","src/word_lock.rs":"2c030aedb340ae8ca564365206452c298fe29986d005d6a40e808c9760f91c95"},"package":"d7c6d9b8427445284a09c55be860a15855ab580a417ccad9da88f5a06787ced0"}
|
||||
{"files":{"Cargo.toml":"fdba14f9aee05b55ba008685e1d3a9050d14a56251608b23cc0970caa6b9fae4","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"c9a75f18b9ab2927829a208fc6aa2cf4e63b8420887ba29cdb265d6619ae82d5","build.rs":"29e629057144d1238dcd8ea70ad6cbb6ec14ca742797af3fa9335710ff5cbaaa","src/lib.rs":"7baf09034aafc28f7dbb1550cdde89221e4eb5dfda51b55aeb652ee8710c715d","src/parking_lot.rs":"58125667bd78399e8753b6bd8acef84f180f369f0bc174c573887176bab9f9d3","src/spinwait.rs":"d568d8a81f9144ec4c4a139dc934d7d04ee1656a4a221eb548742fe7aba09ab1","src/thread_parker/generic.rs":"574aecb3c325012b683eca4135441ec73f44c33cc9955aa05db24d7e4c991cd7","src/thread_parker/linux.rs":"4a2c76b3dc09301ceb73d904460f49d91bc1a2492cc123ee26ca22ece3faae79","src/thread_parker/mod.rs":"9c675b7690bbde62e88d946fad218623d423edccff4e01e8e52b116d815c695c","src/thread_parker/redox.rs":"91ca107c4edffa57e87294cadec3b6010b584fb272c044e2557c925dbcb90f6a","src/thread_parker/sgx.rs":"898ced116fb7b0ac077b5977b5bcac610f1d55beffb613ec73e083b1ef09cc28","src/thread_parker/unix.rs":"02a17ad1241e8547cc7ee096318757b01d328354b639d0f799fca66ff2f07439","src/thread_parker/wasm.rs":"903b7eec240cdbe8a23467f6b41d042d93b35755bd1763be02f9cc55756c4aec","src/thread_parker/wasm_atomic.rs":"cf761157803256b18205e747bc99e30b18d5410c27121fa9595e12cb51bb6bef","src/thread_parker/windows/keyed_event.rs":"fc1cf4e592d814c4c949217d91317ec2afb6048430abebb3cea2e8487b369734","src/thread_parker/windows/mod.rs":"c99a3871e69800452a56928a9e870530b7f48a563a4d3efe6184103147899f0c","src/thread_parker/windows/waitaddress.rs":"8e037df2a5692905e2bc2d4ea955295ab92bcc7e26eea0bb7a4eaac9ce657321","src/util.rs":"285e6133150645525f2ca1ece41f6d35bad4e7c5e08b42b20c99d2a97e04a974","src/word_lock.rs":"9ba49082359c35ad5b4e8d219fede1ffca75225f9ccb971cbba01f20e2ed2738"},"package":"d76e8e1493bcac0d2766c42737f34458f1c8c50c0d23bcb24ea953affb273216"}
|
|
@ -3,17 +3,16 @@
|
|||
# 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
|
||||
# to registry (e.g., crates.io) dependencies.
|
||||
#
|
||||
# If you believe there's an error in this file please file an
|
||||
# issue against the rust-lang/cargo repository. If you're
|
||||
# editing this file be aware that the upstream Cargo.toml
|
||||
# will likely look very different (and much more reasonable)
|
||||
# If you are reading this file be aware that the original Cargo.toml
|
||||
# will likely look very different (and much more reasonable).
|
||||
# See Cargo.toml.orig for the original contents.
|
||||
|
||||
[package]
|
||||
edition = "2018"
|
||||
name = "parking_lot_core"
|
||||
version = "0.8.1"
|
||||
version = "0.8.5"
|
||||
authors = ["Amanieu d'Antras <amanieu@gmail.com>"]
|
||||
description = "An advanced API for creating custom synchronization primitives."
|
||||
keywords = ["mutex", "condvar", "rwlock", "once", "thread"]
|
||||
|
@ -21,33 +20,33 @@ categories = ["concurrency"]
|
|||
license = "Apache-2.0/MIT"
|
||||
repository = "https://github.com/Amanieu/parking_lot"
|
||||
[dependencies.backtrace]
|
||||
version = "0.3.49"
|
||||
version = "0.3.60"
|
||||
optional = true
|
||||
|
||||
[dependencies.cfg-if]
|
||||
version = "1.0.0"
|
||||
|
||||
[dependencies.instant]
|
||||
version = "0.1.4"
|
||||
version = "0.1.9"
|
||||
|
||||
[dependencies.petgraph]
|
||||
version = "0.5.1"
|
||||
optional = true
|
||||
|
||||
[dependencies.smallvec]
|
||||
version = "1.0"
|
||||
version = "1.6.1"
|
||||
|
||||
[dependencies.thread-id]
|
||||
version = "3.3.0"
|
||||
version = "4.0.0"
|
||||
optional = true
|
||||
|
||||
[features]
|
||||
deadlock_detection = ["petgraph", "thread-id", "backtrace"]
|
||||
nightly = []
|
||||
[target."cfg(target_os = \"redox\")".dependencies.redox_syscall]
|
||||
version = "0.1.56"
|
||||
version = "0.2.8"
|
||||
[target."cfg(unix)".dependencies.libc]
|
||||
version = "0.2.71"
|
||||
version = "0.2.95"
|
||||
[target."cfg(windows)".dependencies.winapi]
|
||||
version = "0.3.8"
|
||||
version = "0.3.9"
|
||||
features = ["winnt", "ntstatus", "minwindef", "winerror", "winbase", "errhandlingapi", "handleapi"]
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
// Automatically detect tsan in a way that's compatible with both stable (which
|
||||
// doesn't support sanitizers) and nightly (which does). Works because build
|
||||
// scripts gets `cfg` info, even if the cfg is unstable.
|
||||
fn main() {
|
||||
println!("cargo:rerun-if-changed=build.rs");
|
||||
let santizer_list = std::env::var("CARGO_CFG_SANITIZE").unwrap_or_default();
|
||||
if santizer_list.contains("thread") {
|
||||
println!("cargo:rustc-cfg=tsan_enabled");
|
||||
}
|
||||
}
|
|
@ -156,17 +156,9 @@ impl Drop for ThreadParker {
|
|||
// this behaviour no longer occurs. The same applies to condvars.
|
||||
unsafe {
|
||||
let r = libc::pthread_mutex_destroy(self.mutex.get());
|
||||
if cfg!(target_os = "dragonfly") {
|
||||
debug_assert!(r == 0 || r == libc::EINVAL);
|
||||
} else {
|
||||
debug_assert_eq!(r, 0);
|
||||
}
|
||||
debug_assert!(r == 0 || r == libc::EINVAL);
|
||||
let r = libc::pthread_cond_destroy(self.condvar.get());
|
||||
if cfg!(target_os = "dragonfly") {
|
||||
debug_assert!(r == 0 || r == libc::EINVAL);
|
||||
} else {
|
||||
debug_assert_eq!(r, 0);
|
||||
}
|
||||
debug_assert!(r == 0 || r == libc::EINVAL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -154,7 +154,7 @@ impl WordLock {
|
|||
if let Err(x) = self.state.compare_exchange_weak(
|
||||
state,
|
||||
state.with_queue_head(thread_data),
|
||||
Ordering::Release,
|
||||
Ordering::AcqRel,
|
||||
Ordering::Relaxed,
|
||||
) {
|
||||
return x;
|
||||
|
@ -238,7 +238,7 @@ impl WordLock {
|
|||
}
|
||||
|
||||
// Need an acquire fence before reading the new queue
|
||||
fence(Ordering::Acquire);
|
||||
fence_acquire(&self.state);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -263,7 +263,7 @@ impl WordLock {
|
|||
continue;
|
||||
} else {
|
||||
// Need an acquire fence before reading the new queue
|
||||
fence(Ordering::Acquire);
|
||||
fence_acquire(&self.state);
|
||||
continue 'outer;
|
||||
}
|
||||
}
|
||||
|
@ -286,6 +286,17 @@ impl WordLock {
|
|||
}
|
||||
}
|
||||
|
||||
// Thread-Sanitizer only has partial fence support, so when running under it, we
|
||||
// try and avoid false positives by using a discarded acquire load instead.
|
||||
#[inline]
|
||||
fn fence_acquire(a: &AtomicUsize) {
|
||||
if cfg!(tsan_enabled) {
|
||||
let _ = a.load(Ordering::Acquire);
|
||||
} else {
|
||||
fence(Ordering::Acquire);
|
||||
}
|
||||
}
|
||||
|
||||
trait LockState {
|
||||
fn is_locked(self) -> bool;
|
||||
fn is_queue_locked(self) -> bool;
|
||||
|
|
|
@ -1 +1 @@
|
|||
{"files":{"Cargo.toml":"9494475634c86ca0cfc30688aaf3e3961c0bdab1380e12a9e36597b24dece24c","LICENSE":"efcfee7981ff72431fffb06925cad00a23dce079ed4354f61030ad5abdb78829","README.md":"9161f18ba7f69b4ca51e844aee8ffb8237513a468c5c3b1f3a5f989044f895ac","src/arch/aarch64.rs":"5d9afb0813ca903cd5ac48add7f6f9b538d9e0346bc9bac0924d509d2004c07b","src/arch/arm.rs":"6f0eea58ea5dc7e87a66f335cb4264995bdf5352b379428dd0ba6a11887491a6","src/arch/nonredox.rs":"de54557f642218b34d451fc52fe3cff97e3e4307304ae02a678a900cab96cdb0","src/arch/x86.rs":"a433a3cfaf4fe2987e7516069e814f539172a1bb51d02bcfab74fa4c56dd9fdf","src/arch/x86_64.rs":"0bb1ebc3aba5d240b2ab813f6aa999b071d1230641849775d38d2074e2e4026a","src/call.rs":"b5b53aab18bb91bfef88d82f1708d05e210a30cde141fce0031dad543d988391","src/data.rs":"84f8beb9d40b753a8c1713b922e99ed9913d35e959694b2c849351b1a92d87c9","src/error.rs":"d832a641ccb1baf10315e2e1ce59b12c30d605a526fc65a31f63bb3a92c3a2f7","src/flag.rs":"1e944be3b134d3776725529e2190e2d1548dd67a631838281b8c5bc829523dbe","src/io/dma.rs":"740cd441f844718a14f77c2fe292d29b7c468d686505810d8b3281f9528a6fe7","src/io/io.rs":"1bcb36d1867e9bab6a8186cd6928efe70ae2655e9f9d0dd3def20bc0fb6a82f6","src/io/mmio.rs":"b9fdb37d37a25a48106d60f1a977c541cb5162b20b12507c7dcd6eb3dff0a2c8","src/io/mod.rs":"4df12af3e82e6b5fe22112c9f51552112ee4811b7d1131d2a43d608d8d1cac09","src/io/pio.rs":"39f4176a2995c7acfb32204b065af0ec14d7ff0d45dc51eff2679f3195c36ee2","src/lib.rs":"a5a56fa43f30d2d994075539425ffaa8da7106ccd77c3022950623eb82cd59b1","src/number.rs":"4718baa58a0f3e6b9b66d1f328cb2a145e9b1f807654c3079a13b226c4085a29","src/scheme/generate.sh":"b022adacb74f2af1470e691341c37acc1582f428e9b8b6b9dccb790dde594b40","src/scheme/mod.rs":"2679272397bf0247e1a4695853465243ca02960feb4ced1124969f67ebd3e3ce","src/scheme/scheme.rs":"879728e4d4e7d8f3057df5a3a6af1636079135652594ee50ca1b665e876be595","src/scheme/scheme_block.rs":"a8ea17b1101548e9b36f6c9000f68fd5438a796069252f948bde7dda44088a7f","src/scheme/scheme_block_mut.rs":"8b881f84a54e2477967d43eb68dac7c578ff6451dba59eba0d517037b2ac4def","src/scheme/scheme_mut.rs":"30f9b0750437b7f55d5bb24da546fd4afcb3c27b0af06d5f681b8f1c4877e7b4","src/tests.rs":"b9d60e419f7e57bb942756e8011e19704cfd46fb6ec96ffa925fb7deb35c5d43"},"package":"41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce"}
|
||||
{"files":{"Cargo.toml":"69f08bb56c6fc199b61cbe959b6e9f93df554f5d4e87d5e64551116cedf15067","LICENSE":"efcfee7981ff72431fffb06925cad00a23dce079ed4354f61030ad5abdb78829","README.md":"9161f18ba7f69b4ca51e844aee8ffb8237513a468c5c3b1f3a5f989044f895ac","src/arch/aarch64.rs":"61b5811b47a29257c3b5e15e7d9d15e7143bad99fbe29f0cb17ead9cbc17186f","src/arch/nonredox.rs":"9eac0fa2cf9eae07f0cafa2dd63c4a820791897a3de9ad1a933ab4f53458dbd8","src/arch/riscv64.rs":"20bf9a8db779059773b113643d0cb3737fbb5d57f45ee39b8ae9d3396b6ef636","src/arch/x86_64.rs":"f40bad2680fd5e7f100ee1afaa805f33dd0e12ec8786b956d47204f66771801d","src/call.rs":"0d3e32e33ecdf75963e5d244f9e86e94047d155c5de5fa3c0085faf18ed97b33","src/daemon.rs":"11cd633298fe2eb89906a4d8c12ab34e4ee355f759e1216cee536f24c7c679b2","src/data.rs":"bd4545d4c2fcc59ff26ae52ad7f773a697d5ccf639a2ffc253cece6b31e94d51","src/error.rs":"ef20f3817f997a1aeb7114628407f19cb8bc13c555d4e093918f38a5d098f798","src/flag.rs":"f07d6a7aa6766d30d0a303c7b3bda5bb4c473dd9dd51687cf8e0631b1bf3ec9d","src/io/dma.rs":"fbc46e924d5913f5a3fb723751d7a9dd1b079ccf058500fde4957aaf9fa7dd1c","src/io/io.rs":"e1d454ff47efac70fdaa709251a5a9c1c5637f931994ba3bf6a38c6db9145822","src/io/mmio.rs":"12d0fb4d4f45097bf2c14f73cb1ce21325eae193b537e9f18af73ed5281b5e63","src/io/mod.rs":"62438ff452c266692ea8fcfc4b6aad73184a1f67276327a4d5f71c4fbbaeab55","src/io/pio.rs":"9ee6f2229b700d1c45b4c8c6242bd99fe69634e16dcd5843d9e8d1c958047406","src/lib.rs":"d30eec6d2480c6dbc74221a10cc662a649bd24dc3ac640bbcdab9e416aab727f","src/number.rs":"fe7b47b06566aa1f8a75f50b685801259df03a1a5c85b91817b4552583cd7862","src/scheme/generate.sh":"dde4e30f4e0223fb1a24ed486a6c36e624c854dbf890862cb6866f4fa3c7a6eb","src/scheme/mod.rs":"cb622405deb0aef4ab04499ea1adfd338c9c5dd9c31a1fe9989786dbf69b49d8","src/scheme/scheme.rs":"30263996f0b4930edd76dace5f5750e48229066bc888bc13365846688d0a870b","src/scheme/scheme_block.rs":"b7a761e4349eb87d106c8af14894e8c4272769b9eb235cd500b075ac1f823683","src/scheme/scheme_block_mut.rs":"4a4fc03bce14757b64006b9bc3fa2779e95382b2d99579870146ee0c3be3f46c","src/scheme/scheme_mut.rs":"e6f0671b77f1bf5263e497c69dec553352249b75d52af62ac19477ba5127f803","src/scheme/seek.rs":"94e044de47b0f00eb0c2aea3fb21001ac2b9aa1e4b20d73fd54163fe92fa63f7","src/tests.rs":"416a428ba6a9c5f0d8f4c3dbe91d9aa940a04472ec9a2d17bc5a66c455b4416f"},"package":"62f25bc4c7e55e0b0b7a1d43fb893f4fa1361d0abe38b9ce4f323c2adfe6ef42"}
|
|
@ -3,16 +3,16 @@
|
|||
# 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
|
||||
# to registry (e.g., crates.io) dependencies.
|
||||
#
|
||||
# If you believe there's an error in this file please file an
|
||||
# issue against the rust-lang/cargo repository. If you're
|
||||
# editing this file be aware that the upstream Cargo.toml
|
||||
# will likely look very different (and much more reasonable)
|
||||
# If you are reading this file be aware that the original Cargo.toml
|
||||
# will likely look very different (and much more reasonable).
|
||||
# See Cargo.toml.orig for the original contents.
|
||||
|
||||
[package]
|
||||
edition = "2018"
|
||||
name = "redox_syscall"
|
||||
version = "0.1.57"
|
||||
version = "0.2.13"
|
||||
authors = ["Jeremy Soller <jackpot51@gmail.com>"]
|
||||
description = "A Rust library to access raw Redox system calls"
|
||||
documentation = "https://docs.rs/redox_syscall"
|
||||
|
@ -21,3 +21,6 @@ repository = "https://gitlab.redox-os.org/redox-os/syscall"
|
|||
|
||||
[lib]
|
||||
name = "syscall"
|
||||
|
||||
[dependencies.bitflags]
|
||||
version = "1.1.0"
|
||||
|
|
|
@ -1,77 +1,132 @@
|
|||
use core::{mem, slice};
|
||||
use core::ops::{Deref, DerefMut};
|
||||
|
||||
use super::error::{Error, Result};
|
||||
|
||||
pub unsafe fn syscall0(mut a: usize) -> Result<usize> {
|
||||
llvm_asm!("svc 0"
|
||||
: "={x0}"(a)
|
||||
: "{x8}"(a)
|
||||
: "x0", "x8"
|
||||
: "volatile");
|
||||
macro_rules! syscall {
|
||||
($($name:ident($a:ident, $($b:ident, $($c:ident, $($d:ident, $($e:ident, $($f:ident, )?)?)?)?)?);)+) => {
|
||||
$(
|
||||
pub unsafe fn $name($a: usize, $($b: usize, $($c: usize, $($d: usize, $($e: usize, $($f: usize)?)?)?)?)?) -> Result<usize> {
|
||||
let ret: usize;
|
||||
|
||||
Error::demux(a)
|
||||
core::arch::asm!(
|
||||
"svc 0",
|
||||
in("x8") $a,
|
||||
$(
|
||||
in("x0") $b,
|
||||
$(
|
||||
in("x1") $c,
|
||||
$(
|
||||
in("x2") $d,
|
||||
$(
|
||||
in("x3") $e,
|
||||
$(
|
||||
in("x4") $f,
|
||||
)?
|
||||
)?
|
||||
)?
|
||||
)?
|
||||
)?
|
||||
lateout("x0") ret,
|
||||
options(nostack),
|
||||
);
|
||||
|
||||
Error::demux(ret)
|
||||
}
|
||||
)+
|
||||
};
|
||||
}
|
||||
|
||||
pub unsafe fn syscall1(mut a: usize, b: usize) -> Result<usize> {
|
||||
llvm_asm!("svc 0"
|
||||
: "={x0}"(a)
|
||||
: "{x8}"(a), "{x0}"(b)
|
||||
: "x0", "x8"
|
||||
: "volatile");
|
||||
|
||||
Error::demux(a)
|
||||
syscall! {
|
||||
syscall0(a,);
|
||||
syscall1(a, b,);
|
||||
syscall2(a, b, c,);
|
||||
syscall3(a, b, c, d,);
|
||||
syscall4(a, b, c, d, e,);
|
||||
syscall5(a, b, c, d, e, f,);
|
||||
}
|
||||
|
||||
// Clobbers all registers - special for clone
|
||||
pub unsafe fn syscall1_clobber(mut a: usize, b: usize) -> Result<usize> {
|
||||
llvm_asm!("svc 0"
|
||||
: "={x0}"(a)
|
||||
: "{x8}"(a), "{x0}"(b)
|
||||
: "memory",
|
||||
"x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7",
|
||||
"x8", "x9", "x10", "x11", "x12", "x13", "x14", "x15",
|
||||
"x16", "x17","x18", "x19", "x20", "x21", "x22", "x23",
|
||||
"x24", "x25", "x26", "x27", "x28", "x29", "x30"
|
||||
: "volatile");
|
||||
|
||||
Error::demux(a)
|
||||
#[derive(Copy, Clone, Debug, Default)]
|
||||
#[repr(C)]
|
||||
pub struct IntRegisters {
|
||||
pub elr_el1: usize,
|
||||
pub tpidr_el0: usize,
|
||||
pub tpidrro_el0: usize,
|
||||
pub spsr_el1: usize,
|
||||
pub esr_el1: usize,
|
||||
pub sp_el0: usize, // Shouldn't be used if interrupt occurred at EL1
|
||||
pub padding: usize, // To keep the struct even number aligned
|
||||
pub x30: usize,
|
||||
pub x29: usize,
|
||||
pub x28: usize,
|
||||
pub x27: usize,
|
||||
pub x26: usize,
|
||||
pub x25: usize,
|
||||
pub x24: usize,
|
||||
pub x23: usize,
|
||||
pub x22: usize,
|
||||
pub x21: usize,
|
||||
pub x20: usize,
|
||||
pub x19: usize,
|
||||
pub x18: usize,
|
||||
pub x17: usize,
|
||||
pub x16: usize,
|
||||
pub x15: usize,
|
||||
pub x14: usize,
|
||||
pub x13: usize,
|
||||
pub x12: usize,
|
||||
pub x11: usize,
|
||||
pub x10: usize,
|
||||
pub x9: usize,
|
||||
pub x8: usize,
|
||||
pub x7: usize,
|
||||
pub x6: usize,
|
||||
pub x5: usize,
|
||||
pub x4: usize,
|
||||
pub x3: usize,
|
||||
pub x2: usize,
|
||||
pub x1: usize,
|
||||
pub x0: usize
|
||||
}
|
||||
|
||||
pub unsafe fn syscall2(mut a: usize, b: usize, c: usize) -> Result<usize> {
|
||||
llvm_asm!("svc 0"
|
||||
: "={x0}"(a)
|
||||
: "{x8}"(a), "{x0}"(b), "{x1}"(c)
|
||||
: "x0", "x1", "x8"
|
||||
: "volatile");
|
||||
|
||||
Error::demux(a)
|
||||
impl Deref for IntRegisters {
|
||||
type Target = [u8];
|
||||
fn deref(&self) -> &[u8] {
|
||||
unsafe {
|
||||
slice::from_raw_parts(self as *const IntRegisters as *const u8, mem::size_of::<IntRegisters>())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub unsafe fn syscall3(mut a: usize, b: usize, c: usize, d: usize) -> Result<usize> {
|
||||
llvm_asm!("svc 0"
|
||||
: "={x0}"(a)
|
||||
: "{x8}"(a), "{x0}"(b), "{x1}"(c), "{x2}"(d)
|
||||
: "x0", "x1", "x2", "x8"
|
||||
: "volatile");
|
||||
|
||||
Error::demux(a)
|
||||
impl DerefMut for IntRegisters {
|
||||
fn deref_mut(&mut self) -> &mut [u8] {
|
||||
unsafe {
|
||||
slice::from_raw_parts_mut(self as *mut IntRegisters as *mut u8, mem::size_of::<IntRegisters>())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub unsafe fn syscall4(mut a: usize, b: usize, c: usize, d: usize, e: usize) -> Result<usize> {
|
||||
llvm_asm!("svc 0"
|
||||
: "={x0}"(a)
|
||||
: "{x8}"(a), "{x0}"(b), "{x1}"(c), "{x2}"(d), "{x3}"(e)
|
||||
: "x0", "x1", "x2", "x3", "x8"
|
||||
: "volatile");
|
||||
|
||||
Error::demux(a)
|
||||
#[derive(Clone, Copy, Debug, Default)]
|
||||
#[repr(packed)]
|
||||
pub struct FloatRegisters {
|
||||
pub fp_simd_regs: [u128; 32],
|
||||
pub fpsr: u32,
|
||||
pub fpcr: u32
|
||||
}
|
||||
|
||||
pub unsafe fn syscall5(mut a: usize, b: usize, c: usize, d: usize, e: usize, f: usize)
|
||||
-> Result<usize> {
|
||||
llvm_asm!("svc 0"
|
||||
: "={x0}"(a)
|
||||
: "{x8}"(a), "{x0}"(b), "{x1}"(c), "{x2}"(d), "{x3}"(e), "{x4}"(f)
|
||||
: "x0", "x1", "x2", "x3", "x4", "x8"
|
||||
: "volatile");
|
||||
|
||||
Error::demux(a)
|
||||
impl Deref for FloatRegisters {
|
||||
type Target = [u8];
|
||||
fn deref(&self) -> &[u8] {
|
||||
unsafe {
|
||||
slice::from_raw_parts(self as *const FloatRegisters as *const u8, mem::size_of::<FloatRegisters>())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl DerefMut for FloatRegisters {
|
||||
fn deref_mut(&mut self) -> &mut [u8] {
|
||||
unsafe {
|
||||
slice::from_raw_parts_mut(self as *mut FloatRegisters as *mut u8, mem::size_of::<FloatRegisters>())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,73 +0,0 @@
|
|||
use super::error::{Error, Result};
|
||||
|
||||
pub unsafe fn syscall0(mut a: usize) -> Result<usize> {
|
||||
llvm_asm!("swi $$0"
|
||||
: "={r0}"(a)
|
||||
: "{r7}"(a)
|
||||
: "memory"
|
||||
: "volatile");
|
||||
|
||||
Error::demux(a)
|
||||
}
|
||||
|
||||
pub unsafe fn syscall1(mut a: usize, b: usize) -> Result<usize> {
|
||||
llvm_asm!("swi $$0"
|
||||
: "={r0}"(a)
|
||||
: "{r7}"(a), "{r0}"(b)
|
||||
: "memory"
|
||||
: "volatile");
|
||||
|
||||
Error::demux(a)
|
||||
}
|
||||
|
||||
// Clobbers all registers - special for clone
|
||||
pub unsafe fn syscall1_clobber(mut a: usize, b: usize) -> Result<usize> {
|
||||
llvm_asm!("swi $$0"
|
||||
: "={r0}"(a)
|
||||
: "{r7}"(a), "{r0}"(b)
|
||||
: "memory", "r0", "r1", "r2", "r3", "r4"
|
||||
: "volatile");
|
||||
|
||||
Error::demux(a)
|
||||
}
|
||||
|
||||
pub unsafe fn syscall2(mut a: usize, b: usize, c: usize) -> Result<usize> {
|
||||
llvm_asm!("swi $$0"
|
||||
: "={r0}"(a)
|
||||
: "{r7}"(a), "{r0}"(b), "{r1}"(c)
|
||||
: "memory"
|
||||
: "volatile");
|
||||
|
||||
Error::demux(a)
|
||||
}
|
||||
|
||||
pub unsafe fn syscall3(mut a: usize, b: usize, c: usize, d: usize) -> Result<usize> {
|
||||
llvm_asm!("swi $$0"
|
||||
: "={r0}"(a)
|
||||
: "{r7}"(a), "{r0}"(b), "{r1}"(c), "{r2}"(d)
|
||||
: "memory"
|
||||
: "volatile");
|
||||
|
||||
Error::demux(a)
|
||||
}
|
||||
|
||||
pub unsafe fn syscall4(mut a: usize, b: usize, c: usize, d: usize, e: usize) -> Result<usize> {
|
||||
llvm_asm!("swi $$0"
|
||||
: "={r0}"(a)
|
||||
: "{r7}"(a), "{r0}"(b), "{r1}"(c), "{r2}"(d), "{r3}"(e)
|
||||
: "memory"
|
||||
: "volatile");
|
||||
|
||||
Error::demux(a)
|
||||
}
|
||||
|
||||
pub unsafe fn syscall5(mut a: usize, b: usize, c: usize, d: usize, e: usize, f: usize)
|
||||
-> Result<usize> {
|
||||
llvm_asm!("swi $$0"
|
||||
: "={r0}"(a)
|
||||
: "{r7}"(a), "{r0}"(b), "{r1}"(c), "{r2}"(d), "{r3}"(e), "{r4}"(f)
|
||||
: "memory"
|
||||
: "volatile");
|
||||
|
||||
Error::demux(a)
|
||||
}
|
|
@ -8,11 +8,6 @@ pub unsafe fn syscall1(_a: usize, _b: usize) -> Result<usize> {
|
|||
Err(Error::new(ENOSYS))
|
||||
}
|
||||
|
||||
// Clobbers all registers - special for clone
|
||||
pub unsafe fn syscall1_clobber(_a: usize, _b: usize) -> Result<usize> {
|
||||
Err(Error::new(ENOSYS))
|
||||
}
|
||||
|
||||
pub unsafe fn syscall2(_a: usize, _b: usize, _c: usize) -> Result<usize> {
|
||||
Err(Error::new(ENOSYS))
|
||||
}
|
||||
|
|
|
@ -0,0 +1,93 @@
|
|||
use core::{mem, slice};
|
||||
use core::ops::{Deref, DerefMut};
|
||||
|
||||
use super::error::{Error, Result};
|
||||
|
||||
macro_rules! syscall {
|
||||
($($name:ident($a:ident, $($b:ident, $($c:ident, $($d:ident, $($e:ident, $($f:ident, )?)?)?)?)?);)+) => {
|
||||
$(
|
||||
pub unsafe fn $name($a: usize, $($b: usize, $($c: usize, $($d: usize, $($e: usize, $($f: usize)?)?)?)?)?) -> Result<usize> {
|
||||
let ret: usize;
|
||||
|
||||
asm!(
|
||||
"ecall",
|
||||
in("a7") $a,
|
||||
$(
|
||||
in("a0") $b,
|
||||
$(
|
||||
in("a1") $c,
|
||||
$(
|
||||
in("a2") $d,
|
||||
$(
|
||||
in("a3") $e,
|
||||
$(
|
||||
in("a4") $f,
|
||||
)?
|
||||
)?
|
||||
)?
|
||||
)?
|
||||
)?
|
||||
lateout("a0") ret,
|
||||
options(nostack),
|
||||
);
|
||||
|
||||
Error::demux(ret)
|
||||
}
|
||||
)+
|
||||
};
|
||||
}
|
||||
|
||||
syscall! {
|
||||
syscall0(a,);
|
||||
syscall1(a, b,);
|
||||
syscall2(a, b, c,);
|
||||
syscall3(a, b, c, d,);
|
||||
syscall4(a, b, c, d, e,);
|
||||
syscall5(a, b, c, d, e, f,);
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, Default)]
|
||||
#[repr(C)]
|
||||
pub struct IntRegisters {
|
||||
//TODO
|
||||
}
|
||||
|
||||
impl Deref for IntRegisters {
|
||||
type Target = [u8];
|
||||
fn deref(&self) -> &[u8] {
|
||||
unsafe {
|
||||
slice::from_raw_parts(self as *const IntRegisters as *const u8, mem::size_of::<IntRegisters>())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl DerefMut for IntRegisters {
|
||||
fn deref_mut(&mut self) -> &mut [u8] {
|
||||
unsafe {
|
||||
slice::from_raw_parts_mut(self as *mut IntRegisters as *mut u8, mem::size_of::<IntRegisters>())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Default)]
|
||||
#[repr(packed)]
|
||||
pub struct FloatRegisters {
|
||||
//TODO
|
||||
}
|
||||
|
||||
impl Deref for FloatRegisters {
|
||||
type Target = [u8];
|
||||
fn deref(&self) -> &[u8] {
|
||||
unsafe {
|
||||
slice::from_raw_parts(self as *const FloatRegisters as *const u8, mem::size_of::<FloatRegisters>())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl DerefMut for FloatRegisters {
|
||||
fn deref_mut(&mut self) -> &mut [u8] {
|
||||
unsafe {
|
||||
slice::from_raw_parts_mut(self as *mut FloatRegisters as *mut u8, mem::size_of::<FloatRegisters>())
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,73 +0,0 @@
|
|||
use super::error::{Error, Result};
|
||||
|
||||
pub unsafe fn syscall0(mut a: usize) -> Result<usize> {
|
||||
llvm_asm!("int 0x80"
|
||||
: "={eax}"(a)
|
||||
: "{eax}"(a)
|
||||
: "memory"
|
||||
: "intel", "volatile");
|
||||
|
||||
Error::demux(a)
|
||||
}
|
||||
|
||||
pub unsafe fn syscall1(mut a: usize, b: usize) -> Result<usize> {
|
||||
llvm_asm!("int 0x80"
|
||||
: "={eax}"(a)
|
||||
: "{eax}"(a), "{ebx}"(b)
|
||||
: "memory"
|
||||
: "intel", "volatile");
|
||||
|
||||
Error::demux(a)
|
||||
}
|
||||
|
||||
// Clobbers all registers - special for clone
|
||||
pub unsafe fn syscall1_clobber(mut a: usize, b: usize) -> Result<usize> {
|
||||
llvm_asm!("int 0x80"
|
||||
: "={eax}"(a)
|
||||
: "{eax}"(a), "{ebx}"(b)
|
||||
: "memory", "ebx", "ecx", "edx", "esi", "edi"
|
||||
: "intel", "volatile");
|
||||
|
||||
Error::demux(a)
|
||||
}
|
||||
|
||||
pub unsafe fn syscall2(mut a: usize, b: usize, c: usize) -> Result<usize> {
|
||||
llvm_asm!("int 0x80"
|
||||
: "={eax}"(a)
|
||||
: "{eax}"(a), "{ebx}"(b), "{ecx}"(c)
|
||||
: "memory"
|
||||
: "intel", "volatile");
|
||||
|
||||
Error::demux(a)
|
||||
}
|
||||
|
||||
pub unsafe fn syscall3(mut a: usize, b: usize, c: usize, d: usize) -> Result<usize> {
|
||||
llvm_asm!("int 0x80"
|
||||
: "={eax}"(a)
|
||||
: "{eax}"(a), "{ebx}"(b), "{ecx}"(c), "{edx}"(d)
|
||||
: "memory"
|
||||
: "intel", "volatile");
|
||||
|
||||
Error::demux(a)
|
||||
}
|
||||
|
||||
pub unsafe fn syscall4(mut a: usize, b: usize, c: usize, d: usize, e: usize) -> Result<usize> {
|
||||
llvm_asm!("int 0x80"
|
||||
: "={eax}"(a)
|
||||
: "{eax}"(a), "{ebx}"(b), "{ecx}"(c), "{edx}"(d), "{esi}"(e)
|
||||
: "memory"
|
||||
: "intel", "volatile");
|
||||
|
||||
Error::demux(a)
|
||||
}
|
||||
|
||||
pub unsafe fn syscall5(mut a: usize, b: usize, c: usize, d: usize, e: usize, f: usize)
|
||||
-> Result<usize> {
|
||||
llvm_asm!("int 0x80"
|
||||
: "={eax}"(a)
|
||||
: "{eax}"(a), "{ebx}"(b), "{ecx}"(c), "{edx}"(d), "{esi}"(e), "{edi}"(f)
|
||||
: "memory"
|
||||
: "intel", "volatile");
|
||||
|
||||
Error::demux(a)
|
||||
}
|
|
@ -1,74 +1,155 @@
|
|||
use core::{mem, slice};
|
||||
use core::arch::asm;
|
||||
use core::ops::{Deref, DerefMut};
|
||||
|
||||
use super::error::{Error, Result};
|
||||
|
||||
pub unsafe fn syscall0(mut a: usize) -> Result<usize> {
|
||||
llvm_asm!("syscall"
|
||||
: "={rax}"(a)
|
||||
: "{rax}"(a)
|
||||
: "rcx", "r11", "memory"
|
||||
: "intel", "volatile");
|
||||
macro_rules! syscall {
|
||||
($($name:ident($a:ident, $($b:ident, $($c:ident, $($d:ident, $($e:ident, $($f:ident, )?)?)?)?)?);)+) => {
|
||||
$(
|
||||
pub unsafe fn $name(mut $a: usize, $($b: usize, $($c: usize, $($d: usize, $($e: usize, $($f: usize)?)?)?)?)?) -> Result<usize> {
|
||||
asm!(
|
||||
"syscall",
|
||||
inout("rax") $a,
|
||||
$(
|
||||
in("rdi") $b,
|
||||
$(
|
||||
in("rsi") $c,
|
||||
$(
|
||||
in("rdx") $d,
|
||||
$(
|
||||
in("r10") $e,
|
||||
$(
|
||||
in("r8") $f,
|
||||
)?
|
||||
)?
|
||||
)?
|
||||
)?
|
||||
)?
|
||||
out("rcx") _,
|
||||
out("r11") _,
|
||||
options(nostack),
|
||||
);
|
||||
|
||||
Error::demux(a)
|
||||
Error::demux($a)
|
||||
}
|
||||
)+
|
||||
};
|
||||
}
|
||||
|
||||
pub unsafe fn syscall1(mut a: usize, b: usize) -> Result<usize> {
|
||||
llvm_asm!("syscall"
|
||||
: "={rax}"(a)
|
||||
: "{rax}"(a), "{rdi}"(b)
|
||||
: "rcx", "r11", "memory"
|
||||
: "intel", "volatile");
|
||||
|
||||
Error::demux(a)
|
||||
syscall! {
|
||||
syscall0(a,);
|
||||
syscall1(a, b,);
|
||||
syscall2(a, b, c,);
|
||||
syscall3(a, b, c, d,);
|
||||
syscall4(a, b, c, d, e,);
|
||||
syscall5(a, b, c, d, e, f,);
|
||||
}
|
||||
|
||||
// Clobbers all registers - special for clone
|
||||
pub unsafe fn syscall1_clobber(mut a: usize, b: usize) -> Result<usize> {
|
||||
llvm_asm!("syscall"
|
||||
: "={rax}"(a)
|
||||
: "{rax}"(a), "{rdi}"(b)
|
||||
: "memory", "rbx", "rcx", "rdx", "rsi", "rdi", "r8",
|
||||
"r9", "r10", "r11", "r12", "r13", "r14", "r15"
|
||||
: "intel", "volatile");
|
||||
#[derive(Copy, Clone, Debug, Default)]
|
||||
#[repr(C)]
|
||||
pub struct IntRegisters {
|
||||
// TODO: Some of these don't get set by Redox yet. Should they?
|
||||
|
||||
Error::demux(a)
|
||||
pub r15: usize,
|
||||
pub r14: usize,
|
||||
pub r13: usize,
|
||||
pub r12: usize,
|
||||
pub rbp: usize,
|
||||
pub rbx: usize,
|
||||
pub r11: usize,
|
||||
pub r10: usize,
|
||||
pub r9: usize,
|
||||
pub r8: usize,
|
||||
pub rax: usize,
|
||||
pub rcx: usize,
|
||||
pub rdx: usize,
|
||||
pub rsi: usize,
|
||||
pub rdi: usize,
|
||||
// pub orig_rax: usize,
|
||||
pub rip: usize,
|
||||
pub cs: usize,
|
||||
pub rflags: usize,
|
||||
pub rsp: usize,
|
||||
pub ss: usize,
|
||||
// pub fs_base: usize,
|
||||
// pub gs_base: usize,
|
||||
// pub ds: usize,
|
||||
// pub es: usize,
|
||||
pub fs: usize,
|
||||
// pub gs: usize
|
||||
}
|
||||
|
||||
pub unsafe fn syscall2(mut a: usize, b: usize, c: usize) -> Result<usize> {
|
||||
llvm_asm!("syscall"
|
||||
: "={rax}"(a)
|
||||
: "{rax}"(a), "{rdi}"(b), "{rsi}"(c)
|
||||
: "rcx", "r11", "memory"
|
||||
: "intel", "volatile");
|
||||
|
||||
Error::demux(a)
|
||||
impl Deref for IntRegisters {
|
||||
type Target = [u8];
|
||||
fn deref(&self) -> &[u8] {
|
||||
unsafe {
|
||||
slice::from_raw_parts(self as *const IntRegisters as *const u8, mem::size_of::<IntRegisters>())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub unsafe fn syscall3(mut a: usize, b: usize, c: usize, d: usize) -> Result<usize> {
|
||||
llvm_asm!("syscall"
|
||||
: "={rax}"(a)
|
||||
: "{rax}"(a), "{rdi}"(b), "{rsi}"(c), "{rdx}"(d)
|
||||
: "rcx", "r11", "memory"
|
||||
: "intel", "volatile");
|
||||
|
||||
Error::demux(a)
|
||||
impl DerefMut for IntRegisters {
|
||||
fn deref_mut(&mut self) -> &mut [u8] {
|
||||
unsafe {
|
||||
slice::from_raw_parts_mut(self as *mut IntRegisters as *mut u8, mem::size_of::<IntRegisters>())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub unsafe fn syscall4(mut a: usize, b: usize, c: usize, d: usize, e: usize) -> Result<usize> {
|
||||
llvm_asm!("syscall"
|
||||
: "={rax}"(a)
|
||||
: "{rax}"(a), "{rdi}"(b), "{rsi}"(c), "{rdx}"(d), "{r10}"(e)
|
||||
: "rcx", "r11", "memory"
|
||||
: "intel", "volatile");
|
||||
|
||||
Error::demux(a)
|
||||
#[derive(Clone, Copy, Debug, Default)]
|
||||
#[repr(packed)]
|
||||
pub struct FloatRegisters {
|
||||
pub fcw: u16,
|
||||
pub fsw: u16,
|
||||
pub ftw: u8,
|
||||
pub _reserved: u8,
|
||||
pub fop: u16,
|
||||
pub fip: u64,
|
||||
pub fdp: u64,
|
||||
pub mxcsr: u32,
|
||||
pub mxcsr_mask: u32,
|
||||
pub st_space: [u128; 8],
|
||||
pub xmm_space: [u128; 16],
|
||||
// TODO: YMM/ZMM
|
||||
}
|
||||
|
||||
pub unsafe fn syscall5(mut a: usize, b: usize, c: usize, d: usize, e: usize, f: usize)
|
||||
-> Result<usize> {
|
||||
llvm_asm!("syscall"
|
||||
: "={rax}"(a)
|
||||
: "{rax}"(a), "{rdi}"(b), "{rsi}"(c), "{rdx}"(d), "{r10}"(e), "{r8}"(f)
|
||||
: "rcx", "r11", "memory"
|
||||
: "intel", "volatile");
|
||||
|
||||
Error::demux(a)
|
||||
impl Deref for FloatRegisters {
|
||||
type Target = [u8];
|
||||
fn deref(&self) -> &[u8] {
|
||||
unsafe {
|
||||
slice::from_raw_parts(self as *const FloatRegisters as *const u8, mem::size_of::<FloatRegisters>())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl DerefMut for FloatRegisters {
|
||||
fn deref_mut(&mut self) -> &mut [u8] {
|
||||
unsafe {
|
||||
slice::from_raw_parts_mut(self as *mut FloatRegisters as *mut u8, mem::size_of::<FloatRegisters>())
|
||||
}
|
||||
}
|
||||
}
|
||||
#[derive(Clone, Copy, Debug, Default)]
|
||||
#[repr(packed)]
|
||||
pub struct EnvRegisters {
|
||||
pub fsbase: u64,
|
||||
pub gsbase: u64,
|
||||
// TODO: PKRU?
|
||||
}
|
||||
impl Deref for EnvRegisters {
|
||||
type Target = [u8];
|
||||
fn deref(&self) -> &[u8] {
|
||||
unsafe {
|
||||
slice::from_raw_parts(self as *const EnvRegisters as *const u8, mem::size_of::<EnvRegisters>())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl DerefMut for EnvRegisters {
|
||||
fn deref_mut(&mut self) -> &mut [u8] {
|
||||
unsafe {
|
||||
slice::from_raw_parts_mut(self as *mut EnvRegisters as *mut u8, mem::size_of::<EnvRegisters>())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
use super::arch::*;
|
||||
use super::data::{Map, SigAction, Stat, StatVfs, TimeSpec};
|
||||
use super::error::Result;
|
||||
use super::flag::*;
|
||||
use super::number::*;
|
||||
|
||||
use core::{mem, ptr};
|
||||
|
@ -11,20 +12,6 @@ extern "C" fn restorer() -> ! {
|
|||
unreachable!();
|
||||
}
|
||||
|
||||
/// Set the end of the process's heap
|
||||
///
|
||||
/// When `addr` is `0`, this function will return the current break.
|
||||
///
|
||||
/// When `addr` is nonzero, this function will attempt to set the end of the process's
|
||||
/// heap to `addr` and return the new program break. The new program break should be
|
||||
/// checked by the allocator, it may not be exactly `addr`, as it may be aligned to a page
|
||||
/// boundary.
|
||||
///
|
||||
/// On error, `Err(ENOMEM)` will be returned indicating that no memory is available
|
||||
pub unsafe fn brk(addr: usize) -> Result<usize> {
|
||||
syscall1(SYS_BRK, addr)
|
||||
}
|
||||
|
||||
/// Change the process's working directory
|
||||
///
|
||||
/// This function will attempt to set the process's working directory to `path`, which can be
|
||||
|
@ -39,7 +26,7 @@ pub unsafe fn brk(addr: usize) -> Result<usize> {
|
|||
/// * `EIO` - an I/O error occurred
|
||||
/// * `ENOENT` - `path` does not exit
|
||||
/// * `ENOTDIR` - `path` is not a directory
|
||||
pub fn chdir<T: AsRef<[u8]>>(path: T) -> Result<usize> {
|
||||
pub fn chdir<T: AsRef<str>>(path: T) -> Result<usize> {
|
||||
unsafe { syscall2(SYS_CHDIR, path.as_ref().as_ptr() as usize, path.as_ref().len()) }
|
||||
}
|
||||
|
||||
|
@ -47,13 +34,13 @@ pub fn chdir<T: AsRef<[u8]>>(path: T) -> Result<usize> {
|
|||
since = "0.1.55",
|
||||
note = "use fchmod instead"
|
||||
)]
|
||||
pub fn chmod<T: AsRef<[u8]>>(path: T, mode: usize) -> Result<usize> {
|
||||
pub fn chmod<T: AsRef<str>>(path: T, mode: usize) -> Result<usize> {
|
||||
unsafe { syscall3(SYS_CHMOD, path.as_ref().as_ptr() as usize, path.as_ref().len(), mode) }
|
||||
}
|
||||
|
||||
/// Produce a fork of the current process, or a new process thread
|
||||
pub unsafe fn clone(flags: usize) -> Result<usize> {
|
||||
syscall1_clobber(SYS_CLONE, flags)
|
||||
pub unsafe fn clone(flags: CloneFlags) -> Result<usize> {
|
||||
syscall1(SYS_CLONE, flags.bits())
|
||||
}
|
||||
|
||||
/// Close a file
|
||||
|
@ -103,14 +90,23 @@ pub fn fexec(fd: usize, args: &[[usize; 2]], vars: &[[usize; 2]]) -> Result<usiz
|
|||
unsafe { syscall5(SYS_FEXEC, fd, args.as_ptr() as usize, args.len(), vars.as_ptr() as usize, vars.len()) }
|
||||
}
|
||||
|
||||
/// Map a file into memory
|
||||
/// Map a file into memory, but with the ability to set the address to map into, either as a hint
|
||||
/// or as a requirement of the map.
|
||||
///
|
||||
/// # Errors
|
||||
/// `EACCES` - the file descriptor was not open for reading
|
||||
/// `EBADF` - if the file descriptor was invalid
|
||||
/// `ENODEV` - mmapping was not supported
|
||||
/// `EINVAL` - invalid combination of flags
|
||||
/// `EEXIST` - if [`MapFlags::MAP_FIXED`] was set, and the address specified was already in use.
|
||||
///
|
||||
pub unsafe fn fmap(fd: usize, map: &Map) -> Result<usize> {
|
||||
syscall3(SYS_FMAP, fd, map as *const Map as usize, mem::size_of::<Map>())
|
||||
}
|
||||
|
||||
/// Unmap a memory-mapped file
|
||||
pub unsafe fn funmap(addr: usize) -> Result<usize> {
|
||||
syscall1(SYS_FUNMAP, addr)
|
||||
/// Unmap whole (or partial) continous memory-mapped files
|
||||
pub unsafe fn funmap(addr: usize, len: usize) -> Result<usize> {
|
||||
syscall2(SYS_FUNMAP, addr, len)
|
||||
}
|
||||
|
||||
/// Retrieve the canonical path of a file
|
||||
|
@ -119,7 +115,7 @@ pub fn fpath(fd: usize, buf: &mut [u8]) -> Result<usize> {
|
|||
}
|
||||
|
||||
/// Rename a file
|
||||
pub fn frename<T: AsRef<[u8]>>(fd: usize, path: T) -> Result<usize> {
|
||||
pub fn frename<T: AsRef<str>>(fd: usize, path: T) -> Result<usize> {
|
||||
unsafe { syscall3(SYS_FRENAME, fd, path.as_ref().as_ptr() as usize, path.as_ref().len()) }
|
||||
}
|
||||
|
||||
|
@ -235,8 +231,8 @@ pub fn mkns(schemes: &[[usize; 2]]) -> Result<usize> {
|
|||
}
|
||||
|
||||
/// Change mapping flags
|
||||
pub unsafe fn mprotect(addr: usize, size: usize, flags: usize) -> Result<usize> {
|
||||
syscall3(SYS_MPROTECT, addr, size, flags)
|
||||
pub unsafe fn mprotect(addr: usize, size: usize, flags: MapFlags) -> Result<usize> {
|
||||
syscall3(SYS_MPROTECT, addr, size, flags.bits())
|
||||
}
|
||||
|
||||
/// Sleep for the time specified in `req`
|
||||
|
@ -246,11 +242,11 @@ pub fn nanosleep(req: &TimeSpec, rem: &mut TimeSpec) -> Result<usize> {
|
|||
}
|
||||
|
||||
/// Open a file
|
||||
pub fn open<T: AsRef<[u8]>>(path: T, flags: usize) -> Result<usize> {
|
||||
pub fn open<T: AsRef<str>>(path: T, flags: usize) -> Result<usize> {
|
||||
unsafe { syscall3(SYS_OPEN, path.as_ref().as_ptr() as usize, path.as_ref().len(), flags) }
|
||||
}
|
||||
|
||||
/// Allocate pages, linearly in physical memory
|
||||
/// Allocate frames, linearly in physical memory.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
|
@ -260,6 +256,37 @@ pub unsafe fn physalloc(size: usize) -> Result<usize> {
|
|||
syscall1(SYS_PHYSALLOC, size)
|
||||
}
|
||||
|
||||
/// Allocate frames, linearly in physical memory, with an extra set of flags. If the flags contain
|
||||
/// [`PARTIAL_ALLOC`], this will result in `physalloc3` with `min = 1`.
|
||||
///
|
||||
/// Refer to the simpler [`physalloc`] and the more complex [`physalloc3`], that this convenience
|
||||
/// function is based on.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// * `EPERM` - `uid != 0`
|
||||
/// * `ENOMEM` - the system has run out of available memory
|
||||
pub unsafe fn physalloc2(size: usize, flags: usize) -> Result<usize> {
|
||||
let mut ret = 1usize;
|
||||
physalloc3(size, flags, &mut ret)
|
||||
}
|
||||
|
||||
/// Allocate frames, linearly in physical memory, with an extra set of flags. If the flags contain
|
||||
/// [`PARTIAL_ALLOC`], the `min` parameter specifies the number of frames that have to be allocated
|
||||
/// for this operation to succeed. The return value is the offset of the first frame, and `min` is
|
||||
/// overwritten with the number of frames actually allocated.
|
||||
///
|
||||
/// Refer to the simpler [`physalloc`] and the simpler library function [`physalloc2`].
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// * `EPERM` - `uid != 0`
|
||||
/// * `ENOMEM` - the system has run out of available memory
|
||||
/// * `EINVAL` - `min = 0`
|
||||
pub unsafe fn physalloc3(size: usize, flags: usize, min: &mut usize) -> Result<usize> {
|
||||
syscall3(SYS_PHYSALLOC3, size, flags, min as *mut usize as usize)
|
||||
}
|
||||
|
||||
/// Free physically allocated pages
|
||||
///
|
||||
/// # Errors
|
||||
|
@ -274,8 +301,8 @@ pub unsafe fn physfree(physical_address: usize, size: usize) -> Result<usize> {
|
|||
/// # Errors
|
||||
///
|
||||
/// * `EPERM` - `uid != 0`
|
||||
pub unsafe fn physmap(physical_address: usize, size: usize, flags: usize) -> Result<usize> {
|
||||
syscall3(SYS_PHYSMAP, physical_address, size, flags)
|
||||
pub unsafe fn physmap(physical_address: usize, size: usize, flags: PhysmapFlags) -> Result<usize> {
|
||||
syscall3(SYS_PHYSMAP, physical_address, size, flags.bits())
|
||||
}
|
||||
|
||||
/// Unmap previously mapped physical memory
|
||||
|
@ -299,7 +326,7 @@ pub fn read(fd: usize, buf: &mut [u8]) -> Result<usize> {
|
|||
}
|
||||
|
||||
/// Remove a directory
|
||||
pub fn rmdir<T: AsRef<[u8]>>(path: T) -> Result<usize> {
|
||||
pub fn rmdir<T: AsRef<str>>(path: T) -> Result<usize> {
|
||||
unsafe { syscall2(SYS_RMDIR, path.as_ref().as_ptr() as usize, path.as_ref().len()) }
|
||||
}
|
||||
|
||||
|
@ -349,7 +376,7 @@ pub fn umask(mask: usize) -> Result<usize> {
|
|||
}
|
||||
|
||||
/// Remove a file
|
||||
pub fn unlink<T: AsRef<[u8]>>(path: T) -> Result<usize> {
|
||||
pub fn unlink<T: AsRef<str>>(path: T) -> Result<usize> {
|
||||
unsafe { syscall2(SYS_UNLINK, path.as_ref().as_ptr() as usize, path.as_ref().len()) }
|
||||
}
|
||||
|
||||
|
@ -363,8 +390,8 @@ pub unsafe fn virttophys(virtual_address: usize) -> Result<usize> {
|
|||
}
|
||||
|
||||
/// Check if a child process has exited or received a signal
|
||||
pub fn waitpid(pid: usize, status: &mut usize, options: usize) -> Result<usize> {
|
||||
unsafe { syscall3(SYS_WAITPID, pid, status as *mut usize as usize, options) }
|
||||
pub fn waitpid(pid: usize, status: &mut usize, options: WaitFlags) -> Result<usize> {
|
||||
unsafe { syscall3(SYS_WAITPID, pid, status as *mut usize as usize, options.bits()) }
|
||||
}
|
||||
|
||||
/// Write a buffer to a file descriptor
|
||||
|
|
|
@ -0,0 +1,62 @@
|
|||
use core::convert::Infallible;
|
||||
|
||||
use super::{
|
||||
clone,
|
||||
CloneFlags,
|
||||
close,
|
||||
EIO,
|
||||
Error,
|
||||
exit,
|
||||
pipe2,
|
||||
read,
|
||||
Result,
|
||||
write,
|
||||
};
|
||||
|
||||
#[must_use = "Daemon::ready must be called"]
|
||||
pub struct Daemon {
|
||||
write_pipe: usize,
|
||||
}
|
||||
|
||||
impl Daemon {
|
||||
pub fn new<F: FnOnce(Daemon) -> Infallible>(f: F) -> Result<Infallible> {
|
||||
let mut pipes = [0; 2];
|
||||
pipe2(&mut pipes, 0)?;
|
||||
|
||||
let [read_pipe, write_pipe] = pipes;
|
||||
|
||||
if unsafe { clone(CloneFlags::empty())? } == 0 {
|
||||
let _ = close(read_pipe);
|
||||
|
||||
f(Daemon {
|
||||
write_pipe,
|
||||
});
|
||||
// TODO: Replace Infallible with the never type once it is stabilized.
|
||||
unreachable!();
|
||||
} else {
|
||||
let _ = close(write_pipe);
|
||||
|
||||
let mut data = [0];
|
||||
let res = read(read_pipe, &mut data);
|
||||
let _ = close(read_pipe);
|
||||
|
||||
if res? == 1 {
|
||||
exit(data[0] as usize)?;
|
||||
unreachable!();
|
||||
} else {
|
||||
Err(Error::new(EIO))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn ready(self) -> Result<()> {
|
||||
let res = write(self.write_pipe, &[0]);
|
||||
let _ = close(self.write_pipe);
|
||||
|
||||
if res? == 1 {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(Error::new(EIO))
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,11 +1,12 @@
|
|||
use core::ops::{Deref, DerefMut};
|
||||
use core::{mem, slice};
|
||||
use crate::flag::{EventFlags, MapFlags, PtraceFlags, SigActionFlags};
|
||||
|
||||
#[derive(Copy, Clone, Debug, Default)]
|
||||
#[repr(C)]
|
||||
pub struct Event {
|
||||
pub id: usize,
|
||||
pub flags: usize,
|
||||
pub flags: EventFlags,
|
||||
pub data: usize
|
||||
}
|
||||
|
||||
|
@ -13,7 +14,7 @@ impl Deref for Event {
|
|||
type Target = [u8];
|
||||
fn deref(&self) -> &[u8] {
|
||||
unsafe {
|
||||
slice::from_raw_parts(self as *const Event as *const u8, mem::size_of::<Event>()) as &[u8]
|
||||
slice::from_raw_parts(self as *const Event as *const u8, mem::size_of::<Event>())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -21,7 +22,7 @@ impl Deref for Event {
|
|||
impl DerefMut for Event {
|
||||
fn deref_mut(&mut self) -> &mut [u8] {
|
||||
unsafe {
|
||||
slice::from_raw_parts_mut(self as *mut Event as *mut u8, mem::size_of::<Event>()) as &mut [u8]
|
||||
slice::from_raw_parts_mut(self as *mut Event as *mut u8, mem::size_of::<Event>())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -38,7 +39,7 @@ impl Deref for ITimerSpec {
|
|||
fn deref(&self) -> &[u8] {
|
||||
unsafe {
|
||||
slice::from_raw_parts(self as *const ITimerSpec as *const u8,
|
||||
mem::size_of::<ITimerSpec>()) as &[u8]
|
||||
mem::size_of::<ITimerSpec>())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -47,24 +48,58 @@ impl DerefMut for ITimerSpec {
|
|||
fn deref_mut(&mut self) -> &mut [u8] {
|
||||
unsafe {
|
||||
slice::from_raw_parts_mut(self as *mut ITimerSpec as *mut u8,
|
||||
mem::size_of::<ITimerSpec>()) as &mut [u8]
|
||||
mem::size_of::<ITimerSpec>())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, Default)]
|
||||
#[repr(C)]
|
||||
pub struct Map {
|
||||
pub struct OldMap {
|
||||
pub offset: usize,
|
||||
pub size: usize,
|
||||
pub flags: usize,
|
||||
pub flags: MapFlags,
|
||||
}
|
||||
|
||||
impl Deref for OldMap {
|
||||
type Target = [u8];
|
||||
fn deref(&self) -> &[u8] {
|
||||
unsafe {
|
||||
slice::from_raw_parts(self as *const OldMap as *const u8, mem::size_of::<OldMap>())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl DerefMut for OldMap {
|
||||
fn deref_mut(&mut self) -> &mut [u8] {
|
||||
unsafe {
|
||||
slice::from_raw_parts_mut(self as *mut OldMap as *mut u8, mem::size_of::<OldMap>())
|
||||
}
|
||||
}
|
||||
}
|
||||
#[derive(Copy, Clone, Debug, Default)]
|
||||
#[repr(C)]
|
||||
pub struct Map {
|
||||
/// The offset inside the file that is being mapped.
|
||||
pub offset: usize,
|
||||
|
||||
/// The size of the memory map.
|
||||
pub size: usize,
|
||||
|
||||
/// Contains both prot and map flags.
|
||||
pub flags: MapFlags,
|
||||
|
||||
/// Functions as a hint to where in the virtual address space of the running process, to place
|
||||
/// the memory map. If [`MapFlags::MAP_FIXED`] is set, then this address must be the address to
|
||||
/// map to.
|
||||
pub address: usize,
|
||||
}
|
||||
|
||||
impl Deref for Map {
|
||||
type Target = [u8];
|
||||
fn deref(&self) -> &[u8] {
|
||||
unsafe {
|
||||
slice::from_raw_parts(self as *const Map as *const u8, mem::size_of::<Map>()) as &[u8]
|
||||
slice::from_raw_parts(self as *const Map as *const u8, mem::size_of::<Map>())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -72,7 +107,7 @@ impl Deref for Map {
|
|||
impl DerefMut for Map {
|
||||
fn deref_mut(&mut self) -> &mut [u8] {
|
||||
unsafe {
|
||||
slice::from_raw_parts_mut(self as *mut Map as *mut u8, mem::size_of::<Map>()) as &mut [u8]
|
||||
slice::from_raw_parts_mut(self as *mut Map as *mut u8, mem::size_of::<Map>())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -94,7 +129,7 @@ impl Deref for Packet {
|
|||
type Target = [u8];
|
||||
fn deref(&self) -> &[u8] {
|
||||
unsafe {
|
||||
slice::from_raw_parts(self as *const Packet as *const u8, mem::size_of::<Packet>()) as &[u8]
|
||||
slice::from_raw_parts(self as *const Packet as *const u8, mem::size_of::<Packet>())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -102,30 +137,29 @@ impl Deref for Packet {
|
|||
impl DerefMut for Packet {
|
||||
fn deref_mut(&mut self) -> &mut [u8] {
|
||||
unsafe {
|
||||
slice::from_raw_parts_mut(self as *mut Packet as *mut u8, mem::size_of::<Packet>()) as &mut [u8]
|
||||
slice::from_raw_parts_mut(self as *mut Packet as *mut u8, mem::size_of::<Packet>())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
#[derive(Copy, Clone, Debug, Default, PartialEq)]
|
||||
#[repr(C)]
|
||||
pub struct SigAction {
|
||||
pub sa_handler: extern "C" fn(usize),
|
||||
pub sa_handler: Option<extern "C" fn(usize)>,
|
||||
pub sa_mask: [u64; 2],
|
||||
pub sa_flags: usize,
|
||||
pub sa_flags: SigActionFlags,
|
||||
}
|
||||
|
||||
impl Default for SigAction {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
sa_handler: unsafe { mem::transmute(0usize) },
|
||||
sa_mask: [0; 2],
|
||||
sa_flags: 0,
|
||||
}
|
||||
}
|
||||
#[allow(dead_code)]
|
||||
unsafe fn _assert_size_of_function_is_sane() {
|
||||
// Transmuting will complain *at compile time* if sizes differ.
|
||||
// Rust forbids a fn-pointer from being 0 so to allow SIG_DFL to
|
||||
// exist, we use Option<extern "C" fn(usize)> which will mean 0
|
||||
// becomes None
|
||||
let _ = mem::transmute::<Option<extern "C" fn(usize)>, usize>(None);
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, Default)]
|
||||
#[derive(Copy, Clone, Debug, Default, PartialEq)]
|
||||
#[repr(C)]
|
||||
pub struct Stat {
|
||||
pub st_dev: u64,
|
||||
|
@ -150,7 +184,7 @@ impl Deref for Stat {
|
|||
fn deref(&self) -> &[u8] {
|
||||
unsafe {
|
||||
slice::from_raw_parts(self as *const Stat as *const u8,
|
||||
mem::size_of::<Stat>()) as &[u8]
|
||||
mem::size_of::<Stat>())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -159,12 +193,12 @@ impl DerefMut for Stat {
|
|||
fn deref_mut(&mut self) -> &mut [u8] {
|
||||
unsafe {
|
||||
slice::from_raw_parts_mut(self as *mut Stat as *mut u8,
|
||||
mem::size_of::<Stat>()) as &mut [u8]
|
||||
mem::size_of::<Stat>())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, Default)]
|
||||
#[derive(Copy, Clone, Debug, Default, PartialEq)]
|
||||
#[repr(C)]
|
||||
pub struct StatVfs {
|
||||
pub f_bsize: u32,
|
||||
|
@ -178,7 +212,7 @@ impl Deref for StatVfs {
|
|||
fn deref(&self) -> &[u8] {
|
||||
unsafe {
|
||||
slice::from_raw_parts(self as *const StatVfs as *const u8,
|
||||
mem::size_of::<StatVfs>()) as &[u8]
|
||||
mem::size_of::<StatVfs>())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -187,7 +221,7 @@ impl DerefMut for StatVfs {
|
|||
fn deref_mut(&mut self) -> &mut [u8] {
|
||||
unsafe {
|
||||
slice::from_raw_parts_mut(self as *mut StatVfs as *mut u8,
|
||||
mem::size_of::<StatVfs>()) as &mut [u8]
|
||||
mem::size_of::<StatVfs>())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -204,7 +238,7 @@ impl Deref for TimeSpec {
|
|||
fn deref(&self) -> &[u8] {
|
||||
unsafe {
|
||||
slice::from_raw_parts(self as *const TimeSpec as *const u8,
|
||||
mem::size_of::<TimeSpec>()) as &[u8]
|
||||
mem::size_of::<TimeSpec>())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -213,97 +247,51 @@ impl DerefMut for TimeSpec {
|
|||
fn deref_mut(&mut self) -> &mut [u8] {
|
||||
unsafe {
|
||||
slice::from_raw_parts_mut(self as *mut TimeSpec as *mut u8,
|
||||
mem::size_of::<TimeSpec>()) as &mut [u8]
|
||||
mem::size_of::<TimeSpec>())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, Default)]
|
||||
#[derive(Clone, Copy, Debug, Default)]
|
||||
#[repr(C)]
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
pub struct IntRegisters {
|
||||
pub r15: usize,
|
||||
pub r14: usize,
|
||||
pub r13: usize,
|
||||
pub r12: usize,
|
||||
pub rbp: usize,
|
||||
pub rbx: usize,
|
||||
pub r11: usize,
|
||||
pub r10: usize,
|
||||
pub r9: usize,
|
||||
pub r8: usize,
|
||||
pub rax: usize,
|
||||
pub rcx: usize,
|
||||
pub rdx: usize,
|
||||
pub rsi: usize,
|
||||
pub rdi: usize,
|
||||
// pub orig_rax: usize,
|
||||
pub rip: usize,
|
||||
pub cs: usize,
|
||||
pub eflags: usize,
|
||||
pub rsp: usize,
|
||||
pub ss: usize,
|
||||
pub fs_base: usize,
|
||||
pub gs_base: usize,
|
||||
pub ds: usize,
|
||||
pub es: usize,
|
||||
pub fs: usize,
|
||||
pub gs: usize
|
||||
pub struct PtraceEvent {
|
||||
pub cause: PtraceFlags,
|
||||
pub a: usize,
|
||||
pub b: usize,
|
||||
pub c: usize,
|
||||
pub d: usize,
|
||||
pub e: usize,
|
||||
pub f: usize
|
||||
}
|
||||
|
||||
impl Deref for IntRegisters {
|
||||
impl Deref for PtraceEvent {
|
||||
type Target = [u8];
|
||||
fn deref(&self) -> &[u8] {
|
||||
unsafe {
|
||||
slice::from_raw_parts(self as *const IntRegisters as *const u8, mem::size_of::<IntRegisters>()) as &[u8]
|
||||
slice::from_raw_parts(self as *const PtraceEvent as *const u8, mem::size_of::<PtraceEvent>())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl DerefMut for IntRegisters {
|
||||
impl DerefMut for PtraceEvent {
|
||||
fn deref_mut(&mut self) -> &mut [u8] {
|
||||
unsafe {
|
||||
slice::from_raw_parts_mut(self as *mut IntRegisters as *mut u8, mem::size_of::<IntRegisters>()) as &mut [u8]
|
||||
slice::from_raw_parts_mut(self as *mut PtraceEvent as *mut u8, mem::size_of::<PtraceEvent>())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
#[repr(C)]
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
pub struct FloatRegisters {
|
||||
pub cwd: u16,
|
||||
pub swd: u16,
|
||||
pub ftw: u16,
|
||||
pub fop: u16,
|
||||
pub rip: u64,
|
||||
pub rdp: u64,
|
||||
pub mxcsr: u32,
|
||||
pub mxcr_mask: u32,
|
||||
pub st_space: [u32; 32],
|
||||
pub xmm_space: [u32; 64]
|
||||
}
|
||||
|
||||
impl Default for FloatRegisters {
|
||||
fn default() -> Self {
|
||||
// xmm_space is not Default until const generics
|
||||
unsafe { mem::zeroed() }
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for FloatRegisters {
|
||||
type Target = [u8];
|
||||
fn deref(&self) -> &[u8] {
|
||||
unsafe {
|
||||
slice::from_raw_parts(self as *const FloatRegisters as *const u8, mem::size_of::<FloatRegisters>()) as &[u8]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl DerefMut for FloatRegisters {
|
||||
fn deref_mut(&mut self) -> &mut [u8] {
|
||||
unsafe {
|
||||
slice::from_raw_parts_mut(self as *mut FloatRegisters as *mut u8, mem::size_of::<FloatRegisters>()) as &mut [u8]
|
||||
#[macro_export]
|
||||
macro_rules! ptrace_event {
|
||||
($cause:expr $(, $a:expr $(, $b:expr $(, $c:expr)?)?)?) => {
|
||||
$crate::data::PtraceEvent {
|
||||
cause: $cause,
|
||||
$(a: $a,
|
||||
$(b: $b,
|
||||
$(c: $c,)?
|
||||
)?
|
||||
)?
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@ pub struct Error {
|
|||
pub errno: i32,
|
||||
}
|
||||
|
||||
pub type Result<T> = result::Result<T, Error>;
|
||||
pub type Result<T, E = Error> = result::Result<T, E>;
|
||||
|
||||
impl Error {
|
||||
pub fn new(errno: i32) -> Error {
|
||||
|
|
|
@ -1,17 +1,59 @@
|
|||
pub const CLONE_VM: usize = 0x100;
|
||||
pub const CLONE_FS: usize = 0x200;
|
||||
pub const CLONE_FILES: usize = 0x400;
|
||||
pub const CLONE_SIGHAND: usize = 0x800;
|
||||
pub const CLONE_VFORK: usize = 0x4000;
|
||||
pub const CLONE_THREAD: usize = 0x10000;
|
||||
pub const CLONE_STACK: usize = 0x1000_0000;
|
||||
use bitflags::bitflags as inner_bitflags;
|
||||
use core::{mem, ops::Deref, slice};
|
||||
|
||||
macro_rules! bitflags {
|
||||
(
|
||||
$(#[$outer:meta])*
|
||||
pub struct $BitFlags:ident: $T:ty {
|
||||
$(
|
||||
$(#[$inner:ident $($args:tt)*])*
|
||||
const $Flag:ident = $value:expr;
|
||||
)+
|
||||
}
|
||||
) => {
|
||||
// First, use the inner bitflags
|
||||
inner_bitflags! {
|
||||
#[derive(Default)]
|
||||
$(#[$outer])*
|
||||
pub struct $BitFlags: $T {
|
||||
$(
|
||||
$(#[$inner $($args)*])*
|
||||
const $Flag = $value;
|
||||
)+
|
||||
}
|
||||
}
|
||||
|
||||
// Secondly, re-export all inner constants
|
||||
// (`pub use self::Struct::*` doesn't work)
|
||||
$(
|
||||
$(#[$inner $($args)*])*
|
||||
pub const $Flag: $BitFlags = $BitFlags::$Flag;
|
||||
)+
|
||||
}
|
||||
}
|
||||
|
||||
bitflags! {
|
||||
pub struct CloneFlags: usize {
|
||||
const CLONE_VM = 0x100;
|
||||
const CLONE_FS = 0x200;
|
||||
const CLONE_FILES = 0x400;
|
||||
const CLONE_SIGHAND = 0x800;
|
||||
const CLONE_VFORK = 0x4000;
|
||||
const CLONE_THREAD = 0x10000;
|
||||
const CLONE_STACK = 0x1000_0000;
|
||||
}
|
||||
}
|
||||
|
||||
pub const CLOCK_REALTIME: usize = 1;
|
||||
pub const CLOCK_MONOTONIC: usize = 4;
|
||||
|
||||
pub const EVENT_NONE: usize = 0;
|
||||
pub const EVENT_READ: usize = 1;
|
||||
pub const EVENT_WRITE: usize = 2;
|
||||
bitflags! {
|
||||
pub struct EventFlags: usize {
|
||||
const EVENT_NONE = 0;
|
||||
const EVENT_READ = 1;
|
||||
const EVENT_WRITE = 2;
|
||||
}
|
||||
}
|
||||
|
||||
pub const F_DUPFD: usize = 0;
|
||||
pub const F_GETFD: usize = 1;
|
||||
|
@ -22,9 +64,23 @@ pub const F_SETFL: usize = 4;
|
|||
pub const FUTEX_WAIT: usize = 0;
|
||||
pub const FUTEX_WAKE: usize = 1;
|
||||
pub const FUTEX_REQUEUE: usize = 2;
|
||||
pub const FUTEX_WAIT64: usize = 3;
|
||||
|
||||
pub const MAP_SHARED: usize = 0x0001;
|
||||
pub const MAP_PRIVATE: usize = 0x0002;
|
||||
bitflags! {
|
||||
pub struct MapFlags: usize {
|
||||
const PROT_NONE = 0x0000_0000;
|
||||
const PROT_EXEC = 0x0001_0000;
|
||||
const PROT_WRITE = 0x0002_0000;
|
||||
const PROT_READ = 0x0004_0000;
|
||||
|
||||
const MAP_SHARED = 0x0001;
|
||||
const MAP_PRIVATE = 0x0002;
|
||||
|
||||
/// Only accepted for mmap2(2).
|
||||
const MAP_FIXED = 0x0004;
|
||||
const MAP_FIXED_NOREPLACE = 0x000C;
|
||||
}
|
||||
}
|
||||
|
||||
pub const MODE_TYPE: u16 = 0xF000;
|
||||
pub const MODE_DIR: u16 = 0x4000;
|
||||
|
@ -56,21 +112,129 @@ pub const O_SYMLINK: usize = 0x4000_0000;
|
|||
pub const O_NOFOLLOW: usize = 0x8000_0000;
|
||||
pub const O_ACCMODE: usize = O_RDONLY | O_WRONLY | O_RDWR;
|
||||
|
||||
pub const PHYSMAP_WRITE: usize = 0x0000_0001;
|
||||
pub const PHYSMAP_WRITE_COMBINE: usize = 0x0000_0002;
|
||||
pub const PHYSMAP_NO_CACHE: usize = 0x0000_0004;
|
||||
bitflags! {
|
||||
pub struct PhysmapFlags: usize {
|
||||
const PHYSMAP_WRITE = 0x0000_0001;
|
||||
const PHYSMAP_WRITE_COMBINE = 0x0000_0002;
|
||||
const PHYSMAP_NO_CACHE = 0x0000_0004;
|
||||
}
|
||||
}
|
||||
bitflags! {
|
||||
/// Extra flags for [`physalloc2`] or [`physalloc3`].
|
||||
///
|
||||
/// [`physalloc2`]: ../call/fn.physalloc2.html
|
||||
/// [`physalloc3`]: ../call/fn.physalloc3.html
|
||||
pub struct PhysallocFlags: usize {
|
||||
/// Only allocate memory within the 32-bit physical memory space. This is necessary for
|
||||
/// some devices may not support 64-bit memory.
|
||||
const SPACE_32 = 0x0000_0001;
|
||||
|
||||
pub const PROT_NONE: usize = 0x0000_0000;
|
||||
pub const PROT_EXEC: usize = 0x0001_0000;
|
||||
pub const PROT_WRITE: usize = 0x0002_0000;
|
||||
pub const PROT_READ: usize = 0x0004_0000;
|
||||
/// The frame that will be allocated, is going to reside anywhere in 64-bit space. This
|
||||
/// flag is redundant for the most part, except when overriding some other default.
|
||||
const SPACE_64 = 0x0000_0002;
|
||||
|
||||
pub const PTRACE_CONT: u8 = 0b0000_0001;
|
||||
pub const PTRACE_SINGLESTEP: u8 = 0b0000_0010;
|
||||
pub const PTRACE_SYSCALL: u8 = 0b0000_0011;
|
||||
pub const PTRACE_WAIT: u8 = 0b0000_0100;
|
||||
pub const PTRACE_OPERATIONMASK: u8 = 0b0000_1111;
|
||||
pub const PTRACE_SYSEMU: u8 = 0b0001_0000;
|
||||
/// Do a "partial allocation", which means that not all of the frames specified in the
|
||||
/// frame count `size` actually have to be allocated. This means that if the allocator was
|
||||
/// unable to find a physical memory range large enough, it can instead return whatever
|
||||
/// range it decides is optimal. Thus, instead of letting one driver get an expensive
|
||||
/// 128MiB physical memory range when the physical memory has become fragmented, and
|
||||
/// failing, it can instead be given a more optimal range. If the device supports
|
||||
/// scatter-gather lists, then the driver only has to allocate more ranges, and the device
|
||||
/// will do vectored I/O.
|
||||
///
|
||||
/// PARTIAL_ALLOC supports different allocation strategies, refer to
|
||||
/// [`Optimal`], [`GreatestRange`].
|
||||
///
|
||||
/// [`Optimal`]: ./enum.PartialAllocStrategy.html
|
||||
/// [`GreatestRange`]: ./enum.PartialAllocStrategy.html
|
||||
const PARTIAL_ALLOC = 0x0000_0004;
|
||||
}
|
||||
}
|
||||
|
||||
/// The bitmask of the partial allocation strategy. Currently four different strategies are
|
||||
/// supported. If [`PARTIAL_ALLOC`] is not set, this bitmask is no longer reserved.
|
||||
pub const PARTIAL_ALLOC_STRATEGY_MASK: usize = 0x0003_0000;
|
||||
|
||||
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
|
||||
#[repr(usize)]
|
||||
pub enum PartialAllocStrategy {
|
||||
/// The allocator decides itself the size of the memory range, based on e.g. free memory ranges
|
||||
/// and other processes which require large physical memory chunks.
|
||||
Optimal = 0x0001_0000,
|
||||
|
||||
/// The allocator returns the absolute greatest range it can find.
|
||||
GreatestRange = 0x0002_0000,
|
||||
|
||||
/// The allocator returns the first range that fits the minimum count, without searching extra.
|
||||
Greedy = 0x0003_0000,
|
||||
}
|
||||
impl Default for PartialAllocStrategy {
|
||||
fn default() -> Self {
|
||||
Self::Optimal
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialAllocStrategy {
|
||||
pub fn from_raw(raw: usize) -> Option<Self> {
|
||||
match raw {
|
||||
0x0001_0000 => Some(Self::Optimal),
|
||||
0x0002_0000 => Some(Self::GreatestRange),
|
||||
0x0003_0000 => Some(Self::Greedy),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// The top 48 bits of PTRACE_* are reserved, for now
|
||||
|
||||
bitflags! {
|
||||
pub struct PtraceFlags: u64 {
|
||||
/// Stop before a syscall is handled. Send PTRACE_FLAG_IGNORE to not
|
||||
/// handle the syscall.
|
||||
const PTRACE_STOP_PRE_SYSCALL = 0x0000_0000_0000_0001;
|
||||
/// Stop after a syscall is handled.
|
||||
const PTRACE_STOP_POST_SYSCALL = 0x0000_0000_0000_0002;
|
||||
/// Stop after exactly one instruction. TODO: This may not handle
|
||||
/// fexec/signal boundaries. Should it?
|
||||
const PTRACE_STOP_SINGLESTEP = 0x0000_0000_0000_0004;
|
||||
/// Stop before a signal is handled. Send PTRACE_FLAG_IGNORE to not
|
||||
/// handle signal.
|
||||
const PTRACE_STOP_SIGNAL = 0x0000_0000_0000_0008;
|
||||
/// Stop on a software breakpoint, such as the int3 instruction for
|
||||
/// x86_64.
|
||||
const PTRACE_STOP_BREAKPOINT = 0x0000_0000_0000_0010;
|
||||
/// Stop just before exiting for good.
|
||||
const PTRACE_STOP_EXIT = 0x0000_0000_0000_0020;
|
||||
|
||||
const PTRACE_STOP_MASK = 0x0000_0000_0000_00FF;
|
||||
|
||||
|
||||
/// Sent when a child is cloned, giving you the opportunity to trace it.
|
||||
/// If you don't catch this, the child is started as normal.
|
||||
const PTRACE_EVENT_CLONE = 0x0000_0000_0000_0100;
|
||||
|
||||
const PTRACE_EVENT_MASK = 0x0000_0000_0000_0F00;
|
||||
|
||||
|
||||
/// Special meaning, depending on the event. Usually, when fired before
|
||||
/// an action, it will skip performing that action.
|
||||
const PTRACE_FLAG_IGNORE = 0x0000_0000_0000_1000;
|
||||
|
||||
const PTRACE_FLAG_MASK = 0x0000_0000_0000_F000;
|
||||
}
|
||||
}
|
||||
impl Deref for PtraceFlags {
|
||||
type Target = [u8];
|
||||
fn deref(&self) -> &Self::Target {
|
||||
// Same as to_ne_bytes but in-place
|
||||
unsafe {
|
||||
slice::from_raw_parts(
|
||||
&self.bits as *const _ as *const u8,
|
||||
mem::size_of::<u64>()
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub const SEEK_SET: usize = 0;
|
||||
pub const SEEK_CUR: usize = 1;
|
||||
|
@ -115,18 +279,33 @@ pub const SIG_BLOCK: usize = 0;
|
|||
pub const SIG_UNBLOCK: usize = 1;
|
||||
pub const SIG_SETMASK: usize = 2;
|
||||
|
||||
pub const SA_NOCLDSTOP: usize = 0x00000001;
|
||||
pub const SA_NOCLDWAIT: usize = 0x00000002;
|
||||
pub const SA_SIGINFO: usize = 0x00000004;
|
||||
pub const SA_RESTORER: usize = 0x04000000;
|
||||
pub const SA_ONSTACK: usize = 0x08000000;
|
||||
pub const SA_RESTART: usize = 0x10000000;
|
||||
pub const SA_NODEFER: usize = 0x40000000;
|
||||
pub const SA_RESETHAND: usize = 0x80000000;
|
||||
bitflags! {
|
||||
pub struct SigActionFlags: usize {
|
||||
const SA_NOCLDSTOP = 0x00000001;
|
||||
const SA_NOCLDWAIT = 0x00000002;
|
||||
const SA_SIGINFO = 0x00000004;
|
||||
const SA_RESTORER = 0x04000000;
|
||||
const SA_ONSTACK = 0x08000000;
|
||||
const SA_RESTART = 0x10000000;
|
||||
const SA_NODEFER = 0x40000000;
|
||||
const SA_RESETHAND = 0x80000000;
|
||||
}
|
||||
}
|
||||
|
||||
pub const WNOHANG: usize = 0x01;
|
||||
pub const WUNTRACED: usize = 0x02;
|
||||
pub const WCONTINUED: usize = 0x08;
|
||||
// Auxiliery vector types
|
||||
pub const AT_NULL: usize = 0;
|
||||
pub const AT_PHDR: usize = 3;
|
||||
pub const AT_PHENT: usize = 4;
|
||||
pub const AT_PHNUM: usize = 5;
|
||||
pub const AT_ENTRY: usize = 9;
|
||||
|
||||
bitflags! {
|
||||
pub struct WaitFlags: usize {
|
||||
const WNOHANG = 0x01;
|
||||
const WUNTRACED = 0x02;
|
||||
const WCONTINUED = 0x08;
|
||||
}
|
||||
}
|
||||
|
||||
/// True if status indicates the child is stopped.
|
||||
pub fn wifstopped(status: usize) -> bool {
|
||||
|
|
|
@ -1,76 +1,200 @@
|
|||
use core::{mem, ptr};
|
||||
use core::mem::{self, MaybeUninit};
|
||||
use core::ops::{Deref, DerefMut};
|
||||
use core::{ptr, slice};
|
||||
|
||||
use Result;
|
||||
use crate::Result;
|
||||
use crate::{PartialAllocStrategy, PhysallocFlags};
|
||||
|
||||
struct PhysBox {
|
||||
/// An RAII guard of a physical memory allocation. Currently all physically allocated memory are
|
||||
/// page-aligned and take up at least 4k of space (on x86_64).
|
||||
#[derive(Debug)]
|
||||
pub struct PhysBox {
|
||||
address: usize,
|
||||
size: usize
|
||||
}
|
||||
|
||||
impl PhysBox {
|
||||
fn new(size: usize) -> Result<PhysBox> {
|
||||
let address = unsafe { ::physalloc(size)? };
|
||||
Ok(PhysBox {
|
||||
address: address,
|
||||
size: size
|
||||
/// Construct a PhysBox from an address and a size.
|
||||
///
|
||||
/// # Safety
|
||||
/// This function is unsafe because when dropping, Self has to a valid allocation.
|
||||
pub unsafe fn from_raw_parts(address: usize, size: usize) -> Self {
|
||||
Self {
|
||||
address,
|
||||
size,
|
||||
}
|
||||
}
|
||||
|
||||
/// Retrieve the byte address in physical memory, of this allocation.
|
||||
pub fn address(&self) -> usize {
|
||||
self.address
|
||||
}
|
||||
|
||||
/// Retrieve the size in bytes of the alloc.
|
||||
pub fn size(&self) -> usize {
|
||||
self.size
|
||||
}
|
||||
|
||||
/// Allocate physical memory that must reside in 32-bit space.
|
||||
pub fn new_in_32bit_space(size: usize) -> Result<Self> {
|
||||
Self::new_with_flags(size, PhysallocFlags::SPACE_32)
|
||||
}
|
||||
|
||||
pub fn new_with_flags(size: usize, flags: PhysallocFlags) -> Result<Self> {
|
||||
assert!(!flags.contains(PhysallocFlags::PARTIAL_ALLOC));
|
||||
|
||||
let address = unsafe { crate::physalloc2(size, flags.bits())? };
|
||||
Ok(Self {
|
||||
address,
|
||||
size,
|
||||
})
|
||||
}
|
||||
|
||||
/// "Partially" allocate physical memory, in the sense that the allocation may be smaller than
|
||||
/// expected, but still with a minimum limit. This is particularly useful when the physical
|
||||
/// memory space is fragmented, and a device supports scatter-gather I/O. In that case, the
|
||||
/// driver can optimistically request e.g. 1 alloc of 1 MiB, with the minimum of 512 KiB. If
|
||||
/// that first allocation only returns half the size, the driver can do another allocation
|
||||
/// and then let the device use both buffers.
|
||||
pub fn new_partial_allocation(size: usize, flags: PhysallocFlags, strategy: Option<PartialAllocStrategy>, mut min: usize) -> Result<Self> {
|
||||
debug_assert!(!(flags.contains(PhysallocFlags::PARTIAL_ALLOC) && strategy.is_none()));
|
||||
|
||||
let address = unsafe { crate::physalloc3(size, flags.bits() | strategy.map(|s| s as usize).unwrap_or(0), &mut min)? };
|
||||
Ok(Self {
|
||||
address,
|
||||
size: min,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn new(size: usize) -> Result<Self> {
|
||||
let address = unsafe { crate::physalloc(size)? };
|
||||
Ok(Self {
|
||||
address,
|
||||
size,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for PhysBox {
|
||||
fn drop(&mut self) {
|
||||
let _ = unsafe { ::physfree(self.address, self.size) };
|
||||
let _ = unsafe { crate::physfree(self.address, self.size) };
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Dma<T> {
|
||||
pub struct Dma<T: ?Sized> {
|
||||
phys: PhysBox,
|
||||
virt: *mut T
|
||||
virt: *mut T,
|
||||
}
|
||||
|
||||
impl<T> Dma<T> {
|
||||
pub fn new(value: T) -> Result<Dma<T>> {
|
||||
let phys = PhysBox::new(mem::size_of::<T>())?;
|
||||
let virt = unsafe { ::physmap(phys.address, phys.size, ::PHYSMAP_WRITE)? } as *mut T;
|
||||
unsafe { ptr::write(virt, value); }
|
||||
pub fn from_physbox_uninit(phys: PhysBox) -> Result<Dma<MaybeUninit<T>>> {
|
||||
let virt = unsafe { crate::physmap(phys.address, phys.size, crate::PHYSMAP_WRITE)? } as *mut MaybeUninit<T>;
|
||||
|
||||
Ok(Dma {
|
||||
phys: phys,
|
||||
virt: virt
|
||||
phys,
|
||||
virt,
|
||||
})
|
||||
}
|
||||
pub fn from_physbox_zeroed(phys: PhysBox) -> Result<Dma<MaybeUninit<T>>> {
|
||||
let this = Self::from_physbox_uninit(phys)?;
|
||||
unsafe { ptr::write_bytes(this.virt as *mut MaybeUninit<u8>, 0, this.phys.size) }
|
||||
Ok(this)
|
||||
}
|
||||
|
||||
pub fn from_physbox(phys: PhysBox, value: T) -> Result<Self> {
|
||||
let this = Self::from_physbox_uninit(phys)?;
|
||||
|
||||
Ok(unsafe {
|
||||
ptr::write(this.virt, MaybeUninit::new(value));
|
||||
this.assume_init()
|
||||
})
|
||||
}
|
||||
|
||||
pub fn zeroed() -> Result<Dma<T>> {
|
||||
pub fn new(value: T) -> Result<Self> {
|
||||
let phys = PhysBox::new(mem::size_of::<T>())?;
|
||||
let virt = unsafe { ::physmap(phys.address, phys.size, ::PHYSMAP_WRITE)? } as *mut T;
|
||||
unsafe { ptr::write_bytes(virt as *mut u8, 0, phys.size); }
|
||||
Ok(Dma {
|
||||
phys: phys,
|
||||
virt: virt
|
||||
})
|
||||
Self::from_physbox(phys, value)
|
||||
}
|
||||
|
||||
pub fn physical(&self) -> usize {
|
||||
self.phys.address
|
||||
pub fn zeroed() -> Result<Dma<MaybeUninit<T>>> {
|
||||
let phys = PhysBox::new(mem::size_of::<T>())?;
|
||||
Self::from_physbox_zeroed(phys)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Deref for Dma<T> {
|
||||
impl<T> Dma<MaybeUninit<T>> {
|
||||
pub unsafe fn assume_init(self) -> Dma<T> {
|
||||
let &Dma { phys: PhysBox { address, size }, virt } = &self;
|
||||
mem::forget(self);
|
||||
|
||||
Dma {
|
||||
phys: PhysBox { address, size },
|
||||
virt: virt as *mut T,
|
||||
}
|
||||
}
|
||||
}
|
||||
impl<T: ?Sized> Dma<T> {
|
||||
pub fn physical(&self) -> usize {
|
||||
self.phys.address()
|
||||
}
|
||||
pub fn size(&self) -> usize {
|
||||
self.phys.size()
|
||||
}
|
||||
pub fn phys(&self) -> &PhysBox {
|
||||
&self.phys
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Dma<[T]> {
|
||||
pub fn from_physbox_uninit_unsized(phys: PhysBox, len: usize) -> Result<Dma<[MaybeUninit<T>]>> {
|
||||
let max_len = phys.size() / mem::size_of::<T>();
|
||||
assert!(len <= max_len);
|
||||
|
||||
Ok(Dma {
|
||||
virt: unsafe { slice::from_raw_parts_mut(crate::physmap(phys.address, phys.size, crate::PHYSMAP_WRITE)? as *mut MaybeUninit<T>, len) } as *mut [MaybeUninit<T>],
|
||||
phys,
|
||||
})
|
||||
}
|
||||
pub fn from_physbox_zeroed_unsized(phys: PhysBox, len: usize) -> Result<Dma<[MaybeUninit<T>]>> {
|
||||
let this = Self::from_physbox_uninit_unsized(phys, len)?;
|
||||
unsafe { ptr::write_bytes(this.virt as *mut MaybeUninit<u8>, 0, this.phys.size()) }
|
||||
Ok(this)
|
||||
}
|
||||
/// Creates a new DMA buffer with a size only known at runtime.
|
||||
/// ## Safety
|
||||
/// * `T` must be properly aligned.
|
||||
/// * `T` must be valid as zeroed (i.e. no NonNull pointers).
|
||||
pub unsafe fn zeroed_unsized(count: usize) -> Result<Self> {
|
||||
let phys = PhysBox::new(mem::size_of::<T>() * count)?;
|
||||
Ok(Self::from_physbox_zeroed_unsized(phys, count)?.assume_init())
|
||||
}
|
||||
}
|
||||
impl<T> Dma<[MaybeUninit<T>]> {
|
||||
pub unsafe fn assume_init(self) -> Dma<[T]> {
|
||||
let &Dma { phys: PhysBox { address, size }, virt } = &self;
|
||||
mem::forget(self);
|
||||
|
||||
Dma {
|
||||
phys: PhysBox { address, size },
|
||||
virt: virt as *mut [T],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ?Sized> Deref for Dma<T> {
|
||||
type Target = T;
|
||||
fn deref(&self) -> &T {
|
||||
unsafe { &*self.virt }
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> DerefMut for Dma<T> {
|
||||
impl<T: ?Sized> DerefMut for Dma<T> {
|
||||
fn deref_mut(&mut self) -> &mut T {
|
||||
unsafe { &mut *self.virt }
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Drop for Dma<T> {
|
||||
impl<T: ?Sized> Drop for Dma<T> {
|
||||
fn drop(&mut self) {
|
||||
unsafe { drop(ptr::read(self.virt)); }
|
||||
let _ = unsafe { ::physunmap(self.virt as usize) };
|
||||
unsafe { ptr::drop_in_place(self.virt) }
|
||||
let _ = unsafe { crate::physunmap(self.virt as *mut u8 as usize) };
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,17 +22,19 @@ pub trait Io {
|
|||
}
|
||||
}
|
||||
|
||||
pub struct ReadOnly<I: Io> {
|
||||
pub struct ReadOnly<I> {
|
||||
inner: I
|
||||
}
|
||||
|
||||
impl<I: Io> ReadOnly<I> {
|
||||
impl<I> ReadOnly<I> {
|
||||
pub const fn new(inner: I) -> ReadOnly<I> {
|
||||
ReadOnly {
|
||||
inner: inner
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<I: Io> ReadOnly<I> {
|
||||
#[inline(always)]
|
||||
pub fn read(&self) -> I::Value {
|
||||
self.inner.read()
|
||||
|
@ -44,17 +46,19 @@ impl<I: Io> ReadOnly<I> {
|
|||
}
|
||||
}
|
||||
|
||||
pub struct WriteOnly<I: Io> {
|
||||
pub struct WriteOnly<I> {
|
||||
inner: I
|
||||
}
|
||||
|
||||
impl<I: Io> WriteOnly<I> {
|
||||
impl<I> WriteOnly<I> {
|
||||
pub const fn new(inner: I) -> WriteOnly<I> {
|
||||
WriteOnly {
|
||||
inner: inner
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<I: Io> WriteOnly<I> {
|
||||
#[inline(always)]
|
||||
pub fn write(&mut self, value: I::Value) {
|
||||
self.inner.write(value)
|
||||
|
|
|
@ -1,19 +1,33 @@
|
|||
use core::ptr::{read_volatile, write_volatile};
|
||||
use core::mem::uninitialized;
|
||||
use core::ptr::{read_volatile, write_volatile, addr_of, addr_of_mut};
|
||||
use core::mem::MaybeUninit;
|
||||
use core::ops::{BitAnd, BitOr, Not};
|
||||
|
||||
use super::io::Io;
|
||||
|
||||
#[repr(packed)]
|
||||
pub struct Mmio<T> {
|
||||
value: T,
|
||||
value: MaybeUninit<T>,
|
||||
}
|
||||
|
||||
impl<T> Mmio<T> {
|
||||
/// Create a new Mmio without initializing
|
||||
#[deprecated = "unsound because it's possible to read even though it's uninitialized"]
|
||||
pub fn new() -> Self {
|
||||
Mmio {
|
||||
value: unsafe { uninitialized() }
|
||||
unsafe { Self::uninit() }
|
||||
}
|
||||
pub unsafe fn zeroed() -> Self {
|
||||
Self {
|
||||
value: MaybeUninit::zeroed(),
|
||||
}
|
||||
}
|
||||
pub unsafe fn uninit() -> Self {
|
||||
Self {
|
||||
value: MaybeUninit::uninit(),
|
||||
}
|
||||
}
|
||||
pub const fn from(value: T) -> Self {
|
||||
Self {
|
||||
value: MaybeUninit::new(value),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -22,10 +36,10 @@ impl<T> Io for Mmio<T> where T: Copy + PartialEq + BitAnd<Output = T> + BitOr<Ou
|
|||
type Value = T;
|
||||
|
||||
fn read(&self) -> T {
|
||||
unsafe { read_volatile(&self.value) }
|
||||
unsafe { read_volatile(addr_of!(self.value).cast::<T>()) }
|
||||
}
|
||||
|
||||
fn write(&mut self, value: T) {
|
||||
unsafe { write_volatile(&mut self.value, value) };
|
||||
unsafe { write_volatile(addr_of_mut!(self.value).cast::<T>(), value) };
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,9 +3,13 @@
|
|||
pub use self::dma::*;
|
||||
pub use self::io::*;
|
||||
pub use self::mmio::*;
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
pub use self::pio::*;
|
||||
|
||||
mod dma;
|
||||
mod io;
|
||||
mod mmio;
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
mod pio;
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
use core::arch::asm;
|
||||
use core::marker::PhantomData;
|
||||
|
||||
use super::io::Io;
|
||||
|
@ -13,7 +14,7 @@ impl<T> Pio<T> {
|
|||
/// Create a PIO from a given port
|
||||
pub const fn new(port: u16) -> Self {
|
||||
Pio::<T> {
|
||||
port: port,
|
||||
port,
|
||||
value: PhantomData,
|
||||
}
|
||||
}
|
||||
|
@ -28,7 +29,7 @@ impl Io for Pio<u8> {
|
|||
fn read(&self) -> u8 {
|
||||
let value: u8;
|
||||
unsafe {
|
||||
llvm_asm!("in $0, $1" : "={al}"(value) : "{dx}"(self.port) : "memory" : "intel", "volatile");
|
||||
asm!("in al, dx", in("dx") self.port, out("al") value, options(nostack, nomem, preserves_flags));
|
||||
}
|
||||
value
|
||||
}
|
||||
|
@ -37,7 +38,7 @@ impl Io for Pio<u8> {
|
|||
#[inline(always)]
|
||||
fn write(&mut self, value: u8) {
|
||||
unsafe {
|
||||
llvm_asm!("out $1, $0" : : "{al}"(value), "{dx}"(self.port) : "memory" : "intel", "volatile");
|
||||
asm!("out dx, al", in("dx") self.port, in("al") value, options(nostack, nomem, preserves_flags));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -51,7 +52,7 @@ impl Io for Pio<u16> {
|
|||
fn read(&self) -> u16 {
|
||||
let value: u16;
|
||||
unsafe {
|
||||
llvm_asm!("in $0, $1" : "={ax}"(value) : "{dx}"(self.port) : "memory" : "intel", "volatile");
|
||||
asm!("in ax, dx", in("dx") self.port, out("ax") value, options(nostack, nomem, preserves_flags));
|
||||
}
|
||||
value
|
||||
}
|
||||
|
@ -60,7 +61,7 @@ impl Io for Pio<u16> {
|
|||
#[inline(always)]
|
||||
fn write(&mut self, value: u16) {
|
||||
unsafe {
|
||||
llvm_asm!("out $1, $0" : : "{ax}"(value), "{dx}"(self.port) : "memory" : "intel", "volatile");
|
||||
asm!("out dx, ax", in("dx") self.port, in("ax") value, options(nostack, nomem, preserves_flags));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -74,7 +75,7 @@ impl Io for Pio<u32> {
|
|||
fn read(&self) -> u32 {
|
||||
let value: u32;
|
||||
unsafe {
|
||||
llvm_asm!("in $0, $1" : "={eax}"(value) : "{dx}"(self.port) : "memory" : "intel", "volatile");
|
||||
asm!("in eax, dx", in("dx") self.port, out("eax") value, options(nostack, nomem, preserves_flags));
|
||||
}
|
||||
value
|
||||
}
|
||||
|
@ -83,7 +84,7 @@ impl Io for Pio<u32> {
|
|||
#[inline(always)]
|
||||
fn write(&mut self, value: u32) {
|
||||
unsafe {
|
||||
llvm_asm!("out $1, $0" : : "{eax}"(value), "{dx}"(self.port) : "memory" : "intel", "volatile");
|
||||
asm!("out dx, eax", in("dx") self.port, in("eax") value, options(nostack, nomem, preserves_flags));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
#![feature(llvm_asm)]
|
||||
#![feature(const_fn)]
|
||||
#![cfg_attr(not(test), no_std)]
|
||||
|
||||
#[cfg(test)]
|
||||
|
@ -7,6 +5,7 @@ extern crate core;
|
|||
|
||||
pub use self::arch::*;
|
||||
pub use self::call::*;
|
||||
pub use self::daemon::*;
|
||||
pub use self::data::*;
|
||||
pub use self::error::*;
|
||||
pub use self::flag::*;
|
||||
|
@ -14,23 +13,27 @@ pub use self::io::*;
|
|||
pub use self::number::*;
|
||||
pub use self::scheme::*;
|
||||
|
||||
#[cfg(all(target_os = "redox", target_arch = "arm"))]
|
||||
#[path="arch/arm.rs"]
|
||||
#[cfg(all(any(target_os = "none", target_os = "redox"), target_arch = "arm"))]
|
||||
#[path="arch/nonredox.rs"]
|
||||
mod arch;
|
||||
|
||||
#[cfg(all(target_os = "redox", target_arch = "aarch64"))]
|
||||
#[cfg(all(any(target_os = "none", target_os = "redox"), target_arch = "aarch64"))]
|
||||
#[path="arch/aarch64.rs"]
|
||||
mod arch;
|
||||
|
||||
#[cfg(all(target_os = "redox", target_arch = "x86"))]
|
||||
#[path="arch/x86.rs"]
|
||||
#[cfg(all(any(target_os = "none", target_os = "redox"), target_arch = "riscv64"))]
|
||||
#[path="arch/riscv64.rs"]
|
||||
mod arch;
|
||||
|
||||
#[cfg(all(target_os = "redox", target_arch = "x86_64"))]
|
||||
#[cfg(all(any(target_os = "none", target_os = "redox"), target_arch = "x86"))]
|
||||
#[path="arch/nonredox.rs"]
|
||||
mod arch;
|
||||
|
||||
#[cfg(all(any(target_os = "none", target_os = "redox"), target_arch = "x86_64"))]
|
||||
#[path="arch/x86_64.rs"]
|
||||
mod arch;
|
||||
|
||||
#[cfg(not(target_os = "redox"))]
|
||||
#[cfg(not(any(target_os = "none", target_os = "redox")))]
|
||||
#[path="arch/nonredox.rs"]
|
||||
mod arch;
|
||||
|
||||
|
@ -40,6 +43,9 @@ pub mod call;
|
|||
/// Complex structures that are used for some system calls
|
||||
pub mod data;
|
||||
|
||||
/// Wrapper to make daemons easier to write
|
||||
pub mod daemon;
|
||||
|
||||
/// All errors that can be generated by a system call
|
||||
pub mod error;
|
||||
|
||||
|
|
|
@ -16,28 +16,29 @@ pub const SYS_CHMOD: usize = SYS_CLASS_PATH | 15;
|
|||
pub const SYS_RMDIR: usize = SYS_CLASS_PATH | 84;
|
||||
pub const SYS_UNLINK: usize = SYS_CLASS_PATH | 10;
|
||||
|
||||
pub const SYS_CLOSE: usize = SYS_CLASS_FILE | 6;
|
||||
pub const SYS_DUP: usize = SYS_CLASS_FILE | SYS_RET_FILE | 41;
|
||||
pub const SYS_DUP2: usize = SYS_CLASS_FILE | SYS_RET_FILE | 63;
|
||||
pub const SYS_READ: usize = SYS_CLASS_FILE | SYS_ARG_MSLICE | 3;
|
||||
pub const SYS_WRITE: usize = SYS_CLASS_FILE | SYS_ARG_SLICE | 4;
|
||||
pub const SYS_LSEEK: usize = SYS_CLASS_FILE | 19;
|
||||
pub const SYS_FCHMOD: usize = SYS_CLASS_FILE | 94;
|
||||
pub const SYS_FCHOWN: usize = SYS_CLASS_FILE | 207;
|
||||
pub const SYS_FCNTL: usize = SYS_CLASS_FILE | 55;
|
||||
pub const SYS_FEVENT: usize = SYS_CLASS_FILE | 927;
|
||||
pub const SYS_FEXEC: usize = SYS_CLASS_FILE | 11;
|
||||
pub const SYS_FMAP: usize = SYS_CLASS_FILE | SYS_ARG_SLICE | 90;
|
||||
pub const SYS_FUNMAP: usize = SYS_CLASS_FILE | 91;
|
||||
pub const SYS_FPATH: usize = SYS_CLASS_FILE | SYS_ARG_MSLICE | 928;
|
||||
pub const SYS_FRENAME: usize = SYS_CLASS_FILE | SYS_ARG_PATH | 38;
|
||||
pub const SYS_FSTAT: usize = SYS_CLASS_FILE | SYS_ARG_MSLICE | 28;
|
||||
pub const SYS_FSTATVFS: usize = SYS_CLASS_FILE | SYS_ARG_MSLICE | 100;
|
||||
pub const SYS_FSYNC: usize = SYS_CLASS_FILE | 118;
|
||||
pub const SYS_FTRUNCATE: usize =SYS_CLASS_FILE | 93;
|
||||
pub const SYS_FUTIMENS: usize = SYS_CLASS_FILE | SYS_ARG_SLICE | 320;
|
||||
pub const SYS_CLOSE: usize = SYS_CLASS_FILE | 6;
|
||||
pub const SYS_DUP: usize = SYS_CLASS_FILE | SYS_RET_FILE | 41;
|
||||
pub const SYS_DUP2: usize = SYS_CLASS_FILE | SYS_RET_FILE | 63;
|
||||
pub const SYS_READ: usize = SYS_CLASS_FILE | SYS_ARG_MSLICE | 3;
|
||||
pub const SYS_WRITE: usize = SYS_CLASS_FILE | SYS_ARG_SLICE | 4;
|
||||
pub const SYS_LSEEK: usize = SYS_CLASS_FILE | 19;
|
||||
pub const SYS_FCHMOD: usize = SYS_CLASS_FILE | 94;
|
||||
pub const SYS_FCHOWN: usize = SYS_CLASS_FILE | 207;
|
||||
pub const SYS_FCNTL: usize = SYS_CLASS_FILE | 55;
|
||||
pub const SYS_FEVENT: usize = SYS_CLASS_FILE | 927;
|
||||
pub const SYS_FEXEC: usize = SYS_CLASS_FILE | 11;
|
||||
pub const SYS_FMAP_OLD: usize = SYS_CLASS_FILE | SYS_ARG_SLICE | 90;
|
||||
pub const SYS_FMAP: usize = SYS_CLASS_FILE | SYS_ARG_SLICE | 900;
|
||||
pub const SYS_FUNMAP_OLD: usize = SYS_CLASS_FILE | 91;
|
||||
pub const SYS_FUNMAP: usize = SYS_CLASS_FILE | 92;
|
||||
pub const SYS_FPATH: usize = SYS_CLASS_FILE | SYS_ARG_MSLICE | 928;
|
||||
pub const SYS_FRENAME: usize = SYS_CLASS_FILE | SYS_ARG_PATH | 38;
|
||||
pub const SYS_FSTAT: usize = SYS_CLASS_FILE | SYS_ARG_MSLICE | 28;
|
||||
pub const SYS_FSTATVFS: usize = SYS_CLASS_FILE | SYS_ARG_MSLICE | 100;
|
||||
pub const SYS_FSYNC: usize = SYS_CLASS_FILE | 118;
|
||||
pub const SYS_FTRUNCATE: usize = SYS_CLASS_FILE | 93;
|
||||
pub const SYS_FUTIMENS: usize = SYS_CLASS_FILE | SYS_ARG_SLICE | 320;
|
||||
|
||||
pub const SYS_BRK: usize = 45;
|
||||
pub const SYS_CHDIR: usize = 12;
|
||||
pub const SYS_CLOCK_GETTIME: usize = 265;
|
||||
pub const SYS_CLONE: usize = 120;
|
||||
|
@ -59,6 +60,7 @@ pub const SYS_MPROTECT: usize = 125;
|
|||
pub const SYS_MKNS: usize = 984;
|
||||
pub const SYS_NANOSLEEP: usize =162;
|
||||
pub const SYS_PHYSALLOC: usize =945;
|
||||
pub const SYS_PHYSALLOC3: usize=9453;
|
||||
pub const SYS_PHYSFREE: usize = 946;
|
||||
pub const SYS_PHYSMAP: usize = 947;
|
||||
pub const SYS_PHYSUNMAP: usize =948;
|
||||
|
|
|
@ -11,7 +11,10 @@ echo "Generating SchemeBlock from Scheme"
|
|||
sed 's/trait Scheme/trait SchemeBlock/' scheme.rs \
|
||||
| sed 's/fn handle(\&self, packet: \&mut Packet)/fn handle(\&self, packet: \&Packet) -> Option<usize>/' \
|
||||
| sed 's/packet.a = Error::mux(res);/res.transpose().map(Error::mux)/' \
|
||||
| sed 's/Result<usize>/Result<Option<usize>>/g' \
|
||||
| sed 's/\.map(|f| f\.bits())/\.map(|f| f.map(|f| f.bits()))/' \
|
||||
| sed 's/\.map(|o| o as usize)/.map(|o| o.map(|o| o as usize))/' \
|
||||
| sed 's/Ok(0)/Ok(Some(0))/g' \
|
||||
| sed 's/Result<\([^>]\+\)>/Result<Option<\1>>/g' \
|
||||
> scheme_block.rs
|
||||
|
||||
echo "Generating SchemeBlockMut from SchemeBlock"
|
||||
|
|
|
@ -1,9 +1,18 @@
|
|||
use core::{slice, str};
|
||||
|
||||
pub use self::scheme::Scheme;
|
||||
pub use self::scheme_mut::SchemeMut;
|
||||
pub use self::scheme_block::SchemeBlock;
|
||||
pub use self::scheme_block_mut::SchemeBlockMut;
|
||||
pub use self::seek::*;
|
||||
|
||||
unsafe fn str_from_raw_parts(ptr: *const u8, len: usize) -> Option<&'static str> {
|
||||
let slice = slice::from_raw_parts(ptr, len);
|
||||
str::from_utf8(slice).ok()
|
||||
}
|
||||
|
||||
mod scheme;
|
||||
mod scheme_mut;
|
||||
mod scheme_block;
|
||||
mod scheme_block_mut;
|
||||
mod seek;
|
||||
|
|
|
@ -1,33 +1,61 @@
|
|||
use core::{mem, slice};
|
||||
|
||||
use data::*;
|
||||
use error::*;
|
||||
use number::*;
|
||||
use crate::data::*;
|
||||
use crate::error::*;
|
||||
use crate::flag::*;
|
||||
use crate::number::*;
|
||||
use crate::scheme::str_from_raw_parts;
|
||||
|
||||
pub trait Scheme {
|
||||
fn handle(&self, packet: &mut Packet) {
|
||||
let res = match packet.a {
|
||||
SYS_OPEN => self.open(unsafe { slice::from_raw_parts(packet.b as *const u8, packet.c) }, packet.d, packet.uid, packet.gid),
|
||||
SYS_CHMOD => self.chmod(unsafe { slice::from_raw_parts(packet.b as *const u8, packet.c) }, packet.d as u16, packet.uid, packet.gid),
|
||||
SYS_RMDIR => self.rmdir(unsafe { slice::from_raw_parts(packet.b as *const u8, packet.c) }, packet.uid, packet.gid),
|
||||
SYS_UNLINK => self.unlink(unsafe { slice::from_raw_parts(packet.b as *const u8, packet.c) }, packet.uid, packet.gid),
|
||||
SYS_OPEN => if let Some(path) = unsafe { str_from_raw_parts(packet.b as *const u8, packet.c) } {
|
||||
self.open(path, packet.d, packet.uid, packet.gid)
|
||||
} else {
|
||||
Err(Error::new(EINVAL))
|
||||
},
|
||||
SYS_CHMOD => if let Some(path) = unsafe { str_from_raw_parts(packet.b as *const u8, packet.c) } {
|
||||
self.chmod(path, packet.d as u16, packet.uid, packet.gid)
|
||||
} else {
|
||||
Err(Error::new(EINVAL))
|
||||
},
|
||||
SYS_RMDIR => if let Some(path) = unsafe { str_from_raw_parts(packet.b as *const u8, packet.c) } {
|
||||
self.rmdir(path, packet.uid, packet.gid)
|
||||
} else {
|
||||
Err(Error::new(EINVAL))
|
||||
},
|
||||
SYS_UNLINK => if let Some(path) = unsafe { str_from_raw_parts(packet.b as *const u8, packet.c) } {
|
||||
self.unlink(path, packet.uid, packet.gid)
|
||||
} else {
|
||||
Err(Error::new(EINVAL))
|
||||
},
|
||||
|
||||
SYS_DUP => self.dup(packet.b, unsafe { slice::from_raw_parts(packet.c as *const u8, packet.d) }),
|
||||
SYS_READ => self.read(packet.b, unsafe { slice::from_raw_parts_mut(packet.c as *mut u8, packet.d) }),
|
||||
SYS_WRITE => self.write(packet.b, unsafe { slice::from_raw_parts(packet.c as *const u8, packet.d) }),
|
||||
SYS_LSEEK => self.seek(packet.b, packet.c, packet.d),
|
||||
SYS_LSEEK => self.seek(packet.b, packet.c as isize, packet.d).map(|o| o as usize),
|
||||
SYS_FCHMOD => self.fchmod(packet.b, packet.c as u16),
|
||||
SYS_FCHOWN => self.fchown(packet.b, packet.c as u32, packet.d as u32),
|
||||
SYS_FCNTL => self.fcntl(packet.b, packet.c, packet.d),
|
||||
SYS_FEVENT => self.fevent(packet.b, packet.c),
|
||||
SYS_FEVENT => self.fevent(packet.b, EventFlags::from_bits_truncate(packet.c)).map(|f| f.bits()),
|
||||
SYS_FMAP_OLD => if packet.d >= mem::size_of::<OldMap>() {
|
||||
self.fmap_old(packet.b, unsafe { &*(packet.c as *const OldMap) })
|
||||
} else {
|
||||
Err(Error::new(EFAULT))
|
||||
},
|
||||
SYS_FMAP => if packet.d >= mem::size_of::<Map>() {
|
||||
self.fmap(packet.b, unsafe { &*(packet.c as *const Map) })
|
||||
} else {
|
||||
Err(Error::new(EFAULT))
|
||||
},
|
||||
SYS_FUNMAP => self.funmap(packet.b),
|
||||
SYS_FUNMAP_OLD => self.funmap_old(packet.b),
|
||||
SYS_FUNMAP => self.funmap(packet.b, packet.c),
|
||||
SYS_FPATH => self.fpath(packet.b, unsafe { slice::from_raw_parts_mut(packet.c as *mut u8, packet.d) }),
|
||||
SYS_FRENAME => self.frename(packet.b, unsafe { slice::from_raw_parts(packet.c as *const u8, packet.d) }, packet.uid, packet.gid),
|
||||
SYS_FRENAME => if let Some(path) = unsafe { str_from_raw_parts(packet.c as *const u8, packet.d) } {
|
||||
self.frename(packet.b, path, packet.uid, packet.gid)
|
||||
} else {
|
||||
Err(Error::new(EINVAL))
|
||||
},
|
||||
SYS_FSTAT => if packet.d >= mem::size_of::<Stat>() {
|
||||
self.fstat(packet.b, unsafe { &mut *(packet.c as *mut Stat) })
|
||||
} else {
|
||||
|
@ -55,22 +83,22 @@ pub trait Scheme {
|
|||
/* Scheme operations */
|
||||
|
||||
#[allow(unused_variables)]
|
||||
fn open(&self, path: &[u8], flags: usize, uid: u32, gid: u32) -> Result<usize> {
|
||||
fn open(&self, path: &str, flags: usize, uid: u32, gid: u32) -> Result<usize> {
|
||||
Err(Error::new(ENOENT))
|
||||
}
|
||||
|
||||
#[allow(unused_variables)]
|
||||
fn chmod(&self, path: &[u8], mode: u16, uid: u32, gid: u32) -> Result<usize> {
|
||||
fn chmod(&self, path: &str, mode: u16, uid: u32, gid: u32) -> Result<usize> {
|
||||
Err(Error::new(ENOENT))
|
||||
}
|
||||
|
||||
#[allow(unused_variables)]
|
||||
fn rmdir(&self, path: &[u8], uid: u32, gid: u32) -> Result<usize> {
|
||||
fn rmdir(&self, path: &str, uid: u32, gid: u32) -> Result<usize> {
|
||||
Err(Error::new(ENOENT))
|
||||
}
|
||||
|
||||
#[allow(unused_variables)]
|
||||
fn unlink(&self, path: &[u8], uid: u32, gid: u32) -> Result<usize> {
|
||||
fn unlink(&self, path: &str, uid: u32, gid: u32) -> Result<usize> {
|
||||
Err(Error::new(ENOENT))
|
||||
}
|
||||
|
||||
|
@ -91,7 +119,7 @@ pub trait Scheme {
|
|||
}
|
||||
|
||||
#[allow(unused_variables)]
|
||||
fn seek(&self, id: usize, pos: usize, whence: usize) -> Result<usize> {
|
||||
fn seek(&self, id: usize, pos: isize, whence: usize) -> Result<isize> {
|
||||
Err(Error::new(EBADF))
|
||||
}
|
||||
|
||||
|
@ -111,18 +139,34 @@ pub trait Scheme {
|
|||
}
|
||||
|
||||
#[allow(unused_variables)]
|
||||
fn fevent(&self, id: usize, flags: usize) -> Result<usize> {
|
||||
fn fevent(&self, id: usize, flags: EventFlags) -> Result<EventFlags> {
|
||||
Err(Error::new(EBADF))
|
||||
}
|
||||
|
||||
#[allow(unused_variables)]
|
||||
fn fmap_old(&self, id: usize, map: &OldMap) -> Result<usize> {
|
||||
Err(Error::new(EBADF))
|
||||
}
|
||||
#[allow(unused_variables)]
|
||||
fn fmap(&self, id: usize, map: &Map) -> Result<usize> {
|
||||
Err(Error::new(EBADF))
|
||||
if map.flags.contains(MapFlags::MAP_FIXED) {
|
||||
return Err(Error::new(EINVAL));
|
||||
}
|
||||
self.fmap_old(id, &OldMap {
|
||||
offset: map.offset,
|
||||
size: map.size,
|
||||
flags: map.flags,
|
||||
})
|
||||
}
|
||||
|
||||
#[allow(unused_variables)]
|
||||
fn funmap(&self, address: usize) -> Result<usize> {
|
||||
Err(Error::new(EBADF))
|
||||
fn funmap_old(&self, address: usize) -> Result<usize> {
|
||||
Ok(0)
|
||||
}
|
||||
|
||||
#[allow(unused_variables)]
|
||||
fn funmap(&self, address: usize, length: usize) -> Result<usize> {
|
||||
Ok(0)
|
||||
}
|
||||
|
||||
#[allow(unused_variables)]
|
||||
|
@ -131,7 +175,7 @@ pub trait Scheme {
|
|||
}
|
||||
|
||||
#[allow(unused_variables)]
|
||||
fn frename(&self, id: usize, path: &[u8], uid: u32, gid: u32) -> Result<usize> {
|
||||
fn frename(&self, id: usize, path: &str, uid: u32, gid: u32) -> Result<usize> {
|
||||
Err(Error::new(EBADF))
|
||||
}
|
||||
|
||||
|
|
|
@ -1,33 +1,61 @@
|
|||
use core::{mem, slice};
|
||||
|
||||
use data::*;
|
||||
use error::*;
|
||||
use number::*;
|
||||
use crate::data::*;
|
||||
use crate::error::*;
|
||||
use crate::flag::*;
|
||||
use crate::number::*;
|
||||
use crate::scheme::str_from_raw_parts;
|
||||
|
||||
pub trait SchemeBlock {
|
||||
fn handle(&self, packet: &Packet) -> Option<usize> {
|
||||
let res = match packet.a {
|
||||
SYS_OPEN => self.open(unsafe { slice::from_raw_parts(packet.b as *const u8, packet.c) }, packet.d, packet.uid, packet.gid),
|
||||
SYS_CHMOD => self.chmod(unsafe { slice::from_raw_parts(packet.b as *const u8, packet.c) }, packet.d as u16, packet.uid, packet.gid),
|
||||
SYS_RMDIR => self.rmdir(unsafe { slice::from_raw_parts(packet.b as *const u8, packet.c) }, packet.uid, packet.gid),
|
||||
SYS_UNLINK => self.unlink(unsafe { slice::from_raw_parts(packet.b as *const u8, packet.c) }, packet.uid, packet.gid),
|
||||
SYS_OPEN => if let Some(path) = unsafe { str_from_raw_parts(packet.b as *const u8, packet.c) } {
|
||||
self.open(path, packet.d, packet.uid, packet.gid)
|
||||
} else {
|
||||
Err(Error::new(EINVAL))
|
||||
},
|
||||
SYS_CHMOD => if let Some(path) = unsafe { str_from_raw_parts(packet.b as *const u8, packet.c) } {
|
||||
self.chmod(path, packet.d as u16, packet.uid, packet.gid)
|
||||
} else {
|
||||
Err(Error::new(EINVAL))
|
||||
},
|
||||
SYS_RMDIR => if let Some(path) = unsafe { str_from_raw_parts(packet.b as *const u8, packet.c) } {
|
||||
self.rmdir(path, packet.uid, packet.gid)
|
||||
} else {
|
||||
Err(Error::new(EINVAL))
|
||||
},
|
||||
SYS_UNLINK => if let Some(path) = unsafe { str_from_raw_parts(packet.b as *const u8, packet.c) } {
|
||||
self.unlink(path, packet.uid, packet.gid)
|
||||
} else {
|
||||
Err(Error::new(EINVAL))
|
||||
},
|
||||
|
||||
SYS_DUP => self.dup(packet.b, unsafe { slice::from_raw_parts(packet.c as *const u8, packet.d) }),
|
||||
SYS_READ => self.read(packet.b, unsafe { slice::from_raw_parts_mut(packet.c as *mut u8, packet.d) }),
|
||||
SYS_WRITE => self.write(packet.b, unsafe { slice::from_raw_parts(packet.c as *const u8, packet.d) }),
|
||||
SYS_LSEEK => self.seek(packet.b, packet.c, packet.d),
|
||||
SYS_LSEEK => self.seek(packet.b, packet.c as isize, packet.d).map(|o| o.map(|o| o as usize)),
|
||||
SYS_FCHMOD => self.fchmod(packet.b, packet.c as u16),
|
||||
SYS_FCHOWN => self.fchown(packet.b, packet.c as u32, packet.d as u32),
|
||||
SYS_FCNTL => self.fcntl(packet.b, packet.c, packet.d),
|
||||
SYS_FEVENT => self.fevent(packet.b, packet.c),
|
||||
SYS_FEVENT => self.fevent(packet.b, EventFlags::from_bits_truncate(packet.c)).map(|f| f.map(|f| f.bits())),
|
||||
SYS_FMAP_OLD => if packet.d >= mem::size_of::<OldMap>() {
|
||||
self.fmap_old(packet.b, unsafe { &*(packet.c as *const OldMap) })
|
||||
} else {
|
||||
Err(Error::new(EFAULT))
|
||||
},
|
||||
SYS_FMAP => if packet.d >= mem::size_of::<Map>() {
|
||||
self.fmap(packet.b, unsafe { &*(packet.c as *const Map) })
|
||||
} else {
|
||||
Err(Error::new(EFAULT))
|
||||
},
|
||||
SYS_FUNMAP => self.funmap(packet.b),
|
||||
SYS_FUNMAP_OLD => self.funmap_old(packet.b),
|
||||
SYS_FUNMAP => self.funmap(packet.b, packet.c),
|
||||
SYS_FPATH => self.fpath(packet.b, unsafe { slice::from_raw_parts_mut(packet.c as *mut u8, packet.d) }),
|
||||
SYS_FRENAME => self.frename(packet.b, unsafe { slice::from_raw_parts(packet.c as *const u8, packet.d) }, packet.uid, packet.gid),
|
||||
SYS_FRENAME => if let Some(path) = unsafe { str_from_raw_parts(packet.c as *const u8, packet.d) } {
|
||||
self.frename(packet.b, path, packet.uid, packet.gid)
|
||||
} else {
|
||||
Err(Error::new(EINVAL))
|
||||
},
|
||||
SYS_FSTAT => if packet.d >= mem::size_of::<Stat>() {
|
||||
self.fstat(packet.b, unsafe { &mut *(packet.c as *mut Stat) })
|
||||
} else {
|
||||
|
@ -55,22 +83,22 @@ pub trait SchemeBlock {
|
|||
/* Scheme operations */
|
||||
|
||||
#[allow(unused_variables)]
|
||||
fn open(&self, path: &[u8], flags: usize, uid: u32, gid: u32) -> Result<Option<usize>> {
|
||||
fn open(&self, path: &str, flags: usize, uid: u32, gid: u32) -> Result<Option<usize>> {
|
||||
Err(Error::new(ENOENT))
|
||||
}
|
||||
|
||||
#[allow(unused_variables)]
|
||||
fn chmod(&self, path: &[u8], mode: u16, uid: u32, gid: u32) -> Result<Option<usize>> {
|
||||
fn chmod(&self, path: &str, mode: u16, uid: u32, gid: u32) -> Result<Option<usize>> {
|
||||
Err(Error::new(ENOENT))
|
||||
}
|
||||
|
||||
#[allow(unused_variables)]
|
||||
fn rmdir(&self, path: &[u8], uid: u32, gid: u32) -> Result<Option<usize>> {
|
||||
fn rmdir(&self, path: &str, uid: u32, gid: u32) -> Result<Option<usize>> {
|
||||
Err(Error::new(ENOENT))
|
||||
}
|
||||
|
||||
#[allow(unused_variables)]
|
||||
fn unlink(&self, path: &[u8], uid: u32, gid: u32) -> Result<Option<usize>> {
|
||||
fn unlink(&self, path: &str, uid: u32, gid: u32) -> Result<Option<usize>> {
|
||||
Err(Error::new(ENOENT))
|
||||
}
|
||||
|
||||
|
@ -91,7 +119,7 @@ pub trait SchemeBlock {
|
|||
}
|
||||
|
||||
#[allow(unused_variables)]
|
||||
fn seek(&self, id: usize, pos: usize, whence: usize) -> Result<Option<usize>> {
|
||||
fn seek(&self, id: usize, pos: isize, whence: usize) -> Result<Option<isize>> {
|
||||
Err(Error::new(EBADF))
|
||||
}
|
||||
|
||||
|
@ -111,18 +139,34 @@ pub trait SchemeBlock {
|
|||
}
|
||||
|
||||
#[allow(unused_variables)]
|
||||
fn fevent(&self, id: usize, flags: usize) -> Result<Option<usize>> {
|
||||
fn fevent(&self, id: usize, flags: EventFlags) -> Result<Option<EventFlags>> {
|
||||
Err(Error::new(EBADF))
|
||||
}
|
||||
|
||||
#[allow(unused_variables)]
|
||||
fn fmap_old(&self, id: usize, map: &OldMap) -> Result<Option<usize>> {
|
||||
Err(Error::new(EBADF))
|
||||
}
|
||||
#[allow(unused_variables)]
|
||||
fn fmap(&self, id: usize, map: &Map) -> Result<Option<usize>> {
|
||||
Err(Error::new(EBADF))
|
||||
if map.flags.contains(MapFlags::MAP_FIXED) {
|
||||
return Err(Error::new(EINVAL));
|
||||
}
|
||||
self.fmap_old(id, &OldMap {
|
||||
offset: map.offset,
|
||||
size: map.size,
|
||||
flags: map.flags,
|
||||
})
|
||||
}
|
||||
|
||||
#[allow(unused_variables)]
|
||||
fn funmap(&self, address: usize) -> Result<Option<usize>> {
|
||||
Err(Error::new(EBADF))
|
||||
fn funmap_old(&self, address: usize) -> Result<Option<usize>> {
|
||||
Ok(Some(0))
|
||||
}
|
||||
|
||||
#[allow(unused_variables)]
|
||||
fn funmap(&self, address: usize, length: usize) -> Result<Option<usize>> {
|
||||
Ok(Some(0))
|
||||
}
|
||||
|
||||
#[allow(unused_variables)]
|
||||
|
@ -131,7 +175,7 @@ pub trait SchemeBlock {
|
|||
}
|
||||
|
||||
#[allow(unused_variables)]
|
||||
fn frename(&self, id: usize, path: &[u8], uid: u32, gid: u32) -> Result<Option<usize>> {
|
||||
fn frename(&self, id: usize, path: &str, uid: u32, gid: u32) -> Result<Option<usize>> {
|
||||
Err(Error::new(EBADF))
|
||||
}
|
||||
|
||||
|
|
|
@ -1,33 +1,61 @@
|
|||
use core::{mem, slice};
|
||||
|
||||
use data::*;
|
||||
use error::*;
|
||||
use number::*;
|
||||
use crate::data::*;
|
||||
use crate::error::*;
|
||||
use crate::flag::*;
|
||||
use crate::number::*;
|
||||
use crate::scheme::str_from_raw_parts;
|
||||
|
||||
pub trait SchemeBlockMut {
|
||||
fn handle(&mut self, packet: &Packet) -> Option<usize> {
|
||||
let res = match packet.a {
|
||||
SYS_OPEN => self.open(unsafe { slice::from_raw_parts(packet.b as *const u8, packet.c) }, packet.d, packet.uid, packet.gid),
|
||||
SYS_CHMOD => self.chmod(unsafe { slice::from_raw_parts(packet.b as *const u8, packet.c) }, packet.d as u16, packet.uid, packet.gid),
|
||||
SYS_RMDIR => self.rmdir(unsafe { slice::from_raw_parts(packet.b as *const u8, packet.c) }, packet.uid, packet.gid),
|
||||
SYS_UNLINK => self.unlink(unsafe { slice::from_raw_parts(packet.b as *const u8, packet.c) }, packet.uid, packet.gid),
|
||||
SYS_OPEN => if let Some(path) = unsafe { str_from_raw_parts(packet.b as *const u8, packet.c) } {
|
||||
self.open(path, packet.d, packet.uid, packet.gid)
|
||||
} else {
|
||||
Err(Error::new(EINVAL))
|
||||
},
|
||||
SYS_CHMOD => if let Some(path) = unsafe { str_from_raw_parts(packet.b as *const u8, packet.c) } {
|
||||
self.chmod(path, packet.d as u16, packet.uid, packet.gid)
|
||||
} else {
|
||||
Err(Error::new(EINVAL))
|
||||
},
|
||||
SYS_RMDIR => if let Some(path) = unsafe { str_from_raw_parts(packet.b as *const u8, packet.c) } {
|
||||
self.rmdir(path, packet.uid, packet.gid)
|
||||
} else {
|
||||
Err(Error::new(EINVAL))
|
||||
},
|
||||
SYS_UNLINK => if let Some(path) = unsafe { str_from_raw_parts(packet.b as *const u8, packet.c) } {
|
||||
self.unlink(path, packet.uid, packet.gid)
|
||||
} else {
|
||||
Err(Error::new(EINVAL))
|
||||
},
|
||||
|
||||
SYS_DUP => self.dup(packet.b, unsafe { slice::from_raw_parts(packet.c as *const u8, packet.d) }),
|
||||
SYS_READ => self.read(packet.b, unsafe { slice::from_raw_parts_mut(packet.c as *mut u8, packet.d) }),
|
||||
SYS_WRITE => self.write(packet.b, unsafe { slice::from_raw_parts(packet.c as *const u8, packet.d) }),
|
||||
SYS_LSEEK => self.seek(packet.b, packet.c, packet.d),
|
||||
SYS_LSEEK => self.seek(packet.b, packet.c as isize, packet.d).map(|o| o.map(|o| o as usize)),
|
||||
SYS_FCHMOD => self.fchmod(packet.b, packet.c as u16),
|
||||
SYS_FCHOWN => self.fchown(packet.b, packet.c as u32, packet.d as u32),
|
||||
SYS_FCNTL => self.fcntl(packet.b, packet.c, packet.d),
|
||||
SYS_FEVENT => self.fevent(packet.b, packet.c),
|
||||
SYS_FEVENT => self.fevent(packet.b, EventFlags::from_bits_truncate(packet.c)).map(|f| f.map(|f| f.bits())),
|
||||
SYS_FMAP_OLD => if packet.d >= mem::size_of::<OldMap>() {
|
||||
self.fmap_old(packet.b, unsafe { &*(packet.c as *const OldMap) })
|
||||
} else {
|
||||
Err(Error::new(EFAULT))
|
||||
},
|
||||
SYS_FMAP => if packet.d >= mem::size_of::<Map>() {
|
||||
self.fmap(packet.b, unsafe { &*(packet.c as *const Map) })
|
||||
} else {
|
||||
Err(Error::new(EFAULT))
|
||||
},
|
||||
SYS_FUNMAP => self.funmap(packet.b),
|
||||
SYS_FUNMAP_OLD => self.funmap_old(packet.b),
|
||||
SYS_FUNMAP => self.funmap(packet.b, packet.c),
|
||||
SYS_FPATH => self.fpath(packet.b, unsafe { slice::from_raw_parts_mut(packet.c as *mut u8, packet.d) }),
|
||||
SYS_FRENAME => self.frename(packet.b, unsafe { slice::from_raw_parts(packet.c as *const u8, packet.d) }, packet.uid, packet.gid),
|
||||
SYS_FRENAME => if let Some(path) = unsafe { str_from_raw_parts(packet.c as *const u8, packet.d) } {
|
||||
self.frename(packet.b, path, packet.uid, packet.gid)
|
||||
} else {
|
||||
Err(Error::new(EINVAL))
|
||||
},
|
||||
SYS_FSTAT => if packet.d >= mem::size_of::<Stat>() {
|
||||
self.fstat(packet.b, unsafe { &mut *(packet.c as *mut Stat) })
|
||||
} else {
|
||||
|
@ -55,22 +83,22 @@ pub trait SchemeBlockMut {
|
|||
/* Scheme operations */
|
||||
|
||||
#[allow(unused_variables)]
|
||||
fn open(&mut self, path: &[u8], flags: usize, uid: u32, gid: u32) -> Result<Option<usize>> {
|
||||
fn open(&mut self, path: &str, flags: usize, uid: u32, gid: u32) -> Result<Option<usize>> {
|
||||
Err(Error::new(ENOENT))
|
||||
}
|
||||
|
||||
#[allow(unused_variables)]
|
||||
fn chmod(&mut self, path: &[u8], mode: u16, uid: u32, gid: u32) -> Result<Option<usize>> {
|
||||
fn chmod(&mut self, path: &str, mode: u16, uid: u32, gid: u32) -> Result<Option<usize>> {
|
||||
Err(Error::new(ENOENT))
|
||||
}
|
||||
|
||||
#[allow(unused_variables)]
|
||||
fn rmdir(&mut self, path: &[u8], uid: u32, gid: u32) -> Result<Option<usize>> {
|
||||
fn rmdir(&mut self, path: &str, uid: u32, gid: u32) -> Result<Option<usize>> {
|
||||
Err(Error::new(ENOENT))
|
||||
}
|
||||
|
||||
#[allow(unused_variables)]
|
||||
fn unlink(&mut self, path: &[u8], uid: u32, gid: u32) -> Result<Option<usize>> {
|
||||
fn unlink(&mut self, path: &str, uid: u32, gid: u32) -> Result<Option<usize>> {
|
||||
Err(Error::new(ENOENT))
|
||||
}
|
||||
|
||||
|
@ -91,7 +119,7 @@ pub trait SchemeBlockMut {
|
|||
}
|
||||
|
||||
#[allow(unused_variables)]
|
||||
fn seek(&mut self, id: usize, pos: usize, whence: usize) -> Result<Option<usize>> {
|
||||
fn seek(&mut self, id: usize, pos: isize, whence: usize) -> Result<Option<isize>> {
|
||||
Err(Error::new(EBADF))
|
||||
}
|
||||
|
||||
|
@ -111,18 +139,34 @@ pub trait SchemeBlockMut {
|
|||
}
|
||||
|
||||
#[allow(unused_variables)]
|
||||
fn fevent(&mut self, id: usize, flags: usize) -> Result<Option<usize>> {
|
||||
fn fevent(&mut self, id: usize, flags: EventFlags) -> Result<Option<EventFlags>> {
|
||||
Err(Error::new(EBADF))
|
||||
}
|
||||
|
||||
#[allow(unused_variables)]
|
||||
fn fmap_old(&mut self, id: usize, map: &OldMap) -> Result<Option<usize>> {
|
||||
Err(Error::new(EBADF))
|
||||
}
|
||||
#[allow(unused_variables)]
|
||||
fn fmap(&mut self, id: usize, map: &Map) -> Result<Option<usize>> {
|
||||
Err(Error::new(EBADF))
|
||||
if map.flags.contains(MapFlags::MAP_FIXED) {
|
||||
return Err(Error::new(EINVAL));
|
||||
}
|
||||
self.fmap_old(id, &OldMap {
|
||||
offset: map.offset,
|
||||
size: map.size,
|
||||
flags: map.flags,
|
||||
})
|
||||
}
|
||||
|
||||
#[allow(unused_variables)]
|
||||
fn funmap(&mut self, address: usize) -> Result<Option<usize>> {
|
||||
Err(Error::new(EBADF))
|
||||
fn funmap_old(&mut self, address: usize) -> Result<Option<usize>> {
|
||||
Ok(Some(0))
|
||||
}
|
||||
|
||||
#[allow(unused_variables)]
|
||||
fn funmap(&mut self, address: usize, length: usize) -> Result<Option<usize>> {
|
||||
Ok(Some(0))
|
||||
}
|
||||
|
||||
#[allow(unused_variables)]
|
||||
|
@ -131,7 +175,7 @@ pub trait SchemeBlockMut {
|
|||
}
|
||||
|
||||
#[allow(unused_variables)]
|
||||
fn frename(&mut self, id: usize, path: &[u8], uid: u32, gid: u32) -> Result<Option<usize>> {
|
||||
fn frename(&mut self, id: usize, path: &str, uid: u32, gid: u32) -> Result<Option<usize>> {
|
||||
Err(Error::new(EBADF))
|
||||
}
|
||||
|
||||
|
|
|
@ -1,33 +1,61 @@
|
|||
use core::{mem, slice};
|
||||
|
||||
use data::*;
|
||||
use error::*;
|
||||
use number::*;
|
||||
use crate::data::*;
|
||||
use crate::error::*;
|
||||
use crate::flag::*;
|
||||
use crate::number::*;
|
||||
use crate::scheme::str_from_raw_parts;
|
||||
|
||||
pub trait SchemeMut {
|
||||
fn handle(&mut self, packet: &mut Packet) {
|
||||
let res = match packet.a {
|
||||
SYS_OPEN => self.open(unsafe { slice::from_raw_parts(packet.b as *const u8, packet.c) }, packet.d, packet.uid, packet.gid),
|
||||
SYS_CHMOD => self.chmod(unsafe { slice::from_raw_parts(packet.b as *const u8, packet.c) }, packet.d as u16, packet.uid, packet.gid),
|
||||
SYS_RMDIR => self.rmdir(unsafe { slice::from_raw_parts(packet.b as *const u8, packet.c) }, packet.uid, packet.gid),
|
||||
SYS_UNLINK => self.unlink(unsafe { slice::from_raw_parts(packet.b as *const u8, packet.c) }, packet.uid, packet.gid),
|
||||
SYS_OPEN => if let Some(path) = unsafe { str_from_raw_parts(packet.b as *const u8, packet.c) } {
|
||||
self.open(path, packet.d, packet.uid, packet.gid)
|
||||
} else {
|
||||
Err(Error::new(EINVAL))
|
||||
},
|
||||
SYS_CHMOD => if let Some(path) = unsafe { str_from_raw_parts(packet.b as *const u8, packet.c) } {
|
||||
self.chmod(path, packet.d as u16, packet.uid, packet.gid)
|
||||
} else {
|
||||
Err(Error::new(EINVAL))
|
||||
},
|
||||
SYS_RMDIR => if let Some(path) = unsafe { str_from_raw_parts(packet.b as *const u8, packet.c) } {
|
||||
self.rmdir(path, packet.uid, packet.gid)
|
||||
} else {
|
||||
Err(Error::new(EINVAL))
|
||||
},
|
||||
SYS_UNLINK => if let Some(path) = unsafe { str_from_raw_parts(packet.b as *const u8, packet.c) } {
|
||||
self.unlink(path, packet.uid, packet.gid)
|
||||
} else {
|
||||
Err(Error::new(EINVAL))
|
||||
},
|
||||
|
||||
SYS_DUP => self.dup(packet.b, unsafe { slice::from_raw_parts(packet.c as *const u8, packet.d) }),
|
||||
SYS_READ => self.read(packet.b, unsafe { slice::from_raw_parts_mut(packet.c as *mut u8, packet.d) }),
|
||||
SYS_WRITE => self.write(packet.b, unsafe { slice::from_raw_parts(packet.c as *const u8, packet.d) }),
|
||||
SYS_LSEEK => self.seek(packet.b, packet.c, packet.d),
|
||||
SYS_LSEEK => self.seek(packet.b, packet.c as isize, packet.d).map(|o| o as usize),
|
||||
SYS_FCHMOD => self.fchmod(packet.b, packet.c as u16),
|
||||
SYS_FCHOWN => self.fchown(packet.b, packet.c as u32, packet.d as u32),
|
||||
SYS_FCNTL => self.fcntl(packet.b, packet.c, packet.d),
|
||||
SYS_FEVENT => self.fevent(packet.b, packet.c),
|
||||
SYS_FEVENT => self.fevent(packet.b, EventFlags::from_bits_truncate(packet.c)).map(|f| f.bits()),
|
||||
SYS_FMAP_OLD => if packet.d >= mem::size_of::<OldMap>() {
|
||||
self.fmap_old(packet.b, unsafe { &*(packet.c as *const OldMap) })
|
||||
} else {
|
||||
Err(Error::new(EFAULT))
|
||||
},
|
||||
SYS_FMAP => if packet.d >= mem::size_of::<Map>() {
|
||||
self.fmap(packet.b, unsafe { &*(packet.c as *const Map) })
|
||||
} else {
|
||||
Err(Error::new(EFAULT))
|
||||
},
|
||||
SYS_FUNMAP => self.funmap(packet.b),
|
||||
SYS_FUNMAP_OLD => self.funmap_old(packet.b),
|
||||
SYS_FUNMAP => self.funmap(packet.b, packet.c),
|
||||
SYS_FPATH => self.fpath(packet.b, unsafe { slice::from_raw_parts_mut(packet.c as *mut u8, packet.d) }),
|
||||
SYS_FRENAME => self.frename(packet.b, unsafe { slice::from_raw_parts(packet.c as *const u8, packet.d) }, packet.uid, packet.gid),
|
||||
SYS_FRENAME => if let Some(path) = unsafe { str_from_raw_parts(packet.c as *const u8, packet.d) } {
|
||||
self.frename(packet.b, path, packet.uid, packet.gid)
|
||||
} else {
|
||||
Err(Error::new(EINVAL))
|
||||
},
|
||||
SYS_FSTAT => if packet.d >= mem::size_of::<Stat>() {
|
||||
self.fstat(packet.b, unsafe { &mut *(packet.c as *mut Stat) })
|
||||
} else {
|
||||
|
@ -55,22 +83,22 @@ pub trait SchemeMut {
|
|||
/* Scheme operations */
|
||||
|
||||
#[allow(unused_variables)]
|
||||
fn open(&mut self, path: &[u8], flags: usize, uid: u32, gid: u32) -> Result<usize> {
|
||||
fn open(&mut self, path: &str, flags: usize, uid: u32, gid: u32) -> Result<usize> {
|
||||
Err(Error::new(ENOENT))
|
||||
}
|
||||
|
||||
#[allow(unused_variables)]
|
||||
fn chmod(&mut self, path: &[u8], mode: u16, uid: u32, gid: u32) -> Result<usize> {
|
||||
fn chmod(&mut self, path: &str, mode: u16, uid: u32, gid: u32) -> Result<usize> {
|
||||
Err(Error::new(ENOENT))
|
||||
}
|
||||
|
||||
#[allow(unused_variables)]
|
||||
fn rmdir(&mut self, path: &[u8], uid: u32, gid: u32) -> Result<usize> {
|
||||
fn rmdir(&mut self, path: &str, uid: u32, gid: u32) -> Result<usize> {
|
||||
Err(Error::new(ENOENT))
|
||||
}
|
||||
|
||||
#[allow(unused_variables)]
|
||||
fn unlink(&mut self, path: &[u8], uid: u32, gid: u32) -> Result<usize> {
|
||||
fn unlink(&mut self, path: &str, uid: u32, gid: u32) -> Result<usize> {
|
||||
Err(Error::new(ENOENT))
|
||||
}
|
||||
|
||||
|
@ -91,7 +119,7 @@ pub trait SchemeMut {
|
|||
}
|
||||
|
||||
#[allow(unused_variables)]
|
||||
fn seek(&mut self, id: usize, pos: usize, whence: usize) -> Result<usize> {
|
||||
fn seek(&mut self, id: usize, pos: isize, whence: usize) -> Result<isize> {
|
||||
Err(Error::new(EBADF))
|
||||
}
|
||||
|
||||
|
@ -111,18 +139,34 @@ pub trait SchemeMut {
|
|||
}
|
||||
|
||||
#[allow(unused_variables)]
|
||||
fn fevent(&mut self, id: usize, flags: usize) -> Result<usize> {
|
||||
fn fevent(&mut self, id: usize, flags: EventFlags) -> Result<EventFlags> {
|
||||
Err(Error::new(EBADF))
|
||||
}
|
||||
|
||||
#[allow(unused_variables)]
|
||||
fn fmap_old(&mut self, id: usize, map: &OldMap) -> Result<usize> {
|
||||
Err(Error::new(EBADF))
|
||||
}
|
||||
#[allow(unused_variables)]
|
||||
fn fmap(&mut self, id: usize, map: &Map) -> Result<usize> {
|
||||
Err(Error::new(EBADF))
|
||||
if map.flags.contains(MapFlags::MAP_FIXED) {
|
||||
return Err(Error::new(EINVAL));
|
||||
}
|
||||
self.fmap_old(id, &OldMap {
|
||||
offset: map.offset,
|
||||
size: map.size,
|
||||
flags: map.flags,
|
||||
})
|
||||
}
|
||||
|
||||
#[allow(unused_variables)]
|
||||
fn funmap(&mut self, address: usize) -> Result<usize> {
|
||||
Err(Error::new(EBADF))
|
||||
fn funmap_old(&mut self, address: usize) -> Result<usize> {
|
||||
Ok(0)
|
||||
}
|
||||
|
||||
#[allow(unused_variables)]
|
||||
fn funmap(&mut self, address: usize, length: usize) -> Result<usize> {
|
||||
Ok(0)
|
||||
}
|
||||
|
||||
#[allow(unused_variables)]
|
||||
|
@ -131,7 +175,7 @@ pub trait SchemeMut {
|
|||
}
|
||||
|
||||
#[allow(unused_variables)]
|
||||
fn frename(&mut self, id: usize, path: &[u8], uid: u32, gid: u32) -> Result<usize> {
|
||||
fn frename(&mut self, id: usize, path: &str, uid: u32, gid: u32) -> Result<usize> {
|
||||
Err(Error::new(EBADF))
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
use core::cmp;
|
||||
use core::convert::TryFrom;
|
||||
use crate::error::*;
|
||||
use crate::flag::*;
|
||||
|
||||
/// Helper for seek calls
|
||||
/// In most cases it's easier to use a usize to track the offset and buffer size internally,
|
||||
/// but the seek interface uses isize. This wrapper ensures EOVERFLOW errors are returned
|
||||
/// as appropriate if the value in the usize can't fit in the isize.
|
||||
pub fn calc_seek_offset_usize(cur_offset: usize, pos: isize, whence: usize, buf_len: usize) -> Result<isize> {
|
||||
let cur_offset = isize::try_from(cur_offset).or_else(|_| Err(Error::new(EOVERFLOW)))?;
|
||||
let buf_len = isize::try_from(buf_len).or_else(|_| Err(Error::new(EOVERFLOW)))?;
|
||||
calc_seek_offset_isize(cur_offset, pos, whence, buf_len)
|
||||
}
|
||||
|
||||
/// Helper for seek calls
|
||||
/// Result is guaranteed to be positive.
|
||||
/// EOVERFLOW returned if the arguments would cause an overflow.
|
||||
/// EINVAL returned if the new offset is out of bounds.
|
||||
pub fn calc_seek_offset_isize(cur_offset: isize, pos: isize, whence: usize, buf_len: isize) -> Result<isize> {
|
||||
let new_offset = match whence {
|
||||
SEEK_CUR => pos.checked_add(cur_offset),
|
||||
SEEK_END => pos.checked_add(buf_len),
|
||||
SEEK_SET => Some(pos),
|
||||
_ => None,
|
||||
};
|
||||
|
||||
match new_offset {
|
||||
Some(new_offset) if new_offset < 0 => Err(Error::new(EINVAL)),
|
||||
Some(new_offset) => Ok(cmp::min(new_offset, buf_len)),
|
||||
None => Err(Error::new(EOVERFLOW))
|
||||
}
|
||||
}
|
|
@ -1,17 +1,25 @@
|
|||
#[test]
|
||||
fn brk() {
|
||||
unsafe {
|
||||
let start = dbg!(crate::brk(0)).unwrap();
|
||||
let end = start + 4 * 1024 * 1024;
|
||||
assert_eq!(dbg!(crate::brk(end)), Ok(end));
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn chdir() {
|
||||
//TODO: Verify CWD
|
||||
assert_eq!(dbg!(crate::chdir("file:/")), Ok(0));
|
||||
assert_eq!(dbg!(crate::chdir("file:/root")), Ok(0));
|
||||
use std::str;
|
||||
|
||||
let mut current_buf = [0; 4096];
|
||||
let current_count = dbg!(crate::getcwd(&mut current_buf)).unwrap();
|
||||
let current = dbg!(str::from_utf8(¤t_buf[..current_count])).unwrap();
|
||||
|
||||
let new = "file:";
|
||||
assert_eq!(dbg!(crate::chdir(dbg!(new))), Ok(0));
|
||||
{
|
||||
let mut buf = [0; 4096];
|
||||
let count = dbg!(crate::getcwd(&mut buf)).unwrap();
|
||||
assert_eq!(dbg!(str::from_utf8(&buf[..count])), Ok(new));
|
||||
}
|
||||
|
||||
assert_eq!(dbg!(crate::chdir(current)), Ok(0));
|
||||
{
|
||||
let mut buf = [0; 4096];
|
||||
let count = dbg!(crate::getcwd(&mut buf)).unwrap();
|
||||
assert_eq!(dbg!(str::from_utf8(&buf[..count])), Ok(current));
|
||||
}
|
||||
}
|
||||
|
||||
//TODO: chmod
|
||||
|
@ -19,14 +27,14 @@ fn chdir() {
|
|||
#[test]
|
||||
fn clone() {
|
||||
let expected_status = 42;
|
||||
let pid_res = unsafe { crate::clone(0) };
|
||||
let pid_res = unsafe { crate::clone(crate::CloneFlags::empty()) };
|
||||
if pid_res == Ok(0) {
|
||||
crate::exit(expected_status).unwrap();
|
||||
panic!("failed to exit");
|
||||
} else {
|
||||
let pid = dbg!(pid_res).unwrap();
|
||||
let mut status = 0;
|
||||
assert_eq!(dbg!(crate::waitpid(pid, &mut status, 0)), Ok(pid));
|
||||
assert_eq!(dbg!(crate::waitpid(pid, &mut status, crate::WaitFlags::empty())), Ok(pid));
|
||||
assert_eq!(dbg!(crate::wifexited(status)), true);
|
||||
assert_eq!(dbg!(crate::wexitstatus(status)), expected_status);
|
||||
}
|
||||
|
@ -61,7 +69,7 @@ fn clock_gettime() {
|
|||
|
||||
#[test]
|
||||
fn fexec() {
|
||||
let name = "/bin/ls";
|
||||
let name = "file:/bin/ls";
|
||||
|
||||
let fd = dbg!(
|
||||
crate::open(name, crate::O_RDONLY | crate::O_CLOEXEC)
|
||||
|
@ -73,7 +81,7 @@ fn fexec() {
|
|||
|
||||
let vars = &[];
|
||||
|
||||
let pid_res = unsafe { crate::clone(0) };
|
||||
let pid_res = unsafe { crate::clone(crate::CloneFlags::empty()) };
|
||||
if pid_res == Ok(0) {
|
||||
crate::fexec(fd, args, vars).unwrap();
|
||||
panic!("failed to fexec");
|
||||
|
@ -82,7 +90,7 @@ fn fexec() {
|
|||
|
||||
let pid = dbg!(pid_res).unwrap();
|
||||
let mut status = 0;
|
||||
assert_eq!(dbg!(crate::waitpid(pid, &mut status, 0)), Ok(pid));
|
||||
assert_eq!(dbg!(crate::waitpid(pid, &mut status, crate::WaitFlags::empty())), Ok(pid));
|
||||
assert_eq!(dbg!(crate::wifexited(status)), true);
|
||||
assert_eq!(dbg!(crate::wexitstatus(status)), 0);
|
||||
}
|
||||
|
@ -94,17 +102,20 @@ fn fmap() {
|
|||
|
||||
let fd = dbg!(
|
||||
crate::open(
|
||||
"/tmp/syscall-tests-fmap",
|
||||
"file:/tmp/syscall-tests-fmap",
|
||||
crate::O_CREAT | crate::O_RDWR | crate::O_CLOEXEC
|
||||
)
|
||||
).unwrap();
|
||||
|
||||
let size = 128;
|
||||
|
||||
let map = unsafe {
|
||||
slice::from_raw_parts_mut(
|
||||
dbg!(
|
||||
crate::fmap(fd, &crate::Map {
|
||||
address: 0,
|
||||
offset: 0,
|
||||
size: 128,
|
||||
size,
|
||||
flags: crate::PROT_READ | crate::PROT_WRITE
|
||||
})
|
||||
).unwrap() as *mut u8,
|
||||
|
@ -123,7 +134,337 @@ fn fmap() {
|
|||
//TODO: add msync
|
||||
unsafe {
|
||||
assert_eq!(dbg!(
|
||||
crate::funmap(map.as_mut_ptr() as usize)
|
||||
crate::funmap(map.as_mut_ptr() as usize, size)
|
||||
), Ok(0));
|
||||
}
|
||||
}
|
||||
|
||||
// funmap tested by fmap
|
||||
|
||||
#[test]
|
||||
fn fpath() {
|
||||
use std::str;
|
||||
|
||||
let path = "file:/tmp/syscall-tests-fpath";
|
||||
let fd = dbg!(
|
||||
crate::open(
|
||||
dbg!(path),
|
||||
crate::O_CREAT | crate::O_RDWR | crate::O_CLOEXEC
|
||||
)
|
||||
).unwrap();
|
||||
|
||||
let mut buf = [0; 4096];
|
||||
let count = dbg!(
|
||||
crate::fpath(fd, &mut buf)
|
||||
).unwrap();
|
||||
|
||||
assert_eq!(dbg!(str::from_utf8(&buf[..count])), Ok(path));
|
||||
|
||||
assert_eq!(dbg!(crate::close(fd)), Ok(0));
|
||||
}
|
||||
|
||||
//TODO: frename
|
||||
|
||||
#[test]
|
||||
fn fstat() {
|
||||
let path = "file:/tmp/syscall-tests-fstat";
|
||||
let fd = dbg!(
|
||||
crate::open(
|
||||
dbg!(path),
|
||||
crate::O_CREAT | crate::O_RDWR | crate::O_CLOEXEC
|
||||
)
|
||||
).unwrap();
|
||||
|
||||
let mut stat = crate::Stat::default();
|
||||
assert_eq!(dbg!(crate::fstat(fd, &mut stat)), Ok(0));
|
||||
assert_ne!(dbg!(stat), crate::Stat::default());
|
||||
|
||||
assert_eq!(dbg!(crate::close(fd)), Ok(0));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fstatvfs() {
|
||||
let path = "file:/tmp/syscall-tests-fstatvfs";
|
||||
let fd = dbg!(
|
||||
crate::open(
|
||||
dbg!(path),
|
||||
crate::O_CREAT | crate::O_RDWR | crate::O_CLOEXEC
|
||||
)
|
||||
).unwrap();
|
||||
|
||||
let mut statvfs = crate::StatVfs::default();
|
||||
assert_eq!(dbg!(crate::fstatvfs(fd, &mut statvfs)), Ok(0));
|
||||
assert_ne!(dbg!(statvfs), crate::StatVfs::default());
|
||||
|
||||
assert_eq!(dbg!(crate::close(fd)), Ok(0));
|
||||
}
|
||||
|
||||
//TODO: fsync
|
||||
|
||||
//TODO: ftruncate
|
||||
|
||||
//TODO: futimens
|
||||
|
||||
//TODO: futex
|
||||
|
||||
// getcwd tested by chdir
|
||||
|
||||
#[test]
|
||||
fn getegid() {
|
||||
assert_eq!(crate::getegid(), Ok(0));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn getens() {
|
||||
assert_eq!(crate::getens(), Ok(1));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn geteuid() {
|
||||
assert_eq!(crate::geteuid(), Ok(0));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn getgid() {
|
||||
assert_eq!(crate::getgid(), Ok(0));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn getns() {
|
||||
assert_eq!(crate::getns(), Ok(1));
|
||||
}
|
||||
|
||||
//TODO: getpid
|
||||
|
||||
//TODO: getpgid
|
||||
|
||||
//TODO: getppid
|
||||
|
||||
#[test]
|
||||
fn getuid() {
|
||||
assert_eq!(crate::getuid(), Ok(0));
|
||||
}
|
||||
|
||||
//TODO: iopl
|
||||
|
||||
//TODO: kill
|
||||
|
||||
//TODO: link (probably will not work)
|
||||
|
||||
#[test]
|
||||
fn lseek() {
|
||||
let path = "file:/tmp/syscall-tests-lseek";
|
||||
let fd = dbg!(
|
||||
crate::open(
|
||||
dbg!(path),
|
||||
crate::O_CREAT | crate::O_RDWR | crate::O_CLOEXEC
|
||||
)
|
||||
).unwrap();
|
||||
|
||||
{
|
||||
let mut buf = [0; 256];
|
||||
for i in 0..buf.len() {
|
||||
buf[i] = i as u8;
|
||||
}
|
||||
assert_eq!(dbg!(crate::write(fd, &buf)), Ok(buf.len()));
|
||||
|
||||
assert_eq!(dbg!(crate::lseek(fd, 0, crate::SEEK_CUR)), Ok(buf.len()));
|
||||
assert_eq!(dbg!(crate::lseek(fd, 0, crate::SEEK_SET)), Ok(0));
|
||||
assert_eq!(dbg!(crate::lseek(fd, 0, crate::SEEK_END)), Ok(buf.len()));
|
||||
assert_eq!(dbg!(crate::lseek(fd, 0, crate::SEEK_SET)), Ok(0));
|
||||
}
|
||||
|
||||
{
|
||||
let mut buf = [0; 256];
|
||||
assert_eq!(dbg!(crate::read(fd, &mut buf)), Ok(buf.len()));
|
||||
for i in 0..buf.len() {
|
||||
assert_eq!(buf[i], i as u8);
|
||||
}
|
||||
|
||||
assert_eq!(dbg!(crate::lseek(fd, 0, crate::SEEK_CUR)), Ok(buf.len()));
|
||||
assert_eq!(dbg!(crate::lseek(fd, 0, crate::SEEK_SET)), Ok(0));
|
||||
assert_eq!(dbg!(crate::lseek(fd, 0, crate::SEEK_END)), Ok(buf.len()));
|
||||
assert_eq!(dbg!(crate::lseek(fd, 0, crate::SEEK_SET)), Ok(0));
|
||||
}
|
||||
|
||||
assert_eq!(dbg!(crate::close(fd)), Ok(0));
|
||||
}
|
||||
|
||||
//TODO: mkns
|
||||
|
||||
//TODO: mprotect
|
||||
|
||||
#[test]
|
||||
fn nanosleep() {
|
||||
let req = crate::TimeSpec {
|
||||
tv_sec: 0,
|
||||
tv_nsec: 0,
|
||||
};
|
||||
let mut rem = crate::TimeSpec::default();
|
||||
assert_eq!(crate::nanosleep(&req, &mut rem), Ok(0));
|
||||
assert_eq!(rem, crate::TimeSpec::default());
|
||||
}
|
||||
|
||||
//TODO: open
|
||||
|
||||
//TODO: physalloc
|
||||
|
||||
//TODO: physfree
|
||||
|
||||
//TODO: physmap
|
||||
|
||||
//TODO: physunmap
|
||||
|
||||
#[test]
|
||||
fn pipe2() {
|
||||
let mut fds = [0, 0];
|
||||
assert_eq!(dbg!(crate::pipe2(&mut fds, crate::O_CLOEXEC)), Ok(0));
|
||||
assert_ne!(dbg!(fds), [0, 0]);
|
||||
|
||||
{
|
||||
let mut buf = [0; 256];
|
||||
for i in 0..buf.len() {
|
||||
buf[i] = i as u8;
|
||||
}
|
||||
assert_eq!(dbg!(crate::write(fds[1], &buf)), Ok(buf.len()));
|
||||
}
|
||||
|
||||
{
|
||||
let mut buf = [0; 256];
|
||||
assert_eq!(dbg!(crate::read(fds[0], &mut buf)), Ok(buf.len()));
|
||||
for i in 0..buf.len() {
|
||||
assert_eq!(buf[i], i as u8);
|
||||
}
|
||||
}
|
||||
|
||||
assert_eq!(dbg!(crate::close(fds[0])), Ok(0));
|
||||
assert_eq!(dbg!(crate::close(fds[1])), Ok(0));
|
||||
}
|
||||
|
||||
//TODO: read
|
||||
|
||||
#[test]
|
||||
fn rmdir() {
|
||||
let path = "file:/tmp/syscall-tests-rmdir";
|
||||
let fd = dbg!(
|
||||
crate::open(
|
||||
dbg!(path),
|
||||
crate::O_CREAT | crate::O_DIRECTORY | crate::O_CLOEXEC
|
||||
)
|
||||
).unwrap();
|
||||
|
||||
assert_eq!(dbg!(crate::close(fd)), Ok(0));
|
||||
|
||||
assert_eq!(dbg!(crate::rmdir(path)), Ok(0));
|
||||
}
|
||||
|
||||
//TODO: setpgid
|
||||
|
||||
//TODO: setregid
|
||||
|
||||
//TODO: setrens
|
||||
|
||||
//TODO: setreuid
|
||||
|
||||
//TODO: sigaction
|
||||
|
||||
//TODO: sigprocmask
|
||||
|
||||
//TODO: sigreturn
|
||||
|
||||
#[test]
|
||||
fn umask() {
|
||||
let old = dbg!(crate::umask(0o244)).unwrap();
|
||||
assert_eq!(dbg!(crate::umask(old)), Ok(0o244));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unlink() {
|
||||
let path = "file:/tmp/syscall-tests-unlink";
|
||||
let fd = dbg!(
|
||||
crate::open(
|
||||
dbg!(path),
|
||||
crate::O_CREAT | crate::O_RDWR | crate::O_CLOEXEC
|
||||
)
|
||||
).unwrap();
|
||||
|
||||
assert_eq!(dbg!(crate::close(fd)), Ok(0));
|
||||
|
||||
assert_eq!(dbg!(crate::unlink(path)), Ok(0));
|
||||
}
|
||||
|
||||
//TODO: virttophys
|
||||
|
||||
// waitpid tested by clone
|
||||
|
||||
//TODO: write
|
||||
|
||||
#[test]
|
||||
fn sched_yield() {
|
||||
assert_eq!(dbg!(crate::sched_yield()), Ok(0));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sigaction() {
|
||||
use std::{
|
||||
mem,
|
||||
sync::atomic::{AtomicBool, Ordering}
|
||||
};
|
||||
|
||||
static SA_HANDLER_WAS_RAN: AtomicBool = AtomicBool::new(false);
|
||||
static SA_HANDLER_2_WAS_IGNORED: AtomicBool = AtomicBool::new(false);
|
||||
|
||||
let child = unsafe { crate::clone(crate::CLONE_VM).unwrap() };
|
||||
|
||||
if child == 0 {
|
||||
let pid = crate::getpid().unwrap();
|
||||
|
||||
extern "C" fn hello_im_a_signal_handler(signal: usize) {
|
||||
assert_eq!(signal, crate::SIGUSR1);
|
||||
SA_HANDLER_WAS_RAN.store(true, Ordering::SeqCst);
|
||||
}
|
||||
|
||||
let my_signal_handler = crate::SigAction {
|
||||
sa_handler: Some(hello_im_a_signal_handler),
|
||||
..Default::default()
|
||||
};
|
||||
crate::sigaction(crate::SIGUSR1, Some(&my_signal_handler), None).unwrap();
|
||||
|
||||
crate::kill(pid, crate::SIGUSR1).unwrap(); // calls handler
|
||||
|
||||
let mut old_signal_handler = crate::SigAction::default();
|
||||
crate::sigaction(
|
||||
crate::SIGUSR1,
|
||||
Some(&crate::SigAction {
|
||||
sa_handler: unsafe { mem::transmute::<usize, Option<extern "C" fn(usize)>>(crate::SIG_IGN) },
|
||||
..Default::default()
|
||||
}),
|
||||
Some(&mut old_signal_handler)
|
||||
).unwrap();
|
||||
assert_eq!(my_signal_handler, old_signal_handler);
|
||||
|
||||
crate::kill(pid, crate::SIGUSR1).unwrap(); // does nothing
|
||||
|
||||
SA_HANDLER_2_WAS_IGNORED.store(true, Ordering::SeqCst);
|
||||
|
||||
crate::sigaction(
|
||||
crate::SIGUSR1,
|
||||
Some(&crate::SigAction {
|
||||
sa_handler: unsafe { mem::transmute::<usize, Option<extern "C" fn(usize)>>(crate::SIG_DFL) },
|
||||
..Default::default()
|
||||
}),
|
||||
Some(&mut old_signal_handler)
|
||||
).unwrap();
|
||||
|
||||
crate::kill(pid, crate::SIGUSR1).unwrap(); // actually exits
|
||||
} else {
|
||||
let mut status = 0;
|
||||
dbg!(crate::waitpid(child, &mut status, crate::WaitFlags::empty())).unwrap();
|
||||
|
||||
assert!(crate::wifsignaled(status));
|
||||
assert_eq!(crate::wtermsig(status), crate::SIGUSR1);
|
||||
|
||||
assert!(SA_HANDLER_WAS_RAN.load(Ordering::SeqCst));
|
||||
assert!(SA_HANDLER_2_WAS_IGNORED.load(Ordering::SeqCst));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1 +1 @@
|
|||
{"files":{"Cargo.toml":"526cfadda74195985a5d860855ef4d8213661e9fcde075a2c128121aa7848003","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"8b427f5bc501764575e52ba4f9d95673cf8f6d80a86d0d06599852e1a9a20a36","NEWS":"e7da9558db65f61008aa9196066a18bcb16b4c7c4369766a67ea7ec9d52b632d","README.md":"2388f555712995933c80721d9de80fc9fe3428dd61609cc01cd26079bd543468","src/dir.rs":"50501bbbe44046d3f74c2fa1d590405cc898d5d52643f18f28964b7a82eafb80","src/error.rs":"cc7d8eace0fff11cb342158d2885d5637bfb14b24ef30755e808554772039c5f","src/file/imp/mod.rs":"bec50fb99c14cb4a49402bdbb7c5e6b5b8ff785b06b6fcb13267f35df8f3c8c2","src/file/imp/other.rs":"99c8f9f3251199fc31e7b88810134712e5725fb6fa14648696ed5cbea980fc5b","src/file/imp/unix.rs":"afc860978e362b1266b40722181fc3a509af72ce942a1b2dcd38ef1776897af3","src/file/imp/windows.rs":"03d81d71c404f0d448e1162825d6fbd57a78b4af8d4dc5287ec2e7c5a873d7cc","src/file/mod.rs":"ae7246a5c1445afa89765097742c11383ae996ea7046e8903f2dcbdb197bce53","src/lib.rs":"fb0c982c8dd2c6d0211c7d4542fa1c724d9ca45a8828ff5aeae866f4aa9d1507","src/spooled.rs":"34f5305923de710c58228d68c143133a11843e7ad5029ee31448ab4ab6172b74","src/util.rs":"25c62fb5d87411fd9508596db69ea489e9026b9ad0ffc9996db1ac8670b3da02","tests/namedtempfile.rs":"07ad89e54c9ce79d6b85d37d367d9687ec6f2cabc6cc44cdefd42731056afd6a","tests/spooled.rs":"29e797d486d867cb6ac46d4cf126eb5868a069a4070c3f50ffa02fbb0b887934","tests/tempdir.rs":"771d555d4eaa410207d212eb3744e016e0b5a22f1f1b7199636a4fac5daaf952","tests/tempfile.rs":"a1dacfd9b1ee3c40fdde5131b33995f3cfd62a212455c8664a98c735b9954ee6"},"package":"7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9"}
|
||||
{"files":{"Cargo.toml":"685243e302f6e014de9c8e9b95596e5f63c7bf7fde42e8e66a41a6bc7fd5e803","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"8b427f5bc501764575e52ba4f9d95673cf8f6d80a86d0d06599852e1a9a20a36","NEWS":"4255c86ac140a4d08423cd05cbd0aa42ff796bb4b38579dd19cde289ee3baecd","README.md":"db6717cbd0b3cbbce5f3cdb8a80d8f2d90b1be251b4c1c647557ae0f78ec9748","src/dir.rs":"4499ff439b740f8d2f01458664e2bf72bbfdd1206226780c6a91fb309ef15707","src/error.rs":"cc7d8eace0fff11cb342158d2885d5637bfb14b24ef30755e808554772039c5f","src/file/imp/mod.rs":"f6da9fcd93f11889670a251fdd8231b5f4614e5a971b7b183f52b44af68568d5","src/file/imp/other.rs":"99c8f9f3251199fc31e7b88810134712e5725fb6fa14648696ed5cbea980fc5b","src/file/imp/unix.rs":"cf8eeceecfddc37c9eaf95a1ebe088314dc468f07fe357961d80817eef619ca4","src/file/imp/windows.rs":"03d81d71c404f0d448e1162825d6fbd57a78b4af8d4dc5287ec2e7c5a873d7cc","src/file/mod.rs":"bda4ee3998106089a4c0ccbc8e46dc22b7d3aec427487fd4e414fb132b378736","src/lib.rs":"e2b0df7e17cc6680a5bb0829d0433f069c6bf9eede2007d21e3b01a595df41a8","src/spooled.rs":"51fa1d7639027234e257d343a5d3c95f2e47899ba6a24f0abec8d4d729eba6d6","src/util.rs":"2bd80ee69009e7e36b596d0105bb00184cff04e899e9fcce2e4cc21f23dda073","tests/namedtempfile.rs":"0031cb33ae6faf45be103869b4d98af63bef4040dc489b323212eb7a7ef72a9a","tests/spooled.rs":"29e797d486d867cb6ac46d4cf126eb5868a069a4070c3f50ffa02fbb0b887934","tests/tempdir.rs":"771d555d4eaa410207d212eb3744e016e0b5a22f1f1b7199636a4fac5daaf952","tests/tempfile.rs":"92078a1e20a39af77c1daa9a422345d20c41584dd2010b4829911c8741d1c628"},"package":"5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4"}
|
|
@ -3,17 +3,16 @@
|
|||
# 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
|
||||
# to registry (e.g., crates.io) dependencies.
|
||||
#
|
||||
# If you believe there's an error in this file please file an
|
||||
# issue against the rust-lang/cargo repository. If you're
|
||||
# editing this file be aware that the upstream Cargo.toml
|
||||
# will likely look very different (and much more reasonable)
|
||||
# If you are reading this file be aware that the original Cargo.toml
|
||||
# will likely look very different (and much more reasonable).
|
||||
# See Cargo.toml.orig for the original contents.
|
||||
|
||||
[package]
|
||||
edition = "2018"
|
||||
name = "tempfile"
|
||||
version = "3.1.0"
|
||||
version = "3.3.0"
|
||||
authors = ["Steven Allen <steven@stebalien.com>", "The Rust Project Developers", "Ashley Mannix <ashleymannix@live.com.au>", "Jason White <jasonaw0@gmail.com>"]
|
||||
exclude = ["/.travis.yml", "/appveyor.yml"]
|
||||
description = "A library for managing temporary files and directories."
|
||||
|
@ -23,17 +22,22 @@ keywords = ["tempfile", "tmpfile", "filesystem"]
|
|||
license = "MIT OR Apache-2.0"
|
||||
repository = "https://github.com/Stebalien/tempfile"
|
||||
[dependencies.cfg-if]
|
||||
version = "0.1"
|
||||
version = "1"
|
||||
|
||||
[dependencies.rand]
|
||||
version = "0.7"
|
||||
[dependencies.fastrand]
|
||||
version = "1.6.0"
|
||||
|
||||
[dependencies.remove_dir_all]
|
||||
version = "0.5"
|
||||
[target."cfg(target_os = \"redox\")".dependencies.redox_syscall]
|
||||
version = "0.1"
|
||||
[target."cfg(unix)".dependencies.libc]
|
||||
[dev-dependencies.doc-comment]
|
||||
version = "0.3"
|
||||
|
||||
[features]
|
||||
nightly = []
|
||||
[target."cfg(any(unix, target_os = \"wasi\"))".dependencies.libc]
|
||||
version = "0.2.27"
|
||||
[target."cfg(target_os = \"redox\")".dependencies.redox_syscall]
|
||||
version = "0.2.9"
|
||||
[target."cfg(windows)".dependencies.winapi]
|
||||
version = "0.3"
|
||||
features = ["fileapi", "handleapi", "winbase"]
|
||||
|
|
|
@ -1,3 +1,30 @@
|
|||
3.3.0
|
||||
=====
|
||||
|
||||
Features:
|
||||
|
||||
* Replace rand with fastrand for a significantly smaller dependency tree. Cryptographic randomness
|
||||
isn't necessary for temporary file names, and isn't all that helpful either.
|
||||
* Add limited WASI support.
|
||||
* Add a function to extract the inner data from a `SpooledTempFile`.
|
||||
|
||||
Bug Fixes:
|
||||
|
||||
* Make it possible to persist unnamed temporary files on linux by removing the `O_EXCL` flag.
|
||||
* Fix redox minimum crate version.
|
||||
|
||||
3.2.0
|
||||
=====
|
||||
|
||||
Features:
|
||||
|
||||
* Bump rand dependency to `0.8`.
|
||||
* Bump cfg-if dependency to `1.0`
|
||||
|
||||
Other than that, this release mostly includes small cleanups and simplifications.
|
||||
|
||||
Breaking: The minimum rust version is now `1.40.0`.
|
||||
|
||||
3.1.0
|
||||
=====
|
||||
|
||||
|
|
|
@ -2,8 +2,7 @@ tempfile
|
|||
========
|
||||
|
||||
[![Crate](https://img.shields.io/crates/v/tempfile.svg)](https://crates.io/crates/tempfile)
|
||||
[![Build Status](https://travis-ci.org/Stebalien/tempfile.svg?branch=master)](https://travis-ci.org/Stebalien/tempfile)
|
||||
[![Build status](https://ci.appveyor.com/api/projects/status/5q00b8rvvg46i5tf/branch/master?svg=true)](https://ci.appveyor.com/project/Stebalien/tempfile/branch/master)
|
||||
[![Build Status](https://github.com/Stebalien/tempfile/actions/workflows/ci.yml/badge.svg?branch=master)](https://github.com/Stebalien/tempfile/actions/workflows/ci.yml?query=branch%3Amaster)
|
||||
|
||||
A secure, cross-platform, temporary file library for Rust. In addition to creating
|
||||
temporary files, this library also allows users to securely open multiple
|
||||
|
@ -15,7 +14,7 @@ patterns and surprisingly difficult to implement securely).
|
|||
Usage
|
||||
-----
|
||||
|
||||
Minimum required Rust version: 1.32.0
|
||||
Minimum required Rust version: 1.40.0
|
||||
|
||||
Add this to your `Cargo.toml`:
|
||||
```toml
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
// except according to those terms.
|
||||
|
||||
use remove_dir_all::remove_dir_all;
|
||||
use std::mem;
|
||||
use std::path::{self, Path, PathBuf};
|
||||
use std::{fmt, fs, io};
|
||||
|
||||
|
@ -20,7 +21,7 @@ use crate::Builder;
|
|||
/// The `tempdir` function creates a directory in the file system
|
||||
/// and returns a [`TempDir`].
|
||||
/// The directory will be automatically deleted when the `TempDir`s
|
||||
/// desctructor is run.
|
||||
/// destructor is run.
|
||||
///
|
||||
/// # Resource Leaking
|
||||
///
|
||||
|
@ -69,7 +70,7 @@ pub fn tempdir() -> io::Result<TempDir> {
|
|||
/// The `tempdir` function creates a directory in the file system
|
||||
/// and returns a [`TempDir`].
|
||||
/// The directory will be automatically deleted when the `TempDir`s
|
||||
/// desctructor is run.
|
||||
/// destructor is run.
|
||||
///
|
||||
/// # Resource Leaking
|
||||
///
|
||||
|
@ -192,7 +193,7 @@ pub fn tempdir_in<P: AsRef<Path>>(dir: P) -> io::Result<TempDir> {
|
|||
/// [`std::fs`]: http://doc.rust-lang.org/std/fs/index.html
|
||||
/// [`std::process::exit()`]: http://doc.rust-lang.org/std/process/fn.exit.html
|
||||
pub struct TempDir {
|
||||
path: Option<PathBuf>,
|
||||
path: Box<Path>,
|
||||
}
|
||||
|
||||
impl TempDir {
|
||||
|
@ -292,7 +293,7 @@ impl TempDir {
|
|||
/// # }
|
||||
/// ```
|
||||
pub fn path(&self) -> &path::Path {
|
||||
self.path.as_ref().unwrap()
|
||||
self.path.as_ref()
|
||||
}
|
||||
|
||||
/// Persist the temporary directory to disk, returning the [`PathBuf`] where it is located.
|
||||
|
@ -322,11 +323,16 @@ impl TempDir {
|
|||
/// # Ok(())
|
||||
/// # }
|
||||
/// ```
|
||||
pub fn into_path(mut self) -> PathBuf {
|
||||
self.path.take().unwrap()
|
||||
pub fn into_path(self) -> PathBuf {
|
||||
// Prevent the Drop impl from being called.
|
||||
let mut this = mem::ManuallyDrop::new(self);
|
||||
|
||||
// replace this.path with an empty Box, since an empty Box does not
|
||||
// allocate any heap memory.
|
||||
mem::replace(&mut this.path, PathBuf::new().into_boxed_path()).into()
|
||||
}
|
||||
|
||||
/// Closes and removes the temporary directory, returing a `Result`.
|
||||
/// Closes and removes the temporary directory, returning a `Result`.
|
||||
///
|
||||
/// Although `TempDir` removes the directory on drop, in the destructor
|
||||
/// any errors are ignored. To detect errors cleaning up the temporary
|
||||
|
@ -369,8 +375,12 @@ impl TempDir {
|
|||
pub fn close(mut self) -> io::Result<()> {
|
||||
let result = remove_dir_all(self.path()).with_err_path(|| self.path());
|
||||
|
||||
// Prevent the Drop impl from removing the dir a second time.
|
||||
self.path = None;
|
||||
// Set self.path to empty Box to release the memory, since an empty
|
||||
// Box does not allocate any heap memory.
|
||||
self.path = PathBuf::new().into_boxed_path();
|
||||
|
||||
// Prevent the Drop impl from being called.
|
||||
mem::forget(self);
|
||||
|
||||
result
|
||||
}
|
||||
|
@ -392,15 +402,14 @@ impl fmt::Debug for TempDir {
|
|||
|
||||
impl Drop for TempDir {
|
||||
fn drop(&mut self) {
|
||||
// Path is `None` if `close()` or `into_path()` has been called.
|
||||
if let Some(ref p) = self.path {
|
||||
let _ = remove_dir_all(p);
|
||||
}
|
||||
let _ = remove_dir_all(self.path());
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn create(path: PathBuf) -> io::Result<TempDir> {
|
||||
fs::create_dir(&path)
|
||||
.with_err_path(|| &path)
|
||||
.map(|_| TempDir { path: Some(path) })
|
||||
.map(|_| TempDir {
|
||||
path: path.into_boxed_path(),
|
||||
})
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
cfg_if! {
|
||||
if #[cfg(any(unix, target_os = "redox"))] {
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(any(unix, target_os = "redox", target_os = "wasi"))] {
|
||||
mod unix;
|
||||
pub use self::unix::*;
|
||||
} else if #[cfg(windows)] {
|
||||
|
|
|
@ -2,10 +2,18 @@ use std::env;
|
|||
use std::ffi::{CString, OsStr};
|
||||
use std::fs::{self, File, OpenOptions};
|
||||
use std::io;
|
||||
use std::os::unix::ffi::OsStrExt;
|
||||
use std::os::unix::fs::{MetadataExt, OpenOptionsExt};
|
||||
use std::path::Path;
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(not(target_os = "wasi"))] {
|
||||
use std::os::unix::ffi::OsStrExt;
|
||||
use std::os::unix::fs::{MetadataExt, OpenOptionsExt};
|
||||
} else {
|
||||
use std::os::wasi::ffi::OsStrExt;
|
||||
#[cfg(feature = "nightly")]
|
||||
use std::os::wasi::fs::MetadataExt;
|
||||
}
|
||||
}
|
||||
use crate::util;
|
||||
use std::path::Path;
|
||||
|
||||
#[cfg(not(target_os = "redox"))]
|
||||
use libc::{c_char, c_int, link, rename, unlink};
|
||||
|
@ -33,12 +41,14 @@ pub fn cstr(path: &Path) -> io::Result<CString> {
|
|||
}
|
||||
|
||||
pub fn create_named(path: &Path, open_options: &mut OpenOptions) -> io::Result<File> {
|
||||
open_options
|
||||
.read(true)
|
||||
.write(true)
|
||||
.create_new(true)
|
||||
.mode(0o600)
|
||||
.open(path)
|
||||
open_options.read(true).write(true).create_new(true);
|
||||
|
||||
#[cfg(not(target_os = "wasi"))]
|
||||
{
|
||||
open_options.mode(0o600);
|
||||
}
|
||||
|
||||
open_options.open(path)
|
||||
}
|
||||
|
||||
fn create_unlinked(path: &Path) -> io::Result<File> {
|
||||
|
@ -60,11 +70,11 @@ fn create_unlinked(path: &Path) -> io::Result<File> {
|
|||
|
||||
#[cfg(target_os = "linux")]
|
||||
pub fn create(dir: &Path) -> io::Result<File> {
|
||||
use libc::{EISDIR, ENOENT, EOPNOTSUPP, O_EXCL, O_TMPFILE};
|
||||
use libc::{EISDIR, ENOENT, EOPNOTSUPP, O_TMPFILE};
|
||||
OpenOptions::new()
|
||||
.read(true)
|
||||
.write(true)
|
||||
.custom_flags(O_TMPFILE | O_EXCL) // do not mix with `create_new(true)`
|
||||
.custom_flags(O_TMPFILE) // do not mix with `create_new(true)`
|
||||
.open(dir)
|
||||
.or_else(|e| {
|
||||
match e.raw_os_error() {
|
||||
|
@ -90,6 +100,7 @@ fn create_unix(dir: &Path) -> io::Result<File> {
|
|||
)
|
||||
}
|
||||
|
||||
#[cfg(any(not(target_os = "wasi"), feature = "nightly"))]
|
||||
pub fn reopen(file: &File, path: &Path) -> io::Result<File> {
|
||||
let new_file = OpenOptions::new().read(true).write(true).open(path)?;
|
||||
let old_meta = file.metadata()?;
|
||||
|
@ -103,6 +114,14 @@ pub fn reopen(file: &File, path: &Path) -> io::Result<File> {
|
|||
Ok(new_file)
|
||||
}
|
||||
|
||||
#[cfg(all(target_os = "wasi", not(feature = "nightly")))]
|
||||
pub fn reopen(_file: &File, _path: &Path) -> io::Result<File> {
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::Other,
|
||||
"this operation is supported on WASI only on nightly Rust (with `nightly` feature enabled)",
|
||||
));
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "redox"))]
|
||||
pub fn persist(old_path: &Path, new_path: &Path, overwrite: bool) -> io::Result<()> {
|
||||
unsafe {
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
use std;
|
||||
use std::env;
|
||||
use std::error;
|
||||
use std::ffi::OsStr;
|
||||
|
@ -139,7 +138,7 @@ impl error::Error for PathPersistError {
|
|||
///
|
||||
/// When dropped, the temporary file is deleted.
|
||||
pub struct TempPath {
|
||||
path: PathBuf,
|
||||
path: Box<Path>,
|
||||
}
|
||||
|
||||
impl TempPath {
|
||||
|
@ -177,8 +176,8 @@ impl TempPath {
|
|||
/// # }
|
||||
/// ```
|
||||
pub fn close(mut self) -> io::Result<()> {
|
||||
let result = fs::remove_file(&self.path).with_err_path(|| &self.path);
|
||||
mem::replace(&mut self.path, PathBuf::new());
|
||||
let result = fs::remove_file(&self.path).with_err_path(|| &*self.path);
|
||||
self.path = PathBuf::new().into_boxed_path();
|
||||
mem::forget(self);
|
||||
result
|
||||
}
|
||||
|
@ -189,7 +188,10 @@ impl TempPath {
|
|||
/// If this method fails, it will return `self` in the resulting
|
||||
/// [`PathPersistError`].
|
||||
///
|
||||
/// Note: Temporary files cannot be persisted across filesystems.
|
||||
/// Note: Temporary files cannot be persisted across filesystems. Also
|
||||
/// neither the file contents nor the containing directory are
|
||||
/// synchronized, so the update may not yet have reached the disk when
|
||||
/// `persist` returns.
|
||||
///
|
||||
/// # Security
|
||||
///
|
||||
|
@ -229,7 +231,7 @@ impl TempPath {
|
|||
// Don't drop `self`. We don't want to try deleting the old
|
||||
// temporary file path. (It'll fail, but the failure is never
|
||||
// seen.)
|
||||
mem::replace(&mut self.path, PathBuf::new());
|
||||
self.path = PathBuf::new().into_boxed_path();
|
||||
mem::forget(self);
|
||||
Ok(())
|
||||
}
|
||||
|
@ -240,7 +242,7 @@ impl TempPath {
|
|||
}
|
||||
}
|
||||
|
||||
/// Persist the temporary file at the target path iff no file exists there.
|
||||
/// Persist the temporary file at the target path if and only if no file exists there.
|
||||
///
|
||||
/// If a file exists at the target path, fail. If this method fails, it will
|
||||
/// return `self` in the resulting [`PathPersistError`].
|
||||
|
@ -291,7 +293,7 @@ impl TempPath {
|
|||
// Don't drop `self`. We don't want to try deleting the old
|
||||
// temporary file path. (It'll fail, but the failure is never
|
||||
// seen.)
|
||||
mem::replace(&mut self.path, PathBuf::new());
|
||||
self.path = PathBuf::new().into_boxed_path();
|
||||
mem::forget(self);
|
||||
Ok(())
|
||||
}
|
||||
|
@ -339,10 +341,9 @@ impl TempPath {
|
|||
// Don't drop `self`. We don't want to try deleting the old
|
||||
// temporary file path. (It'll fail, but the failure is never
|
||||
// seen.)
|
||||
let mut path = PathBuf::new();
|
||||
mem::swap(&mut self.path, &mut path);
|
||||
let path = mem::replace(&mut self.path, PathBuf::new().into_boxed_path());
|
||||
mem::forget(self);
|
||||
Ok(path)
|
||||
Ok(path.into())
|
||||
}
|
||||
Err(e) => Err(PathPersistError {
|
||||
error: e,
|
||||
|
@ -350,6 +351,18 @@ impl TempPath {
|
|||
}),
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a new TempPath from an existing path. This can be done even if no
|
||||
/// file exists at the given path.
|
||||
///
|
||||
/// This is mostly useful for interacting with libraries and external
|
||||
/// components that provide files to be consumed or expect a path with no
|
||||
/// existing file to be given.
|
||||
pub fn from_path(path: impl Into<PathBuf>) -> Self {
|
||||
Self {
|
||||
path: path.into().into_boxed_path(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for TempPath {
|
||||
|
@ -584,7 +597,7 @@ impl NamedTempFile {
|
|||
///
|
||||
/// See [`NamedTempFile::new()`] for details.
|
||||
///
|
||||
/// [`NamedTempFile::new()`]: #method.new_in
|
||||
/// [`NamedTempFile::new()`]: #method.new
|
||||
pub fn new_in<P: AsRef<Path>>(dir: P) -> io::Result<NamedTempFile> {
|
||||
Builder::new().tempfile_in(dir)
|
||||
}
|
||||
|
@ -662,11 +675,14 @@ impl NamedTempFile {
|
|||
/// If this method fails, it will return `self` in the resulting
|
||||
/// [`PersistError`].
|
||||
///
|
||||
/// Note: Temporary files cannot be persisted across filesystems.
|
||||
/// Note: Temporary files cannot be persisted across filesystems. Also
|
||||
/// neither the file contents nor the containing directory are
|
||||
/// synchronized, so the update may not yet have reached the disk when
|
||||
/// `persist` returns.
|
||||
///
|
||||
/// # Security
|
||||
///
|
||||
/// This method persists the temporary file using it's path and may not be
|
||||
/// This method persists the temporary file using its path and may not be
|
||||
/// secure in the in all cases. Please read the security section on the top
|
||||
/// level documentation of this type for details.
|
||||
///
|
||||
|
@ -709,7 +725,7 @@ impl NamedTempFile {
|
|||
}
|
||||
}
|
||||
|
||||
/// Persist the temporary file at the target path iff no file exists there.
|
||||
/// Persist the temporary file at the target path if and only if no file exists there.
|
||||
///
|
||||
/// If a file exists at the target path, fail. If this method fails, it will
|
||||
/// return `self` in the resulting PersistError.
|
||||
|
@ -720,7 +736,7 @@ impl NamedTempFile {
|
|||
///
|
||||
/// # Security
|
||||
///
|
||||
/// This method persists the temporary file using it's path and may not be
|
||||
/// This method persists the temporary file using its path and may not be
|
||||
/// secure in the in all cases. Please read the security section on the top
|
||||
/// level documentation of this type for details.
|
||||
///
|
||||
|
@ -949,7 +965,9 @@ pub(crate) fn create_named(
|
|||
imp::create_named(&path, open_options)
|
||||
.with_err_path(|| path.clone())
|
||||
.map(|file| NamedTempFile {
|
||||
path: TempPath { path },
|
||||
path: TempPath {
|
||||
path: path.into_boxed_path(),
|
||||
},
|
||||
file,
|
||||
})
|
||||
}
|
||||
|
|
|
@ -27,6 +27,42 @@
|
|||
//! rely on file paths for _some_ operations. See the security documentation on
|
||||
//! the `NamedTempFile` type for more information.
|
||||
//!
|
||||
//! ## Early drop pitfall
|
||||
//!
|
||||
//! Because `TempDir` and `NamedTempFile` rely on their destructors for cleanup, this can lead
|
||||
//! to an unexpected early removal of the directory/file, usually when working with APIs which are
|
||||
//! generic over `AsRef<Path>`. Consider the following example:
|
||||
//!
|
||||
//! ```no_run
|
||||
//! # use tempfile::tempdir;
|
||||
//! # use std::io;
|
||||
//! # use std::process::Command;
|
||||
//! # fn main() {
|
||||
//! # if let Err(_) = run() {
|
||||
//! # ::std::process::exit(1);
|
||||
//! # }
|
||||
//! # }
|
||||
//! # fn run() -> Result<(), io::Error> {
|
||||
//! // Create a directory inside of `std::env::temp_dir()`.
|
||||
//! let temp_dir = tempdir()?;
|
||||
//!
|
||||
//! // Spawn the `touch` command inside the temporary directory and collect the exit status
|
||||
//! // Note that `temp_dir` is **not** moved into `current_dir`, but passed as a reference
|
||||
//! let exit_status = Command::new("touch").arg("tmp").current_dir(&temp_dir).status()?;
|
||||
//! assert!(exit_status.success());
|
||||
//!
|
||||
//! # Ok(())
|
||||
//! # }
|
||||
//! ```
|
||||
//!
|
||||
//! This works because a reference to `temp_dir` is passed to `current_dir`, resulting in the
|
||||
//! destructor of `temp_dir` being run after the `Command` has finished execution. Moving the
|
||||
//! `TempDir` into the `current_dir` call would result in the `TempDir` being converted into
|
||||
//! an internal representation, with the original value being dropped and the directory thus
|
||||
//! being deleted, before the command can be executed.
|
||||
//!
|
||||
//! The `touch` command would fail with an `No such file or directory` error.
|
||||
//!
|
||||
//! ## Examples
|
||||
//!
|
||||
//! Create a temporary file and write some data into it:
|
||||
|
@ -124,9 +160,11 @@
|
|||
)]
|
||||
#![cfg_attr(test, deny(warnings))]
|
||||
#![deny(rust_2018_idioms)]
|
||||
#![allow(clippy::redundant_field_names)]
|
||||
#![cfg_attr(feature = "nightly", feature(wasi_ext))]
|
||||
|
||||
#[macro_use]
|
||||
extern crate cfg_if;
|
||||
#[cfg(doctest)]
|
||||
doc_comment::doctest!("../README.md");
|
||||
|
||||
const NUM_RETRIES: u32 = 1 << 31;
|
||||
const NUM_RAND_CHARS: usize = 6;
|
||||
|
@ -143,7 +181,9 @@ mod spooled;
|
|||
mod util;
|
||||
|
||||
pub use crate::dir::{tempdir, tempdir_in, TempDir};
|
||||
pub use crate::file::{tempfile, tempfile_in, NamedTempFile, PathPersistError, PersistError, TempPath};
|
||||
pub use crate::file::{
|
||||
tempfile, tempfile_in, NamedTempFile, PathPersistError, PersistError, TempPath,
|
||||
};
|
||||
pub use crate::spooled::{spooled_tempfile, SpooledTempFile};
|
||||
|
||||
/// Create a new temporary file or directory with custom parameters.
|
||||
|
|
|
@ -2,8 +2,9 @@ use crate::file::tempfile;
|
|||
use std::fs::File;
|
||||
use std::io::{self, Cursor, Read, Seek, SeekFrom, Write};
|
||||
|
||||
/// A wrapper for the two states of a `SpooledTempFile`.
|
||||
#[derive(Debug)]
|
||||
enum SpooledInner {
|
||||
pub enum SpooledData {
|
||||
InMemory(Cursor<Vec<u8>>),
|
||||
OnDisk(File),
|
||||
}
|
||||
|
@ -15,7 +16,7 @@ enum SpooledInner {
|
|||
#[derive(Debug)]
|
||||
pub struct SpooledTempFile {
|
||||
max_size: usize,
|
||||
inner: SpooledInner,
|
||||
inner: SpooledData,
|
||||
}
|
||||
|
||||
/// Create a new spooled temporary file.
|
||||
|
@ -66,15 +67,15 @@ impl SpooledTempFile {
|
|||
pub fn new(max_size: usize) -> SpooledTempFile {
|
||||
SpooledTempFile {
|
||||
max_size: max_size,
|
||||
inner: SpooledInner::InMemory(Cursor::new(Vec::new())),
|
||||
inner: SpooledData::InMemory(Cursor::new(Vec::new())),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns true if the file has been rolled over to disk.
|
||||
pub fn is_rolled(&self) -> bool {
|
||||
match self.inner {
|
||||
SpooledInner::InMemory(_) => false,
|
||||
SpooledInner::OnDisk(_) => true,
|
||||
SpooledData::InMemory(_) => false,
|
||||
SpooledData::OnDisk(_) => true,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -83,11 +84,11 @@ impl SpooledTempFile {
|
|||
pub fn roll(&mut self) -> io::Result<()> {
|
||||
if !self.is_rolled() {
|
||||
let mut file = tempfile()?;
|
||||
if let SpooledInner::InMemory(ref mut cursor) = self.inner {
|
||||
if let SpooledData::InMemory(ref mut cursor) = self.inner {
|
||||
file.write_all(cursor.get_ref())?;
|
||||
file.seek(SeekFrom::Start(cursor.position()))?;
|
||||
}
|
||||
self.inner = SpooledInner::OnDisk(file);
|
||||
self.inner = SpooledData::OnDisk(file);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
@ -97,20 +98,25 @@ impl SpooledTempFile {
|
|||
self.roll()?; // does nothing if already rolled over
|
||||
}
|
||||
match self.inner {
|
||||
SpooledInner::InMemory(ref mut cursor) => {
|
||||
SpooledData::InMemory(ref mut cursor) => {
|
||||
cursor.get_mut().resize(size as usize, 0);
|
||||
Ok(())
|
||||
}
|
||||
SpooledInner::OnDisk(ref mut file) => file.set_len(size),
|
||||
SpooledData::OnDisk(ref mut file) => file.set_len(size),
|
||||
}
|
||||
}
|
||||
|
||||
/// Consumes and returns the inner `SpooledData` type.
|
||||
pub fn into_inner(self) -> SpooledData {
|
||||
self.inner
|
||||
}
|
||||
}
|
||||
|
||||
impl Read for SpooledTempFile {
|
||||
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
|
||||
match self.inner {
|
||||
SpooledInner::InMemory(ref mut cursor) => cursor.read(buf),
|
||||
SpooledInner::OnDisk(ref mut file) => file.read(buf),
|
||||
SpooledData::InMemory(ref mut cursor) => cursor.read(buf),
|
||||
SpooledData::OnDisk(ref mut file) => file.read(buf),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -119,7 +125,7 @@ impl Write for SpooledTempFile {
|
|||
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
|
||||
// roll over to file if necessary
|
||||
let mut rolling = false;
|
||||
if let SpooledInner::InMemory(ref mut cursor) = self.inner {
|
||||
if let SpooledData::InMemory(ref mut cursor) = self.inner {
|
||||
rolling = cursor.position() as usize + buf.len() > self.max_size;
|
||||
}
|
||||
if rolling {
|
||||
|
@ -128,16 +134,16 @@ impl Write for SpooledTempFile {
|
|||
|
||||
// write the bytes
|
||||
match self.inner {
|
||||
SpooledInner::InMemory(ref mut cursor) => cursor.write(buf),
|
||||
SpooledInner::OnDisk(ref mut file) => file.write(buf),
|
||||
SpooledData::InMemory(ref mut cursor) => cursor.write(buf),
|
||||
SpooledData::OnDisk(ref mut file) => file.write(buf),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn flush(&mut self) -> io::Result<()> {
|
||||
match self.inner {
|
||||
SpooledInner::InMemory(ref mut cursor) => cursor.flush(),
|
||||
SpooledInner::OnDisk(ref mut file) => file.flush(),
|
||||
SpooledData::InMemory(ref mut cursor) => cursor.flush(),
|
||||
SpooledData::OnDisk(ref mut file) => file.flush(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -145,8 +151,8 @@ impl Write for SpooledTempFile {
|
|||
impl Seek for SpooledTempFile {
|
||||
fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
|
||||
match self.inner {
|
||||
SpooledInner::InMemory(ref mut cursor) => cursor.seek(pos),
|
||||
SpooledInner::OnDisk(ref mut file) => file.seek(pos),
|
||||
SpooledData::InMemory(ref mut cursor) => cursor.seek(pos),
|
||||
SpooledData::OnDisk(ref mut file) => file.seek(pos),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,23 +1,16 @@
|
|||
use rand::distributions::Alphanumeric;
|
||||
use rand::{self, Rng};
|
||||
use fastrand;
|
||||
use std::ffi::{OsStr, OsString};
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::{io, str};
|
||||
use std::{io, iter::repeat_with};
|
||||
|
||||
use crate::error::IoResultExt;
|
||||
|
||||
fn tmpname(prefix: &OsStr, suffix: &OsStr, rand_len: usize) -> OsString {
|
||||
let mut buf = OsString::with_capacity(prefix.len() + suffix.len() + rand_len);
|
||||
buf.push(prefix);
|
||||
|
||||
// Push each character in one-by-one. Unfortunately, this is the only
|
||||
// safe(ish) simple way to do this without allocating a temporary
|
||||
// String/Vec.
|
||||
unsafe {
|
||||
rand::thread_rng()
|
||||
.sample_iter(&Alphanumeric)
|
||||
.take(rand_len)
|
||||
.for_each(|b| buf.push(str::from_utf8_unchecked(&[b as u8])))
|
||||
let mut char_buf = [0u8; 4];
|
||||
for c in repeat_with(fastrand::alphanumeric).take(rand_len) {
|
||||
buf.push(c.encode_utf8(&mut char_buf));
|
||||
}
|
||||
buf.push(suffix);
|
||||
buf
|
||||
|
@ -33,7 +26,11 @@ pub fn create_helper<F, R>(
|
|||
where
|
||||
F: Fn(PathBuf) -> io::Result<R>,
|
||||
{
|
||||
let num_retries = if random_len != 0 { crate::NUM_RETRIES } else { 1 };
|
||||
let num_retries = if random_len != 0 {
|
||||
crate::NUM_RETRIES
|
||||
} else {
|
||||
1
|
||||
};
|
||||
|
||||
for _ in 0..num_retries {
|
||||
let path = base.join(tmpname(prefix, suffix, random_len));
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
#![deny(rust_2018_idioms)]
|
||||
|
||||
use std::env;
|
||||
use std::ffi::{OsStr, OsString};
|
||||
use std::fs::File;
|
||||
use std::io::{Read, Seek, SeekFrom, Write};
|
||||
use std::path::Path;
|
||||
use tempfile::{Builder, NamedTempFile};
|
||||
use std::path::{Path, PathBuf};
|
||||
use tempfile::{tempdir, Builder, NamedTempFile, TempPath};
|
||||
|
||||
fn exists<P: AsRef<Path>>(path: P) -> bool {
|
||||
std::fs::metadata(path.as_ref()).is_ok()
|
||||
|
@ -216,6 +217,50 @@ fn test_temppath_persist_noclobber() {
|
|||
std::fs::remove_file(&persist_path).unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn temp_path_from_existing() {
|
||||
let tmp_dir = tempdir().unwrap();
|
||||
let tmp_file_path_1 = tmp_dir.path().join("testfile1");
|
||||
let tmp_file_path_2 = tmp_dir.path().join("testfile2");
|
||||
|
||||
File::create(&tmp_file_path_1).unwrap();
|
||||
assert!(tmp_file_path_1.exists(), "Test file 1 hasn't been created");
|
||||
|
||||
File::create(&tmp_file_path_2).unwrap();
|
||||
assert!(tmp_file_path_2.exists(), "Test file 2 hasn't been created");
|
||||
|
||||
let tmp_path = TempPath::from_path(&tmp_file_path_1);
|
||||
assert!(
|
||||
tmp_file_path_1.exists(),
|
||||
"Test file has been deleted before dropping TempPath"
|
||||
);
|
||||
|
||||
drop(tmp_path);
|
||||
assert!(
|
||||
!tmp_file_path_1.exists(),
|
||||
"Test file exists after dropping TempPath"
|
||||
);
|
||||
assert!(
|
||||
tmp_file_path_2.exists(),
|
||||
"Test file 2 has been deleted before dropping TempDir"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[allow(unreachable_code)]
|
||||
fn temp_path_from_argument_types() {
|
||||
// This just has to compile
|
||||
return;
|
||||
|
||||
TempPath::from_path("");
|
||||
TempPath::from_path(String::new());
|
||||
TempPath::from_path(OsStr::new(""));
|
||||
TempPath::from_path(OsString::new());
|
||||
TempPath::from_path(Path::new(""));
|
||||
TempPath::from_path(PathBuf::new());
|
||||
TempPath::from_path(PathBuf::new().into_boxed_path());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_write_after_close() {
|
||||
let path = NamedTempFile::new().unwrap().into_temp_path();
|
||||
|
|
|
@ -26,6 +26,8 @@ fn test_cleanup() {
|
|||
assert!(num_files == 0);
|
||||
}
|
||||
|
||||
// Only run this test on Linux. MacOS doesn't like us creating so many files, apparently.
|
||||
#[cfg(target_os = "linux")]
|
||||
#[test]
|
||||
fn test_pathological_cleaner() {
|
||||
let tmpdir = tempfile::tempdir().unwrap();
|
||||
|
|
Загрузка…
Ссылка в новой задаче