1
Fork 0
mirror of https://github.com/RGBCube/uutils-coreutils synced 2026-01-19 19:51:09 +00:00

Fixes bugs. Prepares for conv=sync

- Splits read fn into conv=sync and standard (consecutive)
  versions.
- Fixes bug in previous read/fill where short reads would copy to wrong
  position in output buffer.
- Fixes bug in unit tests. Empty source would pass (since no bytes
  failed to match).
This commit is contained in:
Tyler 2021-06-04 11:29:41 -07:00
parent 787b9696cb
commit f7eaf96eda
7 changed files with 117 additions and 62 deletions

View file

@ -36,27 +36,23 @@ const SYNTAX: &str = "dd [OPERAND]...\ndd OPTION";
const SUMMARY: &str = "convert, and optionally copy, a file";
const LONG_HELP: &str = "";
const DEFAULT_FILL_BYTE: u8 = 0xDD;
const DEFAULT_SKIP_TRIES: u8 = 3;
const DEFAULT_INIT_BYTE: u8 = 0xDD;
const RTN_SUCCESS: i32 = 0;
const RTN_FAILURE: i32 = 1;
// ----- Datatypes -----
enum SrcStat
{
Read(usize),
EOF,
}
type Cbs = usize;
/// Stores all Conv Flags that apply to the input
pub struct IConvFlags
{
ctable: Option<&'static ConversionTable>,
block: Option<usize>,
unblock: Option<usize>,
block: Option<Cbs>,
unblock: Option<Cbs>,
swab: bool,
sync: bool,
sync: Option<u8>,
noerror: bool,
}
@ -179,7 +175,7 @@ impl Input<io::Stdin>
if let Some(amt) = skip
{
let mut buf = vec![DEFAULT_FILL_BYTE; amt];
let mut buf = vec![DEFAULT_INIT_BYTE; amt];
i.force_fill(&mut buf, amt)?;
}
@ -233,43 +229,64 @@ impl<R: Read> Read for Input<R>
fn read(&mut self, mut buf: &mut [u8]) -> io::Result<usize>
{
// Read from source, ignore read errors if conv=noerror
let len = match self.src.read(&mut buf)
match self.src.read(&mut buf)
{
Ok(len) =>
len,
Ok(len),
Err(e) =>
if !self.cflags.noerror
{
return Err(e);
Err(e)
}
else
{
return Ok(0);
Ok(0)
},
};
Ok(len)
}
}
}
impl<R: Read> Input<R>
{
/// Fills to a given size n, which is expected to be 'obs'.
/// Fills a given obs-sized buffer.
/// Reads in increments of 'self.ibs'.
fn fill_n(&mut self, buf: &mut [u8], obs: usize) -> Result<usize, Box<dyn Error>>
fn fill_consecutive(&mut self, buf: &mut [u8]) -> Result<usize, Box<dyn Error>>
{
let mut base_idx = 0;
while base_idx < buf.len()
{
let low_idx = base_idx;
let up_idx = cmp::min(low_idx+self.ibs, buf.len()-1);
let rlen = self.read(&mut buf[low_idx..=up_idx])?;
if rlen > 0
{
base_idx += rlen;
}
else
{
break;
}
}
Ok(base_idx)
}
/// Fills a given obs-sized buffer.
/// Reads in increments of 'self.ibs'.
fn fill_blocks(&mut self, buf: &mut [u8]) -> Result<usize, Box<dyn Error>>
{
let ibs = self.ibs;
let obs = buf.len();
let mut bytes_read = 0;
// TODO: Fix this!
// assert!(obs < ibs);
for n in 0..(obs/ibs) {
for n in 0..cmp::max(obs/ibs, 1) {
// fill an ibs-len slice from src
let this_read = self.read(&mut buf[n*ibs..(n+1)*ibs])?;
let rlen = self.read(&mut buf[n*ibs..(n+1)*ibs])?;
if this_read != 0 {
bytes_read += this_read;
if rlen != 0 {
bytes_read += rlen;
} else {
break;
}
@ -691,13 +708,20 @@ fn read_write_helper<R: Read, W: Write>(i: &mut Input<R>, o: &mut Output<W>) ->
else
{
// Read
let mut buf = vec![DEFAULT_FILL_BYTE; o.obs];
let rlen = i.fill_n(&mut buf, o.obs)?;
buf.resize(rlen, DEFAULT_FILL_BYTE);
let mut buf = vec![DEFAULT_INIT_BYTE; o.obs];
let rlen = if let Some(ch) = i.cflags.sync
{
i.fill_blocks(&mut buf)?
}
else
{
i.fill_consecutive(&mut buf)?
};
buf.truncate(rlen);
if rlen == 0
{
return Ok((0,Vec::new()));
return Ok((0,buf));
}
// Conv etc...

View file

@ -18,7 +18,7 @@ macro_rules! make_block_test (
block: $block,
unblock: None,
swab: false,
sync: false,
sync: None,
noerror: false,
},
iflags: DEFAULT_IFLAGS,
@ -50,7 +50,7 @@ macro_rules! make_unblock_test (
block: None,
unblock: $unblock,
swab: false,
sync: false,
sync: None,
noerror: false,
},
iflags: DEFAULT_IFLAGS,

View file

@ -201,7 +201,7 @@ make_icf_test!(
block: None,
unblock: None,
swab: true,
sync: false,
sync: None,
noerror: false,
},
File::open("./test-resources/seq-byte-values-swapped.test").unwrap()
@ -216,7 +216,7 @@ make_icf_test!(
block: None,
unblock: None,
swab: true,
sync: false,
sync: None,
noerror: false,
},
File::open("./test-resources/seq-byte-values-odd.spec").unwrap()

View file

@ -3,6 +3,7 @@ use super::*;
mod sanity_tests;
mod conversion_tests;
mod block_unblock_tests;
mod conv_sync_tests;
use std::io::prelude::*;
use std::io::BufReader;
@ -72,7 +73,7 @@ macro_rules! icf (
block: None,
unblock: None,
swab: false,
sync: false,
sync: None,
noerror: false,
}
};
@ -115,9 +116,10 @@ macro_rules! make_spec_test (
dd_fileout($i,$o).unwrap();
let res = File::open($tmp_fname).unwrap();
let res = BufReader::new(res);
assert_eq!(res.metadata().unwrap().len(), $spec.metadata().unwrap().len());
let spec = BufReader::new($spec);
let res = BufReader::new(res);
for (b_res, b_spec) in res.bytes().zip(spec.bytes())
{

View file

@ -23,3 +23,45 @@ make_spec_test!(
"random-73k",
File::open("./test-resources/random-5828891cb1230748e146f34223bbd3b5.test").unwrap()
);
make_spec_test!(
random_73k_test_not_a_multiple_obs_gt_ibs,
"random-73k-not-a-multiple-obs-gt-ibs",
Input {
src: File::open("./test-resources/random-5828891cb1230748e146f34223bbd3b5.test").unwrap(),
non_ascii: false,
ibs: 521,
xfer_stats: StatusLevel::None,
cflags: icf!(),
iflags: DEFAULT_IFLAGS,
},
Output {
dst: File::create(format!("./test-resources/FAILED-{}.test", "random-73k-not-a-multiple-obs-gt-ibs")).unwrap(),
obs: 1031,
cflags: DEFAULT_CFO,
oflags: DEFAULT_OFLAGS,
},
File::open("./test-resources/random-5828891cb1230748e146f34223bbd3b5.test").unwrap(),
format!("./test-resources/FAILED-{}.test", "random-73k-not-a-multiple-obs-gt-ibs")
);
make_spec_test!(
random_73k_test_obs_lt_not_a_multiple_ibs,
"random-73k-obs-lt-not-a-multiple-ibs",
Input {
src: File::open("./test-resources/random-5828891cb1230748e146f34223bbd3b5.test").unwrap(),
non_ascii: false,
ibs: 1031,
xfer_stats: StatusLevel::None,
cflags: icf!(),
iflags: DEFAULT_IFLAGS,
},
Output {
dst: File::create(format!("./test-resources/FAILED-{}.test", "random-73k-obs-lt-not-a-multiple-ibs")).unwrap(),
obs: 521,
cflags: DEFAULT_CFO,
oflags: DEFAULT_OFLAGS,
},
File::open("./test-resources/random-5828891cb1230748e146f34223bbd3b5.test").unwrap(),
format!("./test-resources/FAILED-{}.test", "random-73k-obs-lt-not-a-multiple-ibs")
);

View file

@ -475,6 +475,18 @@ pub fn parse_conv_flag_input(matches: &getopts::Matches) -> Result<IConvFlags, P
}
let ctable = parse_ctable(fmt, case);
let sync = if sync && (block.is_some() || unblock.is_some())
{
Some(' ' as u8)
}
else if sync
{
Some(0u8)
}
else
{
None
};
Ok(IConvFlags {
ctable,

View file

@ -9,31 +9,6 @@ use crate::{
// ----- IConvFlags/Output -----
#[test]
fn build_icf()
{
let icf_expd = IConvFlags {
ctable: Some(&ASCII_TO_IBM),
block: None,
unblock: None,
swab: false,
sync: false,
noerror: false,
};
let args = vec![
String::from("dd"),
String::from("--conv=ibm"),
];
let matches = build_app!().parse(args);
let icf_parsed = parse_conv_flag_input(&matches).unwrap();
unimplemented!()
// assert_eq!(icf_expd, icf_parsed);
}
#[test]
#[should_panic]
fn icf_ctable_error()