summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLars Wirzenius <liw@sequoia-pgp.org>2022-03-13 10:14:14 +0200
committerLars Wirzenius <liw@sequoia-pgp.org>2022-03-13 10:14:14 +0200
commitf633203f255f9fabc726ab4939984e083cb95c0f (patch)
tree644b586d0f72f8322faa7d343e9b9da0b98de706
parenta794dd3f525fa27f618e64b97b5c0122dc14d0a0 (diff)
downloadchecksums-f633203f255f9fabc726ab4939984e083cb95c0f.tar.gz
single-threaded
-rw-r--r--Cargo.toml3
-rw-r--r--src/main.rs72
2 files changed, 74 insertions, 1 deletions
diff --git a/Cargo.toml b/Cargo.toml
index f0d7824..dffbe19 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -6,3 +6,6 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
+anyhow = "1.0.56"
+clap = { version = "3.1.6", features = ["derive"] }
+sha2 = "0.10.2"
diff --git a/src/main.rs b/src/main.rs
index e7a11a9..408b697 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,3 +1,73 @@
+use clap::Parser;
+use sha2::{Digest, Sha256};
+use std::fs::File;
+use std::io::{BufReader, Read};
+use std::path::{Path, PathBuf};
+
+const BUF_SIZE: usize = 4096;
+
fn main() {
- println!("Hello, world!");
+ let args = Args::parse();
+ if let Err(e) = checksums_main(&args.filenames) {
+ eprintln!("ERROR: {e}");
+ std::process::exit(1);
+ }
+}
+
+fn checksums_main(filenames: &[PathBuf]) -> anyhow::Result<()> {
+ let x: Result<Vec<()>, std::io::Error> = filenames
+ .iter()
+ .map(|filename| checksum(filename))
+ .map(|x| print_checksum_result(x))
+ .collect();
+ let _ = x?;
+ Ok(())
+}
+
+fn checksum(filename: &Path) -> Result<FileChecksum, std::io::Error> {
+ let mut checksum = Sha256::new();
+
+ let file = File::open(filename)?;
+ let mut reader = BufReader::new(file);
+ loop {
+ let mut buf = vec![0; BUF_SIZE];
+ let n = reader.read(&mut buf)?;
+ if n == 0 {
+ break;
+ }
+ checksum.update(&buf[..n]);
+ }
+
+ let checksum = checksum.finalize();
+ let checksum = format!("{checksum:x}");
+ Ok(FileChecksum::new(filename, checksum))
+}
+
+#[derive(Parser)]
+struct Args {
+ filenames: Vec<PathBuf>,
+}
+
+#[derive(Debug)]
+struct FileChecksum {
+ filename: PathBuf,
+ checksum: String,
+}
+
+impl FileChecksum {
+ fn new(filename: &Path, checksum: String) -> Self {
+ Self {
+ filename: filename.to_path_buf(),
+ checksum,
+ }
+ }
+}
+
+fn print_checksum_result(x: Result<FileChecksum, std::io::Error>) -> Result<(), std::io::Error> {
+ if let Ok(x) = x {
+ println!("{} {}", x.checksum, x.filename.display());
+ Ok(())
+ } else {
+ Err(x.unwrap_err())
+ }
}