improved error handling

This commit is contained in:
Florian Stecker 2023-08-03 19:38:41 -04:00
parent 5d0ac786b1
commit 4d1e08863a
3 changed files with 25 additions and 22 deletions

View File

@ -1,11 +1,11 @@
use crate::btrfs_structs::{ParseBin, Key, ChunkItem, Leaf, Value, Superblock, LogToPhys}; use crate::btrfs_structs::{ParseBin, Key, ChunkItem, Leaf, Value, Superblock, LogToPhys, ParseError};
#[derive(Debug)] #[derive(Debug)]
pub struct AddressMap(Vec<(u64,u64,Vec<(u64,u64)>)>); pub struct AddressMap(Vec<(u64,u64,Vec<(u64,u64)>)>);
// TODO: support for internal nodes, multiple devices? // TODO: support for internal nodes, multiple devices?
impl AddressMap { impl AddressMap {
pub fn new(image: &[u8]) -> Result<AddressMap,String> { 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)?;
@ -36,7 +36,7 @@ impl AddressMap {
Ok(AddressMap(addr_map)) Ok(AddressMap(addr_map))
} }
pub fn from_superblock(superblock: &Superblock) -> Result<AddressMap,String> { pub fn from_superblock(superblock: &Superblock) -> Result<AddressMap, ParseError> {
let sys_chunk_array_size = superblock.sys_chunk_array_size; let sys_chunk_array_size = superblock.sys_chunk_array_size;
let sys_chunk_array: &[u8] = &superblock.sys_chunk_array; let sys_chunk_array: &[u8] = &superblock.sys_chunk_array;
let mut addr_map = Vec::new(); let mut addr_map = Vec::new();

View File

@ -390,15 +390,15 @@ impl From<ParseError> for io::Error {
} }
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), ParseError>;
fn parse(bytes: &[u8]) -> Result<Self, String> { fn parse(bytes: &[u8]) -> Result<Self, ParseError> {
Self::parse_len(bytes).map(|x|x.0) Self::parse_len(bytes).map(|x|x.0)
} }
} }
impl ParseBin for u8 { impl ParseBin for u8 {
fn parse_len(bytes: &[u8]) -> Result<(Self, usize), String> { fn parse_len(bytes: &[u8]) -> Result<(Self, usize), ParseError> {
if bytes.len() < 1 { if bytes.len() < 1 {
Err("not enough data".into()) Err("not enough data".into())
} else { } else {
@ -408,7 +408,7 @@ impl ParseBin for u8 {
} }
impl ParseBin for u16 { impl ParseBin for u16 {
fn parse_len(bytes: &[u8]) -> Result<(Self, usize), String> { fn parse_len(bytes: &[u8]) -> Result<(Self, usize), ParseError> {
if bytes.len() < 2 { if bytes.len() < 2 {
Err("not enough data".into()) Err("not enough data".into())
} else { } else {
@ -419,7 +419,7 @@ impl ParseBin for u16 {
} }
impl ParseBin for u32 { impl ParseBin for u32 {
fn parse_len(bytes: &[u8]) -> Result<(Self, usize), String> { fn parse_len(bytes: &[u8]) -> Result<(Self, usize), ParseError> {
if bytes.len() < 4 { if bytes.len() < 4 {
Err("not enough data".into()) Err("not enough data".into())
} else { } else {
@ -430,7 +430,7 @@ impl ParseBin for u32 {
} }
impl ParseBin for u64 { impl ParseBin for u64 {
fn parse_len(bytes: &[u8]) -> Result<(Self, usize), String> { fn parse_len(bytes: &[u8]) -> Result<(Self, usize), ParseError> {
if bytes.len() < 8 { if bytes.len() < 8 {
Err("not enough data".into()) Err("not enough data".into())
} else { } else {
@ -441,7 +441,7 @@ impl ParseBin for u64 {
} }
impl<const N: usize> ParseBin for [u8; N] { impl<const N: usize> ParseBin for [u8; N] {
fn parse_len(bytes: &[u8]) -> Result<([u8; N], usize), String> { fn parse_len(bytes: &[u8]) -> Result<([u8; N], usize), ParseError> {
if bytes.len() < N { if bytes.len() < N {
Err("not enough data".into()) Err("not enough data".into())
} else { } else {
@ -452,13 +452,13 @@ impl<const N: usize> ParseBin for [u8; N] {
// we use Vec<u8> for "unknown extra data", so just eat up everything // we use Vec<u8> for "unknown extra data", so just eat up everything
impl ParseBin for Vec<u8> { impl ParseBin for Vec<u8> {
fn parse_len(bytes: &[u8]) -> Result<(Self, usize), String> { fn parse_len(bytes: &[u8]) -> Result<(Self, usize), ParseError> {
Ok((Vec::from(bytes), bytes.len())) Ok((Vec::from(bytes), bytes.len()))
} }
} }
impl ParseBin for CString { impl ParseBin for CString {
fn parse_len(bytes: &[u8]) -> Result<(Self, usize), String> { fn parse_len(bytes: &[u8]) -> Result<(Self, usize), ParseError> {
let mut chars = Vec::from(bytes); let mut chars = Vec::from(bytes);
chars.push(0); chars.push(0);
Ok((CString::from_vec_with_nul(chars).unwrap(), bytes.len())) Ok((CString::from_vec_with_nul(chars).unwrap(), bytes.len()))
@ -484,13 +484,13 @@ impl From<u8> for ItemType {
} }
impl ParseBin for ItemType { impl ParseBin for ItemType {
fn parse_len(bytes: &[u8]) -> Result<(ItemType, usize), String> { fn parse_len(bytes: &[u8]) -> Result<(ItemType, usize), ParseError> {
u8::parse(bytes).map(|x|(ItemType::from(x),1)) u8::parse(bytes).map(|x|(ItemType::from(x),1))
} }
} }
impl ParseBin for Leaf { impl ParseBin for Leaf {
fn parse_len(bytes: &[u8]) -> Result<(Leaf, usize), String> { fn parse_len(bytes: &[u8]) -> Result<(Leaf, usize), ParseError> {
if bytes.len() < 0x65 { if bytes.len() < 0x65 {
return Err("not enough data".into()); return Err("not enough data".into());
} }
@ -551,7 +551,7 @@ impl ParseBin for Leaf {
// ExtentDataItem needs a custom implementation because it can have inline or external data // ExtentDataItem needs a custom implementation because it can have inline or external data
impl ParseBin for ExtentDataItem { impl ParseBin for ExtentDataItem {
fn parse_len(bytes: &[u8]) -> Result<(Self, usize), String> { fn parse_len(bytes: &[u8]) -> Result<(Self, usize), ParseError> {
let (header, header_size) = ExtentDataHeader::parse_len(bytes)?; let (header, header_size) = ExtentDataHeader::parse_len(bytes)?;
if header.extent_type == 1 { // external extent if header.extent_type == 1 { // external extent
let (body, body_size) = ExternalExtent::parse_len(&bytes[header_size..])?; let (body, body_size) = ExternalExtent::parse_len(&bytes[header_size..])?;

View File

@ -21,16 +21,19 @@ 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 addr = AddressMap::new(&image).unwrap();
let superblock = Superblock::parse(&image[0x10000..]).map_err(|e|IOError::other(e))?; let superblock = Superblock::parse(&image[0x10000..]).unwrap();
let chunk_root_phys = addr.to_phys(superblock.chunk_root).unwrap() as usize; let chunk_root_phys = addr.to_phys(superblock.chunk_root)
let root_phys = addr.to_phys(superblock.root).unwrap() as usize; .ok_or(IOError::other("Chunk root address stored in superblock is invalid"))? as usize;
let root_phys = addr.to_phys(superblock.root)
.ok_or(IOError::other("Root address stored in superblock is invalid"))? as usize;
let root_tree_leaf = Leaf::parse(&image[root_phys .. root_phys + NODE_SIZE]).map_err(|e|IOError::other(e))?; let root_tree_leaf = Leaf::parse(&image[root_phys .. root_phys + NODE_SIZE])?;
let root_key = Key::new(EXTENT_TREE, ItemType::Root, 0); let root_key = Key::new(EXTENT_TREE, ItemType::Root, 0);
let root = root_tree_leaf.find_key(root_key).unwrap(); let root = root_tree_leaf.find_key(root_key)
.ok_or(IOError::other("Could not find extent tree in tree of roots"))?;
let root_addr = if let Value::Root(root_item) = root.value { let root_addr = if let Value::Root(root_item) = root.value {
addr.to_phys(root_item.bytenr) addr.to_phys(root_item.bytenr)
@ -38,7 +41,7 @@ fn main() -> Result<(), IOError> {
None None
}.unwrap() as usize; }.unwrap() as usize;
let tree_leaf = Leaf::parse(&image[root_addr .. root_addr + NODE_SIZE]).map_err(|e|IOError::other(e))?; let tree_leaf = Leaf::parse(&image[root_addr .. root_addr + NODE_SIZE])?;
println!("{:#?}", &tree_leaf); println!("{:#?}", &tree_leaf);