tempest_core/journal/
header.rs1use crc64::crc64;
2
3use crate::utils::HexU64;
4
5use super::config::JournalError;
6
7pub const JOURNAL_MAGIC_NUM: &[u8; 8] = b"TMPSJRNL";
8
9pub(super) const JOURNAL_HEADER_SIZE: usize = 24;
10
11#[derive(Debug)]
12pub(super) struct JournalHeader {
13 pub(super) filenum: u64,
14}
15
16impl JournalHeader {
17 pub(super) fn new(filenum: u64) -> Self {
18 Self { filenum }
19 }
20
21 pub(super) fn encode(&self) -> [u8; JOURNAL_HEADER_SIZE] {
22 let mut buf = [0u8; JOURNAL_HEADER_SIZE];
23 buf[0..8].copy_from_slice(JOURNAL_MAGIC_NUM);
24 buf[8..16].copy_from_slice(&self.filenum.to_le_bytes());
25 let checksum = crc64(0, &buf[0..16]);
26 buf[16..24].copy_from_slice(&checksum.to_le_bytes());
27 buf
28 }
29
30 pub(super) fn decode_from_slice(buf: &[u8]) -> Result<Self, JournalError> {
37 assert_eq!(
38 buf.len(),
39 JOURNAL_HEADER_SIZE,
40 "could not decode JournalHeader: invalid slice length"
41 );
42 Self::decode(buf.try_into().unwrap())
43 }
44
45 fn decode(buf: [u8; JOURNAL_HEADER_SIZE]) -> Result<Self, JournalError> {
46 let magic_bytes = &buf[0..8];
48 if magic_bytes != JOURNAL_MAGIC_NUM {
49 return Err(JournalError::InvalidMagic);
50 }
51
52 let stored_checksum = u64::from_le_bytes(buf[16..24].try_into().unwrap());
54 let computed_checksum = crc64(0, &buf[0..16]);
55 if stored_checksum != computed_checksum {
56 return Err(JournalError::Checksum);
57 }
58
59 let filenum = u64::from_le_bytes(buf[8..16].try_into().unwrap());
61 Ok(Self { filenum })
62 }
63}
64
65pub(super) const EDIT_PREFIX_SIZE: usize = 12;
66
67#[derive(Debug, Clone, Copy)]
68pub struct EditPrefix {
69 #[debug("{:?}", HexU64(*checksum))]
70 checksum: u64,
71 len: u32,
72}
73
74impl EditPrefix {
75 pub fn new(data: &[u8]) -> Self {
82 assert!(
83 data.len() <= u32::MAX as usize,
84 "journal edits may not be larger than u32::MAX bytes"
85 );
86 let checksum = crc64(0, data);
87 let len = data.len() as u32;
88 Self { checksum, len }
89 }
90
91 pub fn encode(&self) -> [u8; EDIT_PREFIX_SIZE] {
93 let mut buf = [0u8; EDIT_PREFIX_SIZE];
94 buf[0..8].copy_from_slice(&self.checksum.to_le_bytes());
95 buf[8..12].copy_from_slice(&self.len.to_le_bytes());
96 buf
97 }
98
99 pub fn decode_from_slice(buf: &[u8]) -> Self {
106 assert_eq!(
107 buf.len(),
108 EDIT_PREFIX_SIZE,
109 "could not decode EditPrefix: invalid slice length"
110 );
111 Self::decode(buf.try_into().unwrap())
112 }
113
114 pub fn decode(buf: &[u8; EDIT_PREFIX_SIZE]) -> Self {
115 let checksum = u64::from_le_bytes(buf[0..8].try_into().unwrap());
116 let len = u32::from_le_bytes(buf[8..12].try_into().unwrap());
117 Self { checksum, len }
118 }
119
120 pub const fn len(&self) -> u32 {
122 self.len
123 }
124
125 pub fn is_valid(&self, data: &[u8]) -> bool {
132 assert_eq!(data.len(), self.len as usize);
133 let computed = crc64(0, data);
134 computed == self.checksum
135 }
136}