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
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
anyhow = "1.0.72"
|
||||||
binparse_derive = { path = "../binparse_derive" }
|
binparse_derive = { path = "../binparse_derive" }
|
||||||
memmap2 = "0.7.1"
|
memmap2 = "0.7.1"
|
||||||
rouille = "3.6.2"
|
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::AllVariants;
|
||||||
use binparse_derive::ParseBin;
|
use binparse_derive::ParseBin;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
use std::error;
|
||||||
|
use std::io;
|
||||||
use std::ffi::CString;
|
use std::ffi::CString;
|
||||||
|
|
||||||
/***** BTRFS structures *****/
|
/***** BTRFS structures *****/
|
||||||
|
|
||||||
const NODE_SIZE: usize = 0x4000;
|
pub const NODE_SIZE: usize = 0x4000;
|
||||||
|
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
#[derive(Debug,Clone,Copy,AllVariants)]
|
#[derive(Debug,Clone,Copy,AllVariants,PartialEq,Eq,PartialOrd,Ord)]
|
||||||
#[repr(u8)]
|
#[repr(u8)]
|
||||||
pub enum ItemType {
|
pub enum ItemType {
|
||||||
Invalid = 0x00,
|
Invalid = 0x00,
|
||||||
@ -41,7 +43,7 @@ pub enum ItemType {
|
|||||||
FreeSpaceBitmap = 0xc8,
|
FreeSpaceBitmap = 0xc8,
|
||||||
DevExtent = 0xcc, // implemented
|
DevExtent = 0xcc, // implemented
|
||||||
Dev = 0xd8, // implemented
|
Dev = 0xd8, // implemented
|
||||||
Chunk = 0xe4, // implemented? (awaiting len feature)
|
Chunk = 0xe4, // implemented
|
||||||
QGroupStatus = 0xf0,
|
QGroupStatus = 0xf0,
|
||||||
QGroupInfo = 0xf2,
|
QGroupInfo = 0xf2,
|
||||||
QGroupLimit = 0xf4,
|
QGroupLimit = 0xf4,
|
||||||
@ -55,15 +57,15 @@ pub enum ItemType {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
#[derive(Debug,Clone,Copy,ParseBin)]
|
#[derive(Debug,Clone,Copy,ParseBin,PartialEq,Eq,PartialOrd,Ord)]
|
||||||
pub struct Key {
|
pub struct Key {
|
||||||
key_id: u64,
|
pub key_id: u64,
|
||||||
key_type: ItemType,
|
pub key_type: ItemType,
|
||||||
key_offset: u64,
|
pub key_offset: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
#[derive(Debug)]
|
#[derive(Debug,Clone)]
|
||||||
pub enum Value {
|
pub enum Value {
|
||||||
Extent(ExtentItem),
|
Extent(ExtentItem),
|
||||||
BlockGroup(BlockGroupItem),
|
BlockGroup(BlockGroupItem),
|
||||||
@ -82,144 +84,192 @@ pub enum Value {
|
|||||||
|
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
#[derive(Debug)]
|
#[derive(Debug,Clone)]
|
||||||
pub struct Item {
|
pub struct Item {
|
||||||
key: Key,
|
pub key: Key,
|
||||||
value: Value,
|
pub value: Value,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
#[derive(ParseBin)]
|
#[derive(Clone,ParseBin)]
|
||||||
pub struct Checksum([u8; 32]);
|
pub struct Checksum([u8; 32]);
|
||||||
|
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
#[derive(ParseBin)]
|
#[derive(Clone,ParseBin)]
|
||||||
pub struct UUID([u8; 16]);
|
pub struct UUID([u8; 16]);
|
||||||
|
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
#[derive(Debug,ParseBin)]
|
#[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 {
|
pub struct NodeHeader {
|
||||||
csum: Checksum,
|
pub csum: Checksum,
|
||||||
fs_uid: UUID,
|
pub fs_uid: UUID,
|
||||||
bytenr: u64,
|
pub bytenr: u64,
|
||||||
flags: u64,
|
pub flags: u64,
|
||||||
chunk_tree_uid: UUID,
|
pub chunk_tree_uid: UUID,
|
||||||
generation: u64,
|
pub generation: u64,
|
||||||
owner: u64,
|
pub owner: u64,
|
||||||
nritems: u32,
|
pub nritems: u32,
|
||||||
level: u8,
|
pub level: u8,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
#[derive(Debug)]
|
#[derive(Debug,Clone)]
|
||||||
pub struct Leaf {
|
pub struct Leaf {
|
||||||
header: NodeHeader,
|
pub header: NodeHeader,
|
||||||
items: Vec<Item>,
|
pub items: Vec<Item>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
#[derive(Debug,ParseBin)]
|
#[derive(Debug,Clone,ParseBin)]
|
||||||
pub struct BlockGroupItem {
|
pub struct BlockGroupItem {
|
||||||
used: u64,
|
pub used: u64,
|
||||||
chunk_objectid: u64,
|
pub chunk_objectid: u64,
|
||||||
flags: u64,
|
pub flags: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
#[derive(Debug,ParseBin)]
|
#[derive(Debug,Clone,ParseBin)]
|
||||||
pub struct ExtentItem {
|
pub struct ExtentItem {
|
||||||
refs: u64,
|
pub refs: u64,
|
||||||
generation: u64,
|
pub generation: u64,
|
||||||
flags: u64,
|
pub flags: u64,
|
||||||
data: Vec<u8>,
|
pub data: Vec<u8>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
#[derive(Debug,ParseBin)]
|
#[derive(Debug,Clone,ParseBin)]
|
||||||
pub struct Time {
|
pub struct Time {
|
||||||
sec: u64,
|
pub sec: u64,
|
||||||
nsec: u32,
|
pub nsec: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
#[derive(Debug,ParseBin)]
|
#[derive(Debug,Clone,ParseBin)]
|
||||||
pub struct InodeItem {
|
pub struct InodeItem {
|
||||||
generation: u64,
|
pub generation: u64,
|
||||||
transid: u64,
|
pub transid: u64,
|
||||||
size: u64,
|
pub size: u64,
|
||||||
nbytes: u64,
|
pub nbytes: u64,
|
||||||
block_group: u64,
|
pub block_group: u64,
|
||||||
nlink: u32,
|
pub nlink: u32,
|
||||||
uid: u32,
|
pub uid: u32,
|
||||||
gid: u32,
|
pub gid: u32,
|
||||||
mode: u32,
|
pub mode: u32,
|
||||||
rdev: u64,
|
pub rdev: u64,
|
||||||
flags: u64,
|
pub flags: u64,
|
||||||
sequence: u64,
|
pub sequence: u64,
|
||||||
#[skip_bytes = 32]
|
#[skip_bytes = 32]
|
||||||
atime: Time,
|
pub atime: Time,
|
||||||
ctime: Time,
|
pub ctime: Time,
|
||||||
mtime: Time,
|
pub mtime: Time,
|
||||||
otime: Time,
|
pub otime: Time,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
#[derive(Debug,ParseBin)]
|
#[derive(Debug,Clone,ParseBin)]
|
||||||
pub struct ChunkItem {
|
pub struct ChunkItem {
|
||||||
size: u64,
|
pub size: u64,
|
||||||
root: u64,
|
pub root: u64,
|
||||||
stripelen: u64,
|
pub stripelen: u64,
|
||||||
chunktype: u64,
|
pub chunktype: u64,
|
||||||
align: u32,
|
pub align: u32,
|
||||||
width: u32,
|
pub width: u32,
|
||||||
sectorsize: u32,
|
pub sectorsize: u32,
|
||||||
nrstripes: u16,
|
pub nrstripes: u16,
|
||||||
substripes: u16,
|
pub substripes: u16,
|
||||||
|
|
||||||
// #[vector_length = nrstripes]
|
#[len = "nrstripes"]
|
||||||
// stripes: Vec<ChunkItemStripe>,
|
pub stripes: Vec<ChunkItemStripe>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
#[derive(Debug,ParseBin)]
|
#[derive(Debug,Clone,ParseBin)]
|
||||||
pub struct ChunkItemStripe {
|
pub struct ChunkItemStripe {
|
||||||
devid: u64,
|
pub devid: u64,
|
||||||
offset: u64,
|
pub offset: u64,
|
||||||
devuuid: UUID,
|
pub devuuid: UUID,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
#[derive(Debug,ParseBin)]
|
#[derive(Debug,Clone,ParseBin)]
|
||||||
pub struct RootItem {
|
pub struct RootItem {
|
||||||
inode: InodeItem,
|
pub inode: InodeItem,
|
||||||
generation: u64,
|
pub generation: u64,
|
||||||
root_dirid: u64,
|
pub root_dirid: u64,
|
||||||
bytenr: u64,
|
pub bytenr: u64,
|
||||||
byte_limit: u64,
|
pub byte_limit: u64,
|
||||||
bytes_used: u64,
|
pub bytes_used: u64,
|
||||||
last_snapshot: u64,
|
pub last_snapshot: u64,
|
||||||
flags: u64,
|
pub flags: u64,
|
||||||
refs: u32,
|
pub refs: u32,
|
||||||
drop_progress: Key,
|
pub drop_progress: Key,
|
||||||
drop_level: u8,
|
pub drop_level: u8,
|
||||||
level: u8,
|
pub level: u8,
|
||||||
|
|
||||||
generation_v2: u64,
|
pub generation_v2: u64,
|
||||||
uuid: UUID,
|
pub uuid: UUID,
|
||||||
parent_uuid: UUID,
|
pub parent_uuid: UUID,
|
||||||
received_uuid: UUID,
|
pub received_uuid: UUID,
|
||||||
ctransid: u64,
|
pub ctransid: u64,
|
||||||
otransid: u64,
|
pub otransid: u64,
|
||||||
stransid: u64,
|
pub stransid: u64,
|
||||||
rtransid: u64,
|
pub rtransid: u64,
|
||||||
ctime: Time,
|
pub ctime: Time,
|
||||||
otime: Time,
|
pub otime: Time,
|
||||||
stime: Time,
|
pub stime: Time,
|
||||||
rtime: Time,
|
pub rtime: Time,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
#[derive(Debug,ParseBin)]
|
#[derive(Debug,Clone,ParseBin)]
|
||||||
pub struct DirItem {
|
pub struct DirItem {
|
||||||
location: Key,
|
location: Key,
|
||||||
transid: u64,
|
transid: u64,
|
||||||
@ -227,25 +277,25 @@ pub struct DirItem {
|
|||||||
name_len: u16,
|
name_len: u16,
|
||||||
dir_type: u8,
|
dir_type: u8,
|
||||||
|
|
||||||
#[len = "name_len"]
|
// #[len = "name_len"]
|
||||||
name: CString,
|
name: CString,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
#[derive(Debug,ParseBin)]
|
#[derive(Debug,Clone,ParseBin)]
|
||||||
pub struct FreeSpaceInfoItem {
|
pub struct FreeSpaceInfoItem {
|
||||||
extent_count: u32,
|
extent_count: u32,
|
||||||
flags: u32,
|
flags: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
#[derive(Debug,ParseBin)]
|
#[derive(Debug,Clone,ParseBin)]
|
||||||
pub struct UUIDSubvolItem {
|
pub struct UUIDSubvolItem {
|
||||||
subvol_id: u64,
|
subvol_id: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
#[derive(Debug,ParseBin)]
|
#[derive(Debug,Clone,ParseBin)]
|
||||||
pub struct DevItem {
|
pub struct DevItem {
|
||||||
devid: u64,
|
devid: u64,
|
||||||
total_bytes: u64,
|
total_bytes: u64,
|
||||||
@ -264,7 +314,7 @@ pub struct DevItem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
#[derive(Debug,ParseBin)]
|
#[derive(Debug,Clone,ParseBin)]
|
||||||
pub struct DevExtentItem {
|
pub struct DevExtentItem {
|
||||||
chunk_tree: u64,
|
chunk_tree: u64,
|
||||||
chunk_objectid: u64,
|
chunk_objectid: u64,
|
||||||
@ -274,21 +324,21 @@ pub struct DevExtentItem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
#[derive(Debug)]
|
#[derive(Debug,Clone)]
|
||||||
pub struct ExtentDataItem {
|
pub struct ExtentDataItem {
|
||||||
header: ExtentDataHeader,
|
header: ExtentDataHeader,
|
||||||
data: ExtentDataBody,
|
data: ExtentDataBody,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
#[derive(Debug)]
|
#[derive(Debug,Clone)]
|
||||||
pub enum ExtentDataBody {
|
pub enum ExtentDataBody {
|
||||||
Inline(Vec<u8>),
|
Inline(Vec<u8>),
|
||||||
External(ExternalExtent),
|
External(ExternalExtent),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
#[derive(Debug,ParseBin)]
|
#[derive(Debug,Clone,ParseBin)]
|
||||||
pub struct ExternalExtent {
|
pub struct ExternalExtent {
|
||||||
disk_bytenr: u64,
|
disk_bytenr: u64,
|
||||||
disk_num_bytes: u64,
|
disk_num_bytes: u64,
|
||||||
@ -297,7 +347,7 @@ pub struct ExternalExtent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
#[derive(Debug,ParseBin)]
|
#[derive(Debug,Clone,ParseBin)]
|
||||||
pub struct ExtentDataHeader {
|
pub struct ExtentDataHeader {
|
||||||
generation: u64,
|
generation: u64,
|
||||||
ram_bytes: u64,
|
ram_bytes: u64,
|
||||||
@ -310,6 +360,35 @@ pub struct ExtentDataHeader {
|
|||||||
/***** trait for parsing, and implementations for basic types *****/
|
/***** trait for parsing, and implementations for basic types *****/
|
||||||
// most of the more complex types will be parsed using derive macros
|
// 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 {
|
pub trait ParseBin where Self: Sized {
|
||||||
fn parse_len(bytes: &[u8]) -> Result<(Self, usize), String>;
|
fn parse_len(bytes: &[u8]) -> Result<(Self, usize), String>;
|
||||||
|
|
||||||
@ -454,7 +533,6 @@ impl ParseBin for Leaf {
|
|||||||
Value::DevExtent(DevExtentItem::parse(data_slice)?),
|
Value::DevExtent(DevExtentItem::parse(data_slice)?),
|
||||||
ItemType::ExtentData =>
|
ItemType::ExtentData =>
|
||||||
Value::ExtentData(ExtentDataItem::parse(data_slice)?),
|
Value::ExtentData(ExtentDataItem::parse(data_slice)?),
|
||||||
|
|
||||||
_ =>
|
_ =>
|
||||||
Value::Unknown(Vec::from(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 *****/
|
/***** prettier debug output for UUIDs and checksums *****/
|
||||||
|
|
||||||
@ -520,3 +620,9 @@ impl fmt::Debug for Checksum {
|
|||||||
x24, x25, x26, x27, x28, x29, x30, x31)
|
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 memmap2::Mmap;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
|
use std::io::Error as IOError;
|
||||||
|
use anyhow::Error as AError;
|
||||||
use rouille::Request;
|
use rouille::Request;
|
||||||
use rouille::Response;
|
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];
|
//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 file = File::open("../image")?;
|
||||||
let image = unsafe { Mmap::map(&file)? };
|
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[0x253c000..0x2540000]));
|
||||||
println!("{:#?}", Leaf::parse(&image[0x1d04000..0x1d08000]));
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user