2 use std
::convert
::TryInto
;
4 use proxmox
::tools
::io
::ops
::ReadExtOps
;
5 use crate::tools
::write
::WriteUtilOps
;
9 /// Data blob binary storage format
11 /// Data blobs store arbitrary binary data (< 16MB), and can be
12 /// compressed and encrypted. A simply binary format is used to store
13 /// them on disk or transfer them over the network. Please use index
14 /// files to store large data files (".fidx" of ".didx").
17 raw_data
: Vec
<u8>, // tagged, compressed, encryped data
22 /// accessor to raw_data field
23 pub fn raw_data(&self) -> &[u8] {
27 /// accessor to chunk type (magic number)
28 pub fn magic(&self) -> &[u8; 8] {
29 self.raw_data
[0..8].try_into().unwrap()
32 /// accessor to crc32 checksum
33 pub fn crc(&self) -> u32 {
34 let crc_o
= proxmox
::tools
::offsetof!(DataBlobHeader
, crc
);
35 u32::from_le_bytes(self.raw_data
[crc_o
..crc_o
+4].try_into().unwrap())
38 // set the CRC checksum field
39 pub fn set_crc(&mut self, crc
: u32) {
40 let crc_o
= proxmox
::tools
::offsetof!(DataBlobHeader
, crc
);
41 self.raw_data
[crc_o
..crc_o
+4].copy_from_slice(&crc
.to_le_bytes());
44 /// compute the CRC32 checksum
45 pub fn compute_crc(&mut self) -> u32 {
46 let mut hasher
= crc32fast
::Hasher
::new();
47 let start
= std
::mem
::size_of
::<DataBlobHeader
>(); // start after HEAD
48 hasher
.update(&self.raw_data
[start
..]);
54 config
: Option
<&CryptConfig
>,
56 ) -> Result
<Self, Error
> {
58 if data
.len() > 16*1024*1024 {
59 bail
!("data blob too large ({} bytes).", data
.len());
62 if let Some(config
) = config
{
65 let (_compress
, data
, magic
) = if compress
{
66 compr_data
= zstd
::block
::compress(data
, 1)?
;
67 // Note: We only use compression if result is shorter
68 if compr_data
.len() < data
.len() {
69 (true, &compr_data
[..], ENCR_COMPR_BLOB_MAGIC_1_0
)
71 (false, data
, ENCRYPTED_BLOB_MAGIC_1_0
)
74 (false, data
, ENCRYPTED_BLOB_MAGIC_1_0
)
77 let header_len
= std
::mem
::size_of
::<EncryptedDataBlobHeader
>();
78 let mut raw_data
= Vec
::with_capacity(data
.len() + header_len
);
80 let dummy_head
= EncryptedDataBlobHeader
{
81 head
: DataBlobHeader { magic: [0u8; 8], crc: [0; 4] }
,
85 raw_data
.write_value(&dummy_head
)?
;
87 let (iv
, tag
) = config
.encrypt_to(data
, &mut raw_data
)?
;
89 let head
= EncryptedDataBlobHeader
{
90 head
: DataBlobHeader { magic, crc: [0; 4] }
, iv
, tag
,
93 (&mut raw_data
[0..header_len
]).write_value(&head
)?
;
95 return Ok(DataBlob { raw_data }
);
98 let max_data_len
= data
.len() + std
::mem
::size_of
::<DataBlobHeader
>();
100 let mut comp_data
= Vec
::with_capacity(max_data_len
);
102 let head
= DataBlobHeader
{
103 magic
: COMPRESSED_BLOB_MAGIC_1_0
,
106 comp_data
.write_value(&head
)?
;
108 zstd
::stream
::copy_encode(data
, &mut comp_data
, 1)?
;
110 if comp_data
.len() < max_data_len
{
111 return Ok(DataBlob { raw_data: comp_data }
);
115 let mut raw_data
= Vec
::with_capacity(max_data_len
);
117 let head
= DataBlobHeader
{
118 magic
: UNCOMPRESSED_BLOB_MAGIC_1_0
,
121 raw_data
.write_value(&head
)?
;
122 raw_data
.extend_from_slice(data
);
124 return Ok(DataBlob { raw_data }
);
129 pub fn decode(self, config
: Option
<&CryptConfig
>) -> Result
<Vec
<u8>, Error
> {
131 let magic
= self.magic();
133 if magic
== &UNCOMPRESSED_BLOB_MAGIC_1_0
{
134 let data_start
= std
::mem
::size_of
::<DataBlobHeader
>();
135 return Ok(self.raw_data
[data_start
..].to_vec());
136 } else if magic
== &COMPRESSED_BLOB_MAGIC_1_0
{
137 let data_start
= std
::mem
::size_of
::<DataBlobHeader
>();
138 let data
= zstd
::block
::decompress(&self.raw_data
[data_start
..], 16*1024*1024)?
;
140 } else if magic
== &ENCR_COMPR_BLOB_MAGIC_1_0
|| magic
== &ENCRYPTED_BLOB_MAGIC_1_0
{
141 let header_len
= std
::mem
::size_of
::<EncryptedDataBlobHeader
>();
143 (&self.raw_data
[..header_len
]).read_le_value
::<EncryptedDataBlobHeader
>()?
146 if let Some(config
) = config
{
147 let data
= if magic
== &ENCR_COMPR_BLOB_MAGIC_1_0
{
148 config
.decode_compressed_chunk(&self.raw_data
[header_len
..], &head
.iv
, &head
.tag
)?
150 config
.decode_uncompressed_chunk(&self.raw_data
[header_len
..], &head
.iv
, &head
.tag
)?
154 bail
!("unable to decrypt blob - missing CryptConfig");
157 bail
!("Invalid blob magic number.");
161 /// Create Instance from raw data
162 pub fn from_raw(data
: Vec
<u8>) -> Result
<Self, Error
> {
164 if data
.len() < std
::mem
::size_of
::<DataBlobHeader
>() {
165 bail
!("blob too small ({} bytes).", data
.len());
168 let magic
= &data
[0..8];
170 if magic
== ENCR_COMPR_BLOB_MAGIC_1_0
|| magic
== ENCRYPTED_BLOB_MAGIC_1_0
{
172 if data
.len() < std
::mem
::size_of
::<EncryptedDataBlobHeader
>() {
173 bail
!("encrypted blob too small ({} bytes).", data
.len());
176 let blob
= DataBlob { raw_data: data }
;
179 } else if magic
== COMPRESSED_BLOB_MAGIC_1_0
|| magic
== UNCOMPRESSED_BLOB_MAGIC_1_0
{
181 let blob
= DataBlob { raw_data: data }
;
185 bail
!("unable to parse raw blob - wrong magic");