Added some flags usage & refactoring.

This commit is contained in:
Alexey Zinchenko 2021-01-31 00:34:06 +03:00
parent 794546fe3a
commit 31bfb7bf4c
2 changed files with 140 additions and 50 deletions

View File

@ -2,7 +2,9 @@ extern crate clap;
use clap::{App, Arg, crate_authors, crate_name, crate_version}; use clap::{App, Arg, crate_authors, crate_name, crate_version};
use crate::shred::{Shredder, Verbosity}; use crate::shred::{Shredder, Verbosity, ShredOptions};
use std::process::exit;
use std::str::FromStr;
mod shred; mod shred;
@ -25,7 +27,14 @@ fn main() {
.arg(Arg::with_name("i") .arg(Arg::with_name("i")
.short("i") .short("i")
.long("interactive") .long("interactive")
.help("Enables interactive mode") .help("Enables interactive mode"))
.arg(Arg::with_name("k")
.short("k")
.long("keep")
.help("Don't delete files after shredding"))
.arg(Arg::with_name("n")
.short("n")
.help("How many times the file must be overridden")
) )
.get_matches(); .get_matches();
@ -38,15 +47,41 @@ fn main() {
let is_recursively = params.is_present("r"); let is_recursively = params.is_present("r");
let is_interactive = params.is_present("i"); let is_interactive = params.is_present("i");
let keep_files = params.is_present("k");
let iterations_count = if params.is_present("n") {
let value_option = params.value_of("n");
match value_option {
None => {
println!("No argument passed to the 'n' option!");
exit(1);
}
Some(value) => {
match u8::from_str(value) {
Ok(number) => {
number
}
Err(error) => {
println!("{}", error.to_string());
exit(1);
}
}
}
}
} else {
3
};
// Calling .unwrap() is safe here because "INPUT" is required (if "INPUT" wasn't // Calling .unwrap() is safe here because "INPUT" is required (if "INPUT" wasn't
// required we could have used an 'if let' to conditionally get the value) // required we could have used an 'if let' to conditionally get the value)
let path = params.value_of("PATH").unwrap(); let path = params.value_of("PATH").unwrap();
Shredder::new( Shredder::with_options(
path.to_string(), ShredOptions::new(path.to_string())
is_recursively, .set_is_interactive(is_interactive)
is_interactive, .set_is_recursive(is_recursively)
verbosity .set_keep_files(keep_files)
.set_verbosity(verbosity)
.set_rewrite_iterations(iterations_count)
.build()
).run(); ).run();
} }

View File

@ -1,52 +1,48 @@
use std::cmp::Ordering; use std::cmp::Ordering;
use std::fs; use std::fs;
use std::fs::File; use std::fs::File;
use std::io::{BufWriter, Write}; use std::io::{BufWriter, Write, Seek, SeekFrom};
use std::io; use std::io;
use std::process::exit; use std::process::exit;
pub struct Shredder { pub struct Shredder {
path: String, options: ShredOptions,
is_recursively: bool,
is_interactive: bool,
verbosity: Verbosity,
} }
impl Shredder { impl Shredder {
pub fn new(path: String, is_recursively: bool, is_interactive: bool, verbosity: Verbosity) -> Shredder { pub fn with_options(options: ShredOptions) -> Shredder {
Shredder { Shredder {
path, options
is_recursively,
is_interactive,
verbosity
} }
} }
pub fn run(&self) { pub fn run(&self) {
match fs::metadata(&self.path) { let verbosity = &self.options.verbosity;
let metadata_result = fs::metadata(&self.options.path);
match &metadata_result {
Ok(metadata) => { Ok(metadata) => {
if self.verbosity >= Verbosity::Average { if *verbosity >= Verbosity::Average {
println!("Is directory: {}", metadata.is_dir()); println!("Is directory: {}", metadata.is_dir());
println!("Is file: {}", metadata.is_file()); println!("Is file: {}", metadata.is_file());
if self.verbosity == Verbosity::High { if *verbosity == Verbosity::High {
println!("Is recursively: {}", self.is_recursively); println!("Is recursively: {}", self.options.is_recursive);
println!("Is interactive: {}", self.is_interactive); println!("Is interactive: {}", self.options.is_interactive);
println!("Verbosity: {:?}", &self.verbosity); println!("Verbosity: {:?}", &self.options.verbosity);
} }
} }
} }
Err(_) => { Err(_) => {
println!("Provided path is invalid!"); println!("No such file or directory.");
exit(1); exit(1);
} }
} }
if self.verbosity > Verbosity::None { if *verbosity > Verbosity::None {
println!("Using input file: {}", &self.path); println!("Using input file: {}", &self.options.path);
} }
if fs::metadata(&self.path).unwrap().is_file() { if metadata_result.unwrap().is_file() {
Shredder::shred_file(&self.path, self.is_interactive); Shredder::shred_file(&self.options);
} else if self.is_recursively { } else if self.options.is_recursive {
} else { } else {
println!("Target is a directory!"); println!("Target is a directory!");
@ -54,37 +50,46 @@ impl Shredder {
} }
} }
fn shred_file(path: &String, is_interactive: bool) { fn shred_file(options: &ShredOptions) {
match std::fs::canonicalize(path) { match std::fs::canonicalize(&options.path) {
Ok(path) => { Ok(path) => {
if is_interactive { let file_length = path.metadata().unwrap().len();
let file_length = path.metadata().unwrap().len(); let absolute_path = path.to_str().unwrap();
let absolute_path = path.to_str().unwrap(); if options.is_interactive {
println!("Do you really want to shred '{}'? [Y/n]", absolute_path); print!("Do you really want to shred '{}'? [Y/n] ", absolute_path);
io::stdout().flush().unwrap();
let mut input = String::new(); let mut input = String::new();
io::stdin().read_line(&mut input).expect("Failed to read input."); io::stdin().read_line(&mut input).expect("Failed to read input.");
let input = input.trim(); let input = input.trim();
if input.len() == 1 && input.to_lowercase().eq("y") { if input.len() != 1 || !input.to_lowercase().eq("y") {
match File::create(absolute_path) { return;
Ok(file) => { }
println!("File's size: {}", file_length); }
let mut buffer = BufWriter::new(&file);
let random_bytes: Vec<u8> = (0..file_length).map(|_| { match File::create(absolute_path) {
rand::random::<u8>() Ok(file) => {
}).collect(); println!("File's size: {}", file_length);
buffer.write(&random_bytes).unwrap(); let mut buffer = BufWriter::new(&file);
buffer.flush().unwrap(); for _ in 0..options.rewrite_iterations {
file.sync_all().unwrap(); let random_bytes: Vec<u8> = (0..file_length).map(|_| {
} rand::random::<u8>()
Err(error) => { }).collect();
println!("{}", error); buffer.write(&random_bytes).unwrap();
}
buffer.flush().unwrap();
file.sync_all().unwrap();
buffer.seek(SeekFrom::Start(0)).unwrap();
} }
if !options.keep_files {
fs::remove_file(absolute_path).unwrap();
}
}
Err(error) => {
println!("{}", error);
} }
} }
} }
@ -95,6 +100,56 @@ impl Shredder {
} }
} }
pub struct ShredOptions {
verbosity: Verbosity,
is_recursive: bool,
is_interactive: bool,
rewrite_iterations: u8,
keep_files: bool,
path: String,
}
impl ShredOptions {
pub fn new(path: String) -> ShredOptions {
ShredOptions {
path,
is_interactive: true,
is_recursive: false,
rewrite_iterations: 3,
keep_files: false,
verbosity: Verbosity::None,
}
}
pub fn set_verbosity(mut self, verbosity: Verbosity) -> ShredOptions {
self.verbosity = verbosity;
self
}
pub fn set_is_recursive(mut self, is_recursive: bool) -> ShredOptions {
self.is_recursive = is_recursive;
self
}
pub fn set_is_interactive(mut self, is_interactive: bool) -> ShredOptions {
self.is_interactive = is_interactive;
self
}
pub fn set_keep_files(mut self, is_keep_files: bool) -> ShredOptions {
self.keep_files = is_keep_files;
self
}
pub fn set_rewrite_iterations(mut self, count: u8) -> ShredOptions {
self.rewrite_iterations = count;
self
}
pub fn build(self) -> ShredOptions {
self
}
}
#[derive(Debug, Eq)] #[derive(Debug, Eq)]
pub enum Verbosity { pub enum Verbosity {