From 3c55c98ec86765fb8d0b877ae293f19a62e51d66 Mon Sep 17 00:00:00 2001 From: Boxy Uwu Date: Mon, 8 Dec 2025 10:08:32 +0000 Subject: [PATCH 01/58] replace version placeholder --- compiler/rustc_feature/src/accepted.rs | 6 ++--- compiler/rustc_feature/src/removed.rs | 2 +- compiler/rustc_feature/src/unstable.rs | 4 +-- .../alloc/src/collections/vec_deque/mod.rs | 4 +-- library/alloc/src/fmt.rs | 2 +- library/alloc/src/string.rs | 2 +- library/alloc/src/vec/mod.rs | 2 +- library/core/src/char/methods.rs | 4 +-- library/core/src/fmt/builders.rs | 8 +++--- library/core/src/fmt/mod.rs | 2 +- library/core/src/mem/maybe_uninit.rs | 16 ++++++------ library/core/src/num/int_macros.rs | 12 ++++----- library/core/src/num/uint_macros.rs | 8 +++--- library/core/src/ptr/const_ptr.rs | 4 +-- library/core/src/ptr/mut_ptr.rs | 4 +-- library/core/src/slice/mod.rs | 8 +++--- library/core/src/time.rs | 4 +-- library/std/src/lib.rs | 2 +- library/std_detect/src/detect/arch/mod.rs | 2 +- library/std_detect/src/detect/arch/s390x.rs | 26 +++++++++---------- 20 files changed, 61 insertions(+), 61 deletions(-) diff --git a/compiler/rustc_feature/src/accepted.rs b/compiler/rustc_feature/src/accepted.rs index 7e765918d7b69..13c1f2219bed2 100644 --- a/compiler/rustc_feature/src/accepted.rs +++ b/compiler/rustc_feature/src/accepted.rs @@ -61,7 +61,7 @@ declare_features! ( /// Allows explicit discriminants on non-unit enum variants. (accepted, arbitrary_enum_discriminant, "1.66.0", Some(60553)), /// Allows #[cfg(...)] on inline assembly templates and operands. - (accepted, asm_cfg, "CURRENT_RUSTC_VERSION", Some(140364)), + (accepted, asm_cfg, "1.93.0", Some(140364)), /// Allows using `const` operands in inline assembly. (accepted, asm_const, "1.82.0", Some(93332)), /// Allows using `label` operands in inline assembly. @@ -218,7 +218,7 @@ declare_features! ( /// Allows access to crate names passed via `--extern` through prelude. (accepted, extern_prelude, "1.30.0", Some(44660)), /// Allows using `system` as a calling convention with varargs. - (accepted, extern_system_varargs, "CURRENT_RUSTC_VERSION", Some(136946)), + (accepted, extern_system_varargs, "1.93.0", Some(136946)), /// Allows using F16C intrinsics from `core::arch::{x86, x86_64}`. (accepted, f16c_target_feature, "1.68.0", Some(44839)), /// Allows field shorthands (`x` meaning `x: x`) in struct literal expressions. @@ -392,7 +392,7 @@ declare_features! ( /// Allows code like `let x: &'static u32 = &42` to work (RFC 1414). (accepted, rvalue_static_promotion, "1.21.0", Some(38865)), /// Allows use of the `vector` and related s390x target features. - (accepted, s390x_target_feature_vector, "CURRENT_RUSTC_VERSION", Some(145649)), + (accepted, s390x_target_feature_vector, "1.93.0", Some(145649)), /// Allows `Self` in type definitions (RFC 2300). (accepted, self_in_typedefs, "1.32.0", Some(49303)), /// Allows `Self` struct constructor (RFC 2302). diff --git a/compiler/rustc_feature/src/removed.rs b/compiler/rustc_feature/src/removed.rs index cd61facb39bb1..e5d66364c2a6e 100644 --- a/compiler/rustc_feature/src/removed.rs +++ b/compiler/rustc_feature/src/removed.rs @@ -190,7 +190,7 @@ declare_features! ( /// Allows use of unary negate on unsigned integers, e.g., -e for e: u8 (removed, negate_unsigned, "1.0.0", Some(29645), None), /// Allows diverging expressions to fall back to `!` rather than `()`. - (removed, never_type_fallback, "CURRENT_RUSTC_VERSION", Some(65992), Some("removed in favor of unconditional fallback"), 148871), + (removed, never_type_fallback, "1.93.0", Some(65992), Some("removed in favor of unconditional fallback"), 148871), /// Allows `#[no_coverage]` on functions. /// The feature was renamed to `coverage_attribute` and the attribute to `#[coverage(on|off)]` (removed, no_coverage, "1.74.0", Some(84605), Some("renamed to `coverage_attribute`"), 114656), diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index 3ef4eb00c3546..5880af0909bfa 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -410,7 +410,7 @@ declare_features! ( (unstable, c_variadic, "1.34.0", Some(44930)), /// Allows defining c-variadic naked functions with any extern ABI that is allowed /// on c-variadic foreign functions. - (unstable, c_variadic_naked_functions, "CURRENT_RUSTC_VERSION", Some(148767)), + (unstable, c_variadic_naked_functions, "1.93.0", Some(148767)), /// Allows the use of `#[cfg(contract_checks)` to check if contract checks are enabled. (unstable, cfg_contract_checks, "1.86.0", Some(128044)), /// Allows the use of `#[cfg(overflow_checks)` to check if integer overflow behaviour. @@ -484,7 +484,7 @@ declare_features! ( /// Allows deriving the From trait on single-field structs. (unstable, derive_from, "1.91.0", Some(144889)), /// Allows giving non-const impls custom diagnostic messages if attempted to be used as const - (unstable, diagnostic_on_const, "CURRENT_RUSTC_VERSION", Some(143874)), + (unstable, diagnostic_on_const, "1.93.0", Some(143874)), /// Allows `#[doc(cfg(...))]`. (unstable, doc_cfg, "1.21.0", Some(43781)), /// Allows `#[doc(masked)]`. diff --git a/library/alloc/src/collections/vec_deque/mod.rs b/library/alloc/src/collections/vec_deque/mod.rs index ea9d5b128ebe4..0e01d0d19e7a4 100644 --- a/library/alloc/src/collections/vec_deque/mod.rs +++ b/library/alloc/src/collections/vec_deque/mod.rs @@ -2053,7 +2053,7 @@ impl VecDeque { /// assert_eq!(deque, [1, 2, 3, 4]); /// assert_eq!(deque.pop_front_if(pred), None); /// ``` - #[stable(feature = "vec_deque_pop_if", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "vec_deque_pop_if", since = "1.93.0")] pub fn pop_front_if(&mut self, predicate: impl FnOnce(&mut T) -> bool) -> Option { let first = self.front_mut()?; if predicate(first) { self.pop_front() } else { None } @@ -2075,7 +2075,7 @@ impl VecDeque { /// assert_eq!(deque, [0, 1, 2, 3]); /// assert_eq!(deque.pop_back_if(pred), None); /// ``` - #[stable(feature = "vec_deque_pop_if", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "vec_deque_pop_if", since = "1.93.0")] pub fn pop_back_if(&mut self, predicate: impl FnOnce(&mut T) -> bool) -> Option { let last = self.back_mut()?; if predicate(last) { self.pop_back() } else { None } diff --git a/library/alloc/src/fmt.rs b/library/alloc/src/fmt.rs index 4d6fe220a09ad..3d7c580be8c95 100644 --- a/library/alloc/src/fmt.rs +++ b/library/alloc/src/fmt.rs @@ -602,7 +602,7 @@ pub use core::fmt::{DebugAsHex, FormattingOptions, Sign}; pub use core::fmt::{DebugList, DebugMap, DebugSet, DebugStruct, DebugTuple}; #[stable(feature = "rust1", since = "1.0.0")] pub use core::fmt::{Formatter, Result, Write}; -#[stable(feature = "fmt_from_fn", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "fmt_from_fn", since = "1.93.0")] pub use core::fmt::{FromFn, from_fn}; #[stable(feature = "rust1", since = "1.0.0")] pub use core::fmt::{LowerExp, UpperExp}; diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs index f5ba71c288334..78ab4b4bbadd4 100644 --- a/library/alloc/src/string.rs +++ b/library/alloc/src/string.rs @@ -937,7 +937,7 @@ impl String { /// assert_eq!(rebuilt, "hello"); /// ``` #[must_use = "losing the pointer will leak memory"] - #[stable(feature = "vec_into_raw_parts", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "vec_into_raw_parts", since = "1.93.0")] pub fn into_raw_parts(self) -> (*mut u8, usize, usize) { self.vec.into_raw_parts() } diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index 2adce8d270398..d397e1ed313ed 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -781,7 +781,7 @@ impl Vec { /// assert_eq!(rebuilt, [4294967295, 0, 1]); /// ``` #[must_use = "losing the pointer will leak memory"] - #[stable(feature = "vec_into_raw_parts", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "vec_into_raw_parts", since = "1.93.0")] pub fn into_raw_parts(self) -> (*mut T, usize, usize) { let mut me = ManuallyDrop::new(self); (me.as_mut_ptr(), me.len(), me.capacity()) diff --git a/library/core/src/char/methods.rs b/library/core/src/char/methods.rs index d1de2c5606154..89cb069723921 100644 --- a/library/core/src/char/methods.rs +++ b/library/core/src/char/methods.rs @@ -74,12 +74,12 @@ impl char { /// The maximum number of bytes required to [encode](char::encode_utf8) a `char` to /// UTF-8 encoding. - #[stable(feature = "char_max_len_assoc", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "char_max_len_assoc", since = "1.93.0")] pub const MAX_LEN_UTF8: usize = 4; /// The maximum number of two-byte units required to [encode](char::encode_utf16) a `char` /// to UTF-16 encoding. - #[stable(feature = "char_max_len_assoc", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "char_max_len_assoc", since = "1.93.0")] pub const MAX_LEN_UTF16: usize = 2; /// `U+FFFD REPLACEMENT CHARACTER` (�) is used in Unicode to represent a diff --git a/library/core/src/fmt/builders.rs b/library/core/src/fmt/builders.rs index 4ea6c6ba8fb9c..197cddd3fa9de 100644 --- a/library/core/src/fmt/builders.rs +++ b/library/core/src/fmt/builders.rs @@ -1226,7 +1226,7 @@ impl<'a, 'b: 'a> DebugMap<'a, 'b> { /// assert_eq!(format!("{}", wrapped), "'a'"); /// assert_eq!(format!("{:?}", wrapped), "'a'"); /// ``` -#[stable(feature = "fmt_from_fn", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "fmt_from_fn", since = "1.93.0")] #[must_use = "returns a type implementing Debug and Display, which do not have any effects unless they are used"] pub fn from_fn) -> fmt::Result>(f: F) -> FromFn { FromFn(f) @@ -1235,10 +1235,10 @@ pub fn from_fn) -> fmt::Result>(f: F) -> FromFn /// Implements [`fmt::Debug`] and [`fmt::Display`] via the provided closure. /// /// Created with [`from_fn`]. -#[stable(feature = "fmt_from_fn", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "fmt_from_fn", since = "1.93.0")] pub struct FromFn(F); -#[stable(feature = "fmt_from_fn", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "fmt_from_fn", since = "1.93.0")] impl fmt::Debug for FromFn where F: Fn(&mut fmt::Formatter<'_>) -> fmt::Result, @@ -1248,7 +1248,7 @@ where } } -#[stable(feature = "fmt_from_fn", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "fmt_from_fn", since = "1.93.0")] impl fmt::Display for FromFn where F: Fn(&mut fmt::Formatter<'_>) -> fmt::Result, diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs index 7a80023ce64eb..e20109c3cc9a8 100644 --- a/library/core/src/fmt/mod.rs +++ b/library/core/src/fmt/mod.rs @@ -41,7 +41,7 @@ pub use num_buffer::{NumBuffer, NumBufferTrait}; #[stable(feature = "debug_builders", since = "1.2.0")] pub use self::builders::{DebugList, DebugMap, DebugSet, DebugStruct, DebugTuple}; -#[stable(feature = "fmt_from_fn", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "fmt_from_fn", since = "1.93.0")] pub use self::builders::{FromFn, from_fn}; /// The type returned by formatter methods. diff --git a/library/core/src/mem/maybe_uninit.rs b/library/core/src/mem/maybe_uninit.rs index e00cf45fcab20..cff6c0457d025 100644 --- a/library/core/src/mem/maybe_uninit.rs +++ b/library/core/src/mem/maybe_uninit.rs @@ -1140,8 +1140,8 @@ impl [MaybeUninit] { /// ``` /// /// [`write_clone_of_slice`]: slice::write_clone_of_slice - #[stable(feature = "maybe_uninit_write_slice", since = "CURRENT_RUSTC_VERSION")] - #[rustc_const_stable(feature = "maybe_uninit_write_slice", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "maybe_uninit_write_slice", since = "1.93.0")] + #[rustc_const_stable(feature = "maybe_uninit_write_slice", since = "1.93.0")] pub const fn write_copy_of_slice(&mut self, src: &[T]) -> &mut [T] where T: Copy, @@ -1201,7 +1201,7 @@ impl [MaybeUninit] { /// ``` /// /// [`write_copy_of_slice`]: slice::write_copy_of_slice - #[stable(feature = "maybe_uninit_write_slice", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "maybe_uninit_write_slice", since = "1.93.0")] pub fn write_clone_of_slice(&mut self, src: &[T]) -> &mut [T] where T: Clone, @@ -1463,7 +1463,7 @@ impl [MaybeUninit] { /// requirement the compiler knows about it is that the data pointer must be /// non-null. Dropping such a `Vec` however will cause undefined /// behaviour. - #[stable(feature = "maybe_uninit_slice", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "maybe_uninit_slice", since = "1.93.0")] #[inline(always)] #[rustc_const_unstable(feature = "const_drop_in_place", issue = "109342")] pub const unsafe fn assume_init_drop(&mut self) @@ -1485,8 +1485,8 @@ impl [MaybeUninit] { /// Calling this when the content is not yet fully initialized causes undefined /// behavior: it is up to the caller to guarantee that every `MaybeUninit` in /// the slice really is in an initialized state. - #[stable(feature = "maybe_uninit_slice", since = "CURRENT_RUSTC_VERSION")] - #[rustc_const_stable(feature = "maybe_uninit_slice", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "maybe_uninit_slice", since = "1.93.0")] + #[rustc_const_stable(feature = "maybe_uninit_slice", since = "1.93.0")] #[inline(always)] pub const unsafe fn assume_init_ref(&self) -> &[T] { // SAFETY: casting `slice` to a `*const [T]` is safe since the caller guarantees that @@ -1504,8 +1504,8 @@ impl [MaybeUninit] { /// behavior: it is up to the caller to guarantee that every `MaybeUninit` in the /// slice really is in an initialized state. For instance, `.assume_init_mut()` cannot /// be used to initialize a `MaybeUninit` slice. - #[stable(feature = "maybe_uninit_slice", since = "CURRENT_RUSTC_VERSION")] - #[rustc_const_stable(feature = "maybe_uninit_slice", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "maybe_uninit_slice", since = "1.93.0")] + #[rustc_const_stable(feature = "maybe_uninit_slice", since = "1.93.0")] #[inline(always)] pub const unsafe fn assume_init_mut(&mut self) -> &mut [T] { // SAFETY: similar to safety notes for `slice_get_ref`, but we have a diff --git a/library/core/src/num/int_macros.rs b/library/core/src/num/int_macros.rs index 99662768a29f2..bc451197289ed 100644 --- a/library/core/src/num/int_macros.rs +++ b/library/core/src/num/int_macros.rs @@ -1275,8 +1275,8 @@ macro_rules! int_impl { /// i.e. when [`checked_neg`] would return `None`. /// #[doc = concat!("[`checked_neg`]: ", stringify!($SelfT), "::checked_neg")] - #[stable(feature = "unchecked_neg", since = "CURRENT_RUSTC_VERSION")] - #[rustc_const_stable(feature = "unchecked_neg", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "unchecked_neg", since = "1.93.0")] + #[rustc_const_stable(feature = "unchecked_neg", since = "1.93.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline(always)] @@ -1392,8 +1392,8 @@ macro_rules! int_impl { /// i.e. when [`checked_shl`] would return `None`. /// #[doc = concat!("[`checked_shl`]: ", stringify!($SelfT), "::checked_shl")] - #[stable(feature = "unchecked_shifts", since = "CURRENT_RUSTC_VERSION")] - #[rustc_const_stable(feature = "unchecked_shifts", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "unchecked_shifts", since = "1.93.0")] + #[rustc_const_stable(feature = "unchecked_shifts", since = "1.93.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline(always)] @@ -1564,8 +1564,8 @@ macro_rules! int_impl { /// i.e. when [`checked_shr`] would return `None`. /// #[doc = concat!("[`checked_shr`]: ", stringify!($SelfT), "::checked_shr")] - #[stable(feature = "unchecked_shifts", since = "CURRENT_RUSTC_VERSION")] - #[rustc_const_stable(feature = "unchecked_shifts", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "unchecked_shifts", since = "1.93.0")] + #[rustc_const_stable(feature = "unchecked_shifts", since = "1.93.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline(always)] diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs index c8224e92b17e4..64adeda35288a 100644 --- a/library/core/src/num/uint_macros.rs +++ b/library/core/src/num/uint_macros.rs @@ -1851,8 +1851,8 @@ macro_rules! uint_impl { /// i.e. when [`checked_shl`] would return `None`. /// #[doc = concat!("[`checked_shl`]: ", stringify!($SelfT), "::checked_shl")] - #[stable(feature = "unchecked_shifts", since = "CURRENT_RUSTC_VERSION")] - #[rustc_const_stable(feature = "unchecked_shifts", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "unchecked_shifts", since = "1.93.0")] + #[rustc_const_stable(feature = "unchecked_shifts", since = "1.93.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline(always)] @@ -2020,8 +2020,8 @@ macro_rules! uint_impl { /// i.e. when [`checked_shr`] would return `None`. /// #[doc = concat!("[`checked_shr`]: ", stringify!($SelfT), "::checked_shr")] - #[stable(feature = "unchecked_shifts", since = "CURRENT_RUSTC_VERSION")] - #[rustc_const_stable(feature = "unchecked_shifts", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "unchecked_shifts", since = "1.93.0")] + #[rustc_const_stable(feature = "unchecked_shifts", since = "1.93.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline(always)] diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs index 2860bf0a6e69a..00b71f9a997c4 100644 --- a/library/core/src/ptr/const_ptr.rs +++ b/library/core/src/ptr/const_ptr.rs @@ -1462,8 +1462,8 @@ impl *const [T] { /// Gets a raw pointer to the underlying array. /// /// If `N` is not exactly equal to the length of `self`, then this method returns `None`. - #[stable(feature = "core_slice_as_array", since = "CURRENT_RUSTC_VERSION")] - #[rustc_const_stable(feature = "core_slice_as_array", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "core_slice_as_array", since = "1.93.0")] + #[rustc_const_stable(feature = "core_slice_as_array", since = "1.93.0")] #[inline] #[must_use] pub const fn as_array(self) -> Option<*const [T; N]> { diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs index f8dc6ef7ed71f..8976154c61db9 100644 --- a/library/core/src/ptr/mut_ptr.rs +++ b/library/core/src/ptr/mut_ptr.rs @@ -1712,8 +1712,8 @@ impl *mut [T] { /// Gets a raw, mutable pointer to the underlying array. /// /// If `N` is not exactly equal to the length of `self`, then this method returns `None`. - #[stable(feature = "core_slice_as_array", since = "CURRENT_RUSTC_VERSION")] - #[rustc_const_stable(feature = "core_slice_as_array", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "core_slice_as_array", since = "1.93.0")] + #[rustc_const_stable(feature = "core_slice_as_array", since = "1.93.0")] #[inline] #[must_use] pub const fn as_mut_array(self) -> Option<*mut [T; N]> { diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index f03f2045444df..edc31c04ef9b1 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -842,8 +842,8 @@ impl [T] { /// Gets a reference to the underlying array. /// /// If `N` is not exactly equal to the length of `self`, then this method returns `None`. - #[stable(feature = "core_slice_as_array", since = "CURRENT_RUSTC_VERSION")] - #[rustc_const_stable(feature = "core_slice_as_array", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "core_slice_as_array", since = "1.93.0")] + #[rustc_const_stable(feature = "core_slice_as_array", since = "1.93.0")] #[inline] #[must_use] pub const fn as_array(&self) -> Option<&[T; N]> { @@ -861,8 +861,8 @@ impl [T] { /// Gets a mutable reference to the slice's underlying array. /// /// If `N` is not exactly equal to the length of `self`, then this method returns `None`. - #[stable(feature = "core_slice_as_array", since = "CURRENT_RUSTC_VERSION")] - #[rustc_const_stable(feature = "core_slice_as_array", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "core_slice_as_array", since = "1.93.0")] + #[rustc_const_stable(feature = "core_slice_as_array", since = "1.93.0")] #[inline] #[must_use] pub const fn as_mut_array(&mut self) -> Option<&mut [T; N]> { diff --git a/library/core/src/time.rs b/library/core/src/time.rs index 51a01545f5cf5..20895c988c455 100644 --- a/library/core/src/time.rs +++ b/library/core/src/time.rs @@ -325,8 +325,8 @@ impl Duration { /// assert_eq!(10_u64.pow(15), duration.as_secs()); /// assert_eq!(321, duration.subsec_nanos()); /// ``` - #[stable(feature = "duration_from_nanos_u128", since = "CURRENT_RUSTC_VERSION")] - #[rustc_const_stable(feature = "duration_from_nanos_u128", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "duration_from_nanos_u128", since = "1.93.0")] + #[rustc_const_stable(feature = "duration_from_nanos_u128", since = "1.93.0")] #[must_use] #[inline] #[track_caller] diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 0401e9b39ff49..4f8094dc1f2fd 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -668,7 +668,7 @@ pub mod arch { pub use std_detect::is_loongarch_feature_detected; #[unstable(feature = "is_riscv_feature_detected", issue = "111192")] pub use std_detect::is_riscv_feature_detected; - #[stable(feature = "stdarch_s390x_feature_detection", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "stdarch_s390x_feature_detection", since = "1.93.0")] pub use std_detect::is_s390x_feature_detected; #[stable(feature = "simd_x86", since = "1.27.0")] pub use std_detect::is_x86_feature_detected; diff --git a/library/std_detect/src/detect/arch/mod.rs b/library/std_detect/src/detect/arch/mod.rs index 23e7a30b985bf..2be7f091c285e 100644 --- a/library/std_detect/src/detect/arch/mod.rs +++ b/library/std_detect/src/detect/arch/mod.rs @@ -60,7 +60,7 @@ cfg_select! { pub use loongarch::*; } target_arch = "s390x" => { - #[stable(feature = "stdarch_s390x_feature_detection", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "stdarch_s390x_feature_detection", since = "1.93.0")] pub use s390x::*; } _ => { diff --git a/library/std_detect/src/detect/arch/s390x.rs b/library/std_detect/src/detect/arch/s390x.rs index 6122e8f5b8377..a04283f90a025 100644 --- a/library/std_detect/src/detect/arch/s390x.rs +++ b/library/std_detect/src/detect/arch/s390x.rs @@ -9,7 +9,7 @@ features! { /// /// When the feature is known to be enabled at compile time (e.g. via `-Ctarget-feature`) /// the macro expands to `true`. - #[stable(feature = "stdarch_s390x_feature_detection", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "stdarch_s390x_feature_detection", since = "1.93.0")] @FEATURE: #[unstable(feature = "s390x_target_feature", issue = "44839")] concurrent_functions: "concurrent-functions"; /// s390x concurrent-functions facility @FEATURE: #[unstable(feature = "s390x_target_feature", issue = "44839")] deflate_conversion: "deflate-conversion"; @@ -32,30 +32,30 @@ features! { /// s390x message-security-assist-extension9 facility @FEATURE: #[unstable(feature = "s390x_target_feature", issue = "44839")] message_security_assist_extension12: "message-security-assist-extension12"; /// s390x message-security-assist-extension12 facility - @FEATURE: #[stable(feature = "s390x_target_feature_vector", since = "CURRENT_RUSTC_VERSION")] miscellaneous_extensions_2: "miscellaneous-extensions-2"; + @FEATURE: #[stable(feature = "s390x_target_feature_vector", since = "1.93.0")] miscellaneous_extensions_2: "miscellaneous-extensions-2"; /// s390x miscellaneous-extensions-2 facility - @FEATURE: #[stable(feature = "s390x_target_feature_vector", since = "CURRENT_RUSTC_VERSION")] miscellaneous_extensions_3: "miscellaneous-extensions-3"; + @FEATURE: #[stable(feature = "s390x_target_feature_vector", since = "1.93.0")] miscellaneous_extensions_3: "miscellaneous-extensions-3"; /// s390x miscellaneous-extensions-3 facility - @FEATURE: #[stable(feature = "s390x_target_feature_vector", since = "CURRENT_RUSTC_VERSION")] miscellaneous_extensions_4: "miscellaneous-extensions-4"; + @FEATURE: #[stable(feature = "s390x_target_feature_vector", since = "1.93.0")] miscellaneous_extensions_4: "miscellaneous-extensions-4"; /// s390x miscellaneous-extensions-4 facility - @FEATURE: #[stable(feature = "s390x_target_feature_vector", since = "CURRENT_RUSTC_VERSION")] nnp_assist: "nnp-assist"; + @FEATURE: #[stable(feature = "s390x_target_feature_vector", since = "1.93.0")] nnp_assist: "nnp-assist"; /// s390x nnp-assist facility @FEATURE: #[unstable(feature = "s390x_target_feature", issue = "44839")] transactional_execution: "transactional-execution"; /// s390x transactional-execution facility - @FEATURE: #[stable(feature = "s390x_target_feature_vector", since = "CURRENT_RUSTC_VERSION")] vector: "vector"; + @FEATURE: #[stable(feature = "s390x_target_feature_vector", since = "1.93.0")] vector: "vector"; /// s390x vector facility - @FEATURE: #[stable(feature = "s390x_target_feature_vector", since = "CURRENT_RUSTC_VERSION")] vector_enhancements_1: "vector-enhancements-1"; + @FEATURE: #[stable(feature = "s390x_target_feature_vector", since = "1.93.0")] vector_enhancements_1: "vector-enhancements-1"; /// s390x vector-enhancements-1 facility - @FEATURE: #[stable(feature = "s390x_target_feature_vector", since = "CURRENT_RUSTC_VERSION")] vector_enhancements_2: "vector-enhancements-2"; + @FEATURE: #[stable(feature = "s390x_target_feature_vector", since = "1.93.0")] vector_enhancements_2: "vector-enhancements-2"; /// s390x vector-enhancements-2 facility - @FEATURE: #[stable(feature = "s390x_target_feature_vector", since = "CURRENT_RUSTC_VERSION")] vector_enhancements_3: "vector-enhancements-3"; + @FEATURE: #[stable(feature = "s390x_target_feature_vector", since = "1.93.0")] vector_enhancements_3: "vector-enhancements-3"; /// s390x vector-enhancements-3 facility - @FEATURE: #[stable(feature = "s390x_target_feature_vector", since = "CURRENT_RUSTC_VERSION")] vector_packed_decimal: "vector-packed-decimal"; + @FEATURE: #[stable(feature = "s390x_target_feature_vector", since = "1.93.0")] vector_packed_decimal: "vector-packed-decimal"; /// s390x vector-packed-decimal facility - @FEATURE: #[stable(feature = "s390x_target_feature_vector", since = "CURRENT_RUSTC_VERSION")] vector_packed_decimal_enhancement: "vector-packed-decimal-enhancement"; + @FEATURE: #[stable(feature = "s390x_target_feature_vector", since = "1.93.0")] vector_packed_decimal_enhancement: "vector-packed-decimal-enhancement"; /// s390x vector-packed-decimal-enhancement facility - @FEATURE: #[stable(feature = "s390x_target_feature_vector", since = "CURRENT_RUSTC_VERSION")] vector_packed_decimal_enhancement_2: "vector-packed-decimal-enhancement-2"; + @FEATURE: #[stable(feature = "s390x_target_feature_vector", since = "1.93.0")] vector_packed_decimal_enhancement_2: "vector-packed-decimal-enhancement-2"; /// s390x vector-packed-decimal-enhancement-2 facility - @FEATURE: #[stable(feature = "s390x_target_feature_vector", since = "CURRENT_RUSTC_VERSION")] vector_packed_decimal_enhancement_3: "vector-packed-decimal-enhancement-3"; + @FEATURE: #[stable(feature = "s390x_target_feature_vector", since = "1.93.0")] vector_packed_decimal_enhancement_3: "vector-packed-decimal-enhancement-3"; /// s390x vector-packed-decimal-enhancement-3 facility } From f80e3ac62471499664d0317cf4c54d4c258037d5 Mon Sep 17 00:00:00 2001 From: Boxy Uwu Date: Mon, 8 Dec 2025 10:08:52 +0000 Subject: [PATCH 02/58] bump channel --- src/ci/channel | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ci/channel b/src/ci/channel index bf867e0ae5b6c..65b2df87f7df3 100644 --- a/src/ci/channel +++ b/src/ci/channel @@ -1 +1 @@ -nightly +beta From 51da96d7d23625c18559552f5c5649bbbc5bf215 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Sun, 7 Dec 2025 14:51:56 +0100 Subject: [PATCH 03/58] fix: Disable postcard use temporarily --- src/tools/rust-analyzer/crates/proc-macro-api/src/process.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/tools/rust-analyzer/crates/proc-macro-api/src/process.rs b/src/tools/rust-analyzer/crates/proc-macro-api/src/process.rs index e31ab86bdd2d6..d6a8d27bfc42e 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-api/src/process.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-api/src/process.rs @@ -58,7 +58,9 @@ impl ProcMacroServerProcess { if v.pre.as_str() == "nightly" { *v > VERSION } else { *v >= VERSION } }); - let formats: &[_] = if has_working_format_flag { + let formats: &[_] = if std::env::var_os("RUST_ANALYZER_USE_POSTCARD").is_some() + && has_working_format_flag + { &[ (Some("postcard-legacy"), Protocol::LegacyPostcard { mode: SpanMode::Id }), (Some("json-legacy"), Protocol::LegacyJson { mode: SpanMode::Id }), From de868f6b43bc15662028751fc74222cf616fc404 Mon Sep 17 00:00:00 2001 From: Boxy Uwu Date: Sat, 13 Dec 2025 14:31:45 +0000 Subject: [PATCH 04/58] bump stage0 --- src/stage0 | 915 +++++++++++++++++++++++------------------------------ 1 file changed, 391 insertions(+), 524 deletions(-) diff --git a/src/stage0 b/src/stage0 index 0e4e9eb1c4b92..ea0fe3bf84c47 100644 --- a/src/stage0 +++ b/src/stage0 @@ -13,528 +13,395 @@ nightly_branch=main # All changes below this comment will be overridden the next time the # tool is executed. -compiler_channel_manifest_hash=d8adf7e1722d2dc8ebdb327ee661e58a58145464bfcd9bb3cab66d652cc7bb90 -compiler_git_commit_hash=3b4dd9bf1410f8da6329baa36ce5e37673cbbd1f -compiler_date=2025-10-28 -compiler_version=beta -rustfmt_channel_manifest_hash=108599f303463cabaef3b53ab5e0c0e560a6a5a97f606d75a802efb595141baf -rustfmt_git_commit_hash=adaa838976ff99a4f0661136322f64cb466b58a0 -rustfmt_date=2025-10-28 -rustfmt_version=nightly +compiler_channel_manifest_hash=b2a49624353173ecdacf59c158c00929300606e1963f6e4609fb483a508402d0 +compiler_git_commit_hash=ded5c06cf21d2b93bffd5d884aa6e96934ee4234 +compiler_date=2025-12-11 +compiler_version=1.92.0 -dist/2025-10-28/rustc-beta-aarch64-apple-darwin.tar.gz=5d971d3a1c127d314f94f41440f0717b51692176630fef7f05a70d9bcd3bae44 -dist/2025-10-28/rustc-beta-aarch64-apple-darwin.tar.xz=2cedfc3a96acc9ebe82c5cf5bcf5355902a5726e1c28e7d50b15cfa2ee343174 -dist/2025-10-28/rustc-beta-aarch64-pc-windows-gnullvm.tar.gz=1875833b43088879444902023cc76682fa58f39520a1135e438afaacf3605f88 -dist/2025-10-28/rustc-beta-aarch64-pc-windows-gnullvm.tar.xz=a925fb02b296b8ce753ff7b1fae583a27fb2ef6de582a80f1428678a2f61a466 -dist/2025-10-28/rustc-beta-aarch64-pc-windows-msvc.tar.gz=28f423bb7db80232b887bd0d47243341a50611eca913c17c305dd55fa6bd3f12 -dist/2025-10-28/rustc-beta-aarch64-pc-windows-msvc.tar.xz=3be7d39a956afd591ba4b22785b4851fd6c0c7afd23d045c54d6b603cc14bc2d -dist/2025-10-28/rustc-beta-aarch64-unknown-linux-gnu.tar.gz=8b98b7e04ef03c3b2bc95e0d6e3a92ad7849bad8d5a8969d6c9eefe169673066 -dist/2025-10-28/rustc-beta-aarch64-unknown-linux-gnu.tar.xz=1b35688d58c10fdd1f1d02325022ae9eb36ee139f76ae753e16a0f4524d0f6d4 -dist/2025-10-28/rustc-beta-aarch64-unknown-linux-musl.tar.gz=c1de08dbaff419f08f82aef49972965d87e02054822e83e6e7f73714afbc4155 -dist/2025-10-28/rustc-beta-aarch64-unknown-linux-musl.tar.xz=2755a71cee31227e4638499dc882347ed9ecf0698cc64a177ff8a94c6ff3be8c -dist/2025-10-28/rustc-beta-arm-unknown-linux-gnueabi.tar.gz=dac50bed8e2bb5d65b5f6ea52963d2b268829c9f79800304a225e058152be0bd -dist/2025-10-28/rustc-beta-arm-unknown-linux-gnueabi.tar.xz=f818783e566cebc2ac392f923efd0ae8f51ae77ce6ade284514a57c21d288b7e -dist/2025-10-28/rustc-beta-arm-unknown-linux-gnueabihf.tar.gz=922d9d3aba6c5ac4da95ab9310d0f33ec7da4830a7d424b83d6f0181af96bccb -dist/2025-10-28/rustc-beta-arm-unknown-linux-gnueabihf.tar.xz=746a200dab88eec922dc08ea244ae818c27a0ca91360278e578ab9fc433bd3be -dist/2025-10-28/rustc-beta-armv7-unknown-linux-gnueabihf.tar.gz=ac45fe7547dc1064286de6704a9343e95fa760163247ac02ff88ebf2bf4d7d8c -dist/2025-10-28/rustc-beta-armv7-unknown-linux-gnueabihf.tar.xz=35ab727f335242d588742f79f29fb94590ac0c3bef29d012538f2e925cb9f96f -dist/2025-10-28/rustc-beta-i686-pc-windows-gnu.tar.gz=42eab38b498e0b8efd7fae51facd7caaf253e1bc341f915f978b484065e4c812 -dist/2025-10-28/rustc-beta-i686-pc-windows-gnu.tar.xz=d663982b6293285fa1ffcc5987ded64569216c0133476243b5525768cd6123bb -dist/2025-10-28/rustc-beta-i686-pc-windows-msvc.tar.gz=571eeccc9c1f25c4b9c2c6f45d15dbd9730bf6c0ac0f75a5b49652b6d4e98f68 -dist/2025-10-28/rustc-beta-i686-pc-windows-msvc.tar.xz=595a8b6b74910fa53a947ddde81f5519152f8c773a41a2f5b0d663540bc913fa -dist/2025-10-28/rustc-beta-i686-unknown-linux-gnu.tar.gz=3f2261279e5c16b0a4b572e799e2d3079aa33192e7713803214011e14c5c6707 -dist/2025-10-28/rustc-beta-i686-unknown-linux-gnu.tar.xz=c49c0e84b4b43aa6b72dc355173b4b5dc41563f3f76e882c405a8625c00befbc -dist/2025-10-28/rustc-beta-loongarch64-unknown-linux-gnu.tar.gz=92cea4e2708fbd86b35bc798b25a69ab10b62f28e972ff0624709e6e8268db60 -dist/2025-10-28/rustc-beta-loongarch64-unknown-linux-gnu.tar.xz=224f6e9896d19e00e369da70bc0e0dbd545d04033ff6ecff12b3f2d2bfe73fc8 -dist/2025-10-28/rustc-beta-loongarch64-unknown-linux-musl.tar.gz=74901d397d5f6695df197520d16851986df2a5c5d432b8f24da1a5c3a5c0474b -dist/2025-10-28/rustc-beta-loongarch64-unknown-linux-musl.tar.xz=02d8962da7234bfd365147b4177497a99c8f1f12f6841160abede61332edd35f -dist/2025-10-28/rustc-beta-powerpc-unknown-linux-gnu.tar.gz=b8d810c76102a325cdecb98e7d7fab480a8d349328ce8a275366018a627fa4bf -dist/2025-10-28/rustc-beta-powerpc-unknown-linux-gnu.tar.xz=f09c4e8d4a4ae4cf490e55bcd29ab00b6f7c1aed09c93b63f10fc3f812f415e7 -dist/2025-10-28/rustc-beta-powerpc64-unknown-linux-gnu.tar.gz=6c71850444d597cdc07a7169bd5d2564cbd99d1a34ec806ac8b818b39c9fd529 -dist/2025-10-28/rustc-beta-powerpc64-unknown-linux-gnu.tar.xz=01f3537787f41c2fd2ed1f955520ff0852bb27d899141cf44de3ae126abf8808 -dist/2025-10-28/rustc-beta-powerpc64le-unknown-linux-gnu.tar.gz=833dcfab6dc87d375154d593c8e53cd5c74b3029f8b94c753928de718185283c -dist/2025-10-28/rustc-beta-powerpc64le-unknown-linux-gnu.tar.xz=cf99a56b49b3db107d33f5c6e668310317aaeb2b2ca3c80a0ea2b30a09b453dd -dist/2025-10-28/rustc-beta-powerpc64le-unknown-linux-musl.tar.gz=55b1db794a4bb0f535e46a2c4a85eb7ea0016482b7086b6deae033746a42a69d -dist/2025-10-28/rustc-beta-powerpc64le-unknown-linux-musl.tar.xz=a741b18a92f5fa35cab2ed93d90782175b70e3ef5a127e21fde7acabb6228b59 -dist/2025-10-28/rustc-beta-riscv64gc-unknown-linux-gnu.tar.gz=97335caa2ace3f33cd959dc35f01ec8a3d2de5699518b93fd191766eda3fe318 -dist/2025-10-28/rustc-beta-riscv64gc-unknown-linux-gnu.tar.xz=2127853b7b4e2b3cf906ef292e9c7e370ec3f3760ce5576b447ed7902048794f -dist/2025-10-28/rustc-beta-s390x-unknown-linux-gnu.tar.gz=eb3df84c1a840cc69799ef0649972e5312afe59144700ba3652bd6083f48074a -dist/2025-10-28/rustc-beta-s390x-unknown-linux-gnu.tar.xz=16942680ea11ead1ab4d9d46d31389a14f237637a6877b278cd30a608446b787 -dist/2025-10-28/rustc-beta-sparcv9-sun-solaris.tar.gz=5c7848ab2b2cb181bd7f64cdbdc3b5b659b61850c14604a7977c35b9807daa48 -dist/2025-10-28/rustc-beta-sparcv9-sun-solaris.tar.xz=0f12cb118e253206ea74e7b1dabdda6e95bb0b10d47657aa4c560fa9ca28cf83 -dist/2025-10-28/rustc-beta-x86_64-apple-darwin.tar.gz=3c34e03deee0445864c7f5ebc89883db051a3c69b874a2daff658fb5dd364aba -dist/2025-10-28/rustc-beta-x86_64-apple-darwin.tar.xz=292d40e5ea57295ecd921a07fa11796771953d38793edcea9841a95e79d94ac2 -dist/2025-10-28/rustc-beta-x86_64-pc-solaris.tar.gz=6ac79775ff166ba76e663e8760ddf9625e06a28e5033d4d8cc570dcca73ca725 -dist/2025-10-28/rustc-beta-x86_64-pc-solaris.tar.xz=46c214af2c11ccb17529a991201624bad044d59c171c6f872468acb8523b6f96 -dist/2025-10-28/rustc-beta-x86_64-pc-windows-gnu.tar.gz=29067fc4a5e0f123c34a045a1b0d55f88170bc9f658584d50e32219cd5945854 -dist/2025-10-28/rustc-beta-x86_64-pc-windows-gnu.tar.xz=30c20794d0c244bd04dbd4de304ef3aea5ba11e26882f2a004680281f21e05b0 -dist/2025-10-28/rustc-beta-x86_64-pc-windows-gnullvm.tar.gz=6c6c7614b538d9bad498b3642321adf0b2b6cdd3b24706903a8eb2125c0c122a -dist/2025-10-28/rustc-beta-x86_64-pc-windows-gnullvm.tar.xz=09822c7d5bbf218d5113e902968b37719949997fd788523bf80400274f428986 -dist/2025-10-28/rustc-beta-x86_64-pc-windows-msvc.tar.gz=fcf05b8150cf7199e100f560854f6acb6874985a5cfbb00ead36914dc3fb66e9 -dist/2025-10-28/rustc-beta-x86_64-pc-windows-msvc.tar.xz=f5259f5b521ea10f093c522abd5bcec4e9dfb94ce3e384e3b53865a223e700d0 -dist/2025-10-28/rustc-beta-x86_64-unknown-freebsd.tar.gz=c3719366a9687d243483431231b86140e268bf2ce99e1ea1759a611524ea8ade -dist/2025-10-28/rustc-beta-x86_64-unknown-freebsd.tar.xz=015e02fb99098c31d502738e9e525d48ac6ca386e16f3ecb55235c7268d4abe7 -dist/2025-10-28/rustc-beta-x86_64-unknown-illumos.tar.gz=508acec5f2b092d09d55590e7fe921f7415aacc13c535532997776c4ebb86483 -dist/2025-10-28/rustc-beta-x86_64-unknown-illumos.tar.xz=f7437c9b0e747b0eccd7755a3ef551fa81194f23304ddb40ae44bca5782dda4b -dist/2025-10-28/rustc-beta-x86_64-unknown-linux-gnu.tar.gz=cd985cf21af999dbb76e25cb6c9b5ac5723e8cda8625cf511e7df2c98e7e735a -dist/2025-10-28/rustc-beta-x86_64-unknown-linux-gnu.tar.xz=d30acafe9f3ddfd25148abdd3078deaaafb6bb62f7979252e9e7880abc260b23 -dist/2025-10-28/rustc-beta-x86_64-unknown-linux-musl.tar.gz=1778c649d790e52b8462d5ea377339443e607b2434fa9b579236b465f63748c7 -dist/2025-10-28/rustc-beta-x86_64-unknown-linux-musl.tar.xz=909808e6e3a10cd3fc2c0927f47dbe4ac8de4653b4e771c9c44b8e58cbe5fe2d -dist/2025-10-28/rustc-beta-x86_64-unknown-netbsd.tar.gz=8584d5ad71c7cedcf6e64b0f83ed2cfa82346e88a1000acac677f464dbb0e6f6 -dist/2025-10-28/rustc-beta-x86_64-unknown-netbsd.tar.xz=7b85928ce5f6908ad82895097ba07fad70990b7810aa23c63725d7ecbbf54d54 -dist/2025-10-28/rust-std-beta-aarch64-apple-darwin.tar.gz=312c1121edf001f03ea169e8fff9668efd1925a45962b282b32d5f126bd6b010 -dist/2025-10-28/rust-std-beta-aarch64-apple-darwin.tar.xz=11e0fd642939358a892e66ebeea7f1737a009ad23692da486c7427cdce60c37d -dist/2025-10-28/rust-std-beta-aarch64-apple-ios.tar.gz=d7086698f3414ebf1410f79f8167ef2e4cf8e9143dc7e3704200d67e64252080 -dist/2025-10-28/rust-std-beta-aarch64-apple-ios.tar.xz=a71fd039b0bfa2fa7a1abd13c622c89371f7af273fc44b3c210b1ead6a1f9156 -dist/2025-10-28/rust-std-beta-aarch64-apple-ios-macabi.tar.gz=52795cad4c58b32c3f36fb7b596c25a8e3277c85c165e161445d1fc81e0c4200 -dist/2025-10-28/rust-std-beta-aarch64-apple-ios-macabi.tar.xz=7db4e584f7890bd05d7cf8a991f539be249e0f04526e30743575129dada977c2 -dist/2025-10-28/rust-std-beta-aarch64-apple-ios-sim.tar.gz=575b6d5185a71a4f4d29dc881f5dea5fe492d7b21a01c0bd9987cc212bb8ca25 -dist/2025-10-28/rust-std-beta-aarch64-apple-ios-sim.tar.xz=ea1c7896e21d0a89da399405611a25ec447ff71495a4b5d48501c9f8129b2a20 -dist/2025-10-28/rust-std-beta-aarch64-linux-android.tar.gz=f7a85a478dd9d55491a2395dda9539ab7898385782ef5be479362ba35e8be837 -dist/2025-10-28/rust-std-beta-aarch64-linux-android.tar.xz=4fc53a2be557540332410446f6f43f5e6339d10d8010c153d99d707df64a5ef1 -dist/2025-10-28/rust-std-beta-aarch64-pc-windows-gnullvm.tar.gz=99b3f95696883f18e3734d02c75a5dc91edac003b6d9627c5a32baac41f3c69c -dist/2025-10-28/rust-std-beta-aarch64-pc-windows-gnullvm.tar.xz=375db4717baaac6a784d8f53f84035f99d5f76f9a3f7df7dd385ee2d93027368 -dist/2025-10-28/rust-std-beta-aarch64-pc-windows-msvc.tar.gz=b650ca7708ae5b05fc82c7aa483f9aaa42be83d6bcc6c524690da745f32f6f60 -dist/2025-10-28/rust-std-beta-aarch64-pc-windows-msvc.tar.xz=1683d5a33387dd546ff641222b501e90049241df0f52c2f1a5dc568b35594135 -dist/2025-10-28/rust-std-beta-aarch64-unknown-fuchsia.tar.gz=3e2d64dd8d2fdedb30b25f899f8ed8deff653c4d3f3f7e16e534ab7e1eec8a66 -dist/2025-10-28/rust-std-beta-aarch64-unknown-fuchsia.tar.xz=e83d63666e0372f27d404a4ddf48de7abc5b646d9f087ebf8856bcbfe6f86362 -dist/2025-10-28/rust-std-beta-aarch64-unknown-linux-gnu.tar.gz=8a99f5fbaf869f68bced6435acf18127ac8880193fb23e44cb5791546bc795d7 -dist/2025-10-28/rust-std-beta-aarch64-unknown-linux-gnu.tar.xz=53be5ecbcb4d47e6a1fb811a6e8b4ecec7fd6ae2b6efac7d9934dee4cfb19dce -dist/2025-10-28/rust-std-beta-aarch64-unknown-linux-musl.tar.gz=f61af59bc40a53dddf0a85b5205bec90d287a41ee3ac32345a97d21861ae6546 -dist/2025-10-28/rust-std-beta-aarch64-unknown-linux-musl.tar.xz=9ed2894300f6ac917ac33d0724133ba2fada2ab2e42a0b21a9bd994d70c942f4 -dist/2025-10-28/rust-std-beta-aarch64-unknown-linux-ohos.tar.gz=70ad473c7d4934bab123afb8cff98773993fdbb73b4941f6022a25ef2942a223 -dist/2025-10-28/rust-std-beta-aarch64-unknown-linux-ohos.tar.xz=d0a06230a38c725ceed103c89e8031b541b7bc15a3646a1a3662d8147901b2fd -dist/2025-10-28/rust-std-beta-aarch64-unknown-none.tar.gz=90d4484a1e390e0d3edf25331d41f9b419730bd2e318e8927c4a891b2c035652 -dist/2025-10-28/rust-std-beta-aarch64-unknown-none.tar.xz=5b795b7378b6753fb2a8ea0ecef760009ffa05c9a4778815d2d2b4085baffe14 -dist/2025-10-28/rust-std-beta-aarch64-unknown-none-softfloat.tar.gz=52d0e13f1dc2083787d3294d5c3569b11227724ab4ced4ba9905ac0a5f25bde0 -dist/2025-10-28/rust-std-beta-aarch64-unknown-none-softfloat.tar.xz=981dca064b73d6617039bb35a32a17111445bc1ed9ba957525d227d3be9e8f6d -dist/2025-10-28/rust-std-beta-aarch64-unknown-uefi.tar.gz=fbb7066da0824513e4441bb59d4c6a6d4c8bc34f67ed79f67da3b8ec69ff3a4c -dist/2025-10-28/rust-std-beta-aarch64-unknown-uefi.tar.xz=c0bb51d8c513c0b5d597cbc00260bf2764595b12244906606c20ae6f98e0fc66 -dist/2025-10-28/rust-std-beta-arm-linux-androideabi.tar.gz=7cd5763f202c5679dc1bdc0e6551dc8093ee95a9b2d405ad8cbd31fcf232332c -dist/2025-10-28/rust-std-beta-arm-linux-androideabi.tar.xz=126b3a04432a3f6f5f1aef6f5e22deec98629da4a0809b0c7739911ae5e4b6cc -dist/2025-10-28/rust-std-beta-arm-unknown-linux-gnueabi.tar.gz=01bc31ad9812edeb11dc4b6c15d4bf80a325e286390829babd85176b91c38cfa -dist/2025-10-28/rust-std-beta-arm-unknown-linux-gnueabi.tar.xz=0b1c799856c8314afddfaa5109535535c36df31bb9188a319c1e45f4968a7079 -dist/2025-10-28/rust-std-beta-arm-unknown-linux-gnueabihf.tar.gz=8792d0115ba1d9b0e3bfefbd7a9ddf7859f7bbf8431ef32530b05ec7cf9c68b8 -dist/2025-10-28/rust-std-beta-arm-unknown-linux-gnueabihf.tar.xz=fc470db282fb0fab537e4b93a9498d4b4fc65cf014536905654cc2c14f82d245 -dist/2025-10-28/rust-std-beta-arm-unknown-linux-musleabi.tar.gz=fe82493d2a7f4a9566916beefcd7fb26301bd13b8b838b5251398ecac0c867ef -dist/2025-10-28/rust-std-beta-arm-unknown-linux-musleabi.tar.xz=b7cd0514db083e115d8aacceb3f7998da11f26e9f2be44137e8af2e2f9ac786e -dist/2025-10-28/rust-std-beta-arm-unknown-linux-musleabihf.tar.gz=0adc4e2e0f5bee4c28c81ba2cfd9796268e830d23b23b80c71121c30f08e3326 -dist/2025-10-28/rust-std-beta-arm-unknown-linux-musleabihf.tar.xz=8c98799e7b4c454cad130d0eb87e8ed59e0e7e64bb0513af8beb6d1d5f8e3ac7 -dist/2025-10-28/rust-std-beta-arm64ec-pc-windows-msvc.tar.gz=bb1da273578b508b9f397074438ecb2527a729e404d2820bd34d67dc8824106a -dist/2025-10-28/rust-std-beta-arm64ec-pc-windows-msvc.tar.xz=e004d91a9732284851d613a3c488909bc7d457b2053a1af45710aa4bbe3169e9 -dist/2025-10-28/rust-std-beta-armv5te-unknown-linux-gnueabi.tar.gz=7e6b5d4266306001366003cdc4fd4b60d700e86ec5dce01b58b0e73bd6a50c42 -dist/2025-10-28/rust-std-beta-armv5te-unknown-linux-gnueabi.tar.xz=170b32ea83d21436e744d11a56ea8e298278f8b9aa58fd82d6d788ff1e3258f3 -dist/2025-10-28/rust-std-beta-armv5te-unknown-linux-musleabi.tar.gz=8ee71b71a8e90b21d580f9e64cc115f182db8582cd6238f946e24fc32de27e65 -dist/2025-10-28/rust-std-beta-armv5te-unknown-linux-musleabi.tar.xz=9319475d974dce729182c3d99696bd5cf6a36257b1b80186f261d2885610ddb9 -dist/2025-10-28/rust-std-beta-armv7-linux-androideabi.tar.gz=71db2b02df33e229899f0dafc675572f2b4041400954f9145796edee7cd923d4 -dist/2025-10-28/rust-std-beta-armv7-linux-androideabi.tar.xz=0f331806b4523d61204f38f2d7ddd07e6f3dcda8a15806a9f01cb1747a587e8f -dist/2025-10-28/rust-std-beta-armv7-unknown-linux-gnueabi.tar.gz=52f331579373b749fb1c7a6302a770a4be33008cdd9db4a5640208ba1ba7b540 -dist/2025-10-28/rust-std-beta-armv7-unknown-linux-gnueabi.tar.xz=1e8c5dcc4cb672c4e8ba2862549cd281ea6802fb73701c885eaf5423673ab233 -dist/2025-10-28/rust-std-beta-armv7-unknown-linux-gnueabihf.tar.gz=2d0dded898f567cbfa5605dcc09b1e44970e345a030ef91c806eafcac4470258 -dist/2025-10-28/rust-std-beta-armv7-unknown-linux-gnueabihf.tar.xz=3a63913c874f30c8a68d5cbb62dc654ec9c3bf2f4488e1098034f60c51824bb7 -dist/2025-10-28/rust-std-beta-armv7-unknown-linux-musleabi.tar.gz=24c341427a9b5a4d883e7f322a9c7760446896e8c2eeb1f8654b80cef00db6ea -dist/2025-10-28/rust-std-beta-armv7-unknown-linux-musleabi.tar.xz=53c5607351479ad76c3450bcc81353633f2587aafda473487bb11e42f80d8523 -dist/2025-10-28/rust-std-beta-armv7-unknown-linux-musleabihf.tar.gz=beda2ede28453b81588d639c18b36fa6e935e586723159e39ab9b714291c680a -dist/2025-10-28/rust-std-beta-armv7-unknown-linux-musleabihf.tar.xz=f175a55fc81159e9a40407b1d97ea658239014cf0f5191a3533318e53ee1ff7f -dist/2025-10-28/rust-std-beta-armv7-unknown-linux-ohos.tar.gz=db1f0cfd65d795d23a60d29e44f24e6174a0a516b998e65bd1964230c9c6c03c -dist/2025-10-28/rust-std-beta-armv7-unknown-linux-ohos.tar.xz=264efedfd340c095dfe08fc95a35c36392eda0d1c2c179e56c75b27685b90d7e -dist/2025-10-28/rust-std-beta-armv7a-none-eabi.tar.gz=578fe97f24afa73c155290bf7386594e8b18a4652f54477d7a4e3f6f3ada0b5a -dist/2025-10-28/rust-std-beta-armv7a-none-eabi.tar.xz=a373109143f701d266ba53b3fff32206d88f5dfabdd888ac988606fade0b4928 -dist/2025-10-28/rust-std-beta-armv7a-none-eabihf.tar.gz=b3d6ec33c14a034c621aaf7de6ec81f0a916e18f5acc933713cc479fc21af755 -dist/2025-10-28/rust-std-beta-armv7a-none-eabihf.tar.xz=6550b2a97ce84884aa0da9133b81703e08b6e57b65c2e93f310fad2559ea4a08 -dist/2025-10-28/rust-std-beta-armv7r-none-eabi.tar.gz=b50984f65ee8a9e8c1b62158d8e91cb976f7c36f6ebc3c70ccfcab2a3da26533 -dist/2025-10-28/rust-std-beta-armv7r-none-eabi.tar.xz=0227fe58cacca86a04d85860a1de852a29ab9ac1bfea7bc50c2f560b73951d8b -dist/2025-10-28/rust-std-beta-armv7r-none-eabihf.tar.gz=da5e26a7cb5b91d3b8ec4f1a02c81b0f538dbb416e10e9453f3fd9d5cfc08129 -dist/2025-10-28/rust-std-beta-armv7r-none-eabihf.tar.xz=9132e8a69bf5dbd144def8bc647c659304fa785612a0f68f2e1a2df5dc195e33 -dist/2025-10-28/rust-std-beta-armv8r-none-eabihf.tar.gz=a312253ad16ccffacd0d840cba85d290fb5d2580865de99887990eff96f58b45 -dist/2025-10-28/rust-std-beta-armv8r-none-eabihf.tar.xz=474813a75bd586e562cf76705bdabf37a915cda6edb45afe029cbcbe54be3cb5 -dist/2025-10-28/rust-std-beta-i586-unknown-linux-gnu.tar.gz=4be0898bb9da3e8d75cb9b4851d5119efdd3136eb10cf31a42109f188781b6ea -dist/2025-10-28/rust-std-beta-i586-unknown-linux-gnu.tar.xz=5a51fb1f2da0dd645c1eb6ce19f37f16f356042ba176ab109f8bcd4ad3514ad3 -dist/2025-10-28/rust-std-beta-i586-unknown-linux-musl.tar.gz=96f621043d426d00f6baec72f66db5d91940215ba3e6985bb823c7b02acbd7ff -dist/2025-10-28/rust-std-beta-i586-unknown-linux-musl.tar.xz=2e62b9a670e3ca1d892ab18da1cd4b2bd946395e35c3b7829dd4b03726a73e4c -dist/2025-10-28/rust-std-beta-i686-linux-android.tar.gz=6c3b0e8796cb87e1a0369b55a91e49d5129af929deb4b63a623cf68219679543 -dist/2025-10-28/rust-std-beta-i686-linux-android.tar.xz=682747e9ab2706e90b5071ce13e8bff21160987d42ed0565f8e0012acded5f40 -dist/2025-10-28/rust-std-beta-i686-pc-windows-gnu.tar.gz=e7afe1e6ccb84fcf03114a6a3fd7232b40d7b2005f31a00a02d9c8e092af8b5d -dist/2025-10-28/rust-std-beta-i686-pc-windows-gnu.tar.xz=99d64d295d7bc0befe84a1da5d888de3ee0daa67a027c8628f78c36ab53eb7b4 -dist/2025-10-28/rust-std-beta-i686-pc-windows-gnullvm.tar.gz=1b36e3979b73348b46a01961a2515bc6ae19a54924e63272cb1bca709a07bcf0 -dist/2025-10-28/rust-std-beta-i686-pc-windows-gnullvm.tar.xz=f579f144f9f653df8be318e4f5ba363116a538b840030d3cd5305f87e03b9e23 -dist/2025-10-28/rust-std-beta-i686-pc-windows-msvc.tar.gz=79de79f2ed569a93dcd57aba35c7995582dde8b633bafbf0fc43ab6a8fb9d152 -dist/2025-10-28/rust-std-beta-i686-pc-windows-msvc.tar.xz=8c3fdbeb815085aaa9d484f1b22d0adbcc829a88511df5930bb518b139d20801 -dist/2025-10-28/rust-std-beta-i686-unknown-freebsd.tar.gz=d25fbb684148778444743e9d651a6d36dc4527d42367bfa67eebc43200e6cc0f -dist/2025-10-28/rust-std-beta-i686-unknown-freebsd.tar.xz=32c6d84e419a72cb862294a110fc79a88b123c4180a3a64bd53c38b200c60f9a -dist/2025-10-28/rust-std-beta-i686-unknown-linux-gnu.tar.gz=577cec0f5fb83cd22a9256dcf7c74529d95572976f102a8a63eb1cb9550f0a6c -dist/2025-10-28/rust-std-beta-i686-unknown-linux-gnu.tar.xz=dc537d7c09efaeb054d2954689842c813b5e9d646fcad912005f4b10e137181d -dist/2025-10-28/rust-std-beta-i686-unknown-linux-musl.tar.gz=5713f1784a424f509f47f70e0bce2bf8ae82e1a16efab8cd771677988b37516b -dist/2025-10-28/rust-std-beta-i686-unknown-linux-musl.tar.xz=1a3dc46f4cb4e4c8e4f96e9835b1188242addcb7a5a8ebbe3ef614c3aef862c4 -dist/2025-10-28/rust-std-beta-i686-unknown-uefi.tar.gz=4c32dcb28c1fbaeb910c9c7c60ea7dfe50e6556663eb3f002b66ec3ed42bd7ed -dist/2025-10-28/rust-std-beta-i686-unknown-uefi.tar.xz=1683c1c2838a2693b2f08a9daf0626675623d6bccbc4c996fcda8489eac853a1 -dist/2025-10-28/rust-std-beta-loongarch64-unknown-linux-gnu.tar.gz=401945e68f2246d1f502d4ac63666d5443ca7fa2f81ce38e76fbb0647fed4643 -dist/2025-10-28/rust-std-beta-loongarch64-unknown-linux-gnu.tar.xz=9b8d7d2f8a4ebf1369718d8bd3ae6973c977cdcb7030ccea0542f9e28970c281 -dist/2025-10-28/rust-std-beta-loongarch64-unknown-linux-musl.tar.gz=ae351e8f921f0c3b8bcccafa0c84402e15ced7591debf82287e63bac0965801b -dist/2025-10-28/rust-std-beta-loongarch64-unknown-linux-musl.tar.xz=7d64ee15508ebb610abe61e1aa03607140302fdbe41200e82070be85312d4a07 -dist/2025-10-28/rust-std-beta-loongarch64-unknown-none.tar.gz=9f951f51a32a4f037f3548935a07208e14f3e67d29100954ae6fbf61a8e56c06 -dist/2025-10-28/rust-std-beta-loongarch64-unknown-none.tar.xz=80494d9d9e02d7a6f56a638d93253d087a4edb83d4662b4771bd1d5c2cba97b3 -dist/2025-10-28/rust-std-beta-loongarch64-unknown-none-softfloat.tar.gz=f23fd6331ba600a3a4350565ad11f51129ad13a248f35c37b9d485fab725b4ac -dist/2025-10-28/rust-std-beta-loongarch64-unknown-none-softfloat.tar.xz=03d765256191ab9fac9f37102fa4252f7efb05261c8d2464745826232351dcd7 -dist/2025-10-28/rust-std-beta-nvptx64-nvidia-cuda.tar.gz=509bcbeb245d69fcb828bf9f3fa4413d1d4d59a0e85ed28c4f412929c734aacf -dist/2025-10-28/rust-std-beta-nvptx64-nvidia-cuda.tar.xz=543aa41bd2ae544c0114cca0e5a50c15eb7ed78d3d132bf5b48f93f2f92b502d -dist/2025-10-28/rust-std-beta-powerpc-unknown-linux-gnu.tar.gz=d67670d0b9385f4433635a473548031d083fe14e1a407766fb1ae5c4762da93e -dist/2025-10-28/rust-std-beta-powerpc-unknown-linux-gnu.tar.xz=e2f403936d191b38347bbad4e9b9bd66270b23e9df238ba9b5d52f81aaebfdb8 -dist/2025-10-28/rust-std-beta-powerpc64-unknown-linux-gnu.tar.gz=15ef51a8fc10b2298db444d68130ef350414722133097d670b8106e8de68609b -dist/2025-10-28/rust-std-beta-powerpc64-unknown-linux-gnu.tar.xz=515151364a93fc458ab5f11831797d2d708b22d9a71c78f717cf89e4e593417a -dist/2025-10-28/rust-std-beta-powerpc64le-unknown-linux-gnu.tar.gz=8ea0204c3ac93828c5a72f671c12167d0b5120cde99bb797c8d839caeb3ba3d8 -dist/2025-10-28/rust-std-beta-powerpc64le-unknown-linux-gnu.tar.xz=138969d2a43b6c4d736a950f8ba5bc0ed5fc7868c7044623d389d8278727e759 -dist/2025-10-28/rust-std-beta-powerpc64le-unknown-linux-musl.tar.gz=a3423e7917b59232faaf855ad9b9cd3b23e5d2188aeb8636e2cef324d405beb4 -dist/2025-10-28/rust-std-beta-powerpc64le-unknown-linux-musl.tar.xz=36914d3ce6a2e5a56a2a394d2c5a461a7c8a40fc235b3552a658ab1ed7d786f6 -dist/2025-10-28/rust-std-beta-riscv32i-unknown-none-elf.tar.gz=dbc0b69f7eba79726bc08a0a6b357f9d818623d3cbe153dff5f2fcb31aeea61b -dist/2025-10-28/rust-std-beta-riscv32i-unknown-none-elf.tar.xz=39def1e42a80080159347b5e85bc666830a3a346c9b0e83eea8207e94659ed94 -dist/2025-10-28/rust-std-beta-riscv32im-unknown-none-elf.tar.gz=7aebf847c08b0eee42c77da8defc6b30439f4b6d29e4122802f02d029518a31e -dist/2025-10-28/rust-std-beta-riscv32im-unknown-none-elf.tar.xz=35c49b2df4b3e18e0ec8ac20ec8b9a4a81b69f026921d85a666e0a97a671045b -dist/2025-10-28/rust-std-beta-riscv32imac-unknown-none-elf.tar.gz=b10e9e0a0457db1441a9bfeb3c4b9a8b2af4d33518bc58a8ee1d3fa7546c0bb5 -dist/2025-10-28/rust-std-beta-riscv32imac-unknown-none-elf.tar.xz=8e210b59b95b3c8db109d978ea73a540478315fb49d4515ccf248aafa7517617 -dist/2025-10-28/rust-std-beta-riscv32imafc-unknown-none-elf.tar.gz=e2bfdac9e858f144db5e9ae79b494f1e09b2a012b18f0eaac96ce684a6a43e25 -dist/2025-10-28/rust-std-beta-riscv32imafc-unknown-none-elf.tar.xz=6d2f5e60af9f6824fe2078a58a6cb804e61116e4848e1502289e08b0b9a5196c -dist/2025-10-28/rust-std-beta-riscv32imc-unknown-none-elf.tar.gz=382f448ea95627ee9fbb3d42c32ab9ecffe21ea12c00810e4eb8e94553d463a9 -dist/2025-10-28/rust-std-beta-riscv32imc-unknown-none-elf.tar.xz=ad7f534565c1b97495bf29054c202d8fada0a0ddfa0cca110c14a8221c654cb9 -dist/2025-10-28/rust-std-beta-riscv64gc-unknown-linux-gnu.tar.gz=7c8cf6afaa4edb589259dcc61ec5e1e667a5deeace8e277f752a433f20bcbf8d -dist/2025-10-28/rust-std-beta-riscv64gc-unknown-linux-gnu.tar.xz=8a396e9db63f1352bfde7a0d51446dabe6873c9a0a46e3c74f59ee775092e2af -dist/2025-10-28/rust-std-beta-riscv64gc-unknown-linux-musl.tar.gz=551d398055ee522ec4a67a9173daca7a1f0f537ab006383ed2ada6b00cc81cbc -dist/2025-10-28/rust-std-beta-riscv64gc-unknown-linux-musl.tar.xz=cf08dcb74f961bff041ad52efcae0c8e239e6439ecdcb32f869eb57b1a3aea1d -dist/2025-10-28/rust-std-beta-riscv64gc-unknown-none-elf.tar.gz=fd4e49a23ea0d512ed32bbaaefc1e5ea32c837e9a371513b94643966afabc521 -dist/2025-10-28/rust-std-beta-riscv64gc-unknown-none-elf.tar.xz=10700fa42e00a3b58ddcd664c0179016b837b43a31476fe4c56e8124619e4a22 -dist/2025-10-28/rust-std-beta-riscv64imac-unknown-none-elf.tar.gz=ea2f2873255dcc73185490b2c396abb4bcd5f1623f7749f77885426f753ce29f -dist/2025-10-28/rust-std-beta-riscv64imac-unknown-none-elf.tar.xz=7c02315d003cf65ac1246e3ac21b6da39cb1d99e61078ba9941647ae48bf9aa5 -dist/2025-10-28/rust-std-beta-s390x-unknown-linux-gnu.tar.gz=008321f0ccd9b96e77829b709c2683c0053acbb19ae86f2fccef49c2cb964531 -dist/2025-10-28/rust-std-beta-s390x-unknown-linux-gnu.tar.xz=047db35903bec7fee6c1d9deee5b4dc21db546a06e11c30d8372ffaf09814c59 -dist/2025-10-28/rust-std-beta-sparc64-unknown-linux-gnu.tar.gz=19677dc6495a139eac6c5827cb765e54e3b099d64f83e92273190f09ead7dab7 -dist/2025-10-28/rust-std-beta-sparc64-unknown-linux-gnu.tar.xz=d5815d1eb4906a442da0a0b56fe61cf94767dda29479da447d94a23803f9cf0e -dist/2025-10-28/rust-std-beta-sparcv9-sun-solaris.tar.gz=184424d0d18c2c49ce1c819e49804d7667edf2bce34fafedd4eeb6d4f427ae5e -dist/2025-10-28/rust-std-beta-sparcv9-sun-solaris.tar.xz=30ad3f9e3eaf48af0eb700d528b330118ad39f221a7beaab1a42e52b1ffa8531 -dist/2025-10-28/rust-std-beta-thumbv6m-none-eabi.tar.gz=c9a72ea7a13651f1b9bc6e509d9d6d32e56a4659d541e20f571ef9f6dd858480 -dist/2025-10-28/rust-std-beta-thumbv6m-none-eabi.tar.xz=6dd3a25ee5060cdf4631d8b0b7f16aa569bf611ef392d93826e88846053779e5 -dist/2025-10-28/rust-std-beta-thumbv7em-none-eabi.tar.gz=ccf8d09ba0bed60fecc775689649f2de31bab68cff273d796378d213c9d1e44a -dist/2025-10-28/rust-std-beta-thumbv7em-none-eabi.tar.xz=b7a972a9b972a2e0665387cd825491bf0ee9581ff26a586806c986014f0ae742 -dist/2025-10-28/rust-std-beta-thumbv7em-none-eabihf.tar.gz=26baa00580268fb5b7aba63a069c187dcca43dcf29161a0c1b849ef3765bbbda -dist/2025-10-28/rust-std-beta-thumbv7em-none-eabihf.tar.xz=dcd67a3ad1f2c553fb90009c630a8edcd8f571e28e5fcef0ade63c624fa11037 -dist/2025-10-28/rust-std-beta-thumbv7m-none-eabi.tar.gz=cef72caa89fcd3d48c070b1aae2fe85f29547c9b615446af2d51767ef42b5045 -dist/2025-10-28/rust-std-beta-thumbv7m-none-eabi.tar.xz=70ad20d0016c6c81b4526ccf89bbd96f4bc0a97b904b2c06487fd0a0368d7a17 -dist/2025-10-28/rust-std-beta-thumbv7neon-linux-androideabi.tar.gz=f22aeb9cdd40a4a465525fca7e6520aaa74b5fbfb41f45777e1376742f711c59 -dist/2025-10-28/rust-std-beta-thumbv7neon-linux-androideabi.tar.xz=48410a5a2f05c80f3d76b9f0b3e0eb89521495b273a854b40386048f27b553c2 -dist/2025-10-28/rust-std-beta-thumbv7neon-unknown-linux-gnueabihf.tar.gz=a791f5442467819c154f943c3126de1dd8f5fdd6b62527aadd88260ecb8c380b -dist/2025-10-28/rust-std-beta-thumbv7neon-unknown-linux-gnueabihf.tar.xz=cf43ec766a353cad48150d47d108d8df4b1561101b2c95241b909d4a5ec47bce -dist/2025-10-28/rust-std-beta-thumbv8m.base-none-eabi.tar.gz=3699e5b727abc016ab9fa78f40655ef7d88ff157e46759297cd80e5c169136f8 -dist/2025-10-28/rust-std-beta-thumbv8m.base-none-eabi.tar.xz=a6942c04a569f68cf1c5126e520400c51dfccd9e18a1d3941e28d7a8e63ae648 -dist/2025-10-28/rust-std-beta-thumbv8m.main-none-eabi.tar.gz=eb27f46d3ee51e4f71316a75087d4ca2493f55ed5e0b720f0dfa3564c8f19a67 -dist/2025-10-28/rust-std-beta-thumbv8m.main-none-eabi.tar.xz=f50b7fa2830844fd27041ced4c96eaa68ae6595b370eef1c958e3542c718d5aa -dist/2025-10-28/rust-std-beta-thumbv8m.main-none-eabihf.tar.gz=398556eca8a50c1d905ef7e2bf3f25d75f8dcf1d9b679af87b565f5f58af5c2b -dist/2025-10-28/rust-std-beta-thumbv8m.main-none-eabihf.tar.xz=8dc4a5036cfda5725120a8d7e7d0cd05151230ed967ff77fa028c4b73dde6885 -dist/2025-10-28/rust-std-beta-wasm32-unknown-emscripten.tar.gz=212f761263b9a4c72a53aba0b76986f70b3d624557f34d36af2e7d935702359d -dist/2025-10-28/rust-std-beta-wasm32-unknown-emscripten.tar.xz=89c0dae14955afab89b8fa2892944325ff154987c863fd36f93089f29ef993b6 -dist/2025-10-28/rust-std-beta-wasm32-unknown-unknown.tar.gz=92159d52588bb1ca6346025f894dce5520b42d89cb54a78a3ff42ee119c1e90b -dist/2025-10-28/rust-std-beta-wasm32-unknown-unknown.tar.xz=a187e36833f587ad5f117b012a5d9ddacb3122b39b902bc2a9d9d03b5aba27a2 -dist/2025-10-28/rust-std-beta-wasm32-wasip1.tar.gz=fa8971fcd7c22f5d382f4239fa8742238ec967f70fa40180ac9d8a39bffc28b3 -dist/2025-10-28/rust-std-beta-wasm32-wasip1.tar.xz=0603acb7e6fa5540fb458cf363fe473889b0abba91ec0c124ce380ffb1869cbf -dist/2025-10-28/rust-std-beta-wasm32-wasip1-threads.tar.gz=7651d409d4a89dab576cabf51cdd2947f877b77f09f668c6f9b8826dccd5c322 -dist/2025-10-28/rust-std-beta-wasm32-wasip1-threads.tar.xz=a6c3bc7f7f2e6a4cee6db2aa16f74af80cdd17ca92dcfcb1ab1e0c06bbaddd79 -dist/2025-10-28/rust-std-beta-wasm32-wasip2.tar.gz=77537c7a4518e62cb592e5e9d41df02d1ec8a3038b87cdfe082c98ae578973d5 -dist/2025-10-28/rust-std-beta-wasm32-wasip2.tar.xz=794a3c2e08edd74b7a004489017172c30a3242f7f0c5538c3b033937787da332 -dist/2025-10-28/rust-std-beta-wasm32v1-none.tar.gz=746ac6eb726ea2d2996b68be881d5c5fbeeba2bec1fbe57e6c315d4953cccba1 -dist/2025-10-28/rust-std-beta-wasm32v1-none.tar.xz=8bdbcf0cc2b598cbb2098f113128e6f94085dfdaea3ed3d5e15cfd0a82262b56 -dist/2025-10-28/rust-std-beta-x86_64-apple-darwin.tar.gz=2082bcdfd0e837163aec012cba1ae674825f52f5891c8cf3d4d00c619d5bd27b -dist/2025-10-28/rust-std-beta-x86_64-apple-darwin.tar.xz=b2267e0df76f21bcfbb55ab323c58015501d3a3060c4127a005e29fa0e628a7b -dist/2025-10-28/rust-std-beta-x86_64-apple-ios.tar.gz=6a48b60d0aa883ffad612a657d9de232ad1df92f937a5166532a7ee4e655fcc7 -dist/2025-10-28/rust-std-beta-x86_64-apple-ios.tar.xz=81ee2cdad7fd25b56be24d919268d0dc61c1d44d50bccb4c1811e30e85b97869 -dist/2025-10-28/rust-std-beta-x86_64-apple-ios-macabi.tar.gz=01d5952f0970508064fa24196e126cb09aca5085ad6258c53397c3b23b006217 -dist/2025-10-28/rust-std-beta-x86_64-apple-ios-macabi.tar.xz=3c10717be0087060ffb0e5b83c86ce69bff8b0dee9dee95b1be6a44f4238b5c5 -dist/2025-10-28/rust-std-beta-x86_64-fortanix-unknown-sgx.tar.gz=ce87a282ea73eb83015a321b208abfa9d4afdf4a797c799d9efeb1a246e4a64d -dist/2025-10-28/rust-std-beta-x86_64-fortanix-unknown-sgx.tar.xz=5c8866ec1cb4ec7826a94510c00f5cbc7f31822dd7e01ec2fe6b781b25e2afa8 -dist/2025-10-28/rust-std-beta-x86_64-linux-android.tar.gz=19538e0dd74d638b3ac1ac9ed679b8ebc6c058f661d7f167f957eb0866f7cb65 -dist/2025-10-28/rust-std-beta-x86_64-linux-android.tar.xz=15554ba8cc8d1d1c4c46e0438503170aff5a5519eb8bedef07a32d187ca32915 -dist/2025-10-28/rust-std-beta-x86_64-pc-solaris.tar.gz=41a6db659dff188414e33595448dc9c2b99103dbbdedab53d74c6aeccbb76458 -dist/2025-10-28/rust-std-beta-x86_64-pc-solaris.tar.xz=2bbcb13b8271c39a48ac2774e7444fdce883a283622400085623c161f8be405d -dist/2025-10-28/rust-std-beta-x86_64-pc-windows-gnu.tar.gz=e2390bf5da8a91f056df7133020d053d5d90c84c81763738efe8a862864318ae -dist/2025-10-28/rust-std-beta-x86_64-pc-windows-gnu.tar.xz=5d6fb692f2a1d2bad7b550b79e1288223ec598a46975848d07f2a5105b36cb4d -dist/2025-10-28/rust-std-beta-x86_64-pc-windows-gnullvm.tar.gz=30c66f64c7343388f3205e172e64e51dc2930214fae46eb3b21648285092c944 -dist/2025-10-28/rust-std-beta-x86_64-pc-windows-gnullvm.tar.xz=25788901f6fc13a4963bba4e985d619e0739b1239a5679406229a2bd5eaafbaa -dist/2025-10-28/rust-std-beta-x86_64-pc-windows-msvc.tar.gz=9fab4a6cc38c2f06113ae9f0620e40ff5e9134f83562c32576c1e82048ad3bc8 -dist/2025-10-28/rust-std-beta-x86_64-pc-windows-msvc.tar.xz=1b7007f9bc3619cfba09bfa92c3b1e5460316501fee4ae7c8492703a79517f4a -dist/2025-10-28/rust-std-beta-x86_64-unknown-freebsd.tar.gz=461036ed77e332851e88fb6f0f5c64068aef0b177b27662f326d157c06c7115a -dist/2025-10-28/rust-std-beta-x86_64-unknown-freebsd.tar.xz=fd7c7b75a50833650f131a6a676df90dcd57c4784654aee12ce594846da1c219 -dist/2025-10-28/rust-std-beta-x86_64-unknown-fuchsia.tar.gz=882fe895b376384d9b1b1d9c01d9b641ab56b1405d63d7a83266f228b4b759d7 -dist/2025-10-28/rust-std-beta-x86_64-unknown-fuchsia.tar.xz=e9d1fdbd0ba327b6d4e618622c0336eb6895e0e188005423710d514e145baac7 -dist/2025-10-28/rust-std-beta-x86_64-unknown-illumos.tar.gz=aade9f95b362cf13ee48e1d7608eb8487229cf86cc72082afe21fef533e45f5d -dist/2025-10-28/rust-std-beta-x86_64-unknown-illumos.tar.xz=de92c9cf00a2413d5481e96e1db5157c5cb3814851951076e4881b9269651cb9 -dist/2025-10-28/rust-std-beta-x86_64-unknown-linux-gnu.tar.gz=04f6feb37de8305d17e7aacc6174395bd55447340963303767c5a66a63200149 -dist/2025-10-28/rust-std-beta-x86_64-unknown-linux-gnu.tar.xz=2838910a0ef0084245a69fefdc67845ea579f49629cd24fa051b4db0bdc76d98 -dist/2025-10-28/rust-std-beta-x86_64-unknown-linux-gnux32.tar.gz=d2f88d608fdccd0aecbcd83cc184d157d93159e29ad525583188013f327572d1 -dist/2025-10-28/rust-std-beta-x86_64-unknown-linux-gnux32.tar.xz=b5e7ae18377727f93fece51d9ee5704ffd5a9ccd00c540b38ebbf3b9155cf20a -dist/2025-10-28/rust-std-beta-x86_64-unknown-linux-musl.tar.gz=40a52cf3527090a12095b0ed4ad8d35fa5e3cef39146a9a8bff9009cf5772dc1 -dist/2025-10-28/rust-std-beta-x86_64-unknown-linux-musl.tar.xz=28be865d06f9bd744aaad2e82ab8bdb87045e6e2d7ee6fceef2024fa620ba920 -dist/2025-10-28/rust-std-beta-x86_64-unknown-linux-ohos.tar.gz=e0afdd5422adac97fe8c6943470a8561847a614d3e367cb983f28250c0e2e34c -dist/2025-10-28/rust-std-beta-x86_64-unknown-linux-ohos.tar.xz=3007d13a0640d915eca622260c6b8b6a8936788a1228011b90df817b6888155c -dist/2025-10-28/rust-std-beta-x86_64-unknown-netbsd.tar.gz=1744c2485854792601518dcf7855d4223db63e9f3693e2d06c1ac285b92ba33b -dist/2025-10-28/rust-std-beta-x86_64-unknown-netbsd.tar.xz=757803d3cfb8db12dd7c9528852c1e28fb3a9ba97e4230d1e29dbf1834cf3f84 -dist/2025-10-28/rust-std-beta-x86_64-unknown-none.tar.gz=21d5de489cc22d849f246225909278f123483a446e1a3c68b14b8b992c104082 -dist/2025-10-28/rust-std-beta-x86_64-unknown-none.tar.xz=62755ecf24c0a2423b4d05c09ec8e8d38737e6762312d1ba993e1a9417083ba9 -dist/2025-10-28/rust-std-beta-x86_64-unknown-redox.tar.gz=0339d37d857f7f5ecb1607e8c53c499623f0c3563e3b68f2b939ee960d31b270 -dist/2025-10-28/rust-std-beta-x86_64-unknown-redox.tar.xz=613b5ca94e5c33c46d9f29cb557d1e512abd1104c5d81f1897915f6153175cc5 -dist/2025-10-28/rust-std-beta-x86_64-unknown-uefi.tar.gz=1da6167f0a2652b1622cae5ac815d55e307dbd639e4901005a3b225150dcafa7 -dist/2025-10-28/rust-std-beta-x86_64-unknown-uefi.tar.xz=6fca79a15c1ef9f8a3974f84af805106ab453099bdb6f652f584abcd7c8174be -dist/2025-10-28/cargo-beta-aarch64-apple-darwin.tar.gz=e66d076303fe8010c27fdbf8a9e31f47223508a280cd2ffcfea698aede848986 -dist/2025-10-28/cargo-beta-aarch64-apple-darwin.tar.xz=f4e87741a4070fe5bc4ad59ecfd324785cd9a477c539543d6a4fc1675afa8111 -dist/2025-10-28/cargo-beta-aarch64-pc-windows-gnullvm.tar.gz=5e9213968960bab07ad28408563b46d01c1d881c26ccd07651bdb527440461cb -dist/2025-10-28/cargo-beta-aarch64-pc-windows-gnullvm.tar.xz=ec01099da59fab595f8ed8a2f6fb308fbaaabf563cf50c103d47fad4595d72ec -dist/2025-10-28/cargo-beta-aarch64-pc-windows-msvc.tar.gz=ed3cd99db73648bb87c5a25556da30993346f1acc665f9dc906094639370282a -dist/2025-10-28/cargo-beta-aarch64-pc-windows-msvc.tar.xz=c5f89cae65188a7d1b5b5a93f8645774f878db6a14032abb8fd960fa9f4cdb06 -dist/2025-10-28/cargo-beta-aarch64-unknown-linux-gnu.tar.gz=2c85f1c5b1a8bb9532194a16ceb8b04f1586d0ade14442f45e740f3e85022924 -dist/2025-10-28/cargo-beta-aarch64-unknown-linux-gnu.tar.xz=a675601cf6552783625b79c33c1d42715c3918a08078e6eed01236910bafc4b4 -dist/2025-10-28/cargo-beta-aarch64-unknown-linux-musl.tar.gz=e5f2cc9f31b927e2e02117c38a5822c39993242459a057c48e7e11695dabe5a5 -dist/2025-10-28/cargo-beta-aarch64-unknown-linux-musl.tar.xz=1830b8b7e43fc03f0348503ae036b30d0e906cb024bc2257e717a58df95ac222 -dist/2025-10-28/cargo-beta-arm-unknown-linux-gnueabi.tar.gz=eef6f553184a8177525a1ee932d6e293f42eaed6986c1c83f7d76d579f02b867 -dist/2025-10-28/cargo-beta-arm-unknown-linux-gnueabi.tar.xz=13c81e5874532e490c987dbc46b19cf3a7eac14fefdffc30d0c5493a84f8a257 -dist/2025-10-28/cargo-beta-arm-unknown-linux-gnueabihf.tar.gz=56d7f1b41af4d72091c8a99b9a583f24d5aa3912f6dfcbfeeae4eb47bfbf158e -dist/2025-10-28/cargo-beta-arm-unknown-linux-gnueabihf.tar.xz=010292117dca5b10b71b7aabe38d1e8c2f0180ab54e9bf072a9ca8bab3f40ced -dist/2025-10-28/cargo-beta-armv7-unknown-linux-gnueabihf.tar.gz=91671bdd6438df48e4c529e5897afe57b91e8575c12d40c3cb3280493599c0d9 -dist/2025-10-28/cargo-beta-armv7-unknown-linux-gnueabihf.tar.xz=0da8474db35ef547b28f123e8c98ec84dcc4a4a5c4a487a222ac006e809ceb80 -dist/2025-10-28/cargo-beta-i686-pc-windows-gnu.tar.gz=5d9ce7ba82e8d694e53ac877214c0873b0dd78a60c8eabcfe9128433d199d12e -dist/2025-10-28/cargo-beta-i686-pc-windows-gnu.tar.xz=209100fad49e274457d8299360a4c2e83803411a69fec69898a03d9a2bdee955 -dist/2025-10-28/cargo-beta-i686-pc-windows-msvc.tar.gz=edca4ca03b055b40d0c4778e325b93e3759123f207a6d32d7ff42cfa0f323604 -dist/2025-10-28/cargo-beta-i686-pc-windows-msvc.tar.xz=5146440d030e04450de61bd6022cd7ad6364fd06f9cec28bbb7889bad171e579 -dist/2025-10-28/cargo-beta-i686-unknown-linux-gnu.tar.gz=d1045ab266d914060e24224b0e74ea865f4bf4cd527d9a09c5631441c40f48a3 -dist/2025-10-28/cargo-beta-i686-unknown-linux-gnu.tar.xz=caed7a0786cc9f476d1b9fb5367c67a02397ccb12ed18a357b5ed04fe77fb12f -dist/2025-10-28/cargo-beta-loongarch64-unknown-linux-gnu.tar.gz=017335d6ca97cbe4bf93e2ffb4def850b05a8efa0367b008de4cc8b55f1af3cf -dist/2025-10-28/cargo-beta-loongarch64-unknown-linux-gnu.tar.xz=f5671ec0dee9841d4a482183f56ccb986f358a80d043d1ec4b05bc8a356f8ad7 -dist/2025-10-28/cargo-beta-loongarch64-unknown-linux-musl.tar.gz=0a280ebc1b5aab8452f1445fe858ad4808fd7035dd498510951d8b7caa13edc8 -dist/2025-10-28/cargo-beta-loongarch64-unknown-linux-musl.tar.xz=8ab41df2264470d6ed0a6d82b665992f76f9065046a153bc8ee1eda9ca81eaae -dist/2025-10-28/cargo-beta-powerpc-unknown-linux-gnu.tar.gz=7368d0d297fa06108271b03138a9dda0cfbdbe5463a614ebf6fb5b573dde08d7 -dist/2025-10-28/cargo-beta-powerpc-unknown-linux-gnu.tar.xz=1ad0b7d4e3173150768db7105b1a691e8c85db3e9c6a391390e2f5df7844d420 -dist/2025-10-28/cargo-beta-powerpc64-unknown-linux-gnu.tar.gz=75740d0b1847f73777894f484e085f70f24d981b0ef69d00cb5b0c29d276c5b5 -dist/2025-10-28/cargo-beta-powerpc64-unknown-linux-gnu.tar.xz=1ca71e60a6fa9752dd27bfe4f354a1b732b67e55c9e645021e6041a2450b7994 -dist/2025-10-28/cargo-beta-powerpc64le-unknown-linux-gnu.tar.gz=ab37e6d39ccb7fe33c55bf62836c2174f1a4197f02cbe9d88d118b81ec6d49e2 -dist/2025-10-28/cargo-beta-powerpc64le-unknown-linux-gnu.tar.xz=77cc38c5b89fc65fb7453dcc3c3212e0a512923497420b7782ffbfd88f00b39f -dist/2025-10-28/cargo-beta-powerpc64le-unknown-linux-musl.tar.gz=29a2dd23fe30b2d1741e1d4032d4250b4f7f0e2af5ae718b309f2d271e13ef41 -dist/2025-10-28/cargo-beta-powerpc64le-unknown-linux-musl.tar.xz=bac42c5d4af02abbb4db1a9dd4664340d686e4c23f923f372d3b08e090bd105c -dist/2025-10-28/cargo-beta-riscv64gc-unknown-linux-gnu.tar.gz=3b396bf0ddede9f4964bc9fb27b52e628db1d9ccc38dbc5d5e06c316ba8bef87 -dist/2025-10-28/cargo-beta-riscv64gc-unknown-linux-gnu.tar.xz=e706521e4496c79bb677d7d06d79fc1ae2770cdba4a81d8c28ede81ab4ee7909 -dist/2025-10-28/cargo-beta-s390x-unknown-linux-gnu.tar.gz=2fa6ecf04d1cb20dde5f700a0e425ea186d628c5704885e84e197e4494af101f -dist/2025-10-28/cargo-beta-s390x-unknown-linux-gnu.tar.xz=e8810699e679fd0306d4e6c95608970ec5a1d1ccffcdd707fe4a4508518a0e6d -dist/2025-10-28/cargo-beta-sparcv9-sun-solaris.tar.gz=2fcae7eb2f538d84545944c744bbac39e28b3bd58e8d2bdc862d5f66df7068e7 -dist/2025-10-28/cargo-beta-sparcv9-sun-solaris.tar.xz=2fe42f27469fdc23a9e45ec025c60a09f00be07a239cd8c8df74ce52e94b4cab -dist/2025-10-28/cargo-beta-x86_64-apple-darwin.tar.gz=c92c1a580eb85d96f973df4dd9cf4440eb661f8fab9c632b5f0621cf0839badc -dist/2025-10-28/cargo-beta-x86_64-apple-darwin.tar.xz=6c2b13253e1066e49fc52f3cb1654776d5d38853a15e8022652b4a2cb6845daa -dist/2025-10-28/cargo-beta-x86_64-pc-solaris.tar.gz=ca98af5dcaae734ccc02fde2807dca8d95947918eb753d407c12dd05ae937568 -dist/2025-10-28/cargo-beta-x86_64-pc-solaris.tar.xz=864ed5842890359e9f767b4050b8a27ec9c27c88a8cef20993b8f775c213d394 -dist/2025-10-28/cargo-beta-x86_64-pc-windows-gnu.tar.gz=ec8a9e8436f83388736f16f7ad9962a1d9b72673c3da56b8233a6b39dde54534 -dist/2025-10-28/cargo-beta-x86_64-pc-windows-gnu.tar.xz=1f059aae8e6faedcc56663d833a07417e07eededdc2776b2762822987a010131 -dist/2025-10-28/cargo-beta-x86_64-pc-windows-gnullvm.tar.gz=f364bf2f20f35c7ff0381cbd34c88a256849a1b9a27267436e14bc01b7bacfbd -dist/2025-10-28/cargo-beta-x86_64-pc-windows-gnullvm.tar.xz=451f18d049f1c47bfa0c010481e499afa1baaffb889de11534cf451578c62f76 -dist/2025-10-28/cargo-beta-x86_64-pc-windows-msvc.tar.gz=96ca48b12b27b8e933cbb426e7123873a1120bd884a62d150aceb6a26bfc7694 -dist/2025-10-28/cargo-beta-x86_64-pc-windows-msvc.tar.xz=dfe14d019f5c1744a312da8d926059147974de0b5bcdcd869526b5257a1112b3 -dist/2025-10-28/cargo-beta-x86_64-unknown-freebsd.tar.gz=7ef3d3edb6b536382f5063a5de5aaf036d6ba09bf7bd1ff770b87d8942110c2a -dist/2025-10-28/cargo-beta-x86_64-unknown-freebsd.tar.xz=beb5587235e8ff471a8eb9fd84ae5cf4380e7ec9b00ab03dc0c549be0e661dd0 -dist/2025-10-28/cargo-beta-x86_64-unknown-illumos.tar.gz=b97f511486ad044dae0c8b50df8430e489887ac36b770155f163d8e4216cd9c9 -dist/2025-10-28/cargo-beta-x86_64-unknown-illumos.tar.xz=21fc84a42fa988632fb9b0d9dccdf6ab2fbbd06a6780076282fc9bea56567559 -dist/2025-10-28/cargo-beta-x86_64-unknown-linux-gnu.tar.gz=d5b05dc398716909df77415b4a68233b68a5d578855e0e91dcf423f2985fc1cd -dist/2025-10-28/cargo-beta-x86_64-unknown-linux-gnu.tar.xz=21e79bba772e93a6fd910e9d6ee833b55a53b80088f8280525717a4cd800c21b -dist/2025-10-28/cargo-beta-x86_64-unknown-linux-musl.tar.gz=4d126f2591652ddea26884973c1ae1f1e25246cc5f60baeb3a52d6ff45a1aa15 -dist/2025-10-28/cargo-beta-x86_64-unknown-linux-musl.tar.xz=62113a7383f7ff8a9bee099155ca55c3c69d16bf135fc06046f672b2102deafa -dist/2025-10-28/cargo-beta-x86_64-unknown-netbsd.tar.gz=e9a07f035f308d4b9cf5f1b0ab4ef969cad1c41528adea2fca81d8dfe45ebff0 -dist/2025-10-28/cargo-beta-x86_64-unknown-netbsd.tar.xz=3f3d87269072d8e219e7213ca878a7fd441aaf74e4d052ca44ccc7ad75e83eee -dist/2025-10-28/clippy-beta-aarch64-apple-darwin.tar.gz=a44daddb30309be19856b9572679569ffc2ab2c30318706ad59aa2dc14887587 -dist/2025-10-28/clippy-beta-aarch64-apple-darwin.tar.xz=00576ad0f30db5be96e6434e22a2fcdd167067d65ab85199df06a6d11d1ef6c0 -dist/2025-10-28/clippy-beta-aarch64-pc-windows-gnullvm.tar.gz=24fb3dc6680e845c84e535f9c14be5e3d4052ef3ccc800e0fd81815edccb4836 -dist/2025-10-28/clippy-beta-aarch64-pc-windows-gnullvm.tar.xz=20d2ebdb6e2a902eb74ad502a14a2a66e6a9316d5f94513ec9781d146c323d9d -dist/2025-10-28/clippy-beta-aarch64-pc-windows-msvc.tar.gz=652e5bdffbb89ba281cbd5efe3a2cf103adea6af7ba56a21cb6bb538a2ea6536 -dist/2025-10-28/clippy-beta-aarch64-pc-windows-msvc.tar.xz=59d0fb72db77c484571ebab8c992303659225735d3f820ed7048122d8f96d764 -dist/2025-10-28/clippy-beta-aarch64-unknown-linux-gnu.tar.gz=6bf6fb7279ecf5df6edca6014db5f8ba0427fd8cd32f073630b6b02e2e69feaf -dist/2025-10-28/clippy-beta-aarch64-unknown-linux-gnu.tar.xz=0a8d19bca62dc38e64cf527b239106901fa2e0642ca5c2ef1cde070faaa901b0 -dist/2025-10-28/clippy-beta-aarch64-unknown-linux-musl.tar.gz=663581dbd93b22b3b20d281486c8dc0580e43ceca42d9455d78f2d2c341cc758 -dist/2025-10-28/clippy-beta-aarch64-unknown-linux-musl.tar.xz=49548d8ee0561ab96629e354ad055ed5f0c6f3f60c1559ca2a27352b441ff848 -dist/2025-10-28/clippy-beta-arm-unknown-linux-gnueabi.tar.gz=b3d44866b1f909576e0e586aa34b480f1170aa3eba28209ac5bcb929f544d07c -dist/2025-10-28/clippy-beta-arm-unknown-linux-gnueabi.tar.xz=717397166acd760e391c251b1c308657f45deadd928035d2860c772c8b377b91 -dist/2025-10-28/clippy-beta-arm-unknown-linux-gnueabihf.tar.gz=8911fa3347ca26a2afed6140bc4cafa629830740b8e4ff5e648c517f6ea43c6b -dist/2025-10-28/clippy-beta-arm-unknown-linux-gnueabihf.tar.xz=e7360c728068520ec7bd712d57357ce30bbfbb629ec69cfdcf6596002751d93b -dist/2025-10-28/clippy-beta-armv7-unknown-linux-gnueabihf.tar.gz=6d94df05e43804f1054d17542db72cfd3f2df27eedc275c810b35362f9d581c1 -dist/2025-10-28/clippy-beta-armv7-unknown-linux-gnueabihf.tar.xz=25c33744d9722aad4f9fc80674233d16eb653adb17d0deadcd3be8f16a79ecb7 -dist/2025-10-28/clippy-beta-i686-pc-windows-gnu.tar.gz=dfb9ba0cc842b7c92f1dda8bb88bd1db9beeac746c3ca3d144dd4d66d91ff6ff -dist/2025-10-28/clippy-beta-i686-pc-windows-gnu.tar.xz=20f3cf3fe6b52b8f54391be7edd11331a376313c37b674f4987589f50eac68d0 -dist/2025-10-28/clippy-beta-i686-pc-windows-msvc.tar.gz=bcabe1f7679e1ae416c7ed56afd74ad224ff47cd9b5413dececb0e6f503ce393 -dist/2025-10-28/clippy-beta-i686-pc-windows-msvc.tar.xz=f8ebfef39e7119b45a4f714e91b47964aeb6653fbdaf9b01786ef629cbaf3d31 -dist/2025-10-28/clippy-beta-i686-unknown-linux-gnu.tar.gz=f0fc318e90de4f45f6ca7d0d6ca3ed5d044db75f97254d792cdea9a7b196042e -dist/2025-10-28/clippy-beta-i686-unknown-linux-gnu.tar.xz=27c9adb19a7f84edb19ff4c8ce34dd836fb8d10e8786999591e41ec9c60e4602 -dist/2025-10-28/clippy-beta-loongarch64-unknown-linux-gnu.tar.gz=04673347c7e13eee9e301ffc1640ce7a5ed733915c29d90750706829d6b02884 -dist/2025-10-28/clippy-beta-loongarch64-unknown-linux-gnu.tar.xz=2484f24346fbbd2d48f69d86ab7710ef65a5952bb5ea0141f3388f616c7d6d0c -dist/2025-10-28/clippy-beta-loongarch64-unknown-linux-musl.tar.gz=656eb1b94dd2324958e6ba0b1c7a37281abe24dac7d87b0e406fc10931ea0d29 -dist/2025-10-28/clippy-beta-loongarch64-unknown-linux-musl.tar.xz=3349952da5d2693554d2e1ae60bb7ff9cd64451719cadf4227095b73377228c1 -dist/2025-10-28/clippy-beta-powerpc-unknown-linux-gnu.tar.gz=40eeba3b2807a1d807ed25c3bc0482d5b91135a769d2281a894ec8cb8bb52a35 -dist/2025-10-28/clippy-beta-powerpc-unknown-linux-gnu.tar.xz=0a6e79cea6655d6b3e1ff1218651c627886d8f06a5d36e9c3bd3c9c45b375f57 -dist/2025-10-28/clippy-beta-powerpc64-unknown-linux-gnu.tar.gz=b11f919fce34d70816a6dfa0884e37939c38336bad6261fccf5d67d25935852c -dist/2025-10-28/clippy-beta-powerpc64-unknown-linux-gnu.tar.xz=ead91ce4260d07d4e4f950092e94ae224f067ae3c711efe2ccedc9250b2f3dd7 -dist/2025-10-28/clippy-beta-powerpc64le-unknown-linux-gnu.tar.gz=481a2e3b45751e2d86c30d4fb3897f0a7a18e9eadde2c9a3ad1a8b0259fa2066 -dist/2025-10-28/clippy-beta-powerpc64le-unknown-linux-gnu.tar.xz=d5d6529cfc89c29443d9e87041a5f93b746e5bc5791016242e2f271be5bcb557 -dist/2025-10-28/clippy-beta-powerpc64le-unknown-linux-musl.tar.gz=a70d30948f5e95cdd454fa2b3284b97f29134f59e98e130fc2877781f3b62e89 -dist/2025-10-28/clippy-beta-powerpc64le-unknown-linux-musl.tar.xz=8dddfc0b1b2ca8e8866a11a1c95b8601c50150f1e52adbd3803cca2fabb386e9 -dist/2025-10-28/clippy-beta-riscv64gc-unknown-linux-gnu.tar.gz=bd1b28dd79a52de657515ba5c25063b0b6015eb30ee3b0ee05511567b429c992 -dist/2025-10-28/clippy-beta-riscv64gc-unknown-linux-gnu.tar.xz=5262011db6be068ef70905a28939b1838a2fd2b719d38d59e80754695049269b -dist/2025-10-28/clippy-beta-s390x-unknown-linux-gnu.tar.gz=6d3d83d03c46e1de2cc6b6f204e701acc9dddb6d4baef80fada9d868b7eb86cc -dist/2025-10-28/clippy-beta-s390x-unknown-linux-gnu.tar.xz=e57ac819f962d9b431b699b40a047d3e2530f76f2670c5a04747b7de11c3d5e2 -dist/2025-10-28/clippy-beta-sparcv9-sun-solaris.tar.gz=7a492d27b49facb9554248935728cba483eb7ecf3de317751a7445c3932932e6 -dist/2025-10-28/clippy-beta-sparcv9-sun-solaris.tar.xz=cc02f4f971b9e5eb63ca65ff6947cf3490101bfb40ea9fb2b310283bb6d10b27 -dist/2025-10-28/clippy-beta-x86_64-apple-darwin.tar.gz=56f11b8ca012467ef6aa8dc3458a5bf45950f1de062a616a01f6c0aae412d0fd -dist/2025-10-28/clippy-beta-x86_64-apple-darwin.tar.xz=01fe53ec63d71a8427fa3220d037313fc31f8d0fa33a64305b01109344aac21a -dist/2025-10-28/clippy-beta-x86_64-pc-solaris.tar.gz=d222cfda8613bba09b0ac1d02fad99c0d081d10733f0f9253d809221ffdda506 -dist/2025-10-28/clippy-beta-x86_64-pc-solaris.tar.xz=918706ee8ed38bf398cbf0dad85333e3082dc461fff2fb2399b96e840dc24766 -dist/2025-10-28/clippy-beta-x86_64-pc-windows-gnu.tar.gz=7764df051100b08b4b4e5c434d5ced1aaa84d9665f6a4401c9ed6350db983b70 -dist/2025-10-28/clippy-beta-x86_64-pc-windows-gnu.tar.xz=4a43dee6ce0279de929566f844fa4987d10fa5ca856bb2a2cbea4327eef3308e -dist/2025-10-28/clippy-beta-x86_64-pc-windows-gnullvm.tar.gz=add2532fe4e8afb8b53aee8a729fde0c0b36f83a8f6a859c39ae25f3d01e8dd6 -dist/2025-10-28/clippy-beta-x86_64-pc-windows-gnullvm.tar.xz=7117f0afc57ac09c277ba99be4a7de80d62ffaebe4174706910d5ab6501ec9f7 -dist/2025-10-28/clippy-beta-x86_64-pc-windows-msvc.tar.gz=e71d45b8bdb5346d89f769b4698b404b293884878a7f697680318c72829c1d6f -dist/2025-10-28/clippy-beta-x86_64-pc-windows-msvc.tar.xz=67be8cf6580a4a6e36eff94bfe19fdad290eae5db598d2a016dfcc7516178e14 -dist/2025-10-28/clippy-beta-x86_64-unknown-freebsd.tar.gz=03b78bad90efe98cab6416ecc641b7da0c9a2be5950edbb4c520c0758cdb90a8 -dist/2025-10-28/clippy-beta-x86_64-unknown-freebsd.tar.xz=056aecae34c8ae10a41516834809d983bd6126bd0374a7bf0857710492f0d0a5 -dist/2025-10-28/clippy-beta-x86_64-unknown-illumos.tar.gz=a67147c647da8a9b68a507087b66610ed19e65b94538b08326b000e66c170260 -dist/2025-10-28/clippy-beta-x86_64-unknown-illumos.tar.xz=09bd43034d7bc1e9ad1873610237f98543751809ebe63d8255813eadf4a00e70 -dist/2025-10-28/clippy-beta-x86_64-unknown-linux-gnu.tar.gz=9397e5c3b1f45ce949b8e3420233e8b86f95a887667c917b8e7615218989820f -dist/2025-10-28/clippy-beta-x86_64-unknown-linux-gnu.tar.xz=5b67e9eb803c180d101e799f6d7c2a6ea7ec07a93a6395b4f688bf2592bc30d5 -dist/2025-10-28/clippy-beta-x86_64-unknown-linux-musl.tar.gz=b255c33a89b0b1bd666ffb584c20554daa3a7c48123de75eae5e1b4cbc53e1aa -dist/2025-10-28/clippy-beta-x86_64-unknown-linux-musl.tar.xz=bc7f3f7d59f9c52370849092541a9368632f390ed9bc88f2566f1e3700f4da80 -dist/2025-10-28/clippy-beta-x86_64-unknown-netbsd.tar.gz=a8f366918520cc5a82c9bcfbb419570e6792712455ec5c04655e6557a657e949 -dist/2025-10-28/clippy-beta-x86_64-unknown-netbsd.tar.xz=dad3555be56e7c8d042f65dfced7915856f9f23cec13a7a633a4aad38c634247 -dist/2025-10-28/rust-beta-aarch64-pc-windows-msvc.msi=943683af0d464ecd36678e1c87b1207a67105820cb3d1516eeebaae450a2928b -dist/2025-10-28/rust-beta-i686-pc-windows-gnu.msi=8532743b3406fbf2926e5c6643300194eaace9de492e7f2ad0caa6f7d040f8db -dist/2025-10-28/rust-beta-i686-pc-windows-msvc.msi=1b3b15aa90c3dca73e9d72d53d214eb3c02b97386c83d8755a03f571cc09de4e -dist/2025-10-28/rust-beta-x86_64-pc-windows-gnu.msi=6249ad7cfcfe78b541e4935ed18dc4cfb10130252885668383a4c8f5046ecc2d -dist/2025-10-28/rust-beta-x86_64-pc-windows-msvc.msi=700f63a1baf0de2f0d1972454486f890af15b3700481698ffb0daf403778390a -dist/2025-10-28/rust-beta-aarch64-apple-darwin.pkg=1f2862fd5dbf8a9c7a765e75391cfffc5a3cd6837066b29f95778b5a346f0f59 -dist/2025-10-28/rust-beta-x86_64-apple-darwin.pkg=ffa2c6275b401c73575a5158911bc53edfece2edc03f6b3f6a140823cf870ee4 -dist/2025-10-28/rustc-beta-src.tar.gz=dbbae9e1c0b5e914b588ba5b659b7fb6af3d5b422831aba028d64b00c7161417 -dist/2025-10-28/rustc-beta-src.tar.xz=aa771d2b1ea8c933444c962c03c384bf2511bdeddf90edcaac8f45bd49f5232c -dist/2025-10-28/rustfmt-nightly-aarch64-apple-darwin.tar.gz=5a5e525f45010fd3e30503f408f21eef78cafa54e42adf9709cff50f6cb29720 -dist/2025-10-28/rustfmt-nightly-aarch64-apple-darwin.tar.xz=b6f92173abde0be1f4f3378c682e42016390e6e5e20df7e84cbd7804a6161114 -dist/2025-10-28/rustfmt-nightly-aarch64-pc-windows-gnullvm.tar.gz=430775c6856f4aea6a2b83e245904d5527f6ace134a9375dc7172f77ecd328f6 -dist/2025-10-28/rustfmt-nightly-aarch64-pc-windows-gnullvm.tar.xz=3d14ccf194d04ad5767a5fc3df6f9c1427cd0e282671887d2264b8314586e168 -dist/2025-10-28/rustfmt-nightly-aarch64-pc-windows-msvc.tar.gz=251f7fa0b78fdad3be1977ffd6a2f563d1524b6423d2bab73d1741aec97b4717 -dist/2025-10-28/rustfmt-nightly-aarch64-pc-windows-msvc.tar.xz=534cacc40024fec78c02916e7e2d46cde8b8153d303efc1b805af8789f25fb1e -dist/2025-10-28/rustfmt-nightly-aarch64-unknown-linux-gnu.tar.gz=5663e413cd9ae9f403a4b5c5e9a9862c00d57bcd68bde9161c91e852115e45cd -dist/2025-10-28/rustfmt-nightly-aarch64-unknown-linux-gnu.tar.xz=3625b287a83796cb71741b9a4b002eb4517950d386f97a91470c0acd5aed835c -dist/2025-10-28/rustfmt-nightly-aarch64-unknown-linux-musl.tar.gz=657b0774a95a925eb38d039ef11bc23d15c4733d0b322f172f0b8236bc7410f6 -dist/2025-10-28/rustfmt-nightly-aarch64-unknown-linux-musl.tar.xz=4e058f11346ec86801bc9cdb830c6dec2620b81fe2cd4b439b275a5145859dfa -dist/2025-10-28/rustfmt-nightly-arm-unknown-linux-gnueabi.tar.gz=820ece81e455d11f65ddf09093b6bf97359cc803959d951bd199c70a79ae117e -dist/2025-10-28/rustfmt-nightly-arm-unknown-linux-gnueabi.tar.xz=8a72a3e715ab2427fc120f8af20d67f722881ee9e13bf482e45ef07f5fb2bf86 -dist/2025-10-28/rustfmt-nightly-arm-unknown-linux-gnueabihf.tar.gz=fb583c846e1a11663a1fc525f02c0146dc70e7b4da12c264c8b00cf7927ad9c9 -dist/2025-10-28/rustfmt-nightly-arm-unknown-linux-gnueabihf.tar.xz=8a15430000d48b702142cc4569a5eef3aba59c07f33f69cfb6966250fae18178 -dist/2025-10-28/rustfmt-nightly-armv7-unknown-linux-gnueabihf.tar.gz=c470dd9f35b1b701e8475716e61cfadee5475fa29a2994f407d532a794c0ef82 -dist/2025-10-28/rustfmt-nightly-armv7-unknown-linux-gnueabihf.tar.xz=774898dd43893b99e4e11d004c52244d78d2fb08aaa6fa242cf1d7070d9ff8ac -dist/2025-10-28/rustfmt-nightly-i686-pc-windows-gnu.tar.gz=31ef71bea5f5ce3668b903fabb1582dc256fe6e2f97e5c23ca468e05f3deb7c9 -dist/2025-10-28/rustfmt-nightly-i686-pc-windows-gnu.tar.xz=232351f0a578f9973b536eb587b2e90cb01ca5f76ad376c09d7dd225c09810b0 -dist/2025-10-28/rustfmt-nightly-i686-pc-windows-msvc.tar.gz=eb469e8475af339d36e1381474f931e326ef1f095a6f56f44730019c5f6422fb -dist/2025-10-28/rustfmt-nightly-i686-pc-windows-msvc.tar.xz=42c5f2e88f81cdcc375d26c4ab6d9ec03b387b8de632af8a3fa75bcbfcbf56da -dist/2025-10-28/rustfmt-nightly-i686-unknown-linux-gnu.tar.gz=79e06c14b8f18927b1c24cc4ea97e55a805355137a9bdbe3ba616e334878d85a -dist/2025-10-28/rustfmt-nightly-i686-unknown-linux-gnu.tar.xz=3883c297de03da522a20b893f24970305fadaf726dd9388f89196e1f284115e9 -dist/2025-10-28/rustfmt-nightly-loongarch64-unknown-linux-gnu.tar.gz=b3ddf283d7964a4c261668df7685bc47b469c7294325f975436d465cb7d44163 -dist/2025-10-28/rustfmt-nightly-loongarch64-unknown-linux-gnu.tar.xz=9e63e1bd8b4c52943092e91942737be9b3ee9c128dfbeafdc01d3dc732058165 -dist/2025-10-28/rustfmt-nightly-loongarch64-unknown-linux-musl.tar.gz=83845c5809a9b525655565b3e3b4889e2a07562587c6f046280a44dcbb809094 -dist/2025-10-28/rustfmt-nightly-loongarch64-unknown-linux-musl.tar.xz=533113ead2985a36cf685cfbd6645d43f1a7e2e66b6eaadbde2ff5a72d10c5dd -dist/2025-10-28/rustfmt-nightly-powerpc-unknown-linux-gnu.tar.gz=82c6aa57adb0f03b96982f51edc65aebfac3811cd2845d280b7bf5fb81cbe92a -dist/2025-10-28/rustfmt-nightly-powerpc-unknown-linux-gnu.tar.xz=8f4b3c91072d56ba80ba4702e611dbc6fe66163666e6ee35d74602ef36fe9839 -dist/2025-10-28/rustfmt-nightly-powerpc64-unknown-linux-gnu.tar.gz=4fe0b85296e2249b36a0b021d6b82e7c31c40a5f717a5f447b6bf9b9524069a2 -dist/2025-10-28/rustfmt-nightly-powerpc64-unknown-linux-gnu.tar.xz=9257bb295a58a7df3fbbda809bafc74a8601618afd0fd41467439a8972278cae -dist/2025-10-28/rustfmt-nightly-powerpc64le-unknown-linux-gnu.tar.gz=d3a5851060a66a0e027ba142dbdb6e827f4f5f5116b5fdb0b8e86ee56616d682 -dist/2025-10-28/rustfmt-nightly-powerpc64le-unknown-linux-gnu.tar.xz=fe1e9e4e3a234ba8cb656b08b7bbf5349f5068906cb60a4c5c53f7fe3e214487 -dist/2025-10-28/rustfmt-nightly-powerpc64le-unknown-linux-musl.tar.gz=2187f1ccbd4e638efaf9f05566998b579b32729fd9ee4332964a3c54556c3a20 -dist/2025-10-28/rustfmt-nightly-powerpc64le-unknown-linux-musl.tar.xz=88526ca6af21bdbc6c46130012cb5fdde25fd44e6372187e66d273067efbc052 -dist/2025-10-28/rustfmt-nightly-riscv64gc-unknown-linux-gnu.tar.gz=9299c8d4dfc320cf331dc4005c36a0108961a6d5ad750a5b0a6be8c7cda77953 -dist/2025-10-28/rustfmt-nightly-riscv64gc-unknown-linux-gnu.tar.xz=7da58822a9ba4d65258ca0cd514b9abcc85070baa195ce65d40ed9d9de049049 -dist/2025-10-28/rustfmt-nightly-s390x-unknown-linux-gnu.tar.gz=e07cc8f1166bb39aada202559c1e2ee9190cf85fc11b4d4abb921cab352748f8 -dist/2025-10-28/rustfmt-nightly-s390x-unknown-linux-gnu.tar.xz=ebcb49b4ee1e8dded5e6569c7edea1578a369e92aac9030a51d11e95bd8bb8b1 -dist/2025-10-28/rustfmt-nightly-sparcv9-sun-solaris.tar.gz=247ce6a1fb10911b8f38bc8f88617d9a7dd2147e1f1896710b0b610f8bb4b86e -dist/2025-10-28/rustfmt-nightly-sparcv9-sun-solaris.tar.xz=020d64391c730a61f4c61d802b432a463d4909d0e4d5fe4756db4683df6e000c -dist/2025-10-28/rustfmt-nightly-x86_64-apple-darwin.tar.gz=547d7711acee55435e271fca1cebead82045375b0fb136404be7df379b0d404b -dist/2025-10-28/rustfmt-nightly-x86_64-apple-darwin.tar.xz=e8ef4fa56be91b642fd3a8c29afb9dfb3fb7601c8fbd24393be4f3dea1802163 -dist/2025-10-28/rustfmt-nightly-x86_64-pc-solaris.tar.gz=0e41caa314927c9a8656d16b6623c95463a64f07a23941d03597a17582c224d6 -dist/2025-10-28/rustfmt-nightly-x86_64-pc-solaris.tar.xz=d73dcd42d9110befbdf64c46b9e4e8bad07839302cec49e2d8cd99ab436d4bbf -dist/2025-10-28/rustfmt-nightly-x86_64-pc-windows-gnu.tar.gz=8e821c45dc91d5df1b9f8487554cadc4deb86a9ef3db25f4e21b38eab3cc8ed2 -dist/2025-10-28/rustfmt-nightly-x86_64-pc-windows-gnu.tar.xz=f98ccfcc37b7412788a546cbafe5f09b90c26f823e3cad17e71432df4ba910ef -dist/2025-10-28/rustfmt-nightly-x86_64-pc-windows-gnullvm.tar.gz=762e15406bac23f0f41dae2b1b3370458b92e8be771868b4f8f536f53cb26fc3 -dist/2025-10-28/rustfmt-nightly-x86_64-pc-windows-gnullvm.tar.xz=cd87b4a4c2af3edea8ba09ce9bb8704449d8f51c5dee8ba10161e0ce2ec2aa19 -dist/2025-10-28/rustfmt-nightly-x86_64-pc-windows-msvc.tar.gz=7de2ee69be5384656024a6d7c3481315fe90abc9ba9a26726f1eab09aae2c818 -dist/2025-10-28/rustfmt-nightly-x86_64-pc-windows-msvc.tar.xz=16377ae5474e30b6c11ba886579ef13db4039d0b9f43240db00aacf7366b37d7 -dist/2025-10-28/rustfmt-nightly-x86_64-unknown-freebsd.tar.gz=d98fd17080ed5a4fda444719011540a80320001a0b0dc36148f2e3f78e5f5c33 -dist/2025-10-28/rustfmt-nightly-x86_64-unknown-freebsd.tar.xz=c825c2b46f43fe71f4452494fb422cd9565ec6454857835a6c77081553081523 -dist/2025-10-28/rustfmt-nightly-x86_64-unknown-illumos.tar.gz=8844743cc05351b1f6ba8fb50ac1d86161a285775eb4c0e474308aec71b631c7 -dist/2025-10-28/rustfmt-nightly-x86_64-unknown-illumos.tar.xz=172dc660ceb00e7003e855a09f46d9f83096773495ed6d7b8b1ed6b9e770912f -dist/2025-10-28/rustfmt-nightly-x86_64-unknown-linux-gnu.tar.gz=2710450c26834b07a5eb80bf990dc67a6db89f87e26d6b613ed96116c28958d4 -dist/2025-10-28/rustfmt-nightly-x86_64-unknown-linux-gnu.tar.xz=bbb8eac454e0ba3b23c9803d8201fa341d0f0af509aa9e8b530c9b98a1d9886c -dist/2025-10-28/rustfmt-nightly-x86_64-unknown-linux-musl.tar.gz=e6bb6a67878c9cbbbbc96f1a1858500403ecc3b8c951366e18ace0f2601f41cb -dist/2025-10-28/rustfmt-nightly-x86_64-unknown-linux-musl.tar.xz=f6509af9551e73ac16c425c53e667382bf7b6b48be65f4779485ee7843e68030 -dist/2025-10-28/rustfmt-nightly-x86_64-unknown-netbsd.tar.gz=3915f1907939fbfcd82012efa4293e7ddf22bd5bf1484efffacb31c805e6cf68 -dist/2025-10-28/rustfmt-nightly-x86_64-unknown-netbsd.tar.xz=cca6182ce9f2906a8b16971741a8435dbcf60d9ef6020cc7d6f7909525a73dc2 -dist/2025-10-28/rustc-nightly-aarch64-apple-darwin.tar.gz=876004fa16a6154ea8ea46cd1bb60a06fc14b24e72e26e20e42fde4e32882b46 -dist/2025-10-28/rustc-nightly-aarch64-apple-darwin.tar.xz=0a98f29bb6a2a1555f6ceaa161ecdd2e599ffe879b98bc98c6066e257fc12362 -dist/2025-10-28/rustc-nightly-aarch64-pc-windows-gnullvm.tar.gz=b07b2f7975b463970cbb4a8c92e51788ac63c3a46d3ae6c8cb54c7024161d899 -dist/2025-10-28/rustc-nightly-aarch64-pc-windows-gnullvm.tar.xz=5445b2e30804733fe2a7d07f66a77c2e3ec5e7c71bb55403541b8d365cf91870 -dist/2025-10-28/rustc-nightly-aarch64-pc-windows-msvc.tar.gz=d2cff6b8cb52172f4bb394f8ca891897c774ece1b87f9d30729aa236dfa24900 -dist/2025-10-28/rustc-nightly-aarch64-pc-windows-msvc.tar.xz=a6d0c00367b49654c91d4b71b33819854f628d51b7193c2475b9f737258a575a -dist/2025-10-28/rustc-nightly-aarch64-unknown-linux-gnu.tar.gz=c30649c2360aef41d97bdbf76d55bbfe674a1225161bc125a8215d3954656cda -dist/2025-10-28/rustc-nightly-aarch64-unknown-linux-gnu.tar.xz=3b204fb1461f47b4e2a79a67923abcf8610ab7ab006ee3f9a70cdc87458f81c5 -dist/2025-10-28/rustc-nightly-aarch64-unknown-linux-musl.tar.gz=949f55697b50db7d70a6465b100ae4458d2f676b818ca7227014ddc9c5f707e5 -dist/2025-10-28/rustc-nightly-aarch64-unknown-linux-musl.tar.xz=ff500cd8f318f0316936af462264254df2aa1bd5a2b368ad3c5758e9079eaf71 -dist/2025-10-28/rustc-nightly-arm-unknown-linux-gnueabi.tar.gz=231c4cfa37df03a0e0517843bd115a0f0b13ec259397d6e4dfb4014d3a0d4d9f -dist/2025-10-28/rustc-nightly-arm-unknown-linux-gnueabi.tar.xz=50f4d7060d02833949ffc970b88c5ad2183fabd3c498334bf63d87d0c9602720 -dist/2025-10-28/rustc-nightly-arm-unknown-linux-gnueabihf.tar.gz=f89586ea5bac722a06c225a50d7d603b4895aea89297509f248a1cb51a5cf0ed -dist/2025-10-28/rustc-nightly-arm-unknown-linux-gnueabihf.tar.xz=0de0552ae68cb9b61f2c5031cdbefae5ccde39c4003441e93c2e4e704d3751aa -dist/2025-10-28/rustc-nightly-armv7-unknown-linux-gnueabihf.tar.gz=019bbb267d1c0520a715287e0a1a680b58dd5e9ece2071f3ebd6f2b1d8eb2228 -dist/2025-10-28/rustc-nightly-armv7-unknown-linux-gnueabihf.tar.xz=069bcd46adfb5e14786fd8aced5ceb74af24cc05dfa2bd41ebd81ac146122598 -dist/2025-10-28/rustc-nightly-i686-pc-windows-gnu.tar.gz=911eb977b10aa4bb1f25124f08f3397fb3ac65f36666865be40bf44259b5d77a -dist/2025-10-28/rustc-nightly-i686-pc-windows-gnu.tar.xz=14ed0abc8708a90e8bbaf0c0de2aec1a4ed60c63b4db00fd4a732f3c808c125b -dist/2025-10-28/rustc-nightly-i686-pc-windows-msvc.tar.gz=8917e6dd4786f0f413908e9db4c92e060bce525f91b9cc0d43b453d26057435d -dist/2025-10-28/rustc-nightly-i686-pc-windows-msvc.tar.xz=86a8580a180de9224c176beb1ada2c69acc37fc73ae0e7c7780bbbded842365c -dist/2025-10-28/rustc-nightly-i686-unknown-linux-gnu.tar.gz=0d29e999ccbc46ff6b0c50a5648e0c5c8f767daa9a0d1fc86dff30c6e0078dd5 -dist/2025-10-28/rustc-nightly-i686-unknown-linux-gnu.tar.xz=bcafb54ca3f587d3cc9302c057da2fbdb4531e2279ef462fc8682e82e1046561 -dist/2025-10-28/rustc-nightly-loongarch64-unknown-linux-gnu.tar.gz=0a5bfd49a7a2fb98fe06815a2a50d9dc859722da3cc107928e36596c7b8c7f8e -dist/2025-10-28/rustc-nightly-loongarch64-unknown-linux-gnu.tar.xz=b8ec7898e087577b78ef1b716f8935c7023d740b389234f38075a09b2c7b494a -dist/2025-10-28/rustc-nightly-loongarch64-unknown-linux-musl.tar.gz=5cab6709c372feed484b5148ec642cf9767e7fe051146023459467012f2e0b64 -dist/2025-10-28/rustc-nightly-loongarch64-unknown-linux-musl.tar.xz=e42a3c007bdf7e8179c597daffc61d7a6bd8eac782b8d81d0b883267bc226f86 -dist/2025-10-28/rustc-nightly-powerpc-unknown-linux-gnu.tar.gz=a7cb220770ebd482ff9737d787d04e2e1274c46b7da0809041d06712e27f69ae -dist/2025-10-28/rustc-nightly-powerpc-unknown-linux-gnu.tar.xz=088b1d0898bc5b5d83d0fe20edfdadc2d1c0865c39108d11a5d078074aa37a1f -dist/2025-10-28/rustc-nightly-powerpc64-unknown-linux-gnu.tar.gz=90a3b28ca667187fb18eee8b87f5aebdb2c2e457acbe5b7b088d9b9a39314a1a -dist/2025-10-28/rustc-nightly-powerpc64-unknown-linux-gnu.tar.xz=4eb8f1d20b2eeb85a2b78d3e28a1d665e1171e1271540bdd8453833818d53c30 -dist/2025-10-28/rustc-nightly-powerpc64le-unknown-linux-gnu.tar.gz=e4fc106d7d4e098912b4dc0ac0211769ecc1f01731e118bf6c0bca33c7ceb9f5 -dist/2025-10-28/rustc-nightly-powerpc64le-unknown-linux-gnu.tar.xz=74bf23136731240e8dac7497d8b1a244fc35cd529d12f77fff308099354f3aef -dist/2025-10-28/rustc-nightly-powerpc64le-unknown-linux-musl.tar.gz=85ada50366246530a0dcbd462aef31a6edac600d22074d97bfc07321569eafdf -dist/2025-10-28/rustc-nightly-powerpc64le-unknown-linux-musl.tar.xz=f0cb51df2f6639fc65091608d569b9ac0730f5a8d88e27079d87bc8a8834b1e4 -dist/2025-10-28/rustc-nightly-riscv64gc-unknown-linux-gnu.tar.gz=c37432d8d8db7aaad9132e1301025dd5bf3671bad0ac1fea0f04e9aae238cae3 -dist/2025-10-28/rustc-nightly-riscv64gc-unknown-linux-gnu.tar.xz=57f72896f0309149a4b376a21d56ea28e65316db08065bfe32cdbd750bbc9657 -dist/2025-10-28/rustc-nightly-s390x-unknown-linux-gnu.tar.gz=170776eefa09f01859af0b3694c013ebfab04e9fcf8fb44233593ef4a763bd38 -dist/2025-10-28/rustc-nightly-s390x-unknown-linux-gnu.tar.xz=29335ffe7d88b758ec1a7a067056e35fe8f24430e8d899df3256b4e2d19ac16e -dist/2025-10-28/rustc-nightly-sparcv9-sun-solaris.tar.gz=14b5cfe710c92e8691aaad99de891695ef025638eca065587107c075a31215bf -dist/2025-10-28/rustc-nightly-sparcv9-sun-solaris.tar.xz=d21bb41b4abdaededefd199192bc257424295ec74d482693d032ca67f02dee15 -dist/2025-10-28/rustc-nightly-x86_64-apple-darwin.tar.gz=09c7d0777ea308ad552ea1e958f5c65fa3380c9cb93efa1e6edec3a29fc30b5c -dist/2025-10-28/rustc-nightly-x86_64-apple-darwin.tar.xz=923ef47f5bd9608d277b6636b8c798c5b2760460264fa6f0c0836f317746a89c -dist/2025-10-28/rustc-nightly-x86_64-pc-solaris.tar.gz=805643ab958df449ffd8dd5557e43c5e7060a10a3deab2238096b721ab451f08 -dist/2025-10-28/rustc-nightly-x86_64-pc-solaris.tar.xz=f2fb0c0643808bd9f483bf9bf66ead4444285f2e50bc1264b4861deddfaa9c62 -dist/2025-10-28/rustc-nightly-x86_64-pc-windows-gnu.tar.gz=05b7ee4041b2cdcee1739da7a22e4083acc24c043d11cb3f61d0c22237a9f42a -dist/2025-10-28/rustc-nightly-x86_64-pc-windows-gnu.tar.xz=2f3b04d56dd929ab5997711bc52395fa700247ff38b9362cda375b685c740337 -dist/2025-10-28/rustc-nightly-x86_64-pc-windows-gnullvm.tar.gz=52575038868d91349b40434ec8faf9836a0aa0a4f77c2decc634a9ba02796c07 -dist/2025-10-28/rustc-nightly-x86_64-pc-windows-gnullvm.tar.xz=d2d1f2a0d26cc3dc86d88ae46a9dcaa5f0ce694ebac3f46b7466fb058a1a76e5 -dist/2025-10-28/rustc-nightly-x86_64-pc-windows-msvc.tar.gz=5469701cbe03939a82ce5ec50dc166342ab968d2f96cb372dee8f29dfd6e4362 -dist/2025-10-28/rustc-nightly-x86_64-pc-windows-msvc.tar.xz=e6d18f7b7fa3a3613f1aa129f4a14820d4fa1977550689cd99b7dad12054edab -dist/2025-10-28/rustc-nightly-x86_64-unknown-freebsd.tar.gz=e2a5ff9df2b07f8c939fdb885da717faf19a5b3e63ab780962dc288f832cba6f -dist/2025-10-28/rustc-nightly-x86_64-unknown-freebsd.tar.xz=b577558a8f1b42d6bbbc80804e3b72835a85979c98659696db32832595283d04 -dist/2025-10-28/rustc-nightly-x86_64-unknown-illumos.tar.gz=5535a693d5b8edf3fae7e1da97c20596a1f60135fefe22835109ed3648765a16 -dist/2025-10-28/rustc-nightly-x86_64-unknown-illumos.tar.xz=bfc15f0678099ea110135d4e7bcb1b9a545f041e5810f6528d49e0b5451a29bb -dist/2025-10-28/rustc-nightly-x86_64-unknown-linux-gnu.tar.gz=877bf56730551f851e2ce5279c105f231906959bcf904aa2fc29acaba5160cc5 -dist/2025-10-28/rustc-nightly-x86_64-unknown-linux-gnu.tar.xz=911bf7891d7687675f9200d3bd51946e21df3762b5320b7d31bd49d58526a8a7 -dist/2025-10-28/rustc-nightly-x86_64-unknown-linux-musl.tar.gz=c0c26704d16d6612d0d99ad078bbcb2ac0ed86419a0404a9e08739990acc5ad9 -dist/2025-10-28/rustc-nightly-x86_64-unknown-linux-musl.tar.xz=677f5c6126262b64126b5fc7c3c527cbc9e8ba62aaf4376c924149b6d05e16db -dist/2025-10-28/rustc-nightly-x86_64-unknown-netbsd.tar.gz=84c82523969ff1b987a09d5f7401e9a773b3110f51f00d708a4791ef6615272b -dist/2025-10-28/rustc-nightly-x86_64-unknown-netbsd.tar.xz=680eb70467d5695e986b013b3d16dbd0c0b0b7bc85cf8df4a3392c100f97eff9 -dist/2025-10-28/rust-nightly-aarch64-pc-windows-msvc.msi=a8f7ef71113d5ca8094d9433f23d5bab8ae910803e0cc23110d4fd0e04816bf3 -dist/2025-10-28/rust-nightly-i686-pc-windows-gnu.msi=6c4c49c2c2303f94a39d5c598c4f75b9d2c894b1c30aa6b49c8ab7ca674c8ca9 -dist/2025-10-28/rust-nightly-i686-pc-windows-msvc.msi=f7c80d8c614f5b53a596bfd8a263fc0e680b554ec47630e36e23354afb7fd426 -dist/2025-10-28/rust-nightly-x86_64-pc-windows-gnu.msi=2f830bf3391a7da78de14ba4ffd82de8a49652262fcc7a3ae377a3703fe7ab93 -dist/2025-10-28/rust-nightly-x86_64-pc-windows-msvc.msi=c9b61b50bace832fc504853a5ea5dacd869909946c04d1d9c95b15385e98fd47 -dist/2025-10-28/rust-nightly-aarch64-apple-darwin.pkg=8d7cb75018220eac497ffa180c94b210e2e53e8e8c36ab8a39d6c4c6234fe72b -dist/2025-10-28/rust-nightly-x86_64-apple-darwin.pkg=82e9979fe0cdbac0e008f46cd2d7da70e9fa2caa0d4f1df56654cf57114c993a -dist/2025-10-28/rustc-nightly-src.tar.gz=f6da3a086dd47e5ace7eec9f03879d4c3082503912fe631e54e38168dac60f22 -dist/2025-10-28/rustc-nightly-src.tar.xz=523289ae9e6a87f076decc1beb412897184e728302826882bf53dfde4df4ce15 +dist/2025-12-11/rustc-1.92.0-aarch64-apple-darwin.tar.gz=9bba82c249776b282e25f4bc9c9386ea5ec81d3a2346281516c9da8910a5fd22 +dist/2025-12-11/rustc-1.92.0-aarch64-apple-darwin.tar.xz=15dee753c9217dff4cf45d734b29dc13ce6017d8a55fe34eed75022b39a63ff0 +dist/2025-12-11/rustc-1.92.0-aarch64-pc-windows-gnullvm.tar.gz=be37ee49589ab366548802d5f123ebd20eaeb7046c2f2149bbaef76582a154bb +dist/2025-12-11/rustc-1.92.0-aarch64-pc-windows-gnullvm.tar.xz=a7556b86bce94dd8c078a62f71a9a0a3f4b3e841bc5d4fae546d797b78186eb1 +dist/2025-12-11/rustc-1.92.0-aarch64-pc-windows-msvc.tar.gz=9296c18c3502c9c083bf39be6c5cab0d1afd39d3270810a1e630d6237f1cde0a +dist/2025-12-11/rustc-1.92.0-aarch64-pc-windows-msvc.tar.xz=07ba5606143de3bc916455714f67732fca05805591396a8190d5e88b8863eea3 +dist/2025-12-11/rustc-1.92.0-aarch64-unknown-linux-gnu.tar.gz=0d4e2145fe184fd6069c3a67deb44cc5bdadee7a631e742a025a47e3ea774577 +dist/2025-12-11/rustc-1.92.0-aarch64-unknown-linux-gnu.tar.xz=7c8706fad4c038b5eacab0092e15db54d2b365d5f3323ca046fe987f814e7826 +dist/2025-12-11/rustc-1.92.0-aarch64-unknown-linux-musl.tar.gz=da8c6d290ed86fb58ac9a7af78d3b0c27e1171e2ec62893fce667c085d172593 +dist/2025-12-11/rustc-1.92.0-aarch64-unknown-linux-musl.tar.xz=e7099dddd30f92093916e47a34cd6a866ea0acbf2836c17b74bdd795f0137a2a +dist/2025-12-11/rustc-1.92.0-arm-unknown-linux-gnueabi.tar.gz=601d613c027cccc3ed295c057d5948fe57cbe75992419970d15dc04e9b083b6f +dist/2025-12-11/rustc-1.92.0-arm-unknown-linux-gnueabi.tar.xz=18961e1d83fb747b60c766f68f8297a54452def6e79cc3e02c2d23712e0b3a17 +dist/2025-12-11/rustc-1.92.0-arm-unknown-linux-gnueabihf.tar.gz=5b79849c220f59a41f0949cd3b8fbf719200d3230b5922ae9b1c88e1f0860c42 +dist/2025-12-11/rustc-1.92.0-arm-unknown-linux-gnueabihf.tar.xz=53406761d1774302d50007ab005ff95befc9396856389fadbc94949629bed71d +dist/2025-12-11/rustc-1.92.0-armv7-unknown-linux-gnueabihf.tar.gz=f34a35f33fd922ffb5f9b40753c86159707449788dbb7fe43090dc030bc47cf1 +dist/2025-12-11/rustc-1.92.0-armv7-unknown-linux-gnueabihf.tar.xz=c49d5679f7f4f5ce3cf0d3b72c4299a0f95521087f3122d6c15be77658d4f9e9 +dist/2025-12-11/rustc-1.92.0-i686-pc-windows-gnu.tar.gz=9e8839f507a74653cfc06fc6de8a028d7874b933ea55e953f5a1d1eab29c9d0f +dist/2025-12-11/rustc-1.92.0-i686-pc-windows-gnu.tar.xz=a3dd59a53c7c919457b4c4eab814c3cd18cdc7a3f679fdaf8df6f9a21ef8c1ef +dist/2025-12-11/rustc-1.92.0-i686-pc-windows-msvc.tar.gz=4883ea7d39f7030a4290d7e9e5cc71483c867b4188bff293ff8f770bf4ee8f66 +dist/2025-12-11/rustc-1.92.0-i686-pc-windows-msvc.tar.xz=e892036f2ac1f24cdf853df74f631e9ad80fa6fcb2b9ca241527ed5b03eea96d +dist/2025-12-11/rustc-1.92.0-i686-unknown-linux-gnu.tar.gz=81b884e76b8e3b45509c20874f93d993477c4db2131745c8bf61282c8e673d78 +dist/2025-12-11/rustc-1.92.0-i686-unknown-linux-gnu.tar.xz=c1c920cd59e255e5dcf844af22b80483fe4b04ff04f143be6da69314bd6733f8 +dist/2025-12-11/rustc-1.92.0-loongarch64-unknown-linux-gnu.tar.gz=d85f10ad64fa7e8ddde205538503a97968f10d800e1432e8d22c94ff48a4345f +dist/2025-12-11/rustc-1.92.0-loongarch64-unknown-linux-gnu.tar.xz=6207ea209b332c01437fe742c2ef2bc914c88b6d4f9a23a43bc01ad924f6e4a8 +dist/2025-12-11/rustc-1.92.0-loongarch64-unknown-linux-musl.tar.gz=4203f9a11ffb57374dc498a6eb6f2df6f7bff4d13586a10af12476a69fb801b6 +dist/2025-12-11/rustc-1.92.0-loongarch64-unknown-linux-musl.tar.xz=66ac74c23df9f42cbda26587a37a70a67d5fd9821673656712a9f5a3b4cc8151 +dist/2025-12-11/rustc-1.92.0-powerpc-unknown-linux-gnu.tar.gz=84dc48d1b6b553439267dbb22bda57232e604764181cba7c19ed6a601b17ef27 +dist/2025-12-11/rustc-1.92.0-powerpc-unknown-linux-gnu.tar.xz=961cb6b8c2b5e969ad8eb0256fee43b88608b27310d946a7df3c9e9577139cae +dist/2025-12-11/rustc-1.92.0-powerpc64-unknown-linux-gnu.tar.gz=209a0e4371ae4f5670c58ca35cdd295d4b9f590b5270225b045a4655e3ca216e +dist/2025-12-11/rustc-1.92.0-powerpc64-unknown-linux-gnu.tar.xz=357dd4745f978080d35dbb6192ecfea331abbb93d88be7d70407856b30722a40 +dist/2025-12-11/rustc-1.92.0-powerpc64le-unknown-linux-gnu.tar.gz=89cdf91094ff3f68cc3bc679274134e491087eea3b0cf2fe61ebc2ce5f211827 +dist/2025-12-11/rustc-1.92.0-powerpc64le-unknown-linux-gnu.tar.xz=f48a214ff6fa36a77de8a0a2ee009be8aa48ba1533792450aca5edac29497606 +dist/2025-12-11/rustc-1.92.0-powerpc64le-unknown-linux-musl.tar.gz=9215fe368a7d22143b96d42d9ada17009420ea080e5650d30fb8a4e2e720117e +dist/2025-12-11/rustc-1.92.0-powerpc64le-unknown-linux-musl.tar.xz=f418ffded33abecec8d8aa72abf40448511ac78e8ae14ca43c066c7dd98310c3 +dist/2025-12-11/rustc-1.92.0-riscv64gc-unknown-linux-gnu.tar.gz=e36b96182e9a0c2e2f3a83cddfc5318a8ca2d049a0bddca9b42d05428ebed89d +dist/2025-12-11/rustc-1.92.0-riscv64gc-unknown-linux-gnu.tar.xz=729f4c074ccda30bff493fa94f255bcfcec1be594fecd8a4d0f57da845121c64 +dist/2025-12-11/rustc-1.92.0-s390x-unknown-linux-gnu.tar.gz=1fb255054864d857b32ca2c0dd06a2739cdd464d8872e18f2b103fb7a6d1f530 +dist/2025-12-11/rustc-1.92.0-s390x-unknown-linux-gnu.tar.xz=6a8cf614a74f7469c70d32b378f0163633e6bbe19624b248b758501c5bcdfe84 +dist/2025-12-11/rustc-1.92.0-sparcv9-sun-solaris.tar.gz=a5d20ba9277bb8b3b756f9f6dd2f7a1e9931ac8673fcca31d745eb81f1d573b6 +dist/2025-12-11/rustc-1.92.0-sparcv9-sun-solaris.tar.xz=74d6f885557f11b136d780c6fcc22d1db4b80644baaad22dbbbe29c890a0475a +dist/2025-12-11/rustc-1.92.0-x86_64-apple-darwin.tar.gz=d3dc5b7ddad48bb0afba0c6448aa00efec2d3fa9bc02ca55575c76d425c15ce4 +dist/2025-12-11/rustc-1.92.0-x86_64-apple-darwin.tar.xz=0facbd5d2742c8e97c53d59c9b5b81db6088cfc285d9ecb99523a50d6765fc5c +dist/2025-12-11/rustc-1.92.0-x86_64-pc-solaris.tar.gz=aeec5a91df699ab7a6b276e694a2711a59988dcc664ba9de43d5502e53d7b504 +dist/2025-12-11/rustc-1.92.0-x86_64-pc-solaris.tar.xz=03ed0965a4b4006f347513e7a2e7e0a9dac13053b432d65e97c59fd604973542 +dist/2025-12-11/rustc-1.92.0-x86_64-pc-windows-gnu.tar.gz=338ec86978c5d25799b79105c7bfb146002208d656f9e82b14692cd535c2ae65 +dist/2025-12-11/rustc-1.92.0-x86_64-pc-windows-gnu.tar.xz=fa0cbdf49f267f316433f054ca99951177827d0d406ddbaba9a0bbdcb093b56d +dist/2025-12-11/rustc-1.92.0-x86_64-pc-windows-gnullvm.tar.gz=b3575d7f29cd0423dbcf89457a9682acf8c0c1ad923136a12c7d3162c7b9a2d9 +dist/2025-12-11/rustc-1.92.0-x86_64-pc-windows-gnullvm.tar.xz=e67ec11b4c6e04e95effa7b4063ae8327c2861c6d08a7c692d69a0f1adcd8ecb +dist/2025-12-11/rustc-1.92.0-x86_64-pc-windows-msvc.tar.gz=4f321ca1903b8b08ceb07c0305f9f0320bc711ff6e285d726b8ef1dda774935d +dist/2025-12-11/rustc-1.92.0-x86_64-pc-windows-msvc.tar.xz=6aec5aba5384ce1041538e71ebebf671d82e29f4fe697bc7844626d94b0dbfe6 +dist/2025-12-11/rustc-1.92.0-x86_64-unknown-freebsd.tar.gz=a0c0710281e86f7523d116c3826ed406491430d9f92769e4f4b4caf28e686edf +dist/2025-12-11/rustc-1.92.0-x86_64-unknown-freebsd.tar.xz=f9b3a4fdb825c171e15f68db7c4faefecd60ea7475b9b11e98004fb7d711fd7c +dist/2025-12-11/rustc-1.92.0-x86_64-unknown-illumos.tar.gz=b48d9c46b58f00a164b35611a58d0ed13bf5dd4ff7b138252b61f8100fcd7434 +dist/2025-12-11/rustc-1.92.0-x86_64-unknown-illumos.tar.xz=e74f639cdfb368edfede795394932c8665cb192a2618e88c947ebd57ce2cc159 +dist/2025-12-11/rustc-1.92.0-x86_64-unknown-linux-gnu.tar.gz=e133546ebb40974356cc82434e07f6a0ce15966d8b01898f97eab235c46883e8 +dist/2025-12-11/rustc-1.92.0-x86_64-unknown-linux-gnu.tar.xz=78b2dd9c6b1fcd2621fa81c611cf5e2d6950690775038b585c64f364422886e0 +dist/2025-12-11/rustc-1.92.0-x86_64-unknown-linux-musl.tar.gz=eaff6d6b051e59875eb585a981c799be87a2a68f1d52556dc64e26531a499531 +dist/2025-12-11/rustc-1.92.0-x86_64-unknown-linux-musl.tar.xz=f1a037c367d29d329d041f0bf1d271e60440adc961b6eaa9ea902018a672d4a3 +dist/2025-12-11/rustc-1.92.0-x86_64-unknown-netbsd.tar.gz=49f33344d9b22dea5a4f97f1d1c4fdb52afd1c34bd5fd78bb8d7e5e5ee92333c +dist/2025-12-11/rustc-1.92.0-x86_64-unknown-netbsd.tar.xz=a0cdbdd508e72de8f3e783b61827fac1f741acd6503464dc263a7292880a16e5 +dist/2025-12-11/rust-std-1.92.0-aarch64-apple-darwin.tar.gz=b1f55aac4bc982ea67b68b262b711263005e470d31cab5d09d534bc1866d455a +dist/2025-12-11/rust-std-1.92.0-aarch64-apple-darwin.tar.xz=ea619984fcb8e24b05dbd568d599b8e10d904435ab458dfba6469e03e0fd69aa +dist/2025-12-11/rust-std-1.92.0-aarch64-apple-ios.tar.gz=449a3f453215eaa86ee80bd4f70cb1a8dfca0447e27f7e820a73047913d7c724 +dist/2025-12-11/rust-std-1.92.0-aarch64-apple-ios.tar.xz=81fb496f94a3f52ec2818a76a7107905b13b37d490ca849d22c0a7a7d7b0125e +dist/2025-12-11/rust-std-1.92.0-aarch64-apple-ios-macabi.tar.gz=cc4ca331919012b71cb634082ab761003c752067a7b7cbcdb5a513a56f629bef +dist/2025-12-11/rust-std-1.92.0-aarch64-apple-ios-macabi.tar.xz=d0453906db0abe9efb595e1ed59feb131a94c0312c0bc72da6482936667ff8da +dist/2025-12-11/rust-std-1.92.0-aarch64-apple-ios-sim.tar.gz=1e08495db970e62931fd1f2349b10c04a765469aecd84b9ded10bcf09e98904d +dist/2025-12-11/rust-std-1.92.0-aarch64-apple-ios-sim.tar.xz=9362b66fbaf2503276ea34f34b41b171269db9ba4dce05dde3472ea9d1852601 +dist/2025-12-11/rust-std-1.92.0-aarch64-linux-android.tar.gz=f6689cf5b71056e887261ec84ae1f499eeb42c67e5ae73e7c0e06065b6648c44 +dist/2025-12-11/rust-std-1.92.0-aarch64-linux-android.tar.xz=ce6350bd43856c630773c93e40310989c6cb98a1178233c44e512a31761943d0 +dist/2025-12-11/rust-std-1.92.0-aarch64-pc-windows-gnullvm.tar.gz=4b4774c66e6952fb46d0049dffb2c664d95712052c4816e354bca3e97799dda4 +dist/2025-12-11/rust-std-1.92.0-aarch64-pc-windows-gnullvm.tar.xz=4e79f57b80040757a3425568b5978986f026daf771649a64021c74bcc138214b +dist/2025-12-11/rust-std-1.92.0-aarch64-pc-windows-msvc.tar.gz=7b27adfa0f10ee44a78430ad7ec000eb95cf4586b7338bc001dae5d5b865578c +dist/2025-12-11/rust-std-1.92.0-aarch64-pc-windows-msvc.tar.xz=b20c5c696af4ecfb683370ca0ee3c76ab8726fe6470ce9f1368d41a5b06ea065 +dist/2025-12-11/rust-std-1.92.0-aarch64-unknown-fuchsia.tar.gz=ead00e822bf91191e4982e35d89744e977a9c51aa1b3ea1717e744c899067ee5 +dist/2025-12-11/rust-std-1.92.0-aarch64-unknown-fuchsia.tar.xz=6021246b6c0d9d6104c0b350f7cd48a31d5707edaa8063f77f5636fe07bdb79d +dist/2025-12-11/rust-std-1.92.0-aarch64-unknown-linux-gnu.tar.gz=04a5c9883bce2c4e89d22dd68af1bdc29b741bb456c01f8839b759a163e8e9d4 +dist/2025-12-11/rust-std-1.92.0-aarch64-unknown-linux-gnu.tar.xz=ce2ab42c09d633b0a8b4b65a297c700ae0fad47aae890f75894782f95be7e36d +dist/2025-12-11/rust-std-1.92.0-aarch64-unknown-linux-musl.tar.gz=715fbcfd8712c723947a020d0371c8a1a21f7531f2b696aeaed50ac23ba675c9 +dist/2025-12-11/rust-std-1.92.0-aarch64-unknown-linux-musl.tar.xz=94b9f84f21d29825c55a27fbb6b4b9fb9296a4a841aa54d85b95c42445623363 +dist/2025-12-11/rust-std-1.92.0-aarch64-unknown-linux-ohos.tar.gz=0971b3c864ab1baa06a7fb5ba2fb176d8ca762bdecfd9e374810dc827d69d134 +dist/2025-12-11/rust-std-1.92.0-aarch64-unknown-linux-ohos.tar.xz=6fb30061fae54c4a27bb209d314456d04826c345a8015b10d1fe9b82eeb46f9c +dist/2025-12-11/rust-std-1.92.0-aarch64-unknown-none.tar.gz=93e18afe654009b56783f1295d25a8bafa31badc8f6fcb46c2e217856daf68a6 +dist/2025-12-11/rust-std-1.92.0-aarch64-unknown-none.tar.xz=ab6a2edab924739fc2c86e9f8fd8068b379e881a6261a177d66608d3ea4cacb1 +dist/2025-12-11/rust-std-1.92.0-aarch64-unknown-none-softfloat.tar.gz=911108d6f01ff1040ea3de993bcf3ea52fe19aee099516a607e9967ce4813bcb +dist/2025-12-11/rust-std-1.92.0-aarch64-unknown-none-softfloat.tar.xz=0dc46fafaaa36f53eec49e14a69e1d6d9ac6f0b9624a01081ad311d8139a2be0 +dist/2025-12-11/rust-std-1.92.0-aarch64-unknown-uefi.tar.gz=a14f2491f87149b779460b898ff1208adc31fc463094d8eff86e778fce9f6ce6 +dist/2025-12-11/rust-std-1.92.0-aarch64-unknown-uefi.tar.xz=f98001222bf23743598382c232b08d3137035b53645a420a1425288d501808af +dist/2025-12-11/rust-std-1.92.0-arm-linux-androideabi.tar.gz=7d9d430c187580c1075649dfdef03dde9f5616ed74ed050ae01cc9d5eda79268 +dist/2025-12-11/rust-std-1.92.0-arm-linux-androideabi.tar.xz=d41ec7255556b605dda04201a23e4445b5b86bc6786c703f91eb985bddc9f4ca +dist/2025-12-11/rust-std-1.92.0-arm-unknown-linux-gnueabi.tar.gz=56d8b0df4b716a69aeefc06fbd859461938d54bcac37d7eea25b07764f6e3c5c +dist/2025-12-11/rust-std-1.92.0-arm-unknown-linux-gnueabi.tar.xz=35478e20f8cc13912b31f2905b313a2820ddae564b363a66ab7a5da39d12787f +dist/2025-12-11/rust-std-1.92.0-arm-unknown-linux-gnueabihf.tar.gz=d0a355524cf219351f15d8984c102f6425bc2c6c1e14af9282e2db60a997a5e0 +dist/2025-12-11/rust-std-1.92.0-arm-unknown-linux-gnueabihf.tar.xz=836ada282b65c57d71f9b7e6fb490832410c954aac905c5437fb0bf851b53c83 +dist/2025-12-11/rust-std-1.92.0-arm-unknown-linux-musleabi.tar.gz=a505ed45f3c55334e8294f304366e2210609305dd25a86b0396c89016219a9d7 +dist/2025-12-11/rust-std-1.92.0-arm-unknown-linux-musleabi.tar.xz=91d3c5fdbda9ba2e778bb638e3a5d060f3021bbc7a60edf22b0035be4e611b30 +dist/2025-12-11/rust-std-1.92.0-arm-unknown-linux-musleabihf.tar.gz=1a2bba0ac573420064fec467a713ab169b54d9281d5652817d5d628a98ff167a +dist/2025-12-11/rust-std-1.92.0-arm-unknown-linux-musleabihf.tar.xz=20411e3858308add0dadde9ce2059d82cdd6c5339881fa93ac995e733df0f832 +dist/2025-12-11/rust-std-1.92.0-arm64ec-pc-windows-msvc.tar.gz=8cca22404b172c1ac590e6a507ec73bece0e3698bfd74f549246d23392ee3a45 +dist/2025-12-11/rust-std-1.92.0-arm64ec-pc-windows-msvc.tar.xz=1618d3d429a3c9b06d43bcc12ec7c50c5eb6cb01cb2f077c525bc0f077c7a6f0 +dist/2025-12-11/rust-std-1.92.0-armv5te-unknown-linux-gnueabi.tar.gz=547a6282ed5896dbac1df388a116301cfedf41fc579fa25caa57b3ee7e333e19 +dist/2025-12-11/rust-std-1.92.0-armv5te-unknown-linux-gnueabi.tar.xz=702be50f225ad4681af1bf9c40fd020b4623ee46aab5363ea96e4874dffb694d +dist/2025-12-11/rust-std-1.92.0-armv5te-unknown-linux-musleabi.tar.gz=578a0eee2513520e4195e09c0657b074cc9f7bff215507ddd905cfe7b15bab77 +dist/2025-12-11/rust-std-1.92.0-armv5te-unknown-linux-musleabi.tar.xz=c1c645c1b33625b9735a7c6f062a122fb172957093fac33f8ee3b80663deeb41 +dist/2025-12-11/rust-std-1.92.0-armv7-linux-androideabi.tar.gz=18f6e6903c5f4361efe8c8a1ea546303e4473e8b9cd1b11fcf4e5b170468d464 +dist/2025-12-11/rust-std-1.92.0-armv7-linux-androideabi.tar.xz=06ac2f08dcf5c480e7767c0541c9bd7460754ec3a369a4b7097b328eca28fab9 +dist/2025-12-11/rust-std-1.92.0-armv7-unknown-linux-gnueabi.tar.gz=1e2238cb33c6adc29c13fdc980a4019587f69af5ae88f7bd473da2dbd9b70a2c +dist/2025-12-11/rust-std-1.92.0-armv7-unknown-linux-gnueabi.tar.xz=3d5e3fb14441ea8e6fc6307cbd89efd69be42143ff7f2b8dfb19818ddca993c0 +dist/2025-12-11/rust-std-1.92.0-armv7-unknown-linux-gnueabihf.tar.gz=2c44994e0982bdb60c132c40b481b3c6ca83a131f09d568831553e3e29384130 +dist/2025-12-11/rust-std-1.92.0-armv7-unknown-linux-gnueabihf.tar.xz=e3ac810db43067d8af9e17679d47534e871f1daad8cd0762e67da935681e9e19 +dist/2025-12-11/rust-std-1.92.0-armv7-unknown-linux-musleabi.tar.gz=3bf1b0015dc3b0f5f6f5622588431855c658d5c47093f24e4077f6893229ab30 +dist/2025-12-11/rust-std-1.92.0-armv7-unknown-linux-musleabi.tar.xz=89cbf7db934d543754b446a52398081ec40ee6b98ed5bca93ac1dbd5faf48c16 +dist/2025-12-11/rust-std-1.92.0-armv7-unknown-linux-musleabihf.tar.gz=fc5c4ca757599caab8e93000becb9d57587088d32dab5c4f3b253f00ec3a2fd6 +dist/2025-12-11/rust-std-1.92.0-armv7-unknown-linux-musleabihf.tar.xz=c7c08a389bd351226fd52266bfe2d2c444597e1bbb5d0307da44bdfa4df62c99 +dist/2025-12-11/rust-std-1.92.0-armv7-unknown-linux-ohos.tar.gz=4cc8337f39f1b2820880dd8cac203399b5fd0eee7716d0a9c785a71f6d9fbf50 +dist/2025-12-11/rust-std-1.92.0-armv7-unknown-linux-ohos.tar.xz=e75603f745d5becd2e79d0cd6c7976e53bcc56d7af8ba1ac4e3494effc502f15 +dist/2025-12-11/rust-std-1.92.0-armv7a-none-eabi.tar.gz=b7b68dc24eb7e80592938a928372391e57fc04066238b178855f06863a597341 +dist/2025-12-11/rust-std-1.92.0-armv7a-none-eabi.tar.xz=e97368a7876332ce5181d8efca43996ee9d16ecc0be195e7d9b4f295a36c39ac +dist/2025-12-11/rust-std-1.92.0-armv7a-none-eabihf.tar.gz=f79f1983b5c3867657ba1849472b0aa1a54ab1ab94bab66f046583f8858bebad +dist/2025-12-11/rust-std-1.92.0-armv7a-none-eabihf.tar.xz=407899b91b4a44d5096bebbae00b3044ecc71e4cce958f79a149f4149a662bf6 +dist/2025-12-11/rust-std-1.92.0-armv7r-none-eabi.tar.gz=310c5149e672a794364c389ee383f437e367eac912c8c9c63e9e024c8eb5a98e +dist/2025-12-11/rust-std-1.92.0-armv7r-none-eabi.tar.xz=d135b9aa652dbdbf8115c31a71eb5b5e022968dd3c98a6d0421ad13ed8b8385e +dist/2025-12-11/rust-std-1.92.0-armv7r-none-eabihf.tar.gz=49b7583f91e42ee05c057e8ca5b736d883725d40e71bc8f8ce369b46bb074343 +dist/2025-12-11/rust-std-1.92.0-armv7r-none-eabihf.tar.xz=d6b44323ffcb32ead9be54ef4786048f48cec1f18cd269e2fcab36d2c3d5e7e9 +dist/2025-12-11/rust-std-1.92.0-armv8r-none-eabihf.tar.gz=f0b184acd74d500d6a7f559a62d7946d00fed6ac427bdbd7c52640be6d98e767 +dist/2025-12-11/rust-std-1.92.0-armv8r-none-eabihf.tar.xz=355ffd45d0d450e1e5d2ce8aa1ff0977ebb4b3ca9c6689e8d72dcd2c56b6046d +dist/2025-12-11/rust-std-1.92.0-i586-unknown-linux-gnu.tar.gz=3fb6630b6341a07a9bbc37a8c541ad3e389a26dc0ef48c09aa3b14a6afbf672a +dist/2025-12-11/rust-std-1.92.0-i586-unknown-linux-gnu.tar.xz=8b984b31ffca1f27d32ee77ec2cc4c2ab59e72beab67bfce13bbd926dbea8715 +dist/2025-12-11/rust-std-1.92.0-i586-unknown-linux-musl.tar.gz=6c39e5506fd6a0532d15f3cd9510e6e9fb0da0712f426b8a55f04114125b6e13 +dist/2025-12-11/rust-std-1.92.0-i586-unknown-linux-musl.tar.xz=059d919f147e6bd40e132ad00ee23de59d5464f5e3409f3139b3ac14faf45893 +dist/2025-12-11/rust-std-1.92.0-i686-linux-android.tar.gz=d994d70493ad68ced22a5269e41b9fa6f83af9f3adabade154860058bc2e18c0 +dist/2025-12-11/rust-std-1.92.0-i686-linux-android.tar.xz=e45832b005556f65c6d26f05f34bd4ab5ceea8d9b9fefc4175d52b0780ca89db +dist/2025-12-11/rust-std-1.92.0-i686-pc-windows-gnu.tar.gz=5f30330e61a7d87426e3192e3ba99ec5db2b3d239825f15ce7482b88e695757e +dist/2025-12-11/rust-std-1.92.0-i686-pc-windows-gnu.tar.xz=b3eefe10d4aed3ccbeaff3ae9cd2e0e0a36894c0635d0e69af1c9a698679d75f +dist/2025-12-11/rust-std-1.92.0-i686-pc-windows-gnullvm.tar.gz=916badef8e6415e599b41b706aa522f514ee2932b5e65baea5b04db34e03c185 +dist/2025-12-11/rust-std-1.92.0-i686-pc-windows-gnullvm.tar.xz=e6d709f85dea51d81f2f1a030845b732b9f7761d95d93c57c7276b0a451c2993 +dist/2025-12-11/rust-std-1.92.0-i686-pc-windows-msvc.tar.gz=2d248d48ff8650e61097c57d653ae3c785413b8fa916c51623374b22c5f3be0c +dist/2025-12-11/rust-std-1.92.0-i686-pc-windows-msvc.tar.xz=e5671b276047647e994a7cab99c90ee70c46787572fbe4e266a13c6edb84d5ce +dist/2025-12-11/rust-std-1.92.0-i686-unknown-freebsd.tar.gz=235c77dac41505cfc170a448ff70695fbb78b986e6febbb72eb931f23c66d8cc +dist/2025-12-11/rust-std-1.92.0-i686-unknown-freebsd.tar.xz=e008a0506ec4d5eff30abdf376c7933e235670bd6c5e1131c52bcda097a21116 +dist/2025-12-11/rust-std-1.92.0-i686-unknown-linux-gnu.tar.gz=f568a3c307fad16528bf5accecfdce9e77b6ebda3302ae7a79588adc10d2bd29 +dist/2025-12-11/rust-std-1.92.0-i686-unknown-linux-gnu.tar.xz=abc840631a4462a4c8ec61341110ff653ab2ef86ef3b10f84489d00cc8a9310d +dist/2025-12-11/rust-std-1.92.0-i686-unknown-linux-musl.tar.gz=3d6ccb700a17533eea10c7541896c92817783045c5537af37228142da7668fb3 +dist/2025-12-11/rust-std-1.92.0-i686-unknown-linux-musl.tar.xz=c796874b1343721f575203fa179dc258e09ac45cd95dd6c35c4d5979a3870494 +dist/2025-12-11/rust-std-1.92.0-i686-unknown-uefi.tar.gz=78814c81a60fc1e3326f6d00eee4bc907053bb3a8971a825bf6728ba645f264c +dist/2025-12-11/rust-std-1.92.0-i686-unknown-uefi.tar.xz=90da7759e28e62fb82454d4eb4e02ac14320b8da3372e02f9ca4f47f7afbfe40 +dist/2025-12-11/rust-std-1.92.0-loongarch64-unknown-linux-gnu.tar.gz=cabff40eb871616ce5d40592262b25aba1e6ff8f309bb6e0dab08609470dcfce +dist/2025-12-11/rust-std-1.92.0-loongarch64-unknown-linux-gnu.tar.xz=62e2568ebf6f1addc750a8c32dd1fa4fef8d27679cbac33b837afeb54f204819 +dist/2025-12-11/rust-std-1.92.0-loongarch64-unknown-linux-musl.tar.gz=e46b3f6a18ba0faa5190deb3ee296fc971214c9d38f9d616fce2457e335a98a8 +dist/2025-12-11/rust-std-1.92.0-loongarch64-unknown-linux-musl.tar.xz=274838eebb615e6d2719157aa53230cd0c3233a1e6f1c975c0f5978198c55da3 +dist/2025-12-11/rust-std-1.92.0-loongarch64-unknown-none.tar.gz=dfe120d2bc8cb81ee70c2a2e1ad685d382a0ebd72b37231183d8cb7b6890effe +dist/2025-12-11/rust-std-1.92.0-loongarch64-unknown-none.tar.xz=7e03cbb3aeb5a2c882433f2de0d096455bcab2465729cb0399d1b31e2d400075 +dist/2025-12-11/rust-std-1.92.0-loongarch64-unknown-none-softfloat.tar.gz=7e07f54e69ee2b7e4ef2861d7b1fcadfe3fda3ccb5442e0d85afe1dfdfc52b8a +dist/2025-12-11/rust-std-1.92.0-loongarch64-unknown-none-softfloat.tar.xz=dd01f0348ca2c90d6115b79894360f9ae8468aa8755e0f345e53fe5186f2d891 +dist/2025-12-11/rust-std-1.92.0-nvptx64-nvidia-cuda.tar.gz=3f4ac1e0c35b4a709d926727a49c86d169fa61660d08e940f10f948da9777375 +dist/2025-12-11/rust-std-1.92.0-nvptx64-nvidia-cuda.tar.xz=e8d3d0d81d5bb92baae3f0cc0c43d456e312d6f2770c460ff62521dccba7a855 +dist/2025-12-11/rust-std-1.92.0-powerpc-unknown-linux-gnu.tar.gz=28320c60a2fb42756d7a825f44d35c12100492c44770b0658056e4c468974f86 +dist/2025-12-11/rust-std-1.92.0-powerpc-unknown-linux-gnu.tar.xz=c3e809a324b00eb53096c58df38645bb496c6560de334dfe04ed0b77c0605aaa +dist/2025-12-11/rust-std-1.92.0-powerpc64-unknown-linux-gnu.tar.gz=c47938c152f1b237c901090d69522ce1ccfa69a859ed10d634fe3083108c3017 +dist/2025-12-11/rust-std-1.92.0-powerpc64-unknown-linux-gnu.tar.xz=2ce706afa4a46b6773340854de877fc63618a40e351298a4e3da8eb482619863 +dist/2025-12-11/rust-std-1.92.0-powerpc64le-unknown-linux-gnu.tar.gz=f63de16a3c3f8e11aaf21de60ec38de59b1234aea4fe38d0577414a43adc4a8e +dist/2025-12-11/rust-std-1.92.0-powerpc64le-unknown-linux-gnu.tar.xz=eba59766c2d9805c0a1fc82fd723acbb36569e1bec1088c037bba84d965f70ba +dist/2025-12-11/rust-std-1.92.0-powerpc64le-unknown-linux-musl.tar.gz=696958d87842d877640140ddbbaa74d044374874dee9516e227a395b70bfb8d4 +dist/2025-12-11/rust-std-1.92.0-powerpc64le-unknown-linux-musl.tar.xz=8b515e18b6ac8f8d37ea3cabe644b7f571984333c3b4192b7f5877e79eae7893 +dist/2025-12-11/rust-std-1.92.0-riscv32i-unknown-none-elf.tar.gz=a56084ad27ec50df0a0da2473deb84d51cb831cbf913bf983a029850e9e9f0ac +dist/2025-12-11/rust-std-1.92.0-riscv32i-unknown-none-elf.tar.xz=e115633fa0dccec2f94477e26c5c93cbb17c54af2769e19b4636f50708a00f6b +dist/2025-12-11/rust-std-1.92.0-riscv32im-unknown-none-elf.tar.gz=b1ac7c191995b67f819446f2dc1bc4a3e66036aa5ae54ad05b7891bb4bbf0e50 +dist/2025-12-11/rust-std-1.92.0-riscv32im-unknown-none-elf.tar.xz=2d7547fbf012b06a2b570c94e3611b86fb10edcf23589c47ea4da99c87d50537 +dist/2025-12-11/rust-std-1.92.0-riscv32imac-unknown-none-elf.tar.gz=52d8c75e48a2575381e2a041a5bb359adf161a6c29f4ba990e54384fa6699861 +dist/2025-12-11/rust-std-1.92.0-riscv32imac-unknown-none-elf.tar.xz=5915223db6b8afa173f67eb4fe6f5aff2402351ed9abab1b370d0860be4af6c9 +dist/2025-12-11/rust-std-1.92.0-riscv32imafc-unknown-none-elf.tar.gz=2bd1d15d7d1e1a133afc7244375f3af405453153c4c3f924a0ee019fff807ca6 +dist/2025-12-11/rust-std-1.92.0-riscv32imafc-unknown-none-elf.tar.xz=a3de78da39a79a9facf729ac005f69b4d3c68044f0b8ec4daa9e271a719d9a46 +dist/2025-12-11/rust-std-1.92.0-riscv32imc-unknown-none-elf.tar.gz=939b46b6320a082d562ba79efd53a028b3c01276f70106ecbcc95148b013f990 +dist/2025-12-11/rust-std-1.92.0-riscv32imc-unknown-none-elf.tar.xz=e1c6968ce25ab78f2c5b5460691763a2d39cb71b01d6d54c208d4a8b735b0584 +dist/2025-12-11/rust-std-1.92.0-riscv64gc-unknown-linux-gnu.tar.gz=b15965fec2297deff49412cc0e22a005db5ff710ca77187058c4907f1e7dd467 +dist/2025-12-11/rust-std-1.92.0-riscv64gc-unknown-linux-gnu.tar.xz=8ee20dcf3b1063fa6069b3ce85e1fcf42794dfa783263314865cb53fff42d9e4 +dist/2025-12-11/rust-std-1.92.0-riscv64gc-unknown-linux-musl.tar.gz=34f5722ff2a0940bcd7ff6603a7748d2b963de72f6f713579c39c74ead06a7a0 +dist/2025-12-11/rust-std-1.92.0-riscv64gc-unknown-linux-musl.tar.xz=f20d822309900fd6c7230688694baf91e900154e44e6247feca49b7b7a203a57 +dist/2025-12-11/rust-std-1.92.0-riscv64gc-unknown-none-elf.tar.gz=aa6d992ef5ea58a732e9f7a5843b37b6d03059f0de90bd6f0e45a9067e4c52cf +dist/2025-12-11/rust-std-1.92.0-riscv64gc-unknown-none-elf.tar.xz=7eacf6a98786d58ef912643fd5aedc35111712e96a47b7e5d3ccddcdf9fb166d +dist/2025-12-11/rust-std-1.92.0-riscv64imac-unknown-none-elf.tar.gz=d81c6b2c7c71e38e6b0e1634af5b782e23f35adef36e1f35237d66c191d9f170 +dist/2025-12-11/rust-std-1.92.0-riscv64imac-unknown-none-elf.tar.xz=e3eda32b99bbff3fe77aa72c29de9373009e8650f7ab93c2b4c344ad13bc459e +dist/2025-12-11/rust-std-1.92.0-s390x-unknown-linux-gnu.tar.gz=c33203be69a7415c6d3465bc30189617684105bdcd68a3c78d6b7257c83b005b +dist/2025-12-11/rust-std-1.92.0-s390x-unknown-linux-gnu.tar.xz=ebf944dc95015498d322504a54e4f9cdb28590f7790aa3a9eb86d6cf4b6c93ff +dist/2025-12-11/rust-std-1.92.0-sparc64-unknown-linux-gnu.tar.gz=6915a7d1880facef71d4712623b254a78fdc7c9edc8f98e3200b6095d81b99ab +dist/2025-12-11/rust-std-1.92.0-sparc64-unknown-linux-gnu.tar.xz=d85afb14120c3c7367338a565a920db653dccd4bc5062398791d7b62b89fd1fd +dist/2025-12-11/rust-std-1.92.0-sparcv9-sun-solaris.tar.gz=637a8fcc402792ab97411031258fdbbfbe66328fbc4aad8aa536f598501ba10d +dist/2025-12-11/rust-std-1.92.0-sparcv9-sun-solaris.tar.xz=e9ae7dc479e6c97335b3ebee8c3d69069cf6a617942196871229794ca94f3458 +dist/2025-12-11/rust-std-1.92.0-thumbv6m-none-eabi.tar.gz=a8a57993bb98d61486fac274b285168e253988d7a7fca0b3f72dc23057d9a88e +dist/2025-12-11/rust-std-1.92.0-thumbv6m-none-eabi.tar.xz=f55de77126b60e1da38f8a5cdd127db872155ce9fbb53d4459502dd47b1dd476 +dist/2025-12-11/rust-std-1.92.0-thumbv7em-none-eabi.tar.gz=fdbc35de85989f4c2155b813d1ba4abb34f57c195d97ed863c06de8b8fb426d7 +dist/2025-12-11/rust-std-1.92.0-thumbv7em-none-eabi.tar.xz=fdee017dcebfa8675220c20ca65b945b6eaee744d5d19b92cb0ca5480dd19ba6 +dist/2025-12-11/rust-std-1.92.0-thumbv7em-none-eabihf.tar.gz=d94cd679358a4eb33970df571fdfcacb385980c4f4a3f92114ffa5d356f86456 +dist/2025-12-11/rust-std-1.92.0-thumbv7em-none-eabihf.tar.xz=6bfd083ce4917440fb4b04ca39ab4dadc9f40d9dc2775056899857bfa8911fd0 +dist/2025-12-11/rust-std-1.92.0-thumbv7m-none-eabi.tar.gz=7861c515c0fdb2fcf74e434813d43de8d0b084babdd87b9cd8bf67fc173cfc54 +dist/2025-12-11/rust-std-1.92.0-thumbv7m-none-eabi.tar.xz=7dc4c92e97db5ce1ddd9fbb7fbb1ad2d367f1c2e20d296a6d6427480c900c315 +dist/2025-12-11/rust-std-1.92.0-thumbv7neon-linux-androideabi.tar.gz=28f77e164fbdb373d5bf729a7672d775d57a08ccbbf2d8d6aefffa0f1b9d6112 +dist/2025-12-11/rust-std-1.92.0-thumbv7neon-linux-androideabi.tar.xz=ce99df993198da32a2f655d8f6666f2ef7995242cdc31686db49bfeac07e6f7c +dist/2025-12-11/rust-std-1.92.0-thumbv7neon-unknown-linux-gnueabihf.tar.gz=c9de934e22d796a4f542783d60b43b62a213a15014bbea02ca9f9520abfec872 +dist/2025-12-11/rust-std-1.92.0-thumbv7neon-unknown-linux-gnueabihf.tar.xz=08a51cb570fc25bf226c25c1031b98d3963a52e263bbacd873f111faa918484e +dist/2025-12-11/rust-std-1.92.0-thumbv8m.base-none-eabi.tar.gz=06453a93570c63a0d6a56000493d4e6ff20f1e20c4c3b9ec7124359ebc79a3eb +dist/2025-12-11/rust-std-1.92.0-thumbv8m.base-none-eabi.tar.xz=3c5d71fa1d6f242be184339d8bbb360acf9ca552f0093c10309c83e06a95bcaf +dist/2025-12-11/rust-std-1.92.0-thumbv8m.main-none-eabi.tar.gz=c3c0cde9afce994bfbd0f2fbde02efb6ad1238a3d33056ccac6e99aba579af3a +dist/2025-12-11/rust-std-1.92.0-thumbv8m.main-none-eabi.tar.xz=61a6a80d03ebdb80ab06a044d4ec60e3c2bd8dc4d6011e920cf41592df4f0646 +dist/2025-12-11/rust-std-1.92.0-thumbv8m.main-none-eabihf.tar.gz=21336cc1a032eb35b8c4a546805ce1e8e3afa24735ee23aae5599fd8787ce581 +dist/2025-12-11/rust-std-1.92.0-thumbv8m.main-none-eabihf.tar.xz=24c2f65371a2a5c6a40b51ae0e276ea9afff0479255f180f5e1549a0a4d58fb3 +dist/2025-12-11/rust-std-1.92.0-wasm32-unknown-emscripten.tar.gz=fec9cb6cced27592fa601c18afb357bb861d5ebeaad1dda9304f6acfd85b4000 +dist/2025-12-11/rust-std-1.92.0-wasm32-unknown-emscripten.tar.xz=59b7adf18c0cc416a005fad7f704203b965905eb1c0ed9c556daa3c14048b9f4 +dist/2025-12-11/rust-std-1.92.0-wasm32-unknown-unknown.tar.gz=4763b575ecceab7637557527a91af6c5c36816a68e3f2de1e18518dd15a63bcd +dist/2025-12-11/rust-std-1.92.0-wasm32-unknown-unknown.tar.xz=6c73f053ccd6adc886f802270ba960fd854e5e1111e4b5cfb875f1fdcfc0eb60 +dist/2025-12-11/rust-std-1.92.0-wasm32-wasip1.tar.gz=a8736000e35213951e53315e3d5841cbe8e6c70fad167a302bd8ae1a43331cec +dist/2025-12-11/rust-std-1.92.0-wasm32-wasip1.tar.xz=8107dc35f0b6b744d998e766351419b4e0d27cddd6456c461337753a25f29fcd +dist/2025-12-11/rust-std-1.92.0-wasm32-wasip1-threads.tar.gz=87476037322f6bb9467467ce0b11bc2fe81d9fab181a14f6adbb949136f044d6 +dist/2025-12-11/rust-std-1.92.0-wasm32-wasip1-threads.tar.xz=feea056dd657a26560dfddfe4b53daeef3ded83c140b453b6dbdebaabd2a664c +dist/2025-12-11/rust-std-1.92.0-wasm32-wasip2.tar.gz=20b2ee79e2a66f80764f2829b9cd313bd66532fff85c71a75cd7d4f6f75decbf +dist/2025-12-11/rust-std-1.92.0-wasm32-wasip2.tar.xz=e69ce601b6b24eea08b0d9e1fb0d9bf2a4188b3109353b272be4d995f687c943 +dist/2025-12-11/rust-std-1.92.0-wasm32v1-none.tar.gz=b5d12a32aef0ce2be6999e7a15f21496e50fc9366e2dceb273e3816381821f73 +dist/2025-12-11/rust-std-1.92.0-wasm32v1-none.tar.xz=0b89f2b5a720589168a81e294fc80ab6bc2c7bbe5509030dd17ad38e221ce903 +dist/2025-12-11/rust-std-1.92.0-x86_64-apple-darwin.tar.gz=1e5a8fee4e038ea2d35d82a680e2b9bf44ffccb3746aaf9dbdc56cb14152dcb8 +dist/2025-12-11/rust-std-1.92.0-x86_64-apple-darwin.tar.xz=6ce143bf9e83c71e200f4180e8774ab22c8c8c2351c88484b13ff13be82c8d57 +dist/2025-12-11/rust-std-1.92.0-x86_64-apple-ios.tar.gz=4ca50621893f34bde5ad81cd82006c8b271fef8cc0ba4a4e1418fe3dbf599e56 +dist/2025-12-11/rust-std-1.92.0-x86_64-apple-ios.tar.xz=b6e38e5f8c9e6fb294681a7951301856b8f9424af4589e14493c0c939338814c +dist/2025-12-11/rust-std-1.92.0-x86_64-apple-ios-macabi.tar.gz=14e6389c01ab709dbf62885639b8c3e6fc97e6d8fa91f9805db26e9309107ec2 +dist/2025-12-11/rust-std-1.92.0-x86_64-apple-ios-macabi.tar.xz=6a292d774653f2deaac743060ec68bfd5d7ff01d9b364e1a7d1e57a679650b47 +dist/2025-12-11/rust-std-1.92.0-x86_64-fortanix-unknown-sgx.tar.gz=88fc95491ec06d98bde84ccf4b6a4cc63aa0a6d3e66e0d796de158afb7d69c67 +dist/2025-12-11/rust-std-1.92.0-x86_64-fortanix-unknown-sgx.tar.xz=b0339c3bf7966e7b1c9892f855c85d123382632f49a1d1f589db68bf0908feb7 +dist/2025-12-11/rust-std-1.92.0-x86_64-linux-android.tar.gz=b9074f6961baff09334afaff745fb16dbf9f05cdf856b17309d8e6232a281c40 +dist/2025-12-11/rust-std-1.92.0-x86_64-linux-android.tar.xz=ffd39429435ff2f0763b940dd6afb4b9ccb1ed443eeef4fff9f1e9b3c5730026 +dist/2025-12-11/rust-std-1.92.0-x86_64-pc-solaris.tar.gz=28f7f5568399c56e64f614194dc70f7073c0e394c5ad60bcb85dc1b1018c6089 +dist/2025-12-11/rust-std-1.92.0-x86_64-pc-solaris.tar.xz=776ceb389296b22a74bd7631f4440b965504d1687448030d2d51c853fe4598a5 +dist/2025-12-11/rust-std-1.92.0-x86_64-pc-windows-gnu.tar.gz=6256f3497e3b14b6650511e84fdfb51fc632db1908ae5a173dffcdc96c80b7ce +dist/2025-12-11/rust-std-1.92.0-x86_64-pc-windows-gnu.tar.xz=d4043304ef0e4792fb79a1153cbeca41308aac37cb1af3aa6bc3f0bb6d2276e1 +dist/2025-12-11/rust-std-1.92.0-x86_64-pc-windows-gnullvm.tar.gz=67bd7e328b9579c01365c01f58e29fa616806444eafb9b8bfead0de2b57fcf32 +dist/2025-12-11/rust-std-1.92.0-x86_64-pc-windows-gnullvm.tar.xz=6169605b3073a7c2d6960bc1c74cb9cd6b65f45ee34e7ede02368e07ce4564cf +dist/2025-12-11/rust-std-1.92.0-x86_64-pc-windows-msvc.tar.gz=3af377fb29083c2117e85e6a107aedb008bd76929c22d56ce45c5be1be3a2540 +dist/2025-12-11/rust-std-1.92.0-x86_64-pc-windows-msvc.tar.xz=b4e53a9c9b96a1a0618364791b7728a1c8978101ec6d1ee78fe930e1ef061994 +dist/2025-12-11/rust-std-1.92.0-x86_64-unknown-freebsd.tar.gz=3616afb808cd030e65e66c51f6f0fb6a6fc52d877d0d70bb681b0c35238adbe8 +dist/2025-12-11/rust-std-1.92.0-x86_64-unknown-freebsd.tar.xz=151929a4255175d14b2cbcb69ef46d9217add23be268b9cd1446f8eab16616f2 +dist/2025-12-11/rust-std-1.92.0-x86_64-unknown-fuchsia.tar.gz=8b895dc4bbd95481cd171a6de01a0b74248fbd3f55bafec8dc0360e110946836 +dist/2025-12-11/rust-std-1.92.0-x86_64-unknown-fuchsia.tar.xz=51ec26391d166e2f190a329919e3c7bd793861f02284aba461a086268725d9f1 +dist/2025-12-11/rust-std-1.92.0-x86_64-unknown-illumos.tar.gz=a197e02ac48cdacfdb7487f612818b23c461c52e7e6015737a6b0a1cc2a744c5 +dist/2025-12-11/rust-std-1.92.0-x86_64-unknown-illumos.tar.xz=31c6f2296543e684554b9eb4ac34551270a0a9c7d0cbc96986cf15a301e27035 +dist/2025-12-11/rust-std-1.92.0-x86_64-unknown-linux-gnu.tar.gz=ba4e0b4a60c082e0b1cc6284a38bb144844c92f1aab09732cd1183658e08a6e7 +dist/2025-12-11/rust-std-1.92.0-x86_64-unknown-linux-gnu.tar.xz=5f106805ed86ebf8df287039e53a45cf974391ef4d088c2760776b05b8e48b5d +dist/2025-12-11/rust-std-1.92.0-x86_64-unknown-linux-gnux32.tar.gz=8b9c9330278a97b79f3783dbacaaf4c0d110bb608cd1c615bb931b340ca6b27f +dist/2025-12-11/rust-std-1.92.0-x86_64-unknown-linux-gnux32.tar.xz=f29c2380d21edbd0cd9f674a2915ccc95822c9ecdae3b2e823f066de32760bb9 +dist/2025-12-11/rust-std-1.92.0-x86_64-unknown-linux-musl.tar.gz=8bfd9a42c8295949d556587201acdb35d2bfb8b7ce55223845f337aa5614f9a3 +dist/2025-12-11/rust-std-1.92.0-x86_64-unknown-linux-musl.tar.xz=11f0b7efccdb5e7972e3c0fc23693a487abc28b624675c08161d055a016d527e +dist/2025-12-11/rust-std-1.92.0-x86_64-unknown-linux-ohos.tar.gz=61dfeaf174eabc9152fff91b9de705539e76f623f37606ac878564fef79fb4fc +dist/2025-12-11/rust-std-1.92.0-x86_64-unknown-linux-ohos.tar.xz=a5d6c40e3e712d9d7ffcc3d3895e53dad19bcba792ad6b6945a60304bdb82be1 +dist/2025-12-11/rust-std-1.92.0-x86_64-unknown-netbsd.tar.gz=1048621ad4bcd2c629882e74f9439d8b0508e6eb4ce5fee5dab0ffd6a5988261 +dist/2025-12-11/rust-std-1.92.0-x86_64-unknown-netbsd.tar.xz=db6a8d3a091551701b12e40cc58d4a541adfb63f250074aae90d250329beb8de +dist/2025-12-11/rust-std-1.92.0-x86_64-unknown-none.tar.gz=a912deaa2ceff2042cb67a12e82b9212c849c1bc0321aea639f2ec432d13f9d2 +dist/2025-12-11/rust-std-1.92.0-x86_64-unknown-none.tar.xz=1d8420ab8eb241a35e38b76470277c722bd5a7aa4ac0c7a565ad6f30b37cb852 +dist/2025-12-11/rust-std-1.92.0-x86_64-unknown-redox.tar.gz=c5a5c0dc2ca2eec79b78d9efa4af92815a3b0aefdb4009fb523b9d2a989d55de +dist/2025-12-11/rust-std-1.92.0-x86_64-unknown-redox.tar.xz=c5c1466da81956d483fe673c604e7c66f5d16e44752d39c79fab45906738b178 +dist/2025-12-11/rust-std-1.92.0-x86_64-unknown-uefi.tar.gz=89a5e952221daa4cdbd4d033bb33a18855e1f3428a022af31843391af6cda8dc +dist/2025-12-11/rust-std-1.92.0-x86_64-unknown-uefi.tar.xz=1b849250cf095269f3a2c7bc2087a919386da7da28e80dc289e6268bc705142d +dist/2025-12-11/cargo-1.92.0-aarch64-apple-darwin.tar.gz=5295d590590a606d98e3f97b730fe3b4e8d96a0c78e5268232b15b3c45180d28 +dist/2025-12-11/cargo-1.92.0-aarch64-apple-darwin.tar.xz=bce6e7def37240c5a63115828017a9fc0ebcb31e64115382f5943b62b71aa34a +dist/2025-12-11/cargo-1.92.0-aarch64-pc-windows-gnullvm.tar.gz=77567d78fd5d8ae368a21682172aa929cb6b293dd03d234b01fb0e014b14c29c +dist/2025-12-11/cargo-1.92.0-aarch64-pc-windows-gnullvm.tar.xz=56d38a6a89e2a38ec777938d74feb93a3498bc8788df96a94fcb4eac2e07338b +dist/2025-12-11/cargo-1.92.0-aarch64-pc-windows-msvc.tar.gz=c283f18461a840191b2e03d19a8ac0e6441646b668a94a03a3e76e11b75296fb +dist/2025-12-11/cargo-1.92.0-aarch64-pc-windows-msvc.tar.xz=3fc47cc29781190c5075f807836c4b98d411aaf27c59598fbfb2aa781ccf6190 +dist/2025-12-11/cargo-1.92.0-aarch64-unknown-linux-gnu.tar.gz=f0bc99a9990f722c3c795bd778cae6aa7927a9907100698a1eed272beb4bef20 +dist/2025-12-11/cargo-1.92.0-aarch64-unknown-linux-gnu.tar.xz=cb2ce6be6411b986e25c71ad8a813f9dfbe3461738136fd684e3644f8dd75df4 +dist/2025-12-11/cargo-1.92.0-aarch64-unknown-linux-musl.tar.gz=92287147c07b5b31b69b355eb8040f4d3cb22cede8418ee77f806a93e90cc005 +dist/2025-12-11/cargo-1.92.0-aarch64-unknown-linux-musl.tar.xz=492614aa4fab1d58cdf495ab040426174e740038f715145bbbce7a87716a4c8b +dist/2025-12-11/cargo-1.92.0-arm-unknown-linux-gnueabi.tar.gz=09dc930cf59637c3bd48ff5bc0b53200949e5194e39fbba374f139a7a03f69a8 +dist/2025-12-11/cargo-1.92.0-arm-unknown-linux-gnueabi.tar.xz=d09d3e8402f868b784aa17f2e8268de91d8f4634c34bfb5be65596abc6043d35 +dist/2025-12-11/cargo-1.92.0-arm-unknown-linux-gnueabihf.tar.gz=401b054bc35f33835e6234352b519858ca9fe009bd01b85766dbcacce986dc48 +dist/2025-12-11/cargo-1.92.0-arm-unknown-linux-gnueabihf.tar.xz=dbeb44e4924218afc7c57db5f7a48058fe0bd0653c292fab5cc4a8b9016b2096 +dist/2025-12-11/cargo-1.92.0-armv7-unknown-linux-gnueabihf.tar.gz=861561f65347eb9020cb93daa51eb43592f994dca7c392a3e8d9771ab797435a +dist/2025-12-11/cargo-1.92.0-armv7-unknown-linux-gnueabihf.tar.xz=713f7d2ca8776ce537c0a5e716f7bdf644d54949c78c0a98ca4113f80bd670e7 +dist/2025-12-11/cargo-1.92.0-i686-pc-windows-gnu.tar.gz=c7f394ac5eb52bb9790feedbc2a22bbf5770c614f94ac899004e895580fe8955 +dist/2025-12-11/cargo-1.92.0-i686-pc-windows-gnu.tar.xz=8b6368d75f20c3cdfbb0c03f2cd7c386b9224bbf3717fbd635fff6ace0260660 +dist/2025-12-11/cargo-1.92.0-i686-pc-windows-msvc.tar.gz=25035fc699d3d907e0ac3c77ee4b524455b29d762b98951dd4f8084c64d0c416 +dist/2025-12-11/cargo-1.92.0-i686-pc-windows-msvc.tar.xz=a734070e84d1d9124bd0f4157eadf66c5b2030e49162f209ad0a0ebf895333ff +dist/2025-12-11/cargo-1.92.0-i686-unknown-linux-gnu.tar.gz=f95a54f1aabc6b4611d80f2bd5dda8f27719266f7cd829c5b9c2edcbf190a42c +dist/2025-12-11/cargo-1.92.0-i686-unknown-linux-gnu.tar.xz=63001bbde1c036fae9ad624807bfb18117c7e7cb4a04de81adc4acc7e8580c07 +dist/2025-12-11/cargo-1.92.0-loongarch64-unknown-linux-gnu.tar.gz=572a85632fcf90dd9fa359dd6eaed16266b75eaccc7d47e2c6974a01b0139b27 +dist/2025-12-11/cargo-1.92.0-loongarch64-unknown-linux-gnu.tar.xz=32f4b393f1471d7d50c9a50512f02116187b3ea6a885c26ff2d74f87fa72baa8 +dist/2025-12-11/cargo-1.92.0-loongarch64-unknown-linux-musl.tar.gz=0a02be499899e8a59fdf97e08bd1c2eaeb2bcb1328e230d8966eb1c0c0fc736e +dist/2025-12-11/cargo-1.92.0-loongarch64-unknown-linux-musl.tar.xz=edf8ae60bbe7821dfd02434951cca3b8c3ea63dc075b8a425ca45ac84da5796e +dist/2025-12-11/cargo-1.92.0-powerpc-unknown-linux-gnu.tar.gz=f33e2312126f52f0da9e5073b4311e9cad114228607e0fb5c3ae51b3add2a624 +dist/2025-12-11/cargo-1.92.0-powerpc-unknown-linux-gnu.tar.xz=1249c64f95d8187b3a89cf8429329bdbc98f53a9fc538e898c95c487e3234d90 +dist/2025-12-11/cargo-1.92.0-powerpc64-unknown-linux-gnu.tar.gz=414cfee5d5c39b757fb4bead92af90018601f8e40a447c2d2ee172a235605ecb +dist/2025-12-11/cargo-1.92.0-powerpc64-unknown-linux-gnu.tar.xz=e94a8f97c3143158e285b4f8ade1fae844961caca30c0eeed44f6c14da484f05 +dist/2025-12-11/cargo-1.92.0-powerpc64le-unknown-linux-gnu.tar.gz=69f56f4df9722d1a50273a69d32ed4593e84ec81f61ec949e58684e2ab1fac5c +dist/2025-12-11/cargo-1.92.0-powerpc64le-unknown-linux-gnu.tar.xz=49dd01f5d10e3f368181223db0fbf7dc191161f7d80a295de4909bf87e53da58 +dist/2025-12-11/cargo-1.92.0-powerpc64le-unknown-linux-musl.tar.gz=37a3d27d185abf8e3af51912f5f28b6acbd768445d1ca78e97acab5de4741b8a +dist/2025-12-11/cargo-1.92.0-powerpc64le-unknown-linux-musl.tar.xz=0f64d4df6bfad74ac9a60dfccf0c574ef56cd092d3207931b100e9b9130f7640 +dist/2025-12-11/cargo-1.92.0-riscv64gc-unknown-linux-gnu.tar.gz=6e6e42f0fbe0d0f8aca38946b3884b8d0cde6513ffe59fe9c2bcccd89d40f0e4 +dist/2025-12-11/cargo-1.92.0-riscv64gc-unknown-linux-gnu.tar.xz=e8708d0a929ad15941ecde368e8a156911927a805b492afafc737124b6aa55d4 +dist/2025-12-11/cargo-1.92.0-s390x-unknown-linux-gnu.tar.gz=8efdf1355d3eb6107854dcd3ab5b4396bed7b09910099dc791633740859cf5f2 +dist/2025-12-11/cargo-1.92.0-s390x-unknown-linux-gnu.tar.xz=a290edf359a5632dfda3b2325a309d9edeb58c97de97e3cc67274335b58adf05 +dist/2025-12-11/cargo-1.92.0-sparcv9-sun-solaris.tar.gz=535bf08187504fc5b157be2443973310e94ce75ab029ccf54f39f59b0f2d4c88 +dist/2025-12-11/cargo-1.92.0-sparcv9-sun-solaris.tar.xz=a0749eb1c52b8b6488fa0515ce0ae945f5a8dee331762334e1462776dfa0ec96 +dist/2025-12-11/cargo-1.92.0-x86_64-apple-darwin.tar.gz=3423880db7c38ba0259dbe8106039ad9cfb650c65b7bf311a33addd05aec3cb5 +dist/2025-12-11/cargo-1.92.0-x86_64-apple-darwin.tar.xz=b033a7c33aba8af947c9d0ab2785f9696347cded228ffe731897f1c627466262 +dist/2025-12-11/cargo-1.92.0-x86_64-pc-solaris.tar.gz=6f6f2a5b13fdde3ebcdb4e3f9a0a62104616940400bad050d27dec9c9cb00b25 +dist/2025-12-11/cargo-1.92.0-x86_64-pc-solaris.tar.xz=cbfc3e9543990f65dff8c76f0cc87b22b15f5ed6777cfb71b7eb7ea634a4d27f +dist/2025-12-11/cargo-1.92.0-x86_64-pc-windows-gnu.tar.gz=e2c59ffc93e18049f0ee829e6a9b768aa97a7aee480a28576cf786fd4aeb95dd +dist/2025-12-11/cargo-1.92.0-x86_64-pc-windows-gnu.tar.xz=962e0350346b417719cc36db333424a03e368d602fb411676c901f15487ea29c +dist/2025-12-11/cargo-1.92.0-x86_64-pc-windows-gnullvm.tar.gz=8c5de85558085a3e0f3b3280865236d3ea6d06c6e39fc458318c6b4becb7ad7f +dist/2025-12-11/cargo-1.92.0-x86_64-pc-windows-gnullvm.tar.xz=c27d5936e1c11feb33f3221b85741c33f783c8723fca84552e7c2a5a73959352 +dist/2025-12-11/cargo-1.92.0-x86_64-pc-windows-msvc.tar.gz=9f6178ddcaed7c9190c454db5da801e2fe6c8fde8600258a9bdd0e107e81ac3b +dist/2025-12-11/cargo-1.92.0-x86_64-pc-windows-msvc.tar.xz=f4057534ec58708ed3554957582a6c8e8c6abfee011b5c8ad45c3ab27c0b3076 +dist/2025-12-11/cargo-1.92.0-x86_64-unknown-freebsd.tar.gz=a43043c5bbc907260594d542ea0dd17630d432024dd0af0b90c99b7397227f9e +dist/2025-12-11/cargo-1.92.0-x86_64-unknown-freebsd.tar.xz=7bf1853c6ac4b426d7b4b67ee4ecf60f4a3e83151147a13b4cf04f81ccff3c4b +dist/2025-12-11/cargo-1.92.0-x86_64-unknown-illumos.tar.gz=4c679e0c8c18649ca280096b1d6b7856a26540a6ac37e4fca371576c1dc0811e +dist/2025-12-11/cargo-1.92.0-x86_64-unknown-illumos.tar.xz=a620fd5c893261ac0f9b59dfe6062f4a8e1eaf517b8116b64d3c0925dc1a5d1d +dist/2025-12-11/cargo-1.92.0-x86_64-unknown-linux-gnu.tar.gz=2aa2b1c1df189d346f3937b4887c901b737df2663a667de17beb8f1098442bb9 +dist/2025-12-11/cargo-1.92.0-x86_64-unknown-linux-gnu.tar.xz=e5e12be2c7126a7036c8adf573078a28b92611f5767cc9bd0a6f7c83081df103 +dist/2025-12-11/cargo-1.92.0-x86_64-unknown-linux-musl.tar.gz=df116b5f1400daffd0074125e6c7cb98e5763ae9aefe341e3605b623042b7b11 +dist/2025-12-11/cargo-1.92.0-x86_64-unknown-linux-musl.tar.xz=b37ef0ce8c49103a904559f17c83c6e5a182f0f165f158e7be00e9036ca8c6d5 +dist/2025-12-11/cargo-1.92.0-x86_64-unknown-netbsd.tar.gz=e6ddc2363ad9073d101368110eeedb2bd91fa7a318f3823295edab3bc191747a +dist/2025-12-11/cargo-1.92.0-x86_64-unknown-netbsd.tar.xz=19065f32ac1edae4f000695d3814b5b1ae2649e218304d223e8af1634f465b37 +dist/2025-12-11/clippy-1.92.0-aarch64-apple-darwin.tar.gz=02cb1fb33fead2b4378c37db711fda2945b7487ccc462ee1abeeb3a4ffcff312 +dist/2025-12-11/clippy-1.92.0-aarch64-apple-darwin.tar.xz=08c65b6cf8faae3861706f8c97acf2aa6b784ed9455354c3b13495a7cfe5cb84 +dist/2025-12-11/clippy-1.92.0-aarch64-pc-windows-gnullvm.tar.gz=8a7fcc3e006b5fe1160011f692adec30a8c772585572541c52fc5647b9ec74d4 +dist/2025-12-11/clippy-1.92.0-aarch64-pc-windows-gnullvm.tar.xz=ea3e63c684273f629f918e8f50d510225c48a35ec28eaf026fa68c27f273bbd6 +dist/2025-12-11/clippy-1.92.0-aarch64-pc-windows-msvc.tar.gz=4fa5ed26256ad52a5f5f2039c3b2fa008ee890a6c366153806368c912d74b0db +dist/2025-12-11/clippy-1.92.0-aarch64-pc-windows-msvc.tar.xz=2aa2f1288072ea1f870d6d860d09f5911c1305d506f344b65cf5e27b5070e262 +dist/2025-12-11/clippy-1.92.0-aarch64-unknown-linux-gnu.tar.gz=37c0bc5ea8a2421d2353bbb871620617ac5de0c3aaa7548a0952d0d64d551222 +dist/2025-12-11/clippy-1.92.0-aarch64-unknown-linux-gnu.tar.xz=333ab38c673b589468b8293b525e5704fb52515d9d516ee28d3d34dd5a63d3c3 +dist/2025-12-11/clippy-1.92.0-aarch64-unknown-linux-musl.tar.gz=8e7a88b0bee51760b9c416dce4a0b355a74cf8681de115ef55bee14a6bf9ba46 +dist/2025-12-11/clippy-1.92.0-aarch64-unknown-linux-musl.tar.xz=8aecf9e71c9a8b349587e5c0c69dc91e373264ffc55d946a00ab8f9aff072e64 +dist/2025-12-11/clippy-1.92.0-arm-unknown-linux-gnueabi.tar.gz=39ce64be0c9878f2fd20f9bdda70f6cdf7bfc5928986c65719d93580cd784a11 +dist/2025-12-11/clippy-1.92.0-arm-unknown-linux-gnueabi.tar.xz=957d0c8bb77f6589d579d6133e98aaf351dfbbcec3ef1603659a90d9d7c2ce41 +dist/2025-12-11/clippy-1.92.0-arm-unknown-linux-gnueabihf.tar.gz=27ac4e9184be7e3a245ce6dddf438a2728a6b4fd8959e665e9f02b63ef99f671 +dist/2025-12-11/clippy-1.92.0-arm-unknown-linux-gnueabihf.tar.xz=0c360081ff01d1319cf9667b1c46f9ee684276bfbabce268589342e304c32299 +dist/2025-12-11/clippy-1.92.0-armv7-unknown-linux-gnueabihf.tar.gz=b85d187bb8f896383e349ec91699501205644152fce229c2ffbc87723e44d4ff +dist/2025-12-11/clippy-1.92.0-armv7-unknown-linux-gnueabihf.tar.xz=c47e0bb86ac299c36492a125f0231bc715787fc65ab28de5a2dd576ac613cbd3 +dist/2025-12-11/clippy-1.92.0-i686-pc-windows-gnu.tar.gz=4f8cecf22d6ba620ed2739ef84463f546da12b1b4320ac97144f4a1adda12e23 +dist/2025-12-11/clippy-1.92.0-i686-pc-windows-gnu.tar.xz=37bf65d4d059534ff633996963e497cc470fbd8f3d52a87af45298c1d3785473 +dist/2025-12-11/clippy-1.92.0-i686-pc-windows-msvc.tar.gz=5291a3c1f8c1ba513575b1240613eabf1fc423570d1fec8ed2927b8d7110b70f +dist/2025-12-11/clippy-1.92.0-i686-pc-windows-msvc.tar.xz=974ed40fe323ea3a6c2de1226aed5634d168b29113ac25d87370d4934c956ea5 +dist/2025-12-11/clippy-1.92.0-i686-unknown-linux-gnu.tar.gz=987e71ce7fd0b633db9fc0ab37eb149cb6d67add4e767d0fe30870cd6a6d2e62 +dist/2025-12-11/clippy-1.92.0-i686-unknown-linux-gnu.tar.xz=f21090ddb01503ab7e326ff8b1ab44121611121e83572aa2dba2c5ceffe12d22 +dist/2025-12-11/clippy-1.92.0-loongarch64-unknown-linux-gnu.tar.gz=bfd0bd79f87e61f99645cdc439be58b7fd64a4a9ef0ef32aeab2ec59ec250d1a +dist/2025-12-11/clippy-1.92.0-loongarch64-unknown-linux-gnu.tar.xz=70783e0b31682938db53b78f87c948acfe589e3ece5dee6ae6aa5b667a384f3c +dist/2025-12-11/clippy-1.92.0-loongarch64-unknown-linux-musl.tar.gz=cf38e7b7abb35fff475847285c8e6d71651bc230fc69df91d8b5d9fa7c09c277 +dist/2025-12-11/clippy-1.92.0-loongarch64-unknown-linux-musl.tar.xz=790b5b921c6423a007951f3839a083c4c73a9b64fb6c5019e1e117f98975d9f9 +dist/2025-12-11/clippy-1.92.0-powerpc-unknown-linux-gnu.tar.gz=162f860ee371105f141aa2ac9024d6c597615f4511b7bc628f33d6346625f4f3 +dist/2025-12-11/clippy-1.92.0-powerpc-unknown-linux-gnu.tar.xz=93ed9fdd6fc2655c7789ed096d57a47178532b6bda1ec4480adca7920563e934 +dist/2025-12-11/clippy-1.92.0-powerpc64-unknown-linux-gnu.tar.gz=d430546bbad6c5710d68bb88e6c6f405bd79b191af2da1ca2760b7d1adfd1b93 +dist/2025-12-11/clippy-1.92.0-powerpc64-unknown-linux-gnu.tar.xz=7912584254f455b90ed6ce6089c4efded33bb753d1bf948286ef2f4f782d2f30 +dist/2025-12-11/clippy-1.92.0-powerpc64le-unknown-linux-gnu.tar.gz=46c0b94dbf705439bebd9cb47de7fb6925e462b62db8885375205e4b48db518f +dist/2025-12-11/clippy-1.92.0-powerpc64le-unknown-linux-gnu.tar.xz=873047278043e6506f5c98b8f633a9b96dc49ff83869a86a151fe5b1b9455044 +dist/2025-12-11/clippy-1.92.0-powerpc64le-unknown-linux-musl.tar.gz=d630a37d6b9ff16c17a0b363adf6ace44bfbf71cd61db1c11f9e4d5ac135774f +dist/2025-12-11/clippy-1.92.0-powerpc64le-unknown-linux-musl.tar.xz=b0b1ebe31d7b2ec101cb0464c64bdcd28e1ca4172f765fcc8478ebd8b2f90b39 +dist/2025-12-11/clippy-1.92.0-riscv64gc-unknown-linux-gnu.tar.gz=7a5d3773d578649f3b683463c3d7559b8788370d8c79b4fb6036e3d72ced8e6d +dist/2025-12-11/clippy-1.92.0-riscv64gc-unknown-linux-gnu.tar.xz=bdedabeedd48080e6ef70376c52338fbb45ff80d1fbb12a81aa2d8cabbb706c8 +dist/2025-12-11/clippy-1.92.0-s390x-unknown-linux-gnu.tar.gz=80bd8a76913069a8f467f5121a0d2fa969a9dc525813d033f2234c3304531a06 +dist/2025-12-11/clippy-1.92.0-s390x-unknown-linux-gnu.tar.xz=41aa44f1cf37cac87b83e450eb19148c539ff266bb40dc146207ad5b9e1e1acc +dist/2025-12-11/clippy-1.92.0-sparcv9-sun-solaris.tar.gz=b73f28698ae974ebdb03f89cac3933fd34bd048ec2b4392d13fd082302b44720 +dist/2025-12-11/clippy-1.92.0-sparcv9-sun-solaris.tar.xz=c8e6cfbfe8442f9e34c0e6d2d2a6ae8f7fec5278b800c8adc4446c7ca89fc6d7 +dist/2025-12-11/clippy-1.92.0-x86_64-apple-darwin.tar.gz=4bdbc9b3a0dcbf04f1bf807dc74311fe4a4fbadc1887e57e01f3bae1d16bd801 +dist/2025-12-11/clippy-1.92.0-x86_64-apple-darwin.tar.xz=39cce87aab3d8b71350edcb3f943fba7bc59581ce1e65e158ee01e64cf0f1cf5 +dist/2025-12-11/clippy-1.92.0-x86_64-pc-solaris.tar.gz=8d9b266efa76ef5e4514705c61b7f92a0829a15bcc9e492895b551e7d9811ae1 +dist/2025-12-11/clippy-1.92.0-x86_64-pc-solaris.tar.xz=4cd9a59b61ba75146a20d24c016a14b971ffefbc9256fdd2145f31987520b8d7 +dist/2025-12-11/clippy-1.92.0-x86_64-pc-windows-gnu.tar.gz=c4a858e83cea2aab2eb101285b61df663eb08042226c4c13f4cdc18b3e94698e +dist/2025-12-11/clippy-1.92.0-x86_64-pc-windows-gnu.tar.xz=e9084ced75940856b57e61e3dda7ccce08d57890dff9c2caa8c814c356fa34d2 +dist/2025-12-11/clippy-1.92.0-x86_64-pc-windows-gnullvm.tar.gz=4495c4d97736105fe93fbe9bce954ba21508ebb8d31b473ebc0f6cf57ac981c3 +dist/2025-12-11/clippy-1.92.0-x86_64-pc-windows-gnullvm.tar.xz=b22f615210f328aabafa8d0eab3fed62784fa771956c51a92ae24a4dfd2073ed +dist/2025-12-11/clippy-1.92.0-x86_64-pc-windows-msvc.tar.gz=c4f5bf37194bf71a872ab0c7248338d7d6ddf28d0cf35cfde9bad94745bd9f9e +dist/2025-12-11/clippy-1.92.0-x86_64-pc-windows-msvc.tar.xz=51a9a67931a3e50eb0c26b4c6a7ec2ef6ddd633319343a2d4767710c1e33b21f +dist/2025-12-11/clippy-1.92.0-x86_64-unknown-freebsd.tar.gz=617ef6d0be4bc2accc80909037e80d450fb1c0cbf797f0d6152fb50a26356437 +dist/2025-12-11/clippy-1.92.0-x86_64-unknown-freebsd.tar.xz=73d799e51800ebe4af40395c63c46ec60fc51b7b5f56467b550d5a29f213075a +dist/2025-12-11/clippy-1.92.0-x86_64-unknown-illumos.tar.gz=031f313032ef7c704f6212a5a84a798a828e9775a61e40ed7b246dcce43c12a7 +dist/2025-12-11/clippy-1.92.0-x86_64-unknown-illumos.tar.xz=8b7383dfc99c026917b037c0fbad8f42da494a898d71fb7ff6c98ebfea4e9448 +dist/2025-12-11/clippy-1.92.0-x86_64-unknown-linux-gnu.tar.gz=cd63fc19e6047742b735e959ed615f2013df5a0653913ec37a7e17fe9b0f99d7 +dist/2025-12-11/clippy-1.92.0-x86_64-unknown-linux-gnu.tar.xz=2c1bf6e7da8ec50feba03fe188fc9a744ba59e2c6ece7970c13e201d08defa9a +dist/2025-12-11/clippy-1.92.0-x86_64-unknown-linux-musl.tar.gz=81596511aa023876b881869224188d98d803bf393b6d5a5abe32b486f7fc1dc7 +dist/2025-12-11/clippy-1.92.0-x86_64-unknown-linux-musl.tar.xz=8051ed46eb7c3650361dc26dc348dcdcbffb765ef099f9f44bbf8141e223050a +dist/2025-12-11/clippy-1.92.0-x86_64-unknown-netbsd.tar.gz=55678429c5dd5370cb455bb6600dbb2c9383662789bf75577282a7c8b1a2ff10 +dist/2025-12-11/clippy-1.92.0-x86_64-unknown-netbsd.tar.xz=66ab46b59f74700d99b5554a191877011aa465e805b52118b65f4964c4ce3563 +dist/2025-12-11/rust-1.92.0-aarch64-pc-windows-msvc.msi=dbb09f213d5a9ebb3b2f4c7d65ba7c3c6cad7d9a76927d079604020c3ea0ad5a +dist/2025-12-11/rust-1.92.0-i686-pc-windows-gnu.msi=95a4922605093c67f6527c44c0e982026727b38a1e25979fcd8b2b0ff9cc7968 +dist/2025-12-11/rust-1.92.0-i686-pc-windows-msvc.msi=b73f851252fe3ae340b9be8e1f9cc05e34210498c0c3321a46243be633454909 +dist/2025-12-11/rust-1.92.0-x86_64-pc-windows-gnu.msi=899c79a6a68c59470d5f721ae90718f83cabd613e0a7fb595fe87ab6429a0fc6 +dist/2025-12-11/rust-1.92.0-x86_64-pc-windows-msvc.msi=bd3fd270e92d12094151aae3a67435b7fef2164b10d96e99a94230929cda09fd +dist/2025-12-11/rust-1.92.0-aarch64-apple-darwin.pkg=ce8eca0010032eb9ccb1baa8d3527d3ed7099c06db5a048205d0940c3866b0c9 +dist/2025-12-11/rust-1.92.0-x86_64-apple-darwin.pkg=d8b439cbabd4db21a3958d6cf9126bd216257f29c1457bba524363d06f4b1eec +dist/2025-12-11/rustc-1.92.0-src.tar.gz=9e0d2ca75c7e275fdc758255bf4b03afb3d65d1543602746907c933b6901c3b8 +dist/2025-12-11/rustc-1.92.0-src.tar.xz=ebee170bfe4c4dfc59521a101de651e5534f4dae889756a5c97ca9ea40d0c307 From 2a8e61f538ed530c8c491ff6b5c125ebf0e9e451 Mon Sep 17 00:00:00 2001 From: Ross Sullivan Date: Fri, 12 Dec 2025 15:16:59 +0900 Subject: [PATCH 05/58] Backport Cargo bug fixes for Rust 1.93 --- src/tools/cargo | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/cargo b/src/tools/cargo index 2c283a9a5c596..083ac5135f967 160000 --- a/src/tools/cargo +++ b/src/tools/cargo @@ -1 +1 @@ -Subproject commit 2c283a9a5c5968eeb9a8f12313f04feb1ff8dfac +Subproject commit 083ac5135f967fd9dc906ab057a2315861c7a80d From 3f4f07f0b9ebbb08cb7ef1702d6f79b553eb33bc Mon Sep 17 00:00:00 2001 From: Kivooeo Date: Thu, 4 Dec 2025 21:53:11 +0000 Subject: [PATCH 06/58] add check for uninhabited types along side never (cherry picked from commit 2a2da782d32f25d69b66880b5dca640e2be8fe3e) --- compiler/rustc_mir_build/src/builder/mod.rs | 21 ++++++++++++++++++- .../uninhabited-unreachable-warning-149571.rs | 10 +++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) create mode 100644 tests/ui/uninhabited/uninhabited-unreachable-warning-149571.rs diff --git a/compiler/rustc_mir_build/src/builder/mod.rs b/compiler/rustc_mir_build/src/builder/mod.rs index 206eb9126f54b..14a24265a8f4b 100644 --- a/compiler/rustc_mir_build/src/builder/mod.rs +++ b/compiler/rustc_mir_build/src/builder/mod.rs @@ -839,6 +839,25 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { self.infcx.typing_env(self.param_env), ); + // check if the function's return type is inhabited + // this was added here because of this regression + // https://github.com/rust-lang/rust/issues/149571 + let output_is_inhabited = + if matches!(self.tcx.def_kind(self.def_id), DefKind::Fn | DefKind::AssocFn) { + self.tcx + .fn_sig(self.def_id) + .instantiate_identity() + .skip_binder() + .output() + .is_inhabited_from( + self.tcx, + self.parent_module, + self.infcx.typing_env(self.param_env), + ) + } else { + true + }; + if !ty_is_inhabited { // Unreachable code warnings are already emitted during type checking. // However, during type checking, full type information is being @@ -849,7 +868,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // uninhabited types (e.g. empty enums). The check above is used so // that we do not emit the same warning twice if the uninhabited type // is indeed `!`. - if !ty.is_never() { + if !ty.is_never() && output_is_inhabited { lints.push((target_bb, ty, term.source_info.span)); } diff --git a/tests/ui/uninhabited/uninhabited-unreachable-warning-149571.rs b/tests/ui/uninhabited/uninhabited-unreachable-warning-149571.rs new file mode 100644 index 0000000000000..a389562d649e3 --- /dev/null +++ b/tests/ui/uninhabited/uninhabited-unreachable-warning-149571.rs @@ -0,0 +1,10 @@ +#![deny(unreachable_code)] +//@ run-pass + +use std::convert::Infallible; + +pub fn foo(f: impl FnOnce() -> Infallible) -> Infallible { + f() +} + +fn main() {} From 834ced45a471742e8e3fb0bcece4f575c07bfeb2 Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Tue, 16 Dec 2025 12:32:00 +0100 Subject: [PATCH 07/58] Update to LLVM 21.1.8 (cherry picked from commit f33abb17db4045a629e0ef4e9755dc145e3fdaec) --- src/llvm-project | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/llvm-project b/src/llvm-project index 16b5ac8b0a545..85a90d119deb2 160000 --- a/src/llvm-project +++ b/src/llvm-project @@ -1 +1 @@ -Subproject commit 16b5ac8b0a5456eb23c72e1bff3fc9bd6e824f84 +Subproject commit 85a90d119deb25b518867cd37d62c7b93b575a6f From 4bc6d7559250e95aecada1067b03058b32c62492 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Wed, 17 Dec 2025 14:33:52 +0000 Subject: [PATCH 08/58] Revert #148937 (Remove initialized-bytes tracking from `BorrowedBuf` and `BorrowedCursor`) This caused several performance regressions because of existing code which uses `Read::read` and therefore requires full buffer initialization. This is particularly a problem when the same buffer is re-used for multiple read calls since this means it needs to be fully re-initialized each time. There is still some benefit to landing the API changes, but we will have to add private APIs so that the existing infrastructure can track and avoid redundant initialization. (cherry picked from commit 4b07875505bdd5c4b635fbf821401fcd4573dffd) --- library/core/src/io/borrowed_buf.rs | 162 +++++++++++++++--- library/coretests/tests/io/borrowed_buf.rs | 90 ++++++++-- library/std/src/fs/tests.rs | 2 + library/std/src/io/buffered/bufreader.rs | 9 + .../std/src/io/buffered/bufreader/buffer.rs | 27 ++- library/std/src/io/buffered/tests.rs | 24 +++ library/std/src/io/copy.rs | 13 ++ library/std/src/io/mod.rs | 53 +++++- library/std/src/io/tests.rs | 9 + library/std/src/io/util.rs | 2 +- library/std/src/io/util/tests.rs | 8 + library/std/src/net/tcp/tests.rs | 2 + library/std/src/process/tests.rs | 2 + library/std/src/sys/fd/hermit.rs | 2 +- library/std/src/sys/fd/unix.rs | 4 +- library/std/src/sys/fd/wasi.rs | 2 +- library/std/src/sys/fs/solid.rs | 2 +- .../src/sys/net/connection/socket/hermit.rs | 2 +- .../src/sys/net/connection/socket/solid.rs | 2 +- .../std/src/sys/net/connection/socket/unix.rs | 2 +- .../src/sys/net/connection/socket/wasip2.rs | 2 +- .../src/sys/net/connection/socket/windows.rs | 2 +- .../std/src/sys/pal/sgx/abi/usercalls/mod.rs | 2 +- library/std/src/sys/pal/windows/handle.rs | 4 +- library/std/src/sys/pal/windows/pipe.rs | 2 +- library/std/src/sys/stdio/zkvm.rs | 2 +- 26 files changed, 368 insertions(+), 65 deletions(-) diff --git a/library/core/src/io/borrowed_buf.rs b/library/core/src/io/borrowed_buf.rs index b765b96fd00a5..088dea7812945 100644 --- a/library/core/src/io/borrowed_buf.rs +++ b/library/core/src/io/borrowed_buf.rs @@ -2,26 +2,27 @@ use crate::fmt::{self, Debug, Formatter}; use crate::mem::{self, MaybeUninit}; +use crate::{cmp, ptr}; -/// A borrowed buffer of initially uninitialized bytes, which is incrementally filled. +/// A borrowed byte buffer which is incrementally filled and initialized. /// -/// This type makes it safer to work with `MaybeUninit` buffers, such as to read into a buffer -/// without having to initialize it first. It tracks the region of bytes that have been filled and -/// the region that remains uninitialized. +/// This type is a sort of "double cursor". It tracks three regions in the buffer: a region at the beginning of the +/// buffer that has been logically filled with data, a region that has been initialized at some point but not yet +/// logically filled, and a region at the end that is fully uninitialized. The filled region is guaranteed to be a +/// subset of the initialized region. /// -/// The contents of the buffer can be visualized as: +/// In summary, the contents of the buffer can be visualized as: /// ```not_rust -/// [ capacity ] -/// [ len: filled and initialized | capacity - len: uninitialized ] +/// [ capacity ] +/// [ filled | unfilled ] +/// [ initialized | uninitialized ] /// ``` /// -/// Note that `BorrowedBuf` does not distinguish between uninitialized data and data that was -/// previously initialized but no longer contains valid data. -/// -/// A `BorrowedBuf` is created around some existing data (or capacity for data) via a unique -/// reference (`&mut`). The `BorrowedBuf` can be configured (e.g., using `clear` or `set_len`), but -/// cannot be directly written. To write into the buffer, use `unfilled` to create a -/// `BorrowedCursor`. The cursor has write-only access to the unfilled portion of the buffer. +/// A `BorrowedBuf` is created around some existing data (or capacity for data) via a unique reference +/// (`&mut`). The `BorrowedBuf` can be configured (e.g., using `clear` or `set_init`), but cannot be +/// directly written. To write into the buffer, use `unfilled` to create a `BorrowedCursor`. The cursor +/// has write-only access to the unfilled portion of the buffer (you can think of it as a +/// write-only iterator). /// /// The lifetime `'data` is a bound on the lifetime of the underlying data. pub struct BorrowedBuf<'data> { @@ -29,11 +30,14 @@ pub struct BorrowedBuf<'data> { buf: &'data mut [MaybeUninit], /// The length of `self.buf` which is known to be filled. filled: usize, + /// The length of `self.buf` which is known to be initialized. + init: usize, } impl Debug for BorrowedBuf<'_> { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { f.debug_struct("BorrowedBuf") + .field("init", &self.init) .field("filled", &self.filled) .field("capacity", &self.capacity()) .finish() @@ -44,22 +48,24 @@ impl Debug for BorrowedBuf<'_> { impl<'data> From<&'data mut [u8]> for BorrowedBuf<'data> { #[inline] fn from(slice: &'data mut [u8]) -> BorrowedBuf<'data> { + let len = slice.len(); + BorrowedBuf { - // SAFETY: Always in bounds. We treat the buffer as uninitialized, even though it's - // already initialized. + // SAFETY: initialized data never becoming uninitialized is an invariant of BorrowedBuf buf: unsafe { (slice as *mut [u8]).as_uninit_slice_mut().unwrap() }, filled: 0, + init: len, } } } /// Creates a new `BorrowedBuf` from an uninitialized buffer. /// -/// Use `set_filled` if part of the buffer is known to be already filled. +/// Use `set_init` if part of the buffer is known to be already initialized. impl<'data> From<&'data mut [MaybeUninit]> for BorrowedBuf<'data> { #[inline] fn from(buf: &'data mut [MaybeUninit]) -> BorrowedBuf<'data> { - BorrowedBuf { buf, filled: 0 } + BorrowedBuf { buf, filled: 0, init: 0 } } } @@ -68,11 +74,14 @@ impl<'data> From<&'data mut [MaybeUninit]> for BorrowedBuf<'data> { /// Use `BorrowedCursor::with_unfilled_buf` instead for a safer alternative. impl<'data> From> for BorrowedBuf<'data> { #[inline] - fn from(buf: BorrowedCursor<'data>) -> BorrowedBuf<'data> { + fn from(mut buf: BorrowedCursor<'data>) -> BorrowedBuf<'data> { + let init = buf.init_mut().len(); BorrowedBuf { - // SAFETY: Always in bounds. We treat the buffer as uninitialized. + // SAFETY: no initialized byte is ever uninitialized as per + // `BorrowedBuf`'s invariant buf: unsafe { buf.buf.buf.get_unchecked_mut(buf.buf.filled..) }, filled: 0, + init, } } } @@ -90,6 +99,12 @@ impl<'data> BorrowedBuf<'data> { self.filled } + /// Returns the length of the initialized part of the buffer. + #[inline] + pub fn init_len(&self) -> usize { + self.init + } + /// Returns a shared reference to the filled portion of the buffer. #[inline] pub fn filled(&self) -> &[u8] { @@ -144,16 +159,33 @@ impl<'data> BorrowedBuf<'data> { /// Clears the buffer, resetting the filled region to empty. /// - /// The contents of the buffer are not modified. + /// The number of initialized bytes is not changed, and the contents of the buffer are not modified. #[inline] pub fn clear(&mut self) -> &mut Self { self.filled = 0; self } + + /// Asserts that the first `n` bytes of the buffer are initialized. + /// + /// `BorrowedBuf` assumes that bytes are never de-initialized, so this method does nothing when called with fewer + /// bytes than are already known to be initialized. + /// + /// # Safety + /// + /// The caller must ensure that the first `n` unfilled bytes of the buffer have already been initialized. + #[inline] + pub unsafe fn set_init(&mut self, n: usize) -> &mut Self { + self.init = cmp::max(self.init, n); + self + } } /// A writeable view of the unfilled portion of a [`BorrowedBuf`]. /// +/// The unfilled portion consists of an initialized and an uninitialized part; see [`BorrowedBuf`] +/// for details. +/// /// Data can be written directly to the cursor by using [`append`](BorrowedCursor::append) or /// indirectly by getting a slice of part or all of the cursor and writing into the slice. In the /// indirect case, the caller must call [`advance`](BorrowedCursor::advance) after writing to inform @@ -206,17 +238,48 @@ impl<'a> BorrowedCursor<'a> { self.buf.filled } + /// Returns a mutable reference to the initialized portion of the cursor. + #[inline] + pub fn init_mut(&mut self) -> &mut [u8] { + // SAFETY: We only slice the initialized part of the buffer, which is always valid + unsafe { + let buf = self.buf.buf.get_unchecked_mut(self.buf.filled..self.buf.init); + buf.assume_init_mut() + } + } + /// Returns a mutable reference to the whole cursor. /// /// # Safety /// - /// The caller must not uninitialize any previously initialized bytes. + /// The caller must not uninitialize any bytes in the initialized portion of the cursor. #[inline] pub unsafe fn as_mut(&mut self) -> &mut [MaybeUninit] { // SAFETY: always in bounds unsafe { self.buf.buf.get_unchecked_mut(self.buf.filled..) } } + /// Advances the cursor by asserting that `n` bytes have been filled. + /// + /// After advancing, the `n` bytes are no longer accessible via the cursor and can only be + /// accessed via the underlying buffer. I.e., the buffer's filled portion grows by `n` elements + /// and its unfilled portion (and the capacity of this cursor) shrinks by `n` elements. + /// + /// If less than `n` bytes initialized (by the cursor's point of view), `set_init` should be + /// called first. + /// + /// # Panics + /// + /// Panics if there are less than `n` bytes initialized. + #[inline] + pub fn advance(&mut self, n: usize) -> &mut Self { + // The subtraction cannot underflow by invariant of this type. + assert!(n <= self.buf.init - self.buf.filled); + + self.buf.filled += n; + self + } + /// Advances the cursor by asserting that `n` bytes have been filled. /// /// After advancing, the `n` bytes are no longer accessible via the cursor and can only be @@ -225,11 +288,42 @@ impl<'a> BorrowedCursor<'a> { /// /// # Safety /// - /// The caller must ensure that the first `n` bytes of the cursor have been initialized. `n` - /// must not exceed the remaining capacity of this cursor. + /// The caller must ensure that the first `n` bytes of the cursor have been properly + /// initialised. #[inline] - pub unsafe fn advance(&mut self, n: usize) -> &mut Self { + pub unsafe fn advance_unchecked(&mut self, n: usize) -> &mut Self { self.buf.filled += n; + self.buf.init = cmp::max(self.buf.init, self.buf.filled); + self + } + + /// Initializes all bytes in the cursor. + #[inline] + pub fn ensure_init(&mut self) -> &mut Self { + // SAFETY: always in bounds and we never uninitialize these bytes. + let uninit = unsafe { self.buf.buf.get_unchecked_mut(self.buf.init..) }; + + // SAFETY: 0 is a valid value for MaybeUninit and the length matches the allocation + // since it is comes from a slice reference. + unsafe { + ptr::write_bytes(uninit.as_mut_ptr(), 0, uninit.len()); + } + self.buf.init = self.buf.capacity(); + + self + } + + /// Asserts that the first `n` unfilled bytes of the cursor are initialized. + /// + /// `BorrowedBuf` assumes that bytes are never de-initialized, so this method does nothing when + /// called with fewer bytes than are already known to be initialized. + /// + /// # Safety + /// + /// The caller must ensure that the first `n` bytes of the buffer have already been initialized. + #[inline] + pub unsafe fn set_init(&mut self, n: usize) -> &mut Self { + self.buf.init = cmp::max(self.buf.init, self.buf.filled + n); self } @@ -247,6 +341,10 @@ impl<'a> BorrowedCursor<'a> { self.as_mut()[..buf.len()].write_copy_of_slice(buf); } + // SAFETY: We just added the entire contents of buf to the filled section. + unsafe { + self.set_init(buf.len()); + } self.buf.filled += buf.len(); } @@ -269,9 +367,17 @@ impl<'a> BorrowedCursor<'a> { // there, one could mark some bytes as initialized even though there aren't. assert!(core::ptr::addr_eq(prev_ptr, buf.buf)); - // SAFETY: These bytes were filled in the `BorrowedBuf`, so they're filled in the cursor - // too, because the buffer wasn't replaced. - self.buf.filled += buf.filled; + let filled = buf.filled; + let init = buf.init; + + // Update `init` and `filled` fields with what was written to the buffer. + // `self.buf.filled` was the starting length of the `BorrowedBuf`. + // + // SAFETY: These amounts of bytes were initialized/filled in the `BorrowedBuf`, + // and therefore they are initialized/filled in the cursor too, because the + // buffer wasn't replaced. + self.buf.init = self.buf.filled + init; + self.buf.filled += filled; res } diff --git a/library/coretests/tests/io/borrowed_buf.rs b/library/coretests/tests/io/borrowed_buf.rs index 730ba04465a11..aaa98d26ff8b9 100644 --- a/library/coretests/tests/io/borrowed_buf.rs +++ b/library/coretests/tests/io/borrowed_buf.rs @@ -8,6 +8,7 @@ fn new() { let mut rbuf: BorrowedBuf<'_> = buf.into(); assert_eq!(rbuf.filled().len(), 0); + assert_eq!(rbuf.init_len(), 16); assert_eq!(rbuf.capacity(), 16); assert_eq!(rbuf.unfilled().capacity(), 16); } @@ -19,16 +20,27 @@ fn uninit() { let mut rbuf: BorrowedBuf<'_> = buf.into(); assert_eq!(rbuf.filled().len(), 0); + assert_eq!(rbuf.init_len(), 0); assert_eq!(rbuf.capacity(), 16); assert_eq!(rbuf.unfilled().capacity(), 16); } +#[test] +fn initialize_unfilled() { + let buf: &mut [_] = &mut [MaybeUninit::uninit(); 16]; + let mut rbuf: BorrowedBuf<'_> = buf.into(); + + rbuf.unfilled().ensure_init(); + + assert_eq!(rbuf.init_len(), 16); +} + #[test] fn advance_filled() { let buf: &mut [_] = &mut [0; 16]; let mut rbuf: BorrowedBuf<'_> = buf.into(); - unsafe { rbuf.unfilled().advance(1) }; + rbuf.unfilled().advance(1); assert_eq!(rbuf.filled().len(), 1); assert_eq!(rbuf.unfilled().capacity(), 15); @@ -39,7 +51,7 @@ fn clear() { let buf: &mut [_] = &mut [255; 16]; let mut rbuf: BorrowedBuf<'_> = buf.into(); - unsafe { rbuf.unfilled().advance(16) }; + rbuf.unfilled().advance(16); assert_eq!(rbuf.filled().len(), 16); assert_eq!(rbuf.unfilled().capacity(), 0); @@ -49,9 +61,33 @@ fn clear() { assert_eq!(rbuf.filled().len(), 0); assert_eq!(rbuf.unfilled().capacity(), 16); - unsafe { rbuf.unfilled().advance(16) }; + assert_eq!(rbuf.unfilled().init_mut(), [255; 16]); +} + +#[test] +fn set_init() { + let buf: &mut [_] = &mut [MaybeUninit::zeroed(); 16]; + let mut rbuf: BorrowedBuf<'_> = buf.into(); + + unsafe { + rbuf.set_init(8); + } + + assert_eq!(rbuf.init_len(), 8); + + rbuf.unfilled().advance(4); - assert_eq!(rbuf.filled(), [255; 16]); + unsafe { + rbuf.set_init(2); + } + + assert_eq!(rbuf.init_len(), 8); + + unsafe { + rbuf.set_init(8); + } + + assert_eq!(rbuf.init_len(), 8); } #[test] @@ -61,6 +97,7 @@ fn append() { rbuf.unfilled().append(&[0; 8]); + assert_eq!(rbuf.init_len(), 8); assert_eq!(rbuf.filled().len(), 8); assert_eq!(rbuf.filled(), [0; 8]); @@ -68,6 +105,7 @@ fn append() { rbuf.unfilled().append(&[1; 16]); + assert_eq!(rbuf.init_len(), 16); assert_eq!(rbuf.filled().len(), 16); assert_eq!(rbuf.filled(), [1; 16]); } @@ -87,12 +125,43 @@ fn reborrow_written() { assert_eq!(cursor.written(), 32); assert_eq!(buf.unfilled().written(), 32); + assert_eq!(buf.init_len(), 32); assert_eq!(buf.filled().len(), 32); let filled = buf.filled(); assert_eq!(&filled[..16], [1; 16]); assert_eq!(&filled[16..], [2; 16]); } +#[test] +fn cursor_set_init() { + let buf: &mut [_] = &mut [MaybeUninit::zeroed(); 16]; + let mut rbuf: BorrowedBuf<'_> = buf.into(); + + unsafe { + rbuf.unfilled().set_init(8); + } + + assert_eq!(rbuf.init_len(), 8); + assert_eq!(rbuf.unfilled().init_mut().len(), 8); + assert_eq!(unsafe { rbuf.unfilled().as_mut().len() }, 16); + + rbuf.unfilled().advance(4); + + unsafe { + rbuf.unfilled().set_init(2); + } + + assert_eq!(rbuf.init_len(), 8); + + unsafe { + rbuf.unfilled().set_init(8); + } + + assert_eq!(rbuf.init_len(), 12); + assert_eq!(rbuf.unfilled().init_mut().len(), 8); + assert_eq!(unsafe { rbuf.unfilled().as_mut().len() }, 12); +} + #[test] fn cursor_with_unfilled_buf() { let buf: &mut [_] = &mut [MaybeUninit::uninit(); 16]; @@ -100,30 +169,31 @@ fn cursor_with_unfilled_buf() { let mut cursor = rbuf.unfilled(); cursor.with_unfilled_buf(|buf| { - assert_eq!(buf.capacity(), 16); buf.unfilled().append(&[1, 2, 3]); assert_eq!(buf.filled(), &[1, 2, 3]); }); + assert_eq!(cursor.init_mut().len(), 0); assert_eq!(cursor.written(), 3); cursor.with_unfilled_buf(|buf| { assert_eq!(buf.capacity(), 13); + assert_eq!(buf.init_len(), 0); - unsafe { - buf.unfilled().as_mut().write_filled(0); - buf.unfilled().advance(4) - }; + buf.unfilled().ensure_init(); + buf.unfilled().advance(4); }); + assert_eq!(cursor.init_mut().len(), 9); assert_eq!(cursor.written(), 7); cursor.with_unfilled_buf(|buf| { assert_eq!(buf.capacity(), 9); + assert_eq!(buf.init_len(), 9); }); + assert_eq!(cursor.init_mut().len(), 9); assert_eq!(cursor.written(), 7); - assert_eq!(rbuf.len(), 7); assert_eq!(rbuf.filled(), &[1, 2, 3, 0, 0, 0, 0]); } diff --git a/library/std/src/fs/tests.rs b/library/std/src/fs/tests.rs index bcaafcfee787a..0a5d1153d860c 100644 --- a/library/std/src/fs/tests.rs +++ b/library/std/src/fs/tests.rs @@ -709,6 +709,8 @@ fn file_test_read_buf() { let mut file = check!(File::open(filename)); check!(file.read_buf(buf.unfilled())); assert_eq!(buf.filled(), &[1, 2, 3, 4]); + // File::read_buf should omit buffer initialization. + assert_eq!(buf.init_len(), 4); check!(fs::remove_file(filename)); } diff --git a/library/std/src/io/buffered/bufreader.rs b/library/std/src/io/buffered/bufreader.rs index 69c260b5410af..40441dc057d0d 100644 --- a/library/std/src/io/buffered/bufreader.rs +++ b/library/std/src/io/buffered/bufreader.rs @@ -284,6 +284,15 @@ impl BufReader { } } +// This is only used by a test which asserts that the initialization-tracking is correct. +#[cfg(test)] +impl BufReader { + #[allow(missing_docs)] + pub fn initialized(&self) -> usize { + self.buf.initialized() + } +} + impl BufReader { /// Seeks relative to the current position. If the new position lies within the buffer, /// the buffer will not be flushed, allowing for more efficient seeks. diff --git a/library/std/src/io/buffered/bufreader/buffer.rs b/library/std/src/io/buffered/bufreader/buffer.rs index 2694726b3f44f..9b600cd55758b 100644 --- a/library/std/src/io/buffered/bufreader/buffer.rs +++ b/library/std/src/io/buffered/bufreader/buffer.rs @@ -21,19 +21,25 @@ pub struct Buffer { // Each call to `fill_buf` sets `filled` to indicate how many bytes at the start of `buf` are // initialized with bytes from a read. filled: usize, + // This is the max number of bytes returned across all `fill_buf` calls. We track this so that we + // can accurately tell `read_buf` how many bytes of buf are initialized, to bypass as much of its + // defensive initialization as possible. Note that while this often the same as `filled`, it + // doesn't need to be. Calls to `fill_buf` are not required to actually fill the buffer, and + // omitting this is a huge perf regression for `Read` impls that do not. + initialized: usize, } impl Buffer { #[inline] pub fn with_capacity(capacity: usize) -> Self { let buf = Box::new_uninit_slice(capacity); - Self { buf, pos: 0, filled: 0 } + Self { buf, pos: 0, filled: 0, initialized: 0 } } #[inline] pub fn try_with_capacity(capacity: usize) -> io::Result { match Box::try_new_uninit_slice(capacity) { - Ok(buf) => Ok(Self { buf, pos: 0, filled: 0 }), + Ok(buf) => Ok(Self { buf, pos: 0, filled: 0, initialized: 0 }), Err(_) => { Err(io::const_error!(ErrorKind::OutOfMemory, "failed to allocate read buffer")) } @@ -62,6 +68,12 @@ impl Buffer { self.pos } + // This is only used by a test which asserts that the initialization-tracking is correct. + #[cfg(test)] + pub fn initialized(&self) -> usize { + self.initialized + } + #[inline] pub fn discard_buffer(&mut self) { self.pos = 0; @@ -98,8 +110,13 @@ impl Buffer { /// Read more bytes into the buffer without discarding any of its contents pub fn read_more(&mut self, mut reader: impl Read) -> io::Result { let mut buf = BorrowedBuf::from(&mut self.buf[self.filled..]); + let old_init = self.initialized - self.filled; + unsafe { + buf.set_init(old_init); + } reader.read_buf(buf.unfilled())?; self.filled += buf.len(); + self.initialized += buf.init_len() - old_init; Ok(buf.len()) } @@ -120,10 +137,16 @@ impl Buffer { debug_assert!(self.pos == self.filled); let mut buf = BorrowedBuf::from(&mut *self.buf); + // SAFETY: `self.filled` bytes will always have been initialized. + unsafe { + buf.set_init(self.initialized); + } + let result = reader.read_buf(buf.unfilled()); self.pos = 0; self.filled = buf.len(); + self.initialized = buf.init_len(); result?; } diff --git a/library/std/src/io/buffered/tests.rs b/library/std/src/io/buffered/tests.rs index 068dca819775a..17f6107aa030c 100644 --- a/library/std/src/io/buffered/tests.rs +++ b/library/std/src/io/buffered/tests.rs @@ -1052,6 +1052,30 @@ fn single_formatted_write() { assert_eq!(writer.get_ref().events, [RecordedEvent::Write("hello, world!\n".to_string())]); } +#[test] +fn bufreader_full_initialize() { + struct OneByteReader; + impl Read for OneByteReader { + fn read(&mut self, buf: &mut [u8]) -> crate::io::Result { + if buf.len() > 0 { + buf[0] = 0; + Ok(1) + } else { + Ok(0) + } + } + } + let mut reader = BufReader::new(OneByteReader); + // Nothing is initialized yet. + assert_eq!(reader.initialized(), 0); + + let buf = reader.fill_buf().unwrap(); + // We read one byte... + assert_eq!(buf.len(), 1); + // But we initialized the whole buffer! + assert_eq!(reader.initialized(), reader.capacity()); +} + /// This is a regression test for https://github.com/rust-lang/rust/issues/127584. #[test] fn bufwriter_aliasing() { diff --git a/library/std/src/io/copy.rs b/library/std/src/io/copy.rs index 8b5e7c4df4e08..2b558efb8885e 100644 --- a/library/std/src/io/copy.rs +++ b/library/std/src/io/copy.rs @@ -214,19 +214,28 @@ impl BufferedWriterSpec for BufWriter { } let mut len = 0; + let mut init = 0; loop { let buf = self.buffer_mut(); let mut read_buf: BorrowedBuf<'_> = buf.spare_capacity_mut().into(); + unsafe { + // SAFETY: init is either 0 or the init_len from the previous iteration. + read_buf.set_init(init); + } + if read_buf.capacity() >= DEFAULT_BUF_SIZE { let mut cursor = read_buf.unfilled(); match reader.read_buf(cursor.reborrow()) { Ok(()) => { let bytes_read = cursor.written(); + if bytes_read == 0 { return Ok(len); } + + init = read_buf.init_len() - bytes_read; len += bytes_read as u64; // SAFETY: BorrowedBuf guarantees all of its filled bytes are init @@ -239,6 +248,10 @@ impl BufferedWriterSpec for BufWriter { Err(e) => return Err(e), } } else { + // All the bytes that were already in the buffer are initialized, + // treat them as such when the buffer is flushed. + init += buf.len(); + self.flush_buf()?; } } diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs index 4c064c435e5bc..b7756befa11e9 100644 --- a/library/std/src/io/mod.rs +++ b/library/std/src/io/mod.rs @@ -419,6 +419,8 @@ pub(crate) fn default_read_to_end( .and_then(|s| s.checked_add(1024)?.checked_next_multiple_of(DEFAULT_BUF_SIZE)) .unwrap_or(DEFAULT_BUF_SIZE); + let mut initialized = 0; // Extra initialized bytes from previous loop iteration + const PROBE_SIZE: usize = 32; fn small_probe_read(r: &mut R, buf: &mut Vec) -> Result { @@ -447,6 +449,8 @@ pub(crate) fn default_read_to_end( } } + let mut consecutive_short_reads = 0; + loop { if buf.len() == buf.capacity() && buf.capacity() == start_cap { // The buffer might be an exact fit. Let's read into a probe buffer @@ -470,6 +474,11 @@ pub(crate) fn default_read_to_end( spare = &mut spare[..buf_len]; let mut read_buf: BorrowedBuf<'_> = spare.into(); + // SAFETY: These bytes were initialized but not filled in the previous loop + unsafe { + read_buf.set_init(initialized); + } + let mut cursor = read_buf.unfilled(); let result = loop { match r.read_buf(cursor.reborrow()) { @@ -480,7 +489,9 @@ pub(crate) fn default_read_to_end( } }; + let unfilled_but_initialized = cursor.init_mut().len(); let bytes_read = cursor.written(); + let was_fully_initialized = read_buf.init_len() == buf_len; // SAFETY: BorrowedBuf's invariants mean this much memory is initialized. unsafe { @@ -495,8 +506,27 @@ pub(crate) fn default_read_to_end( return Ok(buf.len() - start_len); } + if bytes_read < buf_len { + consecutive_short_reads += 1; + } else { + consecutive_short_reads = 0; + } + + // store how much was initialized but not filled + initialized = unfilled_but_initialized; + // Use heuristics to determine the max read size if no initial size hint was provided if size_hint.is_none() { + // The reader is returning short reads but it doesn't call ensure_init(). + // In that case we no longer need to restrict read sizes to avoid + // initialization costs. + // When reading from disk we usually don't get any short reads except at EOF. + // So we wait for at least 2 short reads before uncapping the read buffer; + // this helps with the Windows issue. + if !was_fully_initialized && consecutive_short_reads > 1 { + max_read_size = usize::MAX; + } + // we have passed a larger buffer than previously and the // reader still hasn't returned a short read if buf_len >= max_read_size && bytes_read == buf_len { @@ -557,13 +587,8 @@ pub(crate) fn default_read_buf(read: F, mut cursor: BorrowedCursor<'_>) -> Re where F: FnOnce(&mut [u8]) -> Result, { - // SAFETY: We do not uninitialize any part of the buffer. - let n = read(unsafe { cursor.as_mut().write_filled(0) })?; - assert!(n <= cursor.capacity()); - // SAFETY: We've initialized the entire buffer, and `read` can't make it uninitialized. - unsafe { - cursor.advance(n); - } + let n = read(cursor.ensure_init().init_mut())?; + cursor.advance(n); Ok(()) } @@ -3073,21 +3098,31 @@ impl Read for Take { // The condition above guarantees that `self.limit` fits in `usize`. let limit = self.limit as usize; + let extra_init = cmp::min(limit, buf.init_mut().len()); + // SAFETY: no uninit data is written to ibuf let ibuf = unsafe { &mut buf.as_mut()[..limit] }; let mut sliced_buf: BorrowedBuf<'_> = ibuf.into(); + // SAFETY: extra_init bytes of ibuf are known to be initialized + unsafe { + sliced_buf.set_init(extra_init); + } + let mut cursor = sliced_buf.unfilled(); let result = self.inner.read_buf(cursor.reborrow()); + let new_init = cursor.init_mut().len(); let filled = sliced_buf.len(); // cursor / sliced_buf / ibuf must drop here - // SAFETY: filled bytes have been filled and therefore initialized unsafe { - buf.advance(filled); + // SAFETY: filled bytes have been filled and therefore initialized + buf.advance_unchecked(filled); + // SAFETY: new_init bytes of buf's unfilled buffer have been initialized + buf.set_init(new_init); } self.limit -= filled as u64; diff --git a/library/std/src/io/tests.rs b/library/std/src/io/tests.rs index e14e6432eafaf..b22988d4a8a9d 100644 --- a/library/std/src/io/tests.rs +++ b/library/std/src/io/tests.rs @@ -209,6 +209,15 @@ fn read_buf_exact() { assert_eq!(c.read_buf_exact(buf.unfilled()).unwrap_err().kind(), io::ErrorKind::UnexpectedEof); } +#[test] +#[should_panic] +fn borrowed_cursor_advance_overflow() { + let mut buf = [0; 512]; + let mut buf = BorrowedBuf::from(&mut buf[..]); + buf.unfilled().advance(1); + buf.unfilled().advance(usize::MAX); +} + #[test] fn take_eof() { struct R; diff --git a/library/std/src/io/util.rs b/library/std/src/io/util.rs index a09c8bc069306..0410df3ef1a3e 100644 --- a/library/std/src/io/util.rs +++ b/library/std/src/io/util.rs @@ -283,7 +283,7 @@ impl Read for Repeat { // SAFETY: No uninit bytes are being written. unsafe { buf.as_mut() }.write_filled(self.byte); // SAFETY: the entire unfilled portion of buf has been initialized. - unsafe { buf.advance(buf.capacity()) }; + unsafe { buf.advance_unchecked(buf.capacity()) }; Ok(()) } diff --git a/library/std/src/io/util/tests.rs b/library/std/src/io/util/tests.rs index 92dbc3919bea2..d0f106d7af416 100644 --- a/library/std/src/io/util/tests.rs +++ b/library/std/src/io/util/tests.rs @@ -75,36 +75,43 @@ fn empty_reads() { let mut buf: BorrowedBuf<'_> = buf.into(); e.read_buf(buf.unfilled()).unwrap(); assert_eq!(buf.len(), 0); + assert_eq!(buf.init_len(), 0); let buf: &mut [_] = &mut [MaybeUninit::uninit()]; let mut buf: BorrowedBuf<'_> = buf.into(); e.read_buf(buf.unfilled()).unwrap(); assert_eq!(buf.len(), 0); + assert_eq!(buf.init_len(), 0); let buf: &mut [_] = &mut [MaybeUninit::uninit(); 1024]; let mut buf: BorrowedBuf<'_> = buf.into(); e.read_buf(buf.unfilled()).unwrap(); assert_eq!(buf.len(), 0); + assert_eq!(buf.init_len(), 0); let buf: &mut [_] = &mut [MaybeUninit::uninit(); 1024]; let mut buf: BorrowedBuf<'_> = buf.into(); Read::by_ref(&mut e).read_buf(buf.unfilled()).unwrap(); assert_eq!(buf.len(), 0); + assert_eq!(buf.init_len(), 0); let buf: &mut [MaybeUninit<_>] = &mut []; let mut buf: BorrowedBuf<'_> = buf.into(); e.read_buf_exact(buf.unfilled()).unwrap(); assert_eq!(buf.len(), 0); + assert_eq!(buf.init_len(), 0); let buf: &mut [_] = &mut [MaybeUninit::uninit()]; let mut buf: BorrowedBuf<'_> = buf.into(); assert_eq!(e.read_buf_exact(buf.unfilled()).unwrap_err().kind(), ErrorKind::UnexpectedEof); assert_eq!(buf.len(), 0); + assert_eq!(buf.init_len(), 0); let buf: &mut [_] = &mut [MaybeUninit::uninit(); 1024]; let mut buf: BorrowedBuf<'_> = buf.into(); assert_eq!(e.read_buf_exact(buf.unfilled()).unwrap_err().kind(), ErrorKind::UnexpectedEof); assert_eq!(buf.len(), 0); + assert_eq!(buf.init_len(), 0); let buf: &mut [_] = &mut [MaybeUninit::uninit(); 1024]; let mut buf: BorrowedBuf<'_> = buf.into(); @@ -113,6 +120,7 @@ fn empty_reads() { ErrorKind::UnexpectedEof, ); assert_eq!(buf.len(), 0); + assert_eq!(buf.init_len(), 0); let mut buf = Vec::new(); assert_eq!(e.read_to_end(&mut buf).unwrap(), 0); diff --git a/library/std/src/net/tcp/tests.rs b/library/std/src/net/tcp/tests.rs index 4787f8a1040b9..7c7ef7b2f7018 100644 --- a/library/std/src/net/tcp/tests.rs +++ b/library/std/src/net/tcp/tests.rs @@ -315,6 +315,8 @@ fn read_buf() { let mut buf = BorrowedBuf::from(buf.as_mut_slice()); t!(s.read_buf(buf.unfilled())); assert_eq!(buf.filled(), &[1, 2, 3, 4]); + // TcpStream::read_buf should omit buffer initialization. + assert_eq!(buf.init_len(), 4); t.join().ok().expect("thread panicked"); }) diff --git a/library/std/src/process/tests.rs b/library/std/src/process/tests.rs index c8a83edffe427..12c5130defe5a 100644 --- a/library/std/src/process/tests.rs +++ b/library/std/src/process/tests.rs @@ -188,8 +188,10 @@ fn child_stdout_read_buf() { // ChildStdout::read_buf should omit buffer initialization. if cfg!(target_os = "windows") { assert_eq!(buf.filled(), b"abc\r\n"); + assert_eq!(buf.init_len(), 5); } else { assert_eq!(buf.filled(), b"abc\n"); + assert_eq!(buf.init_len(), 4); }; } diff --git a/library/std/src/sys/fd/hermit.rs b/library/std/src/sys/fd/hermit.rs index afcd8c6355416..7e8ba065f1b96 100644 --- a/library/std/src/sys/fd/hermit.rs +++ b/library/std/src/sys/fd/hermit.rs @@ -34,7 +34,7 @@ impl FileDesc { ) })?; // SAFETY: Exactly `result` bytes have been filled. - unsafe { buf.advance(result as usize) }; + unsafe { buf.advance_unchecked(result as usize) }; Ok(()) } diff --git a/library/std/src/sys/fd/unix.rs b/library/std/src/sys/fd/unix.rs index a631e1d91393f..2b2dfe48e89e2 100644 --- a/library/std/src/sys/fd/unix.rs +++ b/library/std/src/sys/fd/unix.rs @@ -185,7 +185,7 @@ impl FileDesc { // SAFETY: `ret` bytes were written to the initialized portion of the buffer unsafe { - cursor.advance(ret as usize); + cursor.advance_unchecked(ret as usize); } Ok(()) } @@ -203,7 +203,7 @@ impl FileDesc { // SAFETY: `ret` bytes were written to the initialized portion of the buffer unsafe { - cursor.advance(ret as usize); + cursor.advance_unchecked(ret as usize); } Ok(()) } diff --git a/library/std/src/sys/fd/wasi.rs b/library/std/src/sys/fd/wasi.rs index a468b31168afa..80a5143ff0b00 100644 --- a/library/std/src/sys/fd/wasi.rs +++ b/library/std/src/sys/fd/wasi.rs @@ -59,7 +59,7 @@ impl WasiFd { }]; match wasi::fd_read(self.as_raw_fd() as wasi::Fd, &bufs) { Ok(n) => { - buf.advance(n); + buf.advance_unchecked(n); Ok(()) } Err(e) => Err(err2io(e)), diff --git a/library/std/src/sys/fs/solid.rs b/library/std/src/sys/fs/solid.rs index ec1db262855ad..f6d5d3b784d3b 100644 --- a/library/std/src/sys/fs/solid.rs +++ b/library/std/src/sys/fs/solid.rs @@ -401,7 +401,7 @@ impl File { // Safety: `num_bytes_read` bytes were written to the unfilled // portion of the buffer - cursor.advance(num_bytes_read); + cursor.advance_unchecked(num_bytes_read); Ok(()) } diff --git a/library/std/src/sys/net/connection/socket/hermit.rs b/library/std/src/sys/net/connection/socket/hermit.rs index f044bf8dfae08..2f5c6fa31d407 100644 --- a/library/std/src/sys/net/connection/socket/hermit.rs +++ b/library/std/src/sys/net/connection/socket/hermit.rs @@ -143,7 +143,7 @@ impl Socket { ) })?; unsafe { - buf.advance(ret as usize); + buf.advance_unchecked(ret as usize); } Ok(()) } diff --git a/library/std/src/sys/net/connection/socket/solid.rs b/library/std/src/sys/net/connection/socket/solid.rs index 731157ec319c5..14cf75adcc06f 100644 --- a/library/std/src/sys/net/connection/socket/solid.rs +++ b/library/std/src/sys/net/connection/socket/solid.rs @@ -191,7 +191,7 @@ impl Socket { netc::recv(self.as_raw_fd(), buf.as_mut().as_mut_ptr().cast(), buf.capacity(), flags) })?; unsafe { - buf.advance(ret as usize); + buf.advance_unchecked(ret as usize); } Ok(()) } diff --git a/library/std/src/sys/net/connection/socket/unix.rs b/library/std/src/sys/net/connection/socket/unix.rs index c892daf0d39c3..559e27604a9d3 100644 --- a/library/std/src/sys/net/connection/socket/unix.rs +++ b/library/std/src/sys/net/connection/socket/unix.rs @@ -293,7 +293,7 @@ impl Socket { ) })?; unsafe { - buf.advance(ret as usize); + buf.advance_unchecked(ret as usize); } Ok(()) } diff --git a/library/std/src/sys/net/connection/socket/wasip2.rs b/library/std/src/sys/net/connection/socket/wasip2.rs index f86034266c26a..a1b08609eb024 100644 --- a/library/std/src/sys/net/connection/socket/wasip2.rs +++ b/library/std/src/sys/net/connection/socket/wasip2.rs @@ -167,7 +167,7 @@ impl Socket { ) })?; unsafe { - buf.advance(ret as usize); + buf.advance_unchecked(ret as usize); } Ok(()) } diff --git a/library/std/src/sys/net/connection/socket/windows.rs b/library/std/src/sys/net/connection/socket/windows.rs index 08196d61aa30d..6dbebc5e276ec 100644 --- a/library/std/src/sys/net/connection/socket/windows.rs +++ b/library/std/src/sys/net/connection/socket/windows.rs @@ -244,7 +244,7 @@ impl Socket { } } _ => { - unsafe { buf.advance(result as usize) }; + unsafe { buf.advance_unchecked(result as usize) }; Ok(()) } } diff --git a/library/std/src/sys/pal/sgx/abi/usercalls/mod.rs b/library/std/src/sys/pal/sgx/abi/usercalls/mod.rs index f1e4a5a42577a..5041770faf661 100644 --- a/library/std/src/sys/pal/sgx/abi/usercalls/mod.rs +++ b/library/std/src/sys/pal/sgx/abi/usercalls/mod.rs @@ -46,7 +46,7 @@ pub fn read_buf(fd: Fd, mut buf: BorrowedCursor<'_>) -> IoResult<()> { let mut userbuf = alloc::User::<[u8]>::uninitialized(buf.capacity()); let len = raw::read(fd, userbuf.as_mut_ptr().cast(), userbuf.len()).from_sgx_result()?; userbuf[..len].copy_to_enclave(&mut buf.as_mut()[..len]); - buf.advance(len); + buf.advance_unchecked(len); Ok(()) } } diff --git a/library/std/src/sys/pal/windows/handle.rs b/library/std/src/sys/pal/windows/handle.rs index 712f41ba80308..76c8aa939d3b2 100644 --- a/library/std/src/sys/pal/windows/handle.rs +++ b/library/std/src/sys/pal/windows/handle.rs @@ -121,7 +121,7 @@ impl Handle { Ok(read) => { // Safety: `read` bytes were written to the initialized portion of the buffer unsafe { - cursor.advance(read); + cursor.advance_unchecked(read); } Ok(()) } @@ -144,7 +144,7 @@ impl Handle { // SAFETY: `read` bytes were written to the initialized portion of the buffer unsafe { - cursor.advance(read); + cursor.advance_unchecked(read); } Ok(()) } diff --git a/library/std/src/sys/pal/windows/pipe.rs b/library/std/src/sys/pal/windows/pipe.rs index d8e306068d73c..b5ccf037a4f22 100644 --- a/library/std/src/sys/pal/windows/pipe.rs +++ b/library/std/src/sys/pal/windows/pipe.rs @@ -259,7 +259,7 @@ impl AnonPipe { Err(e) => Err(e), Ok(n) => { unsafe { - buf.advance(n); + buf.advance_unchecked(n); } Ok(()) } diff --git a/library/std/src/sys/stdio/zkvm.rs b/library/std/src/sys/stdio/zkvm.rs index 84496ac937363..f31c6c26e87cd 100644 --- a/library/std/src/sys/stdio/zkvm.rs +++ b/library/std/src/sys/stdio/zkvm.rs @@ -19,7 +19,7 @@ impl io::Read for Stdin { fn read_buf(&mut self, mut buf: BorrowedCursor<'_>) -> io::Result<()> { unsafe { let n = abi::sys_read(fileno::STDIN, buf.as_mut().as_mut_ptr().cast(), buf.capacity()); - buf.advance(n); + buf.advance_unchecked(n); } Ok(()) } From 14c38553beafd9580447e955a3d429fd0dbbbc2e Mon Sep 17 00:00:00 2001 From: Dennis Duda Date: Fri, 15 Nov 2024 23:36:33 +0100 Subject: [PATCH 09/58] Add `{i586,i686,x86_64}-rust9x-windows-msvc` targets --- compiler/rustc_target/src/spec/mod.rs | 3 ++ .../spec/targets/i586_rust9x_windows_msvc.rs | 10 +++++++ .../spec/targets/i686_rust9x_windows_msvc.rs | 29 +++++++++++++++++++ .../targets/x86_64_rust9x_windows_msvc.rs | 29 +++++++++++++++++++ library/std/Cargo.toml | 1 + library/windows_targets/Cargo.toml | 5 ++++ src/bootstrap/src/core/sanity.rs | 3 ++ 7 files changed, 80 insertions(+) create mode 100644 compiler/rustc_target/src/spec/targets/i586_rust9x_windows_msvc.rs create mode 100644 compiler/rustc_target/src/spec/targets/i686_rust9x_windows_msvc.rs create mode 100644 compiler/rustc_target/src/spec/targets/x86_64_rust9x_windows_msvc.rs diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index 424026bdceab8..30fb63fc1019a 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -1624,9 +1624,12 @@ supported_targets! { ("x86_64-pc-windows-msvc", x86_64_pc_windows_msvc), ("x86_64-uwp-windows-msvc", x86_64_uwp_windows_msvc), ("x86_64-win7-windows-msvc", x86_64_win7_windows_msvc), + ("x86_64-rust9x-windows-msvc", x86_64_rust9x_windows_msvc), ("i686-pc-windows-msvc", i686_pc_windows_msvc), ("i686-uwp-windows-msvc", i686_uwp_windows_msvc), ("i686-win7-windows-msvc", i686_win7_windows_msvc), + ("i686-rust9x-windows-msvc", i686_rust9x_windows_msvc), + ("i586-rust9x-windows-msvc", i586_rust9x_windows_msvc), ("thumbv7a-pc-windows-msvc", thumbv7a_pc_windows_msvc), ("thumbv7a-uwp-windows-msvc", thumbv7a_uwp_windows_msvc), diff --git a/compiler/rustc_target/src/spec/targets/i586_rust9x_windows_msvc.rs b/compiler/rustc_target/src/spec/targets/i586_rust9x_windows_msvc.rs new file mode 100644 index 0000000000000..c1cda96cf160d --- /dev/null +++ b/compiler/rustc_target/src/spec/targets/i586_rust9x_windows_msvc.rs @@ -0,0 +1,10 @@ +use crate::spec::Target; + +pub(crate) fn target() -> Target { + let mut base = super::i686_rust9x_windows_msvc::target(); + base.cpu = "pentium".into(); + base.llvm_target = "i586-pc-windows-msvc".into(); + // go back to x87 FPU ABI spec + base.rustc_abi = None; + base +} diff --git a/compiler/rustc_target/src/spec/targets/i686_rust9x_windows_msvc.rs b/compiler/rustc_target/src/spec/targets/i686_rust9x_windows_msvc.rs new file mode 100644 index 0000000000000..b7cceb97b20f2 --- /dev/null +++ b/compiler/rustc_target/src/spec/targets/i686_rust9x_windows_msvc.rs @@ -0,0 +1,29 @@ +use crate::spec::{LinkerFlavor, Lld, Target, cvs}; + +pub(crate) fn target() -> Target { + let mut base = super::i686_pc_windows_msvc::target(); + base.families = cvs!["windows", "rust9x"]; + + base.add_pre_link_args( + LinkerFlavor::Msvc(Lld::No), + &[ + // "/LARGEADDRESSAWARE", + // "/SAFESEH", + // ↑ these are already added in the base target + + // Link to ___CxxFrameHandler (XP and earlier MSVCRT) instead of ___CxxFrameHandler3. + // This cannot be done in the MSVC `eh_personality` handling because LLVM hardcodes SEH + // support based on that name, sadly + "/ALTERNATENAME:___CxxFrameHandler3=___CxxFrameHandler", + ], + ); + + base.metadata = crate::spec::TargetMetadata { + description: Some("32-bit MSVC rust9x (Windows 95/NT3.51+)".into()), + tier: Some(4), + host_tools: Some(false), + std: Some(true), + }; + + base +} diff --git a/compiler/rustc_target/src/spec/targets/x86_64_rust9x_windows_msvc.rs b/compiler/rustc_target/src/spec/targets/x86_64_rust9x_windows_msvc.rs new file mode 100644 index 0000000000000..3153f04e79a56 --- /dev/null +++ b/compiler/rustc_target/src/spec/targets/x86_64_rust9x_windows_msvc.rs @@ -0,0 +1,29 @@ +use crate::spec::{LinkerFlavor, Lld, Target, cvs}; + +pub(crate) fn target() -> Target { + let mut base = super::x86_64_pc_windows_msvc::target(); + // these aren't available on all x86_64 CPUs + // base.features = "+cx16,+sse3,+sahf".into(); + base.plt_by_default = false; + base.max_atomic_width = Some(64); + base.families = cvs!["windows", "rust9x"]; + + base.add_pre_link_args( + LinkerFlavor::Msvc(Lld::No), + &[ + // Link to ___CxxFrameHandler (XP and earlier MSVCRT) instead of ___CxxFrameHandler3. + // This cannot be done in the MSVC `eh_personality` handling because LLVM hardcodes SEH + // support based on that name, sadly + "/ALTERNATENAME:___CxxFrameHandler3=___CxxFrameHandler", + ], + ); + + base.metadata = crate::spec::TargetMetadata { + description: Some("64-bit MSVC rust9x (Windows XP 64bit+)".into()), + tier: Some(4), + host_tools: Some(false), + std: Some(true), + }; + + base +} diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml index 3a673cf23b835..a051047c412c9 100644 --- a/library/std/Cargo.toml +++ b/library/std/Cargo.toml @@ -177,4 +177,5 @@ check-cfg = [ 'cfg(target_has_reliable_f16_math)', 'cfg(target_has_reliable_f128)', 'cfg(target_has_reliable_f128_math)', + 'cfg(target_family, values("rust9x"))', ] diff --git a/library/windows_targets/Cargo.toml b/library/windows_targets/Cargo.toml index 1c804a0ab391f..2ce91e3ba83ce 100644 --- a/library/windows_targets/Cargo.toml +++ b/library/windows_targets/Cargo.toml @@ -13,3 +13,8 @@ doc = false # Enable using raw-dylib for Windows imports. # This will eventually be the default. windows_raw_dylib = [] + +[lints.rust] +unexpected_cfgs = { level = "warn", check-cfg = [ + 'cfg(target_family, values("rust9x"))', +] } diff --git a/src/bootstrap/src/core/sanity.rs b/src/bootstrap/src/core/sanity.rs index 50d8154014bbc..ed5b5960f0b34 100644 --- a/src/bootstrap/src/core/sanity.rs +++ b/src/bootstrap/src/core/sanity.rs @@ -42,6 +42,9 @@ const STAGE0_MISSING_TARGETS: &[&str] = &[ // just a dummy comment so the list doesn't get onelined "riscv64gc-unknown-redox", "hexagon-unknown-qurt", + "i586-rust9x-windows-msvc", + "i686-rust9x-windows-msvc", + "x86_64-rust9x-windows-msvc", ]; /// Minimum version threshold for libstdc++ required when using prebuilt LLVM From e4b6eddc82a1ba52418fbfb5149a7e95fa4770b8 Mon Sep 17 00:00:00 2001 From: Dennis Duda Date: Sun, 1 Dec 2024 18:17:37 +0100 Subject: [PATCH 10/58] Skip adding unicows-wrapped libraries automatically --- compiler/rustc_codegen_ssa/src/back/link.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index d35c3b6bb189e..300e063d90c89 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -2655,6 +2655,13 @@ fn add_native_libs_from_crate( return; } + const UNICOWS_LIBS: &[&str] = &[ + "kernel32", "advapi32", "user32", "gdi32", "shell32", "comdlg32", "version", "mpr", + "rasapi32", "winmm", "winspool", "vfw32", "secur32", "oleacc", "oledlg", "sensapi", + ]; + let is_target_rust9x_x86 = sess.target.families.iter().any(|fam| fam == "rust9x") + && sess.target.arch == rustc_target::spec::Arch::X86; + if link_static && cnum != LOCAL_CRATE && !bundled_libs.is_empty() { // If rlib contains native libs as archives, unpack them to tmpdir. let rlib = &codegen_results.crate_info.used_crate_source[&cnum].rlib.as_ref().unwrap().0; @@ -2682,6 +2689,13 @@ fn add_native_libs_from_crate( }; let name = lib.name.as_str(); + + if is_target_rust9x_x86 && UNICOWS_LIBS.contains(&name) { + // skip adding unicows-wrapped libraries in order to properly support adding + // `unicows.lib` before them + continue; + } + let verbatim = lib.verbatim; match lib.kind { NativeLibKind::Static { bundle, whole_archive } => { From df621798730488f1a7bbbbeb5712b46602958590 Mon Sep 17 00:00:00 2001 From: Dennis Duda Date: Tue, 3 Dec 2024 22:30:51 +0100 Subject: [PATCH 11/58] Add example bootstrap.toml --- bootstrap.rust9x.toml | 52 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 bootstrap.rust9x.toml diff --git a/bootstrap.rust9x.toml b/bootstrap.rust9x.toml new file mode 100644 index 0000000000000..c57817af878a3 --- /dev/null +++ b/bootstrap.rust9x.toml @@ -0,0 +1,52 @@ +# See bootstrap.example.toml for documentation of available options +# +change-id = 148795 + +[llvm] +# Will download LLVM from CI if available on your platform. +download-ci-llvm = true +# NOTE: if you set ↑ to false, disable other LLVM targets to save lots of build time! +# targets = "X86" +# experimental-targets = "" + +[build] +build = "x86_64-pc-windows-msvc" +target = [ + "i586-rust9x-windows-msvc", + "i686-rust9x-windows-msvc", + "x86_64-rust9x-windows-msvc", + "x86_64-pc-windows-msvc", +] + +docs = false + +# extended = true +# tools = [ +# # "cargo", +# # "clippy", +# "rustdoc", +# # "rustfmt", +# # "rust-analyzer", +# # "rust-analyzer-proc-macro-srv", +# # "analysis", +# "src", +# # "wasm-component-ld", +# # "miri", "cargo-miri" # for dev/nightly channels +# ] + +[install] +# for creating a downloadable package: python x.py install, then create and archive this +prefix = "../dist/rust9x" +sysconfdir = "." + +[rust] +# enable rust-lld.exe so we don't need editbin.exe +lld = true +dist-src = false + +# you can override this with -i/--incremental +# incremental = false +# incremental = true + +[dist] +src-tarball = false From bc9bbf03407bd4a2886cee4e590c4a16556af1d4 Mon Sep 17 00:00:00 2001 From: Dennis Duda Date: Sat, 16 Nov 2024 00:17:34 +0100 Subject: [PATCH 12/58] Add more `compat_fn` machinery; NT/9x startup check This will be necessary for some APIs that exist on both platforms but with different behavior/capabilities. --- library/std/src/sys/pal/windows/c.rs | 6 +- .../std/src/sys/pal/windows/c/bindings.txt | 2 + .../std/src/sys/pal/windows/c/windows_sys.rs | 2 + library/std/src/sys/pal/windows/compat.rs | 128 +++++++++++++++--- .../std/src/sys/pal/windows/compat/checks.rs | 33 +++++ 5 files changed, 146 insertions(+), 25 deletions(-) create mode 100644 library/std/src/sys/pal/windows/compat/checks.rs diff --git a/library/std/src/sys/pal/windows/c.rs b/library/std/src/sys/pal/windows/c.rs index 25c1a82cc426a..29ef317a53e09 100644 --- a/library/std/src/sys/pal/windows/c.rs +++ b/library/std/src/sys/pal/windows/c.rs @@ -5,7 +5,7 @@ #![unstable(issue = "none", feature = "windows_c")] #![allow(clippy::style)] -use core::ffi::{CStr, c_uint, c_ulong, c_ushort, c_void}; +use core::ffi::{c_uint, c_ulong, c_ushort, c_void}; use core::ptr; mod windows_sys; @@ -129,7 +129,7 @@ windows_targets::link!("ntdll.dll" "system" fn NtCreateNamedPipeFile( // Functions that aren't available on every version of Windows that we support, // but we still use them and just provide some form of a fallback implementation. compat_fn_with_fallback! { - pub static KERNEL32: &CStr = c"kernel32"; + pub static KERNEL32: &CStr = c"kernel32" => { load: false, unicows: false }; // >= Win10 1607 // https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-setthreaddescription @@ -196,7 +196,7 @@ compat_fn_optional! { #[cfg(any(target_vendor = "win7"))] compat_fn_with_fallback! { - pub static NTDLL: &CStr = c"ntdll"; + pub static NTDLL: &CStr = c"ntdll" => { load: false, unicows: false }; #[cfg(target_vendor = "win7")] pub fn NtCreateKeyedEvent( diff --git a/library/std/src/sys/pal/windows/c/bindings.txt b/library/std/src/sys/pal/windows/c/bindings.txt index 9009aa09f48ed..da6a1ccdf937c 100644 --- a/library/std/src/sys/pal/windows/c/bindings.txt +++ b/library/std/src/sys/pal/windows/c/bindings.txt @@ -2188,6 +2188,7 @@ GetSystemTimeAsFileTime GetSystemTimePreciseAsFileTime GetTempPathW GetUserProfileDirectoryW +GetVersion GetWindowsDirectoryW HANDLE HANDLE_FLAG_INHERIT @@ -2261,6 +2262,7 @@ IPV6_MULTICAST_LOOP IPV6_V6ONLY LINGER listen +LoadLibraryA LocalFree LOCKFILE_EXCLUSIVE_LOCK LOCKFILE_FAIL_IMMEDIATELY diff --git a/library/std/src/sys/pal/windows/c/windows_sys.rs b/library/std/src/sys/pal/windows/c/windows_sys.rs index 98f277b33780c..4a8ff4e0bd484 100644 --- a/library/std/src/sys/pal/windows/c/windows_sys.rs +++ b/library/std/src/sys/pal/windows/c/windows_sys.rs @@ -64,10 +64,12 @@ windows_targets::link!("kernel32.dll" "system" fn GetSystemTimeAsFileTime(lpsyst windows_targets::link!("kernel32.dll" "system" fn GetSystemTimePreciseAsFileTime(lpsystemtimeasfiletime : *mut FILETIME)); windows_targets::link!("kernel32.dll" "system" fn GetTempPathW(nbufferlength : u32, lpbuffer : PWSTR) -> u32); windows_targets::link!("userenv.dll" "system" fn GetUserProfileDirectoryW(htoken : HANDLE, lpprofiledir : PWSTR, lpcchsize : *mut u32) -> BOOL); +windows_targets::link!("kernel32.dll" "system" fn GetVersion() -> u32); windows_targets::link!("kernel32.dll" "system" fn GetWindowsDirectoryW(lpbuffer : PWSTR, usize : u32) -> u32); windows_targets::link!("kernel32.dll" "system" fn InitOnceBeginInitialize(lpinitonce : *mut INIT_ONCE, dwflags : u32, fpending : *mut BOOL, lpcontext : *mut *mut core::ffi::c_void) -> BOOL); windows_targets::link!("kernel32.dll" "system" fn InitOnceComplete(lpinitonce : *mut INIT_ONCE, dwflags : u32, lpcontext : *const core::ffi::c_void) -> BOOL); windows_targets::link!("kernel32.dll" "system" fn InitializeProcThreadAttributeList(lpattributelist : LPPROC_THREAD_ATTRIBUTE_LIST, dwattributecount : u32, dwflags : u32, lpsize : *mut usize) -> BOOL); +windows_targets::link!("kernel32.dll" "system" fn LoadLibraryA(lplibfilename : PCSTR) -> HMODULE); windows_targets::link!("kernel32.dll" "system" fn LocalFree(hmem : HLOCAL) -> HLOCAL); windows_targets::link!("kernel32.dll" "system" fn LockFileEx(hfile : HANDLE, dwflags : LOCK_FILE_FLAGS, dwreserved : u32, nnumberofbytestolocklow : u32, nnumberofbytestolockhigh : u32, lpoverlapped : *mut OVERLAPPED) -> BOOL); windows_targets::link!("kernel32.dll" "system" fn MoveFileExW(lpexistingfilename : PCWSTR, lpnewfilename : PCWSTR, dwflags : MOVE_FILE_FLAGS) -> BOOL); diff --git a/library/std/src/sys/pal/windows/compat.rs b/library/std/src/sys/pal/windows/compat.rs index c465ceb2301ce..f3fad40a8e512 100644 --- a/library/std/src/sys/pal/windows/compat.rs +++ b/library/std/src/sys/pal/windows/compat.rs @@ -23,6 +23,9 @@ use crate::ffi::{CStr, c_void}; use crate::ptr::NonNull; use crate::sys::c; +#[cfg(target_family = "rust9x")] +pub(crate) mod checks; + // This uses a static initializer to preload some imported functions. // The CRT (C runtime) executes static initializers before `main` // is called (for binaries) and before `DllMain` is called (for DLLs). @@ -37,7 +40,7 @@ use crate::sys::c; // file an issue for discussion; currently we don't guarantee any functionality // before main. // See https://docs.microsoft.com/en-us/cpp/c-runtime-library/crt-initialization?view=msvc-170 -#[cfg(target_vendor = "win7")] +#[cfg(any(target_vendor = "win7", target_family = "rust9x"))] #[used] #[unsafe(link_section = ".CRT$XCT")] static INIT_TABLE_ENTRY: unsafe extern "C" fn() = init; @@ -68,6 +71,21 @@ unsafe extern "C" fn init() { load_synch_functions(); } +#[cfg(target_family = "rust9x")] +unsafe extern "C" fn init() { + // In an exe this code is executed before main() so is single threaded. + // In a DLL the system's loader lock will be held thereby synchronizing + // access. So the same best practices apply here as they do to running in DllMain: + // https://docs.microsoft.com/en-us/windows/win32/dlls/dynamic-link-library-best-practices + // + // DO NOT do anything interesting or complicated in this function! DO NOT call + // any Rust functions or CRT functions if those functions touch any global state, + // because this function runs during global initialization. For example, DO NOT + // do any dynamic allocation, don't call LoadLibrary, etc. + + checks::init_rust9x_checks(); +} + /// Helper macro for creating CStrs from literals and symbol names. macro_rules! ansi_str { (sym $ident:ident) => {{ crate::sys::compat::const_cstr_from_bytes(concat!(stringify!($ident), "\0").as_bytes()) }}; @@ -118,6 +136,15 @@ impl Module { } } + #[allow(dead_code)] + pub unsafe fn load(name: &CStr) -> Option { + // SAFETY: A CStr is always null terminated. + unsafe { + let module = c::LoadLibraryA(name.as_ptr().cast::()); + NonNull::new(module).map(Self) + } + } + // Try to get the address of a function. pub fn proc_address(self, name: &CStr) -> Option> { unsafe { @@ -131,59 +158,84 @@ impl Module { } } +pub static UNICOWS: &CStr = c"unicows"; + /// Load a function or use a fallback implementation if that fails. macro_rules! compat_fn_with_fallback { - (pub static $module:ident: &CStr = $name:expr; $( - $(#[$meta:meta])* - $vis:vis fn $symbol:ident($($argname:ident: $argtype:ty),*) -> $rettype:ty $fallback_body:block - )*) => ( - pub static $module: &CStr = $name; + { + pub static $module:ident: &CStr = $name:expr => { load: $load:expr, unicows: $unicows:expr }; + $( + $(#[$meta:meta])* + $vis:vis fn $symbol:ident($($argname:ident: $argtype:ty),* $(,)?) $(-> $rettype:ty)? $fallback_body:block + )* + } => { $( $(#[$meta])* pub mod $symbol { #[allow(unused_imports)] use super::*; use crate::mem; - use crate::ffi::CStr; + use crate::ffi::{c_void, CStr}; use crate::sync::atomic::{Atomic, AtomicPtr, Ordering}; - use crate::sys::compat::Module; - type F = unsafe extern "system" fn($($argtype),*) -> $rettype; + type F = unsafe extern "system" fn($($argtype),*) $(-> $rettype)?; /// `PTR` contains a function pointer to one of three functions. /// It starts with the `load` function. /// When that is called it attempts to load the requested symbol. /// If it succeeds, `PTR` is set to the address of that symbol. /// If it fails, then `PTR` is set to `fallback`. - static PTR: Atomic<*mut c_void> = AtomicPtr::new(load as unsafe extern "system" fn($($argname: $argtype),*) -> $rettype as *mut _); + pub(in crate::sys) static PTR: Atomic<*mut c_void> = AtomicPtr::new(load as unsafe extern "system" fn($($argname: $argtype),*) $(-> $rettype)? as *mut _); - unsafe extern "system" fn load($($argname: $argtype),*) -> $rettype { + unsafe extern "system" fn load($($argname: $argtype),*) $(-> $rettype)? { unsafe { - let func = load_from_module(Module::new($module)); + let func = load_from_module(); func($($argname),*) } } - fn load_from_module(module: Option) -> F { + fn load_from_module() -> F { unsafe { static SYMBOL_NAME: &CStr = ansi_str!(sym $symbol); - if let Some(f) = module.and_then(|m| m.proc_address(SYMBOL_NAME)) { + + let f = crate::sys::compat::load_from_module( + $name, + SYMBOL_NAME, + $load, + $unicows + ); + + if let Some(f) = f { PTR.store(f.as_ptr(), Ordering::Relaxed); mem::transmute(f) } else { - PTR.store(fallback as unsafe extern "system" fn($($argname: $argtype),*) -> $rettype as *mut _, Ordering::Relaxed); + PTR.store(fallback as unsafe extern "system" fn($($argname: $argtype),*) $(-> $rettype)? as *mut _, Ordering::Relaxed); fallback } } } + #[allow(dead_code)] + pub fn available() -> Option { + let mut ptr = PTR.load(Ordering::Relaxed); + if ptr == load as *mut _ { + ptr = load_from_module() as *mut _; + } + + if ptr != fallback as *mut _ { + Some(unsafe { mem::transmute(ptr) }) + } else { + None + } + } + #[allow(unused_variables)] - unsafe extern "system" fn fallback($($argname: $argtype),*) -> $rettype { + unsafe extern "system" fn fallback($($argname: $argtype),*) $(-> $rettype)? { $fallback_body } #[inline(always)] - pub unsafe fn call($($argname: $argtype),*) -> $rettype { + pub unsafe fn call($($argname: $argtype),*) $(-> $rettype)? { unsafe { let func: F = mem::transmute(PTR.load(Ordering::Relaxed)); func($($argname),*) @@ -193,7 +245,8 @@ macro_rules! compat_fn_with_fallback { #[allow(unused)] $(#[$meta])* $vis use $symbol::call as $symbol; - )*) + )* + } } /// Optionally loaded functions. @@ -203,7 +256,7 @@ macro_rules! compat_fn_with_fallback { macro_rules! compat_fn_optional { ($( $(#[$meta:meta])* - $vis:vis fn $symbol:ident($($argname:ident: $argtype:ty),*) $(-> $rettype:ty)?; + $vis:vis fn $symbol:ident($($argname:ident: $argtype:ty),* $(,)?) $(-> $rettype:ty)?; )+) => ( $( pub mod $symbol { @@ -219,8 +272,19 @@ macro_rules! compat_fn_optional { type F = unsafe extern "system" fn($($argtype),*) $(-> $rettype)?; #[inline(always)] + #[allow(dead_code)] pub fn option() -> Option { - NonNull::new(PTR.load(Ordering::Relaxed)).map(|f| unsafe { mem::transmute(f) }) + unsafe { + NonNull::new(PTR.load(Ordering::Relaxed)).map(|f| unsafe { mem::transmute(f) }) + } + } + + #[inline(always)] + #[allow(dead_code)] + pub unsafe fn call($($argname: $argtype),*) $(-> $rettype)? { + unsafe { + (mem::transmute::<_, F>(PTR.load(Ordering::Relaxed)))($($argname),*) + } } } #[inline] @@ -231,6 +295,28 @@ macro_rules! compat_fn_optional { ) } +pub(crate) fn load_from_module( + module_name: &CStr, + symbol_name: &CStr, + load: bool, + unicows: bool, +) -> Option> { + let in_unicows = if unicows { + unsafe { Module::new(UNICOWS).and_then(|m| m.proc_address(symbol_name)) } + } else { + None + }; + + in_unicows.or_else(|| { + if load { + unsafe { Module::new(module_name) } + } else { + unsafe { Module::load(module_name) } + } + .and_then(|m| m.proc_address(symbol_name)) + }) +} + /// Load all needed functions from "api-ms-win-core-synch-l1-2-0". #[cfg(target_vendor = "win7")] pub(super) fn load_synch_functions() { @@ -250,6 +336,4 @@ pub(super) fn load_synch_functions() { c::WakeByAddressSingle::PTR.store(wake_by_address_single.as_ptr(), Ordering::Relaxed); Some(()) } - - try_load(); } diff --git a/library/std/src/sys/pal/windows/compat/checks.rs b/library/std/src/sys/pal/windows/compat/checks.rs new file mode 100644 index 0000000000000..871033e07e341 --- /dev/null +++ b/library/std/src/sys/pal/windows/compat/checks.rs @@ -0,0 +1,33 @@ +use crate::sys::c; + +/// Returns true if we are running on a Windows NT-based system. Only use this for APIs where the +/// same API differs in behavior or capability on 9x/ME compared to NT. +#[allow(dead_code)] +#[inline(always)] +#[cfg(target_arch = "x86")] +pub fn is_windows_nt() -> bool { + unsafe { IS_NT } +} + +#[allow(dead_code)] +#[inline(always)] +#[cfg(target_arch = "x86_64")] +pub fn is_windows_nt() -> bool { + true // let me know once someone ported 9x to 64bit LOL +} + +pub fn init_rust9x_checks() { + // DO NOT do anything interesting or complicated in this function! DO NOT call + // any Rust functions or CRT functions if those functions touch any global state, + // because this function runs during global initialization. For example, DO NOT + // do any dynamic allocation, don't call LoadLibrary, etc. + + init_windows_version_check(); +} + +static mut IS_NT: bool = true; + +fn init_windows_version_check() { + // according to old MSDN info, the high-order bit is set only on 95/98/ME. + unsafe { IS_NT = c::GetVersion() < 0x8000_0000 }; +} From 5ef6faec868ef783ef383dc0219b22994f6b0ab4 Mon Sep 17 00:00:00 2001 From: Dennis Duda Date: Wed, 20 Nov 2024 00:06:00 +0100 Subject: [PATCH 13/58] Implement thread parking, RwLock, Once fallbacks - Bring back "Generic" thread parker - Add checks for Win8 and WinXP APIs to decide which thread parker impl to use - Use `queue::RwLock` for rust9x. Now that the thread parker is available, we get this high-quality `RwLock` implementation on all API levels, without any extra fallback impls! - Same for `Once` --- library/std/src/sys/pal/windows/c.rs | 31 +++- library/std/src/sys/pal/windows/compat.rs | 3 + .../sys/pal/windows/compat/thread_parking.rs | 40 ++++++ library/std/src/sys/sync/once/mod.rs | 2 +- library/std/src/sys/sync/rwlock/mod.rs | 4 +- .../src/sys/sync/thread_parking/generic.rs | 125 ++++++++++++++++ .../std/src/sys/sync/thread_parking/mod.rs | 9 +- .../std/src/sys/sync/thread_parking/rust9x.rs | 83 +++++++++++ .../src/sys/sync/thread_parking/windowsxp.rs | 133 ++++++++++++++++++ 9 files changed, 421 insertions(+), 9 deletions(-) create mode 100644 library/std/src/sys/pal/windows/compat/thread_parking.rs create mode 100644 library/std/src/sys/sync/thread_parking/generic.rs create mode 100644 library/std/src/sys/sync/thread_parking/rust9x.rs create mode 100644 library/std/src/sys/sync/thread_parking/windowsxp.rs diff --git a/library/std/src/sys/pal/windows/c.rs b/library/std/src/sys/pal/windows/c.rs index 29ef317a53e09..f87f001b61654 100644 --- a/library/std/src/sys/pal/windows/c.rs +++ b/library/std/src/sys/pal/windows/c.rs @@ -5,6 +5,7 @@ #![unstable(issue = "none", feature = "windows_c")] #![allow(clippy::style)] +#[allow(unused_imports)] use core::ffi::{c_uint, c_ulong, c_ushort, c_void}; use core::ptr; @@ -157,7 +158,7 @@ compat_fn_with_fallback! { } } -#[cfg(not(target_vendor = "win7"))] +#[cfg(not(any(target_vendor = "win7", target_family = "rust9x")))] // Use raw-dylib to import synchronization functions to workaround issues with the older mingw import library. #[cfg_attr( target_arch = "x86", @@ -194,11 +195,31 @@ compat_fn_optional! { pub fn WakeByAddressSingle(address: *const c_void); } -#[cfg(any(target_vendor = "win7"))] +#[cfg(target_family = "rust9x")] +compat_fn_with_fallback! { + pub static SYNCH: &CStr = c"api-ms-win-core-synch-l1-2-0" => { load: true, unicows: false }; + + pub fn WaitOnAddress( + address: *const c_void, + compareaddress: *const c_void, + addresssize: usize, + dwmilliseconds: u32 + ) -> BOOL { + rtabort!("unimplemented") + } + pub fn WakeByAddressSingle(address: *const c_void) { + rtabort!("unimplemented") + } + pub fn WakeByAddressAll(address: *const c_void) { + rtabort!("unimplemented") + } +} + +#[cfg(any(target_vendor = "win7", target_family = "rust9x"))] compat_fn_with_fallback! { pub static NTDLL: &CStr = c"ntdll" => { load: false, unicows: false }; - #[cfg(target_vendor = "win7")] + #[cfg(any(target_vendor = "win7", target_family = "rust9x"))] pub fn NtCreateKeyedEvent( KeyedEventHandle: *mut HANDLE, DesiredAccess: u32, @@ -207,7 +228,7 @@ compat_fn_with_fallback! { ) -> NTSTATUS { panic!("keyed events not available") } - #[cfg(target_vendor = "win7")] + #[cfg(any(target_vendor = "win7", target_family = "rust9x"))] pub fn NtReleaseKeyedEvent( EventHandle: HANDLE, Key: *const c_void, @@ -216,7 +237,7 @@ compat_fn_with_fallback! { ) -> NTSTATUS { panic!("keyed events not available") } - #[cfg(target_vendor = "win7")] + #[cfg(any(target_vendor = "win7", target_family = "rust9x"))] pub fn NtWaitForKeyedEvent( EventHandle: HANDLE, Key: *const c_void, diff --git a/library/std/src/sys/pal/windows/compat.rs b/library/std/src/sys/pal/windows/compat.rs index f3fad40a8e512..c3e31f3997989 100644 --- a/library/std/src/sys/pal/windows/compat.rs +++ b/library/std/src/sys/pal/windows/compat.rs @@ -26,6 +26,9 @@ use crate::sys::c; #[cfg(target_family = "rust9x")] pub(crate) mod checks; +#[cfg(target_family = "rust9x")] +pub(crate) mod thread_parking; + // This uses a static initializer to preload some imported functions. // The CRT (C runtime) executes static initializers before `main` // is called (for binaries) and before `DllMain` is called (for DLLs). diff --git a/library/std/src/sys/pal/windows/compat/thread_parking.rs b/library/std/src/sys/pal/windows/compat/thread_parking.rs new file mode 100644 index 0000000000000..1533f16257a9f --- /dev/null +++ b/library/std/src/sys/pal/windows/compat/thread_parking.rs @@ -0,0 +1,40 @@ +static mut THREAD_PARKING_IMPL: Option = None; + +#[derive(Clone, Copy, PartialEq, Eq)] +pub(crate) enum ThreadParkingImpl { + // WaitOnAddress-based, Windows 8+ + Futex, + // NtCreatedKeyedEvent-based, Windows XP+ + KeyedEvent, + // Generic thread parker based on Mutex+Condvar + Generic, +} + +// This CANNOT be called during global init because it has to `LoadLibrary` to figure out which impl +// is available. +pub(crate) fn thread_parking_impl() -> ThreadParkingImpl { + if let Some(implementation) = unsafe { THREAD_PARKING_IMPL } { + return implementation; + } + + let implementation = { + if crate::sys::c::WaitOnAddress::available().is_some() + && crate::sys::c::WakeByAddressSingle::available().is_some() + { + ThreadParkingImpl::Futex + } else if crate::sys::c::NtCreateKeyedEvent::available().is_some() + && crate::sys::c::NtReleaseKeyedEvent::available().is_some() + && crate::sys::c::NtWaitForKeyedEvent::available().is_some() + { + ThreadParkingImpl::KeyedEvent + } else { + ThreadParkingImpl::Generic + } + }; + + unsafe { + THREAD_PARKING_IMPL = Some(implementation); + } + + implementation +} diff --git a/library/std/src/sys/sync/once/mod.rs b/library/std/src/sys/sync/once/mod.rs index aeea884b9f617..09c57f2418616 100644 --- a/library/std/src/sys/sync/once/mod.rs +++ b/library/std/src/sys/sync/once/mod.rs @@ -9,7 +9,7 @@ cfg_select! { any( - all(target_os = "windows", not(target_vendor="win7")), + all(target_os = "windows", not(any(target_vendor = "win7", target_family = "rust9x"))), target_os = "linux", target_os = "android", all(target_arch = "wasm32", target_feature = "atomics"), diff --git a/library/std/src/sys/sync/rwlock/mod.rs b/library/std/src/sys/sync/rwlock/mod.rs index 8603fca2da5b5..4d313116b333f 100644 --- a/library/std/src/sys/sync/rwlock/mod.rs +++ b/library/std/src/sys/sync/rwlock/mod.rs @@ -1,6 +1,6 @@ cfg_select! { any( - all(target_os = "windows", not(target_vendor = "win7")), + all(target_os = "windows", not(any(target_vendor = "win7", target_family = "rust9x"))), target_os = "linux", target_os = "android", target_os = "freebsd", @@ -16,7 +16,7 @@ cfg_select! { } any( target_family = "unix", - all(target_os = "windows", target_vendor = "win7"), + all(target_os = "windows", any(target_vendor = "win7", target_family = "rust9x")), all(target_vendor = "fortanix", target_env = "sgx"), target_os = "xous", target_os = "teeos", diff --git a/library/std/src/sys/sync/thread_parking/generic.rs b/library/std/src/sys/sync/thread_parking/generic.rs new file mode 100644 index 0000000000000..3209bffe353ed --- /dev/null +++ b/library/std/src/sys/sync/thread_parking/generic.rs @@ -0,0 +1,125 @@ +//! Parker implementation based on a Mutex and Condvar. + +use crate::pin::Pin; +use crate::sync::atomic::AtomicUsize; +use crate::sync::atomic::Ordering::SeqCst; +use crate::sync::{Condvar, Mutex}; +use crate::time::Duration; + +const EMPTY: usize = 0; +const PARKED: usize = 1; +const NOTIFIED: usize = 2; + +pub struct Parker { + state: AtomicUsize, + lock: Mutex<()>, + cvar: Condvar, +} + +impl Parker { + /// Construct the generic parker. The UNIX parker implementation + /// requires this to happen in-place. + pub unsafe fn new_in_place(parker: *mut Parker) { + parker.write(Parker { + state: AtomicUsize::new(EMPTY), + lock: Mutex::new(()), + cvar: Condvar::new(), + }); + } + + // This implementation doesn't require `unsafe` and `Pin`, but other implementations do. + pub unsafe fn park(self: Pin<&Self>) { + // If we were previously notified then we consume this notification and + // return quickly. + if self.state.compare_exchange(NOTIFIED, EMPTY, SeqCst, SeqCst).is_ok() { + return; + } + + // Otherwise we need to coordinate going to sleep + let mut m = self.lock.lock().unwrap(); + match self.state.compare_exchange(EMPTY, PARKED, SeqCst, SeqCst) { + Ok(_) => {} + Err(NOTIFIED) => { + // We must read here, even though we know it will be `NOTIFIED`. + // This is because `unpark` may have been called again since we read + // `NOTIFIED` in the `compare_exchange` above. We must perform an + // acquire operation that synchronizes with that `unpark` to observe + // any writes it made before the call to unpark. To do that we must + // read from the write it made to `state`. + let old = self.state.swap(EMPTY, SeqCst); + assert_eq!(old, NOTIFIED, "park state changed unexpectedly"); + return; + } // should consume this notification, so prohibit spurious wakeups in next park. + Err(_) => panic!("inconsistent park state"), + } + loop { + m = self.cvar.wait(m).unwrap(); + match self.state.compare_exchange(NOTIFIED, EMPTY, SeqCst, SeqCst) { + Ok(_) => return, // got a notification + Err(_) => {} // spurious wakeup, go back to sleep + } + } + } + + // This implementation doesn't require `unsafe` and `Pin`, but other implementations do. + pub unsafe fn park_timeout(self: Pin<&Self>, dur: Duration) { + // Like `park` above we have a fast path for an already-notified thread, and + // afterwards we start coordinating for a sleep. + // return quickly. + if self.state.compare_exchange(NOTIFIED, EMPTY, SeqCst, SeqCst).is_ok() { + return; + } + let m = self.lock.lock().unwrap(); + match self.state.compare_exchange(EMPTY, PARKED, SeqCst, SeqCst) { + Ok(_) => {} + Err(NOTIFIED) => { + // We must read again here, see `park`. + let old = self.state.swap(EMPTY, SeqCst); + assert_eq!(old, NOTIFIED, "park state changed unexpectedly"); + return; + } // should consume this notification, so prohibit spurious wakeups in next park. + Err(_) => panic!("inconsistent park_timeout state"), + } + + // Wait with a timeout, and if we spuriously wake up or otherwise wake up + // from a notification we just want to unconditionally set the state back to + // empty, either consuming a notification or un-flagging ourselves as + // parked. + let (_m, _result) = self.cvar.wait_timeout(m, dur).unwrap(); + match self.state.swap(EMPTY, SeqCst) { + NOTIFIED => {} // got a notification, hurray! + PARKED => {} // no notification, alas + n => panic!("inconsistent park_timeout state: {n}"), + } + } + + // This implementation doesn't require `Pin`, but other implementations do. + pub fn unpark(self: Pin<&Self>) { + // To ensure the unparked thread will observe any writes we made + // before this call, we must perform a release operation that `park` + // can synchronize with. To do that we must write `NOTIFIED` even if + // `state` is already `NOTIFIED`. That is why this must be a swap + // rather than a compare-and-swap that returns if it reads `NOTIFIED` + // on failure. + match self.state.swap(NOTIFIED, SeqCst) { + EMPTY => return, // no one was waiting + NOTIFIED => return, // already unparked + PARKED => {} // gotta go wake someone up + _ => panic!("inconsistent state in unpark"), + } + + // There is a period between when the parked thread sets `state` to + // `PARKED` (or last checked `state` in the case of a spurious wake + // up) and when it actually waits on `cvar`. If we were to notify + // during this period it would be ignored and then when the parked + // thread went to sleep it would never wake up. Fortunately, it has + // `lock` locked at this stage so we can acquire `lock` to wait until + // it is ready to receive the notification. + // + // Releasing `lock` before the call to `notify_one` means that when the + // parked thread wakes it doesn't get woken only to have to wait for us + // to release `lock`. + drop(self.lock.lock().unwrap()); + self.cvar.notify_one() + } +} diff --git a/library/std/src/sys/sync/thread_parking/mod.rs b/library/std/src/sys/sync/thread_parking/mod.rs index 74b5b72b19a75..9ed094a065172 100644 --- a/library/std/src/sys/sync/thread_parking/mod.rs +++ b/library/std/src/sys/sync/thread_parking/mod.rs @@ -1,6 +1,6 @@ cfg_select! { any( - all(target_os = "windows", not(target_vendor = "win7")), + all(target_os = "windows", not(any(target_vendor = "win7", target_family = "rust9x"))), target_os = "linux", target_os = "android", all(target_arch = "wasm32", target_feature = "atomics"), @@ -26,6 +26,13 @@ cfg_select! { mod windows7; pub use windows7::Parker; } + target_family = "rust9x" => { + mod futex; + mod windowsxp; + mod generic; + mod rust9x; + pub use rust9x::Parker; + } all(target_vendor = "apple", not(miri)) => { // Doesn't work in Miri, see . mod darwin; diff --git a/library/std/src/sys/sync/thread_parking/rust9x.rs b/library/std/src/sys/sync/thread_parking/rust9x.rs new file mode 100644 index 0000000000000..464fa2d82870a --- /dev/null +++ b/library/std/src/sys/sync/thread_parking/rust9x.rs @@ -0,0 +1,83 @@ +use crate::mem::ManuallyDrop; +use crate::pin::Pin; +use crate::sys::compat::thread_parking::{ThreadParkingImpl, thread_parking_impl}; +use crate::time::Duration; + +pub union Parker { + futex: ManuallyDrop, + keyed_event: ManuallyDrop, + generic: ManuallyDrop, +} + +impl Parker { + pub unsafe fn new_in_place(parker: *mut Parker) { + let impl_ = thread_parking_impl(); + + match impl_ { + ThreadParkingImpl::Futex => unsafe { + super::futex::Parker::new_in_place(&mut (*(*parker).futex)) + }, + ThreadParkingImpl::KeyedEvent => unsafe { + super::windowsxp::Parker::new_in_place(&mut (*(*parker).keyed_event)) + }, + ThreadParkingImpl::Generic => unsafe { + super::generic::Parker::new_in_place(&mut (*(*parker).generic)) + }, + } + } + + pub unsafe fn park(self: Pin<&Self>) { + let impl_ = thread_parking_impl(); + + match impl_ { + ThreadParkingImpl::Futex => unsafe { self.map_unchecked(|p| &*p.futex).park() }, + ThreadParkingImpl::KeyedEvent => unsafe { + self.map_unchecked(|p| &*p.keyed_event).park() + }, + ThreadParkingImpl::Generic => unsafe { self.map_unchecked(|p| &*p.generic).park() }, + } + } + + pub unsafe fn park_timeout(self: Pin<&Self>, timeout: Duration) { + let impl_ = thread_parking_impl(); + + match impl_ { + ThreadParkingImpl::Futex => unsafe { + self.map_unchecked(|p| &*p.futex).park_timeout(timeout) + }, + ThreadParkingImpl::KeyedEvent => unsafe { + self.map_unchecked(|p| &*p.keyed_event).park_timeout(timeout) + }, + ThreadParkingImpl::Generic => unsafe { + self.map_unchecked(|p| &*p.generic).park_timeout(timeout) + }, + } + } + + pub fn unpark(self: Pin<&Self>) { + let impl_ = thread_parking_impl(); + + match impl_ { + ThreadParkingImpl::Futex => unsafe { + self.map_unchecked(|p| &*p.futex).unpark(); + }, + ThreadParkingImpl::KeyedEvent => unsafe { + self.map_unchecked(|p| &*p.keyed_event).unpark() + }, + ThreadParkingImpl::Generic => unsafe { self.map_unchecked(|p| &*p.generic).unpark() }, + } + } +} + +impl Drop for Parker { + fn drop(&mut self) { + let impl_ = thread_parking_impl(); + + match impl_ { + ThreadParkingImpl::Futex | ThreadParkingImpl::KeyedEvent => { + // these don't require any cleanup + } + ThreadParkingImpl::Generic => unsafe { ManuallyDrop::drop(&mut self.generic) }, + } + } +} diff --git a/library/std/src/sys/sync/thread_parking/windowsxp.rs b/library/std/src/sys/sync/thread_parking/windowsxp.rs new file mode 100644 index 0000000000000..ae0928c410173 --- /dev/null +++ b/library/std/src/sys/sync/thread_parking/windowsxp.rs @@ -0,0 +1,133 @@ +// Just the Windows XP+ implementation yoinked from the Windows 7 implementation, without the +// Win8+/futex implementation around it, see super::windows7 for more info. + +use core::pin::Pin; +use core::ptr; +use core::sync::atomic::Ordering::{Acquire, Relaxed, Release}; +use core::sync::atomic::{AtomicI8, AtomicPtr}; +use core::time::Duration; + +use crate::ffi::c_void; +use crate::sys::c; + +pub struct Parker { + state: AtomicI8, +} + +const PARKED: i8 = -1; +const EMPTY: i8 = 0; +const NOTIFIED: i8 = 1; + +impl Parker { + pub unsafe fn new_in_place(parker: *mut Parker) { + parker.write(Self { state: AtomicI8::new(EMPTY) }); + } + + pub unsafe fn park(self: Pin<&Self>) { + // Change NOTIFIED=>EMPTY or EMPTY=>PARKED, and directly return in the + // first case. + if self.state.fetch_sub(1, Acquire) == NOTIFIED { + return; + } + + // Wait for unpark() to produce this event. + c::NtWaitForKeyedEvent(keyed_event_handle(), self.ptr(), false, ptr::null_mut()); + // Set the state back to EMPTY (from either PARKED or NOTIFIED). + // Note that we don't just write EMPTY, but use swap() to also + // include an acquire-ordered read to synchronize with unpark()'s + // release-ordered write. + self.state.swap(EMPTY, Acquire); + return; + } + + pub unsafe fn park_timeout(self: Pin<&Self>, timeout: Duration) { + // Change NOTIFIED=>EMPTY or EMPTY=>PARKED, and directly return in the + // first case. + if self.state.fetch_sub(1, Acquire) == NOTIFIED { + return; + } + + // Need to wait for unpark() using NtWaitForKeyedEvent. + let handle = keyed_event_handle(); + + // NtWaitForKeyedEvent uses a unit of 100ns, and uses negative + // values to indicate a relative time on the monotonic clock. + // This is documented here for the underlying KeWaitForSingleObject function: + // https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/nf-wdm-kewaitforsingleobject + let mut timeout = match i64::try_from((timeout.as_nanos() + 99) / 100) { + Ok(t) => -t, + Err(_) => i64::MIN, + }; + + // Wait for unpark() to produce this event. + let unparked = + c::NtWaitForKeyedEvent(handle, self.ptr(), false, &mut timeout) == c::STATUS_SUCCESS; + + // Set the state back to EMPTY (from either PARKED or NOTIFIED). + let prev_state = self.state.swap(EMPTY, Acquire); + + if !unparked && prev_state == NOTIFIED { + // We were awoken by a timeout, not by unpark(), but the state + // was set to NOTIFIED, which means we *just* missed an + // unpark(), which is now blocked on us to wait for it. + // Wait for it to consume the event and unblock that thread. + c::NtWaitForKeyedEvent(handle, self.ptr(), false, ptr::null_mut()); + } + } + + pub unsafe fn unpark(self: Pin<&Self>) { + // Change PARKED=>NOTIFIED, EMPTY=>NOTIFIED, or NOTIFIED=>NOTIFIED, and + // wake the thread in the first case. + // + // Note that even NOTIFIED=>NOTIFIED results in a write. This is on + // purpose, to make sure every unpark() has a release-acquire ordering + // with park(). + if self.state.swap(NOTIFIED, Release) == PARKED { + // If we run NtReleaseKeyedEvent before the waiting thread runs + // NtWaitForKeyedEvent, this (shortly) blocks until we can wake it up. + // If the waiting thread wakes up before we run NtReleaseKeyedEvent + // (e.g. due to a timeout), this blocks until we do wake up a thread. + // To prevent this thread from blocking indefinitely in that case, + // park_impl() will, after seeing the state set to NOTIFIED after + // waking up, call NtWaitForKeyedEvent again to unblock us. + c::NtReleaseKeyedEvent(keyed_event_handle(), self.ptr(), false, ptr::null_mut()); + } + } + + fn ptr(&self) -> *const c_void { + (&raw const self.state).cast::() + } +} + +fn keyed_event_handle() -> c::HANDLE { + const INVALID: c::HANDLE = ptr::without_provenance_mut(!0); + static HANDLE: AtomicPtr = AtomicPtr::new(INVALID); + match HANDLE.load(Relaxed) { + INVALID => { + let mut handle = c::INVALID_HANDLE_VALUE; + unsafe { + match c::NtCreateKeyedEvent( + &mut handle, + c::GENERIC_READ | c::GENERIC_WRITE, + ptr::null_mut(), + 0, + ) { + c::STATUS_SUCCESS => {} + r => panic!("Unable to create keyed event handle: error {r}"), + } + } + match HANDLE.compare_exchange(INVALID, handle, Relaxed, Relaxed) { + Ok(_) => handle, + Err(h) => { + // Lost the race to another thread initializing HANDLE before we did. + // Closing our handle and using theirs instead. + unsafe { + c::CloseHandle(handle); + } + h + } + } + } + handle => handle, + } +} From 5dfcb83be6782378a447b6e12a2a35795ca2e024 Mon Sep 17 00:00:00 2001 From: Dennis Duda Date: Sat, 23 Nov 2024 23:37:22 +0100 Subject: [PATCH 14/58] Add downlevel implementations for Mutex and Condvar --- library/std/src/sys/pal/windows/c.rs | 45 +++++- .../std/src/sys/pal/windows/c/bindings.txt | 11 ++ .../std/src/sys/pal/windows/c/windows_sys.rs | 55 ++++++++ .../std/src/sys/pal/windows/compat/checks.rs | 36 +++++ library/std/src/sys/pal/windows/futex.rs | 2 + library/std/src/sys/sync/condvar/mod.rs | 7 +- library/std/src/sys/sync/condvar/rust9x.rs | 75 ++++++++++ .../std/src/sys/sync/condvar/rust9x/legacy.rs | 132 ++++++++++++++++++ library/std/src/sys/sync/condvar/windows7.rs | 4 + library/std/src/sys/sync/mutex/mod.rs | 7 +- library/std/src/sys/sync/mutex/rust9x.rs | 79 +++++++++++ .../sys/sync/mutex/rust9x/critical_section.rs | 103 ++++++++++++++ .../std/src/sys/sync/mutex/rust9x/legacy.rs | 108 ++++++++++++++ library/std/src/sys/sync/mutex/windows7.rs | 4 + 14 files changed, 664 insertions(+), 4 deletions(-) create mode 100644 library/std/src/sys/sync/condvar/rust9x.rs create mode 100644 library/std/src/sys/sync/condvar/rust9x/legacy.rs create mode 100644 library/std/src/sys/sync/mutex/rust9x.rs create mode 100644 library/std/src/sys/sync/mutex/rust9x/critical_section.rs create mode 100644 library/std/src/sys/sync/mutex/rust9x/legacy.rs diff --git a/library/std/src/sys/pal/windows/c.rs b/library/std/src/sys/pal/windows/c.rs index f87f001b61654..ef7e8dc180d9a 100644 --- a/library/std/src/sys/pal/windows/c.rs +++ b/library/std/src/sys/pal/windows/c.rs @@ -20,9 +20,9 @@ pub const INVALID_HANDLE_VALUE: HANDLE = ::core::ptr::without_provenance_mut(-1i pub const EXIT_SUCCESS: u32 = 0; pub const EXIT_FAILURE: u32 = 1; -#[cfg(target_vendor = "win7")] +#[cfg(any(target_vendor = "win7", target_family = "rust9x"))] pub const CONDITION_VARIABLE_INIT: CONDITION_VARIABLE = CONDITION_VARIABLE { Ptr: ptr::null_mut() }; -#[cfg(target_vendor = "win7")] +#[cfg(any(target_vendor = "win7", target_family = "rust9x"))] pub const SRWLOCK_INIT: SRWLOCK = SRWLOCK { Ptr: ptr::null_mut() }; #[cfg(not(target_thread_local))] pub const INIT_ONCE_STATIC_INIT: INIT_ONCE = INIT_ONCE { Ptr: ptr::null_mut() }; @@ -258,3 +258,44 @@ cfg_select! { } _ => {} } + +#[cfg(target_family = "rust9x")] +compat_fn_with_fallback! { + pub static KERNEL32: &CStr = c"kernel32" => { load: false, unicows: false }; + + // >= NT 4 + // https://learn.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-signalobjectandwait + pub fn SignalObjectAndWait( + hobjecttosignal: HANDLE, + hobjecttowaiton: HANDLE, + dwmilliseconds: u32, + balertable: BOOL + ) -> WAIT_EVENT { rtabort!("unimplemented") } + // >= NT 4 + // https://learn.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-tryentercriticalsection + pub fn TryEnterCriticalSection(lpcriticalsection: *mut CRITICAL_SECTION) -> BOOL { + rtabort!("unimplemented") + } + // >= Win7 / Server 2008 R2 + // https://learn.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-tryacquiresrwlockexclusive + pub fn TryAcquireSRWLockExclusive(srwlock: *mut SRWLOCK) -> bool { rtabort!("unimplemented") } + pub fn TryAcquireSRWLockShared(srwlock: *mut SRWLOCK) -> bool { rtabort!("unimplemented") } + // >= Vista / Server 2008 + // https://learn.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-acquiresrwlockexclusive + pub fn AcquireSRWLockExclusive(srwlock: *mut SRWLOCK) -> () { rtabort!("unimplemented") } + pub fn AcquireSRWLockShared(srwlock: *mut SRWLOCK) -> () { rtabort!("unimplemented") } + pub fn ReleaseSRWLockExclusive(srwlock: *mut SRWLOCK) -> () { rtabort!("unimplemented") } + pub fn ReleaseSRWLockShared(srwlock: *mut SRWLOCK) -> () { rtabort!("unimplemented") } + pub fn SleepConditionVariableSRW( + conditionvariable: *mut CONDITION_VARIABLE, + srwlock: *mut SRWLOCK, + dwmilliseconds: u32, + flags: u32, + ) -> BOOL { rtabort!("unimplemented") } + pub fn WakeAllConditionVariable(conditionvariable: *mut CONDITION_VARIABLE) -> () { + rtabort!("unimplemented") + } + pub fn WakeConditionVariable(conditionvariable: *mut CONDITION_VARIABLE) -> () { + rtabort!("unimplemented") + } +} diff --git a/library/std/src/sys/pal/windows/c/bindings.txt b/library/std/src/sys/pal/windows/c/bindings.txt index da6a1ccdf937c..abef8085d95ec 100644 --- a/library/std/src/sys/pal/windows/c/bindings.txt +++ b/library/std/src/sys/pal/windows/c/bindings.txt @@ -53,9 +53,11 @@ CREATE_UNICODE_ENVIRONMENT CREATE_WAITABLE_TIMER_HIGH_RESOLUTION CREATE_WAITABLE_TIMER_MANUAL_RESET CreateDirectoryW +CreateEventA CreateEventW CreateFileW CreateHardLinkW +CreateMutexA CreateNamedPipeW CreatePipe CreateProcessW @@ -68,6 +70,7 @@ CSTR_LESS_THAN DEBUG_ONLY_THIS_PROCESS DEBUG_PROCESS DELETE +DeleteCriticalSection DeleteFileW DeleteProcThreadAttributeList DETACHED_PROCESS @@ -271,6 +274,7 @@ ENABLE_VIRTUAL_TERMINAL_INPUT ENABLE_VIRTUAL_TERMINAL_PROCESSING ENABLE_WINDOW_INPUT ENABLE_WRAP_AT_EOL_OUTPUT +EnterCriticalSection ERROR_ABANDON_HIBERFILE ERROR_ABANDONED_WAIT_0 ERROR_ABANDONED_WAIT_63 @@ -2203,6 +2207,7 @@ INFINITE INHERIT_CALLER_PRIORITY INHERIT_PARENT_AFFINITY INIT_ONCE_INIT_FAILED +InitializeCriticalSection InitializeProcThreadAttributeList InitOnceBeginInitialize InitOnceComplete @@ -2260,6 +2265,7 @@ IPV6_DROP_MEMBERSHIP IPV6_MREQ IPV6_MULTICAST_LOOP IPV6_V6ONLY +LeaveCriticalSection LINGER listen LoadLibraryA @@ -2352,9 +2358,11 @@ ReadFileEx REALTIME_PRIORITY_CLASS recv recvfrom +ReleaseMutex ReleaseSRWLockExclusive ReleaseSRWLockShared RemoveDirectoryW +ResetEvent RtlGenRandom RtlNtStatusToDosError SD_BOTH @@ -2376,6 +2384,7 @@ sendto SET_FILE_POINTER_MOVE_METHOD SetCurrentDirectoryW SetEnvironmentVariableW +SetEvent SetFileAttributesW SetFileInformationByHandle SetFilePointerEx @@ -2386,6 +2395,7 @@ setsockopt SetThreadStackGuarantee SetWaitableTimer shutdown +SignalObjectAndWait Sleep SleepConditionVariableSRW SleepEx @@ -2489,6 +2499,7 @@ TRUE TRUNCATE_EXISTING TryAcquireSRWLockExclusive TryAcquireSRWLockShared +TryEnterCriticalSection UNICODE_STRING UnlockFile UpdateProcThreadAttribute diff --git a/library/std/src/sys/pal/windows/c/windows_sys.rs b/library/std/src/sys/pal/windows/c/windows_sys.rs index 4a8ff4e0bd484..da62eb96b4736 100644 --- a/library/std/src/sys/pal/windows/c/windows_sys.rs +++ b/library/std/src/sys/pal/windows/c/windows_sys.rs @@ -10,19 +10,23 @@ windows_targets::link!("kernel32.dll" "system" fn CloseHandle(hobject : HANDLE) windows_targets::link!("kernel32.dll" "system" fn CompareStringOrdinal(lpstring1 : PCWSTR, cchcount1 : i32, lpstring2 : PCWSTR, cchcount2 : i32, bignorecase : BOOL) -> COMPARESTRING_RESULT); windows_targets::link!("kernel32.dll" "system" fn CopyFileExW(lpexistingfilename : PCWSTR, lpnewfilename : PCWSTR, lpprogressroutine : LPPROGRESS_ROUTINE, lpdata : *const core::ffi::c_void, pbcancel : *mut BOOL, dwcopyflags : COPYFILE_FLAGS) -> BOOL); windows_targets::link!("kernel32.dll" "system" fn CreateDirectoryW(lppathname : PCWSTR, lpsecurityattributes : *const SECURITY_ATTRIBUTES) -> BOOL); +windows_targets::link!("kernel32.dll" "system" fn CreateEventA(lpeventattributes : *const SECURITY_ATTRIBUTES, bmanualreset : BOOL, binitialstate : BOOL, lpname : PCSTR) -> HANDLE); windows_targets::link!("kernel32.dll" "system" fn CreateEventW(lpeventattributes : *const SECURITY_ATTRIBUTES, bmanualreset : BOOL, binitialstate : BOOL, lpname : PCWSTR) -> HANDLE); windows_targets::link!("kernel32.dll" "system" fn CreateFileW(lpfilename : PCWSTR, dwdesiredaccess : u32, dwsharemode : FILE_SHARE_MODE, lpsecurityattributes : *const SECURITY_ATTRIBUTES, dwcreationdisposition : FILE_CREATION_DISPOSITION, dwflagsandattributes : FILE_FLAGS_AND_ATTRIBUTES, htemplatefile : HANDLE) -> HANDLE); windows_targets::link!("kernel32.dll" "system" fn CreateHardLinkW(lpfilename : PCWSTR, lpexistingfilename : PCWSTR, lpsecurityattributes : *const SECURITY_ATTRIBUTES) -> BOOL); +windows_targets::link!("kernel32.dll" "system" fn CreateMutexA(lpmutexattributes : *const SECURITY_ATTRIBUTES, binitialowner : BOOL, lpname : PCSTR) -> HANDLE); windows_targets::link!("kernel32.dll" "system" fn CreateNamedPipeW(lpname : PCWSTR, dwopenmode : FILE_FLAGS_AND_ATTRIBUTES, dwpipemode : NAMED_PIPE_MODE, nmaxinstances : u32, noutbuffersize : u32, ninbuffersize : u32, ndefaulttimeout : u32, lpsecurityattributes : *const SECURITY_ATTRIBUTES) -> HANDLE); windows_targets::link!("kernel32.dll" "system" fn CreatePipe(hreadpipe : *mut HANDLE, hwritepipe : *mut HANDLE, lppipeattributes : *const SECURITY_ATTRIBUTES, nsize : u32) -> BOOL); windows_targets::link!("kernel32.dll" "system" fn CreateProcessW(lpapplicationname : PCWSTR, lpcommandline : PWSTR, lpprocessattributes : *const SECURITY_ATTRIBUTES, lpthreadattributes : *const SECURITY_ATTRIBUTES, binherithandles : BOOL, dwcreationflags : PROCESS_CREATION_FLAGS, lpenvironment : *const core::ffi::c_void, lpcurrentdirectory : PCWSTR, lpstartupinfo : *const STARTUPINFOW, lpprocessinformation : *mut PROCESS_INFORMATION) -> BOOL); windows_targets::link!("kernel32.dll" "system" fn CreateSymbolicLinkW(lpsymlinkfilename : PCWSTR, lptargetfilename : PCWSTR, dwflags : SYMBOLIC_LINK_FLAGS) -> bool); windows_targets::link!("kernel32.dll" "system" fn CreateThread(lpthreadattributes : *const SECURITY_ATTRIBUTES, dwstacksize : usize, lpstartaddress : LPTHREAD_START_ROUTINE, lpparameter : *const core::ffi::c_void, dwcreationflags : THREAD_CREATION_FLAGS, lpthreadid : *mut u32) -> HANDLE); windows_targets::link!("kernel32.dll" "system" fn CreateWaitableTimerExW(lptimerattributes : *const SECURITY_ATTRIBUTES, lptimername : PCWSTR, dwflags : u32, dwdesiredaccess : u32) -> HANDLE); +windows_targets::link!("kernel32.dll" "system" fn DeleteCriticalSection(lpcriticalsection : *mut CRITICAL_SECTION)); windows_targets::link!("kernel32.dll" "system" fn DeleteFileW(lpfilename : PCWSTR) -> BOOL); windows_targets::link!("kernel32.dll" "system" fn DeleteProcThreadAttributeList(lpattributelist : LPPROC_THREAD_ATTRIBUTE_LIST)); windows_targets::link!("kernel32.dll" "system" fn DeviceIoControl(hdevice : HANDLE, dwiocontrolcode : u32, lpinbuffer : *const core::ffi::c_void, ninbuffersize : u32, lpoutbuffer : *mut core::ffi::c_void, noutbuffersize : u32, lpbytesreturned : *mut u32, lpoverlapped : *mut OVERLAPPED) -> BOOL); windows_targets::link!("kernel32.dll" "system" fn DuplicateHandle(hsourceprocesshandle : HANDLE, hsourcehandle : HANDLE, htargetprocesshandle : HANDLE, lptargethandle : *mut HANDLE, dwdesiredaccess : u32, binherithandle : BOOL, dwoptions : DUPLICATE_HANDLE_OPTIONS) -> BOOL); +windows_targets::link!("kernel32.dll" "system" fn EnterCriticalSection(lpcriticalsection : *mut CRITICAL_SECTION)); windows_targets::link!("kernel32.dll" "system" fn ExitProcess(uexitcode : u32) -> !); windows_targets::link!("kernel32.dll" "system" fn FindClose(hfindfile : HANDLE) -> BOOL); windows_targets::link!("kernel32.dll" "system" fn FindFirstFileExW(lpfilename : PCWSTR, finfolevelid : FINDEX_INFO_LEVELS, lpfindfiledata : *mut core::ffi::c_void, fsearchop : FINDEX_SEARCH_OPS, lpsearchfilter : *const core::ffi::c_void, dwadditionalflags : FIND_FIRST_EX_FLAGS) -> HANDLE); @@ -68,7 +72,9 @@ windows_targets::link!("kernel32.dll" "system" fn GetVersion() -> u32); windows_targets::link!("kernel32.dll" "system" fn GetWindowsDirectoryW(lpbuffer : PWSTR, usize : u32) -> u32); windows_targets::link!("kernel32.dll" "system" fn InitOnceBeginInitialize(lpinitonce : *mut INIT_ONCE, dwflags : u32, fpending : *mut BOOL, lpcontext : *mut *mut core::ffi::c_void) -> BOOL); windows_targets::link!("kernel32.dll" "system" fn InitOnceComplete(lpinitonce : *mut INIT_ONCE, dwflags : u32, lpcontext : *const core::ffi::c_void) -> BOOL); +windows_targets::link!("kernel32.dll" "system" fn InitializeCriticalSection(lpcriticalsection : *mut CRITICAL_SECTION)); windows_targets::link!("kernel32.dll" "system" fn InitializeProcThreadAttributeList(lpattributelist : LPPROC_THREAD_ATTRIBUTE_LIST, dwattributecount : u32, dwflags : u32, lpsize : *mut usize) -> BOOL); +windows_targets::link!("kernel32.dll" "system" fn LeaveCriticalSection(lpcriticalsection : *mut CRITICAL_SECTION)); windows_targets::link!("kernel32.dll" "system" fn LoadLibraryA(lplibfilename : PCSTR) -> HMODULE); windows_targets::link!("kernel32.dll" "system" fn LocalFree(hmem : HLOCAL) -> HLOCAL); windows_targets::link!("kernel32.dll" "system" fn LockFileEx(hfile : HANDLE, dwflags : LOCK_FILE_FLAGS, dwreserved : u32, nnumberofbytestolocklow : u32, nnumberofbytestolockhigh : u32, lpoverlapped : *mut OVERLAPPED) -> BOOL); @@ -84,13 +90,16 @@ windows_targets::link!("kernel32.dll" "system" fn QueryPerformanceFrequency(lpfr windows_targets::link!("kernel32.dll" "system" fn ReadConsoleW(hconsoleinput : HANDLE, lpbuffer : *mut core::ffi::c_void, nnumberofcharstoread : u32, lpnumberofcharsread : *mut u32, pinputcontrol : *const CONSOLE_READCONSOLE_CONTROL) -> BOOL); windows_targets::link!("kernel32.dll" "system" fn ReadFile(hfile : HANDLE, lpbuffer : *mut u8, nnumberofbytestoread : u32, lpnumberofbytesread : *mut u32, lpoverlapped : *mut OVERLAPPED) -> BOOL); windows_targets::link!("kernel32.dll" "system" fn ReadFileEx(hfile : HANDLE, lpbuffer : *mut u8, nnumberofbytestoread : u32, lpoverlapped : *mut OVERLAPPED, lpcompletionroutine : LPOVERLAPPED_COMPLETION_ROUTINE) -> BOOL); +windows_targets::link!("kernel32.dll" "system" fn ReleaseMutex(hmutex : HANDLE) -> BOOL); windows_targets::link!("kernel32.dll" "system" fn ReleaseSRWLockExclusive(srwlock : *mut SRWLOCK)); windows_targets::link!("kernel32.dll" "system" fn ReleaseSRWLockShared(srwlock : *mut SRWLOCK)); windows_targets::link!("kernel32.dll" "system" fn RemoveDirectoryW(lppathname : PCWSTR) -> BOOL); +windows_targets::link!("kernel32.dll" "system" fn ResetEvent(hevent : HANDLE) -> BOOL); windows_targets::link!("advapi32.dll" "system" "SystemFunction036" fn RtlGenRandom(randombuffer : *mut core::ffi::c_void, randombufferlength : u32) -> bool); windows_targets::link!("ntdll.dll" "system" fn RtlNtStatusToDosError(status : NTSTATUS) -> u32); windows_targets::link!("kernel32.dll" "system" fn SetCurrentDirectoryW(lppathname : PCWSTR) -> BOOL); windows_targets::link!("kernel32.dll" "system" fn SetEnvironmentVariableW(lpname : PCWSTR, lpvalue : PCWSTR) -> BOOL); +windows_targets::link!("kernel32.dll" "system" fn SetEvent(hevent : HANDLE) -> BOOL); windows_targets::link!("kernel32.dll" "system" fn SetFileAttributesW(lpfilename : PCWSTR, dwfileattributes : FILE_FLAGS_AND_ATTRIBUTES) -> BOOL); windows_targets::link!("kernel32.dll" "system" fn SetFileInformationByHandle(hfile : HANDLE, fileinformationclass : FILE_INFO_BY_HANDLE_CLASS, lpfileinformation : *const core::ffi::c_void, dwbuffersize : u32) -> BOOL); windows_targets::link!("kernel32.dll" "system" fn SetFilePointerEx(hfile : HANDLE, lidistancetomove : i64, lpnewfilepointer : *mut i64, dwmovemethod : SET_FILE_POINTER_MOVE_METHOD) -> BOOL); @@ -99,6 +108,7 @@ windows_targets::link!("kernel32.dll" "system" fn SetHandleInformation(hobject : windows_targets::link!("kernel32.dll" "system" fn SetLastError(dwerrcode : WIN32_ERROR)); windows_targets::link!("kernel32.dll" "system" fn SetThreadStackGuarantee(stacksizeinbytes : *mut u32) -> BOOL); windows_targets::link!("kernel32.dll" "system" fn SetWaitableTimer(htimer : HANDLE, lpduetime : *const i64, lperiod : i32, pfncompletionroutine : PTIMERAPCROUTINE, lpargtocompletionroutine : *const core::ffi::c_void, fresume : BOOL) -> BOOL); +windows_targets::link!("kernel32.dll" "system" fn SignalObjectAndWait(hobjecttosignal : HANDLE, hobjecttowaiton : HANDLE, dwmilliseconds : u32, balertable : BOOL) -> WAIT_EVENT); windows_targets::link!("kernel32.dll" "system" fn Sleep(dwmilliseconds : u32)); windows_targets::link!("kernel32.dll" "system" fn SleepConditionVariableSRW(conditionvariable : *mut CONDITION_VARIABLE, srwlock : *mut SRWLOCK, dwmilliseconds : u32, flags : u32) -> BOOL); windows_targets::link!("kernel32.dll" "system" fn SleepEx(dwmilliseconds : u32, balertable : BOOL) -> u32); @@ -110,6 +120,7 @@ windows_targets::link!("kernel32.dll" "system" fn TlsGetValue(dwtlsindex : u32) windows_targets::link!("kernel32.dll" "system" fn TlsSetValue(dwtlsindex : u32, lptlsvalue : *const core::ffi::c_void) -> BOOL); windows_targets::link!("kernel32.dll" "system" fn TryAcquireSRWLockExclusive(srwlock : *mut SRWLOCK) -> bool); windows_targets::link!("kernel32.dll" "system" fn TryAcquireSRWLockShared(srwlock : *mut SRWLOCK) -> bool); +windows_targets::link!("kernel32.dll" "system" fn TryEnterCriticalSection(lpcriticalsection : *mut CRITICAL_SECTION) -> BOOL); windows_targets::link!("kernel32.dll" "system" fn UnlockFile(hfile : HANDLE, dwfileoffsetlow : u32, dwfileoffsethigh : u32, nnumberofbytestounlocklow : u32, nnumberofbytestounlockhigh : u32) -> BOOL); windows_targets::link!("kernel32.dll" "system" fn UpdateProcThreadAttribute(lpattributelist : LPPROC_THREAD_ATTRIBUTE_LIST, dwflags : u32, attribute : usize, lpvalue : *const core::ffi::c_void, cbsize : usize, lppreviousvalue : *mut core::ffi::c_void, lpreturnsize : *const usize) -> BOOL); windows_targets::link!("ws2_32.dll" "system" fn WSACleanup() -> i32); @@ -465,6 +476,39 @@ pub const CREATE_SUSPENDED: PROCESS_CREATION_FLAGS = 4u32; pub const CREATE_UNICODE_ENVIRONMENT: PROCESS_CREATION_FLAGS = 1024u32; pub const CREATE_WAITABLE_TIMER_HIGH_RESOLUTION: u32 = 2u32; pub const CREATE_WAITABLE_TIMER_MANUAL_RESET: u32 = 1u32; +#[repr(C)] +#[derive(Clone, Copy)] +pub struct CRITICAL_SECTION { + pub DebugInfo: *mut CRITICAL_SECTION_DEBUG, + pub LockCount: i32, + pub RecursionCount: i32, + pub OwningThread: HANDLE, + pub LockSemaphore: HANDLE, + pub SpinCount: usize, +} +impl Default for CRITICAL_SECTION { + fn default() -> Self { + unsafe { core::mem::zeroed() } + } +} +#[repr(C)] +#[derive(Clone, Copy)] +pub struct CRITICAL_SECTION_DEBUG { + pub Type: u16, + pub CreatorBackTraceIndex: u16, + pub CriticalSection: *mut CRITICAL_SECTION, + pub ProcessLocksList: LIST_ENTRY, + pub EntryCount: u32, + pub ContentionCount: u32, + pub Flags: u32, + pub CreatorBackTraceIndexHigh: u16, + pub Identifier: u16, +} +impl Default for CRITICAL_SECTION_DEBUG { + fn default() -> Self { + unsafe { core::mem::zeroed() } + } +} pub const CSTR_EQUAL: COMPARESTRING_RESULT = 2i32; pub const CSTR_GREATER_THAN: COMPARESTRING_RESULT = 3i32; pub const CSTR_LESS_THAN: COMPARESTRING_RESULT = 1i32; @@ -2913,6 +2957,17 @@ pub struct LINGER { pub l_onoff: u16, pub l_linger: u16, } +#[repr(C)] +#[derive(Clone, Copy)] +pub struct LIST_ENTRY { + pub Flink: *mut LIST_ENTRY, + pub Blink: *mut LIST_ENTRY, +} +impl Default for LIST_ENTRY { + fn default() -> Self { + unsafe { core::mem::zeroed() } + } +} pub const LOCKFILE_EXCLUSIVE_LOCK: LOCK_FILE_FLAGS = 2u32; pub const LOCKFILE_FAIL_IMMEDIATELY: LOCK_FILE_FLAGS = 1u32; pub type LOCK_FILE_FLAGS = u32; diff --git a/library/std/src/sys/pal/windows/compat/checks.rs b/library/std/src/sys/pal/windows/compat/checks.rs index 871033e07e341..30fb4e048fe03 100644 --- a/library/std/src/sys/pal/windows/compat/checks.rs +++ b/library/std/src/sys/pal/windows/compat/checks.rs @@ -23,6 +23,7 @@ pub fn init_rust9x_checks() { // do any dynamic allocation, don't call LoadLibrary, etc. init_windows_version_check(); + init_mutex_kind_check(); } static mut IS_NT: bool = true; @@ -31,3 +32,38 @@ fn init_windows_version_check() { // according to old MSDN info, the high-order bit is set only on 95/98/ME. unsafe { IS_NT = c::GetVersion() < 0x8000_0000 }; } + +#[derive(Clone, Copy, PartialEq)] +pub(crate) enum MutexKind { + /// Win 7+ (Vista doesn't support the `Try*` APIs) + SrwLock, + /// NT 4+ (9x/ME/NT3.x support critical sections, but don't support `TryEnterCriticalSection`) + CriticalSection, + /// `CreateMutex`, available everywhere + Legacy, +} + +static mut MUTEX_KIND: MutexKind = MutexKind::Legacy; + +#[inline(always)] +pub(crate) fn mutex_kind() -> MutexKind { + unsafe { MUTEX_KIND } +} + +fn init_mutex_kind_check() { + let kind = if c::TryAcquireSRWLockExclusive::available().is_some() { + MutexKind::SrwLock + } else if { + // Windows 9x exports `TryEnterCriticalSection`, but it returns ERROR_CALL_NOT_IMPLEMENTED. + // MSDN specifies that the function is available on NT4 and later. + is_windows_nt() && c::TryEnterCriticalSection::available().is_some() + } { + MutexKind::CriticalSection + } else { + MutexKind::Legacy + }; + + unsafe { + MUTEX_KIND = kind; + } +} diff --git a/library/std/src/sys/pal/windows/futex.rs b/library/std/src/sys/pal/windows/futex.rs index cfa0a6b3815bd..6ec6b69c8ed6d 100644 --- a/library/std/src/sys/pal/windows/futex.rs +++ b/library/std/src/sys/pal/windows/futex.rs @@ -1,3 +1,5 @@ +#![allow(dead_code)] + use core::ffi::c_void; use core::ptr; use core::sync::atomic::{ diff --git a/library/std/src/sys/sync/condvar/mod.rs b/library/std/src/sys/sync/condvar/mod.rs index 83cf0ae629851..a4de85014a10c 100644 --- a/library/std/src/sys/sync/condvar/mod.rs +++ b/library/std/src/sys/sync/condvar/mod.rs @@ -1,6 +1,6 @@ cfg_select! { any( - all(target_os = "windows", not(target_vendor="win7")), + all(target_os = "windows", not(any(target_vendor = "win7", target_family = "rust9x"))), target_os = "linux", target_os = "android", target_os = "freebsd", @@ -25,6 +25,11 @@ cfg_select! { mod windows7; pub use windows7::Condvar; } + all(target_os = "windows", target_family = "rust9x") => { + mod windows7; + mod rust9x; + pub use rust9x::Condvar; + } all(target_vendor = "fortanix", target_env = "sgx") => { mod sgx; pub use sgx::Condvar; diff --git a/library/std/src/sys/sync/condvar/rust9x.rs b/library/std/src/sys/sync/condvar/rust9x.rs new file mode 100644 index 0000000000000..887c9ac27cd9a --- /dev/null +++ b/library/std/src/sys/sync/condvar/rust9x.rs @@ -0,0 +1,75 @@ +use super::windows7; +use crate::mem::{ManuallyDrop, MaybeUninit}; +use crate::sys::compat::checks::{MutexKind, mutex_kind}; +use crate::sys::sync::Mutex; +use crate::time::Duration; + +mod legacy; + +pub union Condvar { + windows7: ManuallyDrop, + legacy: ManuallyDrop, +} + +impl Drop for Condvar { + #[inline] + fn drop(&mut self) { + unsafe { + match mutex_kind() { + MutexKind::SrwLock => ManuallyDrop::drop(&mut self.windows7), + MutexKind::CriticalSection | MutexKind::Legacy => { + ManuallyDrop::drop(&mut self.legacy) + } + } + } + } +} + +unsafe impl Send for Condvar {} +unsafe impl Sync for Condvar {} + +impl Condvar { + #[inline] + pub const fn new() -> Condvar { + // SAFETY: all variants are valid when zero-initialized: + // - Windows 7 CONDITION_VARIABLE: The initialized value `CONDITION_VARIABLE_INIT` is a zero + // pointer value. + // - Legacy: The `OnceBox` is valid when zero-initialized. + unsafe { MaybeUninit::zeroed().assume_init() } + } + + #[inline] + pub unsafe fn wait(&self, mutex: &Mutex) { + match mutex_kind() { + MutexKind::SrwLock => self.windows7.wait(mutex), + MutexKind::CriticalSection | MutexKind::Legacy => self.legacy.wait(mutex), + } + } + + pub unsafe fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool { + match mutex_kind() { + MutexKind::SrwLock => self.windows7.wait_timeout(mutex, dur), + MutexKind::CriticalSection | MutexKind::Legacy => self.legacy.wait_timeout(mutex, dur), + } + } + + #[inline] + pub fn notify_one(&self) { + unsafe { + match mutex_kind() { + MutexKind::SrwLock => self.windows7.notify_one(), + MutexKind::CriticalSection | MutexKind::Legacy => self.legacy.notify_one(), + } + } + } + + #[inline] + pub fn notify_all(&self) { + unsafe { + match mutex_kind() { + MutexKind::SrwLock => self.windows7.notify_all(), + MutexKind::CriticalSection | MutexKind::Legacy => self.legacy.notify_all(), + } + } + } +} diff --git a/library/std/src/sys/sync/condvar/rust9x/legacy.rs b/library/std/src/sys/sync/condvar/rust9x/legacy.rs new file mode 100644 index 0000000000000..544e320a7420f --- /dev/null +++ b/library/std/src/sys/sync/condvar/rust9x/legacy.rs @@ -0,0 +1,132 @@ +use crate::os::windows::io::{AsRawHandle, FromRawHandle, OwnedHandle}; +use crate::pin::Pin; +use crate::sys::c; +use crate::sys::compat::checks::{MutexKind, is_windows_nt, mutex_kind}; +use crate::sys::pal::{cvt, dur2timeout}; +use crate::sys::sync::{Mutex, OnceBox}; +use crate::time::Duration; +use crate::{io, ptr}; + +/// Very basic condvar implementation for pre-Win7. +pub struct Condvar { + inner: OnceBox, +} + +unsafe impl Send for Condvar {} +unsafe impl Sync for Condvar {} + +impl Condvar { + #[inline] + #[cfg_attr( + target_family = "rust9x", + allow(dead_code, reason = "initialized via rust9x::Mutex::new") + )] + pub const fn new() -> Condvar { + Condvar { inner: OnceBox::new() } + } + + fn init() -> Pin> { + unsafe { + let event = c::CreateEventA( + ptr::null_mut(), + c::TRUE, // manual reset event + c::FALSE, + ptr::null(), + ); + + if event.is_null() { + panic!("failed creating event: {}", io::Error::last_os_error()); + } + + Box::pin(OwnedHandle::from_raw_handle(event)) + } + } + + #[inline] + pub unsafe fn wait(&self, mutex: &Mutex) { + let event = self.inner.get_or_init(Self::init); + // SignalObjectAndWait is exported on 98SE/Me, but not implemented + let use_signal_object_and_wait = if mutex_kind() == MutexKind::Legacy && is_windows_nt() { + c::SignalObjectAndWait::available() + } else { + None + }; + + unsafe { + if let Some(signal_object_and_wait) = use_signal_object_and_wait { + if signal_object_and_wait( + mutex.legacy.inner.get_unchecked().as_raw_handle(), + event.as_raw_handle(), + c::INFINITE, + c::FALSE, + ) != c::WAIT_OBJECT_0 + { + panic!("event wait failed: {}", io::Error::last_os_error()) + } + mutex.lock(); + } else { + mutex.unlock(); + if (c::WaitForSingleObject(event.as_raw_handle(), c::INFINITE)) != c::WAIT_OBJECT_0 + { + panic!("event wait failed: {}", io::Error::last_os_error()) + } + mutex.lock(); + } + } + } + + pub unsafe fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool { + let event = self.inner.get_or_init(Self::init); + // SignalObjectAndWait is exported on 98SE/Me, but not implemented + let use_signal_object_and_wait = if mutex_kind() == MutexKind::Legacy && is_windows_nt() { + c::SignalObjectAndWait::available() + } else { + None + }; + + unsafe { + if let Some(signal_object_and_wait) = use_signal_object_and_wait { + let ret = match signal_object_and_wait( + mutex.legacy.inner.get_unchecked().as_raw_handle(), + event.as_raw_handle(), + dur2timeout(dur), + c::FALSE, + ) { + c::WAIT_OBJECT_0 => true, + c::WAIT_TIMEOUT => false, + _ => panic!("event wait failed: {}", io::Error::last_os_error()), + }; + mutex.lock(); + + ret + } else { + mutex.unlock(); + let ret = match c::WaitForSingleObject(event.as_raw_handle(), dur2timeout(dur)) { + c::WAIT_OBJECT_0 => true, + c::WAIT_TIMEOUT => false, + _ => panic!("event wait failed: {}", io::Error::last_os_error()), + }; + mutex.lock(); + + ret + } + } + } + + #[inline] + pub fn notify_one(&self) { + // lots of spurious wakeups, but that's valid + self.notify_all(); + } + + #[inline] + pub fn notify_all(&self) { + let event = self.inner.get_or_init(Self::init); + + unsafe { + cvt(c::SetEvent(event.as_raw_handle())).unwrap(); + crate::thread::yield_now(); + cvt(c::ResetEvent(event.as_raw_handle())).unwrap(); + } + } +} diff --git a/library/std/src/sys/sync/condvar/windows7.rs b/library/std/src/sys/sync/condvar/windows7.rs index f03feef222124..5aaf221c36883 100644 --- a/library/std/src/sys/sync/condvar/windows7.rs +++ b/library/std/src/sys/sync/condvar/windows7.rs @@ -12,6 +12,10 @@ unsafe impl Sync for Condvar {} impl Condvar { #[inline] + #[cfg_attr( + target_family = "rust9x", + allow(dead_code, reason = "initialized via rust9x::Mutex::new") + )] pub const fn new() -> Condvar { Condvar { inner: UnsafeCell::new(c::CONDITION_VARIABLE_INIT) } } diff --git a/library/std/src/sys/sync/mutex/mod.rs b/library/std/src/sys/sync/mutex/mod.rs index e3d6ad1129c83..fe6e9fdbf915b 100644 --- a/library/std/src/sys/sync/mutex/mod.rs +++ b/library/std/src/sys/sync/mutex/mod.rs @@ -1,6 +1,6 @@ cfg_select! { any( - all(target_os = "windows", not(target_vendor = "win7")), + all(target_os = "windows", not(any(target_vendor = "win7", target_family = "rust9x"))), target_os = "linux", target_os = "android", target_os = "freebsd", @@ -28,6 +28,11 @@ cfg_select! { mod windows7; pub use windows7::{Mutex, raw}; } + all(target_os = "windows", target_family = "rust9x") => { + mod windows7; + mod rust9x; + pub use rust9x::{Mutex, raw}; + } all(target_vendor = "fortanix", target_env = "sgx") => { mod sgx; pub use sgx::Mutex; diff --git a/library/std/src/sys/sync/mutex/rust9x.rs b/library/std/src/sys/sync/mutex/rust9x.rs new file mode 100644 index 0000000000000..0c336d4605076 --- /dev/null +++ b/library/std/src/sys/sync/mutex/rust9x.rs @@ -0,0 +1,79 @@ +use super::windows7; +use crate::mem::{ManuallyDrop, MaybeUninit}; +use crate::sys::c; +use crate::sys::compat::checks::{MutexKind, mutex_kind}; + +mod critical_section; +mod legacy; + +/// Only to be used with MutexKind::SrwLock. +#[inline] +pub unsafe fn raw(m: &Mutex) -> *mut c::SRWLOCK { + unsafe { windows7::raw(&m.srwlock) } +} + +pub union Mutex { + pub(crate) srwlock: ManuallyDrop, + critical_section: ManuallyDrop, + pub(crate) legacy: ManuallyDrop, +} + +unsafe impl Send for Mutex {} +unsafe impl Sync for Mutex {} + +impl Drop for Mutex { + #[inline] + fn drop(&mut self) { + unsafe { + match mutex_kind() { + MutexKind::SrwLock => ManuallyDrop::drop(&mut self.srwlock), + MutexKind::CriticalSection => ManuallyDrop::drop(&mut self.critical_section), + MutexKind::Legacy => ManuallyDrop::drop(&mut self.legacy), + } + } + } +} + +impl Mutex { + #[inline] + pub const fn new() -> Mutex { + // SAFETY: all variants are valid when zero-initialized: + // - Windows 7 SRWLOCK: The initialized value `SRWLOCK_INIT` is a zero pointer value. + // - Critical section: The `OnceBox` is valid when zero-initialized. `held` is a `bool` that + // should be initialized to `false`. + // - Legacy: The `OnceBox` is valid when zero-initialized. `held` is a `bool` that should be + // initialized to `false`. + unsafe { MaybeUninit::zeroed().assume_init() } + } + + #[inline] + pub fn lock(&self) { + unsafe { + match mutex_kind() { + MutexKind::SrwLock => self.srwlock.lock(), + MutexKind::CriticalSection => self.critical_section.lock(), + MutexKind::Legacy => self.legacy.lock(), + } + } + } + + #[inline] + pub fn try_lock(&self) -> bool { + unsafe { + match mutex_kind() { + MutexKind::SrwLock => self.srwlock.try_lock(), + MutexKind::CriticalSection => self.critical_section.try_lock(), + MutexKind::Legacy => self.legacy.try_lock(), + } + } + } + + #[inline] + pub unsafe fn unlock(&self) { + match mutex_kind() { + MutexKind::SrwLock => self.srwlock.unlock(), + MutexKind::CriticalSection => self.critical_section.unlock(), + MutexKind::Legacy => self.legacy.unlock(), + } + } +} diff --git a/library/std/src/sys/sync/mutex/rust9x/critical_section.rs b/library/std/src/sys/sync/mutex/rust9x/critical_section.rs new file mode 100644 index 0000000000000..b630b89459402 --- /dev/null +++ b/library/std/src/sys/sync/mutex/rust9x/critical_section.rs @@ -0,0 +1,103 @@ +use crate::cell::UnsafeCell; +use crate::mem::MaybeUninit; +use crate::pin::Pin; +use crate::sys::c; +use crate::sys::sync::OnceBox; + +/// Mutex based on critical sections. +/// +/// Critical sections are available on all windows versions, but `TryEnterCriticalSection` was only +/// added with NT4, and never to the 9x range. +/// +/// Critical sections cannot be moved while initialized, so they have to be boxed. For this reason +/// we use `OnceBox`, which also allows for a `const` constructor. +pub struct CriticalSectionMutex { + inner: OnceBox>, + // used to prevent reentrancy: + // + // > The exact behavior on locking a mutex in the thread which already holds the lock is left + // > unspecified. However, this function will not return on the second call (it might panic or + // > deadlock, for example). + held: UnsafeCell, +} + +unsafe impl Send for CriticalSectionMutex {} +unsafe impl Sync for CriticalSectionMutex {} + +impl CriticalSectionMutex { + #[inline] + #[allow(dead_code, reason = "initialized via rust9x::Mutex::new")] + pub const fn new() -> Self { + Self { inner: OnceBox::new(), held: UnsafeCell::new(false) } + } + + fn init() -> Pin>> { + unsafe { + let boxed = Box::pin(UnsafeCell::new(MaybeUninit::zeroed().assume_init())); + c::InitializeCriticalSection(UnsafeCell::get(&boxed)); + boxed + } + } + + #[inline] + pub unsafe fn lock(&self) { + let cell = self.inner.get_or_init(Self::init); + c::EnterCriticalSection(UnsafeCell::get(&cell)); + + if !self.flag_locked() { + self.unlock(); + panic!("cannot recursively lock a mutex"); + } + } + + #[inline] + pub unsafe fn try_lock(&self) -> bool { + let cell = self.inner.get_or_init(Self::init); + let successful = c::TryEnterCriticalSection(UnsafeCell::get(&cell)) != 0; + + if !successful { + false + } else if self.flag_locked() { + true + } else { + self.unlock(); + false + } + } + + #[inline] + pub unsafe fn unlock(&self) { + *self.held.get() = false; + + // SAFETY: The outer mutex code prevents calls to unlock before lock, so the mutex is + // guaranteed to be initialized. + let cell = self.inner.get_unchecked(); + c::LeaveCriticalSection(UnsafeCell::get(&cell)); + } + + unsafe fn flag_locked(&self) -> bool { + if *self.held.get() { + false + } else { + *self.held.get() = true; + true + } + } +} + +impl Drop for CriticalSectionMutex { + #[inline] + fn drop(&mut self) { + unsafe { + if self.try_lock() { + self.unlock(); + let cell = self.inner.get_unchecked(); + c::DeleteCriticalSection(UnsafeCell::get(&cell)); + } else { + // The mutex is locked. This happens if a MutexGuard is leaked. + // In this case, we have to leak the Mutex too. + core::mem::forget(self.inner.take()); + } + } + } +} diff --git a/library/std/src/sys/sync/mutex/rust9x/legacy.rs b/library/std/src/sys/sync/mutex/rust9x/legacy.rs new file mode 100644 index 0000000000000..137de0179b4ef --- /dev/null +++ b/library/std/src/sys/sync/mutex/rust9x/legacy.rs @@ -0,0 +1,108 @@ +use crate::cell::UnsafeCell; +use crate::os::windows::io::{AsRawHandle, FromRawHandle, OwnedHandle}; +use crate::pin::Pin; +use crate::sys::sync::OnceBox; +use crate::sys::{c, cvt}; +use crate::{io, ptr}; + +/// Mutex based on `CreateMutex`. Slow, but available everywhere. +/// +/// Doesn't need to stay fixed in place, but we need to lazily initialize it to have a const +/// constructor, so we use a `OnceBox` for that. +pub struct LegacyMutex { + pub(crate) inner: OnceBox, + // used to prevent reentrancy: + // + // > The exact behavior on locking a mutex in the thread which already holds the lock is left + // > unspecified. However, this function will not return on the second call (it might panic or + // > deadlock, for example). + held: UnsafeCell, +} + +unsafe impl Send for LegacyMutex {} +unsafe impl Sync for LegacyMutex {} + +impl LegacyMutex { + #[inline] + #[allow(dead_code, reason = "initialized via rust9x::Mutex::new")] + pub const fn new() -> Self { + Self { inner: OnceBox::new(), held: UnsafeCell::new(false) } + } + + fn init() -> Pin> { + unsafe { + let handle = c::CreateMutexA(ptr::null_mut(), c::FALSE, ptr::null()); + if handle.is_null() { + panic!("failed creating mutex: {}", io::Error::last_os_error()); + } + + Box::pin(OwnedHandle::from_raw_handle(handle)) + } + } + + #[inline] + pub unsafe fn lock(&self) { + let handle = self.inner.get_or_init(Self::init); + if c::WaitForSingleObject(handle.as_raw_handle(), c::INFINITE) != c::WAIT_OBJECT_0 { + panic!("mutex lock failed: {}", io::Error::last_os_error()) + } + + if !self.flag_locked() { + self.unlock(); + panic!("cannot recursively lock a mutex"); + } + } + + #[inline] + pub unsafe fn try_lock(&self) -> bool { + let handle = self.inner.get_or_init(Self::init); + let successful = match c::WaitForSingleObject(handle.as_raw_handle(), 0) { + c::WAIT_OBJECT_0 => true, + c::WAIT_TIMEOUT => false, + _ => panic!("try lock error: {}", io::Error::last_os_error()), + }; + + if !successful { + false + } else if self.flag_locked() { + true + } else { + self.unlock(); + false + } + } + + #[inline] + pub unsafe fn unlock(&self) { + *self.held.get() = false; + + // SAFETY: The outer mutex code prevents calls to unlock before lock, so the mutex is + // guaranteed to be initialized. + let handle = self.inner.get_unchecked(); + cvt(c::ReleaseMutex(handle.as_raw_handle())).unwrap(); + } + + unsafe fn flag_locked(&self) -> bool { + if *self.held.get() { + false + } else { + *self.held.get() = true; + true + } + } +} + +impl Drop for LegacyMutex { + #[inline] + fn drop(&mut self) { + unsafe { + if self.try_lock() { + self.unlock(); + } else { + // The mutex is locked. This happens if a MutexGuard is leaked. + // In this case, we have to leak the Mutex too. + core::mem::forget(self.inner.take()); + } + } + } +} diff --git a/library/std/src/sys/sync/mutex/windows7.rs b/library/std/src/sys/sync/mutex/windows7.rs index 0b57de78ba6dd..d9768c5ed85fe 100644 --- a/library/std/src/sys/sync/mutex/windows7.rs +++ b/library/std/src/sys/sync/mutex/windows7.rs @@ -31,6 +31,10 @@ pub unsafe fn raw(m: &Mutex) -> *mut c::SRWLOCK { impl Mutex { #[inline] + #[cfg_attr( + target_family = "rust9x", + allow(dead_code, reason = "initialized via rust9x::Mutex::new") + )] pub const fn new() -> Mutex { Mutex { srwlock: UnsafeCell::new(c::SRWLOCK_INIT) } } From 8f78f94f2b902b1dbe5ee26c0e3c12c8c9a43ebf Mon Sep 17 00:00:00 2001 From: Dennis Duda Date: Sun, 24 Nov 2024 17:18:00 +0100 Subject: [PATCH 15/58] Allow `reserve_stack` and stack overflow exception registration to fail on unsupported systems --- library/std/src/sys/pal/windows/c.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/library/std/src/sys/pal/windows/c.rs b/library/std/src/sys/pal/windows/c.rs index ef7e8dc180d9a..2686ea16ad6b1 100644 --- a/library/std/src/sys/pal/windows/c.rs +++ b/library/std/src/sys/pal/windows/c.rs @@ -299,3 +299,17 @@ compat_fn_with_fallback! { rtabort!("unimplemented") } } + +#[cfg(target_family = "rust9x")] +compat_fn_with_fallback! { + pub static KERNEL32: &CStr = c"kernel32" => { load: false, unicows: false }; + // >= XP + // https://learn.microsoft.com/en-us/windows/win32/api/errhandlingapi/nf-errhandlingapi-addvectoredexceptionhandler + pub fn AddVectoredExceptionHandler( + first: u32, + handler: PVECTORED_EXCEPTION_HANDLER + ) -> *mut core::ffi::c_void { core::ptr::null_mut() } + // >= Vista / Server 2003 SP1 / XPx64 + // https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-setthreadstackguarantee + pub fn SetThreadStackGuarantee(stacksizeinbytes: *mut u32) -> BOOL { TRUE } +} From 7cf512c79418dea95993d1e289da1708037b727d Mon Sep 17 00:00:00 2001 From: Dennis Duda Date: Sun, 24 Nov 2024 17:21:49 +0100 Subject: [PATCH 16/58] Remove `GetProcessId` usage Instead, store the ID when spawning the process. >= XP SP1 / Vista / Server 2003 https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-getprocessid --- library/std/src/sys/process/windows.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/library/std/src/sys/process/windows.rs b/library/std/src/sys/process/windows.rs index 6e8be21a1fa6d..b21b01d6694b3 100644 --- a/library/std/src/sys/process/windows.rs +++ b/library/std/src/sys/process/windows.rs @@ -426,6 +426,7 @@ impl Command { Process { handle: Handle::from_raw_handle(pi.hProcess), main_thread_handle: Handle::from_raw_handle(pi.hThread), + id: pi.dwProcessId, }, pipes, )) @@ -681,6 +682,7 @@ impl From for Stdio { pub struct Process { handle: Handle, main_thread_handle: Handle, + id: u32, } impl Process { @@ -699,7 +701,7 @@ impl Process { } pub fn id(&self) -> u32 { - unsafe { c::GetProcessId(self.handle.as_raw_handle()) } + self.id } pub fn main_thread_handle(&self) -> BorrowedHandle<'_> { From 4b3c39adbac97f6fcbb9e326caffb69534955eb7 Mon Sep 17 00:00:00 2001 From: Dennis Duda Date: Sun, 24 Nov 2024 17:25:33 +0100 Subject: [PATCH 17/58] Add fallback impls for sleep and time functions - `GetSystemTimePreciseAsFileTime`: fall back to `GetSystemTimeAsFileTime` - `GetSystemTimeAsFileTime`: fall back to `GetSystemTime` and `SystemTimeToFileTime` - (only necessary for NT 3.1) - `SwitchToThread`: fall back to `Sleep(0)` - `CreateWaitableTimerExW`: optional import, fallback already in place --- library/std/src/sys/pal/windows/c.rs | 46 ++++++++++++++++++- .../std/src/sys/pal/windows/c/bindings.txt | 2 + .../std/src/sys/pal/windows/c/windows_sys.rs | 14 ++++++ 3 files changed, 61 insertions(+), 1 deletion(-) diff --git a/library/std/src/sys/pal/windows/c.rs b/library/std/src/sys/pal/windows/c.rs index 2686ea16ad6b1..24effab3e0912 100644 --- a/library/std/src/sys/pal/windows/c.rs +++ b/library/std/src/sys/pal/windows/c.rs @@ -146,7 +146,7 @@ compat_fn_with_fallback! { // >= Win8 / Server 2012 // https://docs.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-getsystemtimepreciseasfiletime - #[cfg(target_vendor = "win7")] + #[cfg(any(target_vendor = "win7", target_family = "rust9x"))] pub fn GetSystemTimePreciseAsFileTime(lpsystemtimeasfiletime: *mut FILETIME) -> () { unsafe { GetSystemTimeAsFileTime(lpsystemtimeasfiletime) } } @@ -313,3 +313,47 @@ compat_fn_with_fallback! { // https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-setthreadstackguarantee pub fn SetThreadStackGuarantee(stacksizeinbytes: *mut u32) -> BOOL { TRUE } } + +#[cfg(target_family = "rust9x")] +compat_fn_with_fallback! { + pub static KERNEL32: &CStr = c"kernel32" => { load: false, unicows: false }; + // >= 95 / NT 3.5 + // https://learn.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-getsystemtimeasfiletime + pub fn GetSystemTimeAsFileTime(lpSystemTimeAsFileTime: *mut FILETIME) { + unsafe { + // implementation based on old MSDN docs + let mut st: SYSTEMTIME = crate::mem::zeroed(); + GetSystemTime(&mut st); + crate::sys::cvt(SystemTimeToFileTime(&st, lpSystemTimeAsFileTime)).unwrap(); + } + } + // >= NT 4 + // https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-switchtothread + pub fn SwitchToThread() -> BOOL { + unsafe { Sleep(0); } + TRUE + } + + // >= Vista / Server 2008 + // https://learn.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-createwaitabletimerexw + pub fn CreateWaitableTimerExW( + lptimerattributes: *const SECURITY_ATTRIBUTES, + lptimername: PCWSTR, + dwflags: u32, + dwdesiredaccess: u32 + ) -> HANDLE { + ptr::null_mut() + } + + // >= 98 / NT 4 + // https://learn.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-setwaitabletimer + pub fn SetWaitableTimer(htimer: HANDLE, + lpduetime: *const i64, + lperiod: i32, + pfncompletionroutine: PTIMERAPCROUTINE, + lpargtocompletionroutine: *const core::ffi::c_void, + fresume: BOOL + ) -> BOOL { + rtabort!("unimplemented") + } +} diff --git a/library/std/src/sys/pal/windows/c/bindings.txt b/library/std/src/sys/pal/windows/c/bindings.txt index abef8085d95ec..5027504ae6be3 100644 --- a/library/std/src/sys/pal/windows/c/bindings.txt +++ b/library/std/src/sys/pal/windows/c/bindings.txt @@ -2188,6 +2188,7 @@ getsockopt GetStdHandle GetSystemDirectoryW GetSystemInfo +GetSystemTime GetSystemTimeAsFileTime GetSystemTimePreciseAsFileTime GetTempPathW @@ -2460,6 +2461,7 @@ SYMBOLIC_LINK_FLAGS SYMLINK_FLAG_RELATIVE SYNCHRONIZE SYSTEM_INFO +SystemTimeToFileTime TCP_NODELAY TerminateProcess THREAD_CREATE_RUN_IMMEDIATELY diff --git a/library/std/src/sys/pal/windows/c/windows_sys.rs b/library/std/src/sys/pal/windows/c/windows_sys.rs index da62eb96b4736..8c83a1e682042 100644 --- a/library/std/src/sys/pal/windows/c/windows_sys.rs +++ b/library/std/src/sys/pal/windows/c/windows_sys.rs @@ -64,6 +64,7 @@ windows_targets::link!("kernel32.dll" "system" fn GetProcessId(process : HANDLE) windows_targets::link!("kernel32.dll" "system" fn GetStdHandle(nstdhandle : STD_HANDLE) -> HANDLE); windows_targets::link!("kernel32.dll" "system" fn GetSystemDirectoryW(lpbuffer : PWSTR, usize : u32) -> u32); windows_targets::link!("kernel32.dll" "system" fn GetSystemInfo(lpsysteminfo : *mut SYSTEM_INFO)); +windows_targets::link!("kernel32.dll" "system" fn GetSystemTime(lpsystemtime : *mut SYSTEMTIME)); windows_targets::link!("kernel32.dll" "system" fn GetSystemTimeAsFileTime(lpsystemtimeasfiletime : *mut FILETIME)); windows_targets::link!("kernel32.dll" "system" fn GetSystemTimePreciseAsFileTime(lpsystemtimeasfiletime : *mut FILETIME)); windows_targets::link!("kernel32.dll" "system" fn GetTempPathW(nbufferlength : u32, lpbuffer : PWSTR) -> u32); @@ -113,6 +114,7 @@ windows_targets::link!("kernel32.dll" "system" fn Sleep(dwmilliseconds : u32)); windows_targets::link!("kernel32.dll" "system" fn SleepConditionVariableSRW(conditionvariable : *mut CONDITION_VARIABLE, srwlock : *mut SRWLOCK, dwmilliseconds : u32, flags : u32) -> BOOL); windows_targets::link!("kernel32.dll" "system" fn SleepEx(dwmilliseconds : u32, balertable : BOOL) -> u32); windows_targets::link!("kernel32.dll" "system" fn SwitchToThread() -> BOOL); +windows_targets::link!("kernel32.dll" "system" fn SystemTimeToFileTime(lpsystemtime : *const SYSTEMTIME, lpfiletime : *mut FILETIME) -> BOOL); windows_targets::link!("kernel32.dll" "system" fn TerminateProcess(hprocess : HANDLE, uexitcode : u32) -> BOOL); windows_targets::link!("kernel32.dll" "system" fn TlsAlloc() -> u32); windows_targets::link!("kernel32.dll" "system" fn TlsFree(dwtlsindex : u32) -> BOOL); @@ -3342,6 +3344,18 @@ pub type SYNCHRONIZATION_ACCESS_RIGHTS = u32; pub const SYNCHRONIZE: FILE_ACCESS_RIGHTS = 1048576u32; #[repr(C)] #[derive(Clone, Copy)] +pub struct SYSTEMTIME { + pub wYear: u16, + pub wMonth: u16, + pub wDayOfWeek: u16, + pub wDay: u16, + pub wHour: u16, + pub wMinute: u16, + pub wSecond: u16, + pub wMilliseconds: u16, +} +#[repr(C)] +#[derive(Clone, Copy)] pub struct SYSTEM_INFO { pub Anonymous: SYSTEM_INFO_0, pub dwPageSize: u32, From f6e12a58fc12fc030bf61d1fd5cfc40dfacb576c Mon Sep 17 00:00:00 2001 From: Dennis Duda Date: Sun, 24 Nov 2024 20:46:06 +0100 Subject: [PATCH 18/58] Add fallback impls for `File::truncate` and `File::seek`, `file_attr` - Fallback for `SetFilePointerEx` based on `SetFilePointer` - Fallback for file truncation (`SetFileInformationByHandle` with `FileEndOfFileInfo`) based on `SetFilePointerEx` and `SetEndOfFile` - file_attr: Don't query reparse tag if API is not available (`GetFileInformationByHandleEx` with `FileAttributeTagInfo`) --- library/std/src/sys/fs/windows.rs | 63 ++++++++++++++----- library/std/src/sys/io/is_terminal/windows.rs | 6 +- library/std/src/sys/pal/windows/c.rs | 55 ++++++++++++++++ .../std/src/sys/pal/windows/c/bindings.txt | 3 + .../std/src/sys/pal/windows/c/windows_sys.rs | 3 + 5 files changed, 114 insertions(+), 16 deletions(-) diff --git a/library/std/src/sys/fs/windows.rs b/library/std/src/sys/fs/windows.rs index f2d325da35c7d..33aa043e5d25a 100644 --- a/library/std/src/sys/fs/windows.rs +++ b/library/std/src/sys/fs/windows.rs @@ -354,11 +354,8 @@ impl File { // remove the fallback. let alloc = c::FILE_ALLOCATION_INFO { AllocationSize: 0 }; set_file_information_by_handle(handle.as_raw_handle(), &alloc) - .or_else(|_| { - let eof = c::FILE_END_OF_FILE_INFO { EndOfFile: 0 }; - set_file_information_by_handle(handle.as_raw_handle(), &eof) - }) - .io_result()?; + .io_result() + .or_else(|_| Self::truncate_inner(handle.as_raw_handle(), 0))?; } Ok(File { handle: Handle::from_inner(handle) }) } else { @@ -484,8 +481,37 @@ impl File { } pub fn truncate(&self, size: u64) -> io::Result<()> { + Self::truncate_inner(self.handle.as_raw_handle(), size) + } + + #[cfg(not(target_family = "rust9x"))] + pub fn truncate_inner(handle: RawHandle, size: u64) -> io::Result<()> { let info = c::FILE_END_OF_FILE_INFO { EndOfFile: size as i64 }; - api::set_file_information_by_handle(self.handle.as_raw_handle(), &info).io_result() + api::set_file_information_by_handle(handle, &info).io_result() + } + + #[cfg(target_family = "rust9x")] + pub fn truncate_inner(handle: RawHandle, size: u64) -> io::Result<()> { + if c::SetFileInformationByHandle::available().is_some() { + let info = c::FILE_END_OF_FILE_INFO { EndOfFile: size as i64 }; + api::set_file_information_by_handle(handle, &info).io_result() + } else { + let mut saved_pos = 0i64; + unsafe { + // get current file pointer position + cvt(c::SetFilePointerEx(handle, 0, &mut saved_pos, c::FILE_CURRENT))?; + + // seek to new end position + cvt(c::SetFilePointerEx(handle, size as i64, ptr::null_mut(), c::FILE_BEGIN))?; + + // set current position as end of file + cvt(c::SetEndOfFile(handle))?; + + // go back to saved position + cvt(c::SetFilePointerEx(handle, saved_pos, ptr::null_mut(), c::FILE_BEGIN))?; + } + Ok(()) + } } #[cfg(not(target_vendor = "uwp"))] @@ -495,15 +521,22 @@ impl File { cvt(c::GetFileInformationByHandle(self.handle.as_raw_handle(), &mut info))?; let mut reparse_tag = 0; if info.dwFileAttributes & c::FILE_ATTRIBUTE_REPARSE_POINT != 0 { - let mut attr_tag: c::FILE_ATTRIBUTE_TAG_INFO = mem::zeroed(); - cvt(c::GetFileInformationByHandleEx( - self.handle.as_raw_handle(), - c::FileAttributeTagInfo, - (&raw mut attr_tag).cast(), - size_of::().try_into().unwrap(), - ))?; - if attr_tag.FileAttributes & c::FILE_ATTRIBUTE_REPARSE_POINT != 0 { - reparse_tag = attr_tag.ReparseTag; + #[cfg(target_family = "rust9x")] + let f = c::GetFileInformationByHandleEx::available(); + #[cfg(not(target_family = "rust9x"))] + let f = Some(c::GetFileInformationByHandleEx); + + if let Some(f) = f { + let mut attr_tag: c::FILE_ATTRIBUTE_TAG_INFO = mem::zeroed(); + cvt(f( + self.handle.as_raw_handle(), + c::FileAttributeTagInfo, + (&raw mut attr_tag).cast(), + size_of::().try_into().unwrap(), + ))?; + if attr_tag.FileAttributes & c::FILE_ATTRIBUTE_REPARSE_POINT != 0 { + reparse_tag = attr_tag.ReparseTag; + } } } Ok(FileAttr { diff --git a/library/std/src/sys/io/is_terminal/windows.rs b/library/std/src/sys/io/is_terminal/windows.rs index b0c718d71f9f3..e331fa166c798 100644 --- a/library/std/src/sys/io/is_terminal/windows.rs +++ b/library/std/src/sys/io/is_terminal/windows.rs @@ -41,7 +41,11 @@ fn msys_tty_on(handle: BorrowedHandle<'_>) -> bool { let mut name_info = FILE_NAME_INFO { FileNameLength: 0, FileName: [0; c::MAX_PATH as usize] }; // Safety: buffer length is fixed. let res = unsafe { - c::GetFileInformationByHandleEx( + #[cfg(target_family = "rust9x")] + let Some(fun) = c::GetFileInformationByHandleEx::available() else { return false }; + #[cfg(not(target_family = "rust9x"))] + let fun = c::GetFileInformationByHandleEx; + fun( handle.as_raw_handle(), c::FileNameInfo, (&raw mut name_info) as *mut c_void, diff --git a/library/std/src/sys/pal/windows/c.rs b/library/std/src/sys/pal/windows/c.rs index 24effab3e0912..2920482a7bca8 100644 --- a/library/std/src/sys/pal/windows/c.rs +++ b/library/std/src/sys/pal/windows/c.rs @@ -357,3 +357,58 @@ compat_fn_with_fallback! { rtabort!("unimplemented") } } + +#[cfg(target_family = "rust9x")] +compat_fn_with_fallback! { + pub static KERNEL32: &CStr = c"kernel32" => { load: false, unicows: false }; + // >= 2000 + // https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-setfilepointerex + pub fn SetFilePointerEx( + hfile: HANDLE, + lidistancetomove: i64, + lpnewfilepointer: *mut i64, + dwmovemethod: SET_FILE_POINTER_MOVE_METHOD, + ) -> BOOL { + unsafe { + let distance_low = lidistancetomove as i32; + let mut distance_high = (lidistancetomove >> 32) as i32; + + let new_pos_low = SetFilePointer(hfile, distance_low, &mut distance_high, dwmovemethod); + + // since (-1 as u32) could be a valid value for the lower 32 bits of the new file + // pointer position, a call to GetLastError is needed to actually see if it failed + if new_pos_low == INVALID_SET_FILE_POINTER && GetLastError() != NO_ERROR { + return FALSE; + } + + if !lpnewfilepointer.is_null() { + *lpnewfilepointer = (distance_high as i64) << 32 | (new_pos_low as i64); + } + + TRUE + } + } + + // >= Vista / Server 2008 (XP / Server 2003 when linking a supported FileExtd.lib) + // https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-setfileinformationbyhandle + pub fn SetFileInformationByHandle( + hfile: HANDLE, + fileinformationclass: FILE_INFO_BY_HANDLE_CLASS, + lpfileinformation: *const ::core::ffi::c_void, + dwbuffersize: u32, + ) -> BOOL { + unsafe { SetLastError(ERROR_CALL_NOT_IMPLEMENTED as u32); }; + FALSE + } + // >= Vista / Server 2008 (XP / Server 2003 when linking a supported FileExtd.lib) + // https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-getfileinformationbyhandleex + pub fn GetFileInformationByHandleEx( + hfile: HANDLE, + fileinformationclass: FILE_INFO_BY_HANDLE_CLASS, + lpfileinformation: *mut ::core::ffi::c_void, + dwbuffersize: u32, + ) -> BOOL { + unsafe { SetLastError(ERROR_CALL_NOT_IMPLEMENTED as u32); }; + FALSE + } +} diff --git a/library/std/src/sys/pal/windows/c/bindings.txt b/library/std/src/sys/pal/windows/c/bindings.txt index 5027504ae6be3..d84d1241cf159 100644 --- a/library/std/src/sys/pal/windows/c/bindings.txt +++ b/library/std/src/sys/pal/windows/c/bindings.txt @@ -2213,6 +2213,7 @@ InitializeProcThreadAttributeList InitOnceBeginInitialize InitOnceComplete INVALID_FILE_ATTRIBUTES +INVALID_SET_FILE_POINTER INVALID_SOCKET IO_REPARSE_TAG_MOUNT_POINT IO_REPARSE_TAG_SYMLINK @@ -2384,10 +2385,12 @@ SEND_RECV_FLAGS sendto SET_FILE_POINTER_MOVE_METHOD SetCurrentDirectoryW +SetEndOfFile SetEnvironmentVariableW SetEvent SetFileAttributesW SetFileInformationByHandle +SetFilePointer SetFilePointerEx SetFileTime SetHandleInformation diff --git a/library/std/src/sys/pal/windows/c/windows_sys.rs b/library/std/src/sys/pal/windows/c/windows_sys.rs index 8c83a1e682042..3b4ddb7e662ac 100644 --- a/library/std/src/sys/pal/windows/c/windows_sys.rs +++ b/library/std/src/sys/pal/windows/c/windows_sys.rs @@ -99,10 +99,12 @@ windows_targets::link!("kernel32.dll" "system" fn ResetEvent(hevent : HANDLE) -> windows_targets::link!("advapi32.dll" "system" "SystemFunction036" fn RtlGenRandom(randombuffer : *mut core::ffi::c_void, randombufferlength : u32) -> bool); windows_targets::link!("ntdll.dll" "system" fn RtlNtStatusToDosError(status : NTSTATUS) -> u32); windows_targets::link!("kernel32.dll" "system" fn SetCurrentDirectoryW(lppathname : PCWSTR) -> BOOL); +windows_targets::link!("kernel32.dll" "system" fn SetEndOfFile(hfile : HANDLE) -> BOOL); windows_targets::link!("kernel32.dll" "system" fn SetEnvironmentVariableW(lpname : PCWSTR, lpvalue : PCWSTR) -> BOOL); windows_targets::link!("kernel32.dll" "system" fn SetEvent(hevent : HANDLE) -> BOOL); windows_targets::link!("kernel32.dll" "system" fn SetFileAttributesW(lpfilename : PCWSTR, dwfileattributes : FILE_FLAGS_AND_ATTRIBUTES) -> BOOL); windows_targets::link!("kernel32.dll" "system" fn SetFileInformationByHandle(hfile : HANDLE, fileinformationclass : FILE_INFO_BY_HANDLE_CLASS, lpfileinformation : *const core::ffi::c_void, dwbuffersize : u32) -> BOOL); +windows_targets::link!("kernel32.dll" "system" fn SetFilePointer(hfile : HANDLE, ldistancetomove : i32, lpdistancetomovehigh : *mut i32, dwmovemethod : SET_FILE_POINTER_MOVE_METHOD) -> u32); windows_targets::link!("kernel32.dll" "system" fn SetFilePointerEx(hfile : HANDLE, lidistancetomove : i64, lpnewfilepointer : *mut i64, dwmovemethod : SET_FILE_POINTER_MOVE_METHOD) -> BOOL); windows_targets::link!("kernel32.dll" "system" fn SetFileTime(hfile : HANDLE, lpcreationtime : *const FILETIME, lplastaccesstime : *const FILETIME, lplastwritetime : *const FILETIME) -> BOOL); windows_targets::link!("kernel32.dll" "system" fn SetHandleInformation(hobject : HANDLE, dwmask : u32, dwflags : HANDLE_FLAGS) -> BOOL); @@ -2823,6 +2825,7 @@ impl Default for INIT_ONCE { } pub const INIT_ONCE_INIT_FAILED: u32 = 4u32; pub const INVALID_FILE_ATTRIBUTES: u32 = 4294967295u32; +pub const INVALID_SET_FILE_POINTER: u32 = 4294967295u32; pub const INVALID_SOCKET: SOCKET = -1i32 as _; #[repr(C)] #[derive(Clone, Copy)] From 819bfe7a74b7e0ea55a120a910ad3dce7da88473 Mon Sep 17 00:00:00 2001 From: Dennis Duda Date: Sun, 24 Nov 2024 23:25:06 +0100 Subject: [PATCH 19/58] Fallbacks for `CreateSymbolicLinkW`, `CreateHardLinkW`, `GetFinalPathNameByHandleW` - `CreateSymbolicLinkW` is used in `std::fs::soft_link`. Fails on unsupported systems. - `CreateHardLinkW` is used in `std::fs::hard_link`. Fails on unsupported systems. - `GetFinalPathNameByHandleW` is used in `std::fs::canonicalize`. Systems that don't support `GetFinalPathNameByHandleW` also don't support symlinks, so the fallback uses `GetFullPathNameW` instead. --- library/std/src/sys/fs/windows.rs | 22 +++++++++++++++++ library/std/src/sys/pal/windows/c.rs | 35 ++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+) diff --git a/library/std/src/sys/fs/windows.rs b/library/std/src/sys/fs/windows.rs index 33aa043e5d25a..ef98a8d08f559 100644 --- a/library/std/src/sys/fs/windows.rs +++ b/library/std/src/sys/fs/windows.rs @@ -1573,6 +1573,7 @@ fn get_path(f: &File) -> io::Result { ) } +#[cfg(not(target_family = "rust9x"))] pub fn canonicalize(p: &WCStr) -> io::Result { let mut opts = OpenOptions::new(); // No read or write permissions are necessary @@ -1583,6 +1584,27 @@ pub fn canonicalize(p: &WCStr) -> io::Result { get_path(&f) } +#[cfg(target_family = "rust9x")] +pub fn canonicalize(p: &WCStr) -> io::Result { + if c::GetFinalPathNameByHandleW::available().is_some() { + let mut opts = OpenOptions::new(); + // No read or write permissions are necessary + opts.access_mode(0); + // This flag is so we can open directories too + opts.custom_flags(c::FILE_FLAG_BACKUP_SEMANTICS); + let f = File::open_native(p, &opts)?; + get_path(&f) + } else { + // systems that don't support GetFinalPathNameByHandleW also don't support symlinks, so we + // fall back to using GetFullPathName. + let mut file_part = ptr::null_mut(); + fill_utf16_buf( + |buf, sz| unsafe { c::GetFullPathNameW(p.as_ptr(), sz, buf, &mut file_part) }, + |buf| PathBuf::from(OsString::from_wide(buf)), + ) + } +} + pub fn copy(from: &WCStr, to: &WCStr) -> io::Result { unsafe extern "system" fn callback( _TotalFileSize: i64, diff --git a/library/std/src/sys/pal/windows/c.rs b/library/std/src/sys/pal/windows/c.rs index 2920482a7bca8..43c7b64359c9d 100644 --- a/library/std/src/sys/pal/windows/c.rs +++ b/library/std/src/sys/pal/windows/c.rs @@ -412,3 +412,38 @@ compat_fn_with_fallback! { FALSE } } + +#[cfg(target_family = "rust9x")] +compat_fn_with_fallback! { + pub static KERNEL32: &CStr = c"kernel32" => { load: false, unicows: false }; + // >= Vista / Server 2008 + // https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-createsymboliclinkw + pub fn CreateSymbolicLinkW( + lpsymlinkfilename: PCWSTR, + lptargetfilename: PCWSTR, + dwflags: SYMBOLIC_LINK_FLAGS, + ) -> bool { + unsafe { SetLastError(ERROR_CALL_NOT_IMPLEMENTED as u32); }; + false + } + // >= Vista / Server 2008 + // https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getfinalpathnamebyhandlew + pub fn GetFinalPathNameByHandleW( + hfile: HANDLE, + lpszfilepath: PWSTR, + cchfilepath: u32, + dwflags: GETFINALPATHNAMEBYHANDLE_FLAGS + ) -> u32 { + rtabort!("unimplemented") + } + // >= 2000 + // https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-createhardlinkw + pub fn CreateHardLinkW( + lpfilename: PCWSTR, + lpexistingfilename: PCWSTR, + lpsecurityattributes: *const SECURITY_ATTRIBUTES, + ) -> BOOL { + unsafe { SetLastError(ERROR_CALL_NOT_IMPLEMENTED as u32); }; + FALSE + } +} From 7582e354fb44173894e0bb05ba4aaa733dade338 Mon Sep 17 00:00:00 2001 From: Dennis Duda Date: Sun, 24 Nov 2024 23:31:27 +0100 Subject: [PATCH 20/58] Remove static dependency on advapi.dll, impl random generation fallbacks Down to Win95IE3.02/Win95OSR2/NT4 we get a somewhat reasonable implementation based on CryptGenRandom, before that we fall back to a non-cryptographic PRNG instead. --- library/std/src/sys/pal/windows/c.rs | 35 ++++++- .../std/src/sys/pal/windows/c/bindings.txt | 6 ++ .../std/src/sys/pal/windows/c/windows_sys.rs | 8 +- library/std/src/sys/random/windows.rs | 96 ++++++++++++++++++- library/std/src/sys/sync/mod.rs | 2 +- 5 files changed, 143 insertions(+), 4 deletions(-) diff --git a/library/std/src/sys/pal/windows/c.rs b/library/std/src/sys/pal/windows/c.rs index 43c7b64359c9d..76f1c720bfc27 100644 --- a/library/std/src/sys/pal/windows/c.rs +++ b/library/std/src/sys/pal/windows/c.rs @@ -100,7 +100,7 @@ pub struct MOUNT_POINT_REPARSE_BUFFER { pub const EXCEPTION_CONTINUE_SEARCH: i32 = 0; // Use raw-dylib to import ProcessPrng as we can't rely on there being an import library. -#[cfg(not(target_vendor = "win7"))] +#[cfg(not(any(target_vendor = "win7", target_family = "rust9x")))] #[cfg_attr( target_arch = "x86", link(name = "bcryptprimitives", kind = "raw-dylib", import_name_type = "undecorated") @@ -447,3 +447,36 @@ compat_fn_with_fallback! { FALSE } } + +#[cfg(target_family = "rust9x")] +compat_fn_with_fallback! { + pub static advapi32: &CStr = c"advapi32" => { load: true, unicows: false }; + // >= XP / Server 2003 + // https://learn.microsoft.com/en-us/windows/win32/api/ntsecapi/nf-ntsecapi-rtlgenrandom + pub fn SystemFunction036( + randombuffer: *mut core::ffi::c_void, + randombufferlength: u32 + ) -> bool { + rtabort!("unimplemented") + } + + // >= NT 4.0 / Windows 95 OSR2 / Windows 95 with IE 3.02 + // https://learn.microsoft.com/en-us/windows/win32/api/wincrypt/nf-wincrypt-cryptacquirecontexta + pub fn CryptAcquireContextA( + phprov: *mut usize, + szcontainer: PCSTR, + szprovider: PCSTR, + dwprovtype: u32, + dwflags: u32 + ) -> BOOL { + rtabort!("unimplemented") + } + pub fn CryptReleaseContext(hprov: usize, dwflags: u32) -> BOOL { + rtabort!("unimplemented") + } + pub fn CryptGenRandom(hprov: usize, dwlen: u32, pbbuffer: *mut u8) -> BOOL { + rtabort!("unimplemented") + } +} +#[cfg(target_family = "rust9x")] +pub use self::SystemFunction036 as RtlGenRandom; diff --git a/library/std/src/sys/pal/windows/c/bindings.txt b/library/std/src/sys/pal/windows/c/bindings.txt index d84d1241cf159..f1e9b6285f26c 100644 --- a/library/std/src/sys/pal/windows/c/bindings.txt +++ b/library/std/src/sys/pal/windows/c/bindings.txt @@ -64,6 +64,10 @@ CreateProcessW CreateSymbolicLinkW CreateThread CreateWaitableTimerExW +CRYPT_VERIFYCONTEXT +CryptAcquireContextA +CryptGenRandom +CryptReleaseContext CSTR_EQUAL CSTR_GREATER_THAN CSTR_LESS_THAN @@ -2192,6 +2196,7 @@ GetSystemTime GetSystemTimeAsFileTime GetSystemTimePreciseAsFileTime GetTempPathW +GetTickCount GetUserProfileDirectoryW GetVersion GetWindowsDirectoryW @@ -2351,6 +2356,7 @@ PROFILE_KERNEL PROFILE_SERVER PROFILE_USER PROGRESS_CONTINUE +PROV_RSA_FULL QueryPerformanceCounter QueryPerformanceFrequency READ_CONTROL diff --git a/library/std/src/sys/pal/windows/c/windows_sys.rs b/library/std/src/sys/pal/windows/c/windows_sys.rs index 3b4ddb7e662ac..661ddee282262 100644 --- a/library/std/src/sys/pal/windows/c/windows_sys.rs +++ b/library/std/src/sys/pal/windows/c/windows_sys.rs @@ -21,6 +21,9 @@ windows_targets::link!("kernel32.dll" "system" fn CreateProcessW(lpapplicationna windows_targets::link!("kernel32.dll" "system" fn CreateSymbolicLinkW(lpsymlinkfilename : PCWSTR, lptargetfilename : PCWSTR, dwflags : SYMBOLIC_LINK_FLAGS) -> bool); windows_targets::link!("kernel32.dll" "system" fn CreateThread(lpthreadattributes : *const SECURITY_ATTRIBUTES, dwstacksize : usize, lpstartaddress : LPTHREAD_START_ROUTINE, lpparameter : *const core::ffi::c_void, dwcreationflags : THREAD_CREATION_FLAGS, lpthreadid : *mut u32) -> HANDLE); windows_targets::link!("kernel32.dll" "system" fn CreateWaitableTimerExW(lptimerattributes : *const SECURITY_ATTRIBUTES, lptimername : PCWSTR, dwflags : u32, dwdesiredaccess : u32) -> HANDLE); +windows_targets::link!("advapi32.dll" "system" fn CryptAcquireContextA(phprov : *mut usize, szcontainer : PCSTR, szprovider : PCSTR, dwprovtype : u32, dwflags : u32) -> BOOL); +windows_targets::link!("advapi32.dll" "system" fn CryptGenRandom(hprov : usize, dwlen : u32, pbbuffer : *mut u8) -> BOOL); +windows_targets::link!("advapi32.dll" "system" fn CryptReleaseContext(hprov : usize, dwflags : u32) -> BOOL); windows_targets::link!("kernel32.dll" "system" fn DeleteCriticalSection(lpcriticalsection : *mut CRITICAL_SECTION)); windows_targets::link!("kernel32.dll" "system" fn DeleteFileW(lpfilename : PCWSTR) -> BOOL); windows_targets::link!("kernel32.dll" "system" fn DeleteProcThreadAttributeList(lpattributelist : LPPROC_THREAD_ATTRIBUTE_LIST)); @@ -68,6 +71,7 @@ windows_targets::link!("kernel32.dll" "system" fn GetSystemTime(lpsystemtime : * windows_targets::link!("kernel32.dll" "system" fn GetSystemTimeAsFileTime(lpsystemtimeasfiletime : *mut FILETIME)); windows_targets::link!("kernel32.dll" "system" fn GetSystemTimePreciseAsFileTime(lpsystemtimeasfiletime : *mut FILETIME)); windows_targets::link!("kernel32.dll" "system" fn GetTempPathW(nbufferlength : u32, lpbuffer : PWSTR) -> u32); +windows_targets::link!("kernel32.dll" "system" fn GetTickCount() -> u32); windows_targets::link!("userenv.dll" "system" fn GetUserProfileDirectoryW(htoken : HANDLE, lpprofiledir : PWSTR, lpcchsize : *mut u32) -> BOOL); windows_targets::link!("kernel32.dll" "system" fn GetVersion() -> u32); windows_targets::link!("kernel32.dll" "system" fn GetWindowsDirectoryW(lpbuffer : PWSTR, usize : u32) -> u32); @@ -513,6 +517,7 @@ impl Default for CRITICAL_SECTION_DEBUG { unsafe { core::mem::zeroed() } } } +pub const CRYPT_VERIFYCONTEXT: u32 = 4026531840u32; pub const CSTR_EQUAL: COMPARESTRING_RESULT = 2i32; pub const CSTR_GREATER_THAN: COMPARESTRING_RESULT = 3i32; pub const CSTR_LESS_THAN: COMPARESTRING_RESULT = 1i32; @@ -3142,6 +3147,7 @@ pub const PROFILE_KERNEL: PROCESS_CREATION_FLAGS = 536870912u32; pub const PROFILE_SERVER: PROCESS_CREATION_FLAGS = 1073741824u32; pub const PROFILE_USER: PROCESS_CREATION_FLAGS = 268435456u32; pub const PROGRESS_CONTINUE: COPYPROGRESSROUTINE_PROGRESS = 0u32; +pub const PROV_RSA_FULL: u32 = 1u32; pub type PSID = *mut core::ffi::c_void; pub type PSTR = *mut u8; pub type PTIMERAPCROUTINE = Option< @@ -3346,7 +3352,7 @@ pub const SYMLINK_FLAG_RELATIVE: u32 = 1u32; pub type SYNCHRONIZATION_ACCESS_RIGHTS = u32; pub const SYNCHRONIZE: FILE_ACCESS_RIGHTS = 1048576u32; #[repr(C)] -#[derive(Clone, Copy)] +#[derive(Clone, Copy, Default)] pub struct SYSTEMTIME { pub wYear: u16, pub wMonth: u16, diff --git a/library/std/src/sys/random/windows.rs b/library/std/src/sys/random/windows.rs index f5da637f56ca9..1aeb6bde0f69e 100644 --- a/library/std/src/sys/random/windows.rs +++ b/library/std/src/sys/random/windows.rs @@ -1,6 +1,6 @@ use crate::sys::c; -#[cfg(not(target_vendor = "win7"))] +#[cfg(not(any(target_vendor = "win7", target_family = "rust9x")))] #[inline] pub fn fill_bytes(bytes: &mut [u8]) { let ret = unsafe { c::ProcessPrng(bytes.as_mut_ptr(), bytes.len()) }; @@ -18,3 +18,97 @@ pub fn fill_bytes(mut bytes: &mut [u8]) { bytes = &mut bytes[len as usize..]; } } + +#[cfg(target_family = "rust9x")] +mod rust9x { + use super::*; + use crate::pin::Pin; + use crate::sys::sync::OnceBox; + + pub fn fill_bytes(mut bytes: &mut [u8]) { + if let Some(f) = c::RtlGenRandom::available() { + while !bytes.is_empty() { + let len = bytes.len().try_into().unwrap_or(u32::MAX); + let ret = unsafe { f(bytes.as_mut_ptr().cast(), len) }; + assert_ne!(ret, false, "failed to generate random data"); + bytes = &mut bytes[len as usize..]; + } + } else if let Some(f) = c::CryptGenRandom::available() { + let ctx = CRYPT_CONTEXT.get_or_init(init_crypt_context); + while !bytes.is_empty() { + let len = bytes.len().try_into().unwrap_or(u32::MAX); + let ret = unsafe { f(ctx.0, len, bytes.as_mut_ptr().cast()) }; + assert_ne!(ret, 0, "failed to generate random data"); + bytes = &mut bytes[len as usize..]; + } + } else { + // well, we tried, fall back to a non-cryptographically-secure PRNG + // for NT <4.0 and 95 without IE3.02 or higher. + + // seed with stack address and tick count + let mut state: [u32; 2] = [unsafe { c::GetTickCount() }, 0]; + state[1] = (&raw const state) as u32; + + let mut chunks = bytes.chunks_exact_mut(4); + for chunk in &mut chunks { + let [a, b, c, d] = xoroshiro64_star_star(&mut state).to_ne_bytes(); + chunk[0] = a; + chunk[1] = b; + chunk[2] = c; + chunk[3] = d; + } + + let remainder = chunks.into_remainder(); + if remainder.is_empty() { + return; + } + + for (rem, val) in + remainder.iter_mut().zip(xoroshiro64_star_star(&mut state).to_ne_bytes()) + { + *rem = val; + } + } + } + + static CRYPT_CONTEXT: OnceBox = OnceBox::new(); + + struct HCryptProvider(usize); + impl Drop for HCryptProvider { + fn drop(&mut self) { + unsafe { + c::CryptReleaseContext(self.0, 0); + } + } + } + + fn init_crypt_context() -> Pin> { + let mut crypt_context = 0; + unsafe { + let ret = c::CryptAcquireContextA( + &mut crypt_context, + core::ptr::null(), + core::ptr::null(), + c::PROV_RSA_FULL, + c::CRYPT_VERIFYCONTEXT, + ); + assert_ne!(ret, c::FALSE, "failed to acquire crypt context: {:#X}", c::GetLastError()); + }; + Box::pin(HCryptProvider(crypt_context)) + } + + // xoroshiro64** + // 2018 by David Blackman and Sebastiano Vigna (vigna@acm.org) + // https://prng.di.unimi.it/xoroshiro64starstar.c + fn xoroshiro64_star_star(state: &mut [u32; 2]) -> u32 { + let result = state[0].wrapping_mul(0x9E3779BB).rotate_left(5).wrapping_mul(5); + state[1] ^= state[0]; + state[0] = state[0].rotate_left(26) ^ state[1] ^ (state[1] << 9); + state[1] = state[1].rotate_left(13); + + result + } +} + +#[cfg(target_family = "rust9x")] +pub use rust9x::fill_bytes; diff --git a/library/std/src/sys/sync/mod.rs b/library/std/src/sys/sync/mod.rs index 0691e96785198..d4f1cc525cbff 100644 --- a/library/std/src/sys/sync/mod.rs +++ b/library/std/src/sys/sync/mod.rs @@ -9,6 +9,6 @@ pub use condvar::Condvar; pub use mutex::Mutex; pub use once::{Once, OnceState}; #[allow(unused)] // Only used on some platforms. -use once_box::OnceBox; +pub(crate) use once_box::OnceBox; pub use rwlock::RwLock; pub use thread_parking::Parker; From 374c4e7bafbd9793d5fb7689fde71e9f890c9c8f Mon Sep 17 00:00:00 2001 From: Dennis Duda Date: Sun, 1 Dec 2024 22:12:31 +0100 Subject: [PATCH 21/58] Make std::hash::RandomState not be align(8) to work around TLS issues on 95 At least on Windows 95 RTM, the TLS variables are only aligned to a 4 byte boundary. Unclear if this affects other systems, but NT4 is fine. --- library/std/src/hash/random.rs | 9 ++++++--- library/std/src/sys/random/mod.rs | 6 ++---- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/library/std/src/hash/random.rs b/library/std/src/hash/random.rs index 236803b24a2ec..8f677f587ba84 100644 --- a/library/std/src/hash/random.rs +++ b/library/std/src/hash/random.rs @@ -65,13 +65,16 @@ impl RandomState { // iteration order allows a form of DOS attack. To counter that we // increment one of the seeds on every RandomState creation, giving // every corresponding HashMap a different iteration order. - thread_local!(static KEYS: Cell<(u64, u64)> = { + thread_local!(static KEYS: Cell<[u8; 16]> = { Cell::new(hashmap_random_keys()) }); KEYS.with(|keys| { - let (k0, k1) = keys.get(); - keys.set((k0.wrapping_add(1), k1)); + let [n0, n1, n2, n3, n4, n5, n6, n7, n8, n9, n10, n11, n12, n13, n14, n15] = keys.get(); + let k0 = u64::from_ne_bytes([n0, n1, n2, n3, n4, n5, n6, n7]); + let k1 = u64::from_ne_bytes([n8, n9, n10, n11, n12, n13, n14, n15]); + let [n0, n1, n2, n3, n4, n5, n6, n7] = k0.wrapping_add(1).to_ne_bytes(); + keys.set([n0, n1, n2, n3, n4, n5, n6, n7, n8, n9, n10, n11, n12, n13, n14, n15]); RandomState { k0, k1 } }) } diff --git a/library/std/src/sys/random/mod.rs b/library/std/src/sys/random/mod.rs index 91f72d0738790..4cdc98feb42e6 100644 --- a/library/std/src/sys/random/mod.rs +++ b/library/std/src/sys/random/mod.rs @@ -123,10 +123,8 @@ cfg_select! { target_os = "xous", target_os = "vexos", )))] -pub fn hashmap_random_keys() -> (u64, u64) { +pub fn hashmap_random_keys() -> [u8; 16] { let mut buf = [0; 16]; fill_bytes(&mut buf); - let k1 = u64::from_ne_bytes(buf[..8].try_into().unwrap()); - let k2 = u64::from_ne_bytes(buf[8..].try_into().unwrap()); - (k1, k2) + buf } From 4107d8488c4693fdd1a715627561b9177f116d0b Mon Sep 17 00:00:00 2001 From: Dennis Duda Date: Fri, 29 Nov 2024 20:53:05 +0100 Subject: [PATCH 22/58] Add fallback for `home_dir_crt` just returns `None` if unsupported --- library/std/src/sys/pal/windows/c.rs | 30 +++++++++++++++++++++++++++ library/std/src/sys/pal/windows/os.rs | 4 ++-- library/windows_targets/src/lib.rs | 2 +- 3 files changed, 33 insertions(+), 3 deletions(-) diff --git a/library/std/src/sys/pal/windows/c.rs b/library/std/src/sys/pal/windows/c.rs index 76f1c720bfc27..b92d6d5d63090 100644 --- a/library/std/src/sys/pal/windows/c.rs +++ b/library/std/src/sys/pal/windows/c.rs @@ -480,3 +480,33 @@ compat_fn_with_fallback! { } #[cfg(target_family = "rust9x")] pub use self::SystemFunction036 as RtlGenRandom; + +#[cfg(target_family = "rust9x")] +compat_fn_with_fallback! { + pub static userenv: &CStr = c"userenv" => { load: true, unicows: false }; + // >= NT 4.0 + // https://learn.microsoft.com/en-us/windows/win32/api/userenv/nf-userenv-getuserprofiledirectoryw + pub fn GetUserProfileDirectoryW( + htoken: HANDLE, + lpprofiledir: PWSTR, + lpcchsize: *mut u32 + ) -> BOOL { + unsafe { SetLastError(ERROR_CALL_NOT_IMPLEMENTED as u32); }; + FALSE + } +} + +#[cfg(target_family = "rust9x")] +compat_fn_with_fallback! { + pub static advapi32: &CStr = c"advapi32" => { load: true, unicows: false }; + // >= NT + // https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-openprocesstoken + pub fn OpenProcessToken( + processhandle: HANDLE, + desiredaccess: TOKEN_ACCESS_MASK, + tokenhandle: *mut HANDLE + ) -> BOOL { + unsafe { SetLastError(ERROR_CALL_NOT_IMPLEMENTED as u32); }; + FALSE + } +} diff --git a/library/std/src/sys/pal/windows/os.rs b/library/std/src/sys/pal/windows/os.rs index 1b3c80c079bef..acb36431452a6 100644 --- a/library/std/src/sys/pal/windows/os.rs +++ b/library/std/src/sys/pal/windows/os.rs @@ -186,7 +186,7 @@ pub fn temp_dir() -> PathBuf { super::fill_utf16_buf(|buf, sz| unsafe { c::GetTempPath2W(sz, buf) }, super::os2path).unwrap() } -#[cfg(all(not(target_vendor = "uwp"), not(target_vendor = "win7")))] +#[cfg(all(not(target_vendor = "uwp"), not(target_vendor = "win7"), not(target_family = "rust9x")))] fn home_dir_crt() -> Option { unsafe { // Defined in processthreadsapi.h. @@ -212,7 +212,7 @@ fn home_dir_crt() -> Option { } } -#[cfg(target_vendor = "win7")] +#[cfg(any(target_vendor = "win7", target_family = "rust9x"))] fn home_dir_crt() -> Option { unsafe { use crate::sys::handle::Handle; diff --git a/library/windows_targets/src/lib.rs b/library/windows_targets/src/lib.rs index 3446e2113dda9..c4161d74f5a64 100644 --- a/library/windows_targets/src/lib.rs +++ b/library/windows_targets/src/lib.rs @@ -46,7 +46,7 @@ pub macro link($($tt:tt)*) { #[cfg(not(target_os = "cygwin"))] // Cygwin doesn't need these libs #[cfg_attr(target_vendor = "win7", link(name = "advapi32"))] #[link(name = "ntdll")] -#[link(name = "userenv")] +#[cfg_attr(not(target_family = "rust9x"), link(name = "userenv"))] #[link(name = "ws2_32")] #[link(name = "dbghelp")] // required for backtrace-rs symbolization unsafe extern "C" {} From f81748ad7a30ea2a9b8915d09d3b1549e78d3af6 Mon Sep 17 00:00:00 2001 From: Dennis Duda Date: Fri, 29 Nov 2024 22:21:26 +0100 Subject: [PATCH 23/58] Convert winsock calls to `WSA...A` --- library/std/src/fs/tests.rs | 2 +- library/std/src/os/windows/io/socket.rs | 8 ++--- .../src/sys/net/connection/socket/windows.rs | 4 +-- .../std/src/sys/pal/windows/c/bindings.txt | 3 ++ .../std/src/sys/pal/windows/c/windows_sys.rs | 31 +++++++++++++++++++ 5 files changed, 41 insertions(+), 7 deletions(-) diff --git a/library/std/src/fs/tests.rs b/library/std/src/fs/tests.rs index 0a5d1153d860c..1c0c8777e6b5f 100644 --- a/library/std/src/fs/tests.rs +++ b/library/std/src/fs/tests.rs @@ -2072,7 +2072,7 @@ fn windows_unix_socket_exists() { // std doesn't currently support Unix sockets on Windows so manually create one here. net::init(); unsafe { - let socket = c::WSASocketW( + let socket = c::WSASocketA( c::AF_UNIX as i32, c::SOCK_STREAM, 0, diff --git a/library/std/src/os/windows/io/socket.rs b/library/std/src/os/windows/io/socket.rs index 28e972925e667..117b1319337f6 100644 --- a/library/std/src/os/windows/io/socket.rs +++ b/library/std/src/os/windows/io/socket.rs @@ -99,9 +99,9 @@ impl BorrowedSocket<'_> { /// object as the existing `BorrowedSocket` instance. #[stable(feature = "io_safety", since = "1.63.0")] pub fn try_clone_to_owned(&self) -> io::Result { - let mut info = unsafe { mem::zeroed::() }; + let mut info = unsafe { mem::zeroed::() }; let result = unsafe { - sys::c::WSADuplicateSocketW( + sys::c::WSADuplicateSocketA( self.as_raw_socket() as sys::c::SOCKET, sys::c::GetCurrentProcessId(), &mut info, @@ -109,7 +109,7 @@ impl BorrowedSocket<'_> { }; sys::net::cvt(result)?; let socket = unsafe { - sys::c::WSASocketW( + sys::c::WSASocketA( info.iAddressFamily, info.iSocketType, info.iProtocol, @@ -129,7 +129,7 @@ impl BorrowedSocket<'_> { } let socket = unsafe { - sys::c::WSASocketW( + sys::c::WSASocketA( info.iAddressFamily, info.iSocketType, info.iProtocol, diff --git a/library/std/src/sys/net/connection/socket/windows.rs b/library/std/src/sys/net/connection/socket/windows.rs index 6dbebc5e276ec..53fb5f9c41909 100644 --- a/library/std/src/sys/net/connection/socket/windows.rs +++ b/library/std/src/sys/net/connection/socket/windows.rs @@ -119,7 +119,7 @@ pub struct Socket(OwnedSocket); impl Socket { pub fn new(family: c_int, ty: c_int) -> io::Result { let socket = unsafe { - c::WSASocketW( + c::WSASocketA( family, ty, 0, @@ -139,7 +139,7 @@ impl Socket { } let socket = - unsafe { c::WSASocketW(family, ty, 0, ptr::null_mut(), 0, c::WSA_FLAG_OVERLAPPED) }; + unsafe { c::WSASocketA(family, ty, 0, ptr::null_mut(), 0, c::WSA_FLAG_OVERLAPPED) }; if socket == c::INVALID_SOCKET { return Err(last_error()); diff --git a/library/std/src/sys/pal/windows/c/bindings.txt b/library/std/src/sys/pal/windows/c/bindings.txt index f1e9b6285f26c..c3c18f32447e5 100644 --- a/library/std/src/sys/pal/windows/c/bindings.txt +++ b/library/std/src/sys/pal/windows/c/bindings.txt @@ -2587,6 +2587,7 @@ WSABASEERR WSABUF WSACleanup WSADATA +WSADuplicateSocketA WSADuplicateSocketW WSAEACCES WSAEADDRINUSE @@ -2643,11 +2644,13 @@ WSAHOST_NOT_FOUND WSANO_DATA WSANO_RECOVERY WSANOTINITIALISED +WSAPROTOCOL_INFOA WSAPROTOCOL_INFOW WSAPROTOCOLCHAIN WSARecv WSASend WSASERVICE_NOT_FOUND +WSASocketA WSASocketW WSAStartup WSASYSCALLFAILURE diff --git a/library/std/src/sys/pal/windows/c/windows_sys.rs b/library/std/src/sys/pal/windows/c/windows_sys.rs index 661ddee282262..ed3da4939343c 100644 --- a/library/std/src/sys/pal/windows/c/windows_sys.rs +++ b/library/std/src/sys/pal/windows/c/windows_sys.rs @@ -132,10 +132,12 @@ windows_targets::link!("kernel32.dll" "system" fn TryEnterCriticalSection(lpcrit windows_targets::link!("kernel32.dll" "system" fn UnlockFile(hfile : HANDLE, dwfileoffsetlow : u32, dwfileoffsethigh : u32, nnumberofbytestounlocklow : u32, nnumberofbytestounlockhigh : u32) -> BOOL); windows_targets::link!("kernel32.dll" "system" fn UpdateProcThreadAttribute(lpattributelist : LPPROC_THREAD_ATTRIBUTE_LIST, dwflags : u32, attribute : usize, lpvalue : *const core::ffi::c_void, cbsize : usize, lppreviousvalue : *mut core::ffi::c_void, lpreturnsize : *const usize) -> BOOL); windows_targets::link!("ws2_32.dll" "system" fn WSACleanup() -> i32); +windows_targets::link!("ws2_32.dll" "system" fn WSADuplicateSocketA(s : SOCKET, dwprocessid : u32, lpprotocolinfo : *mut WSAPROTOCOL_INFOA) -> i32); windows_targets::link!("ws2_32.dll" "system" fn WSADuplicateSocketW(s : SOCKET, dwprocessid : u32, lpprotocolinfo : *mut WSAPROTOCOL_INFOW) -> i32); windows_targets::link!("ws2_32.dll" "system" fn WSAGetLastError() -> WSA_ERROR); windows_targets::link!("ws2_32.dll" "system" fn WSARecv(s : SOCKET, lpbuffers : *const WSABUF, dwbuffercount : u32, lpnumberofbytesrecvd : *mut u32, lpflags : *mut u32, lpoverlapped : *mut OVERLAPPED, lpcompletionroutine : LPWSAOVERLAPPED_COMPLETION_ROUTINE) -> i32); windows_targets::link!("ws2_32.dll" "system" fn WSASend(s : SOCKET, lpbuffers : *const WSABUF, dwbuffercount : u32, lpnumberofbytessent : *mut u32, dwflags : u32, lpoverlapped : *mut OVERLAPPED, lpcompletionroutine : LPWSAOVERLAPPED_COMPLETION_ROUTINE) -> i32); +windows_targets::link!("ws2_32.dll" "system" fn WSASocketA(af : i32, r#type : i32, protocol : i32, lpprotocolinfo : *const WSAPROTOCOL_INFOA, g : u32, dwflags : u32) -> SOCKET); windows_targets::link!("ws2_32.dll" "system" fn WSASocketW(af : i32, r#type : i32, protocol : i32, lpprotocolinfo : *const WSAPROTOCOL_INFOW, g : u32, dwflags : u32) -> SOCKET); windows_targets::link!("ws2_32.dll" "system" fn WSAStartup(wversionrequested : u16, lpwsadata : *mut WSADATA) -> i32); windows_targets::link!("kernel32.dll" "system" fn WaitForMultipleObjects(ncount : u32, lphandles : *const HANDLE, bwaitall : BOOL, dwmilliseconds : u32) -> WAIT_EVENT); @@ -3598,6 +3600,35 @@ impl Default for WSAPROTOCOLCHAIN { } #[repr(C)] #[derive(Clone, Copy)] +pub struct WSAPROTOCOL_INFOA { + pub dwServiceFlags1: u32, + pub dwServiceFlags2: u32, + pub dwServiceFlags3: u32, + pub dwServiceFlags4: u32, + pub dwProviderFlags: u32, + pub ProviderId: GUID, + pub dwCatalogEntryId: u32, + pub ProtocolChain: WSAPROTOCOLCHAIN, + pub iVersion: i32, + pub iAddressFamily: i32, + pub iMaxSockAddr: i32, + pub iMinSockAddr: i32, + pub iSocketType: i32, + pub iProtocol: i32, + pub iProtocolMaxOffset: i32, + pub iNetworkByteOrder: i32, + pub iSecurityScheme: i32, + pub dwMessageSize: u32, + pub dwProviderReserved: u32, + pub szProtocol: [i8; 256], +} +impl Default for WSAPROTOCOL_INFOA { + fn default() -> Self { + unsafe { core::mem::zeroed() } + } +} +#[repr(C)] +#[derive(Clone, Copy)] pub struct WSAPROTOCOL_INFOW { pub dwServiceFlags1: u32, pub dwServiceFlags2: u32, From 7db5b5646d52e38643c194ed65ebd238e9b2254b Mon Sep 17 00:00:00 2001 From: Dennis Duda Date: Fri, 29 Nov 2024 23:02:21 +0100 Subject: [PATCH 24/58] WinSock2 fallbacks Add fallback implementations for `getaddrinfo` and `freeaddrinfo` These fall back to wship6.dll (NT4/2000) if available, or are impl'd via a translation of the header-only wspiapi.h implementations (IPv4 only, all Windows versions with WS2 support). Fall back to `gethostname` if `GetHostNameW` is not available Stub `SetHandleInformation`/`Socket::set_no_inherit` SetHandleInformation is exported by kernel32 on Win9X/ME, but is just stubbed, returning `ERROR_CALL_NOT_IMPLEMENTED`. Sockets are non-inheritable on these systems anyways, so we "fail successfully". https://www.betaarchive.com/wiki/index.php/Microsoft_KB_Archive/150523#MORE_INFORMATION SetHandleInformation is also unavailable on WinNT before 3.51. This is fine, however, because MS did not supply WinSock 2 for Windows NT before 4.0, so this function is not called. --- library/std/src/os/windows/io/socket.rs | 27 +- .../src/sys/net/connection/socket/windows.rs | 2 +- library/std/src/sys/net/hostname/windows.rs | 10 + library/std/src/sys/pal/windows/c.rs | 66 +++ .../std/src/sys/pal/windows/c/bindings.txt | 5 + .../std/src/sys/pal/windows/c/windows_sys.rs | 49 ++ library/std/src/sys/pal/windows/c/wspiapi.rs | 524 ++++++++++++++++++ 7 files changed, 681 insertions(+), 2 deletions(-) create mode 100644 library/std/src/sys/pal/windows/c/wspiapi.rs diff --git a/library/std/src/os/windows/io/socket.rs b/library/std/src/os/windows/io/socket.rs index 117b1319337f6..0e97b1de94fdc 100644 --- a/library/std/src/os/windows/io/socket.rs +++ b/library/std/src/os/windows/io/socket.rs @@ -76,7 +76,7 @@ impl OwnedSocket { // FIXME(strict_provenance_magic): we defined RawSocket to be a u64 ;-; #[allow(fuzzy_provenance_casts)] - #[cfg(not(target_vendor = "uwp"))] + #[cfg(not(any(target_vendor = "uwp", target_family = "rust9x")))] pub(crate) fn set_no_inherit(&self) -> io::Result<()> { cvt(unsafe { sys::c::SetHandleInformation( @@ -87,6 +87,31 @@ impl OwnedSocket { }) .map(drop) } + #[allow(fuzzy_provenance_casts)] + #[cfg(target_family = "rust9x")] + pub(crate) fn set_no_inherit(&self) -> io::Result<()> { + let res = cvt(unsafe { + sys::c::SetHandleInformation( + self.as_raw_socket() as sys::c::HANDLE, + sys::c::HANDLE_FLAG_INHERIT, + 0, + ) + }) + .map(drop); + + match res { + // SetHandleInformation is exported by kernel32 on Win9X/ME, but only returns + // `ERROR_CALL_NOT_IMPLEMENTED`. Sockets are non-inheritable on these systems anyways, + // so we "fail successfully" here. + // https://www.betaarchive.com/wiki/index.php/Microsoft_KB_Archive/150523#MORE_INFORMATION + + // SetHandleInformation is also unavailable on WinNT before 3.51. This is fine, + // however, because MS did not supply WinSock 2 for Windows NT before 4.0, so this + // function is not called. + Err(e) if e.raw_os_error() == Some(sys::c::ERROR_CALL_NOT_IMPLEMENTED as i32) => Ok(()), + res => res, + } + } #[cfg(target_vendor = "uwp")] pub(crate) fn set_no_inherit(&self) -> io::Result<()> { diff --git a/library/std/src/sys/net/connection/socket/windows.rs b/library/std/src/sys/net/connection/socket/windows.rs index 53fb5f9c41909..5b77d8655b88d 100644 --- a/library/std/src/sys/net/connection/socket/windows.rs +++ b/library/std/src/sys/net/connection/socket/windows.rs @@ -17,7 +17,7 @@ use crate::{cmp, mem, ptr, sys}; #[allow(non_camel_case_types)] pub type wrlen_t = i32; -pub(super) mod netc { +pub(crate) mod netc { //! BSD socket compatibility shim //! //! Some Windows API types are not quite what's expected by our cross-platform diff --git a/library/std/src/sys/net/hostname/windows.rs b/library/std/src/sys/net/hostname/windows.rs index 24eed100f32d4..0cc7ab3d7f52d 100644 --- a/library/std/src/sys/net/hostname/windows.rs +++ b/library/std/src/sys/net/hostname/windows.rs @@ -8,6 +8,16 @@ use crate::sys::pal::winsock::{self, cvt}; pub fn hostname() -> Result { winsock::startup(); + #[cfg(target_family = "rust9x")] + if c::GetHostNameW::available().is_none() { + use core::ffi::CStr; + let mut buffer = [const { MaybeUninit::::uninit() }; 256]; + cvt(unsafe { c::gethostname(buffer.as_mut_ptr().cast(), buffer.len() as i32) })?; + return unsafe { + Ok(OsString::from(CStr::from_ptr(buffer.as_ptr().cast()).to_str().unwrap())) + }; + } + // The documentation of GetHostNameW says that a buffer size of 256 is // always enough. let mut buffer = [const { MaybeUninit::::uninit() }; 256]; diff --git a/library/std/src/sys/pal/windows/c.rs b/library/std/src/sys/pal/windows/c.rs index b92d6d5d63090..99fa4a1a06294 100644 --- a/library/std/src/sys/pal/windows/c.rs +++ b/library/std/src/sys/pal/windows/c.rs @@ -12,6 +12,9 @@ use core::ptr; mod windows_sys; pub use windows_sys::*; +#[cfg(target_family = "rust9x")] +pub(crate) mod wspiapi; + pub type WCHAR = u16; pub const INVALID_HANDLE_VALUE: HANDLE = ::core::ptr::without_provenance_mut(-1i32 as _); @@ -510,3 +513,66 @@ compat_fn_with_fallback! { FALSE } } + +#[cfg(target_family = "rust9x")] +compat_fn_with_fallback! { + pub static KERNEL32: &CStr = c"kernel32" => { load: false, unicows: false }; + // >= NT 3.51+ + // https://learn.microsoft.com/en-us/windows/win32/api/handleapi/nf-handleapi-sethandleinformation + pub fn SetHandleInformation(hobject: HANDLE, dwmask: u32, dwflags: HANDLE_FLAGS) -> BOOL { + unsafe { SetLastError(ERROR_CALL_NOT_IMPLEMENTED as u32); }; + FALSE + } +} + +#[cfg(target_family = "rust9x")] +mod ws2_32 { + use super::*; + compat_fn_with_fallback! { + pub static WS2_32: &CStr = c"ws2_32" => { load: true, unicows: false }; + + // >= NT4/2000 with IPv6 Tech Preview + // https://learn.microsoft.com/en-us/windows/win32/api/ws2tcpip/nf-ws2tcpip-getaddrinfo + pub fn getaddrinfo( + pnodename: PCSTR, + pservicename: PCSTR, + phints: *const ADDRINFOA, + ppresult: *mut *mut ADDRINFOA, + ) -> i32 { + unsafe { wship6::getaddrinfo(pnodename, pservicename, phints, ppresult) } + } + // >= NT4/2000 with IPv6 Tech Preview + pub fn freeaddrinfo(paddrinfo: *const ADDRINFOA) -> () { + unsafe { wship6::freeaddrinfo(paddrinfo) } + } + pub fn GetHostNameW(name: PWSTR, namelen: i32) -> i32 { + rtabort!("unimplemented") + } + } +} +#[cfg(target_family = "rust9x")] +pub use ws2_32::{GetHostNameW, freeaddrinfo, getaddrinfo}; + +#[cfg(target_family = "rust9x")] +mod wship6 { + use super::wspiapi::{wspiapi_freeaddrinfo, wspiapi_getaddrinfo}; + use super::{ADDRINFOA, PCSTR}; + + compat_fn_with_fallback! { + pub static WSHIP6: &CStr = c"wship6" => { load: true, unicows: false }; + + // >= 2000 with IPv6 Tech Preview + pub fn getaddrinfo( + pnodename: PCSTR, + pservicename: PCSTR, + phints: *const ADDRINFOA, + ppresult: *mut *mut ADDRINFOA, + ) -> i32 { + unsafe { wspiapi_getaddrinfo(pnodename, pservicename, phints, ppresult) } + } + // >= 2000 with IPv6 Tech Preview + pub fn freeaddrinfo(paddrinfo: *const ADDRINFOA)-> () { + unsafe { wspiapi_freeaddrinfo(paddrinfo) } + } + } +} diff --git a/library/std/src/sys/pal/windows/c/bindings.txt b/library/std/src/sys/pal/windows/c/bindings.txt index c3c18f32447e5..c108b3cc1d980 100644 --- a/library/std/src/sys/pal/windows/c/bindings.txt +++ b/library/std/src/sys/pal/windows/c/bindings.txt @@ -2178,6 +2178,8 @@ GetFileType GETFINALPATHNAMEBYHANDLE_FLAGS GetFinalPathNameByHandleW GetFullPathNameW +gethostbyname +gethostname GetHostNameW GetLastError GetModuleFileNameW @@ -2187,6 +2189,7 @@ GetOverlappedResult getpeername GetProcAddress GetProcessId +getservbyname getsockname getsockopt GetStdHandle @@ -2209,6 +2212,8 @@ HMODULE IDLE_PRIORITY_CLASS IN6_ADDR IN_ADDR +inet_addr +inet_ntoa INFINITE INHERIT_CALLER_PRIORITY INHERIT_PARENT_AFFINITY diff --git a/library/std/src/sys/pal/windows/c/windows_sys.rs b/library/std/src/sys/pal/windows/c/windows_sys.rs index ed3da4939343c..dcc5a1dc513a2 100644 --- a/library/std/src/sys/pal/windows/c/windows_sys.rs +++ b/library/std/src/sys/pal/windows/c/windows_sys.rs @@ -153,9 +153,14 @@ windows_targets::link!("ws2_32.dll" "system" fn closesocket(s : SOCKET) -> i32); windows_targets::link!("ws2_32.dll" "system" fn connect(s : SOCKET, name : *const SOCKADDR, namelen : i32) -> i32); windows_targets::link!("ws2_32.dll" "system" fn freeaddrinfo(paddrinfo : *const ADDRINFOA)); windows_targets::link!("ws2_32.dll" "system" fn getaddrinfo(pnodename : PCSTR, pservicename : PCSTR, phints : *const ADDRINFOA, ppresult : *mut *mut ADDRINFOA) -> i32); +windows_targets::link!("ws2_32.dll" "system" fn gethostbyname(name : PCSTR) -> *mut HOSTENT); +windows_targets::link!("ws2_32.dll" "system" fn gethostname(name : PSTR, namelen : i32) -> i32); windows_targets::link!("ws2_32.dll" "system" fn getpeername(s : SOCKET, name : *mut SOCKADDR, namelen : *mut i32) -> i32); +windows_targets::link!("ws2_32.dll" "system" fn getservbyname(name : PCSTR, proto : PCSTR) -> *mut SERVENT); windows_targets::link!("ws2_32.dll" "system" fn getsockname(s : SOCKET, name : *mut SOCKADDR, namelen : *mut i32) -> i32); windows_targets::link!("ws2_32.dll" "system" fn getsockopt(s : SOCKET, level : i32, optname : i32, optval : PSTR, optlen : *mut i32) -> i32); +windows_targets::link!("ws2_32.dll" "system" fn inet_addr(cp : PCSTR) -> u32); +windows_targets::link!("ws2_32.dll" "system" fn inet_ntoa(r#in : IN_ADDR) -> PSTR); windows_targets::link!("ws2_32.dll" "system" fn ioctlsocket(s : SOCKET, cmd : i32, argp : *mut u32) -> i32); windows_targets::link!("ws2_32.dll" "system" fn listen(s : SOCKET, backlog : i32) -> i32); windows_targets::link!("kernel32.dll" "system" fn lstrlenW(lpstring : PCWSTR) -> i32); @@ -2794,6 +2799,20 @@ pub const HIGH_PRIORITY_CLASS: PROCESS_CREATION_FLAGS = 128u32; pub type HINSTANCE = *mut core::ffi::c_void; pub type HLOCAL = *mut core::ffi::c_void; pub type HMODULE = *mut core::ffi::c_void; +#[repr(C)] +#[derive(Clone, Copy)] +pub struct HOSTENT { + pub h_name: PSTR, + pub h_aliases: *mut *mut i8, + pub h_addrtype: i16, + pub h_length: i16, + pub h_addr_list: *mut *mut i8, +} +impl Default for HOSTENT { + fn default() -> Self { + unsafe { core::mem::zeroed() } + } +} pub type HRESULT = i32; pub const IDLE_PRIORITY_CLASS: PROCESS_CREATION_FLAGS = 64u32; #[repr(C)] @@ -3214,6 +3233,36 @@ pub struct SECURITY_QUALITY_OF_SERVICE { pub const SECURITY_SQOS_PRESENT: FILE_FLAGS_AND_ATTRIBUTES = 1048576u32; pub const SECURITY_VALID_SQOS_FLAGS: FILE_FLAGS_AND_ATTRIBUTES = 2031616u32; pub type SEND_RECV_FLAGS = i32; +#[repr(C)] +#[cfg(target_arch = "x86")] +#[derive(Clone, Copy)] +pub struct SERVENT { + pub s_name: PSTR, + pub s_aliases: *mut *mut i8, + pub s_port: i16, + pub s_proto: PSTR, +} +#[cfg(target_arch = "x86")] +impl Default for SERVENT { + fn default() -> Self { + unsafe { core::mem::zeroed() } + } +} +#[repr(C)] +#[cfg(any(target_arch = "aarch64", target_arch = "arm64ec", target_arch = "x86_64"))] +#[derive(Clone, Copy)] +pub struct SERVENT { + pub s_name: PSTR, + pub s_aliases: *mut *mut i8, + pub s_proto: PSTR, + pub s_port: i16, +} +#[cfg(any(target_arch = "aarch64", target_arch = "arm64ec", target_arch = "x86_64"))] +impl Default for SERVENT { + fn default() -> Self { + unsafe { core::mem::zeroed() } + } +} pub type SET_FILE_POINTER_MOVE_METHOD = u32; #[repr(C)] #[derive(Clone, Copy)] diff --git a/library/std/src/sys/pal/windows/c/wspiapi.rs b/library/std/src/sys/pal/windows/c/wspiapi.rs new file mode 100644 index 0000000000000..fcd743e81914c --- /dev/null +++ b/library/std/src/sys/pal/windows/c/wspiapi.rs @@ -0,0 +1,524 @@ +//! WSPiApi.h getaddr/freeaddrinfo shim converted to rust + +use crate::ffi::{CStr, c_int, c_ulong}; +use crate::ptr; +use crate::sys::c::{ + ADDRESS_FAMILY, ADDRINFOA, AF_INET, PCSTR, PSTR, SOCK_DGRAM, SOCK_STREAM, WSAGetLastError, +}; +use crate::sys::net::netc::{in_addr, sockaddr_in}; + +const WSABASEERR: c_int = 10000; +const WSAHOST_NOT_FOUND: c_int = WSABASEERR + 1001; +const WSATRY_AGAIN: c_int = WSABASEERR + 1002; +const WSANO_RECOVERY: c_int = WSABASEERR + 1003; +const WSANO_DATA: c_int = WSABASEERR + 1004; + +const EAI_NONAME: c_int = WSAHOST_NOT_FOUND; + +// https://lists.freebsd.org/pipermail/freebsd-ports/2003-October/005757.html +const EAI_NODATA: c_int = EAI_NONAME; +const EAI_AGAIN: c_int = WSATRY_AGAIN; +const EAI_FAIL: c_int = WSANO_RECOVERY; +const EAI_BADFLAGS: c_int = 10022; +const EAI_FAMILY: c_int = 10047; +const EAI_SOCKTYPE: c_int = 10044; +const EAI_SERVICE: c_int = 10109; + +const WSA_NOT_ENOUGH_MEMORY: c_int = 8; +const EAI_MEMORY: c_int = WSA_NOT_ENOUGH_MEMORY; + +const AI_PASSIVE: i32 = 0x00000001; +const AI_CANONNAME: i32 = 0x00000002; +const AI_NUMERICHOST: i32 = 0x00000004; + +const PF_UNSPEC: i32 = 0; +const PF_INET: i32 = 2; + +const SOCK_RAW: i32 = 3; + +const INADDR_ANY: u32 = 0x00000000; +const INADDR_LOOPBACK: u32 = 0x7f000001; + +const NI_MAXHOST: usize = 1025; + +pub unsafe fn wspiapi_freeaddrinfo(head: *const ADDRINFOA) { + let mut head = head as *mut ADDRINFOA; + let mut next_ptr = head; + + unsafe { + while !next_ptr.is_null() { + // scope to make sure the `next` borrow is dropped before freeeing the `ADDRINFOA` it + // references + { + let next = &*next_ptr; + if !next.ai_canonname.is_null() { + drop(crate::ffi::CString::from_raw(next.ai_canonname.cast())); + } + + if !next.ai_addr.is_null() { + drop(Box::::from_raw(next.ai_addr as *mut _)); + } + + head = next.ai_next; + } + + drop(Box::::from_raw(next_ptr)); + next_ptr = head; + } + } +} + +/// Protocol-independent name-to-address translation. +/// +/// As specified in RFC 2553, Section 6.4. +/// This is the hacked version that only supports IPv4. +/// +/// Arguments +/// - node node name to lookup. +/// - service service name to lookup. +/// - hints hints about how to process request. +/// - res where to return result. +/// +/// Return Value +/// - returns zero if successful, an EAI_* error code if not. +pub unsafe fn wspiapi_getaddrinfo( + node: PCSTR, + service: PCSTR, + hints: *const ADDRINFOA, + res: *mut *mut ADDRINFOA, +) -> c_int { + unsafe { + // initialize res with default return value. + *res = ptr::null_mut(); + + // the node name and the service name can't both be NULL. + if node.is_null() && service.is_null() { + return EAI_NONAME; + } + + let mut flags: i32 = 0; + let mut socket_type: i32 = 0; + let mut protocol: i32 = 0; + + // validate hints. + if let Some(hints) = ptr::NonNull::::new(hints as *mut _) { + let hints = hints.as_ref(); + + // all members other than ai_flags, ai_family, ai_socktype + // and ai_protocol must be zero or a null pointer. + if hints.ai_addrlen != 0 + || !hints.ai_canonname.is_null() + || !hints.ai_addr.is_null() + || !hints.ai_next.is_null() + { + return EAI_FAIL; + } + + // the spec has the "bad flags" error code, so presumably we + // should check something here. insisting that there aren't + // any unspecified flags set would break forward compatibility, + // however. so we just check for non-sensical combinations. + // + // we cannot come up with a canonical name given a null node name. + flags = hints.ai_flags; + if flags & AI_CANONNAME != 0 && node.is_null() { + return EAI_BADFLAGS; + } + + // we only support a limited number of protocol families. + if !matches!(hints.ai_family, PF_UNSPEC | PF_INET) { + return EAI_FAMILY; + } + + // we only support only these socket types. + socket_type = hints.ai_socktype; + if !matches!(socket_type, 0 | SOCK_STREAM | SOCK_DGRAM | SOCK_RAW) { + return EAI_SOCKTYPE; + } + + // REVIEW: What if ai_socktype and ai_protocol are at odds? + protocol = hints.ai_protocol; + } + + let mut port: u16 = 0; + let mut udp_port: u16 = 0; + let mut clone: bool = false; + + // do service lookup + if !service.is_null() { + if let Some(raw_port) = + CStr::from_ptr(service.cast()).to_str().ok().and_then(|s| s.parse::().ok()) + { + // numeric port string + + port = (raw_port as u16).to_be(); + udp_port = port; + + if socket_type == 0 { + clone = true; + socket_type = SOCK_STREAM; + } + } else { + let mut tcp_port: u16 = 0; + + // non numeric port string + + if socket_type == 0 || socket_type == SOCK_DGRAM { + let servent = getservbyname(service, c"udp".as_ptr().cast()); + if !servent.is_null() { + port = (*servent).s_port; + udp_port = port; + } + } + + if socket_type == 0 || socket_type == SOCK_STREAM { + let servent = getservbyname(service, c"tcp".as_ptr().cast()); + if !servent.is_null() { + port = (*servent).s_port; + tcp_port = port; + } + } + + // assumes 0 is an invalid service port... + if port == 0 { + // no service exists + return if socket_type != 0 { EAI_SERVICE } else { EAI_NONAME }; + } + + if socket_type == 0 { + // if both tcp and udp, process tcp now & clone udp later. + socket_type = if tcp_port != 0 { SOCK_STREAM } else { SOCK_DGRAM }; + clone = tcp_port != 0 && udp_port != 0; + } + } + } + + // do node name lookup + + // if we weren't given a node name, + // return the wildcard or loopback address (depending on AI_PASSIVE). + // + // if we have a numeric host address string, + // return the binary address. + // + + let address: Option = if node.is_null() { + Some((if flags & AI_PASSIVE != 0 { INADDR_ANY } else { INADDR_LOOPBACK }).to_be()) + } else { + wspiapi_parse_v4_address(CStr::from_ptr(node.cast())) + }; + + let mut error: i32 = 0; + + if let Some(address) = address { + // create an addrinfo structure... + *res = wspiapi_new_addr_info(socket_type, protocol, port, address); + + if error != 0 && !node.is_null() { + // implementation specific behavior: set AI_NUMERICHOST + // to indicate that we got a numeric host address string. + (**res).ai_flags |= AI_NUMERICHOST; + + // return the numeric address string as the canonical name + if flags & AI_CANONNAME != 0 { + (**res).ai_canonname = wspiapi_strdup(inet_ntoa(in_addr { s_addr: address })); + + if (**res).ai_canonname.is_null() { + error = EAI_MEMORY; + } + } + } + } else if flags & AI_NUMERICHOST != 0 { + // if we do not have a numeric host address string and + // AI_NUMERICHOST flag is set, return an error! + error = EAI_NONAME; + } else { + // since we have a non-numeric node name, + // we have to do a regular node name lookup. + error = wspiapi_lookup_node( + CStr::from_ptr(node.cast()), + socket_type, + protocol, + port, + flags & AI_CANONNAME != 0, + res, + ); + } + + if error == 0 && clone { + error = wspiapi_clone(udp_port, *res); + } + + if error != 0 { + wspiapi_freeaddrinfo(*res); + *res = ptr::null_mut(); + } + + return error; + } +} + +unsafe fn wspiapi_clone(udp_port: u16, res: *mut ADDRINFOA) -> i32 { + let mut next_ptr = res; + + unsafe { + while !next_ptr.is_null() { + let next = &mut *next_ptr; + + // create an addrinfo structure... + let new_ptr = wspiapi_new_addr_info( + SOCK_DGRAM, + next.ai_protocol, + udp_port, + (*(next.ai_addr as *mut sockaddr_in)).sin_addr.s_addr, + ); + let new = &mut *new_ptr; + + // link the cloned addrinfo + new.ai_next = next.ai_next; + next.ai_next = new_ptr; + next_ptr = new.ai_next; + } + } + + 0 +} + +/// Resolve a nodename and return a list of addrinfo structures. +/// IPv4 specific internal function, not exported. +/// +/// *res would need to be freed if an error is returned. +/// +/// NOTE: if `ai_canonname` is true, the canonical name should be +/// returned in the first addrinfo structure. +/// +/// Arguments +/// - node name of node to resolve. +/// - socket_type SOCK_*. can be wildcarded (zero). +/// - protocol IPPROTO_*. can be wildcarded (zero). +/// - port port number of service (in network order). +/// - ai_canonname whether the AI_CANONNAME flag is set. +/// - res where to return result. +/// +/// Return Value +/// - Returns 0 on success, an EAI_* style error value otherwise. +unsafe fn wspiapi_lookup_node( + node: &CStr, + socket_type: i32, + protocol: i32, + port: u16, + ai_canonname: bool, + res: *mut *mut ADDRINFOA, +) -> i32 { + let mut error: i32; + let mut alias_count = 0; + + let mut name = [0u8; NI_MAXHOST]; + wspiapi_strcpy_ni_maxhost(&mut name, node.to_bytes()); + + let mut alias = [0u8; NI_MAXHOST]; + + let mut name_ref = &mut name; + let mut alias_ref = &mut alias; + + unsafe { + loop { + error = wspiapi_query_dns(node, socket_type, protocol, port, alias_ref, res); + + if error != 0 { + break; + } + + // if we found addresses, then we are done. + if !(*res).is_null() { + break; + } + + if alias_ref[0] == b'\0' + || CStr::from_ptr(name_ref.as_ptr() as *const _) + == CStr::from_ptr(alias_ref.as_ptr() as *const _) + || { + alias_count += 1; + alias_count + } == 16 + { + error = EAI_FAIL; + break; + } + + crate::mem::swap(&mut name_ref, &mut alias_ref); + } + + if error == 0 && ai_canonname { + (**res).ai_canonname = wspiapi_strdup(alias_ref.as_ptr()); + } + } + + error +} + +fn wspiapi_strcpy_ni_maxhost(dest: &mut [u8; NI_MAXHOST], source_without_nul: &[u8]) { + let len = source_without_nul.len().min(NI_MAXHOST - 1); + dest[0..len].copy_from_slice(&source_without_nul[0..len]); + dest[len] = b'\0'; +} + +unsafe fn wspiapi_query_dns( + node: &CStr, + socket_type: i32, + protocol: i32, + port: u16, + alias_ref: &mut [u8; NI_MAXHOST], + res: *mut *mut ADDRINFOA, +) -> i32 { + unsafe { + let mut next = res; + + alias_ref[0] = b'\0'; + + let host = gethostbyname(node.as_ptr().cast()); + if let Some(host) = ptr::NonNull::::new(host as *mut _) { + let host = host.as_ref(); + + if host.h_addrtype == AF_INET as i16 + && host.h_length == crate::mem::size_of::() as i16 + { + let mut addresses = host.h_addr_list; + + while !(*addresses).is_null() { + *next = wspiapi_new_addr_info( + socket_type, + protocol, + port, + (*((*addresses) as *const in_addr)).s_addr, + ); + + next = ptr::addr_of_mut!((**next).ai_next); + + addresses = addresses.add(1); + } + } + + wspiapi_strcpy_ni_maxhost(alias_ref, CStr::from_ptr(host.h_name.cast()).to_bytes()); + + return 0; + } + + match WSAGetLastError() { + WSAHOST_NOT_FOUND => EAI_NONAME, + WSATRY_AGAIN => EAI_AGAIN, + WSANO_RECOVERY => EAI_FAIL, + WSANO_DATA => EAI_NODATA, + _ => EAI_NONAME, + } + } +} + +unsafe fn wspiapi_new_addr_info( + socket_type: i32, + protocol: i32, + port: u16, + address: u32, +) -> *mut ADDRINFOA { + let sockaddr = Box::new(sockaddr_in { + sin_family: AF_INET as ADDRESS_FAMILY, + sin_port: port, + sin_addr: in_addr { s_addr: address }, + sin_zero: [0; 8], + }); + + let new = Box::new(ADDRINFOA { + ai_family: PF_INET, + ai_socktype: socket_type, + ai_protocol: protocol, + ai_addrlen: crate::mem::size_of::(), + ai_addr: Box::into_raw(sockaddr) as *mut _, + ai_canonname: ptr::null_mut(), + ai_flags: 0, + ai_next: ptr::null_mut(), + }); + + Box::into_raw(new) +} + +/// Get the IPv4 address (in network byte order) from its string representation. +/// The syntax should be `a.b.c.d`. +/// +/// Arguments +/// - pszArgument string representation of the IPv4 address +/// - ptAddress pointer to the resulting IPv4 address +/// +/// Return Value +/// - Returns FALSE if there is an error, TRUE for success. +fn wspiapi_parse_v4_address(address: &CStr) -> Option { + // ensure there are 3 '.' (periods) + if address.to_bytes().iter().filter(|&&c| c == b'.').count() != 3 { + return None; + } + + // return an error if dwAddress is INADDR_NONE (255.255.255.255) + // since this is never a valid argument to getaddrinfo. + let addr: u32 = unsafe { inet_addr(address.as_ptr().cast()) }; + + const INADDR_NONE: u32 = 0xffffffff; + if addr == INADDR_NONE { + return None; + } + + return Some(addr); +} + +unsafe fn wspiapi_strdup(string: PCSTR) -> PSTR { + if string.is_null() { + ptr::null_mut() + } else { + unsafe { CStr::from_ptr(string.cast()).to_owned().into_raw().cast() } + } +} + +// from Winsock2.h +#[repr(C)] +pub struct servent { + s_name: *mut PSTR, + s_aliases: *mut *mut i8, + #[cfg(target_pointer_width = "32")] + s_port: u16, + #[cfg(target_pointer_width = "32")] + s_proto: *mut PSTR, + #[cfg(target_pointer_width = "64")] + s_proto: *mut PSTR, + #[cfg(target_pointer_width = "64")] + s_port: u16, +} + +#[repr(C)] +pub struct hostent { + pub h_name: PSTR, + pub h_aliases: *mut *mut i8, + pub h_addrtype: i16, + pub h_length: i16, + pub h_addr_list: *mut *mut i8, +} + +compat_fn_with_fallback! { + // load is not needed, we already need ws2_32 to get here + pub static WS2_32: &CStr = c"ws2_32" => { load: false, unicows: false }; + + /// The pointer that is returned points to the SERVENT structure allocated by the + /// Windows Sockets library. The application must never attempt to modify this + /// structure or to free any of its components. Furthermore only one copy of this + /// structure is allocated per thread, so the application should copy any information + /// it needs before issuing any other Windows Sockets function calls. + pub fn getservbyname(name: PCSTR, proto: PCSTR) -> *const servent { unimplemented!(); } + /// The `gethostbyname` function returns a pointer to a hostent structure—a structure allocated + /// by Windows Sockets. The hostent structure contains the results of a successful search for + /// the host specified in the name parameter. + /// + /// The application must never attempt to modify this structure or to free any of its + /// components. Furthermore, only one copy of this structure is allocated per thread, so the + /// application should copy any information it needs before issuing any other Windows Sockets + /// function calls. + pub fn gethostbyname(name: PCSTR) -> *const hostent { unimplemented!(); } + pub fn inet_addr(cp: PCSTR) -> u32 { unimplemented!(); } + pub fn inet_ntoa(r#in: in_addr) -> PSTR { unimplemented!(); } +} From e2168b51968c869aed90a2226a04f7cd81d6a5b7 Mon Sep 17 00:00:00 2001 From: Dennis Duda Date: Fri, 29 Nov 2024 23:37:27 +0100 Subject: [PATCH 25/58] Ignore `proc_thread_attributes` if the system doesn't support it --- library/std/src/sys/pal/windows/c.rs | 31 ++++++++++++++++++++++++++ library/std/src/sys/process/windows.rs | 12 +++++++++- 2 files changed, 42 insertions(+), 1 deletion(-) diff --git a/library/std/src/sys/pal/windows/c.rs b/library/std/src/sys/pal/windows/c.rs index 99fa4a1a06294..c93b13956a389 100644 --- a/library/std/src/sys/pal/windows/c.rs +++ b/library/std/src/sys/pal/windows/c.rs @@ -576,3 +576,34 @@ mod wship6 { } } } + +#[cfg(target_family = "rust9x")] +compat_fn_with_fallback! { + pub static KERNEL32: &CStr = c"kernel32" => { load: false, unicows: false }; + // >= Vista / Server 2008 + // https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-initializeprocthreadattributelist + pub fn InitializeProcThreadAttributeList( + lpattributelist: LPPROC_THREAD_ATTRIBUTE_LIST, + dwattributecount: u32, + dwflags: u32, + lpsize: *mut usize + ) -> BOOL { + rtabort!("unimplemented") + } + // >= Vista / Server 2008 + pub fn UpdateProcThreadAttribute( + lpattributelist: LPPROC_THREAD_ATTRIBUTE_LIST, + dwflags: u32, + attribute: usize, + lpvalue: *const core::ffi::c_void, + cbsize: usize, + lppreviousvalue: *mut core::ffi::c_void, + lpreturnsize: *const usize + ) -> BOOL { + rtabort!("unimplemented") + } + // >= Vista / Server 2008 + pub fn DeleteProcThreadAttributeList(lpattributelist: LPPROC_THREAD_ATTRIBUTE_LIST) { + rtabort!("unimplemented") + } +} diff --git a/library/std/src/sys/process/windows.rs b/library/std/src/sys/process/windows.rs index b21b01d6694b3..692805d8ad554 100644 --- a/library/std/src/sys/process/windows.rs +++ b/library/std/src/sys/process/windows.rs @@ -389,7 +389,17 @@ impl Command { let mut si_ex; - if let Some(proc_thread_attribute_list) = proc_thread_attribute_list { + #[allow(unused)] + let mut proc_thread_addributes_supported = true; + #[cfg(target_family = "rust9x")] + { + proc_thread_addributes_supported = + c::InitializeProcThreadAttributeList::available().is_some(); + } + + if let Some(proc_thread_attribute_list) = proc_thread_attribute_list + && proc_thread_addributes_supported + { si.cb = size_of::() as u32; flags |= c::EXTENDED_STARTUPINFO_PRESENT; From 59af8c69c5db50a4b824f70d698cecd1cf0d65bf Mon Sep 17 00:00:00 2001 From: Dennis Duda Date: Fri, 29 Nov 2024 23:39:21 +0100 Subject: [PATCH 26/58] Stub `FreeEnvironmentStringsW` to just leak on NT 3.1 Yup, this function just doesn't exist on NT 3.1, so `env::vars`/`env::vars_os` will just leak the OS-allocated buffer. --- library/std/src/sys/pal/windows/c.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/library/std/src/sys/pal/windows/c.rs b/library/std/src/sys/pal/windows/c.rs index c93b13956a389..7bdc827796453 100644 --- a/library/std/src/sys/pal/windows/c.rs +++ b/library/std/src/sys/pal/windows/c.rs @@ -607,3 +607,14 @@ compat_fn_with_fallback! { rtabort!("unimplemented") } } + +#[cfg(target_family = "rust9x")] +compat_fn_with_fallback! { + pub static KERNEL32: &CStr = c"kernel32" => { load: false, unicows: true }; + // >= NT 3.5+, 95+ + // https://learn.microsoft.com/en-us/windows/win32/api/processenv/nf-processenv-freeenvironmentstringsw + pub fn FreeEnvironmentStringsW(penv: PCWSTR) -> BOOL { + // just leak it on NT 3.1 + TRUE + } +} From 30099552962aa57c2b096ceca0ea4cc1177804c3 Mon Sep 17 00:00:00 2001 From: Dennis Duda Date: Fri, 29 Nov 2024 23:45:20 +0100 Subject: [PATCH 27/58] Remove dependency on `GetModuleHandleW` and `CreateEventW` Just use the `A` variants instead (already imported anyways) --- library/std/src/sys/fs/windows.rs | 2 +- library/std/src/sys/pal/windows/handle.rs | 2 +- library/std/src/sys/pal/windows/os.rs | 7 +------ 3 files changed, 3 insertions(+), 8 deletions(-) diff --git a/library/std/src/sys/fs/windows.rs b/library/std/src/sys/fs/windows.rs index ef98a8d08f559..d85ab91f78efd 100644 --- a/library/std/src/sys/fs/windows.rs +++ b/library/std/src/sys/fs/windows.rs @@ -375,7 +375,7 @@ impl File { fn acquire_lock(&self, flags: c::LOCK_FILE_FLAGS) -> io::Result<()> { unsafe { let mut overlapped: c::OVERLAPPED = mem::zeroed(); - let event = c::CreateEventW(ptr::null_mut(), c::FALSE, c::FALSE, ptr::null()); + let event = c::CreateEventA(ptr::null_mut(), c::FALSE, c::FALSE, ptr::null()); if event.is_null() { return Err(io::Error::last_os_error()); } diff --git a/library/std/src/sys/pal/windows/handle.rs b/library/std/src/sys/pal/windows/handle.rs index 76c8aa939d3b2..7e2c2767d6022 100644 --- a/library/std/src/sys/pal/windows/handle.rs +++ b/library/std/src/sys/pal/windows/handle.rs @@ -23,7 +23,7 @@ impl Handle { pub fn new_event(manual: bool, init: bool) -> io::Result { unsafe { let event = - c::CreateEventW(ptr::null_mut(), manual as c::BOOL, init as c::BOOL, ptr::null()); + c::CreateEventA(ptr::null_mut(), manual as c::BOOL, init as c::BOOL, ptr::null()); if event.is_null() { Err(io::Error::last_os_error()) } else { diff --git a/library/std/src/sys/pal/windows/os.rs b/library/std/src/sys/pal/windows/os.rs index acb36431452a6..4ad8e19d8c01a 100644 --- a/library/std/src/sys/pal/windows/os.rs +++ b/library/std/src/sys/pal/windows/os.rs @@ -31,12 +31,7 @@ pub fn error_string(mut errnum: i32) -> String { // GetLastError. For more information about Windows error codes, see // `[MS-ERREF]`: https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-erref/0642cb2f-2075-4469-918c-4441e69c548a if (errnum & c::FACILITY_NT_BIT as i32) != 0 { - // format according to https://support.microsoft.com/en-us/help/259693 - const NTDLL_DLL: &[u16] = &[ - 'N' as _, 'T' as _, 'D' as _, 'L' as _, 'L' as _, '.' as _, 'D' as _, 'L' as _, - 'L' as _, 0, - ]; - module = c::GetModuleHandleW(NTDLL_DLL.as_ptr()); + module = c::GetModuleHandleA(c"NTDLL.DLL".as_ptr().cast()); if !module.is_null() { errnum ^= c::FACILITY_NT_BIT as i32; From f616723d8f8f3678451bbfc2e9e9c99aac1f9d54 Mon Sep 17 00:00:00 2001 From: Dennis Duda Date: Fri, 29 Nov 2024 23:56:14 +0100 Subject: [PATCH 28/58] Fall back to old (broken) env arg behavior if `CompareStringOrdinal` is not available See https://github.com/rust-lang/rust/pull/85270 and https://github.com/rust-lang/rust/pull/87863 --- library/std/src/sys/pal/windows/c.rs | 16 ++++++++++++++++ library/std/src/sys/process/windows.rs | 16 ++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/library/std/src/sys/pal/windows/c.rs b/library/std/src/sys/pal/windows/c.rs index 7bdc827796453..4f727a9ff9bcb 100644 --- a/library/std/src/sys/pal/windows/c.rs +++ b/library/std/src/sys/pal/windows/c.rs @@ -618,3 +618,19 @@ compat_fn_with_fallback! { TRUE } } + +#[cfg(target_family = "rust9x")] +compat_fn_with_fallback! { + pub static KERNEL32: &CStr = c"kernel32" => { load: false, unicows: false }; + // >= Vista / Server 2008 + // https://learn.microsoft.com/en-us/windows/win32/api/stringapiset/nf-stringapiset-comparestringordinal + pub fn CompareStringOrdinal( + lpstring1: PCWSTR, + cchcount1: i32, + lpstring2: PCWSTR, + cchcount2: i32, + bignorecase: BOOL, + ) -> COMPARESTRING_RESULT { + rtabort!("unimplemented") + } +} diff --git a/library/std/src/sys/process/windows.rs b/library/std/src/sys/process/windows.rs index 692805d8ad554..641ac20ce39cc 100644 --- a/library/std/src/sys/process/windows.rs +++ b/library/std/src/sys/process/windows.rs @@ -71,6 +71,13 @@ impl EnvKey { // [4] https://docs.microsoft.com/en-us/windows/win32/api/stringapiset/nf-stringapiset-comparestringordinal impl Ord for EnvKey { fn cmp(&self, other: &Self) -> cmp::Ordering { + #[cfg(target_family = "rust9x")] + { + if c::CompareStringOrdinal::available().is_none() { + return self.os_string.cmp(&other.os_string); + } + } + unsafe { let result = c::CompareStringOrdinal( self.utf16.as_ptr(), @@ -122,6 +129,15 @@ impl PartialEq for EnvKey { // they are compared using a caseless string mapping. impl From for EnvKey { fn from(k: OsString) -> Self { + #[cfg(target_family = "rust9x")] + { + if c::CompareStringOrdinal::available().is_none() { + let mut k = k; + k.make_ascii_uppercase(); + return EnvKey { utf16: Vec::new(), os_string: k }; + } + } + EnvKey { utf16: k.encode_wide().collect(), os_string: k } } } From 5b7bb531783b72c445662e17c117df19bda35497 Mon Sep 17 00:00:00 2001 From: Dennis Duda Date: Sat, 30 Nov 2024 15:46:23 +0100 Subject: [PATCH 29/58] Only use `WC_ERR_INVALID_CHARS` on NT, fall back to `0` flags on incompatible versions of Windows Fixes #18 --- library/std/src/sys/stdio/windows.rs | 35 ++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/library/std/src/sys/stdio/windows.rs b/library/std/src/sys/stdio/windows.rs index 62ec115d7b0cb..8dc092d0fe584 100644 --- a/library/std/src/sys/stdio/windows.rs +++ b/library/std/src/sys/stdio/windows.rs @@ -400,6 +400,10 @@ fn utf16_to_utf8(utf16: &[u16], utf8: &mut [u8]) -> io::Result { return Ok(0); } + #[cfg(target_family = "rust9x")] + let is_nt = crate::sys::compat::checks::is_windows_nt(); + + #[cfg(not(target_family = "rust9x"))] let result = unsafe { c::WideCharToMultiByte( c::CP_UTF8, // CodePage @@ -412,6 +416,37 @@ fn utf16_to_utf8(utf16: &[u16], utf8: &mut [u8]) -> io::Result { ptr::null_mut(), // lpUsedDefaultChar ) }; + #[cfg(target_family = "rust9x")] + let result = { + let mut result = unsafe { + c::WideCharToMultiByte( + c::CP_UTF8, // CodePage + if is_nt { c::WC_ERR_INVALID_CHARS } else { 0 }, // dwFlags + utf16.as_ptr(), // lpWideCharStr + utf16.len() as i32, // cchWideChar + utf8.as_mut_ptr(), // lpMultiByteStr + utf8.len() as i32, // cbMultiByte + ptr::null(), // lpDefaultChar + ptr::null_mut(), // lpUsedDefaultChar + ) + }; + + if result == 0 && unsafe { c::GetLastError() } == c::ERROR_INVALID_FLAGS && is_nt { + result = unsafe { + c::WideCharToMultiByte( + c::CP_UTF8, // CodePage + 0, // dwFlags (0 for pre-Vista compatibility) + utf16.as_ptr(), // lpWideCharStr + utf16.len() as i32, // cchWideChar + utf8.as_mut_ptr(), // lpMultiByteStr + utf8.len() as i32, // cbMultiByte + ptr::null(), // lpDefaultChar + ptr::null_mut(), // lpUsedDefaultChar + ) + }; + } + result + }; if result == 0 { // We can't really do any better than forget all data and return an error. Err(io::const_error!( From f3551dbf25d6ebd5b10268e07708e2b66c3fec2a Mon Sep 17 00:00:00 2001 From: Dennis Duda Date: Sat, 30 Nov 2024 20:28:20 +0100 Subject: [PATCH 30/58] Add fallback for IO internals (pipe, handle): - Add two fallback implementations in stdio redirection: - Add fallback when 'modern' anonymous pipe creation with async io is not available (pre-Vista) - Add fallback for when named pipes are not available (9x/ME, NT before 4.0) Since Windows 9X/ME does not support creating named pipes (only connecting to remote pipes created on NT), we'll have to make do with anonymous pipes, without overlapped I/O. In particular, this means that we'll have to spawn another thread in the case where both stdout and stderr are being piped and read from (`read2`). We also use the fallback implementation on NT before 4.0, as the `Drop` impl of `AsyncPipe` needs to be able to cancel I/O via `CancelIo`. - Add fallbacks for `NtReadFile` and `NtWriteFile` in `synchronous_{read, write}` These might be unsound for handles that _can_ be asynchronous on 9x/ME. See https://github.com/rust-lang/rust/pull/95469 for more info --- library/std/src/sys/fs/windows.rs | 2 +- library/std/src/sys/pal/windows/c.rs | 115 +++++++++++-- .../std/src/sys/pal/windows/c/bindings.txt | 1 + .../std/src/sys/pal/windows/c/windows_sys.rs | 1 + .../std/src/sys/pal/windows/compat/checks.rs | 28 ++- library/std/src/sys/pal/windows/handle.rs | 52 ++++++ library/std/src/sys/pal/windows/pipe.rs | 160 ++++++++++++++++++ 7 files changed, 340 insertions(+), 19 deletions(-) diff --git a/library/std/src/sys/fs/windows.rs b/library/std/src/sys/fs/windows.rs index d85ab91f78efd..daee26b86e366 100644 --- a/library/std/src/sys/fs/windows.rs +++ b/library/std/src/sys/fs/windows.rs @@ -323,7 +323,7 @@ impl File { Self::open_native(&path, opts) } - fn open_native(path: &WCStr, opts: &OpenOptions) -> io::Result { + pub(crate) fn open_native(path: &WCStr, opts: &OpenOptions) -> io::Result { let creation = opts.get_creation_mode()?; let sa = c::SECURITY_ATTRIBUTES { nLength: size_of::() as u32, diff --git a/library/std/src/sys/pal/windows/c.rs b/library/std/src/sys/pal/windows/c.rs index 4f727a9ff9bcb..167c8af2b1650 100644 --- a/library/std/src/sys/pal/windows/c.rs +++ b/library/std/src/sys/pal/windows/c.rs @@ -113,22 +113,50 @@ unsafe extern "system" { pub fn ProcessPrng(pbdata: *mut u8, cbdata: usize) -> BOOL; } -windows_targets::link!("ntdll.dll" "system" fn NtCreateNamedPipeFile( - filehandle: *mut HANDLE, - desiredaccess: FILE_ACCESS_RIGHTS, - objectattributes: *const OBJECT_ATTRIBUTES, - iostatusblock: *mut IO_STATUS_BLOCK, - shareaccess: FILE_SHARE_MODE, - createdisposition: NTCREATEFILE_CREATE_DISPOSITION, - createoptions: NTCREATEFILE_CREATE_OPTIONS, - namedpipetype: u32, - readmode: u32, - completionmode: u32, - maximuminstances: u32, - inboundquota: u32, - outboundquota: u32, - defaulttimeout: *const u64, -) -> NTSTATUS); +cfg_select! { + target_family = "rust9x" => { + compat_fn_with_fallback! { + pub static NTDLL: &CStr = c"ntdll" => { load: false, unicows: false }; + // NT only (duh) + pub fn NtCreateNamedPipeFile( + filehandle: *mut HANDLE, + desiredaccess: FILE_ACCESS_RIGHTS, + objectattributes: *const OBJECT_ATTRIBUTES, + iostatusblock: *mut IO_STATUS_BLOCK, + shareaccess: FILE_SHARE_MODE, + createdisposition: NTCREATEFILE_CREATE_DISPOSITION, + createoptions: NTCREATEFILE_CREATE_OPTIONS, + namedpipetype: u32, + readmode: u32, + completionmode: u32, + maximuminstances: u32, + inboundquota: u32, + outboundquota: u32, + defaulttimeout: *const u64, + ) -> NTSTATUS { + rtabort!("unimplemented") + } + } + } + _ => { + windows_targets::link!("ntdll.dll" "system" fn NtCreateNamedPipeFile( + filehandle: *mut HANDLE, + desiredaccess: FILE_ACCESS_RIGHTS, + objectattributes: *const OBJECT_ATTRIBUTES, + iostatusblock: *mut IO_STATUS_BLOCK, + shareaccess: FILE_SHARE_MODE, + createdisposition: NTCREATEFILE_CREATE_DISPOSITION, + createoptions: NTCREATEFILE_CREATE_OPTIONS, + namedpipetype: u32, + readmode: u32, + completionmode: u32, + maximuminstances: u32, + inboundquota: u32, + outboundquota: u32, + defaulttimeout: *const u64, + ) -> NTSTATUS); + } +} // Functions that aren't available on every version of Windows that we support, // but we still use them and just provide some form of a fallback implementation. @@ -259,6 +287,51 @@ cfg_select! { windows_targets::link_raw_dylib!("ntdll.dll" "system" fn NtWriteFile(filehandle : HANDLE, event : HANDLE, apcroutine : PIO_APC_ROUTINE, apccontext : *const core::ffi::c_void, iostatusblock : *mut IO_STATUS_BLOCK, buffer : *const core::ffi::c_void, length : u32, byteoffset : *const i64, key : *const u32) -> NTSTATUS); windows_targets::link_raw_dylib!("ntdll.dll" "system" fn RtlNtStatusToDosError(status : NTSTATUS) -> u32); } + target_family = "rust9x" => { + compat_fn_with_fallback! { + pub static NTDLL: &CStr = c"ntdll" => { load: false, unicows: false }; + + pub fn NtReadFile( + filehandle: HANDLE, + event: HANDLE, + apcroutine: PIO_APC_ROUTINE, + apccontext: *const c_void, + iostatusblock: *mut IO_STATUS_BLOCK, + buffer: *mut c_void, + length: u32, + byteoffset: *const i64, + key: *const u32 + ) -> NTSTATUS { + STATUS_NOT_IMPLEMENTED + } + pub fn NtWriteFile( + filehandle: HANDLE, + event: HANDLE, + apcroutine: PIO_APC_ROUTINE, + apccontext: *const c_void, + iostatusblock: *mut IO_STATUS_BLOCK, + buffer: *const c_void, + length: u32, + byteoffset: *const i64, + key: *const u32 + ) -> NTSTATUS { + STATUS_NOT_IMPLEMENTED + } + pub fn RtlNtStatusToDosError(Status: NTSTATUS) -> u32 { + Status as u32 + } + pub fn NtOpenFile( + filehandle: *mut HANDLE, + desiredaccess: u32, + objectattributes: *const OBJECT_ATTRIBUTES, + iostatusblock: *mut IO_STATUS_BLOCK, + shareaccess: u32, + openoptions: u32 + ) -> NTSTATUS { + rtabort!("unimplemented") + } + } + } _ => {} } @@ -634,3 +707,13 @@ compat_fn_with_fallback! { rtabort!("unimplemented") } } + +#[cfg(target_family = "rust9x")] +compat_fn_with_fallback! { + pub static KERNEL32: &CStr = c"kernel32" => { load: false, unicows: false }; + // >= 98+, NT4.0 + // https://learn.microsoft.com/en-us/windows/win32/api/stringapiset/nf-stringapiset-comparestringordinal + pub fn CancelIo(hfile: HANDLE) -> BOOL { + rtabort!("unimplemented") + } +} diff --git a/library/std/src/sys/pal/windows/c/bindings.txt b/library/std/src/sys/pal/windows/c/bindings.txt index c108b3cc1d980..e6e763cfdb5cb 100644 --- a/library/std/src/sys/pal/windows/c/bindings.txt +++ b/library/std/src/sys/pal/windows/c/bindings.txt @@ -2545,6 +2545,7 @@ WINSOCK_SOCKET_TYPE WRITE_DAC WRITE_OWNER WriteConsoleW +WriteFile WriteFileEx WSA_E_CANCELLED WSA_E_NO_MORE diff --git a/library/std/src/sys/pal/windows/c/windows_sys.rs b/library/std/src/sys/pal/windows/c/windows_sys.rs index dcc5a1dc513a2..797b759977fe5 100644 --- a/library/std/src/sys/pal/windows/c/windows_sys.rs +++ b/library/std/src/sys/pal/windows/c/windows_sys.rs @@ -146,6 +146,7 @@ windows_targets::link!("kernel32.dll" "system" fn WakeAllConditionVariable(condi windows_targets::link!("kernel32.dll" "system" fn WakeConditionVariable(conditionvariable : *mut CONDITION_VARIABLE)); windows_targets::link!("kernel32.dll" "system" fn WideCharToMultiByte(codepage : u32, dwflags : u32, lpwidecharstr : PCWSTR, cchwidechar : i32, lpmultibytestr : PSTR, cbmultibyte : i32, lpdefaultchar : PCSTR, lpuseddefaultchar : *mut BOOL) -> i32); windows_targets::link!("kernel32.dll" "system" fn WriteConsoleW(hconsoleoutput : HANDLE, lpbuffer : PCWSTR, nnumberofcharstowrite : u32, lpnumberofcharswritten : *mut u32, lpreserved : *const core::ffi::c_void) -> BOOL); +windows_targets::link!("kernel32.dll" "system" fn WriteFile(hfile : HANDLE, lpbuffer : *const u8, nnumberofbytestowrite : u32, lpnumberofbyteswritten : *mut u32, lpoverlapped : *mut OVERLAPPED) -> BOOL); windows_targets::link!("kernel32.dll" "system" fn WriteFileEx(hfile : HANDLE, lpbuffer : *const u8, nnumberofbytestowrite : u32, lpoverlapped : *mut OVERLAPPED, lpcompletionroutine : LPOVERLAPPED_COMPLETION_ROUTINE) -> BOOL); windows_targets::link!("ws2_32.dll" "system" fn accept(s : SOCKET, addr : *mut SOCKADDR, addrlen : *mut i32) -> SOCKET); windows_targets::link!("ws2_32.dll" "system" fn bind(s : SOCKET, name : *const SOCKADDR, namelen : i32) -> i32); diff --git a/library/std/src/sys/pal/windows/compat/checks.rs b/library/std/src/sys/pal/windows/compat/checks.rs index 30fb4e048fe03..d0f392c027bce 100644 --- a/library/std/src/sys/pal/windows/compat/checks.rs +++ b/library/std/src/sys/pal/windows/compat/checks.rs @@ -16,6 +16,23 @@ pub fn is_windows_nt() -> bool { true // let me know once someone ported 9x to 64bit LOL } +#[inline(always)] +pub fn supports_async_io() -> bool { + unsafe { SUPPORTS_ASYNC_IO } +} + +// Whether the new way (just opening \??\PIPE\ / \Device\NamedPipe without a file/pipe name creates +// an anon pipe) is supported. +// +// Prior to Vista (NT 6), kernel32's `CreatePipe` would create a pipe with a unique name via +// `_sprintf(Buffer, "\\Device\\NamedPipe\\Win32Pipes.%08x.%08x", process_id, global_counter)`; +// +// see https://github.com/rust-lang/rust/pull/142517 +#[inline(always)] +pub fn supports_anon_pipe_autoname() -> bool { + unsafe { SUPPORTS_ANON_PIPE_AUTONAME } +} + pub fn init_rust9x_checks() { // DO NOT do anything interesting or complicated in this function! DO NOT call // any Rust functions or CRT functions if those functions touch any global state, @@ -26,11 +43,18 @@ pub fn init_rust9x_checks() { init_mutex_kind_check(); } -static mut IS_NT: bool = true; +static mut IS_NT: bool = false; +static mut SUPPORTS_ASYNC_IO: bool = false; +static mut SUPPORTS_ANON_PIPE_AUTONAME: bool = false; fn init_windows_version_check() { // according to old MSDN info, the high-order bit is set only on 95/98/ME. - unsafe { IS_NT = c::GetVersion() < 0x8000_0000 }; + unsafe { + let version = c::GetVersion(); + IS_NT = version < 0x8000_0000; + SUPPORTS_ASYNC_IO = IS_NT && c::CancelIo::available().is_some(); + SUPPORTS_ANON_PIPE_AUTONAME = IS_NT && version & 0xFF >= 0x06; // Vista+/NT6+ + }; } #[derive(Clone, Copy, PartialEq)] diff --git a/library/std/src/sys/pal/windows/handle.rs b/library/std/src/sys/pal/windows/handle.rs index 7e2c2767d6022..8b30765fdb00b 100644 --- a/library/std/src/sys/pal/windows/handle.rs +++ b/library/std/src/sys/pal/windows/handle.rs @@ -258,6 +258,32 @@ impl Handle { // The length is clamped at u32::MAX. let len = cmp::min(len, u32::MAX as usize) as u32; + + #[cfg(target_family = "rust9x")] + if !crate::sys::compat::checks::supports_async_io() { + unsafe { + if let Some(offset) = offset { + cvt(c::SetFilePointerEx( + self.as_raw_handle(), + offset as i64, + ptr::null_mut(), + c::FILE_BEGIN, + ))?; + } + + let mut bytes_read = 0; + cvt(c::ReadFile( + self.as_raw_handle(), + buf.cast(), + len, + &mut bytes_read, + ptr::null_mut(), + ))?; + + return Ok(bytes_read as usize); + } + } + // SAFETY: It's up to the caller to ensure `buf` is writeable up to // the provided `len`. let status = unsafe { @@ -310,6 +336,32 @@ impl Handle { // The length is clamped at u32::MAX. let len = cmp::min(buf.len(), u32::MAX as usize) as u32; + + #[cfg(target_family = "rust9x")] + if !crate::sys::compat::checks::supports_async_io() { + unsafe { + if let Some(offset) = offset { + cvt(c::SetFilePointerEx( + self.as_raw_handle(), + offset as i64, + ptr::null_mut(), + c::FILE_BEGIN, + ))?; + } + + let mut bytes_written = 0; + cvt(c::WriteFile( + self.as_raw_handle(), + buf.as_ptr(), + len, + &mut bytes_written, + ptr::null_mut(), + ))?; + + return Ok(bytes_written as usize); + } + } + let status = unsafe { c::NtWriteFile( self.as_raw_handle(), diff --git a/library/std/src/sys/pal/windows/pipe.rs b/library/std/src/sys/pal/windows/pipe.rs index b5ccf037a4f22..2c28e2bb5a668 100644 --- a/library/std/src/sys/pal/windows/pipe.rs +++ b/library/std/src/sys/pal/windows/pipe.rs @@ -54,6 +54,133 @@ pub fn anon_pipe(ours_readable: bool, their_handle_inheritable: bool) -> io::Res // A 64kb pipe capacity is the same as a typical Linux default. const PIPE_BUFFER_CAPACITY: u32 = 64 * 1024; + // Since Windows 9X/ME does not support creating named pipes (only connecting to remote pipes + // created on NT), we'll have to make do with anonymous pipes, without overlapped I/O. In + // particular, this means that we'll have to do reading from two threads in the case where both + // stdout and stderr being piped (see `read2`). + + // 9X/ME *does* have a kernel32 export entry for `CreateNamedPipe`, so an availability check + // would not work. We're just gonna check the bit that's only set on non-unicode Windows + // versions instead... + + // The `AnonPipe` impl used in `read2` below needs to be able to cancel the overlapped i/o + // operation, so we also have to check for `CancelIo` being available. This means that the + // "modern" path is taken only for NT4+. + #[cfg(target_family = "rust9x")] + if !crate::sys::compat::checks::supports_async_io() { + let size = mem::size_of::(); + let mut sa = c::SECURITY_ATTRIBUTES { + nLength: size as u32, + lpSecurityDescriptor: ptr::null_mut(), + // We follow the old "Creating a Child Process with Redirected Input and Output" MSDN + // entry (pre-`SetHandleInformation`) here, duplicating the handle that is not being + // sent to the child process as non-inheritable and then closing the inheritable one. + // Usually, this would be racy, but this function is only called in `Stdio::to_handle`, + // which is in turn only called form `process::spawn`, which acquires a lock on process + // spawning because of this. + bInheritHandle: c::TRUE, + }; + + unsafe { + let mut read_pipe = mem::zeroed(); + let mut write_pipe = mem::zeroed(); + crate::sys::cvt(c::CreatePipe( + &mut read_pipe, + &mut write_pipe, + &mut sa, + PIPE_BUFFER_CAPACITY, + ))?; + let read_pipe = Handle::from_raw_handle(read_pipe); + let write_pipe = Handle::from_raw_handle(write_pipe); + + let (ours_inheritable, theirs) = + if ours_readable { (read_pipe, write_pipe) } else { (write_pipe, read_pipe) }; + + // Make `ours` non-inheritable by duplicating it with the approriate setting + let ours = ours_inheritable.duplicate(0, false, c::DUPLICATE_SAME_ACCESS)?; + + // close the old, inheritable handle to the pipe end that is ours + drop(ours_inheritable); + + return Ok(Pipes { + ours: AnonPipe { inner: ours }, + theirs: AnonPipe { inner: theirs }, + }); + } + } + + // based on old Rust implementation from before https://github.com/rust-lang/rust/pull/142517: + // - https://github.com/rust-lang/rust/blob/64033a4ee541c3e9c178fd593e979c74bb798cdc/library/std/src/sys/pal/windows/pipe.rs + // - https://github.com/rust-lang/rust/commit/3371d498b1d6853598b9bedaf1e71d4c3f1d538b: + // `PIPE_REJECT_REMOTE_CLIENTS` was added with Vista, so we don't need to try it in this + // fallback for pre-Vista systems. + // + #[cfg(target_family = "rust9x")] + if !crate::sys::compat::checks::supports_anon_pipe_autoname() { + fn pipe_serial_number() -> usize { + use crate::sync::atomic::{Atomic, AtomicUsize, Ordering}; + static N: Atomic = AtomicUsize::new(0); + return N.fetch_add(1, Ordering::Relaxed); + } + + unsafe { + use crate::ffi::OsStr; + use crate::sys::fs::{File, OpenOptions}; + use crate::sys::path::WCStr; + + let ours; + let name = format!( + r"\\.\pipe\__rust_pipe{}.{}.{}", + c::GetCurrentProcessId(), + c::GetTickCount(), + pipe_serial_number(), + ); + let wide_name = OsStr::new(&name).encode_wide().chain(Some(0)).collect::>(); + let wide_name = WCStr::from_wchars_with_null_unchecked(&wide_name); + let mut flags = c::FILE_FLAG_FIRST_PIPE_INSTANCE | c::FILE_FLAG_OVERLAPPED; + if ours_readable { + flags |= c::PIPE_ACCESS_INBOUND; + } else { + flags |= c::PIPE_ACCESS_OUTBOUND; + } + + let handle = c::CreateNamedPipeW( + wide_name.as_ptr(), + flags, + c::PIPE_TYPE_BYTE | c::PIPE_READMODE_BYTE | c::PIPE_WAIT, + 1, + PIPE_BUFFER_CAPACITY, + PIPE_BUFFER_CAPACITY, + 0, + ptr::null_mut(), + ); + if handle == c::INVALID_HANDLE_VALUE { + return Err(io::Error::last_os_error()); + } + + ours = Handle::from_raw_handle(handle); + + // Connect to the named pipe we just created. This handle is going to be + // returned in `theirs`, so if `ours` is readable we want this to be + // writable, otherwise if `ours` is writable we want this to be + // readable. + // + // Additionally we don't enable overlapped mode on this because most + // client processes aren't enabled to work with that. + let mut opts = OpenOptions::new(); + opts.write(ours_readable); + opts.read(!ours_readable); + opts.share_mode(0); + opts.inherit_handle(true); + let theirs = File::open_native(wide_name, &opts)?; + + return Ok(Pipes { + ours: AnonPipe { inner: ours }, + theirs: AnonPipe { inner: theirs.into_inner() }, + }); + } + } + // Note that we specifically do *not* use `CreatePipe` here because // unfortunately the anonymous pipes returned do not support overlapped // operations. Instead, we use `NtCreateNamedPipeFile` to create the @@ -223,6 +350,11 @@ impl AnonPipe { } pub fn read(&self, buf: &mut [u8]) -> io::Result { + #[cfg(target_family = "rust9x")] + if !crate::sys::compat::checks::supports_async_io() { + return self.inner.read(buf); + } + let result = unsafe { let len = crate::cmp::min(buf.len(), u32::MAX as usize) as u32; let ptr = buf.as_mut_ptr(); @@ -242,6 +374,11 @@ impl AnonPipe { } pub fn read_buf(&self, mut buf: BorrowedCursor<'_>) -> io::Result<()> { + #[cfg(target_family = "rust9x")] + if !crate::sys::compat::checks::supports_async_io() { + return self.inner.read_buf(buf); + } + let result = unsafe { let len = crate::cmp::min(buf.capacity(), u32::MAX as usize) as u32; let ptr = buf.as_mut().as_mut_ptr().cast::(); @@ -280,6 +417,11 @@ impl AnonPipe { } pub fn write(&self, buf: &[u8]) -> io::Result { + #[cfg(target_family = "rust9x")] + if !crate::sys::compat::checks::supports_async_io() { + return self.inner.write(buf); + } + unsafe { let len = crate::cmp::min(buf.len(), u32::MAX as usize) as u32; self.alertable_io_internal(|overlapped, callback| { @@ -399,6 +541,24 @@ pub fn read2(p1: AnonPipe, v1: &mut Vec, p2: AnonPipe, v2: &mut Vec) -> let p1 = p1.into_handle(); let p2 = p2.into_handle(); + #[cfg(target_family = "rust9x")] + if !crate::sys::compat::checks::supports_async_io() { + // Since we are using anonymous pipes (= without overlapped I/O support) here, we can't do + // async waiting on both stdout and stderr at the same time on one thread, so we have to + // spawn an additional thread to do the waiting for the second pipe. + + // See https://github.com/rust-lang/rust/pull/31618, where this was removed initially. + let second_pipe = crate::thread::spawn(move || { + let mut ret = Vec::new(); + (&p2).read_to_end(&mut ret).map(|_| ret) + }); + + (&p1).read_to_end(v1)?; + *v2 = second_pipe.join().unwrap()?; + + return Ok(()); + } + let mut p1 = AsyncPipe::new(p1, v1)?; let mut p2 = AsyncPipe::new(p2, v2)?; let objs = [p1.event.as_raw_handle(), p2.event.as_raw_handle()]; From 45dd1f421dc0d04559b8ac6e7937e9e8f188cacf Mon Sep 17 00:00:00 2001 From: Dennis Duda Date: Sat, 30 Nov 2024 21:40:49 +0100 Subject: [PATCH 31/58] Process API fallbacks for 9x/ME/NT 9x/ME: - Don't use `CREATE_UNICODE_ENVIRONMENT` - Use `command.com` instead of `cmd.exe` - Use `NUL` instead of `\\.\NUL` NT: - Use /X instead of /e:ON for support for ancient cmd.exe versions --- library/std/src/sys/args/windows.rs | 10 ++++ library/std/src/sys/process/windows.rs | 66 ++++++++++++++++++++++++-- 2 files changed, 72 insertions(+), 4 deletions(-) diff --git a/library/std/src/sys/args/windows.rs b/library/std/src/sys/args/windows.rs index 81c44fabdcc67..c76a4c749155e 100644 --- a/library/std/src/sys/args/windows.rs +++ b/library/std/src/sys/args/windows.rs @@ -302,7 +302,17 @@ pub(crate) fn make_bat_command_line( // hence the trailing quote here. It will be closed after all arguments // have been added. // Using /e:ON enables "command extensions" which is essential for the `%` hack to work. + #[cfg(not(target_family = "rust9x"))] let mut cmd: Vec = "cmd.exe /e:ON /v:OFF /d /c \"".encode_utf16().collect(); + #[cfg(target_family = "rust9x")] + let mut cmd: Vec = if crate::sys::compat::checks::is_windows_nt() { + // Using /X instead of /e:ON for old NT versions. + "cmd.exe /X /v:OFF /d /c \"" + } else { + "command.com /c \"" + } + .encode_utf16() + .collect(); // Push the script name surrounded by its quote pair. cmd.push(b'"' as u16); diff --git a/library/std/src/sys/process/windows.rs b/library/std/src/sys/process/windows.rs index 641ac20ce39cc..c587af86d77e6 100644 --- a/library/std/src/sys/process/windows.rs +++ b/library/std/src/sys/process/windows.rs @@ -301,6 +301,7 @@ impl Command { None }; let program = resolve_exe(&self.program, || env::var_os("PATH"), child_paths)?; + #[cfg(not(target_family = "rust9x"))] let has_bat_extension = |program: &[u16]| { matches!( // Case insensitive "ends_with" of UTF-16 encoded ".bat" or ".cmd" @@ -308,6 +309,20 @@ impl Command { Some([46, 98 | 66, 97 | 65, 116 | 84] | [46, 99 | 67, 109 | 77, 100 | 68]) ) }; + #[cfg(target_family = "rust9x")] + let has_bat_extension = |program: &[u16]| { + let ext = program.len().checked_sub(4).and_then(|i| program.get(i..)); + if crate::sys::compat::checks::is_windows_nt() { + matches!( + // Case insensitive "ends_with" of UTF-16 encoded ".bat" or ".cmd" + ext, + Some([46, 98 | 66, 97 | 65, 116 | 84] | [46, 99 | 67, 109 | 77, 100 | 68]) + ) + } else { + // Case insensitive "ends_with" of UTF-16 encoded ".bat" + matches!(ext, Some([46, 98 | 66, 97 | 65, 116 | 84, 0])) + } + }; let is_batch_file = if path::is_verbatim(&program) { has_bat_extension(&program[..program.len() - 1]) } else { @@ -331,7 +346,16 @@ impl Command { cmd_str.push(0); // add null terminator // stolen from the libuv code. + #[cfg(not(target_family = "rust9x"))] let mut flags = self.flags | c::CREATE_UNICODE_ENVIRONMENT; + #[cfg(target_family = "rust9x")] + let mut flags = { + let mut flags = self.flags; + if crate::sys::compat::checks::is_windows_nt() { + flags |= c::CREATE_UNICODE_ENVIRONMENT; + } + flags + }; if self.detach { flags |= c::DETACHED_PROCESS | c::CREATE_NEW_PROCESS_GROUP; } @@ -660,6 +684,16 @@ impl Stdio { opts.read(stdio_id == c::STD_INPUT_HANDLE); opts.write(stdio_id != c::STD_INPUT_HANDLE); opts.inherit_handle(true); + #[cfg(target_family = "rust9x")] + { + let p = if crate::sys::compat::checks::is_windows_nt() { + r"\\.\NUL" + } else { + r"NUL" + }; + File::open(Path::new(p), &opts).map(|file| file.into_inner()) + } + #[cfg(not(target_family = "rust9x"))] File::open(Path::new(r"\\.\NUL"), &opts).map(|file| file.into_inner()) } } @@ -903,10 +937,34 @@ fn make_command_line(argv0: &OsStr, args: &[Arg], force_quotes: bool) -> io::Res // Get `cmd.exe` for use with bat scripts, encoded as a UTF-16 string. fn command_prompt() -> io::Result> { - let mut system: Vec = - fill_utf16_buf(|buf, size| unsafe { c::GetSystemDirectoryW(buf, size) }, |buf| buf.into())?; - system.extend("\\cmd.exe".encode_utf16().chain([0])); - Ok(system) + #[cfg(target_family = "rust9x")] + { + if crate::sys::compat::checks::is_windows_nt() { + let mut system: Vec = fill_utf16_buf( + |buf, size| unsafe { c::GetSystemDirectoryW(buf, size) }, + |buf| buf.into(), + )?; + system.extend("\\cmd.exe".encode_utf16().chain([0])); + Ok(system) + } else { + let mut system: Vec = fill_utf16_buf( + |buf, size| unsafe { c::GetWindowsDirectoryW(buf, size) }, + |buf| buf.into(), + )?; + system.extend("\\command.com".encode_utf16().chain([0])); + Ok(system) + } + } + + #[cfg(not(target_family = "rust9x"))] + { + let mut system: Vec = fill_utf16_buf( + |buf, size| unsafe { c::GetSystemDirectoryW(buf, size) }, + |buf| buf.into(), + )?; + system.extend("\\cmd.exe".encode_utf16().chain([0])); + Ok(system) + } } fn make_envp(maybe_env: Option>) -> io::Result<(*mut c_void, Vec)> { From 2488d40cc2191b0fc18704f971a6fbe8496630a3 Mon Sep 17 00:00:00 2001 From: Dennis Duda Date: Sun, 1 Dec 2024 16:43:00 +0100 Subject: [PATCH 32/58] Fall back to old impl for `remove_dir_all` The recursive directory removal implementation falls back to the old one if the necessary APIs are not available (`NtCreateFile`, `GetFileInformationByHandleEx`, `SetFileInformationByHandle`). The APIs are available on Vista/Server 2008. See notes on `fileextd.lib` above to extend the support to Windows XP/Server 2003. **This might cause security issues**, see https://github.com/rust-lang/rust/pull/93112 --- library/std/src/sys/fs/mod.rs | 4 +- library/std/src/sys/fs/windows.rs | 40 +++++++++++++++++++ .../std/src/sys/fs/windows/remove_dir_all.rs | 19 +++++++++ 3 files changed, 61 insertions(+), 2 deletions(-) diff --git a/library/std/src/sys/fs/mod.rs b/library/std/src/sys/fs/mod.rs index eaea28871241a..eef1987026b83 100644 --- a/library/std/src/sys/fs/mod.rs +++ b/library/std/src/sys/fs/mod.rs @@ -84,9 +84,9 @@ pub fn remove_dir(path: &Path) -> io::Result<()> { pub fn remove_dir_all(path: &Path) -> io::Result<()> { // FIXME: use with_native_path on all platforms - #[cfg(not(windows))] + #[cfg(any(not(windows), target_family = "rust9x"))] return imp::remove_dir_all(path); - #[cfg(windows)] + #[cfg(all(windows, not(target_family = "rust9x")))] with_native_path(path, &imp::remove_dir_all) } diff --git a/library/std/src/sys/fs/windows.rs b/library/std/src/sys/fs/windows.rs index daee26b86e366..c59472d478fe7 100644 --- a/library/std/src/sys/fs/windows.rs +++ b/library/std/src/sys/fs/windows.rs @@ -1377,6 +1377,46 @@ pub fn rmdir(p: &WCStr) -> io::Result<()> { Ok(()) } +#[cfg(target_family = "rust9x")] +pub fn remove_dir_all(p: &Path) -> io::Result<()> { + use crate::sys::path::with_native_path; + + with_native_path(p, &|path| { + // if the modern file/directory APIs are not available, we'll fall back to the old (unsafe, see + // https://github.com/rust-lang/rust/pull/93112) directory removal implementation + if !(c::NtOpenFile::available().is_some() + && c::GetFileInformationByHandleEx::available().is_some() + && c::SetFileInformationByHandle::available().is_some()) + { + let filetype = lstat(path)?.file_type(); + if filetype.is_symlink() { + // On Windows symlinks to files and directories are removed differently. + // rmdir only deletes dir symlinks and junctions, not file symlinks. + return rmdir(path); + } else { + return remove_dir_all::remove_dir_all_recursive_old(p); + } + } + + // Open a file or directory without following symlinks. + let mut opts = OpenOptions::new(); + opts.access_mode(c::FILE_LIST_DIRECTORY); + // `FILE_FLAG_BACKUP_SEMANTICS` allows opening directories. + // `FILE_FLAG_OPEN_REPARSE_POINT` opens a link instead of its target. + opts.custom_flags(c::FILE_FLAG_BACKUP_SEMANTICS | c::FILE_FLAG_OPEN_REPARSE_POINT); + let file = File::open_native(path, &opts)?; + + // Test if the file is not a directory or a symlink to a directory. + if (file.basic_info()?.FileAttributes & c::FILE_ATTRIBUTE_DIRECTORY) == 0 { + return Err(io::Error::from_raw_os_error(c::ERROR_DIRECTORY as _)); + } + + // Remove the directory and all its contents. + remove_dir_all_iterative(file).io_result() + }) +} + +#[cfg(not(target_family = "rust9x"))] pub fn remove_dir_all(path: &WCStr) -> io::Result<()> { // Open a file or directory without following symlinks. let mut opts = OpenOptions::new(); diff --git a/library/std/src/sys/fs/windows/remove_dir_all.rs b/library/std/src/sys/fs/windows/remove_dir_all.rs index c8b1a07676855..baf14becb8eea 100644 --- a/library/std/src/sys/fs/windows/remove_dir_all.rs +++ b/library/std/src/sys/fs/windows/remove_dir_all.rs @@ -204,3 +204,22 @@ pub fn remove_dir_all_iterative(dir: File) -> Result<(), WinError> { } Ok(()) } + +#[cfg(target_family = "rust9x")] +pub fn remove_dir_all_recursive_old(path: &crate::path::Path) -> crate::io::Result<()> { + use super::*; + use crate::sys::path::with_native_path; + + for child in readdir(path)? { + let child = child?; + let child_type = child.file_type()?; + if child_type.is_dir() { + remove_dir_all_recursive_old(&child.path())?; + } else if child_type.is_symlink_dir() { + with_native_path(&child.path(), &rmdir)?; + } else { + with_native_path(&child.path(), &unlink)?; + } + } + with_native_path(path, &rmdir) +} From b1cd94566efe6a698ac7fd8ace327bbb05288f59 Mon Sep 17 00:00:00 2001 From: Dennis Duda Date: Sun, 1 Dec 2024 16:47:24 +0100 Subject: [PATCH 33/58] Work around missing flag support for `CreateFile` on 9x/ME - 9x/ME only supports a limited number of access rights. This means that we can't use the special append-only behavior (atomic appends). Additionally, files opened with `append(true)` *will* be able to seek back and overwrite existing data on these systems. - 9x/ME does not support `FILE_SHARE_DELETE`. Opened files cannot be opened to request a delete at the same time. --- library/std/src/sys/fs/windows.rs | 68 ++++++++++++++++++++++++++++++- 1 file changed, 67 insertions(+), 1 deletion(-) diff --git a/library/std/src/sys/fs/windows.rs b/library/std/src/sys/fs/windows.rs index c59472d478fe7..de1ca5bb6f2fb 100644 --- a/library/std/src/sys/fs/windows.rs +++ b/library/std/src/sys/fs/windows.rs @@ -188,6 +188,7 @@ impl DirEntry { } impl OpenOptions { + #[cfg(not(target_family = "rust9x"))] pub fn new() -> OpenOptions { OpenOptions { // generic @@ -207,6 +208,31 @@ impl OpenOptions { } } + #[cfg(target_family = "rust9x")] + pub fn new() -> OpenOptions { + OpenOptions { + // generic + read: false, + write: false, + append: false, + truncate: false, + create: false, + create_new: false, + // system-specific + custom_flags: 0, + access_mode: None, + share_mode: if crate::sys::compat::checks::is_windows_nt() { + c::FILE_SHARE_READ | c::FILE_SHARE_WRITE | c::FILE_SHARE_DELETE + } else { + // _DELETE is only supported on NT-based systems. + c::FILE_SHARE_READ | c::FILE_SHARE_WRITE + }, + attributes: 0, + security_qos_flags: 0, + inherit_handle: false, + } + } + pub fn read(&mut self, read: bool) { self.read = read; } @@ -247,6 +273,7 @@ impl OpenOptions { self.inherit_handle = inherit; } + #[cfg(not(target_family = "rust9x"))] fn get_access_mode(&self) -> io::Result { match (self.read, self.write, self.append, self.access_mode) { (.., Some(mode)) => Ok(mode), @@ -275,6 +302,35 @@ impl OpenOptions { } } + #[cfg(target_family = "rust9x")] + fn get_access_mode(&self) -> io::Result { + // 9x/ME only supports a limited number of access rights (DELETE, FILE_WRITE_ATTRIBUTES, + // GENERIC_READ, and GENERIC_WRITE). This means that we can't use the special append-only + // behavior (atomic appends). Additionally, files opened with `append(true)` *will* be able + // to seek back and overwrite existing data on these systems. + let is_nt = crate::sys::compat::checks::is_windows_nt(); + + match (self.read, self.write, self.append, self.access_mode) { + (.., Some(mode)) => Ok(mode), + (true, false, false, None) => Ok(c::GENERIC_READ), + (false, true, false, None) => Ok(c::GENERIC_WRITE), + (true, true, false, None) => Ok(c::GENERIC_READ | c::GENERIC_WRITE), + (false, _, true, None) => Ok(if is_nt { + c::FILE_GENERIC_WRITE & !c::FILE_WRITE_DATA + } else { + c::GENERIC_WRITE + }), + (true, _, true, None) => Ok(if is_nt { + c::GENERIC_READ | (c::FILE_GENERIC_WRITE & !c::FILE_WRITE_DATA) + } else { + c::GENERIC_READ | c::GENERIC_WRITE + }), + (false, false, false, None) => { + Err(Error::from_raw_os_error(c::ERROR_INVALID_PARAMETER as i32)) + } + } + } + fn get_creation_mode(&self) -> io::Result { match (self.write, self.append) { (true, false) => {} @@ -357,7 +413,17 @@ impl File { .io_result() .or_else(|_| Self::truncate_inner(handle.as_raw_handle(), 0))?; } - Ok(File { handle: Handle::from_inner(handle) }) + let file = File { handle: Handle::from_inner(handle) }; + + // 9x/ME do not support FILE_APPEND_DATA/FILE_WRITE_DATA, which means that we cannot get + // the append-only behaviors: atomic appends, cursor starts at the end of the file. The + // latter can be emulated, at least, by just seeking to the end. + #[cfg(target_family = "rust9x")] + if opts.append && !crate::sys::compat::checks::is_windows_nt() { + file.seek(SeekFrom::End(0))?; + } + + Ok(file) } else { Err(Error::last_os_error()) } From ae90bb858ff30d568cf20050fdb2822f20748a77 Mon Sep 17 00:00:00 2001 From: Dennis Duda Date: Sun, 1 Dec 2024 17:33:57 +0100 Subject: [PATCH 34/58] Implement file handling fallbacks for 9x/ME - Skip `maybe_verbatim` handling on 9x/ME - 9x/ME only supports a limited number of access rights. This means that we can't use the special append-only behavior (atomic appends). Additionally, files opened with `append(true)` *will* be able to seek back and overwrite existing data on these systems. - 9x/ME does not support `FILE_SHARE_DELETE`. Opened files cannot be opened to request a delete at the same time. Implement fallbacks for functions needing `FILE_FLAG_BACKUP_SEMANTICS` (not available on 9x/ME) - Implement fallback for `metadata` to work on directories on 9x/ME - Implement fallback for `exists` to work on directories on 9x/ME Implement fallback for File::try_lock - `try_lock` can just use `LockFile` instead of `LockFileEx` (= 9x/ME support) - `try_lock_shared` will just fail on 9x/ME as shared locks are not supported - blocking lock is not supported on 9x/ME either. We try `try_lock` in hopes of getting the lock instead, and then fall back to the proper lock impl, which will fail on 9x/ME --- library/std/src/sys/fs/windows.rs | 127 ++++++++++++++++-- library/std/src/sys/pal/windows/c.rs | 31 +++++ .../std/src/sys/pal/windows/c/bindings.txt | 2 + .../std/src/sys/pal/windows/c/windows_sys.rs | 2 + library/std/src/sys/path/windows.rs | 6 + 5 files changed, 157 insertions(+), 11 deletions(-) diff --git a/library/std/src/sys/fs/windows.rs b/library/std/src/sys/fs/windows.rs index de1ca5bb6f2fb..6c68df3fb81cb 100644 --- a/library/std/src/sys/fs/windows.rs +++ b/library/std/src/sys/fs/windows.rs @@ -480,6 +480,15 @@ impl File { } pub fn lock(&self) -> io::Result<()> { + #[cfg(target_family = "rust9x")] + { + // try `LockFile`/`try_lock`, as that one is available on 9x/ME + if self.try_lock().is_ok() { + return Ok(()); + } + + // otherwise just fail the call to `LockFileEx` here + } self.acquire_lock(c::LOCKFILE_EXCLUSIVE_LOCK) } @@ -488,17 +497,8 @@ impl File { } pub fn try_lock(&self) -> Result<(), TryLockError> { - let result = cvt(unsafe { - let mut overlapped = mem::zeroed(); - c::LockFileEx( - self.handle.as_raw_handle(), - c::LOCKFILE_EXCLUSIVE_LOCK | c::LOCKFILE_FAIL_IMMEDIATELY, - 0, - u32::MAX, - u32::MAX, - &mut overlapped, - ) - }); + let result = + cvt(unsafe { c::LockFile(self.handle.as_raw_handle(), 0, 0, u32::MAX, u32::MAX) }); match result { Ok(_) => Ok(()), @@ -1303,6 +1303,7 @@ pub fn readdir(p: &Path) -> io::Result { // // We can pass FIND_FIRST_EX_LARGE_FETCH to dwAdditionalFlags to speed up things more, // but as we don't know user's use profile of this function, lets be conservative. + #[cfg(not(target_family = "rust9x"))] let find_handle = c::FindFirstFileExW( path.as_ptr(), c::FindExInfoBasic, @@ -1312,6 +1313,11 @@ pub fn readdir(p: &Path) -> io::Result { 0, ); + // We take the hit of filling in the alternate file name because both `FindFirstFileExW` and + // `FindExInfoBasic` aren't necessarily supported. + #[cfg(target_family = "rust9x")] + let find_handle = c::FindFirstFileW(path.as_ptr(), &mut wfd); + if find_handle != c::INVALID_HANDLE_VALUE { Ok(ReadDir { handle: Some(FindNextFileHandle(find_handle)), @@ -1590,13 +1596,57 @@ fn metadata(path: &WCStr, reparse: ReparsePoint) -> io::Result { let mut opts = OpenOptions::new(); // No read or write permissions are necessary opts.access_mode(0); + + #[cfg(not(target_family = "rust9x"))] opts.custom_flags(c::FILE_FLAG_BACKUP_SEMANTICS | reparse.as_flag()); + #[cfg(target_family = "rust9x")] + if crate::sys::compat::checks::is_windows_nt() { + opts.custom_flags(c::FILE_FLAG_BACKUP_SEMANTICS | reparse.as_flag()); + } // Attempt to open the file normally. // If that fails with `ERROR_SHARING_VIOLATION` then retry using `FindFirstFileExW`. // If the fallback fails for any reason we return the original error. match File::open_native(&path, &opts) { Ok(file) => file.file_attr(), + #[cfg(target_family = "rust9x")] + Err(e) if !crate::sys::compat::checks::is_windows_nt() => unsafe { + // Get at least the attributes in case `FindFirstFile` fails down below + let attr = c::GetFileAttributesW(path.as_ptr()); + if attr == c::INVALID_FILE_ATTRIBUTES { + return Err(e); + } + + // Since we don't have access to `FILE_FLAG_BACKUP_SEMANTICS` on 9x/ME, fall back to + // `FindFirstFile` for directories + let mut find_data: c::WIN32_FIND_DATAW = mem::zeroed(); + let handle = c::FindFirstFileW(path.as_ptr(), &mut find_data); + + if handle == c::INVALID_HANDLE_VALUE { + // You can't get info about the root directory via FindFirstFile, so in that + // case and any other cases where FindFirstFile fails, fall back to the + // already-retrieved attributes. + // + // For directories, we can only get attributes on 9x/ME. + return Ok(FileAttr { + attributes: attr, + creation_time: mem::zeroed(), + last_access_time: mem::zeroed(), + last_write_time: mem::zeroed(), + change_time: None, + file_size: 0, + reparse_tag: 0, + volume_serial_number: None, + number_of_links: None, + file_index: None, + }); + } + + let attrs = FileAttr::from(find_data); + c::FindClose(handle); + + return Ok(attrs); + }, Err(e) if [Some(c::ERROR_SHARING_VIOLATION as _), Some(c::ERROR_ACCESS_DENIED as _)] .contains(&e.raw_os_error()) => @@ -1823,6 +1873,7 @@ pub fn junction_point(original: &Path, link: &Path) -> io::Result<()> { } } +#[cfg(not(target_family = "rust9x"))] // Try to see if a file exists but, unlike `exists`, report I/O errors. pub fn exists(path: &WCStr) -> io::Result { // Open the file to ensure any symlinks are followed to their target. @@ -1857,3 +1908,57 @@ pub fn exists(path: &WCStr) -> io::Result { Ok(_) => Ok(true), } } + +#[cfg(target_family = "rust9x")] +// Try to see if a file exists but, unlike `exists`, report I/O errors. +pub fn exists(path: &WCStr) -> io::Result { + fn match_kind(e: crate::io::Error) -> io::Result { + match e.kind() { + // The file definitely does not exist + io::ErrorKind::NotFound => Ok(false), + + // `ERROR_SHARING_VIOLATION` means that the file has been locked by + // another process. This is often temporary so we simply report it + // as the file existing. + _ if e.raw_os_error() == Some(c::ERROR_SHARING_VIOLATION as i32) => Ok(true), + + // `ERROR_CANT_ACCESS_FILE` means that a file exists but that the + // reparse point could not be handled by `CreateFile`. + // This can happen for special files such as: + // * Unix domain sockets which you need to `connect` to + // * App exec links which require using `CreateProcess` + _ if e.raw_os_error() == Some(c::ERROR_CANT_ACCESS_FILE as i32) => Ok(true), + + // Other errors such as `ERROR_ACCESS_DENIED` may indicate that the + // file exists. However, these types of errors are usually more + // permanent so we report them here. + _ => Err(e), + } + } + + // Open the file to ensure any symlinks are followed to their target. + let mut opts = OpenOptions::new(); + // No read, write, etc access rights are needed. + opts.access_mode(0); + + if crate::sys::compat::checks::is_windows_nt() { + // Backup semantics enables opening directories as well as files. + opts.custom_flags(c::FILE_FLAG_BACKUP_SEMANTICS); + } else { + let attr = unsafe { c::GetFileAttributesW(path.as_ptr()) }; + if attr == c::INVALID_FILE_ATTRIBUTES { + return match_kind(io::Error::last_os_error()); + } else { + // can't open a directory on 9x/ME anyways + if attr & c::FILE_ATTRIBUTE_DIRECTORY != 0 { + return Ok(true); + } + } + } + + match File::open_native(path, &opts) { + Err(e) => match_kind(e), + // The file was opened successfully therefore it must exist, + Ok(_) => Ok(true), + } +} diff --git a/library/std/src/sys/pal/windows/c.rs b/library/std/src/sys/pal/windows/c.rs index 167c8af2b1650..6d465dcc3b2ac 100644 --- a/library/std/src/sys/pal/windows/c.rs +++ b/library/std/src/sys/pal/windows/c.rs @@ -717,3 +717,34 @@ compat_fn_with_fallback! { rtabort!("unimplemented") } } + +#[cfg(target_family = "rust9x")] +compat_fn_with_fallback! { + pub static KERNEL32: &CStr = c"kernel32" => { load: false, unicows: false }; + // >= NT4.0 + // https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-findfirstfileexw + pub fn FindFirstFileExW( + lpfilename: PCWSTR, + finfolevelid: FINDEX_INFO_LEVELS, + lpfindfiledata: *mut core::ffi::c_void, + fsearchop: FINDEX_SEARCH_OPS, + lpsearchfilter: *const core::ffi::c_void, + dwadditionalflags: FIND_FIRST_EX_FLAGS + ) -> HANDLE { + rtabort!("unimplemented") + } + + // >= NT + // https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-lockfileex + pub fn LockFileEx( + hfile: HANDLE, + dwflags: LOCK_FILE_FLAGS, + dwreserved: u32, + nnumberofbytestolocklow: u32, + nnumberofbytestolockhigh: u32, + lpoverlapped: *mut OVERLAPPED + ) -> BOOL { + unsafe { SetLastError(ERROR_CALL_NOT_IMPLEMENTED as u32); }; + FALSE + } +} diff --git a/library/std/src/sys/pal/windows/c/bindings.txt b/library/std/src/sys/pal/windows/c/bindings.txt index e6e763cfdb5cb..f74b0313cce0d 100644 --- a/library/std/src/sys/pal/windows/c/bindings.txt +++ b/library/std/src/sys/pal/windows/c/bindings.txt @@ -2136,6 +2136,7 @@ FindClose FindExInfoBasic FindExSearchNameMatch FindFirstFileExW +FindFirstFileW FindNextFileW FIONBIO FlushFileBuffers @@ -2282,6 +2283,7 @@ LINGER listen LoadLibraryA LocalFree +LockFile LOCKFILE_EXCLUSIVE_LOCK LOCKFILE_FAIL_IMMEDIATELY LockFileEx diff --git a/library/std/src/sys/pal/windows/c/windows_sys.rs b/library/std/src/sys/pal/windows/c/windows_sys.rs index 797b759977fe5..eab5fa89cfe70 100644 --- a/library/std/src/sys/pal/windows/c/windows_sys.rs +++ b/library/std/src/sys/pal/windows/c/windows_sys.rs @@ -33,6 +33,7 @@ windows_targets::link!("kernel32.dll" "system" fn EnterCriticalSection(lpcritica windows_targets::link!("kernel32.dll" "system" fn ExitProcess(uexitcode : u32) -> !); windows_targets::link!("kernel32.dll" "system" fn FindClose(hfindfile : HANDLE) -> BOOL); windows_targets::link!("kernel32.dll" "system" fn FindFirstFileExW(lpfilename : PCWSTR, finfolevelid : FINDEX_INFO_LEVELS, lpfindfiledata : *mut core::ffi::c_void, fsearchop : FINDEX_SEARCH_OPS, lpsearchfilter : *const core::ffi::c_void, dwadditionalflags : FIND_FIRST_EX_FLAGS) -> HANDLE); +windows_targets::link!("kernel32.dll" "system" fn FindFirstFileW(lpfilename : PCWSTR, lpfindfiledata : *mut WIN32_FIND_DATAW) -> HANDLE); windows_targets::link!("kernel32.dll" "system" fn FindNextFileW(hfindfile : HANDLE, lpfindfiledata : *mut WIN32_FIND_DATAW) -> BOOL); windows_targets::link!("kernel32.dll" "system" fn FlushFileBuffers(hfile : HANDLE) -> BOOL); windows_targets::link!("kernel32.dll" "system" fn FormatMessageW(dwflags : FORMAT_MESSAGE_OPTIONS, lpsource : *const core::ffi::c_void, dwmessageid : u32, dwlanguageid : u32, lpbuffer : PWSTR, nsize : u32, arguments : *const *const i8) -> u32); @@ -82,6 +83,7 @@ windows_targets::link!("kernel32.dll" "system" fn InitializeProcThreadAttributeL windows_targets::link!("kernel32.dll" "system" fn LeaveCriticalSection(lpcriticalsection : *mut CRITICAL_SECTION)); windows_targets::link!("kernel32.dll" "system" fn LoadLibraryA(lplibfilename : PCSTR) -> HMODULE); windows_targets::link!("kernel32.dll" "system" fn LocalFree(hmem : HLOCAL) -> HLOCAL); +windows_targets::link!("kernel32.dll" "system" fn LockFile(hfile : HANDLE, dwfileoffsetlow : u32, dwfileoffsethigh : u32, nnumberofbytestolocklow : u32, nnumberofbytestolockhigh : u32) -> BOOL); windows_targets::link!("kernel32.dll" "system" fn LockFileEx(hfile : HANDLE, dwflags : LOCK_FILE_FLAGS, dwreserved : u32, nnumberofbytestolocklow : u32, nnumberofbytestolockhigh : u32, lpoverlapped : *mut OVERLAPPED) -> BOOL); windows_targets::link!("kernel32.dll" "system" fn MoveFileExW(lpexistingfilename : PCWSTR, lpnewfilename : PCWSTR, dwflags : MOVE_FILE_FLAGS) -> BOOL); windows_targets::link!("kernel32.dll" "system" fn MultiByteToWideChar(codepage : u32, dwflags : MULTI_BYTE_TO_WIDE_CHAR_FLAGS, lpmultibytestr : PCSTR, cbmultibyte : i32, lpwidecharstr : PWSTR, cchwidechar : i32) -> i32); diff --git a/library/std/src/sys/path/windows.rs b/library/std/src/sys/path/windows.rs index 509b13b6ae812..4b27e51c5bac2 100644 --- a/library/std/src/sys/path/windows.rs +++ b/library/std/src/sys/path/windows.rs @@ -85,6 +85,12 @@ pub(crate) fn append_suffix(path: PathBuf, suffix: &OsStr) -> PathBuf { /// This path may or may not have a verbatim prefix. pub(crate) fn maybe_verbatim(path: &Path) -> io::Result> { let path = to_u16s(path)?; + + #[cfg(target_family = "rust9x")] + if !crate::sys::compat::checks::is_windows_nt() { + return Ok(path); + } + get_long_path(path, true) } From 6fc79d39b9240ff634d3793b2d55d191ec04fa38 Mon Sep 17 00:00:00 2001 From: Dennis Duda Date: Sun, 1 Dec 2024 17:40:17 +0100 Subject: [PATCH 35/58] Fallbacks in `write_valid_utf8_to_console` - Allow dropping unknown characters. unicows just doesn't understand emojis :( - Ignore mismatched lengths when writing to console on non-Unicode Windows. (workaround for #13) --- library/std/src/sys/stdio/windows.rs | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/library/std/src/sys/stdio/windows.rs b/library/std/src/sys/stdio/windows.rs index 8dc092d0fe584..8df0c04af38d6 100644 --- a/library/std/src/sys/stdio/windows.rs +++ b/library/std/src/sys/stdio/windows.rs @@ -197,12 +197,15 @@ fn write_valid_utf8_to_console(handle: c::HANDLE, utf8: &str) -> io::Result io::Result Date: Sun, 1 Dec 2024 21:08:47 +0100 Subject: [PATCH 36/58] 9x/ME: Thread ID parameter for `CreateThread` is not optional --- library/std/src/sys/thread/windows.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/library/std/src/sys/thread/windows.rs b/library/std/src/sys/thread/windows.rs index 1ef496a20cfe4..9565ccaee6027 100644 --- a/library/std/src/sys/thread/windows.rs +++ b/library/std/src/sys/thread/windows.rs @@ -29,13 +29,14 @@ impl Thread { // SAFETY: `thread_start` has the right ABI for a thread's entry point. // `data` is simply passed through to the new thread without being touched. let ret = unsafe { + let mut thread_id = 0; let ret = c::CreateThread( ptr::null_mut(), stack, Some(thread_start), data as *mut _, c::STACK_SIZE_PARAM_IS_A_RESERVATION, - ptr::null_mut(), + &mut thread_id, ); HandleOrNull::from_raw_handle(ret) }; From fb6e4b6da5ccea0899faf4c4057c780480d2eb5a Mon Sep 17 00:00:00 2001 From: Dennis Duda Date: Thu, 26 Dec 2024 00:40:09 +0100 Subject: [PATCH 37/58] Reimplement Win32 APIs for `GetFileInformationByHandleEx` and `SetFileInformationByHandle` Reimplement them on-top of native NT APIs as done in `fileextd.lib`. This allows more file system APIs to work on XP and below. Affected APIs: - File truncation (can now set end of file without multiple SetFilePointerEx calls on NT) - Cleaner fallback impl for reparse tags - remove_dir_all: Modern impl now supported on all NT-based systems --- library/std/src/sys/fs/windows.rs | 49 ++--- library/std/src/sys/io/is_terminal/windows.rs | 9 +- library/std/src/sys/pal/windows/c.rs | 77 +++++--- .../std/src/sys/pal/windows/c/bindings.txt | 14 ++ library/std/src/sys/pal/windows/c/fileextd.rs | 178 ++++++++++++++++++ .../std/src/sys/pal/windows/c/windows_sys.rs | 44 +++++ 6 files changed, 321 insertions(+), 50 deletions(-) create mode 100644 library/std/src/sys/pal/windows/c/fileextd.rs diff --git a/library/std/src/sys/fs/windows.rs b/library/std/src/sys/fs/windows.rs index 6c68df3fb81cb..8aec4ddaf4c5d 100644 --- a/library/std/src/sys/fs/windows.rs +++ b/library/std/src/sys/fs/windows.rs @@ -558,7 +558,7 @@ impl File { #[cfg(target_family = "rust9x")] pub fn truncate_inner(handle: RawHandle, size: u64) -> io::Result<()> { - if c::SetFileInformationByHandle::available().is_some() { + if crate::sys::compat::checks::is_windows_nt() { let info = c::FILE_END_OF_FILE_INFO { EndOfFile: size as i64 }; api::set_file_information_by_handle(handle, &info).io_result() } else { @@ -587,22 +587,20 @@ impl File { cvt(c::GetFileInformationByHandle(self.handle.as_raw_handle(), &mut info))?; let mut reparse_tag = 0; if info.dwFileAttributes & c::FILE_ATTRIBUTE_REPARSE_POINT != 0 { - #[cfg(target_family = "rust9x")] - let f = c::GetFileInformationByHandleEx::available(); - #[cfg(not(target_family = "rust9x"))] - let f = Some(c::GetFileInformationByHandleEx); - - if let Some(f) = f { - let mut attr_tag: c::FILE_ATTRIBUTE_TAG_INFO = mem::zeroed(); - cvt(f( - self.handle.as_raw_handle(), - c::FileAttributeTagInfo, - (&raw mut attr_tag).cast(), - size_of::().try_into().unwrap(), - ))?; - if attr_tag.FileAttributes & c::FILE_ATTRIBUTE_REPARSE_POINT != 0 { - reparse_tag = attr_tag.ReparseTag; - } + let mut attr_tag: c::FILE_ATTRIBUTE_TAG_INFO = mem::zeroed(); + // rust9x: If a reparse point attribute is returned, we must be on NT-based Windows + // with support for FileAttributeTagInformation, so our + // fallback implementation of `GetFileInformationByHandleEx` will work without + // further checks. + + cvt(c::GetFileInformationByHandleEx( + self.handle.as_raw_handle(), + c::FileAttributeTagInfo, + (&raw mut attr_tag).cast(), + mem::size_of::().try_into().unwrap(), + ))?; + if attr_tag.FileAttributes & c::FILE_ATTRIBUTE_REPARSE_POINT != 0 { + reparse_tag = attr_tag.ReparseTag; } } Ok(FileAttr { @@ -955,6 +953,10 @@ impl File { /// you will always iterate an empty directory regardless of the target. #[allow(unused)] fn fill_dir_buff(&self, buffer: &mut DirBuff, restart: bool) -> Result { + #[cfg(target_family = "rust9x")] + let class = + if restart { c::FileFullDirectoryRestartInfo } else { c::FileFullDirectoryInfo }; + #[cfg(not(target_family = "rust9x"))] let class = if restart { c::FileIdBothDirectoryRestartInfo } else { c::FileIdBothDirectoryInfo }; @@ -1031,6 +1033,9 @@ impl<'a> Iterator for DirBuffIter<'a> { // `FILE_ID_BOTH_DIR_INFO` and the trailing filename (for at least // `FileNameLength` bytes) let (name, is_directory, next_entry) = unsafe { + #[cfg(target_family = "rust9x")] + let info = buffer.as_ptr().cast::(); + #[cfg(not(target_family = "rust9x"))] let info = buffer.as_ptr().cast::(); // While this is guaranteed to be aligned in documentation for // https://docs.microsoft.com/en-us/windows/win32/api/winbase/ns-winbase-file_id_both_dir_info @@ -1454,12 +1459,10 @@ pub fn remove_dir_all(p: &Path) -> io::Result<()> { use crate::sys::path::with_native_path; with_native_path(p, &|path| { - // if the modern file/directory APIs are not available, we'll fall back to the old (unsafe, see - // https://github.com/rust-lang/rust/pull/93112) directory removal implementation - if !(c::NtOpenFile::available().is_some() - && c::GetFileInformationByHandleEx::available().is_some() - && c::SetFileInformationByHandle::available().is_some()) - { + // if the modern file/directory APIs are not available (9x/Me), we'll fall back to the old + // (unsafe, see https://github.com/rust-lang/rust/pull/93112) directory removal + // implementation + if !crate::sys::compat::checks::is_windows_nt() { let filetype = lstat(path)?.file_type(); if filetype.is_symlink() { // On Windows symlinks to files and directories are removed differently. diff --git a/library/std/src/sys/io/is_terminal/windows.rs b/library/std/src/sys/io/is_terminal/windows.rs index e331fa166c798..0f1c9a61bdcf5 100644 --- a/library/std/src/sys/io/is_terminal/windows.rs +++ b/library/std/src/sys/io/is_terminal/windows.rs @@ -42,10 +42,11 @@ fn msys_tty_on(handle: BorrowedHandle<'_>) -> bool { // Safety: buffer length is fixed. let res = unsafe { #[cfg(target_family = "rust9x")] - let Some(fun) = c::GetFileInformationByHandleEx::available() else { return false }; - #[cfg(not(target_family = "rust9x"))] - let fun = c::GetFileInformationByHandleEx; - fun( + if !crate::sys::compat::checks::is_windows_nt() { + return false; + } + + c::GetFileInformationByHandleEx( handle.as_raw_handle(), c::FileNameInfo, (&raw mut name_info) as *mut c_void, diff --git a/library/std/src/sys/pal/windows/c.rs b/library/std/src/sys/pal/windows/c.rs index 6d465dcc3b2ac..b576e6562e936 100644 --- a/library/std/src/sys/pal/windows/c.rs +++ b/library/std/src/sys/pal/windows/c.rs @@ -12,6 +12,8 @@ use core::ptr; mod windows_sys; pub use windows_sys::*; +#[cfg(target_family = "rust9x")] +pub(crate) mod fileextd; #[cfg(target_family = "rust9x")] pub(crate) mod wspiapi; @@ -464,29 +466,6 @@ compat_fn_with_fallback! { TRUE } } - - // >= Vista / Server 2008 (XP / Server 2003 when linking a supported FileExtd.lib) - // https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-setfileinformationbyhandle - pub fn SetFileInformationByHandle( - hfile: HANDLE, - fileinformationclass: FILE_INFO_BY_HANDLE_CLASS, - lpfileinformation: *const ::core::ffi::c_void, - dwbuffersize: u32, - ) -> BOOL { - unsafe { SetLastError(ERROR_CALL_NOT_IMPLEMENTED as u32); }; - FALSE - } - // >= Vista / Server 2008 (XP / Server 2003 when linking a supported FileExtd.lib) - // https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-getfileinformationbyhandleex - pub fn GetFileInformationByHandleEx( - hfile: HANDLE, - fileinformationclass: FILE_INFO_BY_HANDLE_CLASS, - lpfileinformation: *mut ::core::ffi::c_void, - dwbuffersize: u32, - ) -> BOOL { - unsafe { SetLastError(ERROR_CALL_NOT_IMPLEMENTED as u32); }; - FALSE - } } #[cfg(target_family = "rust9x")] @@ -748,3 +727,55 @@ compat_fn_with_fallback! { FALSE } } + +#[cfg(target_family = "rust9x")] +pub(crate) use fileextd::{ + get_file_information_by_handle_ex as GetFileInformationByHandleEx, + set_file_information_by_handle as SetFileInformationByHandle, +}; + +#[cfg(target_family = "rust9x")] +compat_fn_with_fallback! { + pub static NTDLL: &CStr = c"ntdll" => { load: false, unicows: false }; + // all NT only + fn NtQueryDirectoryFile( + filehandle: HANDLE, + event: HANDLE, + apcroutine: PIO_APC_ROUTINE, + apccontext: *const core::ffi::c_void, + iostatusblock: *mut IO_STATUS_BLOCK, + fileinformation: *mut core::ffi::c_void, + length: u32, + fileinformationclass: FILE_INFORMATION_CLASS, + returnsingleentry: bool, + filename: *const UNICODE_STRING, + restartscan: bool + ) -> NTSTATUS { + rtabort!("unimplemented") + } + fn NtQueryInformationFile( + filehandle: HANDLE, + iostatusblock: *mut IO_STATUS_BLOCK, + fileinformation: *mut core::ffi::c_void, + length: u32, + fileinformationclass: FILE_INFORMATION_CLASS + ) -> NTSTATUS { + rtabort!("unimplemented") + } + fn NtSetInformationFile( + filehandle: HANDLE, + iostatusblock: *mut IO_STATUS_BLOCK, + fileinformation: *const core::ffi::c_void, + length: u32, + fileinformationclass: FILE_INFORMATION_CLASS + ) -> NTSTATUS { + rtabort!("unimplemented") + } + fn NtWaitForSingleObject( + handle: HANDLE, + alertable: bool, + timeout: *mut i64 + ) -> NTSTATUS { + rtabort!("unimplemented") + } +} diff --git a/library/std/src/sys/pal/windows/c/bindings.txt b/library/std/src/sys/pal/windows/c/bindings.txt index f74b0313cce0d..765d6797dc541 100644 --- a/library/std/src/sys/pal/windows/c/bindings.txt +++ b/library/std/src/sys/pal/windows/c/bindings.txt @@ -2047,13 +2047,16 @@ FILE_FLAG_SEQUENTIAL_SCAN FILE_FLAG_SESSION_AWARE FILE_FLAG_WRITE_THROUGH FILE_FLAGS_AND_ATTRIBUTES +FILE_FULL_DIR_INFO FILE_GENERIC_EXECUTE FILE_GENERIC_READ FILE_GENERIC_WRITE FILE_ID_BOTH_DIR_INFO FILE_INFO_BY_HANDLE_CLASS +FILE_INFORMATION_CLASS FILE_IO_PRIORITY_HINT_INFO FILE_LIST_DIRECTORY +FILE_NAME_INFO FILE_NAME_NORMALIZED FILE_NAME_OPENED FILE_NO_EA_KNOWLEDGE @@ -2109,13 +2112,19 @@ FILE_WRITE_THROUGH FileAlignmentInfo FileAllocationInfo FileAttributeTagInfo +FileAttributeTagInformation FileBasicInfo +FileBasicInformation FileCaseSensitiveInfo FileCompressionInfo FileDispositionInfo FileDispositionInfoEx +FileDispositionInformation +FileDispositionInformationEx FileEndOfFileInfo +FileEndOfFileInformation FileFullDirectoryInfo +FileFullDirectoryInformation FileFullDirectoryRestartInfo FileIdBothDirectoryInfo FileIdBothDirectoryRestartInfo @@ -2124,6 +2133,7 @@ FileIdExtdDirectoryRestartInfo FileIdInfo FileIoPriorityHintInfo FileNameInfo +FileNameInformation FileNormalizedNameInfo FileRemoteProtocolInfo FileRenameInfo @@ -2324,8 +2334,12 @@ NtCreateFile NTCREATEFILE_CREATE_DISPOSITION NTCREATEFILE_CREATE_OPTIONS NtOpenFile +NtQueryDirectoryFile +NtQueryInformationFile NtReadFile +NtSetInformationFile NTSTATUS +NtWaitForSingleObject NtWriteFile OBJ_CASE_INSENSITIVE OBJ_DONT_REPARSE diff --git a/library/std/src/sys/pal/windows/c/fileextd.rs b/library/std/src/sys/pal/windows/c/fileextd.rs new file mode 100644 index 0000000000000..a03a376885b21 --- /dev/null +++ b/library/std/src/sys/pal/windows/c/fileextd.rs @@ -0,0 +1,178 @@ +//! Manual implementation of a subset of `GetFileInformationByHandleEx` and +//! `SetFileInformationByHandle` based on `fileextd.lib` from Microsoft. Many of their later-added +//! APIs do exist all the way back to NT3.1, but were not exposed via a Win32 API until later. + +use super::*; + +pub(crate) unsafe fn get_file_information_by_handle_ex( + file_handle: HANDLE, + fileinformationclass: FILE_INFO_BY_HANDLE_CLASS, + lpfileinformation: *mut core::ffi::c_void, + dwbuffersize: u32, +) -> BOOL { + if !crate::sys::compat::checks::is_windows_nt() { + unsafe { SetLastError(ERROR_CALL_NOT_IMPLEMENTED) }; + return FALSE; + } + + unsafe { + #[allow(non_upper_case_globals)] + let (class, min_buffer_size, use_directory_api_info): ( + FILE_INFORMATION_CLASS, + u32, + Option, + ) = match fileinformationclass { + FileBasicInfo => { + (FileBasicInformation, core::mem::size_of::() as u32, None) + } + FileNameInfo => { + (FileNameInformation, core::mem::size_of::() as u32, None) + } + FileAttributeTagInfo => ( + // NT API: 2000 and up + FileAttributeTagInformation, + core::mem::size_of::() as u32, + None, + ), + // + // rust9x NOTE: these two (FileIdBothDirectoryInfo, FileIdBothDirectoryRestartInfo) are + // replaced with FileFullDirectoryInfo/FileFullDirectoryRestartInfo below, as the Full + // versions are available on older Windows versions. + // + // FileIdBothDirectoryInfo => ( + // // NT API: XP/2003 and up; exposed via Win32 API since Vista + // FileIdBothDirectoryInformation, + // core::mem::size_of::() as u32, + // Some(false), + // ), + // FileIdBothDirectoryRestartInfo => ( + // // NT API: XP/2003 and up; exposed via Win32 API since Vista + // FileIdBothDirectoryInformation, + // core::mem::size_of::() as u32, + // Some(true), + // ), + FileFullDirectoryInfo => ( + // NT API: at least NT4 but likely 3.1+; exposed via Win32 API since Win8 + FileFullDirectoryInformation, + core::mem::size_of::() as u32, + Some(false), + ), + FileFullDirectoryRestartInfo => ( + // NT API: at least NT4 but likely 3.1+; exposed via Win32 API since Win8 + FileFullDirectoryInformation, + core::mem::size_of::() as u32, + Some(true), + ), + _ => { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + }; + + if dwbuffersize < min_buffer_size { + SetLastError(ERROR_BAD_LENGTH); + return FALSE; + } + + let mut io_status_block: IO_STATUS_BLOCK = core::mem::zeroed(); + let mut status = if let Some(restart_scan) = use_directory_api_info { + NtQueryDirectoryFile( + file_handle, + core::ptr::null_mut(), + None, + core::ptr::null(), + &mut io_status_block, + lpfileinformation, + dwbuffersize, + class, + false, + core::ptr::null(), + restart_scan, + ) + } else { + NtQueryInformationFile( + file_handle, + &mut io_status_block, + lpfileinformation, + dwbuffersize, + class, + ) + }; + + if status == STATUS_PENDING { + status = NtWaitForSingleObject(file_handle, false, core::ptr::null_mut()); + } + + if status < 0 { + set_last_error_from_ntstatus(status); + return FALSE; + } + + // keeping for reference; FileStreamInformation is not used by the standard library + // currently if class == FileStreamInformation && io_status_block.Information == 0 { + // set_last_error_from_ntstatus(STATUS_END_OF_FILE); return FALSE; } + } + TRUE +} + +pub(crate) unsafe fn set_file_information_by_handle( + file_handle: HANDLE, + fileinformationclass: FILE_INFO_BY_HANDLE_CLASS, + lpfileinformation: *const core::ffi::c_void, + dwbuffersize: u32, +) -> BOOL { + if !crate::sys::compat::checks::is_windows_nt() { + unsafe { SetLastError(ERROR_CALL_NOT_IMPLEMENTED) }; + return FALSE; + } + + unsafe { + #[allow(non_upper_case_globals)] + let (class, min_buffer_size): (FILE_INFORMATION_CLASS, u32) = match fileinformationclass { + FileBasicInfo => (FileBasicInformation, core::mem::size_of::() as u32), + FileEndOfFileInfo => { + (FileEndOfFileInformation, core::mem::size_of::() as u32) + } + FileDispositionInfo => { + (FileDispositionInformation, core::mem::size_of::() as u32) + } + FileDispositionInfoEx => ( + // NT API: some Windows 10 version + FileDispositionInformationEx, + core::mem::size_of::() as u32, + ), + _ => { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + }; + + if dwbuffersize < min_buffer_size { + SetLastError(ERROR_BAD_LENGTH); + return FALSE; + } + + let mut io_status_block: IO_STATUS_BLOCK = core::mem::zeroed(); + let status = NtSetInformationFile( + file_handle, + &mut io_status_block, + lpfileinformation, + dwbuffersize, + class, + ); + + if status < 0 { + set_last_error_from_ntstatus(status); + return FALSE; + } + } + + TRUE +} + +fn set_last_error_from_ntstatus(status: NTSTATUS) { + unsafe { + let error = RtlNtStatusToDosError(status); + SetLastError(error); + } +} diff --git a/library/std/src/sys/pal/windows/c/windows_sys.rs b/library/std/src/sys/pal/windows/c/windows_sys.rs index eab5fa89cfe70..211868860b2be 100644 --- a/library/std/src/sys/pal/windows/c/windows_sys.rs +++ b/library/std/src/sys/pal/windows/c/windows_sys.rs @@ -89,7 +89,11 @@ windows_targets::link!("kernel32.dll" "system" fn MoveFileExW(lpexistingfilename windows_targets::link!("kernel32.dll" "system" fn MultiByteToWideChar(codepage : u32, dwflags : MULTI_BYTE_TO_WIDE_CHAR_FLAGS, lpmultibytestr : PCSTR, cbmultibyte : i32, lpwidecharstr : PWSTR, cchwidechar : i32) -> i32); windows_targets::link!("ntdll.dll" "system" fn NtCreateFile(filehandle : *mut HANDLE, desiredaccess : FILE_ACCESS_RIGHTS, objectattributes : *const OBJECT_ATTRIBUTES, iostatusblock : *mut IO_STATUS_BLOCK, allocationsize : *const i64, fileattributes : FILE_FLAGS_AND_ATTRIBUTES, shareaccess : FILE_SHARE_MODE, createdisposition : NTCREATEFILE_CREATE_DISPOSITION, createoptions : NTCREATEFILE_CREATE_OPTIONS, eabuffer : *const core::ffi::c_void, ealength : u32) -> NTSTATUS); windows_targets::link!("ntdll.dll" "system" fn NtOpenFile(filehandle : *mut HANDLE, desiredaccess : u32, objectattributes : *const OBJECT_ATTRIBUTES, iostatusblock : *mut IO_STATUS_BLOCK, shareaccess : u32, openoptions : u32) -> NTSTATUS); +windows_targets::link!("ntdll.dll" "system" fn NtQueryDirectoryFile(filehandle : HANDLE, event : HANDLE, apcroutine : PIO_APC_ROUTINE, apccontext : *const core::ffi::c_void, iostatusblock : *mut IO_STATUS_BLOCK, fileinformation : *mut core::ffi::c_void, length : u32, fileinformationclass : FILE_INFORMATION_CLASS, returnsingleentry : bool, filename : *const UNICODE_STRING, restartscan : bool) -> NTSTATUS); +windows_targets::link!("ntdll.dll" "system" fn NtQueryInformationFile(filehandle : HANDLE, iostatusblock : *mut IO_STATUS_BLOCK, fileinformation : *mut core::ffi::c_void, length : u32, fileinformationclass : FILE_INFORMATION_CLASS) -> NTSTATUS); windows_targets::link!("ntdll.dll" "system" fn NtReadFile(filehandle : HANDLE, event : HANDLE, apcroutine : PIO_APC_ROUTINE, apccontext : *const core::ffi::c_void, iostatusblock : *mut IO_STATUS_BLOCK, buffer : *mut core::ffi::c_void, length : u32, byteoffset : *const i64, key : *const u32) -> NTSTATUS); +windows_targets::link!("ntdll.dll" "system" fn NtSetInformationFile(filehandle : HANDLE, iostatusblock : *mut IO_STATUS_BLOCK, fileinformation : *const core::ffi::c_void, length : u32, fileinformationclass : FILE_INFORMATION_CLASS) -> NTSTATUS); +windows_targets::link!("ntdll.dll" "system" fn NtWaitForSingleObject(handle : HANDLE, alertable : bool, timeout : *mut i64) -> NTSTATUS); windows_targets::link!("ntdll.dll" "system" fn NtWriteFile(filehandle : HANDLE, event : HANDLE, apcroutine : PIO_APC_ROUTINE, apccontext : *const core::ffi::c_void, iostatusblock : *mut IO_STATUS_BLOCK, buffer : *const core::ffi::c_void, length : u32, byteoffset : *const i64, key : *const u32) -> NTSTATUS); windows_targets::link!("advapi32.dll" "system" fn OpenProcessToken(processhandle : HANDLE, desiredaccess : TOKEN_ACCESS_MASK, tokenhandle : *mut HANDLE) -> BOOL); windows_targets::link!("kernel32.dll" "system" fn QueryPerformanceCounter(lpperformancecount : *mut i64) -> BOOL); @@ -2570,6 +2574,27 @@ pub const FILE_FLAG_RANDOM_ACCESS: FILE_FLAGS_AND_ATTRIBUTES = 268435456u32; pub const FILE_FLAG_SEQUENTIAL_SCAN: FILE_FLAGS_AND_ATTRIBUTES = 134217728u32; pub const FILE_FLAG_SESSION_AWARE: FILE_FLAGS_AND_ATTRIBUTES = 8388608u32; pub const FILE_FLAG_WRITE_THROUGH: FILE_FLAGS_AND_ATTRIBUTES = 2147483648u32; +#[repr(C)] +#[derive(Clone, Copy)] +pub struct FILE_FULL_DIR_INFO { + pub NextEntryOffset: u32, + pub FileIndex: u32, + pub CreationTime: i64, + pub LastAccessTime: i64, + pub LastWriteTime: i64, + pub ChangeTime: i64, + pub EndOfFile: i64, + pub AllocationSize: i64, + pub FileAttributes: u32, + pub FileNameLength: u32, + pub EaSize: u32, + pub FileName: [u16; 1], +} +impl Default for FILE_FULL_DIR_INFO { + fn default() -> Self { + unsafe { core::mem::zeroed() } + } +} pub const FILE_GENERIC_EXECUTE: FILE_ACCESS_RIGHTS = 1179808u32; pub const FILE_GENERIC_READ: FILE_ACCESS_RIGHTS = 1179785u32; pub const FILE_GENERIC_WRITE: FILE_ACCESS_RIGHTS = 1179926u32; @@ -2597,6 +2622,7 @@ impl Default for FILE_ID_BOTH_DIR_INFO { unsafe { core::mem::zeroed() } } } +pub type FILE_INFORMATION_CLASS = i32; pub type FILE_INFO_BY_HANDLE_CLASS = i32; #[repr(C)] #[derive(Clone, Copy, Default)] @@ -2604,6 +2630,17 @@ pub struct FILE_IO_PRIORITY_HINT_INFO { pub PriorityHint: PRIORITY_HINT, } pub const FILE_LIST_DIRECTORY: FILE_ACCESS_RIGHTS = 1u32; +#[repr(C)] +#[derive(Clone, Copy)] +pub struct FILE_NAME_INFO { + pub FileNameLength: u32, + pub FileName: [u16; 1], +} +impl Default for FILE_NAME_INFO { + fn default() -> Self { + unsafe { core::mem::zeroed() } + } +} pub const FILE_NAME_NORMALIZED: GETFINALPATHNAMEBYHANDLE_FLAGS = 0u32; pub const FILE_NAME_OPENED: GETFINALPATHNAMEBYHANDLE_FLAGS = 8u32; pub const FILE_NON_DIRECTORY_FILE: NTCREATEFILE_CREATE_OPTIONS = 64u32; @@ -2746,13 +2783,19 @@ pub const FSCTL_SET_REPARSE_POINT: u32 = 589988u32; pub const FileAlignmentInfo: FILE_INFO_BY_HANDLE_CLASS = 17i32; pub const FileAllocationInfo: FILE_INFO_BY_HANDLE_CLASS = 5i32; pub const FileAttributeTagInfo: FILE_INFO_BY_HANDLE_CLASS = 9i32; +pub const FileAttributeTagInformation: FILE_INFORMATION_CLASS = 35i32; pub const FileBasicInfo: FILE_INFO_BY_HANDLE_CLASS = 0i32; +pub const FileBasicInformation: FILE_INFORMATION_CLASS = 4i32; pub const FileCaseSensitiveInfo: FILE_INFO_BY_HANDLE_CLASS = 23i32; pub const FileCompressionInfo: FILE_INFO_BY_HANDLE_CLASS = 8i32; pub const FileDispositionInfo: FILE_INFO_BY_HANDLE_CLASS = 4i32; pub const FileDispositionInfoEx: FILE_INFO_BY_HANDLE_CLASS = 21i32; +pub const FileDispositionInformation: FILE_INFORMATION_CLASS = 13i32; +pub const FileDispositionInformationEx: FILE_INFORMATION_CLASS = 64i32; pub const FileEndOfFileInfo: FILE_INFO_BY_HANDLE_CLASS = 6i32; +pub const FileEndOfFileInformation: FILE_INFORMATION_CLASS = 20i32; pub const FileFullDirectoryInfo: FILE_INFO_BY_HANDLE_CLASS = 14i32; +pub const FileFullDirectoryInformation: FILE_INFORMATION_CLASS = 2i32; pub const FileFullDirectoryRestartInfo: FILE_INFO_BY_HANDLE_CLASS = 15i32; pub const FileIdBothDirectoryInfo: FILE_INFO_BY_HANDLE_CLASS = 10i32; pub const FileIdBothDirectoryRestartInfo: FILE_INFO_BY_HANDLE_CLASS = 11i32; @@ -2761,6 +2804,7 @@ pub const FileIdExtdDirectoryRestartInfo: FILE_INFO_BY_HANDLE_CLASS = 20i32; pub const FileIdInfo: FILE_INFO_BY_HANDLE_CLASS = 18i32; pub const FileIoPriorityHintInfo: FILE_INFO_BY_HANDLE_CLASS = 12i32; pub const FileNameInfo: FILE_INFO_BY_HANDLE_CLASS = 2i32; +pub const FileNameInformation: FILE_INFORMATION_CLASS = 9i32; pub const FileNormalizedNameInfo: FILE_INFO_BY_HANDLE_CLASS = 24i32; pub const FileRemoteProtocolInfo: FILE_INFO_BY_HANDLE_CLASS = 13i32; pub const FileRenameInfo: FILE_INFO_BY_HANDLE_CLASS = 3i32; From e646ff96fb1bada17e8e09810a6a158bf3d2ff5c Mon Sep 17 00:00:00 2001 From: Dennis Duda Date: Thu, 1 Jan 2026 19:17:23 +0100 Subject: [PATCH 38/58] Add patched backtrace crate - Get rid of RtlCaptureContext import, manually implement it - Add support for older dbghelp versions. With this, backtraces on XP+ are supported out of the box. It seems that the "best" version for old systems is the one from VS2005, found in "Microsoft Visual Studio 8\Common7\IDE\dbghelp.dll". This one is compiled with 9x support (unlike the VS2003 one!). --- .gitmodules | 3 ++- library/backtrace | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.gitmodules b/.gitmodules index 8617643a12029..1bcef88f01d4b 100644 --- a/.gitmodules +++ b/.gitmodules @@ -33,8 +33,9 @@ shallow = true [submodule "library/backtrace"] path = library/backtrace - url = https://github.com/rust-lang/backtrace-rs.git + url = https://github.com/rust9x/backtrace-rs.git shallow = true + branch = rust9x-1.93-beta [submodule "src/tools/rustc-perf"] path = src/tools/rustc-perf url = https://github.com/rust-lang/rustc-perf.git diff --git a/library/backtrace b/library/backtrace index b65ab935fb2e0..f9456b4b5c889 160000 --- a/library/backtrace +++ b/library/backtrace @@ -1 +1 @@ -Subproject commit b65ab935fb2e0d59dba8966ffca09c9cc5a5f57c +Subproject commit f9456b4b5c889123b61480ff1540e6d7ed8ead1d From b44fed05cae814aad46ce8047463267e8353bc01 Mon Sep 17 00:00:00 2001 From: zhangxuan2011 Date: Sun, 22 Feb 2026 15:36:18 +0800 Subject: [PATCH 39/58] docs: Updated docs - Update README.md to adapt the rust9x - Remove INSTALL.md and CODE_OF_CONDUCT.md to remove the unnessary docs --- CODE_OF_CONDUCT.md | 3 - INSTALL.md | 310 --------------------------------------------- README.md | 89 +++++++++---- 3 files changed, 61 insertions(+), 341 deletions(-) delete mode 100644 CODE_OF_CONDUCT.md delete mode 100644 INSTALL.md diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md deleted file mode 100644 index e3708bc485399..0000000000000 --- a/CODE_OF_CONDUCT.md +++ /dev/null @@ -1,3 +0,0 @@ -# The Rust Code of Conduct - -The Code of Conduct for this repository [can be found online](https://www.rust-lang.org/conduct.html). diff --git a/INSTALL.md b/INSTALL.md deleted file mode 100644 index 98eb825cd10f6..0000000000000 --- a/INSTALL.md +++ /dev/null @@ -1,310 +0,0 @@ -# Installing from Source - -**Note: This document describes _building_ Rust _from source_. -This is _not recommended_ if you don't know what you're doing. -If you just want to install Rust, check out the [README.md](README.md) instead.** - -The Rust build system uses a Python script called `x.py` to build the compiler, -which manages the bootstrapping process. It lives at the root of the project. -It also uses a file named `bootstrap.toml` to determine various configuration -settings for the build. You can see a full list of options in -`bootstrap.example.toml`. - -The `x.py` command can be run directly on most Unix systems in the following -format: - -```sh -./x.py [flags] -``` - -This is how the documentation and examples assume you are running `x.py`. -See the [rustc dev guide][rustcguidebuild] if this does not work on your -platform. - -More information about `x.py` can be found by running it with the `--help` flag -or reading the [rustc dev guide][rustcguidebuild]. - -[gettingstarted]: https://rustc-dev-guide.rust-lang.org/getting-started.html -[rustcguidebuild]: https://rustc-dev-guide.rust-lang.org/building/how-to-build-and-run.html#what-is-xpy - -## Dependencies - -Make sure you have installed the dependencies: - -* `python` 3 or 2.7 -* `git` -* A C compiler (when building for the host, `cc` is enough; cross-compiling may - need additional compilers) -* `curl` (not needed on Windows) -* `pkg-config` if you are compiling on Linux and targeting Linux -* `libiconv` (already included with glibc on Debian-based distros) - -To build Cargo, you'll also need OpenSSL (`libssl-dev` or `openssl-devel` on -most Unix distros). - -If building LLVM from source, you'll need additional tools: - -* `g++`, `clang++`, or MSVC with versions listed on - [LLVM's documentation](https://llvm.org/docs/GettingStarted.html#host-c-toolchain-both-compiler-and-standard-library) -* `ninja`, or GNU `make` 3.81 or later (Ninja is recommended, especially on - Windows) -* `cmake` version listed on [LLVM's documentation](https://llvm.org/docs/GettingStarted.html#software) -* `libstdc++-static` may be required on some Linux distributions such as Fedora - and Ubuntu - -On tier 1 or tier 2 with host tools platforms, you can also choose to download -LLVM by setting `llvm.download-ci-llvm = true`. -Otherwise, you'll need LLVM installed and `llvm-config` in your path. -See [the rustc-dev-guide for more info][sysllvm]. - -[sysllvm]: https://rustc-dev-guide.rust-lang.org/building/new-target.html#using-pre-built-llvm - - -## Building on a Unix-like system - -### Build steps - -1. Clone the [source] with `git`: - - ```sh - git clone https://github.com/rust-lang/rust.git - cd rust - ``` - -[source]: https://github.com/rust-lang/rust - -2. Configure the build settings: - - If you're unsure which build configurations to use and need a good default, you - can run the interactive `x.py setup` command. This will guide you through selecting - a config profile, setting up the LSP, configuring a Git hook, etc. - - With `configure` script, you can handle multiple configurations in a single - command which is useful to create complex/advanced config files. For example: - - ```sh - ./configure --build=aarch64-unknown-linux-gnu \ - --enable-full-tools \ - --enable-profiler \ - --enable-sanitizers \ - --enable-compiler-docs \ - --set target.aarch64-unknown-linux-gnu.linker=clang \ - --set target.aarch64-unknown-linux-gnu.ar=/rustroot/bin/llvm-ar \ - --set target.aarch64-unknown-linux-gnu.ranlib=/rustroot/bin/llvm-ranlib \ - --set llvm.link-shared=true \ - --set llvm.thin-lto=true \ - --set llvm.libzstd=true \ - --set llvm.ninja=false \ - --set rust.debug-assertions=false \ - --set rust.jemalloc \ - --set rust.use-lld=true \ - --set rust.lto=thin \ - --set rust.codegen-units=1 - ``` - - If you plan to use `x.py install` to create an installation, you can either - set `DESTDIR` environment variable to your custom directory path: - - ```bash - export DESTDIR= - ``` - - or set `prefix` and `sysconfdir` in the `[install]` section to your custom - directory path: - - ```sh - ./configure --set install.prefix= --set install.sysconfdir= - ``` - - When the `DESTDIR` environment variable is present, the `prefix` and - `sysconfdir` values are combined with the path from the `DESTDIR` - environment variable. - -3. Build and install: - - ```sh - ./x.py build && ./x.py install - ``` - - When complete, `./x.py install` will place several programs into - `$PREFIX/bin`: `rustc`, the Rust compiler, and `rustdoc`, the - API-documentation tool. By default, it will also include [Cargo], Rust's - package manager. You can disable this behavior by passing - `--set build.extended=false` to `./configure`. - -[Cargo]: https://github.com/rust-lang/cargo - -### Configure and Make - -This project provides a configure script and makefile (the latter of which just -invokes `x.py`). `./configure` is the recommended way to programmatically -generate a `bootstrap.toml`. `make` is not recommended (we suggest using `x.py` -directly), but it is supported and we try not to break it unnecessarily. - -```sh -./configure -make && sudo make install -``` - -`configure` generates a `bootstrap.toml` which can also be used with normal `x.py` -invocations. - -## Building on Windows - -On Windows, we suggest using [winget] to install dependencies by running the -following in a terminal: - -```powershell -winget install -e Python.Python.3 -winget install -e Kitware.CMake -winget install -e Git.Git -``` - -Then edit your system's `PATH` variable and add: `C:\Program Files\CMake\bin`. -See -[this guide on editing the system `PATH`](https://www.java.com/en/download/help/path.html) -from the Java documentation. - -[winget]: https://github.com/microsoft/winget-cli - -There are two prominent ABIs in use on Windows: the native (MSVC) ABI used by -Visual Studio and the GNU ABI used by the GCC toolchain. Which version of Rust -you need depends largely on what C/C++ libraries you want to interoperate with. -Use the MSVC build of Rust to interop with software produced by Visual Studio -and the GNU build to interop with GNU software built using the MinGW/MSYS2 -toolchain. - -### MinGW - -[MSYS2][msys2] can be used to easily build Rust on Windows: - -[msys2]: https://www.msys2.org/ - -1. Download the latest [MSYS2 installer][msys2] and go through the installer. - -2. Download and install [Git for Windows](https://git-scm.com/download/win). - Make sure that it's in your Windows PATH. To enable access to it from within - MSYS2, edit the relevant `mingw[32|64].ini` file in your MSYS2 installation - directory and uncomment the line `MSYS2_PATH_TYPE=inherit`. - - You could install and use MSYS2's version of git instead with `pacman`, - however this is not recommended as it's excruciatingly slow, and not frequently - tested for compatibility. - -3. Start a MINGW64 or MINGW32 shell (depending on whether you want 32-bit - or 64-bit Rust) either from your start menu, or by running `mingw64.exe` - or `mingw32.exe` from your MSYS2 installation directory (e.g. `C:\msys64`). - -4. From this terminal, install the required tools: - - ```sh - # Update package mirrors (may be needed if you have a fresh install of MSYS2) - pacman -Sy pacman-mirrors - - # Install build tools needed for Rust. If you're building a 32-bit compiler, - # then replace "x86_64" below with "i686". - # Note that it is important that you do **not** use the 'python2', 'cmake', - # and 'ninja' packages from the 'msys2' subsystem. - # The build has historically been known to fail with these packages. - pacman -S make \ - diffutils \ - tar \ - mingw-w64-x86_64-python \ - mingw-w64-x86_64-cmake \ - mingw-w64-x86_64-gcc \ - mingw-w64-x86_64-ninja - ``` - -5. Navigate to Rust's source code (or clone it), then build it: - - ```sh - python x.py setup dist && python x.py build && python x.py install - ``` - -If you want to try the native Windows versions of Python or CMake, you can remove -them from the above pacman command and install them from another source. Follow -the instructions in step 2 to get them on PATH. - -Using Windows native Python can be helpful if you get errors when building LLVM. -You may also want to use Git for Windows, as it is often *much* faster. Turning -off real-time protection in the Windows Virus & Threat protections settings can -also help with long run times (although note that it will automatically turn -itself back on after some time). - -### MSVC - -MSVC builds of Rust additionally requires an installation of: - -- Visual Studio 2022 (or later) build tools so `rustc` can use its linker. Older - Visual Studio versions such as 2019 *may* work but aren't actively tested. -- A recent Windows 10 or 11 SDK. - -The simplest way is to get [Visual Studio], check the "C++ build tools". - -[Visual Studio]: https://visualstudio.microsoft.com/downloads/ - -(If you're installing CMake yourself, be careful that "C++ CMake tools for -Windows" doesn't get included under "Individual components".) - -With these dependencies installed, you can build the compiler in a `cmd.exe` -shell with: - -```sh -python x.py setup user -python x.py build -``` - -Right now, building Rust only works with some known versions of Visual Studio. -If you have a more recent version installed and the build system doesn't -understand, you may need to force bootstrap to use an older version. -This can be done by manually calling the appropriate vcvars file before running -the bootstrap. - -```batch -CALL "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvars64.bat" -python x.py build -``` - -### Specifying an ABI - -Each specific ABI can also be used from either environment (for example, using -the GNU ABI in PowerShell) by using an explicit build triple. The available -Windows build triples are: -- GNU ABI (using GCC) - - `i686-pc-windows-gnu` - - `x86_64-pc-windows-gnu` -- The MSVC ABI - - `i686-pc-windows-msvc` - - `x86_64-pc-windows-msvc` - -The build triple can be specified by either specifying `--build=` when -invoking `x.py` commands, or by creating a `bootstrap.toml` file (as described in -[Building on a Unix-like system](#building-on-a-unix-like-system)), and passing -`--set build.build=` to `./configure`. - -## Building Documentation - -If you'd like to build the documentation, it's almost the same: - -```sh -./x.py doc -``` - -The generated documentation will appear under `doc` in the `build` directory for -the ABI used. That is, if the ABI was `x86_64-pc-windows-msvc`, the directory -will be `build\x86_64-pc-windows-msvc\doc`. - -## Notes - -Since the Rust compiler is written in Rust, it must be built by a precompiled -"snapshot" version of itself (made in an earlier stage of development). -As such, source builds require an Internet connection to fetch snapshots, and an -OS that can execute the available snapshot binaries. - -See https://doc.rust-lang.org/nightly/rustc/platform-support.html for a list of -supported platforms. -Only "host tools" platforms have a pre-compiled snapshot binary available; to -compile for a platform without host tools you must cross-compile. - -You may find that other platforms work, but these are our officially supported -build environments that are most likely to work. diff --git a/README.md b/README.md index 611260470f12b..020ba0aa860d0 100644 --- a/README.md +++ b/README.md @@ -6,53 +6,82 @@ src="https://raw.githubusercontent.com/rust-lang/www.rust-lang.org/master/static/images/rust-social-wide-light.svg" width="50%"> - -[Website][Rust] | [Getting started] | [Learn] | [Documentation] | [Contributing] -This is the main source code repository for [Rust]. It contains the compiler, +This is the main source code repository for [Rust9x]. It contains the compiler, standard library, and documentation. -[Rust]: https://www.rust-lang.org/ -[Getting Started]: https://www.rust-lang.org/learn/get-started -[Learn]: https://www.rust-lang.org/learn -[Documentation]: https://www.rust-lang.org/learn#learn-use -[Contributing]: CONTRIBUTING.md - -## Why Rust? - -- **Performance:** Fast and memory-efficient, suitable for critical services, embedded devices, and easily integrated with other languages. +Note that this project can not only used on Windows 10 and 11, but also on Windows 7, XP, even +Windows 2000, 98 and 95 -- **Reliability:** Our rich type system and ownership model ensure memory and thread safety, reducing bugs at compile-time. +# Links -- **Productivity:** Comprehensive documentation, a compiler committed to providing great diagnostics, and advanced tooling including package manager and build tool ([Cargo]), auto-formatter ([rustfmt]), linter ([Clippy]) and editor support ([rust-analyzer]). +## Official [Cargo]: https://github.com/rust-lang/cargo [rustfmt]: https://github.com/rust-lang/rustfmt [Clippy]: https://github.com/rust-lang/rust-clippy [rust-analyzer]: https://github.com/rust-lang/rust-analyzer -## Quick Start +## Rust9x +[Wiki]: https://github.com/rust9x/rust/wiki + +# Build + +If you want to build this source by yourself, you can follow [this instructions](https://github.com/rust9x/rust/wiki#installation) and set up your target. + +# Install + +If you think build this source is so sucks, perhaps you can follow this: + +1. Download the latest release + +View [here](https://github.com/zhangxuan/rust9x/releases/latest) and choose the best platform for you. + +If you don't know how to choose, you can click [here](#choose-the-platform) -Read ["Installation"] from [The Book]. +## Choose the platform -["Installation"]: https://doc.rust-lang.org/book/ch01-01-installation.html -[The Book]: https://doc.rust-lang.org/book/index.html +When you visited the release page, you might see these assets: +- `rust9x-toolchain--x86_64-windows.tar.gz` +- `rust9x-toolchain--i686-windows.tar.gz` +- `rust9x-toolchain--i586-windows.tar.gz` -## Installing from Source +For each assets has its own platform, you can choose the one that fits the target system. -If you really want to install from source (though this is not recommended), see -[INSTALL.md](INSTALL.md). +### x86_64 Windows -## Getting Help +File name: `rust9x-toolchain--x86_64-windows.tar.gz` -See https://www.rust-lang.org/community for a list of chat platforms and forums. +Support targets: +- Windows 10 and 11 +- x86_64 systems (simply called "64-bit systems") -## Contributing +### i686 Windows -See [CONTRIBUTING.md](CONTRIBUTING.md). +File name: `rust9x-toolchain--i686-windows.tar.gz` -## License +Support targets: +- Windows 7 and XP +- i686 systems (simply called "32-bit systems") + +### i586 Windows + +File name: `rust9x-toolchain--i586-windows.tar.gz` + +Support targets: +- Windows 2000, Windows 9x and older +- i586 systems (simply called "16-bit systems") + +For more information, please visit [here](https://github.com/rust9x/rust/wiki#installation) + +# Contributing + +Thanks for your interest in contributing to this project! + +If you want to know more, perhaps you can see [CONTRIBUTING.md](CONTRIBUTING.md) for more details. + +# License Rust is primarily distributed under the terms of both the MIT license and the Apache License (Version 2.0), with portions covered by various BSD-like @@ -61,7 +90,11 @@ licenses. See [LICENSE-APACHE](LICENSE-APACHE), [LICENSE-MIT](LICENSE-MIT), and [COPYRIGHT](COPYRIGHT) for details. -## Trademark +# The Rust Code of Conduct + +The Code of Conduct for this repository can be found [here](https://www.rust-lang.org/conduct.html). + +# Trademark [The Rust Foundation][rust-foundation] owns and protects the Rust and Cargo trademarks and logos (the "Rust Trademarks"). @@ -74,4 +107,4 @@ Third-party logos may be subject to third-party copyrights and trademarks. See [rust-foundation]: https://rustfoundation.org/ [trademark-policy]: https://rustfoundation.org/policy/rust-trademark-policy/ -[policies-licenses]: https://www.rust-lang.org/policies/licenses +[policies-licenses]: https://www.rust-lang.org/policies/licenses \ No newline at end of file From 045255cb45ba207fc37fed271cf2f75e4d1b146c Mon Sep 17 00:00:00 2001 From: zhangxuan2011 Date: Sun, 22 Feb 2026 15:39:07 +0800 Subject: [PATCH 40/58] refactor(bootstrap): Updated bootstrap - Added some comments of the bootstrap - Enabled some extended tools - Enabled incremental build --- bootstrap.rust9x.toml | 26 ++++++++++---------------- 1 file changed, 10 insertions(+), 16 deletions(-) diff --git a/bootstrap.rust9x.toml b/bootstrap.rust9x.toml index c57817af878a3..e4f11d16b1475 100644 --- a/bootstrap.rust9x.toml +++ b/bootstrap.rust9x.toml @@ -6,7 +6,7 @@ change-id = 148795 # Will download LLVM from CI if available on your platform. download-ci-llvm = true # NOTE: if you set ↑ to false, disable other LLVM targets to save lots of build time! -# targets = "X86" +targets = "X86" # experimental-targets = "" [build] @@ -17,22 +17,16 @@ target = [ "x86_64-rust9x-windows-msvc", "x86_64-pc-windows-msvc", ] - +# The docs is unnessary to build, because it's as same as the official one docs = false -# extended = true -# tools = [ -# # "cargo", -# # "clippy", -# "rustdoc", -# # "rustfmt", -# # "rust-analyzer", -# # "rust-analyzer-proc-macro-srv", -# # "analysis", -# "src", -# # "wasm-component-ld", -# # "miri", "cargo-miri" # for dev/nightly channels -# ] +# We want the extended tools +extended = true +tools = [ + "cargo", + "rustdoc", + "src", +] [install] # for creating a downloadable package: python x.py install, then create and archive this @@ -46,7 +40,7 @@ dist-src = false # you can override this with -i/--incremental # incremental = false -# incremental = true +incremental = true [dist] src-tarball = false From b4eb5f920b7e323698b11b1adb99250ef9da2757 Mon Sep 17 00:00:00 2001 From: zhangxuan2011 Date: Sun, 22 Feb 2026 15:40:59 +0800 Subject: [PATCH 41/58] fix(bootstrap): Fixed encoding issue - Uses UTF-8 always to read config file - Friendly in Chinese/otherlang PC [including me :) ] --- src/bootstrap/bootstrap.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index 4dd465edb0df9..1455a47b1ccdf 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -1316,7 +1316,7 @@ def bootstrap(args): # Give a hard error if `--config` or `RUST_BOOTSTRAP_CONFIG` are set to a missing path, # but not if `bootstrap.toml` hasn't been created. if not using_default_path or os.path.exists(toml_path): - with open(toml_path) as config: + with open(toml_path, encoding="utf-8") as config: config_toml = config.read() else: config_toml = "" From cda3e5172cc307a3437a263112fcbc0f7e299d05 Mon Sep 17 00:00:00 2001 From: zhangxuan2011 Date: Sun, 22 Feb 2026 15:43:18 +0800 Subject: [PATCH 42/58] ci: Added auto-build workflow --- .github/workflows/build-target.yml | 88 ++++++++++++++++++++++++++++++ 1 file changed, 88 insertions(+) create mode 100644 .github/workflows/build-target.yml diff --git a/.github/workflows/build-target.yml b/.github/workflows/build-target.yml new file mode 100644 index 0000000000000..d114157623185 --- /dev/null +++ b/.github/workflows/build-target.yml @@ -0,0 +1,88 @@ +# This workflow will build the current toolchain automatically, and +# push it into release. +# +# It will also built-in an install script, which can scan it as a rustup toolchain, so +# that we can manage them easily. +# +# If we can, we will add multiple platform support (e.g. Windows, macOS, Linux) +# so that you can do cross-compile by using this toolchain. +# +# Workflow file by "zhangxuan2011 " + +name: Build Target Toolchain + +on: + push: + tags: + - "v*" + workflow_dispatch: + +permissions: + contents: write + +jobs: + build: + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + include: + # Windows, x86_64 + - os: windows-latest + arch: x64 + target: x86_64-pc-windows-msvc + target_short: x86_64-windows + + # Windows, i686 + - os: windows-latest + arch: x86 + target: i686-pc-windows-msvc + target_short: i686-windows + + # Windows, i586 + - os: windows-latest + arch: x86 + target: i586-pc-windows-msvc + target_short: i586-windows + + defaults: + run: + shell: cmd + + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + submodules: recursive + + - name: Install NASM + run: choco install nasm -y + + - name: Activate MSVC environment + uses: ilammy/msvc-dev-cmd@v1 + with: + arch: ${{ matrix.arch }} + + - name: Build toolchain + run: | + python x.py install --config bootstrap.rust9x.toml + if %errorlevel% neq 0 exit /b 1 + + - name: Pack toolchain + run: | + set VERSION=${{ github.ref_name }} + set ARCHIVE_NAME=rust9x-toolchain-%VERSION%-${{ matrix.target_short }}.tar.gz + + :: Check build folder + if not exist "build" ( + echo Error: build directory not found + exit /b 1 + ) + + :: Pack everything inside build + tar -czvf "%ARCHIVE_NAME%" -C dist/rust9x + + - name: Upload to release + uses: softprops/action-gh-release@v2 + with: + files: rust9x-toolchain-*.tar.gz From b011bfc5449fb82b0c7503093b9f3284f753dcd6 Mon Sep 17 00:00:00 2001 From: zhangxuan <114813512+zhangxuan2011@users.noreply.github.com> Date: Sun, 22 Feb 2026 16:15:37 +0800 Subject: [PATCH 43/58] chore: Removed submodules recursive (because bootstrap will do!) --- .github/workflows/build-target.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build-target.yml b/.github/workflows/build-target.yml index d114157623185..7e4aac63b7e87 100644 --- a/.github/workflows/build-target.yml +++ b/.github/workflows/build-target.yml @@ -53,7 +53,7 @@ jobs: - uses: actions/checkout@v4 with: fetch-depth: 0 - submodules: recursive + submodules: false - name: Install NASM run: choco install nasm -y From 6ef9b9afdc79f6c21eac52d791f1224d7354f0e6 Mon Sep 17 00:00:00 2001 From: zhangxuan2011 Date: Sun, 22 Feb 2026 15:54:02 +0800 Subject: [PATCH 44/58] fix(config): Fixed some error of bootstrap cfg --- bootstrap.rust9x.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bootstrap.rust9x.toml b/bootstrap.rust9x.toml index e4f11d16b1475..e8b52011165d2 100644 --- a/bootstrap.rust9x.toml +++ b/bootstrap.rust9x.toml @@ -6,7 +6,7 @@ change-id = 148795 # Will download LLVM from CI if available on your platform. download-ci-llvm = true # NOTE: if you set ↑ to false, disable other LLVM targets to save lots of build time! -targets = "X86" +# targets = "X86" # experimental-targets = "" [build] @@ -30,7 +30,7 @@ tools = [ [install] # for creating a downloadable package: python x.py install, then create and archive this -prefix = "../dist/rust9x" +prefix = "dist/rust9x" sysconfdir = "." [rust] From b4367a8a46ac0a1be0781fa203deffce18d51f1f Mon Sep 17 00:00:00 2001 From: zhangxuan2011 Date: Sun, 22 Feb 2026 18:09:53 +0800 Subject: [PATCH 45/58] ci(build-target): Add a upstream in building repo - Added a upstream after check out --- .github/workflows/build-target.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/build-target.yml b/.github/workflows/build-target.yml index 7e4aac63b7e87..e1426973e4e64 100644 --- a/.github/workflows/build-target.yml +++ b/.github/workflows/build-target.yml @@ -55,6 +55,9 @@ jobs: fetch-depth: 0 submodules: false + - name: Set up upstream + run: git remote add upstream https://github.com/rust-lang/rust.git + - name: Install NASM run: choco install nasm -y From 76549193cd9b71691835d1b00f9d65eb9e8d2967 Mon Sep 17 00:00:00 2001 From: zhangxuan2011 Date: Sun, 22 Feb 2026 18:19:10 +0800 Subject: [PATCH 46/58] chore(ci): :fire: Removed unnessary workflows - Removed 3 workflows which is from official repo, they are unuseful --- .github/workflows/ghcr.yml | 75 -------------------------------- .github/workflows/post-merge.yml | 53 ---------------------- 2 files changed, 128 deletions(-) delete mode 100644 .github/workflows/ghcr.yml delete mode 100644 .github/workflows/post-merge.yml diff --git a/.github/workflows/ghcr.yml b/.github/workflows/ghcr.yml deleted file mode 100644 index a89867efe666b..0000000000000 --- a/.github/workflows/ghcr.yml +++ /dev/null @@ -1,75 +0,0 @@ -# Mirror DockerHub images used by the Rust project to ghcr.io. -# Images are available at https://github.com/orgs/rust-lang/packages. -# -# In some CI jobs, we pull images from ghcr.io instead of Docker Hub because -# Docker Hub has a rate limit, while ghcr.io doesn't. -# Those images are pushed to ghcr.io by this job. -# -# While Docker Hub rate limit *shouldn't* be an issue on GitHub Actions, -# it certainly is for AWS codebuild. -# -# Note that authenticating to DockerHub or other registries isn't possible -# for PR jobs, because forks can't access secrets. -# That's why we use ghcr.io: it has no rate limit and it doesn't require authentication. - -name: GHCR image mirroring - -on: - workflow_dispatch: - schedule: - # Run daily at midnight UTC - - cron: '0 0 * * *' - -jobs: - mirror: - name: DockerHub mirror - runs-on: ubuntu-24.04 - if: github.repository == 'rust-lang/rust' - permissions: - # Needed to write to the ghcr.io registry - packages: write - steps: - - uses: actions/checkout@v5 - with: - persist-credentials: false - - - name: Log in to registry - run: echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u ${{ github.repository_owner }} --password-stdin - - # Download crane in the current directory. - # We use crane because it copies the docker image for all the architectures available in - # DockerHub for the image. - # Learn more about crane at - # https://github.com/google/go-containerregistry/blob/main/cmd/crane/README.md - - name: Download crane - run: | - curl -sL "https://github.com/google/go-containerregistry/releases/download/${VERSION}/go-containerregistry_${OS}_${ARCH}.tar.gz" | tar -xzf - - env: - VERSION: v0.20.2 - OS: Linux - ARCH: x86_64 - - - name: Mirror DockerHub - run: | - # List of DockerHub images to mirror to ghcr.io - images=( - # Mirrored because used by the tidy job, which doesn't cache Docker images - "ubuntu:22.04" - # Mirrored because used by all linux CI jobs, including tidy - "moby/buildkit:buildx-stable-1" - # Mirrored because used when CI is running inside a Docker container - "alpine:3.4" - # Mirrored because used by dist-x86_64-linux - "centos:7" - ) - - # Mirror each image from DockerHub to ghcr.io - for img in "${images[@]}"; do - echo "Mirroring ${img}..." - # Remove namespace from the image if any. - # E.g. "moby/buildkit:buildx-stable-1" becomes "buildkit:buildx-stable-1" - dest_image=$(echo "${img}" | cut -d'/' -f2-) - ./crane copy \ - "docker.io/${img}" \ - "ghcr.io/${{ github.repository_owner }}/${dest_image}" - done diff --git a/.github/workflows/post-merge.yml b/.github/workflows/post-merge.yml deleted file mode 100644 index d38cc0e8a17f3..0000000000000 --- a/.github/workflows/post-merge.yml +++ /dev/null @@ -1,53 +0,0 @@ -# Workflow that runs after a merge to the default branch, analyses changes in test executions -# and posts the result to the merged PR. - -name: Post merge analysis - -on: - push: - branches: - - main - -jobs: - analysis: - runs-on: ubuntu-24.04 - if: github.repository == 'rust-lang/rust' - permissions: - pull-requests: write - steps: - - uses: actions/checkout@v5 - with: - # Make sure that we have enough commits to find the parent merge commit. - # Since all merges should be through merge commits, fetching two commits - # should be enough to get the parent bors merge commit. - fetch-depth: 2 - - name: Perform analysis and send PR - env: - GH_TOKEN: ${{ github.token }} - run: | - # Give GitHub some time to propagate the information that the PR was merged - sleep 60 - - # Get closest bors merge commit - PARENT_COMMIT=`git rev-list --author='bors ' -n1 --first-parent HEAD^1` - echo "Parent: ${PARENT_COMMIT}" - - # Find PR for the current commit - HEAD_PR=`gh pr list --search "${{ github.sha }}" --state merged --json number --jq '.[0].number'` - if [ -z "${HEAD_PR}" ]; then - echo "PR for commit SHA ${{ github.sha }} not found, exiting" - exit 1 - fi - echo "HEAD: ${{ github.sha }} (#${HEAD_PR})" - - cd src/ci/citool - - printf "
\nWhat is this?\n" >> output.log - printf "This is an experimental post-merge analysis report that shows differences in test outcomes between the merged PR and its parent PR.\n" >> output.log - printf "
\n\n" >> output.log - - cargo run --release post-merge-report ${PARENT_COMMIT} ${{ github.sha }} >> output.log - - cat output.log - - gh pr comment ${HEAD_PR} -F output.log From 5db6b1ac97d8c49783853f6acf3a9a4717777af7 Mon Sep 17 00:00:00 2001 From: zhangxuan2011 Date: Mon, 23 Feb 2026 05:04:50 +0800 Subject: [PATCH 47/58] fix(build-target): :ambulance: Fixed the issue about "build failed" - Set the `GITHUB_ACTIONS` to none to avoid bootstrap get wrong commit hash - Added `CARGO_TERM_COLOR`, which is `always` --- .github/workflows/build-target.yml | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build-target.yml b/.github/workflows/build-target.yml index e1426973e4e64..7c5a60d97bb5e 100644 --- a/.github/workflows/build-target.yml +++ b/.github/workflows/build-target.yml @@ -20,6 +20,9 @@ on: permissions: contents: write +env: + CARGO_TERM_COLOR: always + jobs: build: runs-on: ${{ matrix.os }} @@ -67,8 +70,15 @@ jobs: arch: ${{ matrix.arch }} - name: Build toolchain + env: + # If this env exists, the commit hash is wrong and just return 404. + GITHUB_ACTIONS: run: | - python x.py install --config bootstrap.rust9x.toml + :: Avoid failed to unset + set GITHUB_ACTIONS= + + :: Build & install in dist/rust9x + python x.py install --config bootstrap.rust9x.toml --stage 2 if %errorlevel% neq 0 exit /b 1 - name: Pack toolchain From ac75b6321ed96fabba356f810e1043c7a928ac57 Mon Sep 17 00:00:00 2001 From: zhangxuan2011 Date: Mon, 23 Feb 2026 14:27:17 +0800 Subject: [PATCH 48/58] fix(build-target): :green_heart: Fixed the packing issue - Specified the packing dir - Removed the check of `build` directory --- .github/workflows/build-target.yml | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/.github/workflows/build-target.yml b/.github/workflows/build-target.yml index 7c5a60d97bb5e..8d41977d57539 100644 --- a/.github/workflows/build-target.yml +++ b/.github/workflows/build-target.yml @@ -86,14 +86,8 @@ jobs: set VERSION=${{ github.ref_name }} set ARCHIVE_NAME=rust9x-toolchain-%VERSION%-${{ matrix.target_short }}.tar.gz - :: Check build folder - if not exist "build" ( - echo Error: build directory not found - exit /b 1 - ) - :: Pack everything inside build - tar -czvf "%ARCHIVE_NAME%" -C dist/rust9x + tar -czvf "%ARCHIVE_NAME%" -C dist/rust9x . - name: Upload to release uses: softprops/action-gh-release@v2 From 141cf5c786b277e1145633f40565507b5a203ff7 Mon Sep 17 00:00:00 2001 From: zhangxuan2011 Date: Mon, 23 Feb 2026 15:51:29 +0800 Subject: [PATCH 49/58] chore: :zap: Optimized the bootstrap docs to approve the build-time - Removed the `rustdoc`, because the official one provided. - Use `rustfmt` instead of `rustdoc` - Disable building `llvm-tools`. --- bootstrap.rust9x.toml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/bootstrap.rust9x.toml b/bootstrap.rust9x.toml index e8b52011165d2..698f201ab85f6 100644 --- a/bootstrap.rust9x.toml +++ b/bootstrap.rust9x.toml @@ -17,6 +17,7 @@ target = [ "x86_64-rust9x-windows-msvc", "x86_64-pc-windows-msvc", ] + # The docs is unnessary to build, because it's as same as the official one docs = false @@ -24,8 +25,7 @@ docs = false extended = true tools = [ "cargo", - "rustdoc", - "src", + "rustfmt" ] [install] @@ -37,6 +37,7 @@ sysconfdir = "." # enable rust-lld.exe so we don't need editbin.exe lld = true dist-src = false +llvm-tools = false # you can override this with -i/--incremental # incremental = false From 2e6cde5834a9b02d1c58ae082939b1a880b52e4e Mon Sep 17 00:00:00 2001 From: zhangxuan2011 Date: Mon, 23 Feb 2026 15:57:19 +0800 Subject: [PATCH 50/58] refactor(ci): Changed the workflow filename - Uses `build-toolchain` instead of `build-target` - Changed name to `Build Rust9x Toolchain` --- .github/workflows/{build-target.yml => build-toolchain.yml} | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) rename .github/workflows/{build-target.yml => build-toolchain.yml} (98%) diff --git a/.github/workflows/build-target.yml b/.github/workflows/build-toolchain.yml similarity index 98% rename from .github/workflows/build-target.yml rename to .github/workflows/build-toolchain.yml index 8d41977d57539..0d841fa37d4b0 100644 --- a/.github/workflows/build-target.yml +++ b/.github/workflows/build-toolchain.yml @@ -9,7 +9,9 @@ # # Workflow file by "zhangxuan2011 " -name: Build Target Toolchain +--- + +name: Build Rust9x Toolchain on: push: From 8a7eb052659e6871380bea5fe60e78c3636320da Mon Sep 17 00:00:00 2001 From: zhangxuan2011 Date: Mon, 23 Feb 2026 16:12:25 +0800 Subject: [PATCH 51/58] fix(ci): :bug: Fixed the uploading issue - Added input in `workflow_dispatch` - Added the `GITHUB_TOKEN` env --- .github/workflows/build-toolchain.yml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.github/workflows/build-toolchain.yml b/.github/workflows/build-toolchain.yml index 0d841fa37d4b0..3a328550868ec 100644 --- a/.github/workflows/build-toolchain.yml +++ b/.github/workflows/build-toolchain.yml @@ -18,6 +18,11 @@ on: tags: - "v*" workflow_dispatch: + inputs: + version: + description: "The version to release, which must start with `v`" + required: true + default: "v1.93.0-rust9x" permissions: contents: write @@ -95,3 +100,5 @@ jobs: uses: softprops/action-gh-release@v2 with: files: rust9x-toolchain-*.tar.gz + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} From 2c90e7ac4af8c348fddae076323271598b1f4ded Mon Sep 17 00:00:00 2001 From: zhangxuan2011 Date: Mon, 23 Feb 2026 21:04:10 +0800 Subject: [PATCH 52/58] chore(readme): :memo: Fixed the display of README.md - Added some links on title `Links` --- README.md | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 020ba0aa860d0..e3b790d8a4757 100644 --- a/README.md +++ b/README.md @@ -8,23 +8,23 @@ -This is the main source code repository for [Rust9x]. It contains the compiler, +This is the source code repository for [Rust9x]. It contains the compiler, standard library, and documentation. Note that this project can not only used on Windows 10 and 11, but also on Windows 7, XP, even Windows 2000, 98 and 95 -# Links +--- -## Official +# Links +**Cargo**: https://github.com/rust-lang/cargo +**rustfmt**: https://github.com/rust-lang/rustfmt +**Clippy**: https://github.com/rust-lang/rust-clippy +**rust-analyzer**: https://github.com/rust-lang/rust-analyzer +**Rust9x**: https://github.com/rust9x/rust/wiki -[Cargo]: https://github.com/rust-lang/cargo -[rustfmt]: https://github.com/rust-lang/rustfmt -[Clippy]: https://github.com/rust-lang/rust-clippy -[rust-analyzer]: https://github.com/rust-lang/rust-analyzer -## Rust9x -[Wiki]: https://github.com/rust9x/rust/wiki +[Rust9x]: https://github.com/rust9x/rust/wiki # Build @@ -73,7 +73,7 @@ Support targets: - Windows 2000, Windows 9x and older - i586 systems (simply called "16-bit systems") -For more information, please visit [here](https://github.com/rust9x/rust/wiki#installation) +For more information, please visit [the rust9x installation guide](https://github.com/rust9x/rust/wiki#installation) for further information. # Contributing From 63d7f9f29910a72771f29d7c712bf5016d301996 Mon Sep 17 00:00:00 2001 From: zhangxuan2011 Date: Mon, 23 Feb 2026 21:46:16 +0800 Subject: [PATCH 53/58] chore(bootstrap): Added the `src` tools to support `rust-analyzer`check - Added `src` into tools's list --- bootstrap.rust9x.toml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/bootstrap.rust9x.toml b/bootstrap.rust9x.toml index 698f201ab85f6..a4a9815e69c78 100644 --- a/bootstrap.rust9x.toml +++ b/bootstrap.rust9x.toml @@ -25,7 +25,8 @@ docs = false extended = true tools = [ "cargo", - "rustfmt" + "rustfmt", + "src" ] [install] From 2dfe01d709bccf2ffda6c48e93539442a9e1ef77 Mon Sep 17 00:00:00 2001 From: zhangxuan2011 Date: Tue, 24 Feb 2026 08:46:27 +0800 Subject: [PATCH 54/58] ci(build-target): :art: Removed unnessary steps to save time - Removed `Set up upstream` and `Install NASM` steps in workflow file - Removed Windows i586 support --- .github/workflows/build-toolchain.yml | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/.github/workflows/build-toolchain.yml b/.github/workflows/build-toolchain.yml index 3a328550868ec..19e98b24bfd66 100644 --- a/.github/workflows/build-toolchain.yml +++ b/.github/workflows/build-toolchain.yml @@ -49,12 +49,6 @@ jobs: target: i686-pc-windows-msvc target_short: i686-windows - # Windows, i586 - - os: windows-latest - arch: x86 - target: i586-pc-windows-msvc - target_short: i586-windows - defaults: run: shell: cmd @@ -65,12 +59,6 @@ jobs: fetch-depth: 0 submodules: false - - name: Set up upstream - run: git remote add upstream https://github.com/rust-lang/rust.git - - - name: Install NASM - run: choco install nasm -y - - name: Activate MSVC environment uses: ilammy/msvc-dev-cmd@v1 with: From 1dd868b8b0b5d0a22d09495eabec3e5ae68d54dd Mon Sep 17 00:00:00 2001 From: zhangxuan2011 Date: Tue, 24 Feb 2026 13:26:04 +0800 Subject: [PATCH 55/58] fix(build-target): Fix that the toolchain won't work on i686 --- .github/workflows/build-toolchain.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build-toolchain.yml b/.github/workflows/build-toolchain.yml index 19e98b24bfd66..c6f11d9a339d3 100644 --- a/.github/workflows/build-toolchain.yml +++ b/.github/workflows/build-toolchain.yml @@ -73,7 +73,7 @@ jobs: set GITHUB_ACTIONS= :: Build & install in dist/rust9x - python x.py install --config bootstrap.rust9x.toml --stage 2 + python x.py install --config bootstrap.rust9x.toml --set build.host=["${{ matrix.target }}"] --stage 2 if %errorlevel% neq 0 exit /b 1 - name: Pack toolchain From e549de4798bcb414bf131ea427c0cff37956301b Mon Sep 17 00:00:00 2001 From: zhangxuan2011 Date: Tue, 24 Feb 2026 13:33:17 +0800 Subject: [PATCH 56/58] fix(build-target): :bug: Fixed the format error --- .github/workflows/build-toolchain.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build-toolchain.yml b/.github/workflows/build-toolchain.yml index c6f11d9a339d3..b4e1b0842a743 100644 --- a/.github/workflows/build-toolchain.yml +++ b/.github/workflows/build-toolchain.yml @@ -73,7 +73,7 @@ jobs: set GITHUB_ACTIONS= :: Build & install in dist/rust9x - python x.py install --config bootstrap.rust9x.toml --set build.host=["${{ matrix.target }}"] --stage 2 + python x.py install --config bootstrap.rust9x.toml --set build.host=[\"${{ matrix.target }}\"] --stage 2 if %errorlevel% neq 0 exit /b 1 - name: Pack toolchain From 4d92a9d1f1e6ec61bbdebb3b482822ee79b320d0 Mon Sep 17 00:00:00 2001 From: zhangxuan <114813512+zhangxuan2011@users.noreply.github.com> Date: Tue, 24 Feb 2026 15:40:01 +0800 Subject: [PATCH 57/58] ci: updated build-toolchain.yml --- .github/workflows/build-toolchain.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build-toolchain.yml b/.github/workflows/build-toolchain.yml index b4e1b0842a743..309d378a8350b 100644 --- a/.github/workflows/build-toolchain.yml +++ b/.github/workflows/build-toolchain.yml @@ -45,7 +45,7 @@ jobs: # Windows, i686 - os: windows-latest - arch: x86 + arch: x64 target: i686-pc-windows-msvc target_short: i686-windows From dd57e8b0b250d34630fdbdbf28925d4fbe42498a Mon Sep 17 00:00:00 2001 From: zhangxuan2011 Date: Tue, 24 Feb 2026 18:11:53 +0800 Subject: [PATCH 58/58] chore(build-target): :fire: Disabled the i686 compiling temporary - Commented the `windows-i686` matrix --- .github/workflows/build-toolchain.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/build-toolchain.yml b/.github/workflows/build-toolchain.yml index 309d378a8350b..66c6e611d27b7 100644 --- a/.github/workflows/build-toolchain.yml +++ b/.github/workflows/build-toolchain.yml @@ -44,10 +44,10 @@ jobs: target_short: x86_64-windows # Windows, i686 - - os: windows-latest - arch: x64 - target: i686-pc-windows-msvc - target_short: i686-windows + # - os: windows-latest + # arch: x64 + # target: i686-pc-windows-msvc + # target_short: i686-windows defaults: run: