combine crates to workspace
This commit is contained in:
parent
e853f8bc46
commit
bc852d6b6a
16
Cargo.toml
16
Cargo.toml
@ -1,10 +1,8 @@
|
|||||||
[package]
|
[workspace]
|
||||||
name = "parsebtrfs"
|
resolver = "2"
|
||||||
version = "0.1.0"
|
|
||||||
edition = "2021"
|
|
||||||
|
|
||||||
[dependencies]
|
members = [
|
||||||
binparse_derive = { path = "../binparse_derive" }
|
"btrfs_explorer_bin",
|
||||||
maud = "0.26.0"
|
"btrfs_parse_derive",
|
||||||
memmap2 = "0.7.1"
|
"btrfs_explorer",
|
||||||
rouille = "3.6.2"
|
]
|
||||||
|
9
btrfs_explorer/Cargo.toml
Normal file
9
btrfs_explorer/Cargo.toml
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
[package]
|
||||||
|
name = "btrfs_explorer"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
btrfs_parse_derive = { path = "../btrfs_parse_derive" }
|
||||||
|
maud = "0.26.0"
|
||||||
|
rouille = "3.6.2"
|
12
btrfs_explorer_bin/Cargo.toml
Normal file
12
btrfs_explorer_bin/Cargo.toml
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
[package]
|
||||||
|
name = "btrfs_explorer_bin"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
btrfs_explorer = { path = "../btrfs_explorer" }
|
||||||
|
memmap2 = "0.7.1"
|
||||||
|
maud = "0.26.0"
|
||||||
|
rouille = "3.6.2"
|
@ -3,7 +3,7 @@ use std::{
|
|||||||
};
|
};
|
||||||
use memmap2::{Mmap, MmapOptions};
|
use memmap2::{Mmap, MmapOptions};
|
||||||
use rouille::{Request, Response, router};
|
use rouille::{Request, Response, router};
|
||||||
use parsebtrfs::{
|
use btrfs_explorer::{
|
||||||
btrfs_structs::{TreeID, Value::Extent, Value::BlockGroup, NODE_SIZE, ItemType},
|
btrfs_structs::{TreeID, Value::Extent, Value::BlockGroup, NODE_SIZE, ItemType},
|
||||||
btrfs_lookup::Tree,
|
btrfs_lookup::Tree,
|
||||||
addrmap::AddressMap,
|
addrmap::AddressMap,
|
||||||
@ -41,15 +41,15 @@ fn main() -> Result<(), MainError> {
|
|||||||
(GET) ["/"] =>
|
(GET) ["/"] =>
|
||||||
http_main_boxes(&image, request),
|
http_main_boxes(&image, request),
|
||||||
(GET) ["/root"] =>
|
(GET) ["/root"] =>
|
||||||
parsebtrfs::http_tree::http_root(&image, None, request),
|
btrfs_explorer::http_tree::http_root(&image, None, request),
|
||||||
(GET) ["/tree/{tree}", tree: String] =>
|
(GET) ["/tree/{tree}", tree: String] =>
|
||||||
parsebtrfs::http_tree::http_tree(&image, &tree, None, request.get_param("key").as_deref(), request).unwrap(),
|
btrfs_explorer::http_tree::http_tree(&image, &tree, None, request.get_param("key").as_deref(), request).unwrap(),
|
||||||
(GET) ["/tree/{tree}/{key}", tree: String, key: String] =>
|
(GET) ["/tree/{tree}/{key}", tree: String, key: String] =>
|
||||||
parsebtrfs::http_tree::http_tree(&image, &tree, None, Some(&key), request).unwrap(),
|
btrfs_explorer::http_tree::http_tree(&image, &tree, None, Some(&key), request).unwrap(),
|
||||||
(GET) ["/tree/{tree}?key={key}", tree: String, key: String] =>
|
(GET) ["/tree/{tree}?key={key}", tree: String, key: String] =>
|
||||||
parsebtrfs::http_tree::http_tree(&image, &tree, None, Some(&key), request).unwrap(),
|
btrfs_explorer::http_tree::http_tree(&image, &tree, None, Some(&key), request).unwrap(),
|
||||||
(GET) ["/tree/{tree}/{method}/{key}", tree: String, method: String, key: String] =>
|
(GET) ["/tree/{tree}/{method}/{key}", tree: String, method: String, key: String] =>
|
||||||
parsebtrfs::http_tree::http_tree(&image, &tree, Some(&method), Some(&key), request).unwrap(),
|
btrfs_explorer::http_tree::http_tree(&image, &tree, Some(&method), Some(&key), request).unwrap(),
|
||||||
(GET) ["/favicon.ico"] => Response::empty_404(),
|
(GET) ["/favicon.ico"] => Response::empty_404(),
|
||||||
(GET) ["/style.css"] => Response::from_file("text/css", File::open("style.css").unwrap()),
|
(GET) ["/style.css"] => Response::from_file("text/css", File::open("style.css").unwrap()),
|
||||||
(GET) ["/htmx.min.js"] => Response::from_file("text/css", File::open("htmx.min.js").unwrap()),
|
(GET) ["/htmx.min.js"] => Response::from_file("text/css", File::open("htmx.min.js").unwrap()),
|
14
btrfs_parse_derive/Cargo.toml
Normal file
14
btrfs_parse_derive/Cargo.toml
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
[package]
|
||||||
|
name = "btrfs_parse_derive"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
proc-macro2 = "1.0.66"
|
||||||
|
quote = "1.0.32"
|
||||||
|
syn = "2.0.27"
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
proc-macro = true
|
184
btrfs_parse_derive/src/lib.rs
Normal file
184
btrfs_parse_derive/src/lib.rs
Normal file
@ -0,0 +1,184 @@
|
|||||||
|
extern crate proc_macro;
|
||||||
|
extern crate syn;
|
||||||
|
#[macro_use]
|
||||||
|
extern crate quote;
|
||||||
|
extern crate proc_macro2;
|
||||||
|
|
||||||
|
use proc_macro2::Span;
|
||||||
|
use proc_macro::TokenStream;
|
||||||
|
use syn::{DeriveInput, Data::Enum, parse_macro_input};
|
||||||
|
|
||||||
|
#[proc_macro_derive(AllVariants)]
|
||||||
|
pub fn derive_all_variants(input: TokenStream) -> TokenStream {
|
||||||
|
let syn_item: DeriveInput = parse_macro_input!(input);
|
||||||
|
|
||||||
|
let variants = match syn_item.data {
|
||||||
|
Enum(enum_item) => {
|
||||||
|
enum_item.variants.into_iter().map(|v|v.ident)
|
||||||
|
},
|
||||||
|
_ => panic!("AllVariants only works on enums!"),
|
||||||
|
};
|
||||||
|
let enum_name = syn_item.ident;
|
||||||
|
|
||||||
|
let expanded = quote! {
|
||||||
|
impl #enum_name {
|
||||||
|
fn all_variants() -> &'static[#enum_name] {
|
||||||
|
&[ #(#enum_name::#variants),* ]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
expanded.into()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[proc_macro_derive(ParseBin, attributes(skip_bytes, len))]
|
||||||
|
pub fn derive_parse_bin(input: TokenStream) -> TokenStream {
|
||||||
|
let syn_item: DeriveInput = parse_macro_input!(input);
|
||||||
|
let name = syn_item.ident;
|
||||||
|
|
||||||
|
match syn_item.data {
|
||||||
|
syn::Data::Struct(struct_item) => {
|
||||||
|
match struct_item.fields {
|
||||||
|
syn::Fields::Named(fields_named) => {
|
||||||
|
return derive_parse_bin_struct(&name, &fields_named.named);
|
||||||
|
},
|
||||||
|
syn::Fields::Unnamed(fields_unnamed) => {
|
||||||
|
if fields_unnamed.unnamed.len() != 1 {
|
||||||
|
panic!("ParseBin does not support tuple structs!");
|
||||||
|
}
|
||||||
|
|
||||||
|
let inner_type = fields_unnamed.unnamed.into_iter().next().unwrap().ty;
|
||||||
|
return 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 {
|
||||||
|
quote! {
|
||||||
|
impl ParseBin for #name {
|
||||||
|
fn parse_len(bytes: &[u8]) -> Result<(Self, usize), ParseError> {
|
||||||
|
let (result, size) = <#ty>::parse_len(bytes)?;
|
||||||
|
Ok((#name(result), size))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.into()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn derive_parse_bin_struct<'a, T>(name: &syn::Ident, fields: T) -> TokenStream
|
||||||
|
where T: IntoIterator<Item = &'a syn::Field>
|
||||||
|
{
|
||||||
|
let mut parsing_statements = Vec::new();
|
||||||
|
let mut combining_expressions = Vec::new();
|
||||||
|
|
||||||
|
for field in fields {
|
||||||
|
let field_name = field.ident.as_ref().unwrap();
|
||||||
|
let field_type = &field.ty;
|
||||||
|
let mut skip: Option<usize> = None;
|
||||||
|
let mut veclen: Option<String> = None;
|
||||||
|
|
||||||
|
// look for attributes
|
||||||
|
for at in &field.attrs {
|
||||||
|
if let syn::Meta::NameValue(nv) = &at.meta {
|
||||||
|
if nv.path.segments.len() == 1 {
|
||||||
|
let attr_name = nv.path.segments[0].ident.to_string();
|
||||||
|
if attr_name == "skip_bytes" {
|
||||||
|
if let syn::Expr::Lit(expr) = &nv.value {
|
||||||
|
if let syn::Lit::Int(nbytes) = &expr.lit {
|
||||||
|
// println!("reserved = {}", nbytes);
|
||||||
|
skip = nbytes.base10_parse::<usize>().ok()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if attr_name == "len" {
|
||||||
|
if let syn::Expr::Lit(expr) = &nv.value {
|
||||||
|
if let syn::Lit::Str(litstr) = &expr.lit {
|
||||||
|
// println!("len = {}", litstr.value());
|
||||||
|
veclen = Some(litstr.value());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(offset) = skip {
|
||||||
|
parsing_statements.push(quote!{
|
||||||
|
__parse_bin_derive_size += #offset;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
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<_>");
|
||||||
|
|
||||||
|
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));
|
||||||
|
} else {
|
||||||
|
parsing_statements.push(quote!{
|
||||||
|
let #field_name = <#field_type>::parse_len(&bytes[__parse_bin_derive_size..])?;
|
||||||
|
__parse_bin_derive_size += #field_name.1;
|
||||||
|
});
|
||||||
|
|
||||||
|
combining_expressions.push(quote!(#field_name: #field_name.0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
quote! {
|
||||||
|
impl ParseBin for #name {
|
||||||
|
fn parse_len(bytes: &[u8]) -> Result<(Self, usize), ParseError> {
|
||||||
|
let mut __parse_bin_derive_size: usize = 0;
|
||||||
|
|
||||||
|
#(#parsing_statements)*
|
||||||
|
|
||||||
|
let result = #name {
|
||||||
|
#(#combining_expressions),*
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok((result, __parse_bin_derive_size))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.into()
|
||||||
|
}
|
38
style.css
38
style.css
@ -10,9 +10,6 @@ table td {
|
|||||||
padding: 0.1em 0.2em;
|
padding: 0.1em 0.2em;
|
||||||
}
|
}
|
||||||
|
|
||||||
table tr:nth-child(even) {
|
|
||||||
}
|
|
||||||
|
|
||||||
table th {
|
table th {
|
||||||
text-align: left;
|
text-align: left;
|
||||||
border-bottom: 1px solid #ccc;
|
border-bottom: 1px solid #ccc;
|
||||||
@ -42,23 +39,10 @@ table > tbody > tr.fold.open {
|
|||||||
display: table-row;
|
display: table-row;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
table > tbody > tr.view td:first-child:before {
|
|
||||||
color: #999;
|
|
||||||
content: "x";
|
|
||||||
transition: all 0.3s ease;
|
|
||||||
}
|
|
||||||
|
|
||||||
table > tbody > tr.view.open td:first-child:before {
|
|
||||||
transform: rotate(-180deg);
|
|
||||||
color: #333;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
div.nav {
|
div.nav {
|
||||||
padding: 5px;
|
padding: 5px;
|
||||||
background-color: #dde;
|
background-color: #dde;
|
||||||
border-radius: 5px;
|
border-radius: 4px;
|
||||||
margin: 5px 0;
|
margin: 5px 0;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
@ -69,10 +53,10 @@ a.nav {
|
|||||||
}
|
}
|
||||||
|
|
||||||
details.item {
|
details.item {
|
||||||
padding: 5px;
|
padding: 3px;
|
||||||
background-color: #dde;
|
background-color: #dde;
|
||||||
border-radius: 5px;
|
border-radius: 4px;
|
||||||
margin: 5px 0;
|
margin: 3px 0;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -81,15 +65,15 @@ a {
|
|||||||
}
|
}
|
||||||
|
|
||||||
details.highlight {
|
details.highlight {
|
||||||
background-color: #abc;
|
background-color: #bbc;
|
||||||
}
|
}
|
||||||
|
|
||||||
details .details {
|
details .details {
|
||||||
color: white;
|
color: black;
|
||||||
background-color: #222;
|
// background-color: #222;
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
margin-top: 5px;
|
margin-top: 5px;
|
||||||
border-radius: 5px;
|
border-radius: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
details .itemvalue {
|
details .itemvalue {
|
||||||
@ -103,7 +87,7 @@ details .itemvalue {
|
|||||||
details .key {
|
details .key {
|
||||||
color: white;
|
color: white;
|
||||||
background-color: #999;
|
background-color: #999;
|
||||||
border-radius: 5px;
|
border-radius: 4px;
|
||||||
padding: 3px;
|
padding: 3px;
|
||||||
margin: 1px 2px;
|
margin: 1px 2px;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
@ -155,11 +139,11 @@ span.key_type.root {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.details td {
|
.details td {
|
||||||
border: 1px solid white;
|
border: 1px solid black;
|
||||||
}
|
}
|
||||||
|
|
||||||
.details td:first-child {
|
.details td:first-child {
|
||||||
border: 1px solid white;
|
border: 1px solid black;
|
||||||
width: 160px;
|
width: 160px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user