• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

Achiefs / fim / 14275166216

04 Apr 2025 10:13PM UTC coverage: 84.711% (-0.4%) from 85.125%
14275166216

push

github

web-flow
Merge pull request #194 from Achiefs/177-db-hash

Added Hash diff scanner

353 of 433 new or added lines in 12 files covered. (81.52%)

4 existing lines in 1 file now uncovered.

1435 of 1694 relevant lines covered (84.71%)

1.52 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

84.52
/src/hash.rs
1
// Copyright (C) 2021, Achiefs.
2

3
// Constants definitions
4
const READ_CAPACITY: usize = 1024 * 1024 * 8; // Read file in chunks of 8MB
5

6
// To get file checksums
7
use hex::{encode, decode};
8
//use sha3::{Digest, Sha3_256, Sha3_512, Sha3_224};
9
use sha3::{Digest, digest::DynDigest,
10
    Sha3_224, Sha3_256, Sha3_384, Sha3_512,
11
    Keccak224, Keccak256, Keccak384, Keccak512};
12
// To log the program process
13
use log::*;
14
// To manage hex to ascii conversion
15
use std::str;
16
// To manage files
17
use std::fs::File;
18
use std::path::Path;
19
// To read file content
20
use std::io::{BufRead, BufReader};
21

22
// ----------------------------------------------------------------------------
23

24
#[derive(Debug)]
25
#[derive(PartialEq)]
26
#[derive(Clone)]
27
pub enum ShaType {
28
    Sha224,
29
    Sha256,
30
    Sha384,
31
    Sha512,
32
    Keccak224,
33
    Keccak256,
34
    Keccak384,
35
    Keccak512
36
}
37

38
#[cfg(test)]
39
mod test;
40

41
// To calculate file content hash
42
pub fn get_checksum(filename: String, read_limit: usize, algorithm: ShaType) -> String {
2✔
43
    let mut length = 1;
2✔
44
    let mut iteration = 0;
2✔
45
    let mut data_read = 0;
2✔
46
    let limit: usize = read_limit * 1024 * 1024;
4✔
47
    let mut hasher: Box<dyn DynDigest> = match algorithm {
4✔
48
        ShaType::Sha224 => Box::new(Sha3_224::new()),
2✔
49
        ShaType::Sha256 => Box::new(Sha3_256::new()),
4✔
50
        ShaType::Sha384 => Box::new(Sha3_384::new()),
2✔
51
        ShaType::Sha512 => Box::new(Sha3_512::new()),
2✔
52
        ShaType::Keccak224 => Box::new(Keccak224::new()),
2✔
53
        ShaType::Keccak256 => Box::new(Keccak256::new()),
2✔
54
        ShaType::Keccak384 => Box::new(Keccak384::new()),
2✔
55
        ShaType::Keccak512 => Box::new(Keccak512::new()),
2✔
56
    };
57
    
58
    if Path::new(&filename).is_file() { 
4✔
59
        debug!("Getting hash of file: {}", filename);
6✔
60
        match File::open(filename.clone()){
4✔
61
            Ok(file) => {
2✔
62
                let size: usize = file.metadata().unwrap().len() as usize;
4✔
63
                let mut reader = BufReader::with_capacity(READ_CAPACITY, file);
2✔
64

65
                if size > limit {
2✔
66
                    info!("File size is above limit. Getting file '{}' header/partial checksum.", filename);
3✔
67
                    get_partial_checksum(filename, algorithm)
2✔
68
                }else{
69
                    while length > 0 && data_read <= limit {
6✔
70
                        if iteration == 2 {
2✔
NEW
71
                            debug!("Big file detected, the hash will take a while");
×
72
                        }
73
                        
74
                        length = {
1✔
75
                            match reader.fill_buf(){
4✔
76
                                Ok(buffer) =>{
2✔
77
                                    hasher.update(buffer);
2✔
78
                                    buffer.len()
2✔
79
                                },
NEW
80
                                Err(e) => {
×
NEW
81
                                    debug!("Cannot read file. Checksum set to 'UNKNOWN', error: {}", e);
×
NEW
82
                                    0
×
83
                                }
84
                            }
85
                        };
86
                        reader.consume(length);
2✔
87
                        data_read += length;
2✔
88
                        iteration += 1;
4✔
89
                    };
90
                    encode(hasher.finalize())
4✔
91
                }
92
            },
93
            Err(e) => {
×
94
                debug!("Cannot open file to get checksum, error: {:?}", e);
×
95
                String::from("UNKNOWN")
×
96
            }
97
        }
98
    }else{
99
        debug!("Cannot produce checksum of a removed file or directory.");
3✔
100
        String::from("UNKNOWN")
2✔
101
    }
102
}
103

104
// ----------------------------------------------------------------------------
105

106
/// Produce partial checksum of file, it read the first MB of the file
107
/// This method is targeted for big files where you cannot get checksum in a reasonable time.
108
pub fn get_partial_checksum(filename: String, algorithm: ShaType) -> String {
2✔
109
    let limit: usize = 1024 * 1024; // 1MB
2✔
110
    let mut hasher: Box<dyn DynDigest> = match algorithm {
5✔
111
        ShaType::Sha224 => Box::new(Sha3_224::new()),
5✔
112
        ShaType::Sha256 => Box::new(Sha3_256::new()),
2✔
113
        ShaType::Sha384 => Box::new(Sha3_384::new()),
2✔
114
        ShaType::Sha512 => Box::new(Sha3_512::new()),
2✔
115
        ShaType::Keccak224 => Box::new(Keccak224::new()),
2✔
116
        ShaType::Keccak256 => Box::new(Keccak256::new()),
2✔
117
        ShaType::Keccak384 => Box::new(Keccak384::new()),
2✔
118
        ShaType::Keccak512 => Box::new(Keccak512::new()),
2✔
119
    };
120

121
    if Path::new(&filename).is_file() {
6✔
122
        debug!("Getting hash of file: {}", filename);
6✔
123
        match File::open(filename.clone()){
4✔
124
            Ok(file) => {
2✔
125
                let metadata = file.metadata().unwrap();
4✔
126
                let mut reader = BufReader::with_capacity(limit, file);
2✔
127

128
                let length = {
129
                    match reader.fill_buf(){
4✔
130
                        Ok(buffer) =>{
2✔
131
                            hasher.update(buffer);
2✔
132
                            buffer.len()
2✔
133
                        },
NEW
134
                        Err(e) => {
×
NEW
135
                            debug!("Cannot read file. Checksum set to 'UNKNOWN', error: {}", e);
×
NEW
136
                            0
×
137
                        }
138
                    }
139
                };
140
                reader.consume(length);
2✔
141
                let hash_data: Vec<u8> = vec![metadata.len() as u8];
2✔
142
                hasher.update(&hash_data);
4✔
143
                encode(hasher.finalize())
2✔
144
            },
NEW
145
            Err(e) => {
×
NEW
146
                debug!("Cannot open file to get checksum, error: {:?}", e);
×
NEW
147
                String::from("UNKNOWN")
×
148
            }
149
        }
150
    }else{
151
        debug!("Cannot produce checksum of a removed file or directory.");
3✔
152
        String::from("UNKNOWN")
2✔
153
    }
154
}
155

156

157
// ----------------------------------------------------------------------------
158

159
pub fn hex_to_ascii(hex: String) -> String {
1✔
160
    debug!("HEX: {}", hex);
3✔
161
    let bytes = match decode(hex){
2✔
162
        Ok(d) => d,
1✔
163
        Err(e) => {
1✔
164
            debug!("Could not decode HEX data. Error: {}", e);
3✔
165
            Vec::new()
2✔
166
        }
167
    };
168
    String::from(str::from_utf8(&bytes).unwrap())
3✔
169
        .replace('\u{0000}', " ")
170
}
171

172
// ----------------------------------------------------------------------------
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc