Skip to content

Commit d954cb7

Browse files
committed
dd: refactor stdin handling to use StdinRaw struct
1 parent f65350a commit d954cb7

1 file changed

Lines changed: 37 additions & 11 deletions

File tree

src/uu/dd/src/dd.rs

Lines changed: 37 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,34 @@ fn read_and_discard<R: Read>(reader: &mut R, n: u64, buf_size: usize) -> io::Res
205205
Ok(total)
206206
}
207207

208+
#[cfg(unix)]
209+
struct StdinRaw(core::mem::ManuallyDrop<File>);
210+
211+
#[cfg(unix)]
212+
impl StdinRaw {
213+
fn new() -> Self {
214+
let fd = io::stdin().as_raw_fd();
215+
let f = unsafe { File::from_raw_fd(fd) };
216+
Self(core::mem::ManuallyDrop::new(f))
217+
}
218+
}
219+
220+
#[cfg(unix)]
221+
impl core::ops::Deref for StdinRaw {
222+
type Target = File;
223+
224+
fn deref(&self) -> &Self::Target {
225+
&self.0
226+
}
227+
}
228+
229+
#[cfg(unix)]
230+
impl core::ops::DerefMut for StdinRaw {
231+
fn deref_mut(&mut self) -> &mut Self::Target {
232+
&mut self.0
233+
}
234+
}
235+
208236
/// Data sources.
209237
///
210238
/// Use [`Source::stdin_as_file`] if available to enable more
@@ -219,7 +247,7 @@ enum Source {
219247

220248
/// Input from stdin, opened from its file descriptor.
221249
#[cfg(unix)]
222-
StdinFile(File),
250+
StdinRaw(StdinRaw),
223251

224252
/// Input from a named pipe, also known as a FIFO.
225253
#[cfg(unix)]
@@ -229,16 +257,14 @@ enum Source {
229257
impl Source {
230258
/// Create a source from stdin using its raw file descriptor.
231259
///
232-
/// This returns an instance of the `Source::StdinFile` variant,
260+
/// This returns an instance of the `Source::StdinRaw` variant,
233261
/// using the raw file descriptor of [`io::Stdin`] to create
234262
/// the [`File`] parameter. You can use this instead of
235263
/// `Source::Stdin` to allow reading from stdin without consuming
236264
/// the entire contents of stdin when this process terminates.
237265
#[cfg(unix)]
238-
fn stdin_as_file() -> Self {
239-
let fd = io::stdin().as_raw_fd();
240-
let f = unsafe { File::from_raw_fd(fd) };
241-
Self::StdinFile(f)
266+
fn stdin_raw() -> Self {
267+
Self::StdinRaw(StdinRaw::new())
242268
}
243269

244270
fn skip(&mut self, n: u64, ibs: usize) -> io::Result<u64> {
@@ -255,7 +281,7 @@ impl Source {
255281
Ok(m)
256282
}
257283
#[cfg(unix)]
258-
Self::StdinFile(f) => {
284+
Self::StdinRaw(f) => {
259285
if let Ok(Some(len)) = try_get_len_of_block_device(f)
260286
&& len < n
261287
{
@@ -284,7 +310,7 @@ impl Source {
284310
// ESPIPE means the file descriptor is not seekable (e.g., a pipe),
285311
// so fall back to reading and discarding bytes using ibs-sized buffer
286312
Some(Err(e)) if e.raw_os_error() == Some(libc::ESPIPE) => {
287-
let m = read_and_discard(f, n, ibs)?;
313+
let m = read_and_discard::<File>(f, n, ibs)?;
288314
if m < n {
289315
show_error!(
290316
"{}",
@@ -335,7 +361,7 @@ impl Read for Source {
335361
Self::Stdin(stdin) => stdin.read(buf),
336362
Self::File(f) => f.read(buf),
337363
#[cfg(unix)]
338-
Self::StdinFile(f) => f.read(buf),
364+
Self::StdinRaw(f) => f.read(buf),
339365
#[cfg(unix)]
340366
Self::Fifo(f) => f.read(buf),
341367
}
@@ -379,9 +405,9 @@ impl<'a> Input<'a> {
379405
}
380406
};
381407
#[cfg(unix)]
382-
let mut src = Source::stdin_as_file();
408+
let mut src = Source::stdin_raw();
383409
#[cfg(unix)]
384-
if let Source::StdinFile(f) = &src
410+
if let Source::StdinRaw(f) = &src
385411
&& settings.iflags.directory
386412
&& !f.metadata()?.is_dir()
387413
{

0 commit comments

Comments
 (0)