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)]
|
#[derive(Debug,Clone,Copy,AllVariants,PartialEq,Eq,PartialOrd,Ord)]
|
||||||
#[repr(u8)]
|
#[repr(u8)]
|
||||||
pub enum ItemType {
|
pub enum ItemType {
|
||||||
Invalid = 0x00, // invalid
|
Invalid = 0x00, // invalid, but seems to exist?
|
||||||
Inode = 0x01, // implemented
|
Inode = 0x01, // implemented
|
||||||
Ref = 0x0c, // implemented
|
Ref = 0x0c, // implemented
|
||||||
ExtRef = 0x0d,
|
ExtRef = 0x0d,
|
||||||
XAttr = 0x18,
|
XAttr = 0x18, // TODO
|
||||||
VerityDesc = 0x24,
|
VerityDesc = 0x24,
|
||||||
VerityMerkle = 0x25,
|
VerityMerkle = 0x25,
|
||||||
Orphan = 0x30,
|
Orphan = 0x30,
|
||||||
@ -25,12 +25,12 @@ pub enum ItemType {
|
|||||||
Dir = 0x54, // implemented (better with len feature; allow multiple?)
|
Dir = 0x54, // implemented (better with len feature; allow multiple?)
|
||||||
DirIndex = 0x60, // implemented
|
DirIndex = 0x60, // implemented
|
||||||
ExtentData = 0x6c, // implemented
|
ExtentData = 0x6c, // implemented
|
||||||
ExtentCsum = 0x80,
|
ExtentCsum = 0x80, // TODO
|
||||||
Root = 0x84, // implemented
|
Root = 0x84, // implemented
|
||||||
RootBackRef = 0x90,
|
RootBackRef = 0x90, // implemented
|
||||||
RootRef = 0x9c,
|
RootRef = 0x9c, // implemented
|
||||||
Extent = 0xa8, // implemented (with only one version of extra data)
|
Extent = 0xa8, // implemented (with only one version of extra data!!)
|
||||||
Metadata = 0xa9, // implemented (with only one version of extra data)
|
Metadata = 0xa9, // implemented (with only one version of extra data!!)
|
||||||
TreeBlockRef = 0xb0,
|
TreeBlockRef = 0xb0,
|
||||||
ExtentDataRef = 0xb2,
|
ExtentDataRef = 0xb2,
|
||||||
ExtentRefV0 = 0xb4,
|
ExtentRefV0 = 0xb4,
|
||||||
@ -53,7 +53,7 @@ pub enum ItemType {
|
|||||||
UUIDSubvol = 0xfb, // implemented
|
UUIDSubvol = 0xfb, // implemented
|
||||||
UUIDReceivedSubvol = 0xfc,
|
UUIDReceivedSubvol = 0xfc,
|
||||||
String = 0xfd,
|
String = 0xfd,
|
||||||
InvalidMax = 0xff,
|
InvalidMax = 0xff, // invalid
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
@ -309,6 +309,8 @@ pub struct RootItem {
|
|||||||
pub otime: Time,
|
pub otime: Time,
|
||||||
pub stime: Time,
|
pub stime: Time,
|
||||||
pub rtime: Time,
|
pub rtime: Time,
|
||||||
|
|
||||||
|
data: Vec<u8>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
@ -320,7 +322,7 @@ pub struct DirItem {
|
|||||||
pub name_len: u16,
|
pub name_len: u16,
|
||||||
pub dir_type: u8,
|
pub dir_type: u8,
|
||||||
|
|
||||||
// #[len = "name_len"]
|
#[len = "name_len"]
|
||||||
pub name: CString,
|
pub name: CString,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -406,7 +408,7 @@ pub struct RefItem {
|
|||||||
pub index: u64,
|
pub index: u64,
|
||||||
pub name_len: u16,
|
pub name_len: u16,
|
||||||
|
|
||||||
// #[len = "name_len"]
|
#[len = "name_len"]
|
||||||
pub name: CString,
|
pub name: CString,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -416,6 +418,8 @@ pub struct RootRefItem {
|
|||||||
pub directory: u64,
|
pub directory: u64,
|
||||||
pub index: u64,
|
pub index: u64,
|
||||||
pub name_len: u16,
|
pub name_len: u16,
|
||||||
|
|
||||||
|
#[len = "name_len"]
|
||||||
pub name: CString,
|
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 {
|
impl ParseBin for Node {
|
||||||
fn parse_len(bytes: &[u8]) -> Result<(Node, usize), ParseError> {
|
fn parse_len(bytes: &[u8]) -> Result<(Node, usize), ParseError> {
|
||||||
|
|
||||||
@ -604,45 +616,45 @@ impl ParseBin for Node {
|
|||||||
|
|
||||||
let value = match key.key_type {
|
let value = match key.key_type {
|
||||||
ItemType::BlockGroup =>
|
ItemType::BlockGroup =>
|
||||||
Value::BlockGroup(BlockGroupItem::parse(data_slice)?),
|
Value::BlockGroup(parse_check_size(data_slice)?),
|
||||||
ItemType::Metadata => {
|
ItemType::Metadata => {
|
||||||
let item = ExtentItem::parse(data_slice)?;
|
let item: ExtentItem = parse_check_size(data_slice)?;
|
||||||
if item.flags != 2 || item.refs > 1 {
|
if item.flags != 2 || item.refs > 1 {
|
||||||
println!("Metadata item with refs = {}, flags = {}, data = {:x?}", item.refs, item.flags, &data_slice[0x18..]);
|
println!("Metadata item with refs = {}, flags = {}, data = {:x?}", item.refs, item.flags, &data_slice[0x18..]);
|
||||||
}
|
}
|
||||||
Value::Extent(item)
|
Value::Extent(item)
|
||||||
},
|
},
|
||||||
ItemType::Extent =>
|
ItemType::Extent =>
|
||||||
Value::Extent(ExtentItem::parse(data_slice)?),
|
Value::Extent(parse_check_size(data_slice)?),
|
||||||
ItemType::Inode =>
|
ItemType::Inode =>
|
||||||
Value::Inode(InodeItem::parse(data_slice)?),
|
Value::Inode(parse_check_size(data_slice)?),
|
||||||
ItemType::Root =>
|
ItemType::Root =>
|
||||||
Value::Root(RootItem::parse(data_slice)?),
|
Value::Root(parse_check_size(data_slice)?),
|
||||||
ItemType::Dir =>
|
ItemType::Dir =>
|
||||||
Value::Dir(DirItem::parse(data_slice)?),
|
Value::Dir(parse_check_size(data_slice)?),
|
||||||
ItemType::DirIndex =>
|
ItemType::DirIndex =>
|
||||||
Value::DirIndex(DirItem::parse(data_slice)?),
|
Value::DirIndex(parse_check_size(data_slice)?),
|
||||||
ItemType::Chunk =>
|
ItemType::Chunk =>
|
||||||
Value::Chunk(ChunkItem::parse(data_slice)?),
|
Value::Chunk(parse_check_size(data_slice)?),
|
||||||
ItemType::FreeSpaceInfo =>
|
ItemType::FreeSpaceInfo =>
|
||||||
Value::FreeSpaceInfo(FreeSpaceInfoItem::parse(data_slice)?),
|
Value::FreeSpaceInfo(parse_check_size(data_slice)?),
|
||||||
ItemType::FreeSpaceExtent =>
|
ItemType::FreeSpaceExtent =>
|
||||||
Value::FreeSpaceExtent,
|
Value::FreeSpaceExtent,
|
||||||
ItemType::UUIDSubvol =>
|
ItemType::UUIDSubvol =>
|
||||||
Value::UUIDSubvol(UUIDSubvolItem::parse(data_slice)?),
|
Value::UUIDSubvol(parse_check_size(data_slice)?),
|
||||||
ItemType::Dev =>
|
ItemType::Dev =>
|
||||||
Value::Dev(DevItem::parse(data_slice)?),
|
Value::Dev(parse_check_size(data_slice)?),
|
||||||
ItemType::DevExtent =>
|
ItemType::DevExtent =>
|
||||||
Value::DevExtent(DevExtentItem::parse(data_slice)?),
|
Value::DevExtent(parse_check_size(data_slice)?),
|
||||||
ItemType::ExtentData =>
|
ItemType::ExtentData =>
|
||||||
Value::ExtentData(ExtentDataItem::parse(data_slice)?),
|
Value::ExtentData(parse_check_size(data_slice)?),
|
||||||
ItemType::Ref => {
|
ItemType::Ref => {
|
||||||
Value::Ref(RefItem::parse(data_slice)?)
|
Value::Ref(parse_check_size(data_slice)?)
|
||||||
}
|
}
|
||||||
ItemType::RootRef =>
|
ItemType::RootRef =>
|
||||||
Value::RootRef(RootRefItem::parse(data_slice)?),
|
Value::RootRef(parse_check_size(data_slice)?),
|
||||||
ItemType::RootBackRef =>
|
ItemType::RootBackRef =>
|
||||||
Value::RootRef(RootRefItem::parse(data_slice)?),
|
Value::RootRef(parse_check_size(data_slice)?),
|
||||||
_ =>
|
_ =>
|
||||||
Value::Unknown(Vec::from(data_slice)),
|
Value::Unknown(Vec::from(data_slice)),
|
||||||
};
|
};
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
use crate::btrfs_structs::{Item, Key, ItemType, Value, ExtentDataBody};
|
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};
|
use maud::{Markup, html, DOCTYPE, PreEscaped};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[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 {
|
match &item.value {
|
||||||
Value::Inode(inode_item) => {
|
Value::Inode(inode_item) => {
|
||||||
html! { table { tbody {
|
html! { table { tbody {
|
||||||
@ -222,7 +222,7 @@ fn item_details_string(tree_id: u64, item: &Item) -> Markup {
|
|||||||
},
|
},
|
||||||
Value::ExtentData(extent_item) => {
|
Value::ExtentData(extent_item) => {
|
||||||
match &extent_item.data {
|
match &extent_item.data {
|
||||||
ExtentDataBody::Inline(data) => {
|
ExtentDataBody::Inline(_data) => {
|
||||||
html! {} // we really want data as string / hex
|
html! {} // we really want data as string / hex
|
||||||
},
|
},
|
||||||
ExtentDataBody::External(ext_extent) => {
|
ExtentDataBody::External(ext_extent) => {
|
||||||
@ -255,7 +255,6 @@ fn item_details_string(tree_id: u64, item: &Item) -> Markup {
|
|||||||
}}}
|
}}}
|
||||||
},
|
},
|
||||||
Value::Root(root_item) => {
|
Value::Root(root_item) => {
|
||||||
let inode = &root_item.inode;
|
|
||||||
html! { table { tbody {
|
html! { table { tbody {
|
||||||
tr { td { "root dir id" } td { (format!("{:X}", root_item.root_dirid)) } }
|
tr { td { "root dir id" } td { (format!("{:X}", root_item.root_dirid)) } }
|
||||||
tr { td { "logical address" } td { (format!("{:X}", root_item.bytenr)) } }
|
tr { td { "logical address" } td { (format!("{:X}", root_item.bytenr)) } }
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use std::{
|
use std::{
|
||||||
collections::HashMap, env, fs::{File, OpenOptions}, iter,
|
collections::HashMap, env, fs::{File, OpenOptions}, iter,
|
||||||
};
|
};
|
||||||
use memmap2::{Mmap, MmapOptions};
|
use memmap2::MmapOptions;
|
||||||
use rouille::{Request, Response, router};
|
use rouille::{Request, Response, router};
|
||||||
use btrfs_explorer::{
|
use btrfs_explorer::{
|
||||||
btrfs_structs::{TreeID, Value::Extent, Value::BlockGroup, NODE_SIZE, ItemType},
|
btrfs_structs::{TreeID, Value::Extent, Value::BlockGroup, NODE_SIZE, ItemType},
|
||||||
@ -20,7 +20,6 @@ fn main() -> Result<(), MainError> {
|
|||||||
let image = unsafe { Mmap::map(&file)? };
|
let image = unsafe { Mmap::map(&file)? };
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const O_DIRECT: i32 = 0x4000;
|
|
||||||
let file = OpenOptions::new().read(true).open(filename)?;
|
let file = OpenOptions::new().read(true).open(filename)?;
|
||||||
let image = unsafe { MmapOptions::new().len(493921239040usize).map(&file)? };
|
let image = unsafe { MmapOptions::new().len(493921239040usize).map(&file)? };
|
||||||
|
|
||||||
|
@ -1,9 +1,4 @@
|
|||||||
extern crate proc_macro;
|
use quote::{quote, format_ident};
|
||||||
extern crate syn;
|
|
||||||
#[macro_use]
|
|
||||||
extern crate quote;
|
|
||||||
extern crate proc_macro2;
|
|
||||||
|
|
||||||
use proc_macro2::Span;
|
use proc_macro2::Span;
|
||||||
use proc_macro::TokenStream;
|
use proc_macro::TokenStream;
|
||||||
use syn::{DeriveInput, Data::Enum, parse_macro_input};
|
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) => {
|
syn::Data::Struct(struct_item) => {
|
||||||
match struct_item.fields {
|
match struct_item.fields {
|
||||||
syn::Fields::Named(fields_named) => {
|
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) => {
|
syn::Fields::Unnamed(fields_unnamed) => {
|
||||||
if fields_unnamed.unnamed.len() != 1 {
|
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;
|
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 on unit structs makes no sense!"),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
_ => panic!("ParseBin only works on structs so far!"),
|
_ => panic!("ParseBin only works on structs so far!"),
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn derive_parse_bin_alias(name: syn::Ident, ty: syn::Type) -> TokenStream {
|
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 {
|
if let Some(varname) = veclen {
|
||||||
let field_name_item = format_ident!("{}_item", field_name);
|
let field_name_item = format_ident!("{}_item", field_name);
|
||||||
|
|
||||||
let field_type_item: &syn::Type = match &field_type {
|
enum FieldType<'a> {
|
||||||
syn::Type::Path(tp) => {
|
Vec(&'a syn::Type),
|
||||||
match tp.path.segments.iter().next() {
|
CString,
|
||||||
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,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 {
|
} else {
|
||||||
None
|
panic!("The len attribute is only allowed on Vec<_> or CString")
|
||||||
}
|
};
|
||||||
},
|
|
||||||
None => None,
|
|
||||||
}
|
|
||||||
},
|
|
||||||
_ => None,
|
|
||||||
}.expect("The len attribute is only allowed on type Vec<_>");
|
|
||||||
|
|
||||||
let varname_ident = syn::Ident::new(&varname, Span::call_site());
|
let varname_ident = syn::Ident::new(&varname, Span::call_site());
|
||||||
|
|
||||||
|
|
||||||
|
match field_type {
|
||||||
|
FieldType::Vec(field_type_item) => {
|
||||||
parsing_statements.push(quote!{
|
parsing_statements.push(quote!{
|
||||||
let mut #field_name = Vec::new();
|
let mut #field_name = Vec::new();
|
||||||
for i in 0 .. #varname_ident.0 as usize {
|
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);
|
#field_name.push(#field_name_item.0);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
combining_expressions.push(quote!(#field_name: #field_name));
|
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 {
|
} else {
|
||||||
parsing_statements.push(quote!{
|
parsing_statements.push(quote!{
|
||||||
let #field_name = <#field_type>::parse_len(&bytes[__parse_bin_derive_size..])?;
|
let #field_name = <#field_type>::parse_len(&bytes[__parse_bin_derive_size..])?;
|
||||||
|
Loading…
Reference in New Issue
Block a user