]> git.proxmox.com Git - proxmox-backup.git/blame - src/backup/data_blob_writer.rs
switch from failure to anyhow
[proxmox-backup.git] / src / backup / data_blob_writer.rs
CommitLineData
f7d4e4b5 1use anyhow::{Error};
9025312a 2use std::sync::Arc;
018d11bb
DM
3use std::io::{Write, Seek, SeekFrom};
4use proxmox::tools::io::WriteExt;
5
6use super::*;
7
9025312a
WB
8enum 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
18pub struct DataBlobWriter<W: Write> {
19 state: BlobWriterState<W>,
018d11bb
DM
20}
21
9025312a 22impl <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 196impl <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}