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:
parent
f1d72018d7
commit
0454d3b243
2 changed files with 40 additions and 1 deletions
|
@ -31,18 +31,38 @@ impl TruncateMode {
|
||||||
///
|
///
|
||||||
/// `fsize` is the size of the reference file, in bytes.
|
/// `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
|
/// # Examples
|
||||||
///
|
///
|
||||||
|
/// Extending a file of 10 bytes by 5 bytes:
|
||||||
|
///
|
||||||
/// ```rust,ignore
|
/// ```rust,ignore
|
||||||
/// let mode = TruncateMode::Extend(5);
|
/// let mode = TruncateMode::Extend(5);
|
||||||
/// let fsize = 10;
|
/// let fsize = 10;
|
||||||
/// assert_eq!(mode.to_size(fsize), 15);
|
/// 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 {
|
fn to_size(&self, fsize: usize) -> usize {
|
||||||
match self {
|
match self {
|
||||||
TruncateMode::Absolute(size) => *size,
|
TruncateMode::Absolute(size) => *size,
|
||||||
TruncateMode::Extend(size) => fsize + 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::AtMost(size) => fsize.min(*size),
|
||||||
TruncateMode::AtLeast(size) => fsize.max(*size),
|
TruncateMode::AtLeast(size) => fsize.max(*size),
|
||||||
TruncateMode::RoundDown(size) => fsize - fsize % 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::RoundDown(10)));
|
||||||
assert_eq!(parse_mode_and_size("%10"), Ok(TruncateMode::RoundUp(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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -377,3 +377,15 @@ fn test_division_by_zero_reference_and_size() {
|
||||||
.no_stdout()
|
.no_stdout()
|
||||||
.stderr_contains("division by zero");
|
.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());
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue