diff --git a/RELEASES.md b/RELEASES.md
index b14cc499b46d0..0dffe931e6eb1 100644
--- a/RELEASES.md
+++ b/RELEASES.md
@@ -1,3 +1,88 @@
+Version 1.92.0 (2025-12-11)
+==========================
+
+
+
+Language
+--------
+- [Document `MaybeUninit` representation and validity](https://github.com/rust-lang/rust/pull/140463)
+- [Allow `&raw [mut | const]` for union field in safe code](https://github.com/rust-lang/rust/pull/141469)
+- [Prefer item bounds of associated types over where-bounds for auto-traits and `Sized`](https://github.com/rust-lang/rust/pull/144064)
+- [Do not materialize `X` in `[X; 0]` when `X` is unsizing a const](https://github.com/rust-lang/rust/pull/145277)
+- [Support combining `#[track_caller]` and `#[no_mangle]` (requires every declaration specifying `#[track_caller]` as well)](https://github.com/rust-lang/rust/pull/145724)
+- [Make never type lints `never_type_fallback_flowing_into_unsafe` and `dependency_on_unit_never_type_fallback` deny-by-default](https://github.com/rust-lang/rust/pull/146167)
+- [Allow specifying multiple bounds for same associated item, except in trait objects](https://github.com/rust-lang/rust/pull/146593)
+- [Slightly strengthen higher-ranked region handling in coherence](https://github.com/rust-lang/rust/pull/146725)
+- [The `unused_must_use` lint no longer warns on `Result<(), Uninhabited>` (for instance, `Result<(), !>`), or `ControlFlow`](https://github.com/rust-lang/rust/pull/147382). This avoids having to check for an error that can never happen.
+
+
+
+Compiler
+--------
+- [Make `mips64el-unknown-linux-muslabi64` link dynamically](https://github.com/rust-lang/rust/pull/146858)
+- [Remove current code for embedding command-line args in PDB](https://github.com/rust-lang/rust/pull/147022)
+ Command-line information is typically not needed by debugging tools, and the removed code
+ was causing problems for incremental builds even on targets that don't use PDB debuginfo.
+
+
+
+Libraries
+---------
+- [Specialize `Iterator::eq{_by}` for `TrustedLen` iterators](https://github.com/rust-lang/rust/pull/137122)
+- [Simplify `Extend` for tuples](https://github.com/rust-lang/rust/pull/138799)
+- [Added details to `Debug` for `EncodeWide`](https://github.com/rust-lang/rust/pull/140153).
+- [`iter::Repeat::last`](https://github.com/rust-lang/rust/pull/147258) and [`count`](https://github.com/rust-lang/rust/pull/146410) will now panic, rather than looping infinitely.
+
+
+
+Stabilized APIs
+---------------
+
+- [`NonZero::div_ceil`](https://doc.rust-lang.org/stable/std/num/struct.NonZero.html#method.div_ceil)
+- [`Location::file_as_c_str`](https://doc.rust-lang.org/stable/std/panic/struct.Location.html#method.file_as_c_str)
+- [`RwLockWriteGuard::downgrade`](https://doc.rust-lang.org/stable/std/sync/struct.RwLockWriteGuard.html#method.downgrade)
+- [`Box::new_zeroed`](https://doc.rust-lang.org/stable/std/boxed/struct.Box.html#method.new_zeroed)
+- [`Box::new_zeroed_slice`](https://doc.rust-lang.org/stable/std/boxed/struct.Box.html#method.new_zeroed_slice)
+- [`Rc::new_zeroed`](https://doc.rust-lang.org/stable/std/rc/struct.Rc.html#method.new_zeroed)
+- [`Rc::new_zeroed_slice`](https://doc.rust-lang.org/stable/std/rc/struct.Rc.html#method.new_zeroed_slice)
+- [`Arc::new_zeroed`](https://doc.rust-lang.org/stable/std/sync/struct.Arc.html#method.new_zeroed)
+- [`Arc::new_zeroed_slice`](https://doc.rust-lang.org/stable/std/sync/struct.Arc.html#method.new_zeroed_slice)
+- [`btree_map::Entry::insert_entry`](https://doc.rust-lang.org/stable/std/collections/btree_map/enum.Entry.html#method.insert_entry)
+- [`btree_map::VacantEntry::insert_entry`](https://doc.rust-lang.org/stable/std/collections/btree_map/struct.VacantEntry.html#method.insert_entry)
+- [`impl Extend for proc_macro::TokenStream`](https://doc.rust-lang.org/stable/proc_macro/struct.TokenStream.html#impl-Extend%3CGroup%3E-for-TokenStream)
+- [`impl Extend for proc_macro::TokenStream`](https://doc.rust-lang.org/stable/proc_macro/struct.TokenStream.html#impl-Extend%3CLiteral%3E-for-TokenStream)
+- [`impl Extend for proc_macro::TokenStream`](https://doc.rust-lang.org/stable/proc_macro/struct.TokenStream.html#impl-Extend%3CPunct%3E-for-TokenStream)
+- [`impl Extend for proc_macro::TokenStream`](https://doc.rust-lang.org/stable/proc_macro/struct.TokenStream.html#impl-Extend%3CIdent%3E-for-TokenStream)
+
+These previously stable APIs are now stable in const contexts:
+
+- [`<[_]>::rotate_left`](https://doc.rust-lang.org/stable/std/primitive.slice.html#method.rotate_left)
+- [`<[_]>::rotate_right`](https://doc.rust-lang.org/stable/std/primitive.slice.html#method.rotate_right)
+
+
+
+Cargo
+-----
+- [Added a new chapter](https://github.com/rust-lang/cargo/issues/16119) to the Cargo book, ["Optimizing Build Performance"](https://doc.rust-lang.org/stable/cargo/guide/build-performance.html).
+
+
+
+Rustdoc
+-----
+- [If a trait item appears in rustdoc search, hide the corresponding impl items](https://github.com/rust-lang/rust/pull/145898). Previously a search for "last" would show both `Iterator::last` as well as impl methods like `std::vec::IntoIter::last`. Now these impl methods will be hidden, freeing up space for inherent methods like `BTreeSet::last`.
+- [Relax rules for identifiers in search](https://github.com/rust-lang/rust/pull/147860). Previously you could only search for identifiers that were valid in rust code, now searches only need to be valid as part of an identifier. For example, you can now perform a search that starts with a digit.
+
+
+
+Compatibility Notes
+-------------------
+* [Fix backtraces with `-C panic=abort` on Linux by generating unwind tables by default](https://github.com/rust-lang/rust/pull/143613). Build with `-C force-unwind-tables=no` to keep omitting unwind tables.
+- As part of the larger effort refactoring compiler built-in attributes and their diagnostics, [the future-compatibility lint `invalid_macro_export_arguments` is upgraded to deny-by-default and will be reported in dependencies too.](https://github.com/rust-lang/rust/pull/143857)
+- [Update the minimum external LLVM to 20](https://github.com/rust-lang/rust/pull/145071)
+- [Prevent downstream `impl DerefMut for Pin`](https://github.com/rust-lang/rust/pull/145608)
+- [Don't apply temporary lifetime extension rules to the arguments of non-extended `pin!` and formatting macros](https://github.com/rust-lang/rust/pull/145838)
+
+
Version 1.91.1 (2025-11-10)
===========================
diff --git a/compiler/rustc_ast_lowering/src/delegation.rs b/compiler/rustc_ast_lowering/src/delegation.rs
index e6e88eff2d5bc..0e7db7c9503cb 100644
--- a/compiler/rustc_ast_lowering/src/delegation.rs
+++ b/compiler/rustc_ast_lowering/src/delegation.rs
@@ -44,6 +44,7 @@ use hir::{BodyId, HirId};
use rustc_abi::ExternAbi;
use rustc_ast::*;
use rustc_errors::ErrorGuaranteed;
+use rustc_hir::attrs::{AttributeKind, InlineAttr};
use rustc_hir::def_id::DefId;
use rustc_middle::span_bug;
use rustc_middle::ty::{Asyncness, ResolverAstLowering};
@@ -87,6 +88,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
let sig_id = self.get_delegation_sig_id(item_id, delegation.id, span, is_in_trait_impl);
match sig_id {
Ok(sig_id) => {
+ self.add_inline_attribute_if_needed(span);
+
let is_method = self.is_method(sig_id, span);
let (param_count, c_variadic) = self.param_count(sig_id);
let decl = self.lower_delegation_decl(sig_id, param_count, c_variadic, span);
@@ -100,6 +103,31 @@ impl<'hir> LoweringContext<'_, 'hir> {
}
}
+ fn add_inline_attribute_if_needed(&mut self, span: Span) {
+ const PARENT_ID: hir::ItemLocalId = hir::ItemLocalId::ZERO;
+ let create_inline_attr_slice =
+ || [hir::Attribute::Parsed(AttributeKind::Inline(InlineAttr::Hint, span))];
+
+ let new_attributes = match self.attrs.get(&PARENT_ID) {
+ Some(attrs) => {
+ // Check if reuse already specifies any inline attribute, if so, do nothing
+ if attrs
+ .iter()
+ .any(|a| matches!(a, hir::Attribute::Parsed(AttributeKind::Inline(..))))
+ {
+ return;
+ }
+
+ self.arena.alloc_from_iter(
+ attrs.into_iter().map(|a| a.clone()).chain(create_inline_attr_slice()),
+ )
+ }
+ None => self.arena.alloc_from_iter(create_inline_attr_slice()),
+ };
+
+ self.attrs.insert(PARENT_ID, new_attributes);
+ }
+
fn get_delegation_sig_id(
&self,
item_id: NodeId,
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index ab5caff86204d..2f0c96618af06 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -1677,7 +1677,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
let output = match coro {
Some(coro) => {
let fn_def_id = self.local_def_id(fn_node_id);
- self.lower_coroutine_fn_ret_ty(&decl.output, fn_def_id, coro, kind, fn_span)
+ self.lower_coroutine_fn_ret_ty(&decl.output, fn_def_id, coro, kind)
}
None => match &decl.output {
FnRetTy::Ty(ty) => {
@@ -1762,9 +1762,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
fn_def_id: LocalDefId,
coro: CoroutineKind,
fn_kind: FnDeclKind,
- fn_span: Span,
) -> hir::FnRetTy<'hir> {
- let span = self.lower_span(fn_span);
+ let span = self.lower_span(output.span());
let (opaque_ty_node_id, allowed_features) = match coro {
CoroutineKind::Async { return_impl_trait_id, .. } => (return_impl_trait_id, None),
diff --git a/compiler/rustc_attr_parsing/src/attributes/cfg.rs b/compiler/rustc_attr_parsing/src/attributes/cfg.rs
index bd228315b2c95..490e28ed64c5d 100644
--- a/compiler/rustc_attr_parsing/src/attributes/cfg.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/cfg.rs
@@ -2,16 +2,16 @@ use std::convert::identity;
use rustc_ast::token::Delimiter;
use rustc_ast::tokenstream::DelimSpan;
-use rustc_ast::{AttrItem, Attribute, CRATE_NODE_ID, LitKind, NodeId, ast, token};
+use rustc_ast::{AttrItem, Attribute, CRATE_NODE_ID, LitKind, ast, token};
use rustc_errors::{Applicability, PResult};
use rustc_feature::{AttrSuggestionStyle, AttributeTemplate, Features, template};
use rustc_hir::attrs::CfgEntry;
+use rustc_hir::lints::AttributeLintKind;
use rustc_hir::{AttrPath, RustcVersion};
use rustc_parse::parser::{ForceCollect, Parser};
use rustc_parse::{exp, parse_in};
use rustc_session::Session;
use rustc_session::config::ExpectedValues;
-use rustc_session::lint::BuiltinLintDiag;
use rustc_session::lint::builtin::UNEXPECTED_CFGS;
use rustc_session::parse::{ParseSess, feature_err};
use rustc_span::{ErrorGuaranteed, Span, Symbol, sym};
@@ -23,10 +23,7 @@ use crate::session_diagnostics::{
AttributeParseError, AttributeParseErrorReason, CfgAttrBadDelim, MetaBadDelimSugg,
ParsedDescription,
};
-use crate::{
- AttributeParser, CfgMatchesLintEmitter, fluent_generated, parse_version, session_diagnostics,
- try_gate_cfg,
-};
+use crate::{AttributeParser, fluent_generated, parse_version, session_diagnostics, try_gate_cfg};
pub const CFG_TEMPLATE: AttributeTemplate = template!(
List: &["predicate"],
@@ -195,43 +192,46 @@ fn parse_name_value(
}
};
- Ok(CfgEntry::NameValue { name, name_span, value, span })
+ match cx.sess.psess.check_config.expecteds.get(&name) {
+ Some(ExpectedValues::Some(values)) if !values.contains(&value.map(|(v, _)| v)) => cx
+ .emit_lint(
+ UNEXPECTED_CFGS,
+ AttributeLintKind::UnexpectedCfgValue((name, name_span), value),
+ span,
+ ),
+ None if cx.sess.psess.check_config.exhaustive_names => cx.emit_lint(
+ UNEXPECTED_CFGS,
+ AttributeLintKind::UnexpectedCfgName((name, name_span), value),
+ span,
+ ),
+ _ => { /* not unexpected */ }
+ }
+
+ Ok(CfgEntry::NameValue { name, value: value.map(|(v, _)| v), span })
}
-pub fn eval_config_entry(
- sess: &Session,
- cfg_entry: &CfgEntry,
- id: NodeId,
- emit_lints: ShouldEmit,
-) -> EvalConfigResult {
+pub fn eval_config_entry(sess: &Session, cfg_entry: &CfgEntry) -> EvalConfigResult {
match cfg_entry {
CfgEntry::All(subs, ..) => {
- let mut all = None;
for sub in subs {
- let res = eval_config_entry(sess, sub, id, emit_lints);
- // We cannot short-circuit because `eval_config_entry` emits some lints
+ let res = eval_config_entry(sess, sub);
if !res.as_bool() {
- all.get_or_insert(res);
+ return res;
}
}
- all.unwrap_or_else(|| EvalConfigResult::True)
+ EvalConfigResult::True
}
CfgEntry::Any(subs, span) => {
- let mut any = None;
for sub in subs {
- let res = eval_config_entry(sess, sub, id, emit_lints);
- // We cannot short-circuit because `eval_config_entry` emits some lints
+ let res = eval_config_entry(sess, sub);
if res.as_bool() {
- any.get_or_insert(res);
+ return res;
}
}
- any.unwrap_or_else(|| EvalConfigResult::False {
- reason: cfg_entry.clone(),
- reason_span: *span,
- })
+ EvalConfigResult::False { reason: cfg_entry.clone(), reason_span: *span }
}
CfgEntry::Not(sub, span) => {
- if eval_config_entry(sess, sub, id, emit_lints).as_bool() {
+ if eval_config_entry(sess, sub).as_bool() {
EvalConfigResult::False { reason: cfg_entry.clone(), reason_span: *span }
} else {
EvalConfigResult::True
@@ -244,32 +244,8 @@ pub fn eval_config_entry(
EvalConfigResult::False { reason: cfg_entry.clone(), reason_span: *span }
}
}
- CfgEntry::NameValue { name, name_span, value, span } => {
- if let ShouldEmit::ErrorsAndLints = emit_lints {
- match sess.psess.check_config.expecteds.get(name) {
- Some(ExpectedValues::Some(values))
- if !values.contains(&value.map(|(v, _)| v)) =>
- {
- id.emit_span_lint(
- sess,
- UNEXPECTED_CFGS,
- *span,
- BuiltinLintDiag::UnexpectedCfgValue((*name, *name_span), *value),
- );
- }
- None if sess.psess.check_config.exhaustive_names => {
- id.emit_span_lint(
- sess,
- UNEXPECTED_CFGS,
- *span,
- BuiltinLintDiag::UnexpectedCfgName((*name, *name_span), *value),
- );
- }
- _ => { /* not unexpected */ }
- }
- }
-
- if sess.psess.config.contains(&(*name, value.map(|(v, _)| v))) {
+ CfgEntry::NameValue { name, value, span } => {
+ if sess.psess.config.contains(&(*name, *value)) {
EvalConfigResult::True
} else {
EvalConfigResult::False { reason: cfg_entry.clone(), reason_span: *span }
diff --git a/compiler/rustc_attr_parsing/src/attributes/cfg_old.rs b/compiler/rustc_attr_parsing/src/attributes/cfg_old.rs
index 70228d1e15101..adae3fa635f43 100644
--- a/compiler/rustc_attr_parsing/src/attributes/cfg_old.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/cfg_old.rs
@@ -2,6 +2,7 @@ use rustc_ast::{LitKind, MetaItem, MetaItemInner, MetaItemKind, MetaItemLit, Nod
use rustc_ast_pretty::pprust;
use rustc_feature::{Features, GatedCfg, find_gated_cfg};
use rustc_hir::RustcVersion;
+use rustc_hir::lints::AttributeLintKind;
use rustc_session::Session;
use rustc_session::config::ExpectedValues;
use rustc_session::lint::builtin::UNEXPECTED_CFGS;
@@ -51,10 +52,10 @@ pub fn cfg_matches(
sess,
UNEXPECTED_CFGS,
cfg.span,
- BuiltinLintDiag::UnexpectedCfgValue(
+ BuiltinLintDiag::AttributeLint(AttributeLintKind::UnexpectedCfgValue(
(cfg.name, cfg.name_span),
cfg.value.map(|v| (v, cfg.value_span.unwrap())),
- ),
+ )),
);
}
None if sess.psess.check_config.exhaustive_names => {
@@ -62,10 +63,10 @@ pub fn cfg_matches(
sess,
UNEXPECTED_CFGS,
cfg.span,
- BuiltinLintDiag::UnexpectedCfgName(
+ BuiltinLintDiag::AttributeLint(AttributeLintKind::UnexpectedCfgName(
(cfg.name, cfg.name_span),
cfg.value.map(|v| (v, cfg.value_span.unwrap())),
- ),
+ )),
);
}
_ => { /* not unexpected */ }
diff --git a/compiler/rustc_builtin_macros/src/cfg.rs b/compiler/rustc_builtin_macros/src/cfg.rs
index b24e3065622d2..7bc9080ba0229 100644
--- a/compiler/rustc_builtin_macros/src/cfg.rs
+++ b/compiler/rustc_builtin_macros/src/cfg.rs
@@ -26,13 +26,7 @@ pub(crate) fn expand_cfg(
ExpandResult::Ready(match parse_cfg(cx, sp, tts) {
Ok(cfg) => {
- let matches_cfg = attr::eval_config_entry(
- cx.sess,
- &cfg,
- cx.current_expansion.lint_node_id,
- ShouldEmit::ErrorsAndLints,
- )
- .as_bool();
+ let matches_cfg = attr::eval_config_entry(cx.sess, &cfg).as_bool();
MacEager::expr(cx.expr_bool(sp, matches_cfg))
}
diff --git a/compiler/rustc_builtin_macros/src/cfg_select.rs b/compiler/rustc_builtin_macros/src/cfg_select.rs
index b77a121ca0b95..dc8077b2a1ffb 100644
--- a/compiler/rustc_builtin_macros/src/cfg_select.rs
+++ b/compiler/rustc_builtin_macros/src/cfg_select.rs
@@ -1,7 +1,7 @@
use rustc_ast::tokenstream::TokenStream;
use rustc_attr_parsing as attr;
use rustc_attr_parsing::{
- CfgSelectBranches, CfgSelectPredicate, EvalConfigResult, ShouldEmit, parse_cfg_select,
+ CfgSelectBranches, CfgSelectPredicate, EvalConfigResult, parse_cfg_select,
};
use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacroExpanderResult};
use rustc_span::{Ident, Span, sym};
@@ -10,21 +10,13 @@ use crate::errors::{CfgSelectNoMatches, CfgSelectUnreachable};
/// Selects the first arm whose predicate evaluates to true.
fn select_arm(ecx: &ExtCtxt<'_>, branches: CfgSelectBranches) -> Option<(TokenStream, Span)> {
- let mut result = None;
for (cfg, tt, arm_span) in branches.reachable {
- if let EvalConfigResult::True = attr::eval_config_entry(
- &ecx.sess,
- &cfg,
- ecx.current_expansion.lint_node_id,
- ShouldEmit::ErrorsAndLints,
- ) {
- // FIXME(#149215) Ideally we should short-circuit here, but `eval_config_entry` currently emits lints so we cannot do this yet.
- result.get_or_insert((tt, arm_span));
+ if let EvalConfigResult::True = attr::eval_config_entry(&ecx.sess, &cfg) {
+ return Some((tt, arm_span));
}
}
- let wildcard = branches.wildcard.map(|(_, tt, span)| (tt, span));
- result.or(wildcard)
+ branches.wildcard.map(|(_, tt, span)| (tt, span))
}
pub(super) fn expand_cfg_select<'cx>(
diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs
index d35c3b6bb189e..70db6794742d0 100644
--- a/compiler/rustc_codegen_ssa/src/back/link.rs
+++ b/compiler/rustc_codegen_ssa/src/back/link.rs
@@ -13,8 +13,7 @@ use find_msvc_tools;
use itertools::Itertools;
use regex::Regex;
use rustc_arena::TypedArena;
-use rustc_ast::CRATE_NODE_ID;
-use rustc_attr_parsing::{ShouldEmit, eval_config_entry};
+use rustc_attr_parsing::eval_config_entry;
use rustc_data_structures::fx::FxIndexSet;
use rustc_data_structures::memmap::Mmap;
use rustc_data_structures::temp_dir::MaybeTempDir;
@@ -3029,9 +3028,7 @@ fn add_dynamic_crate(cmd: &mut dyn Linker, sess: &Session, cratepath: &Path) {
fn relevant_lib(sess: &Session, lib: &NativeLib) -> bool {
match lib.cfg {
- Some(ref cfg) => {
- eval_config_entry(sess, cfg, CRATE_NODE_ID, ShouldEmit::ErrorsAndLints).as_bool()
- }
+ Some(ref cfg) => eval_config_entry(sess, cfg).as_bool(),
None => true,
}
}
diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs
index 0b3ac472e0e83..492c845df1710 100644
--- a/compiler/rustc_expand/src/config.rs
+++ b/compiler/rustc_expand/src/config.rs
@@ -163,10 +163,7 @@ pub fn pre_configure_attrs(sess: &Session, attrs: &[Attribute]) -> ast::AttrVec
.iter()
.flat_map(|attr| strip_unconfigured.process_cfg_attr(attr))
.take_while(|attr| {
- !is_cfg(attr)
- || strip_unconfigured
- .cfg_true(attr, strip_unconfigured.lint_node_id, ShouldEmit::Nothing)
- .as_bool()
+ !is_cfg(attr) || strip_unconfigured.cfg_true(attr, ShouldEmit::Nothing).as_bool()
})
.collect()
}
@@ -309,14 +306,7 @@ impl<'a> StripUnconfigured<'a> {
);
}
- if !attr::eval_config_entry(
- self.sess,
- &cfg_predicate,
- ast::CRATE_NODE_ID,
- ShouldEmit::ErrorsAndLints,
- )
- .as_bool()
- {
+ if !attr::eval_config_entry(self.sess, &cfg_predicate).as_bool() {
return vec![trace_attr];
}
@@ -400,23 +390,17 @@ impl<'a> StripUnconfigured<'a> {
/// Determines if a node with the given attributes should be included in this configuration.
fn in_cfg(&self, attrs: &[Attribute]) -> bool {
- attrs.iter().all(|attr| {
- !is_cfg(attr)
- || self.cfg_true(attr, self.lint_node_id, ShouldEmit::ErrorsAndLints).as_bool()
- })
+ attrs
+ .iter()
+ .all(|attr| !is_cfg(attr) || self.cfg_true(attr, ShouldEmit::ErrorsAndLints).as_bool())
}
- pub(crate) fn cfg_true(
- &self,
- attr: &Attribute,
- node: NodeId,
- emit_errors: ShouldEmit,
- ) -> EvalConfigResult {
+ pub(crate) fn cfg_true(&self, attr: &Attribute, emit_errors: ShouldEmit) -> EvalConfigResult {
let Some(cfg) = AttributeParser::parse_single(
self.sess,
attr,
attr.span,
- node,
+ self.lint_node_id,
self.features,
emit_errors,
parse_cfg,
@@ -426,7 +410,7 @@ impl<'a> StripUnconfigured<'a> {
return EvalConfigResult::True;
};
- eval_config_entry(self.sess, &cfg, self.lint_node_id, emit_errors)
+ eval_config_entry(self.sess, &cfg)
}
/// If attributes are not allowed on expressions, emit an error for `attr`
diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs
index 20fb321307ac5..90563b21d2e80 100644
--- a/compiler/rustc_expand/src/expand.rs
+++ b/compiler/rustc_expand/src/expand.rs
@@ -2213,7 +2213,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
attr: ast::Attribute,
pos: usize,
) -> EvalConfigResult {
- let res = self.cfg().cfg_true(&attr, node.node_id(), ShouldEmit::ErrorsAndLints);
+ let res = self.cfg().cfg_true(&attr, ShouldEmit::ErrorsAndLints);
if res.as_bool() {
// A trace attribute left in AST in place of the original `cfg` attribute.
// It can later be used by lints or other diagnostics.
diff --git a/compiler/rustc_hir/src/attrs/data_structures.rs b/compiler/rustc_hir/src/attrs/data_structures.rs
index d3cc1dd6cf751..aff79d0558387 100644
--- a/compiler/rustc_hir/src/attrs/data_structures.rs
+++ b/compiler/rustc_hir/src/attrs/data_structures.rs
@@ -190,7 +190,7 @@ pub enum CfgEntry {
Any(ThinVec, Span),
Not(Box, Span),
Bool(bool, Span),
- NameValue { name: Symbol, name_span: Span, value: Option<(Symbol, Span)>, span: Span },
+ NameValue { name: Symbol, value: Option, span: Span },
Version(Option, Span),
}
diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl
index bc1c246b8f03a..0553bc95caa29 100644
--- a/compiler/rustc_lint/messages.ftl
+++ b/compiler/rustc_lint/messages.ftl
@@ -416,6 +416,8 @@ lint_improper_ctypes_union_layout_help = consider adding a `#[repr(C)]` or `#[re
lint_improper_ctypes_union_layout_reason = this union has unspecified layout
lint_improper_ctypes_union_non_exhaustive = this union is non-exhaustive
+lint_improper_ctypes_unsafe_binder = unsafe binders are incompatible with foreign function interfaces
+
lint_int_to_ptr_transmutes = transmuting an integer to a pointer creates a pointer without provenance
.note = this is dangerous because dereferencing the resulting pointer is undefined behavior
.note_exposed_provenance = exposed provenance semantics can be used to create a pointer based on some previously exposed provenance
diff --git a/compiler/rustc_lint/src/early/diagnostics.rs b/compiler/rustc_lint/src/early/diagnostics.rs
index ff364e5f814ab..589594a3ec5e6 100644
--- a/compiler/rustc_lint/src/early/diagnostics.rs
+++ b/compiler/rustc_lint/src/early/diagnostics.rs
@@ -169,12 +169,6 @@ pub fn decorate_builtin_lint(
}
.decorate_lint(diag);
}
- BuiltinLintDiag::UnexpectedCfgName(name, value) => {
- check_cfg::unexpected_cfg_name(sess, tcx, name, value).decorate_lint(diag);
- }
- BuiltinLintDiag::UnexpectedCfgValue(name, value) => {
- check_cfg::unexpected_cfg_value(sess, tcx, name, value).decorate_lint(diag);
- }
BuiltinLintDiag::DeprecatedWhereclauseLocation(left_sp, sugg) => {
let suggestion = match sugg {
Some((right_sp, sugg)) => lints::DeprecatedWhereClauseLocationSugg::MoveToEnd {
@@ -310,8 +304,8 @@ pub fn decorate_builtin_lint(
}
pub fn decorate_attribute_lint(
- _sess: &Session,
- _tcx: Option>,
+ sess: &Session,
+ tcx: Option>,
kind: &AttributeLintKind,
diag: &mut Diag<'_, ()>,
) {
@@ -367,5 +361,11 @@ pub fn decorate_attribute_lint(
suggestion: lints::UnsafeAttrOutsideUnsafeSuggestion { left, right },
}
.decorate_lint(diag),
+ &AttributeLintKind::UnexpectedCfgName(name, value) => {
+ check_cfg::unexpected_cfg_name(sess, tcx, name, value).decorate_lint(diag)
+ }
+ &AttributeLintKind::UnexpectedCfgValue(name, value) => {
+ check_cfg::unexpected_cfg_value(sess, tcx, name, value).decorate_lint(diag)
+ }
}
}
diff --git a/compiler/rustc_lint/src/types/improper_ctypes.rs b/compiler/rustc_lint/src/types/improper_ctypes.rs
index 9e38ea6b685bd..38094c67c34a0 100644
--- a/compiler/rustc_lint/src/types/improper_ctypes.rs
+++ b/compiler/rustc_lint/src/types/improper_ctypes.rs
@@ -669,7 +669,9 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
FfiSafe
}
- ty::UnsafeBinder(_) => todo!("FIXME(unsafe_binder)"),
+ ty::UnsafeBinder(_) => {
+ FfiUnsafe { ty, reason: fluent::lint_improper_ctypes_unsafe_binder, help: None }
+ }
ty::Param(..)
| ty::Alias(ty::Projection | ty::Inherent | ty::Free, ..)
diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs
index 19ba27a27eafe..376310838cc74 100644
--- a/compiler/rustc_lint_defs/src/lib.rs
+++ b/compiler/rustc_lint_defs/src/lib.rs
@@ -636,8 +636,6 @@ pub enum BuiltinLintDiag {
},
BreakWithLabelAndLoop(Span),
UnicodeTextFlow(Span, String),
- UnexpectedCfgName((Symbol, Span), Option<(Symbol, Span)>),
- UnexpectedCfgValue((Symbol, Span), Option<(Symbol, Span)>),
DeprecatedWhereclauseLocation(Span, Option<(Span, String)>),
SingleUseLifetime {
/// Span of the parameter which declares this lifetime.
@@ -733,6 +731,8 @@ pub enum AttributeLintKind {
attribute_name_span: Span,
sugg_spans: (Span, Span),
},
+ UnexpectedCfgName((Symbol, Span), Option<(Symbol, Span)>),
+ UnexpectedCfgValue((Symbol, Span), Option<(Symbol, Span)>),
}
pub type RegisteredTools = FxIndexSet;
diff --git a/compiler/rustc_metadata/src/native_libs.rs b/compiler/rustc_metadata/src/native_libs.rs
index 250657bc6806b..e08460c3d4c9a 100644
--- a/compiler/rustc_metadata/src/native_libs.rs
+++ b/compiler/rustc_metadata/src/native_libs.rs
@@ -2,8 +2,7 @@ use std::ops::ControlFlow;
use std::path::{Path, PathBuf};
use rustc_abi::ExternAbi;
-use rustc_ast::CRATE_NODE_ID;
-use rustc_attr_parsing::{ShouldEmit, eval_config_entry};
+use rustc_attr_parsing::eval_config_entry;
use rustc_data_structures::fx::FxHashSet;
use rustc_hir::attrs::{AttributeKind, NativeLibKind, PeImportNameType};
use rustc_hir::find_attr;
@@ -188,9 +187,7 @@ pub(crate) fn collect(tcx: TyCtxt<'_>, LocalCrate: LocalCrate) -> Vec
pub(crate) fn relevant_lib(sess: &Session, lib: &NativeLib) -> bool {
match lib.cfg {
- Some(ref cfg) => {
- eval_config_entry(sess, cfg, CRATE_NODE_ID, ShouldEmit::ErrorsAndLints).as_bool()
- }
+ Some(ref cfg) => eval_config_entry(sess, cfg).as_bool(),
None => true,
}
}
diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs
index 33c111708e366..a675c62ddf705 100644
--- a/compiler/rustc_resolve/src/diagnostics.rs
+++ b/compiler/rustc_resolve/src/diagnostics.rs
@@ -3070,7 +3070,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
continue;
}
- let item_was = if let CfgEntry::NameValue { value: Some((feature, _)), .. } = cfg.0 {
+ let item_was = if let CfgEntry::NameValue { value: Some(feature), .. } = cfg.0 {
errors::ItemWas::BehindFeature { feature, span: cfg.1 }
} else {
errors::ItemWas::CfgOut { span: cfg.1 }
diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs
index 1094f00e42f29..fd845e31c9093 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs
@@ -1886,12 +1886,56 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
let ty::Dynamic(_, _) = trait_pred.self_ty().skip_binder().kind() else {
return false;
};
+ if let Node::Item(hir::Item { kind: hir::ItemKind::Fn { sig: fn_sig, .. }, .. })
+ | Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Fn(fn_sig, _), .. })
+ | Node::TraitItem(hir::TraitItem { kind: hir::TraitItemKind::Fn(fn_sig, _), .. }) =
+ self.tcx.hir_node_by_def_id(obligation.cause.body_id)
+ && let hir::FnRetTy::Return(ty) = fn_sig.decl.output
+ && let hir::TyKind::Path(qpath) = ty.kind
+ && let hir::QPath::Resolved(None, path) = qpath
+ && let Res::Def(DefKind::TyAlias, def_id) = path.res
+ {
+ // Do not suggest
+ // type T = dyn Trait;
+ // fn foo() -> impl T { .. }
+ err.span_note(self.tcx.def_span(def_id), "this type alias is unsized");
+ err.multipart_suggestion(
+ format!(
+ "consider boxing the return type, and wrapping all of the returned values in \
+ `Box::new`",
+ ),
+ vec![
+ (ty.span.shrink_to_lo(), "Box<".to_string()),
+ (ty.span.shrink_to_hi(), ">".to_string()),
+ ],
+ Applicability::MaybeIncorrect,
+ );
+ return false;
+ }
err.code(E0746);
err.primary_message("return type cannot be a trait object without pointer indirection");
err.children.clear();
- let span = obligation.cause.span;
+ let mut span = obligation.cause.span;
+ if let DefKind::Closure = self.tcx.def_kind(obligation.cause.body_id)
+ && let parent = self.tcx.parent(obligation.cause.body_id.into())
+ && let DefKind::Fn | DefKind::AssocFn = self.tcx.def_kind(parent)
+ && self.tcx.asyncness(parent).is_async()
+ && let Some(parent) = parent.as_local()
+ && let Node::Item(hir::Item { kind: hir::ItemKind::Fn { sig: fn_sig, .. }, .. })
+ | Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Fn(fn_sig, _), .. })
+ | Node::TraitItem(hir::TraitItem {
+ kind: hir::TraitItemKind::Fn(fn_sig, _), ..
+ }) = self.tcx.hir_node_by_def_id(parent)
+ {
+ // Do not suggest (#147894)
+ // async fn foo() -> dyn Display impl { .. }
+ // and
+ // async fn foo() -> dyn Display Box
+ span = fn_sig.decl.output.span();
+ err.span(span);
+ }
let body = self.tcx.hir_body_owned_by(obligation.cause.body_id);
let mut visitor = ReturnsVisitor::default();
diff --git a/library/Cargo.lock b/library/Cargo.lock
index accbbe9d236ff..513d3f1366987 100644
--- a/library/Cargo.lock
+++ b/library/Cargo.lock
@@ -146,9 +146,9 @@ dependencies = [
[[package]]
name = "libc"
-version = "0.2.177"
+version = "0.2.178"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976"
+checksum = "37c93d8daa9d8a012fd8ab92f088405fb202ea0b6ab73ee2482ae66af4f42091"
dependencies = [
"rustc-std-workspace-core",
]
diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml
index 3a673cf23b835..83a0826ac425d 100644
--- a/library/std/Cargo.toml
+++ b/library/std/Cargo.toml
@@ -33,7 +33,7 @@ miniz_oxide = { version = "0.8.0", optional = true, default-features = false }
addr2line = { version = "0.25.0", optional = true, default-features = false }
[target.'cfg(not(all(windows, target_env = "msvc")))'.dependencies]
-libc = { version = "0.2.177", default-features = false, features = [
+libc = { version = "0.2.178", default-features = false, features = [
'rustc-dep-of-std',
], public = true }
@@ -78,7 +78,7 @@ hermit-abi = { version = "0.5.0", features = [
'rustc-dep-of-std',
], public = true }
-[target.'cfg(target_os = "wasi")'.dependencies]
+[target.'cfg(all(target_os = "wasi", target_env = "p1"))'.dependencies]
wasi = { version = "0.11.0", features = [
'rustc-dep-of-std',
], default-features = false }
diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs
index 8b3e943b4ccd0..d14d0ad2f0ea6 100644
--- a/library/std/src/fs.rs
+++ b/library/std/src/fs.rs
@@ -1324,7 +1324,7 @@ impl Read for &File {
///
/// # Platform-specific behavior
///
- /// This function currently returns `true` on Unix an `false` on Windows.
+ /// This function currently returns `true` on Unix and `false` on Windows.
/// Note that this [may change in the future][changes].
///
/// [changes]: io#platform-specific-behavior
@@ -1385,7 +1385,7 @@ impl Write for &File {
///
/// # Platform-specific behavior
///
- /// This function currently returns `true` on Unix an `false` on Windows.
+ /// This function currently returns `true` on Unix and `false` on Windows.
/// Note that this [may change in the future][changes].
///
/// [changes]: io#platform-specific-behavior
diff --git a/library/std/src/os/wasi/fs.rs b/library/std/src/os/wasi/fs.rs
index 5ea91dd6521ad..9145283dae6e1 100644
--- a/library/std/src/os/wasi/fs.rs
+++ b/library/std/src/os/wasi/fs.rs
@@ -1,4 +1,4 @@
-//! WASI-specific extensions to primitives in the [`std::fs`] module.
+//! WASIp1-specific extensions to primitives in the [`std::fs`] module.
//!
//! [`std::fs`]: crate::fs
@@ -8,11 +8,16 @@
#[allow(unused_imports)]
use io::{Read, Write};
+#[cfg(target_env = "p1")]
use crate::ffi::OsStr;
-use crate::fs::{self, File, Metadata, OpenOptions};
-use crate::io::{self, IoSlice, IoSliceMut};
-use crate::path::{Path, PathBuf};
-use crate::sys_common::{AsInner, AsInnerMut, FromInner};
+use crate::fs::{self, File, OpenOptions};
+use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut};
+#[cfg(target_env = "p1")]
+use crate::os::fd::AsRawFd;
+use crate::path::Path;
+#[cfg(target_env = "p1")]
+use crate::sys::err2io;
+use crate::sys_common::{AsInner, AsInnerMut};
/// WASI-specific extensions to [`File`].
pub trait FileExt {
@@ -27,10 +32,7 @@ pub trait FileExt {
///
/// Note that similar to [`File::read`], it is not an error to return with a
/// short read.
- fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result {
- let bufs = &mut [IoSliceMut::new(buf)];
- self.read_vectored_at(bufs, offset)
- }
+ fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result;
/// Reads a number of bytes starting from a given offset.
///
@@ -45,6 +47,13 @@ pub trait FileExt {
/// return with a short read.
fn read_vectored_at(&self, bufs: &mut [IoSliceMut<'_>], offset: u64) -> io::Result;
+ /// Reads some bytes starting from a given offset into the buffer.
+ ///
+ /// This equivalent to the [`read_at`](FileExt::read_at) method, except that it is passed a
+ /// [`BorrowedCursor`] rather than `&mut [u8]` to allow use with uninitialized buffers. The new
+ /// data will be appended to any existing contents of `buf`.
+ fn read_buf_at(&self, buf: BorrowedCursor<'_>, offset: u64) -> io::Result<()>;
+
/// Reads the exact number of byte required to fill `buf` from the given offset.
///
/// The offset is relative to the start of the file and thus independent
@@ -102,10 +111,7 @@ pub trait FileExt {
///
/// Note that similar to [`File::write`], it is not an error to return a
/// short write.
- fn write_at(&self, buf: &[u8], offset: u64) -> io::Result {
- let bufs = &[IoSlice::new(buf)];
- self.write_vectored_at(bufs, offset)
- }
+ fn write_at(&self, buf: &[u8], offset: u64) -> io::Result;
/// Writes a number of bytes starting from a given offset.
///
@@ -164,54 +170,49 @@ pub trait FileExt {
///
/// This corresponds to the `fd_fdstat_set_flags` syscall.
#[doc(alias = "fd_fdstat_set_flags")]
+ #[cfg(target_env = "p1")]
fn fdstat_set_flags(&self, flags: u16) -> io::Result<()>;
/// Adjusts the rights associated with this file.
///
/// This corresponds to the `fd_fdstat_set_rights` syscall.
#[doc(alias = "fd_fdstat_set_rights")]
+ #[cfg(target_env = "p1")]
fn fdstat_set_rights(&self, rights: u64, inheriting: u64) -> io::Result<()>;
/// Provides file advisory information on a file descriptor.
///
/// This corresponds to the `fd_advise` syscall.
#[doc(alias = "fd_advise")]
+ #[cfg(target_env = "p1")]
fn advise(&self, offset: u64, len: u64, advice: u8) -> io::Result<()>;
/// Forces the allocation of space in a file.
///
/// This corresponds to the `fd_allocate` syscall.
#[doc(alias = "fd_allocate")]
+ #[cfg(target_env = "p1")]
fn allocate(&self, offset: u64, len: u64) -> io::Result<()>;
/// Creates a directory.
///
/// This corresponds to the `path_create_directory` syscall.
#[doc(alias = "path_create_directory")]
+ #[cfg(target_env = "p1")]
fn create_directory>(&self, dir: P) -> io::Result<()>;
- /// Reads the contents of a symbolic link.
- ///
- /// This corresponds to the `path_readlink` syscall.
- #[doc(alias = "path_readlink")]
- fn read_link>(&self, path: P) -> io::Result;
-
- /// Returns the attributes of a file or directory.
- ///
- /// This corresponds to the `path_filestat_get` syscall.
- #[doc(alias = "path_filestat_get")]
- fn metadata_at>(&self, lookup_flags: u32, path: P) -> io::Result;
-
/// Unlinks a file.
///
/// This corresponds to the `path_unlink_file` syscall.
#[doc(alias = "path_unlink_file")]
+ #[cfg(target_env = "p1")]
fn remove_file>(&self, path: P) -> io::Result<()>;
/// Removes a directory.
///
/// This corresponds to the `path_remove_directory` syscall.
#[doc(alias = "path_remove_directory")]
+ #[cfg(target_env = "p1")]
fn remove_directory>(&self, path: P) -> io::Result<()>;
}
@@ -222,23 +223,41 @@ pub trait FileExt {
// FIXME: bind poll_oneoff maybe? - probably should wait for I/O to settle
// FIXME: bind random_get maybe? - on crates.io for unix
-impl FileExt for fs::File {
+impl FileExt for File {
+ fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result {
+ self.as_inner().read_at(buf, offset)
+ }
+
+ fn read_buf_at(&self, buf: BorrowedCursor<'_>, offset: u64) -> io::Result<()> {
+ self.as_inner().read_buf_at(buf, offset)
+ }
+
fn read_vectored_at(&self, bufs: &mut [IoSliceMut<'_>], offset: u64) -> io::Result {
- self.as_inner().as_inner().pread(bufs, offset)
+ self.as_inner().read_vectored_at(bufs, offset)
+ }
+
+ fn write_at(&self, buf: &[u8], offset: u64) -> io::Result {
+ self.as_inner().write_at(buf, offset)
}
fn write_vectored_at(&self, bufs: &[IoSlice<'_>], offset: u64) -> io::Result {
- self.as_inner().as_inner().pwrite(bufs, offset)
+ self.as_inner().write_vectored_at(bufs, offset)
}
+ #[cfg(target_env = "p1")]
fn fdstat_set_flags(&self, flags: u16) -> io::Result<()> {
- self.as_inner().as_inner().set_flags(flags)
+ unsafe { wasi::fd_fdstat_set_flags(self.as_raw_fd() as wasi::Fd, flags).map_err(err2io) }
}
+ #[cfg(target_env = "p1")]
fn fdstat_set_rights(&self, rights: u64, inheriting: u64) -> io::Result<()> {
- self.as_inner().as_inner().set_rights(rights, inheriting)
+ unsafe {
+ wasi::fd_fdstat_set_rights(self.as_raw_fd() as wasi::Fd, rights, inheriting)
+ .map_err(err2io)
+ }
}
+ #[cfg(target_env = "p1")]
fn advise(&self, offset: u64, len: u64, advice: u8) -> io::Result<()> {
let advice = match advice {
a if a == wasi::ADVICE_NORMAL.raw() => wasi::ADVICE_NORMAL,
@@ -255,149 +274,46 @@ impl FileExt for fs::File {
}
};
- self.as_inner().as_inner().advise(offset, len, advice)
+ unsafe {
+ wasi::fd_advise(self.as_raw_fd() as wasi::Fd, offset, len, advice).map_err(err2io)
+ }
}
+ #[cfg(target_env = "p1")]
fn allocate(&self, offset: u64, len: u64) -> io::Result<()> {
- self.as_inner().as_inner().allocate(offset, len)
+ unsafe { wasi::fd_allocate(self.as_raw_fd() as wasi::Fd, offset, len).map_err(err2io) }
}
+ #[cfg(target_env = "p1")]
fn create_directory>(&self, dir: P) -> io::Result<()> {
- self.as_inner().as_inner().create_directory(osstr2str(dir.as_ref().as_ref())?)
- }
-
- fn read_link>(&self, path: P) -> io::Result {
- self.as_inner().read_link(path.as_ref())
- }
-
- fn metadata_at>(&self, lookup_flags: u32, path: P) -> io::Result {
- let m = self.as_inner().metadata_at(lookup_flags, path.as_ref())?;
- Ok(FromInner::from_inner(m))
+ let path = osstr2str(dir.as_ref().as_ref())?;
+ unsafe { wasi::path_create_directory(self.as_raw_fd() as wasi::Fd, path).map_err(err2io) }
}
+ #[cfg(target_env = "p1")]
fn remove_file>(&self, path: P) -> io::Result<()> {
- self.as_inner().as_inner().unlink_file(osstr2str(path.as_ref().as_ref())?)
+ let path = osstr2str(path.as_ref().as_ref())?;
+ unsafe { wasi::path_unlink_file(self.as_raw_fd() as wasi::Fd, path).map_err(err2io) }
}
+ #[cfg(target_env = "p1")]
fn remove_directory>(&self, path: P) -> io::Result<()> {
- self.as_inner().as_inner().remove_directory(osstr2str(path.as_ref().as_ref())?)
+ let path = osstr2str(path.as_ref().as_ref())?;
+ unsafe { wasi::path_remove_directory(self.as_raw_fd() as wasi::Fd, path).map_err(err2io) }
}
}
-/// WASI-specific extensions to [`fs::OpenOptions`].
+/// WASI-specific extensions to [`OpenOptions`].
pub trait OpenOptionsExt {
- /// Pass custom `dirflags` argument to `path_open`.
- ///
- /// This option configures the `dirflags` argument to the
- /// `path_open` syscall which `OpenOptions` will eventually call. The
- /// `dirflags` argument configures how the file is looked up, currently
- /// primarily affecting whether symlinks are followed or not.
- ///
- /// By default this value is `__WASI_LOOKUP_SYMLINK_FOLLOW`, or symlinks are
- /// followed. You can call this method with 0 to disable following symlinks
- fn lookup_flags(&mut self, flags: u32) -> &mut Self;
-
- /// Indicates whether `OpenOptions` must open a directory or not.
- ///
- /// This method will configure whether the `__WASI_O_DIRECTORY` flag is
- /// passed when opening a file. When passed it will require that the opened
- /// path is a directory.
- ///
- /// This option is by default `false`
- fn directory(&mut self, dir: bool) -> &mut Self;
-
- /// Indicates whether `__WASI_FDFLAG_DSYNC` is passed in the `fs_flags`
- /// field of `path_open`.
- ///
- /// This option is by default `false`
- fn dsync(&mut self, dsync: bool) -> &mut Self;
-
- /// Indicates whether `__WASI_FDFLAG_NONBLOCK` is passed in the `fs_flags`
- /// field of `path_open`.
- ///
- /// This option is by default `false`
- fn nonblock(&mut self, nonblock: bool) -> &mut Self;
-
- /// Indicates whether `__WASI_FDFLAG_RSYNC` is passed in the `fs_flags`
- /// field of `path_open`.
- ///
- /// This option is by default `false`
- fn rsync(&mut self, rsync: bool) -> &mut Self;
-
- /// Indicates whether `__WASI_FDFLAG_SYNC` is passed in the `fs_flags`
- /// field of `path_open`.
- ///
- /// This option is by default `false`
- fn sync(&mut self, sync: bool) -> &mut Self;
-
- /// Indicates the value that should be passed in for the `fs_rights_base`
- /// parameter of `path_open`.
- ///
- /// This option defaults based on the `read` and `write` configuration of
- /// this `OpenOptions` builder. If this method is called, however, the
- /// exact mask passed in will be used instead.
- fn fs_rights_base(&mut self, rights: u64) -> &mut Self;
-
- /// Indicates the value that should be passed in for the
- /// `fs_rights_inheriting` parameter of `path_open`.
- ///
- /// The default for this option is the same value as what will be passed
- /// for the `fs_rights_base` parameter but if this method is called then
- /// the specified value will be used instead.
- fn fs_rights_inheriting(&mut self, rights: u64) -> &mut Self;
-
- /// Open a file or directory.
- ///
- /// This corresponds to the `path_open` syscall.
- #[doc(alias = "path_open")]
- fn open_at>(&self, file: &File, path: P) -> io::Result;
+ /// Pass custom flags to the `flags` argument of `open`.
+ fn custom_flags(&mut self, flags: i32) -> &mut Self;
}
impl OpenOptionsExt for OpenOptions {
- fn lookup_flags(&mut self, flags: u32) -> &mut OpenOptions {
- self.as_inner_mut().lookup_flags(flags);
- self
- }
-
- fn directory(&mut self, dir: bool) -> &mut OpenOptions {
- self.as_inner_mut().directory(dir);
- self
- }
-
- fn dsync(&mut self, enabled: bool) -> &mut OpenOptions {
- self.as_inner_mut().dsync(enabled);
- self
- }
-
- fn nonblock(&mut self, enabled: bool) -> &mut OpenOptions {
- self.as_inner_mut().nonblock(enabled);
- self
- }
-
- fn rsync(&mut self, enabled: bool) -> &mut OpenOptions {
- self.as_inner_mut().rsync(enabled);
- self
- }
-
- fn sync(&mut self, enabled: bool) -> &mut OpenOptions {
- self.as_inner_mut().sync(enabled);
+ fn custom_flags(&mut self, flags: i32) -> &mut OpenOptions {
+ self.as_inner_mut().custom_flags(flags);
self
}
-
- fn fs_rights_base(&mut self, rights: u64) -> &mut OpenOptions {
- self.as_inner_mut().fs_rights_base(rights);
- self
- }
-
- fn fs_rights_inheriting(&mut self, rights: u64) -> &mut OpenOptions {
- self.as_inner_mut().fs_rights_inheriting(rights);
- self
- }
-
- fn open_at>(&self, file: &File, path: P) -> io::Result {
- let inner = file.as_inner().open_at(path.as_ref(), self.as_inner())?;
- Ok(File::from_inner(inner))
- }
}
/// WASI-specific extensions to [`fs::Metadata`].
@@ -408,37 +324,17 @@ pub trait MetadataExt {
fn ino(&self) -> u64;
/// Returns the `st_nlink` field of the internal `filestat_t`
fn nlink(&self) -> u64;
- /// Returns the `st_size` field of the internal `filestat_t`
- fn size(&self) -> u64;
- /// Returns the `st_atim` field of the internal `filestat_t`
- fn atim(&self) -> u64;
- /// Returns the `st_mtim` field of the internal `filestat_t`
- fn mtim(&self) -> u64;
- /// Returns the `st_ctim` field of the internal `filestat_t`
- fn ctim(&self) -> u64;
}
impl MetadataExt for fs::Metadata {
fn dev(&self) -> u64 {
- self.as_inner().as_wasi().dev
+ self.as_inner().as_inner().st_dev
}
fn ino(&self) -> u64 {
- self.as_inner().as_wasi().ino
+ self.as_inner().as_inner().st_ino
}
fn nlink(&self) -> u64 {
- self.as_inner().as_wasi().nlink
- }
- fn size(&self) -> u64 {
- self.as_inner().as_wasi().size
- }
- fn atim(&self) -> u64 {
- self.as_inner().as_wasi().atim
- }
- fn mtim(&self) -> u64 {
- self.as_inner().as_wasi().mtim
- }
- fn ctim(&self) -> u64 {
- self.as_inner().as_wasi().ctim
+ self.as_inner().as_inner().st_nlink
}
}
@@ -451,28 +347,19 @@ pub trait FileTypeExt {
fn is_block_device(&self) -> bool;
/// Returns `true` if this file type is a character device.
fn is_char_device(&self) -> bool;
- /// Returns `true` if this file type is a socket datagram.
- fn is_socket_dgram(&self) -> bool;
- /// Returns `true` if this file type is a socket stream.
- fn is_socket_stream(&self) -> bool;
/// Returns `true` if this file type is any type of socket.
- fn is_socket(&self) -> bool {
- self.is_socket_stream() || self.is_socket_dgram()
- }
+ fn is_socket(&self) -> bool;
}
impl FileTypeExt for fs::FileType {
fn is_block_device(&self) -> bool {
- self.as_inner().bits() == wasi::FILETYPE_BLOCK_DEVICE
+ self.as_inner().is(libc::S_IFBLK)
}
fn is_char_device(&self) -> bool {
- self.as_inner().bits() == wasi::FILETYPE_CHARACTER_DEVICE
- }
- fn is_socket_dgram(&self) -> bool {
- self.as_inner().bits() == wasi::FILETYPE_SOCKET_DGRAM
+ self.as_inner().is(libc::S_IFCHR)
}
- fn is_socket_stream(&self) -> bool {
- self.as_inner().bits() == wasi::FILETYPE_SOCKET_STREAM
+ fn is_socket(&self) -> bool {
+ self.as_inner().is(libc::S_IFSOCK)
}
}
@@ -492,6 +379,7 @@ impl DirEntryExt for fs::DirEntry {
///
/// This corresponds to the `path_link` syscall.
#[doc(alias = "path_link")]
+#[cfg(target_env = "p1")]
pub fn link, U: AsRef>(
old_fd: &File,
old_flags: u32,
@@ -499,43 +387,58 @@ pub fn link, U: AsRef>(
new_fd: &File,
new_path: U,
) -> io::Result<()> {
- old_fd.as_inner().as_inner().link(
- old_flags,
- osstr2str(old_path.as_ref().as_ref())?,
- new_fd.as_inner().as_inner(),
- osstr2str(new_path.as_ref().as_ref())?,
- )
+ unsafe {
+ wasi::path_link(
+ old_fd.as_raw_fd() as wasi::Fd,
+ old_flags,
+ osstr2str(old_path.as_ref().as_ref())?,
+ new_fd.as_raw_fd() as wasi::Fd,
+ osstr2str(new_path.as_ref().as_ref())?,
+ )
+ .map_err(err2io)
+ }
}
/// Renames a file or directory.
///
/// This corresponds to the `path_rename` syscall.
#[doc(alias = "path_rename")]
+#[cfg(target_env = "p1")]
pub fn rename, U: AsRef>(
old_fd: &File,
old_path: P,
new_fd: &File,
new_path: U,
) -> io::Result<()> {
- old_fd.as_inner().as_inner().rename(
- osstr2str(old_path.as_ref().as_ref())?,
- new_fd.as_inner().as_inner(),
- osstr2str(new_path.as_ref().as_ref())?,
- )
+ unsafe {
+ wasi::path_rename(
+ old_fd.as_raw_fd() as wasi::Fd,
+ osstr2str(old_path.as_ref().as_ref())?,
+ new_fd.as_raw_fd() as wasi::Fd,
+ osstr2str(new_path.as_ref().as_ref())?,
+ )
+ .map_err(err2io)
+ }
}
/// Creates a symbolic link.
///
/// This corresponds to the `path_symlink` syscall.
#[doc(alias = "path_symlink")]
+#[cfg(target_env = "p1")]
pub fn symlink, U: AsRef>(
old_path: P,
fd: &File,
new_path: U,
) -> io::Result<()> {
- fd.as_inner()
- .as_inner()
- .symlink(osstr2str(old_path.as_ref().as_ref())?, osstr2str(new_path.as_ref().as_ref())?)
+ unsafe {
+ wasi::path_symlink(
+ osstr2str(old_path.as_ref().as_ref())?,
+ fd.as_raw_fd() as wasi::Fd,
+ osstr2str(new_path.as_ref().as_ref())?,
+ )
+ .map_err(err2io)
+ }
}
/// Creates a symbolic link.
@@ -546,6 +449,7 @@ pub fn symlink_path, U: AsRef>(old_path: P, new_path: U) ->
crate::sys::fs::symlink(old_path.as_ref(), new_path.as_ref())
}
+#[cfg(target_env = "p1")]
fn osstr2str(f: &OsStr) -> io::Result<&str> {
f.to_str().ok_or_else(|| io::const_error!(io::ErrorKind::Uncategorized, "input must be utf-8"))
}
diff --git a/library/std/src/os/wasi/net/mod.rs b/library/std/src/os/wasi/net/mod.rs
index 4704dd574517a..9430cd3b05eee 100644
--- a/library/std/src/os/wasi/net/mod.rs
+++ b/library/std/src/os/wasi/net/mod.rs
@@ -2,7 +2,8 @@
#![unstable(feature = "wasi_ext", issue = "71213")]
-use crate::sys_common::AsInner;
+use crate::os::fd::AsRawFd;
+use crate::sys::err2io;
use crate::{io, net};
/// WASI-specific extensions to [`std::net::TcpListener`].
@@ -17,6 +18,6 @@ pub trait TcpListenerExt {
impl TcpListenerExt for net::TcpListener {
fn sock_accept(&self, flags: u16) -> io::Result {
- self.as_inner().as_inner().as_inner().sock_accept(flags)
+ unsafe { wasi::sock_accept(self.as_raw_fd() as wasi::Fd, flags).map_err(err2io) }
}
}
diff --git a/library/std/src/sys/fd/mod.rs b/library/std/src/sys/fd/mod.rs
index 330499ecc18f6..02d61a62f4e6b 100644
--- a/library/std/src/sys/fd/mod.rs
+++ b/library/std/src/sys/fd/mod.rs
@@ -3,7 +3,7 @@
#![forbid(unsafe_op_in_unsafe_fn)]
cfg_select! {
- target_family = "unix" => {
+ any(target_family = "unix", target_os = "wasi") => {
mod unix;
pub use unix::*;
}
@@ -19,9 +19,5 @@ cfg_select! {
mod sgx;
pub use sgx::*;
}
- target_os = "wasi" => {
- mod wasi;
- pub use wasi::*;
- }
_ => {}
}
diff --git a/library/std/src/sys/fd/unix.rs b/library/std/src/sys/fd/unix.rs
index a631e1d91393f..33fff36b35b01 100644
--- a/library/std/src/sys/fd/unix.rs
+++ b/library/std/src/sys/fd/unix.rs
@@ -35,7 +35,7 @@ cfg_select! {
use crate::cmp;
use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut, Read};
-use crate::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd};
+use crate::os::fd::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd};
use crate::sys::cvt;
#[cfg(all(target_os = "android", target_pointer_width = "64"))]
use crate::sys::pal::weak::syscall;
@@ -152,7 +152,8 @@ impl FileDesc {
target_os = "espidf",
target_os = "horizon",
target_os = "vita",
- target_os = "nuttx"
+ target_os = "nuttx",
+ target_os = "wasi",
)))
}
@@ -385,7 +386,8 @@ impl FileDesc {
target_os = "espidf",
target_os = "horizon",
target_os = "vita",
- target_os = "nuttx"
+ target_os = "nuttx",
+ target_os = "wasi",
)))
}
@@ -560,6 +562,7 @@ impl FileDesc {
target_os = "redox",
target_os = "vxworks",
target_os = "nto",
+ target_os = "wasi",
)))]
pub fn set_cloexec(&self) -> io::Result<()> {
unsafe {
@@ -583,6 +586,7 @@ impl FileDesc {
target_os = "redox",
target_os = "vxworks",
target_os = "nto",
+ target_os = "wasi",
))]
pub fn set_cloexec(&self) -> io::Result<()> {
unsafe {
diff --git a/library/std/src/sys/fd/wasi.rs b/library/std/src/sys/fd/wasi.rs
deleted file mode 100644
index a468b31168afa..0000000000000
--- a/library/std/src/sys/fd/wasi.rs
+++ /dev/null
@@ -1,331 +0,0 @@
-#![expect(dead_code)]
-
-use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut, SeekFrom};
-use crate::mem;
-use crate::net::Shutdown;
-use crate::os::wasi::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd};
-use crate::sys::pal::err2io;
-use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner};
-
-#[derive(Debug)]
-pub struct WasiFd {
- fd: OwnedFd,
-}
-
-fn iovec<'a>(a: &'a mut [IoSliceMut<'_>]) -> &'a [wasi::Iovec] {
- assert_eq!(size_of::>(), size_of::());
- assert_eq!(align_of::>(), align_of::());
- // SAFETY: `IoSliceMut` and `IoVec` have exactly the same memory layout.
- // We decorate our `IoSliceMut` with `repr(transparent)` (see `io.rs`), and
- // `crate::io::IoSliceMut` is a `repr(transparent)` wrapper around our type, so this is
- // guaranteed.
- unsafe { mem::transmute(a) }
-}
-
-fn ciovec<'a>(a: &'a [IoSlice<'_>]) -> &'a [wasi::Ciovec] {
- assert_eq!(size_of::>(), size_of::());
- assert_eq!(align_of::>(), align_of::());
- // SAFETY: `IoSlice` and `CIoVec` have exactly the same memory layout.
- // We decorate our `IoSlice` with `repr(transparent)` (see `io.rs`), and
- // `crate::io::IoSlice` is a `repr(transparent)` wrapper around our type, so this is
- // guaranteed.
- unsafe { mem::transmute(a) }
-}
-
-impl WasiFd {
- pub fn datasync(&self) -> io::Result<()> {
- unsafe { wasi::fd_datasync(self.as_raw_fd() as wasi::Fd).map_err(err2io) }
- }
-
- pub fn pread(&self, bufs: &mut [IoSliceMut<'_>], offset: u64) -> io::Result {
- unsafe { wasi::fd_pread(self.as_raw_fd() as wasi::Fd, iovec(bufs), offset).map_err(err2io) }
- }
-
- pub fn pwrite(&self, bufs: &[IoSlice<'_>], offset: u64) -> io::Result {
- unsafe {
- wasi::fd_pwrite(self.as_raw_fd() as wasi::Fd, ciovec(bufs), offset).map_err(err2io)
- }
- }
-
- pub fn read(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result {
- unsafe { wasi::fd_read(self.as_raw_fd() as wasi::Fd, iovec(bufs)).map_err(err2io) }
- }
-
- pub fn read_buf(&self, mut buf: BorrowedCursor<'_>) -> io::Result<()> {
- unsafe {
- let bufs = [wasi::Iovec {
- buf: buf.as_mut().as_mut_ptr() as *mut u8,
- buf_len: buf.capacity(),
- }];
- match wasi::fd_read(self.as_raw_fd() as wasi::Fd, &bufs) {
- Ok(n) => {
- buf.advance(n);
- Ok(())
- }
- Err(e) => Err(err2io(e)),
- }
- }
- }
-
- pub fn write(&self, bufs: &[IoSlice<'_>]) -> io::Result {
- unsafe { wasi::fd_write(self.as_raw_fd() as wasi::Fd, ciovec(bufs)).map_err(err2io) }
- }
-
- pub fn seek(&self, pos: SeekFrom) -> io::Result {
- let (whence, offset) = match pos {
- SeekFrom::Start(pos) => (wasi::WHENCE_SET, pos as i64),
- SeekFrom::End(pos) => (wasi::WHENCE_END, pos),
- SeekFrom::Current(pos) => (wasi::WHENCE_CUR, pos),
- };
- unsafe { wasi::fd_seek(self.as_raw_fd() as wasi::Fd, offset, whence).map_err(err2io) }
- }
-
- pub fn tell(&self) -> io::Result {
- unsafe { wasi::fd_tell(self.as_raw_fd() as wasi::Fd).map_err(err2io) }
- }
-
- // FIXME: __wasi_fd_fdstat_get
-
- pub fn set_flags(&self, flags: wasi::Fdflags) -> io::Result<()> {
- unsafe { wasi::fd_fdstat_set_flags(self.as_raw_fd() as wasi::Fd, flags).map_err(err2io) }
- }
-
- pub fn set_rights(&self, base: wasi::Rights, inheriting: wasi::Rights) -> io::Result<()> {
- unsafe {
- wasi::fd_fdstat_set_rights(self.as_raw_fd() as wasi::Fd, base, inheriting)
- .map_err(err2io)
- }
- }
-
- pub fn sync(&self) -> io::Result<()> {
- unsafe { wasi::fd_sync(self.as_raw_fd() as wasi::Fd).map_err(err2io) }
- }
-
- pub(crate) fn advise(&self, offset: u64, len: u64, advice: wasi::Advice) -> io::Result<()> {
- unsafe {
- wasi::fd_advise(self.as_raw_fd() as wasi::Fd, offset, len, advice).map_err(err2io)
- }
- }
-
- pub fn allocate(&self, offset: u64, len: u64) -> io::Result<()> {
- unsafe { wasi::fd_allocate(self.as_raw_fd() as wasi::Fd, offset, len).map_err(err2io) }
- }
-
- pub fn create_directory(&self, path: &str) -> io::Result<()> {
- unsafe { wasi::path_create_directory(self.as_raw_fd() as wasi::Fd, path).map_err(err2io) }
- }
-
- pub fn link(
- &self,
- old_flags: wasi::Lookupflags,
- old_path: &str,
- new_fd: &WasiFd,
- new_path: &str,
- ) -> io::Result<()> {
- unsafe {
- wasi::path_link(
- self.as_raw_fd() as wasi::Fd,
- old_flags,
- old_path,
- new_fd.as_raw_fd() as wasi::Fd,
- new_path,
- )
- .map_err(err2io)
- }
- }
-
- pub fn open(
- &self,
- dirflags: wasi::Lookupflags,
- path: &str,
- oflags: wasi::Oflags,
- fs_rights_base: wasi::Rights,
- fs_rights_inheriting: wasi::Rights,
- fs_flags: wasi::Fdflags,
- ) -> io::Result {
- unsafe {
- wasi::path_open(
- self.as_raw_fd() as wasi::Fd,
- dirflags,
- path,
- oflags,
- fs_rights_base,
- fs_rights_inheriting,
- fs_flags,
- )
- .map(|fd| WasiFd::from_raw_fd(fd as RawFd))
- .map_err(err2io)
- }
- }
-
- pub fn readdir(&self, buf: &mut [u8], cookie: wasi::Dircookie) -> io::Result {
- unsafe {
- wasi::fd_readdir(self.as_raw_fd() as wasi::Fd, buf.as_mut_ptr(), buf.len(), cookie)
- .map_err(err2io)
- }
- }
-
- pub fn readlink(&self, path: &str, buf: &mut [u8]) -> io::Result {
- unsafe {
- wasi::path_readlink(self.as_raw_fd() as wasi::Fd, path, buf.as_mut_ptr(), buf.len())
- .map_err(err2io)
- }
- }
-
- pub fn rename(&self, old_path: &str, new_fd: &WasiFd, new_path: &str) -> io::Result<()> {
- unsafe {
- wasi::path_rename(
- self.as_raw_fd() as wasi::Fd,
- old_path,
- new_fd.as_raw_fd() as wasi::Fd,
- new_path,
- )
- .map_err(err2io)
- }
- }
-
- pub(crate) fn filestat_get(&self) -> io::Result {
- unsafe { wasi::fd_filestat_get(self.as_raw_fd() as wasi::Fd).map_err(err2io) }
- }
-
- pub fn filestat_set_times(
- &self,
- atim: wasi::Timestamp,
- mtim: wasi::Timestamp,
- fstflags: wasi::Fstflags,
- ) -> io::Result<()> {
- unsafe {
- wasi::fd_filestat_set_times(self.as_raw_fd() as wasi::Fd, atim, mtim, fstflags)
- .map_err(err2io)
- }
- }
-
- pub fn filestat_set_size(&self, size: u64) -> io::Result<()> {
- unsafe { wasi::fd_filestat_set_size(self.as_raw_fd() as wasi::Fd, size).map_err(err2io) }
- }
-
- pub(crate) fn path_filestat_get(
- &self,
- flags: wasi::Lookupflags,
- path: &str,
- ) -> io::Result {
- unsafe {
- wasi::path_filestat_get(self.as_raw_fd() as wasi::Fd, flags, path).map_err(err2io)
- }
- }
-
- pub fn path_filestat_set_times(
- &self,
- flags: wasi::Lookupflags,
- path: &str,
- atim: wasi::Timestamp,
- mtim: wasi::Timestamp,
- fstflags: wasi::Fstflags,
- ) -> io::Result<()> {
- unsafe {
- wasi::path_filestat_set_times(
- self.as_raw_fd() as wasi::Fd,
- flags,
- path,
- atim,
- mtim,
- fstflags,
- )
- .map_err(err2io)
- }
- }
-
- pub fn symlink(&self, old_path: &str, new_path: &str) -> io::Result<()> {
- unsafe {
- wasi::path_symlink(old_path, self.as_raw_fd() as wasi::Fd, new_path).map_err(err2io)
- }
- }
-
- pub fn unlink_file(&self, path: &str) -> io::Result<()> {
- unsafe { wasi::path_unlink_file(self.as_raw_fd() as wasi::Fd, path).map_err(err2io) }
- }
-
- pub fn remove_directory(&self, path: &str) -> io::Result<()> {
- unsafe { wasi::path_remove_directory(self.as_raw_fd() as wasi::Fd, path).map_err(err2io) }
- }
-
- pub fn sock_accept(&self, flags: wasi::Fdflags) -> io::Result {
- unsafe { wasi::sock_accept(self.as_raw_fd() as wasi::Fd, flags).map_err(err2io) }
- }
-
- pub fn sock_recv(
- &self,
- ri_data: &mut [IoSliceMut<'_>],
- ri_flags: wasi::Riflags,
- ) -> io::Result<(usize, wasi::Roflags)> {
- unsafe {
- wasi::sock_recv(self.as_raw_fd() as wasi::Fd, iovec(ri_data), ri_flags).map_err(err2io)
- }
- }
-
- pub fn sock_send(&self, si_data: &[IoSlice<'_>], si_flags: wasi::Siflags) -> io::Result {
- unsafe {
- wasi::sock_send(self.as_raw_fd() as wasi::Fd, ciovec(si_data), si_flags).map_err(err2io)
- }
- }
-
- pub fn sock_shutdown(&self, how: Shutdown) -> io::Result<()> {
- let how = match how {
- Shutdown::Read => wasi::SDFLAGS_RD,
- Shutdown::Write => wasi::SDFLAGS_WR,
- Shutdown::Both => wasi::SDFLAGS_WR | wasi::SDFLAGS_RD,
- };
- unsafe { wasi::sock_shutdown(self.as_raw_fd() as wasi::Fd, how).map_err(err2io) }
- }
-}
-
-impl AsInner for WasiFd {
- #[inline]
- fn as_inner(&self) -> &OwnedFd {
- &self.fd
- }
-}
-
-impl AsInnerMut for WasiFd {
- #[inline]
- fn as_inner_mut(&mut self) -> &mut OwnedFd {
- &mut self.fd
- }
-}
-
-impl IntoInner for WasiFd {
- fn into_inner(self) -> OwnedFd {
- self.fd
- }
-}
-
-impl FromInner for WasiFd {
- fn from_inner(owned_fd: OwnedFd) -> Self {
- Self { fd: owned_fd }
- }
-}
-
-impl AsFd for WasiFd {
- fn as_fd(&self) -> BorrowedFd<'_> {
- self.fd.as_fd()
- }
-}
-
-impl AsRawFd for WasiFd {
- #[inline]
- fn as_raw_fd(&self) -> RawFd {
- self.fd.as_raw_fd()
- }
-}
-
-impl IntoRawFd for WasiFd {
- fn into_raw_fd(self) -> RawFd {
- self.fd.into_raw_fd()
- }
-}
-
-impl FromRawFd for WasiFd {
- unsafe fn from_raw_fd(raw_fd: RawFd) -> Self {
- unsafe { Self { fd: FromRawFd::from_raw_fd(raw_fd) } }
- }
-}
diff --git a/library/std/src/sys/fs/mod.rs b/library/std/src/sys/fs/mod.rs
index eaea28871241a..4a66227ce5f45 100644
--- a/library/std/src/sys/fs/mod.rs
+++ b/library/std/src/sys/fs/mod.rs
@@ -6,12 +6,14 @@ use crate::path::{Path, PathBuf};
pub mod common;
cfg_select! {
- target_family = "unix" => {
+ any(target_family = "unix", target_os = "wasi") => {
mod unix;
use unix as imp;
+ #[cfg(not(target_os = "wasi"))]
pub use unix::{chown, fchown, lchown, mkfifo};
- #[cfg(not(target_os = "fuchsia"))]
+ #[cfg(not(any(target_os = "fuchsia", target_os = "wasi")))]
pub use unix::chroot;
+ #[cfg(not(target_os = "wasi"))]
pub(crate) use unix::debug_assert_fd_is_open;
#[cfg(any(target_os = "linux", target_os = "android"))]
pub(super) use unix::CachedFileMetadata;
@@ -43,10 +45,6 @@ cfg_select! {
mod vexos;
use vexos as imp;
}
- target_os = "wasi" => {
- mod wasi;
- use wasi as imp;
- }
_ => {
mod unsupported;
use unsupported as imp;
@@ -54,7 +52,7 @@ cfg_select! {
}
// FIXME: Replace this with platform-specific path conversion functions.
-#[cfg(not(any(target_family = "unix", target_os = "windows")))]
+#[cfg(not(any(target_family = "unix", target_os = "windows", target_os = "wasi")))]
#[inline]
pub fn with_native_path(path: &Path, f: &dyn Fn(&Path) -> io::Result) -> io::Result {
f(path)
diff --git a/library/std/src/sys/fs/unix.rs b/library/std/src/sys/fs/unix.rs
index 47d9ee226653e..507d093d2b2f6 100644
--- a/library/std/src/sys/fs/unix.rs
+++ b/library/std/src/sys/fs/unix.rs
@@ -31,6 +31,7 @@ use libc::fstatat64;
target_os = "redox",
target_os = "solaris",
target_os = "vita",
+ target_os = "wasi",
all(target_os = "linux", target_env = "musl"),
))]
use libc::readdir as readdir64;
@@ -47,6 +48,7 @@ use libc::readdir as readdir64;
target_os = "redox",
target_os = "solaris",
target_os = "vita",
+ target_os = "wasi",
)))]
use libc::readdir_r as readdir64_r;
#[cfg(any(all(target_os = "linux", not(target_env = "musl")), target_os = "hurd"))]
@@ -80,8 +82,11 @@ use crate::ffi::{CStr, OsStr, OsString};
use crate::fmt::{self, Write as _};
use crate::fs::TryLockError;
use crate::io::{self, BorrowedCursor, Error, IoSlice, IoSliceMut, SeekFrom};
-use crate::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd};
+use crate::os::fd::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd};
+#[cfg(target_family = "unix")]
use crate::os::unix::prelude::*;
+#[cfg(target_os = "wasi")]
+use crate::os::wasi::prelude::*;
use crate::path::{Path, PathBuf};
use crate::sync::Arc;
use crate::sys::common::small_c_string::run_path_with_cstr;
@@ -285,6 +290,7 @@ unsafe impl Sync for Dir {}
target_os = "redox",
target_os = "solaris",
target_os = "vita",
+ target_os = "wasi",
))]
pub struct DirEntry {
dir: Arc,
@@ -310,6 +316,7 @@ pub struct DirEntry {
target_os = "redox",
target_os = "solaris",
target_os = "vita",
+ target_os = "wasi",
))]
struct dirent64_min {
d_ino: u64,
@@ -335,6 +342,7 @@ struct dirent64_min {
target_os = "redox",
target_os = "solaris",
target_os = "vita",
+ target_os = "wasi",
)))]
pub struct DirEntry {
dir: Arc,
@@ -480,7 +488,7 @@ impl FileAttr {
}
}
-#[cfg(not(any(target_os = "netbsd", target_os = "nto", target_os = "aix")))]
+#[cfg(not(any(target_os = "netbsd", target_os = "nto", target_os = "aix", target_os = "wasi")))]
impl FileAttr {
#[cfg(not(any(
target_os = "vxworks",
@@ -595,18 +603,18 @@ impl FileAttr {
}
}
-#[cfg(target_os = "nto")]
+#[cfg(any(target_os = "nto", target_os = "wasi"))]
impl FileAttr {
pub fn modified(&self) -> io::Result {
- SystemTime::new(self.stat.st_mtim.tv_sec, self.stat.st_mtim.tv_nsec)
+ SystemTime::new(self.stat.st_mtim.tv_sec, self.stat.st_mtim.tv_nsec.into())
}
pub fn accessed(&self) -> io::Result {
- SystemTime::new(self.stat.st_atim.tv_sec, self.stat.st_atim.tv_nsec)
+ SystemTime::new(self.stat.st_atim.tv_sec, self.stat.st_atim.tv_nsec.into())
}
pub fn created(&self) -> io::Result {
- SystemTime::new(self.stat.st_ctim.tv_sec, self.stat.st_ctim.tv_nsec)
+ SystemTime::new(self.stat.st_ctim.tv_sec, self.stat.st_ctim.tv_nsec.into())
}
}
@@ -632,6 +640,7 @@ impl FilePermissions {
self.mode |= 0o222;
}
}
+ #[cfg(not(target_os = "wasi"))]
pub fn mode(&self) -> u32 {
self.mode as u32
}
@@ -715,6 +724,7 @@ impl Iterator for ReadDir {
target_os = "redox",
target_os = "solaris",
target_os = "vita",
+ target_os = "wasi",
))]
fn next(&mut self) -> Option> {
use crate::sys::os::{errno, set_errno};
@@ -812,6 +822,7 @@ impl Iterator for ReadDir {
target_os = "redox",
target_os = "solaris",
target_os = "vita",
+ target_os = "wasi",
)))]
fn next(&mut self) -> Option> {
if self.end_of_stream {
@@ -1002,6 +1013,7 @@ impl DirEntry {
target_os = "solaris",
target_os = "vita",
target_os = "vxworks",
+ target_os = "wasi",
target_vendor = "apple",
))]
pub fn ino(&self) -> u64 {
@@ -1057,6 +1069,7 @@ impl DirEntry {
target_os = "nto",
target_os = "vita",
target_os = "hurd",
+ target_os = "wasi",
)))]
fn name_cstr(&self) -> &CStr {
unsafe { CStr::from_ptr(self.entry.d_name.as_ptr()) }
@@ -1073,6 +1086,7 @@ impl DirEntry {
target_os = "nto",
target_os = "vita",
target_os = "hurd",
+ target_os = "wasi",
))]
fn name_cstr(&self) -> &CStr {
&self.name
@@ -1121,6 +1135,7 @@ impl OpenOptions {
pub fn custom_flags(&mut self, flags: i32) {
self.custom_flags = flags;
}
+ #[cfg(not(target_os = "wasi"))]
pub fn mode(&mut self, mode: u32) {
self.mode = mode as mode_t;
}
@@ -1769,6 +1784,7 @@ impl DirBuilder {
run_path_with_cstr(p, &|p| cvt(unsafe { libc::mkdir(p.as_ptr(), self.mode) }).map(|_| ()))
}
+ #[cfg(not(target_os = "wasi"))]
pub fn set_mode(&mut self, mode: u32) {
self.mode = mode as mode_t;
}
@@ -2217,7 +2233,7 @@ pub fn set_times_nofollow(p: &CStr, times: FileTimes) -> io::Result<()> {
set_times_impl(p, times, false)
}
-#[cfg(target_os = "espidf")]
+#[cfg(any(target_os = "espidf", target_os = "wasi"))]
fn open_to_and_set_permissions(
to: &Path,
_reader_metadata: &crate::fs::Metadata,
@@ -2228,7 +2244,7 @@ fn open_to_and_set_permissions(
Ok((writer, writer_metadata))
}
-#[cfg(not(target_os = "espidf"))]
+#[cfg(not(any(target_os = "espidf", target_os = "wasi")))]
fn open_to_and_set_permissions(
to: &Path,
reader_metadata: &crate::fs::Metadata,
@@ -2376,6 +2392,7 @@ pub fn copy(from: &Path, to: &Path) -> io::Result {
Ok(bytes_copied as u64)
}
+#[cfg(not(target_os = "wasi"))]
pub fn chown(path: &Path, uid: u32, gid: u32) -> io::Result<()> {
run_path_with_cstr(path, &|path| {
cvt(unsafe { libc::chown(path.as_ptr(), uid as libc::uid_t, gid as libc::gid_t) })
@@ -2383,12 +2400,13 @@ pub fn chown(path: &Path, uid: u32, gid: u32) -> io::Result<()> {
})
}
+#[cfg(not(target_os = "wasi"))]
pub fn fchown(fd: c_int, uid: u32, gid: u32) -> io::Result<()> {
cvt(unsafe { libc::fchown(fd, uid as libc::uid_t, gid as libc::gid_t) })?;
Ok(())
}
-#[cfg(not(target_os = "vxworks"))]
+#[cfg(not(any(target_os = "vxworks", target_os = "wasi")))]
pub fn lchown(path: &Path, uid: u32, gid: u32) -> io::Result<()> {
run_path_with_cstr(path, &|path| {
cvt(unsafe { libc::lchown(path.as_ptr(), uid as libc::uid_t, gid as libc::gid_t) })
@@ -2402,7 +2420,7 @@ pub fn lchown(path: &Path, uid: u32, gid: u32) -> io::Result<()> {
Err(io::const_error!(io::ErrorKind::Unsupported, "lchown not supported by vxworks"))
}
-#[cfg(not(any(target_os = "fuchsia", target_os = "vxworks")))]
+#[cfg(not(any(target_os = "fuchsia", target_os = "vxworks", target_os = "wasi")))]
pub fn chroot(dir: &Path) -> io::Result<()> {
run_path_with_cstr(dir, &|dir| cvt(unsafe { libc::chroot(dir.as_ptr()) }).map(|_| ()))
}
@@ -2413,6 +2431,7 @@ pub fn chroot(dir: &Path) -> io::Result<()> {
Err(io::const_error!(io::ErrorKind::Unsupported, "chroot not supported by vxworks"))
}
+#[cfg(not(target_os = "wasi"))]
pub fn mkfifo(path: &Path, mode: u32) -> io::Result<()> {
run_path_with_cstr(path, &|path| {
cvt(unsafe { libc::mkfifo(path.as_ptr(), mode.try_into().unwrap()) }).map(|_| ())
@@ -2451,11 +2470,11 @@ mod remove_dir_impl {
#[cfg(all(target_os = "linux", target_env = "gnu"))]
use libc::{fdopendir, openat64 as openat, unlinkat};
- use super::{Dir, DirEntry, InnerReadDir, ReadDir, lstat};
+ use super::{
+ AsRawFd, Dir, DirEntry, FromRawFd, InnerReadDir, IntoRawFd, OwnedFd, RawFd, ReadDir, lstat,
+ };
use crate::ffi::CStr;
use crate::io;
- use crate::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd};
- use crate::os::unix::prelude::{OwnedFd, RawFd};
use crate::path::{Path, PathBuf};
use crate::sys::common::small_c_string::run_path_with_cstr;
use crate::sys::{cvt, cvt_r};
@@ -2543,6 +2562,16 @@ mod remove_dir_impl {
// open the directory passing ownership of the fd
let (dir, fd) = fdreaddir(fd)?;
+
+ // For WASI all directory entries for this directory are read first
+ // before any removal is done. This works around the fact that the
+ // WASIp1 API for reading directories is not well-designed for handling
+ // mutations between invocations of reading a directory. By reading all
+ // the entries at once this ensures that, at least without concurrent
+ // modifications, it should be possible to delete everything.
+ #[cfg(target_os = "wasi")]
+ let dir = dir.collect::>();
+
for child in dir {
let child = child?;
let child_name = child.name_cstr();
diff --git a/library/std/src/sys/fs/wasi.rs b/library/std/src/sys/fs/wasi.rs
deleted file mode 100644
index 92eb35317415f..0000000000000
--- a/library/std/src/sys/fs/wasi.rs
+++ /dev/null
@@ -1,913 +0,0 @@
-use crate::ffi::{CStr, OsStr, OsString};
-use crate::fs::TryLockError;
-use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut, SeekFrom};
-use crate::mem::{self, ManuallyDrop};
-use crate::os::raw::c_int;
-use crate::os::wasi::ffi::{OsStrExt, OsStringExt};
-use crate::os::wasi::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, RawFd};
-use crate::path::{Path, PathBuf};
-use crate::sync::Arc;
-use crate::sys::common::small_c_string::run_path_with_cstr;
-use crate::sys::fd::WasiFd;
-pub use crate::sys::fs::common::exists;
-use crate::sys::time::SystemTime;
-use crate::sys::{unsupported, unsupported_err};
-use crate::sys_common::{AsInner, FromInner, IntoInner, ignore_notfound};
-use crate::{fmt, iter, ptr};
-
-pub struct File {
- fd: WasiFd,
-}
-
-#[derive(Clone)]
-pub struct FileAttr {
- meta: wasi::Filestat,
-}
-
-pub struct ReadDir {
- inner: Arc,
- state: ReadDirState,
-}
-
-enum ReadDirState {
- /// Fill `buf` with `buf.len()` bytes starting from `next_read_offset`.
- FillBuffer {
- next_read_offset: wasi::Dircookie,
- buf: Vec,
- },
- ProcessEntry {
- buf: Vec,
- next_read_offset: Option,
- offset: usize,
- },
- /// There is no more data to get in [`Self::FillBuffer`]; keep returning
- /// entries via ProcessEntry until `buf` is exhausted.
- RunUntilExhaustion {
- buf: Vec,
- offset: usize,
- },
- Done,
-}
-
-struct ReadDirInner {
- root: PathBuf,
- dir: File,
-}
-
-pub struct DirEntry {
- meta: wasi::Dirent,
- name: Vec,
- inner: Arc,
-}
-
-#[derive(Clone, Debug, Default)]
-pub struct OpenOptions {
- read: bool,
- write: bool,
- append: bool,
- dirflags: wasi::Lookupflags,
- fdflags: wasi::Fdflags,
- oflags: wasi::Oflags,
- rights_base: Option,
- rights_inheriting: Option,
-}
-
-#[derive(Clone, PartialEq, Eq, Debug)]
-pub struct FilePermissions {
- readonly: bool,
-}
-
-#[derive(Copy, Clone, Debug, Default)]
-pub struct FileTimes {
- accessed: Option,
- modified: Option,
-}
-
-#[derive(PartialEq, Eq, Hash, Debug, Copy, Clone)]
-pub struct FileType {
- bits: wasi::Filetype,
-}
-
-#[derive(Debug)]
-pub struct DirBuilder {}
-
-impl FileAttr {
- pub fn size(&self) -> u64 {
- self.meta.size
- }
-
- pub fn perm(&self) -> FilePermissions {
- // not currently implemented in wasi yet
- FilePermissions { readonly: false }
- }
-
- pub fn file_type(&self) -> FileType {
- FileType { bits: self.meta.filetype }
- }
-
- pub fn modified(&self) -> io::Result {
- Ok(SystemTime::from_wasi_timestamp(self.meta.mtim))
- }
-
- pub fn accessed(&self) -> io::Result {
- Ok(SystemTime::from_wasi_timestamp(self.meta.atim))
- }
-
- pub fn created(&self) -> io::Result {
- Ok(SystemTime::from_wasi_timestamp(self.meta.ctim))
- }
-
- pub(crate) fn as_wasi(&self) -> &wasi::Filestat {
- &self.meta
- }
-}
-
-impl FilePermissions {
- pub fn readonly(&self) -> bool {
- self.readonly
- }
-
- pub fn set_readonly(&mut self, readonly: bool) {
- self.readonly = readonly;
- }
-}
-
-impl FileTimes {
- pub fn set_accessed(&mut self, t: SystemTime) {
- self.accessed = Some(t);
- }
-
- pub fn set_modified(&mut self, t: SystemTime) {
- self.modified = Some(t);
- }
-}
-
-impl FileType {
- pub fn is_dir(&self) -> bool {
- self.bits == wasi::FILETYPE_DIRECTORY
- }
-
- pub fn is_file(&self) -> bool {
- self.bits == wasi::FILETYPE_REGULAR_FILE
- }
-
- pub fn is_symlink(&self) -> bool {
- self.bits == wasi::FILETYPE_SYMBOLIC_LINK
- }
-
- pub(crate) fn bits(&self) -> wasi::Filetype {
- self.bits
- }
-}
-
-impl ReadDir {
- fn new(dir: File, root: PathBuf) -> ReadDir {
- ReadDir {
- inner: Arc::new(ReadDirInner { dir, root }),
- state: ReadDirState::FillBuffer { next_read_offset: 0, buf: vec![0; 128] },
- }
- }
-}
-
-impl fmt::Debug for ReadDir {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- f.debug_struct("ReadDir").finish_non_exhaustive()
- }
-}
-
-impl core::iter::FusedIterator for ReadDir {}
-
-impl Iterator for ReadDir {
- type Item = io::Result;
-
- fn next(&mut self) -> Option> {
- match &mut self.state {
- ReadDirState::FillBuffer { next_read_offset, buf } => {
- let result = self.inner.dir.fd.readdir(buf, *next_read_offset);
- match result {
- Ok(read_bytes) => {
- if read_bytes < buf.len() {
- buf.truncate(read_bytes);
- self.state =
- ReadDirState::RunUntilExhaustion { buf: mem::take(buf), offset: 0 };
- } else {
- debug_assert_eq!(read_bytes, buf.len());
- self.state = ReadDirState::ProcessEntry {
- buf: mem::take(buf),
- offset: 0,
- next_read_offset: Some(*next_read_offset),
- };
- }
- self.next()
- }
- Err(e) => {
- self.state = ReadDirState::Done;
- return Some(Err(e));
- }
- }
- }
- ReadDirState::ProcessEntry { buf, next_read_offset, offset } => {
- let contents = &buf[*offset..];
- const DIRENT_SIZE: usize = size_of::();
- if contents.len() >= DIRENT_SIZE {
- let (dirent, data) = contents.split_at(DIRENT_SIZE);
- let dirent =
- unsafe { ptr::read_unaligned(dirent.as_ptr() as *const wasi::Dirent) };
- // If the file name was truncated, then we need to reinvoke
- // `readdir` so we truncate our buffer to start over and reread this
- // descriptor.
- if data.len() < dirent.d_namlen as usize {
- if buf.len() < dirent.d_namlen as usize + DIRENT_SIZE {
- buf.resize(dirent.d_namlen as usize + DIRENT_SIZE, 0);
- }
- if let Some(next_read_offset) = *next_read_offset {
- self.state =
- ReadDirState::FillBuffer { next_read_offset, buf: mem::take(buf) };
- } else {
- self.state = ReadDirState::Done;
- }
-
- return self.next();
- }
- next_read_offset.as_mut().map(|cookie| {
- *cookie = dirent.d_next;
- });
- *offset = *offset + DIRENT_SIZE + dirent.d_namlen as usize;
-
- let name = &data[..(dirent.d_namlen as usize)];
-
- // These names are skipped on all other platforms, so let's skip
- // them here too
- if name == b"." || name == b".." {
- return self.next();
- }
-
- return Some(Ok(DirEntry {
- meta: dirent,
- name: name.to_vec(),
- inner: self.inner.clone(),
- }));
- } else if let Some(next_read_offset) = *next_read_offset {
- self.state = ReadDirState::FillBuffer { next_read_offset, buf: mem::take(buf) };
- } else {
- self.state = ReadDirState::Done;
- }
- self.next()
- }
- ReadDirState::RunUntilExhaustion { buf, offset } => {
- if *offset >= buf.len() {
- self.state = ReadDirState::Done;
- } else {
- self.state = ReadDirState::ProcessEntry {
- buf: mem::take(buf),
- offset: *offset,
- next_read_offset: None,
- };
- }
-
- self.next()
- }
- ReadDirState::Done => None,
- }
- }
-}
-
-impl DirEntry {
- pub fn path(&self) -> PathBuf {
- let name = OsStr::from_bytes(&self.name);
- self.inner.root.join(name)
- }
-
- pub fn file_name(&self) -> OsString {
- OsString::from_vec(self.name.clone())
- }
-
- pub fn metadata(&self) -> io::Result {
- metadata_at(&self.inner.dir.fd, 0, OsStr::from_bytes(&self.name).as_ref())
- }
-
- pub fn file_type(&self) -> io::Result {
- Ok(FileType { bits: self.meta.d_type })
- }
-
- pub fn ino(&self) -> wasi::Inode {
- self.meta.d_ino
- }
-}
-
-impl OpenOptions {
- pub fn new() -> OpenOptions {
- let mut base = OpenOptions::default();
- base.dirflags = wasi::LOOKUPFLAGS_SYMLINK_FOLLOW;
- base
- }
-
- pub fn read(&mut self, read: bool) {
- self.read = read;
- }
-
- pub fn write(&mut self, write: bool) {
- self.write = write;
- }
-
- pub fn truncate(&mut self, truncate: bool) {
- self.oflag(wasi::OFLAGS_TRUNC, truncate);
- }
-
- pub fn create(&mut self, create: bool) {
- self.oflag(wasi::OFLAGS_CREAT, create);
- }
-
- pub fn create_new(&mut self, create_new: bool) {
- self.oflag(wasi::OFLAGS_EXCL, create_new);
- self.oflag(wasi::OFLAGS_CREAT, create_new);
- }
-
- pub fn directory(&mut self, directory: bool) {
- self.oflag(wasi::OFLAGS_DIRECTORY, directory);
- }
-
- fn oflag(&mut self, bit: wasi::Oflags, set: bool) {
- if set {
- self.oflags |= bit;
- } else {
- self.oflags &= !bit;
- }
- }
-
- pub fn append(&mut self, append: bool) {
- self.append = append;
- self.fdflag(wasi::FDFLAGS_APPEND, append);
- }
-
- pub fn dsync(&mut self, set: bool) {
- self.fdflag(wasi::FDFLAGS_DSYNC, set);
- }
-
- pub fn nonblock(&mut self, set: bool) {
- self.fdflag(wasi::FDFLAGS_NONBLOCK, set);
- }
-
- pub fn rsync(&mut self, set: bool) {
- self.fdflag(wasi::FDFLAGS_RSYNC, set);
- }
-
- pub fn sync(&mut self, set: bool) {
- self.fdflag(wasi::FDFLAGS_SYNC, set);
- }
-
- fn fdflag(&mut self, bit: wasi::Fdflags, set: bool) {
- if set {
- self.fdflags |= bit;
- } else {
- self.fdflags &= !bit;
- }
- }
-
- pub fn fs_rights_base(&mut self, rights: wasi::Rights) {
- self.rights_base = Some(rights);
- }
-
- pub fn fs_rights_inheriting(&mut self, rights: wasi::Rights) {
- self.rights_inheriting = Some(rights);
- }
-
- fn rights_base(&self) -> wasi::Rights {
- if let Some(rights) = self.rights_base {
- return rights;
- }
-
- // If rights haven't otherwise been specified try to pick a reasonable
- // set. This can always be overridden by users via extension traits, and
- // implementations may give us fewer rights silently than we ask for. So
- // given that, just look at `read` and `write` and bucket permissions
- // based on that.
- let mut base = 0;
- if self.read {
- base |= wasi::RIGHTS_FD_READ;
- base |= wasi::RIGHTS_FD_READDIR;
- }
- if self.write || self.append {
- base |= wasi::RIGHTS_FD_WRITE;
- base |= wasi::RIGHTS_FD_DATASYNC;
- base |= wasi::RIGHTS_FD_ALLOCATE;
- base |= wasi::RIGHTS_FD_FILESTAT_SET_SIZE;
- }
-
- // FIXME: some of these should probably be read-only or write-only...
- base |= wasi::RIGHTS_FD_ADVISE;
- base |= wasi::RIGHTS_FD_FDSTAT_SET_FLAGS;
- base |= wasi::RIGHTS_FD_FILESTAT_GET;
- base |= wasi::RIGHTS_FD_FILESTAT_SET_TIMES;
- base |= wasi::RIGHTS_FD_SEEK;
- base |= wasi::RIGHTS_FD_SYNC;
- base |= wasi::RIGHTS_FD_TELL;
- base |= wasi::RIGHTS_PATH_CREATE_DIRECTORY;
- base |= wasi::RIGHTS_PATH_CREATE_FILE;
- base |= wasi::RIGHTS_PATH_FILESTAT_GET;
- base |= wasi::RIGHTS_PATH_LINK_SOURCE;
- base |= wasi::RIGHTS_PATH_LINK_TARGET;
- base |= wasi::RIGHTS_PATH_OPEN;
- base |= wasi::RIGHTS_PATH_READLINK;
- base |= wasi::RIGHTS_PATH_REMOVE_DIRECTORY;
- base |= wasi::RIGHTS_PATH_RENAME_SOURCE;
- base |= wasi::RIGHTS_PATH_RENAME_TARGET;
- base |= wasi::RIGHTS_PATH_SYMLINK;
- base |= wasi::RIGHTS_PATH_UNLINK_FILE;
- base |= wasi::RIGHTS_POLL_FD_READWRITE;
-
- base
- }
-
- fn rights_inheriting(&self) -> wasi::Rights {
- self.rights_inheriting.unwrap_or_else(|| self.rights_base())
- }
-
- pub fn lookup_flags(&mut self, flags: wasi::Lookupflags) {
- self.dirflags = flags;
- }
-}
-
-impl File {
- pub fn open(path: &Path, opts: &OpenOptions) -> io::Result {
- let (dir, file) = open_parent(path)?;
- open_at(&dir, &file, opts)
- }
-
- pub fn open_at(&self, path: &Path, opts: &OpenOptions) -> io::Result {
- open_at(&self.fd, path, opts)
- }
-
- pub fn file_attr(&self) -> io::Result {
- self.fd.filestat_get().map(|meta| FileAttr { meta })
- }
-
- pub fn metadata_at(&self, flags: wasi::Lookupflags, path: &Path) -> io::Result {
- metadata_at(&self.fd, flags, path)
- }
-
- pub fn fsync(&self) -> io::Result<()> {
- self.fd.sync()
- }
-
- pub fn datasync(&self) -> io::Result<()> {
- self.fd.datasync()
- }
-
- pub fn lock(&self) -> io::Result<()> {
- unsupported()
- }
-
- pub fn lock_shared(&self) -> io::Result<()> {
- unsupported()
- }
-
- pub fn try_lock(&self) -> Result<(), TryLockError> {
- Err(TryLockError::Error(unsupported_err()))
- }
-
- pub fn try_lock_shared(&self) -> Result<(), TryLockError> {
- Err(TryLockError::Error(unsupported_err()))
- }
-
- pub fn unlock(&self) -> io::Result<()> {
- unsupported()
- }
-
- pub fn truncate(&self, size: u64) -> io::Result<()> {
- self.fd.filestat_set_size(size)
- }
-
- pub fn read(&self, buf: &mut [u8]) -> io::Result {
- self.read_vectored(&mut [IoSliceMut::new(buf)])
- }
-
- pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result {
- self.fd.read(bufs)
- }
-
- #[inline]
- pub fn is_read_vectored(&self) -> bool {
- true
- }
-
- pub fn read_buf(&self, cursor: BorrowedCursor<'_>) -> io::Result<()> {
- self.fd.read_buf(cursor)
- }
-
- pub fn write(&self, buf: &[u8]) -> io::Result {
- self.write_vectored(&[IoSlice::new(buf)])
- }
-
- pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result {
- self.fd.write(bufs)
- }
-
- #[inline]
- pub fn is_write_vectored(&self) -> bool {
- true
- }
-
- pub fn flush(&self) -> io::Result<()> {
- Ok(())
- }
-
- pub fn seek(&self, pos: SeekFrom) -> io::Result {
- self.fd.seek(pos)
- }
-
- pub fn size(&self) -> Option> {
- None
- }
-
- pub fn tell(&self) -> io::Result {
- self.fd.tell()
- }
-
- pub fn duplicate(&self) -> io::Result {
- // https://github.com/CraneStation/wasmtime/blob/master/docs/WASI-rationale.md#why-no-dup
- unsupported()
- }
-
- pub fn set_permissions(&self, _perm: FilePermissions) -> io::Result<()> {
- // Permissions haven't been fully figured out in wasi yet, so this is
- // likely temporary
- unsupported()
- }
-
- pub fn set_times(&self, times: FileTimes) -> io::Result<()> {
- self.fd.filestat_set_times(
- to_wasi_timestamp_or_now(times.accessed)?,
- to_wasi_timestamp_or_now(times.modified)?,
- times.accessed.map_or(0, |_| wasi::FSTFLAGS_ATIM)
- | times.modified.map_or(0, |_| wasi::FSTFLAGS_MTIM),
- )
- }
-
- pub fn read_link(&self, file: &Path) -> io::Result {
- read_link(&self.fd, file)
- }
-}
-
-impl AsInner for File {
- #[inline]
- fn as_inner(&self) -> &WasiFd {
- &self.fd
- }
-}
-
-impl IntoInner for File {
- fn into_inner(self) -> WasiFd {
- self.fd
- }
-}
-
-impl FromInner for File {
- fn from_inner(fd: WasiFd) -> File {
- File { fd }
- }
-}
-
-impl AsFd for File {
- fn as_fd(&self) -> BorrowedFd<'_> {
- self.fd.as_fd()
- }
-}
-
-impl AsRawFd for File {
- #[inline]
- fn as_raw_fd(&self) -> RawFd {
- self.fd.as_raw_fd()
- }
-}
-
-impl IntoRawFd for File {
- fn into_raw_fd(self) -> RawFd {
- self.fd.into_raw_fd()
- }
-}
-
-impl FromRawFd for File {
- unsafe fn from_raw_fd(raw_fd: RawFd) -> Self {
- unsafe { Self { fd: FromRawFd::from_raw_fd(raw_fd) } }
- }
-}
-
-impl DirBuilder {
- pub fn new() -> DirBuilder {
- DirBuilder {}
- }
-
- pub fn mkdir(&self, p: &Path) -> io::Result<()> {
- let (dir, file) = open_parent(p)?;
- dir.create_directory(osstr2str(file.as_ref())?)
- }
-}
-
-impl fmt::Debug for File {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- f.debug_struct("File").field("fd", &self.as_raw_fd()).finish()
- }
-}
-
-pub fn readdir(p: &Path) -> io::Result {
- let mut opts = OpenOptions::new();
- opts.directory(true);
- opts.read(true);
- let dir = File::open(p, &opts)?;
- Ok(ReadDir::new(dir, p.to_path_buf()))
-}
-
-pub fn unlink(p: &Path) -> io::Result<()> {
- let (dir, file) = open_parent(p)?;
- dir.unlink_file(osstr2str(file.as_ref())?)
-}
-
-pub fn rename(old: &Path, new: &Path) -> io::Result<()> {
- let (old, old_file) = open_parent(old)?;
- let (new, new_file) = open_parent(new)?;
- old.rename(osstr2str(old_file.as_ref())?, &new, osstr2str(new_file.as_ref())?)
-}
-
-pub fn set_perm(_p: &Path, _perm: FilePermissions) -> io::Result<()> {
- // Permissions haven't been fully figured out in wasi yet, so this is
- // likely temporary
- unsupported()
-}
-
-#[inline(always)]
-pub fn set_times(p: &Path, times: FileTimes) -> io::Result<()> {
- let (dir, file) = open_parent(p)?;
- set_times_impl(&dir, &file, times, wasi::LOOKUPFLAGS_SYMLINK_FOLLOW)
-}
-
-#[inline(always)]
-pub fn set_times_nofollow(p: &Path, times: FileTimes) -> io::Result<()> {
- let (dir, file) = open_parent(p)?;
- set_times_impl(&dir, &file, times, 0)
-}
-
-fn to_wasi_timestamp_or_now(time: Option) -> io::Result {
- match time {
- Some(time) if let Some(ts) = time.to_wasi_timestamp() => Ok(ts),
- Some(_) => Err(io::const_error!(
- io::ErrorKind::InvalidInput,
- "timestamp is too large to set as a file time",
- )),
- None => Ok(0),
- }
-}
-
-fn set_times_impl(
- fd: &WasiFd,
- path: &Path,
- times: FileTimes,
- flags: wasi::Lookupflags,
-) -> io::Result<()> {
- fd.path_filestat_set_times(
- flags,
- osstr2str(path.as_ref())?,
- to_wasi_timestamp_or_now(times.accessed)?,
- to_wasi_timestamp_or_now(times.modified)?,
- times.accessed.map_or(0, |_| wasi::FSTFLAGS_ATIM)
- | times.modified.map_or(0, |_| wasi::FSTFLAGS_MTIM),
- )
-}
-
-pub fn rmdir(p: &Path) -> io::Result<()> {
- let (dir, file) = open_parent(p)?;
- dir.remove_directory(osstr2str(file.as_ref())?)
-}
-
-pub fn readlink(p: &Path) -> io::Result {
- let (dir, file) = open_parent(p)?;
- read_link(&dir, &file)
-}
-
-fn read_link(fd: &WasiFd, file: &Path) -> io::Result {
- // Try to get a best effort initial capacity for the vector we're going to
- // fill. Note that if it's not a symlink we don't use a file to avoid
- // allocating gigabytes if you read_link a huge movie file by accident.
- // Additionally we add 1 to the initial size so if it doesn't change until
- // when we call `readlink` the returned length will be less than the
- // capacity, guaranteeing that we got all the data.
- let meta = metadata_at(fd, 0, file)?;
- let initial_size = if meta.file_type().is_symlink() {
- (meta.size() as usize).saturating_add(1)
- } else {
- 1 // this'll fail in just a moment
- };
-
- // Now that we have an initial guess of how big to make our buffer, call
- // `readlink` in a loop until it fails or reports it filled fewer bytes than
- // we asked for, indicating we got everything.
- let file = osstr2str(file.as_ref())?;
- let mut destination = vec![0u8; initial_size];
- loop {
- let len = fd.readlink(file, &mut destination)?;
- if len < destination.len() {
- destination.truncate(len);
- destination.shrink_to_fit();
- return Ok(PathBuf::from(OsString::from_vec(destination)));
- }
- let amt_to_add = destination.len();
- destination.extend(iter::repeat(0).take(amt_to_add));
- }
-}
-
-pub fn symlink(original: &Path, link: &Path) -> io::Result<()> {
- let (link, link_file) = open_parent(link)?;
- link.symlink(osstr2str(original.as_ref())?, osstr2str(link_file.as_ref())?)
-}
-
-pub fn link(original: &Path, link: &Path) -> io::Result<()> {
- let (original, original_file) = open_parent(original)?;
- let (link, link_file) = open_parent(link)?;
- // Pass 0 as the flags argument, meaning don't follow symlinks.
- original.link(0, osstr2str(original_file.as_ref())?, &link, osstr2str(link_file.as_ref())?)
-}
-
-pub fn stat(p: &Path) -> io::Result {
- let (dir, file) = open_parent(p)?;
- metadata_at(&dir, wasi::LOOKUPFLAGS_SYMLINK_FOLLOW, &file)
-}
-
-pub fn lstat(p: &Path) -> io::Result {
- let (dir, file) = open_parent(p)?;
- metadata_at(&dir, 0, &file)
-}
-
-fn metadata_at(fd: &WasiFd, flags: wasi::Lookupflags, path: &Path) -> io::Result {
- let meta = fd.path_filestat_get(flags, osstr2str(path.as_ref())?)?;
- Ok(FileAttr { meta })
-}
-
-pub fn canonicalize(_p: &Path) -> io::Result {
- // This seems to not be in wasi's API yet, and we may need to end up
- // emulating it ourselves. For now just return an error.
- unsupported()
-}
-
-fn open_at(fd: &WasiFd, path: &Path, opts: &OpenOptions) -> io::Result {
- let fd = fd.open(
- opts.dirflags,
- osstr2str(path.as_ref())?,
- opts.oflags,
- opts.rights_base(),
- opts.rights_inheriting(),
- opts.fdflags,
- )?;
- Ok(File { fd })
-}
-
-/// Attempts to open a bare path `p`.
-///
-/// WASI has no fundamental capability to do this. All syscalls and operations
-/// are relative to already-open file descriptors. The C library, however,
-/// manages a map of pre-opened file descriptors to their path, and then the C
-/// library provides an API to look at this. In other words, when you want to
-/// open a path `p`, you have to find a previously opened file descriptor in a
-/// global table and then see if `p` is relative to that file descriptor.
-///
-/// This function, if successful, will return two items:
-///
-/// * The first is a `ManuallyDrop`. This represents a pre-opened file
-/// descriptor which we don't have ownership of, but we can use. You shouldn't
-/// actually drop the `fd`.
-///
-/// * The second is a path that should be a part of `p` and represents a
-/// relative traversal from the file descriptor specified to the desired
-/// location `p`.
-///
-/// If successful you can use the returned file descriptor to perform
-/// file-descriptor-relative operations on the path returned as well. The
-/// `rights` argument indicates what operations are desired on the returned file
-/// descriptor, and if successful the returned file descriptor should have the
-/// appropriate rights for performing `rights` actions.
-///
-/// Note that this can fail if `p` doesn't look like it can be opened relative
-/// to any pre-opened file descriptor.
-fn open_parent(p: &Path) -> io::Result<(ManuallyDrop, PathBuf)> {
- run_path_with_cstr(p, &|p| {
- let mut buf = Vec::::with_capacity(512);
- loop {
- unsafe {
- let mut relative_path = buf.as_ptr().cast();
- let mut abs_prefix = ptr::null();
- let fd = __wasilibc_find_relpath(
- p.as_ptr(),
- &mut abs_prefix,
- &mut relative_path,
- buf.capacity(),
- );
- if fd == -1 {
- if io::Error::last_os_error().raw_os_error() == Some(libc::ENOMEM) {
- // Trigger the internal buffer resizing logic of `Vec` by requiring
- // more space than the current capacity.
- let cap = buf.capacity();
- buf.set_len(cap);
- buf.reserve(1);
- continue;
- }
- let msg = format!(
- "failed to find a pre-opened file descriptor \
- through which {p:?} could be opened",
- );
- return Err(io::Error::new(io::ErrorKind::Uncategorized, msg));
- }
- let relative = CStr::from_ptr(relative_path).to_bytes().to_vec();
-
- return Ok((
- ManuallyDrop::new(WasiFd::from_raw_fd(fd as c_int)),
- PathBuf::from(OsString::from_vec(relative)),
- ));
- }
- }
-
- unsafe extern "C" {
- pub fn __wasilibc_find_relpath(
- path: *const libc::c_char,
- abs_prefix: *mut *const libc::c_char,
- relative_path: *mut *const libc::c_char,
- relative_path_len: libc::size_t,
- ) -> libc::c_int;
- }
- })
-}
-
-pub fn osstr2str(f: &OsStr) -> io::Result<&str> {
- f.to_str().ok_or_else(|| io::const_error!(io::ErrorKind::Uncategorized, "input must be utf-8"))
-}
-
-pub fn copy(from: &Path, to: &Path) -> io::Result {
- use crate::fs::File;
-
- let mut reader = File::open(from)?;
- let mut writer = File::create(to)?;
-
- io::copy(&mut reader, &mut writer)
-}
-
-pub fn remove_dir_all(path: &Path) -> io::Result<()> {
- let (parent, path) = open_parent(path)?;
- remove_dir_all_recursive(&parent, &path)
-}
-
-fn remove_dir_all_recursive(parent: &WasiFd, path: &Path) -> io::Result<()> {
- // Open up a file descriptor for the directory itself. Note that we don't
- // follow symlinks here and we specifically open directories.
- //
- // At the root invocation of this function this will correctly handle
- // symlinks passed to the top-level `remove_dir_all`. At the recursive
- // level this will double-check that after the `readdir` call deduced this
- // was a directory it's still a directory by the time we open it up.
- //
- // If the opened file was actually a symlink then the symlink is deleted,
- // not the directory recursively.
- let mut opts = OpenOptions::new();
- opts.lookup_flags(0);
- opts.directory(true);
- opts.read(true);
- let fd = open_at(parent, path, &opts)?;
- if fd.file_attr()?.file_type().is_symlink() {
- return parent.unlink_file(osstr2str(path.as_ref())?);
- }
-
- // this "root" is only used by `DirEntry::path` which we don't use below so
- // it's ok for this to be a bogus value
- let dummy_root = PathBuf::new();
-
- // Iterate over all the entries in this directory, and travel recursively if
- // necessary
- //
- // Note that all directory entries for this directory are read first before
- // any removal is done. This works around the fact that the WASIp1 API for
- // reading directories is not well-designed for handling mutations between
- // invocations of reading a directory. By reading all the entries at once
- // this ensures that, at least without concurrent modifications, it should
- // be possible to delete everything.
- for entry in ReadDir::new(fd, dummy_root).collect::>() {
- let entry = entry?;
- let path = crate::str::from_utf8(&entry.name).map_err(|_| {
- io::const_error!(io::ErrorKind::Uncategorized, "invalid utf-8 file name found")
- })?;
-
- let result: io::Result<()> = try {
- if entry.file_type()?.is_dir() {
- remove_dir_all_recursive(&entry.inner.dir.fd, path.as_ref())?;
- } else {
- entry.inner.dir.fd.unlink_file(path)?;
- }
- };
- // ignore internal NotFound errors
- if let Err(err) = &result
- && err.kind() != io::ErrorKind::NotFound
- {
- return result;
- }
- }
-
- // Once all this directory's contents are deleted it should be safe to
- // delete the directory tiself.
- ignore_notfound(parent.remove_directory(osstr2str(path.as_ref())?))
-}
diff --git a/library/std/src/sys/io/io_slice/iovec.rs b/library/std/src/sys/io/io_slice/iovec.rs
index df56358969a39..d549aca250d5f 100644
--- a/library/std/src/sys/io/io_slice/iovec.rs
+++ b/library/std/src/sys/io/io_slice/iovec.rs
@@ -1,6 +1,6 @@
#[cfg(target_os = "hermit")]
use hermit_abi::iovec;
-#[cfg(any(target_family = "unix", target_os = "trusty"))]
+#[cfg(any(target_family = "unix", target_os = "trusty", target_os = "wasi"))]
use libc::iovec;
use crate::ffi::c_void;
diff --git a/library/std/src/sys/io/io_slice/wasi.rs b/library/std/src/sys/io/io_slice/wasi.rs
deleted file mode 100644
index 87acbbd924e56..0000000000000
--- a/library/std/src/sys/io/io_slice/wasi.rs
+++ /dev/null
@@ -1,76 +0,0 @@
-use crate::marker::PhantomData;
-use crate::slice;
-
-#[derive(Copy, Clone)]
-#[repr(transparent)]
-pub struct IoSlice<'a> {
- vec: wasi::Ciovec,
- _p: PhantomData<&'a [u8]>,
-}
-
-impl<'a> IoSlice<'a> {
- #[inline]
- pub fn new(buf: &'a [u8]) -> IoSlice<'a> {
- IoSlice { vec: wasi::Ciovec { buf: buf.as_ptr(), buf_len: buf.len() }, _p: PhantomData }
- }
-
- #[inline]
- pub fn advance(&mut self, n: usize) {
- if self.vec.buf_len < n {
- panic!("advancing IoSlice beyond its length");
- }
-
- unsafe {
- self.vec.buf_len -= n;
- self.vec.buf = self.vec.buf.add(n);
- }
- }
-
- #[inline]
- pub const fn as_slice(&self) -> &'a [u8] {
- unsafe { slice::from_raw_parts(self.vec.buf as *const u8, self.vec.buf_len) }
- }
-}
-
-#[repr(transparent)]
-pub struct IoSliceMut<'a> {
- vec: wasi::Iovec,
- _p: PhantomData<&'a mut [u8]>,
-}
-
-impl<'a> IoSliceMut<'a> {
- #[inline]
- pub fn new(buf: &'a mut [u8]) -> IoSliceMut<'a> {
- IoSliceMut {
- vec: wasi::Iovec { buf: buf.as_mut_ptr(), buf_len: buf.len() },
- _p: PhantomData,
- }
- }
-
- #[inline]
- pub fn advance(&mut self, n: usize) {
- if self.vec.buf_len < n {
- panic!("advancing IoSlice beyond its length");
- }
-
- unsafe {
- self.vec.buf_len -= n;
- self.vec.buf = self.vec.buf.add(n);
- }
- }
-
- #[inline]
- pub fn as_slice(&self) -> &[u8] {
- unsafe { slice::from_raw_parts(self.vec.buf as *const u8, self.vec.buf_len) }
- }
-
- #[inline]
- pub const fn into_slice(self) -> &'a mut [u8] {
- unsafe { slice::from_raw_parts_mut(self.vec.buf as *mut u8, self.vec.buf_len) }
- }
-
- #[inline]
- pub fn as_mut_slice(&mut self) -> &mut [u8] {
- unsafe { slice::from_raw_parts_mut(self.vec.buf as *mut u8, self.vec.buf_len) }
- }
-}
diff --git a/library/std/src/sys/io/mod.rs b/library/std/src/sys/io/mod.rs
index e2c5e7f88d492..b4e4e6ec73123 100644
--- a/library/std/src/sys/io/mod.rs
+++ b/library/std/src/sys/io/mod.rs
@@ -2,7 +2,7 @@
mod io_slice {
cfg_select! {
- any(target_family = "unix", target_os = "hermit", target_os = "solid_asp3", target_os = "trusty") => {
+ any(target_family = "unix", target_os = "hermit", target_os = "solid_asp3", target_os = "trusty", target_os = "wasi") => {
mod iovec;
pub use iovec::*;
}
@@ -10,10 +10,6 @@ mod io_slice {
mod windows;
pub use windows::*;
}
- target_os = "wasi" => {
- mod wasi;
- pub use wasi::*;
- }
target_os = "uefi" => {
mod uefi;
pub use uefi::*;
diff --git a/library/std/src/sys/net/connection/socket/mod.rs b/library/std/src/sys/net/connection/socket/mod.rs
index 1d941dec1b792..63d5c1d23124e 100644
--- a/library/std/src/sys/net/connection/socket/mod.rs
+++ b/library/std/src/sys/net/connection/socket/mod.rs
@@ -22,14 +22,10 @@ cfg_select! {
mod solid;
pub use solid::*;
}
- target_family = "unix" => {
+ any(target_family = "unix", target_os = "wasi") => {
mod unix;
pub use unix::*;
}
- all(target_os = "wasi", any(target_env = "p2", target_env = "p3")) => {
- mod wasip2;
- pub use wasip2::*;
- }
target_os = "windows" => {
mod windows;
pub use windows::*;
diff --git a/library/std/src/sys/net/connection/socket/unix.rs b/library/std/src/sys/net/connection/socket/unix.rs
index c892daf0d39c3..d30f6054077d9 100644
--- a/library/std/src/sys/net/connection/socket/unix.rs
+++ b/library/std/src/sys/net/connection/socket/unix.rs
@@ -4,7 +4,7 @@ use libc::{MSG_PEEK, c_int, c_void, size_t, sockaddr, socklen_t};
use crate::ffi::CStr;
use crate::io::{self, BorrowedBuf, BorrowedCursor, IoSlice, IoSliceMut};
use crate::net::{Shutdown, SocketAddr};
-use crate::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, RawFd};
+use crate::os::fd::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, RawFd};
use crate::sys::fd::FileDesc;
use crate::sys::net::{getsockopt, setsockopt};
use crate::sys::pal::IsMinusOne;
@@ -107,7 +107,7 @@ impl Socket {
}
}
- #[cfg(not(target_os = "vxworks"))]
+ #[cfg(not(any(target_os = "vxworks", target_os = "wasi")))]
pub fn new_pair(fam: c_int, ty: c_int) -> io::Result<(Socket, Socket)> {
unsafe {
let mut fds = [0, 0];
@@ -275,6 +275,7 @@ impl Socket {
self.0.duplicate().map(Socket)
}
+ #[cfg(not(target_os = "wasi"))]
pub fn send_with_flags(&self, buf: &[u8], flags: c_int) -> io::Result {
let len = cmp::min(buf.len(), ::MAX as usize) as wrlen_t;
let ret = cvt(unsafe {
@@ -361,6 +362,7 @@ impl Socket {
self.recv_from_with_flags(buf, MSG_PEEK)
}
+ #[cfg(not(target_os = "wasi"))]
pub fn write(&self, buf: &[u8]) -> io::Result {
self.0.write(buf)
}
diff --git a/library/std/src/sys/net/connection/socket/wasip2.rs b/library/std/src/sys/net/connection/socket/wasip2.rs
deleted file mode 100644
index f86034266c26a..0000000000000
--- a/library/std/src/sys/net/connection/socket/wasip2.rs
+++ /dev/null
@@ -1,408 +0,0 @@
-#![deny(unsafe_op_in_unsafe_fn)]
-
-pub(super) use libc as netc;
-use libc::{c_int, c_void, size_t};
-
-use super::{getsockopt, setsockopt, socket_addr_from_c, socket_addr_to_c};
-use crate::ffi::CStr;
-use crate::io::{self, BorrowedBuf, BorrowedCursor, IoSlice, IoSliceMut};
-use crate::net::{Shutdown, SocketAddr};
-use crate::os::wasi::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd};
-use crate::sys::unsupported;
-use crate::sys_common::{AsInner, FromInner, IntoInner};
-use crate::time::{Duration, Instant};
-use crate::{cmp, mem, str};
-
-#[allow(non_camel_case_types)]
-pub type wrlen_t = size_t;
-
-#[doc(hidden)]
-pub trait IsMinusOne {
- fn is_minus_one(&self) -> bool;
-}
-
-macro_rules! impl_is_minus_one {
- ($($t:ident)*) => ($(impl IsMinusOne for $t {
- fn is_minus_one(&self) -> bool {
- *self == -1
- }
- })*)
-}
-
-impl_is_minus_one! { i8 i16 i32 i64 isize }
-
-pub fn cvt(t: T) -> crate::io::Result {
- if t.is_minus_one() { Err(crate::io::Error::last_os_error()) } else { Ok(t) }
-}
-
-pub fn cvt_r(mut f: F) -> crate::io::Result
-where
- T: IsMinusOne,
- F: FnMut() -> T,
-{
- loop {
- match cvt(f()) {
- Err(ref e) if e.is_interrupted() => {}
- other => return other,
- }
- }
-}
-
-pub fn cvt_gai(err: c_int) -> io::Result<()> {
- if err == 0 {
- return Ok(());
- }
-
- if err == netc::EAI_SYSTEM {
- return Err(io::Error::last_os_error());
- }
-
- let detail = unsafe {
- str::from_utf8(CStr::from_ptr(netc::gai_strerror(err)).to_bytes()).unwrap().to_owned()
- };
-
- Err(io::Error::new(
- io::ErrorKind::Uncategorized,
- &format!("failed to lookup address information: {detail}")[..],
- ))
-}
-
-pub fn init() {}
-
-pub struct WasiSocket(OwnedFd);
-
-pub struct Socket(WasiSocket);
-
-impl Socket {
- pub fn new(family: c_int, ty: c_int) -> io::Result {
- let fd = cvt(unsafe { netc::socket(family, ty, 0) })?;
- Ok(unsafe { Self::from_raw_fd(fd) })
- }
-
- pub fn connect(&self, addr: &SocketAddr) -> io::Result<()> {
- let (addr, len) = socket_addr_to_c(addr);
- cvt_r(|| unsafe { netc::connect(self.as_raw_fd(), addr.as_ptr(), len) })?;
- Ok(())
- }
-
- pub fn connect_timeout(&self, addr: &SocketAddr, timeout: Duration) -> io::Result<()> {
- self.set_nonblocking(true)?;
- let r = self.connect(addr);
- self.set_nonblocking(false)?;
-
- match r {
- Ok(_) => return Ok(()),
- // there's no ErrorKind for EINPROGRESS
- Err(ref e) if e.raw_os_error() == Some(netc::EINPROGRESS) => {}
- Err(e) => return Err(e),
- }
-
- let mut pollfd = netc::pollfd { fd: self.as_raw_fd(), events: netc::POLLOUT, revents: 0 };
-
- if timeout.as_secs() == 0 && timeout.subsec_nanos() == 0 {
- return Err(io::Error::ZERO_TIMEOUT);
- }
-
- let start = Instant::now();
-
- loop {
- let elapsed = start.elapsed();
- if elapsed >= timeout {
- return Err(io::const_error!(io::ErrorKind::TimedOut, "connection timed out"));
- }
-
- let timeout = timeout - elapsed;
- let mut timeout = timeout
- .as_secs()
- .saturating_mul(1_000)
- .saturating_add(timeout.subsec_nanos() as u64 / 1_000_000);
- if timeout == 0 {
- timeout = 1;
- }
-
- let timeout = cmp::min(timeout, c_int::MAX as u64) as c_int;
-
- match unsafe { netc::poll(&mut pollfd, 1, timeout) } {
- -1 => {
- let err = io::Error::last_os_error();
- if !err.is_interrupted() {
- return Err(err);
- }
- }
- 0 => {}
- _ => {
- // WASI poll does not return POLLHUP or POLLERR in revents. Check if the
- // connection actually succeeded and return ok only when the socket is
- // ready and no errors were found.
- if let Some(e) = self.take_error()? {
- return Err(e);
- }
-
- return Ok(());
- }
- }
- }
- }
-
- pub fn accept(
- &self,
- storage: *mut netc::sockaddr,
- len: *mut netc::socklen_t,
- ) -> io::Result {
- let fd = cvt_r(|| unsafe { netc::accept(self.as_raw_fd(), storage, len) })?;
- Ok(unsafe { Self::from_raw_fd(fd) })
- }
-
- pub fn duplicate(&self) -> io::Result {
- unsupported()
- }
-
- fn recv_with_flags(&self, mut buf: BorrowedCursor<'_>, flags: c_int) -> io::Result<()> {
- let ret = cvt(unsafe {
- netc::recv(
- self.as_raw_fd(),
- buf.as_mut().as_mut_ptr() as *mut c_void,
- buf.capacity(),
- flags,
- )
- })?;
- unsafe {
- buf.advance(ret as usize);
- }
- Ok(())
- }
-
- pub fn read(&self, buf: &mut [u8]) -> io::Result {
- let mut buf = BorrowedBuf::from(buf);
- self.recv_with_flags(buf.unfilled(), 0)?;
- Ok(buf.len())
- }
-
- pub fn peek(&self, buf: &mut [u8]) -> io::Result {
- let mut buf = BorrowedBuf::from(buf);
- self.recv_with_flags(buf.unfilled(), netc::MSG_PEEK)?;
- Ok(buf.len())
- }
-
- pub fn read_buf(&self, buf: BorrowedCursor<'_>) -> io::Result<()> {
- self.recv_with_flags(buf, 0)
- }
-
- pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result {
- io::default_read_vectored(|b| self.read(b), bufs)
- }
-
- #[inline]
- pub fn is_read_vectored(&self) -> bool {
- false
- }
-
- fn recv_from_with_flags(
- &self,
- buf: &mut [u8],
- flags: c_int,
- ) -> io::Result<(usize, SocketAddr)> {
- let mut storage: netc::sockaddr_storage = unsafe { mem::zeroed() };
- let mut addrlen = size_of_val(&storage) as netc::socklen_t;
-
- let n = cvt(unsafe {
- netc::recvfrom(
- self.as_raw_fd(),
- buf.as_mut_ptr() as *mut c_void,
- buf.len(),
- flags,
- core::ptr::addr_of_mut!(storage) as *mut _,
- &mut addrlen,
- )
- })?;
- Ok((n as usize, unsafe { socket_addr_from_c(&storage, addrlen as usize)? }))
- }
-
- pub fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
- self.recv_from_with_flags(buf, 0)
- }
-
- pub fn peek_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
- self.recv_from_with_flags(buf, netc::MSG_PEEK)
- }
-
- fn write(&self, buf: &[u8]) -> io::Result {
- let len = cmp::min(buf.len(), ::MAX as usize) as wrlen_t;
- let ret = cvt(unsafe {
- netc::send(self.as_raw(), buf.as_ptr() as *const c_void, len, netc::MSG_NOSIGNAL)
- })?;
- Ok(ret as usize)
- }
-
- pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result {
- io::default_write_vectored(|b| self.write(b), bufs)
- }
-
- #[inline]
- pub fn is_write_vectored(&self) -> bool {
- false
- }
-
- pub fn set_timeout(&self, dur: Option, kind: c_int) -> io::Result<()> {
- let timeout = match dur {
- Some(dur) => {
- if dur.as_secs() == 0 && dur.subsec_nanos() == 0 {
- return Err(io::Error::ZERO_TIMEOUT);
- }
-
- let secs = dur.as_secs().try_into().unwrap_or(netc::time_t::MAX);
- let mut timeout = netc::timeval {
- tv_sec: secs,
- tv_usec: dur.subsec_micros() as netc::suseconds_t,
- };
- if timeout.tv_sec == 0 && timeout.tv_usec == 0 {
- timeout.tv_usec = 1;
- }
- timeout
- }
- None => netc::timeval { tv_sec: 0, tv_usec: 0 },
- };
- unsafe { setsockopt(self, netc::SOL_SOCKET, kind, timeout) }
- }
-
- pub fn timeout(&self, kind: c_int) -> io::Result