mirror of
https://github.com/uutils/coreutils
synced 2024-11-16 17:58:06 +00:00
Fix type-error when calling parse_size
from dd
This commit is contained in:
parent
b6c952c46e
commit
88dfb8d374
3 changed files with 80 additions and 55 deletions
|
@ -83,8 +83,8 @@ pub struct OFlags {
|
|||
/// then becomes Bytes(N)
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub enum CountType {
|
||||
Reads(usize),
|
||||
Bytes(usize),
|
||||
Reads(u64),
|
||||
Bytes(u64),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
|
|
@ -37,9 +37,8 @@ use std::time;
|
|||
use clap::{crate_version, App, AppSettings, Arg, ArgMatches};
|
||||
use gcd::Gcd;
|
||||
use uucore::display::Quotable;
|
||||
use uucore::error::{FromIo, UResult, USimpleError};
|
||||
use uucore::show_error;
|
||||
use uucore::InvalidEncodingHandling;
|
||||
use uucore::error::{FromIo, UResult};
|
||||
use uucore::{show_error, InvalidEncodingHandling};
|
||||
|
||||
const ABOUT: &str = "copy, and optionally convert, a file system resource";
|
||||
const BUF_INIT_BYTE: u8 = 0xDD;
|
||||
|
@ -75,11 +74,13 @@ impl Input<io::Stdin> {
|
|||
};
|
||||
|
||||
if let Some(amt) = skip {
|
||||
let num_bytes_read = i
|
||||
.force_fill(amt.try_into().unwrap())
|
||||
.map_err_context(|| "failed to read input".to_string())?;
|
||||
if num_bytes_read < amt {
|
||||
show_error!("'standard input': cannot skip to specified offset");
|
||||
if let Err(e) = i.read_skip(amt) {
|
||||
if let io::ErrorKind::UnexpectedEof = e.kind() {
|
||||
show_error!("'standard input': cannot skip to specified offset");
|
||||
} else {
|
||||
return io::Result::Err(e)
|
||||
.map_err_context(|| "I/O error while skipping".to_string());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -148,9 +149,6 @@ impl Input<File> {
|
|||
};
|
||||
|
||||
if let Some(amt) = skip {
|
||||
let amt: u64 = amt
|
||||
.try_into()
|
||||
.map_err(|_| USimpleError::new(1, "failed to parse seek amount"))?;
|
||||
src.seek(io::SeekFrom::Start(amt))
|
||||
.map_err_context(|| "failed to seek in input file".to_string())?;
|
||||
}
|
||||
|
@ -262,19 +260,18 @@ impl<R: Read> Input<R> {
|
|||
})
|
||||
}
|
||||
|
||||
/// Read the specified number of bytes from this reader.
|
||||
///
|
||||
/// On success, this method returns the number of bytes read. If
|
||||
/// this reader has fewer than `n` bytes available, then it reads
|
||||
/// as many as possible. In that case, this method returns a
|
||||
/// number less than `n`.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// If there is a problem reading.
|
||||
fn force_fill(&mut self, n: u64) -> std::io::Result<usize> {
|
||||
let mut buf = vec![];
|
||||
self.take(n).read_to_end(&mut buf)
|
||||
/// Skips amount_to_read bytes from the Input by copying into a sink
|
||||
fn read_skip(&mut self, amount_to_read: u64) -> std::io::Result<()> {
|
||||
let copy_result = io::copy(&mut self.src.by_ref().take(amount_to_read), &mut io::sink());
|
||||
if let Ok(n) = copy_result {
|
||||
if n != amount_to_read {
|
||||
io::Result::Err(io::Error::new(io::ErrorKind::UnexpectedEof, ""))
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
} else {
|
||||
io::Result::Err(copy_result.unwrap_err())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -301,8 +298,7 @@ impl OutputTrait for Output<io::Stdout> {
|
|||
|
||||
// stdout is not seekable, so we just write null bytes.
|
||||
if let Some(amt) = seek {
|
||||
let bytes = vec![b'\0'; amt];
|
||||
dst.write_all(&bytes)
|
||||
io::copy(&mut io::repeat(0u8).take(amt as u64), &mut dst)
|
||||
.map_err_context(|| String::from("write error"))?;
|
||||
}
|
||||
|
||||
|
@ -526,7 +522,7 @@ impl OutputTrait for Output<File> {
|
|||
// Instead, we suppress the error by calling
|
||||
// `Result::ok()`. This matches the behavior of GNU `dd`
|
||||
// when given the command-line argument `of=/dev/null`.
|
||||
let i = seek.unwrap_or(0).try_into().unwrap();
|
||||
let i = seek.unwrap_or(0);
|
||||
if !cflags.notrunc {
|
||||
dst.set_len(i).ok();
|
||||
}
|
||||
|
@ -658,15 +654,14 @@ fn calc_loop_bsize(
|
|||
) -> usize {
|
||||
match count {
|
||||
Some(CountType::Reads(rmax)) => {
|
||||
let rmax: u64 = (*rmax).try_into().unwrap();
|
||||
let rsofar = rstat.reads_complete + rstat.reads_partial;
|
||||
let rremain: usize = (rmax - rsofar).try_into().unwrap();
|
||||
cmp::min(ideal_bsize, rremain * ibs)
|
||||
let rremain = rmax - rsofar;
|
||||
cmp::min(ideal_bsize as u64, rremain * ibs as u64) as usize
|
||||
}
|
||||
Some(CountType::Bytes(bmax)) => {
|
||||
let bmax: u128 = (*bmax).try_into().unwrap();
|
||||
let bremain: usize = (bmax - wstat.bytes_total).try_into().unwrap();
|
||||
cmp::min(ideal_bsize, bremain)
|
||||
let bremain: u128 = bmax - wstat.bytes_total;
|
||||
cmp::min(ideal_bsize as u128, bremain as u128) as usize
|
||||
}
|
||||
None => ideal_bsize,
|
||||
}
|
||||
|
@ -677,7 +672,7 @@ fn calc_loop_bsize(
|
|||
fn below_count_limit(count: &Option<CountType>, rstat: &ReadStat, wstat: &WriteStat) -> bool {
|
||||
match count {
|
||||
Some(CountType::Reads(n)) => {
|
||||
let n = (*n).try_into().unwrap();
|
||||
let n = *n;
|
||||
rstat.reads_complete + rstat.reads_partial <= n
|
||||
}
|
||||
Some(CountType::Bytes(n)) => {
|
||||
|
|
|
@ -31,6 +31,10 @@ pub enum ParseError {
|
|||
BlockUnblockWithoutCBS,
|
||||
StatusLevelNotRecognized(String),
|
||||
Unimplemented(String),
|
||||
BsOutOfRange,
|
||||
IbsOutOfRange,
|
||||
ObsOutOfRange,
|
||||
CbsOutOfRange,
|
||||
}
|
||||
|
||||
impl ParseError {
|
||||
|
@ -48,6 +52,10 @@ impl ParseError {
|
|||
Self::BlockUnblockWithoutCBS => Self::BlockUnblockWithoutCBS,
|
||||
Self::StatusLevelNotRecognized(_) => Self::StatusLevelNotRecognized(s),
|
||||
Self::Unimplemented(_) => Self::Unimplemented(s),
|
||||
Self::BsOutOfRange => Self::BsOutOfRange,
|
||||
Self::IbsOutOfRange => Self::IbsOutOfRange,
|
||||
Self::ObsOutOfRange => Self::ObsOutOfRange,
|
||||
Self::CbsOutOfRange => Self::CbsOutOfRange,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -92,6 +100,18 @@ impl std::fmt::Display for ParseError {
|
|||
Self::StatusLevelNotRecognized(arg) => {
|
||||
write!(f, "status=LEVEL not recognized -> {}", arg)
|
||||
}
|
||||
ParseError::BsOutOfRange => {
|
||||
write!(f, "bs=N cannot fit into memory")
|
||||
}
|
||||
ParseError::IbsOutOfRange => {
|
||||
write!(f, "ibs=N cannot fit into memory")
|
||||
}
|
||||
ParseError::ObsOutOfRange => {
|
||||
write!(f, "ibs=N cannot fit into memory")
|
||||
}
|
||||
ParseError::CbsOutOfRange => {
|
||||
write!(f, "cbs=N cannot fit into memory")
|
||||
}
|
||||
Self::Unimplemented(arg) => {
|
||||
write!(f, "feature not implemented on this system -> {}", arg)
|
||||
}
|
||||
|
@ -334,7 +354,7 @@ fn show_zero_multiplier_warning() {
|
|||
}
|
||||
|
||||
/// Parse bytes using str::parse, then map error if needed.
|
||||
fn parse_bytes_only(s: &str) -> Result<usize, ParseError> {
|
||||
fn parse_bytes_only(s: &str) -> Result<u64, ParseError> {
|
||||
s.parse()
|
||||
.map_err(|_| ParseError::MultiplierStringParseFailure(s.to_string()))
|
||||
}
|
||||
|
@ -364,7 +384,7 @@ fn parse_bytes_only(s: &str) -> Result<usize, ParseError> {
|
|||
/// assert_eq!(parse_bytes_no_x("2b").unwrap(), 2 * 512);
|
||||
/// assert_eq!(parse_bytes_no_x("2k").unwrap(), 2 * 1024);
|
||||
/// ```
|
||||
fn parse_bytes_no_x(s: &str) -> Result<usize, ParseError> {
|
||||
fn parse_bytes_no_x(s: &str) -> Result<u64, ParseError> {
|
||||
let (num, multiplier) = match (s.find('c'), s.rfind('w'), s.rfind('b')) {
|
||||
(None, None, None) => match uucore::parse_size::parse_size(s) {
|
||||
Ok(n) => (n, 1),
|
||||
|
@ -387,7 +407,7 @@ fn parse_bytes_no_x(s: &str) -> Result<usize, ParseError> {
|
|||
/// Parse byte and multiplier like 512, 5KiB, or 1G.
|
||||
/// Uses uucore::parse_size, and adds the 'w' and 'c' suffixes which are mentioned
|
||||
/// in dd's info page.
|
||||
fn parse_bytes_with_opt_multiplier(s: &str) -> Result<usize, ParseError> {
|
||||
fn parse_bytes_with_opt_multiplier(s: &str) -> Result<u64, ParseError> {
|
||||
// TODO On my Linux system, there seems to be a maximum block size of 4096 bytes:
|
||||
//
|
||||
// $ printf "%0.sa" {1..10000} | dd bs=4095 count=1 status=none | wc -c
|
||||
|
@ -420,9 +440,27 @@ fn parse_bytes_with_opt_multiplier(s: &str) -> Result<usize, ParseError> {
|
|||
|
||||
pub fn parse_ibs(matches: &Matches) -> Result<usize, ParseError> {
|
||||
if let Some(mixed_str) = matches.value_of(options::BS) {
|
||||
parse_bytes_with_opt_multiplier(mixed_str)
|
||||
parse_bytes_with_opt_multiplier(mixed_str)?
|
||||
.try_into()
|
||||
.map_err(|_| ParseError::BsOutOfRange)
|
||||
} else if let Some(mixed_str) = matches.value_of(options::IBS) {
|
||||
parse_bytes_with_opt_multiplier(mixed_str)
|
||||
parse_bytes_with_opt_multiplier(mixed_str)?
|
||||
.try_into()
|
||||
.map_err(|_| ParseError::IbsOutOfRange)
|
||||
} else {
|
||||
Ok(512)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parse_obs(matches: &Matches) -> Result<usize, ParseError> {
|
||||
if let Some(mixed_str) = matches.value_of("bs") {
|
||||
parse_bytes_with_opt_multiplier(mixed_str)?
|
||||
.try_into()
|
||||
.map_err(|_| ParseError::BsOutOfRange)
|
||||
} else if let Some(mixed_str) = matches.value_of("obs") {
|
||||
parse_bytes_with_opt_multiplier(mixed_str)?
|
||||
.try_into()
|
||||
.map_err(|_| ParseError::ObsOutOfRange)
|
||||
} else {
|
||||
Ok(512)
|
||||
}
|
||||
|
@ -430,7 +468,9 @@ pub fn parse_ibs(matches: &Matches) -> Result<usize, ParseError> {
|
|||
|
||||
fn parse_cbs(matches: &Matches) -> Result<Option<usize>, ParseError> {
|
||||
if let Some(s) = matches.value_of(options::CBS) {
|
||||
let bytes = parse_bytes_with_opt_multiplier(s)?;
|
||||
let bytes = parse_bytes_with_opt_multiplier(s)?
|
||||
.try_into()
|
||||
.map_err(|_| ParseError::CbsOutOfRange)?;
|
||||
Ok(Some(bytes))
|
||||
} else {
|
||||
Ok(None)
|
||||
|
@ -447,16 +487,6 @@ pub(crate) fn parse_status_level(matches: &Matches) -> Result<Option<StatusLevel
|
|||
}
|
||||
}
|
||||
|
||||
pub fn parse_obs(matches: &Matches) -> Result<usize, ParseError> {
|
||||
if let Some(mixed_str) = matches.value_of("bs") {
|
||||
parse_bytes_with_opt_multiplier(mixed_str)
|
||||
} else if let Some(mixed_str) = matches.value_of("obs") {
|
||||
parse_bytes_with_opt_multiplier(mixed_str)
|
||||
} else {
|
||||
Ok(512)
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_ctable(fmt: Option<ConvFlag>, case: Option<ConvFlag>) -> Option<&'static ConversionTable> {
|
||||
fn parse_conv_and_case_table(
|
||||
fmt: &ConvFlag,
|
||||
|
@ -715,13 +745,13 @@ pub fn parse_skip_amt(
|
|||
ibs: &usize,
|
||||
iflags: &IFlags,
|
||||
matches: &Matches,
|
||||
) -> Result<Option<usize>, ParseError> {
|
||||
) -> Result<Option<u64>, ParseError> {
|
||||
if let Some(amt) = matches.value_of(options::SKIP) {
|
||||
let n = parse_bytes_with_opt_multiplier(amt)?;
|
||||
if iflags.skip_bytes {
|
||||
Ok(Some(n))
|
||||
} else {
|
||||
Ok(Some(ibs * n))
|
||||
Ok(Some(*ibs as u64 * n))
|
||||
}
|
||||
} else {
|
||||
Ok(None)
|
||||
|
@ -733,13 +763,13 @@ pub fn parse_seek_amt(
|
|||
obs: &usize,
|
||||
oflags: &OFlags,
|
||||
matches: &Matches,
|
||||
) -> Result<Option<usize>, ParseError> {
|
||||
) -> Result<Option<u64>, ParseError> {
|
||||
if let Some(amt) = matches.value_of(options::SEEK) {
|
||||
let n = parse_bytes_with_opt_multiplier(amt)?;
|
||||
if oflags.seek_bytes {
|
||||
Ok(Some(n))
|
||||
} else {
|
||||
Ok(Some(obs * n))
|
||||
Ok(Some(*obs as u64 * n))
|
||||
}
|
||||
} else {
|
||||
Ok(None)
|
||||
|
|
Loading…
Reference in a new issue