use core::fmt;
#[cfg(feature = "std")]
use std::error;
use crate::phys::{
BinaryDecodeError, BinaryDecoder, BinaryEncodeError, BinaryEncoder, BlockPointer,
BlockPointerDecodeError, BlockPointerEncodeError,
};
#[derive(Debug)]
pub struct DslDirectoryUsedBreakdown {
pub head: u64,
pub snapshot: u64,
pub child: u64,
pub child_reserved: u64,
pub referenced_reservation: u64,
}
impl DslDirectoryUsedBreakdown {
pub const SIZE: usize = 40;
}
#[derive(Debug)]
pub struct DslDirectory {
pub creation_time: u64,
pub head_dataset_obj: Option<u64>,
pub parent_directory_obj: Option<u64>,
pub origin_dataset_obj: Option<u64>,
pub child_directory_zap_obj: u64,
pub used_bytes: u64,
pub compressed_bytes: u64,
pub uncompressed_bytes: u64,
pub quota: u64,
pub reserved: u64,
pub properties_zap_obj: u64,
pub delegation_zap_obj: Option<u64>,
pub used_breakdown: Option<DslDirectoryUsedBreakdown>,
pub clones: u64,
}
impl DslDirectory {
pub const SIZE: usize = 256;
const PADDING_SIZE: usize = 104;
const FLAG_USED_BREAKDOWN: u64 = 1 << 0;
const FLAG_ALL: u64 = DslDirectory::FLAG_USED_BREAKDOWN;
pub fn from_decoder(
decoder: &mut dyn BinaryDecoder<'_>,
) -> Result<DslDirectory, DslDirectoryDecodeError> {
let creation_time = decoder.get_u64()?;
let head_dataset_obj = match decoder.get_u64()? {
0 => None,
v => Some(v),
};
let parent_directory_obj = match decoder.get_u64()? {
0 => None,
v => Some(v),
};
let origin_dataset_obj = match decoder.get_u64()? {
0 => None,
v => Some(v),
};
let child_directory_zap_obj = match decoder.get_u64()? {
0 => return Err(DslDirectoryDecodeError::MissingChildDirectory {}),
v => v,
};
let used_bytes = decoder.get_u64()?;
let compressed_bytes = decoder.get_u64()?;
let uncompressed_bytes = decoder.get_u64()?;
let quota = decoder.get_u64()?;
let reserved = decoder.get_u64()?;
let properties_zap_obj = match decoder.get_u64()? {
0 => return Err(DslDirectoryDecodeError::MissingProperties {}),
v => v,
};
let delegation_zap_obj = match decoder.get_u64()? {
0 => None,
v => Some(v),
};
let flags = decoder.get_u64()?;
if (flags & DslDirectory::FLAG_ALL) != flags {
return Err(DslDirectoryDecodeError::Flags { flags });
}
let used_breakdown = if (flags & DslDirectory::FLAG_USED_BREAKDOWN) == 0 {
decoder.skip_zeros(DslDirectoryUsedBreakdown::SIZE)?;
None
} else {
Some(DslDirectoryUsedBreakdown {
head: decoder.get_u64()?,
snapshot: decoder.get_u64()?,
child: decoder.get_u64()?,
child_reserved: decoder.get_u64()?,
referenced_reservation: decoder.get_u64()?,
})
};
let clones = decoder.get_u64()?;
decoder.skip_zeros(DslDirectory::PADDING_SIZE)?;
Ok(DslDirectory {
creation_time,
head_dataset_obj,
parent_directory_obj,
origin_dataset_obj,
child_directory_zap_obj,
used_bytes,
compressed_bytes,
uncompressed_bytes,
quota,
reserved,
properties_zap_obj,
delegation_zap_obj,
used_breakdown,
clones,
})
}
pub fn to_encoder(
&self,
encoder: &mut dyn BinaryEncoder<'_>,
) -> Result<(), DslDirectoryEncodeError> {
encoder.put_u64(self.creation_time)?;
encoder.put_u64(self.head_dataset_obj.unwrap_or(0))?;
encoder.put_u64(self.parent_directory_obj.unwrap_or(0))?;
encoder.put_u64(self.origin_dataset_obj.unwrap_or(0))?;
if self.child_directory_zap_obj == 0 {
return Err(DslDirectoryEncodeError::MissingChildDirectory {});
}
encoder.put_u64(self.child_directory_zap_obj)?;
encoder.put_u64(self.used_bytes)?;
encoder.put_u64(self.compressed_bytes)?;
encoder.put_u64(self.uncompressed_bytes)?;
encoder.put_u64(self.quota)?;
encoder.put_u64(self.reserved)?;
encoder.put_u64(self.properties_zap_obj)?;
if self.properties_zap_obj == 0 {
return Err(DslDirectoryEncodeError::MissingProperties {});
}
encoder.put_u64(self.delegation_zap_obj.unwrap_or(0))?;
let flags = if self.used_breakdown.is_none() {
0
} else {
DslDirectory::FLAG_USED_BREAKDOWN
};
encoder.put_u64(flags)?;
match &self.used_breakdown {
Some(used_breakdown) => {
encoder.put_u64(used_breakdown.head)?;
encoder.put_u64(used_breakdown.snapshot)?;
encoder.put_u64(used_breakdown.child)?;
encoder.put_u64(used_breakdown.child_reserved)?;
encoder.put_u64(used_breakdown.referenced_reservation)?;
}
None => encoder.put_zeros(DslDirectoryUsedBreakdown::SIZE)?,
}
encoder.put_zeros(DslDirectory::PADDING_SIZE)?;
Ok(())
}
}
#[derive(Debug)]
pub enum DslDirectoryDecodeError {
Binary {
err: BinaryDecodeError,
},
Flags {
flags: u64,
},
MissingChildDirectory {},
MissingProperties {},
}
impl From<BinaryDecodeError> for DslDirectoryDecodeError {
fn from(err: BinaryDecodeError) -> Self {
DslDirectoryDecodeError::Binary { err }
}
}
impl fmt::Display for DslDirectoryDecodeError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
DslDirectoryDecodeError::Binary { err } => {
write!(f, "DslDirectory decode error | {err}")
}
DslDirectoryDecodeError::Flags { flags } => {
write!(f, "DslDirectory decode error, unknown flags {flags}")
}
DslDirectoryDecodeError::MissingChildDirectory {} => {
write!(
f,
"DslDirectory decode error, child directory ZAP object is 0"
)
}
DslDirectoryDecodeError::MissingProperties {} => {
write!(f, "DslDirectory decode error, properties ZAP object is 0")
}
}
}
}
#[cfg(feature = "std")]
impl error::Error for DslDirectoryDecodeError {
fn source(&self) -> Option<&(dyn error::Error + 'static)> {
match self {
DslDirectoryDecodeError::Binary { err } => Some(err),
_ => None,
}
}
}
#[derive(Debug)]
pub enum DslDirectoryEncodeError {
Binary {
err: BinaryEncodeError,
},
MissingChildDirectory {},
MissingProperties {},
}
impl From<BinaryEncodeError> for DslDirectoryEncodeError {
fn from(err: BinaryEncodeError) -> Self {
DslDirectoryEncodeError::Binary { err }
}
}
impl fmt::Display for DslDirectoryEncodeError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
DslDirectoryEncodeError::Binary { err } => {
write!(f, "DslDirectory encode error | {err}")
}
DslDirectoryEncodeError::MissingChildDirectory {} => {
write!(
f,
"DslDirectory encode error, child directory ZAP object is 0"
)
}
DslDirectoryEncodeError::MissingProperties {} => {
write!(f, "DslDirectory encode error, properties ZAP object is 0")
}
}
}
}
#[cfg(feature = "std")]
impl error::Error for DslDirectoryEncodeError {
fn source(&self) -> Option<&(dyn error::Error + 'static)> {
match self {
DslDirectoryEncodeError::Binary { err } => Some(err),
_ => None,
}
}
}
#[derive(Debug)]
pub struct DslDataSet {
pub dir_obj: u64,
pub prev_snapshot_obj: Option<u64>,
pub prev_snapshot_txg: Option<u64>,
pub next_snapshot_obj: Option<u64>,
pub snapshot_names_zap_obj: Option<u64>,
pub num_children: u64,
pub creation_time: u64,
pub creation_txg: u64,
pub deadlist_obj: u64,
pub referenced_bytes: u64,
pub compressed_bytes: u64,
pub uncompressed_bytes: u64,
pub unique_bytes: u64,
pub fsid_guid: u64,
pub guid: u64,
pub flags: u64,
pub block_pointer: Option<BlockPointer>,
pub next_clones_obj: u64,
pub snapshot_props_obj: Option<u64>,
pub user_refs_obj: u64,
}
impl DslDataSet {
pub const SIZE: usize = 320;
const PADDING_SIZE: usize = 40;
const FLAG_INCONSISTENT: u64 = (1 << 0);
const FLAG_NO_PROMOTE: u64 = (1 << 1);
const FLAG_UNIQUE_ACCURATE: u64 = (1 << 2);
const FLAG_DEFER_DESTROY: u64 = (1 << 3);
const FLAG_CASE_INSENSITIVE_FS: u64 = (1 << 16);
const FLAG_NO_DIRTY: u64 = (1 << 24);
const FLAG_ALL: u64 = DslDataSet::FLAG_INCONSISTENT
| DslDataSet::FLAG_NO_PROMOTE
| DslDataSet::FLAG_UNIQUE_ACCURATE
| DslDataSet::FLAG_DEFER_DESTROY
| DslDataSet::FLAG_CASE_INSENSITIVE_FS
| DslDataSet::FLAG_NO_DIRTY;
pub fn from_decoder(
decoder: &mut dyn BinaryDecoder<'_>,
) -> Result<DslDataSet, DslDataSetDecodeError> {
let dir_obj = match decoder.get_u64()? {
0 => return Err(DslDataSetDecodeError::MissingDirectory {}),
v => v,
};
let prev_snapshot_obj = match decoder.get_u64()? {
0 => None,
v => Some(v),
};
let prev_snapshot_txg = match decoder.get_u64()? {
0 => None,
v => Some(v),
};
if prev_snapshot_obj.is_none() != prev_snapshot_txg.is_none() {
return Err(DslDataSetDecodeError::PreviousSnapshot {
prev_snapshot_obj: prev_snapshot_obj.unwrap_or(0),
prev_snapshot_txg: prev_snapshot_txg.unwrap_or(0),
});
}
let next_snapshot_obj = match decoder.get_u64()? {
0 => None,
v => Some(v),
};
let snapshot_names_zap_obj = match decoder.get_u64()? {
0 => None,
v => Some(v),
};
let num_children = decoder.get_u64()?;
let creation_time = decoder.get_u64()?;
let creation_txg = decoder.get_u64()?;
let deadlist_obj = decoder.get_u64()?;
let referenced_bytes = decoder.get_u64()?;
let compressed_bytes = decoder.get_u64()?;
let uncompressed_bytes = decoder.get_u64()?;
let unique_bytes = decoder.get_u64()?;
let fsid_guid = decoder.get_u64()?;
let guid = decoder.get_u64()?;
let flags = decoder.get_u64()?;
if (flags & DslDataSet::FLAG_ALL) != flags {
return Err(DslDataSetDecodeError::Flags { flags });
}
let block_pointer = BlockPointer::from_decoder(decoder)?;
let next_clones_obj = decoder.get_u64()?;
let snapshot_props_obj = match decoder.get_u64()? {
0 => None,
v => Some(v),
};
let user_refs_obj = decoder.get_u64()?;
decoder.skip_zeros(DslDataSet::PADDING_SIZE)?;
Ok(DslDataSet {
dir_obj,
prev_snapshot_obj,
prev_snapshot_txg,
next_snapshot_obj,
snapshot_names_zap_obj,
num_children,
creation_time,
creation_txg,
deadlist_obj,
referenced_bytes,
compressed_bytes,
uncompressed_bytes,
unique_bytes,
fsid_guid,
guid,
flags,
block_pointer,
next_clones_obj,
snapshot_props_obj,
user_refs_obj,
})
}
pub fn to_encoder(
&self,
encoder: &mut dyn BinaryEncoder<'_>,
) -> Result<(), DslDataSetEncodeError> {
if self.dir_obj == 0 {
return Err(DslDataSetEncodeError::MissingDirectory {});
}
encoder.put_u64(self.dir_obj)?;
if (self.prev_snapshot_obj.unwrap_or(0) == 0) != (self.prev_snapshot_txg.unwrap_or(0) == 0)
{
return Err(DslDataSetEncodeError::PreviousSnapshot {
prev_snapshot_obj: self.prev_snapshot_obj.unwrap_or(0),
prev_snapshot_txg: self.prev_snapshot_txg.unwrap_or(0),
});
}
encoder.put_u64(self.prev_snapshot_obj.unwrap_or(0))?;
encoder.put_u64(self.prev_snapshot_txg.unwrap_or(0))?;
encoder.put_u64(self.next_snapshot_obj.unwrap_or(0))?;
encoder.put_u64(self.snapshot_names_zap_obj.unwrap_or(0))?;
encoder.put_u64(self.num_children)?;
encoder.put_u64(self.creation_time)?;
encoder.put_u64(self.creation_txg)?;
encoder.put_u64(self.deadlist_obj)?;
encoder.put_u64(self.referenced_bytes)?;
encoder.put_u64(self.compressed_bytes)?;
encoder.put_u64(self.uncompressed_bytes)?;
encoder.put_u64(self.unique_bytes)?;
encoder.put_u64(self.fsid_guid)?;
encoder.put_u64(self.guid)?;
encoder.put_u64(self.flags)?;
BlockPointer::option_to_encoder(&self.block_pointer, encoder)?;
encoder.put_u64(self.next_clones_obj)?;
encoder.put_u64(self.snapshot_props_obj.unwrap_or(0))?;
encoder.put_u64(self.user_refs_obj)?;
encoder.put_zeros(DslDataSet::PADDING_SIZE)?;
Ok(())
}
}
#[derive(Debug)]
pub enum DslDataSetDecodeError {
Binary {
err: BinaryDecodeError,
},
BlockPointer {
err: BlockPointerDecodeError,
},
Flags {
flags: u64,
},
MissingDirectory {},
PreviousSnapshot {
prev_snapshot_obj: u64,
prev_snapshot_txg: u64,
},
}
impl From<BinaryDecodeError> for DslDataSetDecodeError {
fn from(err: BinaryDecodeError) -> Self {
DslDataSetDecodeError::Binary { err }
}
}
impl From<BlockPointerDecodeError> for DslDataSetDecodeError {
fn from(err: BlockPointerDecodeError) -> Self {
DslDataSetDecodeError::BlockPointer { err }
}
}
impl fmt::Display for DslDataSetDecodeError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
DslDataSetDecodeError::Binary { err } => {
write!(f, "DslDataSet decode error | {err}")
}
DslDataSetDecodeError::BlockPointer { err } => {
write!(f, "DslDataSet decode error | {err}")
}
DslDataSetDecodeError::Flags { flags } => {
write!(f, "ObjectSet decode error, unknown flags {flags:#016x}")
}
DslDataSetDecodeError::MissingDirectory {} => {
write!(f, "DslDataSet decode error, missing directory object")
}
DslDataSetDecodeError::PreviousSnapshot {
prev_snapshot_obj,
prev_snapshot_txg,
} => {
write!(f, "DslDataSet decode error, previous snapshot, obj: {prev_snapshot_obj} txg: {prev_snapshot_txg}")
}
}
}
}
#[cfg(feature = "std")]
impl error::Error for DslDataSetDecodeError {
fn source(&self) -> Option<&(dyn error::Error + 'static)> {
match self {
DslDataSetDecodeError::Binary { err } => Some(err),
DslDataSetDecodeError::BlockPointer { err } => Some(err),
_ => None,
}
}
}
#[derive(Debug)]
pub enum DslDataSetEncodeError {
Binary {
err: BinaryEncodeError,
},
BlockPointer {
err: BlockPointerEncodeError,
},
MissingDirectory {},
PreviousSnapshot {
prev_snapshot_obj: u64,
prev_snapshot_txg: u64,
},
}
impl From<BinaryEncodeError> for DslDataSetEncodeError {
fn from(err: BinaryEncodeError) -> Self {
DslDataSetEncodeError::Binary { err }
}
}
impl From<BlockPointerEncodeError> for DslDataSetEncodeError {
fn from(err: BlockPointerEncodeError) -> Self {
DslDataSetEncodeError::BlockPointer { err }
}
}
impl fmt::Display for DslDataSetEncodeError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
DslDataSetEncodeError::Binary { err } => {
write!(f, "DslDataSet encode error | {err}")
}
DslDataSetEncodeError::BlockPointer { err } => {
write!(f, "DslDataSet encode error | {err}")
}
DslDataSetEncodeError::MissingDirectory {} => {
write!(f, "DslDataSet encode error, missing directory object")
}
DslDataSetEncodeError::PreviousSnapshot {
prev_snapshot_obj,
prev_snapshot_txg,
} => {
write!(f, "DslDataSet encode error, previous snapshot, obj: {prev_snapshot_obj} txg: {prev_snapshot_txg}")
}
}
}
}
#[cfg(feature = "std")]
impl error::Error for DslDataSetEncodeError {
fn source(&self) -> Option<&(dyn error::Error + 'static)> {
match self {
DslDataSetEncodeError::Binary { err } => Some(err),
DslDataSetEncodeError::BlockPointer { err } => Some(err),
_ => None,
}
}
}