use brec_common::*;
use thiserror::Error;
#[cfg(feature = "crypt")]
use crate::crypt::CryptError;
#[cfg(feature = "observer")]
use crate::storage::SensorError;
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum UnrecognizedSignature {
Block([u8; 4]),
Payload(Vec<u8>),
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Unrecognized {
pub sig: UnrecognizedSignature,
pub pos: Option<u64>,
pub len: Option<u64>,
}
impl Default for Unrecognized {
fn default() -> Self {
Self {
sig: UnrecognizedSignature::Block([0; 4]),
pos: None,
len: None,
}
}
}
impl Unrecognized {
pub fn block(sig: [u8; 4]) -> Self {
Self {
sig: UnrecognizedSignature::Block(sig),
..Self::default()
}
}
pub fn payload(sig: Vec<u8>) -> Self {
Self {
sig: UnrecognizedSignature::Payload(sig),
..Self::default()
}
}
pub fn block_from<T: std::io::Read>(buf: &mut T) -> Result<Self, Error> {
let mut sig = [0u8; BLOCK_SIG_LEN];
let read_sig = read_exact_partial(buf, &mut sig)?;
if read_sig < BLOCK_SIG_LEN {
return Err(Error::NotEnoughtSignatureData(read_sig, BLOCK_SIG_LEN));
}
#[cfg(not(feature = "resilient"))]
{
Ok(Self::block(sig))
}
#[cfg(feature = "resilient")]
{
let mut unrecognized = Self::block(sig);
let mut blk_len = [0u8; BLOCK_SIZE_FIELD_LEN];
let read_len = read_exact_partial(buf, &mut blk_len)?;
if read_len < BLOCK_SIZE_FIELD_LEN {
return Err(Error::NotEnoughData(BLOCK_SIZE_FIELD_LEN - read_len));
}
unrecognized.len = Some(u32::from_le_bytes(blk_len) as u64);
Ok(unrecognized)
}
}
pub fn block_from_slice(buf: &[u8]) -> Result<Self, Error> {
if buf.len() < BLOCK_SIG_LEN {
return Err(Error::NotEnoughtSignatureData(buf.len(), BLOCK_SIG_LEN));
}
let sig = <[u8; BLOCK_SIG_LEN]>::try_from(&buf[..BLOCK_SIG_LEN])?;
#[cfg(not(feature = "resilient"))]
{
Ok(Self::block(sig))
}
#[cfg(feature = "resilient")]
{
let from = BLOCK_SIG_LEN;
let to = BLOCK_SIG_LEN + BLOCK_SIZE_FIELD_LEN;
if buf.len() < to {
return Err(Error::NotEnoughData(to - buf.len()));
}
let blk_len = <[u8; BLOCK_SIZE_FIELD_LEN]>::try_from(&buf[from..to])?;
let mut unrecognized = Self::block(sig);
unrecognized.len = Some(u32::from_le_bytes(blk_len) as u64);
Ok(unrecognized)
}
}
pub fn block_from_buffer<T: std::io::BufRead>(buf: &mut T) -> Result<Self, Error> {
let bytes = buf.fill_buf()?;
Self::block_from_slice(bytes)
}
}
fn read_exact_partial<T: std::io::Read>(
buf: &mut T,
dst: &mut [u8],
) -> Result<usize, std::io::Error> {
let mut total = 0usize;
while total < dst.len() {
match buf.read(&mut dst[total..]) {
Ok(0) => break,
Ok(n) => total += n,
Err(err) if err.kind() == std::io::ErrorKind::Interrupted => continue,
Err(err) => return Err(err),
}
}
Ok(total)
}
#[derive(Error, Debug)]
pub enum Error {
#[error("Not enought data; required = {0}")]
NotEnoughData(usize),
#[error("Not enought data to read signature; data len = {0}; required = {1}")]
NotEnoughtSignatureData(usize, usize),
#[error("Invalid data align; data len = {0}; required = {1}; offset = {2} (expected 0)")]
InvalidAlign(usize, usize, usize),
#[error("Invalid buffer capacity: {0}; expected: {1}")]
InvalidCapacity(usize, String),
#[error("TryFromSliceError: {0}")]
TryFromSliceError(#[from] std::array::TryFromSliceError),
#[error("Signature doesn't match to target entity")]
SignatureDismatch(Unrecognized),
#[error("Crc doesn't match to target entity")]
CrcDismatch,
#[error("Same rule has been added already")]
RuleDuplicate,
#[error("Block has zero length")]
ZeroLengthBlock,
#[error("Invalid encoded length")]
InvalidLength,
#[error("Attempt to read more blocks than allowed")]
MaxBlocksCount,
#[error("Misaligned slice pointer")]
MisalignedPointer,
#[error("Unexpected slice length")]
UnexpectedSliceLength,
#[error("Fail converting \"{0}\" with error: {1}")]
FailedConverting(String, String),
#[error("IO Error: {0}")]
Io(#[from] std::io::Error),
#[error("Fail to exctract data from vector for ByteBlock")]
FailExtractByteBlock,
#[error("Fail to read payload header")]
FailToReadPayloadHeader,
#[error("Memory allocation failed")]
MemoryAllocationFailed,
#[error("Encoding error: {0}")]
EncodeError(String),
#[error("No pending packet to accept")]
NoPendingPacket,
#[error("Fail to read packet header")]
FailToReadPacketHeader,
#[error("PacketBufReader fall down into invalid logic")]
InvalidPacketReaderLogic,
#[error("Fail to find free slot")]
CannotFindFreeSlot,
#[error("Fail to find free palce in slot")]
CannotFindFreePlaceInSlot,
#[error("Fail to insert data into slot")]
CannotInsertIntoSlot,
#[error("Damaged slot: {0}")]
DamagedSlot(Box<Error>),
#[error("Too many attempts to read block; made {0} attempts")]
TooManyAttemptsToReadBlock(usize),
#[error("Out of bounds; len = {0}; requested = {1}")]
OutOfBounds(usize, usize),
#[error("Path isn't a file: {0}")]
PathIsNotFile(String),
#[error("File is locked: {0}")]
FileIsLocked(String),
#[error("Timeout error. File is locked: {0}")]
TimeoutToWaitLockedFile(String),
#[error("Fail to lock file: {0}")]
FailToLockFile(std::io::Error),
#[error("Fail to access slot:{0}")]
AccessSlot(usize),
#[error("Empty source")]
EmptySource,
#[cfg(feature = "crypt")]
#[error("Crypt: {0}")]
Crypt(#[from] CryptError),
#[cfg(feature = "observer")]
#[error("Sensor: {0}")]
Sensor(SensorError),
#[cfg(feature = "observer")]
#[error("No subscription")]
NoSubscription,
#[error("Test error has been fired")]
Test,
}
impl Error {
pub fn into_read_status<T>(self) -> Result<crate::ReadStatus<T>, Self> {
match self {
Self::NotEnoughtSignatureData(len, required) => {
Ok(crate::ReadStatus::NotEnoughData((required - len) as u64))
}
Self::NotEnoughData(needed) => Ok(crate::ReadStatus::NotEnoughData(needed as u64)),
err => Err(err),
}
}
}
impl From<Error> for std::io::Error {
fn from(value: Error) -> Self {
std::io::Error::other(value.to_string())
}
}
#[cfg(feature = "observer")]
impl From<SensorError> for Error {
fn from(value: SensorError) -> Self {
Error::Sensor(value)
}
}