use rmp_serde::{Deserializer, Serializer};
use serde::{Deserialize, Serialize};
use super::storage::Storage;
use super::BLK_SIZE;
use base::crypto::{Cipher, Cost, Crypto, Key, Salt, SALT_SIZE};
use base::{Time, Version};
use error::{Error, Result};
use trans::Eid;
#[derive(Debug, Default)]
pub(super) struct Head {
pub salt: Salt,
pub cost: Cost,
pub cipher: Cipher,
}
impl Head {
const BYTES_LEN: usize = SALT_SIZE + Cost::BYTES_LEN + Cipher::BYTES_LEN;
fn seri(&self) -> Vec<u8> {
let mut pos = 0;
let mut buf = vec![0u8; Self::BYTES_LEN];
buf[..SALT_SIZE].copy_from_slice(self.salt.as_ref());
pos += SALT_SIZE;
buf[pos] = self.cost.to_u8();
pos += Cost::BYTES_LEN;
buf[pos] = self.cipher.into();
buf
}
fn deseri(buf: &[u8]) -> Result<Self> {
if buf.len() < Self::BYTES_LEN {
return Err(Error::InvalidSuperBlk);
}
let mut pos = 0;
let salt = Salt::from_slice(&buf[..SALT_SIZE]);
pos += SALT_SIZE;
let cost = Cost::from_u8(buf[pos])?;
pos += Cost::BYTES_LEN;
let cipher = Cipher::from_u8(buf[pos])?;
Ok(Head { salt, cost, cipher })
}
}
#[derive(Debug, Default, Deserialize, Serialize)]
pub(super) struct Body {
seq: u64,
pub volume_id: Eid,
pub ver: Version,
pub key: Key,
pub uri: String,
pub compress: bool,
pub ctime: Time,
pub mtime: Time,
pub payload: Vec<u8>,
}
impl Body {
fn seri(&mut self) -> Result<Vec<u8>> {
let mut buf = Vec::new();
self.seq += 1;
self.mtime = Time::now();
self.serialize(&mut Serializer::new(&mut buf))?;
Ok(buf)
}
fn deseri(buf: &[u8]) -> Result<Self> {
let mut de = Deserializer::new(buf);
let body: Body = Deserialize::deserialize(&mut de)?;
Ok(body)
}
}
#[derive(Debug, Default)]
pub(super) struct SuperBlk {
pub head: Head,
pub body: Body,
}
impl SuperBlk {
const MAGIC: [u8; 4] = [233, 239, 241, 251];
pub fn save(&mut self, pwd: &str, storage: &mut Storage) -> Result<()> {
let crypto = Crypto::new(self.head.cost, self.head.cipher)?;
let pwd_hash = crypto.hash_pwd(pwd, &self.head.salt)?;
let vkey = &pwd_hash.value;
let head_buf = self.head.seri();
let body_buf = self.body.seri()?;
let mut comp_buf = vec![0u8; 8 + body_buf.len()];
comp_buf[..8].copy_from_slice(&((body_buf.len() as u64).to_le_bytes()));
comp_buf[8..8 + body_buf.len()].copy_from_slice(&body_buf);
let new_len = crypto.decrypted_len(BLK_SIZE - head_buf.len());
if comp_buf.len() > new_len {
return Err(Error::InvalidSuperBlk);
}
comp_buf.resize(new_len, 0);
let enc_buf = crypto.encrypt_with_ad(&comp_buf, vkey, &Self::MAGIC)?;
let mut pos = 0;
let mut buf = vec![0u8; head_buf.len() + enc_buf.len()];
buf[..head_buf.len()].copy_from_slice(&head_buf);
pos += head_buf.len();
buf[pos..pos + enc_buf.len()].copy_from_slice(&enc_buf);
storage
.put_super_block(&buf, 0)
.and(storage.put_super_block(&buf, 1))
}
fn load_arm(suffix: u64, pwd: &str, storage: &mut Storage) -> Result<Self> {
let buf = storage.get_super_block(suffix)?;
let head = Head::deseri(&buf)?;
let crypto = Crypto::new(head.cost, head.cipher)?;
let pwd_hash = crypto.hash_pwd(pwd, &head.salt)?;
let vkey = &pwd_hash.value;
let comp_buf = crypto.decrypt_with_ad(
&buf[Head::BYTES_LEN..],
vkey,
&Self::MAGIC,
)?;
let mut buf: [u8; 8] = Default::default();
buf.copy_from_slice(&comp_buf[..8]);
let body_buf_len = u64::from_le_bytes(buf) as usize;
let body = Body::deseri(&comp_buf[8..8 + body_buf_len])?;
Ok(SuperBlk { head, body })
}
pub fn load(pwd: &str, storage: &mut Storage) -> Result<Self> {
let left = Self::load_arm(0, pwd, storage)?;
let right = Self::load_arm(1, pwd, storage)?;
if left.body.seq == right.body.seq {
Ok(left)
} else {
Err(Error::InvalidSuperBlk)
}
}
pub fn repair(pwd: &str, storage: &mut Storage) -> Result<()> {
let left_arm = Self::load_arm(0, pwd, storage);
let right_arm = Self::load_arm(1, pwd, storage);
match left_arm {
Ok(mut left) => match right_arm {
Ok(mut right) => {
if left.body.volume_id != right.body.volume_id
|| left.body.key != right.body.key
{
return Err(Error::InvalidSuperBlk);
}
if left.body.seq > right.body.seq {
left.save(pwd, storage)?;
} else if left.body.seq < right.body.seq {
right.save(pwd, storage)?;
} else {
debug!("super block all good, no need repair");
return Ok(());
}
}
Err(_) => left.save(pwd, storage)?,
},
Err(err) => {
if let Ok(mut right) = right_arm {
right.save(pwd, storage)?;
} else {
return Err(err);
}
}
}
debug!("super block repaired");
Ok(())
}
}