]> git.proxmox.com Git - proxmox-backup.git/blame - pbs-datastore/src/data_blob_writer.rs
update to first proxmox crate split
[proxmox-backup.git] / pbs-datastore / src / data_blob_writer.rs
CommitLineData
f323e906
WB
1use std::io::{Seek, SeekFrom, Write};
2use std::sync::Arc;
018d11bb 3
6ef1b649
WB
4use anyhow::Error;
5
6use proxmox_io::WriteExt;
7
bbdda58b
DM
8use pbs_tools::crypt_config::CryptConfig;
9
f323e906 10use crate::checksum_writer::ChecksumWriter;
f323e906
WB
11use crate::crypt_writer::CryptWriter;
12use crate::file_formats::{self, DataBlobHeader, EncryptedDataBlobHeader};
018d11bb 13
90ff75f8 14enum 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
30pub struct DataBlobWriter<'writer, W: Write> {
31 state: BlobWriterState<'writer, W>,
018d11bb
DM
32}
33
f323e906 34impl<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 186impl<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}