diff --git a/coreutils/src/commands/dd.rs b/coreutils/src/commands/dd.rs new file mode 100644 index 0000000..43fac19 --- /dev/null +++ b/coreutils/src/commands/dd.rs @@ -0,0 +1,85 @@ +use boxutils::commands::Command; +use std::env; +use std::collections::HashMap; +use std::io::{self, Read, Write, BufReader}; +use std::fs::File; +use std::time::Instant; + +pub struct Dd; + +impl Command for Dd { + fn execute(&self) { + // dd has its seperate argument parsing + let mut arguments = HashMap::new(); + let mut blocksize = 512; + + for argument in env::args() { + if let Some((k, v)) = argument.split_once('=') { + arguments.insert(k.to_string().to_lowercase(), v.to_string()); + } // don't handle anything that does not follow dd's syntax. + // TODO: inform about malformed arguments + } + + if let Some(bs) = arguments.get("bs") { + let (k, v) = bs.split_at(bs.len() - 1); + if v.parse::().is_ok() { + // assume the bs is specified in bytes, + // because the last char is a number + blocksize = bs.parse::().unwrap() + } else { + match v { + "K" | "k" => blocksize = k.parse::().unwrap() * 1024, + "M" => blocksize = k.parse::().unwrap() * 1024 * 1024, + "G" => blocksize = k.parse::().unwrap() * 1024 * 1024 * 1024, + "kB" => blocksize = k.parse::().unwrap() * 1000, + "MB" => blocksize = k.parse::().unwrap() * 1000 * 1000, + "GB" => blocksize = k.parse::().unwrap() * 1000 * 1000 * 1000, + _ => { + eprintln!("Invalid blocksize specified."); + return + } + } + } + } + + let mut vecbuf = Vec::with_capacity(blocksize.try_into().unwrap()); + let start = Instant::now(); + + if let Some(input) = arguments.get("if") { + let mut f = BufReader::new(File::open(input).unwrap()); + let _ = f.read_to_end(&mut vecbuf).unwrap(); + } else { + let _ = io::stdin().read_to_end(&mut vecbuf).unwrap(); + } + + if let Some(output) = arguments.get("of") { + let buffer = File::create(output); + let _ = buffer.unwrap().write(&vecbuf); + } else { + let _ = io::stdout().write_all(&vecbuf); + } + + let duration = start.elapsed().as_millis() / 1000; + + let out_blocks = vecbuf.len() as u64 / blocksize; + let out_remainder = vecbuf.len() as u64 % blocksize; + + println!( + "{}+{} records in", // TODO: actually calculate records in + out_blocks, + out_remainder + ); + + println!( + "{}+{} records out", + out_blocks, + out_remainder + ); + + println!( + "{} bytes copied, ca. {} seconds", + vecbuf.len(), + duration + ) + } +} diff --git a/coreutils/src/commands/mod.rs b/coreutils/src/commands/mod.rs index 17f40fd..2a57ec5 100644 --- a/coreutils/src/commands/mod.rs +++ b/coreutils/src/commands/mod.rs @@ -9,3 +9,6 @@ pub use echo::Echo; mod mkdir; pub use mkdir::Mkdir; + +mod dd; +pub use dd::Dd; diff --git a/src/registry.rs b/src/registry.rs index 130d127..6967e7d 100644 --- a/src/registry.rs +++ b/src/registry.rs @@ -9,6 +9,7 @@ pub fn get_registry() -> CommandRegistry { registry.register("echo", Box::new(coreutils::commands::Echo)); registry.register("mkdir", Box::new(coreutils::commands::Mkdir)); registry.register("ash", Box::new(shell::ash::Ash)); + registry.register("dd", Box::new(coreutils::commands::Dd)); registry.register("box", Box::new(Boxcmd)); registry