initial version
This commit is contained in:
commit
bdcc597b9a
10
Cargo.toml
Normal file
10
Cargo.toml
Normal file
@ -0,0 +1,10 @@
|
||||
[package]
|
||||
name = "parsebtrfs"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
memmap2 = "0.7.1"
|
||||
rouille = "3.6.2"
|
575
src/main.rs
Normal file
575
src/main.rs
Normal file
@ -0,0 +1,575 @@
|
||||
use memmap2::Mmap;
|
||||
use std::fs::File;
|
||||
use rouille::Request;
|
||||
use rouille::Response;
|
||||
|
||||
const ACTIVE_NODES: &'static[usize] = &[0x14000, 0x18000, 0x1c000, 0x20000, 0x28000, 0x2c000, 0x3c000, 0x40000];
|
||||
|
||||
fn main() -> Result<(), std::io::Error> {
|
||||
let file = File::open("../image")?;
|
||||
let image = unsafe { Mmap::map(&file)? };
|
||||
|
||||
let addr = AddressTranslation::new(&image);
|
||||
|
||||
rouille::start_server("127.0.0.1:8080", move |request| {
|
||||
http_main_list(&image, &addr, request)
|
||||
});
|
||||
}
|
||||
|
||||
fn http_main_boxes(image: &[u8], addr: &AddressTranslation, req: &Request) -> Response {
|
||||
let chunk_offset = 0x02500000;
|
||||
let nodes_in_chunk = 2048;
|
||||
let mut result = String::new();
|
||||
|
||||
result.push_str("<body><table style=\"margin: 0 auto;\">\n<tr>\n");
|
||||
|
||||
for i in 0..nodes_in_chunk {
|
||||
if i % 64 == 0 {
|
||||
result.push_str("</tr>\n<tr>\n");
|
||||
}
|
||||
|
||||
let node = read_node(&image, chunk_offset + i*0x4000);
|
||||
|
||||
let active = node.generation > 0 && ACTIVE_NODES.contains(&(i*0x4000));
|
||||
|
||||
let newbox = format!("<td style=\"{}\"></td>\n",
|
||||
if active {
|
||||
"height:10px;width:10px;padding:0;background:black;"
|
||||
} else {
|
||||
"height:10px;width:10px;padding:0;background:lightgray;"
|
||||
});
|
||||
result.push_str(&newbox);
|
||||
}
|
||||
|
||||
result.push_str("</tr>\n</table></body>");
|
||||
|
||||
Response::html(result)
|
||||
}
|
||||
|
||||
fn http_main_list(image: &[u8], addr: &AddressTranslation, req: &Request) -> Response {
|
||||
let chunk_offset = 0x02500000;
|
||||
let nodes_in_chunk = 2048;
|
||||
let mut result = String::new();
|
||||
|
||||
result.push_str("<body>\n");
|
||||
|
||||
for i in 0..nodes_in_chunk {
|
||||
let node = read_node(&image, chunk_offset + i*0x4000);
|
||||
|
||||
let active = ACTIVE_NODES.contains(&(i*0x4000));
|
||||
let style = if active { "color:black;" } else { "color:lightgray;" };
|
||||
|
||||
let newline = format!("<p style=\"{}\">{:x} {} {} {}\n<ul>\n",
|
||||
style,
|
||||
chunk_offset + i*0x4000,
|
||||
node.level,
|
||||
node.items.len(),
|
||||
node.generation);
|
||||
result.push_str(&newline);
|
||||
|
||||
for item in &node.items {
|
||||
let newline = format!("<li style=\"{}\">{:016x} {:?} {:x}</li>\n",
|
||||
style,
|
||||
item.key.key_id,
|
||||
item.key.key_type,
|
||||
item.key.key_offset);
|
||||
result.push_str(&newline);
|
||||
}
|
||||
|
||||
result.push_str("</ul></p>\n");
|
||||
}
|
||||
|
||||
Response::html(result)
|
||||
}
|
||||
|
||||
/**********************************************************************/
|
||||
|
||||
trait FromBytes {
|
||||
fn get(bytes: &[u8], offset: usize) -> Self;
|
||||
}
|
||||
|
||||
impl FromBytes for u8 {
|
||||
fn get(bytes: &[u8], offset: usize) -> u8 {
|
||||
bytes[offset]
|
||||
}
|
||||
}
|
||||
|
||||
impl FromBytes for u16 {
|
||||
fn get(bytes: &[u8], offset: usize) -> u16 {
|
||||
u16::from_le_bytes(bytes[offset..offset+2].try_into().unwrap())
|
||||
}
|
||||
}
|
||||
|
||||
impl FromBytes for u32 {
|
||||
fn get(bytes: &[u8], offset: usize) -> u32 {
|
||||
u32::from_le_bytes(bytes[offset..offset+4].try_into().unwrap())
|
||||
}
|
||||
}
|
||||
|
||||
impl FromBytes for u64 {
|
||||
fn get(bytes: &[u8], offset: usize) -> u64 {
|
||||
u64::from_le_bytes(bytes[offset..offset+8].try_into().unwrap())
|
||||
}
|
||||
}
|
||||
|
||||
impl<const N: usize> FromBytes for [u8; N] {
|
||||
fn get(bytes: &[u8], offset: usize) -> [u8; N] {
|
||||
bytes[offset..offset+N].try_into().unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
impl FromBytes for BtrfsKey {
|
||||
fn get(bytes: &[u8], offset: usize) -> BtrfsKey {
|
||||
BtrfsKey {
|
||||
key_id: FromBytes::get(bytes, offset),
|
||||
key_type: itemtype_from_code(FromBytes::get(bytes, offset+8)),
|
||||
key_offset: FromBytes::get(bytes, offset+9),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FromBytes for BtrfsTime {
|
||||
fn get(bytes: &[u8], offset: usize) -> BtrfsTime {
|
||||
BtrfsTime {
|
||||
sec: FromBytes::get(bytes, offset),
|
||||
nsec: FromBytes::get(bytes, offset+8),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FromBytes for BtrfsBlockGroupItem {
|
||||
fn get(bytes: &[u8], offset: usize) -> BtrfsBlockGroupItem {
|
||||
BtrfsBlockGroupItem {
|
||||
used: FromBytes::get(bytes, 0),
|
||||
chunk_objectid: FromBytes::get(bytes, 8),
|
||||
flags: FromBytes::get(bytes, 16),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FromBytes for BtrfsExtentItem {
|
||||
fn get(bytes: &[u8], offset: usize) -> BtrfsExtentItem {
|
||||
BtrfsExtentItem {
|
||||
refs: FromBytes::get(bytes, 0),
|
||||
generation: FromBytes::get(bytes, 8),
|
||||
flags: FromBytes::get(bytes, 16),
|
||||
data: Vec::from(&bytes[24..]),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FromBytes for BtrfsChunkItem {
|
||||
fn get(bytes: &[u8], offset: usize) -> BtrfsChunkItem {
|
||||
let data_slice = &bytes[offset..];
|
||||
let nrstripes: u16 = FromBytes::get(data_slice, 0x2c);
|
||||
let mut stripes: Vec<BtrfsChunkItemStripe> = Vec::new();
|
||||
|
||||
for i in 0..nrstripes as usize {
|
||||
stripes.push(BtrfsChunkItemStripe {
|
||||
devid: FromBytes::get(data_slice, 0x30 + i*0x20),
|
||||
offset: FromBytes::get(data_slice, 0x38 + i*0x20),
|
||||
devuuid: FromBytes::get(data_slice, 0x40 + i*0x20),
|
||||
});
|
||||
}
|
||||
|
||||
BtrfsChunkItem {
|
||||
size: FromBytes::get(data_slice, 0x00),
|
||||
root: FromBytes::get(data_slice, 0x08),
|
||||
stripelen: FromBytes::get(data_slice, 0x10),
|
||||
chunktype: FromBytes::get(data_slice, 0x18),
|
||||
align: FromBytes::get(data_slice, 0x20),
|
||||
width: FromBytes::get(data_slice, 0x24),
|
||||
sectorsize: FromBytes::get(data_slice, 0x28),
|
||||
nrstripes: FromBytes::get(data_slice, 0x2c),
|
||||
substripes: FromBytes::get(data_slice, 0x2e),
|
||||
stripes: stripes,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FromBytes for BtrfsInodeItem {
|
||||
fn get(bytes: &[u8], offset: usize) -> BtrfsInodeItem {
|
||||
let data_slice = &bytes[offset..];
|
||||
BtrfsInodeItem {
|
||||
generation: FromBytes::get(data_slice, 0x00),
|
||||
transid: FromBytes::get(data_slice, 0x08),
|
||||
size: FromBytes::get(data_slice, 0x10),
|
||||
nbytes: FromBytes::get(data_slice, 0x18),
|
||||
block_group: FromBytes::get(data_slice, 0x20),
|
||||
nlink: FromBytes::get(data_slice, 0x28),
|
||||
uid: FromBytes::get(data_slice, 0x2c),
|
||||
gid: FromBytes::get(data_slice, 0x30),
|
||||
mode: FromBytes::get(data_slice, 0x34),
|
||||
rdev: FromBytes::get(data_slice, 0x38),
|
||||
flags: FromBytes::get(data_slice, 0x40),
|
||||
sequence: FromBytes::get(data_slice, 0x48),
|
||||
atime: FromBytes::get(data_slice, 0x54),
|
||||
ctime: FromBytes::get(data_slice, 0x60),
|
||||
mtime: FromBytes::get(data_slice, 0x6c),
|
||||
otime: FromBytes::get(data_slice, 0x78),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FromBytes for BtrfsRootItem {
|
||||
fn get(bytes: &[u8], offset: usize) -> BtrfsRootItem {
|
||||
let data_slice = &bytes[offset..];
|
||||
BtrfsRootItem {
|
||||
inode: FromBytes::get(data_slice, 0x00),
|
||||
generation: FromBytes::get(data_slice, 0xa0),
|
||||
root_dirid: FromBytes::get(data_slice, 0xa8),
|
||||
bytenr: FromBytes::get(data_slice, 0xb0),
|
||||
byte_limit: FromBytes::get(data_slice, 0xb9),
|
||||
bytes_used: FromBytes::get(data_slice, 0xc0),
|
||||
last_snapshot: FromBytes::get(data_slice, 0xc8),
|
||||
flags: FromBytes::get(data_slice, 0xd0),
|
||||
refs: FromBytes::get(data_slice, 0xd8),
|
||||
drop_progress: FromBytes::get(data_slice, 0xdc),
|
||||
drop_level: FromBytes::get(data_slice, 0xed),
|
||||
level: FromBytes::get(data_slice, 0xee),
|
||||
|
||||
/*
|
||||
generation_v2: FromBytes::get(data_slice, 0xd3),
|
||||
uuid: FromBytes::get(data_slice, 0xeb),
|
||||
parent_uuid: FromBytes::get(data_slice, 0xfb),
|
||||
received_uuid: FromBytes::get(data_slice, 0x10b),
|
||||
ctransid: FromBytes::get(data_slice, 0x11b),
|
||||
otransid: FromBytes::get(data_slice, 0x123),
|
||||
stransid: FromBytes::get(data_slice, 0x12b),
|
||||
rtransid: FromBytes::get(data_slice, 0x133),
|
||||
ctime: FromBytes::get(data_slice, 0x13b),
|
||||
otime: FromBytes::get(data_slice, 0x147),
|
||||
stime: FromBytes::get(data_slice, 0x153),
|
||||
rtime: FromBytes::get(data_slice, 0x15f),
|
||||
*/
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fn read_node_log(image: &[u8], trans: &AddressTranslation, log: u64) -> Option<Box<BtrfsNode>> {
|
||||
let phys = trans.to_phys(log)?;
|
||||
Some(read_node(image, phys as usize))
|
||||
}
|
||||
|
||||
fn read_node(image: &[u8], offset: usize) -> Box<BtrfsNode> {
|
||||
let mut result = Box::new(BtrfsNode {
|
||||
csum: FromBytes::get(image, offset),
|
||||
fs_uid: FromBytes::get(image, offset + 0x20),
|
||||
bytenr: FromBytes::get(image, offset + 0x30),
|
||||
flags: FromBytes::get(image, offset + 0x38),
|
||||
chunk_tree_uid: FromBytes::get(image, offset + 0x40),
|
||||
generation: FromBytes::get(image, offset + 0x50),
|
||||
owner: FromBytes::get(image, offset + 0x58),
|
||||
nritems: FromBytes::get(image, offset + 0x60),
|
||||
level: FromBytes::get(image, offset + 0x64),
|
||||
items: Vec::new(),
|
||||
});
|
||||
|
||||
// assuming leaf for now
|
||||
|
||||
for i in 0..result.nritems as usize {
|
||||
let key_id: u64 = FromBytes::get(image, offset + 0x65 + i*0x19);
|
||||
let key_type_code: u8 = FromBytes::get(image, offset + 0x65 + i*0x19 + 0x08);
|
||||
let key_offset: u64 = FromBytes::get(image, offset + 0x65 + i*0x19 + 0x09);
|
||||
let data_offset: u32 = FromBytes::get(image, offset + 0x65 + i*0x19 + 0x11);
|
||||
let data_size: u32 = FromBytes::get(image, offset + 0x65 + i*0x19 + 0x15);
|
||||
|
||||
let key_type = itemtype_from_code(key_type_code);
|
||||
let data_slice = &image[(offset + 0x65 + data_offset as usize) .. (offset + 0x65 + data_offset as usize + data_size as usize)];
|
||||
|
||||
let value = match key_type {
|
||||
BtrfsItemType::BlockGroup => BtrfsValue::BlockGroup(FromBytes::get(data_slice, 0)),
|
||||
BtrfsItemType::Metadata => BtrfsValue::Extent(FromBytes::get(data_slice, 0)),
|
||||
BtrfsItemType::Chunk => BtrfsValue::Chunk(FromBytes::get(data_slice, 0)),
|
||||
BtrfsItemType::Root => BtrfsValue::Root(FromBytes::get(data_slice, 0)),
|
||||
_ => BtrfsValue::Unknown(Vec::from(data_slice)),
|
||||
};
|
||||
|
||||
result.items.push(BtrfsItem {
|
||||
key: BtrfsKey {
|
||||
key_id: key_id,
|
||||
key_type: key_type,
|
||||
key_offset: key_offset,
|
||||
},
|
||||
value: value,
|
||||
});
|
||||
}
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
fn itemtype_from_code(code: u8) -> BtrfsItemType {
|
||||
match BTRFS_ITEM_TYPE_VALUES.binary_search_by_key(&code, |x|*x as u8) {
|
||||
Ok(i) => BTRFS_ITEM_TYPE_VALUES[i],
|
||||
Err(_) => { panic!("expected BtrfsItemType, found {code}"); }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug,Clone,Copy)]
|
||||
#[repr(u8)]
|
||||
enum BtrfsItemType {
|
||||
Invalid = 0x00,
|
||||
Inode = 0x01,
|
||||
Ref = 0x0c,
|
||||
ExtRef = 0x0d,
|
||||
XAttr = 0x18,
|
||||
VerityDesc = 0x24,
|
||||
VerityMerkle = 0x25,
|
||||
Orphan = 0x30,
|
||||
DirLog = 0x3c,
|
||||
DirLogIndex = 0x48,
|
||||
Dir = 0x54,
|
||||
DirIndex = 0x60,
|
||||
ExtentData = 0x6c,
|
||||
ExtentCsum = 0x80,
|
||||
Root = 0x84,
|
||||
RootBackref = 0x90,
|
||||
RootRef = 0x9c,
|
||||
Extent = 0xa8,
|
||||
Metadata = 0xa9,
|
||||
TreeBlockRef = 0xb0,
|
||||
ExtentDataRef = 0xb2,
|
||||
ExtentRefV0 = 0xb4,
|
||||
SharedBlockRef = 0xb6,
|
||||
SharedDataRef = 0xb8,
|
||||
BlockGroup = 0xc0,
|
||||
FreeSpaceInfo = 0xc6,
|
||||
FreeSpaceExtent = 0xc7,
|
||||
FreeSpaceBitmap = 0xc8,
|
||||
DevExtent = 0xcc,
|
||||
Dev = 0xd8,
|
||||
Chunk = 0xe4,
|
||||
QGroupStatus = 0xf0,
|
||||
QGroupInfo = 0xf2,
|
||||
QGroupLimit = 0xf4,
|
||||
QGroupRelation = 0xf6,
|
||||
Temporary = 0xf8,
|
||||
Persistent = 0xf9,
|
||||
DevReplace = 0xfa,
|
||||
UUIDSubvol = 0xfb,
|
||||
UUIDReceivedSubvol = 0xfc,
|
||||
String = 0xfd,
|
||||
}
|
||||
|
||||
const BTRFS_ITEM_TYPE_VALUES: &[BtrfsItemType] = &[BtrfsItemType::Invalid, BtrfsItemType::Inode, BtrfsItemType::Ref, BtrfsItemType::ExtRef, BtrfsItemType::XAttr, BtrfsItemType::VerityDesc, BtrfsItemType::VerityMerkle, BtrfsItemType::Orphan, BtrfsItemType::DirLog, BtrfsItemType::DirLogIndex, BtrfsItemType::Dir, BtrfsItemType::DirIndex, BtrfsItemType::ExtentData, BtrfsItemType::ExtentCsum, BtrfsItemType::Root, BtrfsItemType::RootBackref, BtrfsItemType::RootRef, BtrfsItemType::Extent, BtrfsItemType::Metadata, BtrfsItemType::TreeBlockRef, BtrfsItemType::ExtentDataRef, BtrfsItemType::ExtentRefV0, BtrfsItemType::SharedBlockRef, BtrfsItemType::SharedDataRef, BtrfsItemType::BlockGroup, BtrfsItemType::FreeSpaceInfo, BtrfsItemType::FreeSpaceExtent, BtrfsItemType::FreeSpaceBitmap, BtrfsItemType::DevExtent, BtrfsItemType::Dev, BtrfsItemType::Chunk, BtrfsItemType::QGroupStatus, BtrfsItemType::QGroupInfo, BtrfsItemType::QGroupLimit, BtrfsItemType::QGroupRelation, BtrfsItemType::Temporary, BtrfsItemType::Persistent, BtrfsItemType::DevReplace, BtrfsItemType::UUIDSubvol, BtrfsItemType::UUIDReceivedSubvol, BtrfsItemType::String];
|
||||
|
||||
#[derive(Debug)]
|
||||
struct BtrfsNode {
|
||||
csum: [u8; 32],
|
||||
fs_uid: BtrfsUUID,
|
||||
bytenr: u64,
|
||||
flags: u64,
|
||||
chunk_tree_uid: BtrfsUUID,
|
||||
generation: u64,
|
||||
owner: u64,
|
||||
nritems: u32,
|
||||
level: u8,
|
||||
|
||||
items: Vec<BtrfsItem>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct BtrfsItem {
|
||||
key: BtrfsKey,
|
||||
value: BtrfsValue,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct BtrfsKey {
|
||||
key_id: u64,
|
||||
key_type: BtrfsItemType,
|
||||
key_offset: u64,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
enum BtrfsValue {
|
||||
NodePtr(u64),
|
||||
Extent(BtrfsExtentItem),
|
||||
BlockGroup(BtrfsBlockGroupItem),
|
||||
Chunk(BtrfsChunkItem),
|
||||
Root(BtrfsRootItem),
|
||||
Unknown(Vec<u8>),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct BtrfsExtentItem {
|
||||
refs: u64,
|
||||
generation: u64,
|
||||
flags: u64,
|
||||
data: Vec<u8>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct BtrfsBlockGroupItem {
|
||||
used: u64,
|
||||
chunk_objectid: u64,
|
||||
flags: u64,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct BtrfsDevItem {
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct BtrfsChunkItem {
|
||||
size: u64,
|
||||
root: u64,
|
||||
stripelen: u64,
|
||||
chunktype: u64,
|
||||
align: u32,
|
||||
width: u32,
|
||||
sectorsize: u32,
|
||||
nrstripes: u16,
|
||||
substripes: u16,
|
||||
|
||||
stripes: Vec<BtrfsChunkItemStripe>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct BtrfsChunkItemStripe {
|
||||
devid: u64,
|
||||
offset: u64,
|
||||
devuuid: BtrfsUUID,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct BtrfsTime {
|
||||
sec: u64,
|
||||
nsec: u32,
|
||||
}
|
||||
|
||||
type BtrfsUUID = [u8; 16];
|
||||
|
||||
#[derive(Debug)]
|
||||
struct BtrfsInodeItem {
|
||||
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,
|
||||
atime: BtrfsTime,
|
||||
ctime: BtrfsTime,
|
||||
mtime: BtrfsTime,
|
||||
otime: BtrfsTime,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct BtrfsRootItem {
|
||||
inode: BtrfsInodeItem,
|
||||
generation: u64,
|
||||
root_dirid: u64,
|
||||
bytenr: u64,
|
||||
byte_limit: u64,
|
||||
bytes_used: u64,
|
||||
last_snapshot: u64,
|
||||
flags: u64,
|
||||
refs: u32,
|
||||
drop_progress: BtrfsKey,
|
||||
drop_level: u8,
|
||||
level: u8,
|
||||
|
||||
/*
|
||||
generation_v2: u64,
|
||||
uuid: BtrfsUUID,
|
||||
parent_uuid: BtrfsUUID,
|
||||
received_uuid: BtrfsUUID,
|
||||
ctransid: u64,
|
||||
otransid: u64,
|
||||
stransid: u64,
|
||||
rtransid: u64,
|
||||
ctime: BtrfsTime,
|
||||
otime: BtrfsTime,
|
||||
stime: BtrfsTime,
|
||||
rtime: BtrfsTime,
|
||||
*/
|
||||
}
|
||||
|
||||
struct AddressTranslation {
|
||||
addr_map: Vec<(u64,u64,Vec<(u64,u64)>)>,
|
||||
}
|
||||
|
||||
// TODO: support for internal nodes, multiple devices?
|
||||
impl AddressTranslation {
|
||||
fn new(image: &[u8]) -> AddressTranslation {
|
||||
let bootstrap_addr = AddressTranslation::from_superblock(&image);
|
||||
|
||||
let chunk_root_log: u64 = FromBytes::get(&image, 0x10058);
|
||||
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 = read_node(&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 BtrfsValue::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);
|
||||
AddressTranslation { addr_map }
|
||||
}
|
||||
|
||||
fn from_superblock(image: &[u8]) -> AddressTranslation {
|
||||
let sys_chunk_array_size: u32 = FromBytes::get(&image, 0x100a0);
|
||||
let mut addr_map = Vec::new();
|
||||
let mut len: usize = 0;
|
||||
|
||||
while len < sys_chunk_array_size as usize {
|
||||
let chunk_key: BtrfsKey = FromBytes::get(&image, 0x1032b + len);
|
||||
let chunk_value: BtrfsChunkItem = FromBytes::get(&image, 0x1033c + len);
|
||||
|
||||
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);
|
||||
AddressTranslation { addr_map }
|
||||
}
|
||||
|
||||
fn to_phys(&self, log: u64) -> Option<u64> {
|
||||
let index = match self.addr_map.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.addr_map[index].0;
|
||||
let size = self.addr_map[index].1;
|
||||
let phys_offset = self.addr_map[index].2[0].1;
|
||||
|
||||
if log >= log_offset && log < log_offset + size {
|
||||
Some(phys_offset + (log - log_offset))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user