adapt address translator to derive parser
This commit is contained in:
parent
7ac28455cc
commit
98b6f5d1f6
@ -6,6 +6,7 @@ edition = "2021"
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1.0.72"
|
||||
binparse_derive = { path = "../binparse_derive" }
|
||||
memmap2 = "0.7.1"
|
||||
rouille = "3.6.2"
|
||||
|
86
src/addrmap.rs
Normal file
86
src/addrmap.rs
Normal file
@ -0,0 +1,86 @@
|
||||
use crate::btrfs_structs::{ParseBin, Key, ChunkItem, Leaf, Value, Superblock, LogToPhys};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct AddressMap(Vec<(u64,u64,Vec<(u64,u64)>)>);
|
||||
|
||||
// TODO: support for internal nodes, multiple devices?
|
||||
impl AddressMap {
|
||||
pub fn new(image: &[u8]) -> Result<AddressMap,String> {
|
||||
let superblock = Superblock::parse(&image[0x10000..])?;
|
||||
let bootstrap_addr = AddressMap::from_superblock(&superblock)?;
|
||||
|
||||
let chunk_root_log = superblock.chunk_root;
|
||||
println!("Chunk Tree Root Logical Address: {:016x}", chunk_root_log);
|
||||
|
||||
let chunk_root_phys = bootstrap_addr.to_phys(chunk_root_log).unwrap();
|
||||
println!("Chunk Tree Root Physical Address: {:016x}", chunk_root_phys);
|
||||
|
||||
let chunk_root = Leaf::parse(&image[chunk_root_phys as usize..])?;
|
||||
|
||||
let mut addr_map = Vec::new();
|
||||
for item in chunk_root.items {
|
||||
let chunk_key = item.key;
|
||||
if let Value::Chunk(chunk_value) = item.value {
|
||||
addr_map.push((
|
||||
chunk_key.key_offset,
|
||||
chunk_value.size,
|
||||
chunk_value.stripes.iter()
|
||||
.map(|stripe|(stripe.devid, stripe.offset))
|
||||
.collect()
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
addr_map.sort_by_key(|x|x.0);
|
||||
println!("Address Table: {:?}", addr_map);
|
||||
Ok(AddressMap(addr_map))
|
||||
}
|
||||
|
||||
pub fn from_superblock(superblock: &Superblock) -> Result<AddressMap,String> {
|
||||
let sys_chunk_array_size = superblock.sys_chunk_array_size;
|
||||
let sys_chunk_array: &[u8] = &superblock.sys_chunk_array;
|
||||
let mut addr_map = Vec::new();
|
||||
let mut len: usize = 0;
|
||||
|
||||
while len < sys_chunk_array_size as usize {
|
||||
let chunk_key: Key = Key::parse(&sys_chunk_array[len .. ])?;
|
||||
let chunk_value: ChunkItem = ChunkItem::parse(&sys_chunk_array[len+0x11 .. ])?;
|
||||
|
||||
addr_map.push((
|
||||
chunk_key.key_offset,
|
||||
chunk_value.size,
|
||||
chunk_value.stripes.iter()
|
||||
.map(|stripe|(stripe.devid, stripe.offset))
|
||||
.collect()
|
||||
));
|
||||
len += 0x41 + 0x20 * chunk_value.stripes.len();
|
||||
}
|
||||
|
||||
addr_map.sort_by_key(|x|x.0);
|
||||
println!("Bootstrap Address Table: {:?}", addr_map);
|
||||
Ok(AddressMap(addr_map))
|
||||
}
|
||||
}
|
||||
|
||||
impl LogToPhys for AddressMap {
|
||||
fn to_phys(&self, log: u64) -> Option<u64> {
|
||||
let index = match self.0.binary_search_by_key(&log, |x|x.0) {
|
||||
Ok(idx) => idx as usize,
|
||||
Err(idx) => if idx == 0 {
|
||||
return None;
|
||||
} else {
|
||||
idx-1 as usize
|
||||
}
|
||||
};
|
||||
|
||||
let log_offset = self.0[index].0;
|
||||
let size = self.0[index].1;
|
||||
let phys_offset = self.0[index].2[0].1;
|
||||
|
||||
if log >= log_offset && log < log_offset + size {
|
||||
Some(phys_offset + (log - log_offset))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
@ -1,14 +1,16 @@
|
||||
use binparse_derive::AllVariants;
|
||||
use binparse_derive::ParseBin;
|
||||
use std::fmt;
|
||||
use std::error;
|
||||
use std::io;
|
||||
use std::ffi::CString;
|
||||
|
||||
/***** BTRFS structures *****/
|
||||
|
||||
const NODE_SIZE: usize = 0x4000;
|
||||
pub const NODE_SIZE: usize = 0x4000;
|
||||
|
||||
#[allow(unused)]
|
||||
#[derive(Debug,Clone,Copy,AllVariants)]
|
||||
#[derive(Debug,Clone,Copy,AllVariants,PartialEq,Eq,PartialOrd,Ord)]
|
||||
#[repr(u8)]
|
||||
pub enum ItemType {
|
||||
Invalid = 0x00,
|
||||
@ -41,7 +43,7 @@ pub enum ItemType {
|
||||
FreeSpaceBitmap = 0xc8,
|
||||
DevExtent = 0xcc, // implemented
|
||||
Dev = 0xd8, // implemented
|
||||
Chunk = 0xe4, // implemented? (awaiting len feature)
|
||||
Chunk = 0xe4, // implemented
|
||||
QGroupStatus = 0xf0,
|
||||
QGroupInfo = 0xf2,
|
||||
QGroupLimit = 0xf4,
|
||||
@ -55,15 +57,15 @@ pub enum ItemType {
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
#[derive(Debug,Clone,Copy,ParseBin)]
|
||||
#[derive(Debug,Clone,Copy,ParseBin,PartialEq,Eq,PartialOrd,Ord)]
|
||||
pub struct Key {
|
||||
key_id: u64,
|
||||
key_type: ItemType,
|
||||
key_offset: u64,
|
||||
pub key_id: u64,
|
||||
pub key_type: ItemType,
|
||||
pub key_offset: u64,
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug,Clone)]
|
||||
pub enum Value {
|
||||
Extent(ExtentItem),
|
||||
BlockGroup(BlockGroupItem),
|
||||
@ -82,144 +84,192 @@ pub enum Value {
|
||||
|
||||
#[allow(unused)]
|
||||
#[allow(unused)]
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug,Clone)]
|
||||
pub struct Item {
|
||||
key: Key,
|
||||
value: Value,
|
||||
pub key: Key,
|
||||
pub value: Value,
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
#[derive(ParseBin)]
|
||||
#[derive(Clone,ParseBin)]
|
||||
pub struct Checksum([u8; 32]);
|
||||
|
||||
#[allow(unused)]
|
||||
#[derive(ParseBin)]
|
||||
#[derive(Clone,ParseBin)]
|
||||
pub struct UUID([u8; 16]);
|
||||
|
||||
#[allow(unused)]
|
||||
#[derive(Debug,ParseBin)]
|
||||
pub struct Superblock {
|
||||
pub csum: Checksum,
|
||||
pub fsid: UUID,
|
||||
pub bytenr: u64,
|
||||
pub flags: u64,
|
||||
pub magic: u64,
|
||||
pub generation: u64,
|
||||
pub root: u64,
|
||||
pub chunk_root: u64,
|
||||
pub log_root: u64,
|
||||
#[skip_bytes = 8]
|
||||
pub total_bytes: u64,
|
||||
pub bytes_used: u64,
|
||||
|
||||
pub root_dir_objectid: u64,
|
||||
pub num_devices: u64,
|
||||
pub sectorsize: u32,
|
||||
pub nodesize: u32,
|
||||
#[skip_bytes = 4]
|
||||
pub stripesize: u32,
|
||||
pub sys_chunk_array_size: u32,
|
||||
pub chunk_root_generation: u64,
|
||||
pub compat_flags: u64,
|
||||
pub compat_ro_flags: u64,
|
||||
pub incompat_flags: u64,
|
||||
pub csum_type: u16,
|
||||
pub root_level: u8,
|
||||
pub chunk_root_level: u8,
|
||||
pub log_root_level: u8,
|
||||
|
||||
pub dev_item: DevItem,
|
||||
|
||||
pub label: [u8; 0x100],
|
||||
|
||||
pub cache_generation: u64,
|
||||
pub uuid_tree_generation: u64,
|
||||
|
||||
pub metadata_uuid: UUID,
|
||||
pub nr_global_roots: u64,
|
||||
|
||||
#[skip_bytes = 216]
|
||||
pub sys_chunk_array: [u8; 0x800],
|
||||
|
||||
// next up would be the root backups, but we don't read them for now
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
#[derive(Debug,Clone,ParseBin)]
|
||||
pub struct NodeHeader {
|
||||
csum: Checksum,
|
||||
fs_uid: UUID,
|
||||
bytenr: u64,
|
||||
flags: u64,
|
||||
chunk_tree_uid: UUID,
|
||||
generation: u64,
|
||||
owner: u64,
|
||||
nritems: u32,
|
||||
level: u8,
|
||||
pub csum: Checksum,
|
||||
pub fs_uid: UUID,
|
||||
pub bytenr: u64,
|
||||
pub flags: u64,
|
||||
pub chunk_tree_uid: UUID,
|
||||
pub generation: u64,
|
||||
pub owner: u64,
|
||||
pub nritems: u32,
|
||||
pub level: u8,
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug,Clone)]
|
||||
pub struct Leaf {
|
||||
header: NodeHeader,
|
||||
items: Vec<Item>,
|
||||
pub header: NodeHeader,
|
||||
pub items: Vec<Item>,
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
#[derive(Debug,ParseBin)]
|
||||
#[derive(Debug,Clone,ParseBin)]
|
||||
pub struct BlockGroupItem {
|
||||
used: u64,
|
||||
chunk_objectid: u64,
|
||||
flags: u64,
|
||||
pub used: u64,
|
||||
pub chunk_objectid: u64,
|
||||
pub flags: u64,
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
#[derive(Debug,ParseBin)]
|
||||
#[derive(Debug,Clone,ParseBin)]
|
||||
pub struct ExtentItem {
|
||||
refs: u64,
|
||||
generation: u64,
|
||||
flags: u64,
|
||||
data: Vec<u8>,
|
||||
pub refs: u64,
|
||||
pub generation: u64,
|
||||
pub flags: u64,
|
||||
pub data: Vec<u8>,
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
#[derive(Debug,ParseBin)]
|
||||
#[derive(Debug,Clone,ParseBin)]
|
||||
pub struct Time {
|
||||
sec: u64,
|
||||
nsec: u32,
|
||||
pub sec: u64,
|
||||
pub nsec: u32,
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
#[derive(Debug,ParseBin)]
|
||||
#[derive(Debug,Clone,ParseBin)]
|
||||
pub struct InodeItem {
|
||||
generation: u64,
|
||||
transid: u64,
|
||||
size: u64,
|
||||
nbytes: u64,
|
||||
block_group: u64,
|
||||
nlink: u32,
|
||||
uid: u32,
|
||||
gid: u32,
|
||||
mode: u32,
|
||||
rdev: u64,
|
||||
flags: u64,
|
||||
sequence: u64,
|
||||
pub generation: u64,
|
||||
pub transid: u64,
|
||||
pub size: u64,
|
||||
pub nbytes: u64,
|
||||
pub block_group: u64,
|
||||
pub nlink: u32,
|
||||
pub uid: u32,
|
||||
pub gid: u32,
|
||||
pub mode: u32,
|
||||
pub rdev: u64,
|
||||
pub flags: u64,
|
||||
pub sequence: u64,
|
||||
#[skip_bytes = 32]
|
||||
atime: Time,
|
||||
ctime: Time,
|
||||
mtime: Time,
|
||||
otime: Time,
|
||||
pub atime: Time,
|
||||
pub ctime: Time,
|
||||
pub mtime: Time,
|
||||
pub otime: Time,
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
#[derive(Debug,ParseBin)]
|
||||
#[derive(Debug,Clone,ParseBin)]
|
||||
pub struct ChunkItem {
|
||||
size: u64,
|
||||
root: u64,
|
||||
stripelen: u64,
|
||||
chunktype: u64,
|
||||
align: u32,
|
||||
width: u32,
|
||||
sectorsize: u32,
|
||||
nrstripes: u16,
|
||||
substripes: u16,
|
||||
pub size: u64,
|
||||
pub root: u64,
|
||||
pub stripelen: u64,
|
||||
pub chunktype: u64,
|
||||
pub align: u32,
|
||||
pub width: u32,
|
||||
pub sectorsize: u32,
|
||||
pub nrstripes: u16,
|
||||
pub substripes: u16,
|
||||
|
||||
// #[vector_length = nrstripes]
|
||||
// stripes: Vec<ChunkItemStripe>,
|
||||
#[len = "nrstripes"]
|
||||
pub stripes: Vec<ChunkItemStripe>,
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
#[derive(Debug,ParseBin)]
|
||||
#[derive(Debug,Clone,ParseBin)]
|
||||
pub struct ChunkItemStripe {
|
||||
devid: u64,
|
||||
offset: u64,
|
||||
devuuid: UUID,
|
||||
pub devid: u64,
|
||||
pub offset: u64,
|
||||
pub devuuid: UUID,
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
#[derive(Debug,ParseBin)]
|
||||
#[derive(Debug,Clone,ParseBin)]
|
||||
pub struct RootItem {
|
||||
inode: InodeItem,
|
||||
generation: u64,
|
||||
root_dirid: u64,
|
||||
bytenr: u64,
|
||||
byte_limit: u64,
|
||||
bytes_used: u64,
|
||||
last_snapshot: u64,
|
||||
flags: u64,
|
||||
refs: u32,
|
||||
drop_progress: Key,
|
||||
drop_level: u8,
|
||||
level: u8,
|
||||
pub inode: InodeItem,
|
||||
pub generation: u64,
|
||||
pub root_dirid: u64,
|
||||
pub bytenr: u64,
|
||||
pub byte_limit: u64,
|
||||
pub bytes_used: u64,
|
||||
pub last_snapshot: u64,
|
||||
pub flags: u64,
|
||||
pub refs: u32,
|
||||
pub drop_progress: Key,
|
||||
pub drop_level: u8,
|
||||
pub level: u8,
|
||||
|
||||
generation_v2: u64,
|
||||
uuid: UUID,
|
||||
parent_uuid: UUID,
|
||||
received_uuid: UUID,
|
||||
ctransid: u64,
|
||||
otransid: u64,
|
||||
stransid: u64,
|
||||
rtransid: u64,
|
||||
ctime: Time,
|
||||
otime: Time,
|
||||
stime: Time,
|
||||
rtime: Time,
|
||||
pub generation_v2: u64,
|
||||
pub uuid: UUID,
|
||||
pub parent_uuid: UUID,
|
||||
pub received_uuid: UUID,
|
||||
pub ctransid: u64,
|
||||
pub otransid: u64,
|
||||
pub stransid: u64,
|
||||
pub rtransid: u64,
|
||||
pub ctime: Time,
|
||||
pub otime: Time,
|
||||
pub stime: Time,
|
||||
pub rtime: Time,
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
#[derive(Debug,ParseBin)]
|
||||
#[derive(Debug,Clone,ParseBin)]
|
||||
pub struct DirItem {
|
||||
location: Key,
|
||||
transid: u64,
|
||||
@ -227,25 +277,25 @@ pub struct DirItem {
|
||||
name_len: u16,
|
||||
dir_type: u8,
|
||||
|
||||
#[len = "name_len"]
|
||||
// #[len = "name_len"]
|
||||
name: CString,
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
#[derive(Debug,ParseBin)]
|
||||
#[derive(Debug,Clone,ParseBin)]
|
||||
pub struct FreeSpaceInfoItem {
|
||||
extent_count: u32,
|
||||
flags: u32,
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
#[derive(Debug,ParseBin)]
|
||||
#[derive(Debug,Clone,ParseBin)]
|
||||
pub struct UUIDSubvolItem {
|
||||
subvol_id: u64,
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
#[derive(Debug,ParseBin)]
|
||||
#[derive(Debug,Clone,ParseBin)]
|
||||
pub struct DevItem {
|
||||
devid: u64,
|
||||
total_bytes: u64,
|
||||
@ -264,7 +314,7 @@ pub struct DevItem {
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
#[derive(Debug,ParseBin)]
|
||||
#[derive(Debug,Clone,ParseBin)]
|
||||
pub struct DevExtentItem {
|
||||
chunk_tree: u64,
|
||||
chunk_objectid: u64,
|
||||
@ -274,21 +324,21 @@ pub struct DevExtentItem {
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug,Clone)]
|
||||
pub struct ExtentDataItem {
|
||||
header: ExtentDataHeader,
|
||||
data: ExtentDataBody,
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug,Clone)]
|
||||
pub enum ExtentDataBody {
|
||||
Inline(Vec<u8>),
|
||||
External(ExternalExtent),
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
#[derive(Debug,ParseBin)]
|
||||
#[derive(Debug,Clone,ParseBin)]
|
||||
pub struct ExternalExtent {
|
||||
disk_bytenr: u64,
|
||||
disk_num_bytes: u64,
|
||||
@ -297,7 +347,7 @@ pub struct ExternalExtent {
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
#[derive(Debug,ParseBin)]
|
||||
#[derive(Debug,Clone,ParseBin)]
|
||||
pub struct ExtentDataHeader {
|
||||
generation: u64,
|
||||
ram_bytes: u64,
|
||||
@ -310,6 +360,35 @@ pub struct ExtentDataHeader {
|
||||
/***** trait for parsing, and implementations for basic types *****/
|
||||
// most of the more complex types will be parsed using derive macros
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ParseError(String);
|
||||
|
||||
impl error::Error for ParseError {}
|
||||
|
||||
impl fmt::Display for ParseError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "{}", &self.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<String> for ParseError {
|
||||
fn from(value: String) -> ParseError {
|
||||
ParseError(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&str> for ParseError {
|
||||
fn from(value: &str) -> ParseError {
|
||||
ParseError::from(String::from(value))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ParseError> for io::Error {
|
||||
fn from(value: ParseError) -> io::Error {
|
||||
io::Error::other(value)
|
||||
}
|
||||
}
|
||||
|
||||
pub trait ParseBin where Self: Sized {
|
||||
fn parse_len(bytes: &[u8]) -> Result<(Self, usize), String>;
|
||||
|
||||
@ -454,7 +533,6 @@ impl ParseBin for Leaf {
|
||||
Value::DevExtent(DevExtentItem::parse(data_slice)?),
|
||||
ItemType::ExtentData =>
|
||||
Value::ExtentData(ExtentDataItem::parse(data_slice)?),
|
||||
|
||||
_ =>
|
||||
Value::Unknown(Vec::from(data_slice)),
|
||||
};
|
||||
@ -489,6 +567,28 @@ impl ParseBin for ExtentDataItem {
|
||||
}
|
||||
}
|
||||
|
||||
/***** looking up keys *****/
|
||||
|
||||
impl Leaf {
|
||||
pub fn find_key(&self, key: Key) -> Option<Item> {
|
||||
self.items.iter().find(|x|x.key == key).map(|x|x.clone())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn node_at_log<'a, T: LogToPhys>(image: &'a [u8], addr: &T, log: u64) -> Option<&'a [u8]> {
|
||||
let phys_addr = addr.to_phys(log)?;
|
||||
Some(&image[phys_addr as usize .. phys_addr as usize + NODE_SIZE])
|
||||
}
|
||||
|
||||
pub trait LogToPhys {
|
||||
fn to_phys(&self, log: u64) -> Option<u64>;
|
||||
}
|
||||
|
||||
pub fn find_key_in_tree<T: LogToPhys>(image: &[u8], addr: &T, root_addr_log: u64, key: Key) -> Option<Item> {
|
||||
// assuming level is 0
|
||||
let leaf = Leaf::parse(node_at_log(image, addr, root_addr_log)?).ok()?;
|
||||
leaf.find_key(key)
|
||||
}
|
||||
|
||||
/***** prettier debug output for UUIDs and checksums *****/
|
||||
|
||||
@ -520,3 +620,9 @@ impl fmt::Debug for Checksum {
|
||||
x24, x25, x26, x27, x28, x29, x30, x31)
|
||||
}
|
||||
}
|
||||
|
||||
impl Key {
|
||||
pub fn new(key_id: u64, key_type: ItemType, key_offset: u64) -> Key {
|
||||
Key { key_id, key_type, key_offset }
|
||||
}
|
||||
}
|
||||
|
37
src/main.rs
37
src/main.rs
@ -1,19 +1,48 @@
|
||||
mod btrfs_structs;
|
||||
#![feature(io_error_other)]
|
||||
|
||||
mod btrfs_structs;
|
||||
mod addrmap;
|
||||
|
||||
use addrmap::AddressMap;
|
||||
use memmap2::Mmap;
|
||||
use std::fs::File;
|
||||
use std::io::Error as IOError;
|
||||
use anyhow::Error as AError;
|
||||
use rouille::Request;
|
||||
use rouille::Response;
|
||||
use btrfs_structs::{ItemType, ParseBin, Key, Item, Leaf, NodeHeader};
|
||||
use btrfs_structs::{ItemType, ParseBin, Key, Item, Leaf, NodeHeader, NODE_SIZE, Superblock, Value, LogToPhys};
|
||||
|
||||
//const ACTIVE_NODES: &'static[usize] = &[0x14000, 0x18000, 0x1c000, 0x20000, 0x28000, 0x2c000, 0x3c000, 0x40000];
|
||||
|
||||
fn main() -> Result<(), std::io::Error> {
|
||||
const EXTENT_TREE: u64 = 2;
|
||||
const FS_TREE: u64 = 5;
|
||||
|
||||
fn main() -> Result<(), IOError> {
|
||||
let file = File::open("../image")?;
|
||||
let image = unsafe { Mmap::map(&file)? };
|
||||
|
||||
let addr = AddressMap::new(&image).map_err(|e|IOError::other(e))?;
|
||||
let superblock = Superblock::parse(&image[0x10000..]).map_err(|e|IOError::other(e))?;
|
||||
|
||||
let chunk_root_phys = addr.to_phys(superblock.chunk_root).unwrap() as usize;
|
||||
let root_phys = addr.to_phys(superblock.root).unwrap() as usize;
|
||||
|
||||
let root_tree_leaf = Leaf::parse(&image[root_phys .. root_phys + NODE_SIZE]).map_err(|e|IOError::other(e))?;
|
||||
|
||||
let root_key = Key::new(EXTENT_TREE, ItemType::Root, 0);
|
||||
let root = root_tree_leaf.find_key(root_key).unwrap();
|
||||
|
||||
let root_addr = if let Value::Root(root_item) = root.value {
|
||||
addr.to_phys(root_item.bytenr)
|
||||
} else {
|
||||
None
|
||||
}.unwrap() as usize;
|
||||
|
||||
let tree_leaf = Leaf::parse(&image[root_addr .. root_addr + NODE_SIZE]).map_err(|e|IOError::other(e))?;
|
||||
|
||||
println!("{:#?}", &tree_leaf);
|
||||
|
||||
// println!("{:#?}", Leaf::parse(&image[0x253c000..0x2540000]));
|
||||
println!("{:#?}", Leaf::parse(&image[0x1d04000..0x1d08000]));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user