check size of items

This commit is contained in:
Florian Stecker 2024-03-01 13:31:34 -05:00
parent bc852d6b6a
commit b41547ddcb
4 changed files with 84 additions and 80 deletions

View File

@ -12,11 +12,11 @@ pub const NODE_SIZE: usize = 0x4000;
#[derive(Debug,Clone,Copy,AllVariants,PartialEq,Eq,PartialOrd,Ord)]
#[repr(u8)]
pub enum ItemType {
Invalid = 0x00, // invalid
Invalid = 0x00, // invalid, but seems to exist?
Inode = 0x01, // implemented
Ref = 0x0c, // implemented
ExtRef = 0x0d,
XAttr = 0x18,
XAttr = 0x18, // TODO
VerityDesc = 0x24,
VerityMerkle = 0x25,
Orphan = 0x30,
@ -25,12 +25,12 @@ pub enum ItemType {
Dir = 0x54, // implemented (better with len feature; allow multiple?)
DirIndex = 0x60, // implemented
ExtentData = 0x6c, // implemented
ExtentCsum = 0x80,
ExtentCsum = 0x80, // TODO
Root = 0x84, // implemented
RootBackRef = 0x90,
RootRef = 0x9c,
Extent = 0xa8, // implemented (with only one version of extra data)
Metadata = 0xa9, // implemented (with only one version of extra data)
RootBackRef = 0x90, // implemented
RootRef = 0x9c, // implemented
Extent = 0xa8, // implemented (with only one version of extra data!!)
Metadata = 0xa9, // implemented (with only one version of extra data!!)
TreeBlockRef = 0xb0,
ExtentDataRef = 0xb2,
ExtentRefV0 = 0xb4,
@ -53,7 +53,7 @@ pub enum ItemType {
UUIDSubvol = 0xfb, // implemented
UUIDReceivedSubvol = 0xfc,
String = 0xfd,
InvalidMax = 0xff,
InvalidMax = 0xff, // invalid
}
#[allow(unused)]
@ -309,6 +309,8 @@ pub struct RootItem {
pub otime: Time,
pub stime: Time,
pub rtime: Time,
data: Vec<u8>,
}
#[allow(unused)]
@ -320,7 +322,7 @@ pub struct DirItem {
pub name_len: u16,
pub dir_type: u8,
// #[len = "name_len"]
#[len = "name_len"]
pub name: CString,
}
@ -406,7 +408,7 @@ pub struct RefItem {
pub index: u64,
pub name_len: u16,
// #[len = "name_len"]
#[len = "name_len"]
pub name: CString,
}
@ -416,6 +418,8 @@ pub struct RootRefItem {
pub directory: u64,
pub index: u64,
pub name_len: u16,
#[len = "name_len"]
pub name: CString,
}
@ -571,6 +575,14 @@ impl ParseBin for ItemType {
}
}
fn parse_check_size<T: ParseBin>(bytes: &[u8]) -> Result<T, ParseError> {
let (result, real_len) = T::parse_len(bytes)?;
if real_len != bytes.len() {
eprintln!("{} parsing incomplete! Parsed {} of {} bytes", std::any::type_name::<T>(), real_len, bytes.len());
}
Ok(result)
}
impl ParseBin for Node {
fn parse_len(bytes: &[u8]) -> Result<(Node, usize), ParseError> {
@ -604,45 +616,45 @@ impl ParseBin for Node {
let value = match key.key_type {
ItemType::BlockGroup =>
Value::BlockGroup(BlockGroupItem::parse(data_slice)?),
Value::BlockGroup(parse_check_size(data_slice)?),
ItemType::Metadata => {
let item = ExtentItem::parse(data_slice)?;
let item: ExtentItem = parse_check_size(data_slice)?;
if item.flags != 2 || item.refs > 1 {
println!("Metadata item with refs = {}, flags = {}, data = {:x?}", item.refs, item.flags, &data_slice[0x18..]);
}
Value::Extent(item)
},
ItemType::Extent =>
Value::Extent(ExtentItem::parse(data_slice)?),
Value::Extent(parse_check_size(data_slice)?),
ItemType::Inode =>
Value::Inode(InodeItem::parse(data_slice)?),
Value::Inode(parse_check_size(data_slice)?),
ItemType::Root =>
Value::Root(RootItem::parse(data_slice)?),
Value::Root(parse_check_size(data_slice)?),
ItemType::Dir =>
Value::Dir(DirItem::parse(data_slice)?),
Value::Dir(parse_check_size(data_slice)?),
ItemType::DirIndex =>
Value::DirIndex(DirItem::parse(data_slice)?),
Value::DirIndex(parse_check_size(data_slice)?),
ItemType::Chunk =>
Value::Chunk(ChunkItem::parse(data_slice)?),
Value::Chunk(parse_check_size(data_slice)?),
ItemType::FreeSpaceInfo =>
Value::FreeSpaceInfo(FreeSpaceInfoItem::parse(data_slice)?),
Value::FreeSpaceInfo(parse_check_size(data_slice)?),
ItemType::FreeSpaceExtent =>
Value::FreeSpaceExtent,
ItemType::UUIDSubvol =>
Value::UUIDSubvol(UUIDSubvolItem::parse(data_slice)?),
Value::UUIDSubvol(parse_check_size(data_slice)?),
ItemType::Dev =>
Value::Dev(DevItem::parse(data_slice)?),
Value::Dev(parse_check_size(data_slice)?),
ItemType::DevExtent =>
Value::DevExtent(DevExtentItem::parse(data_slice)?),
Value::DevExtent(parse_check_size(data_slice)?),
ItemType::ExtentData =>
Value::ExtentData(ExtentDataItem::parse(data_slice)?),
Value::ExtentData(parse_check_size(data_slice)?),
ItemType::Ref => {
Value::Ref(RefItem::parse(data_slice)?)
Value::Ref(parse_check_size(data_slice)?)
}
ItemType::RootRef =>
Value::RootRef(RootRefItem::parse(data_slice)?),
Value::RootRef(parse_check_size(data_slice)?),
ItemType::RootBackRef =>
Value::RootRef(RootRefItem::parse(data_slice)?),
Value::RootRef(parse_check_size(data_slice)?),
_ =>
Value::Unknown(Vec::from(data_slice)),
};

View File

@ -1,5 +1,5 @@
use crate::btrfs_structs::{Item, Key, ItemType, Value, ExtentDataBody};
use crate::render_common::{DebugRender, Hex, size_name};
use crate::render_common::{Hex, size_name};
use maud::{Markup, html, DOCTYPE, PreEscaped};
#[derive(Debug)]
@ -205,7 +205,7 @@ fn item_value_string(tree_id: u64, item: &Item) -> Markup {
}
}
fn item_details_string(tree_id: u64, item: &Item) -> Markup {
fn item_details_string(_tree_id: u64, item: &Item) -> Markup {
match &item.value {
Value::Inode(inode_item) => {
html! { table { tbody {
@ -222,7 +222,7 @@ fn item_details_string(tree_id: u64, item: &Item) -> Markup {
},
Value::ExtentData(extent_item) => {
match &extent_item.data {
ExtentDataBody::Inline(data) => {
ExtentDataBody::Inline(_data) => {
html! {} // we really want data as string / hex
},
ExtentDataBody::External(ext_extent) => {
@ -255,7 +255,6 @@ fn item_details_string(tree_id: u64, item: &Item) -> Markup {
}}}
},
Value::Root(root_item) => {
let inode = &root_item.inode;
html! { table { tbody {
tr { td { "root dir id" } td { (format!("{:X}", root_item.root_dirid)) } }
tr { td { "logical address" } td { (format!("{:X}", root_item.bytenr)) } }

View File

@ -1,7 +1,7 @@
use std::{
collections::HashMap, env, fs::{File, OpenOptions}, iter,
};
use memmap2::{Mmap, MmapOptions};
use memmap2::MmapOptions;
use rouille::{Request, Response, router};
use btrfs_explorer::{
btrfs_structs::{TreeID, Value::Extent, Value::BlockGroup, NODE_SIZE, ItemType},
@ -20,7 +20,6 @@ fn main() -> Result<(), MainError> {
let image = unsafe { Mmap::map(&file)? };
*/
const O_DIRECT: i32 = 0x4000;
let file = OpenOptions::new().read(true).open(filename)?;
let image = unsafe { MmapOptions::new().len(493921239040usize).map(&file)? };

View File

@ -1,9 +1,4 @@
extern crate proc_macro;
extern crate syn;
#[macro_use]
extern crate quote;
extern crate proc_macro2;
use quote::{quote, format_ident};
use proc_macro2::Span;
use proc_macro::TokenStream;
use syn::{DeriveInput, Data::Enum, parse_macro_input};
@ -40,7 +35,7 @@ pub fn derive_parse_bin(input: TokenStream) -> TokenStream {
syn::Data::Struct(struct_item) => {
match struct_item.fields {
syn::Fields::Named(fields_named) => {
return derive_parse_bin_struct(&name, &fields_named.named);
derive_parse_bin_struct(&name, &fields_named.named)
},
syn::Fields::Unnamed(fields_unnamed) => {
if fields_unnamed.unnamed.len() != 1 {
@ -48,13 +43,13 @@ pub fn derive_parse_bin(input: TokenStream) -> TokenStream {
}
let inner_type = fields_unnamed.unnamed.into_iter().next().unwrap().ty;
return derive_parse_bin_alias(name, inner_type);
derive_parse_bin_alias(name, inner_type)
},
_ => panic!("ParseBin on unit structs makes no sense!"),
}
},
_ => panic!("ParseBin only works on structs so far!"),
};
}
}
fn derive_parse_bin_alias(name: syn::Ident, ty: syn::Type) -> TokenStream {
@ -113,49 +108,48 @@ fn derive_parse_bin_struct<'a, T>(name: &syn::Ident, fields: T) -> TokenStream
if let Some(varname) = veclen {
let field_name_item = format_ident!("{}_item", field_name);
let field_type_item: &syn::Type = match &field_type {
syn::Type::Path(tp) => {
match tp.path.segments.iter().next() {
Some(single) => {
if &single.ident.to_string() == "Vec" {
match &single.arguments {
syn::PathArguments::AngleBracketed(args) => {
match args.args.iter().next() {
Some(firstarg) => {
match firstarg {
syn::GenericArgument::Type(ty) => {
Some(ty)
},
_ => None,
}
},
None => None,
}
},
_ => None,
}
} else {
None
}
},
None => None,
}
},
_ => None,
}.expect("The len attribute is only allowed on type Vec<_>");
enum FieldType<'a> {
Vec(&'a syn::Type),
CString,
}
let syn::Type::Path(tp) = &field_type else { panic!() };
let single = tp.path.segments.iter().next().unwrap();
let field_type = if &single.ident.to_string() == "Vec" {
let syn::PathArguments::AngleBracketed(args) = &single.arguments else { panic!() };
let firstarg = args.args.iter().next().unwrap();
let syn::GenericArgument::Type(ty) = firstarg else { panic!() };
FieldType::Vec(ty)
} else if &single.ident.to_string() == "CString" {
FieldType::CString
} else {
panic!("The len attribute is only allowed on Vec<_> or CString")
};
let varname_ident = syn::Ident::new(&varname, Span::call_site());
parsing_statements.push(quote!{
let mut #field_name = Vec::new();
for i in 0 .. #varname_ident.0 as usize {
let #field_name_item = <#field_type_item>::parse_len(&bytes[__parse_bin_derive_size..])?;
__parse_bin_derive_size += #field_name_item.1;
#field_name.push(#field_name_item.0);
}
});
combining_expressions.push(quote!(#field_name: #field_name));
match field_type {
FieldType::Vec(field_type_item) => {
parsing_statements.push(quote!{
let mut #field_name = Vec::new();
for i in 0 .. #varname_ident.0 as usize {
let #field_name_item = <#field_type_item>::parse_len(&bytes[__parse_bin_derive_size..])?;
__parse_bin_derive_size += #field_name_item.1;
#field_name.push(#field_name_item.0);
}
});
combining_expressions.push(quote!(#field_name: #field_name));
},
FieldType::CString => {
parsing_statements.push(quote!{
let #field_name = CString::parse_len(&bytes[__parse_bin_derive_size .. __parse_bin_derive_size + #varname_ident.0 as usize])?;
__parse_bin_derive_size += #varname_ident.0 as usize;
});
combining_expressions.push(quote!(#field_name: #field_name.0));
},
}
} else {
parsing_statements.push(quote!{
let #field_name = <#field_type>::parse_len(&bytes[__parse_bin_derive_size..])?;