use crc64::crc64;
use crate::utils::HexU64;
use super::config::JournalError;
pub const JOURNAL_MAGIC_NUM: &[u8; 8] = b"TMPSJRNL";
pub(super) const JOURNAL_HEADER_SIZE: usize = 24;
#[derive(Debug)]
pub(super) struct JournalHeader {
pub(super) filenum: u64,
}
impl JournalHeader {
pub(super) fn new(filenum: u64) -> Self {
Self { filenum }
}
pub(super) fn encode(&self) -> [u8; JOURNAL_HEADER_SIZE] {
let mut buf = [0u8; JOURNAL_HEADER_SIZE];
buf[0..8].copy_from_slice(JOURNAL_MAGIC_NUM);
buf[8..16].copy_from_slice(&self.filenum.to_le_bytes());
let checksum = crc64(0, &buf[0..16]);
buf[16..24].copy_from_slice(&checksum.to_le_bytes());
buf
}
pub(super) fn decode_from_slice(buf: &[u8]) -> Result<Self, JournalError> {
assert_eq!(
buf.len(),
JOURNAL_HEADER_SIZE,
"could not decode JournalHeader: invalid slice length"
);
Self::decode(buf.try_into().unwrap())
}
fn decode(buf: [u8; JOURNAL_HEADER_SIZE]) -> Result<Self, JournalError> {
let magic_bytes = &buf[0..8];
if magic_bytes != JOURNAL_MAGIC_NUM {
return Err(JournalError::InvalidMagic);
}
let stored_checksum = u64::from_le_bytes(buf[16..24].try_into().unwrap());
let computed_checksum = crc64(0, &buf[0..16]);
if stored_checksum != computed_checksum {
return Err(JournalError::Checksum);
}
let filenum = u64::from_le_bytes(buf[8..16].try_into().unwrap());
Ok(Self { filenum })
}
}
pub(super) const EDIT_PREFIX_SIZE: usize = 12;
#[derive(Debug, Clone, Copy)]
pub struct EditPrefix {
#[debug("{:?}", HexU64(*checksum))]
checksum: u64,
len: u32,
}
impl EditPrefix {
pub fn new(data: &[u8]) -> Self {
assert!(
data.len() <= u32::MAX as usize,
"journal edits may not be larger than u32::MAX bytes"
);
let checksum = crc64(0, data);
let len = data.len() as u32;
Self { checksum, len }
}
pub fn encode(&self) -> [u8; EDIT_PREFIX_SIZE] {
let mut buf = [0u8; EDIT_PREFIX_SIZE];
buf[0..8].copy_from_slice(&self.checksum.to_le_bytes());
buf[8..12].copy_from_slice(&self.len.to_le_bytes());
buf
}
pub fn decode_from_slice(buf: &[u8]) -> Self {
assert_eq!(
buf.len(),
EDIT_PREFIX_SIZE,
"could not decode EditPrefix: invalid slice length"
);
Self::decode(buf.try_into().unwrap())
}
pub fn decode(buf: &[u8; EDIT_PREFIX_SIZE]) -> Self {
let checksum = u64::from_le_bytes(buf[0..8].try_into().unwrap());
let len = u32::from_le_bytes(buf[8..12].try_into().unwrap());
Self { checksum, len }
}
pub const fn len(&self) -> u32 {
self.len
}
pub fn is_valid(&self, data: &[u8]) -> bool {
assert_eq!(data.len(), self.len as usize);
let computed = crc64(0, data);
computed == self.checksum
}
}