]>
Commit | Line | Data |
---|---|---|
f323e906 WB |
1 | use std::io::{Seek, SeekFrom, Write}; |
2 | use std::sync::Arc; | |
018d11bb | 3 | |
6ef1b649 WB |
4 | use anyhow::Error; |
5 | ||
6 | use proxmox_io::WriteExt; | |
7 | ||
bbdda58b DM |
8 | use pbs_tools::crypt_config::CryptConfig; |
9 | ||
f323e906 | 10 | use crate::checksum_writer::ChecksumWriter; |
f323e906 WB |
11 | use crate::crypt_writer::CryptWriter; |
12 | use crate::file_formats::{self, DataBlobHeader, EncryptedDataBlobHeader}; | |
018d11bb | 13 | |
90ff75f8 | 14 | enum BlobWriterState<'writer, W: Write> { |
f323e906 WB |
15 | Uncompressed { |
16 | csum_writer: ChecksumWriter<W>, | |
17 | }, | |
18 | Compressed { | |
19 | compr: zstd::stream::write::Encoder<'writer, ChecksumWriter<W>>, | |
20 | }, | |
21 | Encrypted { | |
22 | crypt_writer: CryptWriter<ChecksumWriter<W>>, | |
23 | }, | |
24 | EncryptedCompressed { | |
25 | compr: zstd::stream::write::Encoder<'writer, CryptWriter<ChecksumWriter<W>>>, | |
26 | }, | |
018d11bb DM |
27 | } |
28 | ||
29 | /// Data blob writer | |
90ff75f8 FG |
30 | pub struct DataBlobWriter<'writer, W: Write> { |
31 | state: BlobWriterState<'writer, W>, | |
018d11bb DM |
32 | } |
33 | ||
f323e906 | 34 | impl<W: Write + Seek> DataBlobWriter<'_, W> { |
018d11bb DM |
35 | pub fn new_uncompressed(mut writer: W) -> Result<Self, Error> { |
36 | writer.seek(SeekFrom::Start(0))?; | |
f323e906 WB |
37 | let head = DataBlobHeader { |
38 | magic: file_formats::UNCOMPRESSED_BLOB_MAGIC_1_0, | |
39 | crc: [0; 4], | |
40 | }; | |
018d11bb DM |
41 | unsafe { |
42 | writer.write_le_value(head)?; | |
43 | } | |
44 | let csum_writer = ChecksumWriter::new(writer, None); | |
f323e906 WB |
45 | Ok(Self { |
46 | state: BlobWriterState::Uncompressed { csum_writer }, | |
47 | }) | |
018d11bb DM |
48 | } |
49 | ||
50 | pub fn new_compressed(mut writer: W) -> Result<Self, Error> { | |
f323e906 WB |
51 | writer.seek(SeekFrom::Start(0))?; |
52 | let head = DataBlobHeader { | |
53 | magic: file_formats::COMPRESSED_BLOB_MAGIC_1_0, | |
54 | crc: [0; 4], | |
55 | }; | |
018d11bb DM |
56 | unsafe { |
57 | writer.write_le_value(head)?; | |
58 | } | |
59 | let csum_writer = ChecksumWriter::new(writer, None); | |
60 | let compr = zstd::stream::write::Encoder::new(csum_writer, 1)?; | |
f323e906 WB |
61 | Ok(Self { |
62 | state: BlobWriterState::Compressed { compr }, | |
63 | }) | |
018d11bb DM |
64 | } |
65 | ||
9025312a | 66 | pub fn new_encrypted(mut writer: W, config: Arc<CryptConfig>) -> Result<Self, Error> { |
018d11bb DM |
67 | writer.seek(SeekFrom::Start(0))?; |
68 | let head = EncryptedDataBlobHeader { | |
f323e906 WB |
69 | head: DataBlobHeader { |
70 | magic: file_formats::ENCRYPTED_BLOB_MAGIC_1_0, | |
71 | crc: [0; 4], | |
72 | }, | |
018d11bb DM |
73 | iv: [0u8; 16], |
74 | tag: [0u8; 16], | |
75 | }; | |
76 | unsafe { | |
77 | writer.write_le_value(head)?; | |
78 | } | |
79 | ||
80 | let csum_writer = ChecksumWriter::new(writer, None); | |
f323e906 WB |
81 | let crypt_writer = CryptWriter::new(csum_writer, config)?; |
82 | Ok(Self { | |
83 | state: BlobWriterState::Encrypted { crypt_writer }, | |
84 | }) | |
018d11bb DM |
85 | } |
86 | ||
f323e906 WB |
87 | pub fn new_encrypted_compressed( |
88 | mut writer: W, | |
89 | config: Arc<CryptConfig>, | |
90 | ) -> Result<Self, Error> { | |
018d11bb DM |
91 | writer.seek(SeekFrom::Start(0))?; |
92 | let head = EncryptedDataBlobHeader { | |
f323e906 WB |
93 | head: DataBlobHeader { |
94 | magic: file_formats::ENCR_COMPR_BLOB_MAGIC_1_0, | |
95 | crc: [0; 4], | |
96 | }, | |
018d11bb DM |
97 | iv: [0u8; 16], |
98 | tag: [0u8; 16], | |
99 | }; | |
100 | unsafe { | |
101 | writer.write_le_value(head)?; | |
102 | } | |
103 | ||
104 | let csum_writer = ChecksumWriter::new(writer, None); | |
f323e906 | 105 | let crypt_writer = CryptWriter::new(csum_writer, config)?; |
018d11bb | 106 | let compr = zstd::stream::write::Encoder::new(crypt_writer, 1)?; |
f323e906 WB |
107 | Ok(Self { |
108 | state: BlobWriterState::EncryptedCompressed { compr }, | |
109 | }) | |
018d11bb DM |
110 | } |
111 | ||
112 | pub fn finish(self) -> Result<W, Error> { | |
113 | match self.state { | |
114 | BlobWriterState::Uncompressed { csum_writer } => { | |
115 | // write CRC | |
116 | let (mut writer, crc, _) = csum_writer.finish()?; | |
f323e906 WB |
117 | let head = DataBlobHeader { |
118 | magic: file_formats::UNCOMPRESSED_BLOB_MAGIC_1_0, | |
119 | crc: crc.to_le_bytes(), | |
120 | }; | |
018d11bb DM |
121 | |
122 | writer.seek(SeekFrom::Start(0))?; | |
123 | unsafe { | |
124 | writer.write_le_value(head)?; | |
125 | } | |
126 | ||
62ee2eb4 | 127 | Ok(writer) |
018d11bb DM |
128 | } |
129 | BlobWriterState::Compressed { compr } => { | |
130 | let csum_writer = compr.finish()?; | |
131 | let (mut writer, crc, _) = csum_writer.finish()?; | |
132 | ||
f323e906 WB |
133 | let head = DataBlobHeader { |
134 | magic: file_formats::COMPRESSED_BLOB_MAGIC_1_0, | |
135 | crc: crc.to_le_bytes(), | |
136 | }; | |
018d11bb DM |
137 | |
138 | writer.seek(SeekFrom::Start(0))?; | |
139 | unsafe { | |
140 | writer.write_le_value(head)?; | |
141 | } | |
142 | ||
62ee2eb4 | 143 | Ok(writer) |
018d11bb | 144 | } |
018d11bb DM |
145 | BlobWriterState::Encrypted { crypt_writer } => { |
146 | let (csum_writer, iv, tag) = crypt_writer.finish()?; | |
147 | let (mut writer, crc, _) = csum_writer.finish()?; | |
148 | ||
149 | let head = EncryptedDataBlobHeader { | |
f323e906 WB |
150 | head: DataBlobHeader { |
151 | magic: file_formats::ENCRYPTED_BLOB_MAGIC_1_0, | |
152 | crc: crc.to_le_bytes(), | |
153 | }, | |
154 | iv, | |
155 | tag, | |
018d11bb DM |
156 | }; |
157 | writer.seek(SeekFrom::Start(0))?; | |
158 | unsafe { | |
159 | writer.write_le_value(head)?; | |
160 | } | |
62ee2eb4 | 161 | Ok(writer) |
018d11bb DM |
162 | } |
163 | BlobWriterState::EncryptedCompressed { compr } => { | |
164 | let crypt_writer = compr.finish()?; | |
165 | let (csum_writer, iv, tag) = crypt_writer.finish()?; | |
166 | let (mut writer, crc, _) = csum_writer.finish()?; | |
167 | ||
168 | let head = EncryptedDataBlobHeader { | |
f323e906 WB |
169 | head: DataBlobHeader { |
170 | magic: file_formats::ENCR_COMPR_BLOB_MAGIC_1_0, | |
171 | crc: crc.to_le_bytes(), | |
172 | }, | |
173 | iv, | |
174 | tag, | |
018d11bb DM |
175 | }; |
176 | writer.seek(SeekFrom::Start(0))?; | |
177 | unsafe { | |
178 | writer.write_le_value(head)?; | |
179 | } | |
62ee2eb4 | 180 | Ok(writer) |
018d11bb DM |
181 | } |
182 | } | |
183 | } | |
184 | } | |
185 | ||
f323e906 | 186 | impl<W: Write + Seek> Write for DataBlobWriter<'_, W> { |
018d11bb DM |
187 | fn write(&mut self, buf: &[u8]) -> Result<usize, std::io::Error> { |
188 | match self.state { | |
f323e906 WB |
189 | BlobWriterState::Uncompressed { |
190 | ref mut csum_writer, | |
191 | } => csum_writer.write(buf), | |
192 | BlobWriterState::Compressed { ref mut compr } => compr.write(buf), | |
193 | BlobWriterState::Encrypted { | |
194 | ref mut crypt_writer, | |
195 | } => crypt_writer.write(buf), | |
196 | BlobWriterState::EncryptedCompressed { ref mut compr } => compr.write(buf), | |
018d11bb DM |
197 | } |
198 | } | |
199 | ||
200 | fn flush(&mut self) -> Result<(), std::io::Error> { | |
201 | match self.state { | |
f323e906 WB |
202 | BlobWriterState::Uncompressed { |
203 | ref mut csum_writer, | |
204 | } => csum_writer.flush(), | |
205 | BlobWriterState::Compressed { ref mut compr } => compr.flush(), | |
206 | BlobWriterState::Encrypted { | |
207 | ref mut crypt_writer, | |
208 | } => crypt_writer.flush(), | |
209 | BlobWriterState::EncryptedCompressed { ref mut compr } => compr.flush(), | |
018d11bb DM |
210 | } |
211 | } | |
212 | } |