split node reading logic off from tree
This commit is contained in:
parent
ae91f77d02
commit
ad3f782c67
@ -3,6 +3,7 @@ use std::sync::Arc;
|
|||||||
|
|
||||||
use crate::btrfs_structs::{ParseBin, Key, ChunkItem, Value, Superblock, ParseError, NODE_SIZE};
|
use crate::btrfs_structs::{ParseBin, Key, ChunkItem, Value, Superblock, ParseError, NODE_SIZE};
|
||||||
use crate::btrfs_lookup::Tree;
|
use crate::btrfs_lookup::Tree;
|
||||||
|
use crate::nodereader::NodeReader;
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct AddressMap(pub Vec<(u64,u64,Vec<(u64,u64)>)>);
|
pub struct AddressMap(pub Vec<(u64,u64,Vec<(u64,u64)>)>);
|
||||||
@ -12,10 +13,11 @@ impl AddressMap {
|
|||||||
pub fn new(image: &[u8]) -> Result<AddressMap, ParseError> {
|
pub fn new(image: &[u8]) -> Result<AddressMap, ParseError> {
|
||||||
let superblock = Superblock::parse(&image[0x10000..])?;
|
let superblock = Superblock::parse(&image[0x10000..])?;
|
||||||
let bootstrap_addr = AddressMap::from_superblock(&superblock)?;
|
let bootstrap_addr = AddressMap::from_superblock(&superblock)?;
|
||||||
|
let reader = Rc::new(NodeReader::with_addrmap(image, bootstrap_addr)?);
|
||||||
|
|
||||||
let chunk_tree = Tree {
|
let chunk_tree = Tree {
|
||||||
image: image,
|
image,
|
||||||
addr_map: Arc::new(bootstrap_addr),
|
reader,
|
||||||
root_addr_log: superblock.chunk_root,
|
root_addr_log: superblock.chunk_root,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -90,7 +92,7 @@ impl LogToPhys for AddressMap {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
pub fn node_at_log<'a, T: LogToPhys>(image: &'a [u8], addr: &T, log: u64) -> Result<&'a [u8], ParseError> {
|
pub fn node_at_log<'a, T: LogToPhys>(image: &'a [u8], addr: &T, log: u64) -> Result<&'a [u8], ParseError> {
|
||||||
if let Some(phys_addr) = addr.to_phys(log) {
|
if let Some(phys_addr) = addr.to_phys(log) {
|
||||||
Ok(&image[phys_addr as usize .. phys_addr as usize + NODE_SIZE])
|
Ok(&image[phys_addr as usize .. phys_addr as usize + NODE_SIZE])
|
||||||
@ -98,7 +100,16 @@ pub fn node_at_log<'a, T: LogToPhys>(image: &'a [u8], addr: &T, log: u64) -> Res
|
|||||||
err!("Logical address {:x} could not be translated to physical address", log)
|
err!("Logical address {:x} could not be translated to physical address", log)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
pub trait LogToPhys {
|
pub trait LogToPhys {
|
||||||
fn to_phys(&self, log: u64) -> Option<u64>;
|
fn to_phys(&self, log: u64) -> Option<u64>;
|
||||||
|
|
||||||
|
fn node_at_log<'a>(&self, image: &'a [u8], log: u64) -> Result<&'a [u8], ParseError> {
|
||||||
|
if let Some(phys_addr) = self.to_phys(log) {
|
||||||
|
Ok(&image[phys_addr as usize .. phys_addr as usize + NODE_SIZE])
|
||||||
|
} else {
|
||||||
|
err!("Logical address {:x} could not be translated to physical address", log)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,27 +1,28 @@
|
|||||||
use std::convert::identity;
|
use std::convert::identity;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use std::sync::Arc;
|
|
||||||
use std::ops::{Deref, RangeBounds, Bound};
|
use std::ops::{Deref, RangeBounds, Bound};
|
||||||
|
|
||||||
use crate::btrfs_structs::{Leaf, Key, Item, InteriorNode, Node, ParseError, ParseBin, Value, Superblock, ItemType, ZERO_KEY};
|
use crate::btrfs_structs::{Leaf, Key, Item, InteriorNode, Node, ParseError, ParseBin, Value, Superblock, ItemType, ZERO_KEY};
|
||||||
use crate::addrmap::{node_at_log, AddressMap};
|
use crate::addrmap::{AddressMap, LogToPhys};
|
||||||
|
use crate::nodereader::NodeReader;
|
||||||
|
|
||||||
/// Represents a B-Tree inside a filesystem image. Can be used to look up keys,
|
/// Represents a B-Tree inside a filesystem image. Can be used to look up keys,
|
||||||
/// and handles the tree traversal and the virtual address translation.
|
/// and handles the tree traversal and the virtual address translation.
|
||||||
pub struct Tree<'a> {
|
pub struct Tree<'a> {
|
||||||
pub image: &'a [u8],
|
pub image: &'a [u8],
|
||||||
pub addr_map: Arc<AddressMap>,
|
pub reader: Rc<NodeReader<'a>>,
|
||||||
pub root_addr_log: u64,
|
pub root_addr_log: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Tree<'a> {
|
impl<'a> Tree<'a> {
|
||||||
pub fn new<T: Into<u64>>(image: &'a [u8], tree_id: T) -> Result<Tree<'a>, ParseError> {
|
pub fn new<T: Into<u64>>(image: &'a [u8], tree_id: T) -> Result<Tree<'a>, ParseError> {
|
||||||
let addr_map = Arc::new(AddressMap::new(image)?);
|
// let addr_map = Arc::new(AddressMap::new(image)?);
|
||||||
let superblock = Superblock::parse(&image[0x10000..])?;
|
let superblock = Superblock::parse(&image[0x10000..])?;
|
||||||
|
let reader = Rc::new(NodeReader::new(image)?);
|
||||||
|
|
||||||
let root_tree = Tree {
|
let root_tree = Tree {
|
||||||
image,
|
image,
|
||||||
addr_map: Arc::clone(&addr_map),
|
reader: Rc::clone(&reader),
|
||||||
root_addr_log: superblock.root
|
root_addr_log: superblock.root
|
||||||
};
|
};
|
||||||
let tree_root_item = root_tree.find_key(Key::new(tree_id.into(), ItemType::Root, 0))?;
|
let tree_root_item = root_tree.find_key(Key::new(tree_id.into(), ItemType::Root, 0))?;
|
||||||
@ -31,30 +32,23 @@ impl<'a> Tree<'a> {
|
|||||||
_ => return Err("root item invalid".into())
|
_ => return Err("root item invalid".into())
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(Tree { image, addr_map, root_addr_log })
|
Ok(Tree { image, reader: Rc::clone(&reader), root_addr_log })
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn root(image: &'a [u8]) -> Result<Tree<'a>, ParseError> {
|
pub fn root(image: &'a [u8]) -> Result<Tree<'a>, ParseError> {
|
||||||
let addr_map = Arc::new(AddressMap::new(image)?);
|
let reader = Rc::new(NodeReader::new(image)?);
|
||||||
|
// let addr_map = Arc::new(AddressMap::new(image)?);
|
||||||
let superblock = Superblock::parse(&image[0x10000..])?;
|
let superblock = Superblock::parse(&image[0x10000..])?;
|
||||||
|
|
||||||
Ok(Tree { image, addr_map, root_addr_log: superblock.root })
|
Ok(Tree { image, reader, root_addr_log: superblock.root })
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn chunk(image: &'a [u8]) -> Result<Tree<'a>, ParseError> {
|
pub fn chunk(image: &'a [u8]) -> Result<Tree<'a>, ParseError> {
|
||||||
let addr_map = Arc::new(AddressMap::new(image)?);
|
let reader = Rc::new(NodeReader::new(image)?);
|
||||||
|
// let addr_map = Arc::new(AddressMap::new(image)?);
|
||||||
let superblock = Superblock::parse(&image[0x10000..])?;
|
let superblock = Superblock::parse(&image[0x10000..])?;
|
||||||
|
|
||||||
Ok(Tree { image, addr_map, root_addr_log: superblock.chunk_root })
|
Ok(Tree { image, reader, root_addr_log: superblock.chunk_root })
|
||||||
}
|
|
||||||
|
|
||||||
/// Read a node given its logical address
|
|
||||||
pub fn get_node(&self, addr: u64) -> Result<Arc<Node>, ParseError> {
|
|
||||||
// eprintln!("Reading node at {:x}", addr);
|
|
||||||
|
|
||||||
let node_data = node_at_log(self.image, self.addr_map.as_ref(), addr)?;
|
|
||||||
let node = Node::parse(node_data)?;
|
|
||||||
Ok(Arc::new(node))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -98,7 +92,7 @@ impl Tree<'_> {
|
|||||||
/// Recursively traverse a tree to find a key, given they key and logical address
|
/// Recursively traverse a tree to find a key, given they key and logical address
|
||||||
/// of the tree root. Internal function, `Tree::find_key` is the public interface.
|
/// of the tree root. Internal function, `Tree::find_key` is the public interface.
|
||||||
fn find_key_in_node(&self, addr: u64, key: Key) -> Result<Item, ParseError> {
|
fn find_key_in_node(&self, addr: u64, key: Key) -> Result<Item, ParseError> {
|
||||||
let node = self.get_node(self.root_addr_log)?;
|
let node = self.reader.get_node(self.root_addr_log)?;
|
||||||
|
|
||||||
match node.deref() {
|
match node.deref() {
|
||||||
Node::Interior(interior_node) => {
|
Node::Interior(interior_node) => {
|
||||||
@ -183,7 +177,7 @@ impl<'a> Tree<'a> {
|
|||||||
/// Get the first item under the node at logical address `addr`.
|
/// Get the first item under the node at logical address `addr`.
|
||||||
/// This function panics if there are no items
|
/// This function panics if there are no items
|
||||||
fn get_first_item(tree: &Tree, addr: u64) -> Result<Item, ParseError> {
|
fn get_first_item(tree: &Tree, addr: u64) -> Result<Item, ParseError> {
|
||||||
match tree.get_node(addr)?.deref() {
|
match tree.reader.get_node(addr)?.deref() {
|
||||||
Node::Interior(intnode) => {
|
Node::Interior(intnode) => {
|
||||||
get_first_item(tree, intnode.children[0].ptr)
|
get_first_item(tree, intnode.children[0].ptr)
|
||||||
},
|
},
|
||||||
@ -196,7 +190,7 @@ fn get_first_item(tree: &Tree, addr: u64) -> Result<Item, ParseError> {
|
|||||||
/// Get the last item under the node at logical address `addr`.
|
/// Get the last item under the node at logical address `addr`.
|
||||||
/// This function panics if there are no items
|
/// This function panics if there are no items
|
||||||
fn get_last_item(tree: &Tree, addr: u64) -> Result<Item, ParseError> {
|
fn get_last_item(tree: &Tree, addr: u64) -> Result<Item, ParseError> {
|
||||||
match tree.get_node(addr)?.deref() {
|
match tree.reader.get_node(addr)?.deref() {
|
||||||
Node::Interior(intnode) => {
|
Node::Interior(intnode) => {
|
||||||
get_last_item(tree, intnode.children.last().unwrap().ptr)
|
get_last_item(tree, intnode.children.last().unwrap().ptr)
|
||||||
},
|
},
|
||||||
@ -222,7 +216,7 @@ fn find_closest_key(tree: &Tree, key: Key, mode: FindKeyMode) -> Result<Option<I
|
|||||||
let mut next: Option<u64> = None;
|
let mut next: Option<u64> = None;
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
let node = tree.get_node(current)?;
|
let node = tree.reader.get_node(current)?;
|
||||||
match node.deref() {
|
match node.deref() {
|
||||||
Node::Interior(intnode) => {
|
Node::Interior(intnode) => {
|
||||||
match intnode.find_key_or_previous(key) {
|
match intnode.find_key_or_previous(key) {
|
||||||
|
@ -3,6 +3,7 @@ pub mod util;
|
|||||||
pub mod btrfs_structs;
|
pub mod btrfs_structs;
|
||||||
pub mod btrfs_lookup;
|
pub mod btrfs_lookup;
|
||||||
pub mod addrmap;
|
pub mod addrmap;
|
||||||
|
pub mod nodereader;
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test;
|
mod test;
|
||||||
|
@ -10,7 +10,8 @@ use memmap2::Mmap;
|
|||||||
use rouille::{Request, Response, router};
|
use rouille::{Request, Response, router};
|
||||||
use parsebtrfs::{
|
use parsebtrfs::{
|
||||||
btrfs_structs::{TreeID, Value::Extent, Value::BlockGroup, ParseError, NODE_SIZE, ItemType, Item, RootItem, Value, Key, ExtentDataBody},
|
btrfs_structs::{TreeID, Value::Extent, Value::BlockGroup, ParseError, NODE_SIZE, ItemType, Item, RootItem, Value, Key, ExtentDataBody},
|
||||||
btrfs_lookup::Tree, key,
|
btrfs_lookup::Tree,
|
||||||
|
addrmap::AddressMap,
|
||||||
};
|
};
|
||||||
|
|
||||||
const COLORS: &[&str] = &["#e6194b", "#3cb44b", "#ffe119", "#4363d8", "#f58231", "#911eb4", "#46f0f0", "#f032e6", "#bcf60c", "#fabebe", "#008080", "#e6beff", "#9a6324", "#fffac8", "#800000", "#aaffc3", "#808000", "#ffd8b1", "#000075", "#808080", "#000000"];
|
const COLORS: &[&str] = &["#e6194b", "#3cb44b", "#ffe119", "#4363d8", "#f58231", "#911eb4", "#46f0f0", "#f032e6", "#bcf60c", "#fabebe", "#008080", "#e6beff", "#9a6324", "#fffac8", "#800000", "#aaffc3", "#808000", "#ffd8b1", "#000075", "#808080", "#000000"];
|
||||||
@ -245,6 +246,7 @@ fn http_main_boxes(image: &[u8], _req: &Request) -> Response {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// header
|
// header
|
||||||
|
let addr_map: &AddressMap = extent_tree.reader.as_ref().addr_map();
|
||||||
result.push_str(
|
result.push_str(
|
||||||
&format!(
|
&format!(
|
||||||
"<h3 style=\"text-align: center;\">{:x} - {:x} ({}, {})</h3><p>Physical: {}</p>\n",
|
"<h3 style=\"text-align: center;\">{:x} - {:x} ({}, {})</h3><p>Physical: {}</p>\n",
|
||||||
@ -264,8 +266,8 @@ fn http_main_boxes(image: &[u8], _req: &Request) -> Response {
|
|||||||
0x04 => "Metadata",
|
0x04 => "Metadata",
|
||||||
_ => "???",
|
_ => "???",
|
||||||
},
|
},
|
||||||
match extent_tree.addr_map.as_ref().0.binary_search_by_key(&bg.key.key_id, |x|x.0) {
|
match addr_map.0.binary_search_by_key(&bg.key.key_id, |x|x.0) {
|
||||||
Ok(i) => format!("{:x?}", &extent_tree.addr_map.as_ref().0[i].2),
|
Ok(i) => format!("{:x?}", &addr_map.0[i].2),
|
||||||
_ => String::from(""),
|
_ => String::from(""),
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
Loading…
Reference in New Issue
Block a user