Skip to content

Commit 5da8c11

Browse files
committed
dd: ignore a failed cache drop while copying
Signed-off-by: Zhiwei Liang <zhiwei.liang@zliang.me>
1 parent 5eb255f commit 5da8c11

3 files changed

Lines changed: 75 additions & 52 deletions

File tree

src/uu/dd/src/bufferedoutput.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,8 @@ impl<'a> BufferedOutput<'a> {
4141
Ok(Self { inner, buf })
4242
}
4343

44-
pub(crate) fn discard_cache(&self, offset: u64, len: u64) {
45-
self.inner.discard_cache(offset, len);
44+
pub(crate) fn discard_cache(&self, offset: u64, len: u64) -> std::io::Result<()> {
45+
self.inner.discard_cache(offset, len)
4646
}
4747

4848
/// Flush the partial block stored in the internal buffer.

src/uu/dd/src/dd.rs

Lines changed: 53 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,6 @@ use uucore::display::Quotable;
5353
use uucore::error::{FromIo, UResult};
5454
#[cfg(unix)]
5555
use uucore::error::{USimpleError, set_exit_code};
56-
#[cfg(any(target_os = "linux", target_os = "android", target_os = "freebsd"))]
5756
use uucore::show_if_err;
5857
use uucore::{format_usage, show_error};
5958

@@ -495,28 +494,22 @@ impl Input<'_> {
495494
///
496495
/// `offset` and `len` specify a contiguous portion of the input.
497496
/// This function informs the kernel that the specified portion of
498-
/// the input file is no longer needed. If not possible, then this
499-
/// function prints an error message to stderr and sets the exit
500-
/// status code to 1.
501-
#[cfg_attr(
502-
not(any(target_os = "linux", target_os = "android", target_os = "freebsd")),
503-
allow(clippy::unused_self, unused_variables)
497+
/// the input file is no longer needed. If not possible, the error is
498+
/// returned and the caller decides whether to report it; only the
499+
/// `count=0` path in [`flush_caches_full_length`] does.
500+
#[cfg(any(target_os = "linux", target_os = "android", target_os = "freebsd"))]
501+
fn discard_cache(&self, offset: u64, len: u64) -> io::Result<()> {
502+
self.src.discard_cache(offset, len)
503+
}
504+
505+
// TODO: Is there a way to discard filesystem cache on other targets?
506+
#[cfg(not(any(target_os = "linux", target_os = "android", target_os = "freebsd")))]
507+
#[allow(
508+
clippy::unnecessary_wraps,
509+
reason = "platform stub; keeps one signature for every caller"
504510
)]
505-
fn discard_cache(&self, offset: u64, len: u64) {
506-
#[cfg(any(target_os = "linux", target_os = "android", target_os = "freebsd"))]
507-
{
508-
let file = self
509-
.settings
510-
.infile
511-
.clone()
512-
.unwrap_or_else(|| translate!("dd-standard-input"));
513-
show_if_err!(
514-
self.src.discard_cache(offset, len).map_err_context(
515-
|| translate!("dd-error-failed-discard-cache", "file" => file)
516-
)
517-
);
518-
}
519-
// TODO: Is there a way to discard filesystem cache on other targets?
511+
fn discard_cache(&self, _offset: u64, _len: u64) -> io::Result<()> {
512+
Ok(())
520513
}
521514

522515
/// Fills a given buffer.
@@ -948,28 +941,22 @@ impl<'a> Output<'a> {
948941
///
949942
/// `offset` and `len` specify a contiguous portion of the output.
950943
/// This function informs the kernel that the specified portion of
951-
/// the output file is no longer needed. If not possible, then
952-
/// this function prints an error message to stderr and sets the
953-
/// exit status code to 1.
954-
#[cfg_attr(
955-
not(any(target_os = "linux", target_os = "android", target_os = "freebsd")),
956-
allow(clippy::unused_self, unused_variables)
944+
/// the output file is no longer needed. If not possible, the error is
945+
/// returned and the caller decides whether to report it; only the
946+
/// `count=0` path in [`flush_caches_full_length`] does.
947+
#[cfg(any(target_os = "linux", target_os = "android", target_os = "freebsd"))]
948+
fn discard_cache(&self, offset: u64, len: u64) -> io::Result<()> {
949+
self.dst.discard_cache(offset, len)
950+
}
951+
952+
// TODO: Is there a way to discard filesystem cache on other targets?
953+
#[cfg(not(any(target_os = "linux", target_os = "android", target_os = "freebsd")))]
954+
#[allow(
955+
clippy::unnecessary_wraps,
956+
reason = "platform stub; keeps one signature for every caller"
957957
)]
958-
fn discard_cache(&self, offset: u64, len: u64) {
959-
#[cfg(any(target_os = "linux", target_os = "android", target_os = "freebsd"))]
960-
{
961-
let file = self
962-
.settings
963-
.outfile
964-
.clone()
965-
.unwrap_or_else(|| translate!("dd-standard-output"));
966-
show_if_err!(
967-
self.dst.discard_cache(offset, len).map_err_context(
968-
|| translate!("dd-error-failed-discard-cache", "file" => file)
969-
)
970-
);
971-
}
972-
// TODO Is there a way to discard filesystem cache on other targets?
958+
fn discard_cache(&self, _offset: u64, _len: u64) -> io::Result<()> {
959+
Ok(())
973960
}
974961

975962
/// writes a block of data. optionally retries when first try didn't complete
@@ -1057,7 +1044,7 @@ enum BlockWriter<'a> {
10571044
}
10581045

10591046
impl BlockWriter<'_> {
1060-
fn discard_cache(&self, offset: u64, len: u64) {
1047+
fn discard_cache(&self, offset: u64, len: u64) -> io::Result<()> {
10611048
match self {
10621049
Self::Unbuffered(o) => o.discard_cache(offset, len),
10631050
Self::Buffered(o) => o.discard_cache(offset, len),
@@ -1103,10 +1090,26 @@ impl BlockWriter<'_> {
11031090
fn flush_caches_full_length(i: &Input, o: &Output) {
11041091
// Using len=0 in posix_fadvise means "to end of file"
11051092
if i.settings.iflags.nocache {
1106-
i.discard_cache(0, 0);
1093+
let file = i
1094+
.settings
1095+
.infile
1096+
.clone()
1097+
.unwrap_or_else(|| translate!("dd-standard-input"));
1098+
show_if_err!(
1099+
i.discard_cache(0, 0)
1100+
.map_err_context(|| translate!("dd-error-failed-discard-cache", "file" => file))
1101+
);
11071102
}
11081103
if i.settings.oflags.nocache {
1109-
o.discard_cache(0, 0);
1104+
let file = o
1105+
.settings
1106+
.outfile
1107+
.clone()
1108+
.unwrap_or_else(|| translate!("dd-standard-output"));
1109+
show_if_err!(
1110+
o.discard_cache(0, 0)
1111+
.map_err_context(|| translate!("dd-error-failed-discard-cache", "file" => file))
1112+
);
11101113
}
11111114
}
11121115

@@ -1246,10 +1249,10 @@ fn dd_copy(mut i: Input, o: Output) -> io::Result<()> {
12461249
};
12471250
if rstat_update.is_empty() {
12481251
if input_nocache {
1249-
i.discard_cache(read_offset, 0);
1252+
let _ = i.discard_cache(read_offset, 0);
12501253
}
12511254
if output_nocache || output_direct {
1252-
o.discard_cache(write_offset.try_into().unwrap(), 0);
1255+
let _ = o.discard_cache(write_offset.try_into().unwrap(), 0);
12531256
}
12541257
break;
12551258
}
@@ -1265,7 +1268,7 @@ fn dd_copy(mut i: Input, o: Output) -> io::Result<()> {
12651268
if input_nocache {
12661269
let offset = read_offset;
12671270
let len = read_len;
1268-
i.discard_cache(offset, len);
1271+
let _ = i.discard_cache(offset, len);
12691272
}
12701273
read_offset += read_len;
12711274

@@ -1277,7 +1280,7 @@ fn dd_copy(mut i: Input, o: Output) -> io::Result<()> {
12771280
if output_nocache {
12781281
let offset = write_offset.try_into().unwrap();
12791282
let len = write_len.try_into().unwrap();
1280-
o.discard_cache(offset, len);
1283+
let _ = o.discard_cache(offset, len);
12811284
}
12821285
write_offset += write_len;
12831286

tests/by-util/test_dd.rs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1899,6 +1899,26 @@ fn test_iflag_directory_fails_when_file_is_piped_via_std_in() {
18991899
.stderr_only("dd: setting flags for 'standard input': Not a directory\n");
19001900
}
19011901

1902+
#[test]
1903+
#[cfg(any(target_os = "linux", target_os = "android"))]
1904+
fn test_nocache_on_a_pipe_is_silent_at_eof() {
1905+
new_ucmd!()
1906+
.args(&["iflag=nocache", "oflag=nocache", "status=none"])
1907+
.pipe_in("")
1908+
.succeeds()
1909+
.no_output();
1910+
}
1911+
1912+
#[test]
1913+
#[cfg(any(target_os = "linux", target_os = "android"))]
1914+
fn test_nocache_on_a_pipe_is_silent_while_copying() {
1915+
new_ucmd!()
1916+
.args(&["iflag=nocache", "oflag=nocache", "status=none"])
1917+
.pipe_in("abc")
1918+
.succeeds()
1919+
.stdout_only("abc");
1920+
}
1921+
19021922
#[test]
19031923
fn test_stdin_stdout_not_rewound_even_when_connected_to_seekable_file() {
19041924
let ts = TestScenario::new(util_name!());

0 commit comments

Comments
 (0)