1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
use std::str::{from_utf8, FromStr};
use std::io::{self, Read, Seek, SeekFrom};
use {HashType};
fn hex_to_digit(v: u8) -> Option<u8> {
match v {
b'0'...b'9' => Some(v & 0x0f),
b'a'...b'f' | b'A'...b'F' => Some((v & 0x0f) + 9),
_ => None
}
}
pub fn get_hash<F: Read+Seek>(f: &mut F) -> Result<Vec<u8>, io::Error> {
let einval = io::ErrorKind::InvalidData;
let mut signature = [0u8; 32];
f.read(&mut signature)?;
if &signature[..16] != b"DIRSIGNATURE.v1 " {
return Err(einval.into());
}
let hash = signature[16..].iter().position(|&x| x == b' ')
.and_then(|e| from_utf8(&signature[16..16+e]).ok())
.and_then(|s| HashType::from_str(s).ok())
.ok_or(einval)?;
let nbytes = hash.output_bytes()*2+2;
f.seek(SeekFrom::End(- (nbytes as i64)))?;
let mut buf = [0u8; 100];
assert!(buf.len() >= nbytes);
if f.read(&mut buf)? != nbytes {
return Err(io::ErrorKind::UnexpectedEof.into());
}
if buf[0] != b'\n' || buf[nbytes-1] != b'\n' {
return Err(einval.into());
}
let mut hash = Vec::with_capacity(hash.output_bytes());
for d in buf[1..nbytes-1].chunks(2) {
hash.push(
(hex_to_digit(d[0]).ok_or(einval)? << 4)
| hex_to_digit(d[1]).ok_or(einval)?);
}
return Ok(hash);
}
#[cfg(test)]
mod test {
use super::get_hash;
use std::io::Cursor;
const DATA: &'static [u8] = b"\
DIRSIGNATURE.v1 sha512/256 block_size=32768
/
hello.txt f 6 8dd499a36d950b8732f85a3bffbc8d8bee4a0af391e8ee2bb0aa0c4553b6c0fc
test.txt f 0
/subdir
.hidden f 7 24f72d3a930b5f7933ddd91a5c7cb7ba09a093f936a04bf6486c8b1763c59819
file.txt f 10 9ce28248299290fe84340d7821adf01b3b6a579ef827e1e58bc3949de4b7e5d9
11928917e3e44838af46bad1c7a43a8c16eb26052997f70328d7b07ae4dd6eac
";
#[test]
fn read() {
let hash = get_hash(&mut Cursor::new(DATA)).unwrap();
assert_eq!(hash,
vec![0x11, 0x92, 0x89, 0x17, 0xe3, 0xe4, 0x48, 0x38, 0xaf,
0x46, 0xba, 0xd1, 0xc7, 0xa4, 0x3a, 0x8c, 0x16, 0xeb,
0x26, 0x05, 0x29, 0x97, 0xf7, 0x03, 0x28, 0xd7, 0xb0,
0x7a, 0xe4, 0xdd, 0x6e, 0xac]);
}
}