use core::fmt;
use core::fmt::Display;
#[cfg(feature = "std")]
use std::error;
use crate::phys::{
BinaryDecodeError, BinaryDecoder, BinaryEncodeError, BinaryEncoder, ChecksumType,
ChecksumTypeError, ChecksumValue, ChecksumValueDecodeError, ChecksumValueEncodeError,
CompressionType, CompressionTypeError, DmuType, DmuTypeError, Dva, DvaDecodeError,
DvaEncodeError, EndianOrder,
};
#[derive(Debug)]
pub enum BlockPointer {
Embedded(BlockPointerEmbedded),
Encrypted(BlockPointerEncrypted),
Regular(BlockPointerRegular),
}
impl BlockPointer {
pub const SIZE: usize = (3 * Dva::SIZE) + 48 + ChecksumValue::SIZE;
pub const LOGICAL_SECTORS_MAX: u32 = 1 << 16;
pub const PHYSICAL_SECTORS_MAX: u32 = 1 << 16;
const COMPRESSION_MASK_DOWN_SHIFTED: u64 = 0x1f;
const COMPRESSION_SHIFT: u64 = 32;
const CHECKSUM_SHIFT: u64 = 40;
const DMU_SHIFT: u64 = 48;
const LEVEL_MASK_DOWN_SHIFTED: u64 = 0x1f;
const LEVEL_SHIFT: u64 = 56;
const EMBEDDED_BIT_FLAG: u64 = 1 << 39;
const ENCRYPTED_BIT_FLAG: u64 = 1 << 61;
const DEDUP_BIT_FLAG: u64 = 1 << 62;
const LITTLE_ENDIAN_BIT_FLAG: u64 = 1 << 63;
pub fn from_decoder(
decoder: &mut dyn BinaryDecoder<'_>,
) -> Result<Option<BlockPointer>, BlockPointerDecodeError> {
if decoder.is_skip_zeros(BlockPointer::SIZE)? {
return Ok(None);
}
let offset = decoder.offset();
decoder.skip(3 * Dva::SIZE)?;
let flags = decoder.get_u64()?;
decoder.seek(offset)?;
let embedded = (flags & BlockPointer::EMBEDDED_BIT_FLAG) != 0;
let encrypted = (flags & BlockPointer::ENCRYPTED_BIT_FLAG) != 0;
match (embedded, encrypted) {
(false, false) => Ok(Some(BlockPointer::Regular(
BlockPointerRegular::from_decoder(decoder)?,
))),
(false, true) => Ok(Some(BlockPointer::Encrypted(
BlockPointerEncrypted::from_decoder(decoder)?,
))),
(true, false) => Ok(Some(BlockPointer::Embedded(
BlockPointerEmbedded::from_decoder(decoder)?,
))),
(true, true) => Err(BlockPointerDecodeError::InvalidBlockPointerType {
embedded,
encrypted,
}),
}
}
pub fn to_encoder(
&self,
encoder: &mut dyn BinaryEncoder<'_>,
) -> Result<(), BlockPointerEncodeError> {
match self {
BlockPointer::Embedded(ptr) => ptr.to_encoder(encoder),
BlockPointer::Encrypted(ptr) => ptr.to_encoder(encoder),
BlockPointer::Regular(ptr) => ptr.to_encoder(encoder),
}
}
pub fn empty_to_encoder(
encoder: &mut dyn BinaryEncoder<'_>,
) -> Result<(), BlockPointerEncodeError> {
Ok(encoder.put_zeros(BlockPointer::SIZE)?)
}
pub fn option_to_encoder(
ptr: &Option<BlockPointer>,
encoder: &mut dyn BinaryEncoder<'_>,
) -> Result<(), BlockPointerEncodeError> {
match ptr {
Some(v) => v.to_encoder(encoder),
None => Ok(BlockPointer::empty_to_encoder(encoder)?),
}
}
pub fn order(&self) -> EndianOrder {
match self {
BlockPointer::Embedded(ptr) => ptr.order,
BlockPointer::Encrypted(ptr) => ptr.order,
BlockPointer::Regular(ptr) => ptr.order,
}
}
}
#[derive(Debug)]
pub struct BlockPointerEmbedded {
pub compression: CompressionType,
pub dmu: DmuType,
pub embedded_type: BlockPointerEmbeddedType,
pub order: EndianOrder,
pub level: u8,
pub logical_birth_txg: u64,
pub logical_size: usize,
pub physical_size: usize,
pub payload: [u8; BlockPointerEmbedded::PHYSICAL_SIZE_MAX],
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
#[repr(u8)]
pub enum BlockPointerEmbeddedType {
Data = 0,
Reserved = 1,
Redacted = 2,
}
impl Display for BlockPointerEmbeddedType {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
BlockPointerEmbeddedType::Data => write!(f, "Data"),
BlockPointerEmbeddedType::Reserved => write!(f, "Reserved"),
BlockPointerEmbeddedType::Redacted => write!(f, "Redacted"),
}
}
}
impl From<BlockPointerEmbeddedType> for u8 {
fn from(val: BlockPointerEmbeddedType) -> u8 {
val as u8
}
}
impl TryFrom<u8> for BlockPointerEmbeddedType {
type Error = BlockPointerEmbeddedTypeError;
fn try_from(embedded_type: u8) -> Result<Self, Self::Error> {
match embedded_type {
0 => Ok(BlockPointerEmbeddedType::Data),
1 => Ok(BlockPointerEmbeddedType::Reserved),
2 => Ok(BlockPointerEmbeddedType::Redacted),
_ => Err(BlockPointerEmbeddedTypeError::Unknown { embedded_type }),
}
}
}
#[derive(Debug)]
pub enum BlockPointerEmbeddedTypeError {
Unknown {
embedded_type: u8,
},
}
impl fmt::Display for BlockPointerEmbeddedTypeError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
BlockPointerEmbeddedTypeError::Unknown { embedded_type } => {
write!(f, "Unknown BlockPointerEmbeddedType {embedded_type}")
}
}
}
}
#[cfg(feature = "std")]
impl error::Error for BlockPointerEmbeddedTypeError {
fn source(&self) -> Option<&(dyn error::Error + 'static)> {
None
}
}
impl BlockPointerEmbedded {
pub const LOGICAL_SIZE_MAX: usize = (BlockPointerEmbedded::LOGICAL_SIZE_MASK as usize);
pub const PHYSICAL_SIZE_MAX: usize = 112;
const LOGICAL_SIZE_MASK: u64 = (1 << 25) - 1;
const PHYSICAL_SIZE_MASK_DOWN_SHIFTED: u64 = 0x7f;
const PHYSICAL_SIZE_SHIFT: u64 = 25;
pub fn from_decoder(
decoder: &mut dyn BinaryDecoder<'_>,
) -> Result<BlockPointerEmbedded, BlockPointerDecodeError> {
let mut payload = [0; BlockPointerEmbedded::PHYSICAL_SIZE_MAX];
let part_1 = &mut payload[0..48];
part_1.copy_from_slice(decoder.get_bytes_n(part_1.len())?);
let flags = decoder.get_u64()?;
let part_2 = &mut payload[48..72];
part_2.copy_from_slice(decoder.get_bytes_n(part_2.len())?);
let logical_birth_txg = decoder.get_u64()?;
let part_3 = &mut payload[72..112];
part_3.copy_from_slice(decoder.get_bytes_n(part_3.len())?);
let embedded = (flags & BlockPointer::EMBEDDED_BIT_FLAG) != 0;
let encrypted = (flags & BlockPointer::ENCRYPTED_BIT_FLAG) != 0;
if (embedded, encrypted) != (true, false) {
return Err(BlockPointerDecodeError::InvalidBlockPointerType {
embedded,
encrypted,
});
}
let dedup = (flags & BlockPointer::DEDUP_BIT_FLAG) != 0;
if dedup {
return Err(BlockPointerDecodeError::InvalidDedupValue { dedup });
}
let order = (flags & BlockPointer::LITTLE_ENDIAN_BIT_FLAG) != 0;
let order = match order {
true => EndianOrder::Little,
false => EndianOrder::Big,
};
let level =
((flags >> BlockPointer::LEVEL_SHIFT) & BlockPointer::LEVEL_MASK_DOWN_SHIFTED) as u8;
let dmu = (flags >> BlockPointer::DMU_SHIFT) as u8;
let dmu = DmuType::try_from(dmu)?;
let embedded_type = (flags >> BlockPointer::CHECKSUM_SHIFT) as u8;
let embedded_type = BlockPointerEmbeddedType::try_from(embedded_type)?;
let compression = ((flags >> BlockPointer::COMPRESSION_SHIFT)
& BlockPointer::COMPRESSION_MASK_DOWN_SHIFTED) as u8;
let compression = CompressionType::try_from(compression)?;
let logical_size = ((flags & BlockPointerEmbedded::LOGICAL_SIZE_MASK) as u32) + 1;
let logical_size = match usize::try_from(logical_size) {
Ok(v) => v,
Err(_) => return Err(BlockPointerDecodeError::LogicalSizeTooLarge { logical_size }),
};
let physical_size = usize::from(
((flags >> BlockPointerEmbedded::PHYSICAL_SIZE_SHIFT)
& BlockPointerEmbedded::PHYSICAL_SIZE_MASK_DOWN_SHIFTED) as u8,
) + 1;
if physical_size > payload.len() {
return Err(BlockPointerDecodeError::InvalidEmbeddedLength {
length: physical_size,
});
}
Ok(BlockPointerEmbedded {
compression,
dmu,
embedded_type,
order,
level,
logical_birth_txg,
logical_size,
payload,
physical_size,
})
}
pub fn to_encoder(
&self,
encoder: &mut dyn BinaryEncoder<'_>,
) -> Result<(), BlockPointerEncodeError> {
if self.physical_size > self.payload.len() {
return Err(BlockPointerEncodeError::InvalidEmbeddedLength {
length: self.physical_size,
});
}
encoder.put_bytes(&self.payload[0..48])?;
let level: u64 = self.level.into();
if level > BlockPointer::LEVEL_MASK_DOWN_SHIFTED {
return Err(BlockPointerEncodeError::InvalidLevel { level: self.level });
}
let dmu: u8 = self.dmu.into();
let embedded_type: u8 = self.embedded_type.into();
let compression: u8 = self.compression.into();
if self.logical_size > (BlockPointerEmbedded::LOGICAL_SIZE_MASK as usize) {
return Err(BlockPointerEncodeError::InvalidLogicalSize {
logical_size: self.logical_size,
});
}
let flags = (self.logical_size as u64)
| (self.physical_size as u64) << BlockPointerEmbedded::PHYSICAL_SIZE_SHIFT
| u64::from(compression) << BlockPointer::COMPRESSION_SHIFT
| BlockPointer::EMBEDDED_BIT_FLAG
| u64::from(embedded_type) << BlockPointer::CHECKSUM_SHIFT
| u64::from(dmu) << BlockPointer::DMU_SHIFT
| level << BlockPointer::LEVEL_SHIFT
| match self.order {
EndianOrder::Little => BlockPointer::LITTLE_ENDIAN_BIT_FLAG,
EndianOrder::Big => 0,
};
encoder.put_u64(flags)?;
encoder.put_bytes(&self.payload[48..72])?;
encoder.put_u64(self.logical_birth_txg)?;
encoder.put_bytes(&self.payload[72..112])?;
Ok(())
}
}
#[derive(Debug)]
pub struct BlockPointerEncrypted {
pub checksum_type: ChecksumType,
pub checksum_value: [u64; 2],
pub compression: CompressionType,
pub dedup: bool,
pub dmu: DmuType,
pub dvas: [Option<Dva>; 2],
pub order: EndianOrder,
pub fill_count: u32,
pub iv_1: u64,
pub iv_2: u32,
pub level: u8,
pub logical_birth_txg: u64,
pub logical_sectors: u32,
pub mac: [u64; 2],
pub physical_birth_txg: u64,
pub physical_sectors: u32,
pub salt: u64,
}
impl BlockPointerEncrypted {
const PADDING_SIZE: usize = 16;
const LOGICAL_SECTORS_MASK: u64 = (1 << 16) - 1;
const PHYSICAL_SECTORS_MASK_DOWN_SHIFTED: u64 = (1 << 16) - 1;
const PHYSICAL_SECTORS_SHIFT: u64 = 16;
const IV_2_SHIFT: u64 = 32;
const IV_FILL_MASK: u64 = (1 << 32) - 1;
pub fn from_decoder(
decoder: &mut dyn BinaryDecoder<'_>,
) -> Result<BlockPointerEncrypted, BlockPointerDecodeError> {
let dvas = [Dva::from_decoder(decoder)?, Dva::from_decoder(decoder)?];
let salt = decoder.get_u64()?;
let iv_1 = decoder.get_u64()?;
let flags = decoder.get_u64()?;
let embedded = (flags & BlockPointer::EMBEDDED_BIT_FLAG) != 0;
let encrypted = (flags & BlockPointer::ENCRYPTED_BIT_FLAG) != 0;
if (embedded, encrypted) != (false, true) {
return Err(BlockPointerDecodeError::InvalidBlockPointerType {
embedded,
encrypted,
});
}
let dedup = (flags & BlockPointer::DEDUP_BIT_FLAG) != 0;
let order = (flags & BlockPointer::LITTLE_ENDIAN_BIT_FLAG) != 0;
let order = match order {
true => EndianOrder::Little,
false => EndianOrder::Big,
};
let level =
((flags >> BlockPointer::LEVEL_SHIFT) & BlockPointer::LEVEL_MASK_DOWN_SHIFTED) as u8;
let dmu = (flags >> BlockPointer::DMU_SHIFT) as u8;
let dmu = DmuType::try_from(dmu)?;
let checksum_type = (flags >> BlockPointer::CHECKSUM_SHIFT) as u8;
let checksum_type = ChecksumType::try_from(checksum_type)?;
let compression = ((flags >> BlockPointer::COMPRESSION_SHIFT)
& BlockPointer::COMPRESSION_MASK_DOWN_SHIFTED) as u8;
let compression = CompressionType::try_from(compression)?;
let logical_sectors = ((flags & BlockPointerEncrypted::LOGICAL_SECTORS_MASK) as u32) + 1;
let physical_sectors = (((flags >> BlockPointerEncrypted::PHYSICAL_SECTORS_SHIFT)
& BlockPointerEncrypted::PHYSICAL_SECTORS_MASK_DOWN_SHIFTED)
as u32)
+ 1;
decoder.skip_zeros(BlockPointerEncrypted::PADDING_SIZE)?;
let physical_birth_txg = decoder.get_u64()?;
let logical_birth_txg = decoder.get_u64()?;
let iv_fill = decoder.get_u64()?;
let iv_2 = (iv_fill >> BlockPointerEncrypted::IV_2_SHIFT) as u32;
let fill_count = (iv_fill & BlockPointerEncrypted::IV_FILL_MASK) as u32;
let checksum_value = [decoder.get_u64()?, decoder.get_u64()?];
let mac = [decoder.get_u64()?, decoder.get_u64()?];
Ok(BlockPointerEncrypted {
checksum_type,
checksum_value,
compression,
dedup,
dmu,
dvas,
order,
fill_count,
level,
iv_1,
iv_2,
logical_birth_txg,
logical_sectors,
mac,
physical_birth_txg,
physical_sectors,
salt,
})
}
pub fn to_encoder(
&self,
encoder: &mut dyn BinaryEncoder<'_>,
) -> Result<(), BlockPointerEncodeError> {
for dva in &self.dvas {
match dva {
Some(v) => v.to_encoder(encoder)?,
None => Dva::empty_to_encoder(encoder)?,
}
}
if self.logical_sectors < 1 || self.logical_sectors > BlockPointer::LOGICAL_SECTORS_MAX {
return Err(BlockPointerEncodeError::InvalidLogicalSectors {
sectors: self.logical_sectors,
});
}
if self.physical_sectors < 1 || self.physical_sectors > BlockPointer::PHYSICAL_SECTORS_MAX {
return Err(BlockPointerEncodeError::InvalidPhysicalSectors {
sectors: self.physical_sectors,
});
}
encoder.put_u64(self.salt)?;
encoder.put_u64(self.iv_1)?;
let level: u64 = self.level.into();
if level > BlockPointer::LEVEL_MASK_DOWN_SHIFTED {
return Err(BlockPointerEncodeError::InvalidLevel { level: self.level });
}
let checksum: u8 = self.checksum_type.into();
let dmu: u8 = self.dmu.into();
let compression: u8 = self.compression.into();
let flags = u64::from(self.logical_sectors - 1)
| u64::from(self.physical_sectors - 1) << BlockPointerEncrypted::PHYSICAL_SECTORS_SHIFT
| u64::from(compression) << BlockPointer::COMPRESSION_SHIFT
| u64::from(checksum) << BlockPointer::CHECKSUM_SHIFT
| u64::from(dmu) << BlockPointer::DMU_SHIFT
| level << BlockPointer::LEVEL_SHIFT
| BlockPointer::ENCRYPTED_BIT_FLAG
| if self.dedup {
BlockPointer::DEDUP_BIT_FLAG
} else {
0
}
| match self.order {
EndianOrder::Little => BlockPointer::LITTLE_ENDIAN_BIT_FLAG,
EndianOrder::Big => 0,
};
encoder.put_u64(flags)?;
encoder.put_zeros(BlockPointerEncrypted::PADDING_SIZE)?;
encoder.put_u64(self.physical_birth_txg)?;
encoder.put_u64(self.logical_birth_txg)?;
encoder.put_u64(
u64::from(self.fill_count) | u64::from(self.iv_2) << BlockPointerEncrypted::IV_2_SHIFT,
)?;
for checksum in self.checksum_value {
encoder.put_u64(checksum)?;
}
for mac in self.mac {
encoder.put_u64(mac)?;
}
Ok(())
}
}
#[derive(Debug)]
pub struct BlockPointerRegular {
pub checksum_type: ChecksumType,
pub checksum_value: ChecksumValue,
pub compression: CompressionType,
pub dedup: bool,
pub dmu: DmuType,
pub dvas: [Option<Dva>; 3],
pub order: EndianOrder,
pub fill_count: u64,
pub level: u8,
pub logical_birth_txg: u64,
pub logical_sectors: u32,
pub physical_birth_txg: u64,
pub physical_sectors: u32,
}
impl BlockPointerRegular {
const PADDING_SIZE: usize = 16;
const LOGICAL_SECTORS_MASK: u64 = (1 << 16) - 1;
const PHYSICAL_SECTORS_MASK_DOWN_SHIFTED: u64 = (1 << 16) - 1;
const PHYSICAL_SECTORS_SHIFT: u64 = 16;
pub fn from_decoder(
decoder: &mut dyn BinaryDecoder<'_>,
) -> Result<BlockPointerRegular, BlockPointerDecodeError> {
let dvas = [
Dva::from_decoder(decoder)?,
Dva::from_decoder(decoder)?,
Dva::from_decoder(decoder)?,
];
let flags = decoder.get_u64()?;
let embedded = (flags & BlockPointer::EMBEDDED_BIT_FLAG) != 0;
let encrypted = (flags & BlockPointer::ENCRYPTED_BIT_FLAG) != 0;
if (embedded, encrypted) != (false, false) {
return Err(BlockPointerDecodeError::InvalidBlockPointerType {
embedded,
encrypted,
});
}
let dedup = (flags & (BlockPointer::DEDUP_BIT_FLAG)) != 0;
let order = (flags & BlockPointer::LITTLE_ENDIAN_BIT_FLAG) != 0;
let order = match order {
true => EndianOrder::Little,
false => EndianOrder::Big,
};
let level =
((flags >> BlockPointer::LEVEL_SHIFT) & BlockPointer::LEVEL_MASK_DOWN_SHIFTED) as u8;
let dmu = (flags >> BlockPointer::DMU_SHIFT) as u8;
let dmu = DmuType::try_from(dmu)?;
let checksum_type = (flags >> BlockPointer::CHECKSUM_SHIFT) as u8;
let checksum_type = ChecksumType::try_from(checksum_type)?;
let compression = ((flags >> BlockPointer::COMPRESSION_SHIFT)
& BlockPointer::COMPRESSION_MASK_DOWN_SHIFTED) as u8;
let compression = CompressionType::try_from(compression)?;
let logical_sectors = ((flags & BlockPointerRegular::LOGICAL_SECTORS_MASK) as u32) + 1;
let physical_sectors = (((flags >> BlockPointerRegular::PHYSICAL_SECTORS_SHIFT)
& BlockPointerRegular::PHYSICAL_SECTORS_MASK_DOWN_SHIFTED)
as u32)
+ 1;
decoder.skip_zeros(BlockPointerRegular::PADDING_SIZE)?;
let physical_birth_txg = decoder.get_u64()?;
let logical_birth_txg = decoder.get_u64()?;
let fill_count = decoder.get_u64()?;
let checksum_value = ChecksumValue::from_decoder(decoder)?;
Ok(BlockPointerRegular {
checksum_type,
checksum_value,
compression,
dedup,
dmu,
dvas,
order,
fill_count,
level,
logical_birth_txg,
logical_sectors,
physical_birth_txg,
physical_sectors,
})
}
pub fn to_encoder(
&self,
encoder: &mut dyn BinaryEncoder<'_>,
) -> Result<(), BlockPointerEncodeError> {
for dva in &self.dvas {
match dva {
Some(v) => v.to_encoder(encoder)?,
None => Dva::empty_to_encoder(encoder)?,
}
}
if self.logical_sectors < 1 || self.logical_sectors > BlockPointer::LOGICAL_SECTORS_MAX {
return Err(BlockPointerEncodeError::InvalidLogicalSectors {
sectors: self.logical_sectors,
});
}
if self.physical_sectors < 1 || self.physical_sectors > BlockPointer::PHYSICAL_SECTORS_MAX {
return Err(BlockPointerEncodeError::InvalidPhysicalSectors {
sectors: self.physical_sectors,
});
}
let level: u64 = self.level.into();
if level > BlockPointer::LEVEL_MASK_DOWN_SHIFTED {
return Err(BlockPointerEncodeError::InvalidLevel { level: self.level });
}
let checksum: u8 = self.checksum_type.into();
let dmu: u8 = self.dmu.into();
let compression: u8 = self.compression.into();
let flags = u64::from(self.logical_sectors - 1)
| u64::from(self.physical_sectors - 1) << BlockPointerRegular::PHYSICAL_SECTORS_SHIFT
| u64::from(compression) << BlockPointer::COMPRESSION_SHIFT
| u64::from(checksum) << BlockPointer::CHECKSUM_SHIFT
| u64::from(dmu) << BlockPointer::DMU_SHIFT
| level << BlockPointer::LEVEL_SHIFT
| if self.dedup {
BlockPointer::DEDUP_BIT_FLAG
} else {
0
}
| match self.order {
EndianOrder::Little => BlockPointer::LITTLE_ENDIAN_BIT_FLAG,
EndianOrder::Big => 0,
};
encoder.put_u64(flags)?;
encoder.put_zeros(BlockPointerRegular::PADDING_SIZE)?;
encoder.put_u64(self.physical_birth_txg)?;
encoder.put_u64(self.logical_birth_txg)?;
encoder.put_u64(self.fill_count)?;
self.checksum_value.to_encoder(encoder)?;
Ok(())
}
}
#[derive(Debug)]
pub enum BlockPointerDecodeError {
BlockPointerEmbeddedType {
err: BlockPointerEmbeddedTypeError,
},
ChecksumType {
err: ChecksumTypeError,
},
ChecksumValue {
err: ChecksumValueDecodeError,
},
CompressionType {
err: CompressionTypeError,
},
DmuType {
err: DmuTypeError,
},
Dva {
err: DvaDecodeError,
},
Binary {
err: BinaryDecodeError,
},
InvalidBlockPointerType {
embedded: bool,
encrypted: bool,
},
InvalidDedupValue {
dedup: bool,
},
InvalidEmbeddedLength {
length: usize,
},
LogicalSizeTooLarge {
logical_size: u32,
},
}
impl From<BinaryDecodeError> for BlockPointerDecodeError {
fn from(err: BinaryDecodeError) -> Self {
BlockPointerDecodeError::Binary { err }
}
}
impl From<BlockPointerEmbeddedTypeError> for BlockPointerDecodeError {
fn from(err: BlockPointerEmbeddedTypeError) -> Self {
BlockPointerDecodeError::BlockPointerEmbeddedType { err }
}
}
impl From<ChecksumTypeError> for BlockPointerDecodeError {
fn from(err: ChecksumTypeError) -> Self {
BlockPointerDecodeError::ChecksumType { err }
}
}
impl From<ChecksumValueDecodeError> for BlockPointerDecodeError {
fn from(err: ChecksumValueDecodeError) -> Self {
BlockPointerDecodeError::ChecksumValue { err }
}
}
impl From<CompressionTypeError> for BlockPointerDecodeError {
fn from(err: CompressionTypeError) -> Self {
BlockPointerDecodeError::CompressionType { err }
}
}
impl From<DmuTypeError> for BlockPointerDecodeError {
fn from(err: DmuTypeError) -> Self {
BlockPointerDecodeError::DmuType { err }
}
}
impl From<DvaDecodeError> for BlockPointerDecodeError {
fn from(err: DvaDecodeError) -> Self {
BlockPointerDecodeError::Dva { err }
}
}
impl fmt::Display for BlockPointerDecodeError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
BlockPointerDecodeError::Binary { err } => {
write!(f, "BlockPointer decode error | {err}")
}
BlockPointerDecodeError::BlockPointerEmbeddedType { err } => {
write!(f, "BlockPointer decode error | {err}")
}
BlockPointerDecodeError::ChecksumType { err } => {
write!(f, "BlockPointer decode error | {err}")
}
BlockPointerDecodeError::ChecksumValue { err } => {
write!(f, "BlockPointer decode error | {err}")
}
BlockPointerDecodeError::CompressionType { err } => {
write!(f, "BlockPointer decode error | {err}")
}
BlockPointerDecodeError::DmuType { err } => {
write!(f, "BlockPointer decode error | {err}")
}
BlockPointerDecodeError::Dva { err } => {
write!(f, "BlockPointer decode error | {err}")
}
BlockPointerDecodeError::InvalidBlockPointerType {
embedded,
encrypted,
} => {
write!(
f,
"BlockPointer decode error, invalid embedded {embedded} encrypted {encrypted}"
)
}
BlockPointerDecodeError::InvalidDedupValue { dedup } => {
write!(f, "BlockPointer decode error, invalid dedup value {dedup}")
}
BlockPointerDecodeError::InvalidEmbeddedLength { length } => {
write!(
f,
"BlockPointer decode error, invalid embdedded length {length}"
)
}
BlockPointerDecodeError::LogicalSizeTooLarge { logical_size } => {
write!(
f,
"BlockPointer decode error, logical size too big for usize {logical_size}"
)
}
}
}
}
#[cfg(feature = "std")]
impl error::Error for BlockPointerDecodeError {
fn source(&self) -> Option<&(dyn error::Error + 'static)> {
match self {
BlockPointerDecodeError::Binary { err } => Some(err),
BlockPointerDecodeError::BlockPointerEmbeddedType { err } => Some(err),
BlockPointerDecodeError::ChecksumType { err } => Some(err),
BlockPointerDecodeError::ChecksumValue { err } => Some(err),
BlockPointerDecodeError::CompressionType { err } => Some(err),
BlockPointerDecodeError::DmuType { err } => Some(err),
BlockPointerDecodeError::Dva { err } => Some(err),
_ => None,
}
}
}
#[derive(Debug)]
pub enum BlockPointerEncodeError {
ChecksumValue {
err: ChecksumValueEncodeError,
},
Dva {
err: DvaEncodeError,
},
Endian {
err: BinaryEncodeError,
},
InvalidEmbeddedLength {
length: usize,
},
InvalidLevel {
level: u8,
},
InvalidLogicalSectors {
sectors: u32,
},
InvalidLogicalSize {
logical_size: usize,
},
InvalidPhysicalSectors {
sectors: u32,
},
}
impl From<ChecksumValueEncodeError> for BlockPointerEncodeError {
fn from(err: ChecksumValueEncodeError) -> Self {
BlockPointerEncodeError::ChecksumValue { err }
}
}
impl From<DvaEncodeError> for BlockPointerEncodeError {
fn from(err: DvaEncodeError) -> Self {
BlockPointerEncodeError::Dva { err }
}
}
impl From<BinaryEncodeError> for BlockPointerEncodeError {
fn from(err: BinaryEncodeError) -> Self {
BlockPointerEncodeError::Endian { err }
}
}
impl fmt::Display for BlockPointerEncodeError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
BlockPointerEncodeError::ChecksumValue { err } => {
write!(f, "BlockPointer encode error | {err}")
}
BlockPointerEncodeError::Dva { err } => {
write!(f, "BlockPointer encode error | {err}")
}
BlockPointerEncodeError::Endian { err } => {
write!(f, "BlockPointer encode error | {err}")
}
BlockPointerEncodeError::InvalidEmbeddedLength { length } => {
write!(
f,
"BlockPointer encode error, invalid embdedded length {length}"
)
}
BlockPointerEncodeError::InvalidLevel { level } => {
write!(f, "BlockPointer encode error, invalid level {level}")
}
BlockPointerEncodeError::InvalidLogicalSectors { sectors } => {
write!(
f,
"BlockPointer encode error, invalid logical sectors {sectors}"
)
}
BlockPointerEncodeError::InvalidLogicalSize { logical_size } => {
write!(
f,
"BlockPointer encode error, invalid logical size {logical_size}"
)
}
BlockPointerEncodeError::InvalidPhysicalSectors { sectors } => {
write!(
f,
"BlockPointer encode error, invalid physical sectors {sectors}"
)
}
}
}
}
#[cfg(feature = "std")]
impl error::Error for BlockPointerEncodeError {
fn source(&self) -> Option<&(dyn error::Error + 'static)> {
match self {
BlockPointerEncodeError::ChecksumValue { err } => Some(err),
BlockPointerEncodeError::Dva { err } => Some(err),
BlockPointerEncodeError::Endian { err } => Some(err),
_ => None,
}
}
}
#[derive(Debug)]
pub struct BpObjectHeaderAccountingExtension {
pub compressed_size: u64,
pub uncompressed_size: u64,
}
#[derive(Debug)]
pub struct BpObjectHeaderDeadListsExtension {
pub sub_objects_obj: Option<u64>,
pub sub_objects_num: u64,
}
#[derive(Debug)]
pub struct BpObjectHeaderLiveListExtension {
pub block_pointers_freed: u64,
}
#[derive(Debug)]
pub enum BpObjectHeaderExtension {
Zero {},
One {
accounting: BpObjectHeaderAccountingExtension,
},
Two {
accounting: BpObjectHeaderAccountingExtension,
dead_lists: BpObjectHeaderDeadListsExtension,
},
Three {
accounting: BpObjectHeaderAccountingExtension,
dead_lists: BpObjectHeaderDeadListsExtension,
live_list: BpObjectHeaderLiveListExtension,
},
}
#[derive(Debug)]
pub struct BpObjectHeader {
pub block_pointers_count: u64,
pub physical_size: u64,
pub extensions: BpObjectHeaderExtension,
}
impl BpObjectHeader {
pub fn from_decoder(
decoder: &mut dyn BinaryDecoder<'_>,
) -> Result<BpObjectHeader, BpObjectHeaderDecodeError> {
let block_pointers_count = decoder.get_u64()?;
let physical_size = decoder.get_u64()?;
let mut extensions = BpObjectHeaderExtension::Zero {};
if !decoder.is_empty() {
let accounting = BpObjectHeaderAccountingExtension {
compressed_size: decoder.get_u64()?,
uncompressed_size: decoder.get_u64()?,
};
if decoder.is_empty() {
extensions = BpObjectHeaderExtension::One { accounting };
} else {
let dead_lists = BpObjectHeaderDeadListsExtension {
sub_objects_obj: match decoder.get_u64()? {
0 => None,
v => Some(v),
},
sub_objects_num: decoder.get_u64()?,
};
if decoder.is_empty() {
extensions = BpObjectHeaderExtension::Two {
accounting,
dead_lists,
};
} else {
let live_list = BpObjectHeaderLiveListExtension {
block_pointers_freed: decoder.get_u64()?,
};
extensions = BpObjectHeaderExtension::Three {
accounting,
dead_lists,
live_list,
};
}
}
}
if !decoder.is_empty() {
return Err(BpObjectHeaderDecodeError::Size {
size: decoder.len(),
});
}
Ok(BpObjectHeader {
block_pointers_count,
physical_size,
extensions,
})
}
pub fn to_encoder(
&self,
encoder: &mut dyn BinaryEncoder<'_>,
) -> Result<(), BpObjectHeaderEncodeError> {
encoder.put_u64(self.block_pointers_count)?;
encoder.put_u64(self.physical_size)?;
if let Some(accounting) = self.accounting() {
encoder.put_u64(accounting.compressed_size)?;
encoder.put_u64(accounting.uncompressed_size)?;
if let Some(dead_lists) = self.dead_lists() {
encoder.put_u64(dead_lists.sub_objects_obj.unwrap_or(0))?;
encoder.put_u64(dead_lists.sub_objects_num)?;
if let Some(live_list) = self.live_list() {
encoder.put_u64(live_list.block_pointers_freed)?;
}
}
}
Ok(())
}
pub fn accounting(&self) -> Option<&BpObjectHeaderAccountingExtension> {
match &self.extensions {
BpObjectHeaderExtension::Zero {} => None,
BpObjectHeaderExtension::One { accounting } => Some(accounting),
BpObjectHeaderExtension::Two {
accounting,
dead_lists: _,
} => Some(accounting),
BpObjectHeaderExtension::Three {
accounting,
dead_lists: _,
live_list: _,
} => Some(accounting),
}
}
pub fn dead_lists(&self) -> Option<&BpObjectHeaderDeadListsExtension> {
match &self.extensions {
BpObjectHeaderExtension::Zero {} => None,
BpObjectHeaderExtension::One { accounting: _ } => None,
BpObjectHeaderExtension::Two {
accounting: _,
dead_lists,
} => Some(dead_lists),
BpObjectHeaderExtension::Three {
accounting: _,
dead_lists,
live_list: _,
} => Some(dead_lists),
}
}
pub fn live_list(&self) -> Option<&BpObjectHeaderLiveListExtension> {
match &self.extensions {
BpObjectHeaderExtension::Zero {} => None,
BpObjectHeaderExtension::One { .. } => None,
BpObjectHeaderExtension::Two { .. } => None,
BpObjectHeaderExtension::Three {
accounting: _,
dead_lists: _,
live_list,
} => Some(live_list),
}
}
}
#[derive(Debug)]
pub enum BpObjectHeaderDecodeError {
Binary {
err: BinaryDecodeError,
},
Size {
size: usize,
},
}
impl From<BinaryDecodeError> for BpObjectHeaderDecodeError {
fn from(err: BinaryDecodeError) -> Self {
BpObjectHeaderDecodeError::Binary { err }
}
}
impl fmt::Display for BpObjectHeaderDecodeError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
BpObjectHeaderDecodeError::Binary { err } => {
write!(f, "BpObjectHeader decode error | {err}")
}
BpObjectHeaderDecodeError::Size { size } => {
write!(f, "BpObjectHeader decode error, unknown size {size}")
}
}
}
}
#[cfg(feature = "std")]
impl error::Error for BpObjectHeaderDecodeError {
fn source(&self) -> Option<&(dyn error::Error + 'static)> {
match self {
BpObjectHeaderDecodeError::Binary { err } => Some(err),
_ => None,
}
}
}
#[derive(Debug)]
pub enum BpObjectHeaderEncodeError {
Binary {
err: BinaryEncodeError,
},
}
impl From<BinaryEncodeError> for BpObjectHeaderEncodeError {
fn from(err: BinaryEncodeError) -> Self {
BpObjectHeaderEncodeError::Binary { err }
}
}
impl fmt::Display for BpObjectHeaderEncodeError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
BpObjectHeaderEncodeError::Binary { err } => {
write!(f, "BpObjectHeader encode error | {err}")
}
}
}
}
#[cfg(feature = "std")]
impl error::Error for BpObjectHeaderEncodeError {
fn source(&self) -> Option<&(dyn error::Error + 'static)> {
match self {
BpObjectHeaderEncodeError::Binary { err } => Some(err),
}
}
}