ddup_bak/chunks/
storage.rs1use super::ChunkHash;
2use std::{io::Write, path::PathBuf};
3
4pub trait ChunkStorage: Sync + Send {
5 #[inline]
6 fn path_from_chunk(&self, chunk: &ChunkHash) -> PathBuf {
7 let mut path = PathBuf::new();
8 for byte in chunk.iter().take(2) {
9 path.push(format!("{byte:02x}"));
10 }
11
12 let mut file_name = String::with_capacity(32 * 2 - 2 * 2 + 6);
13 for byte in chunk.iter().skip(2) {
14 file_name.push_str(&format!("{byte:02x}"));
15 }
16 file_name.push_str(".chunk");
17
18 path.push(file_name);
19
20 path
21 }
22
23 fn read_chunk_content(
24 &self,
25 chunk: &ChunkHash,
26 ) -> std::io::Result<Box<dyn std::io::Read + Send>>;
27 fn write_chunk_content(
28 &self,
29 chunk: &ChunkHash,
30 content: Box<dyn std::io::Read + Send>,
31 ) -> std::io::Result<()>;
32 fn delete_chunk_content(&self, chunk: &ChunkHash) -> std::io::Result<()>;
33}
34
35pub struct ChunkStorageLocal(pub PathBuf);
36impl ChunkStorage for ChunkStorageLocal {
37 #[inline]
38 fn read_chunk_content(
39 &self,
40 chunk: &ChunkHash,
41 ) -> std::io::Result<Box<dyn std::io::Read + Send>> {
42 let path = self.0.join(self.path_from_chunk(chunk));
43 let file = std::fs::File::open(path)?;
44
45 Ok(Box::new(file))
46 }
47
48 #[inline]
49 fn write_chunk_content(
50 &self,
51 chunk: &ChunkHash,
52 mut content: Box<dyn std::io::Read + Send>,
53 ) -> std::io::Result<()> {
54 let path = self.0.join(self.path_from_chunk(chunk));
55 std::fs::create_dir_all(path.parent().unwrap())?;
56
57 let mut file = std::fs::File::create(path)?;
58
59 let mut buffer = [0; 4096];
60 loop {
61 let bytes_read = content.read(&mut buffer)?;
62 if bytes_read == 0 {
63 break;
64 }
65 file.write_all(&buffer[..bytes_read])?;
66 }
67
68 Ok(())
69 }
70
71 #[inline]
72 fn delete_chunk_content(&self, chunk: &ChunkHash) -> std::io::Result<()> {
73 let mut path = self.0.join(self.path_from_chunk(chunk));
74 std::fs::remove_file(&path)?;
75
76 while let Some(parent) = path.parent() {
77 if parent == self.0 {
78 break;
79 }
80
81 if std::fs::read_dir(parent)?.count() == 0 {
82 std::fs::remove_dir(parent)?;
83 } else {
84 break;
85 }
86
87 path = parent.to_path_buf();
88 }
89
90 Ok(())
91 }
92}