From 90c113e5453ec92fdb1a8633a5a4c56dfb72ee47 Mon Sep 17 00:00:00 2001 From: xtqqczze <45661989+xtqqczze@users.noreply.github.com> Date: Tue, 12 May 2026 15:23:49 +0100 Subject: [PATCH] feat(dd): use wasi_ext feature on nightly https://dev-doc.rust-lang.org/beta/unstable-book/library-features/wasi-ext.html --- Cargo.lock | 1 + Cargo.toml | 2 ++ src/uu/dd/Cargo.toml | 3 +++ src/uu/dd/build.rs | 11 +++++++++++ src/uu/dd/src/dd.rs | 42 ++++++++++++++++++++++++------------------ 5 files changed, 41 insertions(+), 18 deletions(-) create mode 100644 src/uu/dd/build.rs diff --git a/Cargo.lock b/Cargo.lock index b7ad1451247..95bbb918751 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3433,6 +3433,7 @@ dependencies = [ "fluent", "libc", "num-integer", + "rustc_version", "rustix", "tempfile", "thiserror 2.0.20", diff --git a/Cargo.toml b/Cargo.toml index 7ce0a2c10be..892957a70cc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -393,6 +393,7 @@ rayon = "1.10" regex = "1.10.4" rstest = "0.27.0" rstest_reuse = "0.7.0" +rustc_version = "0.4.1" rustc-hash = "2.1.1" rustix = { version = "1.1.4", default-features = false } self_cell = "1.0.4" @@ -451,6 +452,7 @@ renamed_and_removed_lints = { level = "allow", priority = -1 } # https://doc.rust-lang.org/nightly/rustc/check-cfg/cargo-specifics.html unexpected_cfgs = { level = "warn", check-cfg = [ 'cfg(fuzzing)', + 'cfg(nightly)', 'cfg(pgo_training)', 'cfg(target_os, values("cygwin"))', 'cfg(wasi_runner)', diff --git a/src/uu/dd/Cargo.toml b/src/uu/dd/Cargo.toml index bb93d41d608..00e699caf44 100644 --- a/src/uu/dd/Cargo.toml +++ b/src/uu/dd/Cargo.toml @@ -41,6 +41,9 @@ divan = { workspace = true } tempfile = { workspace = true } uucore = { workspace = true, features = ["benchmark"] } +[build-dependencies] +rustc_version = { workspace = true } + [lints] workspace = true diff --git a/src/uu/dd/build.rs b/src/uu/dd/build.rs new file mode 100644 index 00000000000..fea33e2f5a9 --- /dev/null +++ b/src/uu/dd/build.rs @@ -0,0 +1,11 @@ +// This file is part of the uutils coreutils package. +// +// For the full copyright and license information, please view the LICENSE +// file that was distributed with this source code. + +fn main() { + if rustc_version::version_meta().unwrap().channel == rustc_version::Channel::Nightly { + // Allows conditional compilation with `#[cfg(nightly)]`. + println!("cargo:rustc-cfg=nightly"); + } +} diff --git a/src/uu/dd/src/dd.rs b/src/uu/dd/src/dd.rs index 7863203b56f..04805cf73da 100644 --- a/src/uu/dd/src/dd.rs +++ b/src/uu/dd/src/dd.rs @@ -5,6 +5,9 @@ // spell-checker:ignore fname, ftype, tname, fpath, specfile, testfile, unspec, ifile, ofile, outfile, fullblock, urand, fileio, atoe, atoibm, behaviour, bmax, bremain, cflags, creat, ctable, ctty, datastructures, doesnt, etoa, fileout, fname, gnudd, iconvflags, iseek, nocache, noctty, noerror, nofollow, nolinks, nonblock, oconvflags, oseek, outfile, parseargs, rlen, rmax, rremain, rsofar, rstat, sigusr, virtio, wlen, wstat, zram, oconv canonicalized FADV DONTNEED ESPIPE SPIPE bufferedoutput, SETFL +// TODO: Remove once https://github.com/rust-lang/rust/issues/71213 is stabilized. +#![cfg_attr(all(nightly, target_os = "wasi"), feature(wasi_ext))] + mod blocks; mod bufferedoutput; mod conversion_tables; @@ -28,17 +31,18 @@ use uucore::translate; use std::cmp; use std::env; use std::ffi::OsString; -#[cfg(unix)] +#[cfg(any(unix, all(nightly, target_os = "wasi")))] use std::fs::Metadata; use std::fs::{File, OpenOptions}; use std::io::{self, Read, Seek, SeekFrom, Write}; +#[cfg(any(unix, all(nightly, target_os = "wasi")))] +use std::os::fd::{AsRawFd, FromRawFd}; +#[cfg(unix)] +use std::os::unix::fs::FileTypeExt; #[cfg(any(target_os = "linux", target_os = "android"))] use std::os::unix::fs::OpenOptionsExt; -#[cfg(unix)] -use std::os::unix::{ - fs::FileTypeExt, - io::{AsRawFd, FromRawFd}, -}; +#[cfg(all(nightly, target_os = "wasi"))] +use std::os::wasi::fs::FileTypeExt; #[cfg(windows)] use std::os::windows::{fs::MetadataExt, io::AsHandle}; use std::path::Path; @@ -50,9 +54,11 @@ use std::time::{Duration, Instant}; use clap::{Arg, Command}; use num_integer::Integer; use uucore::display::Quotable; -use uucore::error::{FromIo, UResult}; #[cfg(unix)] -use uucore::error::{USimpleError, set_exit_code}; +use uucore::error::USimpleError; +#[cfg(any(unix, all(nightly, target_os = "wasi")))] +use uucore::error::set_exit_code; +use uucore::error::{FromIo, UResult}; #[cfg(any(target_os = "linux", target_os = "android", target_os = "freebsd"))] use uucore::show_if_err; use uucore::{format_usage, show_error}; @@ -213,14 +219,14 @@ impl AlignedBuf { /// fine-grained access to reading from stdin. enum Source { /// Input from stdin. - #[cfg(not(unix))] + #[cfg(not(any(unix, all(nightly, target_os = "wasi"))))] Stdin(io::Stdin), /// Input from a file. File(File), /// Input from stdin, opened from its file descriptor. - #[cfg(unix)] + #[cfg(any(unix, all(nightly, target_os = "wasi")))] StdinFile(File), /// Input from a named pipe, also known as a FIFO. @@ -236,7 +242,7 @@ impl Source { /// the [`File`] parameter. You can use this instead of /// `Source::Stdin` to allow reading from stdin without consuming /// the entire contents of stdin when this process terminates. - #[cfg(unix)] + #[cfg(any(unix, all(nightly, target_os = "wasi")))] fn stdin_as_file() -> Self { let fd = io::stdin().as_raw_fd(); let f = unsafe { File::from_raw_fd(fd) }; @@ -245,7 +251,7 @@ impl Source { fn skip(&mut self, n: u64, ibs: usize) -> io::Result { match self { - #[cfg(not(unix))] + #[cfg(not(any(unix, all(nightly, target_os = "wasi"))))] Self::Stdin(stdin) => { let m = uucore::io::read_and_discard(stdin, n, ibs)?; if m < n { @@ -256,7 +262,7 @@ impl Source { } Ok(m) } - #[cfg(unix)] + #[cfg(any(unix, all(nightly, target_os = "wasi")))] Self::StdinFile(f) => { if let Ok(Some(len)) = try_get_len_of_block_device(f) && len < n @@ -335,10 +341,10 @@ impl Source { impl Read for Source { fn read(&mut self, buf: &mut [u8]) -> io::Result { match self { - #[cfg(not(unix))] + #[cfg(not(any(unix, all(nightly, target_os = "wasi"))))] Self::Stdin(stdin) => stdin.read(buf), Self::File(f) => f.read(buf), - #[cfg(unix)] + #[cfg(any(unix, all(nightly, target_os = "wasi")))] Self::StdinFile(f) => f.read(buf), #[cfg(unix)] Self::Fifo(f) => f.read(buf), @@ -376,9 +382,9 @@ impl<'a> Input<'a> { _ => Source::Stdin(io::stdin()), } }; - #[cfg(all(not(unix), not(windows)))] + #[cfg(all(not(unix), not(windows), not(all(nightly, target_os = "wasi"))))] let mut src = Source::Stdin(io::stdin()); - #[cfg(unix)] + #[cfg(any(unix, all(nightly, target_os = "wasi")))] let mut src = Source::stdin_as_file(); #[cfg(unix)] if let Source::StdinFile(f) = &src @@ -1538,7 +1544,7 @@ fn is_stdout_redirected_to_seekable_file() -> bool { } /// Try to get the len if it is a block device -#[cfg(unix)] +#[cfg(any(unix, all(nightly, target_os = "wasi")))] fn try_get_len_of_block_device(file: &mut File) -> io::Result> { let ftype = file.metadata()?.file_type(); if !ftype.is_block_device() {