Skip to main content

ewf_image/
verify.rs

1use md5::{Digest, Md5};
2use sha1::Sha1;
3
4use crate::EwfError;
5use crate::{Image, Result, VerifyResult};
6
7impl Image {
8    /// Computes streamed MD5 and SHA1 hashes for the logical media stream.
9    ///
10    /// The returned [`VerifyResult`] contains computed hashes and optional match
11    /// results. Match values are `None` when the image did not store the
12    /// corresponding expected hash.
13    ///
14    /// # Errors
15    ///
16    /// Returns an error if reading the logical media stream fails, if the read
17    /// reaches EOF before [`ImageInfo::logical_size`](crate::ImageInfo::logical_size),
18    /// or if the image has been aborted with [`Image::signal_abort`].
19    pub fn verify(&self) -> Result<VerifyResult> {
20        let mut md5 = Md5::new();
21        let mut sha1 = Sha1::new();
22        let mut offset = 0_u64;
23        let logical_size = self.info().logical_size;
24        let mut buf = vec![0; 1024 * 1024];
25
26        while offset < logical_size {
27            let remaining = logical_size - offset;
28            let request = usize::try_from(remaining.min(buf.len() as u64))
29                .map_err(|_| EwfError::Malformed("verify read size does not fit usize".into()))?;
30            let read = self.read_at(&mut buf[..request], offset)?;
31            if read == 0 {
32                return Err(EwfError::Malformed(
33                    "verify reached EOF before logical image end".into(),
34                ));
35            }
36
37            md5.update(&buf[..read]);
38            sha1.update(&buf[..read]);
39            offset += u64::try_from(read).expect("usize fits u64");
40        }
41
42        let computed_md5: [u8; 16] = md5.finalize().into();
43        let computed_sha1: [u8; 20] = sha1.finalize().into();
44        let stored = &self.info().stored_hashes;
45
46        Ok(VerifyResult {
47            computed_md5: Some(computed_md5),
48            computed_sha1: Some(computed_sha1),
49            md5_match: stored.md5.map(|expected| expected == computed_md5),
50            sha1_match: stored.sha1.map(|expected| expected == computed_sha1),
51        })
52    }
53}