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