check size of items
This commit is contained in:
parent
bc852d6b6a
commit
b41547ddcb
@ -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)),
|
||||
};
|
||||
|
@ -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)) } }
|
||||
|
@ -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)? };
|
||||
|
||||
|
@ -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,39 +108,30 @@ 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,
|
||||
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 {
|
||||
None
|
||||
}
|
||||
},
|
||||
None => None,
|
||||
}
|
||||
},
|
||||
_ => None,
|
||||
}.expect("The len attribute is only allowed on type Vec<_>");
|
||||
panic!("The len attribute is only allowed on Vec<_> or CString")
|
||||
};
|
||||
|
||||
let varname_ident = syn::Ident::new(&varname, Span::call_site());
|
||||
|
||||
|
||||
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 {
|
||||
@ -154,8 +140,16 @@ fn derive_parse_bin_struct<'a, T>(name: &syn::Ident, fields: T) -> TokenStream
|
||||
#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..])?;
|
||||
|
Loading…
Reference in New Issue
Block a user