diff --git a/src/uu/dd/src/dd.rs b/src/uu/dd/src/dd.rs index b9c7078e3..b02c21acb 100644 --- a/src/uu/dd/src/dd.rs +++ b/src/uu/dd/src/dd.rs @@ -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, - unblock: Option, + block: Option, + unblock: Option, swab: bool, - sync: bool, + sync: Option, noerror: bool, } @@ -179,7 +175,7 @@ impl Input 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 Read for Input fn read(&mut self, mut buf: &mut [u8]) -> io::Result { // 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 Input { - /// 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> + fn fill_consecutive(&mut self, buf: &mut [u8]) -> Result> + { + 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> { 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(i: &mut Input, o: &mut Output) -> 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... diff --git a/src/uu/dd/src/dd_unit_tests/block_unblock_tests.rs b/src/uu/dd/src/dd_unit_tests/block_unblock_tests.rs index 238765888..241088e63 100644 --- a/src/uu/dd/src/dd_unit_tests/block_unblock_tests.rs +++ b/src/uu/dd/src/dd_unit_tests/block_unblock_tests.rs @@ -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, diff --git a/src/uu/dd/src/dd_unit_tests/conversion_tests.rs b/src/uu/dd/src/dd_unit_tests/conversion_tests.rs index 9652a6b76..521dd11f4 100644 --- a/src/uu/dd/src/dd_unit_tests/conversion_tests.rs +++ b/src/uu/dd/src/dd_unit_tests/conversion_tests.rs @@ -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() diff --git a/src/uu/dd/src/dd_unit_tests/mod.rs b/src/uu/dd/src/dd_unit_tests/mod.rs index faeb13e20..7e654ec14 100644 --- a/src/uu/dd/src/dd_unit_tests/mod.rs +++ b/src/uu/dd/src/dd_unit_tests/mod.rs @@ -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()) { diff --git a/src/uu/dd/src/dd_unit_tests/sanity_tests.rs b/src/uu/dd/src/dd_unit_tests/sanity_tests.rs index b772d6a27..f7a7ec448 100644 --- a/src/uu/dd/src/dd_unit_tests/sanity_tests.rs +++ b/src/uu/dd/src/dd_unit_tests/sanity_tests.rs @@ -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") +); diff --git a/src/uu/dd/src/parseargs.rs b/src/uu/dd/src/parseargs.rs index 5af5d0cce..f115a6a2c 100644 --- a/src/uu/dd/src/parseargs.rs +++ b/src/uu/dd/src/parseargs.rs @@ -475,6 +475,18 @@ pub fn parse_conv_flag_input(matches: &getopts::Matches) -> Result