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 crate::shred::{Shredder, Verbosity};
use crate::shred::{Shredder, Verbosity, ShredOptions};
use std::process::exit;
use std::str::FromStr;
mod shred;
@ -25,7 +27,14 @@ fn main() {
.arg(Arg::with_name("i")
.short("i")
.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();
@ -38,15 +47,41 @@ fn main() {
let is_recursively = params.is_present("r");
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
// required we could have used an 'if let' to conditionally get the value)
let path = params.value_of("PATH").unwrap();
Shredder::new(
path.to_string(),
is_recursively,
is_interactive,
verbosity
Shredder::with_options(
ShredOptions::new(path.to_string())
.set_is_interactive(is_interactive)
.set_is_recursive(is_recursively)
.set_keep_files(keep_files)
.set_verbosity(verbosity)
.set_rewrite_iterations(iterations_count)
.build()
).run();
}

View File

@ -1,52 +1,48 @@
use std::cmp::Ordering;
use std::fs;
use std::fs::File;
use std::io::{BufWriter, Write};
use std::io::{BufWriter, Write, Seek, SeekFrom};
use std::io;
use std::process::exit;
pub struct Shredder {
path: String,
is_recursively: bool,
is_interactive: bool,
verbosity: Verbosity,
options: ShredOptions,
}
impl Shredder {
pub fn new(path: String, is_recursively: bool, is_interactive: bool, verbosity: Verbosity) -> Shredder {
pub fn with_options(options: ShredOptions) -> Shredder {
Shredder {
path,
is_recursively,
is_interactive,
verbosity
options
}
}
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) => {
if self.verbosity >= Verbosity::Average {
if *verbosity >= Verbosity::Average {
println!("Is directory: {}", metadata.is_dir());
println!("Is file: {}", metadata.is_file());
if self.verbosity == Verbosity::High {
println!("Is recursively: {}", self.is_recursively);
println!("Is interactive: {}", self.is_interactive);
println!("Verbosity: {:?}", &self.verbosity);
if *verbosity == Verbosity::High {
println!("Is recursively: {}", self.options.is_recursive);
println!("Is interactive: {}", self.options.is_interactive);
println!("Verbosity: {:?}", &self.options.verbosity);
}
}
}
Err(_) => {
println!("Provided path is invalid!");
println!("No such file or directory.");
exit(1);
}
}
if self.verbosity > Verbosity::None {
println!("Using input file: {}", &self.path);
if *verbosity > Verbosity::None {
println!("Using input file: {}", &self.options.path);
}
if fs::metadata(&self.path).unwrap().is_file() {
Shredder::shred_file(&self.path, self.is_interactive);
} else if self.is_recursively {
if metadata_result.unwrap().is_file() {
Shredder::shred_file(&self.options);
} else if self.options.is_recursive {
} else {
println!("Target is a directory!");
@ -54,24 +50,30 @@ impl Shredder {
}
}
fn shred_file(path: &String, is_interactive: bool) {
match std::fs::canonicalize(path) {
fn shred_file(options: &ShredOptions) {
match std::fs::canonicalize(&options.path) {
Ok(path) => {
if is_interactive {
let file_length = path.metadata().unwrap().len();
let absolute_path = path.to_str().unwrap();
println!("Do you really want to shred '{}'? [Y/n]", absolute_path);
if options.is_interactive {
print!("Do you really want to shred '{}'? [Y/n] ", absolute_path);
io::stdout().flush().unwrap();
let mut input = String::new();
io::stdin().read_line(&mut input).expect("Failed to read input.");
let input = input.trim();
if input.len() == 1 && input.to_lowercase().eq("y") {
if input.len() != 1 || !input.to_lowercase().eq("y") {
return;
}
}
match File::create(absolute_path) {
Ok(file) => {
println!("File's size: {}", file_length);
let mut buffer = BufWriter::new(&file);
for _ in 0..options.rewrite_iterations {
let random_bytes: Vec<u8> = (0..file_length).map(|_| {
rand::random::<u8>()
}).collect();
@ -79,14 +81,17 @@ impl Shredder {
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);
}
}
}
}
}
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)]
pub enum Verbosity {