mirror of
https://github.com/RGBCube/uutils-coreutils
synced 2025-07-29 03:57:44 +00:00
Builds out arg parsing. Adds support for if, of, & multiplier strings)
- Adds support for calling dd fn from cl - Adds basic cl tests from project root - Adds support for multiplier strings (c, w, b, kB, KB, KiB, ... EB, E, EiB.
This commit is contained in:
parent
0df457596c
commit
4996308753
6 changed files with 891 additions and 341 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -1593,6 +1593,7 @@ dependencies = [
|
||||||
name = "uu_dd"
|
name = "uu_dd"
|
||||||
version = "0.0.4"
|
version = "0.0.4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"getopts 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"hex-literal 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"hex-literal 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"md-5 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"md-5 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"rand 0.8.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
"rand 0.8.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
|
|
@ -17,6 +17,8 @@ path = "src/dd.rs"
|
||||||
[dependencies]
|
[dependencies]
|
||||||
uucore = { version=">=0.0.7", package="uucore", path="../../uucore" }
|
uucore = { version=">=0.0.7", package="uucore", path="../../uucore" }
|
||||||
uucore_procs = { version=">=0.0.5", package="uucore_procs", path="../../uucore_procs" }
|
uucore_procs = { version=">=0.0.5", package="uucore_procs", path="../../uucore_procs" }
|
||||||
|
# Probably best to keep this identical to the version of getopts in the uucore crate
|
||||||
|
getopts = "<= 0.2.21"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
md-5 = "0.9"
|
md-5 = "0.9"
|
||||||
|
|
|
@ -10,28 +10,35 @@
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate uucore;
|
extern crate uucore;
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test_dd_internal;
|
||||||
|
|
||||||
|
mod ddargs;
|
||||||
|
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::{
|
use std::io::{
|
||||||
self, Read, Write,
|
self, Read, Write,
|
||||||
BufWriter,
|
|
||||||
};
|
};
|
||||||
use std::sync::mpsc;
|
use std::sync::mpsc;
|
||||||
use std::thread;
|
use std::thread;
|
||||||
|
use getopts;
|
||||||
|
|
||||||
const NAME: &str = "dd";
|
const NAME: &str = "dd";
|
||||||
const SUMMARY: &str = "Copies, and optionally converts, file system resources.";
|
const SUMMARY: &str = "convert and copy a file";
|
||||||
const LONG_HELP: &str = "TODO: This is where the long help string for dd goes!";
|
const LONG_HELP: &str = "TODO: This is where the long help string for dd goes!";
|
||||||
|
|
||||||
const RTN_SUCCESS: i32 = 0;
|
const RTN_SUCCESS: i32 = 0;
|
||||||
const RTN_FAILURE: i32 = 1;
|
const RTN_FAILURE: i32 = 1;
|
||||||
|
|
||||||
|
// ----- Conversion -----
|
||||||
|
//
|
||||||
// Conversion tables are just lookup tables.
|
// Conversion tables are just lookup tables.
|
||||||
// eg. The ASCII->EBCDIC table stores the EBCDIC code at the index
|
// eg. The ASCII->EBCDIC table stores the EBCDIC code at the index
|
||||||
// obtained by treating the ASCII representation as a number.
|
// obtained by treating the ASCII representation as a number.
|
||||||
type ConversionTable = [u8; 256];
|
type ConversionTable = [u8; 256];
|
||||||
|
|
||||||
const ascii_to_ebcdic: ConversionTable = [
|
const ASCII_TO_EBCDIC: ConversionTable = [
|
||||||
0x00, 0x01, 0x02, 0x03, 0x37, 0x2d, 0x2e, 0x2f, 0x16, 0x05, 0x25, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
0x00, 0x01, 0x02, 0x03, 0x37, 0x2d, 0x2e, 0x2f, 0x16, 0x05, 0x25, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
||||||
0x10, 0x11, 0x12, 0x13, 0x3c, 0x3d, 0x32, 0x26, 0x18, 0x19, 0x3f, 0x27, 0x1c, 0x1d, 0x1e, 0x1f,
|
0x10, 0x11, 0x12, 0x13, 0x3c, 0x3d, 0x32, 0x26, 0x18, 0x19, 0x3f, 0x27, 0x1c, 0x1d, 0x1e, 0x1f,
|
||||||
0x40, 0x5a, 0x7f, 0x7b, 0x5b, 0x6c, 0x50, 0x7d, 0x4d, 0x5d, 0x5c, 0x4e, 0x6b, 0x60, 0x4b, 0x61,
|
0x40, 0x5a, 0x7f, 0x7b, 0x5b, 0x6c, 0x50, 0x7d, 0x4d, 0x5d, 0x5c, 0x4e, 0x6b, 0x60, 0x4b, 0x61,
|
||||||
|
@ -50,7 +57,7 @@ const ascii_to_ebcdic: ConversionTable = [
|
||||||
0xdc, 0xdd, 0xde, 0xdf, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff,
|
0xdc, 0xdd, 0xde, 0xdf, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff,
|
||||||
];
|
];
|
||||||
|
|
||||||
const ascii_to_ibm: ConversionTable = [
|
const ASCII_TO_IBM: ConversionTable = [
|
||||||
0x00, 0x01, 0x02, 0x03, 0x37, 0x2d, 0x2e, 0x2f, 0x16, 0x05, 0x25, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
0x00, 0x01, 0x02, 0x03, 0x37, 0x2d, 0x2e, 0x2f, 0x16, 0x05, 0x25, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
||||||
0x10, 0x11, 0x12, 0x13, 0x3c, 0x3d, 0x32, 0x26, 0x18, 0x19, 0x3f, 0x27, 0x1c, 0x1d, 0x1e, 0x1f,
|
0x10, 0x11, 0x12, 0x13, 0x3c, 0x3d, 0x32, 0x26, 0x18, 0x19, 0x3f, 0x27, 0x1c, 0x1d, 0x1e, 0x1f,
|
||||||
0x40, 0x5a, 0x7f, 0x7b, 0x5b, 0x6c, 0x50, 0x7d, 0x4d, 0x5d, 0x5c, 0x4e, 0x6b, 0x60, 0x4b, 0x61,
|
0x40, 0x5a, 0x7f, 0x7b, 0x5b, 0x6c, 0x50, 0x7d, 0x4d, 0x5d, 0x5c, 0x4e, 0x6b, 0x60, 0x4b, 0x61,
|
||||||
|
@ -69,7 +76,7 @@ const ascii_to_ibm: ConversionTable = [
|
||||||
0xdc, 0xdd, 0xde, 0xdf, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff,
|
0xdc, 0xdd, 0xde, 0xdf, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff,
|
||||||
];
|
];
|
||||||
|
|
||||||
const ebcdic_to_ascii: ConversionTable = [
|
const EBCDIC_TO_ASCII: ConversionTable = [
|
||||||
0x00, 0x01, 0x02, 0x03, 0x9c, 0x09, 0x86, 0x7f, 0x97, 0x8d, 0x8e, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
0x00, 0x01, 0x02, 0x03, 0x9c, 0x09, 0x86, 0x7f, 0x97, 0x8d, 0x8e, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
||||||
0x10, 0x11, 0x12, 0x13, 0x9d, 0x85, 0x08, 0x87, 0x18, 0x19, 0x92, 0x8f, 0x1c, 0x1d, 0x1e, 0x1f,
|
0x10, 0x11, 0x12, 0x13, 0x9d, 0x85, 0x08, 0x87, 0x18, 0x19, 0x92, 0x8f, 0x1c, 0x1d, 0x1e, 0x1f,
|
||||||
0x80, 0x81, 0x82, 0x83, 0x84, 0x0a, 0x17, 0x1b, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x05, 0x06, 0x07,
|
0x80, 0x81, 0x82, 0x83, 0x84, 0x0a, 0x17, 0x1b, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x05, 0x06, 0x07,
|
||||||
|
@ -88,7 +95,7 @@ const ebcdic_to_ascii: ConversionTable = [
|
||||||
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff,
|
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff,
|
||||||
];
|
];
|
||||||
|
|
||||||
const lcase_to_ucase: ConversionTable = [
|
const LCASE_TO_UCASE: ConversionTable = [
|
||||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
||||||
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
|
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
|
||||||
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
|
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
|
||||||
|
@ -108,7 +115,7 @@ const lcase_to_ucase: ConversionTable = [
|
||||||
|
|
||||||
];
|
];
|
||||||
|
|
||||||
const ucase_to_lcase: ConversionTable = [
|
const UCASE_TO_LCASE: ConversionTable = [
|
||||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
||||||
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
|
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
|
||||||
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
|
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
|
||||||
|
@ -127,13 +134,29 @@ const ucase_to_lcase: ConversionTable = [
|
||||||
0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff,
|
0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff,
|
||||||
];
|
];
|
||||||
|
|
||||||
// ----- Datatypes -----
|
// ----- Types -----
|
||||||
enum SrcStat
|
enum SrcStat
|
||||||
{
|
{
|
||||||
Read(usize),
|
Read(usize),
|
||||||
EOF,
|
EOF,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
enum InternalError
|
||||||
|
{
|
||||||
|
WrongInputType,
|
||||||
|
WrongOutputType,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::fmt::Display for InternalError
|
||||||
|
{
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
write!(f, "Internal dd error")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Error for InternalError {}
|
||||||
|
|
||||||
struct Input<R: Read>
|
struct Input<R: Read>
|
||||||
{
|
{
|
||||||
src: R,
|
src: R,
|
||||||
|
@ -149,6 +172,47 @@ impl<R: Read> Read for Input<R>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Input<io::Stdin>
|
||||||
|
{
|
||||||
|
fn new(matches: &getopts::Matches) -> Result<Self, Box<dyn Error>>
|
||||||
|
{
|
||||||
|
let ibs: usize = ddargs::parse_ibs(matches)?;
|
||||||
|
let output_progress = ddargs::parse_progress_level(matches)?;
|
||||||
|
|
||||||
|
Ok(
|
||||||
|
Input {
|
||||||
|
src: io::stdin(),
|
||||||
|
ibs,
|
||||||
|
output_progress,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Input<File>
|
||||||
|
{
|
||||||
|
fn new(matches: &getopts::Matches) -> Result<Self, Box<dyn Error>>
|
||||||
|
{
|
||||||
|
let ibs: usize = ddargs::parse_ibs(matches)?;
|
||||||
|
let output_progress = ddargs::parse_progress_level(matches)?;
|
||||||
|
|
||||||
|
if let Some(fname) = matches.opt_str("if")
|
||||||
|
{
|
||||||
|
Ok(Input {
|
||||||
|
src: File::open(fname)?,
|
||||||
|
ibs,
|
||||||
|
output_progress,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Err(Box::new(InternalError::WrongInputType))
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<R: Read> Input<R>
|
impl<R: Read> Input<R>
|
||||||
{
|
{
|
||||||
fn fill_n(&mut self, buf: &mut [u8], obs: usize) -> Result<SrcStat, Box<dyn Error>>
|
fn fill_n(&mut self, buf: &mut [u8], obs: usize) -> Result<SrcStat, Box<dyn Error>>
|
||||||
|
@ -182,6 +246,43 @@ struct Output<W: Write>
|
||||||
conv_table: Option<ConversionTable>,
|
conv_table: Option<ConversionTable>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Output<io::Stdout> {
|
||||||
|
fn new(matches: &getopts::Matches) -> Result<Self, Box<dyn Error>>
|
||||||
|
{
|
||||||
|
let obs: usize = ddargs::parse_obs(matches)?;
|
||||||
|
let conv_table = ddargs::parse_conv_table(matches)?;
|
||||||
|
|
||||||
|
Ok(
|
||||||
|
Output {
|
||||||
|
dst: io::stdout(),
|
||||||
|
obs,
|
||||||
|
conv_table,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Output<File> {
|
||||||
|
fn new(matches: &getopts::Matches) -> Result<Self, Box<dyn Error>>
|
||||||
|
{
|
||||||
|
let obs: usize = ddargs::parse_obs(matches)?;
|
||||||
|
let conv_table = ddargs::parse_conv_table(matches)?;
|
||||||
|
|
||||||
|
if let Some(fname) = matches.opt_str("if")
|
||||||
|
{
|
||||||
|
Ok(Output {
|
||||||
|
dst: File::open(fname)?,
|
||||||
|
obs,
|
||||||
|
conv_table,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Err(Box::new(InternalError::WrongOutputType))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<W: Write> Write for Output<W>
|
impl<W: Write> Write for Output<W>
|
||||||
{
|
{
|
||||||
fn write(&mut self, buf: &[u8]) -> io::Result<usize>
|
fn write(&mut self, buf: &[u8]) -> io::Result<usize>
|
||||||
|
@ -209,10 +310,9 @@ impl<W: Write> Write for Output<W>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----- Implementation -----
|
|
||||||
fn gen_prog_updater(rx: mpsc::Receiver<usize>) -> impl Fn() -> ()
|
fn gen_prog_updater(rx: mpsc::Receiver<usize>) -> impl Fn() -> ()
|
||||||
{
|
{
|
||||||
move || { // LAAAAMBDA!
|
move || {
|
||||||
|
|
||||||
// TODO: Replace ?? with accurate info
|
// TODO: Replace ?? with accurate info
|
||||||
print!("\rProgress ({}/??)", 0);
|
print!("\rProgress ({}/??)", 0);
|
||||||
|
@ -246,7 +346,6 @@ fn dd<R: Read, W: Write>(mut i: Input<R>, mut o: Output<W>) -> Result<(usize, us
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
let mut bytes_in = 0;
|
let mut bytes_in = 0;
|
||||||
let mut bytes_out = 0;
|
let mut bytes_out = 0;
|
||||||
|
|
||||||
|
@ -278,37 +377,105 @@ fn dd<R: Read, W: Write>(mut i: Input<R>, mut o: Output<W>) -> Result<(usize, us
|
||||||
Ok((bytes_in, bytes_out))
|
Ok((bytes_in, bytes_out))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn append_dashes_if_not_present(mut acc: Vec<String>, s: &String) -> Vec<String>
|
||||||
|
{
|
||||||
|
if Some("--") == s.get(0..=1) {
|
||||||
|
acc
|
||||||
|
} else {
|
||||||
|
acc.push(format!("--{}", s));
|
||||||
|
acc
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn uumain(args: impl uucore::Args) -> i32
|
pub fn uumain(args: impl uucore::Args) -> i32
|
||||||
{
|
{
|
||||||
// TODO: parse args
|
let dashed_args = args.collect_str()
|
||||||
|
.iter()
|
||||||
|
.fold(Vec::new(), append_dashes_if_not_present);
|
||||||
|
|
||||||
let if_name = "foo.txt";
|
let syntax = format!(
|
||||||
let of_name = "bar.txt";
|
"{0} [OPERAND]...\n{0} OPTION",
|
||||||
let ibs = 512;
|
NAME
|
||||||
let obs = 4096;
|
);
|
||||||
|
|
||||||
let in_f = File::open(if_name)
|
let matches = app!(&syntax, SUMMARY, LONG_HELP)
|
||||||
.expect("TODO: Handle this error in the project-specific way");
|
.optopt(
|
||||||
|
"",
|
||||||
|
"if",
|
||||||
|
"The input file",
|
||||||
|
"FILE"
|
||||||
|
)
|
||||||
|
.optopt(
|
||||||
|
"",
|
||||||
|
"ibs",
|
||||||
|
"read up to BYTES bytes at a time (default: 512)",
|
||||||
|
"BYTES"
|
||||||
|
)
|
||||||
|
.optopt(
|
||||||
|
"",
|
||||||
|
"of",
|
||||||
|
"The output file",
|
||||||
|
"FILE"
|
||||||
|
)
|
||||||
|
.optopt(
|
||||||
|
"",
|
||||||
|
"obs",
|
||||||
|
"write BYTES bytes at a time (default: 512)",
|
||||||
|
"BYTES"
|
||||||
|
)
|
||||||
|
.optopt(
|
||||||
|
"",
|
||||||
|
"conv",
|
||||||
|
"One or more conversion options as a comma-serparated list",
|
||||||
|
"OPT[,OPT]..."
|
||||||
|
)
|
||||||
|
.parse(dashed_args);
|
||||||
|
|
||||||
let out_f = File::open(of_name)
|
let result = match (matches.opt_present("if"), matches.opt_present("of"))
|
||||||
.expect("TODO: Handle this error in the project-specific way");
|
{
|
||||||
let out_f = BufWriter::with_capacity(obs, out_f);
|
(true, true) =>
|
||||||
|
{
|
||||||
|
let i = Input::<File>::new(&matches)
|
||||||
|
.expect("TODO: Return correct error code");
|
||||||
|
let o = Output::<File>::new(&matches)
|
||||||
|
.expect("TODO: Return correct error code");
|
||||||
|
|
||||||
let i = Input {
|
dd(i, o)
|
||||||
src: in_f,
|
},
|
||||||
ibs,
|
(true, false) =>
|
||||||
output_progress: false,
|
{
|
||||||
};
|
let i = Input::<File>::new(&matches)
|
||||||
let o = Output {
|
.expect("TODO: Return correct error code");
|
||||||
dst: out_f,
|
let o = Output::<io::Stdout>::new(&matches)
|
||||||
obs,
|
.expect("TODO: Return correct error code");
|
||||||
conv_table: None,
|
|
||||||
|
dd(i, o)
|
||||||
|
},
|
||||||
|
(false, true) =>
|
||||||
|
{
|
||||||
|
let i = Input::<io::Stdin>::new(&matches)
|
||||||
|
.expect("TODO: Return correct error code");
|
||||||
|
let o = Output::<File>::new(&matches)
|
||||||
|
.expect("TODO: Return correct error code");
|
||||||
|
|
||||||
|
dd(i, o)
|
||||||
|
},
|
||||||
|
(false, false) =>
|
||||||
|
{
|
||||||
|
let i = Input::<io::Stdin>::new(&matches)
|
||||||
|
.expect("TODO: Return correct error code");
|
||||||
|
let o = Output::<io::Stdout>::new(&matches)
|
||||||
|
.expect("TODO: Return correct error code");
|
||||||
|
|
||||||
|
dd(i, o)
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
match dd(i, o) {
|
match result
|
||||||
|
{
|
||||||
Ok((b_in, b_out)) =>
|
Ok((b_in, b_out)) =>
|
||||||
{
|
{
|
||||||
println!("Completed: Bytes in: {}, Bytes out: {}", b_in, b_out);
|
// TODO: Print output stats, unless noxfer
|
||||||
|
|
||||||
RTN_SUCCESS
|
RTN_SUCCESS
|
||||||
},
|
},
|
||||||
|
@ -317,309 +484,3 @@ pub fn uumain(args: impl uucore::Args) -> i32
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod test_dd_internal
|
|
||||||
{
|
|
||||||
#[allow(unused_imports)]
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
use std::io::prelude::*;
|
|
||||||
use std::io::BufReader;
|
|
||||||
use std::fs;
|
|
||||||
use md5::{ Md5, Digest, };
|
|
||||||
use hex_literal::hex;
|
|
||||||
|
|
||||||
macro_rules! make_hash_test (
|
|
||||||
( $test_id:ident, $test_name:expr, $src:expr, $exp:expr ) =>
|
|
||||||
{
|
|
||||||
#[test]
|
|
||||||
fn $test_id()
|
|
||||||
{
|
|
||||||
let tmp_fname = format!("./test-resources/FAILED-{}.test", $test_name);
|
|
||||||
|
|
||||||
let i = Input {
|
|
||||||
src: $src,
|
|
||||||
ibs: 256,
|
|
||||||
output_progress: false,
|
|
||||||
};
|
|
||||||
|
|
||||||
let o = Output {
|
|
||||||
dst: File::create(&tmp_fname).unwrap(),
|
|
||||||
obs: 1024,
|
|
||||||
conv_table: None,
|
|
||||||
};
|
|
||||||
|
|
||||||
dd(i,o).unwrap();
|
|
||||||
|
|
||||||
let res = {
|
|
||||||
let res = File::open(&tmp_fname).unwrap();
|
|
||||||
let res = BufReader::new(res);
|
|
||||||
|
|
||||||
let mut h = Md5::new();
|
|
||||||
for b in res.bytes()
|
|
||||||
{
|
|
||||||
h.update([b.unwrap()]);
|
|
||||||
}
|
|
||||||
|
|
||||||
h.finalize()
|
|
||||||
};
|
|
||||||
|
|
||||||
assert_eq!(hex!($exp), res[..]);
|
|
||||||
|
|
||||||
fs::remove_file(&tmp_fname).unwrap();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
( $test_id:ident, $test_name:expr, $i:expr, $o:expr, $exp:expr ) =>
|
|
||||||
{
|
|
||||||
#[test]
|
|
||||||
fn $test_id()
|
|
||||||
{
|
|
||||||
let tmp_fname = format!("./test-resources/FAILED-{}.test", $test_name);
|
|
||||||
|
|
||||||
let o = Output {
|
|
||||||
dst: File::create(&tmp_fname).unwrap(),
|
|
||||||
obs: $o.obs,
|
|
||||||
conv_table: $o.conv_table,
|
|
||||||
};
|
|
||||||
|
|
||||||
dd($i,o).unwrap();
|
|
||||||
|
|
||||||
let res = {
|
|
||||||
let res = File::open(&tmp_fname).unwrap();
|
|
||||||
let res = BufReader::new(res);
|
|
||||||
|
|
||||||
let mut h = Md5::new();
|
|
||||||
for b in res.bytes()
|
|
||||||
{
|
|
||||||
h.update([b.unwrap()]);
|
|
||||||
}
|
|
||||||
|
|
||||||
h.finalize()
|
|
||||||
};
|
|
||||||
|
|
||||||
assert_eq!(hex!($exp), res[..]);
|
|
||||||
|
|
||||||
fs::remove_file(&tmp_fname).unwrap();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
);
|
|
||||||
|
|
||||||
macro_rules! make_spec_test (
|
|
||||||
( $test_id:ident, $test_name:expr, $i:expr, $o:expr, $spec:expr ) =>
|
|
||||||
{
|
|
||||||
#[test]
|
|
||||||
fn $test_id()
|
|
||||||
{
|
|
||||||
let tmp_fname = format!("./test-resources/FAILED-{}.test", $test_name);
|
|
||||||
|
|
||||||
let o = Output {
|
|
||||||
dst: File::create(&tmp_fname).unwrap(),
|
|
||||||
obs: $o.obs,
|
|
||||||
conv_table: $o.conv_table,
|
|
||||||
};
|
|
||||||
|
|
||||||
dd($i,o).unwrap();
|
|
||||||
|
|
||||||
let res = File::open(&tmp_fname).unwrap();
|
|
||||||
let res = BufReader::new(res);
|
|
||||||
|
|
||||||
let spec = BufReader::new($spec);
|
|
||||||
|
|
||||||
for (b_res, b_spec) in res.bytes().zip(spec.bytes())
|
|
||||||
{
|
|
||||||
assert_eq!(b_res.unwrap(),
|
|
||||||
b_spec.unwrap());
|
|
||||||
}
|
|
||||||
|
|
||||||
fs::remove_file(&tmp_fname).unwrap();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
);
|
|
||||||
|
|
||||||
make_hash_test!(
|
|
||||||
empty_file_test,
|
|
||||||
"stdio-empty-file",
|
|
||||||
io::empty(),
|
|
||||||
"d41d8cd98f00b204e9800998ecf8427e"
|
|
||||||
);
|
|
||||||
|
|
||||||
make_hash_test!(
|
|
||||||
zeros_4k_test,
|
|
||||||
"zeros-4k",
|
|
||||||
File::open("./test-resources/zeros-620f0b67a91f7f74151bc5be745b7110.test").unwrap(),
|
|
||||||
"620f0b67a91f7f74151bc5be745b7110"
|
|
||||||
);
|
|
||||||
|
|
||||||
make_hash_test!(
|
|
||||||
ones_4k_test,
|
|
||||||
"ones-4k",
|
|
||||||
File::open("./test-resources/ones-6ae59e64850377ee5470c854761551ea.test").unwrap(),
|
|
||||||
"6ae59e64850377ee5470c854761551ea"
|
|
||||||
);
|
|
||||||
|
|
||||||
make_hash_test!(
|
|
||||||
deadbeef_32k_test,
|
|
||||||
"deadbeef-32k",
|
|
||||||
File::open("./test-resources/deadbeef-18d99661a1de1fc9af21b0ec2cd67ba3.test").unwrap(),
|
|
||||||
"18d99661a1de1fc9af21b0ec2cd67ba3"
|
|
||||||
);
|
|
||||||
|
|
||||||
make_hash_test!(
|
|
||||||
random_73k_test,
|
|
||||||
"random-73k",
|
|
||||||
File::open("./test-resources/random-5828891cb1230748e146f34223bbd3b5.test").unwrap(),
|
|
||||||
"5828891cb1230748e146f34223bbd3b5"
|
|
||||||
);
|
|
||||||
|
|
||||||
make_spec_test!(
|
|
||||||
atoe_conv_spec_test,
|
|
||||||
"atoe-conv-spec-test",
|
|
||||||
Input {
|
|
||||||
src: File::open("./test-resources/seq-byte-values-b632a992d3aed5d8d1a59cc5a5a455ba.test").unwrap(),
|
|
||||||
ibs: 512,
|
|
||||||
output_progress: false,
|
|
||||||
},
|
|
||||||
Output {
|
|
||||||
dst: Vec::new(), // unused!
|
|
||||||
obs: 512,
|
|
||||||
conv_table: Some(ascii_to_ebcdic),
|
|
||||||
},
|
|
||||||
File::open("./test-resources/gnudd-conv-atoe-seq-byte-values.spec").unwrap()
|
|
||||||
);
|
|
||||||
|
|
||||||
make_spec_test!(
|
|
||||||
etoa_conv_spec_test,
|
|
||||||
"etoa-conv-spec-test",
|
|
||||||
Input {
|
|
||||||
src: File::open("./test-resources/seq-byte-values-b632a992d3aed5d8d1a59cc5a5a455ba.test").unwrap(),
|
|
||||||
ibs: 512,
|
|
||||||
output_progress: false,
|
|
||||||
},
|
|
||||||
Output {
|
|
||||||
dst: Vec::new(), // unused!
|
|
||||||
obs: 512,
|
|
||||||
conv_table: Some(ebcdic_to_ascii),
|
|
||||||
},
|
|
||||||
File::open("./test-resources/gnudd-conv-etoa-seq-byte-values.spec").unwrap()
|
|
||||||
);
|
|
||||||
|
|
||||||
make_spec_test!(
|
|
||||||
atoibm_conv_spec_test,
|
|
||||||
"atoibm-conv-spec-test",
|
|
||||||
Input {
|
|
||||||
src: File::open("./test-resources/seq-byte-values-b632a992d3aed5d8d1a59cc5a5a455ba.test").unwrap(),
|
|
||||||
ibs: 512,
|
|
||||||
output_progress: false,
|
|
||||||
},
|
|
||||||
Output {
|
|
||||||
dst: Vec::new(), // unused!
|
|
||||||
obs: 512,
|
|
||||||
conv_table: Some(ascii_to_ibm),
|
|
||||||
},
|
|
||||||
File::open("./test-resources/gnudd-conv-atoibm-seq-byte-values.spec").unwrap()
|
|
||||||
);
|
|
||||||
|
|
||||||
make_spec_test!(
|
|
||||||
lcase_ascii_to_ucase_ascii,
|
|
||||||
"lcase_ascii_to_ucase_ascii",
|
|
||||||
Input {
|
|
||||||
src: File::open("./test-resources/lcase-ascii.test").unwrap(),
|
|
||||||
ibs: 512,
|
|
||||||
output_progress: false,
|
|
||||||
},
|
|
||||||
Output {
|
|
||||||
dst: Vec::new(), // unused!
|
|
||||||
obs: 512,
|
|
||||||
conv_table: Some(lcase_to_ucase),
|
|
||||||
},
|
|
||||||
File::open("./test-resources/ucase-ascii.test").unwrap()
|
|
||||||
);
|
|
||||||
|
|
||||||
make_spec_test!(
|
|
||||||
ucase_ascii_to_lcase_ascii,
|
|
||||||
"ucase_ascii_to_lcase_ascii",
|
|
||||||
Input {
|
|
||||||
src: File::open("./test-resources/ucase-ascii.test").unwrap(),
|
|
||||||
ibs: 512,
|
|
||||||
output_progress: false,
|
|
||||||
},
|
|
||||||
Output {
|
|
||||||
dst: Vec::new(), // unused!
|
|
||||||
obs: 512,
|
|
||||||
conv_table: Some(ucase_to_lcase),
|
|
||||||
},
|
|
||||||
File::open("./test-resources/lcase-ascii.test").unwrap()
|
|
||||||
);
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn all_valid_ascii_ebcdic_ascii_roundtrip_conv_test()
|
|
||||||
{
|
|
||||||
// ASCII->EBCDIC
|
|
||||||
let test_name = "all-valid-ascii-to-ebcdic";
|
|
||||||
let tmp_fname_ae = format!("./test-resources/FAILED-{}.test", test_name);
|
|
||||||
|
|
||||||
let i = Input {
|
|
||||||
src: File::open("./test-resources/all-valid-ascii-chars-37eff01866ba3f538421b30b7cbefcac.test").unwrap(),
|
|
||||||
ibs: 256,
|
|
||||||
output_progress: false,
|
|
||||||
};
|
|
||||||
|
|
||||||
let o = Output {
|
|
||||||
dst: File::create(&tmp_fname_ae).unwrap(),
|
|
||||||
obs: 1024,
|
|
||||||
conv_table: Some(ascii_to_ebcdic),
|
|
||||||
};
|
|
||||||
|
|
||||||
dd(i,o).unwrap();
|
|
||||||
|
|
||||||
// EBCDIC->ASCII
|
|
||||||
let test_name = "all-valid-ebcdic-to-ascii";
|
|
||||||
let tmp_fname_ea = format!("./test-resources/FAILED-{}.test", test_name);
|
|
||||||
|
|
||||||
let i = Input {
|
|
||||||
src: File::open(&tmp_fname_ae).unwrap(),
|
|
||||||
ibs: 256,
|
|
||||||
output_progress: false,
|
|
||||||
};
|
|
||||||
|
|
||||||
let o = Output {
|
|
||||||
dst: File::create(&tmp_fname_ea).unwrap(),
|
|
||||||
obs: 1024,
|
|
||||||
conv_table: Some(ebcdic_to_ascii),
|
|
||||||
};
|
|
||||||
|
|
||||||
dd(i,o).unwrap();
|
|
||||||
|
|
||||||
let res = {
|
|
||||||
let res = File::open(&tmp_fname_ea).unwrap();
|
|
||||||
let res = BufReader::new(res);
|
|
||||||
|
|
||||||
let mut h = Md5::new();
|
|
||||||
for b in res.bytes()
|
|
||||||
{
|
|
||||||
h.update([b.unwrap()]);
|
|
||||||
}
|
|
||||||
|
|
||||||
h.finalize()
|
|
||||||
};
|
|
||||||
|
|
||||||
assert_eq!(hex!("37eff01866ba3f538421b30b7cbefcac"), res[..]);
|
|
||||||
|
|
||||||
fs::remove_file(&tmp_fname_ae).unwrap();
|
|
||||||
fs::remove_file(&tmp_fname_ea).unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
//use rand::prelude::*;
|
|
||||||
//#[test]
|
|
||||||
//fn make_test_data()
|
|
||||||
//{
|
|
||||||
// let mut f = File::create("./test-resources/random-walk-through-the-ascii-ranged-forest.test").unwrap();
|
|
||||||
// // let mut rng = rand::thread_rng();
|
|
||||||
|
|
||||||
// for _ in 0..65536 {
|
|
||||||
// f.write(&[c]).unwrap();
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
303
src/uu/dd/src/ddargs.rs
Normal file
303
src/uu/dd/src/ddargs.rs
Normal file
|
@ -0,0 +1,303 @@
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
enum ParseError
|
||||||
|
{
|
||||||
|
MultiplierString(String),
|
||||||
|
MultiplierStringWouldOverflow(String),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::fmt::Display for ParseError
|
||||||
|
{
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
write!(f, "dd-args: Parse Error")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Error for ParseError {}
|
||||||
|
|
||||||
|
fn parse_multiplier<'a>(s: &'a str) -> Result<usize, Box<dyn Error>>
|
||||||
|
{
|
||||||
|
let s = s.trim();
|
||||||
|
|
||||||
|
match s
|
||||||
|
{
|
||||||
|
"c" =>
|
||||||
|
Ok(1),
|
||||||
|
"w" =>
|
||||||
|
Ok(2),
|
||||||
|
"b" =>
|
||||||
|
Ok(512),
|
||||||
|
"kB" =>
|
||||||
|
Ok(1000),
|
||||||
|
"K" | "KiB" =>
|
||||||
|
Ok(1024),
|
||||||
|
"MB" =>
|
||||||
|
Ok(1000*1000),
|
||||||
|
"M" | "MiB" =>
|
||||||
|
Ok(1024*1024),
|
||||||
|
"GB" =>
|
||||||
|
Ok(1000*1000*1000),
|
||||||
|
"G" | "GiB" =>
|
||||||
|
Ok(1024*1024*1024),
|
||||||
|
"TB" =>
|
||||||
|
Ok(1000*1000*1000*1000),
|
||||||
|
"T" | "TiB" =>
|
||||||
|
Ok(1024*1024*1024*1024),
|
||||||
|
"PB" =>
|
||||||
|
Ok(1000*1000*1000*1000*1000),
|
||||||
|
"P" | "PiB" =>
|
||||||
|
Ok(1024*1024*1024*1024*1024),
|
||||||
|
"EB" =>
|
||||||
|
Ok(1000*1000*1000*1000*1000*1000),
|
||||||
|
"E" | "EiB" =>
|
||||||
|
Ok(1024*1024*1024*1024*1024*1024),
|
||||||
|
// The following would overflow on my x64 system
|
||||||
|
// "ZB" =>
|
||||||
|
// Ok(1000*1000*1000*1000*1000*1000*1000),
|
||||||
|
// "Z" | "ZiB" =>
|
||||||
|
// Ok(1024*1024*1024*1024*1024*1024*1024),
|
||||||
|
// "YB" =>
|
||||||
|
// Ok(1000*1000*1000*1000*1000*1000*1000*1000),
|
||||||
|
// "Y" | "YiB" =>
|
||||||
|
// Ok(1024*1024*1024*1024*1024*1024*1024*1024),
|
||||||
|
_ =>
|
||||||
|
Err(Box::new(ParseError::MultiplierString(String::from(s)))),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_bytes_with_opt_multiplier(s: String) -> Result<usize, Box<dyn Error>>
|
||||||
|
{
|
||||||
|
if let Some(idx) = s.find(' ')
|
||||||
|
{
|
||||||
|
let base: usize = s[0..idx].parse()?;
|
||||||
|
let mult = parse_multiplier(&s[idx..])?;
|
||||||
|
|
||||||
|
if let Some(bytes) = base.checked_mul(mult)
|
||||||
|
{
|
||||||
|
Ok(bytes)
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Err(Box::new(ParseError::MultiplierStringWouldOverflow(s)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
let bytes: usize = s.parse()?;
|
||||||
|
|
||||||
|
Ok(bytes)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn parse_ibs(matches: &getopts::Matches) -> Result<usize, Box<dyn Error>>
|
||||||
|
{
|
||||||
|
if let Some(mixed_str) = matches.opt_str("bs")
|
||||||
|
{
|
||||||
|
parse_bytes_with_opt_multiplier(mixed_str)
|
||||||
|
}
|
||||||
|
else if let Some(mixed_str) = matches.opt_str("ibs")
|
||||||
|
{
|
||||||
|
parse_bytes_with_opt_multiplier(mixed_str)
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Ok(512)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn parse_progress_level(matches: &getopts::Matches) -> Result<bool, Box<dyn Error>>
|
||||||
|
{
|
||||||
|
// TODO: Implement this stub proc
|
||||||
|
Ok(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn parse_obs(matches: &getopts::Matches) -> Result<usize, Box<dyn Error>>
|
||||||
|
{
|
||||||
|
if let Some(str_with_prefixes) = matches.opt_str("bs")
|
||||||
|
{
|
||||||
|
// TODO: Parse a string containing the number with potential k, kB, kiB, ... multiplier
|
||||||
|
// possibly implemented elsewhere, but probably not in exactly the dd style
|
||||||
|
panic!()
|
||||||
|
}
|
||||||
|
else if let Some(str_with_prefixes) = matches.opt_str("obs")
|
||||||
|
{
|
||||||
|
// TODO: Parse a string containing the number with potential k, kB, kiB, ... multiplier
|
||||||
|
// possibly implemented elsewhere, but probably not in exactly the dd style
|
||||||
|
panic!()
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Ok(512)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn parse_conv_table(matches: &getopts::Matches) -> Result<Option<ConversionTable>, Box<dyn Error>>
|
||||||
|
{
|
||||||
|
// TODO: Complete this stub fn
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
macro_rules! test_byte_parser (
|
||||||
|
( $test_name:ident, $bs_str:expr, $bs:expr ) =>
|
||||||
|
{
|
||||||
|
#[test]
|
||||||
|
fn $test_name()
|
||||||
|
{
|
||||||
|
let bs_str = String::from($bs_str);
|
||||||
|
assert_eq!($bs, parse_bytes_with_opt_multiplier(bs_str).unwrap())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_input_parser()
|
||||||
|
{
|
||||||
|
panic!()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_output_parser()
|
||||||
|
{
|
||||||
|
panic!()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_conv_options_parser()
|
||||||
|
{
|
||||||
|
panic!()
|
||||||
|
}
|
||||||
|
|
||||||
|
test_byte_parser!(
|
||||||
|
test_bytes_n,
|
||||||
|
"765",
|
||||||
|
765
|
||||||
|
);
|
||||||
|
test_byte_parser!(
|
||||||
|
test_bytes_c,
|
||||||
|
"13 c",
|
||||||
|
13
|
||||||
|
);
|
||||||
|
|
||||||
|
test_byte_parser!(
|
||||||
|
test_bytes_w,
|
||||||
|
"1 w",
|
||||||
|
2
|
||||||
|
);
|
||||||
|
|
||||||
|
test_byte_parser!(
|
||||||
|
test_bytes_b,
|
||||||
|
"1 b",
|
||||||
|
512
|
||||||
|
);
|
||||||
|
|
||||||
|
test_byte_parser!(
|
||||||
|
test_bytes_k,
|
||||||
|
"1 kB",
|
||||||
|
1000
|
||||||
|
);
|
||||||
|
test_byte_parser!(
|
||||||
|
test_bytes_K,
|
||||||
|
"1 K",
|
||||||
|
1024
|
||||||
|
);
|
||||||
|
test_byte_parser!(
|
||||||
|
test_bytes_Ki,
|
||||||
|
"1 KiB",
|
||||||
|
1024
|
||||||
|
);
|
||||||
|
|
||||||
|
test_byte_parser!(
|
||||||
|
test_bytes_MB,
|
||||||
|
"1 MB",
|
||||||
|
1000*1000
|
||||||
|
);
|
||||||
|
test_byte_parser!(
|
||||||
|
test_bytes_M,
|
||||||
|
"1 M",
|
||||||
|
1024*1024
|
||||||
|
);
|
||||||
|
test_byte_parser!(
|
||||||
|
test_bytes_Mi,
|
||||||
|
"1 MiB",
|
||||||
|
1024*1024
|
||||||
|
);
|
||||||
|
|
||||||
|
test_byte_parser!(
|
||||||
|
test_bytes_GB,
|
||||||
|
"1 GB",
|
||||||
|
1000*1000*1000
|
||||||
|
);
|
||||||
|
test_byte_parser!(
|
||||||
|
test_bytes_G,
|
||||||
|
"1 G",
|
||||||
|
1024*1024*1024
|
||||||
|
);
|
||||||
|
test_byte_parser!(
|
||||||
|
test_bytes_Gi,
|
||||||
|
"1 GiB",
|
||||||
|
1024*1024*1024
|
||||||
|
);
|
||||||
|
|
||||||
|
test_byte_parser!(
|
||||||
|
test_bytes_TB,
|
||||||
|
"1 TB",
|
||||||
|
1000*1000*1000*1000
|
||||||
|
);
|
||||||
|
test_byte_parser!(
|
||||||
|
test_bytes_T,
|
||||||
|
"1 T",
|
||||||
|
1024*1024*1024*1024
|
||||||
|
);
|
||||||
|
test_byte_parser!(
|
||||||
|
test_bytes_Ti,
|
||||||
|
"1 TiB",
|
||||||
|
1024*1024*1024*1024
|
||||||
|
);
|
||||||
|
|
||||||
|
test_byte_parser!(
|
||||||
|
test_bytes_PB,
|
||||||
|
"1 PB",
|
||||||
|
1000*1000*1000*1000*1000
|
||||||
|
);
|
||||||
|
test_byte_parser!(
|
||||||
|
test_bytes_P,
|
||||||
|
"1 P",
|
||||||
|
1024*1024*1024*1024*1024
|
||||||
|
);
|
||||||
|
test_byte_parser!(
|
||||||
|
test_bytes_Pi,
|
||||||
|
"1 PiB",
|
||||||
|
1024*1024*1024*1024*1024
|
||||||
|
);
|
||||||
|
|
||||||
|
test_byte_parser!(
|
||||||
|
test_bytes_EB,
|
||||||
|
"1 EB",
|
||||||
|
1000*1000*1000*1000*1000*1000
|
||||||
|
);
|
||||||
|
test_byte_parser!(
|
||||||
|
test_bytes_E,
|
||||||
|
"1 E",
|
||||||
|
1024*1024*1024*1024*1024*1024
|
||||||
|
);
|
||||||
|
test_byte_parser!(
|
||||||
|
test_bytes_Ei,
|
||||||
|
"1 EiB",
|
||||||
|
1024*1024*1024*1024*1024*1024
|
||||||
|
);
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[should_panic]
|
||||||
|
fn test_KB_multiplier_error()
|
||||||
|
{
|
||||||
|
let bs_str = String::from("2000 KB");
|
||||||
|
|
||||||
|
parse_bytes_with_opt_multiplier(bs_str).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
329
src/uu/dd/src/test_dd_internal.rs
Normal file
329
src/uu/dd/src/test_dd_internal.rs
Normal file
|
@ -0,0 +1,329 @@
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
use std::io::prelude::*;
|
||||||
|
use std::io::BufReader;
|
||||||
|
use std::fs;
|
||||||
|
use md5::{ Md5, Digest, };
|
||||||
|
use hex_literal::hex;
|
||||||
|
// use tempfile::tempfile;
|
||||||
|
// TODO: (Maybe) Use tempfiles in the tests.
|
||||||
|
|
||||||
|
macro_rules! make_hash_test (
|
||||||
|
( $test_id:ident, $test_name:expr, $src:expr, $exp:expr ) =>
|
||||||
|
{
|
||||||
|
#[test]
|
||||||
|
fn $test_id()
|
||||||
|
{
|
||||||
|
let tmp_fname = format!("./test-resources/FAILED-{}.test", $test_name);
|
||||||
|
|
||||||
|
let i = Input {
|
||||||
|
src: $src,
|
||||||
|
ibs: 256,
|
||||||
|
output_progress: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
let o = Output {
|
||||||
|
dst: File::create(&tmp_fname).unwrap(),
|
||||||
|
obs: 1024,
|
||||||
|
conv_table: None,
|
||||||
|
};
|
||||||
|
|
||||||
|
dd(i,o).unwrap();
|
||||||
|
|
||||||
|
let res = {
|
||||||
|
let res = File::open(&tmp_fname).unwrap();
|
||||||
|
let res = BufReader::new(res);
|
||||||
|
|
||||||
|
let mut h = Md5::new();
|
||||||
|
for b in res.bytes()
|
||||||
|
{
|
||||||
|
h.update([b.unwrap()]);
|
||||||
|
}
|
||||||
|
|
||||||
|
h.finalize()
|
||||||
|
};
|
||||||
|
|
||||||
|
assert_eq!(hex!($exp), res[..]);
|
||||||
|
|
||||||
|
fs::remove_file(&tmp_fname).unwrap();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
( $test_id:ident, $test_name:expr, $i:expr, $o:expr, $exp:expr ) =>
|
||||||
|
{
|
||||||
|
#[test]
|
||||||
|
fn $test_id()
|
||||||
|
{
|
||||||
|
let tmp_fname = format!("./test-resources/FAILED-{}.test", $test_name);
|
||||||
|
|
||||||
|
let o = Output {
|
||||||
|
dst: File::create(&tmp_fname).unwrap(),
|
||||||
|
obs: $o.obs,
|
||||||
|
conv_table: $o.conv_table,
|
||||||
|
};
|
||||||
|
|
||||||
|
dd($i,o).unwrap();
|
||||||
|
|
||||||
|
let res = {
|
||||||
|
let res = File::open(&tmp_fname).unwrap();
|
||||||
|
let res = BufReader::new(res);
|
||||||
|
|
||||||
|
let mut h = Md5::new();
|
||||||
|
for b in res.bytes()
|
||||||
|
{
|
||||||
|
h.update([b.unwrap()]);
|
||||||
|
}
|
||||||
|
|
||||||
|
h.finalize()
|
||||||
|
};
|
||||||
|
|
||||||
|
assert_eq!(hex!($exp), res[..]);
|
||||||
|
|
||||||
|
fs::remove_file(&tmp_fname).unwrap();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
);
|
||||||
|
|
||||||
|
macro_rules! make_spec_test (
|
||||||
|
( $test_id:ident, $test_name:expr, $i:expr, $o:expr, $spec:expr ) =>
|
||||||
|
{
|
||||||
|
#[test]
|
||||||
|
fn $test_id()
|
||||||
|
{
|
||||||
|
let tmp_fname = format!("./test-resources/FAILED-{}.test", $test_name);
|
||||||
|
|
||||||
|
let o = Output {
|
||||||
|
dst: File::create(&tmp_fname).unwrap(),
|
||||||
|
obs: $o.obs,
|
||||||
|
conv_table: $o.conv_table,
|
||||||
|
};
|
||||||
|
|
||||||
|
dd($i,o).unwrap();
|
||||||
|
|
||||||
|
let res = File::open(&tmp_fname).unwrap();
|
||||||
|
let res = BufReader::new(res);
|
||||||
|
|
||||||
|
let spec = BufReader::new($spec);
|
||||||
|
|
||||||
|
for (b_res, b_spec) in res.bytes().zip(spec.bytes())
|
||||||
|
{
|
||||||
|
assert_eq!(b_res.unwrap(),
|
||||||
|
b_spec.unwrap());
|
||||||
|
}
|
||||||
|
|
||||||
|
fs::remove_file(&tmp_fname).unwrap();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
);
|
||||||
|
|
||||||
|
make_hash_test!(
|
||||||
|
empty_file_test,
|
||||||
|
"stdio-empty-file",
|
||||||
|
io::empty(),
|
||||||
|
"d41d8cd98f00b204e9800998ecf8427e"
|
||||||
|
);
|
||||||
|
|
||||||
|
make_hash_test!(
|
||||||
|
zeros_4k_test,
|
||||||
|
"zeros-4k",
|
||||||
|
File::open("./test-resources/zeros-620f0b67a91f7f74151bc5be745b7110.test").unwrap(),
|
||||||
|
"620f0b67a91f7f74151bc5be745b7110"
|
||||||
|
);
|
||||||
|
|
||||||
|
make_hash_test!(
|
||||||
|
ones_4k_test,
|
||||||
|
"ones-4k",
|
||||||
|
File::open("./test-resources/ones-6ae59e64850377ee5470c854761551ea.test").unwrap(),
|
||||||
|
"6ae59e64850377ee5470c854761551ea"
|
||||||
|
);
|
||||||
|
|
||||||
|
make_hash_test!(
|
||||||
|
deadbeef_32k_test,
|
||||||
|
"deadbeef-32k",
|
||||||
|
File::open("./test-resources/deadbeef-18d99661a1de1fc9af21b0ec2cd67ba3.test").unwrap(),
|
||||||
|
"18d99661a1de1fc9af21b0ec2cd67ba3"
|
||||||
|
);
|
||||||
|
|
||||||
|
make_hash_test!(
|
||||||
|
random_73k_test,
|
||||||
|
"random-73k",
|
||||||
|
File::open("./test-resources/random-5828891cb1230748e146f34223bbd3b5.test").unwrap(),
|
||||||
|
"5828891cb1230748e146f34223bbd3b5"
|
||||||
|
);
|
||||||
|
|
||||||
|
make_spec_test!(
|
||||||
|
atoe_conv_spec_test,
|
||||||
|
"atoe-conv-spec-test",
|
||||||
|
Input {
|
||||||
|
src: File::open("./test-resources/seq-byte-values-b632a992d3aed5d8d1a59cc5a5a455ba.test").unwrap(),
|
||||||
|
ibs: 512,
|
||||||
|
output_progress: false,
|
||||||
|
},
|
||||||
|
Output {
|
||||||
|
dst: Vec::new(), // unused!
|
||||||
|
obs: 512,
|
||||||
|
conv_table: Some(ASCII_TO_EBCDIC),
|
||||||
|
},
|
||||||
|
File::open("./test-resources/gnudd-conv-atoe-seq-byte-values.spec").unwrap()
|
||||||
|
);
|
||||||
|
|
||||||
|
make_spec_test!(
|
||||||
|
etoa_conv_spec_test,
|
||||||
|
"etoa-conv-spec-test",
|
||||||
|
Input {
|
||||||
|
src: File::open("./test-resources/seq-byte-values-b632a992d3aed5d8d1a59cc5a5a455ba.test").unwrap(),
|
||||||
|
ibs: 512,
|
||||||
|
output_progress: false,
|
||||||
|
},
|
||||||
|
Output {
|
||||||
|
dst: Vec::new(), // unused!
|
||||||
|
obs: 512,
|
||||||
|
conv_table: Some(EBCDIC_TO_ASCII),
|
||||||
|
},
|
||||||
|
File::open("./test-resources/gnudd-conv-etoa-seq-byte-values.spec").unwrap()
|
||||||
|
);
|
||||||
|
|
||||||
|
make_spec_test!(
|
||||||
|
atoibm_conv_spec_test,
|
||||||
|
"atoibm-conv-spec-test",
|
||||||
|
Input {
|
||||||
|
src: File::open("./test-resources/seq-byte-values-b632a992d3aed5d8d1a59cc5a5a455ba.test").unwrap(),
|
||||||
|
ibs: 512,
|
||||||
|
output_progress: false,
|
||||||
|
},
|
||||||
|
Output {
|
||||||
|
dst: Vec::new(), // unused!
|
||||||
|
obs: 512,
|
||||||
|
conv_table: Some(ASCII_TO_IBM),
|
||||||
|
},
|
||||||
|
File::open("./test-resources/gnudd-conv-atoibm-seq-byte-values.spec").unwrap()
|
||||||
|
);
|
||||||
|
|
||||||
|
make_spec_test!(
|
||||||
|
lcase_ascii_to_ucase_ascii,
|
||||||
|
"lcase_ascii_to_ucase_ascii",
|
||||||
|
Input {
|
||||||
|
src: File::open("./test-resources/lcase-ascii.test").unwrap(),
|
||||||
|
ibs: 512,
|
||||||
|
output_progress: false,
|
||||||
|
},
|
||||||
|
Output {
|
||||||
|
dst: Vec::new(), // unused!
|
||||||
|
obs: 512,
|
||||||
|
conv_table: Some(LCASE_TO_UCASE),
|
||||||
|
},
|
||||||
|
File::open("./test-resources/ucase-ascii.test").unwrap()
|
||||||
|
);
|
||||||
|
|
||||||
|
make_spec_test!(
|
||||||
|
ucase_ascii_to_lcase_ascii,
|
||||||
|
"ucase_ascii_to_lcase_ascii",
|
||||||
|
Input {
|
||||||
|
src: File::open("./test-resources/ucase-ascii.test").unwrap(),
|
||||||
|
ibs: 512,
|
||||||
|
output_progress: false,
|
||||||
|
},
|
||||||
|
Output {
|
||||||
|
dst: Vec::new(), // unused!
|
||||||
|
obs: 512,
|
||||||
|
conv_table: Some(UCASE_TO_LCASE),
|
||||||
|
},
|
||||||
|
File::open("./test-resources/lcase-ascii.test").unwrap()
|
||||||
|
);
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn all_valid_ascii_ebcdic_ascii_roundtrip_conv_test()
|
||||||
|
{
|
||||||
|
// ASCII->EBCDIC
|
||||||
|
let test_name = "all-valid-ascii-to-ebcdic";
|
||||||
|
let tmp_fname_ae = format!("./test-resources/FAILED-{}.test", test_name);
|
||||||
|
|
||||||
|
let i = Input {
|
||||||
|
src: File::open("./test-resources/all-valid-ascii-chars-37eff01866ba3f538421b30b7cbefcac.test").unwrap(),
|
||||||
|
ibs: 256,
|
||||||
|
output_progress: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
let o = Output {
|
||||||
|
dst: File::create(&tmp_fname_ae).unwrap(),
|
||||||
|
obs: 1024,
|
||||||
|
conv_table: Some(ASCII_TO_EBCDIC),
|
||||||
|
};
|
||||||
|
|
||||||
|
dd(i,o).unwrap();
|
||||||
|
|
||||||
|
// EBCDIC->ASCII
|
||||||
|
let test_name = "all-valid-ebcdic-to-ascii";
|
||||||
|
let tmp_fname_ea = format!("./test-resources/FAILED-{}.test", test_name);
|
||||||
|
|
||||||
|
let i = Input {
|
||||||
|
src: File::open(&tmp_fname_ae).unwrap(),
|
||||||
|
ibs: 256,
|
||||||
|
output_progress: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
let o = Output {
|
||||||
|
dst: File::create(&tmp_fname_ea).unwrap(),
|
||||||
|
obs: 1024,
|
||||||
|
conv_table: Some(EBCDIC_TO_ASCII),
|
||||||
|
};
|
||||||
|
|
||||||
|
dd(i,o).unwrap();
|
||||||
|
|
||||||
|
let res = {
|
||||||
|
let res = File::open(&tmp_fname_ea).unwrap();
|
||||||
|
let res = BufReader::new(res);
|
||||||
|
|
||||||
|
let mut h = Md5::new();
|
||||||
|
for b in res.bytes()
|
||||||
|
{
|
||||||
|
h.update([b.unwrap()]);
|
||||||
|
}
|
||||||
|
|
||||||
|
h.finalize()
|
||||||
|
};
|
||||||
|
|
||||||
|
assert_eq!(hex!("37eff01866ba3f538421b30b7cbefcac"), res[..]);
|
||||||
|
|
||||||
|
fs::remove_file(&tmp_fname_ae).unwrap();
|
||||||
|
fs::remove_file(&tmp_fname_ea).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
// #[test]
|
||||||
|
// fn copy_zerofile_from_args()
|
||||||
|
// {
|
||||||
|
// let spec = File::open("./test-resources/zeros-620f0b67a91f7f74151bc5be745b7110.test").unwrap();
|
||||||
|
// let tmp_fname = format!("./test-resources/{}", "zeros-from-args.test");
|
||||||
|
//
|
||||||
|
// let args = vec![
|
||||||
|
// String::from("if=./test-resources/zeros-620f0b67a91f7f74151bc5be745b7110.test"),
|
||||||
|
// String::from(&tmp_fname),
|
||||||
|
// ];
|
||||||
|
// let args = Args { args };
|
||||||
|
//
|
||||||
|
// uumain(args);
|
||||||
|
//
|
||||||
|
// let res = File::open(&tmp_fname).unwrap();
|
||||||
|
// let res = BufReader::new(res);
|
||||||
|
//
|
||||||
|
// let spec = BufReader::new(spec);
|
||||||
|
//
|
||||||
|
// for (b_res, b_spec) in res.bytes().zip(spec.bytes())
|
||||||
|
// {
|
||||||
|
// assert_eq!(b_res.unwrap(),
|
||||||
|
// b_spec.unwrap());
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// fs::remove_file(&tmp_fname).unwrap();
|
||||||
|
// }
|
||||||
|
|
||||||
|
//use rand::prelude::*;
|
||||||
|
//#[test]
|
||||||
|
//fn make_test_data()
|
||||||
|
//{
|
||||||
|
// let mut f = File::create("./test-resources/random-walk-through-the-ascii-ranged-forest.test").unwrap();
|
||||||
|
// // let mut rng = rand::thread_rng();
|
||||||
|
|
||||||
|
// for _ in 0..65536 {
|
||||||
|
// f.write(&[c]).unwrap();
|
||||||
|
// }
|
||||||
|
//}
|
|
@ -1,7 +1,61 @@
|
||||||
use crate::common::util::*;
|
use crate::common::util::*;
|
||||||
|
|
||||||
|
use std::io::prelude::*;
|
||||||
|
use std::io::BufReader;
|
||||||
|
use std::fs::{self, File};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn fail_from_test_dd()
|
fn dd_zeros_to_stdout_test_from_args()
|
||||||
{
|
{
|
||||||
panic!()
|
new_ucmd!()
|
||||||
|
.args(&[
|
||||||
|
"if=../../src/uu/dd/test-resources/zeros-620f0b67a91f7f74151bc5be745b7110.test",
|
||||||
|
])
|
||||||
|
.succeeds()
|
||||||
|
.stdout_only(
|
||||||
|
"0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\
|
||||||
|
0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\
|
||||||
|
0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\
|
||||||
|
0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\
|
||||||
|
0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\
|
||||||
|
0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\
|
||||||
|
0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\
|
||||||
|
0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\
|
||||||
|
0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\
|
||||||
|
0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\
|
||||||
|
0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\
|
||||||
|
0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\
|
||||||
|
0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\
|
||||||
|
0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\
|
||||||
|
0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\
|
||||||
|
0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\
|
||||||
|
"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn dd_ones_to_file_test_from_args()
|
||||||
|
{
|
||||||
|
let tmp_fname = "../../src/uu/dd/test-resources/FAILED-ones-to-file-from-args.test";
|
||||||
|
|
||||||
|
new_ucmd!()
|
||||||
|
.args(&[
|
||||||
|
"if=../../src/uu/dd/test-resources/ones-6ae59e64850377ee5470c854761551ea.test",
|
||||||
|
&format!("of={}", &tmp_fname),
|
||||||
|
])
|
||||||
|
.succeeds();
|
||||||
|
|
||||||
|
let res = File::open(&tmp_fname).unwrap();
|
||||||
|
let res = BufReader::new(res);
|
||||||
|
|
||||||
|
let spec = File::open("../../src/uu/dd/test-resources/ones-6ae59e64850377ee5470c854761551ea.test").unwrap();
|
||||||
|
let spec = BufReader::new(spec);
|
||||||
|
|
||||||
|
for (b_res, b_spec) in res.bytes().zip(spec.bytes())
|
||||||
|
{
|
||||||
|
assert_eq!(b_res.unwrap(),
|
||||||
|
b_spec.unwrap());
|
||||||
|
}
|
||||||
|
|
||||||
|
fs::remove_file(&tmp_fname).unwrap();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue