mirror of
https://github.com/RGBCube/uutils-coreutils
synced 2025-07-30 20:47:46 +00:00
dd: add Settings.buffered field
Add the `Settings.buffered` field to indicate whether partial output blocks should be buffered until they are complete.
This commit is contained in:
parent
cd4f455a77
commit
016ae34d50
3 changed files with 49 additions and 34 deletions
|
@ -76,6 +76,8 @@ struct Settings {
|
||||||
oconv: OConvFlags,
|
oconv: OConvFlags,
|
||||||
oflags: OFlags,
|
oflags: OFlags,
|
||||||
status: Option<StatusLevel>,
|
status: Option<StatusLevel>,
|
||||||
|
/// Whether the output writer should buffer partial blocks until complete.
|
||||||
|
buffered: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A timer which triggers on a given interval
|
/// A timer which triggers on a given interval
|
||||||
|
@ -128,6 +130,12 @@ enum Num {
|
||||||
Bytes(u64),
|
Bytes(u64),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Default for Num {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::Blocks(0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Num {
|
impl Num {
|
||||||
fn force_bytes_if(self, force: bool) -> Self {
|
fn force_bytes_if(self, force: bool) -> Self {
|
||||||
match self {
|
match self {
|
||||||
|
|
|
@ -35,41 +35,28 @@ pub enum ParseError {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Contains a temporary state during parsing of the arguments
|
/// Contains a temporary state during parsing of the arguments
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq, Default)]
|
||||||
pub struct Parser {
|
pub struct Parser {
|
||||||
infile: Option<String>,
|
infile: Option<String>,
|
||||||
outfile: Option<String>,
|
outfile: Option<String>,
|
||||||
ibs: usize,
|
/// The block size option specified on the command-line, if any.
|
||||||
obs: usize,
|
bs: Option<usize>,
|
||||||
|
/// The input block size option specified on the command-line, if any.
|
||||||
|
ibs: Option<usize>,
|
||||||
|
/// The output block size option specified on the command-line, if any.
|
||||||
|
obs: Option<usize>,
|
||||||
cbs: Option<usize>,
|
cbs: Option<usize>,
|
||||||
skip: Num,
|
skip: Num,
|
||||||
seek: Num,
|
seek: Num,
|
||||||
count: Option<Num>,
|
count: Option<Num>,
|
||||||
conv: ConvFlags,
|
conv: ConvFlags,
|
||||||
|
/// Whether a data-transforming `conv` option has been specified.
|
||||||
|
is_conv_specified: bool,
|
||||||
iflag: IFlags,
|
iflag: IFlags,
|
||||||
oflag: OFlags,
|
oflag: OFlags,
|
||||||
status: Option<StatusLevel>,
|
status: Option<StatusLevel>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Parser {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self {
|
|
||||||
ibs: 512,
|
|
||||||
obs: 512,
|
|
||||||
cbs: None,
|
|
||||||
infile: None,
|
|
||||||
outfile: None,
|
|
||||||
skip: Num::Blocks(0),
|
|
||||||
seek: Num::Blocks(0),
|
|
||||||
count: None,
|
|
||||||
conv: ConvFlags::default(),
|
|
||||||
iflag: IFlags::default(),
|
|
||||||
oflag: OFlags::default(),
|
|
||||||
status: None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Default, PartialEq, Eq)]
|
#[derive(Debug, Default, PartialEq, Eq)]
|
||||||
pub struct ConvFlags {
|
pub struct ConvFlags {
|
||||||
ascii: bool,
|
ascii: bool,
|
||||||
|
@ -212,15 +199,34 @@ impl Parser {
|
||||||
fsync: conv.fsync,
|
fsync: conv.fsync,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Input and output block sizes.
|
||||||
|
//
|
||||||
|
// The `bs` option takes precedence. If either is not
|
||||||
|
// provided, `ibs` and `obs` are each 512 bytes by default.
|
||||||
|
let (ibs, obs) = match self.bs {
|
||||||
|
None => (self.ibs.unwrap_or(512), self.obs.unwrap_or(512)),
|
||||||
|
Some(bs) => (bs, bs),
|
||||||
|
};
|
||||||
|
|
||||||
|
// Whether to buffer partial output blocks until they are completed.
|
||||||
|
//
|
||||||
|
// From the GNU `dd` documentation for the `bs=BYTES` option:
|
||||||
|
//
|
||||||
|
// > [...] if no data-transforming 'conv' option is specified,
|
||||||
|
// > input is copied to the output as soon as it's read, even if
|
||||||
|
// > it is smaller than the block size.
|
||||||
|
//
|
||||||
|
let buffered = self.bs.is_none() || self.is_conv_specified;
|
||||||
|
|
||||||
let skip = self
|
let skip = self
|
||||||
.skip
|
.skip
|
||||||
.force_bytes_if(self.iflag.skip_bytes)
|
.force_bytes_if(self.iflag.skip_bytes)
|
||||||
.to_bytes(self.ibs as u64);
|
.to_bytes(ibs as u64);
|
||||||
|
|
||||||
let seek = self
|
let seek = self
|
||||||
.seek
|
.seek
|
||||||
.force_bytes_if(self.oflag.seek_bytes)
|
.force_bytes_if(self.oflag.seek_bytes)
|
||||||
.to_bytes(self.obs as u64);
|
.to_bytes(obs as u64);
|
||||||
|
|
||||||
let count = self.count.map(|c| c.force_bytes_if(self.iflag.count_bytes));
|
let count = self.count.map(|c| c.force_bytes_if(self.iflag.count_bytes));
|
||||||
|
|
||||||
|
@ -230,8 +236,9 @@ impl Parser {
|
||||||
count,
|
count,
|
||||||
iconv,
|
iconv,
|
||||||
oconv,
|
oconv,
|
||||||
ibs: self.ibs,
|
ibs,
|
||||||
obs: self.obs,
|
obs,
|
||||||
|
buffered,
|
||||||
infile: self.infile,
|
infile: self.infile,
|
||||||
outfile: self.outfile,
|
outfile: self.outfile,
|
||||||
iflags: self.iflag,
|
iflags: self.iflag,
|
||||||
|
@ -244,18 +251,17 @@ impl Parser {
|
||||||
match operand.split_once('=') {
|
match operand.split_once('=') {
|
||||||
None => return Err(ParseError::UnrecognizedOperand(operand.to_string())),
|
None => return Err(ParseError::UnrecognizedOperand(operand.to_string())),
|
||||||
Some((k, v)) => match k {
|
Some((k, v)) => match k {
|
||||||
"bs" => {
|
"bs" => self.bs = Some(Self::parse_bytes(k, v)?),
|
||||||
let bs = Self::parse_bytes(k, v)?;
|
|
||||||
self.ibs = bs;
|
|
||||||
self.obs = bs;
|
|
||||||
}
|
|
||||||
"cbs" => self.cbs = Some(Self::parse_bytes(k, v)?),
|
"cbs" => self.cbs = Some(Self::parse_bytes(k, v)?),
|
||||||
"conv" => self.parse_conv_flags(v)?,
|
"conv" => {
|
||||||
|
self.is_conv_specified = true;
|
||||||
|
self.parse_conv_flags(v)?;
|
||||||
|
}
|
||||||
"count" => self.count = Some(Self::parse_n(v)?),
|
"count" => self.count = Some(Self::parse_n(v)?),
|
||||||
"ibs" => self.ibs = Self::parse_bytes(k, v)?,
|
"ibs" => self.ibs = Some(Self::parse_bytes(k, v)?),
|
||||||
"if" => self.infile = Some(v.to_string()),
|
"if" => self.infile = Some(v.to_string()),
|
||||||
"iflag" => self.parse_input_flags(v)?,
|
"iflag" => self.parse_input_flags(v)?,
|
||||||
"obs" => self.obs = Self::parse_bytes(k, v)?,
|
"obs" => self.obs = Some(Self::parse_bytes(k, v)?),
|
||||||
"of" => self.outfile = Some(v.to_string()),
|
"of" => self.outfile = Some(v.to_string()),
|
||||||
"oflag" => self.parse_output_flags(v)?,
|
"oflag" => self.parse_output_flags(v)?,
|
||||||
"seek" | "oseek" => self.seek = Self::parse_n(v)?,
|
"seek" | "oseek" => self.seek = Self::parse_n(v)?,
|
||||||
|
|
|
@ -358,6 +358,7 @@ fn parse_icf_tokens_remaining() {
|
||||||
fsync: true,
|
fsync: true,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
|
is_conv_specified: true,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue