diff --git a/btrfs/src/structs.rs b/btrfs/src/structs.rs index 99507cd..af8dde2 100644 --- a/btrfs/src/structs.rs +++ b/btrfs/src/structs.rs @@ -229,8 +229,29 @@ macro_rules! impl_parse_try_from_ctx { }; } -impl_parse_try_from_ctx!(Chunk, Header, Key, RootItem, INodeItem, INodeRef, DirItem); -impl_try_from_ctx!(Key, Chunk, Header, Superblock, RootItem, INodeItem, INodeRef, DirItem); +impl_parse_try_from_ctx!( + Chunk, + Header, + Key, + RootItem, + INodeItem, + INodeRef, + DirItem, + ExtentData1, + ExtentData2 +); +impl_try_from_ctx!( + Key, + Chunk, + Header, + Superblock, + RootItem, + INodeItem, + INodeRef, + DirItem, + ExtentData1, + ExtentData2 +); const MAX_LABEL_SIZE: usize = 0x100; const SYS_CHUNK_ARRAY_SIZE: usize = 0x800; @@ -294,31 +315,71 @@ pub struct ChunkItemStripe { dev_uuid: Uuid, } -#[repr(C, packed(1))] -#[derive(Debug, Clone, Copy, Pod, Zeroable)] -pub struct ExtentData { - generation: u64, - decoded_size: u64, - compression: u8, - encryption: u8, - encoding: u16, - ty: u8, - data: [u8; 1], +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] +pub enum ExtentDataType { + Inline, + Regular, + PreAlloc, +} + +#[derive(Debug, Clone)] +pub enum ExtentData { + Inline { header: ExtentData1, data: Vec }, + Other(ExtentData2), +} + +impl Parseable for ExtentData { + fn parse(bytes: &[u8]) -> Result { + let header = ExtentData1::parse(bytes)?; + + let extent = match header.ty() { + ExtentDataType::Inline => { + let data = bytes[size_of::()..].to_vec(); + Self::Inline { header, data } + } + _ => Self::Other(ExtentData2::parse(bytes)?), + }; + + Ok(extent) + } } #[repr(C, packed(1))] -#[derive(Debug, Clone, Copy, Pod, Zeroable)] +#[derive(Debug, Clone, Copy, FromBytes, AsBytes)] +pub struct ExtentData1 { + generation: U64, + decoded_size: U64, + compression: u8, + encryption: u8, + encoding: U16, + ty: u8, +} + +impl ExtentData1 { + pub fn ty(&self) -> ExtentDataType { + match self.ty { + 0 => ExtentDataType::Inline, + 1 => ExtentDataType::Regular, + 2 => ExtentDataType::PreAlloc, + _ => panic!("extentdatatype of invalid"), + } + } +} + +#[repr(C, packed(1))] +#[derive(Debug, Clone, Copy, FromBytes, AsBytes)] pub struct ExtentData2 { - address: u64, - size: u64, - offset: u64, - num_bytes: u64, + header: ExtentData1, + address: U64, + size: U64, + offset: U64, + num_bytes: U64, } #[repr(C, packed(1))] #[derive(Debug, Clone, Copy, FromBytes, AsBytes)] pub struct INodeRef { - index: U64, + pub index: U64, name_len: U16, } @@ -878,6 +939,11 @@ where pub fn item(&self) -> &I { &self.inner } + + pub fn name(&self) -> &Vec { + &self.name + } + pub fn name_as_str(&self) -> core::result::Result<&str, core::str::Utf8Error> { core::str::from_utf8(&self.name) } @@ -907,8 +973,10 @@ pub struct InodeRef { } #[repr(C, packed)] -#[derive(Debug, Clone, PartialEq, Eq, Copy, FromBytes, AsBytes)] +#[derive(Derivative, Clone, PartialEq, Eq, Copy, FromBytes, AsBytes)] +#[derivative(Debug)] pub struct Header { + #[derivative(Debug = "ignore")] pub csum: [u8; 32], pub fsid: Uuid, /// Which block this node is supposed to live in @@ -946,6 +1014,7 @@ use alloc::vec::Vec; pub enum TreeItem { Chunk(Chunk), Root(RootItem), + ExtentData(ExtentData), DirItem(Vec), DirIndex(DirItemEntry), INodeItem(INodeItem), @@ -989,6 +1058,12 @@ impl From for TreeItem { } } +impl From for TreeItem { + fn from(value: ExtentData) -> Self { + Self::ExtentData(value) + } +} + impl TreeItem { pub fn parse(item: &Item, bytes: &[u8]) -> Result { Ok(match item.key.ty() { @@ -998,20 +1073,13 @@ impl TreeItem { ObjectType::DirIndex => DirItemEntry::parse(bytes)?.into(), ObjectType::INodeItem => INodeItem::parse(bytes)?.into(), ObjectType::INodeRef => INodeRefEntry::parse(bytes)?.into(), + ObjectType::ExtentData => ExtentData::parse(bytes)?.into(), _ => TreeItem::Unimplemented, }) } - pub fn as_dir_item(&self) -> Option<&Vec> { - if let Self::DirItem(v) = self { - Some(v) - } else { - None - } - } - - pub fn as_dir_index(&self) -> Option<&DirItemEntry> { - if let Self::DirIndex(v) = self { + pub fn as_extent_data(&self) -> Option<&ExtentData> { + if let Self::ExtentData(v) = self { Some(v) } else { None @@ -1035,6 +1103,38 @@ impl TreeItem { None } } + + pub fn as_dir_item(&self) -> Option<&Vec> { + if let Self::DirItem(v) = self { + Some(v) + } else { + None + } + } + + pub fn as_dir_index(&self) -> Option<&DirItemEntry> { + if let Self::DirIndex(v) = self { + Some(v) + } else { + None + } + } + + pub fn as_inode_ref(&self) -> Option<&INodeRefEntry> { + if let Self::INodeRef(v) = self { + Some(v) + } else { + None + } + } + + pub fn as_inode_item(&self) -> Option<&INodeItem> { + if let Self::INodeItem(v) = self { + Some(v) + } else { + None + } + } } #[derive(Debug, Clone)]