-
-
Notifications
You must be signed in to change notification settings - Fork 2k
Expand file tree
/
Copy pathcksum.rs
More file actions
139 lines (117 loc) · 4.78 KB
/
Copy pathcksum.rs
File metadata and controls
139 lines (117 loc) · 4.78 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
// This file is part of the uutils coreutils package.
//
// For the full copyright and license information, please view the LICENSE
// file that was distributed with this source code.
// spell-checker:ignore (ToDO) fname, algo, bitlen
use std::io::{Write, stderr};
use clap::Command;
use uu_checksum_common::{ChecksumCommand, checksum_main, default_checksum_app, options};
use uucore::checksum::compute::OutputFormat;
use uucore::checksum::{
AlgoKind, BlakeLength, ChecksumError, HashLength, MAX_SHAKE_OUTPUT_BITS, parse_blake_length,
sanitize_sha2_sha3_length_str,
};
use uucore::error::UResult;
use uucore::hardware::{HasHardwareFeatures as _, SimdPolicy};
use uucore::translate;
/// Print CPU hardware capability detection information to stderr
/// 2>/dev/full does not abort
/// This matches GNU cksum's --debug behavior
fn print_cpu_debug_info() {
fn print_feature(name: &str, available: bool) {
if available {
let _ = writeln!(stderr(), "using {name} hardware support");
} else {
let _ = writeln!(stderr(), "{name} support not detected");
}
}
let features = SimdPolicy::detect();
// x86/x86_64
print_feature("avx512", features.has_avx512());
print_feature("avx2", features.has_avx2());
print_feature("pclmul", features.has_pclmul());
// ARM aarch64
if cfg!(target_arch = "aarch64") {
print_feature("vmull", features.has_vmull());
}
}
/// Sanitize the `--length` argument depending on `--algorithm` and `--length`.
fn maybe_sanitize_length(
algo_cli: Option<AlgoKind>,
input_length: Option<&str>,
) -> UResult<Option<HashLength>> {
match (algo_cli, input_length) {
// No provided length is not a problem so far.
(_, None) => Ok(None),
// For SHA2 and SHA3, if a length is provided, ensure it is correct.
(Some(algo @ (AlgoKind::Sha2 | AlgoKind::Sha3)), Some(s_len)) => {
sanitize_sha2_sha3_length_str(algo, s_len).map(Some)
}
// SHAKE128 and SHAKE256 algorithms optionally take a bit length. Any
// value up to `MAX_SHAKE_OUTPUT_BITS` is valid; larger requests are
// rejected instead of aborting the process when the (huge) output
// buffer fails to allocate. If the given length is not a multiple of 8,
// the last byte of the output will have its extra bits set to zero.
(Some(AlgoKind::Shake128 | AlgoKind::Shake256), Some(len)) => match len.parse::<usize>() {
Ok(0) => Ok(None),
Ok(l) if l > MAX_SHAKE_OUTPUT_BITS => Err(ChecksumError::ShakeLengthTooBig.into()),
Ok(l) => Ok(Some(HashLength::from_bits(l))),
Err(_) => Err(ChecksumError::InvalidLength(len.into()).into()),
},
// For BLAKE, if a length is provided, validate it.
(Some(algo @ (AlgoKind::Blake2b | AlgoKind::Blake3)), Some(len)) => {
parse_blake_length(algo, BlakeLength::String(len)).map(Some)
}
// For any other provided algorithm, check if length is 0.
// Otherwise, this is an error.
(_, Some(len)) if len.parse::<u32>() == Ok(0_u32) => Ok(None),
(_, Some(_)) => Err(ChecksumError::LengthOnlyForBlake2bSha2Sha3.into()),
}
}
#[uucore::main]
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
let matches = uucore::clap_localization::handle_clap_result(uu_app(), args)?;
let algo_cli = matches
.get_one::<String>(options::ALGORITHM)
.map(AlgoKind::from_cksum)
.transpose()?;
let input_length = matches
.get_one::<String>(options::LENGTH)
.map(String::as_str);
let length = maybe_sanitize_length(algo_cli, input_length)?;
let tag = !matches.get_flag(options::UNTAGGED);
let binary = matches.get_flag(options::BINARY);
let text = matches.get_flag(options::TEXT);
//Specifying --text without ever mentioning --untagged fails.
if text && tag {
return Err(ChecksumError::TextWithoutUntagged.into());
}
let output_format = OutputFormat::from_cksum(
algo_cli.unwrap_or(AlgoKind::Crc),
tag,
binary,
/* raw */ matches.get_flag(options::RAW),
/* base64 */ matches.get_flag(options::BASE64),
);
// Print hardware debug info if requested
if matches.get_flag(options::DEBUG) {
print_cpu_debug_info();
}
checksum_main(algo_cli, length, matches, output_format)
}
pub fn uu_app() -> Command {
default_checksum_app(translate!("cksum-about"), translate!("cksum-usage"))
.name("cksum")
.with_algo()
.with_untagged()
.with_tag(true)
.with_length()
.with_raw()
.with_check_and_opts()
.with_base64()
.with_text(false)
.with_binary()
.with_zero()
.with_debug()
.after_help(translate!("cksum-after-help"))
}