From 899b759b3dde3eac60e62c5bfc6d9a58cdcdd4ac Mon Sep 17 00:00:00 2001 From: Janis Date: Wed, 29 Mar 2023 17:51:53 +0200 Subject: [PATCH] slight refactor pre --- btrfs/src/lib.rs | 94 ++++++++++++++++++++++++++------------------ btrfs/src/structs.rs | 22 +++++++++-- btrfs/src/tree.rs | 92 ++++++++++++++++++++++++++++++++----------- 3 files changed, 144 insertions(+), 64 deletions(-) diff --git a/btrfs/src/lib.rs b/btrfs/src/lib.rs index 87fe3d6..04d67ac 100644 --- a/btrfs/src/lib.rs +++ b/btrfs/src/lib.rs @@ -1,3 +1,4 @@ +#![allow(dead_code)] #![feature(error_in_core)] #![cfg_attr(not(any(feature = "std", test)), no_std)] @@ -16,13 +17,15 @@ use scroll::Pread; use thiserror::Error; use structs::{Chunk, Key, KeyPtr, KnownObjectId, ObjectType, RootItem, Stripe, Superblock}; -use tree::Tree; +use tree::{PartialKey, Tree}; extern crate alloc; pub mod crc32c; +pub mod files; pub mod structs; pub mod tree; +pub mod v2; #[cfg(feature = "std")] pub mod std_io { @@ -33,7 +36,7 @@ pub mod std_io { impl VolumeIo for T { fn read(&mut self, dst: &mut [u8], address: u64) -> Result<(), Error> { self.seek(std::io::SeekFrom::Start(address)) - .map_err(|a| Error::SeekFailed)?; + .map_err(|a| Error::ReadFailed)?; self.read_exact(dst).map_err(|_| Error::ReadFailed) } @@ -43,36 +46,7 @@ pub mod std_io { } } -#[derive(Debug, Error)] -pub enum Error { - #[error("read failed")] - ReadFailed, - #[error("seek failed")] - SeekFailed, - #[error("invalid magic signature")] - InvalidMagic, - #[error("invalid offset")] - InvalidOffset, - #[error("Expected an internal node")] - ExpectedInternalNode, - #[error("Expected a leaf node")] - ExpectedLeafNode, - #[error("Invalid checksum: expected {expected:#?} but got {actual:#?}")] - InvalidChecksum { - expected: [u8; 32], - actual: [u8; 32], - }, - #[error("{0}")] - ScrollError(scroll::Error), -} - -impl From for Error { - fn from(value: scroll::Error) -> Self { - Self::ScrollError(value) - } -} - -pub type Result = core::result::Result; +pub use v2::error::*; pub trait VolumeIo { fn read(&mut self, dst: &mut [u8], address: u64) -> Result<()>; @@ -144,11 +118,13 @@ pub struct Btrfs { roots: BTreeMap, } +#[derive(Debug)] pub struct Root<'a, R: VolumeIo> { id: KnownObjectId, tree: Tree<'a, R>, } +#[derive(Debug)] pub struct Volume<'a, R: VolumeIo> { fs: &'a Btrfs, root: Root<'a, R>, @@ -357,25 +333,65 @@ impl Btrfs { } } - pub fn find_default_subvol(&self) -> Result<()> { + pub fn find_default_subvol(&self) -> Result>> { let root_tree = Tree::from_logical_offset(self, self.superblock().root.get())?; - let range = root_tree.full_range(); + let _range = root_tree.full_range(); + // we are looking for the root tree directory (?) + // this is a DIR_ITEM entry in the root tree, with the name "default", + // and the crc32 of "default" as its offset let key = Key::new( KnownObjectId::Custom(self.superblock.root_dir_objectid.get()), ObjectType::DirItem, 0x8dbfc2d2, // crc of "default" ); - if let Some((item, value)) = root_tree.find_key(key)? { - //let fs_root = value. - Root { - id: item.key.id(), - tree: todo!(), + if let Some(subvol_root) = root_tree.find_key(&key)? { + // if we found the dir entry of the "default subvol" (mharmstone nomenclature) + // we then look for the root fs tree in the root tree with the ID found in the `.location` of the dir_item only (from mharmstone) + let search_key = PartialKey::new( + Some( + subvol_root + .1 + .as_dir_item() + .expect("dir item") + .first() + .expect("dir item entry") + .dir_item + .location + .id(), + ), + Some(ObjectType::RootItem), + None, + ); + log::info!("subvol item: {subvol_root:#?}"); + + let subvol_id = subvol_root + .1 + .as_dir_item() + .expect("dir item") + .first() + .expect("dir item entry") + .dir_item + .location + .id(); + + if let Some(root) = self.roots.get(&subvol_id) { + log::info!("my root: {root:#?}"); + + let root = Root { + id: subvol_id, + tree: Tree::from_logical_offset(self, root.bytenr.get())?, + }; + + Ok(Some(Volume { fs: self, root })) + } else { + Ok(None) } } else { log::warn!("default subvol not found"); + Ok(None) } } diff --git a/btrfs/src/structs.rs b/btrfs/src/structs.rs index 082fd67..cc3ff76 100644 --- a/btrfs/src/structs.rs +++ b/btrfs/src/structs.rs @@ -22,7 +22,7 @@ pub enum KnownObjectId { QuotaTree, UuidTree, FreeSpaceTree, - __FirstFreeId = 256, + RootINode = 0x100, __LastFreeId = u64::MAX - 256, DataRelocTree = u64::MAX - 9, TreeReloc = u64::MAX - 8, @@ -797,7 +797,7 @@ impl DirItem { DirItemType::from_primitive(self.ty) } - pub fn parse_single(bytes: &[u8]) -> Result<(DirItemEntry)> { + pub fn parse_single(bytes: &[u8]) -> Result { let offset = &mut 0; Self::parse_single_inner(bytes, offset) } @@ -813,7 +813,7 @@ impl DirItem { Ok(DirItemEntry::new(dir_item, name.to_vec())) } - pub fn parse(bytes: &[u8]) -> Result> { + pub fn parse(bytes: &[u8]) -> Result> { let offset = &mut 0; let entries = core::iter::from_fn(|| { if *offset + size_of::() < bytes.len() { @@ -942,6 +942,22 @@ impl TreeItem { _ => 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 { + Some(v) + } else { + None + } + } } impl TreeItem { diff --git a/btrfs/src/tree.rs b/btrfs/src/tree.rs index d4538ae..e9fc38c 100644 --- a/btrfs/src/tree.rs +++ b/btrfs/src/tree.rs @@ -1,15 +1,11 @@ use core::{mem::size_of, ops::Deref}; use crate::{ - structs::{Chunk, Header, Item, Key, KeyPtr, KnownObjectId, ObjectType, RootItem, TreeItem}, + structs::{Header, Item, Key, KeyPtr, KnownObjectId, ObjectType, TreeItem}, Btrfs, Error, Result, VolumeIo, }; -use alloc::{ - borrow::Cow, - collections::VecDeque, - rc::{self, Rc}, - vec::Vec, -}; +use alloc::{borrow::Cow, rc::Rc, vec::Vec}; +use derivative::Derivative; use scroll::Pread; use zerocopy::FromBytes; @@ -85,6 +81,46 @@ mod partial_key_tests { let pkey = PartialKey::new(None, Some(ObjectType::DirItem), Some(0xdeadbeef)); assert_ne!(pkey.partial_cmp(&key), None); + + let pkey = PartialKey::new( + Some(KnownObjectId::ChunkTree), + Some(ObjectType::DirItem), + Some(0x8dbfc2d2), + ); + assert_eq!(pkey.partial_cmp(&key), Some(core::cmp::Ordering::Equal)); + } + + #[test] + fn test_partial_eq_partial_key() { + let key = Key::new( + KnownObjectId::ChunkTree, + ObjectType::DirItem, + 0x8dbfc2d2, // crc of "default" + ); + + let pkey = PartialKey::new( + Some(KnownObjectId::ChunkTree), + Some(ObjectType::DirItem), + None, + ); + assert!(pkey.eq(&key)); + + let pkey = PartialKey::new( + Some(KnownObjectId::ChunkTree), + Some(ObjectType::DirItem), + Some(0xdeadbeef), + ); + assert!(!pkey.eq(&key)); + + let pkey = PartialKey::new(None, Some(ObjectType::DirItem), Some(0xdeadbeef)); + assert!(!pkey.eq(&key)); + + let pkey = PartialKey::new( + Some(KnownObjectId::ChunkTree), + Some(ObjectType::DirItem), + Some(0x8dbfc2d2), + ); + assert!(pkey.eq(&key)); } } @@ -241,9 +277,11 @@ pub struct Tree<'a, R: VolumeIo> { root: BoxedNode<'a>, } -#[derive(Debug)] +#[derive(Derivative)] +#[derivative(Debug)] pub struct Node<'a> { inner: BTreeNode, + #[derivative(Debug = "ignore")] bytes: Cow<'a, [u8]>, } @@ -265,20 +303,27 @@ impl<'a> Node<'a> { } } - pub fn find_key(self: &Rc, key: &Key) -> SearchResult<'a> { + pub fn find_key + PartialOrd>( + self: &Rc, + key: &K, + ) -> SearchResult<'a> { match &self.inner { BTreeNode::Internal(node) => { for (i, child) in node.children.iter().enumerate() { - if key < &child.key { - return SearchResult::Edge(NodeHandle { - node: self.clone(), - idx: if i == 0 { 0 } else { i as u32 - 1 }, - }); - } else if key == &child.key { - return SearchResult::Edge(NodeHandle { - node: self.clone(), - idx: i as u32, - }); + match key.partial_cmp(&child.key) { + Some(core::cmp::Ordering::Less) => { + return SearchResult::Edge(NodeHandle { + node: self.clone(), + idx: if i == 0 { 0 } else { i as u32 - 1 }, + }); + } + Some(core::cmp::Ordering::Equal) | None => { + return SearchResult::Edge(NodeHandle { + node: self.clone(), + idx: i as u32, + }); + } + _ => {} } } @@ -295,7 +340,7 @@ impl<'a> Node<'a> { // idx: if i == 0 { 0 } else { i as u32 - 1 }, // }); // } else - if key == &child.key { + if key.eq(&child.key) { return SearchResult::Leaf(NodeHandle { node: self.clone(), idx: i as u32, @@ -601,11 +646,14 @@ impl<'a, R: VolumeIo> Tree<'a, R> { Ok(Self { volume, root }) } - pub fn find_key(&self, key: Key) -> Result> { + pub fn find_key + PartialOrd>( + &self, + key: &K, + ) -> Result> { let mut node = self.root.clone(); loop { - let search = node.find_key(&key); + let search = node.find_key(key); match search { SearchResult::Leaf(a) => { return a.parse_item();