mirror of
https://github.com/RGBCube/uutils-coreutils
synced 2025-07-29 12:07:46 +00:00
Address review comments
This commit is contained in:
parent
ab2cc2f17a
commit
2e704b8572
1 changed files with 95 additions and 102 deletions
|
@ -68,12 +68,11 @@ pub struct HashAlgorithm {
|
||||||
pub bits: usize,
|
pub bits: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
struct ChecksumResult {
|
struct ChecksumResult {
|
||||||
pub bad_format: i32,
|
pub bad_format: i32,
|
||||||
pub failed_cksum: i32,
|
pub failed_cksum: i32,
|
||||||
pub failed_open_file: i32,
|
pub failed_open_file: i32,
|
||||||
pub correct_format: i32,
|
|
||||||
pub properly_formatted: bool,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Error)]
|
#[derive(Debug, Error)]
|
||||||
|
@ -322,7 +321,7 @@ fn determine_regex(
|
||||||
.into())
|
.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Function to convert bytes to a hexadecimal string
|
// Converts bytes to a hexadecimal string
|
||||||
fn bytes_to_hex(bytes: &[u8]) -> String {
|
fn bytes_to_hex(bytes: &[u8]) -> String {
|
||||||
bytes
|
bytes
|
||||||
.iter()
|
.iter()
|
||||||
|
@ -331,8 +330,6 @@ fn bytes_to_hex(bytes: &[u8]) -> String {
|
||||||
.join("")
|
.join("")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Function to get the expected checksum
|
|
||||||
|
|
||||||
fn get_expected_checksum(
|
fn get_expected_checksum(
|
||||||
filename: &str,
|
filename: &str,
|
||||||
caps: ®ex::Captures,
|
caps: ®ex::Captures,
|
||||||
|
@ -358,22 +355,21 @@ fn get_expected_checksum(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a reader that reads from the specified file, or from stdin if `input_is_stdin` is true.
|
/// Returns a reader that reads from the specified file, or from stdin if `filename_to_check` is "-".
|
||||||
fn get_file_to_check(
|
fn get_file_to_check(
|
||||||
filename_to_check: &str,
|
filename: &str,
|
||||||
filename_to_check_unescaped: &str,
|
|
||||||
ignore_missing: bool,
|
ignore_missing: bool,
|
||||||
res: &mut ChecksumResult,
|
res: &mut ChecksumResult,
|
||||||
) -> Option<Box<dyn Read>> {
|
) -> Option<Box<dyn Read>> {
|
||||||
if filename_to_check == "-" {
|
if filename == "-" {
|
||||||
Some(Box::new(stdin())) // Use stdin if "-" is specified in the checksum file
|
Some(Box::new(stdin())) // Use stdin if "-" is specified in the checksum file
|
||||||
} else {
|
} else {
|
||||||
match File::open(filename_to_check_unescaped) {
|
match File::open(filename) {
|
||||||
Ok(f) => {
|
Ok(f) => {
|
||||||
if f.metadata().ok()?.is_dir() {
|
if f.metadata().ok()?.is_dir() {
|
||||||
show!(USimpleError::new(
|
show!(USimpleError::new(
|
||||||
1,
|
1,
|
||||||
format!("{}: Is a directory", filename_to_check_unescaped)
|
format!("{}: Is a directory", filename)
|
||||||
));
|
));
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
|
@ -383,8 +379,8 @@ fn get_file_to_check(
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
if !ignore_missing {
|
if !ignore_missing {
|
||||||
// yes, we have both stderr and stdout here
|
// yes, we have both stderr and stdout here
|
||||||
show!(err.map_err_context(|| filename_to_check.to_string()));
|
show!(err.map_err_context(|| filename.to_string()));
|
||||||
println!("{}: FAILED open or read", filename_to_check);
|
println!("{}: FAILED open or read", filename);
|
||||||
}
|
}
|
||||||
res.failed_open_file += 1;
|
res.failed_open_file += 1;
|
||||||
// we could not open the file but we want to continue
|
// we could not open the file but we want to continue
|
||||||
|
@ -395,75 +391,69 @@ fn get_file_to_check(
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a reader to the list of checksums
|
/// Returns a reader to the list of checksums
|
||||||
fn get_input_file(filename_input: &OsStr, input_is_stdin: bool) -> UResult<Box<dyn Read>> {
|
fn get_input_file(filename: &OsStr) -> UResult<Box<dyn Read>> {
|
||||||
if input_is_stdin {
|
match File::open(filename) {
|
||||||
Ok(Box::new(stdin())) // Use stdin if "-" is specified
|
Ok(f) => {
|
||||||
} else {
|
if f.metadata()?.is_dir() {
|
||||||
match File::open(filename_input) {
|
Err(io::Error::new(
|
||||||
Ok(f) => Ok(Box::new(f)),
|
io::ErrorKind::Other,
|
||||||
Err(_) => Err(io::Error::new(
|
format!("{}: Is a directory", filename.to_string_lossy()),
|
||||||
io::ErrorKind::Other,
|
)
|
||||||
format!(
|
.into())
|
||||||
"{}: No such file or directory",
|
} else {
|
||||||
filename_input.to_string_lossy()
|
Ok(Box::new(f))
|
||||||
),
|
}
|
||||||
)
|
|
||||||
.into()),
|
|
||||||
}
|
}
|
||||||
|
Err(_) => Err(io::Error::new(
|
||||||
|
io::ErrorKind::Other,
|
||||||
|
format!("{}: No such file or directory", filename.to_string_lossy()),
|
||||||
|
)
|
||||||
|
.into()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Extracts the algorithm name and length from the regex captures if the algo-based format is matched.
|
/// Extracts the algorithm name and length from the regex captures if the algo-based format is matched.
|
||||||
fn get_algo_name_and_length(
|
fn identify_algo_name_and_length(
|
||||||
caps: ®ex::Captures,
|
caps: ®ex::Captures,
|
||||||
is_algo_based_format: bool,
|
|
||||||
algo_name_input: Option<&str>,
|
algo_name_input: Option<&str>,
|
||||||
length_input: Option<usize>,
|
|
||||||
res: &mut ChecksumResult,
|
res: &mut ChecksumResult,
|
||||||
|
properly_formatted: &mut bool,
|
||||||
) -> (String, Option<usize>) {
|
) -> (String, Option<usize>) {
|
||||||
if is_algo_based_format {
|
// When the algo-based format is matched, extract details from regex captures
|
||||||
// When the algo-based format is matched, extract details from regex captures
|
let algorithm = caps.name("algo").map_or("", |m| m.as_str()).to_lowercase();
|
||||||
let algorithm = caps.name("algo").map_or("", |m| m.as_str()).to_lowercase();
|
|
||||||
|
|
||||||
// check if we are called with XXXsum (example: md5sum) but we detected a different algo parsing the file
|
// check if we are called with XXXsum (example: md5sum) but we detected a different algo parsing the file
|
||||||
// (for example SHA1 (f) = d...)
|
// (for example SHA1 (f) = d...)
|
||||||
// Also handle the case cksum -s sm3 but the file contains other formats
|
// Also handle the case cksum -s sm3 but the file contains other formats
|
||||||
if algo_name_input.is_some() && algo_name_input != Some(&algorithm) {
|
if algo_name_input.is_some() && algo_name_input != Some(&algorithm) {
|
||||||
res.bad_format += 1;
|
res.bad_format += 1;
|
||||||
res.properly_formatted = false;
|
*properly_formatted = false;
|
||||||
return (String::new(), None);
|
return (String::new(), None);
|
||||||
}
|
|
||||||
|
|
||||||
if !SUPPORTED_ALGORITHMS.contains(&algorithm.as_str()) {
|
|
||||||
// Not supported algo, leave early
|
|
||||||
res.properly_formatted = false;
|
|
||||||
return (String::new(), None);
|
|
||||||
}
|
|
||||||
|
|
||||||
let bits = caps.name("bits").map_or(Some(None), |m| {
|
|
||||||
let bits_value = m.as_str().parse::<usize>().unwrap();
|
|
||||||
if bits_value % 8 == 0 {
|
|
||||||
Some(Some(bits_value / 8))
|
|
||||||
} else {
|
|
||||||
res.properly_formatted = false;
|
|
||||||
None // Return None to signal a divisibility issue
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if bits.is_none() {
|
|
||||||
// If bits is None, we have a parsing or divisibility issue
|
|
||||||
// Exit the loop outside of the closure
|
|
||||||
return (String::new(), None);
|
|
||||||
}
|
|
||||||
|
|
||||||
(algorithm, bits.unwrap())
|
|
||||||
} else if let Some(a) = algo_name_input {
|
|
||||||
// When a specific algorithm name is input, use it and use the provided bits
|
|
||||||
(a.to_lowercase(), length_input)
|
|
||||||
} else {
|
|
||||||
// Default case if no algorithm is specified and non-algo based format is matched
|
|
||||||
(String::new(), None)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !SUPPORTED_ALGORITHMS.contains(&algorithm.as_str()) {
|
||||||
|
// Not supported algo, leave early
|
||||||
|
*properly_formatted = false;
|
||||||
|
return (String::new(), None);
|
||||||
|
}
|
||||||
|
|
||||||
|
let bits = caps.name("bits").map_or(Some(None), |m| {
|
||||||
|
let bits_value = m.as_str().parse::<usize>().unwrap();
|
||||||
|
if bits_value % 8 == 0 {
|
||||||
|
Some(Some(bits_value / 8))
|
||||||
|
} else {
|
||||||
|
*properly_formatted = false;
|
||||||
|
None // Return None to signal a divisibility issue
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if bits.is_none() {
|
||||||
|
// If bits is None, we have a parsing or divisibility issue
|
||||||
|
// Exit the loop outside of the closure
|
||||||
|
return (String::new(), None);
|
||||||
|
}
|
||||||
|
|
||||||
|
(algorithm, bits.unwrap())
|
||||||
}
|
}
|
||||||
|
|
||||||
/***
|
/***
|
||||||
|
@ -486,16 +476,17 @@ where
|
||||||
{
|
{
|
||||||
// if cksum has several input files, it will print the result for each file
|
// if cksum has several input files, it will print the result for each file
|
||||||
for filename_input in files {
|
for filename_input in files {
|
||||||
let mut res = ChecksumResult {
|
let mut correct_format = 0;
|
||||||
bad_format: 0,
|
let mut properly_formatted = false;
|
||||||
failed_cksum: 0,
|
let mut res = ChecksumResult::default();
|
||||||
failed_open_file: 0,
|
|
||||||
correct_format: 0,
|
|
||||||
properly_formatted: false,
|
|
||||||
};
|
|
||||||
let input_is_stdin = filename_input == OsStr::new("-");
|
let input_is_stdin = filename_input == OsStr::new("-");
|
||||||
|
|
||||||
let file: Box<dyn Read> = get_input_file(filename_input, input_is_stdin)?;
|
let file: Box<dyn Read> = if input_is_stdin {
|
||||||
|
// Use stdin if "-" is specified
|
||||||
|
Box::new(stdin())
|
||||||
|
} else {
|
||||||
|
get_input_file(filename_input)?
|
||||||
|
};
|
||||||
|
|
||||||
let reader = BufReader::new(file);
|
let reader = BufReader::new(file);
|
||||||
let lines: Vec<String> = reader.lines().collect::<Result<_, _>>()?;
|
let lines: Vec<String> = reader.lines().collect::<Result<_, _>>()?;
|
||||||
|
@ -504,7 +495,7 @@ where
|
||||||
|
|
||||||
for (i, line) in lines.iter().enumerate() {
|
for (i, line) in lines.iter().enumerate() {
|
||||||
if let Some(caps) = chosen_regex.captures(line) {
|
if let Some(caps) = chosen_regex.captures(line) {
|
||||||
res.properly_formatted = true;
|
properly_formatted = true;
|
||||||
|
|
||||||
let mut filename_to_check = caps.name("filename").unwrap().as_str();
|
let mut filename_to_check = caps.name("filename").unwrap().as_str();
|
||||||
if filename_to_check.starts_with('*')
|
if filename_to_check.starts_with('*')
|
||||||
|
@ -520,17 +511,24 @@ where
|
||||||
|
|
||||||
// If the algo_name is provided, we use it, otherwise we try to detect it
|
// If the algo_name is provided, we use it, otherwise we try to detect it
|
||||||
|
|
||||||
let (algo_name, length) = get_algo_name_and_length(
|
let (algo_name, length) = if is_algo_based_format {
|
||||||
&caps,
|
identify_algo_name_and_length(
|
||||||
is_algo_based_format,
|
&caps,
|
||||||
algo_name_input,
|
algo_name_input,
|
||||||
length_input,
|
&mut res,
|
||||||
&mut res,
|
&mut properly_formatted,
|
||||||
);
|
)
|
||||||
|
} else if let Some(a) = algo_name_input {
|
||||||
|
// When a specific algorithm name is input, use it and use the provided bits
|
||||||
|
(a.to_lowercase(), length_input)
|
||||||
|
} else {
|
||||||
|
// Default case if no algorithm is specified and non-algo based format is matched
|
||||||
|
(String::new(), None)
|
||||||
|
};
|
||||||
|
|
||||||
if algo_name.is_empty() {
|
if algo_name.is_empty() {
|
||||||
// we haven't been able to detect the algo name. No point to continue
|
// we haven't been able to detect the algo name. No point to continue
|
||||||
res.properly_formatted = false;
|
properly_formatted = false;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
let mut algo = detect_algo(&algo_name, length)?;
|
let mut algo = detect_algo(&algo_name, length)?;
|
||||||
|
@ -538,17 +536,12 @@ where
|
||||||
let (filename_to_check_unescaped, prefix) = unescape_filename(filename_to_check);
|
let (filename_to_check_unescaped, prefix) = unescape_filename(filename_to_check);
|
||||||
|
|
||||||
// manage the input file
|
// manage the input file
|
||||||
|
let file_to_check =
|
||||||
let file_to_check = match get_file_to_check(
|
match get_file_to_check(&filename_to_check_unescaped, ignore_missing, &mut res)
|
||||||
filename_to_check,
|
{
|
||||||
&filename_to_check_unescaped,
|
Some(file) => file,
|
||||||
ignore_missing,
|
None => continue,
|
||||||
&mut res,
|
};
|
||||||
) {
|
|
||||||
Some(file) => file,
|
|
||||||
None => continue,
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut file_reader = BufReader::new(file_to_check);
|
let mut file_reader = BufReader::new(file_to_check);
|
||||||
// Read the file and calculate the checksum
|
// Read the file and calculate the checksum
|
||||||
let create_fn = &mut algo.create_fn;
|
let create_fn = &mut algo.create_fn;
|
||||||
|
@ -561,7 +554,7 @@ where
|
||||||
if !quiet && !status {
|
if !quiet && !status {
|
||||||
println!("{prefix}{filename_to_check}: OK");
|
println!("{prefix}{filename_to_check}: OK");
|
||||||
}
|
}
|
||||||
res.correct_format += 1;
|
correct_format += 1;
|
||||||
} else {
|
} else {
|
||||||
if !status {
|
if !status {
|
||||||
println!("{prefix}{filename_to_check}: FAILED");
|
println!("{prefix}{filename_to_check}: FAILED");
|
||||||
|
@ -594,7 +587,7 @@ where
|
||||||
|
|
||||||
// not a single line correctly formatted found
|
// not a single line correctly formatted found
|
||||||
// return an error
|
// return an error
|
||||||
if !res.properly_formatted {
|
if !properly_formatted {
|
||||||
if !status {
|
if !status {
|
||||||
return Err(ChecksumError::NoProperlyFormattedChecksumLinesFound {
|
return Err(ChecksumError::NoProperlyFormattedChecksumLinesFound {
|
||||||
filename: get_filename_for_output(filename_input, input_is_stdin),
|
filename: get_filename_for_output(filename_input, input_is_stdin),
|
||||||
|
@ -606,7 +599,7 @@ where
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
if ignore_missing && res.correct_format == 0 {
|
if ignore_missing && correct_format == 0 {
|
||||||
// we have only bad format
|
// we have only bad format
|
||||||
// and we had ignore-missing
|
// and we had ignore-missing
|
||||||
eprintln!(
|
eprintln!(
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue