Compare commits
10 Commits
2e724d4f36
...
1cd2fb99b4
| Author | SHA1 | Date | |
|---|---|---|---|
| 1cd2fb99b4 | |||
| 4a4ef493e3 | |||
| b8eece98d2 | |||
| f7370c7fa3 | |||
| ec6e988377 | |||
| ade4c304da | |||
| aed7cdd0ca | |||
| 31a40f5c87 | |||
| 675afc4604 | |||
| fe9b522a7b |
+239
-4
@@ -1,3 +1,238 @@
|
||||
Version 1.94.0 (2026-03-05)
|
||||
==========================
|
||||
|
||||
<a id="1.94.0-Language"></a>
|
||||
|
||||
Language
|
||||
--------
|
||||
- [Impls and impl items inherit `dead_code` lint level of the corresponding traits and trait items](https://github.com/rust-lang/rust/pull/144113)
|
||||
- [Stabilize additional 29 RISC-V target features including large portions of the RVA22U64 / RVA23U64 profiles](https://github.com/rust-lang/rust/pull/145948)
|
||||
- [Add warn-by-default `unused_visibilities` lint for visibility on `const _` declarations](https://github.com/rust-lang/rust/pull/147136)
|
||||
- [Update to Unicode 17](https://github.com/rust-lang/rust/pull/148321)
|
||||
- [Avoid incorrect lifetime errors for closures](https://github.com/rust-lang/rust/pull/148329)
|
||||
|
||||
<a id="1.94.0-Platform-Support"></a>
|
||||
|
||||
Platform Support
|
||||
----------------
|
||||
|
||||
- [Add `riscv64im-unknown-none-elf` as a tier 3 target](https://github.com/rust-lang/rust/pull/148790)
|
||||
|
||||
Refer to Rust's [platform support page][platform-support-doc]
|
||||
for more information on Rust's tiered platform support.
|
||||
|
||||
[platform-support-doc]: https://doc.rust-lang.org/rustc/platform-support.html
|
||||
|
||||
<a id="1.94.0-Libraries"></a>
|
||||
|
||||
Libraries
|
||||
---------
|
||||
|
||||
- [Relax `T: Ord` bound for some `BinaryHeap<T>` methods.](https://github.com/rust-lang/rust/pull/149408)
|
||||
|
||||
<a id="1.94.0-Stabilized-APIs"></a>
|
||||
|
||||
Stabilized APIs
|
||||
---------------
|
||||
|
||||
- [`<[T]>::array_windows`](https://doc.rust-lang.org/stable/std/primitive.slice.html#method.array_windows)
|
||||
- [`<[T]>::element_offset`](https://doc.rust-lang.org/stable/std/primitive.slice.html#method.element_offset)
|
||||
- [`LazyCell::get`](https://doc.rust-lang.org/stable/std/cell/struct.LazyCell.html#method.get)
|
||||
- [`LazyCell::get_mut`](https://doc.rust-lang.org/stable/std/cell/struct.LazyCell.html#method.get_mut)
|
||||
- [`LazyCell::force_mut`](https://doc.rust-lang.org/stable/std/cell/struct.LazyCell.html#method.force_mut)
|
||||
- [`LazyLock::get`](https://doc.rust-lang.org/stable/std/sync/struct.LazyLock.html#method.get)
|
||||
- [`LazyLock::get_mut`](https://doc.rust-lang.org/stable/std/sync/struct.LazyLock.html#method.get_mut)
|
||||
- [`LazyLock::force_mut`](https://doc.rust-lang.org/stable/std/sync/struct.LazyLock.html#method.force_mut)
|
||||
- [`impl TryFrom<char> for usize`](https://doc.rust-lang.org/stable/std/convert/trait.TryFrom.html#impl-TryFrom%3Cchar%3E-for-usize)
|
||||
- [`std::iter::Peekable::next_if_map`](https://doc.rust-lang.org/stable/std/iter/struct.Peekable.html#method.next_if_map)
|
||||
- [`std::iter::Peekable::next_if_map_mut`](https://doc.rust-lang.org/stable/std/iter/struct.Peekable.html#method.next_if_map_mut)
|
||||
- [x86 `avx512fp16` intrinsics](https://github.com/rust-lang/rust/issues/127213)
|
||||
(excluding those that depend directly on the unstable `f16` type)
|
||||
- [AArch64 NEON fp16 intrinsics](https://github.com/rust-lang/rust/issues/136306)
|
||||
(excluding those that depend directly on the unstable `f16` type)
|
||||
- [`f32::consts::EULER_GAMMA`](https://doc.rust-lang.org/stable/std/f32/consts/constant.EULER_GAMMA.html)
|
||||
- [`f64::consts::EULER_GAMMA`](https://doc.rust-lang.org/stable/std/f64/consts/constant.EULER_GAMMA.html)
|
||||
- [`f32::consts::GOLDEN_RATIO`](https://doc.rust-lang.org/stable/std/f32/consts/constant.GOLDEN_RATIO.html)
|
||||
- [`f64::consts::GOLDEN_RATIO`](https://doc.rust-lang.org/stable/std/f64/consts/constant.GOLDEN_RATIO.html)
|
||||
|
||||
|
||||
These previously stable APIs are now stable in const contexts:
|
||||
|
||||
- [`f32::mul_add`](https://doc.rust-lang.org/stable/std/primitive.f32.html#method.mul_add)
|
||||
- [`f64::mul_add`](https://doc.rust-lang.org/stable/std/primitive.f64.html#method.mul_add)
|
||||
|
||||
|
||||
<a id="1.94.0-Cargo"></a>
|
||||
|
||||
Cargo
|
||||
-----
|
||||
|
||||
- Stabilize the config include key. The top-level include config key allows loading additional config files, enabling better organization, sharing, and management of Cargo configurations across projects and environments. [docs](https://doc.rust-lang.org/nightly/cargo/reference/config.html#including-extra-configuration-files) [#16284](https://github.com/rust-lang/cargo/pull/16284)
|
||||
- Stabilize the pubtime field in registry index. This records when a crate version was published and enables time-based dependency resolution in the future. Note that crates.io will gradually backfill existing packages when a new version is published. Not all crates have pubtime yet. [#16369](https://github.com/rust-lang/cargo/pull/16369) [#16372](https://github.com/rust-lang/cargo/pull/16372)
|
||||
- Cargo now parses [TOML v1.1](https://toml.io/en/v1.1.0) for manifests and configuration files. Note that using these features in Cargo.toml will raise your development MSRV, but the published manifest remains compatible with older parsers. [#16415](https://github.com/rust-lang/cargo/pull/16415)
|
||||
- [Make `CARGO_BIN_EXE_<crate>` available at runtime ](https://github.com/rust-lang/cargo/pull/16421/)
|
||||
|
||||
<a id="1.94.0-Compatibility-Notes"></a>
|
||||
|
||||
Compatibility Notes
|
||||
-------------------
|
||||
- [Forbid freely casting lifetime bounds of `dyn`-types](https://github.com/rust-lang/rust/pull/136776)
|
||||
- [Make closure capturing have consistent and correct behaviour around patterns](https://github.com/rust-lang/rust/pull/138961)
|
||||
Some finer details of how precise closure captures get affected by pattern matching have been changed. In some cases, this can cause a non-move closure that was previously capturing an entire variable by move, to now capture only part of that variable by move, and other parts by borrow. This can cause the borrow checker to complain where it previously didn't, or cause `Drop` to run at a different point in time.
|
||||
- [Standard library macros are now imported via prelude, not via injected `#[macro_use]`](https://github.com/rust-lang/rust/pull/139493)
|
||||
This will raise an error if macros of the same name are glob imported.
|
||||
For example if a crate defines their own `matches` macro and then glob imports that,
|
||||
it's now ambiguous whether the custom or standard library `matches` is meant and
|
||||
an explicit import of the name is required to resolve the ambiguity.
|
||||
One exception is `core::panic` and `std::panic`, if their import is ambiguous
|
||||
a new warning ([`ambiguous_panic_imports`](https://github.com/rust-lang/rust/issues/147319)) is raised.
|
||||
This may raise a new warning ([`ambiguous_panic_imports`](https://github.com/rust-lang/rust/issues/147319)) on `#![no_std]` code glob importing the std crate.
|
||||
Both `core::panic!` and `std::panic!` are then in scope and which is used is ambiguous.
|
||||
- [Don't strip shebang in expression-context `include!(…)`s](https://github.com/rust-lang/rust/pull/146377)
|
||||
This can cause previously working includes to no longer compile if they included files which started with a shebang.
|
||||
- [Ambiguous glob reexports are now also visible cross-crate](https://github.com/rust-lang/rust/pull/147984)
|
||||
This unifies behavior between local and cross-crate errors on these exports, which may introduce new ambiguity errors.
|
||||
- [Don't normalize where-clauses before checking well-formedness](https://github.com/rust-lang/rust/pull/148477)
|
||||
- [Introduce a future compatibility warning on codegen attributes on body-free trait methods](https://github.com/rust-lang/rust/pull/148756)
|
||||
These attributes currently have no effect in this position.
|
||||
- [On Windows `std::time::SystemTime::checked_sub_duration` will return `None` for times before the Windows epoch (1/1/1601)](https://github.com/rust-lang/rust/pull/148825)
|
||||
- [Lifetime identifiers such as `'a` are now NFC normalized](https://github.com/rust-lang/rust/pull/149192).
|
||||
- [Overhaul filename handling for cross-compiler consistency](https://github.com/rust-lang/rust/pull/149709)
|
||||
Any paths emitted by compiler now always respect the relative-ness of the paths and `--remap-path-prefix` given originally.
|
||||
One side-effect of this change is that paths emitted for local crates in Cargo (path dependencies and workspace members) are no longer absolute but relative when emitted as part of a diagnostic in a downstream crate.
|
||||
|
||||
<a id="1.94.0-Internal-Changes"></a>
|
||||
|
||||
Internal Changes
|
||||
----------------
|
||||
|
||||
These changes do not affect any public interfaces of Rust, but they represent
|
||||
significant improvements to the performance or internals of rustc and related
|
||||
tools.
|
||||
|
||||
- [Switch to `annotate-snippets` for error emission](https://github.com/rust-lang/rust/pull/150032)
|
||||
This should preserve mostly the same outputs in rustc error messages.
|
||||
|
||||
Version 1.93.1 (2026-02-12)
|
||||
===========================
|
||||
|
||||
<a id="1.93.1"></a>
|
||||
|
||||
- [Don't try to recover keyword as non-keyword identifier](https://github.com/rust-lang/rust/pull/150590), fixing an ICE that especially [affected rustfmt](https://github.com/rust-lang/rustfmt/issues/6739).
|
||||
- [Fix `clippy::panicking_unwrap` false-positive on field access with implicit deref](https://github.com/rust-lang/rust-clippy/pull/16196).
|
||||
- [Revert "Update wasm-related dependencies in CI"](https://github.com/rust-lang/rust/pull/152259), fixing file descriptor leaks on the `wasm32-wasip2` target.
|
||||
|
||||
Version 1.93.0 (2026-01-22)
|
||||
==========================
|
||||
|
||||
<a id="1.93.0-Language"></a>
|
||||
|
||||
Language
|
||||
--------
|
||||
- [Stabilize several s390x `vector`-related target features and the `is_s390x_feature_detected!` macro](https://github.com/rust-lang/rust/pull/145656)
|
||||
- [Stabilize declaration of C-style variadic functions for the `system` ABI](https://github.com/rust-lang/rust/pull/145954)
|
||||
- [Emit error when using some keyword as a `cfg` predicate](https://github.com/rust-lang/rust/pull/146978)
|
||||
- [Stabilize `asm_cfg`](https://github.com/rust-lang/rust/pull/147736)
|
||||
- [During const-evaluation, support copying pointers byte-by-byte](https://github.com/rust-lang/rust/pull/148259)
|
||||
- [LUB coercions now correctly handle function item types, and functions with differing safeties](https://github.com/rust-lang/rust/pull/148602)
|
||||
- [Allow `const` items that contain mutable references to `static` (which is *very* unsafe, but not *always* UB)](https://github.com/rust-lang/rust/pull/148746)
|
||||
- [Add warn-by-default `const_item_interior_mutations` lint to warn against calls which mutate interior mutable `const` items](https://github.com/rust-lang/rust/pull/148407)
|
||||
- [Add warn-by-default `function_casts_as_integer` lint](https://github.com/rust-lang/rust/pull/141470)
|
||||
|
||||
|
||||
<a id="1.93.0-Compiler"></a>
|
||||
|
||||
Compiler
|
||||
--------
|
||||
- [Stabilize `-Cjump-tables=bool`](https://github.com/rust-lang/rust/pull/145974). The flag was previously called `-Zno-jump-tables`.
|
||||
|
||||
<a id="1.93.0-Platform-Support"></a>
|
||||
|
||||
Platform Support
|
||||
----------------
|
||||
|
||||
- [Promote `riscv64a23-unknown-linux-gnu` to Tier 2 (without host tools)](https://github.com/rust-lang/rust/pull/148435)
|
||||
|
||||
Refer to Rust's [platform support page][platform-support-doc]
|
||||
for more information on Rust's tiered platform support.
|
||||
|
||||
[platform-support-doc]: https://doc.rust-lang.org/rustc/platform-support.html
|
||||
|
||||
<a id="1.93.0-Libraries"></a>
|
||||
|
||||
Libraries
|
||||
---------
|
||||
- [Stop internally using `specialization` on the `Copy` trait as it is unsound in the presence of lifetime dependent `Copy` implementations. This may result in some performance regressions as some standard library APIs may now call `Clone::clone` instead of performing bitwise copies](https://github.com/rust-lang/rust/pull/135634)
|
||||
- [Allow the global allocator to use thread-local storage and `std::thread::current()`](https://github.com/rust-lang/rust/pull/144465)
|
||||
- [Make `BTree::append` not update existing keys when appending an entry which already exists](https://github.com/rust-lang/rust/pull/145628)
|
||||
- [Don't require `T: RefUnwindSafe` for `vec::IntoIter<T>: UnwindSafe`](https://github.com/rust-lang/rust/pull/145665)
|
||||
|
||||
|
||||
<a id="1.93.0-Stabilized-APIs"></a>
|
||||
|
||||
Stabilized APIs
|
||||
---------------
|
||||
|
||||
- [`<[MaybeUninit<T>]>::assume_init_drop`](https://doc.rust-lang.org/stable/core/primitive.slice.html#method.assume_init_drop)
|
||||
- [`<[MaybeUninit<T>]>::assume_init_ref`](https://doc.rust-lang.org/stable/core/primitive.slice.html#method.assume_init_ref)
|
||||
- [`<[MaybeUninit<T>]>::assume_init_mut`](https://doc.rust-lang.org/stable/core/primitive.slice.html#method.assume_init_mut)
|
||||
- [`<[MaybeUninit<T>]>::write_copy_of_slice`](https://doc.rust-lang.org/stable/std/primitive.slice.html#method.write_copy_of_slice)
|
||||
- [`<[MaybeUninit<T>]>::write_clone_of_slice`](https://doc.rust-lang.org/stable/std/primitive.slice.html#method.write_clone_of_slice)
|
||||
- [`String::into_raw_parts`](https://doc.rust-lang.org/stable/std/string/struct.String.html#method.into_raw_parts)
|
||||
- [`Vec::into_raw_parts`](https://doc.rust-lang.org/stable/std/vec/struct.Vec.html#method.into_raw_parts)
|
||||
- [`<iN>::unchecked_neg`](https://doc.rust-lang.org/stable/std/primitive.isize.html#method.unchecked_neg)
|
||||
- [`<iN>::unchecked_shl`](https://doc.rust-lang.org/stable/std/primitive.isize.html#method.unchecked_shl)
|
||||
- [`<iN>::unchecked_shr`](https://doc.rust-lang.org/stable/std/primitive.isize.html#method.unchecked_shr)
|
||||
- [`<uN>::unchecked_shl`](https://doc.rust-lang.org/stable/std/primitive.usize.html#method.unchecked_shl)
|
||||
- [`<uN>::unchecked_shr`](https://doc.rust-lang.org/stable/std/primitive.usize.html#method.unchecked_shr)
|
||||
- [`<[T]>::as_array`](https://doc.rust-lang.org/stable/std/primitive.slice.html#method.as_array)
|
||||
- [`<[T]>::as_mut_array`](https://doc.rust-lang.org/stable/std/primitive.slice.html#method.as_mut_array)
|
||||
- [`<*const [T]>::as_array`](https://doc.rust-lang.org/stable/std/primitive.pointer.html#method.as_array)
|
||||
- [`<*mut [T]>::as_mut_array`](https://doc.rust-lang.org/stable/std/primitive.pointer.html#method.as_mut_array)
|
||||
- [`VecDeque::pop_front_if`](https://doc.rust-lang.org/stable/std/collections/struct.VecDeque.html#method.pop_front_if)
|
||||
- [`VecDeque::pop_back_if`](https://doc.rust-lang.org/stable/std/collections/struct.VecDeque.html#method.pop_back_if)
|
||||
- [`Duration::from_nanos_u128`](https://doc.rust-lang.org/stable/std/time/struct.Duration.html#method.from_nanos_u128)
|
||||
- [`char::MAX_LEN_UTF8`](https://doc.rust-lang.org/stable/std/primitive.char.html#associatedconstant.MAX_LEN_UTF8)
|
||||
- [`char::MAX_LEN_UTF16`](https://doc.rust-lang.org/stable/std/primitive.char.html#associatedconstant.MAX_LEN_UTF16)
|
||||
- [`std::fmt::from_fn`](https://doc.rust-lang.org/stable/std/fmt/fn.from_fn.html)
|
||||
- [`std::fmt::FromFn`](https://doc.rust-lang.org/stable/std/fmt/struct.FromFn.html)
|
||||
|
||||
|
||||
<a id="1.93.0-Cargo"></a>
|
||||
|
||||
Cargo
|
||||
-----
|
||||
- [Enable CARGO_CFG_DEBUG_ASSERTIONS in build scripts based on profile](https://github.com/rust-lang/cargo/pull/16160/)
|
||||
- [In `cargo tree`, support long forms for `--format` variables](https://github.com/rust-lang/cargo/pull/16204/)
|
||||
- [Add `--workspace` to `cargo clean`](https://github.com/rust-lang/cargo/pull/16263/)
|
||||
|
||||
<a id="1.93.0-Rustdoc"></a>
|
||||
|
||||
Rustdoc
|
||||
-----
|
||||
- [Remove `#![doc(document_private_items)]`](https://github.com/rust-lang/rust/pull/146495)
|
||||
- [Include attribute and derive macros in search filters for "macros"](https://github.com/rust-lang/rust/pull/148176)
|
||||
- [Include extern crates in search filters for `import`](https://github.com/rust-lang/rust/pull/148301)
|
||||
- [Validate usage of crate-level doc attributes](https://github.com/rust-lang/rust/pull/149197). This means if any of `html_favicon_url`, `html_logo_url`, `html_playground_url`, `issue_tracker_base_url`, or `html_no_source` either has a missing value, an unexpected value, or a value of the wrong type, rustdoc will emit the deny-by-default lint `rustdoc::invalid_doc_attributes`.
|
||||
|
||||
|
||||
<a id="1.93.0-Compatibility-Notes"></a>
|
||||
|
||||
Compatibility Notes
|
||||
-------------------
|
||||
- [Introduce `pin_v2` into the builtin attributes namespace](https://github.com/rust-lang/rust/pull/139751)
|
||||
- [Update bundled musl to 1.2.5](https://github.com/rust-lang/rust/pull/142682)
|
||||
- [On Emscripten, the unwinding ABI used when compiling with `panic=unwind` was changed from the JS exception handling ABI to the wasm exception handling ABI.](https://github.com/rust-lang/rust/pull/147224) If linking C/C++ object files with Rust objects, `-fwasm-exceptions` must be passed to the linker now. On nightly Rust, it is possible to get the old behavior with `-Zwasm-emscripten-eh=false -Zbuild-std`, but it will be removed in a future release.
|
||||
- The `#[test]` attribute, used to define tests, was previously ignored in various places where it had no meaning (e.g on trait methods or types). Putting the `#[test]` attribute in these places is no longer ignored, and will now result in an error; this may also result in errors when generating rustdoc. [Error when `test` attribute is applied to structs](https://github.com/rust-lang/rust/pull/147841)
|
||||
- Cargo now sets the `CARGO_CFG_DEBUG_ASSERTIONS` environment variable in more situations. This will cause crates depending on `static-init` versions 1.0.1 to 1.0.3 to fail compilation with "failed to resolve: use of unresolved module or unlinked crate `parking_lot`". See [the linked issue](https://github.com/rust-lang/rust/issues/150646#issuecomment-3718964342) for details.
|
||||
- [User written types in the `offset_of!` macro are now checked to be well formed.](https://github.com/rust-lang/rust/issues/150465/)
|
||||
- `cargo publish` no longer emits `.crate` files as a final artifact for user access when the `build.build-dir` config is unset
|
||||
- [Upgrade the `deref_nullptr` lint from warn-by-default to deny-by-default](https://github.com/rust-lang/rust/pull/148122)
|
||||
- [Add future-incompatibility warning for `...` function parameters without a pattern outside of `extern` blocks](https://github.com/rust-lang/rust/pull/143619)
|
||||
- [Introduce future-compatibility warning for `repr(C)` enums whose discriminant values do not fit into a `c_int` or `c_uint`](https://github.com/rust-lang/rust/pull/147017)
|
||||
- [Introduce future-compatibility warning against ignoring `repr(C)` types as part of `repr(transparent)`](https://github.com/rust-lang/rust/pull/147185)
|
||||
|
||||
|
||||
Version 1.92.0 (2025-12-11)
|
||||
==========================
|
||||
|
||||
@@ -1435,7 +1670,7 @@ Compatibility Notes
|
||||
- [Check well-formedness of the source type's signature in fn pointer casts.](https://github.com/rust-lang/rust/pull/129021) This partly closes a soundness hole that comes when casting a function item to function pointer
|
||||
- [Use equality instead of subtyping when resolving type dependent paths.](https://github.com/rust-lang/rust/pull/129073)
|
||||
- Linking on macOS now correctly includes Rust's default deployment target. Due to a linker bug, you might have to pass `MACOSX_DEPLOYMENT_TARGET` or fix your `#[link]` attributes to point to the correct frameworks. See <https://github.com/rust-lang/rust/pull/129369>.
|
||||
- [Rust will now correctly raise an error for `repr(Rust)` written on non-`struct`/`enum`/`union` items, since it previous did not have any effect.](https://github.com/rust-lang/rust/pull/129422)
|
||||
- [Rust will now correctly raise an error for `repr(Rust)` written on non-`struct`/`enum`/`union` items, since it previously did not have any effect.](https://github.com/rust-lang/rust/pull/129422)
|
||||
- The future incompatibility lint `deprecated_cfg_attr_crate_type_name` [has been made into a hard error](https://github.com/rust-lang/rust/pull/129670). It was used to deny usage of `#![crate_type]` and `#![crate_name]` attributes in `#![cfg_attr]`, which required a hack in the compiler to be able to change the used crate type and crate name after cfg expansion.
|
||||
Users can use `--crate-type` instead of `#![cfg_attr(..., crate_type = "...")]` and `--crate-name` instead of `#![cfg_attr(..., crate_name = "...")]` when running `rustc`/`cargo rustc` on the command line.
|
||||
Use of those two attributes outside of `#![cfg_attr]` continue to be fully supported.
|
||||
@@ -1611,7 +1846,7 @@ Cargo
|
||||
Compatibility Notes
|
||||
-------------------
|
||||
- We now [disallow setting some built-in cfgs via the command-line](https://github.com/rust-lang/rust/pull/126158) with the newly added [`explicit_builtin_cfgs_in_flags`](https://doc.rust-lang.org/rustc/lints/listing/deny-by-default.html#explicit-builtin-cfgs-in-flags) lint in order to prevent incoherent state, eg. `windows` cfg active but target is Linux based. The appropriate [`rustc` flag](https://doc.rust-lang.org/rustc/command-line-arguments.html) should be used instead.
|
||||
- The standard library has a new implementation of `binary_search` which is significantly improves performance ([#128254](https://github.com/rust-lang/rust/pull/128254)). However when a sorted slice has multiple values which compare equal, the new implementation may select a different value among the equal ones than the old implementation.
|
||||
- The standard library has a new implementation of `binary_search` which significantly improves performance ([#128254](https://github.com/rust-lang/rust/pull/128254)). However when a sorted slice has multiple values which compare equal, the new implementation may select a different value among the equal ones than the old implementation.
|
||||
- [illumos/Solaris now sets `MSG_NOSIGNAL` when writing to sockets](https://github.com/rust-lang/rust/pull/128259). This avoids killing the process with SIGPIPE when writing to a closed socket, which matches the existing behavior on other UNIX targets.
|
||||
- [Removes a problematic hack that always passed the --whole-archive linker flag for tests, which may cause linker errors for code accidentally relying on it.](https://github.com/rust-lang/rust/pull/128400)
|
||||
- The WebAssembly target features `multivalue` and `reference-types` are now
|
||||
@@ -1761,7 +1996,7 @@ These changes do not affect any public interfaces of Rust, but they represent
|
||||
significant improvements to the performance or internals of rustc and related
|
||||
tools.
|
||||
|
||||
- [Add a Rust-for Linux `auto` CI job to check kernel builds.](https://github.com/rust-lang/rust/pull/125209/)
|
||||
- [Add a Rust-for-Linux `auto` CI job to check kernel builds.](https://github.com/rust-lang/rust/pull/125209/)
|
||||
|
||||
Version 1.80.1 (2024-08-08)
|
||||
===========================
|
||||
@@ -4399,7 +4634,7 @@ Compatibility Notes
|
||||
saturating to `0` instead][89926]. In the real world the panic happened mostly
|
||||
on platforms with buggy monotonic clock implementations rather than catching
|
||||
programming errors like reversing the start and end times. Such programming
|
||||
errors will now results in `0` rather than a panic.
|
||||
errors will now result in `0` rather than a panic.
|
||||
- In a future release we're planning to increase the baseline requirements for
|
||||
the Linux kernel to version 3.2, and for glibc to version 2.17. We'd love
|
||||
your feedback in [PR #95026][95026].
|
||||
|
||||
@@ -366,6 +366,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
||||
// - A glob decl is overwritten by its clone after setting ambiguity in it.
|
||||
// FIXME: avoid this by removing `warn_ambiguity`, or by triggering glob re-fetch
|
||||
// with the same decl in some way.
|
||||
// - A glob decl is overwritten by a glob decl with larger visibility.
|
||||
// FIXME: avoid this by updating this visibility in place.
|
||||
// - A glob decl is overwritten by a glob decl re-fetching an
|
||||
// overwritten decl from other module (the recursive case).
|
||||
// Here we are detecting all such re-fetches and overwrite old decls
|
||||
@@ -379,7 +381,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
||||
// FIXME: reenable the asserts when `warn_ambiguity` is removed (#149195).
|
||||
// assert_ne!(old_deep_decl, deep_decl);
|
||||
// assert!(old_deep_decl.is_glob_import());
|
||||
assert!(!deep_decl.is_glob_import());
|
||||
// FIXME: reenable the assert when visibility is updated in place.
|
||||
// assert!(!deep_decl.is_glob_import());
|
||||
if old_glob_decl.ambiguity.get().is_some() && glob_decl.ambiguity.get().is_none() {
|
||||
// Do not lose glob ambiguities when re-fetching the glob.
|
||||
glob_decl.ambiguity.set_unchecked(old_glob_decl.ambiguity.get());
|
||||
|
||||
@@ -42,3 +42,4 @@ pub(crate) mod windows_msvc;
|
||||
pub(crate) mod windows_uwp_gnu;
|
||||
pub(crate) mod windows_uwp_msvc;
|
||||
pub(crate) mod xtensa;
|
||||
pub(crate) mod yggdrasil;
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
use crate::spec::{
|
||||
Cc, LinkOutputKind, LinkerFlavor, Lld, Os, RelocModel, StackProbeType, TargetOptions,
|
||||
crt_objects,
|
||||
};
|
||||
|
||||
pub(crate) fn opts() -> TargetOptions {
|
||||
let pre_link_args = TargetOptions::link_args(
|
||||
LinkerFlavor::Gnu(Cc::No, Lld::No),
|
||||
&["-zmax-page-size=4096", "--dynamic-linker=/libexec/dyn-loader"],
|
||||
);
|
||||
|
||||
TargetOptions {
|
||||
os: Os::Yggdrasil,
|
||||
|
||||
linker: Some("rust-lld".into()),
|
||||
linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes),
|
||||
pre_link_objects: crt_objects::new(&[
|
||||
(LinkOutputKind::DynamicNoPicExe, &["rust_entry0.o"]),
|
||||
(LinkOutputKind::DynamicPicExe, &["rust_entry0.o"]),
|
||||
(LinkOutputKind::StaticNoPicExe, &["rust_entry0.o"]),
|
||||
(LinkOutputKind::StaticPicExe, &["rust_entry0.o"]),
|
||||
]),
|
||||
executables: true,
|
||||
dynamic_linking: true,
|
||||
position_independent_executables: true,
|
||||
relocation_model: RelocModel::Pic,
|
||||
|
||||
pre_link_args,
|
||||
stack_probes: StackProbeType::Inline,
|
||||
max_atomic_width: Some(128),
|
||||
eh_frame_header: false,
|
||||
has_thread_local: true,
|
||||
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
@@ -1801,6 +1801,10 @@ supported_targets! {
|
||||
("x86_64-lynx-lynxos178", x86_64_lynx_lynxos178),
|
||||
|
||||
("x86_64-pc-cygwin", x86_64_pc_cygwin),
|
||||
|
||||
("aarch64-unknown-yggdrasil", aarch64_unknown_yggdrasil),
|
||||
("riscv64-unknown-yggdrasil", riscv64_unknown_yggdrasil),
|
||||
("x86_64-unknown-yggdrasil", x86_64_unknown_yggdrasil),
|
||||
}
|
||||
|
||||
/// Cow-Vec-Str: Cow<'static, [Cow<'static, str>]>
|
||||
@@ -1994,6 +1998,7 @@ crate::target_spec_enum! {
|
||||
Windows = "windows",
|
||||
Xous = "xous",
|
||||
Zkvm = "zkvm",
|
||||
Yggdrasil = "yggdrasil",
|
||||
Unknown = "unknown",
|
||||
}
|
||||
other_variant = Other;
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
use crate::spec::{Arch, PanicStrategy, Target, TargetMetadata};
|
||||
|
||||
pub(crate) fn target() -> Target {
|
||||
let mut base = crate::spec::base::yggdrasil::opts();
|
||||
|
||||
base.disable_redzone = true;
|
||||
base.panic_strategy = PanicStrategy::Abort;
|
||||
base.features = "+fp-armv8,+neon,+strict-align,+v8a".into();
|
||||
base.plt_by_default = true;
|
||||
|
||||
Target {
|
||||
llvm_target: "aarch64-unknown-none".into(),
|
||||
pointer_width: 64,
|
||||
arch: Arch::AArch64,
|
||||
data_layout: "e-m:e-p270:32:32-p271:32:32-p272:64:64-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32".into(),
|
||||
metadata: TargetMetadata {
|
||||
description: Some("AArch64 yggdrasil".into()),
|
||||
tier: Some(1),
|
||||
host_tools: Some(true),
|
||||
std: Some(true),
|
||||
},
|
||||
options: base,
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
use crate::spec::{Arch, CodeModel, PanicStrategy, Target, TargetMetadata, TargetOptions};
|
||||
|
||||
pub(crate) fn target() -> Target {
|
||||
let base = crate::spec::base::yggdrasil::opts();
|
||||
|
||||
Target {
|
||||
llvm_target: "riscv64".into(),
|
||||
pointer_width: 64,
|
||||
arch: Arch::RiscV64,
|
||||
data_layout: "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128".into(),
|
||||
metadata: TargetMetadata {
|
||||
description: Some("RISC-V 64-bit yggdrasil".into()),
|
||||
tier: Some(1),
|
||||
host_tools: Some(false),
|
||||
std: Some(true),
|
||||
},
|
||||
options: TargetOptions {
|
||||
code_model: Some(CodeModel::Medium),
|
||||
disable_redzone: true,
|
||||
max_atomic_width: Some(64),
|
||||
features: "+m,+a,+c,+zicsr,+zifencei".into(),
|
||||
panic_strategy: PanicStrategy::Abort,
|
||||
llvm_abiname: "lp64".into(),
|
||||
plt_by_default: true,
|
||||
|
||||
..base // From android
|
||||
// features: "+m,+a,+f,+d,+c,+b,+v,+zicsr,+zifencei".into(),
|
||||
// supported_sanitizers: SanitizerSet::ADDRESS,
|
||||
// supported_split_debuginfo: Cow::Borrowed(&[SplitDebuginfo::Off]),
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
use crate::spec::{Arch, PanicStrategy, Target, TargetMetadata};
|
||||
|
||||
pub(crate) fn target() -> Target {
|
||||
let mut base = crate::spec::base::yggdrasil::opts();
|
||||
|
||||
base.disable_redzone = true;
|
||||
base.panic_strategy = PanicStrategy::Abort;
|
||||
base.plt_by_default = true;
|
||||
base.features = "+sse,+cx16".into();
|
||||
|
||||
Target {
|
||||
llvm_target: "x86_64-unknown-linux-gnu".into(),
|
||||
pointer_width: 64,
|
||||
arch: Arch::X86_64,
|
||||
data_layout:
|
||||
"e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128".into(),
|
||||
metadata: TargetMetadata {
|
||||
description: Some("x86_64 yggdrasil".into()),
|
||||
tier: Some(1),
|
||||
host_tools: Some(true),
|
||||
std: Some(true),
|
||||
},
|
||||
options: base,
|
||||
}
|
||||
}
|
||||
@@ -777,7 +777,9 @@ fn layout_of_uncached<'tcx>(
|
||||
let err = if ty.has_param() || !cx.typing_env.param_env.caller_bounds().is_empty() {
|
||||
LayoutError::TooGeneric(ty)
|
||||
} else {
|
||||
unreachable!("invalid rigid alias in layout_of after normalization: {ty:?}");
|
||||
LayoutError::ReferencesError(cx.tcx().dcx().delayed_bug(format!(
|
||||
"unexpected rigid alias in layout_of after normalization: {ty:?}"
|
||||
)))
|
||||
};
|
||||
return Err(error(cx, err));
|
||||
}
|
||||
|
||||
@@ -2,6 +2,31 @@
|
||||
# It is not intended for manual editing.
|
||||
version = 4
|
||||
|
||||
[[package]]
|
||||
name = "abi-generator"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "abi-lib"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"rustc-std-workspace-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "abi-serde"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"rustc-std-workspace-alloc",
|
||||
"rustc-std-workspace-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "addr2line"
|
||||
version = "0.25.1"
|
||||
@@ -153,6 +178,22 @@ dependencies = [
|
||||
"rustc-std-workspace-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libm"
|
||||
version = "0.2.8"
|
||||
dependencies = [
|
||||
"rustc-std-workspace-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libyalloc"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"rustc-std-workspace-core",
|
||||
"yggdrasil-rt",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.7.6"
|
||||
@@ -213,6 +254,25 @@ dependencies = [
|
||||
"unwind",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "prettyplease"
|
||||
version = "0.2.37"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.106"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc_macro"
|
||||
version = "0.0.0"
|
||||
@@ -229,6 +289,15 @@ dependencies = [
|
||||
"cc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.45"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "r-efi"
|
||||
version = "5.3.0"
|
||||
@@ -331,6 +400,7 @@ dependencies = [
|
||||
"hashbrown",
|
||||
"hermit-abi",
|
||||
"libc",
|
||||
"libyalloc",
|
||||
"miniz_oxide",
|
||||
"moto-rt",
|
||||
"object",
|
||||
@@ -347,6 +417,7 @@ dependencies = [
|
||||
"wasi 0.11.1+wasi-snapshot-preview1",
|
||||
"wasi 0.14.4+wasi-0.2.4",
|
||||
"windows-targets 0.0.0",
|
||||
"yggdrasil-rt",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -358,6 +429,17 @@ dependencies = [
|
||||
"rustc-std-workspace-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.117"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sysroot"
|
||||
version = "0.0.0"
|
||||
@@ -378,6 +460,32 @@ dependencies = [
|
||||
"std",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "1.0.69"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52"
|
||||
dependencies = [
|
||||
"thiserror-impl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror-impl"
|
||||
version = "1.0.69"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.24"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75"
|
||||
|
||||
[[package]]
|
||||
name = "unwind"
|
||||
version = "0.0.0"
|
||||
@@ -520,3 +628,30 @@ dependencies = [
|
||||
"rustc-std-workspace-alloc",
|
||||
"rustc-std-workspace-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "yggdrasil-abi"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"abi-generator",
|
||||
"abi-lib",
|
||||
"abi-serde",
|
||||
"prettyplease",
|
||||
"rustc-std-workspace-alloc",
|
||||
"rustc-std-workspace-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "yggdrasil-rt"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"abi-generator",
|
||||
"abi-lib",
|
||||
"abi-serde",
|
||||
"cc",
|
||||
"libm",
|
||||
"prettyplease",
|
||||
"rustc-std-workspace-alloc",
|
||||
"rustc-std-workspace-core",
|
||||
"yggdrasil-abi",
|
||||
]
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
#![feature(no_core, lang_items, auto_traits)]
|
||||
#![allow(internal_features)]
|
||||
#![crate_type = "rlib"]
|
||||
#![no_core]
|
||||
#![no_main]
|
||||
|
||||
#[lang = "pointee_sized"]
|
||||
pub trait PointeeSized {}
|
||||
#[lang = "meta_sized"]
|
||||
pub trait MetaSized: PointeeSized {}
|
||||
#[lang = "sized"]
|
||||
pub trait Sized: MetaSized {}
|
||||
|
||||
#[lang = "sync"]
|
||||
auto trait Sync {}
|
||||
#[lang = "copy"]
|
||||
trait Copy {}
|
||||
#[lang = "freeze"]
|
||||
auto trait Freeze {}
|
||||
|
||||
impl ::Copy for usize {}
|
||||
|
||||
// #[lang = "drop_in_place"]
|
||||
// #[inline]
|
||||
// #[allow(unconditional_recursion)]
|
||||
// pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
|
||||
// drop_in_place(to_drop);
|
||||
// }
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
unsafe extern "C" fn _start(arg: usize) -> ! {
|
||||
extern "C" {
|
||||
fn __rust_start(arg: usize, main: usize) -> !;
|
||||
fn main(argc: isize, argv: *const *const u8) -> i32;
|
||||
}
|
||||
|
||||
__rust_start(arg, main as *const () as usize)
|
||||
}
|
||||
@@ -102,6 +102,10 @@ vex-sdk = { version = "0.27.0", features = [
|
||||
'rustc-dep-of-std',
|
||||
], default-features = false }
|
||||
|
||||
[target.'cfg(target_os = "yggdrasil")'.dependencies]
|
||||
yggdrasil-rt = { path = "../../../lib/runtime", features = ['rustc-dep-of-std'] }
|
||||
libyalloc = { path = "../../../lib/libyalloc", features = ['rustc-dep-of-std'] }
|
||||
|
||||
[features]
|
||||
backtrace = [
|
||||
'addr2line/rustc-dep-of-std',
|
||||
|
||||
@@ -57,6 +57,7 @@ fn main() {
|
||||
|| target_os == "nuttx"
|
||||
|| target_os == "cygwin"
|
||||
|| target_os == "vexos"
|
||||
|| target_os == "yggdrasil"
|
||||
|
||||
// See src/bootstrap/src/core/build_steps/synthetic_targets.rs
|
||||
|| env::var("RUSTC_BOOTSTRAP_SYNTHETIC_TARGET").is_ok()
|
||||
|
||||
@@ -183,6 +183,8 @@ pub mod vita;
|
||||
pub mod vxworks;
|
||||
#[cfg(target_os = "xous")]
|
||||
pub mod xous;
|
||||
#[cfg(target_os = "yggdrasil")]
|
||||
pub mod yggdrasil;
|
||||
|
||||
#[cfg(any(
|
||||
unix,
|
||||
@@ -194,5 +196,9 @@ pub mod xous;
|
||||
))]
|
||||
pub mod fd;
|
||||
|
||||
#[stable(feature = "os_fd", since = "1.66.0")]
|
||||
#[cfg(target_os = "yggdrasil")]
|
||||
pub use yggdrasil::io::fd;
|
||||
|
||||
#[cfg(any(target_os = "linux", target_os = "android", target_os = "cygwin", doc))]
|
||||
mod net;
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
#![unstable(feature = "yggdrasil_os", issue = "none")]
|
||||
|
||||
use yggdrasil_rt::io::FileMode;
|
||||
use yggdrasil_rt::sys as syscall;
|
||||
|
||||
use crate::fs::{FileType, Metadata, OpenOptions};
|
||||
use crate::io;
|
||||
use crate::path::Path;
|
||||
use crate::sys::{AsInner, AsInnerMut};
|
||||
|
||||
#[unstable(feature = "yggdrasil_os", issue = "none")]
|
||||
pub trait MetadataExt {
|
||||
fn mode_ext(&self) -> FileMode;
|
||||
fn inode(&self) -> Option<u32>;
|
||||
fn block_count(&self) -> u64;
|
||||
fn block_size(&self) -> u64;
|
||||
}
|
||||
|
||||
#[unstable(feature = "yggdrasil_os", issue = "none")]
|
||||
pub trait FileTypeExt {
|
||||
fn is_block_device(&self) -> bool;
|
||||
fn is_char_device(&self) -> bool;
|
||||
}
|
||||
|
||||
#[unstable(feature = "yggdrasil_os", issue = "none")]
|
||||
pub trait OpenOptionsExt {
|
||||
fn mode_ext(&mut self, mode: FileMode) -> &mut Self;
|
||||
}
|
||||
|
||||
impl MetadataExt for Metadata {
|
||||
fn mode_ext(&self) -> FileMode {
|
||||
self.as_inner().mode_ext()
|
||||
}
|
||||
|
||||
fn inode(&self) -> Option<u32> {
|
||||
self.as_inner().inode()
|
||||
}
|
||||
|
||||
fn block_count(&self) -> u64 {
|
||||
self.as_inner().block_count()
|
||||
}
|
||||
|
||||
fn block_size(&self) -> u64 {
|
||||
self.as_inner().block_size()
|
||||
}
|
||||
}
|
||||
|
||||
impl OpenOptionsExt for OpenOptions {
|
||||
fn mode_ext(&mut self, mode: FileMode) -> &mut Self {
|
||||
self.as_inner_mut().mode = mode;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl FileTypeExt for FileType {
|
||||
#[inline]
|
||||
fn is_block_device(&self) -> bool {
|
||||
self.as_inner().is_block_device()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn is_char_device(&self) -> bool {
|
||||
self.as_inner().is_char_device()
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "yggdrasil_os", issue = "none")]
|
||||
pub fn symlink<P: AsRef<Path>, Q: AsRef<Path>>(target: P, path: Q) -> Result<(), io::Error> {
|
||||
let target = target.as_ref().to_str().unwrap();
|
||||
let path = path.as_ref().to_str().unwrap();
|
||||
|
||||
unsafe { syscall::create_symlink(None, target, path) }?;
|
||||
Ok(())
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
#![unstable(feature = "yggdrasil_os", issue = "none")]
|
||||
|
||||
use yggdrasil_rt::io::device as rt;
|
||||
use yggdrasil_rt::sys as syscall;
|
||||
|
||||
use crate::io;
|
||||
|
||||
#[unstable(feature = "yggdrasil_os", issue = "none")]
|
||||
pub type MountOptions<'a> = rt::MountOptions<'a>;
|
||||
|
||||
#[unstable(feature = "yggdrasil_os", issue = "none")]
|
||||
pub type UnmountOptions = rt::UnmountOptions;
|
||||
|
||||
#[unstable(feature = "yggdrasil_os", issue = "none")]
|
||||
pub unsafe fn mount_raw(options: &MountOptions<'_>) -> io::Result<()> {
|
||||
syscall::mount(options)?;
|
||||
Ok(())
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
mod owned;
|
||||
mod raw;
|
||||
|
||||
pub use owned::*;
|
||||
pub use raw::*;
|
||||
|
||||
use crate::io;
|
||||
|
||||
#[unstable(feature = "yggdrasil_os", issue = "none")]
|
||||
pub fn clone_fd(src: RawFd) -> io::Result<RawFd> {
|
||||
Ok(unsafe { yggdrasil_rt::sys::clone_fd(src, None) }?)
|
||||
}
|
||||
@@ -0,0 +1,150 @@
|
||||
#![stable(feature = "io_safety", since = "1.63.0")]
|
||||
|
||||
use super::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
|
||||
use crate::marker::PhantomData;
|
||||
use crate::mem::forget;
|
||||
use crate::sys::IntoInner;
|
||||
|
||||
macro_rules! stdio_impl_as_fd {
|
||||
($($ty:ty => $n:expr),*) => {$(
|
||||
#[stable(feature = "io_safety", since = "1.63.0")]
|
||||
impl AsFd for $ty {
|
||||
#[inline]
|
||||
fn as_fd(&self) -> BorrowedFd<'_> {
|
||||
BorrowedFd {
|
||||
fd: $n,
|
||||
_pd: PhantomData
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// #[stable(feature = "io_safety", since = "1.21.0")]
|
||||
// impl AsFd for &$ty {
|
||||
// #[inline]
|
||||
// fn as_raw_fd(&self) -> RawFd {
|
||||
// $n
|
||||
// }
|
||||
// }
|
||||
)*};
|
||||
}
|
||||
|
||||
#[stable(feature = "io_safety", since = "1.63.0")]
|
||||
#[repr(transparent)]
|
||||
#[derive(Debug)]
|
||||
pub struct OwnedFd {
|
||||
fd: RawFd,
|
||||
}
|
||||
|
||||
#[stable(feature = "io_safety", since = "1.63.0")]
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
#[repr(transparent)]
|
||||
pub struct BorrowedFd<'fd> {
|
||||
fd: RawFd,
|
||||
_pd: PhantomData<&'fd OwnedFd>,
|
||||
}
|
||||
|
||||
#[stable(feature = "io_safety", since = "1.63.0")]
|
||||
pub trait AsFd {
|
||||
#[stable(feature = "io_safety", since = "1.63.0")]
|
||||
fn as_fd(&self) -> BorrowedFd<'_>;
|
||||
}
|
||||
|
||||
#[stable(feature = "io_safety", since = "1.63.0")]
|
||||
impl<T: AsFd> AsFd for &T {
|
||||
fn as_fd(&self) -> BorrowedFd<'_> {
|
||||
T::as_fd(self)
|
||||
}
|
||||
}
|
||||
|
||||
// Borrowed
|
||||
|
||||
impl BorrowedFd<'_> {
|
||||
#[rustc_const_stable(feature = "io_safety", since = "1.63.0")]
|
||||
#[stable(feature = "io_safety", since = "1.63.0")]
|
||||
pub const unsafe fn borrow_raw(fd: RawFd) -> Self {
|
||||
// assert_ne!(fd, u32::MAX as RawFd);
|
||||
Self { fd, _pd: PhantomData }
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "io_safety", since = "1.63.0")]
|
||||
impl AsFd for BorrowedFd<'_> {
|
||||
fn as_fd(&self) -> BorrowedFd<'_> {
|
||||
*self
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "io_safety", since = "1.63.0")]
|
||||
impl AsRawFd for BorrowedFd<'_> {
|
||||
fn as_raw_fd(&self) -> RawFd {
|
||||
self.fd
|
||||
}
|
||||
}
|
||||
|
||||
// Owned
|
||||
|
||||
#[stable(feature = "io_safety", since = "1.63.0")]
|
||||
impl AsFd for OwnedFd {
|
||||
fn as_fd(&self) -> BorrowedFd<'_> {
|
||||
unsafe { BorrowedFd::borrow_raw(self.as_raw_fd()) }
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "io_safety", since = "1.63.0")]
|
||||
impl IntoRawFd for OwnedFd {
|
||||
fn into_raw_fd(self) -> RawFd {
|
||||
let fd = self.fd;
|
||||
forget(self);
|
||||
fd
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "io_safety", since = "1.63.0")]
|
||||
impl FromRawFd for OwnedFd {
|
||||
unsafe fn from_raw_fd(fd: RawFd) -> Self {
|
||||
Self { fd }
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "io_safety", since = "1.63.0")]
|
||||
impl AsRawFd for OwnedFd {
|
||||
fn as_raw_fd(&self) -> RawFd {
|
||||
self.fd
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "io_safety", since = "1.63.0")]
|
||||
impl Drop for OwnedFd {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
yggdrasil_rt::sys::close(self.fd).ok();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: AsFd for File, From<File> for OwnedFd, From<OwnedFd> for File,
|
||||
#[stable(feature = "io_safety", since = "1.63.0")]
|
||||
impl From<crate::fs::File> for OwnedFd {
|
||||
fn from(value: crate::fs::File) -> OwnedFd {
|
||||
let inner = value.into_inner();
|
||||
Self { fd: inner.into_raw_fd() }
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "io_safety", since = "1.63.0")]
|
||||
impl AsFd for crate::fs::File {
|
||||
fn as_fd(&self) -> BorrowedFd<'_> {
|
||||
BorrowedFd { fd: self.as_raw_fd(), _pd: PhantomData }
|
||||
}
|
||||
}
|
||||
|
||||
stdio_impl_as_fd!(
|
||||
crate::io::Stdin => RawFd::STDIN,
|
||||
crate::io::Stdout => RawFd::STDOUT,
|
||||
crate::io::Stderr => RawFd::STDERR
|
||||
);
|
||||
stdio_impl_as_fd!(
|
||||
crate::io::StdinLock<'_> => RawFd::STDIN,
|
||||
crate::io::StdoutLock<'_> => RawFd::STDOUT,
|
||||
crate::io::StderrLock<'_> => RawFd::STDERR
|
||||
);
|
||||
@@ -0,0 +1,98 @@
|
||||
#![stable(feature = "os_fd", since = "1.66.0")]
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub type RawFd = yggdrasil_rt::io::RawFd;
|
||||
|
||||
use crate::sys::{AsInner, FromInner, IntoInner};
|
||||
|
||||
macro_rules! stdio_impl_as_raw_fd {
|
||||
($($ty:ty => $n:expr),*) => {$(
|
||||
#[stable(feature = "asraw_stdio", since = "1.21.0")]
|
||||
impl AsRawFd for $ty {
|
||||
#[inline]
|
||||
fn as_raw_fd(&self) -> RawFd {
|
||||
$n
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "asraw_stdio", since = "1.21.0")]
|
||||
impl AsRawFd for &$ty {
|
||||
#[inline]
|
||||
fn as_raw_fd(&self) -> RawFd {
|
||||
$n
|
||||
}
|
||||
}
|
||||
)*};
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub trait AsRawFd {
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
fn as_raw_fd(&self) -> RawFd;
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub trait FromRawFd {
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
unsafe fn from_raw_fd(fd: RawFd) -> Self;
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub trait IntoRawFd {
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
fn into_raw_fd(self) -> RawFd;
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl AsRawFd for RawFd {
|
||||
fn as_raw_fd(&self) -> RawFd {
|
||||
*self
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl FromRawFd for RawFd {
|
||||
unsafe fn from_raw_fd(fd: RawFd) -> Self {
|
||||
fd
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl IntoRawFd for RawFd {
|
||||
fn into_raw_fd(self) -> RawFd {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
stdio_impl_as_raw_fd!(
|
||||
crate::io::Stdin => RawFd::STDIN,
|
||||
crate::io::Stdout => RawFd::STDOUT,
|
||||
crate::io::Stderr => RawFd::STDERR
|
||||
);
|
||||
stdio_impl_as_raw_fd!(
|
||||
crate::io::StdinLock<'_> => RawFd::STDIN,
|
||||
crate::io::StdoutLock<'_> => RawFd::STDOUT,
|
||||
crate::io::StderrLock<'_> => RawFd::STDERR
|
||||
);
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl AsRawFd for crate::fs::File {
|
||||
fn as_raw_fd(&self) -> RawFd {
|
||||
self.as_inner().as_raw_fd()
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl FromRawFd for crate::fs::File {
|
||||
unsafe fn from_raw_fd(fd: RawFd) -> Self {
|
||||
let inner = crate::sys::fs::File::from_raw_fd(fd);
|
||||
crate::fs::File::from_inner(inner)
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl IntoRawFd for crate::fs::File {
|
||||
fn into_raw_fd(self) -> RawFd {
|
||||
self.into_inner().into_raw_fd()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
#![unstable(feature = "yggdrasil_os", issue = "none")]
|
||||
|
||||
use super::fd::RawFd;
|
||||
use crate::os::fd::{AsRawFd, OwnedFd};
|
||||
|
||||
#[unstable(feature = "yggdrasil_os", issue = "none")]
|
||||
pub struct FileMapping<'a> {
|
||||
data: &'a mut [u8],
|
||||
fd: OwnedFd,
|
||||
}
|
||||
|
||||
#[unstable(feature = "yggdrasil_os", issue = "none")]
|
||||
impl<'a> FileMapping<'a> {
|
||||
pub fn new<F: Into<OwnedFd>>(f: F, offset: u64, len: usize) -> crate::io::Result<Self> {
|
||||
use yggdrasil_rt::mem::{MappingFlags, MappingSource};
|
||||
|
||||
let owned_fd = f.into();
|
||||
let raw_fd = owned_fd.as_raw_fd();
|
||||
let base = unsafe {
|
||||
yggdrasil_rt::sys::map_memory(
|
||||
None,
|
||||
len,
|
||||
MappingFlags::WRITE,
|
||||
&MappingSource::File(raw_fd, offset),
|
||||
)
|
||||
}?;
|
||||
|
||||
#[allow(fuzzy_provenance_casts)]
|
||||
let data = unsafe { crate::slice::from_raw_parts_mut(base as *mut u8, len) };
|
||||
|
||||
Ok(Self { data, fd: owned_fd })
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "yggdrasil_os", issue = "none")]
|
||||
impl crate::ops::Deref for FileMapping<'_> {
|
||||
type Target = [u8];
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
self.data
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "yggdrasil_os", issue = "none")]
|
||||
impl crate::ops::DerefMut for FileMapping<'_> {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
self.data
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "yggdrasil_os", issue = "none")]
|
||||
impl Drop for FileMapping<'_> {
|
||||
fn drop(&mut self) {
|
||||
// Unmap the memory
|
||||
let base = self.data.as_ptr() as usize;
|
||||
let len = self.data.len();
|
||||
unsafe {
|
||||
yggdrasil_rt::sys::unmap_memory(base, len).expect("Memory unmap failed");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRawFd for FileMapping<'_> {
|
||||
fn as_raw_fd(&self) -> RawFd {
|
||||
self.fd.as_raw_fd()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
#![allow(dead_code)]
|
||||
|
||||
pub mod fd;
|
||||
|
||||
pub mod device;
|
||||
pub mod mapping;
|
||||
// pub mod message_channel;
|
||||
pub mod net;
|
||||
//pub mod pid;
|
||||
pub mod pipe;
|
||||
pub mod poll;
|
||||
pub mod shared_memory;
|
||||
pub mod terminal;
|
||||
pub mod timer;
|
||||
|
||||
pub use yggdrasil_rt::io::{FileMetadataUpdate, FileMetadataUpdateMode, FileMode as RawFileMode};
|
||||
|
||||
pub fn update_metadata<P: AsRef<crate::path::Path>>(
|
||||
path: P,
|
||||
update: &FileMetadataUpdate,
|
||||
) -> crate::io::Result<()> {
|
||||
let path = path.as_ref().to_str().unwrap();
|
||||
unsafe { yggdrasil_rt::sys::update_metadata(None, path, &update) }?;
|
||||
Ok(())
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
pub mod raw_socket;
|
||||
@@ -0,0 +1,41 @@
|
||||
#![unstable(feature = "yggdrasil_os", issue = "none")]
|
||||
|
||||
use yggdrasil_rt::net::{self as rt, SocketInterfaceQuery};
|
||||
|
||||
use crate::io;
|
||||
use crate::os::fd::{AsRawFd, FromRawFd, RawFd};
|
||||
use crate::sys::fd::FileDesc;
|
||||
|
||||
#[unstable(feature = "yggdrasil_os", issue = "none")]
|
||||
pub struct RawSocket(FileDesc);
|
||||
|
||||
impl RawSocket {
|
||||
#[unstable(feature = "yggdrasil_os", issue = "none")]
|
||||
pub fn bind<'a, Q: Into<SocketInterfaceQuery<'a>>>(interface: Q) -> io::Result<Self> {
|
||||
let query = interface.into();
|
||||
let raw = rt::bind_raw(query)?;
|
||||
let inner = unsafe { FileDesc::from_raw_fd(raw) };
|
||||
Ok(Self(inner))
|
||||
}
|
||||
|
||||
pub fn send(&self, data: &[u8]) -> io::Result<usize> {
|
||||
Ok(rt::socket::send(self.as_raw_fd(), data)?)
|
||||
}
|
||||
|
||||
pub fn recv(&self, data: &mut [u8]) -> io::Result<usize> {
|
||||
Ok(rt::socket::receive(self.as_raw_fd(), data)?)
|
||||
}
|
||||
|
||||
pub fn hardware_address(&self) -> io::Result<[u8; 6]> {
|
||||
rt::get_socket_option!(self.as_raw_fd(), rt::options::BoundHardwareAddress)
|
||||
.map(Into::into)
|
||||
.map_err(io::Error::from)
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "yggdrasil_os", issue = "none")]
|
||||
impl AsRawFd for RawSocket {
|
||||
fn as_raw_fd(&self) -> RawFd {
|
||||
self.0.as_raw_fd()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
#![unstable(feature = "yggdrasil_os", issue = "none")]
|
||||
|
||||
use yggdrasil_rt::io as rt;
|
||||
|
||||
use crate::os::fd::{FromRawFd, OwnedFd};
|
||||
|
||||
#[unstable(feature = "yggdrasil_os", issue = "none")]
|
||||
pub fn create_pipe_pair(
|
||||
read_nonblocking: bool,
|
||||
write_nonblocking: bool,
|
||||
) -> crate::io::Result<(OwnedFd, OwnedFd)> {
|
||||
let (read, write) = rt::create_pipe_pair(read_nonblocking, write_nonblocking)?;
|
||||
let read = unsafe { OwnedFd::from_raw_fd(read) };
|
||||
let write = unsafe { OwnedFd::from_raw_fd(write) };
|
||||
|
||||
Ok((read, write))
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
#![unstable(feature = "yggdrasil_os", issue = "none")]
|
||||
|
||||
use yggdrasil_rt::io::poll as rt;
|
||||
|
||||
use crate::io;
|
||||
use crate::os::fd::{AsRawFd, FromRawFd, OwnedFd, RawFd};
|
||||
use crate::time::Duration;
|
||||
|
||||
#[unstable(feature = "yggdrasil_os", issue = "none")]
|
||||
pub type PollControl = rt::PollControl;
|
||||
|
||||
#[unstable(feature = "yggdrasil_os", issue = "none")]
|
||||
pub struct PollChannel(OwnedFd);
|
||||
|
||||
impl PollChannel {
|
||||
#[unstable(feature = "yggdrasil_os", issue = "none")]
|
||||
pub fn new() -> io::Result<Self> {
|
||||
let raw_fd = unsafe { yggdrasil_rt::sys::create_poll_channel() }?;
|
||||
let fd = unsafe { OwnedFd::from_raw_fd(raw_fd) };
|
||||
Ok(Self(fd))
|
||||
}
|
||||
|
||||
#[unstable(feature = "yggdrasil_os", issue = "none")]
|
||||
pub fn add(&mut self, fd: RawFd) -> io::Result<()> {
|
||||
unsafe {
|
||||
yggdrasil_rt::sys::poll_channel_control(self.0.as_raw_fd(), PollControl::AddFd, fd)
|
||||
}?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[unstable(feature = "yggdrasil_os", issue = "none")]
|
||||
pub fn remove(&mut self, fd: RawFd) -> io::Result<()> {
|
||||
unsafe {
|
||||
yggdrasil_rt::sys::poll_channel_control(self.0.as_raw_fd(), PollControl::RemoveFd, fd)
|
||||
}?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[unstable(feature = "yggdrasil_os", issue = "none")]
|
||||
pub fn wait(
|
||||
&mut self,
|
||||
timeout: Option<Duration>,
|
||||
retain: bool,
|
||||
) -> io::Result<Option<(RawFd, io::Result<()>)>> {
|
||||
let mut output = None;
|
||||
unsafe {
|
||||
yggdrasil_rt::sys::poll_channel_wait(self.0.as_raw_fd(), &timeout, retain, &mut output)
|
||||
}?;
|
||||
Ok(output.map(|(l, r)| (l, r.map_err(io::Error::from))))
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "yggdrasil_os", issue = "none")]
|
||||
impl AsRawFd for PollChannel {
|
||||
fn as_raw_fd(&self) -> RawFd {
|
||||
self.0.as_raw_fd()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
#![unstable(feature = "yggdrasil_os", issue = "none")]
|
||||
|
||||
use yggdrasil_rt::sys as syscall;
|
||||
|
||||
use crate::io;
|
||||
use crate::os::fd::{AsRawFd, FromRawFd, OwnedFd, RawFd};
|
||||
use crate::os::yggdrasil::io::mapping::FileMapping;
|
||||
|
||||
#[unstable(feature = "yggdrasil_os", issue = "none")]
|
||||
pub struct SharedMemory(OwnedFd, usize);
|
||||
|
||||
impl SharedMemory {
|
||||
#[unstable(feature = "yggdrasil_os", issue = "none")]
|
||||
pub fn new(size: usize) -> io::Result<Self> {
|
||||
let raw_fd = unsafe { syscall::create_shared_memory(size) }?;
|
||||
let fd = unsafe { OwnedFd::from_raw_fd(raw_fd) };
|
||||
Ok(Self(fd, size))
|
||||
}
|
||||
|
||||
#[unstable(feature = "yggdrasil_os", issue = "none")]
|
||||
pub fn size(&self) -> usize {
|
||||
self.1
|
||||
}
|
||||
|
||||
#[unstable(feature = "yggdrasil_os", issue = "none")]
|
||||
pub fn into_mapping<'a>(self) -> io::Result<FileMapping<'a>> {
|
||||
FileMapping::new(self.0, 0, self.1)
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "yggdrasil_os", issue = "none")]
|
||||
impl Into<OwnedFd> for SharedMemory {
|
||||
fn into(self) -> OwnedFd {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "yggdrasil_os", issue = "none")]
|
||||
impl AsRawFd for SharedMemory {
|
||||
fn as_raw_fd(&self) -> RawFd {
|
||||
self.0.as_raw_fd()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
#![unstable(feature = "yggdrasil_os", issue = "none")]
|
||||
|
||||
use yggdrasil_rt::io::{FileMode, OpenOptions, terminal as rt};
|
||||
use yggdrasil_rt::process::ProcessGroupId;
|
||||
use yggdrasil_rt::sys as syscall;
|
||||
|
||||
use crate::fs::File;
|
||||
use crate::io;
|
||||
use crate::mem::MaybeUninit;
|
||||
use crate::os::fd::{AsRawFd, FromRawFd, RawFd};
|
||||
use crate::path::Path;
|
||||
|
||||
#[unstable(feature = "yggdrasil_os", issue = "none")]
|
||||
pub type TerminalOptions = rt::TerminalOptions;
|
||||
|
||||
#[unstable(feature = "yggdrasil_os", issue = "none")]
|
||||
pub type TerminalSize = rt::TerminalSize;
|
||||
|
||||
#[unstable(feature = "yggdrasil_os", issue = "none")]
|
||||
pub unsafe fn set_terminal_options<F: AsRawFd>(fd: &F, opt: &TerminalOptions) -> io::Result<()> {
|
||||
rt::set_terminal_options(fd.as_raw_fd(), opt)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[unstable(feature = "yggdrasil_os", issue = "none")]
|
||||
pub unsafe fn get_terminal_options<F: AsRawFd>(fd: &F) -> io::Result<TerminalOptions> {
|
||||
Ok(rt::get_terminal_options(fd.as_raw_fd())?)
|
||||
}
|
||||
|
||||
#[unstable(feature = "yggdrasil_os", issue = "none")]
|
||||
pub unsafe fn set_terminal_group<F: AsRawFd>(fd: &F, group: ProcessGroupId) -> io::Result<()> {
|
||||
Ok(rt::set_terminal_group(fd.as_raw_fd(), group)?)
|
||||
}
|
||||
|
||||
#[unstable(feature = "yggdrasil_os", issue = "none")]
|
||||
pub fn get_terminal_size<F: AsRawFd>(fd: &F) -> io::Result<TerminalSize> {
|
||||
Ok(rt::get_terminal_size(fd.as_raw_fd())?)
|
||||
}
|
||||
|
||||
#[unstable(feature = "yggdrasil_os", issue = "none")]
|
||||
pub unsafe fn update_terminal_options<F: AsRawFd, M: FnOnce(TerminalOptions) -> TerminalOptions>(
|
||||
fd: &F,
|
||||
mutator: M,
|
||||
) -> io::Result<TerminalOptions> {
|
||||
let old = get_terminal_options(fd)?;
|
||||
let new = mutator(old);
|
||||
set_terminal_options(fd, &new)?;
|
||||
Ok(old)
|
||||
}
|
||||
|
||||
#[unstable(feature = "yggdrasil_os", issue = "none")]
|
||||
pub unsafe fn start_terminal_session<P: AsRef<Path>>(terminal: P) -> io::Result<()> {
|
||||
let terminal = terminal.as_ref().to_str().unwrap();
|
||||
|
||||
syscall::start_session()?;
|
||||
|
||||
let stdin_fd = syscall::open(None, terminal, OpenOptions::READ, FileMode::empty())?;
|
||||
let stdout_stderr_fd = syscall::open(None, terminal, OpenOptions::WRITE, FileMode::empty())?;
|
||||
|
||||
syscall::clone_fd(stdin_fd, Some(RawFd::STDIN))?;
|
||||
syscall::clone_fd(stdout_stderr_fd, Some(RawFd::STDOUT))?;
|
||||
syscall::clone_fd(stdout_stderr_fd, Some(RawFd::STDERR))?;
|
||||
|
||||
syscall::close(stdin_fd)?;
|
||||
syscall::close(stdout_stderr_fd)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[unstable(feature = "yggdrasil_os", issue = "none")]
|
||||
pub fn create_pty(
|
||||
options: Option<TerminalOptions>,
|
||||
size: TerminalSize,
|
||||
) -> io::Result<(File, File)> {
|
||||
let options = options.unwrap_or_default();
|
||||
let mut fds = [MaybeUninit::uninit(), MaybeUninit::uninit()];
|
||||
|
||||
unsafe { syscall::create_pty(&options, &size, &mut fds) }?;
|
||||
|
||||
let master = unsafe { File::from_raw_fd(fds[0].assume_init()) };
|
||||
let slave = unsafe { File::from_raw_fd(fds[1].assume_init()) };
|
||||
|
||||
Ok((master, slave))
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
#![unstable(feature = "yggdrasil_os", issue = "none")]
|
||||
|
||||
use yggdrasil_rt::io::TimerOptions;
|
||||
use yggdrasil_rt::sys as syscall;
|
||||
|
||||
use crate::io;
|
||||
use crate::os::fd::{AsRawFd, FromRawFd, RawFd};
|
||||
use crate::sys::fd::FileDesc;
|
||||
use crate::time::Duration;
|
||||
|
||||
#[unstable(feature = "yggdrasil_os", issue = "none")]
|
||||
pub struct TimerFd(FileDesc);
|
||||
|
||||
impl TimerFd {
|
||||
#[unstable(feature = "yggdrasil_os", issue = "none")]
|
||||
pub fn new(repeat: bool, nonblocking: bool) -> io::Result<Self> {
|
||||
let mut options = TimerOptions::empty();
|
||||
if repeat {
|
||||
options |= TimerOptions::REPEAT;
|
||||
}
|
||||
let raw = unsafe { syscall::create_timer(options) }?;
|
||||
let fd = unsafe { FileDesc::from_raw_fd(raw) };
|
||||
if nonblocking {
|
||||
fd.set_nonblocking(true)?;
|
||||
}
|
||||
Ok(Self(fd))
|
||||
}
|
||||
|
||||
pub fn start(&mut self, timeout: Duration) -> io::Result<()> {
|
||||
let tval = timeout.as_micros();
|
||||
unsafe { syscall::write(self.0.as_raw_fd(), &tval.to_ne_bytes()) }?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn is_expired(&mut self) -> io::Result<bool> {
|
||||
let mut buf = [0; 1];
|
||||
match unsafe { syscall::read(self.0.as_raw_fd(), &mut buf) }.map_err(io::Error::from) {
|
||||
Ok(_) => Ok(true),
|
||||
Err(e) if e.kind() == io::ErrorKind::WouldBlock => Ok(false),
|
||||
Err(e) => Err(e),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "yggdrasil_os", issue = "none")]
|
||||
impl AsRawFd for TimerFd {
|
||||
fn as_raw_fd(&self) -> RawFd {
|
||||
self.0.as_raw_fd()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
#![unstable(feature = "yggdrasil_os", issue = "none")]
|
||||
#![allow(exported_private_dependencies)]
|
||||
|
||||
pub use yggdrasil_rt as rt;
|
||||
|
||||
pub mod fs;
|
||||
pub mod io;
|
||||
pub mod process;
|
||||
pub mod signal;
|
||||
|
||||
use yggdrasil_rt::process::ProgramArgumentInner;
|
||||
use yggdrasil_rt::sys as syscall;
|
||||
|
||||
use crate::path::{Path, PathBuf};
|
||||
|
||||
pub(crate) static mut REAL_BINARY_PATH: Option<PathBuf> = None;
|
||||
|
||||
pub(crate) unsafe fn set_real_program(program_arg: &ProgramArgumentInner) {
|
||||
if let Some(real_program) = program_arg.real_program() {
|
||||
let real_program_str = real_program.to_str().expect("Invalid real_program from kernel");
|
||||
REAL_BINARY_PATH = Some(PathBuf::from(real_program_str));
|
||||
}
|
||||
}
|
||||
|
||||
pub fn real_binary_path() -> &'static Path {
|
||||
#[allow(static_mut_refs)]
|
||||
unsafe {
|
||||
REAL_BINARY_PATH.as_deref().unwrap_or_else(|| Path::new(""))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_random(buffer: &mut [crate::mem::MaybeUninit<u8>]) {
|
||||
unsafe { syscall::get_random(buffer.assume_init_mut()) }
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
#![stable(feature = "os", since = "1.0.0")]
|
||||
|
||||
use yggdrasil_rt::io::RawFd;
|
||||
#[unstable(feature = "yggdrasil_os", issue = "none")]
|
||||
pub use yggdrasil_rt::process::ProcessGroupId;
|
||||
use yggdrasil_rt::process::{ProcessId, Signal, SpawnFlags};
|
||||
use yggdrasil_rt::sys as syscall;
|
||||
|
||||
use crate::io;
|
||||
use crate::path::Path;
|
||||
use crate::process::{Child, Command, ExitStatus};
|
||||
use crate::sealed::Sealed;
|
||||
use crate::sys::{AsInner, AsInnerMut};
|
||||
|
||||
#[unstable(feature = "yggdrasil_os", issue = "none")]
|
||||
pub trait ChildExt: Sealed {
|
||||
#[unstable(feature = "yggdrasil_os", issue = "none")]
|
||||
fn main_thread_id(&self) -> io::Result<u32>;
|
||||
}
|
||||
|
||||
#[unstable(feature = "yggdrasil_os", issue = "none")]
|
||||
pub trait CommandExt: Sealed {
|
||||
#[unstable(feature = "yggdrasil_os", issue = "none")]
|
||||
fn process_group(&mut self, pgroup: ProcessGroupId) -> &mut Command;
|
||||
|
||||
#[unstable(feature = "yggdrasil_os", issue = "none")]
|
||||
unsafe fn gain_terminal<F: Into<RawFd>>(&mut self, fd: F) -> &mut Command;
|
||||
|
||||
#[unstable(feature = "yggdrasil_os", issue = "none")]
|
||||
unsafe fn attach_tracing(&mut self) -> &mut Command;
|
||||
|
||||
#[unstable(feature = "yggdrasil_os", issue = "none")]
|
||||
fn disable_aslr(&mut self) -> &mut Command;
|
||||
|
||||
#[unstable(feature = "yggdrasil_os", issue = "none")]
|
||||
fn change_root<P: AsRef<Path>>(&mut self, new: P) -> &mut Command;
|
||||
}
|
||||
|
||||
#[unstable(feature = "yggdrasil_os", issue = "none")]
|
||||
pub trait ExitStatusExt: Sealed {
|
||||
#[unstable(feature = "yggdrasil_os", issue = "none")]
|
||||
fn signal(&self) -> Option<Result<Signal, u32>>;
|
||||
}
|
||||
|
||||
#[unstable(feature = "yggdrasil_os", issue = "none")]
|
||||
impl CommandExt for Command {
|
||||
fn process_group(&mut self, pgroup: ProcessGroupId) -> &mut Command {
|
||||
self.as_inner_mut().pgroup = Some(pgroup);
|
||||
self
|
||||
}
|
||||
|
||||
unsafe fn gain_terminal<F: Into<RawFd>>(&mut self, fd: F) -> &mut Command {
|
||||
self.as_inner_mut().gain_terminal = Some(fd.into());
|
||||
self
|
||||
}
|
||||
|
||||
unsafe fn attach_tracing(&mut self) -> &mut Command {
|
||||
self.as_inner_mut().attach_trace = true;
|
||||
self
|
||||
}
|
||||
|
||||
fn disable_aslr(&mut self) -> &mut Command {
|
||||
self.as_inner_mut().flags |= SpawnFlags::DISABLE_ASLR;
|
||||
self
|
||||
}
|
||||
|
||||
fn change_root<P: AsRef<Path>>(&mut self, new: P) -> &mut Command {
|
||||
self.as_inner_mut().change_root(new);
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "yggdrasil_os", issue = "none")]
|
||||
impl ExitStatusExt for ExitStatus {
|
||||
fn signal(&self) -> Option<Result<Signal, u32>> {
|
||||
self.as_inner().signal()
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "yggdrasil_os", issue = "none")]
|
||||
impl ChildExt for Child {
|
||||
fn main_thread_id(&self) -> io::Result<u32> {
|
||||
self.as_inner().main_thread_id()
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "yggdrasil_os", issue = "none")]
|
||||
pub fn id_ext() -> ProcessId {
|
||||
unsafe { syscall::get_pid() }
|
||||
}
|
||||
|
||||
#[unstable(feature = "yggdrasil_os", issue = "none")]
|
||||
pub fn group_id() -> ProcessGroupId {
|
||||
unsafe { syscall::get_process_group_id() }
|
||||
}
|
||||
|
||||
#[unstable(feature = "yggdrasil_os", issue = "none")]
|
||||
pub fn create_process_group() -> ProcessGroupId {
|
||||
unsafe { syscall::create_process_group() }
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
pub use yggdrasil_rt::process::{ProcessId, Signal};
|
||||
pub use yggdrasil_rt::sys as syscall;
|
||||
|
||||
use crate::io;
|
||||
|
||||
#[must_use = "It is adviced to store the original handler in case it needs to be restored later"]
|
||||
#[derive(Clone, Copy)]
|
||||
pub enum SignalHandler {
|
||||
Ignore,
|
||||
Terminate,
|
||||
Function(fn(Signal)),
|
||||
}
|
||||
|
||||
pub fn set_signal_handler(signal: Signal, handler: SignalHandler) -> SignalHandler {
|
||||
crate::sys::signal::set_signal_handler(signal, handler)
|
||||
}
|
||||
|
||||
pub fn send(destination: u32, signal: Signal) -> io::Result<()> {
|
||||
let destination = unsafe { ProcessId::from_raw(destination) };
|
||||
unsafe { syscall::send_signal(destination, signal) }?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn abort() -> ! {
|
||||
unsafe { syscall::send_signal(syscall::get_pid(), Signal::Aborted) }.expect("Could not abort");
|
||||
unreachable!();
|
||||
}
|
||||
@@ -107,4 +107,7 @@ cfg_select! {
|
||||
target_os = "zkvm" => {
|
||||
mod zkvm;
|
||||
}
|
||||
target_os = "yggdrasil" => {
|
||||
mod yggdrasil;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
use libyalloc::allocator::BucketAllocator;
|
||||
use libyalloc::sys::OsPageProvider;
|
||||
|
||||
use crate::alloc::{GlobalAlloc, Layout, System};
|
||||
use crate::cell::UnsafeCell;
|
||||
use crate::ptr::NonNull;
|
||||
use crate::sys::sync::Mutex;
|
||||
|
||||
struct Global {
|
||||
lock: Mutex,
|
||||
inner: UnsafeCell<BucketAllocator<OsPageProvider>>,
|
||||
}
|
||||
|
||||
#[stable(feature = "alloc_system_type", since = "1.28.0")]
|
||||
unsafe impl GlobalAlloc for System {
|
||||
#[inline]
|
||||
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
|
||||
let ptr = unsafe {
|
||||
ALLOC.lock.lock();
|
||||
let ptr = (*ALLOC.inner.get()).allocate(layout);
|
||||
ALLOC.lock.unlock();
|
||||
ptr
|
||||
};
|
||||
|
||||
if let Some(ptr) = ptr { ptr.as_ptr() } else { crate::ptr::null_mut() }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
|
||||
let ptr = NonNull::new(ptr).expect("Invalid pointer");
|
||||
|
||||
unsafe {
|
||||
ALLOC.lock.lock();
|
||||
(*ALLOC.inner.get()).free(ptr, layout);
|
||||
ALLOC.lock.unlock();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Global {
|
||||
#[rustc_const_unstable(feature = "yggdrasil_os", issue = "none")]
|
||||
const fn new() -> Self {
|
||||
Self { lock: Mutex::new(), inner: UnsafeCell::new(BucketAllocator::new()) }
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl Sync for Global {}
|
||||
|
||||
static ALLOC: Global = Global::new();
|
||||
@@ -53,6 +53,10 @@ cfg_select! {
|
||||
mod zkvm;
|
||||
pub use zkvm::*;
|
||||
}
|
||||
target_os = "yggdrasil" => {
|
||||
mod yggdrasil;
|
||||
pub use yggdrasil::*;
|
||||
}
|
||||
_ => {
|
||||
mod unsupported;
|
||||
pub use unsupported::*;
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
use crate::ffi::OsString;
|
||||
use crate::{fmt, vec};
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(Clone)]
|
||||
pub struct Args {
|
||||
iter: vec::IntoIter<OsString>,
|
||||
}
|
||||
|
||||
pub fn args() -> Args {
|
||||
Args { iter: imp::clone() }
|
||||
}
|
||||
|
||||
impl fmt::Debug for Args {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
fmt::Debug::fmt(&self.iter, f)
|
||||
}
|
||||
}
|
||||
|
||||
impl Iterator for Args {
|
||||
type Item = OsString;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
self.iter.next()
|
||||
}
|
||||
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
self.iter.size_hint()
|
||||
}
|
||||
}
|
||||
|
||||
impl ExactSizeIterator for Args {
|
||||
fn len(&self) -> usize {
|
||||
self.iter.len()
|
||||
}
|
||||
}
|
||||
|
||||
impl DoubleEndedIterator for Args {
|
||||
fn next_back(&mut self) -> Option<Self::Item> {
|
||||
self.iter.next_back()
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) mod imp {
|
||||
use yggdrasil_rt::process::ProgramArgumentInner;
|
||||
|
||||
use crate::ffi::{OsStr, OsString};
|
||||
use crate::sync::atomic::{AtomicPtr, Ordering};
|
||||
use crate::{ptr, vec};
|
||||
|
||||
static ARGS: AtomicPtr<Vec<OsString>> = AtomicPtr::new(ptr::null_mut());
|
||||
|
||||
pub(crate) fn init(arg: &ProgramArgumentInner) {
|
||||
let mut args = Box::new(Vec::new());
|
||||
|
||||
for arg in arg.args() {
|
||||
let arg = unsafe { OsStr::from_encoded_bytes_unchecked(arg.to_bytes()) };
|
||||
args.push(arg.to_owned());
|
||||
}
|
||||
|
||||
let args = Box::into_raw(args);
|
||||
ARGS.store(args, Ordering::Release);
|
||||
}
|
||||
|
||||
pub(super) fn clone() -> vec::IntoIter<OsString> {
|
||||
unsafe {
|
||||
ARGS.load(Ordering::Acquire)
|
||||
.as_ref()
|
||||
.expect("Program arguments not yet initialized")
|
||||
.clone()
|
||||
.into_iter()
|
||||
}
|
||||
}
|
||||
}
|
||||
Vendored
+4
@@ -55,6 +55,10 @@ cfg_select! {
|
||||
mod zkvm;
|
||||
pub use zkvm::*;
|
||||
}
|
||||
target_os = "yggdrasil" => {
|
||||
mod yggdrasil;
|
||||
pub use yggdrasil::*;
|
||||
}
|
||||
_ => {
|
||||
mod unsupported;
|
||||
pub use unsupported::*;
|
||||
|
||||
Vendored
+107
@@ -0,0 +1,107 @@
|
||||
use crate::collections::hash_map;
|
||||
use crate::ffi::{OsStr, OsString};
|
||||
use crate::sys::AsInner;
|
||||
use crate::{fmt, io};
|
||||
|
||||
pub struct Env {
|
||||
iter: hash_map::IntoIter<OsString, OsString>,
|
||||
}
|
||||
|
||||
impl !Send for Env {}
|
||||
impl !Sync for Env {}
|
||||
|
||||
impl Iterator for Env {
|
||||
type Item = (OsString, OsString);
|
||||
|
||||
fn next(&mut self) -> Option<(OsString, OsString)> {
|
||||
self.iter.next()
|
||||
}
|
||||
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
self.iter.size_hint()
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for Env {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
fmt::Debug::fmt(&self.iter, f)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn env() -> Env {
|
||||
let iter = imp::read().clone().into_iter();
|
||||
Env { iter }
|
||||
}
|
||||
|
||||
pub fn getenv(name: &OsStr) -> Option<OsString> {
|
||||
if name.as_inner().as_encoded_bytes().contains(&b'=') {
|
||||
return None;
|
||||
}
|
||||
let env = imp::read();
|
||||
env.get(name).cloned()
|
||||
}
|
||||
|
||||
pub unsafe fn setenv(name: &OsStr, value: &OsStr) -> io::Result<()> {
|
||||
if name.as_inner().as_encoded_bytes().contains(&b'=') {
|
||||
return Err(io::Error::new(io::ErrorKind::Uncategorized, "Invalid env var name"));
|
||||
}
|
||||
let mut env = imp::write();
|
||||
env.insert(name.to_owned(), value.to_owned());
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub unsafe fn unsetenv(name: &OsStr) -> io::Result<()> {
|
||||
if name.as_inner().as_encoded_bytes().contains(&b'=') {
|
||||
return Err(io::Error::new(io::ErrorKind::Uncategorized, "Invalid env var name"));
|
||||
}
|
||||
let mut env = imp::write();
|
||||
env.remove(name);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) mod imp {
|
||||
use yggdrasil_rt::process::ProgramArgumentInner;
|
||||
|
||||
use crate::collections::HashMap;
|
||||
use crate::ffi::{OsStr, OsString};
|
||||
use crate::ptr;
|
||||
use crate::sync::atomic::{AtomicPtr, Ordering};
|
||||
use crate::sync::{RwLock, RwLockReadGuard, RwLockWriteGuard};
|
||||
|
||||
static ENV: AtomicPtr<RwLock<HashMap<OsString, OsString>>> = AtomicPtr::new(ptr::null_mut());
|
||||
|
||||
pub(super) fn read() -> RwLockReadGuard<'static, HashMap<OsString, OsString>> {
|
||||
unsafe {
|
||||
ENV.load(Ordering::Acquire)
|
||||
.as_ref()
|
||||
.expect("Environment variables not initialized")
|
||||
.read()
|
||||
.expect("Could not obtain env read lock")
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn write() -> RwLockWriteGuard<'static, HashMap<OsString, OsString>> {
|
||||
unsafe {
|
||||
ENV.load(Ordering::Acquire)
|
||||
.as_ref()
|
||||
.expect("Environment variables not initialized")
|
||||
.write()
|
||||
.expect("Could not obtain env write lock")
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn init(arg: &ProgramArgumentInner) {
|
||||
let mut envs = HashMap::new();
|
||||
for pair in arg.envs() {
|
||||
let pair = pair.to_bytes();
|
||||
let Some((key, value)) = pair.split_once(|c| *c == b'=') else { continue };
|
||||
let key = unsafe { OsStr::from_encoded_bytes_unchecked(key).to_owned() };
|
||||
let value = unsafe { OsStr::from_encoded_bytes_unchecked(value).to_owned() };
|
||||
|
||||
envs.insert(key, value);
|
||||
}
|
||||
|
||||
let envs = Box::into_raw(Box::new(RwLock::new(envs)));
|
||||
ENV.store(envs, Ordering::Release);
|
||||
}
|
||||
}
|
||||
@@ -15,6 +15,10 @@ cfg_select! {
|
||||
mod motor;
|
||||
pub use motor::*;
|
||||
}
|
||||
target_os = "yggdrasil" => {
|
||||
mod yggdrasil;
|
||||
pub use yggdrasil::*;
|
||||
}
|
||||
all(target_vendor = "fortanix", target_env = "sgx") => {
|
||||
mod sgx;
|
||||
pub use sgx::*;
|
||||
|
||||
@@ -0,0 +1,128 @@
|
||||
use yggdrasil_rt::io::{self as rt, FileSync, options};
|
||||
use yggdrasil_rt::sys as syscall;
|
||||
|
||||
use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut, SeekFrom};
|
||||
use crate::os::fd::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd};
|
||||
use crate::sys::fs::{self, FileAttr};
|
||||
use crate::sys::{AsInner, FromInner, IntoInner};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct FileDesc {
|
||||
fd: OwnedFd,
|
||||
}
|
||||
|
||||
impl FileDesc {
|
||||
pub(crate) fn set_nonblocking(&self, non_blocking: bool) -> io::Result<()> {
|
||||
rt::set_file_option::<options::NonBlocking>(self.as_raw_fd(), &non_blocking)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn read(&self, buffer: &mut [u8]) -> io::Result<usize> {
|
||||
Ok(unsafe { syscall::read(self.fd.as_raw_fd(), buffer) }?)
|
||||
}
|
||||
|
||||
pub(crate) fn read_buf(&self, cursor: BorrowedCursor<'_>) -> io::Result<()> {
|
||||
io::default_read_buf(|buf| self.read(buf), cursor)
|
||||
}
|
||||
|
||||
pub(crate) fn read_vectored(&self, _bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
|
||||
todo!("FileDesc::read_vectored()")
|
||||
}
|
||||
|
||||
pub(crate) fn write(&self, buffer: &[u8]) -> io::Result<usize> {
|
||||
Ok(unsafe { syscall::write(self.fd.as_raw_fd(), buffer) }?)
|
||||
}
|
||||
|
||||
pub(crate) fn write_vectored(&self, _bufs: &[IoSlice<'_>]) -> io::Result<usize> {
|
||||
todo!("FileDesc::write_vectored()")
|
||||
}
|
||||
|
||||
pub(crate) fn read_to_end(&self, buffer: &mut Vec<u8>) -> io::Result<usize> {
|
||||
let mut buf = [0; 512];
|
||||
let mut bytes_read = 0;
|
||||
|
||||
loop {
|
||||
let amount = self.read(&mut buf)?;
|
||||
if amount == 0 {
|
||||
break;
|
||||
}
|
||||
|
||||
buffer.extend_from_slice(&buf[..amount]);
|
||||
bytes_read += amount;
|
||||
}
|
||||
|
||||
Ok(bytes_read)
|
||||
}
|
||||
|
||||
pub(crate) fn try_clone(&self) -> io::Result<Self> {
|
||||
let raw = unsafe { syscall::clone_fd(self.as_raw_fd(), None) }?;
|
||||
Ok(unsafe { Self::from_raw_fd(raw) })
|
||||
}
|
||||
|
||||
pub(crate) fn metadata(&self) -> io::Result<FileAttr> {
|
||||
fs::get_metadata_inner(Some(self.as_raw_fd()), "", true)
|
||||
}
|
||||
|
||||
pub(crate) fn truncate(&self, size: u64) -> io::Result<()> {
|
||||
unsafe { syscall::truncate(self.as_raw_fd(), size) }?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn datasync(&self) -> io::Result<()> {
|
||||
unsafe { syscall::fsync(self.as_raw_fd(), FileSync::DATA) }?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn fsync(&self) -> io::Result<()> {
|
||||
unsafe { syscall::fsync(self.as_raw_fd(), FileSync::METADATA | FileSync::DATA) }?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn seek(&self, pos: SeekFrom) -> io::Result<u64> {
|
||||
let mut output = 0;
|
||||
unsafe { syscall::seek(self.as_raw_fd(), pos.into(), &mut output) }?;
|
||||
Ok(output)
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoInner<OwnedFd> for FileDesc {
|
||||
fn into_inner(self) -> OwnedFd {
|
||||
self.fd
|
||||
}
|
||||
}
|
||||
|
||||
impl FromInner<OwnedFd> for FileDesc {
|
||||
fn from_inner(fd: OwnedFd) -> Self {
|
||||
Self { fd }
|
||||
}
|
||||
}
|
||||
|
||||
impl FromRawFd for FileDesc {
|
||||
unsafe fn from_raw_fd(raw_fd: RawFd) -> Self {
|
||||
unsafe { Self { fd: FromRawFd::from_raw_fd(raw_fd) } }
|
||||
}
|
||||
}
|
||||
|
||||
impl AsInner<OwnedFd> for FileDesc {
|
||||
fn as_inner(&self) -> &OwnedFd {
|
||||
&self.fd
|
||||
}
|
||||
}
|
||||
|
||||
impl AsFd for FileDesc {
|
||||
fn as_fd(&self) -> BorrowedFd<'_> {
|
||||
self.fd.as_fd()
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRawFd for FileDesc {
|
||||
fn as_raw_fd(&self) -> RawFd {
|
||||
self.fd.as_raw_fd()
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoRawFd for FileDesc {
|
||||
fn into_raw_fd(self) -> RawFd {
|
||||
self.fd.into_raw_fd()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
#![allow(exported_private_dependencies)]
|
||||
|
||||
use yggdrasil_rt::io::SeekFrom as OsSeekFrom;
|
||||
|
||||
use crate::io::SeekFrom;
|
||||
|
||||
mod file;
|
||||
mod socket;
|
||||
|
||||
pub use file::FileDesc;
|
||||
pub(crate) use socket::SocketFileDesc;
|
||||
|
||||
#[unstable(feature = "yggdrasil_os", issue = "none")]
|
||||
impl From<SeekFrom> for OsSeekFrom {
|
||||
fn from(value: SeekFrom) -> OsSeekFrom {
|
||||
match value {
|
||||
SeekFrom::Start(v) => OsSeekFrom::Start(v),
|
||||
SeekFrom::End(v) => OsSeekFrom::End(v),
|
||||
SeekFrom::Current(v) => OsSeekFrom::Current(v),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,245 @@
|
||||
use yggdrasil_rt::{io as rt_io, net as rt, sys as syscall};
|
||||
|
||||
use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut};
|
||||
use crate::net::{Ipv4Addr, Ipv6Addr, Shutdown, SocketAddr};
|
||||
use crate::os::fd::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd};
|
||||
use crate::sys::{AsInner, FromInner, IntoInner};
|
||||
use crate::time::Duration;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct SocketFileDesc {
|
||||
fd: OwnedFd,
|
||||
}
|
||||
|
||||
impl SocketFileDesc {
|
||||
pub(crate) fn set_read_timeout(&self, timeout: Option<Duration>) -> io::Result<()> {
|
||||
rt::set_socket_option::<rt::options::RecvTimeout>(self.as_raw_fd(), &timeout)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn set_write_timeout(&self, timeout: Option<Duration>) -> io::Result<()> {
|
||||
rt::set_socket_option::<rt::options::SendTimeout>(self.as_raw_fd(), &timeout)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn set_linger(&self, _linger: Option<Duration>) -> io::Result<()> {
|
||||
todo!("sys::fd::yggdrasil::socket::SocketFileDesc::set_linger()")
|
||||
}
|
||||
|
||||
pub(crate) fn set_nodelay(&self, nodelay: bool) -> io::Result<()> {
|
||||
rt::set_socket_option::<rt::options::NoDelay>(self.as_raw_fd(), &nodelay)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn set_ttl(&self, ttl: u32) -> io::Result<()> {
|
||||
rt::set_socket_option::<rt::options::Ttl>(self.as_raw_fd(), &ttl)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
|
||||
rt_io::set_file_option::<rt_io::options::NonBlocking>(self.as_raw_fd(), &nonblocking)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn set_only_v6(&self, only_v6: bool) -> io::Result<()> {
|
||||
rt::set_socket_option::<rt::options::Ipv6Only>(self.as_raw_fd(), &only_v6)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn set_broadcast(&self, broadcast: bool) -> io::Result<()> {
|
||||
rt::set_socket_option::<rt::options::Broadcast>(self.as_raw_fd(), &broadcast)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn set_multicast_loop_v4(&self, loop_v4: bool) -> io::Result<()> {
|
||||
rt::set_socket_option::<rt::options::MulticastLoopV4>(self.as_raw_fd(), &loop_v4)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn set_multicast_ttl_v4(&self, ttl: u32) -> io::Result<()> {
|
||||
rt::set_socket_option::<rt::options::MulticastTtlV4>(self.as_raw_fd(), &ttl)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn set_multicast_loop_v6(&self, loop_v6: bool) -> io::Result<()> {
|
||||
rt::set_socket_option::<rt::options::MulticastLoopV6>(self.as_raw_fd(), &loop_v6)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn read_timeout(&self) -> io::Result<Option<Duration>> {
|
||||
Ok(rt::get_socket_option!(self.as_raw_fd(), rt::options::RecvTimeout)?)
|
||||
}
|
||||
|
||||
pub(crate) fn write_timeout(&self) -> io::Result<Option<Duration>> {
|
||||
Ok(rt::get_socket_option!(self.as_raw_fd(), rt::options::SendTimeout)?)
|
||||
}
|
||||
|
||||
pub(crate) fn linger(&self) -> io::Result<Option<Duration>> {
|
||||
todo!("sys::fd::yggdrasil::socket::SocketFileDesc::linger()")
|
||||
}
|
||||
|
||||
pub(crate) fn nodelay(&self) -> io::Result<bool> {
|
||||
Ok(rt::get_socket_option!(self.as_raw_fd(), rt::options::NoDelay)?)
|
||||
}
|
||||
|
||||
pub(crate) fn ttl(&self) -> io::Result<u32> {
|
||||
Ok(rt::get_socket_option!(self.as_raw_fd(), rt::options::Ttl)?)
|
||||
}
|
||||
|
||||
pub(crate) fn only_v6(&self) -> io::Result<bool> {
|
||||
Ok(rt::get_socket_option!(self.as_raw_fd(), rt::options::Ipv6Only)?)
|
||||
}
|
||||
|
||||
pub(crate) fn broadcast(&self) -> io::Result<bool> {
|
||||
Ok(rt::get_socket_option!(self.as_raw_fd(), rt::options::Broadcast)?)
|
||||
}
|
||||
|
||||
pub fn multicast_loop_v4(&self) -> io::Result<bool> {
|
||||
Ok(rt::get_socket_option!(self.as_raw_fd(), rt::options::MulticastLoopV4)?)
|
||||
}
|
||||
|
||||
pub fn multicast_ttl_v4(&self) -> io::Result<u32> {
|
||||
Ok(rt::get_socket_option!(self.as_raw_fd(), rt::options::MulticastTtlV4)?)
|
||||
}
|
||||
|
||||
pub fn multicast_loop_v6(&self) -> io::Result<bool> {
|
||||
Ok(rt::get_socket_option!(self.as_raw_fd(), rt::options::MulticastLoopV6)?)
|
||||
}
|
||||
|
||||
pub(crate) fn local_addr(&self) -> io::Result<SocketAddr> {
|
||||
Ok(rt::local_address(self.as_raw_fd())?)
|
||||
}
|
||||
|
||||
pub(crate) fn peer_addr(&self) -> io::Result<SocketAddr> {
|
||||
Ok(rt::peer_address(self.as_raw_fd())?)
|
||||
}
|
||||
|
||||
pub(crate) fn join_multicast_v4(
|
||||
&self,
|
||||
_multiaddr: &Ipv4Addr,
|
||||
_interface: &Ipv4Addr,
|
||||
) -> io::Result<()> {
|
||||
todo!("sys::fd::yggdrasil::socket::SocketFileDesc::join_multicast_v4()")
|
||||
}
|
||||
|
||||
pub(crate) fn join_multicast_v6(
|
||||
&self,
|
||||
_multiaddr: &Ipv6Addr,
|
||||
_interface: u32,
|
||||
) -> io::Result<()> {
|
||||
todo!("sys::fd::yggdrasil::socket::SocketFileDesc::join_multicast_v6()")
|
||||
}
|
||||
|
||||
pub(crate) fn leave_multicast_v4(
|
||||
&self,
|
||||
_multiaddr: &Ipv4Addr,
|
||||
_interface: &Ipv4Addr,
|
||||
) -> io::Result<()> {
|
||||
todo!("sys::fd::yggdrasil::socket::SocketFileDesc::leave_multicast_v4()")
|
||||
}
|
||||
|
||||
pub(crate) fn leave_multicast_v6(
|
||||
&self,
|
||||
_multiaddr: &Ipv6Addr,
|
||||
_interface: u32,
|
||||
) -> io::Result<()> {
|
||||
todo!("sys::fd::yggdrasil::socket::SocketFileDesc::leave_multicast_v6()")
|
||||
}
|
||||
|
||||
pub fn take_error(&self) -> io::Result<Option<io::Error>> {
|
||||
todo!("sys::fd::yggdrasil::socket::SocketFileDesc::take_error()")
|
||||
}
|
||||
|
||||
pub(crate) fn accept(&self) -> io::Result<(SocketFileDesc, SocketAddr)> {
|
||||
let (raw, remote) = rt::socket::accept_ip(self.as_raw_fd())?;
|
||||
let fd = unsafe { Self::from_raw_fd(raw) };
|
||||
Ok((fd, remote))
|
||||
}
|
||||
|
||||
pub(crate) fn recv_from(&self, buffer: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
|
||||
Ok(rt::socket::receive_from_ip(self.as_raw_fd(), buffer)?)
|
||||
}
|
||||
|
||||
pub(crate) fn recv(&self, buffer: &mut [u8]) -> io::Result<usize> {
|
||||
Ok(rt::socket::receive(self.as_raw_fd(), buffer)?)
|
||||
}
|
||||
|
||||
pub(crate) fn recv_buf(&self, _buf: BorrowedCursor<'_>) -> io::Result<()> {
|
||||
todo!("sys::fd::yggdrasil::socket::SocketFileDesc::recv_buf()")
|
||||
}
|
||||
|
||||
pub(crate) fn recv_vectored(&self, _bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
|
||||
todo!("sys::fd::yggdrasil::socket::SocketFileDesc::recv_vectored()")
|
||||
}
|
||||
|
||||
pub(crate) fn peek(&self, _buffer: &mut [u8]) -> io::Result<usize> {
|
||||
todo!("sys::fd::yggdrasil::socket::SocketFileDesc::peek()")
|
||||
}
|
||||
|
||||
pub(crate) fn peek_from(&self, _buffer: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
|
||||
todo!("sys::fd::yggdrasil::socket::SocketFileDesc::peek_from()")
|
||||
}
|
||||
|
||||
pub(crate) fn send(&self, data: &[u8]) -> io::Result<usize> {
|
||||
Ok(rt::socket::send(self.as_raw_fd(), data)?)
|
||||
}
|
||||
|
||||
pub(crate) fn send_to(&self, data: &[u8], dst: &SocketAddr) -> io::Result<usize> {
|
||||
Ok(rt::socket::send_to_ip(self.as_raw_fd(), data, dst)?)
|
||||
}
|
||||
|
||||
pub(crate) fn send_vectored(&self, _data: &[IoSlice<'_>]) -> io::Result<usize> {
|
||||
todo!("sys::fd::yggdrasil::socket::SocketFileDesc::send_vectored()")
|
||||
}
|
||||
|
||||
pub(crate) fn shutdown(&self, _how: Shutdown) -> io::Result<()> {
|
||||
todo!("sys::fd::yggdrasil::socket::SocketFileDesc::shutdown()")
|
||||
}
|
||||
|
||||
pub(crate) fn try_clone(&self) -> io::Result<Self> {
|
||||
let fd = unsafe { syscall::clone_fd(self.as_raw_fd(), None) }?;
|
||||
Ok(unsafe { Self::from_raw_fd(fd) })
|
||||
}
|
||||
}
|
||||
|
||||
impl AsFd for SocketFileDesc {
|
||||
fn as_fd(&self) -> BorrowedFd<'_> {
|
||||
self.fd.as_fd()
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoRawFd for SocketFileDesc {
|
||||
fn into_raw_fd(self) -> RawFd {
|
||||
self.fd.into_raw_fd()
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRawFd for SocketFileDesc {
|
||||
fn as_raw_fd(&self) -> RawFd {
|
||||
self.fd.as_raw_fd()
|
||||
}
|
||||
}
|
||||
|
||||
impl FromRawFd for SocketFileDesc {
|
||||
unsafe fn from_raw_fd(raw_fd: RawFd) -> Self {
|
||||
unsafe { Self { fd: FromRawFd::from_raw_fd(raw_fd) } }
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoInner<OwnedFd> for SocketFileDesc {
|
||||
fn into_inner(self) -> OwnedFd {
|
||||
self.fd
|
||||
}
|
||||
}
|
||||
|
||||
impl AsInner<OwnedFd> for SocketFileDesc {
|
||||
fn as_inner(&self) -> &OwnedFd {
|
||||
&self.fd
|
||||
}
|
||||
}
|
||||
|
||||
impl FromInner<OwnedFd> for SocketFileDesc {
|
||||
fn from_inner(fd: OwnedFd) -> Self {
|
||||
Self { fd }
|
||||
}
|
||||
}
|
||||
@@ -45,6 +45,11 @@ cfg_select! {
|
||||
mod vexos;
|
||||
use vexos as imp;
|
||||
}
|
||||
target_os = "yggdrasil" => {
|
||||
mod yggdrasil;
|
||||
use yggdrasil as imp;
|
||||
pub(crate) use imp::get_metadata_inner;
|
||||
}
|
||||
_ => {
|
||||
mod unsupported;
|
||||
use unsupported as imp;
|
||||
|
||||
@@ -0,0 +1,171 @@
|
||||
use yggdrasil_rt::io::{
|
||||
FileAttr as OsFileAttr, FileMetadataUpdate, FileMetadataUpdateMode, FileMode as OsFileMode,
|
||||
FileType as OsFileType,
|
||||
};
|
||||
use yggdrasil_rt::time::SystemTime as RtSystemTime;
|
||||
|
||||
use crate::hash::Hash;
|
||||
use crate::os::fd::RawFd;
|
||||
use crate::path::Path;
|
||||
use crate::sys::run_with_path_str;
|
||||
use crate::sys::time::SystemTime;
|
||||
use crate::{fmt, io};
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Debug)]
|
||||
pub struct FileAttr(pub(super) OsFileAttr);
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq)]
|
||||
pub struct FilePermissions(pub(super) OsFileMode);
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub struct FileType(pub(super) OsFileType);
|
||||
|
||||
#[derive(Copy, Clone, Debug, Default)]
|
||||
pub struct FileTimes {
|
||||
pub(crate) atime: Option<RtSystemTime>,
|
||||
pub(crate) mtime: Option<RtSystemTime>,
|
||||
}
|
||||
|
||||
impl FileAttr {
|
||||
pub fn size(&self) -> u64 {
|
||||
self.0.size
|
||||
}
|
||||
|
||||
pub fn perm(&self) -> FilePermissions {
|
||||
FilePermissions(self.0.mode)
|
||||
}
|
||||
|
||||
pub fn file_type(&self) -> FileType {
|
||||
FileType(self.0.ty)
|
||||
}
|
||||
|
||||
pub fn mode_ext(&self) -> OsFileMode {
|
||||
self.0.mode
|
||||
}
|
||||
|
||||
pub fn inode(&self) -> Option<u32> {
|
||||
self.0.inode
|
||||
}
|
||||
|
||||
pub fn block_count(&self) -> u64 {
|
||||
self.0.block_count
|
||||
}
|
||||
|
||||
pub fn block_size(&self) -> u64 {
|
||||
self.0.block_size
|
||||
}
|
||||
|
||||
pub fn modified(&self) -> io::Result<SystemTime> {
|
||||
let time = SystemTime(self.0.mtime);
|
||||
Ok(time)
|
||||
}
|
||||
|
||||
pub fn accessed(&self) -> io::Result<SystemTime> {
|
||||
let time = SystemTime(self.0.atime);
|
||||
Ok(time)
|
||||
}
|
||||
|
||||
pub fn created(&self) -> io::Result<SystemTime> {
|
||||
let time = SystemTime(self.0.ctime);
|
||||
Ok(time)
|
||||
}
|
||||
}
|
||||
|
||||
impl FilePermissions {
|
||||
pub fn readonly(&self) -> bool {
|
||||
!self.0.contains_any(
|
||||
OsFileMode::USER_WRITE | OsFileMode::GROUP_WRITE | OsFileMode::OTHER_WRITE,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn set_readonly(&mut self, readonly: bool) {
|
||||
if readonly {
|
||||
self.0 &= !(OsFileMode::USER_WRITE | OsFileMode::GROUP_WRITE | OsFileMode::OTHER_WRITE);
|
||||
} else {
|
||||
self.0 |= OsFileMode::USER_WRITE | OsFileMode::GROUP_WRITE | OsFileMode::OTHER_WRITE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for FilePermissions {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
fmt::Debug::fmt(&self.0.bits(), f)
|
||||
}
|
||||
}
|
||||
|
||||
impl FileType {
|
||||
pub fn is_dir(&self) -> bool {
|
||||
self.0 == OsFileType::Directory
|
||||
}
|
||||
|
||||
pub fn is_file(&self) -> bool {
|
||||
self.0 == OsFileType::File
|
||||
}
|
||||
|
||||
pub fn is_symlink(&self) -> bool {
|
||||
self.0 == OsFileType::Symlink
|
||||
}
|
||||
|
||||
pub fn is_char_device(&self) -> bool {
|
||||
self.0 == OsFileType::Char
|
||||
}
|
||||
|
||||
pub fn is_block_device(&self) -> bool {
|
||||
self.0 == OsFileType::Block
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for FileType {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
fmt::Debug::fmt(&self.0, f)
|
||||
}
|
||||
}
|
||||
|
||||
impl FileTimes {
|
||||
pub fn set_accessed(&mut self, t: SystemTime) {
|
||||
self.atime = Some(t.0);
|
||||
}
|
||||
|
||||
pub fn set_modified(&mut self, t: SystemTime) {
|
||||
self.mtime = Some(t.0);
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn get_metadata_inner(
|
||||
at: Option<RawFd>,
|
||||
path: &str,
|
||||
follow: bool,
|
||||
) -> io::Result<FileAttr> {
|
||||
let mut metadata = crate::mem::MaybeUninit::uninit();
|
||||
unsafe { yggdrasil_rt::sys::get_metadata(at, path, &mut metadata, follow) }?;
|
||||
Ok(unsafe { FileAttr(metadata.assume_init()) })
|
||||
}
|
||||
|
||||
pub fn stat(path: &Path) -> io::Result<FileAttr> {
|
||||
run_with_path_str(path, |path_str| get_metadata_inner(None, path_str, true))
|
||||
}
|
||||
|
||||
pub fn lstat(path: &Path) -> io::Result<FileAttr> {
|
||||
run_with_path_str(path, |path_str| get_metadata_inner(None, path_str, false))
|
||||
}
|
||||
|
||||
pub fn set_perm(path: &Path, perm: FilePermissions) -> io::Result<()> {
|
||||
run_with_path_str(path, |path_str| {
|
||||
unsafe {
|
||||
yggdrasil_rt::sys::update_metadata(
|
||||
None,
|
||||
path_str,
|
||||
&FileMetadataUpdate::Permissions(FileMetadataUpdateMode::Set(perm.0)),
|
||||
)
|
||||
}
|
||||
.map_err(io::Error::from)
|
||||
})
|
||||
}
|
||||
|
||||
pub fn set_times(_p: &Path, _times: FileTimes) -> io::Result<()> {
|
||||
todo!("sys::fs::yggdrasil::set_times()")
|
||||
}
|
||||
|
||||
pub fn set_times_nofollow(_p: &Path, _times: FileTimes) -> io::Result<()> {
|
||||
todo!("sys::fs::yggdrasil::set_times_nofollow()")
|
||||
}
|
||||
@@ -0,0 +1,162 @@
|
||||
use yggdrasil_rt::io::{DirectoryEntry as OsDirectoryEntry, FileMode as OsFileMode};
|
||||
|
||||
use super::{FileAttr, FileType, get_metadata_inner};
|
||||
use crate::ffi::OsString;
|
||||
use crate::mem::MaybeUninit;
|
||||
use crate::os::fd::{AsRawFd, FromRawFd};
|
||||
use crate::path::{Path, PathBuf};
|
||||
use crate::str::FromStr;
|
||||
use crate::sys::fd::FileDesc;
|
||||
use crate::sys::run_with_path_str;
|
||||
use crate::{fmt, io};
|
||||
|
||||
const BUFFER_SIZE: usize = 8;
|
||||
|
||||
pub struct DirEntry {
|
||||
filename: OsString,
|
||||
path: PathBuf,
|
||||
ty: FileType,
|
||||
}
|
||||
|
||||
pub struct ReadDir {
|
||||
fd: FileDesc,
|
||||
path: PathBuf,
|
||||
// TODO fetch more entries at a time
|
||||
buffer: [MaybeUninit<OsDirectoryEntry>; BUFFER_SIZE],
|
||||
buffer_position: usize,
|
||||
buffer_len: usize,
|
||||
eof: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct DirBuilder {
|
||||
mode: OsFileMode,
|
||||
}
|
||||
|
||||
impl ReadDir {
|
||||
fn open(path: &Path) -> io::Result<Self> {
|
||||
let path_buf = PathBuf::from(path);
|
||||
let path_str = path.to_str().unwrap();
|
||||
let fd = unsafe { yggdrasil_rt::sys::open_directory(None, path_str) }?;
|
||||
Ok(ReadDir {
|
||||
fd: unsafe { FileDesc::from_raw_fd(fd) },
|
||||
buffer: [MaybeUninit::uninit(); BUFFER_SIZE],
|
||||
buffer_position: 0,
|
||||
buffer_len: 0,
|
||||
path: path_buf,
|
||||
eof: false,
|
||||
})
|
||||
}
|
||||
|
||||
fn fill_buffer(&mut self) -> io::Result<()> {
|
||||
// If eof, don't attempt to load anything
|
||||
// If pos != len, still have some entries
|
||||
if self.eof || self.buffer_position != self.buffer_len {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
self.buffer_position = 0;
|
||||
self.buffer_len = unsafe {
|
||||
yggdrasil_rt::sys::read_directory_entries(self.fd.as_raw_fd(), &mut self.buffer)
|
||||
}?;
|
||||
|
||||
if self.buffer_len == 0 {
|
||||
self.eof = true;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Iterator for ReadDir {
|
||||
type Item = io::Result<DirEntry>;
|
||||
|
||||
fn next(&mut self) -> Option<io::Result<DirEntry>> {
|
||||
loop {
|
||||
if let Err(e) = self.fill_buffer() {
|
||||
break Some(Err(e));
|
||||
}
|
||||
|
||||
if self.eof {
|
||||
return None;
|
||||
}
|
||||
|
||||
assert_ne!(self.buffer_position, self.buffer_len);
|
||||
|
||||
let entry = unsafe { self.buffer[self.buffer_position].assume_init_ref() };
|
||||
self.buffer_position += 1;
|
||||
|
||||
break Some(DirEntry::from_raw(self.path.clone(), entry));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for ReadDir {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
fmt::Debug::fmt(&*self.path, f)
|
||||
}
|
||||
}
|
||||
|
||||
impl DirEntry {
|
||||
fn from_raw(parent: PathBuf, raw: &OsDirectoryEntry) -> io::Result<Self> {
|
||||
let filename = OsString::from_str(raw.name.as_ref()).unwrap();
|
||||
let path = parent.join(filename.clone());
|
||||
let ty = match raw.ty {
|
||||
Some(ty) => FileType(ty),
|
||||
None => {
|
||||
let metadata = run_with_path_str(path.as_ref(), |path_str| {
|
||||
get_metadata_inner(None, path_str, false)
|
||||
})?;
|
||||
|
||||
metadata.file_type()
|
||||
}
|
||||
};
|
||||
|
||||
Ok(Self { path, filename, ty })
|
||||
}
|
||||
|
||||
pub fn path(&self) -> PathBuf {
|
||||
self.path.clone()
|
||||
}
|
||||
|
||||
pub fn file_name(&self) -> OsString {
|
||||
self.filename.clone()
|
||||
}
|
||||
|
||||
pub fn metadata(&self) -> io::Result<FileAttr> {
|
||||
run_with_path_str(self.path.as_ref(), |path_str| get_metadata_inner(None, path_str, false))
|
||||
}
|
||||
|
||||
pub fn file_type(&self) -> io::Result<FileType> {
|
||||
Ok(self.ty)
|
||||
}
|
||||
}
|
||||
|
||||
impl DirBuilder {
|
||||
pub fn new() -> Self {
|
||||
Self { mode: OsFileMode::default_dir() }
|
||||
}
|
||||
|
||||
pub fn mkdir(&self, path: &Path) -> io::Result<()> {
|
||||
run_with_path_str(path, |path_str| {
|
||||
unsafe { yggdrasil_rt::sys::create_directory(None, path_str, self.mode) }
|
||||
.map_err(io::Error::from)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub fn readdir(path: &Path) -> io::Result<ReadDir> {
|
||||
ReadDir::open(path)
|
||||
}
|
||||
|
||||
pub fn rmdir(path: &Path) -> io::Result<()> {
|
||||
run_with_path_str(path, |path_str| {
|
||||
yggdrasil_rt::io::remove_directory(None, path_str).map_err(io::Error::from)
|
||||
})
|
||||
}
|
||||
|
||||
pub fn remove_dir_all(path: &Path) -> io::Result<()> {
|
||||
run_with_path_str(path, |path_str| {
|
||||
yggdrasil_rt::io::remove_directory_recursive(None, path_str).map_err(io::Error::from)
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,252 @@
|
||||
use yggdrasil_rt::io::{
|
||||
FileMetadataUpdate, FileMetadataUpdateMode, FileMode as OsFileMode, FileTimesUpdate,
|
||||
OpenOptions as OsOpenOptions,
|
||||
};
|
||||
|
||||
use super::{FileAttr, FilePermissions, FileTimes};
|
||||
use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut, SeekFrom};
|
||||
use crate::os::fd::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, RawFd};
|
||||
use crate::path::Path;
|
||||
use crate::sys::fd::FileDesc;
|
||||
use crate::sys::{AsInner, AsInnerMut, FromInner, IntoInner};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct File(FileDesc);
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct OpenOptions {
|
||||
pub(crate) options: OsOpenOptions,
|
||||
pub(crate) mode: OsFileMode,
|
||||
}
|
||||
|
||||
impl OpenOptions {
|
||||
pub fn new() -> Self {
|
||||
Self::default()
|
||||
}
|
||||
|
||||
pub fn read(&mut self, read: bool) {
|
||||
if read {
|
||||
self.options |= OsOpenOptions::READ;
|
||||
} else {
|
||||
self.options &= !OsOpenOptions::READ;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn write(&mut self, write: bool) {
|
||||
if write {
|
||||
self.options |= OsOpenOptions::WRITE;
|
||||
} else {
|
||||
self.options &= !OsOpenOptions::WRITE;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn append(&mut self, append: bool) {
|
||||
if append {
|
||||
self.options |= OsOpenOptions::APPEND;
|
||||
} else {
|
||||
self.options &= !OsOpenOptions::APPEND;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn truncate(&mut self, truncate: bool) {
|
||||
if truncate {
|
||||
self.options |= OsOpenOptions::TRUNCATE;
|
||||
} else {
|
||||
self.options &= !OsOpenOptions::TRUNCATE;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn create(&mut self, create: bool) {
|
||||
if create {
|
||||
self.options |= OsOpenOptions::CREATE;
|
||||
} else {
|
||||
self.options &= !OsOpenOptions::CREATE;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn create_new(&mut self, create_new: bool) {
|
||||
if create_new {
|
||||
self.options |= OsOpenOptions::CREATE_EXCL | OsOpenOptions::CREATE;
|
||||
} else {
|
||||
self.options &= !OsOpenOptions::CREATE_EXCL | OsOpenOptions::CREATE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for OpenOptions {
|
||||
fn default() -> Self {
|
||||
Self { mode: OsFileMode::default_file(), options: OsOpenOptions::default() }
|
||||
}
|
||||
}
|
||||
|
||||
impl File {
|
||||
pub fn open(path: &Path, opts: &OpenOptions) -> io::Result<File> {
|
||||
let path = path.as_os_str();
|
||||
unsafe {
|
||||
yggdrasil_rt::sys::open(None, path.to_str().unwrap(), opts.options, opts.mode)
|
||||
.map(|fd| File::from_raw_fd(fd))
|
||||
.map_err(io::Error::from)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn file_attr(&self) -> io::Result<FileAttr> {
|
||||
self.0.metadata()
|
||||
}
|
||||
|
||||
pub fn fsync(&self) -> io::Result<()> {
|
||||
self.0.fsync()
|
||||
}
|
||||
|
||||
pub fn datasync(&self) -> io::Result<()> {
|
||||
self.0.datasync()
|
||||
}
|
||||
|
||||
pub fn truncate(&self, size: u64) -> io::Result<()> {
|
||||
self.0.truncate(size)
|
||||
}
|
||||
|
||||
pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
|
||||
self.0.read(buf)
|
||||
}
|
||||
|
||||
pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
|
||||
self.0.read_vectored(bufs)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_read_vectored(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
pub fn read_buf(&self, cursor: BorrowedCursor<'_>) -> io::Result<()> {
|
||||
self.0.read_buf(cursor)
|
||||
}
|
||||
|
||||
pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
|
||||
self.0.write(buf)
|
||||
}
|
||||
|
||||
pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
|
||||
self.0.write_vectored(bufs)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_write_vectored(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
pub fn lock(&self) -> io::Result<()> {
|
||||
todo!("File::lock()")
|
||||
}
|
||||
|
||||
pub fn lock_shared(&self) -> io::Result<()> {
|
||||
todo!("File::lock_shared()")
|
||||
}
|
||||
|
||||
pub fn try_lock(&self) -> Result<(), crate::fs::TryLockError> {
|
||||
todo!("File::try_lock()")
|
||||
}
|
||||
|
||||
pub fn try_lock_shared(&self) -> Result<(), crate::fs::TryLockError> {
|
||||
todo!("File::try_lock_shared()")
|
||||
}
|
||||
|
||||
pub fn unlock(&self) -> io::Result<()> {
|
||||
todo!("File::unlock()")
|
||||
}
|
||||
|
||||
pub fn flush(&self) -> io::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn size(&self) -> Option<io::Result<u64>> {
|
||||
// TODO
|
||||
None
|
||||
}
|
||||
|
||||
pub fn tell(&self) -> io::Result<u64> {
|
||||
self.0.seek(SeekFrom::Current(0))
|
||||
}
|
||||
|
||||
pub fn seek(&self, pos: SeekFrom) -> io::Result<u64> {
|
||||
self.0.seek(pos)
|
||||
}
|
||||
|
||||
pub fn duplicate(&self) -> io::Result<File> {
|
||||
self.0.try_clone().map(Self)
|
||||
}
|
||||
|
||||
pub fn set_permissions(&self, perm: FilePermissions) -> io::Result<()> {
|
||||
unsafe {
|
||||
yggdrasil_rt::sys::update_metadata(
|
||||
Some(self.as_raw_fd()),
|
||||
"",
|
||||
&FileMetadataUpdate::Permissions(FileMetadataUpdateMode::Set(perm.0)),
|
||||
)
|
||||
}
|
||||
.map_err(io::Error::from)
|
||||
}
|
||||
|
||||
pub fn set_times(&self, times: FileTimes) -> io::Result<()> {
|
||||
unsafe {
|
||||
yggdrasil_rt::sys::update_metadata(
|
||||
Some(self.as_raw_fd()),
|
||||
"",
|
||||
&FileMetadataUpdate::Times(FileTimesUpdate {
|
||||
atime: times.atime,
|
||||
mtime: times.mtime,
|
||||
ctime: None,
|
||||
}),
|
||||
)
|
||||
}
|
||||
.map_err(io::Error::from)
|
||||
}
|
||||
}
|
||||
|
||||
impl AsInner<FileDesc> for File {
|
||||
fn as_inner(&self) -> &FileDesc {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoInner<FileDesc> for File {
|
||||
fn into_inner(self) -> FileDesc {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl AsInnerMut<FileDesc> for File {
|
||||
fn as_inner_mut(&mut self) -> &mut FileDesc {
|
||||
&mut self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl FromInner<FileDesc> for File {
|
||||
fn from_inner(file_desc: FileDesc) -> Self {
|
||||
Self(file_desc)
|
||||
}
|
||||
}
|
||||
|
||||
impl AsFd for File {
|
||||
fn as_fd(&self) -> BorrowedFd<'_> {
|
||||
self.0.as_fd()
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRawFd for File {
|
||||
fn as_raw_fd(&self) -> RawFd {
|
||||
self.0.as_raw_fd()
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoRawFd for File {
|
||||
fn into_raw_fd(self) -> RawFd {
|
||||
self.0.into_raw_fd()
|
||||
}
|
||||
}
|
||||
|
||||
impl FromRawFd for File {
|
||||
unsafe fn from_raw_fd(raw_fd: RawFd) -> Self {
|
||||
unsafe { Self(FromRawFd::from_raw_fd(raw_fd)) }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
#![allow(exported_private_dependencies)]
|
||||
|
||||
use yggdrasil_rt::io::{AccessMode as OsAccessMode, Rename};
|
||||
|
||||
use crate::os::yggdrasil::fs::{MetadataExt, OpenOptionsExt};
|
||||
use crate::path::{Path, PathBuf};
|
||||
use crate::sys::run_with_path_str;
|
||||
use crate::{io, os};
|
||||
|
||||
mod attr;
|
||||
mod dir;
|
||||
mod file;
|
||||
|
||||
pub(crate) use attr::get_metadata_inner;
|
||||
pub use attr::{
|
||||
FileAttr, FilePermissions, FileTimes, FileType, lstat, set_perm, set_times, set_times_nofollow,
|
||||
stat,
|
||||
};
|
||||
pub use dir::{DirBuilder, DirEntry, ReadDir, readdir, remove_dir_all, rmdir};
|
||||
pub use file::{File, OpenOptions};
|
||||
|
||||
pub use crate::sys::fs::common::Dir;
|
||||
|
||||
pub fn unlink(path: &Path) -> io::Result<()> {
|
||||
run_with_path_str(path, |path_str| {
|
||||
yggdrasil_rt::io::remove_file(None, path_str).map_err(io::Error::from)
|
||||
})
|
||||
}
|
||||
|
||||
pub fn rename(old: &Path, new: &Path) -> io::Result<()> {
|
||||
let old = old.to_str().unwrap();
|
||||
let new = new.to_str().unwrap();
|
||||
unsafe {
|
||||
yggdrasil_rt::sys::rename(&Rename {
|
||||
source_at: None,
|
||||
destination_at: None,
|
||||
source: old,
|
||||
destination: new,
|
||||
})
|
||||
}?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn exists(path: &Path) -> io::Result<bool> {
|
||||
run_with_path_str(path, |path| {
|
||||
unsafe { yggdrasil_rt::sys::check_access(None, path, OsAccessMode::empty()) }
|
||||
.map_err(io::Error::from)
|
||||
})
|
||||
.map(|_| true)
|
||||
}
|
||||
|
||||
pub fn readlink(path: &Path) -> io::Result<PathBuf> {
|
||||
// TODO PATH_MAX
|
||||
let mut buf = [0; 4096];
|
||||
let len = run_with_path_str(path, |path_str| {
|
||||
unsafe { yggdrasil_rt::sys::read_link(None, path_str, &mut buf) }.map_err(io::Error::from)
|
||||
})?;
|
||||
// TODO error handling
|
||||
let path = core::str::from_utf8(&buf[..len]).unwrap();
|
||||
Ok(PathBuf::from(path))
|
||||
}
|
||||
|
||||
pub fn symlink(original: &Path, link: &Path) -> io::Result<()> {
|
||||
os::yggdrasil::fs::symlink(original, link)
|
||||
}
|
||||
|
||||
pub fn link(_original: &Path, _link: &Path) -> io::Result<()> {
|
||||
Err(io::Error::new(io::ErrorKind::Uncategorized, "Hard links are not implemented"))
|
||||
}
|
||||
|
||||
pub fn canonicalize(path: &Path) -> io::Result<PathBuf> {
|
||||
run_with_path_str(path, |path_str| {
|
||||
yggdrasil_rt::io::canonicalize(path_str, |s| s.into()).map_err(io::Error::from)
|
||||
})
|
||||
}
|
||||
|
||||
pub fn copy(from: &Path, to: &Path) -> io::Result<u64> {
|
||||
let src_stat = from.metadata()?;
|
||||
let raw_mode = src_stat.mode_ext();
|
||||
let mut src = crate::fs::File::open(from)?;
|
||||
let mut dst = crate::fs::OpenOptions::new()
|
||||
.write(true)
|
||||
.truncate(true)
|
||||
.create(true)
|
||||
.mode_ext(raw_mode)
|
||||
.open(to)?;
|
||||
|
||||
crate::io::copy(&mut src, &mut dst)
|
||||
}
|
||||
@@ -39,6 +39,10 @@ cfg_select! {
|
||||
mod xous;
|
||||
pub use xous::*;
|
||||
}
|
||||
target_os = "yggdrasil" => {
|
||||
mod yggdrasil;
|
||||
pub use yggdrasil::*;
|
||||
}
|
||||
any(
|
||||
target_os = "vexos",
|
||||
target_family = "wasm",
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
use yggdrasil_rt::Error as OsError;
|
||||
|
||||
use crate::io::{self, RawOsError};
|
||||
|
||||
pub fn errno() -> i32 {
|
||||
// Errors are not reported via errno
|
||||
0
|
||||
}
|
||||
|
||||
pub fn is_interrupted(code: i32) -> bool {
|
||||
decode_error_kind(code) == io::ErrorKind::Interrupted
|
||||
}
|
||||
|
||||
pub fn decode_error_kind(errno: i32) -> io::ErrorKind {
|
||||
let errno = errno as u32;
|
||||
match OsError::try_from(errno) {
|
||||
// I/O kinds
|
||||
Ok(OsError::DoesNotExist) | Ok(OsError::ProcessNotFound) => io::ErrorKind::NotFound,
|
||||
Ok(OsError::AlreadyExists) => io::ErrorKind::AlreadyExists,
|
||||
Ok(OsError::TimedOut) => io::ErrorKind::TimedOut,
|
||||
Ok(OsError::IsADirectory) => io::ErrorKind::IsADirectory,
|
||||
Ok(OsError::NotADirectory) => io::ErrorKind::NotADirectory,
|
||||
Ok(OsError::DirectoryNotEmpty) => io::ErrorKind::DirectoryNotEmpty,
|
||||
Ok(OsError::Interrupted) => io::ErrorKind::Interrupted,
|
||||
Ok(OsError::WouldBlock) => io::ErrorKind::WouldBlock,
|
||||
Ok(OsError::ReadOnly) => io::ErrorKind::ReadOnlyFilesystem,
|
||||
Ok(OsError::PermissionDenied) => io::ErrorKind::PermissionDenied,
|
||||
Ok(OsError::CrossDeviceLink) => io::ErrorKind::CrossesDevices,
|
||||
Ok(OsError::UnrecognizedExecutable)
|
||||
| Ok(OsError::MissingData)
|
||||
| Ok(OsError::BufferTooSmall)
|
||||
| Ok(OsError::QueueFull) => io::ErrorKind::InvalidData,
|
||||
|
||||
// Memory and general
|
||||
Ok(OsError::OutOfMemory) => io::ErrorKind::OutOfMemory,
|
||||
Ok(OsError::InvalidArgument)
|
||||
| Ok(OsError::InvalidMemoryOperation)
|
||||
| Ok(OsError::InvalidOperation)
|
||||
| Ok(OsError::UndefinedSyscall) => io::ErrorKind::InvalidInput,
|
||||
Ok(OsError::NotImplemented) => io::ErrorKind::Unsupported,
|
||||
|
||||
// Network
|
||||
Ok(OsError::HostUnreachable) => io::ErrorKind::HostUnreachable,
|
||||
Ok(OsError::NetworkUnreachable) => io::ErrorKind::NetworkUnreachable,
|
||||
Ok(OsError::ConnectionReset) => io::ErrorKind::ConnectionReset,
|
||||
Ok(OsError::ConnectionRefused) => io::ErrorKind::ConnectionRefused,
|
||||
Ok(OsError::NotConnected) => io::ErrorKind::NotConnected,
|
||||
Ok(OsError::AddrInUse) => io::ErrorKind::AddrInUse,
|
||||
|
||||
// Uncategorized
|
||||
Ok(OsError::InvalidFile) => io::ErrorKind::Uncategorized,
|
||||
Err(_) => io::ErrorKind::Uncategorized,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn error_string(errno: i32) -> String {
|
||||
crate::format!("{}", decode_error_kind(errno))
|
||||
}
|
||||
|
||||
#[allow(exported_private_dependencies)]
|
||||
#[unstable(feature = "yggdrasil_os", issue = "none")]
|
||||
impl From<yggdrasil_rt::Error> for crate::io::Error {
|
||||
fn from(e: yggdrasil_rt::Error) -> Self {
|
||||
let raw_os_error = u32::from(e) as RawOsError;
|
||||
io::Error::from_raw_os_error(raw_os_error)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
use crate::os::fd::{AsFd, AsRawFd};
|
||||
|
||||
pub fn is_terminal(fd: &impl AsFd) -> bool {
|
||||
let fd = fd.as_fd();
|
||||
yggdrasil_rt::io::terminal::is_terminal(fd.as_raw_fd())
|
||||
}
|
||||
@@ -41,6 +41,10 @@ mod is_terminal {
|
||||
mod motor;
|
||||
pub use motor::*;
|
||||
}
|
||||
target_os = "yggdrasil" => {
|
||||
mod yggdrasil;
|
||||
pub use yggdrasil::*;
|
||||
}
|
||||
_ => {
|
||||
mod unsupported;
|
||||
pub use unsupported::*;
|
||||
|
||||
@@ -29,6 +29,10 @@ cfg_select! {
|
||||
mod uefi;
|
||||
pub use uefi::*;
|
||||
}
|
||||
target_os = "yggdrasil" => {
|
||||
mod yggdrasil;
|
||||
pub use yggdrasil::*;
|
||||
}
|
||||
_ => {
|
||||
mod unsupported;
|
||||
pub use unsupported::*;
|
||||
|
||||
@@ -0,0 +1,189 @@
|
||||
use yggdrasil_rt::net::dns::{
|
||||
self, DnsClass, DnsMessage, DnsRecordData, DnsReplyCode, DnsType, UdpRequester,
|
||||
};
|
||||
|
||||
use crate::fs::File;
|
||||
use crate::io::{self, BufRead, BufReader};
|
||||
use crate::net::{IpAddr, Ipv4Addr, SocketAddr, UdpSocket};
|
||||
use crate::os::fd::AsRawFd;
|
||||
use crate::os::yggdrasil::io::poll::PollChannel;
|
||||
use crate::os::yggdrasil::io::timer::TimerFd;
|
||||
use crate::str::FromStr;
|
||||
use crate::sys::pal::util::random;
|
||||
use crate::time::Duration;
|
||||
|
||||
const TIMEOUT: u64 = 500;
|
||||
const NAMESERVER: SocketAddr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 53);
|
||||
const HOSTS_PATH: &str = "/etc/hosts";
|
||||
|
||||
pub struct LookupHost {
|
||||
addresses: Vec<IpAddr>,
|
||||
port: u16,
|
||||
}
|
||||
|
||||
struct DnsRequester {
|
||||
nameserver: SocketAddr,
|
||||
|
||||
poll: PollChannel,
|
||||
|
||||
timer: TimerFd,
|
||||
socket: UdpSocket,
|
||||
}
|
||||
|
||||
impl DnsRequester {
|
||||
pub fn new(nameserver: SocketAddr) -> io::Result<Self> {
|
||||
let mut poll = PollChannel::new()?;
|
||||
let timer = TimerFd::new(false, false)?;
|
||||
let socket = UdpSocket::bind("0.0.0.0:0")?;
|
||||
|
||||
poll.add(timer.as_raw_fd())?;
|
||||
poll.add(socket.as_raw_fd())?;
|
||||
|
||||
Ok(Self { nameserver, poll, timer, socket })
|
||||
}
|
||||
}
|
||||
|
||||
impl UdpRequester for DnsRequester {
|
||||
type Error = io::Error;
|
||||
|
||||
fn send_message(&mut self, message: &[u8]) -> io::Result<()> {
|
||||
self.socket.send_to(message, &self.nameserver)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn receive_message<F: Fn(&[u8]) -> Option<DnsMessage>>(
|
||||
&mut self,
|
||||
map: F,
|
||||
) -> io::Result<DnsMessage> {
|
||||
let mut buffer = [0; 2048];
|
||||
|
||||
self.timer.start(Duration::from_millis(TIMEOUT))?;
|
||||
|
||||
loop {
|
||||
let (poll_fd, result) = self.poll.wait(None, true)?.unwrap();
|
||||
result?;
|
||||
|
||||
match poll_fd {
|
||||
fd if fd == self.socket.as_raw_fd() => {
|
||||
let (len, _) = self.socket.recv_from(&mut buffer)?;
|
||||
|
||||
if let Some(message) = map(&buffer[..len]) {
|
||||
return Ok(message);
|
||||
}
|
||||
}
|
||||
fd if fd == self.timer.as_raw_fd() => {
|
||||
return Err(io::Error::new(io::ErrorKind::TimedOut, "DNS query timed out"));
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// impl LookupHost {
|
||||
// pub fn port(&self) -> u16 {
|
||||
// self.port
|
||||
// }
|
||||
// }
|
||||
|
||||
impl Iterator for LookupHost {
|
||||
type Item = SocketAddr;
|
||||
|
||||
fn next(&mut self) -> Option<SocketAddr> {
|
||||
let ip = self.addresses.pop()?;
|
||||
Some(SocketAddr::new(ip, self.port))
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<&str> for LookupHost {
|
||||
type Error = io::Error;
|
||||
|
||||
fn try_from(s: &str) -> io::Result<Self> {
|
||||
use crate::str::FromStr;
|
||||
|
||||
let (hostname, port) = s
|
||||
.rsplit_once(':')
|
||||
.ok_or(io::Error::new(io::ErrorKind::InvalidData, "Invalid host:port combination"))?;
|
||||
let port =
|
||||
u16::from_str(port).map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
|
||||
|
||||
Self::try_from((hostname, port))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> TryFrom<(&'a str, u16)> for LookupHost {
|
||||
type Error = io::Error;
|
||||
|
||||
fn try_from((hostname, port): (&'a str, u16)) -> io::Result<Self> {
|
||||
if let Ok(addresses) = get_addresses_from_hosts(hostname) {
|
||||
if !addresses.is_empty() {
|
||||
return Ok(Self { addresses, port });
|
||||
}
|
||||
}
|
||||
|
||||
let addresses = get_addresses_from_dns(hostname)?;
|
||||
|
||||
Ok(Self { addresses, port })
|
||||
}
|
||||
}
|
||||
|
||||
pub fn lookup_host(query: &str, port: u16) -> io::Result<LookupHost> {
|
||||
LookupHost::try_from((query, port))
|
||||
}
|
||||
|
||||
fn get_addresses_from_hosts(hostname: &str) -> io::Result<Vec<IpAddr>> {
|
||||
let reader = BufReader::new(File::open(HOSTS_PATH)?);
|
||||
let mut addresses = vec![];
|
||||
for line in reader.lines() {
|
||||
let line = line?;
|
||||
let line = line.trim();
|
||||
if line.starts_with('#') {
|
||||
continue;
|
||||
}
|
||||
let Some((address, host)) = line.split_once(' ') else {
|
||||
continue;
|
||||
};
|
||||
let address = address.trim();
|
||||
let host = host.trim();
|
||||
let Ok(address) = IpAddr::from_str(address) else {
|
||||
continue;
|
||||
};
|
||||
|
||||
if host == hostname {
|
||||
addresses.push(address);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(addresses)
|
||||
}
|
||||
|
||||
fn get_addresses_from_dns(hostname: &str) -> io::Result<Vec<IpAddr>> {
|
||||
let xid = random();
|
||||
let cookie = random();
|
||||
let mut addresses = vec![];
|
||||
let mut requester = DnsRequester::new(NAMESERVER)?;
|
||||
let message = dns::perform_query(&mut requester, hostname, DnsType::A, xid, cookie)?;
|
||||
|
||||
if message.reply_code != DnsReplyCode::NO_ERROR {
|
||||
return Err(io::Error::new(io::ErrorKind::Other, "DNS server returned error"));
|
||||
}
|
||||
|
||||
for answer in message.answers {
|
||||
let Some(name) = answer.name.0.as_ref() else {
|
||||
continue;
|
||||
};
|
||||
let name = name.trim_end_matches('.');
|
||||
if name != hostname {
|
||||
continue;
|
||||
}
|
||||
|
||||
match (answer.ty, answer.class, &answer.rdata) {
|
||||
(DnsType::A, DnsClass::IN, DnsRecordData::A(address)) => {
|
||||
addresses.push(IpAddr::V4(u32::from(*address).into()));
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
||||
Ok(addresses)
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
#![allow(exported_private_dependencies)]
|
||||
|
||||
mod lookup_host;
|
||||
mod tcp_listener;
|
||||
mod tcp_stream;
|
||||
mod udp_socket;
|
||||
|
||||
pub use lookup_host::lookup_host;
|
||||
pub use tcp_listener::TcpListener;
|
||||
pub use tcp_stream::TcpStream;
|
||||
pub use udp_socket::UdpSocket;
|
||||
@@ -0,0 +1,100 @@
|
||||
use yggdrasil_rt::net as rt;
|
||||
|
||||
use super::TcpStream;
|
||||
use crate::io;
|
||||
use crate::net::{SocketAddr, ToSocketAddrs};
|
||||
use crate::os::fd::{AsRawFd, FromRawFd, RawFd};
|
||||
use crate::sys::fd::SocketFileDesc;
|
||||
use crate::sys::net::connection::each_addr;
|
||||
use crate::sys::{AsInner, FromInner, IntoInner};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct TcpListener(SocketFileDesc);
|
||||
|
||||
impl TcpListener {
|
||||
fn try_bind(addr: &SocketAddr) -> io::Result<TcpListener> {
|
||||
let raw = rt::bind_tcp(addr)?;
|
||||
let fd = unsafe { SocketFileDesc::from_raw_fd(raw) };
|
||||
Ok(Self(fd))
|
||||
}
|
||||
|
||||
// pub fn bind(addr: io::Result<&SocketAddr>) -> io::Result<TcpListener> {
|
||||
pub fn bind<A: ToSocketAddrs>(addr: A) -> io::Result<TcpListener> {
|
||||
each_addr(addr, Self::try_bind)
|
||||
}
|
||||
|
||||
pub fn socket_addr(&self) -> io::Result<SocketAddr> {
|
||||
self.0.local_addr()
|
||||
}
|
||||
|
||||
pub fn accept(&self) -> io::Result<(TcpStream, SocketAddr)> {
|
||||
let (fd, remote) = self.0.accept()?;
|
||||
let stream = TcpStream::from_inner(fd);
|
||||
Ok((stream, remote))
|
||||
}
|
||||
|
||||
pub fn duplicate(&self) -> io::Result<TcpListener> {
|
||||
self.0.try_clone().map(Self)
|
||||
}
|
||||
|
||||
pub fn set_ttl(&self, ttl: u32) -> io::Result<()> {
|
||||
self.0.set_ttl(ttl)
|
||||
}
|
||||
|
||||
pub fn ttl(&self) -> io::Result<u32> {
|
||||
self.0.ttl()
|
||||
}
|
||||
|
||||
pub fn set_only_v6(&self, only_v6: bool) -> io::Result<()> {
|
||||
self.0.set_only_v6(only_v6)
|
||||
}
|
||||
|
||||
pub fn only_v6(&self) -> io::Result<bool> {
|
||||
self.0.only_v6()
|
||||
}
|
||||
|
||||
pub fn take_error(&self) -> io::Result<Option<io::Error>> {
|
||||
self.0.take_error()
|
||||
}
|
||||
|
||||
pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
|
||||
self.0.set_nonblocking(nonblocking)
|
||||
}
|
||||
}
|
||||
|
||||
impl FromInner<SocketFileDesc> for TcpListener {
|
||||
fn from_inner(fd: SocketFileDesc) -> Self {
|
||||
Self(fd)
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoInner<SocketFileDesc> for TcpListener {
|
||||
fn into_inner(self) -> SocketFileDesc {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl AsInner<SocketFileDesc> for TcpListener {
|
||||
fn as_inner(&self) -> &SocketFileDesc {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl FromRawFd for TcpListener {
|
||||
unsafe fn from_raw_fd(fd: RawFd) -> Self {
|
||||
Self(SocketFileDesc::from_raw_fd(fd))
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRawFd for TcpListener {
|
||||
fn as_raw_fd(&self) -> RawFd {
|
||||
self.0.as_raw_fd()
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl AsRawFd for crate::net::TcpListener {
|
||||
fn as_raw_fd(&self) -> RawFd {
|
||||
self.as_inner().as_raw_fd()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,164 @@
|
||||
use yggdrasil_rt::net as rt;
|
||||
|
||||
use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut};
|
||||
use crate::net::{Shutdown, SocketAddr, ToSocketAddrs};
|
||||
use crate::os::fd::{AsRawFd, FromRawFd, RawFd};
|
||||
use crate::sys::fd::SocketFileDesc;
|
||||
use crate::sys::net::connection::each_addr;
|
||||
use crate::sys::{AsInner, FromInner, IntoInner};
|
||||
use crate::time::Duration;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct TcpStream(SocketFileDesc);
|
||||
|
||||
impl TcpStream {
|
||||
fn connect_inner(remote: &SocketAddr, timeout: Option<Duration>) -> io::Result<TcpStream> {
|
||||
let fd = rt::connect_tcp(remote, timeout)?;
|
||||
let fd = unsafe { SocketFileDesc::from_raw_fd(fd) };
|
||||
Ok(Self(fd))
|
||||
}
|
||||
|
||||
// pub fn connect(addr: io::Result<&SocketAddr>) -> io::Result<TcpStream> {
|
||||
pub fn connect<A: ToSocketAddrs>(addr: A) -> io::Result<TcpStream> {
|
||||
each_addr(addr, |addr| Self::connect_inner(addr, None))
|
||||
}
|
||||
|
||||
pub fn connect_timeout(addr: &SocketAddr, timeout: Duration) -> io::Result<TcpStream> {
|
||||
Self::connect_inner(addr, Some(timeout))
|
||||
}
|
||||
|
||||
pub fn set_read_timeout(&self, dur: Option<Duration>) -> io::Result<()> {
|
||||
self.0.set_read_timeout(dur)
|
||||
}
|
||||
|
||||
pub fn set_write_timeout(&self, dur: Option<Duration>) -> io::Result<()> {
|
||||
self.0.set_write_timeout(dur)
|
||||
}
|
||||
|
||||
pub fn read_timeout(&self) -> io::Result<Option<Duration>> {
|
||||
self.0.read_timeout()
|
||||
}
|
||||
|
||||
pub fn write_timeout(&self) -> io::Result<Option<Duration>> {
|
||||
self.0.write_timeout()
|
||||
}
|
||||
|
||||
pub fn peek(&self, buf: &mut [u8]) -> io::Result<usize> {
|
||||
self.0.peek(buf)
|
||||
}
|
||||
|
||||
pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
|
||||
self.0.recv(buf)
|
||||
}
|
||||
|
||||
pub fn read_buf(&self, buf: BorrowedCursor<'_>) -> io::Result<()> {
|
||||
self.0.recv_buf(buf)
|
||||
}
|
||||
|
||||
pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
|
||||
self.0.recv_vectored(bufs)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_read_vectored(&self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
|
||||
self.0.send(buf)
|
||||
}
|
||||
|
||||
pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
|
||||
self.0.send_vectored(bufs)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_write_vectored(&self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
pub fn peer_addr(&self) -> io::Result<SocketAddr> {
|
||||
self.0.peer_addr()
|
||||
}
|
||||
|
||||
pub fn socket_addr(&self) -> io::Result<SocketAddr> {
|
||||
self.0.local_addr()
|
||||
}
|
||||
|
||||
pub fn shutdown(&self, how: Shutdown) -> io::Result<()> {
|
||||
self.0.shutdown(how)
|
||||
}
|
||||
|
||||
pub fn duplicate(&self) -> io::Result<TcpStream> {
|
||||
self.0.try_clone().map(Self)
|
||||
}
|
||||
|
||||
pub fn set_linger(&self, linger: Option<Duration>) -> io::Result<()> {
|
||||
self.0.set_linger(linger)
|
||||
}
|
||||
|
||||
pub fn linger(&self) -> io::Result<Option<Duration>> {
|
||||
self.0.linger()
|
||||
}
|
||||
|
||||
pub fn set_nodelay(&self, nodelay: bool) -> io::Result<()> {
|
||||
self.0.set_nodelay(nodelay)
|
||||
}
|
||||
|
||||
pub fn nodelay(&self) -> io::Result<bool> {
|
||||
self.0.nodelay()
|
||||
}
|
||||
|
||||
pub fn set_ttl(&self, ttl: u32) -> io::Result<()> {
|
||||
self.0.set_ttl(ttl)
|
||||
}
|
||||
|
||||
pub fn ttl(&self) -> io::Result<u32> {
|
||||
self.0.ttl()
|
||||
}
|
||||
|
||||
pub fn take_error(&self) -> io::Result<Option<io::Error>> {
|
||||
self.0.take_error()
|
||||
}
|
||||
|
||||
pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
|
||||
self.0.set_nonblocking(nonblocking)
|
||||
}
|
||||
}
|
||||
|
||||
impl FromInner<SocketFileDesc> for TcpStream {
|
||||
fn from_inner(fd: SocketFileDesc) -> Self {
|
||||
Self(fd)
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoInner<SocketFileDesc> for TcpStream {
|
||||
fn into_inner(self) -> SocketFileDesc {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl AsInner<SocketFileDesc> for TcpStream {
|
||||
fn as_inner(&self) -> &SocketFileDesc {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl FromRawFd for TcpStream {
|
||||
unsafe fn from_raw_fd(fd: RawFd) -> Self {
|
||||
Self(SocketFileDesc::from_raw_fd(fd))
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRawFd for TcpStream {
|
||||
fn as_raw_fd(&self) -> RawFd {
|
||||
self.0.as_raw_fd()
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl AsRawFd for crate::net::TcpStream {
|
||||
fn as_raw_fd(&self) -> RawFd {
|
||||
self.as_inner().as_raw_fd()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,187 @@
|
||||
use yggdrasil_rt::net as rt;
|
||||
|
||||
use crate::io;
|
||||
use crate::net::{Ipv4Addr, Ipv6Addr, SocketAddr, ToSocketAddrs};
|
||||
use crate::os::fd::{AsRawFd, FromRawFd, RawFd};
|
||||
use crate::sys::fd::SocketFileDesc;
|
||||
use crate::sys::net::connection::each_addr;
|
||||
use crate::sys::{AsInner, FromInner, IntoInner};
|
||||
use crate::time::Duration;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct UdpSocket(SocketFileDesc);
|
||||
|
||||
impl UdpSocket {
|
||||
fn try_bind(addr: &SocketAddr) -> io::Result<UdpSocket> {
|
||||
let raw = rt::bind_udp(addr)?;
|
||||
let inner = unsafe { SocketFileDesc::from_raw_fd(raw) };
|
||||
Ok(Self(inner))
|
||||
}
|
||||
|
||||
// Should succeed on first call
|
||||
fn try_connect(&self, addr: &SocketAddr) -> io::Result<()> {
|
||||
rt::connect_udp(self.as_raw_fd(), addr)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn bind<A: ToSocketAddrs>(addr: A) -> io::Result<UdpSocket> {
|
||||
each_addr(addr, Self::try_bind)
|
||||
}
|
||||
|
||||
pub fn connect<A: ToSocketAddrs>(&self, addr: A) -> io::Result<()> {
|
||||
each_addr(addr, |addr| self.try_connect(addr))
|
||||
}
|
||||
|
||||
pub fn peer_addr(&self) -> io::Result<SocketAddr> {
|
||||
self.0.peer_addr()
|
||||
}
|
||||
|
||||
pub fn socket_addr(&self) -> io::Result<SocketAddr> {
|
||||
self.0.local_addr()
|
||||
}
|
||||
|
||||
pub fn recv(&self, buffer: &mut [u8]) -> io::Result<usize> {
|
||||
self.0.recv(buffer)
|
||||
}
|
||||
|
||||
pub fn recv_from(&self, buffer: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
|
||||
self.0.recv_from(buffer)
|
||||
}
|
||||
|
||||
pub fn send(&self, buffer: &[u8]) -> io::Result<usize> {
|
||||
self.0.send(buffer)
|
||||
}
|
||||
|
||||
pub fn send_to(&self, buffer: &[u8], dst: &SocketAddr) -> io::Result<usize> {
|
||||
self.0.send_to(buffer, dst)
|
||||
}
|
||||
|
||||
pub fn peek(&self, buf: &mut [u8]) -> io::Result<usize> {
|
||||
self.0.peek(buf)
|
||||
}
|
||||
|
||||
pub fn peek_from(&self, buffer: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
|
||||
self.0.peek_from(buffer)
|
||||
}
|
||||
|
||||
pub fn duplicate(&self) -> io::Result<UdpSocket> {
|
||||
self.0.try_clone().map(Self)
|
||||
}
|
||||
|
||||
pub fn set_read_timeout(&self, dur: Option<Duration>) -> io::Result<()> {
|
||||
self.0.set_read_timeout(dur)
|
||||
}
|
||||
|
||||
pub fn read_timeout(&self) -> io::Result<Option<Duration>> {
|
||||
self.0.read_timeout()
|
||||
}
|
||||
|
||||
pub fn set_write_timeout(&self, dur: Option<Duration>) -> io::Result<()> {
|
||||
self.0.set_write_timeout(dur)
|
||||
}
|
||||
|
||||
pub fn write_timeout(&self) -> io::Result<Option<Duration>> {
|
||||
self.0.write_timeout()
|
||||
}
|
||||
|
||||
pub fn set_ttl(&self, ttl: u32) -> io::Result<()> {
|
||||
self.0.set_ttl(ttl)
|
||||
}
|
||||
|
||||
pub fn ttl(&self) -> io::Result<u32> {
|
||||
self.0.ttl()
|
||||
}
|
||||
|
||||
pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
|
||||
self.0.set_nonblocking(nonblocking)
|
||||
}
|
||||
|
||||
pub fn set_broadcast(&self, broadcast: bool) -> io::Result<()> {
|
||||
self.0.set_broadcast(broadcast)
|
||||
}
|
||||
|
||||
pub fn broadcast(&self) -> io::Result<bool> {
|
||||
self.0.broadcast()
|
||||
}
|
||||
|
||||
pub fn set_multicast_loop_v4(&self, loop_v4: bool) -> io::Result<()> {
|
||||
self.0.set_multicast_loop_v4(loop_v4)
|
||||
}
|
||||
|
||||
pub fn multicast_loop_v4(&self) -> io::Result<bool> {
|
||||
self.0.multicast_loop_v4()
|
||||
}
|
||||
|
||||
pub fn set_multicast_ttl_v4(&self, ttl: u32) -> io::Result<()> {
|
||||
self.0.set_multicast_ttl_v4(ttl)
|
||||
}
|
||||
|
||||
pub fn multicast_ttl_v4(&self) -> io::Result<u32> {
|
||||
self.0.multicast_ttl_v4()
|
||||
}
|
||||
|
||||
pub fn set_multicast_loop_v6(&self, loop_v6: bool) -> io::Result<()> {
|
||||
self.0.set_multicast_loop_v6(loop_v6)
|
||||
}
|
||||
|
||||
pub fn multicast_loop_v6(&self) -> io::Result<bool> {
|
||||
self.0.multicast_loop_v6()
|
||||
}
|
||||
|
||||
pub fn join_multicast_v6(&self, multiaddr: &Ipv6Addr, interface: u32) -> io::Result<()> {
|
||||
self.0.join_multicast_v6(multiaddr, interface)
|
||||
}
|
||||
|
||||
pub fn join_multicast_v4(&self, multiaddr: &Ipv4Addr, interface: &Ipv4Addr) -> io::Result<()> {
|
||||
self.0.join_multicast_v4(multiaddr, interface)
|
||||
}
|
||||
|
||||
pub fn leave_multicast_v6(&self, multiaddr: &Ipv6Addr, interface: u32) -> io::Result<()> {
|
||||
self.0.leave_multicast_v6(multiaddr, interface)
|
||||
}
|
||||
|
||||
pub fn leave_multicast_v4(&self, multiaddr: &Ipv4Addr, interface: &Ipv4Addr) -> io::Result<()> {
|
||||
self.0.leave_multicast_v4(multiaddr, interface)
|
||||
}
|
||||
|
||||
pub fn take_error(&self) -> io::Result<Option<io::Error>> {
|
||||
self.0.take_error()
|
||||
}
|
||||
}
|
||||
|
||||
impl FromInner<SocketFileDesc> for UdpSocket {
|
||||
fn from_inner(fd: SocketFileDesc) -> Self {
|
||||
Self(fd)
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoInner<SocketFileDesc> for UdpSocket {
|
||||
fn into_inner(self) -> SocketFileDesc {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl AsInner<SocketFileDesc> for UdpSocket {
|
||||
fn as_inner(&self) -> &SocketFileDesc {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl FromRawFd for UdpSocket {
|
||||
unsafe fn from_raw_fd(fd: RawFd) -> Self {
|
||||
Self(SocketFileDesc::from_raw_fd(fd))
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRawFd for UdpSocket {
|
||||
fn as_raw_fd(&self) -> RawFd {
|
||||
self.0.as_raw_fd()
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl AsRawFd for crate::net::UdpSocket {
|
||||
fn as_raw_fd(&self) -> RawFd {
|
||||
self.as_inner().as_raw_fd()
|
||||
}
|
||||
}
|
||||
@@ -7,6 +7,10 @@ cfg_select! {
|
||||
mod windows;
|
||||
pub use windows::hostname;
|
||||
}
|
||||
target_os = "yggdrasil" => {
|
||||
mod yggdrasil;
|
||||
pub use yggdrasil::hostname;
|
||||
}
|
||||
_ => {
|
||||
mod unsupported;
|
||||
pub use unsupported::hostname;
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
use crate::ffi::OsString;
|
||||
use crate::io::{Error, Result};
|
||||
|
||||
pub fn hostname() -> Result<OsString> {
|
||||
Err(Error::UNSUPPORTED_PLATFORM)
|
||||
}
|
||||
@@ -60,6 +60,10 @@ cfg_select! {
|
||||
mod zkvm;
|
||||
pub use self::zkvm::*;
|
||||
}
|
||||
target_os = "yggdrasil" => {
|
||||
mod yggdrasil;
|
||||
pub use self::yggdrasil::*;
|
||||
}
|
||||
_ => {
|
||||
mod unsupported;
|
||||
pub use self::unsupported::*;
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
// SAFETY: must be called only once during runtime initialization.
|
||||
// NOTE: this is not guaranteed to run, for example when Rust code is called externally.
|
||||
pub unsafe fn init(_argc: isize, _argv: *const *const u8, _sigpipe: u8) {}
|
||||
|
||||
// SAFETY: must be called only once during runtime cleanup.
|
||||
// NOTE: this is not guaranteed to run, for example when the program aborts.
|
||||
pub unsafe fn cleanup() {}
|
||||
|
||||
pub fn abort_internal() -> ! {
|
||||
core::intrinsics::abort();
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
use yggdrasil_rt::process::{ExitCode as OsExitCode, ProgramArgumentInner};
|
||||
|
||||
use crate::sys::{args, env, signal, thread};
|
||||
|
||||
unsafe fn init_kernel_arg(program_arg: usize) {
|
||||
unsafe {
|
||||
let program_arg = crate::ptr::with_exposed_provenance::<ProgramArgumentInner>(program_arg);
|
||||
let Some(program_arg) = program_arg.as_ref() else {
|
||||
yggdrasil_rt::debug_trace!(Error, "Kernel provided NULL argument");
|
||||
yggdrasil_rt::sys::exit_process(OsExitCode::Exited(1));
|
||||
};
|
||||
|
||||
// Setup TLS as soon as possible
|
||||
thread::init(program_arg.auxv());
|
||||
|
||||
// Setup real binary from auxv
|
||||
crate::os::yggdrasil::set_real_program(program_arg);
|
||||
|
||||
args::imp::init(program_arg);
|
||||
env::imp::init(program_arg);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(test))]
|
||||
#[unsafe(no_mangle)]
|
||||
pub unsafe extern "C" fn __rust_start(program_arg: usize, main_ptr: usize) -> ! {
|
||||
unsafe { init_kernel_arg(program_arg) };
|
||||
|
||||
// Initialize signals
|
||||
signal::init(true);
|
||||
|
||||
if main_ptr != 0 {
|
||||
let main: unsafe extern "C" fn(isize, *const *const u8) -> i32 =
|
||||
unsafe { core::mem::transmute(main_ptr) };
|
||||
let result = unsafe { main(0, core::ptr::null()) };
|
||||
unsafe { yggdrasil_rt::sys::exit_process(OsExitCode::Exited(result)) };
|
||||
}
|
||||
loop {}
|
||||
// let main_ptr = (main as *const ()).addr();
|
||||
// if main_ptr != 0 {
|
||||
// let result = unsafe { main(0, null()) };
|
||||
// }
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
use yggdrasil_rt::process::MutexOperation;
|
||||
use yggdrasil_rt::sys;
|
||||
|
||||
use crate::sync::atomic::Atomic;
|
||||
use crate::time::Duration;
|
||||
|
||||
pub type Primitive = u32;
|
||||
pub type Futex = Atomic<Primitive>;
|
||||
pub type SmallPrimitive = u32;
|
||||
pub type SmallFutex = Atomic<SmallPrimitive>;
|
||||
|
||||
pub fn futex_wait(futex: &Atomic<u32>, expected: u32, timeout: Option<Duration>) -> bool {
|
||||
unsafe { sys::mutex(futex, &MutexOperation::WaitWhileEqual(expected, timeout)).is_ok() }
|
||||
}
|
||||
|
||||
pub fn futex_wake(futex: &Atomic<u32>) -> bool {
|
||||
unsafe { sys::mutex(futex, &MutexOperation::Wake(1)).ok() };
|
||||
true
|
||||
}
|
||||
|
||||
pub fn futex_wake_all(futex: &Atomic<u32>) {
|
||||
unsafe { sys::mutex(futex, &MutexOperation::Wake(u32::MAX)).ok() };
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
#![deny(unsafe_op_in_unsafe_fn)]
|
||||
|
||||
pub mod futex;
|
||||
pub mod os;
|
||||
pub mod signal;
|
||||
pub mod time;
|
||||
pub mod util;
|
||||
|
||||
mod common;
|
||||
mod entry;
|
||||
mod path;
|
||||
|
||||
pub use common::*;
|
||||
pub use path::*;
|
||||
@@ -0,0 +1,108 @@
|
||||
use yggdrasil_rt::process::ExitCode as OsExitCode;
|
||||
use yggdrasil_rt::sys as syscall;
|
||||
|
||||
use crate::error::Error as StdError;
|
||||
use crate::ffi::{OsStr, OsString};
|
||||
use crate::path::{Path, PathBuf};
|
||||
use crate::sys::{AsInner, FromInner, os_str, run_with_path_str};
|
||||
use crate::{fmt, io, iter, mem, slice};
|
||||
|
||||
pub struct SplitPaths<'a> {
|
||||
iter: iter::Map<slice::Split<'a, u8, fn(&u8) -> bool>, fn(&'a [u8]) -> PathBuf>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct JoinPathsError;
|
||||
|
||||
impl<'a> Iterator for SplitPaths<'a> {
|
||||
type Item = PathBuf;
|
||||
|
||||
fn next(&mut self) -> Option<PathBuf> {
|
||||
self.iter.next()
|
||||
}
|
||||
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
self.iter.size_hint()
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for JoinPathsError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "path segment contains separator `/`")
|
||||
}
|
||||
}
|
||||
|
||||
impl StdError for JoinPathsError {
|
||||
#[allow(deprecated)]
|
||||
fn description(&self) -> &str {
|
||||
"failed to join paths"
|
||||
}
|
||||
}
|
||||
|
||||
pub fn split_paths(unparsed: &OsStr) -> SplitPaths<'_> {
|
||||
fn bytes_to_path(b: &[u8]) -> PathBuf {
|
||||
PathBuf::from(unsafe { mem::transmute::<_, &OsStr>(b) })
|
||||
}
|
||||
fn is_separator(b: &u8) -> bool {
|
||||
*b == b'/'
|
||||
}
|
||||
let unparsed = &unparsed.as_inner().inner;
|
||||
SplitPaths {
|
||||
iter: unparsed
|
||||
.split(is_separator as fn(&u8) -> bool)
|
||||
.map(bytes_to_path as fn(&[u8]) -> PathBuf),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn join_paths<I, T>(paths: I) -> Result<OsString, JoinPathsError>
|
||||
where
|
||||
I: Iterator<Item = T>,
|
||||
T: AsRef<OsStr>,
|
||||
{
|
||||
let mut joined = Vec::new();
|
||||
|
||||
for (i, path) in paths.enumerate() {
|
||||
let path = &path.as_ref().as_inner().inner;
|
||||
if i > 0 {
|
||||
joined.push(b'/')
|
||||
}
|
||||
if path.contains(&b'/') {
|
||||
return Err(JoinPathsError);
|
||||
}
|
||||
joined.extend_from_slice(path);
|
||||
}
|
||||
Ok(FromInner::from_inner(os_str::Buf { inner: joined }))
|
||||
}
|
||||
|
||||
pub fn current_exe() -> io::Result<PathBuf> {
|
||||
Ok(yggdrasil_rt::io::current_exe(|s| s.into())?)
|
||||
}
|
||||
|
||||
pub fn home_dir() -> Option<PathBuf> {
|
||||
yggdrasil_rt::io::home_directory(|s| s.into()).ok()
|
||||
}
|
||||
|
||||
pub fn temp_dir() -> PathBuf {
|
||||
// TODO prefix by pid
|
||||
let mut template = *b"/tmp/dXXXXXXXXX";
|
||||
yggdrasil_rt::io::make_temp_directory(&mut template)
|
||||
.expect("Could not set up a temporary directory");
|
||||
PathBuf::from(core::str::from_utf8(&template).unwrap())
|
||||
}
|
||||
|
||||
pub fn getcwd() -> io::Result<PathBuf> {
|
||||
Ok(yggdrasil_rt::io::current_directory(|s| s.into())?)
|
||||
}
|
||||
|
||||
pub fn chdir(path: &Path) -> io::Result<()> {
|
||||
run_with_path_str(path, |p| yggdrasil_rt::io::set_current_directory(p).map_err(io::Error::from))
|
||||
}
|
||||
|
||||
pub fn exit(code: i32) -> ! {
|
||||
let code = OsExitCode::Exited(code);
|
||||
unsafe { syscall::exit_process(code) }
|
||||
}
|
||||
|
||||
pub fn getpid() -> u32 {
|
||||
unsafe { syscall::get_pid() }.into_raw()
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
use crate::path::Path;
|
||||
|
||||
#[inline]
|
||||
pub fn run_with_path_str<T, F: FnOnce(&str) -> T>(path: &Path, f: F) -> T {
|
||||
let path_str = path.to_str().unwrap();
|
||||
f(path_str)
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
#![allow(exported_private_dependencies)]
|
||||
|
||||
use yggdrasil_rt::process::Signal;
|
||||
use yggdrasil_rt::process::signal::{self as imp, SignalHandler as RtHandler};
|
||||
|
||||
use crate::os::yggdrasil::signal::SignalHandler as StdHandler;
|
||||
|
||||
const SIGNAL_STACK_SIZE: usize = 4096 * 8;
|
||||
|
||||
#[unstable(feature = "yggdrasil_os", issue = "none")]
|
||||
impl From<StdHandler> for RtHandler {
|
||||
fn from(std: StdHandler) -> RtHandler {
|
||||
match std {
|
||||
StdHandler::Ignore => RtHandler::Ignore,
|
||||
StdHandler::Terminate => RtHandler::Terminate,
|
||||
StdHandler::Function(function) => RtHandler::Rust(function),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "yggdrasil_os", issue = "none")]
|
||||
impl From<RtHandler> for StdHandler {
|
||||
fn from(rt: RtHandler) -> StdHandler {
|
||||
match rt {
|
||||
RtHandler::Ignore => StdHandler::Ignore,
|
||||
RtHandler::Terminate => StdHandler::Terminate,
|
||||
RtHandler::Rust(function) => StdHandler::Function(function),
|
||||
RtHandler::C(_) => unreachable!("std will never set a C signal handler"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_signal_handler(signal: Signal, handler: StdHandler) -> StdHandler {
|
||||
imp::set_handler(signal, handler.into()).into()
|
||||
}
|
||||
|
||||
pub fn init(main: bool) {
|
||||
if main {
|
||||
imp::setup_signal_full(SIGNAL_STACK_SIZE)
|
||||
.expect("Couldn't setup signal handler for the main thread");
|
||||
} else {
|
||||
imp::setup_signal_stack(SIGNAL_STACK_SIZE).expect("Couldn't setup thread signal stack");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
use yggdrasil_rt::time::{self as rt, SystemTime as SysTimespec};
|
||||
|
||||
use crate::time::Duration;
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
|
||||
pub struct Instant(pub(crate) SysTimespec);
|
||||
|
||||
impl Instant {
|
||||
pub fn now() -> Self {
|
||||
Self(rt::get_monotonic_time().expect("Could not retrieve monotonic time value"))
|
||||
}
|
||||
|
||||
pub fn checked_add_duration(&self, other: &Duration) -> Option<Instant> {
|
||||
self.0.checked_add_duration(other).map(Self)
|
||||
}
|
||||
|
||||
pub fn checked_sub_duration(&self, other: &Duration) -> Option<Instant> {
|
||||
self.0.checked_sub_duration(other).map(Self)
|
||||
}
|
||||
|
||||
pub fn checked_sub_instant(&self, other: &Instant) -> Option<Duration> {
|
||||
self.0.checked_sub_time(&other.0)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
|
||||
pub struct SystemTime(pub(crate) SysTimespec);
|
||||
|
||||
pub const UNIX_EPOCH: SystemTime = SystemTime(SysTimespec::ZERO);
|
||||
|
||||
impl SystemTime {
|
||||
pub const MAX: SystemTime = SystemTime(SysTimespec::MAX);
|
||||
|
||||
pub const MIN: SystemTime = SystemTime(SysTimespec::MIN);
|
||||
|
||||
pub fn now() -> Self {
|
||||
Self(rt::get_real_time().expect("Could not retrieve real time value"))
|
||||
}
|
||||
|
||||
pub fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> {
|
||||
self.0.sub_time(&other.0)
|
||||
}
|
||||
|
||||
pub fn checked_add_duration(&self, other: &Duration) -> Option<Self> {
|
||||
self.0.checked_add_duration(other).map(Self)
|
||||
}
|
||||
|
||||
pub fn checked_sub_duration(&self, other: &Duration) -> Option<Self> {
|
||||
self.0.checked_sub_duration(other).map(Self)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
use crate::env;
|
||||
use crate::path::PathBuf;
|
||||
|
||||
pub fn resolve_binary(name: &str) -> Option<String> {
|
||||
// Already an absolute path
|
||||
if name.starts_with('/') {
|
||||
return None;
|
||||
}
|
||||
|
||||
let Ok(path) = env::var("PATH") else {
|
||||
return None;
|
||||
};
|
||||
|
||||
for entry in path.split(':') {
|
||||
let full_path = PathBuf::from(entry).join(name);
|
||||
|
||||
if full_path.exists() {
|
||||
return Some(full_path.to_str().unwrap().to_owned());
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
macro_rules! impl_random_safe {
|
||||
($($ty:ty),+) => {
|
||||
$(impl RandomSafe for $ty {
|
||||
unsafe fn __randomize(&mut self) {
|
||||
let bytes: &mut [u8; size_of::<Self>()] = unsafe { $crate::mem::transmute(self) };
|
||||
crate::sys::random::fill_bytes(bytes);
|
||||
}
|
||||
})+
|
||||
};
|
||||
}
|
||||
|
||||
pub trait RandomSafe: Default {
|
||||
unsafe fn __randomize(&mut self);
|
||||
}
|
||||
|
||||
impl_random_safe!(u8, u16, u32, u64);
|
||||
|
||||
pub fn random<T: RandomSafe>() -> T {
|
||||
let mut v = T::default();
|
||||
unsafe {
|
||||
v.__randomize();
|
||||
}
|
||||
v
|
||||
}
|
||||
@@ -13,6 +13,10 @@ cfg_select! {
|
||||
mod motor;
|
||||
pub use motor::{Pipe, pipe};
|
||||
}
|
||||
target_os = "yggdrasil" => {
|
||||
mod yggdrasil;
|
||||
pub use yggdrasil::{Pipe, pipe};
|
||||
}
|
||||
_ => {
|
||||
mod unsupported;
|
||||
pub use unsupported::{Pipe, pipe};
|
||||
|
||||
@@ -0,0 +1,124 @@
|
||||
#![allow(exported_private_dependencies)]
|
||||
|
||||
use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut, PipeReader, PipeWriter};
|
||||
use crate::os::fd::{AsRawFd, IntoRawFd, OwnedFd, RawFd};
|
||||
use crate::os::yggdrasil::io::pipe as os_pipe;
|
||||
use crate::sys::fd::FileDesc;
|
||||
use crate::sys::{FromInner, IntoInner};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Pipe(FileDesc);
|
||||
|
||||
impl Pipe {
|
||||
pub fn read(&self, buffer: &mut [u8]) -> io::Result<usize> {
|
||||
self.0.read(buffer)
|
||||
}
|
||||
|
||||
pub fn read_buf(&self, buffer: BorrowedCursor<'_>) -> io::Result<()> {
|
||||
self.0.read_buf(buffer)
|
||||
}
|
||||
|
||||
pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
|
||||
self.0.read_vectored(bufs)
|
||||
}
|
||||
|
||||
pub fn is_read_vectored(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
pub fn read_to_end(&self, buffer: &mut Vec<u8>) -> io::Result<usize> {
|
||||
self.0.read_to_end(buffer)
|
||||
}
|
||||
|
||||
pub fn write(&self, buffer: &[u8]) -> io::Result<usize> {
|
||||
self.0.write(buffer)
|
||||
}
|
||||
|
||||
pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
|
||||
self.0.write_vectored(bufs)
|
||||
}
|
||||
|
||||
pub fn is_write_vectored(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
pub fn try_clone(&self) -> io::Result<Self> {
|
||||
self.0.try_clone().map(Self)
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRawFd for Pipe {
|
||||
fn as_raw_fd(&self) -> RawFd {
|
||||
self.0.as_raw_fd()
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoRawFd for Pipe {
|
||||
fn into_raw_fd(self) -> RawFd {
|
||||
self.0.into_raw_fd()
|
||||
}
|
||||
}
|
||||
|
||||
impl FromInner<FileDesc> for Pipe {
|
||||
fn from_inner(fd: FileDesc) -> Self {
|
||||
Self(fd)
|
||||
}
|
||||
}
|
||||
|
||||
impl FromInner<OwnedFd> for Pipe {
|
||||
fn from_inner(fd: OwnedFd) -> Self {
|
||||
Self(FileDesc::from_inner(fd))
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoInner<FileDesc> for Pipe {
|
||||
fn into_inner(self) -> FileDesc {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn pipe() -> io::Result<(Pipe, Pipe)> {
|
||||
let (p0, p1) = os_pipe::create_pipe_pair(false, false)?;
|
||||
Ok((Pipe::from_inner(p0), Pipe::from_inner(p1)))
|
||||
}
|
||||
|
||||
// pub fn read2(p1: Pipe, v1: &mut Vec<u8>, p2: Pipe, v2: &mut Vec<u8>) -> io::Result<()> {
|
||||
// let p1 = p1.into_inner();
|
||||
// let p2 = p2.into_inner();
|
||||
//
|
||||
// let mut poll = PollChannel::new()?;
|
||||
// poll.add(p1.as_raw_fd())?;
|
||||
// poll.add(p2.as_raw_fd())?;
|
||||
//
|
||||
// loop {
|
||||
// match poll.wait(None, true)? {
|
||||
// Some((fd, _)) if fd == p1.as_raw_fd() => {
|
||||
// p1.read_to_end(v1)?;
|
||||
// p2.read_to_end(v2)?;
|
||||
// break;
|
||||
// }
|
||||
// Some((fd, _)) if fd == p2.as_raw_fd() => {
|
||||
// p2.read_to_end(v2)?;
|
||||
// p1.read_to_end(v1)?;
|
||||
// }
|
||||
// _ => continue,
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// Ok(())
|
||||
// }
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl IntoRawFd for PipeReader {
|
||||
fn into_raw_fd(self) -> RawFd {
|
||||
self.0.into_raw_fd()
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl IntoRawFd for PipeWriter {
|
||||
fn into_raw_fd(self) -> RawFd {
|
||||
self.0.into_raw_fd()
|
||||
}
|
||||
}
|
||||
@@ -15,6 +15,10 @@ cfg_select! {
|
||||
mod motor;
|
||||
use motor as imp;
|
||||
}
|
||||
target_os = "yggdrasil" => {
|
||||
mod yggdrasil;
|
||||
use yggdrasil as imp;
|
||||
}
|
||||
_ => {
|
||||
mod unsupported;
|
||||
use unsupported as imp;
|
||||
@@ -43,7 +47,8 @@ pub use imp::{
|
||||
))
|
||||
),
|
||||
target_os = "windows",
|
||||
target_os = "motor"
|
||||
target_os = "motor",
|
||||
target_os = "yggdrasil"
|
||||
))]
|
||||
pub fn output(cmd: &mut Command) -> crate::io::Result<(ExitStatus, Vec<u8>, Vec<u8>)> {
|
||||
let (mut process, mut pipes) = cmd.spawn(Stdio::MakePipe, false)?;
|
||||
@@ -81,6 +86,7 @@ pub fn output(cmd: &mut Command) -> crate::io::Result<(ExitStatus, Vec<u8>, Vec<
|
||||
))
|
||||
),
|
||||
target_os = "windows",
|
||||
target_os = "motor"
|
||||
target_os = "motor",
|
||||
target_os = "yggdrasil"
|
||||
)))]
|
||||
pub use imp::output;
|
||||
|
||||
@@ -0,0 +1,208 @@
|
||||
use yggdrasil_rt::process::{
|
||||
ProcessGroupId as OsProcessGroupId, SpawnFlags, SpawnOption, SpawnOptions,
|
||||
};
|
||||
use yggdrasil_rt::sys as syscall;
|
||||
|
||||
use super::{ChildPipes, Process, Stdio};
|
||||
use crate::ffi::OsStr;
|
||||
use crate::os::fd::RawFd;
|
||||
use crate::path::{Path, PathBuf};
|
||||
use crate::process::StdioPipes;
|
||||
use crate::sys::process::env::{CommandEnv, CommandEnvs};
|
||||
use crate::sys::util;
|
||||
use crate::{fmt, io};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Command {
|
||||
program: String,
|
||||
args: Vec<String>,
|
||||
env: CommandEnv,
|
||||
cwd: Option<PathBuf>,
|
||||
pub(crate) root: Option<PathBuf>,
|
||||
|
||||
pub(crate) pgroup: Option<OsProcessGroupId>,
|
||||
pub(crate) gain_terminal: Option<RawFd>,
|
||||
pub(crate) attach_trace: bool,
|
||||
pub(crate) flags: SpawnFlags,
|
||||
|
||||
stdin: Stdio,
|
||||
stdout: Stdio,
|
||||
stderr: Stdio,
|
||||
}
|
||||
|
||||
pub struct CommandArgs<'a>(crate::slice::Iter<'a, String>);
|
||||
|
||||
impl Command {
|
||||
pub fn new(program: &OsStr) -> Self {
|
||||
let program = program.to_str().unwrap().to_owned();
|
||||
|
||||
Self {
|
||||
program,
|
||||
args: vec![],
|
||||
env: Default::default(),
|
||||
cwd: None,
|
||||
root: None,
|
||||
pgroup: None,
|
||||
gain_terminal: None,
|
||||
attach_trace: false,
|
||||
flags: SpawnFlags::const_default(),
|
||||
stdin: Stdio::Inherit,
|
||||
stdout: Stdio::Inherit,
|
||||
stderr: Stdio::Inherit,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn arg(&mut self, arg: &OsStr) {
|
||||
if arg.len() == 0 {
|
||||
self.args.push(String::new());
|
||||
} else {
|
||||
let arg = arg.to_str().unwrap().to_owned();
|
||||
self.args.push(arg);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn env_mut(&mut self) -> &mut CommandEnv {
|
||||
&mut self.env
|
||||
}
|
||||
|
||||
pub fn cwd(&mut self, dir: &OsStr) {
|
||||
self.cwd = Some(dir.into());
|
||||
}
|
||||
|
||||
pub fn stdin(&mut self, stdin: Stdio) {
|
||||
self.stdin = stdin;
|
||||
}
|
||||
|
||||
pub fn stdout(&mut self, stdout: Stdio) {
|
||||
self.stdout = stdout;
|
||||
}
|
||||
|
||||
pub fn stderr(&mut self, stderr: Stdio) {
|
||||
self.stderr = stderr;
|
||||
}
|
||||
|
||||
pub fn get_program(&self) -> &OsStr {
|
||||
self.program.as_str().as_ref()
|
||||
}
|
||||
|
||||
pub fn get_args(&self) -> CommandArgs<'_> {
|
||||
CommandArgs(self.args.iter())
|
||||
}
|
||||
|
||||
pub fn get_envs(&self) -> CommandEnvs<'_> {
|
||||
self.env.iter()
|
||||
}
|
||||
|
||||
pub fn get_env_clear(&self) -> bool {
|
||||
self.env.does_clear()
|
||||
}
|
||||
|
||||
pub fn get_current_dir(&self) -> Option<&Path> {
|
||||
self.cwd.as_deref()
|
||||
}
|
||||
|
||||
pub fn spawn(
|
||||
&mut self,
|
||||
_default: Stdio,
|
||||
_needs_stdin: bool,
|
||||
) -> io::Result<(Process, StdioPipes)> {
|
||||
// let default_stdin = if needs_stdin { &default } else { &self.stdin };
|
||||
|
||||
let stdin = &self.stdin;
|
||||
let stdout = &self.stdout;
|
||||
let stderr = &self.stderr;
|
||||
|
||||
let (their_stdin, our_stdin) = stdin.to_child_stdio(true)?;
|
||||
let (their_stdout, our_stdout) = stdout.to_child_stdio(false)?;
|
||||
let (their_stderr, our_stderr) = stderr.to_child_stdio(false)?;
|
||||
|
||||
let ours = StdioPipes { stdin: our_stdin, stdout: our_stdout, stderr: our_stderr };
|
||||
let theirs = ChildPipes { stdin: their_stdin, stdout: their_stdout, stderr: their_stderr };
|
||||
|
||||
let process = self.do_spawn(&theirs)?;
|
||||
|
||||
Ok((process, ours))
|
||||
}
|
||||
|
||||
fn do_spawn(&mut self, pipes: &ChildPipes) -> io::Result<Process> {
|
||||
let mut optional = Vec::new();
|
||||
|
||||
if let Some(stdin) = pipes.stdin.as_inherit_option(RawFd::STDIN) {
|
||||
optional.push(stdin);
|
||||
}
|
||||
if let Some(stdout) = pipes.stdout.as_inherit_option(RawFd::STDOUT) {
|
||||
optional.push(stdout);
|
||||
}
|
||||
if let Some(stderr) = pipes.stderr.as_inherit_option(RawFd::STDERR) {
|
||||
optional.push(stderr);
|
||||
}
|
||||
|
||||
if let Some(pgroup) = self.pgroup {
|
||||
optional.push(SpawnOption::SetProcessGroup(pgroup));
|
||||
}
|
||||
|
||||
if let Some(fd) = self.gain_terminal {
|
||||
optional.push(SpawnOption::GainTerminal(fd));
|
||||
}
|
||||
|
||||
if self.attach_trace {
|
||||
optional.push(SpawnOption::AttachTrace);
|
||||
}
|
||||
|
||||
let program = self.program.as_str();
|
||||
let arguments = &Vec::from_iter(
|
||||
crate::iter::once(self.program.as_str())
|
||||
.chain(self.args.iter().map(|arg| arg.as_str())),
|
||||
);
|
||||
|
||||
let program = &util::resolve_binary(program).unwrap_or_else(|| program.to_owned());
|
||||
|
||||
let envs = Vec::from_iter(self.env.capture().iter().filter_map(|(key, value)| {
|
||||
let key = key.to_str()?;
|
||||
let value = value.to_str()?;
|
||||
Some(format!("{}={}", key, value))
|
||||
}));
|
||||
|
||||
let directory = self.cwd.as_ref().map(|cwd| cwd.to_str().unwrap());
|
||||
let root = self.root.as_ref().map(|root| root.to_str().unwrap());
|
||||
|
||||
let environment = &Vec::from_iter(envs.iter().map(|x| x.as_str()));
|
||||
|
||||
let options = SpawnOptions {
|
||||
program,
|
||||
arguments,
|
||||
environment,
|
||||
directory,
|
||||
root,
|
||||
optional: &optional,
|
||||
flags: self.flags,
|
||||
};
|
||||
|
||||
let pid = unsafe { syscall::spawn_process(&options) }?;
|
||||
|
||||
Ok(Process { pid })
|
||||
}
|
||||
|
||||
pub(crate) fn change_root<P: AsRef<Path>>(&mut self, root: P) {
|
||||
self.root = Some(root.as_ref().into());
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Iterator for CommandArgs<'a> {
|
||||
type Item = &'a OsStr;
|
||||
fn next(&mut self) -> Option<&'a OsStr> {
|
||||
self.0.next().map(|s| s.as_ref())
|
||||
}
|
||||
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
self.0.size_hint()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> ExactSizeIterator for CommandArgs<'a> {}
|
||||
|
||||
impl<'a> fmt::Debug for CommandArgs<'a> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
fmt::Debug::fmt(&self.0, f)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
#![allow(exported_private_dependencies)]
|
||||
|
||||
use yggdrasil_rt::process::{
|
||||
self as rt, ExitCode as OsExitCode, ProcessId as OsProcessId, ProcessWait, Signal as OsSignal,
|
||||
WaitFlags,
|
||||
};
|
||||
use yggdrasil_rt::sys as syscall;
|
||||
|
||||
use crate::io;
|
||||
use crate::os::fd::AsRawFd;
|
||||
use crate::os::yggdrasil::io::poll::PollChannel;
|
||||
|
||||
mod command;
|
||||
mod status;
|
||||
mod stdio;
|
||||
|
||||
pub use command::{Command, CommandArgs};
|
||||
pub use status::{ExitCode, ExitStatus, ExitStatusError};
|
||||
pub use stdio::{ChildPipes, Stdio};
|
||||
|
||||
pub use crate::ffi::OsString as EnvKey;
|
||||
|
||||
// Process
|
||||
|
||||
pub struct Process {
|
||||
pid: OsProcessId,
|
||||
}
|
||||
|
||||
impl Process {
|
||||
pub fn id(&self) -> u32 {
|
||||
self.pid.into_raw()
|
||||
}
|
||||
|
||||
pub fn main_thread_id(&self) -> io::Result<u32> {
|
||||
Ok(rt::get_process_option!(Some(self.pid), rt::options::MainThread)?.into_raw())
|
||||
}
|
||||
|
||||
pub fn kill(&mut self) -> io::Result<()> {
|
||||
unsafe { syscall::send_signal(self.pid, OsSignal::Killed) }?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn wait_impl(&mut self, flags: WaitFlags) -> io::Result<ExitStatus> {
|
||||
let mut status = OsExitCode::Exited(0);
|
||||
unsafe { syscall::wait_process(&ProcessWait::Process(self.pid), &mut status, flags) }?;
|
||||
Ok(ExitStatus(status))
|
||||
}
|
||||
|
||||
pub fn wait(&mut self) -> io::Result<ExitStatus> {
|
||||
self.wait_impl(WaitFlags::empty())
|
||||
}
|
||||
|
||||
pub fn try_wait(&mut self) -> io::Result<Option<ExitStatus>> {
|
||||
match self.wait_impl(WaitFlags::NON_BLOCKING) {
|
||||
Ok(s) => Ok(Some(s)),
|
||||
Err(e) if e.kind() == io::ErrorKind::WouldBlock => Ok(None),
|
||||
Err(e) => Err(e),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ChildPipe
|
||||
|
||||
pub type ChildPipe = crate::sys::pipe::Pipe;
|
||||
|
||||
pub fn read_output(
|
||||
out: ChildPipe,
|
||||
stdout: &mut Vec<u8>,
|
||||
err: ChildPipe,
|
||||
stderr: &mut Vec<u8>,
|
||||
) -> io::Result<()> {
|
||||
let mut poll = PollChannel::new()?;
|
||||
poll.add(out.as_raw_fd())?;
|
||||
poll.add(err.as_raw_fd())?;
|
||||
|
||||
loop {
|
||||
match poll.wait(None, true)? {
|
||||
Some((fd, _)) if fd == out.as_raw_fd() => {
|
||||
out.read_to_end(stdout)?;
|
||||
err.read_to_end(stderr)?;
|
||||
break;
|
||||
}
|
||||
Some((fd, _)) if fd == err.as_raw_fd() => {
|
||||
err.read_to_end(stderr)?;
|
||||
out.read_to_end(stdout)?;
|
||||
}
|
||||
_ => continue,
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
use yggdrasil_rt::process::{ExitCode as OsExitCode, Signal as OsSignal};
|
||||
|
||||
use crate::fmt;
|
||||
use crate::num::NonZeroI32;
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq)]
|
||||
pub struct ExitStatus(pub(super) OsExitCode);
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
||||
pub struct ExitStatusError(pub(super) NonZeroI32);
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
||||
pub struct ExitCode(pub(super) bool);
|
||||
|
||||
impl ExitStatus {
|
||||
pub fn exit_ok(&self) -> Result<(), ExitStatusError> {
|
||||
if let Some(error) = self.0.as_failure() { Err(ExitStatusError(error)) } else { Ok(()) }
|
||||
}
|
||||
|
||||
pub fn code(&self) -> Option<i32> {
|
||||
match self.0 {
|
||||
OsExitCode::Exited(code) => Some(code),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn signal(&self) -> Option<Result<OsSignal, u32>> {
|
||||
self.0.signal()
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for ExitStatus {
|
||||
fn default() -> Self {
|
||||
Self(OsExitCode::SUCCESS)
|
||||
}
|
||||
}
|
||||
|
||||
impl ExitStatusError {
|
||||
pub fn code(self) -> Option<NonZeroI32> {
|
||||
Some(self.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ExitStatusError> for ExitStatus {
|
||||
fn from(value: ExitStatusError) -> Self {
|
||||
Self(OsExitCode::from(i32::from(value.0)))
|
||||
}
|
||||
}
|
||||
|
||||
impl ExitCode {
|
||||
pub const SUCCESS: Self = Self(false);
|
||||
pub const FAILURE: Self = Self(true);
|
||||
|
||||
pub fn as_i32(&self) -> i32 {
|
||||
self.0 as i32
|
||||
}
|
||||
}
|
||||
|
||||
impl From<u8> for ExitCode {
|
||||
fn from(value: u8) -> Self {
|
||||
Self(value != 0)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for ExitStatus {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
fmt::Debug::fmt(&self.0, f)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for ExitStatus {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
fmt::Debug::fmt(&self.0, f)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
use yggdrasil_rt::process::SpawnOption;
|
||||
|
||||
use crate::io::{self, Stderr, Stdin, Stdout};
|
||||
use crate::os::fd::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
|
||||
use crate::os::yggdrasil::io::pipe as os_pipe;
|
||||
use crate::sys::FromInner;
|
||||
use crate::sys::fs::File;
|
||||
use crate::sys::pipe::Pipe;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ChildPipes {
|
||||
pub stdin: ChildStdio,
|
||||
pub stdout: ChildStdio,
|
||||
pub stderr: ChildStdio,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum ChildStdio {
|
||||
Inherit,
|
||||
Null,
|
||||
CopyFd(RawFd),
|
||||
MoveFd(RawFd),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Stdio {
|
||||
Inherit,
|
||||
Null,
|
||||
MakePipe,
|
||||
MoveFd(RawFd),
|
||||
CopyFd(RawFd),
|
||||
}
|
||||
|
||||
impl Stdio {
|
||||
pub fn to_child_stdio(&self, readable: bool) -> io::Result<(ChildStdio, Option<Pipe>)> {
|
||||
match self {
|
||||
Stdio::Inherit => Ok((ChildStdio::Inherit, None)),
|
||||
Stdio::Null => Ok((ChildStdio::Null, None)),
|
||||
Stdio::MakePipe => {
|
||||
let (read, write) = os_pipe::create_pipe_pair(false, false)?;
|
||||
|
||||
if readable {
|
||||
let write = Pipe::from_inner(write);
|
||||
Ok((ChildStdio::MoveFd(read.into_raw_fd()), Some(write)))
|
||||
} else {
|
||||
let read = Pipe::from_inner(read);
|
||||
Ok((ChildStdio::MoveFd(write.into_raw_fd()), Some(read)))
|
||||
}
|
||||
}
|
||||
Stdio::MoveFd(fd) => Ok((ChildStdio::MoveFd(*fd), None)),
|
||||
Stdio::CopyFd(fd) => Ok((ChildStdio::CopyFd(*fd), None)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(ineffective_unstable_trait_impl)]
|
||||
#[unstable(feature = "yggdrasil_os", issue = "none")]
|
||||
impl FromRawFd for crate::process::Stdio {
|
||||
#[inline]
|
||||
unsafe fn from_raw_fd(fd: RawFd) -> crate::process::Stdio {
|
||||
let io = Stdio::MoveFd(fd);
|
||||
crate::process::Stdio::from_inner(io)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Pipe> for Stdio {
|
||||
fn from(pipe: Pipe) -> Stdio {
|
||||
Self::MoveFd(pipe.into_raw_fd())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<File> for Stdio {
|
||||
fn from(file: File) -> Stdio {
|
||||
Self::MoveFd(file.into_raw_fd())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Stdin> for Stdio {
|
||||
fn from(s: Stdin) -> Stdio {
|
||||
Self::CopyFd(s.as_raw_fd())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Stdout> for Stdio {
|
||||
fn from(s: Stdout) -> Stdio {
|
||||
Self::CopyFd(s.as_raw_fd())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Stderr> for Stdio {
|
||||
fn from(s: Stderr) -> Stdio {
|
||||
Self::CopyFd(s.as_raw_fd())
|
||||
}
|
||||
}
|
||||
|
||||
impl ChildStdio {
|
||||
pub(super) fn as_inherit_option(&self, child: RawFd) -> Option<SpawnOption> {
|
||||
match self {
|
||||
Self::Inherit => Some(SpawnOption::CopyFile { source: child, child }),
|
||||
&Self::MoveFd(fd) => Some(SpawnOption::MoveFile { source: fd, child }),
|
||||
&Self::CopyFd(fd) => Some(SpawnOption::CopyFile { source: fd, child }),
|
||||
Self::Null => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -102,6 +102,10 @@ cfg_select! {
|
||||
mod zkvm;
|
||||
pub use zkvm::fill_bytes;
|
||||
}
|
||||
target_os = "yggdrasil" => {
|
||||
mod yggdrasil;
|
||||
pub use yggdrasil::fill_bytes;
|
||||
}
|
||||
any(
|
||||
all(target_family = "wasm", target_os = "unknown"),
|
||||
target_os = "xous",
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
#[inline(always)]
|
||||
pub fn fill_bytes(buffer: &mut [u8]) {
|
||||
unsafe { yggdrasil_rt::sys::get_random(buffer) }
|
||||
}
|
||||
|
||||
// pub fn hashmap_random_keys() -> (u64, u64) {
|
||||
// const KEY_LEN: usize = crate::mem::size_of::<u64>();
|
||||
//
|
||||
// let mut v = [0u8; KEY_LEN * 2];
|
||||
// fill_bytes(&mut v);
|
||||
//
|
||||
// let key1 = v[0..KEY_LEN].try_into().unwrap();
|
||||
// let key2 = v[KEY_LEN..].try_into().unwrap();
|
||||
//
|
||||
// (u64::from_ne_bytes(key1), u64::from_ne_bytes(key2))
|
||||
// }
|
||||
@@ -45,6 +45,10 @@ cfg_select! {
|
||||
mod zkvm;
|
||||
pub use zkvm::*;
|
||||
}
|
||||
target_os = "yggdrasil" => {
|
||||
mod yggdrasil;
|
||||
pub use yggdrasil::*;
|
||||
}
|
||||
_ => {
|
||||
mod unsupported;
|
||||
pub use unsupported::*;
|
||||
|
||||
@@ -0,0 +1,125 @@
|
||||
use yggdrasil_rt::Error as OsError;
|
||||
use yggdrasil_rt::io::RawFd;
|
||||
|
||||
use crate::io;
|
||||
use crate::io::{IoSlice, IoSliceMut};
|
||||
use crate::sealed::Sealed;
|
||||
|
||||
pub struct Stdin;
|
||||
pub struct Stdout;
|
||||
pub struct Stderr;
|
||||
|
||||
impl Sealed for Stdin {}
|
||||
|
||||
impl Stdin {
|
||||
pub const fn new() -> Self {
|
||||
Self
|
||||
}
|
||||
}
|
||||
|
||||
impl Sealed for Stdout {}
|
||||
|
||||
impl Stdout {
|
||||
pub const fn new() -> Self {
|
||||
Self
|
||||
}
|
||||
}
|
||||
|
||||
impl Sealed for Stderr {}
|
||||
|
||||
impl Stderr {
|
||||
pub const fn new() -> Self {
|
||||
Self
|
||||
}
|
||||
}
|
||||
|
||||
impl io::Read for Stdin {
|
||||
fn read(&mut self, data: &mut [u8]) -> io::Result<usize> {
|
||||
Ok(unsafe { yggdrasil_rt::sys::read(RawFd::STDIN, data) }?)
|
||||
}
|
||||
|
||||
fn read_vectored(&mut self, _data: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn is_read_vectored(&self) -> bool {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
impl io::Write for Stdout {
|
||||
fn write(&mut self, data: &[u8]) -> io::Result<usize> {
|
||||
Ok(unsafe { yggdrasil_rt::sys::write(RawFd::STDOUT, data) }?)
|
||||
}
|
||||
|
||||
fn write_vectored(&mut self, _data: &[IoSlice<'_>]) -> io::Result<usize> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn is_write_vectored(&self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
fn flush(&mut self) -> io::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl io::Write for Stderr {
|
||||
fn write(&mut self, data: &[u8]) -> io::Result<usize> {
|
||||
Ok(unsafe { yggdrasil_rt::sys::write(RawFd::STDERR, data) }?)
|
||||
}
|
||||
|
||||
fn write_vectored(&mut self, _data: &[IoSlice<'_>]) -> io::Result<usize> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn is_write_vectored(&self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
fn flush(&mut self) -> io::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub const STDIN_BUF_SIZE: usize = 64;
|
||||
|
||||
impl crate::io::IsTerminal for Stdin {
|
||||
fn is_terminal(&self) -> bool {
|
||||
yggdrasil_rt::io::terminal::is_terminal(RawFd::STDIN)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_ebadf(err: &io::Error) -> bool {
|
||||
err.raw_os_error() == Some(u32::from(OsError::InvalidFile) as i32)
|
||||
}
|
||||
|
||||
pub struct PanicOutput {
|
||||
stderr: Stderr,
|
||||
}
|
||||
|
||||
impl PanicOutput {
|
||||
pub fn new() -> Self {
|
||||
Self { stderr: Stderr::new() }
|
||||
}
|
||||
}
|
||||
|
||||
impl io::Write for PanicOutput {
|
||||
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
|
||||
yggdrasil_rt::debug::trace_raw(yggdrasil_rt::debug::TraceLevel::Error, buf);
|
||||
self.stderr.write(buf).ok();
|
||||
Ok(buf.len())
|
||||
}
|
||||
|
||||
fn flush(&mut self) -> io::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn panic_output() -> Option<impl io::Write> {
|
||||
Some(PanicOutput::new())
|
||||
}
|
||||
@@ -10,6 +10,7 @@ cfg_select! {
|
||||
target_os = "fuchsia",
|
||||
all(target_family = "wasm", target_feature = "atomics"),
|
||||
target_os = "hermit",
|
||||
target_os = "yggdrasil",
|
||||
) => {
|
||||
mod futex;
|
||||
pub use futex::Condvar;
|
||||
|
||||
@@ -9,6 +9,7 @@ cfg_select! {
|
||||
target_os = "dragonfly",
|
||||
all(target_family = "wasm", target_feature = "atomics"),
|
||||
target_os = "hermit",
|
||||
target_os = "yggdrasil",
|
||||
) => {
|
||||
mod futex;
|
||||
pub use futex::Mutex;
|
||||
|
||||
@@ -9,7 +9,8 @@ cfg_select! {
|
||||
target_os = "fuchsia",
|
||||
all(target_family = "wasm", target_feature = "atomics"),
|
||||
target_os = "hermit",
|
||||
target_os = "motor",
|
||||
target_os = "motor",
|
||||
target_os = "yggdrasil",
|
||||
) => {
|
||||
mod futex;
|
||||
pub use futex::RwLock;
|
||||
|
||||
@@ -48,6 +48,11 @@ cfg_select! {
|
||||
mod unsupported;
|
||||
pub use unsupported::{Thread, current_os_id, set_name, yield_now, DEFAULT_MIN_STACK_SIZE};
|
||||
}
|
||||
target_os = "yggdrasil" => {
|
||||
mod yggdrasil;
|
||||
pub use yggdrasil::{available_parallelism, sleep, Thread, current_os_id, set_name, yield_now, DEFAULT_MIN_STACK_SIZE};
|
||||
pub(crate) use yggdrasil::init;
|
||||
}
|
||||
any(target_family = "unix", target_os = "wasi") => {
|
||||
mod unix;
|
||||
pub use unix::{Thread, available_parallelism, current_os_id, sleep, yield_now, DEFAULT_MIN_STACK_SIZE};
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
use yggdrasil_rt::process::{self, AuxValue, ExitCode as OsExitCode, thread as rt, thread_local};
|
||||
|
||||
use crate::boxed::Box;
|
||||
use crate::ffi::CStr;
|
||||
use crate::io;
|
||||
use crate::num::NonZeroUsize;
|
||||
use crate::thread::ThreadInit;
|
||||
use crate::time::Duration;
|
||||
|
||||
#[repr(C)]
|
||||
pub struct Thread {
|
||||
inner: rt::ThreadHandle<()>,
|
||||
}
|
||||
|
||||
pub const DEFAULT_MIN_STACK_SIZE: usize = 8192;
|
||||
|
||||
// TODO put it into OnceLock
|
||||
pub(super) static mut TLS_IMAGE: Option<thread_local::TlsImage> = None;
|
||||
|
||||
impl Thread {
|
||||
pub unsafe fn new(stack_size: usize, init: Box<ThreadInit>) -> io::Result<Thread> {
|
||||
// Unused now
|
||||
let _ = set_name;
|
||||
let info = rt::ThreadCreateInfo {
|
||||
signal_stack: rt::ThreadSignalStack::Allocate(4096 * 8),
|
||||
stack: rt::ThreadStack::Allocate(stack_size),
|
||||
entry: rt::ThreadFunction::Pointer(Self::entry),
|
||||
#[allow(static_mut_refs)]
|
||||
tls_image: TLS_IMAGE.as_ref(),
|
||||
};
|
||||
let inner = rt::Thread::spawn(info, init, false)?;
|
||||
Ok(Thread { inner })
|
||||
}
|
||||
|
||||
pub fn join(self) {
|
||||
self.inner.join_uninterruptible();
|
||||
}
|
||||
|
||||
fn entry(init: Box<ThreadInit>) {
|
||||
let start = init.init();
|
||||
(start)();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_name(name: &CStr) {
|
||||
rt::Thread::<()>::set_name(
|
||||
name.to_str().expect("Thread::set_name() expects a valid UTF-8 string"),
|
||||
);
|
||||
}
|
||||
|
||||
pub fn current_os_id() -> Option<u64> {
|
||||
Some(unsafe { yggdrasil_rt::sys::get_tid() as u64 })
|
||||
}
|
||||
|
||||
pub fn yield_now() {
|
||||
yggdrasil_rt::debug_trace!(Error, "thread::yield_now()");
|
||||
loop {}
|
||||
}
|
||||
|
||||
pub fn sleep(duration: Duration) {
|
||||
process::uninterruptible_sleep(duration)
|
||||
}
|
||||
|
||||
pub fn available_parallelism() -> io::Result<NonZeroUsize> {
|
||||
yggdrasil_rt::debug_trace!(Error, "thread::available_parallelism()");
|
||||
loop {}
|
||||
}
|
||||
|
||||
pub(crate) unsafe fn init<'a, I: Iterator<Item = &'a AuxValue>>(auxv: I) {
|
||||
// Rust doesn't have a pthread_self, so just reserve two slots in the TCB:
|
||||
// * self-pointer
|
||||
// * DTV pointer
|
||||
let image = thread_local::TlsImage::from_auxv(auxv);
|
||||
if let Err(error) = thread_local::init_tls(image.as_ref(), false) {
|
||||
yggdrasil_rt::debug_trace!(Debug, "Could not setup main thread TLS: {error:?}");
|
||||
// TODO kill self with ABORTED signal instead
|
||||
yggdrasil_rt::sys::exit_process(OsExitCode::Exited(1));
|
||||
}
|
||||
TLS_IMAGE = image;
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
use yggdrasil_rt::process::thread_local as imp;
|
||||
|
||||
pub type Key = usize;
|
||||
|
||||
#[inline]
|
||||
pub unsafe fn set(key: Key, value: *mut u8) {
|
||||
let dtv = imp::get_dtv();
|
||||
dtv.set_specific(key, value.cast(), true);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn create(_dtor: Option<unsafe extern "C" fn(*mut u8)>) -> Key {
|
||||
// TODO dtors
|
||||
let dtv = imp::get_dtv();
|
||||
dtv.new_specific()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub unsafe fn destroy(_key: Key) {
|
||||
// TODO dtors
|
||||
}
|
||||
@@ -195,6 +195,15 @@ pub(crate) mod key {
|
||||
pub(super) use moto_rt::tls::{Key, get, set};
|
||||
use moto_rt::tls::{create, destroy};
|
||||
}
|
||||
target_os = "yggdrasil" => {
|
||||
mod racy;
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
mod yggdrasil;
|
||||
pub(super) use racy::LazyKey;
|
||||
pub(super) use yggdrasil::{Key, set};
|
||||
use yggdrasil::{create, destroy};
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -930,29 +930,41 @@ impl Step for StartupObjects {
|
||||
let target = self.target;
|
||||
// Even though no longer necessary on x86_64, they are kept for now to
|
||||
// avoid potential issues in downstream crates.
|
||||
if !target.is_windows_gnu() {
|
||||
if !target.is_windows_gnu() && !target.ends_with("-yggdrasil") {
|
||||
return vec![];
|
||||
}
|
||||
|
||||
let mut target_deps = vec![];
|
||||
if target.ends_with("-yggdrasil") {
|
||||
let dst_dir = &builder.native_dir(target).join("rtstartup");
|
||||
let sysroot_dir = &builder.sysroot_target_libdir(for_compiler, target);
|
||||
t!(fs::create_dir_all(dst_dir));
|
||||
|
||||
let src_dir = &builder.src.join("library").join("rtstartup");
|
||||
let dst_dir = &builder.native_dir(target).join("rtstartup");
|
||||
let sysroot_dir = &builder.sysroot_target_libdir(for_compiler, target);
|
||||
t!(fs::create_dir_all(dst_dir));
|
||||
let src_file = &builder.src.join("library/rtstartup/yggdrasil_rust_entry.rs");
|
||||
let dst_file = &dst_dir.join("rust_entry0.o");
|
||||
let target_file = sysroot_dir.join("rust_entry0.o");
|
||||
|
||||
for file in &["rsbegin", "rsend"] {
|
||||
let src_file = &src_dir.join(file.to_string() + ".rs");
|
||||
let dst_file = &dst_dir.join(file.to_string() + ".o");
|
||||
if !up_to_date(src_file, dst_file) {
|
||||
let mut cmd = command(&builder.initial_rustc);
|
||||
// FIXME(alnyan) do this properly
|
||||
|
||||
let fake_target = if target.starts_with("aarch64-") {
|
||||
"aarch64-unknown-none"
|
||||
} else if target.starts_with("x86_64-") {
|
||||
"x86_64-unknown-none"
|
||||
} else if target.starts_with("i686-") {
|
||||
"i686-unknown-linux-gnu"
|
||||
} else if target.starts_with("riscv64-") {
|
||||
"riscv64imac-unknown-none-elf"
|
||||
} else {
|
||||
unimplemented!("This code shouldn't be reachable");
|
||||
};
|
||||
|
||||
cmd.env("RUSTC_BOOTSTRAP", "1");
|
||||
if !builder.local_rebuild {
|
||||
// a local_rebuild compiler already has stage1 features
|
||||
cmd.arg("--cfg").arg("bootstrap");
|
||||
}
|
||||
cmd.arg("--target")
|
||||
.arg(target.rustc_target_arg())
|
||||
.arg(fake_target)
|
||||
.arg("--emit=obj")
|
||||
.arg("-o")
|
||||
.arg(dst_file)
|
||||
@@ -960,12 +972,45 @@ impl Step for StartupObjects {
|
||||
.run(builder);
|
||||
}
|
||||
|
||||
let obj = sysroot_dir.join((*file).to_string() + ".o");
|
||||
builder.copy_link(dst_file, &obj, FileType::NativeLibrary);
|
||||
target_deps.push((obj, DependencyType::Target));
|
||||
}
|
||||
builder.copy_link(dst_file, &target_file, FileType::NativeLibrary);
|
||||
// builder.copy_link(dst_file, &target);
|
||||
// target_deps.push((target, DependencyType::Target));
|
||||
|
||||
target_deps
|
||||
vec![(target_file, DependencyType::Target)]
|
||||
} else {
|
||||
let mut target_deps = vec![];
|
||||
|
||||
let src_dir = &builder.src.join("library").join("rtstartup");
|
||||
let dst_dir = &builder.native_dir(target).join("rtstartup");
|
||||
let sysroot_dir = &builder.sysroot_target_libdir(for_compiler, target);
|
||||
t!(fs::create_dir_all(dst_dir));
|
||||
|
||||
for file in &["rsbegin", "rsend"] {
|
||||
let src_file = &src_dir.join(file.to_string() + ".rs");
|
||||
let dst_file = &dst_dir.join(file.to_string() + ".o");
|
||||
if !up_to_date(src_file, dst_file) {
|
||||
let mut cmd = command(&builder.initial_rustc);
|
||||
cmd.env("RUSTC_BOOTSTRAP", "1");
|
||||
if !builder.local_rebuild {
|
||||
// a local_rebuild compiler already has stage1 features
|
||||
cmd.arg("--cfg").arg("bootstrap");
|
||||
}
|
||||
cmd.arg("--target")
|
||||
.arg(target.rustc_target_arg())
|
||||
.arg("--emit=obj")
|
||||
.arg("-o")
|
||||
.arg(dst_file)
|
||||
.arg(src_file)
|
||||
.run(builder);
|
||||
}
|
||||
|
||||
let obj = sysroot_dir.join((*file).to_string() + ".o");
|
||||
builder.copy_link(dst_file, &obj, FileType::NativeLibrary);
|
||||
target_deps.push((obj, DependencyType::Target));
|
||||
}
|
||||
|
||||
target_deps
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -38,6 +38,9 @@ pub struct Finder {
|
||||
const STAGE0_MISSING_TARGETS: &[&str] = &[
|
||||
// just a dummy comment so the list doesn't get onelined
|
||||
"riscv64im-unknown-none-elf",
|
||||
"x86_64-unknown-yggdrasil",
|
||||
"aarch64-unknown-yggdrasil",
|
||||
"riscv64-unknown-yggdrasil",
|
||||
];
|
||||
|
||||
/// Minimum version threshold for libstdc++ required when using prebuilt LLVM
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
beta
|
||||
stable
|
||||
|
||||
@@ -444,6 +444,7 @@ impl fmt::Display for Display<'_> {
|
||||
"watchos" => "watchOS",
|
||||
"windows" => "Windows",
|
||||
"visionos" => "visionOS",
|
||||
"yggdrasil" => "Yggdrasil",
|
||||
_ => "",
|
||||
},
|
||||
(sym::target_arch, Some(arch)) => match arch.as_str() {
|
||||
|
||||
@@ -11,10 +11,11 @@ use rustc_ast::util::comments::may_have_doc_links;
|
||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet};
|
||||
use rustc_data_structures::intern::Interned;
|
||||
use rustc_errors::{Applicability, Diag, DiagMessage};
|
||||
use rustc_hir::attrs::AttributeKind;
|
||||
use rustc_hir::def::Namespace::*;
|
||||
use rustc_hir::def::{DefKind, MacroKinds, Namespace, PerNS};
|
||||
use rustc_hir::def_id::{CRATE_DEF_ID, DefId, LOCAL_CRATE};
|
||||
use rustc_hir::{Mutability, Safety};
|
||||
use rustc_hir::{Attribute, Mutability, Safety};
|
||||
use rustc_middle::ty::{Ty, TyCtxt};
|
||||
use rustc_middle::{bug, span_bug, ty};
|
||||
use rustc_resolve::rustdoc::pulldown_cmark::LinkType;
|
||||
@@ -1108,10 +1109,8 @@ impl LinkCollector<'_, '_> {
|
||||
|
||||
// Also resolve links in the note text of `#[deprecated]`.
|
||||
for attr in &item.attrs.other_attrs {
|
||||
let rustc_hir::Attribute::Parsed(rustc_hir::attrs::AttributeKind::Deprecation {
|
||||
span,
|
||||
deprecation,
|
||||
}) = attr
|
||||
let Attribute::Parsed(AttributeKind::Deprecation { span: depr_span, deprecation }) =
|
||||
attr
|
||||
else {
|
||||
continue;
|
||||
};
|
||||
@@ -1128,8 +1127,14 @@ impl LinkCollector<'_, '_> {
|
||||
// inlined item.
|
||||
// <https://github.com/rust-lang/rust/pull/151120>
|
||||
let item_id = if let Some(inline_stmt_id) = item.inline_stmt_id
|
||||
&& item.span(tcx).is_none_or(|item_span| !item_span.inner().contains(*span))
|
||||
{
|
||||
&& tcx.get_all_attrs(inline_stmt_id).iter().any(|attr| {
|
||||
matches!(
|
||||
attr,
|
||||
Attribute::Parsed(AttributeKind::Deprecation {
|
||||
span: attr_span, ..
|
||||
}) if attr_span == depr_span,
|
||||
)
|
||||
}) {
|
||||
inline_stmt_id.to_def_id()
|
||||
} else {
|
||||
item.item_id.expect_def_id()
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
// This test ensures that the intra-doc link from reexported deprecated attribute note
|
||||
// are resolved where they are declared.
|
||||
|
||||
#![deny(rustdoc::broken_intra_doc_links)]
|
||||
|
||||
#[doc(inline)]
|
||||
pub use bar::sql_function_proc as sql_function;
|
||||
|
||||
pub fn define_sql_function() {}
|
||||
|
||||
pub mod bar {
|
||||
#[deprecated(note = "Use [`define_sql_function`] instead")]
|
||||
//~^ ERROR: unresolved link
|
||||
//~| ERROR: unresolved link
|
||||
pub fn sql_function_proc() {}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
error: unresolved link to `define_sql_function`
|
||||
--> $DIR/deprecated-note-from-reexported.rs:12:25
|
||||
|
|
||||
LL | #[deprecated(note = "Use [`define_sql_function`] instead")]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: the link appears in this line:
|
||||
|
||||
Use [`define_sql_function`] instead
|
||||
^^^^^^^^^^^^^^^^^^^^^
|
||||
= note: no item named `define_sql_function` in scope
|
||||
= help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
|
||||
note: the lint level is defined here
|
||||
--> $DIR/deprecated-note-from-reexported.rs:4:9
|
||||
|
|
||||
LL | #![deny(rustdoc::broken_intra_doc_links)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: unresolved link to `define_sql_function`
|
||||
--> $DIR/deprecated-note-from-reexported.rs:12:25
|
||||
|
|
||||
LL | #[deprecated(note = "Use [`define_sql_function`] instead")]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: the link appears in this line:
|
||||
|
||||
Use [`define_sql_function`] instead
|
||||
^^^^^^^^^^^^^^^^^^^^^
|
||||
= note: no item named `define_sql_function` in scope
|
||||
= help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
|
||||
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
// Regression test for issue #152606.
|
||||
|
||||
//@ check-pass
|
||||
|
||||
mod outer {
|
||||
mod inner {
|
||||
use super::*; // should go before the ambiguous glob imports
|
||||
}
|
||||
|
||||
use crate::*;
|
||||
pub use crate::*;
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
@@ -0,0 +1,12 @@
|
||||
error[E0046]: not all trait items implemented, missing: `Assoc`
|
||||
--> $DIR/rigid-alias-due-to-broken-impl.rs:14:1
|
||||
|
|
||||
LL | type Assoc;
|
||||
| ---------- `Assoc` from trait
|
||||
...
|
||||
LL | impl Foo for str {}
|
||||
| ^^^^^^^^^^^^^^^^ missing `Assoc` in implementation
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0046`.
|
||||
Reference in New Issue
Block a user