sysutils: add a simple dd

This commit is contained in:
Mark Poliakov 2023-12-11 02:45:50 +02:00
parent 3370b35811
commit 0752f39089
4 changed files with 199 additions and 1 deletions

View File

@ -59,6 +59,7 @@ pack_initrd() {
cp ${build_dir}/cat ${root_dir}/bin/
cp ${build_dir}/hexd ${root_dir}/bin/
cp ${build_dir}/colors ${root_dir}/bin/
cp ${build_dir}/dd ${root_dir}/bin/
# red
cp ${build_dir}/red ${root_dir}/bin/red

View File

@ -50,3 +50,7 @@ path = "src/hexd.rs"
[[bin]]
name = "colors"
path = "src/colors.rs"
[[bin]]
name = "dd"
path = "src/dd.rs"

130
sysutils/src/dd.rs Normal file
View File

@ -0,0 +1,130 @@
#![feature(yggdrasil_os)]
use std::{
io::{self, Read, Seek, SeekFrom, Write},
process::ExitCode,
};
use clap::Parser;
use sysutils::{Input, Output};
#[derive(Parser)]
struct Args {
#[arg(short)]
source: Option<String>,
#[arg(short)]
destination: Option<String>,
#[arg(long)]
src_skip: Option<u64>,
#[arg(long, default_value_t = 512)]
src_bs: u64,
#[arg(short, long, default_value_t = usize::MAX)]
count: usize,
// TODO: remove this when pipes are a thing
#[arg(short = 'x', long)]
as_hex: bool
}
fn dump_block(offset: u64, data: &[u8]) {
const WINDOW_SIZE: usize = 16;
let window_count = (data.len() + WINDOW_SIZE) / WINDOW_SIZE;
for iw in 0..window_count {
let off = iw * WINDOW_SIZE;
let len = core::cmp::min(data.len() - off, WINDOW_SIZE);
if len == 0 {
break;
}
let window = &data[off..off + len];
print!("{:08X}: ", offset + off as u64);
for i in 0..WINDOW_SIZE {
if i < window.len() {
print!("{:02X}", window[i]);
} else {
print!(" ");
}
if i % 2 == 1 {
print!(" ");
}
}
for &ch in window {
if ch.is_ascii_graphic() || ch == b' ' {
print!("{}", ch as char);
} else {
print!(".");
}
}
println!();
}
}
fn run<I: Read + Seek, O: Write>(
mut input: I,
mut output: O,
src_position: u64,
src_block_size: u64,
mut count: usize,
as_hex: bool,
) -> io::Result<()> {
let mut block = vec![0; src_block_size as usize];
let mut offset = 0;
input.seek(SeekFrom::Start(src_position * src_block_size))?;
while count != 0 {
let read_count = input.read(&mut block)?;
if read_count == 0 {
break;
}
if as_hex {
dump_block((src_position + offset) * src_block_size, &block[..read_count]);
} else {
output.write(&block[..read_count])?;
}
count -= 1;
offset += 1;
}
Ok(())
}
fn main() -> ExitCode {
let args = Args::parse();
let src_path = args.source.as_deref().unwrap_or("-");
let dst_path = args.destination.as_deref().unwrap_or("-");
if src_path == dst_path && src_path != "-" {
eprintln!("Input and output cannot be the same: {}", src_path);
return ExitCode::FAILURE;
}
if args.as_hex && dst_path != "-" {
eprintln!("--as-hex requires stdout output");
return ExitCode::FAILURE;
}
let input = Input::open_str(src_path).unwrap();
let output = Output::open_str(dst_path).unwrap();
let src_position = args.src_skip.unwrap_or(0);
match run(input, output, src_position, args.src_bs, args.count, args.as_hex) {
Ok(_) => {
ExitCode::SUCCESS
}
Err(e) => {
eprintln!("Error: {}", e);
ExitCode::FAILURE
}
}
}

View File

@ -1,6 +1,6 @@
use std::{
fs::File,
io::{self, Read},
io::{self, Read, Write, Seek, SeekFrom},
};
#[cfg(unix)]
@ -65,6 +65,11 @@ pub enum Input {
File(io::BufReader<File>),
}
pub enum Output {
Stdout(io::Stdout),
File(io::BufWriter<File>),
}
impl Input {
pub fn open_str(arg: &str) -> io::Result<Self> {
if arg == "-" {
@ -97,3 +102,61 @@ impl Read for Input {
}
}
}
impl Seek for Input {
fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
match self {
Self::Stdin(_) => todo!(),
Self::File(value) => value.seek(pos),
}
}
}
impl Output {
pub fn open_str(arg: &str) -> io::Result<Self> {
if arg == "-" {
Ok(Self::Stdout(io::stdout()))
} else {
let file = File::create(arg)?;
let writer = io::BufWriter::new(file);
Ok(Self::File(writer))
}
}
}
impl From<io::Stdout> for Output {
fn from(value: io::Stdout) -> Self {
Self::Stdout(value)
}
}
impl From<File> for Output {
fn from(value: File) -> Self {
Self::File(io::BufWriter::new(value))
}
}
impl Write for Output {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
match self {
Self::Stdout(value) => value.write(buf),
Self::File(value) => value.write(buf),
}
}
fn flush(&mut self) -> io::Result<()> {
match self {
Self::Stdout(value) => value.flush(),
Self::File(value) => value.flush(),
}
}
}
impl Seek for Output {
fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
match self {
Self::Stdout(_) => todo!(),
Self::File(value) => value.seek(pos),
}
}
}