Skip to content

Commit

Permalink
shref: manage the case when the input is too small
Browse files Browse the repository at this point in the history
  • Loading branch information
sylvestre committed Dec 4, 2024
1 parent ca19cfb commit 7e05ab9
Show file tree
Hide file tree
Showing 2 changed files with 46 additions and 26 deletions.
52 changes: 27 additions & 25 deletions src/uu/shred/src/shred.rs
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,7 @@ enum BytesWriter {
RandomSource {
file: File,
buffer: Vec<u8>,
path: PathBuf,
},
}

Expand All @@ -194,15 +195,12 @@ impl BytesWriter {
PassType::Random => {
if let Some(path) = random_source {
// Attempt to open the specified file as the random source
match File::open(path) {
Ok(file) => {
let metadata = file.metadata().unwrap();
let buffer_size = metadata.len() as usize;
Self::RandomSource {
file,
buffer: vec![0; buffer_size],
}
}
match File::open(&path) {
Ok(file) => Self::RandomSource {
file,
buffer: Vec::new(),
path,
},
Err(e) => {
// TODO remove panic
panic!("Failed to open random source file: {:?}", e);
Expand Down Expand Up @@ -234,37 +232,42 @@ impl BytesWriter {
}
}

fn bytes_for_pass(&mut self, size: usize) -> &[u8] {
fn bytes_for_pass(&mut self, size: usize) -> Result<&[u8], io::Error> {
match self {
Self::Random { rng, buffer } => {
let bytes = &mut buffer[..size];
rng.fill(bytes);
bytes
Ok(bytes)
}
Self::Pattern { offset, buffer } => {
let bytes = &buffer[*offset..size + *offset];
*offset = (*offset + size) % PATTERN_LENGTH;
bytes
Ok(bytes)
}
Self::RandomSource { file, buffer } => {
Self::RandomSource { file, buffer, path } => {
buffer.resize(size, 0); // Resize buffer to desired size, filling with zeros if needed
let mut total_read = 0;
while total_read < size {
match file.read(&mut buffer[total_read..]) {
Ok(0) => {
// EOF reached, consider whether to wrap around or accept partial fill
break;
// EOF reached before we could read enough data
return Err(io::Error::new(
io::ErrorKind::UnexpectedEof,
format!("{}: end of file", path.maybe_quote()),
));
}
Ok(n) => {
total_read += n;
}
Err(e) => {
// TODO remove panic
panic!("Failed to read random bytes from source file: {:?}", e);
return Err(io::Error::new(
e.kind(),
format!("{}: {}", path.maybe_quote(), e),
));
}
}
}
&buffer[..total_read]
Ok(&buffer[..total_read])
}
}
}
Expand Down Expand Up @@ -542,16 +545,15 @@ fn wipe_file(path_str: &str, opts: &WipeOptions) -> UResult<()> {
pass_name
);
}
// size is an optional argument for exactly how many bytes we want to shred
// Ignore failed writes; just keep trying
show_if_err!(do_pass(
// Propagate errors instead of ignoring them
do_pass(
&mut file,
&pass_type,
opts.exact,
size,
opts.random_source.as_ref()
opts.random_source.as_ref(),
)
.map_err_context(|| format!("{}: File write pass failed", path.maybe_quote())));
.map_err_context(|| format!("{}: File write pass failed", path.maybe_quote()))?;
}

if opts.remove_method != RemoveMethod::None {
Expand All @@ -575,7 +577,7 @@ fn do_pass(

// We start by writing BLOCK_SIZE times as many time as possible.
for _ in 0..(file_size / BLOCK_SIZE as u64) {
let block = writer.bytes_for_pass(BLOCK_SIZE);
let block = writer.bytes_for_pass(BLOCK_SIZE)?;
file.write_all(block)?;
}

Expand All @@ -584,7 +586,7 @@ fn do_pass(
let bytes_left = (file_size % BLOCK_SIZE as u64) as usize;
if bytes_left > 0 {
let size = if exact { bytes_left } else { BLOCK_SIZE };
let block = writer.bytes_for_pass(size);
let block = writer.bytes_for_pass(size)?;
file.write_all(block)?;
}

Expand Down
20 changes: 19 additions & 1 deletion tests/by-util/test_shred.rs
Original file line number Diff line number Diff line change
Expand Up @@ -223,8 +223,26 @@ fn test_random_source() {

ucmd.arg("--verbose")
.arg("--random-source")
.arg(random_source)
.arg(file)
.arg(random_source)
.succeeds()
.stderr_contains("1/3 (random)");
}

#[test]
fn test_random_source_eof() {
let (at, mut ucmd) = at_and_ucmd!();

let test_file = "test_file";
at.write(test_file, "abc");

let random_source = "source";
at.touch(random_source);

ucmd.arg("--verbose")
.arg("--random-source=source")
.arg(test_file)
.fails()
.stderr_contains("end of file")
.code_is(1);
}

0 comments on commit 7e05ab9

Please sign in to comment.