Skip to content

Commit 2ba572a

Browse files
authored
Merge pull request #184 from dbohdan/hash-file-flag
Add flag `--hash-file`
2 parents a774c29 + 5e1407e commit 2ba572a

File tree

4 files changed

+84
-30
lines changed

4 files changed

+84
-30
lines changed

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ Options:
1919
-o <OUT> Where to write the output. If not supplied, we will search for possible disks and ask you for where you want to burn
2020
-z, --compression <COMPRESSION> What compression format the input file is in [default: ask] [possible values: ask, auto, none, gz, bz2, xz]
2121
-s, --hash <HASH> The hash of the input file. For more information, see long help (--help) [default: ask]
22+
--hash-file <HASH_FILE> Where to look for the hash of the input file
2223
--hash-of <HASH_OF> Is the hash calculated from the raw file, or the compressed file? [possible values: raw, compressed]
2324
--show-all-disks If provided, we will show all disks, removable or not
2425
--interactive <INTERACTIVE> If we should run in interactive mode or not [default: auto] [possible values: auto, always, never]
@@ -46,7 +47,7 @@ Options:
4647
There are a couple of ways to install Caligula.
4748

4849
- **Binary release:** You can download pre-built binaries from [the latest Github release](https://github.com/ifd3f/caligula/releases/latest).
49-
- **Arch Linux:**
50+
- **Arch Linux:**
5051
- [Official repository](https://archlinux.org/packages/extra/x86_64/caligula): `pacman -S caligula`
5152
- [caligula-bin on the AUR](https://aur.archlinux.org/packages/caligula-bin): We also automatically publish binaries with every release.
5253
- [caligula-git on the AUR](https://aur.archlinux.org/packages/caligula-git): Build from latest commit on `main` branch

src/hashfile.rs

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,12 +34,12 @@ const HASH_FILES: [(HashAlg, &str); 24] = [
3434
(HashAlg::Sha512, "SHA512SUMS"),
3535
];
3636

37-
pub fn find_hash(input: &Path) -> Option<(HashAlg, &str, Vec<u8>)> {
37+
pub fn find_hash_in_standard_files(input: &Path) -> Option<(Vec<HashAlg>, &str, Vec<u8>)> {
3838
for (alg, hash_file) in HASH_FILES {
3939
let hash_filepath = input.parent()?.join(hash_file);
4040
match File::open(&hash_filepath) {
4141
Ok(file) => match parse_hashfile(BufReader::new(file), input.file_name()?.to_str()?) {
42-
Ok(Some(expected_hash)) => return Some((alg, hash_file, expected_hash)),
42+
Ok(Some(expected_hash)) => return Some((vec![alg], hash_file, expected_hash)),
4343
Ok(None) => tracing::warn!("Hash not found in {}", hash_filepath.display()),
4444
Err(e) => tracing::warn!("{e}"),
4545
},
@@ -50,6 +50,28 @@ pub fn find_hash(input: &Path) -> Option<(HashAlg, &str, Vec<u8>)> {
5050
None
5151
}
5252

53+
pub fn find_hash_in_user_file<'a>(
54+
input: &Path,
55+
hash_filepath: &'a Path,
56+
) -> Option<(Vec<HashAlg>, &'a str, Vec<u8>)> {
57+
match File::open(&hash_filepath) {
58+
Ok(file) => match parse_hashfile(BufReader::new(file), input.file_name()?.to_str()?) {
59+
Ok(Some(expected_hash)) => {
60+
return Some((
61+
HashAlg::detect_from_length(expected_hash.len()).to_vec(),
62+
hash_filepath.file_name()?.to_str()?,
63+
expected_hash,
64+
));
65+
}
66+
Ok(None) => tracing::warn!("Hash not found in {}", hash_filepath.display()),
67+
Err(e) => tracing::warn!("{e}"),
68+
},
69+
Err(e) => tracing::warn!("{e}"),
70+
}
71+
72+
None
73+
}
74+
5375
fn parse_hashfile(hash_file: impl BufRead, input_file: &str) -> anyhow::Result<Option<Vec<u8>>> {
5476
for line in hash_file.lines() {
5577
match line?.split_once(char::is_whitespace) {

src/ui/cli.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,10 @@ pub struct BurnArgs {
6969
)]
7070
pub hash: HashArg,
7171

72+
/// Where to look for the hash of the input file.
73+
#[arg(long, value_parser = parse_path_exists)]
74+
pub hash_file: Option<PathBuf>,
75+
7276
/// Is the hash calculated from the raw file, or the compressed file?
7377
#[arg(long)]
7478
pub hash_of: Option<HashOf>,

src/ui/simple_ui/ask_hash.rs

Lines changed: 54 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -13,31 +13,53 @@ use inquire::{Confirm, Select, Text};
1313
use crate::{
1414
compression::{decompress, CompressionFormat},
1515
hash::{parse_hash_input, FileHashInfo, HashAlg, Hashing},
16-
hashfile::find_hash,
16+
hashfile::{find_hash_in_standard_files, find_hash_in_user_file},
1717
ui::cli::{BurnArgs, HashArg, HashOf},
1818
};
1919

2020
#[tracing::instrument(skip_all, fields(cf))]
2121
pub fn ask_hash(args: &BurnArgs, cf: CompressionFormat) -> anyhow::Result<Option<FileHashInfo>> {
22-
let hash_params = match &args.hash {
23-
HashArg::Skip => None,
24-
HashArg::Ask => {
25-
match find_hash(&args.input) {
26-
Some((alg, expected_hashfile, expected_hash))
27-
if Confirm::new(&format!(
28-
"Detected hash file {expected_hashfile} in the directory. Do you want to use it?"
29-
))
30-
.with_default(true)
31-
.prompt()? =>
22+
let hash_params = match (&args.hash, &args.hash_file) {
23+
(_, Some(hash_file)) => {
24+
let Some((algs, _, expected_hash)) = find_hash_in_user_file(&args.input, hash_file)
25+
else {
26+
eprintln!(
27+
"Could not parse {} as a valid hash file!",
28+
hash_file.to_string_lossy()
29+
);
30+
exit(-1);
31+
};
32+
33+
eprintln!(
34+
"Using user-provided hash file: {}",
35+
hash_file.to_string_lossy()
36+
);
37+
Some(BeginHashParams {
38+
expected_hash,
39+
alg: ask_alg(&algs)?,
40+
hasher_compression: ask_hasher_compression(cf, args.hash_of)?,
41+
})
42+
}
43+
(HashArg::Skip, _) => None,
44+
(HashArg::Ask, _) => {
45+
match find_hash_in_standard_files(&args.input) {
46+
Some((algs, expected_hashfile, expected_hash))
47+
if Confirm::new(&format!(
48+
"Detected hash file {expected_hashfile} in the directory. Do you want to use it?"
49+
))
50+
.with_default(true)
51+
.prompt()? =>
52+
{
3253
Some(BeginHashParams {
3354
expected_hash,
34-
alg,
55+
alg: ask_alg(&algs)?,
3556
hasher_compression: ask_hasher_compression(cf, args.hash_of)?,
36-
}),
37-
_ => ask_hash_loop(cf)?
57+
})
58+
}
59+
_ => ask_hash_loop(cf)?,
3860
}
3961
}
40-
HashArg::Hash { alg, expected_hash } => Some(BeginHashParams {
62+
(HashArg::Hash { alg, expected_hash }, _) => Some(BeginHashParams {
4163
expected_hash: expected_hash.clone(),
4264
alg: *alg,
4365
hasher_compression: ask_hasher_compression(cf, args.hash_of)?,
@@ -109,32 +131,37 @@ fn ask_hash_once(cf: CompressionFormat) -> anyhow::Result<BeginHashParams> {
109131
},
110132
};
111133

112-
let alg = match &algs[..] {
134+
let alg = ask_alg(&algs)?;
135+
136+
let hasher_compression = ask_hasher_compression(cf, None)?;
137+
138+
Ok(BeginHashParams {
139+
expected_hash: hash,
140+
alg,
141+
hasher_compression,
142+
})
143+
}
144+
145+
#[tracing::instrument]
146+
fn ask_alg(algs: &[HashAlg]) -> anyhow::Result<HashAlg> {
147+
match algs {
113148
&[] => {
114149
eprintln!("Could not detect the hash algorithm from your hash!");
115150
Err(Recoverable::AskAgain)?
116151
}
117152
&[only_alg] => {
118153
eprintln!("Detected {}", only_alg);
119-
only_alg
154+
Ok(only_alg)
120155
}
121156
multiple => {
122157
let ans = Select::new("Which algorithm is it?", multiple.into()).prompt_skippable()?;
123158
if let Some(alg) = ans {
124-
alg
159+
Ok(alg)
125160
} else {
126161
Err(Recoverable::AskAgain)?
127162
}
128163
}
129-
};
130-
131-
let hasher_compression = ask_hasher_compression(cf, None)?;
132-
133-
Ok(BeginHashParams {
134-
expected_hash: hash,
135-
alg,
136-
hasher_compression,
137-
})
164+
}
138165
}
139166

140167
#[tracing::instrument]

0 commit comments

Comments
 (0)