1+ use sha2:: digest:: { Digest , OutputSizeUser , generic_array:: ArrayLength } ;
2+
13use super :: DownloadError ;
4+ use crate :: progress_bar:: ProgressBar ;
25
3- use std:: { fs, io:: Read , path:: Path } ;
6+ use std:: { fs, io:: Read , num :: NonZero , path:: Path } ;
47
58/// Represents the supported hash algorithms for file integrity checking.
69///
@@ -20,79 +23,62 @@ pub enum HashAlgorithm {
2023}
2124
2225impl HashAlgorithm {
26+ fn hash_file < H > ( mut hasher : H , file_path : & Path , expected : & str ) -> Result < ( ) , DownloadError >
27+ where
28+ H : Digest + OutputSizeUser ,
29+ <H as OutputSizeUser >:: OutputSize : std:: ops:: Add ,
30+ <<H as OutputSizeUser >:: OutputSize as std:: ops:: Add >:: Output : ArrayLength < u8 > ,
31+ {
32+ let mut file_reader = fs:: OpenOptions :: new ( ) . read ( true ) . open ( file_path) ?;
33+ let file_size = file_reader. metadata ( ) ?. len ( ) ;
34+ let mut progress_bar =
35+ ProgressBar :: new ( NonZero :: new ( file_size) , "Verifying file integrity" ) ;
36+ let mut buf = [ 0u8 ; 1024 ] ;
37+ loop {
38+ let bytes_read = file_reader. read ( & mut buf) ?;
39+ if bytes_read == 0 {
40+ break ;
41+ }
42+ progress_bar. inc ( bytes_read as u64 ) ?;
43+ hasher. update ( & buf[ ..bytes_read] ) ;
44+ }
45+ progress_bar. finish ( ) ?;
46+ let actual = format ! ( "{:x}" , hasher. finalize( ) ) ;
47+ if actual == * expected {
48+ Ok ( ( ) )
49+ } else {
50+ Err ( DownloadError :: HashMismatch {
51+ expected : expected. to_owned ( ) ,
52+ actual,
53+ } )
54+ }
55+ }
56+
2357 /// Verify a given file (located at `file_path`) against the expected checksum value.
2458 ///
2559 /// This method reads the file in chunks (of 1024 bytes) to compute the hash,
2660 /// thus no extraneous memory is allocated when reading the file's entire contents.
2761 ///
2862 /// Note, a progress bar is displayed to stdout.
2963 pub fn verify ( & self , file_path : & Path ) -> Result < ( ) , DownloadError > {
30- let mut file_reader = fs:: OpenOptions :: new ( ) . read ( true ) . open ( file_path) ?;
31- let mut buf = [ 0u8 ; 1024 ] ;
3264 match self {
3365 HashAlgorithm :: Sha256 ( expected) => {
3466 use sha2:: { Digest , Sha256 } ;
3567
36- let mut hasher = Sha256 :: new ( ) ;
37- loop {
38- let bytes_read = file_reader. read ( & mut buf) ?;
39- if bytes_read == 0 {
40- break ;
41- }
42- hasher. update ( & buf[ ..bytes_read] ) ;
43- }
44- let actual = format ! ( "{:x}" , hasher. finalize( ) ) ;
45- if actual == * expected {
46- Ok ( ( ) )
47- } else {
48- Err ( DownloadError :: HashMismatch {
49- expected : expected. clone ( ) ,
50- actual,
51- } )
52- }
68+ let hasher = Sha256 :: new ( ) ;
69+ Self :: hash_file ( hasher, file_path, expected)
5370 }
5471 HashAlgorithm :: Blake2b256 ( expected) => {
5572 use blake2:: { Blake2b , Digest , digest:: consts:: U32 } ;
5673
57- let mut hasher = Blake2b :: < U32 > :: new ( ) ;
58- loop {
59- let bytes_read = file_reader. read ( & mut buf) ?;
60- if bytes_read == 0 {
61- break ;
62- }
63- hasher. update ( & buf[ ..bytes_read] ) ;
64- }
65- let actual = format ! ( "{:x}" , hasher. finalize( ) ) ;
66- if actual == * expected {
67- Ok ( ( ) )
68- } else {
69- Err ( DownloadError :: HashMismatch {
70- expected : expected. clone ( ) ,
71- actual,
72- } )
73- }
74+ let hasher = Blake2b :: < U32 > :: new ( ) ;
75+ Self :: hash_file ( hasher, file_path, expected)
7476 }
7577 HashAlgorithm :: Sha512 ( expected) => {
7678 use sha2:: { Digest , Sha512 } ;
7779
78- let mut hasher = Sha512 :: new ( ) ;
79-
80- loop {
81- let bytes_read = file_reader. read ( & mut buf) ?;
82- if bytes_read == 0 {
83- break ;
84- }
85- hasher. update ( & buf[ ..bytes_read] ) ;
86- }
87- let actual = format ! ( "{:x}" , hasher. finalize( ) ) ;
88- if actual == * expected {
89- Ok ( ( ) )
90- } else {
91- Err ( DownloadError :: HashMismatch {
92- expected : expected. clone ( ) ,
93- actual,
94- } )
95- }
80+ let hasher = Sha512 :: new ( ) ;
81+ Self :: hash_file ( hasher, file_path, expected)
9682 }
9783 }
9884 }
0 commit comments