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