1
Fork 0
mirror of https://github.com/RGBCube/uutils-coreutils synced 2025-07-28 19:47:45 +00:00

truncate: prevent underflow when reducing size

Prevent usize underflow when reducing the size of a file by more than
its current size. For example, if `f` is a file with 3 bytes, then

    truncate -s-5 f

will now set the size of the file to 0 instead of causing a panic.
This commit is contained in:
Jeffrey Finkelstein 2022-01-28 22:44:07 -05:00
parent f1d72018d7
commit 0454d3b243
2 changed files with 40 additions and 1 deletions

View file

@ -31,18 +31,38 @@ impl TruncateMode {
///
/// `fsize` is the size of the reference file, in bytes.
///
/// If the mode is [`TruncateMode::Reduce`] and the value to
/// reduce by is greater than `fsize`, then this function returns
/// 0 (since it cannot return a negative number).
///
/// # Examples
///
/// Extending a file of 10 bytes by 5 bytes:
///
/// ```rust,ignore
/// let mode = TruncateMode::Extend(5);
/// let fsize = 10;
/// assert_eq!(mode.to_size(fsize), 15);
/// ```
///
/// Reducing a file by more than its size results in 0:
///
/// ```rust,ignore
/// let mode = TruncateMode::Reduce(5);
/// let fsize = 3;
/// assert_eq!(mode.to_size(fsize), 0);
/// ```
fn to_size(&self, fsize: usize) -> usize {
match self {
TruncateMode::Absolute(size) => *size,
TruncateMode::Extend(size) => fsize + size,
TruncateMode::Reduce(size) => fsize - size,
TruncateMode::Reduce(size) => {
if *size > fsize {
0
} else {
fsize - size
}
}
TruncateMode::AtMost(size) => fsize.min(*size),
TruncateMode::AtLeast(size) => fsize.max(*size),
TruncateMode::RoundDown(size) => fsize - fsize % size,
@ -377,4 +397,11 @@ mod tests {
assert_eq!(parse_mode_and_size("/10"), Ok(TruncateMode::RoundDown(10)));
assert_eq!(parse_mode_and_size("%10"), Ok(TruncateMode::RoundUp(10)));
}
#[test]
fn test_to_size() {
assert_eq!(TruncateMode::Extend(5).to_size(10), 15);
assert_eq!(TruncateMode::Reduce(5).to_size(10), 5);
assert_eq!(TruncateMode::Reduce(5).to_size(3), 0);
}
}

View file

@ -377,3 +377,15 @@ fn test_division_by_zero_reference_and_size() {
.no_stdout()
.stderr_contains("division by zero");
}
/// Test that truncate with a relative size less than 0 is not an error.
#[test]
fn test_underflow_relative_size() {
let (at, mut ucmd) = at_and_ucmd!();
ucmd.args(&["-s-1", FILE1])
.succeeds()
.no_stdout()
.no_stderr();
assert!(at.file_exists(FILE1));
assert!(at.read_bytes(FILE1).is_empty());
}