mirror of
https://github.com/RGBCube/uutils-coreutils
synced 2025-07-28 03:27:44 +00:00
shred: Implemented --force option (#2012)
This commit is contained in:
parent
9ae4928b7b
commit
18191f9212
3 changed files with 112 additions and 14 deletions
|
@ -259,6 +259,7 @@ static AFTER_HELP: &str =
|
|||
";
|
||||
|
||||
pub mod options {
|
||||
pub const FORCE: &str = "force";
|
||||
pub const FILE: &str = "file";
|
||||
pub const ITERATIONS: &str = "iterations";
|
||||
pub const SIZE: &str = "size";
|
||||
|
@ -278,6 +279,12 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
|
|||
.about(ABOUT)
|
||||
.after_help(AFTER_HELP)
|
||||
.usage(&usage[..])
|
||||
.arg(
|
||||
Arg::with_name(options::FORCE)
|
||||
.long(options::FORCE)
|
||||
.short("f")
|
||||
.help("change permissions to allow writing if necessary"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name(options::ITERATIONS)
|
||||
.long(options::ITERATIONS)
|
||||
|
@ -354,8 +361,7 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
|
|||
|
||||
// TODO: implement --random-source
|
||||
|
||||
// TODO: implement --force
|
||||
|
||||
let force = matches.is_present(options::FORCE);
|
||||
let remove = matches.is_present(options::REMOVE);
|
||||
let size_arg = match matches.value_of(options::SIZE) {
|
||||
Some(s) => Some(s.to_string()),
|
||||
|
@ -375,7 +381,9 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
|
|||
}
|
||||
|
||||
for path_str in matches.values_of(options::FILE).unwrap() {
|
||||
wipe_file(&path_str, iterations, remove, size, exact, zero, verbose);
|
||||
wipe_file(
|
||||
&path_str, iterations, remove, size, exact, zero, verbose, force,
|
||||
);
|
||||
}
|
||||
|
||||
0
|
||||
|
@ -439,18 +447,40 @@ fn wipe_file(
|
|||
exact: bool,
|
||||
zero: bool,
|
||||
verbose: bool,
|
||||
force: bool,
|
||||
) {
|
||||
// Get these potential errors out of the way first
|
||||
let path: &Path = Path::new(path_str);
|
||||
if !path.exists() {
|
||||
println!("{}: {}: No such file or directory", NAME, path.display());
|
||||
show_error!("{}: No such file or directory", path.display());
|
||||
return;
|
||||
}
|
||||
if !path.is_file() {
|
||||
println!("{}: {}: Not a file", NAME, path.display());
|
||||
show_error!("{}: Not a file", path.display());
|
||||
return;
|
||||
}
|
||||
|
||||
// If force is true, set file permissions to not-readonly.
|
||||
if force {
|
||||
let metadata = match fs::metadata(path) {
|
||||
Ok(m) => m,
|
||||
Err(e) => {
|
||||
show_error!("{}", e);
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
let mut perms = metadata.permissions();
|
||||
perms.set_readonly(false);
|
||||
match fs::set_permissions(path, perms) {
|
||||
Err(e) => {
|
||||
show_error!("{}", e);
|
||||
return;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
// Fill up our pass sequence
|
||||
let mut pass_sequence: Vec<PassType> = Vec::new();
|
||||
|
||||
|
@ -489,11 +519,13 @@ fn wipe_file(
|
|||
|
||||
{
|
||||
let total_passes: usize = pass_sequence.len();
|
||||
let mut file: File = OpenOptions::new()
|
||||
.write(true)
|
||||
.truncate(false)
|
||||
.open(path)
|
||||
.expect("Failed to open file for writing");
|
||||
let mut file: File = match OpenOptions::new().write(true).truncate(false).open(path) {
|
||||
Ok(f) => f,
|
||||
Err(e) => {
|
||||
show_error!("{}: failed to open for writing: {}", path.display(), e);
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
// NOTE: it does not really matter what we set for total_bytes and gen_type here, so just
|
||||
// use bogus values
|
||||
|
@ -523,14 +555,23 @@ fn wipe_file(
|
|||
}
|
||||
}
|
||||
// size is an optional argument for exactly how many bytes we want to shred
|
||||
do_pass(&mut file, path, &mut generator, *pass_type, size)
|
||||
.expect("File write pass failed");
|
||||
match do_pass(&mut file, path, &mut generator, *pass_type, size) {
|
||||
Ok(_) => {}
|
||||
Err(e) => {
|
||||
show_error!("{}: File write pass failed: {}", path.display(), e);
|
||||
}
|
||||
}
|
||||
// Ignore failed writes; just keep trying
|
||||
}
|
||||
}
|
||||
|
||||
if remove {
|
||||
do_remove(path, path_str, verbose).expect("Failed to remove file");
|
||||
match do_remove(path, path_str, verbose) {
|
||||
Ok(_) => {}
|
||||
Err(e) => {
|
||||
show_error!("{}: failed to remove file: {}", path.display(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1 +1,51 @@
|
|||
// ToDO: add tests
|
||||
use crate::common::util::*;
|
||||
|
||||
#[test]
|
||||
fn test_shred_remove() {
|
||||
let scene = TestScenario::new(util_name!());
|
||||
let at = &scene.fixtures;
|
||||
|
||||
let file_a = "test_shred_remove_a";
|
||||
let file_b = "test_shred_remove_b";
|
||||
|
||||
// Create file_a and file_b.
|
||||
at.touch(file_a);
|
||||
at.touch(file_b);
|
||||
|
||||
// Shred file_a.
|
||||
scene.ucmd().arg("-u").arg(file_a).run();
|
||||
|
||||
// file_a was deleted, file_b exists.
|
||||
assert!(!at.file_exists(file_a));
|
||||
assert!(at.file_exists(file_b));
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "freebsd"))]
|
||||
#[test]
|
||||
fn test_shred_force() {
|
||||
let scene = TestScenario::new(util_name!());
|
||||
let at = &scene.fixtures;
|
||||
|
||||
let file = "test_shred_force";
|
||||
|
||||
// Create file_a.
|
||||
at.touch(file);
|
||||
assert!(at.file_exists(file));
|
||||
|
||||
// Make file_a readonly.
|
||||
at.set_readonly(file);
|
||||
|
||||
// Try shred -u.
|
||||
let result = scene.ucmd().arg("-u").arg(file).run();
|
||||
println!("stderr = {:?}", result.stderr);
|
||||
println!("stdout = {:?}", result.stdout);
|
||||
|
||||
// file_a was not deleted because it is readonly.
|
||||
assert!(at.file_exists(file));
|
||||
|
||||
// Try shred -u -f.
|
||||
scene.ucmd().arg("-u").arg("-f").arg(file).run();
|
||||
|
||||
// file_a was deleted.
|
||||
assert!(!at.file_exists(file));
|
||||
}
|
||||
|
|
|
@ -351,6 +351,13 @@ impl AtPath {
|
|||
String::from(self.minus(name).to_str().unwrap())
|
||||
}
|
||||
|
||||
pub fn set_readonly(&self, name: &str) {
|
||||
let metadata = fs::metadata(self.plus(name)).unwrap();
|
||||
let mut permissions = metadata.permissions();
|
||||
permissions.set_readonly(true);
|
||||
fs::set_permissions(self.plus(name), permissions).unwrap();
|
||||
}
|
||||
|
||||
pub fn open(&self, name: &str) -> File {
|
||||
log_info("open", self.plus_as_string(name));
|
||||
File::open(self.plus(name)).unwrap()
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue