File: copy.rs

package info (click to toggle)
rust-bmap-parser 0.2.0-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 4,276 kB
  • sloc: makefile: 4
file content (155 lines) | stat: -rw-r--r-- 4,023 bytes parent folder | download | duplicates (2)
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
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
use bmap_parser::{Bmap, Discarder, SeekForward};
use flate2::read::GzDecoder;
use sha2::{Digest, Sha256};
use std::env;
use std::fs::File;
use std::io::Result as IOResult;
use std::io::{Error, ErrorKind, Read, Write};
use std::path::PathBuf;

#[derive(Clone, Debug)]
struct OutputMockRange {
    offset: u64,
    data: Vec<u8>,
}

impl OutputMockRange {
    fn new(offset: u64) -> Self {
        Self {
            offset,
            data: Vec::new(),
        }
    }

    fn write(&mut self, data: &[u8]) {
        self.data.extend_from_slice(data);
    }

    fn sha256(&self) -> [u8; 32] {
        Sha256::digest(&self.data).into()
    }
}

#[derive(Clone, Debug)]
struct OutputMock {
    size: u64,
    offset: u64,
    ranges: Vec<OutputMockRange>,
}

impl OutputMock {
    fn new(size: u64) -> Self {
        Self {
            size,
            offset: 0,
            ranges: Vec::new(),
        }
    }

    fn add_range(&mut self, offset: u64) -> &mut OutputMockRange {
        self.ranges.push(OutputMockRange::new(offset));
        self.ranges.last_mut().unwrap()
    }

    fn sha256(&mut self) -> [u8; 32] {
        fn pad(hasher: &mut Sha256, mut topad: u64) {
            const ZEROES: [u8; 4096] = [0; 4096];
            while topad > 0 {
                let len = ZEROES.len() as u64;
                let len = len.min(topad);
                hasher.update(&ZEROES[0..len as usize]);
                topad -= len;
            }
        }

        let mut hasher = Sha256::new();
        let mut offset = 0;
        for range in self.ranges.iter() {
            if offset < range.offset {
                pad(&mut hasher, range.offset - offset);
                offset = range.offset;
            }

            hasher.update(&range.data);
            offset += range.data.len() as u64;
        }

        pad(&mut hasher, self.size - offset);

        hasher.finalize().into()
    }
}

impl Write for OutputMock {
    fn write(&mut self, data: &[u8]) -> IOResult<usize> {
        let maxsize = self.size as usize;
        let range = match self.ranges.last_mut() {
            Some(last) if last.offset == self.offset => last,
            _ => self.add_range(self.offset),
        };
        if range.offset as usize + range.data.len() + data.len() > maxsize {
            return Err(Error::new(ErrorKind::Other, "Writing outside of space"));
        }
        range.write(data);
        Ok(data.len())
    }

    fn flush(&mut self) -> IOResult<()> {
        Ok(())
    }
}

impl SeekForward for OutputMock {
    fn seek_forward(&mut self, forward: u64) -> IOResult<()> {
        self.offset += if let Some(last) = self.ranges.last() {
            last.data.len() as u64 + forward
        } else {
            forward
        };
        Ok(())
    }
}

fn setup_data(basename: &str) -> (Bmap, impl Read + SeekForward) {
    let mut datadir = PathBuf::new();
    datadir.push(env::var("CARGO_MANIFEST_DIR").unwrap());
    datadir.push("tests/data");

    let mut bmapfile = datadir.clone();
    bmapfile.push(format!("{}.bmap", basename));

    let mut b =
        File::open(&bmapfile).unwrap_or_else(|_| panic!("Failed to open bmap file:{:?}", bmapfile));
    let mut xml = String::new();
    b.read_to_string(&mut xml).unwrap();
    let bmap = Bmap::from_xml(&xml).unwrap();

    let mut datafile = datadir.clone();
    datafile.push(format!("{}.gz", basename));
    let g =
        File::open(&datafile).unwrap_or_else(|_| panic!("Failed to open data file:{:?}", datafile));
    let gz = GzDecoder::new(g);
    let gz = Discarder::new(gz);

    (bmap, gz)
}

fn sha256_reader<R: Read>(mut reader: R) -> [u8; 32] {
    let mut buffer = [0; 4096];
    let mut hasher = Sha256::new();
    loop {
        let r = reader.read(&mut buffer).unwrap();
        if r == 0 {
            break;
        }
        hasher.update(&buffer[0..r]);
    }

    hasher.finalize().into()
}

#[test]
fn copy() {
    let (bmap, mut input) = setup_data("test.img");
    let mut output = OutputMock::new(bmap.image_size());
}