From d97672dfd3197de9148c6aa259c582147b6ee21f Mon Sep 17 00:00:00 2001 From: Tyler Date: Tue, 27 Apr 2021 12:21:35 -0700 Subject: [PATCH] Continues impl - Completes impl of skip=N, and seek=N - Parses cbs=N --- src/uu/dd/src/dd.rs | 48 +++++++++--- src/uu/dd/src/dd_test.rs | 8 ++ src/uu/dd/src/parseargs.rs | 70 +++++++++++++----- src/uu/dd/src/parseargs/test.rs | 8 +- .../test-resources/seq-byte-values-odd.spec | Bin 0 -> 257 bytes .../test-resources/seq-byte-values-odd.test | Bin 0 -> 257 bytes src/uu/dd/test-resources/seq-byte-values.test | Bin 0 -> 256 bytes 7 files changed, 101 insertions(+), 33 deletions(-) create mode 100644 src/uu/dd/test-resources/seq-byte-values-odd.spec create mode 100644 src/uu/dd/test-resources/seq-byte-values-odd.test create mode 100644 src/uu/dd/test-resources/seq-byte-values.test diff --git a/src/uu/dd/src/dd.rs b/src/uu/dd/src/dd.rs index 4efa156ab..f36ac487b 100644 --- a/src/uu/dd/src/dd.rs +++ b/src/uu/dd/src/dd.rs @@ -36,6 +36,7 @@ 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 RTN_SUCCESS: i32 = 0; const RTN_FAILURE: i32 = 1; @@ -51,6 +52,7 @@ enum SrcStat pub struct IConvFlags { ctable: Option<&'static ConversionTable>, + cbs: Option, block: bool, unblock: bool, swab: bool, @@ -131,7 +133,12 @@ enum InternalError impl std::fmt::Display for InternalError { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "Internal dd error") + match self + { + Self::WrongInputType | + Self::WrongOutputType => + write!(f, "Internal dd error"), + } } } @@ -184,7 +191,7 @@ impl Input let xfer_stats = parseargs::parse_status_level(matches)?; let cflags = parseargs::parse_conv_flag_input(matches)?; let iflags = parseargs::parse_iflags(matches)?; - let skip = parseargs::parse_skip_amt(matches)?; + let skip = parseargs::parse_skip_amt(&ibs, &iflags, matches)?; let mut i = Input { src: io::stdin(), @@ -194,10 +201,11 @@ impl Input iflags, }; - if let Some(skip_amt) = skip + if let Some(amt) = skip { - let mut buf = vec![DEFAULT_FILL_BYTE; skip_amt]; - i.read(&mut buf)?; + let mut buf = vec![DEFAULT_FILL_BYTE; amt]; + + i.force_fill(&mut buf, amt)?; } Ok(i) @@ -212,16 +220,16 @@ impl Input let xfer_stats = parseargs::parse_status_level(matches)?; let cflags = parseargs::parse_conv_flag_input(matches)?; let iflags = parseargs::parse_iflags(matches)?; - let skip = parseargs::parse_skip_amt(matches)?; + let skip = parseargs::parse_skip_amt(&ibs, &iflags, matches)?; if let Some(fname) = matches.opt_str("if") { let mut src = File::open(fname)?; - if let Some(skip_amt) = skip + if let Some(amt) = skip { - let skip_amt: u64 = skip_amt.try_into()?; - src.seek(io::SeekFrom::Start(skip_amt))?; + let amt: u64 = amt.try_into()?; + src.seek(io::SeekFrom::Start(amt))?; } let i = Input { @@ -266,6 +274,21 @@ impl Input Ok(SrcStat::EOF) } } + + fn force_fill(&mut self, mut buf: &mut [u8], len: usize) -> Result<(), Box> + { + let mut total_len = 0; + + loop + { + total_len += self.read(&mut buf)?; + + if total_len == len + { + return Ok(()); + } + } + } } struct Output @@ -297,8 +320,8 @@ impl Output { { let obs = parseargs::parse_obs(matches)?; let cflags = parseargs::parse_conv_flag_output(matches)?; - let seek = parseargs::parse_seek_amt(matches)?; let oflags = parseargs::parse_oflags(matches)?; + let seek = parseargs::parse_seek_amt(&obs, &oflags, matches)?; if let Some(fname) = matches.opt_str("of") { @@ -308,9 +331,10 @@ impl Output { .truncate(!cflags.notrunc) .open(fname)?; - if let Some(seek_amt) = seek + if let Some(amt) = seek { - dst.seek(io::SeekFrom::Start(seek_amt))?; + let amt: u64 = amt.try_into()?; + dst.seek(io::SeekFrom::Start(amt))?; } Ok(Output { diff --git a/src/uu/dd/src/dd_test.rs b/src/uu/dd/src/dd_test.rs index 9dd1d1333..ee30b8907 100644 --- a/src/uu/dd/src/dd_test.rs +++ b/src/uu/dd/src/dd_test.rs @@ -65,6 +65,7 @@ macro_rules! icf ( { IConvFlags { ctable: $ctable, + cbs: None, block: false, unblock: false, swab: false, @@ -95,6 +96,7 @@ macro_rules! make_spec_test ( dst: File::create(format!("./test-resources/FAILED-{}.test", $test_name)).unwrap(), obs: 512, cflags: DEFAULT_CFO, + oflags: DEFAULT_OFLAGS, }, $spec, format!("./test-resources/FAILED-{}.test", $test_name) @@ -139,6 +141,7 @@ macro_rules! make_conv_test ( dst: File::create(format!("./test-resources/FAILED-{}.test", $test_name)).unwrap(), obs: 512, cflags: DEFAULT_CFO, + oflags: DEFAULT_OFLAGS, }, $spec, format!("./test-resources/FAILED-{}.test", $test_name) @@ -162,6 +165,7 @@ macro_rules! make_icf_test ( dst: File::create(format!("./test-resources/FAILED-{}.test", $test_name)).unwrap(), obs: 512, cflags: DEFAULT_CFO, + oflags: DEFAULT_OFLAGS, }, $spec, format!("./test-resources/FAILED-{}.test", $test_name) @@ -288,6 +292,7 @@ fn all_valid_ascii_ebcdic_ascii_roundtrip_conv_test() dst: File::create(&tmp_fname_ae).unwrap(), obs: 1024, cflags: DEFAULT_CFO, + oflags: DEFAULT_OFLAGS, }; dd_fileout(i,o).unwrap(); @@ -308,6 +313,7 @@ fn all_valid_ascii_ebcdic_ascii_roundtrip_conv_test() dst: File::create(&tmp_fname_ea).unwrap(), obs: 1024, cflags: DEFAULT_CFO, + oflags: DEFAULT_OFLAGS, }; dd_fileout(i,o).unwrap(); @@ -337,6 +343,7 @@ make_icf_test!( File::open("./test-resources/seq-byte-values.test").unwrap(), IConvFlags { ctable: None, + cbs: None, block: false, unblock: false, swab: true, @@ -352,6 +359,7 @@ make_icf_test!( File::open("./test-resources/seq-byte-values-odd.test").unwrap(), IConvFlags { ctable: None, + cbs: None, block: false, unblock: false, swab: true, diff --git a/src/uu/dd/src/parseargs.rs b/src/uu/dd/src/parseargs.rs index 4605bf6cf..b18054f14 100644 --- a/src/uu/dd/src/parseargs.rs +++ b/src/uu/dd/src/parseargs.rs @@ -23,7 +23,7 @@ pub enum ParseError FlagNoMatch(String), ConvFlagNoMatch(String), NoMatchingMultiplier(String), - MultiplierStringContainsNoValue(String), + ByteStringContainsNoValue(String), MultiplierStringWouldOverflow(String), } @@ -235,15 +235,21 @@ fn parse_multiplier<'a>(s: &'a str) -> Result } } +fn parse_bytes_only(s: &str) -> Result +{ + let bytes: usize = match s.parse() + { + Ok(val) => val, + Err(_) => return Err(ParseError::ByteStringContainsNoValue(String::from(s))), + }; + Ok(bytes) +} + fn parse_bytes_with_opt_multiplier(s: String) -> Result { if let Some(idx) = s.find(char::is_alphabetic) { - let base: usize = match s[0..idx].parse() - { - Ok(val) => val, - Err(_) => return Err(ParseError::MultiplierStringContainsNoValue(s)), - }; + let base = parse_bytes_only(&s[0..idx])?; let mult = parse_multiplier(&s[idx..])?; if let Some(bytes) = base.checked_mul(mult) @@ -257,12 +263,7 @@ fn parse_bytes_with_opt_multiplier(s: String) -> Result } else { - let bytes: usize = match s.parse() - { - Ok(val) => val, - Err(_) => return Err(ParseError::MultiplierStringContainsNoValue(s)), - }; - Ok(bytes) + parse_bytes_only(&s) } } @@ -282,6 +283,19 @@ pub fn parse_ibs(matches: &getopts::Matches) -> Result } } +fn parse_cbs(matches: &getopts::Matches) -> Result, ParseError> +{ + if let Some(s) = matches.opt_str("cbs") + { + let bytes = parse_bytes_with_opt_multiplier(s)?; + Ok(Some(bytes)) + } + else + { + Ok(None) + } +} + pub fn parse_status_level(matches: &getopts::Matches) -> Result { // TODO: Impl @@ -371,6 +385,7 @@ fn parse_flag_list>(tag: &str, matches: & pub fn parse_conv_flag_input(matches: &getopts::Matches) -> Result { let flags = parse_flag_list("conv", matches)?; + let cbs = parse_cbs(matches)?; let mut fmt = None; let mut case = None; @@ -461,6 +476,7 @@ pub fn parse_conv_flag_input(matches: &getopts::Matches) -> Result Result } /// Parse the amount of the input file to skip. -pub fn parse_skip_amt(matches: &getopts::Matches) -> Result, ParseError> +pub fn parse_skip_amt(ibs: &usize, iflags: &IFlags, matches: &getopts::Matches) -> Result, ParseError> { - if let Some(skip_amt) = matches.opt_str("skip") + if let Some(amt) = matches.opt_str("skip") { - unimplemented!() + if iflags.skip_bytes + { + let n = parse_bytes_with_opt_multiplier(amt)?; + Ok(Some(n)) + } + else + { + let n = parse_bytes_only(&amt)?; + Ok(Some(ibs*n)) + } } else { @@ -704,11 +729,20 @@ pub fn parse_skip_amt(matches: &getopts::Matches) -> Result, Parse } /// Parse the amount of the output file to seek. -pub fn parse_seek_amt(matches: &getopts::Matches) -> Result, ParseError> +pub fn parse_seek_amt(obs: &usize, oflags: &OFlags, matches: &getopts::Matches) -> Result, ParseError> { - if let Some(seek_amt) = matches.opt_str("seek") + if let Some(amt) = matches.opt_str("seek") { - unimplemented!() + if oflags.seek_bytes + { + let n = parse_bytes_with_opt_multiplier(amt)?; + Ok(Some(n)) + } + else + { + let n = parse_bytes_only(&amt)?; + Ok(Some(obs*n)) + } } else { diff --git a/src/uu/dd/src/parseargs/test.rs b/src/uu/dd/src/parseargs/test.rs index 390622a12..5587c1c4b 100644 --- a/src/uu/dd/src/parseargs/test.rs +++ b/src/uu/dd/src/parseargs/test.rs @@ -14,6 +14,7 @@ fn build_icf() { let icf_expd = IConvFlags { ctable: Some(&ASCII_TO_IBM), + cbs: None, block: false, unblock: false, swab: false, @@ -103,7 +104,7 @@ fn parse_icf_token_ibm() ]; let matches = build_app!().parse(args); - let act = parse_conv_opts(&matches).unwrap(); + let act = parse_flag_list::("conv", &matches).unwrap(); assert_eq!(exp.len(), act.len()); for cf in &exp @@ -126,7 +127,7 @@ fn parse_icf_tokens_elu() String::from("--conv=ebcdic,lcase,unblock"), ]; let matches = build_app!().parse(args); - let act = parse_conv_opts(&matches).unwrap(); + let act = parse_flag_list::("conv", &matches).unwrap(); assert_eq!(exp.len(), act.len()); for cf in &exp @@ -159,7 +160,8 @@ fn parse_icf_tokens_remaining() String::from("--conv=ascii,ucase,block,sparse,swab,sync,noerror,excl,nocreat,notrunc,noerror,fdatasync,fsync"), ]; let matches = build_app!().parse(args); - let act = parse_conv_opts(&matches).unwrap(); + + let act = parse_flag_list::("conv", &matches).unwrap(); assert_eq!(exp.len(), act.len()); for cf in &exp diff --git a/src/uu/dd/test-resources/seq-byte-values-odd.spec b/src/uu/dd/test-resources/seq-byte-values-odd.spec new file mode 100644 index 0000000000000000000000000000000000000000..2952a28a1779ad29836d61704372bd9feea7e4a5 GIT binary patch literal 257 zcmZQ%U}j=vVQ1sy;O64x;pY<+5Ec>@5f_t`kd~5_k(X0cP*ze^QCHK{(ALt`(bqFH zFg7wZF*mccu(qcc@%IZ12o4Gj2@i{mh>nVliH}Q6NKQ&k zNl(kn$j-{m$aT7=F=93Ve+J@Q>IUw zIb-&$xpU^vTex8HqNPigFI%}{^{TaN*00;RVe_V~Teff8xnuXPy?gfWJ9yymp`%BR zA3J&C^r^FF&Y!z@;qs-cSFT^XdE@r2yLay2d-&k-qo+@vKYRJ&^{cmU-oN|!;q#}j SU%r3)`Q!JmzkmM!y9)p=MC+6cQE@6%&_`l#-T_m6KOcR8m$^Ra4i{)Y8_`)zddH zG%_|ZH8Z!cw6eCbwX=6{baHlab#wRd^z!!c_45x13RUz zF>}`JIdkXDU$Ah|;w4L$Enl&6)#^2C*R9{Mant54TeofBv2)k%J$v`MC+6cQE@6%&_`l#-T_m6KOcR8m$^Ra4i{)Y8_`)zddH zG%_|ZH8Z!cw6eCbwX=6{baHlab#wRd^z!!c_45x13RUz zF>}`JIdkXDU$Ah|;w4L$Enl&6)#^2C*R9{Mant54TeofBv2)k%J$v`