summaryrefslogtreecommitdiff
path: root/src/lib.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib.rs')
-rw-r--r--src/lib.rs36
1 files changed, 33 insertions, 3 deletions
diff --git a/src/lib.rs b/src/lib.rs
index eacce62..9f46f54 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -32,10 +32,15 @@
//! ~~~
use serde::Serialize;
-use std::fs::Metadata;
+use sha2::{Digest, Sha256};
+use std::fs::symlink_metadata;
+use std::fs::File;
+use std::io::{BufReader, Read};
use std::os::linux::fs::MetadataExt;
use std::path::{Path, PathBuf};
+const BUF_SIZE: usize = 1024 * 1024;
+
/// An entry in a file manifest.
#[derive(Serialize, Debug)]
pub struct ManifestEntry {
@@ -48,6 +53,7 @@ pub struct ManifestEntry {
mtime_nsec: i64,
nlink: u64,
size: Option<u64>,
+ sha256: Option<String>,
}
impl ManifestEntry {
@@ -57,8 +63,14 @@ impl ManifestEntry {
/// caller. This function doesn't query the system for it.
///
/// The structure can be serialized using serde.
- pub fn new(path: &Path, m: Metadata) -> Self {
- Self {
+ pub fn new(path: &Path) -> std::io::Result<Self> {
+ let m = symlink_metadata(path)?;
+ let hash = if m.is_file() {
+ Some(file_checksum(path)?)
+ } else {
+ None
+ };
+ Ok(Self {
path: path.to_path_buf(),
atime: m.st_atime(),
atime_nsec: m.st_atime_nsec(),
@@ -67,8 +79,26 @@ impl ManifestEntry {
mtime_nsec: m.st_mtime_nsec(),
nlink: m.st_nlink(),
size: if m.is_dir() { None } else { Some(m.st_size()) },
+ sha256: hash,
+ })
+ }
+}
+
+fn file_checksum(path: &Path) -> std::io::Result<String> {
+ let mut hasher = Sha256::new();
+
+ let file = File::open(path)?;
+ let mut reader = BufReader::new(file);
+ let mut buf = vec![0; BUF_SIZE];
+ loop {
+ let n = reader.read(&mut buf)?;
+ if n == 0 {
+ break;
}
+ hasher.update(&buf[..n]);
}
+ let hash = hasher.finalize();
+ Ok(format!("{:x}", hash))
}
mod mode {