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

Achiefs / fim / 4313434360

pending completion
4313434360

push

github

José Fernández
Ignore checksum of folders

23 of 23 new or added lines in 1 file covered. (100.0%)

684 of 799 relevant lines covered (85.61%)

1.53 hits per line

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

83.78
/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::{Sha3_512, Digest};
9
// To log the program process
10
use log::*;
11
// To manage hex to ascii conversion
12
use std::str;
13
// To manage files
14
use std::fs::File;
15
use std::path::Path;
16
// To read file content
17
use std::io::{BufRead, BufReader};
18

19
// To calculate file content hash in sha512 format (SHA3 implementation)
20
pub fn get_checksum(filename: String, read_limit: usize) -> String {
1✔
21
    let mut hasher = Sha3_512::new();
1✔
22
    let mut length = 1;
1✔
23
    let mut iteration = 0;
1✔
24
    let mut data_read = 0;
1✔
25
    
26
    if Path::new(&filename).is_file() { 
3✔
27
        debug!("Getting hash of file: {}", filename);
4✔
28
        match File::open(filename.clone()){
4✔
29
            Ok(file) => {
2✔
30
                let mut reader = BufReader::with_capacity(READ_CAPACITY, file);
4✔
31

32
                while length > 0 && data_read <= read_limit {
4✔
33
                    if iteration == 2 {
2✔
34
                        info!("Big file detected, the hash will take a while");
×
35
                    }
36
                    
37
                    length = {
2✔
38
                        let buffer = reader.fill_buf().unwrap();
4✔
39
                        hasher.update(&buffer);
2✔
40
                        buffer.len()
2✔
41
                    };
42
                    reader.consume(length);
2✔
43
                    data_read += length / (1024 * 1024);
2✔
44
                    iteration += 1;
4✔
45
                };
46
                if data_read > read_limit {
2✔
47
                    info!("File '{}' checksum skipped. File size is above limit", filename);
×
48
                    String::from("UNKNOWN")
×
49
                }else{
50
                    encode(hasher.finalize())
4✔
51
                }
52
            },
53
            Err(e) => {
×
54
                debug!("Cannot open file to get checksum, error: {:?}", e);
×
55
                String::from("UNKNOWN")
×
56
            }
57
        }
58
    }else{
59
        debug!("Cannot produce checksum of a directory");
3✔
60
        String::from("UNKNOWN")
2✔
61
    }
62
}
63

64
// ----------------------------------------------------------------------------
65

66
pub fn hex_to_ascii(hex: String) -> String {
1✔
67
    debug!("HEX: {}", hex);
3✔
68
    let bytes = match decode(hex){
2✔
69
        Ok(d) => d,
1✔
70
        Err(e) => {
1✔
71
            debug!("Could not decode HEX data. Error: {}", e);
3✔
72
            Vec::new()
2✔
73
        }
74
    };
75
    String::from(str::from_utf8(&bytes).unwrap())
3✔
76
        .replace('\u{0000}', " ")
77
}
78

79
// ----------------------------------------------------------------------------
80

81
#[cfg(test)]
82
mod tests {
83
    const MAX_FILE_READ: usize = 64;
84

85
    use super::*;
86
    use std::fs;
87
    use std::fs::File;
88
    use std::io::prelude::*;
89

90
    fn create_test_file(filename: String) {
91
        File::create(filename).unwrap().write_all(b"This is a test!").unwrap();
92
    }
93

94
    fn remove_test_file(filename: String) {
95
        fs::remove_file(filename).unwrap()
96
    }
97

98
    // ------------------------------------------------------------------------
99

100
    #[test]
101
    fn test_get_checksum_file() {
102
        let filename = String::from("test_get_checksum_file");
103
        create_test_file(filename.clone());
104
        assert_eq!(get_checksum(filename.clone(), MAX_FILE_READ), String::from("46512636eeeb22dee0d60f3aba6473b1fb3258dc0c9ed6fbdbf26bed06df796bc70d4c1f6d50ca977b45f35b494e4bd9fb34e55a1576d6d9a3b5e1ab059953ee"));
105
        remove_test_file(filename.clone());
106
    }
107

108
    // ------------------------------------------------------------------------
109

110
    #[test]
111
    fn test_get_checksum_not_exists() {
112
        assert_ne!(get_checksum(String::from("not_exists"), MAX_FILE_READ), String::from("This is a test"));
113
        assert_eq!(get_checksum(String::from("not_exists"), MAX_FILE_READ), String::from("UNKNOWN"));
114
    }
115

116
    // ------------------------------------------------------------------------
117

118
    #[test]
119
    fn test_get_checksum_bad() {
120
        let filename = String::from("test_get_checksum_bad");
121
        create_test_file(filename.clone());
122
        assert_ne!(get_checksum(filename.clone(), MAX_FILE_READ), String::from("This is a test"));
123
        remove_test_file(filename.clone());
124
    }
125

126
    // ------------------------------------------------------------------------
127

128
    #[test]
129
    fn test_hex_to_ascii() {
130
        let ascii = hex_to_ascii(String::from("746F756368002F746D702F746573742F66696C65342E747874"));
131
        assert_eq!(ascii, "touch /tmp/test/file4.txt");
132
    }
133

134
    // ------------------------------------------------------------------------
135

136
    #[test]
137
    fn test_hex_to_ascii_bad() {
138
        assert_eq!(hex_to_ascii(String::from("ABC")), "");
139
    }
140

141
}
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

© 2026 Coveralls, Inc