From 61d7680af84c0477e58a0fcac53fc4f660abe846 Mon Sep 17 00:00:00 2001 From: Florian Stecker Date: Wed, 22 May 2024 16:05:26 -0400 Subject: [PATCH] explanations and arguments --- btrfs_explorer/src/http_chunk.rs | 6 +- btrfs_explorer/src/render_common.rs | 15 ++++- btrfs_explorer/src/render_tree.rs | 55 ++++++++++++++----- btrfs_explorer_bin/src/main.rs | 30 ++++++---- style.css => btrfs_explorer_bin/src/style.css | 42 ++------------ 5 files changed, 80 insertions(+), 68 deletions(-) rename style.css => btrfs_explorer_bin/src/style.css (80%) diff --git a/btrfs_explorer/src/http_chunk.rs b/btrfs_explorer/src/http_chunk.rs index 0859f39..f0d342b 100644 --- a/btrfs_explorer/src/http_chunk.rs +++ b/btrfs_explorer/src/http_chunk.rs @@ -193,7 +193,7 @@ fn render_chunk(data: ChunkResult) -> Markup { } }; - render_page("", content) + render_page(&header, content) } fn render_allchunks(data: Vec) -> Markup { @@ -231,7 +231,7 @@ fn render_allchunks(data: Vec) -> Markup { } }; - render_page("", content) + render_page("Physical disk layout", content) } fn explanation_allchunks() -> Markup { @@ -274,7 +274,7 @@ fn explanation_chunk() -> Markup { p { "The colors indicate which B-tree the node belongs to. Most of them belong to the filesystem trees. There is one filesystem tree for every subvolume, but we draw them all in the same color here. The other trees are:" } - table { + table.legend { tr { td { table.blocks { tr { td style="background: darkgreen;" {} } } } td { "root tree" } diff --git a/btrfs_explorer/src/render_common.rs b/btrfs_explorer/src/render_common.rs index 53e60c4..d435617 100644 --- a/btrfs_explorer/src/render_common.rs +++ b/btrfs_explorer/src/render_common.rs @@ -1,7 +1,6 @@ use maud::{html, DOCTYPE, Markup, Render}; use std::fmt::{Debug, UpperHex}; - -pub const HTTP_PATH: &str = ""; +use std::sync::OnceLock; pub struct DebugRender(pub T); @@ -43,7 +42,7 @@ pub fn render_page(title: &str, content: Markup) -> Markup { html! { (DOCTYPE) head { - link rel="stylesheet" href={(HTTP_PATH) "/style.css"}; + link rel="stylesheet" href={(http_path()) "/style.css"}; title { (title) } @@ -53,3 +52,13 @@ pub fn render_page(title: &str, content: Markup) -> Markup { } } } + +static HTTP_PATH: OnceLock = OnceLock::new(); + +pub fn http_path() -> &'static str { + HTTP_PATH.get().expect("HTTP_PATH should have been initialized before usage.") +} + +pub fn http_path_set(path: String) { + HTTP_PATH.set(path).expect("HTTP_PATH can only be set once."); +} diff --git a/btrfs_explorer/src/render_tree.rs b/btrfs_explorer/src/render_tree.rs index c0d65d0..18b88ea 100644 --- a/btrfs_explorer/src/render_tree.rs +++ b/btrfs_explorer/src/render_tree.rs @@ -1,5 +1,5 @@ use crate::btrfs_structs::{Item, Key, ItemType, Value, ExtentDataBody}; -use crate::render_common::{Hex, size_name, HTTP_PATH}; +use crate::render_common::{Hex, size_name, http_path}; use maud::{Markup, html, DOCTYPE, PreEscaped}; use std::ffi::CStr; @@ -14,7 +14,6 @@ pub struct TableResult<'a> { } pub fn render_table(table: TableResult) -> Markup { - let header = if let Some(desc) = table.tree_desc { format!("Tree {} ({})", table.tree_id, desc) } else { @@ -23,19 +22,22 @@ pub fn render_table(table: TableResult) -> Markup { let key_input_value = table.key_id.map_or(String::new(), |x| format!("{:X}", x)); - let first_key_url = format!("{HTTP_PATH}/tree/{}", - table.tree_id); - let prev_key_url = format!("{HTTP_PATH}/tree/{}/to/{:016X}-{:02X}-{:016X}", + let first_key_url = format!("{}/tree/{}", + http_path(), table.tree_id); + let prev_key_url = format!("{}/tree/{}/to/{:016X}-{:02X}-{:016X}", + http_path(), table.tree_id, table.first_key.key_id, u8::from(table.first_key.key_type), table.first_key.key_offset); - let next_key_url = format!("{HTTP_PATH}/tree/{}/from/{:016X}-{:02X}-{:016X}", + let next_key_url = format!("{}/tree/{}/from/{:016X}-{:02X}-{:016X}", + http_path(), table.tree_id, table.last_key.key_id, u8::from(table.last_key.key_type), table.first_key.key_offset); - let last_key_url = format!("{HTTP_PATH}/tree/{}/to/{:016X}-{:02X}-{:016X}", + let last_key_url = format!("{}/tree/{}/to/{:016X}-{:02X}-{:016X}", + http_path(), table.tree_id, u64::wrapping_sub(0,1), u8::wrapping_sub(0,1), @@ -100,20 +102,25 @@ pub fn render_table(table: TableResult) -> Markup { html! { (DOCTYPE) head { - link rel="stylesheet" href={(HTTP_PATH) "/style.css"}; + link rel="stylesheet" href={(http_path()) "/style.css"}; } body { h1 { (header) } + details { + summary { "Explanation" } + (explanation_tree()) + } + @if table.tree_id != 1 { - a href={(HTTP_PATH) "/tree/1"} { + a href={(http_path()) "/tree/1"} { "go back to root tree" } } - form method="get" action={(HTTP_PATH) "/tree/" (table.tree_id)} { + form method="get" action={(http_path()) "/tree/" (table.tree_id)} { input type="text" name="key" value=(key_input_value); input type="submit" value="Search"; } @@ -129,6 +136,26 @@ pub fn render_table(table: TableResult) -> Markup { } } +fn explanation_tree() -> Markup { + html! { + p { + "This page shows the content of a tree. It is essentially a list of items, each of which consist of a key and a value." + } + + p { + "The key is shown in the boxes on the left. It is a triple of a 64-bit id, an 8-bit type, and a 64-bit offset. What each of them means depends on the tree we're in. You can search for a key id by using the search field below." + } + + p { + "The value is summarized to the right of the key. To see the value in more detail, unfold the key by clicking on it." + } + + p { + "Finally, to the very right, we have the logical address of the metadata node which the item is stored in." + } + } +} + fn key_type_class(key: Key) -> &'static str { match key.key_type { ItemType::Inode => "inode", @@ -147,7 +174,7 @@ fn row_id_desc(key: Key, tree_id: u64) -> (Markup, Markup, Markup) { let x = format!("{:X}", key.key_id); let y = format!("{:?} ({:02X})", key.key_type, u8::from(key.key_type)); let z = if key.key_type == ItemType::RootRef || key.key_type == ItemType::Ref { - format!("{:X}", tree_id, key.key_offset, key.key_offset) + format!("{:X}", http_path(), tree_id, key.key_offset, key.key_offset) } else { format!("{:X}", key.key_offset) }; @@ -157,7 +184,7 @@ fn row_id_desc(key: Key, tree_id: u64) -> (Markup, Markup, Markup) { fn item_value_string(tree_id: u64, item: &Item) -> Markup { match &item.value { Value::Root(_) => { - html! { a href={(HTTP_PATH) "/tree/" (item.key.key_id)} { "go to tree " (item.key.key_id) } } + html! { a href={(http_path()) "/tree/" (item.key.key_id)} { "go to tree " (item.key.key_id) } } }, Value::Dir(dir_item) | Value::DirIndex(dir_item) => { let name = format!("{:?}", &dir_item.name); @@ -166,12 +193,12 @@ fn item_value_string(tree_id: u64, item: &Item) -> Markup { (name) " @ " @if dir_item.location.key_type == ItemType::Root { - a href=(format!("{HTTP_PATH}/tree/{id}")) { + a href=(format!("{}/tree/{id}", http_path())) { "subvolume " (Hex(id)) } } @else { - a href=(format!("{HTTP_PATH}/tree/{tree_id}/{id:x}")) { + a href=(format!("{}/tree/{tree_id}/{id:x}", http_path())) { (Hex(id)) } } diff --git a/btrfs_explorer_bin/src/main.rs b/btrfs_explorer_bin/src/main.rs index 24df14a..9a5dd02 100644 --- a/btrfs_explorer_bin/src/main.rs +++ b/btrfs_explorer_bin/src/main.rs @@ -1,22 +1,32 @@ use std::{ - env, fs::{File, OpenOptions}, + env, fs::OpenOptions, ops::Deref, include_str, }; use memmap2::MmapOptions; use rouille::{Response, router}; use btrfs_explorer::main_error::MainError; +use btrfs_explorer::render_common::http_path_set; + +const CSS_FILE: &'static str = include_str!("style.css"); fn main() -> Result<(), MainError> { - let filename = env::args().skip(1).next().ok_or("Argument required")?; + let args: Vec = env::args().collect(); - /* - let file = OpenOptions::new().read(true).open(filename)?; - let image = unsafe { Mmap::map(&file)? }; - */ + if args.len() < 2 { + return Err("Argument required".into()); + } + + let filename: &str = args[1].as_ref(); + let sockaddr: &str = args.get(2) + .map_or("localhost:8080", ::deref); + let http_path: String = args.get(3) + .map_or(String::new(), ::to_owned); + http_path_set(http_path); 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)? }; + let image = unsafe { MmapOptions::new().map(&file)? }; - rouille::start_server("127.0.0.1:8080", move |request| { + rouille::start_server(sockaddr, move |request| { router!( request, (GET) ["/"] => @@ -34,8 +44,8 @@ fn main() -> Result<(), MainError> { (GET) ["/tree/{tree}/{method}/{key}", tree: String, method: String, key: String] => btrfs_explorer::http_tree::http_tree(&image, &tree, Some(&method), Some(&key), request).unwrap(), (GET) ["/favicon.ico"] => Response::empty_404(), - (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) ["/style.css"] => Response::from_data("text/css", CSS_FILE),// 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()), _ => Response::empty_404(), ) }); diff --git a/style.css b/btrfs_explorer_bin/src/style.css similarity index 80% rename from style.css rename to btrfs_explorer_bin/src/style.css index e933d8c..00b6486 100644 --- a/style.css +++ b/btrfs_explorer_bin/src/style.css @@ -2,43 +2,6 @@ body { padding: 0.2em 2em; } -table { - width: 100%; -} - -table td { - padding: 0.1em 0.2em; -} - -table th { - text-align: left; - border-bottom: 1px solid #ccc; -} - -table > tbody > tr.view { - cursor: pointer; -} - -table > tbody > tr.even { - background: #eee; -} - -table > tbody > tr.highlight { - background: #0cc; -} - -table > tbody > tr.fold { - display: none; -} - -table > tbody > tr.fold > td { - padding-left: 1em; -} - -table > tbody > tr.fold.open { - display: table-row; -} - div.nav { padding: 5px; background-color: #dde; @@ -171,7 +134,6 @@ table.blocks { margin: 0 auto; border-collapse: separate; border-spacing: 2px; - width: 770px; } table.blocks td { @@ -179,3 +141,7 @@ table.blocks td { width: 10px; padding: 0; } + +table.legend { + margin: 0 auto; +}