Skip to content

Commit

Permalink
dd: fix GNU test 'dd/skip-seek-past-dev'
Browse files Browse the repository at this point in the history
  • Loading branch information
bbara authored and sylvestre committed Apr 14, 2023
1 parent 084510e commit 1f45356
Showing 1 changed file with 48 additions and 9 deletions.
57 changes: 48 additions & 9 deletions src/uu/dd/src/dd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ use std::time;
use clap::{crate_version, Arg, Command};
use gcd::Gcd;
use uucore::display::Quotable;
use uucore::error::{FromIo, UResult};
use uucore::error::{set_exit_code, FromIo, UResult};
use uucore::{format_usage, help_about, help_section, help_usage, show_error};

const ABOUT: &str = help_about!("dd.md");
Expand Down Expand Up @@ -143,14 +143,25 @@ impl Source {
Err(e) => Err(e),
},
#[cfg(unix)]
Self::StdinFile(f) => match io::copy(&mut f.take(n), &mut io::sink()) {
Ok(m) if m < n => {
show_error!("'standard input': cannot skip to specified offset");
Ok(m)
Self::StdinFile(f) => {
if let Ok(Some(len)) = try_get_len_of_block_device(f) {
if len < n {
// GNU compatibility:
// this case prints the stats but sets the exit code to 1
show_error!("'standard input': cannot skip: Invalid argument");
set_exit_code(1);
return Ok(len);
}
}
Ok(m) => Ok(m),
Err(e) => Err(e),
},
match io::copy(&mut f.take(n), &mut io::sink()) {
Ok(m) if m < n => {
show_error!("'standard input': cannot skip to specified offset");
Ok(m)
}
Ok(m) => Ok(m),
Err(e) => Err(e),
}
}
Self::File(f) => f.seek(io::SeekFrom::Start(n)),
#[cfg(unix)]
Self::Fifo(f) => io::copy(&mut f.take(n), &mut io::sink()),
Expand Down Expand Up @@ -426,7 +437,18 @@ impl Dest {
fn seek(&mut self, n: u64) -> io::Result<u64> {
match self {
Self::Stdout(stdout) => io::copy(&mut io::repeat(0).take(n), stdout),
Self::File(f, _) => f.seek(io::SeekFrom::Start(n)),
Self::File(f, _) => {
if let Ok(Some(len)) = try_get_len_of_block_device(f) {
if len < n {
// GNU compatibility:
// this case prints the stats but sets the exit code to 1
show_error!("'standard output': cannot seek: Invalid argument");
set_exit_code(1);
return Ok(len);
}
}
f.seek(io::SeekFrom::Start(n))
}
#[cfg(unix)]
Self::Fifo(f) => {
// Seeking in a named pipe means *reading* from the pipe.
Expand Down Expand Up @@ -925,6 +947,23 @@ fn is_stdout_redirected_to_seekable_file() -> bool {
}
}

/// Try to get the len if it is a block device
fn try_get_len_of_block_device(file: &mut File) -> io::Result<Option<u64>> {
#[cfg(not(unix))]
return Ok(None);

let ftype = file.metadata()?.file_type();
#[cfg(unix)]
if !ftype.is_block_device() {
return Ok(None);
}

// FIXME: this can be replaced by file.stream_len() when stable.
let len = file.seek(SeekFrom::End(0))?;
file.rewind()?;
Ok(Some(len))
}

/// Decide whether the named file is a named pipe, also known as a FIFO.
#[cfg(unix)]
fn is_fifo(filename: &str) -> bool {
Expand Down

0 comments on commit 1f45356

Please sign in to comment.