You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

200 lines
5.2 KiB

//! Handles file formats
use super::*;
use std::{
error,
fmt,
marker::{
PhantomData,
Unpin,
},
};
use tokio::{
prelude::*,
io::{
AsyncWrite,
AsyncRead,
},
};
use version::Version;
pub trait Header: fmt::Debug
{
const CHECK: u16;
fn hash(&self) -> crypto::sha256::Sha256Hash;
}
pub const RAE_HEADER_BIT: [u8; 4] = *b"RAE0";
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
/// The header before all RAE files.
pub struct SuperHeader<H: Header>
{
head: [u8; 4],
vers: Version,
chk: u16,
header_hash: crypto::sha256::Sha256Hash,
_header: PhantomData<H>,
}
impl<H: Header> Default for SuperHeader<H>
{
#[inline]
fn default() -> Self
{
Self::new()
}
}
const MAX_TEXT_SZ: Option<usize> = Some(1024 * 1024);
impl<H: Header> SuperHeader<H>
{
/// Write this superheader as text bytes to this stream
#[instrument(err, skip(out))]
pub async fn write_text<T: AsyncWrite+Unpin+?Sized>(&self, out: &mut T) -> Result<usize, eyre::Report>
{
let vec = serde_json::to_vec(self)
.wrap_err_with(|| eyre::eyre!("Failed to serialise self to JSON"))
.with_section(|| format!("{:?}", self).header("Self was"))?;
out.write_all(&vec[..]).await?;
Ok(vec.len())
}
/// Read a superheader as text bytes from this stream
#[instrument(err, skip(input))]
pub async fn read_text<T: AsyncRead+Unpin+?Sized>(input: &mut T) -> Result<Self, eyre::Report>
{
let whole = input.read_whole_stream(MAX_TEXT_SZ).await
.wrap_err_with(|| eyre::eyre!("Failed to read text stream into memory"))?;
Ok(serde_json::from_slice(&whole[..])
.wrap_err_with(|| eyre::eyre!("Failed to deserialise JSON to value"))
.with_section(move || String::from_utf8_lossy(&whole[..]).into_owned().header("Read text was"))?)
}
/// Write this superheader as bytes to this stream
#[instrument(err, skip(out))]
pub async fn write_bytes<T: AsyncWrite+Unpin+?Sized>(&self, out: &mut T) -> Result<usize, eyre::Report>
{
Ok({out.write_all(&self.head[..]).await?; self.head.len()} +
{out.write_all(self.vers.as_bytes()).await?; std::mem::size_of::<Version>()} +
{out.write_u16(self.chk).await?; 2} +
{out.write_all(self.header_hash.as_ref()).await?; std::mem::size_of::<crypto::sha256::Sha256Hash>()})
}
/// Read a superheader as bytes from this stream
#[instrument(err, skip(input))]
pub async fn read_bytes<T: AsyncRead+Unpin+?Sized>(input: &mut T) -> Result<Self, eyre::Report>
{
let mut new = Self::new();
input.read_exact(&mut new.head[..]).await?;
new.vers = {
let mut bytes = [0u8; std::mem::size_of::<Version>()];
input.read_exact(&mut bytes[..]).await?;
Version::try_from_bytes(bytes)
.wrap_err_with(|| eyre::eyre!("Failed to decode version"))
.with_section(|| bytes.to_broken_hex_string().header("Bytes (hex) were"))?
};
new.chk = input.read_u16().await?;
new.header_hash = {
let mut bytes= crypto::sha256::Sha256Hash::empty();
input.read_exact(bytes.as_mut()).await?;
bytes
};
if new.vers.should_warn(&CURRENT_VERSION) {
warn!("Header ({:?}) is read to have deprecated version {}, we are on version {}", new, new.vers, CURRENT_VERSION)
}
Ok(new)
}
/// Create a new empty superheader
pub fn new() -> Self
{
Self{
head: RAE_HEADER_BIT,
vers: CURRENT_VERSION,
chk: H::CHECK,
header_hash: Default::default(),
_header: PhantomData,
}
}
/// Consume into a new instance with hash for `header`.
pub fn with_hash(self, header: &H) -> Self
{
Self {
header_hash: header.hash(),
..self
}
}
/// Create a new superheader for
pub fn new_for(header: &H) -> Self
{
Self {
header_hash: header.hash(),
..Self::new()
}
}
/// Verify this empty superheader
pub fn verify(&self) -> Result<(), VerificationError>
{
macro_rules! check {
($field:expr, $err:expr) => {
if !$field {
return Err($err);
}
}
}
check!(self.head == RAE_HEADER_BIT, VerificationError::BadHeaderBit);
check!(self.vers.is_compat(&CURRENT_VERSION), VerificationError::IncompatableVersion(self.vers));
check!(self.chk == H::CHECK, VerificationError::BadCheckBit);
Ok(())
}
/// Verify this not-empty header for `header`.
///
/// # Notes
/// This also calls `self.verify()`.
pub fn verify_for(&self, header: &H) -> Result<(), VerificationError>
{
self.verify()?;
if self.header_hash == header.hash() {
Ok(())
} else {
Err(VerificationError::BadHash)
}
}
}
#[derive(Debug)]
#[non_exhaustive]
pub enum VerificationError
{
BadHeaderBit,
IncompatableVersion(Version),
BadCheckBit,
BadHash,
}
impl error::Error for VerificationError{}
impl fmt::Display for VerificationError
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
{
match self {
Self::BadHeaderBit => write!(f, "bad header bit"),
Self::IncompatableVersion(vers) => write!(f, "contained incompatable version {}, we are on version {}", vers, CURRENT_VERSION),
Self::BadCheckBit => write!(f, "contained invalid check bit"),
Self::BadHash => write!(f, "contained invalid header hash"),
}
}
}
mod key;
const CHECK_KEY: u16 = 0x0001;