2 use std
::convert
::TryInto
;
4 use proxmox
::tools
::io
::{ReadExt, WriteExt}
;
6 const MAX_BLOB_SIZE
: usize = 128*1024*1024;
10 /// Data blob binary storage format
12 /// Data blobs store arbitrary binary data (< 128MB), and can be
13 /// compressed and encrypted. A simply binary format is used to store
14 /// them on disk or transfer them over the network. Please use index
15 /// files to store large data files (".fidx" of ".didx").
18 raw_data
: Vec
<u8>, // tagged, compressed, encryped data
23 pub fn header_size(magic
: &[u8; 8]) -> usize {
25 &UNCOMPRESSED_CHUNK_MAGIC_1_0
=> std
::mem
::size_of
::<DataChunkHeader
>(),
26 &COMPRESSED_CHUNK_MAGIC_1_0
=> std
::mem
::size_of
::<DataChunkHeader
>(),
27 &ENCRYPTED_CHUNK_MAGIC_1_0
=> std
::mem
::size_of
::<EncryptedDataChunkHeader
>(),
28 &ENCR_COMPR_CHUNK_MAGIC_1_0
=> std
::mem
::size_of
::<EncryptedDataChunkHeader
>(),
30 &UNCOMPRESSED_BLOB_MAGIC_1_0
=> std
::mem
::size_of
::<DataBlobHeader
>(),
31 &COMPRESSED_BLOB_MAGIC_1_0
=> std
::mem
::size_of
::<DataBlobHeader
>(),
32 &ENCRYPTED_BLOB_MAGIC_1_0
=> std
::mem
::size_of
::<EncryptedDataBlobHeader
>(),
33 &ENCR_COMPR_BLOB_MAGIC_1_0
=> std
::mem
::size_of
::<EncryptedDataBlobHeader
>(),
34 &AUTHENTICATED_BLOB_MAGIC_1_0
=> std
::mem
::size_of
::<AuthenticatedDataBlobHeader
>(),
35 &AUTH_COMPR_BLOB_MAGIC_1_0
=> std
::mem
::size_of
::<AuthenticatedDataBlobHeader
>(),
36 _
=> panic
!("unknown blob magic"),
40 /// accessor to raw_data field
41 pub fn raw_data(&self) -> &[u8] {
45 /// Consume self and returns raw_data
46 pub fn into_inner(self) -> Vec
<u8> {
50 /// accessor to chunk type (magic number)
51 pub fn magic(&self) -> &[u8; 8] {
52 self.raw_data
[0..8].try_into().unwrap()
55 /// accessor to crc32 checksum
56 pub fn crc(&self) -> u32 {
57 let crc_o
= proxmox
::tools
::offsetof!(DataBlobHeader
, crc
);
58 u32::from_le_bytes(self.raw_data
[crc_o
..crc_o
+4].try_into().unwrap())
61 // set the CRC checksum field
62 pub fn set_crc(&mut self, crc
: u32) {
63 let crc_o
= proxmox
::tools
::offsetof!(DataBlobHeader
, crc
);
64 self.raw_data
[crc_o
..crc_o
+4].copy_from_slice(&crc
.to_le_bytes());
67 /// compute the CRC32 checksum
68 pub fn compute_crc(&self) -> u32 {
69 let mut hasher
= crc32fast
::Hasher
::new();
70 let start
= Self::header_size(self.magic()); // start after HEAD
71 hasher
.update(&self.raw_data
[start
..]);
75 /// verify the CRC32 checksum
76 pub fn verify_crc(&self) -> Result
<(), Error
> {
77 let expected_crc
= self.compute_crc();
78 if expected_crc
!= self.crc() {
79 bail
!("Data blob has wrong CRC checksum.");
84 /// Create a DataBlob, optionally compressed and/or encrypted
87 config
: Option
<&CryptConfig
>,
89 ) -> Result
<Self, Error
> {
91 if data
.len() > MAX_BLOB_SIZE
{
92 bail
!("data blob too large ({} bytes).", data
.len());
95 let mut blob
= if let Some(config
) = config
{
98 let (_compress
, data
, magic
) = if compress
{
99 compr_data
= zstd
::block
::compress(data
, 1)?
;
100 // Note: We only use compression if result is shorter
101 if compr_data
.len() < data
.len() {
102 (true, &compr_data
[..], ENCR_COMPR_BLOB_MAGIC_1_0
)
104 (false, data
, ENCRYPTED_BLOB_MAGIC_1_0
)
107 (false, data
, ENCRYPTED_BLOB_MAGIC_1_0
)
110 let header_len
= std
::mem
::size_of
::<EncryptedDataBlobHeader
>();
111 let mut raw_data
= Vec
::with_capacity(data
.len() + header_len
);
113 let dummy_head
= EncryptedDataBlobHeader
{
114 head
: DataBlobHeader { magic: [0u8; 8], crc: [0; 4] }
,
119 raw_data
.write_le_value(dummy_head
)?
;
122 let (iv
, tag
) = config
.encrypt_to(data
, &mut raw_data
)?
;
124 let head
= EncryptedDataBlobHeader
{
125 head
: DataBlobHeader { magic, crc: [0; 4] }
, iv
, tag
,
129 (&mut raw_data
[0..header_len
]).write_le_value(head
)?
;
132 DataBlob { raw_data }
135 let max_data_len
= data
.len() + std
::mem
::size_of
::<DataBlobHeader
>();
137 let mut comp_data
= Vec
::with_capacity(max_data_len
);
139 let head
= DataBlobHeader
{
140 magic
: COMPRESSED_BLOB_MAGIC_1_0
,
144 comp_data
.write_le_value(head
)?
;
147 zstd
::stream
::copy_encode(data
, &mut comp_data
, 1)?
;
149 if comp_data
.len() < max_data_len
{
150 let mut blob
= DataBlob { raw_data: comp_data }
;
151 blob
.set_crc(blob
.compute_crc());
156 let mut raw_data
= Vec
::with_capacity(max_data_len
);
158 let head
= DataBlobHeader
{
159 magic
: UNCOMPRESSED_BLOB_MAGIC_1_0
,
163 raw_data
.write_le_value(head
)?
;
165 raw_data
.extend_from_slice(data
);
167 DataBlob { raw_data }
170 blob
.set_crc(blob
.compute_crc());
176 pub fn decode(self, config
: Option
<&CryptConfig
>) -> Result
<Vec
<u8>, Error
> {
178 let magic
= self.magic();
180 if magic
== &UNCOMPRESSED_BLOB_MAGIC_1_0
{
181 let data_start
= std
::mem
::size_of
::<DataBlobHeader
>();
182 return Ok(self.raw_data
[data_start
..].to_vec());
183 } else if magic
== &COMPRESSED_BLOB_MAGIC_1_0
{
184 let data_start
= std
::mem
::size_of
::<DataBlobHeader
>();
185 let data
= zstd
::block
::decompress(&self.raw_data
[data_start
..], MAX_BLOB_SIZE
)?
;
187 } else if magic
== &ENCR_COMPR_BLOB_MAGIC_1_0
|| magic
== &ENCRYPTED_BLOB_MAGIC_1_0
{
188 let header_len
= std
::mem
::size_of
::<EncryptedDataBlobHeader
>();
190 (&self.raw_data
[..header_len
]).read_le_value
::<EncryptedDataBlobHeader
>()?
193 if let Some(config
) = config
{
194 let data
= if magic
== &ENCR_COMPR_BLOB_MAGIC_1_0
{
195 config
.decode_compressed_chunk(&self.raw_data
[header_len
..], &head
.iv
, &head
.tag
)?
197 config
.decode_uncompressed_chunk(&self.raw_data
[header_len
..], &head
.iv
, &head
.tag
)?
201 bail
!("unable to decrypt blob - missing CryptConfig");
203 } else if magic
== &AUTH_COMPR_BLOB_MAGIC_1_0
|| magic
== &AUTHENTICATED_BLOB_MAGIC_1_0
{
204 let header_len
= std
::mem
::size_of
::<AuthenticatedDataBlobHeader
>();
206 (&self.raw_data
[..header_len
]).read_le_value
::<AuthenticatedDataBlobHeader
>()?
209 let data_start
= std
::mem
::size_of
::<AuthenticatedDataBlobHeader
>();
211 // Note: only verify if we have a crypt config
212 if let Some(config
) = config
{
213 let signature
= config
.compute_auth_tag(&self.raw_data
[data_start
..]);
214 if signature
!= head
.tag
{
215 bail
!("verifying blob signature failed");
219 if magic
== &AUTH_COMPR_BLOB_MAGIC_1_0
{
220 let data
= zstd
::block
::decompress(&self.raw_data
[data_start
..], 16*1024*1024)?
;
223 return Ok(self.raw_data
[data_start
..].to_vec());
226 bail
!("Invalid blob magic number.");
230 /// Create a signed DataBlob, optionally compressed
231 pub fn create_signed(
233 config
: &CryptConfig
,
235 ) -> Result
<Self, Error
> {
237 if data
.len() > MAX_BLOB_SIZE
{
238 bail
!("data blob too large ({} bytes).", data
.len());
242 let (_compress
, data
, magic
) = if compress
{
243 compr_data
= zstd
::block
::compress(data
, 1)?
;
244 // Note: We only use compression if result is shorter
245 if compr_data
.len() < data
.len() {
246 (true, &compr_data
[..], AUTH_COMPR_BLOB_MAGIC_1_0
)
248 (false, data
, AUTHENTICATED_BLOB_MAGIC_1_0
)
251 (false, data
, AUTHENTICATED_BLOB_MAGIC_1_0
)
254 let header_len
= std
::mem
::size_of
::<AuthenticatedDataBlobHeader
>();
255 let mut raw_data
= Vec
::with_capacity(data
.len() + header_len
);
257 let head
= AuthenticatedDataBlobHeader
{
258 head
: DataBlobHeader { magic, crc: [0; 4] }
,
259 tag
: config
.compute_auth_tag(data
),
262 raw_data
.write_le_value(head
)?
;
264 raw_data
.extend_from_slice(data
);
266 let mut blob
= DataBlob { raw_data }
;
267 blob
.set_crc(blob
.compute_crc());
272 /// Create Instance from raw data
273 pub fn from_raw(data
: Vec
<u8>) -> Result
<Self, Error
> {
275 if data
.len() < std
::mem
::size_of
::<DataBlobHeader
>() {
276 bail
!("blob too small ({} bytes).", data
.len());
279 let magic
= &data
[0..8];
281 if magic
== ENCR_COMPR_BLOB_MAGIC_1_0
|| magic
== ENCRYPTED_BLOB_MAGIC_1_0
{
283 if data
.len() < std
::mem
::size_of
::<EncryptedDataBlobHeader
>() {
284 bail
!("encrypted blob too small ({} bytes).", data
.len());
287 let blob
= DataBlob { raw_data: data }
;
290 } else if magic
== COMPRESSED_BLOB_MAGIC_1_0
|| magic
== UNCOMPRESSED_BLOB_MAGIC_1_0
{
292 let blob
= DataBlob { raw_data: data }
;
295 } else if magic
== AUTH_COMPR_BLOB_MAGIC_1_0
|| magic
== AUTHENTICATED_BLOB_MAGIC_1_0
{
296 if data
.len() < std
::mem
::size_of
::<AuthenticatedDataBlobHeader
>() {
297 bail
!("authenticated blob too small ({} bytes).", data
.len());
300 let blob
= DataBlob { raw_data: data }
;
304 bail
!("unable to parse raw blob - wrong magic");
310 use std
::io
::{Read, BufRead, BufReader, Write, Seek, SeekFrom}
;
312 struct CryptWriter
<W
> {
314 encr_buf
: [u8; 64*1024],
316 crypter
: openssl
::symm
::Crypter
,
319 impl <W
: Write
> CryptWriter
<W
> {
321 fn new(writer
: W
, config
: &CryptConfig
) -> Result
<Self, Error
> {
322 let mut iv
= [0u8; 16];
323 proxmox
::sys
::linux
::fill_with_random_data(&mut iv
)?
;
325 let crypter
= config
.data_crypter(&iv
, openssl
::symm
::Mode
::Encrypt
)?
;
327 Ok(Self { writer, iv, crypter, encr_buf: [0u8; 64*1024] }
)
330 fn finish(mut self) -> Result
<(W
, [u8; 16], [u8; 16]), Error
> {
331 let rest
= self.crypter
.finalize(&mut self.encr_buf
)?
;
333 self.writer
.write_all(&self.encr_buf
[..rest
])?
;
336 self.writer
.flush()?
;
338 let mut tag
= [0u8; 16];
339 self.crypter
.get_tag(&mut tag
)?
;
341 Ok((self.writer
, self.iv
, tag
))
345 impl <W
: Write
> Write
for CryptWriter
<W
> {
347 fn write(&mut self, buf
: &[u8]) -> Result
<usize, std
::io
::Error
> {
348 let count
= self.crypter
.update(buf
, &mut self.encr_buf
)
351 std
::io
::ErrorKind
::Other
,
352 format
!("crypter update failed - {}", err
))
355 self.writer
.write_all(&self.encr_buf
[..count
])?
;
360 fn flush(&mut self) -> Result
<(), std
::io
::Error
> {
365 struct ChecksumWriter
<'a
, W
> {
367 hasher
: crc32fast
::Hasher
,
368 signer
: Option
<openssl
::sign
::Signer
<'a
>>,
371 impl <'a
, W
: Write
> ChecksumWriter
<'a
, W
> {
373 fn new(writer
: W
, signer
: Option
<openssl
::sign
::Signer
<'a
>>) -> Self {
374 let hasher
= crc32fast
::Hasher
::new();
375 Self { writer, hasher, signer }
378 pub fn finish(mut self) -> Result
<(W
, u32, Option
<[u8; 32]>), Error
> {
379 let crc
= self.hasher
.finalize();
381 if let Some(ref mut signer
) = self.signer
{
382 let mut tag
= [0u8; 32];
383 signer
.sign(&mut tag
)?
;
384 Ok((self.writer
, crc
, Some(tag
)))
386 Ok((self.writer
, crc
, None
))
391 impl <'a
, W
: Write
> Write
for ChecksumWriter
<'a
, W
> {
393 fn write(&mut self, buf
: &[u8]) -> Result
<usize, std
::io
::Error
> {
394 self.hasher
.update(buf
);
395 if let Some(ref mut signer
) = self.signer
{
399 std
::io
::ErrorKind
::Other
,
400 format
!("hmac update failed - {}", err
))
403 self.writer
.write(buf
)
406 fn flush(&mut self) -> Result
<(), std
::io
::Error
> {
411 enum BlobWriterState
<'a
, W
: Write
> {
412 Uncompressed { csum_writer: ChecksumWriter<'a, W> }
,
413 Compressed { compr: zstd::stream::write::Encoder<ChecksumWriter<'a, W>> }
,
414 Signed { csum_writer: ChecksumWriter<'a, W> }
,
415 SignedCompressed { compr: zstd::stream::write::Encoder<ChecksumWriter<'a, W>> }
,
416 Encrypted { crypt_writer: CryptWriter<ChecksumWriter<'a, W>> }
,
417 EncryptedCompressed { compr: zstd::stream::write::Encoder<CryptWriter<ChecksumWriter<'a, W>>> }
,
420 /// Write compressed data blobs
421 pub struct DataBlobWriter
<'a
, W
: Write
> {
422 state
: BlobWriterState
<'a
, W
>,
425 impl <'a
, W
: Write
+ Seek
> DataBlobWriter
<'a
, W
> {
427 pub fn new_uncompressed(mut writer
: W
) -> Result
<Self, Error
> {
428 writer
.seek(SeekFrom
::Start(0))?
;
429 let head
= DataBlobHeader { magic: UNCOMPRESSED_BLOB_MAGIC_1_0, crc: [0; 4] }
;
431 writer
.write_le_value(head
)?
;
433 let csum_writer
= ChecksumWriter
::new(writer
, None
);
434 Ok(Self { state: BlobWriterState::Uncompressed { csum_writer }
})
437 pub fn new_compressed(mut writer
: W
) -> Result
<Self, Error
> {
438 writer
.seek(SeekFrom
::Start(0))?
;
439 let head
= DataBlobHeader { magic: COMPRESSED_BLOB_MAGIC_1_0, crc: [0; 4] }
;
441 writer
.write_le_value(head
)?
;
443 let csum_writer
= ChecksumWriter
::new(writer
, None
);
444 let compr
= zstd
::stream
::write
::Encoder
::new(csum_writer
, 1)?
;
445 Ok(Self { state: BlobWriterState::Compressed { compr }
})
448 pub fn new_signed(mut writer
: W
, config
: &'a CryptConfig
) -> Result
<Self, Error
> {
449 writer
.seek(SeekFrom
::Start(0))?
;
450 let head
= AuthenticatedDataBlobHeader
{
451 head
: DataBlobHeader { magic: AUTHENTICATED_BLOB_MAGIC_1_0, crc: [0; 4] }
,
455 writer
.write_le_value(head
)?
;
457 let signer
= config
.data_signer();
458 let csum_writer
= ChecksumWriter
::new(writer
, Some(signer
));
459 Ok(Self { state: BlobWriterState::Signed { csum_writer }
})
462 pub fn new_signed_compressed(mut writer
: W
, config
: &'a CryptConfig
) -> Result
<Self, Error
> {
463 writer
.seek(SeekFrom
::Start(0))?
;
464 let head
= AuthenticatedDataBlobHeader
{
465 head
: DataBlobHeader { magic: AUTH_COMPR_BLOB_MAGIC_1_0, crc: [0; 4] }
,
469 writer
.write_le_value(head
)?
;
471 let signer
= config
.data_signer();
472 let csum_writer
= ChecksumWriter
::new(writer
, Some(signer
));
473 let compr
= zstd
::stream
::write
::Encoder
::new(csum_writer
, 1)?
;
474 Ok(Self { state: BlobWriterState::SignedCompressed { compr }
})
477 pub fn new_encrypted(mut writer
: W
, config
: &'a CryptConfig
) -> Result
<Self, Error
> {
478 writer
.seek(SeekFrom
::Start(0))?
;
479 let head
= EncryptedDataBlobHeader
{
480 head
: DataBlobHeader { magic: ENCRYPTED_BLOB_MAGIC_1_0, crc: [0; 4] }
,
485 writer
.write_le_value(head
)?
;
488 let csum_writer
= ChecksumWriter
::new(writer
, None
);
489 let crypt_writer
= CryptWriter
::new(csum_writer
, config
)?
;
490 Ok(Self { state: BlobWriterState::Encrypted { crypt_writer }
})
493 pub fn new_encrypted_compressed(mut writer
: W
, config
: &'a CryptConfig
) -> Result
<Self, Error
> {
494 writer
.seek(SeekFrom
::Start(0))?
;
495 let head
= EncryptedDataBlobHeader
{
496 head
: DataBlobHeader { magic: ENCR_COMPR_BLOB_MAGIC_1_0, crc: [0; 4] }
,
501 writer
.write_le_value(head
)?
;
504 let csum_writer
= ChecksumWriter
::new(writer
, None
);
505 let crypt_writer
= CryptWriter
::new(csum_writer
, config
)?
;
506 let compr
= zstd
::stream
::write
::Encoder
::new(crypt_writer
, 1)?
;
507 Ok(Self { state: BlobWriterState::EncryptedCompressed { compr }
})
510 pub fn finish(self) -> Result
<W
, Error
> {
512 BlobWriterState
::Uncompressed { csum_writer }
=> {
514 let (mut writer
, crc
, _
) = csum_writer
.finish()?
;
515 let head
= DataBlobHeader { magic: UNCOMPRESSED_BLOB_MAGIC_1_0, crc: crc.to_le_bytes() }
;
517 writer
.seek(SeekFrom
::Start(0))?
;
519 writer
.write_le_value(head
)?
;
524 BlobWriterState
::Compressed { compr }
=> {
525 let csum_writer
= compr
.finish()?
;
526 let (mut writer
, crc
, _
) = csum_writer
.finish()?
;
528 let head
= DataBlobHeader { magic: COMPRESSED_BLOB_MAGIC_1_0, crc: crc.to_le_bytes() }
;
530 writer
.seek(SeekFrom
::Start(0))?
;
532 writer
.write_le_value(head
)?
;
537 BlobWriterState
::Signed { csum_writer }
=> {
538 let (mut writer
, crc
, tag
) = csum_writer
.finish()?
;
540 let head
= AuthenticatedDataBlobHeader
{
541 head
: DataBlobHeader { magic: AUTHENTICATED_BLOB_MAGIC_1_0, crc: crc.to_le_bytes() }
,
545 writer
.seek(SeekFrom
::Start(0))?
;
547 writer
.write_le_value(head
)?
;
552 BlobWriterState
::SignedCompressed { compr }
=> {
553 let csum_writer
= compr
.finish()?
;
554 let (mut writer
, crc
, tag
) = csum_writer
.finish()?
;
556 let head
= AuthenticatedDataBlobHeader
{
557 head
: DataBlobHeader { magic: AUTH_COMPR_BLOB_MAGIC_1_0, crc: crc.to_le_bytes() }
,
561 writer
.seek(SeekFrom
::Start(0))?
;
563 writer
.write_le_value(head
)?
;
568 BlobWriterState
::Encrypted { crypt_writer }
=> {
569 let (csum_writer
, iv
, tag
) = crypt_writer
.finish()?
;
570 let (mut writer
, crc
, _
) = csum_writer
.finish()?
;
572 let head
= EncryptedDataBlobHeader
{
573 head
: DataBlobHeader { magic: ENCRYPTED_BLOB_MAGIC_1_0, crc: crc.to_le_bytes() }
,
576 writer
.seek(SeekFrom
::Start(0))?
;
578 writer
.write_le_value(head
)?
;
582 BlobWriterState
::EncryptedCompressed { compr }
=> {
583 let crypt_writer
= compr
.finish()?
;
584 let (csum_writer
, iv
, tag
) = crypt_writer
.finish()?
;
585 let (mut writer
, crc
, _
) = csum_writer
.finish()?
;
587 let head
= EncryptedDataBlobHeader
{
588 head
: DataBlobHeader { magic: ENCR_COMPR_BLOB_MAGIC_1_0, crc: crc.to_le_bytes() }
,
591 writer
.seek(SeekFrom
::Start(0))?
;
593 writer
.write_le_value(head
)?
;
601 impl <'a
, W
: Write
+ Seek
> Write
for DataBlobWriter
<'a
, W
> {
603 fn write(&mut self, buf
: &[u8]) -> Result
<usize, std
::io
::Error
> {
605 BlobWriterState
::Uncompressed { ref mut csum_writer }
=> {
606 csum_writer
.write(buf
)
608 BlobWriterState
::Compressed { ref mut compr }
=> {
611 BlobWriterState
::Signed { ref mut csum_writer }
=> {
612 csum_writer
.write(buf
)
614 BlobWriterState
::SignedCompressed { ref mut compr }
=> {
617 BlobWriterState
::Encrypted { ref mut crypt_writer }
=> {
618 crypt_writer
.write(buf
)
620 BlobWriterState
::EncryptedCompressed { ref mut compr }
=> {
626 fn flush(&mut self) -> Result
<(), std
::io
::Error
> {
628 BlobWriterState
::Uncompressed { ref mut csum_writer }
=> {
631 BlobWriterState
::Compressed { ref mut compr }
=> {
634 BlobWriterState
::Signed { ref mut csum_writer }
=> {
637 BlobWriterState
::SignedCompressed { ref mut compr }
=> {
640 BlobWriterState
::Encrypted { ref mut crypt_writer }
=> {
643 BlobWriterState
::EncryptedCompressed { ref mut compr }
=> {
650 struct ChecksumReader
<'a
, R
> {
652 hasher
: crc32fast
::Hasher
,
653 signer
: Option
<openssl
::sign
::Signer
<'a
>>,
656 impl <'a
, R
: Read
> ChecksumReader
<'a
, R
> {
658 fn new(reader
: R
, signer
: Option
<openssl
::sign
::Signer
<'a
>>) -> Self {
659 let hasher
= crc32fast
::Hasher
::new();
660 Self { reader, hasher, signer }
663 pub fn finish(mut self) -> Result
<(R
, u32, Option
<[u8; 32]>), Error
> {
664 let crc
= self.hasher
.finalize();
666 if let Some(ref mut signer
) = self.signer
{
667 let mut tag
= [0u8; 32];
668 signer
.sign(&mut tag
)?
;
669 Ok((self.reader
, crc
, Some(tag
)))
671 Ok((self.reader
, crc
, None
))
676 impl <'a
, R
: Read
> Read
for ChecksumReader
<'a
, R
> {
678 fn read(&mut self, buf
: &mut [u8]) -> Result
<usize, std
::io
::Error
> {
679 let count
= self.reader
.read(buf
)?
;
681 self.hasher
.update(&buf
[..count
]);
682 if let Some(ref mut signer
) = self.signer
{
683 signer
.update(&buf
[..count
])
686 std
::io
::ErrorKind
::Other
,
687 format
!("hmac update failed - {}", err
))
695 enum BlobReaderState
<'a
, R
: Read
> {
696 Uncompressed { expected_crc: u32, csum_reader: ChecksumReader<'a, R> }
,
697 Compressed { expected_crc: u32, decompr: zstd::stream::read::Decoder<BufReader<ChecksumReader<'a, R>>> }
,
701 pub struct DataBlobReader
<'a
, R
: Read
> {
702 state
: BlobReaderState
<'a
, R
>,
705 impl <'a
, R
: Read
> DataBlobReader
<'a
, R
> {
707 pub fn new(mut reader
: R
) -> Result
<Self, Error
> {
709 let head
: DataBlobHeader
= unsafe { reader.read_le_value()? }
;
711 UNCOMPRESSED_BLOB_MAGIC_1_0
=> {
712 let expected_crc
= u32::from_le_bytes(head
.crc
);
713 let csum_reader
= ChecksumReader
::new(reader
, None
);
714 Ok(Self { state: BlobReaderState::Uncompressed { expected_crc, csum_reader }
})
716 COMPRESSED_BLOB_MAGIC_1_0
=> {
717 let expected_crc
= u32::from_le_bytes(head
.crc
);
718 let csum_reader
= ChecksumReader
::new(reader
, None
);
720 let decompr
= zstd
::stream
::read
::Decoder
::new(csum_reader
)?
;
721 Ok(Self { state: BlobReaderState::Compressed { expected_crc, decompr }
})
723 _
=> bail
!("got wrong magic number {:?}", head
.magic
)
727 pub fn finish(self) -> Result
<R
, Error
> {
729 BlobReaderState
::Uncompressed { csum_reader, expected_crc }
=> {
730 let (reader
, crc
, _
) = csum_reader
.finish()?
;
731 if crc
!= expected_crc
{
732 bail
!("blob crc check failed");
736 BlobReaderState
::Compressed { expected_crc, decompr }
=> {
737 let csum_reader
= decompr
.finish().into_inner();
738 let (reader
, crc
, _
) = csum_reader
.finish()?
;
739 if crc
!= expected_crc
{
740 bail
!("blob crc check failed");
748 impl <'a
, R
: BufRead
> Read
for DataBlobReader
<'a
, R
> {
750 fn read(&mut self, buf
: &mut [u8]) -> Result
<usize, std
::io
::Error
> {
751 match &mut self.state
{
752 BlobReaderState
::Uncompressed { csum_reader, .. }
=> {
753 csum_reader
.read(buf
)
755 BlobReaderState
::Compressed { decompr, .. }
=> {