sysutils: add a simple dd
This commit is contained in:
parent
3370b35811
commit
0752f39089
1
build.sh
1
build.sh
@ -59,6 +59,7 @@ pack_initrd() {
|
|||||||
cp ${build_dir}/cat ${root_dir}/bin/
|
cp ${build_dir}/cat ${root_dir}/bin/
|
||||||
cp ${build_dir}/hexd ${root_dir}/bin/
|
cp ${build_dir}/hexd ${root_dir}/bin/
|
||||||
cp ${build_dir}/colors ${root_dir}/bin/
|
cp ${build_dir}/colors ${root_dir}/bin/
|
||||||
|
cp ${build_dir}/dd ${root_dir}/bin/
|
||||||
|
|
||||||
# red
|
# red
|
||||||
cp ${build_dir}/red ${root_dir}/bin/red
|
cp ${build_dir}/red ${root_dir}/bin/red
|
||||||
|
@ -50,3 +50,7 @@ path = "src/hexd.rs"
|
|||||||
[[bin]]
|
[[bin]]
|
||||||
name = "colors"
|
name = "colors"
|
||||||
path = "src/colors.rs"
|
path = "src/colors.rs"
|
||||||
|
|
||||||
|
[[bin]]
|
||||||
|
name = "dd"
|
||||||
|
path = "src/dd.rs"
|
||||||
|
130
sysutils/src/dd.rs
Normal file
130
sysutils/src/dd.rs
Normal 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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,6 +1,6 @@
|
|||||||
use std::{
|
use std::{
|
||||||
fs::File,
|
fs::File,
|
||||||
io::{self, Read},
|
io::{self, Read, Write, Seek, SeekFrom},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
@ -65,6 +65,11 @@ pub enum Input {
|
|||||||
File(io::BufReader<File>),
|
File(io::BufReader<File>),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub enum Output {
|
||||||
|
Stdout(io::Stdout),
|
||||||
|
File(io::BufWriter<File>),
|
||||||
|
}
|
||||||
|
|
||||||
impl Input {
|
impl Input {
|
||||||
pub fn open_str(arg: &str) -> io::Result<Self> {
|
pub fn open_str(arg: &str) -> io::Result<Self> {
|
||||||
if arg == "-" {
|
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),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user