Skip to content

Commit

Permalink
dd: add discard_cache() funcs for Input, Output
Browse files Browse the repository at this point in the history
Add the `Input::discard_cache()` and `Output::discard_cache()`
functions. These allow discarding the filesystem cache when `dd` no
longer needs to access a specified portion of the input or output
file, respectively.
  • Loading branch information
jfinkels committed Mar 5, 2023
1 parent da9e89b commit 210e2b8
Show file tree
Hide file tree
Showing 3 changed files with 91 additions and 0 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions src/uu/dd/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ path = "src/dd.rs"
clap = { workspace=true }
gcd = { workspace=true }
libc = { workspace=true }
nix = { workspace=true, features = ["fs"] }
uucore = { workspace=true }

[target.'cfg(any(target_os = "linux", target_os = "android"))'.dependencies]
Expand Down
89 changes: 89 additions & 0 deletions src/uu/dd/src/dd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@ use std::time;

use clap::{crate_version, Arg, Command};
use gcd::Gcd;
use nix;
use nix::errno::Errno;
use nix::fcntl::{posix_fadvise, PosixFadviseAdvice};
use uucore::display::Quotable;
use uucore::error::{FromIo, UResult};
use uucore::{format_usage, help_about, help_section, help_usage, show_error};
Expand Down Expand Up @@ -106,6 +109,16 @@ enum Source {
}

impl Source {
/// The length of the data source in number of bytes.
///
/// If it cannot be determined, then this function returns 0.
fn len(&self) -> std::io::Result<i64> {
match self {
Self::File(f) => Ok(f.metadata()?.len().try_into().unwrap_or(i64::MAX)),
_ => Ok(0),
}
}

fn skip(&mut self, n: u64) -> io::Result<u64> {
match self {
Self::Stdin(stdin) => match io::copy(&mut stdin.take(n), &mut io::sink()) {
Expand All @@ -121,6 +134,22 @@ impl Source {
Self::Fifo(f) => io::copy(&mut f.take(n), &mut io::sink()),
}
}

/// Discard the system file cache for the given portion of the data source.
///
/// `offset` and `len` specify a contiguous portion of the data
/// source. This function informs the kernel that the specified
/// portion of the source is no longer needed. If not possible,
/// then this function returns an error.
fn discard_cache(&self, offset: i64, len: i64) -> nix::Result<()> {
match self {
Self::File(f) => {
let advice = PosixFadviseAdvice::POSIX_FADV_DONTNEED;
posix_fadvise(f.as_raw_fd(), offset, len, advice)
}
_ => Err(Errno::ESPIPE), // "Illegal seek"
}
}
}

impl Read for Source {
Expand Down Expand Up @@ -255,6 +284,23 @@ impl<'a> Read for Input<'a> {
}

impl<'a> Input<'a> {
/// Discard the system file cache for the given portion of the input.
///
/// `offset` and `len` specify a contiguous portion of the input.
/// This function informs the kernel that the specified portion of
/// the input file is no longer needed. If not possible, then this
/// function prints an error message to stderr and sets the exit
/// status code to 1.
fn discard_cache(&self, offset: i64, len: i64) {
if let Err(e) = self.src.discard_cache(offset, len) {
show_error!(
"failed to discard cache for: 'standard input': {}",
e.desc()
);
set_exit_code(1);
}
}

/// Fills a given buffer.
/// Reads in increments of 'self.ibs'.
/// The start of each ibs-sized read follows the previous one.
Expand Down Expand Up @@ -410,6 +456,32 @@ impl Dest {
_ => Ok(()),
}
}

/// Discard the system file cache for the given portion of the destination.
///
/// `offset` and `len` specify a contiguous portion of the
/// destination. This function informs the kernel that the
/// specified portion of the destination is no longer needed. If
/// not possible, then this function returns an error.
fn discard_cache(&self, offset: i64, len: i64) -> nix::Result<()> {
match self {
Self::File(f, _) => {
let advice = PosixFadviseAdvice::POSIX_FADV_DONTNEED;
posix_fadvise(f.as_raw_fd(), offset, len, advice)
}
_ => Err(Errno::ESPIPE), // "Illegal seek"
}
}

/// The length of the data destination in number of bytes.
///
/// If it cannot be determined, then this function returns 0.
fn len(&self) -> std::io::Result<i64> {
match self {
Self::File(f, _) => Ok(f.metadata()?.len().try_into().unwrap_or(i64::MAX)),
_ => Ok(0),
}
}
}

/// Decide whether the given buffer is all zeros.
Expand Down Expand Up @@ -543,6 +615,23 @@ impl<'a> Output<'a> {
Ok(Self { dst, settings })
}

/// Discard the system file cache for the given portion of the output.
///
/// `offset` and `len` specify a contiguous portion of the output.
/// This function informs the kernel that the specified portion of
/// the output file is no longer needed. If not possible, then
/// this function prints an error message to stderr and sets the
/// exit status code to 1.
fn discard_cache(&self, offset: i64, len: i64) {
if let Err(e) = self.dst.discard_cache(offset, len) {
show_error!(
"failed to discard cache for: 'standard output': {}",
e.desc()
);
set_exit_code(1);
}
}

/// Write the given bytes one block at a time.
///
/// This may write partial blocks (for example, if the underlying
Expand Down

0 comments on commit 210e2b8

Please sign in to comment.