115 lines
3.0 KiB
Rust
115 lines
3.0 KiB
Rust
use std::rc::Rc;
|
|
|
|
use crate::btrfs_structs::{ParseBin, Key, ChunkItem, Value, Superblock, ParseError, NODE_SIZE};
|
|
use crate::btrfs_lookup::Tree;
|
|
use crate::nodereader::NodeReader;
|
|
|
|
#[derive(Debug, Clone)]
|
|
pub struct AddressMap(pub Vec<(u64,u64,Vec<(u64,u64)>)>);
|
|
|
|
// TODO: support for internal nodes, multiple devices?
|
|
impl AddressMap {
|
|
pub fn new(image: &[u8]) -> Result<AddressMap, ParseError> {
|
|
let superblock = Superblock::parse(&image[0x10000..])?;
|
|
let bootstrap_addr = AddressMap::from_superblock(&superblock)?;
|
|
let reader = Rc::new(NodeReader::with_addrmap(image, bootstrap_addr)?);
|
|
|
|
let chunk_tree = Tree {
|
|
image,
|
|
reader,
|
|
root_addr_log: superblock.chunk_root,
|
|
};
|
|
|
|
let mut addr_map = Vec::new();
|
|
|
|
for item in chunk_tree.iter() {
|
|
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()
|
|
));
|
|
}
|
|
}
|
|
|
|
// almost certainly unnecessary?
|
|
addr_map.sort_by_key(|x|x.0);
|
|
|
|
// addr_map.iter().for_each(|x| println!("{:x?}", x));
|
|
|
|
Ok(AddressMap(addr_map))
|
|
}
|
|
|
|
pub fn from_superblock(superblock: &Superblock) -> Result<AddressMap, ParseError> {
|
|
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);
|
|
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
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
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) {
|
|
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)
|
|
}
|
|
}
|
|
*/
|
|
|
|
pub trait LogToPhys {
|
|
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)
|
|
}
|
|
}
|
|
}
|