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
use hex::FromHex;
use slog::{trace, Logger};
use std::io;
use std::io::Result;
use std::path::PathBuf;
use crate::aio;
/// `StoredChunks` is an iterator for the list of chunks stored in a path,
/// it will crawl the directory structure looking for chunks that have valid
/// digest sized elements as their name. Invalid files with incorrect names
/// will be ignored.
pub struct StoredChunks {
paths: Box<dyn Iterator<Item = io::Result<PathBuf>>>,
digest_size: usize,
log: Logger,
}
impl StoredChunks {
#[allow(dead_code)] // tests
pub fn new(
aio: &aio::AsyncIO,
rel_path: PathBuf,
digest_size: usize,
log: Logger,
) -> Result<StoredChunks> {
let paths = aio.list_recursively(rel_path);
Ok(StoredChunks {
paths,
digest_size,
log,
})
}
}
impl Drop for StoredChunks {
fn drop(&mut self) {
// drain the receiver so the sender can send everything
// without failing
while let Some(_) = self.paths.next() {}
}
}
impl Iterator for StoredChunks {
type Item = Result<Vec<u8>>;
fn next(&mut self) -> Option<Result<Vec<u8>>> {
loop {
let next = self.paths.next();
if let Some(next) = next {
let name = match next {
Ok(name) => name,
Err(e) => return Some(Err(e)),
};
let name = name
.file_name()
.expect("Path terminated with ..?")
.to_string_lossy();
let bytes = name.to_string().into_bytes();
match Vec::from_hex(bytes) {
Ok(digest) => {
if digest.len() == self.digest_size {
return Some(Ok(digest));
}
trace!(self.log, "skipping"; "path" => %name);
// Maybe we should remove this file? It is not a valid
// chunk
// file.
}
Err(e) => trace!(
self.log,
"skipping";
"path" => %name,
"error" => %e
),
}
} else {
return None;
}
}
}
}