Skip to content

Commit 07699da

Browse files
committed
dd: refactor stdout handling to use StdoutRaw struct
1 parent d954cb7 commit 07699da

1 file changed

Lines changed: 45 additions & 13 deletions

File tree

src/uu/dd/src/dd.rs

Lines changed: 45 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ use progress::ProgUpdateType;
2525
use progress::{ProgUpdate, ReadStat, StatusLevel, WriteStat, gen_prog_updater};
2626
#[cfg(target_os = "linux")]
2727
use progress::{check_and_reset_sigusr1, install_sigusr1_handler};
28-
use uucore::io::OwnedFileDescriptorOrHandle;
2928
use uucore::translate;
3029

3130
use std::cmp;
@@ -235,7 +234,7 @@ impl core::ops::DerefMut for StdinRaw {
235234

236235
/// Data sources.
237236
///
238-
/// Use [`Source::stdin_as_file`] if available to enable more
237+
/// Use [`Source::stdin_raw`] if available to enable more
239238
/// fine-grained access to reading from stdin.
240239
enum Source {
241240
/// Input from stdin.
@@ -625,7 +624,7 @@ enum Density {
625624
/// Data destinations.
626625
enum Dest {
627626
/// Output to stdout.
628-
Stdout(File),
627+
StdoutRaw(StdoutRaw),
629628

630629
/// Output to a file.
631630
///
@@ -645,7 +644,7 @@ enum Dest {
645644
impl Dest {
646645
fn fsync(&mut self) -> io::Result<()> {
647646
match self {
648-
Self::Stdout(stdout) => stdout.flush(),
647+
Self::StdoutRaw(stdout) => stdout.flush(),
649648
Self::File(f, _) => {
650649
f.flush()?;
651650
f.sync_all()
@@ -662,7 +661,7 @@ impl Dest {
662661

663662
fn fdatasync(&mut self) -> io::Result<()> {
664663
match self {
665-
Self::Stdout(stdout) => stdout.flush(),
664+
Self::StdoutRaw(stdout) => stdout.flush(),
666665
Self::File(f, _) => {
667666
f.flush()?;
668667
f.sync_data()
@@ -680,7 +679,7 @@ impl Dest {
680679
#[cfg_attr(not(unix), allow(unused_variables))]
681680
fn seek(&mut self, n: u64, obs: usize) -> io::Result<u64> {
682681
match self {
683-
Self::Stdout(stdout) => io::copy(&mut io::repeat(0).take(n), stdout),
682+
Self::StdoutRaw(stdout) => io::copy(&mut io::repeat(0).take(n), &mut **stdout),
684683
Self::File(f, _) => {
685684
#[cfg(unix)]
686685
if let Ok(Some(len)) = try_get_len_of_block_device(f)
@@ -790,6 +789,38 @@ fn handle_o_direct_write(
790789
Err(original_error)
791790
}
792791

792+
struct StdoutRaw(core::mem::ManuallyDrop<File>);
793+
794+
impl StdoutRaw {
795+
#[cfg(not(windows))]
796+
fn new() -> Self {
797+
let fd = io::stdout().as_raw_fd();
798+
let f = unsafe { File::from_raw_fd(fd) };
799+
Self(core::mem::ManuallyDrop::new(f))
800+
}
801+
802+
#[cfg(windows)]
803+
fn new() -> Self {
804+
let handle = std::os::windows::io::AsRawHandle::as_raw_handle(&io::stdout());
805+
let f = unsafe { std::os::windows::io::FromRawHandle::from_raw_handle(handle) };
806+
Self(core::mem::ManuallyDrop::new(f))
807+
}
808+
}
809+
810+
impl core::ops::Deref for StdoutRaw {
811+
type Target = File;
812+
813+
fn deref(&self) -> &Self::Target {
814+
&self.0
815+
}
816+
}
817+
818+
impl core::ops::DerefMut for StdoutRaw {
819+
fn deref_mut(&mut self) -> &mut Self::Target {
820+
&mut self.0
821+
}
822+
}
823+
793824
impl Write for Dest {
794825
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
795826
match self {
@@ -816,7 +847,7 @@ impl Write for Dest {
816847
Err(e) => Err(e),
817848
}
818849
}
819-
Self::Stdout(stdout) => stdout.write(buf),
850+
Self::StdoutRaw(stdout) => stdout.write(buf),
820851
#[cfg(unix)]
821852
Self::Fifo(f) => f.write(buf),
822853
#[cfg(unix)]
@@ -826,7 +857,7 @@ impl Write for Dest {
826857

827858
fn flush(&mut self) -> io::Result<()> {
828859
match self {
829-
Self::Stdout(stdout) => stdout.flush(),
860+
Self::StdoutRaw(stdout) => stdout.flush(),
830861
Self::File(f, _) => f.flush(),
831862
#[cfg(unix)]
832863
Self::Fifo(f) => f.flush(),
@@ -853,8 +884,8 @@ struct Output<'a> {
853884
impl<'a> Output<'a> {
854885
/// Instantiate this struct with stdout as a destination.
855886
fn new_stdout(settings: &'a Settings) -> UResult<Self> {
856-
let fx = OwnedFileDescriptorOrHandle::from(io::stdout())?;
857-
let mut dst = Dest::Stdout(fx.into_file());
887+
let stdout = StdoutRaw::new();
888+
let mut dst = Dest::StdoutRaw(stdout);
858889
dst.seek(settings.seek, settings.obs)
859890
.map_err_context(|| translate!("dd-error-write-error"))?;
860891
Ok(Self { dst, settings })
@@ -914,16 +945,17 @@ impl<'a> Output<'a> {
914945
/// already opened by the system (stdout) and has a state
915946
/// (current position) that shall be used.
916947
fn new_file_from_stdout(settings: &'a Settings) -> UResult<Self> {
917-
let fx = OwnedFileDescriptorOrHandle::from(io::stdout())?;
948+
let stdout = StdoutRaw::new();
918949
#[cfg(any(target_os = "linux", target_os = "android"))]
919950
if let Some(libc_flags) = make_linux_oflags(&settings.oflags) {
920951
nix::fcntl::fcntl(
921-
fx.as_raw().as_fd(),
952+
stdout.as_fd(),
922953
FcntlArg::F_SETFL(OFlag::from_bits_retain(libc_flags)),
923954
)?;
924955
}
925956

926-
Self::prepare_file(fx.into_file(), settings)
957+
// TODO: avoid cloning the underlying file descriptor here
958+
Self::prepare_file(stdout.try_clone()?, settings)
927959
}
928960

929961
/// Instantiate this struct with the given named pipe as a destination.

0 commit comments

Comments
 (0)