From 870c5c7a81ca4e812fc7824ebf3f54066c7154e7 Mon Sep 17 00:00:00 2001 From: Martin Stein Date: Wed, 24 Feb 2021 17:06:40 +0100 Subject: [PATCH] file_vault: GUI control for encrypted virtual FS's Warning! The current version of the file vault is not thought for productive use but for mere demonstrational purpose! Please refrain from storing sensitive data with it! The File Vault component implements a graphical frontend for setting up and controlling encrypted virtual file systems using the Consistent Block Encrypter (CBE) for encryption and snapshot management. For more details see 'repos/gems/src/app/file_vault/README'. Fixes #4032 --- repos/gems/recipes/pkg/file_vault/README | 1 + repos/gems/recipes/pkg/file_vault/archives | 19 + repos/gems/recipes/pkg/file_vault/hash | 1 + repos/gems/recipes/pkg/file_vault/runtime | 105 + repos/gems/recipes/src/file_vault/content.mk | 3 + repos/gems/recipes/src/file_vault/hash | 1 + repos/gems/recipes/src/file_vault/used_apis | 11 + repos/gems/run/file_vault.run | 300 ++ repos/gems/src/app/file_vault/README | 149 + repos/gems/src/app/file_vault/capacity.cc | 58 + repos/gems/src/app/file_vault/capacity.h | 51 + .../src/app/file_vault/child_exit_state.h | 70 + repos/gems/src/app/file_vault/child_state.h | 147 + repos/gems/src/app/file_vault/const_pointer.h | 64 + repos/gems/src/app/file_vault/dynamic_array.h | 194 + .../app/file_vault/gui_input_event_handler.h | 28 + .../app/file_vault/gui_session_component.h | 122 + repos/gems/src/app/file_vault/input.h | 261 ++ repos/gems/src/app/file_vault/main.cc | 4098 +++++++++++++++++ .../src/app/file_vault/menu_view_dialog.cc | 389 ++ .../src/app/file_vault/menu_view_dialog.h | 181 + .../app/file_vault/report_session_component.h | 91 + repos/gems/src/app/file_vault/sandbox.h | 997 ++++ repos/gems/src/app/file_vault/snapshot.h | 45 + .../file_vault/sync_to_cbe_vfs_init/main.cc | 36 + .../file_vault/sync_to_cbe_vfs_init/target.mk | 3 + repos/gems/src/app/file_vault/target.mk | 6 + .../src/app/file_vault/truncate_file/main.cc | 85 + .../app/file_vault/truncate_file/target.mk | 4 + repos/gems/src/app/file_vault/types.h | 55 + repos/gems/src/app/file_vault/utf8.h | 32 + 31 files changed, 7607 insertions(+) create mode 100644 repos/gems/recipes/pkg/file_vault/README create mode 100644 repos/gems/recipes/pkg/file_vault/archives create mode 100644 repos/gems/recipes/pkg/file_vault/hash create mode 100644 repos/gems/recipes/pkg/file_vault/runtime create mode 100644 repos/gems/recipes/src/file_vault/content.mk create mode 100644 repos/gems/recipes/src/file_vault/hash create mode 100644 repos/gems/recipes/src/file_vault/used_apis create mode 100644 repos/gems/run/file_vault.run create mode 100644 repos/gems/src/app/file_vault/README create mode 100644 repos/gems/src/app/file_vault/capacity.cc create mode 100644 repos/gems/src/app/file_vault/capacity.h create mode 100644 repos/gems/src/app/file_vault/child_exit_state.h create mode 100644 repos/gems/src/app/file_vault/child_state.h create mode 100644 repos/gems/src/app/file_vault/const_pointer.h create mode 100644 repos/gems/src/app/file_vault/dynamic_array.h create mode 100644 repos/gems/src/app/file_vault/gui_input_event_handler.h create mode 100644 repos/gems/src/app/file_vault/gui_session_component.h create mode 100644 repos/gems/src/app/file_vault/input.h create mode 100644 repos/gems/src/app/file_vault/main.cc create mode 100644 repos/gems/src/app/file_vault/menu_view_dialog.cc create mode 100644 repos/gems/src/app/file_vault/menu_view_dialog.h create mode 100644 repos/gems/src/app/file_vault/report_session_component.h create mode 100644 repos/gems/src/app/file_vault/sandbox.h create mode 100644 repos/gems/src/app/file_vault/snapshot.h create mode 100644 repos/gems/src/app/file_vault/sync_to_cbe_vfs_init/main.cc create mode 100644 repos/gems/src/app/file_vault/sync_to_cbe_vfs_init/target.mk create mode 100644 repos/gems/src/app/file_vault/target.mk create mode 100644 repos/gems/src/app/file_vault/truncate_file/main.cc create mode 100644 repos/gems/src/app/file_vault/truncate_file/target.mk create mode 100644 repos/gems/src/app/file_vault/types.h create mode 100644 repos/gems/src/app/file_vault/utf8.h diff --git a/repos/gems/recipes/pkg/file_vault/README b/repos/gems/recipes/pkg/file_vault/README new file mode 100644 index 0000000000..a88de3a2e1 --- /dev/null +++ b/repos/gems/recipes/pkg/file_vault/README @@ -0,0 +1 @@ +See repos/gems/src/app/file_vault/README. diff --git a/repos/gems/recipes/pkg/file_vault/archives b/repos/gems/recipes/pkg/file_vault/archives new file mode 100644 index 0000000000..f29ca16179 --- /dev/null +++ b/repos/gems/recipes/pkg/file_vault/archives @@ -0,0 +1,19 @@ +_/src/init +_/src/libc +_/src/libpng +_/src/zlib +_/src/fs_query +_/src/menu_view +_/src/cbe +_/src/spark +_/src/libsparkcrypto +_/src/vfs_block +_/src/vfs_jitterentropy +_/src/vfs +_/src/openssl +_/src/fs_tool +_/src/fs_utils +_/src/posix +_/src/rump +_/src/sandbox +_/src/file_vault diff --git a/repos/gems/recipes/pkg/file_vault/hash b/repos/gems/recipes/pkg/file_vault/hash new file mode 100644 index 0000000000..de77dfd30c --- /dev/null +++ b/repos/gems/recipes/pkg/file_vault/hash @@ -0,0 +1 @@ +2021-04-26-a 405015723954822d3672b119d82e96262fe6763c diff --git a/repos/gems/recipes/pkg/file_vault/runtime b/repos/gems/recipes/pkg/file_vault/runtime new file mode 100644 index 0000000000..a6e0a1cdad --- /dev/null +++ b/repos/gems/recipes/pkg/file_vault/runtime @@ -0,0 +1,105 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/repos/gems/recipes/src/file_vault/content.mk b/repos/gems/recipes/src/file_vault/content.mk new file mode 100644 index 0000000000..d1d6afb128 --- /dev/null +++ b/repos/gems/recipes/src/file_vault/content.mk @@ -0,0 +1,3 @@ +SRC_DIR := src/app/file_vault + +include $(GENODE_DIR)/repos/base/recipes/src/content.inc diff --git a/repos/gems/recipes/src/file_vault/hash b/repos/gems/recipes/src/file_vault/hash new file mode 100644 index 0000000000..349cc5ae12 --- /dev/null +++ b/repos/gems/recipes/src/file_vault/hash @@ -0,0 +1 @@ +2021-04-26-a f1ce555a3cd5070870e541aab731d5b8aa7ed30b diff --git a/repos/gems/recipes/src/file_vault/used_apis b/repos/gems/recipes/src/file_vault/used_apis new file mode 100644 index 0000000000..92bbf66f96 --- /dev/null +++ b/repos/gems/recipes/src/file_vault/used_apis @@ -0,0 +1,11 @@ +base +os +cbe +vfs +report_session +gui_session +input_session +framebuffer_session +posix +libc +sandbox diff --git a/repos/gems/run/file_vault.run b/repos/gems/run/file_vault.run new file mode 100644 index 0000000000..6b1ea79f54 --- /dev/null +++ b/repos/gems/run/file_vault.run @@ -0,0 +1,300 @@ +assert_spec x86_64 + +build { app/file_vault } + +create_boot_directory + +append archives " + [depot_user]/src/[base_src] + [depot_user]/pkg/[drivers_interactive_pkg] + [depot_user]/pkg/fonts_fs + [depot_user]/src/init + [depot_user]/src/nitpicker + [depot_user]/src/libc + [depot_user]/src/libpng + [depot_user]/src/zlib + [depot_user]/src/fs_query + [depot_user]/src/menu_view + [depot_user]/src/cbe + [depot_user]/src/spark + [depot_user]/src/libsparkcrypto + [depot_user]/src/vfs_block + [depot_user]/src/vfs_jitterentropy + [depot_user]/src/vfs + [depot_user]/src/openssl + [depot_user]/src/fs_tool + [depot_user]/src/fs_utils + [depot_user]/src/posix + [depot_user]/src/rump + [depot_user]/src/sandbox +" + +append_if [have_board linux] archives [depot_user]/src/lx_fs + +import_from_depot $archives + +append config { + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +} +if {[have_board linux]} { + + append config { + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + } + +} else { + + append config { + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + } +} +append config { + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +} + +install_config $config + +set fd [open [run_dir]/genode/focus w] +puts $fd " \"/>" +close $fd + +if {[have_board linux]} { + exec mkdir -p bin/file_vault_dir/data + exec mkdir -p bin/file_vault_dir/trust_anchor +} + +append boot_modules { + file_vault + file_vault-sync_to_cbe_vfs_init + file_vault-truncate_file +} + +append qemu_args " -display gtk " + +append_if [have_board linux] boot_modules file_vault_dir + +build_boot_image $boot_modules + +run_genode_until forever diff --git a/repos/gems/src/app/file_vault/README b/repos/gems/src/app/file_vault/README new file mode 100644 index 0000000000..c1c75fda85 --- /dev/null +++ b/repos/gems/src/app/file_vault/README @@ -0,0 +1,149 @@ + The file vault + Martin Stein + +Warning +~~~~~~~ + +The current version of the file vault is not thought for productive use but +for mere demonstrational purpose! Please refrain from storing sensitive data +with it! + + +Brief +~~~~~ + +The file vault is a graphical front end for creating and controlling a virtual +encrypted block device using Genodes Consistent Block Encrypter (CBE). The +vault also takes care of creating and managing a Trust Anchor for securing +the block device and formatting the block device with the ext2 file system +which is then provided to clients through Genodes File System service. + + +Internal structure +~~~~~~~~~~~~~~~~~~ + +The file vault uses the Sandbox library to spawn child components according to +its needs. It starts, closes or adapts children by re-writing the Sandbox +configuration and listens to the Sandbox state report in order to wait for a +specific child to finish or recognize resource requests. + +One child that is always present is an instance of the Menu View component used +by the vault to display its dialog window. The user input however is received +and handled by the vault itself, which, if necessary, then adapts the +graphical output accordingly by re-writing the Menu View configuration. In +order to correlate input events to GUI changes, the vault always keeps track +of the currently hovered GUI element by listening to the hover report of the +Menu View child. + +Whenever possible, the vault doesn't access the back end file systems itself +but instead spawns helper components like fs_tool or fs_query. This allows the +vault to remain simple and protected against problems during file system +access. + +In general, the implementation of the file vault tries to set the focus on +state-driven decisions. The internal state machine of the vault is divided +into 4 major steps: Setup, Startup, Controls, and Shutdown. + +Setup means creating a new Trust Anchor and CBE device as well as formatting +the CBE device. Startup means bringing up an already existing Trust Anchor +and CBE device for use. Controls means showing the main window that allows +manipulating a running CBE device (snapshot management, rekeying, resizing). +Consequently, the Controls step follows after a successful Setup or Startup +step. From the Controls step, the user can trigger a transition to the Shutdown +step. Shutdown means gracefully terminating the use of a running CBE device and +closing the file vault. + +Each of these major steps is subdivided into smaller steps. For instance, the +startup consists of requesting the user to input the device passphrase, +unlocking the trust anchor, and starting the CBE device driver. Examining all +minor steps would be to much in the context of this document but the class +_File_vault::Main::State_ in _gems/src/app/file_vault/main.cc_ lists them in +very descriptive way. + +When the vault is started, it will first try to read the initial state from +the _/file_vault/state_ file in the back-end file system. There are basically +only two results to this: If the file doesn't exist, the Setup step is startet. +If the file exists, however, it's expected to yield the initial state of the +Startup step indicating that the Setup step has already been done on this back +end during a former run of the file vault. + +Once the CBE device is up and running, the file vault enters the Controls +step. This step has several sub-states, for instance the states of rekeying or +creating a snapshot (_File_vault::Main::Rekeying_state_, +_File_vault::Main::Create_snapshot_state_, ...). This is because each of these +operations can be executed independent from each other and in parallel. In +order to execute the operations, the vault accesses the VFS control interface +of the CBE (the CBE VFS plugin) spawned in a dedicated VFS server child. + +Like with the back-end file systems, the vault doesn't access the CBE VFS +itself when executing a device operation. It rather spawns an fs_tool instance +to write to the file that starts the operation and an fs_query instance to +watch the file that provides the operation progress. + + +Configuration +~~~~~~~~~~~~~ + +The file vault should always have the following configuration: + +! +! +! +! +! +! +! + +The vault doesn't consider any further user configuration. + + +Provided service and session requests +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The vault provides a File System service to the ext2 file system once a CBE +device was successfully created and formatted respectively unlocked. Besides +the common Genode environment sessions, the vault requests one File System +session to a fonts file system, one File System session for the back-end +storage of the Trust Anchor, several File System session for the file system +that holds the CBE image file and the persistent vault data, one Gui session, +several timer sessions and an RM session for the Rump kernel it spawns. + + +Further resources +~~~~~~~~~~~~~~~~~ + +The _gems/run/file_vault.run_ provides an example on how to manually integrate +the file vault. It can also be used for analyzing and developing the vault - +when targeting native Linux execution even with a persistent storage back-end. +The file vault was also packaged in _gems/recipes/pkg/file_vault_ and can be +deployed in Sculpt via _+ -> depot -> mstein -> Tools -> File Vault_. + + +Open issues +~~~~~~~~~~~ + +* The vault should show the percantage of used and free blocks in the CBE trees + in order to enable the user to resize or sync to prevent an out-of-resource + situation. +* Although the Trust Anchor data (private key and superblock hash) can + already be stored on a separate device like an USB stick it still has to be + exposed to the system (device driver, file system driver, file vault) + during operation as the file vault yet can't access "real" Trust-Anchor + interfaces like OpenPGP-Smartcard. +* While some device controls (rekeying, resizing, ...) can be controlled via + the vault only in a serial way (the button only shows up again as soon as + the operation is done) creating and discarding snapshots is controlled in a + fire-and-forget fashion (the button immediately shows up again). This is + because the CBE VFS yet doesn't fully propagate the completely asynchronous + way of handling requests of the CBE. +* The creation of the CBE image file is done yet in serial inside the vault + itself which causes the GUI to hang till the image creation is done. +* Shrinking the client FS or the journaling buffer is not yet supported. +* Creating, discarding, and accessing snapshots isn't supported by now in the + file vault, although the underlying CBE and its VFS plugin have full support. +* The CBE might run into a ressource limit when writing block data or replacing + the block encryption key. This is because it doesn't take care yet whether + its Free Tree has enough free blocks left for finishing an operation. It will + just through an exception in the middle of the operation. This won't affect + the integrity of the vault on disk but might lead to the loss of cached + block data. diff --git a/repos/gems/src/app/file_vault/capacity.cc b/repos/gems/src/app/file_vault/capacity.cc new file mode 100644 index 0000000000..b8d18b3a71 --- /dev/null +++ b/repos/gems/src/app/file_vault/capacity.cc @@ -0,0 +1,58 @@ +/* + * \brief Printable byte capacity + * \author Norman Feske + * \author Martin Stein + * \date 2018-04-30 + */ + +/* + * Copyright (C) 2018 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +/* local includes */ +#include + + +/************** + ** Capacity_** + **************/ + +void File_vault::Capacity::print(Output &out) const +{ + static constexpr uint64_t KB = 1024; + static constexpr uint64_t MB = 1024 * KB; + static constexpr uint64_t GB = 1024 * MB; + + Text const text { + (_value >= GB) ? Text((float)_value/GB, " GiB") : + (_value >= MB) ? Text((float)_value/MB, " MiB") : + (_value >= KB) ? Text((float)_value/KB, " KiB") : + Text(_value, " bytes") }; + + Genode::print(out, text); +} + + +File_vault::Capacity::Capacity(uint64_t value) +: + _value { value } +{ } + + +/********************* + ** Capacity_string ** + *********************/ + +File_vault::Capacity_string::Capacity_string(uint64_t value) +: + Capacity::Text { Capacity { value } } +{ } + + +File_vault::Capacity_string::operator char const *() +{ + return Capacity::Text::string(); +} diff --git a/repos/gems/src/app/file_vault/capacity.h b/repos/gems/src/app/file_vault/capacity.h new file mode 100644 index 0000000000..46dd1b34be --- /dev/null +++ b/repos/gems/src/app/file_vault/capacity.h @@ -0,0 +1,51 @@ +/* + * \brief Printable byte capacity + * \author Norman Feske + * \author Martin Stein + * \date 2018-04-30 + */ + +/* + * Copyright (C) 2018 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#ifndef _CAPACITY_H_ +#define _CAPACITY_H_ + +/* local includes */ +#include + +namespace File_vault { + + class Capacity; + class Capacity_string; +} + +class File_vault::Capacity +{ + private: + + uint64_t const _value; + + public: + + using Text = String<64>; + + Capacity(uint64_t value); + + void print(Output &out) const; +}; + +class File_vault::Capacity_string : public Capacity::Text +{ + public: + + Capacity_string(uint64_t value); + + operator char const *(); +}; + +#endif /* _CAPACITY_H_ */ diff --git a/repos/gems/src/app/file_vault/child_exit_state.h b/repos/gems/src/app/file_vault/child_exit_state.h new file mode 100644 index 0000000000..6ab3af6b76 --- /dev/null +++ b/repos/gems/src/app/file_vault/child_exit_state.h @@ -0,0 +1,70 @@ +/* + * \brief Utility for querying the child-exit state from init's state report + * \author Norman Feske + * \author Martin Stein + * \date 2021-03-05 + */ + +/* + * Copyright (C) 2021 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#ifndef _CHILD_EXIT_STATE_H_ +#define _CHILD_EXIT_STATE_H_ + +/* Genode includes */ +#include + +/* local includes */ +#include + +namespace File_vault { + + class Child_exit_state; +} + +class File_vault::Child_exit_state +{ + public: + + typedef String<128> Name; + typedef String<16> Version; + + private: + + bool _exists = false; + bool _exited = false; + bool _responsive = true; + int _code = 0; + Version _version { }; + + public: + + Child_exit_state(Xml_node init_state, Name const &name) + { + init_state.for_each_sub_node("child", [&] (Xml_node child) { + if (child.attribute_value("name", Name()) == name) { + _exists = true; + _version = child.attribute_value("version", Version()); + + if (child.has_attribute("exited")) { + _exited = true; + _code = child.attribute_value("exited", 0L); + } + + _responsive = (child.attribute_value("skipped_heartbeats", 0U) <= 2); + } + }); + } + + bool exists() const { return _exists ; } + bool exited() const { return _exited ; } + bool responsive() const { return _responsive ; } + int code() const { return _code ; } + Version version() const { return _version ; } +}; + +#endif /* _CHILD_EXIT_STATE_H_ */ diff --git a/repos/gems/src/app/file_vault/child_state.h b/repos/gems/src/app/file_vault/child_state.h new file mode 100644 index 0000000000..a27e4b9848 --- /dev/null +++ b/repos/gems/src/app/file_vault/child_state.h @@ -0,0 +1,147 @@ +/* + * \brief Runtime state of a child hosted in the runtime subsystem + * \author Martin Stein + * \author Norman Feske + * \date 2021-02-25 + */ + +/* + * Copyright (C) 2021 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#ifndef _CHILD_STATE_H_ +#define _CHILD_STATE_H_ + +/* Genode includes */ +#include +#include +#include +#include +#include + +/* local includes */ +#include + +namespace File_vault { + + class Child_state; +} + +class File_vault::Child_state : Noncopyable +{ + private: + + using Start_name = String<128>; + using Binary_name = String<128>; + using Registry_element = Registry::Element; + + struct Version + { + unsigned value; + }; + + Registry_element _registry_element; + Start_name const _start_name; + Binary_name const _binary_name; + Ram_quota const _initial_ram_quota; + Cap_quota const _initial_cap_quota; + Ram_quota _ram_quota { _initial_ram_quota }; + Cap_quota _cap_quota { _initial_cap_quota }; + Version _version { 0 }; + + public: + + Child_state(Registry ®istry, + Start_name const &start_name, + Binary_name const &binary_name, + Ram_quota ram_quota, + Cap_quota cap_quota) + : + _registry_element { registry, *this }, + _start_name { start_name }, + _binary_name { binary_name }, + _initial_ram_quota { ram_quota }, + _initial_cap_quota { cap_quota } + { } + + Child_state(Registry ®istry, + Start_name const &start_name, + Ram_quota ram_quota, + Cap_quota cap_quota) + : + _registry_element { registry, *this }, + _start_name { start_name }, + _binary_name { start_name }, + _initial_ram_quota { ram_quota }, + _initial_cap_quota { cap_quota } + { } + + void trigger_restart() + { + _version.value++; + _ram_quota = _initial_ram_quota; + _cap_quota = _initial_cap_quota; + } + + void gen_start_node_version(Xml_generator &xml) const + { + if (_version.value) + xml.attribute("version", _version.value); + } + + template + void gen_start_node(Xml_generator &xml, + GEN_CONTENT const &gen_content) const + { + xml.node("start", [&] () { + xml.attribute("name", _start_name); + xml.attribute("caps", _cap_quota.value); + gen_start_node_version(xml); + + if (_start_name != _binary_name) { + xml.node("binary", [&] () { + xml.attribute("name", _binary_name); + }); + } + xml.node("resource", [&] () { + xml.attribute("name", "RAM"); + Number_of_bytes const bytes(_ram_quota.value); + xml.attribute("quantum", String<64>(bytes)); }); + + gen_content(); + }); + } + + bool apply_child_state_report(Xml_node const &child) + { + bool result = false; + + if (child.attribute_value("name", Start_name()) != _start_name) + return false; + + if (child.has_sub_node("ram") && + child.sub_node("ram").has_attribute("requested")) + { + _ram_quota.value *= 2; + result = true; + } + + if (child.has_sub_node("caps") && + child.sub_node("caps").has_attribute("requested")) + { + _cap_quota.value += 100; + result = true; + } + + return result; + } + + Ram_quota ram_quota() const { return _ram_quota; } + + Start_name start_name() const { return _start_name; } +}; + +#endif /* _CHILD_STATE_H_ */ diff --git a/repos/gems/src/app/file_vault/const_pointer.h b/repos/gems/src/app/file_vault/const_pointer.h new file mode 100644 index 0000000000..c4fcc3345d --- /dev/null +++ b/repos/gems/src/app/file_vault/const_pointer.h @@ -0,0 +1,64 @@ +/* + * \brief Pointer of const object safe against null dereferencing + * \author Martin Stein + * \date 2021-04-02 + */ + +/* + * Copyright (C) 2021 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#ifndef _CONST_POINTER_H_ +#define _CONST_POINTER_H_ + +/* local includes */ +#include + +namespace File_vault { + + template + class Const_pointer; +} + + +template +class File_vault::Const_pointer +{ + private: + + OBJECT_TYPE const *_object; + + public: + + struct Invalid : Genode::Exception { }; + + Const_pointer() : _object { nullptr } { } + + Const_pointer(OBJECT_TYPE const &object) : _object { &object } { } + + OBJECT_TYPE const &object() const + { + if (_object == nullptr) + throw Invalid(); + + return *_object; + } + + bool valid() const { return _object != nullptr; } + + bool operator != (Const_pointer const &other) const + { + if (valid() != other.valid()) { + return true; + } + if (valid()) { + return _object != other._object; + } + return false; + } +}; + +#endif /* _CONST_POINTER_H_ */ diff --git a/repos/gems/src/app/file_vault/dynamic_array.h b/repos/gems/src/app/file_vault/dynamic_array.h new file mode 100644 index 0000000000..12407e274e --- /dev/null +++ b/repos/gems/src/app/file_vault/dynamic_array.h @@ -0,0 +1,194 @@ +/* + * \brief Dynamically growing array + * \author Norman Feske + * \date 2020-01-12 + */ + +/* + * Copyright (C) 2020 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#ifndef _DYNAMIC_ARRAY_H_ +#define _DYNAMIC_ARRAY_H_ + +/* Genode includes */ +#include + +namespace File_vault { + + using namespace Genode; + + template + struct Dynamic_array; +} + + +template +struct File_vault::Dynamic_array +{ + public: + + struct Index { unsigned value; }; + + private: + + Allocator &_alloc; + + using Element = Constructible; + + Element *_array = nullptr; + + unsigned _capacity = 0; + unsigned _upper_bound = 0; /* index after last used element */ + + bool _index_valid(Index at) const + { + return (at.value < _upper_bound) && _array[at.value].constructed(); + } + + /* + * Noncopyable + */ + Dynamic_array(Dynamic_array const &other); + void operator = (Dynamic_array const &); + + public: + + /** + * Moving constructor + */ + Dynamic_array(Dynamic_array &other) + : + _alloc(other._alloc), _array(other._array), + _capacity(other._capacity), _upper_bound(other._upper_bound) + { + other._array = nullptr; + other._capacity = 0; + other._upper_bound = 0; + } + + Dynamic_array(Allocator &alloc) : _alloc(alloc) { } + + ~Dynamic_array() + { + if (!_array) + return; + + clear(); + + _alloc.free(_array, _capacity*sizeof(Element)); + } + + void clear() + { + if (_upper_bound > 0) + for (unsigned i = _upper_bound; i > 0; i--) + destruct(Index{i - 1}); + } + + template + void insert(Index at, ARGS &&... args) + { + /* grow array if index exceeds current capacity or if it's full */ + if (at.value >= _capacity || _upper_bound == _capacity) { + + size_t const new_capacity = + 2 * max(_capacity, max(8U, at.value)); + + Element *new_array = nullptr; + try { + (void)_alloc.alloc(sizeof(Element)*new_capacity, &new_array); + + for (unsigned i = 0; i < new_capacity; i++) + construct_at(&new_array[i]); + } + catch (... /* Out_of_ram, Out_of_caps */ ) { throw; } + + if (_array) { + for (unsigned i = 0; i < _upper_bound; i++) + new_array[i].construct(*_array[i]); + + _alloc.free(_array, sizeof(Element)*_capacity); + } + + _array = new_array; + _capacity = new_capacity; + } + + /* make room for new element */ + if (_upper_bound > 0) + for (unsigned i = _upper_bound; i > at.value; i--) + _array[i].construct(*_array[i - 1]); + + _array[at.value].construct(args...); + + _upper_bound = max(at.value + 1, _upper_bound + 1); + } + + template + void append(ARGS &&... args) { insert(Index{_upper_bound}, args...); } + + bool exists(Index at) const { return _index_valid(at); } + + Index upper_bound() const { return Index { _upper_bound }; } + + void destruct(Index at) + { + if (!_index_valid(at)) + return; + + _array[at.value].destruct(); + + if (_upper_bound > 0) + for (unsigned i = at.value; i < _upper_bound - 1; i++) + _array[i].construct(*_array[i + 1]); + + _upper_bound--; + _array[_upper_bound].destruct(); + } + + template + void apply(Index at, FN const &fn) + { + if (_index_valid(at)) + fn(*_array[at.value]); + } + + template + void apply(Index at, FN const &fn) const + { + if (_index_valid(at)) + fn(*_array[at.value]); + } + + struct Range { Index at; unsigned length; }; + + template + void for_each(Range range, FN const &fn) const + { + unsigned const first = range.at.value; + unsigned const limit = min(_upper_bound, first + range.length); + + for (unsigned i = first; i < limit; i++) + if (_array[i].constructed()) + fn(Index{i}, *_array[i]); + } + + template + void for_each(FN const &fn) const + { + for_each(Range { .at = { 0U }, .length = ~0U }, fn); + } + + void print(Output &out) const + { + for (unsigned i = 0; i < _upper_bound; i++) + if (_array[i].constructed()) + Genode::print(out, *_array[i]); + } +}; + +#endif /* _DYNAMIC_ARRAY_H_ */ diff --git a/repos/gems/src/app/file_vault/gui_input_event_handler.h b/repos/gems/src/app/file_vault/gui_input_event_handler.h new file mode 100644 index 0000000000..6f0a04dc0d --- /dev/null +++ b/repos/gems/src/app/file_vault/gui_input_event_handler.h @@ -0,0 +1,28 @@ +/* + * \brief Interface for handling input events + * \author Norman Feske + * \date 2018-05-02 + */ + +/* + * Copyright (C) 2018 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#ifndef _GUI_INPUT_EVENT_HANDLER_H_ +#define _GUI_INPUT_EVENT_HANDLER_H_ + +/* Genode includes */ +#include +#include + +namespace Gui { struct Input_event_handler; } + +struct Gui::Input_event_handler : Genode::Interface +{ + virtual void handle_input_event(Input::Event const &) = 0; +}; + +#endif /* _GUI_INPUT_EVENT_HANDLER_H_ */ diff --git a/repos/gems/src/app/file_vault/gui_session_component.h b/repos/gems/src/app/file_vault/gui_session_component.h new file mode 100644 index 0000000000..7ad183058e --- /dev/null +++ b/repos/gems/src/app/file_vault/gui_session_component.h @@ -0,0 +1,122 @@ +/* + * \brief GUI wrapper for monitoring the user input of GUI components + * \author Norman Feske + * \date 2020-01-12 + */ + +/* + * Copyright (C) 2020 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#ifndef _GUI_SESSION_COMPONENT_H_ +#define _GUI_SESSION_COMPONENT_H_ + +/* Genode includes */ +#include +#include +#include + +/* local includes */ +#include + +namespace Gui { + + using namespace Genode; + + struct Session_component; +} + + +struct Gui::Session_component : Session_object +{ + Env &_env; + + Input_event_handler &_event_handler; + + Gui::Connection _connection; + + Input::Session_component _input_component { _env, _env.ram() }; + + Signal_handler _input_handler { + _env.ep(), *this, &Session_component::_handle_input }; + + void _handle_input() + { + _connection.input()->for_each_event([&] (Input::Event ev) { + + /* handle event locally within the sculpt manager */ + _event_handler.handle_input_event(ev); + + _input_component.submit(ev); + }); + } + + template + Session_component(Env &env, Input_event_handler &event_handler, ARGS &&... args) + : + Session_object(args...), + _env(env), _event_handler(event_handler), + _connection(env, _label.string()) + { + _connection.input()->sigh(_input_handler); + _env.ep().manage(_input_component); + _input_component.event_queue().enabled(true); + } + + ~Session_component() { _env.ep().dissolve(_input_component); } + + void upgrade(Session::Resources const &resources) + { + _connection.upgrade(resources); + } + + Framebuffer::Session_capability framebuffer_session() override { + return _connection.framebuffer_session(); } + + Input::Session_capability input_session() override { + return _input_component.cap(); } + + View_handle create_view(View_handle parent) override { + return _connection.create_view(parent); } + + void destroy_view(View_handle view) override { + _connection.destroy_view(view); } + + View_handle view_handle(View_capability view_cap, View_handle handle) override { + return _connection.view_handle(view_cap, handle); } + + View_capability view_capability(View_handle view) override { + return _connection.view_capability(view); } + + void release_view_handle(View_handle view) override { + _connection.release_view_handle(view); } + + Dataspace_capability command_dataspace() override { + return _connection.command_dataspace(); } + + void execute() override { + _connection.execute(); } + + Framebuffer::Mode mode() override { + return _connection.mode(); } + + void mode_sigh(Signal_context_capability sigh) override { + _connection.mode_sigh(sigh); } + + void buffer(Framebuffer::Mode mode, bool use_alpha) override + { + /* + * Do not call 'Connection::buffer' to avoid paying session quota + * from our own budget. + */ + _connection.Client::buffer(mode, use_alpha); + } + + void focus(Capability session) override { + _connection.focus(session); } +}; + +#endif /* _GUI_SESSION_COMPONENT_H_ */ diff --git a/repos/gems/src/app/file_vault/input.h b/repos/gems/src/app/file_vault/input.h new file mode 100644 index 0000000000..3fe598e662 --- /dev/null +++ b/repos/gems/src/app/file_vault/input.h @@ -0,0 +1,261 @@ +/* + * \brief Text buffer for a passphrase + * \author Norman Feske + * \author Martin Stein + * \date 2021-03-02 + */ + +/* + * Copyright (C) 2021 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#ifndef _INPUT_H_ +#define _INPUT_H_ + +/* Genode includes */ +#include +#include +#include + +/* local includes */ +#include + +namespace File_vault { + + class Input_single_line; + class Input_passphrase; + class Input_number_of_bytes; + class Input_number_of_blocks; +} + + +class File_vault::Input_single_line +{ + public: + + enum { MAX_LENGTH = 64 }; + + protected: + + Codepoint _characters[MAX_LENGTH] { }; + + unsigned _length = 0; + + void _print_characters(Output &out) const + { + /* + * FIXME This was copied from gems/src/server/terminal/main.cc + */ + + struct Utf8 { char b0, b1, b2, b3, b4; }; + + auto utf8_from_codepoint = [] (unsigned c) { + + /* extract 'n' bits 'at' bit position of value 'c' */ + auto bits = [c] (unsigned at, unsigned n) { + return (c >> at) & ((1 << n) - 1); }; + + return (c < 2<<7) ? Utf8 { char(bits( 0, 7)), 0, 0, 0, 0 } + : (c < 2<<11) ? Utf8 { char(bits( 6, 5) | 0xc0), + char(bits( 0, 6) | 0x80), 0, 0, 0 } + : (c < 2<<16) ? Utf8 { char(bits(12, 4) | 0xe0), + char(bits( 6, 6) | 0x80), + char(bits( 0, 6) | 0x80), 0, 0 } + : (c < 2<<21) ? Utf8 { char(bits(18, 3) | 0xf0), + char(bits(12, 6) | 0x80), + char(bits( 6, 6) | 0x80), + char(bits( 0, 6) | 0x80), 0 } + : Utf8 { }; + }; + + for (unsigned i = 0; i < _length; i++) { + + Utf8 const utf8 = utf8_from_codepoint(_characters[i].value); + + auto _print = [&] (char c) { + if (c) + Genode::print(out, Char(c)); }; + + _print(utf8.b0); _print(utf8.b1); _print(utf8.b2); + _print(utf8.b3); _print(utf8.b4); + } + } + + public: + + void append_character(Codepoint c) + { + if (_length < MAX_LENGTH) { + _characters[_length] = c; + _length++; + } + } + + void remove_last_character() + { + if (_length > 0) { + _length--; + _characters[_length].value = 0; + } + } + + bool equals(Input_single_line const &other) const + { + if (other._length != _length) { + return false; + } + if (memcmp(other._characters, _characters, _length) != 0) { + return false; + } + return true; + } + + unsigned length() const { return _length; } +}; + + + +class File_vault::Input_passphrase : public Input_single_line +{ + private: + + bool _hide { true }; + + void _print_bullets(Output &out) const + { + char const bullet_utf8[4] { + (char)0xe2, (char)0x80, (char)0xa2, 0 }; + + for (unsigned i = 0; i < _length; i++) + Genode::print(out, bullet_utf8); + } + + public: + + bool suitable() const + { + return _length >= 8; + } + + char const *not_suitable_text() const + { + return "Must have at least 8 characters!"; + } + + void print(Output &out) const + { + if (_hide) { + _print_bullets(out); + } else { + _print_characters(out); + } + } + + void hide(bool value) + { + _hide = value; + } + + bool hide() const + { + return _hide; + } + + bool appendable_character(Codepoint code) + { + if (!code.valid()) { + return false; + } + bool const is_printable { + code.value >= 0x20 && code.value < 0xf000 }; + + return is_printable; + } + + String plaintext() const + { + String result { }; + + auto write = [&] (char const *str) + { + result = Cstring(str, strlen(str)); + }; + Buffered_output output(write); + + _print_characters(output); + return result; + } +}; + + +class File_vault::Input_number_of_bytes : public Input_single_line +{ + public: + + void print(Output &out) const + { + _print_characters(out); + } + + size_t value() const + { + String<32> const str { *this }; + Number_of_bytes result { 0 }; + ascii_to(str.string(), result); + return result; + } + + bool appendable_character(Codepoint code) + { + if (!code.valid()) { + return false; + } + bool const is_number { + code.value >= 48 && code.value <= 57 }; + + bool const is_unit_prefix { + code.value == 71 || code.value == 75 || code.value == 77 }; + + return is_number || is_unit_prefix; + } +}; + + +class File_vault::Input_number_of_blocks : public Input_single_line +{ + public: + + void print(Output &out) const + { + _print_characters(out); + } + + unsigned long to_unsigned_long() const + { + String<32> const str { *this }; + unsigned long result { 0 }; + ascii_to(str.string(), result); + return result; + } + + bool is_nr_greater_than_zero() const + { + return (size_t)to_unsigned_long() > 0; + } + + bool appendable_character(Codepoint code) + { + if (!code.valid()) { + return false; + } + bool const is_number { + code.value >= 48 && code.value <= 57 }; + + return is_number; + } +}; + +#endif /* _INPUT_H_ */ diff --git a/repos/gems/src/app/file_vault/main.cc b/repos/gems/src/app/file_vault/main.cc new file mode 100644 index 0000000000..e944481640 --- /dev/null +++ b/repos/gems/src/app/file_vault/main.cc @@ -0,0 +1,4098 @@ +/* + * \brief Graphical front end for controlling CBE devices + * \author Martin Stein + * \author Norman Feske + * \date 2021-02-24 + */ + +/* + * Copyright (C) 2021 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +/* Genode includes */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* local includes */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace File_vault { + + enum { SHOW_CONTROLS_SNAPSHOTS = 0 }; + enum { SHOW_CONTROLS_SECURITY_MASTER_KEY = 0 }; + enum { SHOW_CONTROLS_SECURITY_USER_PASSPHRASE = 0 }; + enum { RENAME_SNAPSHOT_BUFFER_JOURNALING_BUFFER = 1 }; + + class Main; +} + +class File_vault::Main +: + private Sandbox::Local_service_base::Wakeup, + private Sandbox::State_handler, + private Gui::Input_event_handler, + private Dynamic_rom_session::Xml_producer +{ + private: + + enum { + MIN_CLIENT_FS_SIZE = 100 * 1024, + STATE_STRING_CAPACITY = 64, + CBE_BLOCK_SIZE = 4096, + MAIN_FRAME_WIDTH = 46, + CBE_VBD_TREE_NR_OF_LEVELS = 6, + CBE_VBD_TREE_NR_OF_CHILDREN = 64, + CBE_FREE_TREE_NR_OF_LEVELS = 6, + CBE_FREE_TREE_NR_OF_CHILDREN = 64, + CBE_NR_OF_SUPERBLOCKS = 8, + }; + + enum class State + { + INVALID, + SETUP_OBTAIN_PARAMETERS, + SETUP_CREATE_CBE_IMAGE_FILE, + SETUP_RUN_CBE_INIT_TRUST_ANCHOR, + SETUP_RUN_CBE_INIT, + SETUP_START_CBE_VFS, + SETUP_FORMAT_CBE, + STARTUP_OBTAIN_PARAMETERS, + STARTUP_RUN_CBE_INIT_TRUST_ANCHOR, + STARTUP_START_CBE_VFS, + STARTUP_DETERMINE_CLIENT_FS_SIZE, + CONTROLS_ROOT, + CONTROLS_SNAPSHOTS, + CONTROLS_DIMENSIONS, + CONTROLS_EXPAND_CLIENT_FS, + CONTROLS_EXPAND_SNAPSHOT_BUF, + CONTROLS_SECURITY, + CONTROLS_SECURITY_BLOCK_ENCRYPTION_KEY, + CONTROLS_SECURITY_MASTER_KEY, + CONTROLS_SECURITY_USER_PASSPHRASE, + SHUTDOWN_ISSUE_DEINIT_REQUEST_AT_CBE, + SHUTDOWN_WAIT_TILL_DEINIT_REQUEST_IS_DONE + }; + + enum class Setup_obtain_params_hover + { + NONE, + PASSPHRASE_INPUT, + PASSPHRASE_SHOW_HIDE_BUTTON, + CLIENT_FS_SIZE_INPUT, + SNAPSHOT_BUFFER_SIZE_INPUT, + START_BUTTON + }; + + enum class Setup_obtain_params_select + { + NONE, + PASSPHRASE_INPUT, + PASSPHRASE_SHOW_HIDE_BUTTON, + CLIENT_FS_SIZE_INPUT, + SNAPSHOT_BUFFER_SIZE_INPUT, + START_BUTTON + }; + + enum class Controls_root_select + { + NONE, + SHUT_DOWN_BUTTON, + }; + + enum class Controls_root_hover + { + NONE, + SNAPSHOTS_EXPAND_BUTTON, + DIMENSIONS_BUTTON, + SECURITY_EXPAND_BUTTON, + SHUT_DOWN_BUTTON, + }; + + enum class Controls_snapshots_select + { + NONE, + SHUT_DOWN_BUTTON, + CREATE_BUTTON, + GENERATION_DISCARD_BUTTON, + }; + + enum class Controls_snapshots_hover + { + NONE, + SHUT_DOWN_BUTTON, + LEAVE_BUTTON, + CREATE_BUTTON, + GENERATION_LEAVE_BUTTON, + GENERATION_DISCARD_BUTTON, + }; + + enum class Dimensions_select + { + NONE, + EXPAND_CLIENT_FS_EXPAND_BUTTON, + EXPAND_SNAP_BUF_EXPAND_BUTTON, + SHUT_DOWN_BUTTON, + }; + + enum class Dimensions_hover + { + NONE, + LEAVE_BUTTON, + EXPAND_CLIENT_FS_BUTTON, + EXPAND_SNAPSHOT_BUF_BUTTON, + SHUT_DOWN_BUTTON, + }; + + enum class Expand_client_fs_select + { + NONE, + CONTINGENT_INPUT, + START_BUTTON, + SHUT_DOWN_BUTTON, + }; + + enum class Expand_client_fs_hover + { + NONE, + LEAVE_BUTTON, + CONTINGENT_INPUT, + START_BUTTON, + SHUT_DOWN_BUTTON, + }; + + enum class Expand_snapshot_buf_select + { + NONE, + CONTINGENT_INPUT, + START_BUTTON, + SHUT_DOWN_BUTTON, + }; + + enum class Expand_snapshot_buf_hover + { + NONE, + LEAVE_BUTTON, + CONTINGENT_INPUT, + START_BUTTON, + SHUT_DOWN_BUTTON, + }; + + enum class Controls_security_block_encryption_key_select + { + NONE, + REPLACE_BUTTON, + SHUT_DOWN_BUTTON, + }; + + enum class Controls_security_block_encryption_key_hover + { + NONE, + LEAVE_BUTTON, + REPLACE_BUTTON, + SHUT_DOWN_BUTTON, + }; + + enum class Controls_security_master_key_select + { + NONE, + SHUT_DOWN_BUTTON, + }; + + enum class Controls_security_master_key_hover + { + NONE, + LEAVE_BUTTON, + SHUT_DOWN_BUTTON, + }; + + enum class Controls_security_user_passphrase_select + { + NONE, + SHUT_DOWN_BUTTON, + }; + + enum class Controls_security_user_passphrase_hover + { + NONE, + LEAVE_BUTTON, + SHUT_DOWN_BUTTON, + }; + + enum class Controls_security_select + { + NONE, + BLOCK_ENCRYPTION_KEY_EXPAND_BUTTON, + MASTER_KEY_EXPAND_BUTTON, + USER_PASSPHRASE_EXPAND_BUTTON, + SHUT_DOWN_BUTTON, + }; + + enum class Controls_security_hover + { + NONE, + SECURITY_EXPAND_BUTTON, + BLOCK_ENCRYPTION_KEY_EXPAND_BUTTON, + MASTER_KEY_EXPAND_BUTTON, + USER_PASSPHRASE_EXPAND_BUTTON, + SHUT_DOWN_BUTTON, + }; + + enum class Resizing_type + { + NONE, + EXPAND_CLIENT_FS, + EXPAND_SNAPSHOT_BUF, + }; + + enum class Resizing_state + { + INACTIVE, + ADAPT_CBE_IMAGE_SIZE, + WAIT_TILL_DEVICE_IS_READY, + ISSUE_REQUEST_AT_DEVICE, + IN_PROGRESS_AT_DEVICE, + DETERMINE_CLIENT_FS_SIZE, + RUN_RESIZE2FS, + }; + + enum class Rekeying_state + { + INACTIVE, + WAIT_TILL_DEVICE_IS_READY, + ISSUE_REQUEST_AT_DEVICE, + IN_PROGRESS_AT_DEVICE, + }; + + enum class Create_snapshot_state + { + INACTIVE, + ISSUE_REQUEST_AT_DEVICE, + }; + + enum class Discard_snapshot_state + { + INACTIVE, + ISSUE_REQUEST_AT_DEVICE, + }; + + using Report_service = Sandbox::Local_service; + using Gui_service = Sandbox::Local_service; + using Rom_service = Sandbox::Local_service; + using Xml_report_handler = Report::Session_component::Xml_handler
; + using State_string = String; + using Snapshot_registry = Registry>; + using Snapshot_pointer = Const_pointer; + + Env &_env; + State _state { State::INVALID }; + Heap _heap { _env.ram(), _env.rm() }; + Timer::Connection _timer { _env }; + Attached_rom_dataspace _config { _env, "config" }; + Root_directory _vfs { _env, _heap, _config.xml().sub_node("vfs") }; + Registry _children { }; + Child_state _menu_view { _children, "menu_view", Ram_quota { 4 * 1024 * 1024 }, Cap_quota { 200 } }; + Child_state _mke2fs { _children, "mke2fs", Ram_quota { 100 * 1024 * 1024 }, Cap_quota { 500 } }; + Child_state _resize2fs { _children, "resize2fs", Ram_quota { 100 * 1024 * 1024 }, Cap_quota { 500 } }; + Child_state _cbe_vfs { _children, "cbe_vfs", "vfs", Ram_quota { 64 * 1024 * 1024 }, Cap_quota { 200 } }; + Child_state _cbe_trust_anchor_vfs { _children, "cbe_trust_anchor_vfs", "vfs", Ram_quota { 4 * 1024 * 1024 }, Cap_quota { 100 } }; + Child_state _rump_vfs { _children, "rump_vfs", "vfs", Ram_quota { 16 * 1024 * 1024 }, Cap_quota { 200 } }; + Child_state _sync_to_cbe_vfs_init { _children, "sync_to_cbe_vfs_init", "file_vault-sync_to_cbe_vfs_init", Ram_quota { 8 * 1024 * 1024 }, Cap_quota { 100 } }; + Child_state _truncate_file { _children, "truncate_file", "file_vault-truncate_file", Ram_quota { 4 * 1024 * 1024 }, Cap_quota { 100 } }; + Child_state _cbe_vfs_block { _children, "vfs_block", Ram_quota { 4 * 1024 * 1024 }, Cap_quota { 100 } }; + Child_state _fs_query { _children, "fs_query", Ram_quota { 1 * 1024 * 1024 }, Cap_quota { 100 } }; + Child_state _image_fs_query { _children, "image_fs_query", "fs_query", Ram_quota { 1 * 1024 * 1024 }, Cap_quota { 100 } }; + Child_state _client_fs_fs_query { _children, "client_fs_fs_query", "fs_query", Ram_quota { 1 * 1024 * 1024 }, Cap_quota { 100 } }; + Child_state _cbe_init_trust_anchor { _children, "cbe_init_trust_anchor", Ram_quota { 4 * 1024 * 1024 }, Cap_quota { 100 } }; + Child_state _cbe_image_vfs_block { _children, "vfs_block", Ram_quota { 4 * 1024 * 1024 }, Cap_quota { 100 } }; + Child_state _cbe_init { _children, "cbe_init", Ram_quota { 4 * 1024 * 1024 }, Cap_quota { 100 } }; + Child_state _snapshots_fs_query { _children, "snapshots_fs_query", "fs_query", Ram_quota { 1 * 1024 * 1024 }, Cap_quota { 100 } }; + Child_state _resizing_fs_tool { _children, "resizing_fs_tool", "fs_tool", Ram_quota { 5 * 1024 * 1024 }, Cap_quota { 200 } }; + Child_state _resizing_fs_query { _children, "resizing_fs_query", "fs_query", Ram_quota { 1 * 1024 * 1024 }, Cap_quota { 100 } }; + Child_state _rekeying_fs_tool { _children, "rekeying_fs_tool", "fs_tool", Ram_quota { 5 * 1024 * 1024 }, Cap_quota { 200 } }; + Child_state _rekeying_fs_query { _children, "rekeying_fs_query", "fs_query", Ram_quota { 1 * 1024 * 1024 }, Cap_quota { 100 } }; + Child_state _shut_down_fs_tool { _children, "shut_down_fs_tool", "fs_tool", Ram_quota { 5 * 1024 * 1024 }, Cap_quota { 200 } }; + Child_state _shut_down_fs_query { _children, "shut_down_fs_query", "fs_query", Ram_quota { 1 * 1024 * 1024 }, Cap_quota { 100 } }; + Child_state _create_snap_fs_tool { _children, "create_snap_fs_tool", "fs_tool", Ram_quota { 5 * 1024 * 1024 }, Cap_quota { 200 } }; + Child_state _discard_snap_fs_tool { _children, "discard_snap_fs_tool", "fs_tool", Ram_quota { 5 * 1024 * 1024 }, Cap_quota { 200 } }; + Xml_report_handler _fs_query_listing_handler { *this, &Main::_handle_fs_query_listing }; + Xml_report_handler _image_fs_query_listing_handler { *this, &Main::_handle_image_fs_query_listing }; + Xml_report_handler _client_fs_fs_query_listing_handler { *this, &Main::_handle_client_fs_fs_query_listing }; + Xml_report_handler _snapshots_fs_query_listing_handler { *this, &Main::_handle_snapshots_fs_query_listing }; + Xml_report_handler _resizing_fs_query_listing_handler { *this, &Main::_handle_resizing_fs_query_listing }; + Xml_report_handler _rekeying_fs_query_listing_handler { *this, &Main::_handle_rekeying_fs_query_listing }; + Xml_report_handler _shut_down_fs_query_listing_handler { *this, &Main::_handle_shut_down_fs_query_listing }; + Sandbox _sandbox { _env, *this }; + Gui_service _gui_service { _sandbox, *this }; + Rom_service _rom_service { _sandbox, *this }; + Report_service _report_service { _sandbox, *this }; + Xml_report_handler _hover_handler { *this, &Main::_handle_hover }; + Constructible> _watch_handler { }; + Constructible _clipboard_reporter { }; + Constructible _clipboard_rom { }; + bool _initial_config { true }; + Signal_handler
_config_handler { _env.ep(), *this, &Main::_handle_config }; + Signal_handler
_state_handler { _env.ep(), *this, &Main::_handle_state }; + Dynamic_rom_session _dialog { _env.ep(), _env.ram(), _env.rm(), *this }; + Input_passphrase _setup_obtain_params_passphrase { }; + Input_number_of_bytes _client_fs_size_input { }; + Input_number_of_bytes _snapshot_buf_size_input { }; + Setup_obtain_params_hover _setup_obtain_params_hover { Setup_obtain_params_hover::NONE }; + Setup_obtain_params_select _setup_obtain_params_select { Setup_obtain_params_select::PASSPHRASE_INPUT }; + Controls_root_hover _controls_root_hover { Controls_root_hover::NONE }; + Controls_root_select _controls_root_select { Controls_root_select::NONE }; + Controls_snapshots_hover _controls_snapshots_hover { Controls_snapshots_hover::NONE }; + Controls_snapshots_select _controls_snapshots_select { Controls_snapshots_select::NONE }; + Dimensions_hover _dimensions_hover { Dimensions_hover::NONE }; + Dimensions_select _dimensions_select { Dimensions_select::NONE }; + Expand_client_fs_hover _expand_client_fs_hover { Expand_client_fs_hover::NONE }; + Expand_client_fs_select _expand_client_fs_select { Expand_client_fs_select::NONE }; + Expand_snapshot_buf_hover _expand_snapshot_buf_hover { Expand_snapshot_buf_hover::NONE }; + Expand_snapshot_buf_select _expand_snapshot_buf_select { Expand_snapshot_buf_select::NONE }; + Controls_security_hover _controls_security_hover { Controls_security_hover::NONE }; + Controls_security_select _controls_security_select { Controls_security_select::NONE }; + + Controls_security_master_key_hover _controls_security_master_key_hover { Controls_security_master_key_hover::NONE }; + Controls_security_master_key_select _controls_security_master_key_select { Controls_security_master_key_select::NONE }; + Controls_security_block_encryption_key_hover _controls_security_block_encryption_key_hover { Controls_security_block_encryption_key_hover::NONE }; + Controls_security_block_encryption_key_select _controls_security_block_encryption_key_select { Controls_security_block_encryption_key_select::NONE }; + Controls_security_user_passphrase_hover _controls_security_user_passphrase_hover { Controls_security_user_passphrase_hover::NONE }; + Controls_security_user_passphrase_select _controls_security_user_passphrase_select { Controls_security_user_passphrase_select::NONE }; + + Resizing_state _resizing_state { Resizing_state::INACTIVE }; + Resizing_type _resizing_type { Resizing_type::NONE }; + Input_number_of_bytes _expand_client_fs_contingent { }; + Input_number_of_bytes _expand_snapshot_buf_contingent { }; + Rekeying_state _rekeying_state { Rekeying_state::INACTIVE }; + Create_snapshot_state _create_snap_state { Create_snapshot_state::INACTIVE }; + Discard_snapshot_state _discard_snap_state { Discard_snapshot_state::INACTIVE }; + Generation _discard_snap_gen { INVALID_GENERATION }; + Snapshot_registry _snapshots { }; + Snapshot_pointer _snapshots_hover { }; + Snapshot_pointer _snapshots_select { }; + bool _snapshots_expanded { false }; + bool _dimensions_expanded { false }; + Timer::One_shot_timeout
_startup_retry_delay { _timer, *this, &Main::_handle_startup_retry_delay }; + size_t _cbe_image_size { 0 }; + size_t _client_fs_size { 0 }; + bool _nr_of_clients { 0 }; + + static bool _has_name(Xml_node const &node, + Node_name const &name) + { + return node.attribute_value("name", Node_name { }) == name; + } + + size_t _min_snapshot_buf_size() const + { + size_t result { _client_fs_size_input.value() >> 8 }; + if (result < MIN_CLIENT_FS_SIZE) { + result = MIN_CLIENT_FS_SIZE; + } + return result; + } + + template + static void _if_child_exited(Xml_node const &sandbox_state, + Child_state const &child_state, + FUNCTOR const &functor) + { + Child_exit_state const exit_state { sandbox_state, child_state.start_name() }; + + if (!exit_state.exists()) { + class Child_doesnt_exist { }; + throw Child_doesnt_exist { }; + } + if (exit_state.exited()) { + + functor(exit_state.code()); + } + } + + static bool _child_succeeded(Xml_node const &sandbox_state, + Child_state const &child_state); + + static size_t _child_nr_of_provided_sessions(Xml_node const &sandbox_state, + Child_state const &child_state, + String<64> const &service_name); + + void _handle_startup_retry_delay(Duration); + + static State _state_from_string(State_string const &str); + + static State_string _state_to_string(State state); + + static State _state_from_fs_query_listing(Xml_node const &node); + + void _write_to_state_file(State state); + + void _generate_sandbox_config(Xml_generator &xml) const; + + void _handle_fs_query_listing(Xml_node const &node); + + void _handle_image_fs_query_listing(Xml_node const &node); + + void _handle_client_fs_fs_query_listing(Xml_node const &node); + + void _handle_snapshots_fs_query_listing(Xml_node const &node); + + void _handle_resizing_fs_query_listing(Xml_node const &node); + + void _handle_rekeying_fs_query_listing(Xml_node const &node); + + void _handle_shut_down_fs_query_listing(Xml_node const &node); + + void _handle_hover(Xml_node const &node); + + void _handle_config(); + + void _handle_state(); + + void _update_sandbox_config(); + + static size_t _cbe_tree_nr_of_leaves(size_t payload_size); + + + static size_t _tree_nr_of_blocks(size_t nr_of_lvls, + size_t nr_of_children, + size_t nr_of_leafs); + + size_t _cbe_size() const; + + static size_t _cbe_nr_of_blocks(size_t nr_of_superblocks, + size_t nr_of_vbd_lvls, + size_t nr_of_vbd_children, + size_t nr_of_vbd_leafs, + size_t nr_of_ft_lvls, + size_t nr_of_ft_children, + size_t nr_of_ft_leafs); + + static bool cbe_control_file_yields_state_idle(Xml_node const &fs_query_listing, + char const *file_name); + + + /*************************************************** + ** Sandbox::Local_service_base::Wakeup interface ** + ***************************************************/ + + void wakeup_local_service() override; + + + /**************************** + ** Sandbox::State_handler ** + ****************************/ + + void handle_sandbox_state() override; + + + /**************************************** + ** Gui::Input_event_handler interface ** + ****************************************/ + + void handle_input_event(Input::Event const &event) override; + + + /*************************************** + ** Dynamic_rom_session::Xml_producer ** + ***************************************/ + + void produce_xml(Xml_generator &xml) override; + + public: + + Main(Env &env); +}; + +using namespace File_vault; + + +/********************** + ** File_vault::Main ** + **********************/ + +void Main::_handle_config() +{ + _config.update(); + _initial_config = false; +} + + +bool Main::cbe_control_file_yields_state_idle(Xml_node const &fs_query_listing, + char const *file_name) +{ + bool result { false }; + bool done { false }; + fs_query_listing.with_sub_node("dir", [&] (Xml_node const &node_0) { + node_0.for_each_sub_node("file", [&] (Xml_node const &node_1) { + if (done) { + return; + } + if (node_1.attribute_value("name", String<16>()) == file_name) { + node_1.with_raw_content([&] (char const *base, size_t size) { + result = String<5> { Cstring {base, size} } == "idle"; + done = true; + }); + } + }); + }); + return result; +} + + +void Main::_update_sandbox_config() +{ + Buffered_xml const config { _heap, "config", [&] (Xml_generator &xml) { + _generate_sandbox_config(xml); } }; + + config.with_xml_node([&] (Xml_node const &config) { + _sandbox.apply_config(config); }); +} + + +Main::State Main::_state_from_string(State_string const &str) +{ + if (str == "invalid") { return State::INVALID; } + if (str == "setup_obtain_parameters") { return State::SETUP_OBTAIN_PARAMETERS; } + if (str == "setup_run_cbe_init_trust_anchor") { return State::SETUP_RUN_CBE_INIT_TRUST_ANCHOR; } + if (str == "setup_create_cbe_image_file") { return State::SETUP_CREATE_CBE_IMAGE_FILE; } + if (str == "setup_run_cbe_init") { return State::SETUP_RUN_CBE_INIT; } + if (str == "setup_start_cbe_vfs") { return State::SETUP_START_CBE_VFS; } + if (str == "setup_format_cbe") { return State::SETUP_FORMAT_CBE; } + if (str == "controls_root") { return State::CONTROLS_ROOT; } + if (str == "controls_snapshots") { return State::CONTROLS_SNAPSHOTS; } + if (str == "controls_dimensions") { return State::CONTROLS_DIMENSIONS; } + if (str == "controls_expand_client_fs") { return State::CONTROLS_EXPAND_CLIENT_FS; } + if (str == "controls_expand_snapshot_buf") { return State::CONTROLS_EXPAND_SNAPSHOT_BUF; } + if (str == "controls_security") { return State::CONTROLS_SECURITY; } + if (str == "controls_security_block_encryption_key") { return State::CONTROLS_SECURITY_BLOCK_ENCRYPTION_KEY; } + if (str == "controls_security_master_key") { return State::CONTROLS_SECURITY_MASTER_KEY; } + if (str == "controls_security_user_passphrase") { return State::CONTROLS_SECURITY_USER_PASSPHRASE; } + if (str == "startup_obtain_parameters") { return State::STARTUP_OBTAIN_PARAMETERS; } + if (str == "startup_run_cbe_init_trust_anchor") { return State::STARTUP_RUN_CBE_INIT_TRUST_ANCHOR; } + if (str == "startup_start_cbe_vfs") { return State::STARTUP_START_CBE_VFS; } + if (str == "startup_determine_client_fs_size") { return State::STARTUP_DETERMINE_CLIENT_FS_SIZE; } + if (str == "shutdown_issue_deinit_request_at_cbe") { return State::SHUTDOWN_ISSUE_DEINIT_REQUEST_AT_CBE; } + if (str == "shutdown_wait_till_deinit_request_is_done") { return State::SHUTDOWN_WAIT_TILL_DEINIT_REQUEST_IS_DONE; } + class Invalid_state_string { }; + throw Invalid_state_string { }; +} + + +Main::State_string Main::_state_to_string(State state) +{ + switch (state) { + case State::INVALID: return "invalid"; + case State::SETUP_OBTAIN_PARAMETERS: return "setup_obtain_parameters"; + case State::SETUP_RUN_CBE_INIT_TRUST_ANCHOR: return "setup_run_cbe_init_trust_anchor"; + case State::SETUP_CREATE_CBE_IMAGE_FILE: return "setup_create_cbe_image_file"; + case State::SETUP_RUN_CBE_INIT: return "setup_run_cbe_init"; + case State::SETUP_START_CBE_VFS: return "setup_start_cbe_vfs"; + case State::SETUP_FORMAT_CBE: return "setup_format_cbe"; + case State::CONTROLS_ROOT: return "controls_root"; + case State::CONTROLS_SNAPSHOTS: return "controls_snapshots"; + case State::CONTROLS_DIMENSIONS: return "controls_dimensions"; + case State::CONTROLS_EXPAND_CLIENT_FS: return "controls_expand_client_fs"; + case State::CONTROLS_EXPAND_SNAPSHOT_BUF: return "controls_expand_snapshot_buf"; + case State::CONTROLS_SECURITY: return "controls_security"; + case State::CONTROLS_SECURITY_BLOCK_ENCRYPTION_KEY: return "controls_security_block_encryption_key"; + case State::CONTROLS_SECURITY_MASTER_KEY: return "controls_security_master_key"; + case State::CONTROLS_SECURITY_USER_PASSPHRASE: return "controls_security_user_passphrase"; + case State::STARTUP_OBTAIN_PARAMETERS: return "startup_obtain_parameters"; + case State::STARTUP_RUN_CBE_INIT_TRUST_ANCHOR: return "startup_run_cbe_init_trust_anchor"; + case State::STARTUP_START_CBE_VFS: return "startup_start_cbe_vfs"; + case State::STARTUP_DETERMINE_CLIENT_FS_SIZE: return "startup_determine_client_fs_size"; + case State::SHUTDOWN_ISSUE_DEINIT_REQUEST_AT_CBE: return "shutdown_issue_deinit_request_at_cbe"; + case State::SHUTDOWN_WAIT_TILL_DEINIT_REQUEST_IS_DONE: return "shutdown_wait_till_deinit_request_is_done"; + } + class Invalid_state { }; + throw Invalid_state { }; +} + + +Main::State Main::_state_from_fs_query_listing(Xml_node const &node) +{ + State state { State::INVALID }; + node.with_sub_node("dir", [&] (Xml_node const &node_0) { + node_0.with_sub_node("file", [&] (Xml_node const &node_1) { + if (_has_name(node_1, "state")) { + state = _state_from_string( + node_1.decoded_content()); + } + }); + }); + return state; +} + + +void Main::_write_to_state_file(State state) +{ + bool write_error = false; + try { + New_file new_file(_vfs, Directory::Path("/cbe/file_vault/state")); + auto write = [&] (char const *str) + { + switch (new_file.append(str, strlen(str))) { + case New_file::Append_result::OK: + + break; + + case New_file::Append_result::WRITE_ERROR: + + write_error = true; + break; + } + }; + Buffered_output output(write); + print(output, _state_to_string(state)); + } + catch (New_file::Create_failed) { + + class Create_state_file_failed { }; + throw Create_state_file_failed { }; + } + if (write_error) { + + class Write_state_file_failed { }; + throw Write_state_file_failed { }; + } +} + + +void Main::_handle_resizing_fs_query_listing(Xml_node const &node) +{ + switch (_state) { + case State::CONTROLS_ROOT: + case State::CONTROLS_SNAPSHOTS: + case State::CONTROLS_DIMENSIONS: + case State::CONTROLS_EXPAND_CLIENT_FS: + case State::CONTROLS_EXPAND_SNAPSHOT_BUF: + case State::CONTROLS_SECURITY: + case State::CONTROLS_SECURITY_BLOCK_ENCRYPTION_KEY: + case State::CONTROLS_SECURITY_MASTER_KEY: + case State::CONTROLS_SECURITY_USER_PASSPHRASE: + + switch (_resizing_state) { + case Resizing_state::WAIT_TILL_DEVICE_IS_READY: + + if (cbe_control_file_yields_state_idle(node, "extend")) { + + _resizing_state = Resizing_state::ISSUE_REQUEST_AT_DEVICE; + Signal_transmitter(_state_handler).submit(); + } + break; + + case Resizing_state::IN_PROGRESS_AT_DEVICE: + + if (cbe_control_file_yields_state_idle(node, "extend")) { + + switch (_resizing_type) { + case Resizing_type::EXPAND_CLIENT_FS: + + _expand_client_fs_contingent = Input_number_of_bytes { }; + _expand_client_fs_select = Expand_client_fs_select::CONTINGENT_INPUT; + break; + + case Resizing_type::EXPAND_SNAPSHOT_BUF: + + _expand_snapshot_buf_contingent = Input_number_of_bytes { }; + _expand_snapshot_buf_select = Expand_snapshot_buf_select::CONTINGENT_INPUT; + break; + + default: + + class Unexpected_resizing_type { }; + throw Unexpected_resizing_type { }; + break; + } + _resizing_state = Resizing_state::DETERMINE_CLIENT_FS_SIZE; + Signal_transmitter(_state_handler).submit(); + } + break; + + default: + + break; + } + + default: + + break; + } +} + + +void Main::_handle_shut_down_fs_query_listing(Xml_node const &node) +{ + switch (_state) { + case State::SHUTDOWN_WAIT_TILL_DEINIT_REQUEST_IS_DONE: + + if (cbe_control_file_yields_state_idle(node, "deinitialize")) { + + _env.parent().exit(0); + } + break; + + default: + + break; + } +} + + +void Main::_handle_rekeying_fs_query_listing(Xml_node const &node) +{ + switch (_state) { + case State::CONTROLS_ROOT: + case State::CONTROLS_SNAPSHOTS: + case State::CONTROLS_DIMENSIONS: + case State::CONTROLS_EXPAND_CLIENT_FS: + case State::CONTROLS_EXPAND_SNAPSHOT_BUF: + case State::CONTROLS_SECURITY: + case State::CONTROLS_SECURITY_BLOCK_ENCRYPTION_KEY: + case State::CONTROLS_SECURITY_MASTER_KEY: + case State::CONTROLS_SECURITY_USER_PASSPHRASE: + + switch (_rekeying_state) { + case Rekeying_state::WAIT_TILL_DEVICE_IS_READY: + + if (cbe_control_file_yields_state_idle(node, "rekey")) { + + _rekeying_state = Rekeying_state::ISSUE_REQUEST_AT_DEVICE; + Signal_transmitter(_state_handler).submit(); + } + break; + + case Rekeying_state::IN_PROGRESS_AT_DEVICE: + + if (cbe_control_file_yields_state_idle(node, "rekey")) { + + _rekeying_state = Rekeying_state::INACTIVE; + Signal_transmitter(_state_handler).submit(); + } + break; + + default: + + break; + } + break; + + default: + + break; + } +} + + +void Main::_handle_snapshots_fs_query_listing(Xml_node const &node) +{ + switch (_state) { + case State::CONTROLS_ROOT: + case State::CONTROLS_SNAPSHOTS: + case State::CONTROLS_DIMENSIONS: + case State::CONTROLS_EXPAND_CLIENT_FS: + case State::CONTROLS_EXPAND_SNAPSHOT_BUF: + case State::CONTROLS_SECURITY: + case State::CONTROLS_SECURITY_BLOCK_ENCRYPTION_KEY: + case State::CONTROLS_SECURITY_MASTER_KEY: + case State::CONTROLS_SECURITY_USER_PASSPHRASE: + { + bool update_dialog { false }; + node.with_sub_node("dir", [&] (Xml_node const &node_0) { + + _snapshots.for_each([&] (Snapshot const &snap) + { + bool snap_still_exists { false }; + node_0.for_each_sub_node("dir", [&] (Xml_node const &node_1) { + + if (snap_still_exists) { + return; + } + Generation const generation { + node_1.attribute_value( + "name", Generation { INVALID_GENERATION }) }; + + if (generation == INVALID_GENERATION) { + warning("skipping snapshot file with invalid generation number"); + return; + } + if (generation == snap.generation()) { + snap_still_exists = true; + return; + } + }); + if (!snap_still_exists) { + + if (_snapshots_select.valid() && + &_snapshots_select.object() == &snap) { + + _snapshots_select = Snapshot_pointer { }; + } + if (_snapshots_hover.valid() && + &_snapshots_hover.object() == &snap) { + + _snapshots_hover = Snapshot_pointer { }; + } + destroy(&_heap, &const_cast(snap)); + update_dialog = true; + } + }); + + node_0.for_each_sub_node("dir", [&] (Xml_node const &node_1) { + + Generation const generation { + node_1.attribute_value( + "name", Generation { INVALID_GENERATION }) }; + + if (generation == INVALID_GENERATION) { + warning("skipping snapshot file with invalid generation number"); + return; + } + bool snap_already_exists { false }; + _snapshots.for_each([&] (Snapshot const &snap) + { + if (generation == snap.generation()) { + snap_already_exists = true; + } + }); + if (!snap_already_exists) { + new (_heap) Registered(_snapshots, generation); + update_dialog = true; + } + }); + }); + if (update_dialog) { + _dialog.trigger_update(); + } + + break; + } + default: + + break; + } +} + + +void Main::_handle_fs_query_listing(Xml_node const &node) +{ + switch (_state) { + case State::INVALID: + { + State const state { _state_from_fs_query_listing(node) }; + switch (state) { + case State::INVALID: + + _state = State::SETUP_OBTAIN_PARAMETERS; + Signal_transmitter(_state_handler).submit(); + break; + + case State::STARTUP_OBTAIN_PARAMETERS: + + _state = State::STARTUP_OBTAIN_PARAMETERS; + Signal_transmitter(_state_handler).submit(); + break; + + default: + + class Unexpected_state { }; + throw Unexpected_state { }; + } + break; + } + default: + + break; + } +} + + +void Main::_handle_client_fs_fs_query_listing(Xml_node const &node) +{ + switch (_state) { + case State::STARTUP_DETERMINE_CLIENT_FS_SIZE: + + node.with_sub_node("dir", [&] (Xml_node const &node_0) { + node_0.with_sub_node("file", [&] (Xml_node const &node_1) { + + if (_has_name(node_1, "data")) { + + _client_fs_size = node_1.attribute_value("size", (size_t)0); + _state = State::CONTROLS_ROOT; + Signal_transmitter(_state_handler).submit(); + } + }); + }); + break; + + case State::CONTROLS_ROOT: + case State::CONTROLS_SNAPSHOTS: + case State::CONTROLS_DIMENSIONS: + case State::CONTROLS_EXPAND_CLIENT_FS: + case State::CONTROLS_EXPAND_SNAPSHOT_BUF: + case State::CONTROLS_SECURITY: + case State::CONTROLS_SECURITY_BLOCK_ENCRYPTION_KEY: + case State::CONTROLS_SECURITY_MASTER_KEY: + case State::CONTROLS_SECURITY_USER_PASSPHRASE: + + switch (_resizing_state) { + case Resizing_state::DETERMINE_CLIENT_FS_SIZE: + + node.with_sub_node("dir", [&] (Xml_node const &node_0) { + node_0.with_sub_node("file", [&] (Xml_node const &node_1) { + + if (_has_name(node_1, "data")) { + + size_t const size { + node_1.attribute_value("size", (size_t)0) }; + + if (_client_fs_size != size) { + + _client_fs_size = size; + _resizing_state = Resizing_state::RUN_RESIZE2FS; + Signal_transmitter(_state_handler).submit(); + + } else { + + _resizing_type = Resizing_type::NONE; + _resizing_state = Resizing_state::INACTIVE; + Signal_transmitter(_state_handler).submit(); + } + } + }); + }); + break; + + default: + + break; + } + + default: + + break; + } +} + + +void Main::_handle_image_fs_query_listing(Xml_node const &node) +{ + bool update_dialog { false }; + + switch (_state) { + case State::CONTROLS_ROOT: + case State::CONTROLS_SNAPSHOTS: + case State::CONTROLS_DIMENSIONS: + case State::CONTROLS_EXPAND_CLIENT_FS: + case State::CONTROLS_EXPAND_SNAPSHOT_BUF: + case State::CONTROLS_SECURITY: + case State::CONTROLS_SECURITY_BLOCK_ENCRYPTION_KEY: + case State::CONTROLS_SECURITY_MASTER_KEY: + case State::CONTROLS_SECURITY_USER_PASSPHRASE: + { + size_t size { 0 }; + node.with_sub_node("dir", [&] (Xml_node const &node_0) { + node_0.with_sub_node("file", [&] (Xml_node const &node_1) { + if (_has_name(node_1, "cbe.img")) { + size = node_1.attribute_value("size", (size_t)0); + } + }); + }); + if (_cbe_image_size != size) { + + _cbe_image_size = size; + update_dialog = true; + } + break; + } + default: + + break; + } + if (update_dialog) { + _dialog.trigger_update(); + } +} + + +void Main::_handle_state() +{ + _update_sandbox_config(); + _dialog.trigger_update(); +} + + +Main::Main(Env &env) +: + Xml_producer { "dialog" }, + _env { env } +{ + _config.sigh(_config_handler); + _handle_config(); + _update_sandbox_config(); +} + + +size_t +File_vault::Main:: +_child_nr_of_provided_sessions(Xml_node const &sandbox_state, + Child_state const &child_state, + String<64> const &service_name) +{ + size_t result { 0 }; + sandbox_state.for_each_sub_node("child", [&] (Xml_node child) { + + if (child.attribute_value("name", String<128> { }) == child_state.start_name()) { + + child.with_sub_node("provided", [&] (Xml_node const &provided) { + provided.for_each_sub_node("session", [&] (Xml_node const &session) { + + if (session.attribute_value("service", String<64> { }) == service_name) { + result++; + } + }); + }); + } + }); + return result; +} + + +bool File_vault::Main::_child_succeeded(Xml_node const &sandbox_state, + Child_state const &child_state) +{ + Child_exit_state const exit_state { sandbox_state, child_state.start_name() }; + + if (!exit_state.exists()) { + class Child_doesnt_exist { }; + throw Child_doesnt_exist { }; + } + if (exit_state.exited()) { + + if (exit_state.code() != 0) { + class Child_exited_with_error { }; + throw Child_exited_with_error { }; + } + return true; + } + return false; +} + +void File_vault::Main::_handle_startup_retry_delay(Duration) +{ + _state = State::STARTUP_OBTAIN_PARAMETERS; + _setup_obtain_params_passphrase = Input_passphrase { }; + _setup_obtain_params_select = Setup_obtain_params_select::PASSPHRASE_INPUT; + _dialog.trigger_update(); + _update_sandbox_config(); +} + + +void File_vault::Main::handle_sandbox_state() +{ + Buffered_xml sandbox_state { + _heap, "sandbox_state", + [&] (Xml_generator &xml) { + _sandbox.generate_state_report(xml); + } + }; + bool update_sandbox { false }; + bool update_dialog { false }; + bool nr_of_clients { false }; + sandbox_state.with_xml_node([&] (Xml_node const &sandbox_state) { + + switch (_state) { + case State::SETUP_RUN_CBE_INIT_TRUST_ANCHOR: + + if (_child_succeeded(sandbox_state, _cbe_init_trust_anchor)) { + + _state = State::SETUP_RUN_CBE_INIT; + update_dialog = true; + update_sandbox = true; + } + break; + + case State::SETUP_CREATE_CBE_IMAGE_FILE: + + if (_child_succeeded(sandbox_state, _truncate_file)) { + + _state = State::SETUP_RUN_CBE_INIT_TRUST_ANCHOR; + update_dialog = true; + update_sandbox = true; + } + break; + + case State::STARTUP_RUN_CBE_INIT_TRUST_ANCHOR: + + _if_child_exited(sandbox_state, _cbe_init_trust_anchor, [&] (int exit_code) { + + if (exit_code == 0) { + + _state = State::STARTUP_START_CBE_VFS; + update_dialog = true; + update_sandbox = true; + + } else { + + _startup_retry_delay.schedule(Microseconds { 3000000 }); + } + }); + break; + + case State::SETUP_RUN_CBE_INIT: + + if (_child_succeeded(sandbox_state, _cbe_init)) { + + _state = State::SETUP_START_CBE_VFS; + update_dialog = true; + update_sandbox = true; + } + break; + + case State::SETUP_START_CBE_VFS: + + if (_child_succeeded(sandbox_state, _sync_to_cbe_vfs_init)) { + + _state = State::SETUP_FORMAT_CBE; + update_dialog = true; + update_sandbox = true; + } + break; + + case State::STARTUP_START_CBE_VFS: + + if (_child_succeeded(sandbox_state, _sync_to_cbe_vfs_init)) { + + _state = State::STARTUP_DETERMINE_CLIENT_FS_SIZE; + update_dialog = true; + update_sandbox = true; + } + break; + + case State::SETUP_FORMAT_CBE: + + if (_child_succeeded(sandbox_state, _mke2fs)) { + + _write_to_state_file(State::STARTUP_OBTAIN_PARAMETERS); + _state = State::STARTUP_DETERMINE_CLIENT_FS_SIZE; + update_dialog = true; + update_sandbox = true; + } + break; + + case State::CONTROLS_ROOT: + case State::CONTROLS_SNAPSHOTS: + case State::CONTROLS_DIMENSIONS: + case State::CONTROLS_EXPAND_CLIENT_FS: + case State::CONTROLS_EXPAND_SNAPSHOT_BUF: + case State::CONTROLS_SECURITY: + case State::CONTROLS_SECURITY_BLOCK_ENCRYPTION_KEY: + case State::CONTROLS_SECURITY_MASTER_KEY: + case State::CONTROLS_SECURITY_USER_PASSPHRASE: + + if (_resizing_state == Resizing_state::INACTIVE || + _resizing_type != Resizing_type::EXPAND_CLIENT_FS) + { + nr_of_clients = + _child_nr_of_provided_sessions( + sandbox_state, _rump_vfs, "File_system"); + } + switch (_resizing_state) { + case Resizing_state::ADAPT_CBE_IMAGE_SIZE: + + if (_child_succeeded(sandbox_state, _truncate_file)) { + + _resizing_state = Resizing_state::WAIT_TILL_DEVICE_IS_READY; + update_dialog = true; + update_sandbox = true; + } + break; + + case Resizing_state::ISSUE_REQUEST_AT_DEVICE: + + if (_child_succeeded(sandbox_state, _resizing_fs_tool)) { + + _resizing_state = Resizing_state::IN_PROGRESS_AT_DEVICE; + update_dialog = true; + update_sandbox = true; + } + break; + + case Resizing_state::RUN_RESIZE2FS: + + if (_child_succeeded(sandbox_state, _resize2fs)) { + + _resizing_type = Resizing_type::NONE; + _resizing_state = Resizing_state::INACTIVE; + update_dialog = true; + update_sandbox = true; + } + break; + + default: + + break; + } + + switch (_rekeying_state) { + case Rekeying_state::ISSUE_REQUEST_AT_DEVICE: + + if (_child_succeeded(sandbox_state, _rekeying_fs_tool)) { + + _rekeying_state = Rekeying_state::IN_PROGRESS_AT_DEVICE; + update_dialog = true; + update_sandbox = true; + } + break; + + default: + + break; + } + + switch (_create_snap_state) { + case Create_snapshot_state::ISSUE_REQUEST_AT_DEVICE: + + if (_child_succeeded(sandbox_state, _create_snap_fs_tool)) { + + _create_snap_state = Create_snapshot_state::INACTIVE; + update_dialog = true; + update_sandbox = true; + } + break; + + default: + + break; + } + + switch (_discard_snap_state) { + case Discard_snapshot_state::ISSUE_REQUEST_AT_DEVICE: + + if (_child_succeeded(sandbox_state, _discard_snap_fs_tool)) { + + _discard_snap_state = Discard_snapshot_state::INACTIVE; + update_dialog = true; + update_sandbox = true; + } + break; + + default: + + break; + } + + break; + + case State::SHUTDOWN_ISSUE_DEINIT_REQUEST_AT_CBE: + + if (_child_succeeded(sandbox_state, _shut_down_fs_tool)) { + + _state = State::SHUTDOWN_WAIT_TILL_DEINIT_REQUEST_IS_DONE; + update_dialog = true; + update_sandbox = true; + } + break; + + default: + + break; + } + sandbox_state.for_each_sub_node("child", [&] (Xml_node const &child_node) { + _children.for_each([&] (Child_state &child_state) { + if (child_state.apply_child_state_report(child_node)) { + update_sandbox = true; + } + }); + }); + }); + if (_nr_of_clients != nr_of_clients) { + + _nr_of_clients = nr_of_clients; + update_dialog = true; + } + if (update_dialog) { + + _dialog.trigger_update(); + } + if (update_sandbox) { + + _update_sandbox_config(); + } +} + + +void File_vault::Main::produce_xml(Xml_generator &xml) +{ + switch (_state) { + case State::INVALID: + + gen_info_frame(xml, "1", "Please wait...", MAIN_FRAME_WIDTH); + break; + + case State::SETUP_OBTAIN_PARAMETERS: + + gen_main_frame(xml, "1", MAIN_FRAME_WIDTH, [&] (Xml_generator &xml) { + + bool gen_start_button { true }; + bool gen_image_size_info { true }; + gen_input_passphrase( + xml, MAIN_FRAME_WIDTH, + _setup_obtain_params_passphrase, + _setup_obtain_params_select == Setup_obtain_params_select::PASSPHRASE_INPUT, + _setup_obtain_params_hover == Setup_obtain_params_hover::PASSPHRASE_SHOW_HIDE_BUTTON, + _setup_obtain_params_select == Setup_obtain_params_select::PASSPHRASE_SHOW_HIDE_BUTTON); + + if (!_setup_obtain_params_passphrase.suitable()) { + + gen_start_button = false; + gen_info_line(xml, "info_1", "Must have at least 8 characters"); + } + gen_info_line(xml, "pad_1", ""); + gen_titled_text_input( + xml, "Client FS Size", "Client FS size", + _client_fs_size_input, + _setup_obtain_params_select == Setup_obtain_params_select::CLIENT_FS_SIZE_INPUT); + + if (_client_fs_size_input.value() < MIN_CLIENT_FS_SIZE) { + + gen_image_size_info = false; + gen_start_button = false; + gen_info_line(xml, "info_2", + String<128> { + "Must be at least ", + Number_of_bytes { MIN_CLIENT_FS_SIZE } }.string()); + + } + gen_info_line(xml, "pad_2", ""); + gen_titled_text_input( + xml, "Snapshot Buffer Size", + RENAME_SNAPSHOT_BUFFER_JOURNALING_BUFFER ? + "Journaling buffer size" : + "Snapshot buffer size", + _snapshot_buf_size_input, + _setup_obtain_params_select == Setup_obtain_params_select::SNAPSHOT_BUFFER_SIZE_INPUT); + + if (_snapshot_buf_size_input.value() < _min_snapshot_buf_size()) { + + gen_image_size_info = false; + gen_start_button = false; + gen_info_line(xml, "info_3", + String<128> { + "Must be at least ", + Number_of_bytes { _min_snapshot_buf_size() } }.string()); + } + if (gen_image_size_info) { + + gen_info_line(xml, "pad_3", ""); + gen_info_line( + xml, "info_4", + String<256> { "Image size: ", Capacity { _cbe_size() }}.string()); + } + gen_info_line(xml, "pad_4", ""); + if (gen_start_button) { + + gen_action_button_at_bottom( + xml, "ok", "Start", + _setup_obtain_params_hover == Setup_obtain_params_hover::START_BUTTON, + _setup_obtain_params_select == Setup_obtain_params_select::START_BUTTON); + } + }); + break; + + case State::STARTUP_OBTAIN_PARAMETERS: + + gen_main_frame(xml, "1", MAIN_FRAME_WIDTH, [&] (Xml_generator &xml) { + + bool gen_start_button { true }; + gen_input_passphrase( + xml, MAIN_FRAME_WIDTH, + _setup_obtain_params_passphrase, + _setup_obtain_params_select == Setup_obtain_params_select::PASSPHRASE_INPUT, + _setup_obtain_params_hover == Setup_obtain_params_hover::PASSPHRASE_SHOW_HIDE_BUTTON, + _setup_obtain_params_select == Setup_obtain_params_select::PASSPHRASE_SHOW_HIDE_BUTTON); + + if (!_setup_obtain_params_passphrase.suitable()) { + + gen_start_button = false; + } + gen_info_line(xml, "pad_2", ""); + if (gen_start_button) { + + gen_action_button_at_bottom( + xml, "ok", "Start", + _setup_obtain_params_hover == Setup_obtain_params_hover::START_BUTTON, + _setup_obtain_params_select == Setup_obtain_params_select::START_BUTTON); + } + }); + break; + + case State::SETUP_RUN_CBE_INIT_TRUST_ANCHOR: + case State::SETUP_CREATE_CBE_IMAGE_FILE: + case State::SETUP_RUN_CBE_INIT: + case State::SETUP_START_CBE_VFS: + case State::SETUP_FORMAT_CBE: + case State::STARTUP_RUN_CBE_INIT_TRUST_ANCHOR: + case State::STARTUP_START_CBE_VFS: + case State::STARTUP_DETERMINE_CLIENT_FS_SIZE: + + gen_info_frame(xml, "1", "Please wait...", MAIN_FRAME_WIDTH); + break; + + case State::CONTROLS_ROOT: + + gen_controls_frame(xml, "app", [&] (Xml_generator &xml) { + + xml.node("frame", [&] () { + + xml.node("vbox", [&] () { + + if (SHOW_CONTROLS_SNAPSHOTS) { + + gen_closed_menu( + xml, "Snapshots", "", + _controls_root_hover == Controls_root_hover::SNAPSHOTS_EXPAND_BUTTON); + } + gen_closed_menu( + xml, "Dimensions", "", + _controls_root_hover == Controls_root_hover::DIMENSIONS_BUTTON); + + gen_closed_menu( + xml, "Security", "", + _controls_root_hover == Controls_root_hover::SECURITY_EXPAND_BUTTON); + }); + }); + gen_global_controls( + xml, MAIN_FRAME_WIDTH, _cbe_image_size, _client_fs_size, _nr_of_clients, + _controls_root_hover == Controls_root_hover::SHUT_DOWN_BUTTON, + _controls_root_select == Controls_root_select::SHUT_DOWN_BUTTON); + }); + break; + + case State::CONTROLS_SNAPSHOTS: + + gen_controls_frame(xml, "app", [&] (Xml_generator &xml) { + + xml.node("frame", [&] () { + + xml.node("vbox", [&] () { + + if (_snapshots_select.valid()) { + + Snapshot const &snap { _snapshots_select.object() }; + String<64> const snap_str { + "Generation ", snap.generation() }; + + gen_opened_menu( + xml, snap_str.string(), "", + _controls_snapshots_hover == Controls_snapshots_hover::GENERATION_LEAVE_BUTTON, + [&] (Xml_generator &xml) + { + gen_info_line(xml, "pad_1", ""); + switch(_discard_snap_state) { + case Discard_snapshot_state::INACTIVE: + + gen_action_button(xml, "Discard", "Discard", + _controls_snapshots_hover == Controls_snapshots_hover::GENERATION_DISCARD_BUTTON, + _controls_snapshots_select == Controls_snapshots_select::GENERATION_DISCARD_BUTTON); + + break; + + case Discard_snapshot_state::ISSUE_REQUEST_AT_DEVICE: + + gen_action_button(xml, "Inactive Discard", "...", + _controls_snapshots_hover == Controls_snapshots_hover::GENERATION_DISCARD_BUTTON, + false); + + break; + } + }); + } else { + + gen_opened_menu( + xml, "Snapshots", "", + _controls_snapshots_hover == Controls_snapshots_hover::LEAVE_BUTTON, + [&] (Xml_generator &xml) + { + xml.node("vbox", [&] () { + xml.attribute("name", "Generations"); + + _snapshots.for_each([&] (Snapshot const &snap) { + + bool const hovered { + _snapshots_hover.valid() && + _snapshots_hover.object().generation() == snap.generation() }; + + String<64> const snap_str { + "Generation ", snap.generation() }; + + Generation_string const gen_str { snap.generation() }; + + gen_multiple_choice_entry( + xml, gen_str.string(), snap_str.string(), hovered, + false); + }); + }); + gen_info_line(xml, "pad_1", ""); + switch(_create_snap_state) { + case Create_snapshot_state::INACTIVE: + + gen_action_button(xml, "Create", "Create", + _controls_snapshots_hover == Controls_snapshots_hover::CREATE_BUTTON, + _controls_snapshots_select == Controls_snapshots_select::CREATE_BUTTON); + break; + + case Create_snapshot_state::ISSUE_REQUEST_AT_DEVICE: + + gen_action_button(xml, "Inactive Create", "...", + _controls_snapshots_hover == Controls_snapshots_hover::CREATE_BUTTON, + false); + + break; + } + }); + } + }); + }); + gen_global_controls( + xml, MAIN_FRAME_WIDTH, _cbe_image_size, _client_fs_size, _nr_of_clients, + _controls_snapshots_hover == Controls_snapshots_hover::SHUT_DOWN_BUTTON, + _controls_snapshots_select == Controls_snapshots_select::SHUT_DOWN_BUTTON); + }); + break; + + case State::CONTROLS_DIMENSIONS: + + gen_controls_frame(xml, "app", [&] (Xml_generator &xml) { + + xml.node("frame", [&] () { + + gen_opened_menu( + xml, "Dimensions", "", + _dimensions_hover == Dimensions_hover::LEAVE_BUTTON, + [&] (Xml_generator &xml) + { + gen_closed_menu( + xml, "Expand Client FS", "", + _dimensions_hover == Dimensions_hover::EXPAND_CLIENT_FS_BUTTON); + + gen_closed_menu( + xml, + RENAME_SNAPSHOT_BUFFER_JOURNALING_BUFFER ? + "Expand Journaling Buffer" : + "Expand Snapshot Buffer", + "", + _dimensions_hover == Dimensions_hover::EXPAND_SNAPSHOT_BUF_BUTTON); + }); + }); + gen_global_controls( + xml, MAIN_FRAME_WIDTH, _cbe_image_size, _client_fs_size, _nr_of_clients, + _dimensions_hover == Dimensions_hover::SHUT_DOWN_BUTTON, + _dimensions_select == Dimensions_select::SHUT_DOWN_BUTTON); + }); + break; + + case State::CONTROLS_EXPAND_CLIENT_FS: + + gen_controls_frame(xml, "app", [&] (Xml_generator &xml) { + + xml.node("frame", [&] () { + + xml.node("vbox", [&] () { + + gen_opened_menu( + xml, "Expand Client FS", "", + _expand_client_fs_hover == Expand_client_fs_hover::LEAVE_BUTTON, + [&] (Xml_generator &xml) + { + gen_info_line(xml, "pad_1", ""); + switch (_resizing_state) { + case Resizing_state::INACTIVE: + { + if (_nr_of_clients > 0) { + + gen_centered_info_line(xml, "Info 1", "Not possible while in use!"); + gen_info_line(xml, "Padding 1", ""); + + } else { + + gen_titled_text_input( + xml, "Contingent", "Contingent", + _expand_client_fs_contingent, + _expand_client_fs_select == Expand_client_fs_select::CONTINGENT_INPUT); + + bool gen_start_button { true }; + size_t const bytes { + _expand_client_fs_contingent.value() }; + + size_t const effective_bytes { + bytes - (bytes % CBE_BLOCK_SIZE) }; + + if (effective_bytes > 0) { + + gen_info_line( + xml, "inf_2", + String<128> { + "New image size: ", + Capacity { _cbe_image_size + effective_bytes } + }.string()); + + } else { + + gen_info_line(xml, "info_1", + String<128> { + "Must be at least ", + Number_of_bytes { CBE_BLOCK_SIZE } }.string()); + + gen_start_button = false; + } + gen_info_line(xml, "pad_2", ""); + if (gen_start_button) { + + gen_action_button_at_bottom( + xml, "Start", + _expand_client_fs_hover == Expand_client_fs_hover::START_BUTTON, + _expand_client_fs_select == Expand_client_fs_select::START_BUTTON); + } + } + break; + } + case Resizing_state::ADAPT_CBE_IMAGE_SIZE: + case Resizing_state::WAIT_TILL_DEVICE_IS_READY: + case Resizing_state::ISSUE_REQUEST_AT_DEVICE: + case Resizing_state::IN_PROGRESS_AT_DEVICE: + case Resizing_state::DETERMINE_CLIENT_FS_SIZE: + case Resizing_state::RUN_RESIZE2FS: + + gen_centered_info_line(xml, "inf", "Please wait..."); + gen_info_line(xml, "pad_2", ""); + break; + } + }); + }); + }); + gen_global_controls( + xml, MAIN_FRAME_WIDTH, _cbe_image_size, _client_fs_size, _nr_of_clients, + _expand_client_fs_hover == Expand_client_fs_hover::SHUT_DOWN_BUTTON, + _expand_client_fs_select == Expand_client_fs_select::SHUT_DOWN_BUTTON); + }); + break; + + case State::CONTROLS_EXPAND_SNAPSHOT_BUF: + + gen_controls_frame(xml, "app", [&] (Xml_generator &xml) { + + xml.node("frame", [&] () { + + xml.node("vbox", [&] () { + + gen_opened_menu( + xml, + RENAME_SNAPSHOT_BUFFER_JOURNALING_BUFFER ? + "Expand Journaling Buffer" : + "Expand Snapshot Buffer", + "", + _expand_snapshot_buf_hover == Expand_snapshot_buf_hover::LEAVE_BUTTON, + [&] (Xml_generator &xml) + { + gen_info_line(xml, "pad_1", ""); + switch (_resizing_state) { + case Resizing_state::INACTIVE: + { + gen_titled_text_input( + xml, "Contingent", "Contingent", + _expand_snapshot_buf_contingent, + _expand_snapshot_buf_select == Expand_snapshot_buf_select::CONTINGENT_INPUT); + + bool gen_start_button { true }; + size_t const bytes { + _expand_snapshot_buf_contingent.value() }; + + size_t const effective_bytes { + bytes - (bytes % CBE_BLOCK_SIZE) }; + + if (effective_bytes > 0) { + + gen_info_line( + xml, "inf_2", + String<128> { + "New image size: ", + Capacity { _cbe_image_size + effective_bytes } + }.string()); + + } else { + + gen_start_button = false; + gen_info_line(xml, "info_1", + String<128> { + "Must be at least ", + Number_of_bytes { CBE_BLOCK_SIZE } }.string()); + } + gen_info_line(xml, "pad_2", ""); + if (gen_start_button) { + + gen_action_button_at_bottom( + xml, "Start", + _expand_snapshot_buf_hover == Expand_snapshot_buf_hover::START_BUTTON, + _expand_snapshot_buf_select == Expand_snapshot_buf_select::START_BUTTON); + } + break; + } + case Resizing_state::ADAPT_CBE_IMAGE_SIZE: + case Resizing_state::WAIT_TILL_DEVICE_IS_READY: + case Resizing_state::ISSUE_REQUEST_AT_DEVICE: + case Resizing_state::IN_PROGRESS_AT_DEVICE: + case Resizing_state::DETERMINE_CLIENT_FS_SIZE: + case Resizing_state::RUN_RESIZE2FS: + + gen_centered_info_line(xml, "inf", "Please wait..."); + gen_info_line(xml, "pad_2", ""); + break; + } + }); + }); + }); + gen_global_controls( + xml, MAIN_FRAME_WIDTH, _cbe_image_size, _client_fs_size, _nr_of_clients, + _expand_snapshot_buf_hover == Expand_snapshot_buf_hover::SHUT_DOWN_BUTTON, + _expand_snapshot_buf_select == Expand_snapshot_buf_select::SHUT_DOWN_BUTTON); + }); + break; + + case State::CONTROLS_SECURITY: + + gen_controls_frame(xml, "app", [&] (Xml_generator &xml) { + + xml.node("frame", [&] () { + + gen_opened_menu( + xml, "Security", "", + _controls_security_hover == Controls_security_hover::SECURITY_EXPAND_BUTTON, + [&] (Xml_generator &xml) + { + gen_closed_menu( + xml, "Block Encryption Key", "", + _controls_security_hover == Controls_security_hover::BLOCK_ENCRYPTION_KEY_EXPAND_BUTTON); + + if (SHOW_CONTROLS_SECURITY_MASTER_KEY) { + + gen_closed_menu( + xml, "Master Key", "", + _controls_security_hover == Controls_security_hover::MASTER_KEY_EXPAND_BUTTON); + } + if (SHOW_CONTROLS_SECURITY_USER_PASSPHRASE) { + + gen_closed_menu( + xml, "User Passphrase", "", + _controls_security_hover == Controls_security_hover::USER_PASSPHRASE_EXPAND_BUTTON); + } + }); + }); + gen_global_controls( + xml, MAIN_FRAME_WIDTH, _cbe_image_size, _client_fs_size, _nr_of_clients, + _controls_security_hover == Controls_security_hover::SHUT_DOWN_BUTTON, + _controls_security_select == Controls_security_select::SHUT_DOWN_BUTTON); + }); + break; + + case State::CONTROLS_SECURITY_BLOCK_ENCRYPTION_KEY: + + gen_controls_frame(xml, "app", [&] (Xml_generator &xml) { + + xml.node("frame", [&] () { + + gen_opened_menu( + xml, "Block Encryption Key", "", + _controls_security_block_encryption_key_hover == Controls_security_block_encryption_key_hover::LEAVE_BUTTON, + [&] (Xml_generator &xml) + { + gen_info_line(xml, "pad_1", ""); + switch(_rekeying_state) { + case Rekeying_state::INACTIVE: + + gen_action_button(xml, "Rekey", "Replace", + _controls_security_block_encryption_key_hover == Controls_security_block_encryption_key_hover::REPLACE_BUTTON, + _controls_security_block_encryption_key_select == Controls_security_block_encryption_key_select::REPLACE_BUTTON); + + break; + + case Rekeying_state::WAIT_TILL_DEVICE_IS_READY: + case Rekeying_state::ISSUE_REQUEST_AT_DEVICE: + case Rekeying_state::IN_PROGRESS_AT_DEVICE: + + gen_centered_info_line(xml, "inf", "Please wait..."); + gen_info_line(xml, "pad_2", ""); + break; + } + gen_info_line(xml, "pad_1", ""); + }); + }); + gen_global_controls( + xml, MAIN_FRAME_WIDTH, _cbe_image_size, _client_fs_size, _nr_of_clients, + _controls_security_block_encryption_key_hover == Controls_security_block_encryption_key_hover::SHUT_DOWN_BUTTON, + _controls_security_block_encryption_key_select == Controls_security_block_encryption_key_select::SHUT_DOWN_BUTTON); + }); + break; + + case State::CONTROLS_SECURITY_MASTER_KEY: + + gen_controls_frame(xml, "app", [&] (Xml_generator &xml) { + + xml.node("frame", [&] () { + + gen_opened_menu( + xml, "Master Key", "", + _controls_security_master_key_hover == Controls_security_master_key_hover::LEAVE_BUTTON, + [&] (Xml_generator &xml) + { + gen_info_line(xml, "pad_1", ""); + gen_info_line(xml, "inf_1", "The master key cannot be replaced by now."); + gen_info_line(xml, "pad_2", ""); + }); + }); + gen_global_controls( + xml, MAIN_FRAME_WIDTH, _cbe_image_size, _client_fs_size, _nr_of_clients, + _controls_security_master_key_hover == Controls_security_master_key_hover::SHUT_DOWN_BUTTON, + _controls_security_master_key_select == Controls_security_master_key_select::SHUT_DOWN_BUTTON); + }); + break; + + case State::CONTROLS_SECURITY_USER_PASSPHRASE: + + gen_controls_frame(xml, "app", [&] (Xml_generator &xml) { + + xml.node("frame", [&] () { + + gen_opened_menu( + xml, "User Passphrase", "", + _controls_security_user_passphrase_hover == Controls_security_user_passphrase_hover::LEAVE_BUTTON, + [&] (Xml_generator &xml) + { + gen_info_line(xml, "pad_1", ""); + gen_info_line(xml, "inf_1", "The user passphrase cannot be replaced by now."); + gen_info_line(xml, "pad_2", ""); + }); + }); + gen_global_controls( + xml, MAIN_FRAME_WIDTH, _cbe_image_size, _client_fs_size, _nr_of_clients, + _controls_security_user_passphrase_hover == Controls_security_user_passphrase_hover::SHUT_DOWN_BUTTON, + _controls_security_user_passphrase_select == Controls_security_user_passphrase_select::SHUT_DOWN_BUTTON); + }); + break; + + case State::SHUTDOWN_ISSUE_DEINIT_REQUEST_AT_CBE: + case State::SHUTDOWN_WAIT_TILL_DEINIT_REQUEST_IS_DONE: + + gen_info_frame(xml, "1", "Please wait...", MAIN_FRAME_WIDTH); + break; + } +} + + +void File_vault::Main::wakeup_local_service() +{ + _rom_service.for_each_requested_session([&] (Rom_service::Request &request) { + + if (request.label == "menu_view -> dialog") + request.deliver_session(_dialog); + else + request.deny(); + }); + + _report_service.for_each_requested_session([&] (Report_service::Request &request) { + + if (request.label == "fs_query -> listing") { + + Report::Session_component &session { *new (_heap) + Report::Session_component( + _env, _fs_query_listing_handler, _env.ep(), + request.resources, "", request.diag) }; + + request.deliver_session(session); + + } if (request.label == "image_fs_query -> listing") { + + Report::Session_component &session { *new (_heap) + Report::Session_component( + _env, _image_fs_query_listing_handler, _env.ep(), + request.resources, "", request.diag) }; + + request.deliver_session(session); + + } else if (request.label == "client_fs_fs_query -> listing") { + + Report::Session_component &session { *new (_heap) + Report::Session_component( + _env, _client_fs_fs_query_listing_handler, _env.ep(), + request.resources, "", request.diag) }; + + request.deliver_session(session); + + } else if (request.label == "snapshots_fs_query -> listing") { + + Report::Session_component &session { *new (_heap) + Report::Session_component( + _env, _snapshots_fs_query_listing_handler, _env.ep(), + request.resources, "", request.diag) }; + + request.deliver_session(session); + + } else if (request.label == "resizing_fs_query -> listing") { + + Report::Session_component &session { *new (_heap) + Report::Session_component( + _env, _resizing_fs_query_listing_handler, _env.ep(), + request.resources, "", request.diag) }; + + request.deliver_session(session); + + } else if (request.label == "rekeying_fs_query -> listing") { + + Report::Session_component &session { *new (_heap) + Report::Session_component( + _env, _rekeying_fs_query_listing_handler, _env.ep(), + request.resources, "", request.diag) }; + + request.deliver_session(session); + + } else if (request.label == "shut_down_fs_query -> listing") { + + Report::Session_component &session { *new (_heap) + Report::Session_component( + _env, _shut_down_fs_query_listing_handler, _env.ep(), + request.resources, "", request.diag) }; + + request.deliver_session(session); + + } else { + + error("failed to deliver Report session"); + } + }); + + _report_service.for_each_requested_session([&] (Report_service::Request &request) { + + if (request.label == "menu_view -> hover") { + Report::Session_component &session = *new (_heap) + Report::Session_component(_env, _hover_handler, + _env.ep(), + request.resources, "", request.diag); + request.deliver_session(session); + } + }); + + _report_service.for_each_session_to_close([&] (Report::Session_component &session) { + + destroy(_heap, &session); + return Report_service::Close_response::CLOSED; + }); + + _gui_service.for_each_requested_session([&] (Gui_service::Request &request) { + + Gui::Session_component &session = *new (_heap) + Gui::Session_component(_env, *this, _env.ep(), + request.resources, "", request.diag); + + request.deliver_session(session); + }); + + _gui_service.for_each_upgraded_session([&] (Gui::Session_component &session, + Session::Resources const &amount) { + session.upgrade(amount); + return Gui_service::Upgrade_response::CONFIRMED; + }); + + _gui_service.for_each_session_to_close([&] (Gui::Session_component &session) { + + destroy(_heap, &session); + return Gui_service::Close_response::CLOSED; + }); +} + + +size_t Main::_cbe_tree_nr_of_leaves(size_t payload_size) +{ + size_t nr_of_leaves { payload_size / CBE_BLOCK_SIZE }; + if (payload_size % CBE_BLOCK_SIZE) { + nr_of_leaves++; + } + return nr_of_leaves; +} + + +void File_vault::Main::_generate_sandbox_config(Xml_generator &xml) const +{ + switch (_state) { + case State::INVALID: + + gen_parent_provides_and_report_nodes(xml); + gen_menu_view_start_node(xml, _menu_view); + gen_fs_query_start_node(xml, _fs_query); + break; + + case State::SETUP_OBTAIN_PARAMETERS: + + gen_parent_provides_and_report_nodes(xml); + gen_menu_view_start_node(xml, _menu_view); + break; + + case State::STARTUP_OBTAIN_PARAMETERS: + + gen_parent_provides_and_report_nodes(xml); + gen_menu_view_start_node(xml, _menu_view); + break; + + case State::SETUP_RUN_CBE_INIT_TRUST_ANCHOR: + + gen_parent_provides_and_report_nodes(xml); + gen_menu_view_start_node(xml, _menu_view); + gen_cbe_trust_anchor_vfs_start_node(xml, _cbe_trust_anchor_vfs); + gen_cbe_init_trust_anchor_start_node( + xml, _cbe_init_trust_anchor, _setup_obtain_params_passphrase); + + break; + + case State::STARTUP_RUN_CBE_INIT_TRUST_ANCHOR: + + gen_parent_provides_and_report_nodes(xml); + gen_menu_view_start_node(xml, _menu_view); + gen_cbe_trust_anchor_vfs_start_node(xml, _cbe_trust_anchor_vfs); + gen_cbe_init_trust_anchor_start_node( + xml, _cbe_init_trust_anchor, _setup_obtain_params_passphrase); + + break; + + case State::STARTUP_START_CBE_VFS: + + gen_parent_provides_and_report_nodes(xml); + gen_menu_view_start_node(xml, _menu_view); + gen_cbe_trust_anchor_vfs_start_node(xml, _cbe_trust_anchor_vfs); + gen_cbe_vfs_start_node(xml, _cbe_vfs); + gen_sync_to_cbe_vfs_init_start_node(xml, _sync_to_cbe_vfs_init); + break; + + case State::STARTUP_DETERMINE_CLIENT_FS_SIZE: + + gen_parent_provides_and_report_nodes(xml); + gen_menu_view_start_node(xml, _menu_view); + gen_cbe_trust_anchor_vfs_start_node(xml, _cbe_trust_anchor_vfs); + gen_cbe_vfs_start_node(xml, _cbe_vfs); + gen_client_fs_fs_query_start_node(xml, _client_fs_fs_query); + break; + + case State::SETUP_CREATE_CBE_IMAGE_FILE: + + gen_parent_provides_and_report_nodes(xml); + gen_menu_view_start_node(xml, _menu_view); + gen_cbe_trust_anchor_vfs_start_node(xml, _cbe_trust_anchor_vfs); + gen_truncate_file_start_node( + xml, _truncate_file, "/cbe/cbe.img", + CBE_BLOCK_SIZE * + _cbe_nr_of_blocks( + CBE_NR_OF_SUPERBLOCKS, + CBE_VBD_TREE_NR_OF_LEVELS, + CBE_VBD_TREE_NR_OF_CHILDREN, + _cbe_tree_nr_of_leaves(_client_fs_size_input.value()), + CBE_FREE_TREE_NR_OF_LEVELS, + CBE_FREE_TREE_NR_OF_CHILDREN, + _cbe_tree_nr_of_leaves(_snapshot_buf_size_input.value()))); + + break; + + case State::SETUP_RUN_CBE_INIT: + { + Tree_geometry const vbd_tree_geom { + CBE_VBD_TREE_NR_OF_LEVELS, + CBE_VBD_TREE_NR_OF_CHILDREN, + _cbe_tree_nr_of_leaves(_client_fs_size_input.value()) }; + + Tree_geometry const free_tree_geom { + CBE_VBD_TREE_NR_OF_LEVELS, + CBE_VBD_TREE_NR_OF_CHILDREN, + _cbe_tree_nr_of_leaves(_snapshot_buf_size_input.value()) }; + + gen_parent_provides_and_report_nodes(xml); + gen_menu_view_start_node(xml, _menu_view); + gen_cbe_trust_anchor_vfs_start_node(xml, _cbe_trust_anchor_vfs); + gen_cbe_image_vfs_block_start_node(xml, _cbe_image_vfs_block); + gen_cbe_init_start_node(xml, _cbe_init, vbd_tree_geom, free_tree_geom); + break; + } + case State::SETUP_START_CBE_VFS: + + gen_parent_provides_and_report_nodes(xml); + gen_menu_view_start_node(xml, _menu_view); + gen_cbe_trust_anchor_vfs_start_node(xml, _cbe_trust_anchor_vfs); + gen_cbe_vfs_start_node(xml, _cbe_vfs); + gen_sync_to_cbe_vfs_init_start_node(xml, _sync_to_cbe_vfs_init); + break; + + case State::SETUP_FORMAT_CBE: + + gen_parent_provides_and_report_nodes(xml); + gen_menu_view_start_node(xml, _menu_view); + gen_cbe_trust_anchor_vfs_start_node(xml, _cbe_trust_anchor_vfs); + gen_cbe_vfs_start_node(xml, _cbe_vfs); + gen_cbe_vfs_block_start_node(xml, _cbe_vfs_block); + gen_mke2fs_start_node(xml, _mke2fs); + break; + + case State::CONTROLS_ROOT: + case State::CONTROLS_SNAPSHOTS: + case State::CONTROLS_DIMENSIONS: + case State::CONTROLS_EXPAND_CLIENT_FS: + case State::CONTROLS_EXPAND_SNAPSHOT_BUF: + case State::CONTROLS_SECURITY: + case State::CONTROLS_SECURITY_BLOCK_ENCRYPTION_KEY: + case State::CONTROLS_SECURITY_MASTER_KEY: + case State::CONTROLS_SECURITY_USER_PASSPHRASE: + { + gen_parent_provides_and_report_nodes(xml); + gen_menu_view_start_node(xml, _menu_view); + gen_cbe_trust_anchor_vfs_start_node(xml, _cbe_trust_anchor_vfs); + gen_cbe_vfs_start_node(xml, _cbe_vfs); + gen_cbe_vfs_block_start_node(xml, _cbe_vfs_block); + gen_snapshots_fs_query_start_node(xml, _snapshots_fs_query); + gen_image_fs_query_start_node(xml, _image_fs_query); + + switch(_resizing_state) { + case Resizing_state::INACTIVE: + + break; + + case Resizing_state::ADAPT_CBE_IMAGE_SIZE: + + switch (_resizing_type) { + case Resizing_type::EXPAND_CLIENT_FS: + { + size_t const bytes { + _expand_client_fs_contingent.value() }; + + size_t const effective_bytes { + bytes - (bytes % CBE_BLOCK_SIZE) }; + + gen_truncate_file_start_node( + xml, _truncate_file, "/cbe/cbe.img", + _cbe_image_size + effective_bytes); + + break; + } + case Resizing_type::EXPAND_SNAPSHOT_BUF: + { + size_t const bytes { + _expand_snapshot_buf_contingent.value() }; + + size_t const effective_bytes { + bytes - (bytes % CBE_BLOCK_SIZE) }; + + gen_truncate_file_start_node( + xml, _truncate_file, "/cbe/cbe.img", + _cbe_image_size + effective_bytes); + + break; + } + default: + + class Unexpected_resizing_type { }; + throw Unexpected_resizing_type { }; + break; + } + break; + + case Resizing_state::WAIT_TILL_DEVICE_IS_READY: + + gen_resizing_fs_query_start_node(xml, _resizing_fs_query); + break; + + case Resizing_state::ISSUE_REQUEST_AT_DEVICE: + + switch (_resizing_type) { + case Resizing_type::EXPAND_CLIENT_FS: + + gen_resizing_fs_tool_start_node( + xml, _resizing_fs_tool, "vbd", + _expand_client_fs_contingent.value() / CBE_BLOCK_SIZE); + + break; + + case Resizing_type::EXPAND_SNAPSHOT_BUF: + + gen_resizing_fs_tool_start_node( + xml, _resizing_fs_tool, "ft", + _expand_snapshot_buf_contingent.value() / CBE_BLOCK_SIZE); + + break; + + default: + + class Unexpected_resizing_type { }; + throw Unexpected_resizing_type { }; + break; + } + break; + + case Resizing_state::IN_PROGRESS_AT_DEVICE: + + gen_resizing_fs_query_start_node(xml, _resizing_fs_query); + break; + + case Resizing_state::DETERMINE_CLIENT_FS_SIZE: + + gen_client_fs_fs_query_start_node(xml, _client_fs_fs_query); + break; + + case Resizing_state::RUN_RESIZE2FS: + + gen_resize2fs_start_node(xml, _resize2fs); + break; + } + + switch(_rekeying_state) { + case Rekeying_state::INACTIVE: + + break; + + case Rekeying_state::WAIT_TILL_DEVICE_IS_READY: + + gen_rekeying_fs_query_start_node(xml, _rekeying_fs_query); + break; + + case Rekeying_state::ISSUE_REQUEST_AT_DEVICE: + + gen_rekeying_fs_tool_start_node(xml, _rekeying_fs_tool); + break; + + case Rekeying_state::IN_PROGRESS_AT_DEVICE: + + gen_rekeying_fs_query_start_node(xml, _rekeying_fs_query); + break; + } + + switch(_create_snap_state) { + case Create_snapshot_state::INACTIVE: + + break; + + case Create_snapshot_state::ISSUE_REQUEST_AT_DEVICE: + + gen_create_snap_fs_tool_start_node(xml, _create_snap_fs_tool); + break; + } + + switch(_discard_snap_state) { + case Discard_snapshot_state::INACTIVE: + + break; + + case Discard_snapshot_state::ISSUE_REQUEST_AT_DEVICE: + + gen_discard_snap_fs_tool_start_node(xml, _discard_snap_fs_tool, _discard_snap_gen); + break; + } + + if (_resizing_state == Resizing_state::INACTIVE || + _resizing_type != Resizing_type::EXPAND_CLIENT_FS) { + + gen_policy_for_child_service(xml, "File_system", _rump_vfs); + gen_rump_vfs_start_node(xml, _rump_vfs); + } + break; + } + case State::SHUTDOWN_ISSUE_DEINIT_REQUEST_AT_CBE: + + gen_parent_provides_and_report_nodes(xml); + gen_policy_for_child_service(xml, "File_system", _rump_vfs); + gen_menu_view_start_node(xml, _menu_view); + gen_cbe_trust_anchor_vfs_start_node(xml, _cbe_trust_anchor_vfs); + gen_cbe_vfs_start_node(xml, _cbe_vfs); + gen_cbe_vfs_block_start_node(xml, _cbe_vfs_block); + gen_snapshots_fs_query_start_node(xml, _snapshots_fs_query); + gen_shut_down_fs_tool_start_node(xml, _shut_down_fs_tool); + break; + + case State::SHUTDOWN_WAIT_TILL_DEINIT_REQUEST_IS_DONE: + + gen_parent_provides_and_report_nodes(xml); + gen_policy_for_child_service(xml, "File_system", _rump_vfs); + gen_menu_view_start_node(xml, _menu_view); + gen_cbe_trust_anchor_vfs_start_node(xml, _cbe_trust_anchor_vfs); + gen_cbe_vfs_start_node(xml, _cbe_vfs); + gen_cbe_vfs_block_start_node(xml, _cbe_vfs_block); + gen_snapshots_fs_query_start_node(xml, _snapshots_fs_query); + gen_shut_down_fs_query_start_node(xml, _shut_down_fs_query); + break; + } +} + + +size_t Main::_tree_nr_of_blocks(size_t nr_of_lvls, + size_t nr_of_children, + size_t nr_of_leafs) +{ + size_t nr_of_blks { 0 }; + size_t nr_of_last_lvl_blks { nr_of_leafs }; + for (size_t lvl_idx { 0 }; lvl_idx < nr_of_lvls; lvl_idx++) { + nr_of_blks += nr_of_last_lvl_blks; + if (nr_of_last_lvl_blks % nr_of_children) { + nr_of_last_lvl_blks = nr_of_last_lvl_blks / nr_of_children + 1; + } else { + nr_of_last_lvl_blks = nr_of_last_lvl_blks / nr_of_children; + } + } + return nr_of_blks; +} + + +size_t Main::_cbe_size() const +{ + return + _cbe_nr_of_blocks( + CBE_NR_OF_SUPERBLOCKS, + CBE_VBD_TREE_NR_OF_LEVELS, + CBE_VBD_TREE_NR_OF_CHILDREN, + _cbe_tree_nr_of_leaves(_client_fs_size_input.value()), + CBE_FREE_TREE_NR_OF_LEVELS, + CBE_FREE_TREE_NR_OF_CHILDREN, + _cbe_tree_nr_of_leaves(_snapshot_buf_size_input.value())) + * CBE_BLOCK_SIZE; +} + + +size_t Main::_cbe_nr_of_blocks(size_t nr_of_superblocks, + size_t nr_of_vbd_lvls, + size_t nr_of_vbd_children, + size_t nr_of_vbd_leafs, + size_t nr_of_ft_lvls, + size_t nr_of_ft_children, + size_t nr_of_ft_leafs) +{ + size_t const nr_of_vbd_blks { + _tree_nr_of_blocks( + nr_of_vbd_lvls, + nr_of_vbd_children, + nr_of_vbd_leafs) }; + + size_t const nr_of_ft_blks { + _tree_nr_of_blocks( + nr_of_ft_lvls, + nr_of_ft_children, + nr_of_ft_leafs) }; + + /* FIXME + * + * This would be the correct way to calculate the number of MT blocks + * but the CBE still uses an MT the same size as the FT for simplicity + * reasons. As soon as the CBE does it right we should fix also this path. + * + * size_t const nr_of_mt_leafs { + * nr_of_ft_blks - nr_of_ft_leafs }; + * + * size_t const nr_of_mt_blks { + * _tree_nr_of_blocks( + * nr_of_mt_lvls, + * nr_of_mt_children, + * nr_of_mt_leafs) }; + */ + size_t const nr_of_mt_blks { nr_of_ft_blks }; + + return + nr_of_superblocks + + nr_of_vbd_blks + + nr_of_ft_blks + + nr_of_mt_blks; +} + + +void File_vault::Main::handle_input_event(Input::Event const &event) +{ + bool update_dialog { false }; + bool update_sandbox_config { false }; + + switch (_state) { + case State::SETUP_OBTAIN_PARAMETERS: + + event.handle_press([&] (Input::Keycode key, Codepoint code) { + + if (key == Input::BTN_LEFT) { + + Setup_obtain_params_select const prev_select { _setup_obtain_params_select }; + Setup_obtain_params_select next_select { Setup_obtain_params_select::NONE }; + + switch (_setup_obtain_params_hover) { + case Setup_obtain_params_hover::START_BUTTON: + + next_select = Setup_obtain_params_select::START_BUTTON; + break; + + case Setup_obtain_params_hover::PASSPHRASE_SHOW_HIDE_BUTTON: + + next_select = Setup_obtain_params_select::PASSPHRASE_SHOW_HIDE_BUTTON; + break; + + case Setup_obtain_params_hover::PASSPHRASE_INPUT: + + next_select = Setup_obtain_params_select::PASSPHRASE_INPUT; + break; + + case Setup_obtain_params_hover::CLIENT_FS_SIZE_INPUT: + + next_select = Setup_obtain_params_select::CLIENT_FS_SIZE_INPUT; + break; + + case Setup_obtain_params_hover::SNAPSHOT_BUFFER_SIZE_INPUT: + + next_select = Setup_obtain_params_select::SNAPSHOT_BUFFER_SIZE_INPUT; + break; + + case Setup_obtain_params_hover::NONE: + + next_select = Setup_obtain_params_select::NONE; + break; + } + if (next_select != prev_select) { + + _setup_obtain_params_select = next_select; + update_dialog = true; + } + + } else if (key == Input::KEY_ENTER) { + + if (_client_fs_size_input.value() >= MIN_CLIENT_FS_SIZE && + _snapshot_buf_size_input.value() >= _min_snapshot_buf_size() && + _setup_obtain_params_passphrase.suitable() && + _setup_obtain_params_select != Setup_obtain_params_select::START_BUTTON) { + + _setup_obtain_params_select = Setup_obtain_params_select::START_BUTTON; + update_dialog = true; + } + + } else if (key == Input::KEY_TAB) { + + switch (_setup_obtain_params_select) { + case Setup_obtain_params_select::PASSPHRASE_INPUT: + + _setup_obtain_params_select = Setup_obtain_params_select::CLIENT_FS_SIZE_INPUT; + update_dialog = true; + break; + + case Setup_obtain_params_select::CLIENT_FS_SIZE_INPUT: + + _setup_obtain_params_select = Setup_obtain_params_select::SNAPSHOT_BUFFER_SIZE_INPUT; + update_dialog = true; + break; + + case Setup_obtain_params_select::SNAPSHOT_BUFFER_SIZE_INPUT: + + _setup_obtain_params_select = Setup_obtain_params_select::PASSPHRASE_INPUT; + update_dialog = true; + break; + + default: + + break; + } + + } else { + + if (_setup_obtain_params_select == Setup_obtain_params_select::PASSPHRASE_INPUT) { + + if (_setup_obtain_params_passphrase.appendable_character(code)) { + + _setup_obtain_params_passphrase.append_character(code); + update_dialog = true; + + } else if (code.value == CODEPOINT_BACKSPACE) { + + _setup_obtain_params_passphrase.remove_last_character(); + update_dialog = true; + } + + } else if (_setup_obtain_params_select == Setup_obtain_params_select::CLIENT_FS_SIZE_INPUT) { + + if (_client_fs_size_input.appendable_character(code)) { + + _client_fs_size_input.append_character(code); + update_dialog = true; + + } else if (code.value == CODEPOINT_BACKSPACE) { + + _client_fs_size_input.remove_last_character(); + update_dialog = true; + + } + } else if (_setup_obtain_params_select == Setup_obtain_params_select::SNAPSHOT_BUFFER_SIZE_INPUT) { + + if (_snapshot_buf_size_input.appendable_character(code)) { + + _snapshot_buf_size_input.append_character(code); + update_dialog = true; + + } else if (code.value == CODEPOINT_BACKSPACE) { + + _snapshot_buf_size_input.remove_last_character(); + update_dialog = true; + + } + } else if (_setup_obtain_params_select == Setup_obtain_params_select::SNAPSHOT_BUFFER_SIZE_INPUT) { + + if (_snapshot_buf_size_input.appendable_character(code)) { + + _snapshot_buf_size_input.append_character(code); + update_dialog = true; + + } else if (code.value == CODEPOINT_BACKSPACE) { + + _snapshot_buf_size_input.remove_last_character(); + update_dialog = true; + + } + } + } + }); + event.handle_release([&] (Input::Keycode key) { + + if (key == Input::BTN_LEFT || + key == Input::KEY_ENTER) { + + switch (_setup_obtain_params_select) { + case Setup_obtain_params_select::PASSPHRASE_SHOW_HIDE_BUTTON: + + if (_setup_obtain_params_passphrase.hide()) { + _setup_obtain_params_passphrase.hide(false); + } else { + _setup_obtain_params_passphrase.hide(true); + } + _setup_obtain_params_select = Setup_obtain_params_select::PASSPHRASE_INPUT; + update_dialog = true; + break; + + case Setup_obtain_params_select::START_BUTTON: + + if(_client_fs_size_input.value() >= MIN_CLIENT_FS_SIZE && + _snapshot_buf_size_input.value() >= _min_snapshot_buf_size() && + _setup_obtain_params_passphrase.suitable()) { + + _setup_obtain_params_select = Setup_obtain_params_select::NONE; + _state = State::SETUP_CREATE_CBE_IMAGE_FILE; + update_sandbox_config = true; + update_dialog = true; + } + break; + + default: + + break; + } + } + }); + break; + + case State::STARTUP_OBTAIN_PARAMETERS: + + event.handle_press([&] (Input::Keycode key, Codepoint code) { + + if (key == Input::BTN_LEFT) { + + Setup_obtain_params_select const prev_select { _setup_obtain_params_select }; + Setup_obtain_params_select next_select { Setup_obtain_params_select::NONE }; + + switch (_setup_obtain_params_hover) { + case Setup_obtain_params_hover::PASSPHRASE_SHOW_HIDE_BUTTON: + + next_select = Setup_obtain_params_select::PASSPHRASE_SHOW_HIDE_BUTTON; + break; + + case Setup_obtain_params_hover::START_BUTTON: + + next_select = Setup_obtain_params_select::START_BUTTON; + break; + + case Setup_obtain_params_hover::PASSPHRASE_INPUT: + + next_select = Setup_obtain_params_select::PASSPHRASE_INPUT; + break; + + case Setup_obtain_params_hover::CLIENT_FS_SIZE_INPUT: + + class Unexpected_hover_1 { }; + throw Unexpected_hover_1 { }; + + case Setup_obtain_params_hover::SNAPSHOT_BUFFER_SIZE_INPUT: + + class Unexpected_hover_2 { }; + throw Unexpected_hover_2 { }; + + case Setup_obtain_params_hover::NONE: + + next_select = Setup_obtain_params_select::NONE; + break; + } + if (next_select != prev_select) { + + _setup_obtain_params_select = next_select; + update_dialog = true; + } + + } else if (key == Input::KEY_ENTER) { + + if (_setup_obtain_params_passphrase.suitable() && + _setup_obtain_params_select != Setup_obtain_params_select::START_BUTTON) { + + _setup_obtain_params_select = Setup_obtain_params_select::START_BUTTON; + update_dialog = true; + } + + } else { + + if (_setup_obtain_params_select == Setup_obtain_params_select::PASSPHRASE_INPUT) { + + if (_setup_obtain_params_passphrase.appendable_character(code)) { + + _setup_obtain_params_passphrase.append_character(code); + update_dialog = true; + + } else if (code.value == CODEPOINT_BACKSPACE) { + + _setup_obtain_params_passphrase.remove_last_character(); + update_dialog = true; + } + } + } + }); + event.handle_release([&] (Input::Keycode key) { + + if (key == Input::BTN_LEFT || + key == Input::KEY_ENTER) { + + switch (_setup_obtain_params_select) { + case Setup_obtain_params_select::PASSPHRASE_SHOW_HIDE_BUTTON: + + if (_setup_obtain_params_passphrase.hide()) { + _setup_obtain_params_passphrase.hide(false); + } else { + _setup_obtain_params_passphrase.hide(true); + } + _setup_obtain_params_select = Setup_obtain_params_select::PASSPHRASE_INPUT; + update_dialog = true; + break; + + case Setup_obtain_params_select::START_BUTTON: + + if (_setup_obtain_params_passphrase.suitable()) { + + _setup_obtain_params_select = Setup_obtain_params_select::NONE; + _state = State::STARTUP_RUN_CBE_INIT_TRUST_ANCHOR; + update_sandbox_config = true; + update_dialog = true; + } + break; + + default: + + break; + } + } + }); + break; + + case State::CONTROLS_ROOT: + + event.handle_press([&] (Input::Keycode key, Codepoint) { + + if (key == Input::BTN_LEFT) { + + Controls_root_select const prev_select { _controls_root_select }; + Controls_root_select next_select { Controls_root_select::NONE }; + + switch (_controls_root_hover) { + case Controls_root_hover::SNAPSHOTS_EXPAND_BUTTON: + + _state = State::CONTROLS_SNAPSHOTS; + update_dialog = true; + break; + + case Controls_root_hover::DIMENSIONS_BUTTON: + + _state = State::CONTROLS_DIMENSIONS; + update_dialog = true; + break; + + case Controls_root_hover::SECURITY_EXPAND_BUTTON: + + _state = State::CONTROLS_SECURITY; + update_dialog = true; + break; + + case Controls_root_hover::SHUT_DOWN_BUTTON: + + next_select = Controls_root_select::SHUT_DOWN_BUTTON; + break; + + case Controls_root_hover::NONE: + + next_select = Controls_root_select::NONE; + break; + } + if (next_select != prev_select) { + + _controls_root_select = next_select; + update_dialog = true; + } + } + }); + event.handle_release([&] (Input::Keycode key) { + + if (key == Input::BTN_LEFT) { + + switch (_controls_root_select) { + case Controls_root_select::SHUT_DOWN_BUTTON: + + _controls_root_select = Controls_root_select::NONE; + _state = State::SHUTDOWN_ISSUE_DEINIT_REQUEST_AT_CBE; + + update_sandbox_config = true; + update_dialog = true; + break; + + default: + + break; + } + } + }); + break; + + case State::CONTROLS_SNAPSHOTS: + + event.handle_press([&] (Input::Keycode key, Codepoint) { + + if (key == Input::BTN_LEFT) { + + Controls_snapshots_select const prev_select { _controls_snapshots_select }; + Controls_snapshots_select next_select { Controls_snapshots_select::NONE }; + + switch (_controls_snapshots_hover) { + case Controls_snapshots_hover::LEAVE_BUTTON: + + _state = State::CONTROLS_ROOT; + update_dialog = true; + break; + + case Controls_snapshots_hover::SHUT_DOWN_BUTTON: + + next_select = Controls_snapshots_select::SHUT_DOWN_BUTTON; + break; + + case Controls_snapshots_hover::CREATE_BUTTON: + + next_select = Controls_snapshots_select::CREATE_BUTTON; + break; + + case Controls_snapshots_hover::GENERATION_DISCARD_BUTTON: + + next_select = Controls_snapshots_select::GENERATION_DISCARD_BUTTON; + break; + + case Controls_snapshots_hover::GENERATION_LEAVE_BUTTON: + + _snapshots_select = Snapshot_pointer { }; + update_dialog = true; + break; + + case Controls_snapshots_hover::NONE: + + next_select = Controls_snapshots_select::NONE; + break; + } + if (_snapshots_hover.valid()) { + + if (_snapshots_hover != _snapshots_select) { + + _snapshots_select = _snapshots_hover; + update_dialog = true; + } else { + + _snapshots_select = Snapshot_pointer { }; + update_dialog = true; + } + } + if (next_select != prev_select) { + + _controls_snapshots_select = next_select; + update_dialog = true; + } + } + }); + event.handle_release([&] (Input::Keycode key) { + + if (key == Input::BTN_LEFT) { + + switch (_controls_snapshots_select) { + case Controls_snapshots_select::SHUT_DOWN_BUTTON: + + _controls_snapshots_select = Controls_snapshots_select::NONE; + _state = State::SHUTDOWN_ISSUE_DEINIT_REQUEST_AT_CBE; + + update_sandbox_config = true; + update_dialog = true; + break; + + case Controls_snapshots_select::CREATE_BUTTON: + + _controls_snapshots_select = Controls_snapshots_select::NONE; + _create_snap_state = Create_snapshot_state::ISSUE_REQUEST_AT_DEVICE; + + update_sandbox_config = true; + update_dialog = true; + break; + + case Controls_snapshots_select::GENERATION_DISCARD_BUTTON: + + _controls_snapshots_select = Controls_snapshots_select::NONE; + + if (_snapshots_select.valid()) { + _discard_snap_state = Discard_snapshot_state::ISSUE_REQUEST_AT_DEVICE; + _discard_snap_gen = _snapshots_select.object().generation(); + } + update_sandbox_config = true; + update_dialog = true; + break; + + default: + + break; + } + } + }); + break; + + case State::CONTROLS_DIMENSIONS: + + event.handle_press([&] (Input::Keycode key, Codepoint) { + + if (key == Input::BTN_LEFT) { + + Dimensions_select const prev_select { _dimensions_select }; + Dimensions_select next_select { Dimensions_select::NONE }; + + switch (_dimensions_hover) { + case Dimensions_hover::LEAVE_BUTTON: + + _state = State::CONTROLS_ROOT; + update_dialog = true; + break; + + case Dimensions_hover::EXPAND_CLIENT_FS_BUTTON: + + _state = State::CONTROLS_EXPAND_CLIENT_FS; + _expand_client_fs_select = Expand_client_fs_select::CONTINGENT_INPUT; + update_dialog = true; + break; + + case Dimensions_hover::EXPAND_SNAPSHOT_BUF_BUTTON: + + _state = State::CONTROLS_EXPAND_SNAPSHOT_BUF; + _expand_snapshot_buf_select = Expand_snapshot_buf_select::CONTINGENT_INPUT; + update_dialog = true; + break; + + case Dimensions_hover::SHUT_DOWN_BUTTON: + + next_select = Dimensions_select::SHUT_DOWN_BUTTON; + break; + + case Dimensions_hover::NONE: + + next_select = Dimensions_select::NONE; + break; + } + if (next_select != prev_select) { + + _dimensions_select = next_select; + update_dialog = true; + } + } + }); + event.handle_release([&] (Input::Keycode key) { + + if (key == Input::BTN_LEFT) { + + switch (_dimensions_select) { + case Dimensions_select::SHUT_DOWN_BUTTON: + + _dimensions_select = Dimensions_select::NONE; + _state = State::SHUTDOWN_ISSUE_DEINIT_REQUEST_AT_CBE; + + update_sandbox_config = true; + update_dialog = true; + break; + + default: + + break; + } + } + }); + break; + + case State::CONTROLS_EXPAND_CLIENT_FS: + + if (_nr_of_clients > 0) { + + event.handle_press([&] (Input::Keycode key, Codepoint) { + + if (key == Input::BTN_LEFT) { + + Expand_client_fs_select const prev_select { _expand_client_fs_select }; + Expand_client_fs_select next_select { Expand_client_fs_select::NONE }; + + switch (_expand_client_fs_hover) { + case Expand_client_fs_hover::LEAVE_BUTTON: + + _state = State::CONTROLS_DIMENSIONS; + update_dialog = true; + break; + + case Expand_client_fs_hover::SHUT_DOWN_BUTTON: + + next_select = Expand_client_fs_select::SHUT_DOWN_BUTTON; + break; + + case Expand_client_fs_hover::START_BUTTON: + case Expand_client_fs_hover::CONTINGENT_INPUT: + + break; + + case Expand_client_fs_hover::NONE: + + next_select = Expand_client_fs_select::NONE; + break; + } + if (next_select != prev_select) { + + _expand_client_fs_select = next_select; + update_dialog = true; + } + + } + }); + event.handle_release([&] (Input::Keycode key) { + + if (key == Input::BTN_LEFT || + key == Input::KEY_ENTER) { + + switch (_expand_client_fs_select) { + case Expand_client_fs_select::START_BUTTON: + + break; + + case Expand_client_fs_select::SHUT_DOWN_BUTTON: + + _expand_client_fs_select = Expand_client_fs_select::NONE; + _state = State::SHUTDOWN_ISSUE_DEINIT_REQUEST_AT_CBE; + + update_sandbox_config = true; + update_dialog = true; + break; + + default: + + break; + } + } + }); + + } else { + + event.handle_press([&] (Input::Keycode key, Codepoint code) { + + if (key == Input::BTN_LEFT) { + + Expand_client_fs_select const prev_select { _expand_client_fs_select }; + Expand_client_fs_select next_select { Expand_client_fs_select::NONE }; + + switch (_expand_client_fs_hover) { + case Expand_client_fs_hover::LEAVE_BUTTON: + + _state = State::CONTROLS_DIMENSIONS; + update_dialog = true; + break; + + case Expand_client_fs_hover::SHUT_DOWN_BUTTON: + + next_select = Expand_client_fs_select::SHUT_DOWN_BUTTON; + break; + + case Expand_client_fs_hover::START_BUTTON: + + next_select = Expand_client_fs_select::START_BUTTON; + break; + + case Expand_client_fs_hover::CONTINGENT_INPUT: + + next_select = Expand_client_fs_select::CONTINGENT_INPUT; + break; + + case Expand_client_fs_hover::NONE: + + next_select = Expand_client_fs_select::NONE; + break; + } + if (next_select != prev_select) { + + _expand_client_fs_select = next_select; + update_dialog = true; + } + + } else if (key == Input::KEY_ENTER) { + + size_t const bytes { + _expand_client_fs_contingent.value() }; + + size_t const effective_bytes { + bytes - (bytes % CBE_BLOCK_SIZE) }; + + if (effective_bytes > 0) { + + _expand_client_fs_select = Expand_client_fs_select::START_BUTTON; + update_dialog = true; + } + } else { + + if (_expand_client_fs_select == Expand_client_fs_select::CONTINGENT_INPUT) { + + if (_expand_client_fs_contingent.appendable_character(code)) { + + _expand_client_fs_contingent.append_character(code); + update_dialog = true; + + } else if (code.value == CODEPOINT_BACKSPACE) { + + _expand_client_fs_contingent.remove_last_character(); + update_dialog = true; + } + } + } + }); + event.handle_release([&] (Input::Keycode key) { + + if (key == Input::BTN_LEFT || + key == Input::KEY_ENTER) { + + switch (_expand_client_fs_select) { + case Expand_client_fs_select::START_BUTTON: + + _expand_client_fs_select = Expand_client_fs_select::NONE; + _resizing_type = Resizing_type::EXPAND_CLIENT_FS; + _resizing_state = Resizing_state::ADAPT_CBE_IMAGE_SIZE; + update_sandbox_config = true; + update_dialog = true; + + break; + + case Expand_client_fs_select::SHUT_DOWN_BUTTON: + + _expand_client_fs_select = Expand_client_fs_select::NONE; + _state = State::SHUTDOWN_ISSUE_DEINIT_REQUEST_AT_CBE; + + update_sandbox_config = true; + update_dialog = true; + break; + + default: + + break; + } + } + }); + } + break; + + case State::CONTROLS_EXPAND_SNAPSHOT_BUF: + + event.handle_press([&] (Input::Keycode key, Codepoint code) { + + if (key == Input::BTN_LEFT) { + + Expand_snapshot_buf_select const prev_select { _expand_snapshot_buf_select }; + Expand_snapshot_buf_select next_select { Expand_snapshot_buf_select::NONE }; + + switch (_expand_snapshot_buf_hover) { + case Expand_snapshot_buf_hover::LEAVE_BUTTON: + + _state = State::CONTROLS_DIMENSIONS; + update_dialog = true; + break; + + case Expand_snapshot_buf_hover::SHUT_DOWN_BUTTON: + + next_select = Expand_snapshot_buf_select::SHUT_DOWN_BUTTON; + break; + + case Expand_snapshot_buf_hover::START_BUTTON: + + next_select = Expand_snapshot_buf_select::START_BUTTON; + break; + + case Expand_snapshot_buf_hover::CONTINGENT_INPUT: + + next_select = Expand_snapshot_buf_select::CONTINGENT_INPUT; + break; + + case Expand_snapshot_buf_hover::NONE: + + next_select = Expand_snapshot_buf_select::NONE; + break; + } + if (next_select != prev_select) { + + _expand_snapshot_buf_select = next_select; + update_dialog = true; + } + + } else if (key == Input::KEY_ENTER) { + + size_t const bytes { + _expand_snapshot_buf_contingent.value() }; + + size_t const effective_bytes { + bytes - (bytes % CBE_BLOCK_SIZE) }; + + if (effective_bytes > 0) { + + _expand_snapshot_buf_select = Expand_snapshot_buf_select::START_BUTTON; + update_dialog = true; + } + } else { + + if (_expand_snapshot_buf_select == Expand_snapshot_buf_select::CONTINGENT_INPUT) { + + if (_expand_snapshot_buf_contingent.appendable_character(code)) { + + _expand_snapshot_buf_contingent.append_character(code); + update_dialog = true; + + } else if (code.value == CODEPOINT_BACKSPACE) { + + _expand_snapshot_buf_contingent.remove_last_character(); + update_dialog = true; + } + } + } + }); + event.handle_release([&] (Input::Keycode key) { + + if (key == Input::BTN_LEFT || + key == Input::KEY_ENTER) { + + switch (_expand_snapshot_buf_select) { + case Expand_snapshot_buf_select::START_BUTTON: + + _expand_snapshot_buf_select = Expand_snapshot_buf_select::NONE; + _resizing_type = Resizing_type::EXPAND_SNAPSHOT_BUF; + _resizing_state = Resizing_state::WAIT_TILL_DEVICE_IS_READY; + + update_sandbox_config = true; + update_dialog = true; + break; + + case Expand_snapshot_buf_select::SHUT_DOWN_BUTTON: + + _expand_snapshot_buf_select = Expand_snapshot_buf_select::NONE; + _state = State::SHUTDOWN_ISSUE_DEINIT_REQUEST_AT_CBE; + + update_sandbox_config = true; + update_dialog = true; + break; + + default: + + break; + } + } + }); + break; + + case State::CONTROLS_SECURITY: + + event.handle_press([&] (Input::Keycode key, Codepoint) { + + if (key == Input::BTN_LEFT) { + + Controls_security_select const prev_select { _controls_security_select }; + Controls_security_select next_select { Controls_security_select::NONE }; + + switch (_controls_security_hover) { + case Controls_security_hover::SECURITY_EXPAND_BUTTON: + + _state = State::CONTROLS_ROOT; + update_dialog = true; + break; + + case Controls_security_hover::BLOCK_ENCRYPTION_KEY_EXPAND_BUTTON: + + _state = State::CONTROLS_SECURITY_BLOCK_ENCRYPTION_KEY; + update_dialog = true; + break; + + case Controls_security_hover::MASTER_KEY_EXPAND_BUTTON: + + _state = State::CONTROLS_SECURITY_MASTER_KEY; + update_dialog = true; + break; + + case Controls_security_hover::USER_PASSPHRASE_EXPAND_BUTTON: + + _state = State::CONTROLS_SECURITY_USER_PASSPHRASE; + update_dialog = true; + break; + + case Controls_security_hover::SHUT_DOWN_BUTTON: + + next_select = Controls_security_select::SHUT_DOWN_BUTTON; + break; + + case Controls_security_hover::NONE: + + next_select = Controls_security_select::NONE; + break; + } + if (next_select != prev_select) { + + _controls_security_select = next_select; + update_dialog = true; + } + } + }); + event.handle_release([&] (Input::Keycode key) { + + if (key == Input::BTN_LEFT) { + + switch (_controls_security_select) { + case Controls_security_select::SHUT_DOWN_BUTTON: + + _controls_security_select = Controls_security_select::NONE; + _state = State::SHUTDOWN_ISSUE_DEINIT_REQUEST_AT_CBE; + + update_sandbox_config = true; + update_dialog = true; + break; + + default: + + break; + } + } + }); + break; + + case State::CONTROLS_SECURITY_BLOCK_ENCRYPTION_KEY: + + event.handle_press([&] (Input::Keycode key, Codepoint) { + + if (key == Input::BTN_LEFT) { + + Controls_security_block_encryption_key_select const prev_select { _controls_security_block_encryption_key_select }; + Controls_security_block_encryption_key_select next_select { Controls_security_block_encryption_key_select::NONE }; + + switch (_controls_security_block_encryption_key_hover) { + case Controls_security_block_encryption_key_hover::LEAVE_BUTTON: + + _state = State::CONTROLS_SECURITY; + update_dialog = true; + break; + + case Controls_security_block_encryption_key_hover::REPLACE_BUTTON: + + next_select = Controls_security_block_encryption_key_select::REPLACE_BUTTON; + break; + + case Controls_security_block_encryption_key_hover::SHUT_DOWN_BUTTON: + + next_select = Controls_security_block_encryption_key_select::SHUT_DOWN_BUTTON; + break; + + case Controls_security_block_encryption_key_hover::NONE: + + next_select = Controls_security_block_encryption_key_select::NONE; + break; + } + if (next_select != prev_select) { + + _controls_security_block_encryption_key_select = next_select; + update_dialog = true; + } + } + }); + event.handle_release([&] (Input::Keycode key) { + + if (key == Input::BTN_LEFT) { + + switch (_controls_security_block_encryption_key_select) { + case Controls_security_block_encryption_key_select::REPLACE_BUTTON: + + _controls_security_block_encryption_key_select = Controls_security_block_encryption_key_select::NONE; + _rekeying_state = Rekeying_state::WAIT_TILL_DEVICE_IS_READY; + + update_sandbox_config = true; + update_dialog = true; + break; + + case Controls_security_block_encryption_key_select::SHUT_DOWN_BUTTON: + + _controls_security_block_encryption_key_select = Controls_security_block_encryption_key_select::NONE; + _state = State::SHUTDOWN_ISSUE_DEINIT_REQUEST_AT_CBE; + + update_sandbox_config = true; + update_dialog = true; + break; + + default: + + break; + } + } + }); + break; + + case State::CONTROLS_SECURITY_MASTER_KEY: + + event.handle_press([&] (Input::Keycode key, Codepoint) { + + if (key == Input::BTN_LEFT) { + + Controls_security_master_key_select const prev_select { _controls_security_master_key_select }; + Controls_security_master_key_select next_select { Controls_security_master_key_select::NONE }; + + switch (_controls_security_master_key_hover) { + case Controls_security_master_key_hover::LEAVE_BUTTON: + + _state = State::CONTROLS_SECURITY; + update_dialog = true; + break; + + case Controls_security_master_key_hover::SHUT_DOWN_BUTTON: + + next_select = Controls_security_master_key_select::SHUT_DOWN_BUTTON; + break; + + case Controls_security_master_key_hover::NONE: + + next_select = Controls_security_master_key_select::NONE; + break; + } + if (next_select != prev_select) { + + _controls_security_master_key_select = next_select; + update_dialog = true; + } + } + }); + event.handle_release([&] (Input::Keycode key) { + + if (key == Input::BTN_LEFT) { + + switch (_controls_security_master_key_select) { + case Controls_security_master_key_select::SHUT_DOWN_BUTTON: + + _controls_security_master_key_select = Controls_security_master_key_select::NONE; + _state = State::SHUTDOWN_ISSUE_DEINIT_REQUEST_AT_CBE; + + update_sandbox_config = true; + update_dialog = true; + break; + + default: + + break; + } + } + }); + break; + + case State::CONTROLS_SECURITY_USER_PASSPHRASE: + + event.handle_press([&] (Input::Keycode key, Codepoint) { + + if (key == Input::BTN_LEFT) { + + Controls_security_user_passphrase_select const prev_select { _controls_security_user_passphrase_select }; + Controls_security_user_passphrase_select next_select { Controls_security_user_passphrase_select::NONE }; + + switch (_controls_security_user_passphrase_hover) { + case Controls_security_user_passphrase_hover::LEAVE_BUTTON: + + _state = State::CONTROLS_SECURITY; + update_dialog = true; + break; + + case Controls_security_user_passphrase_hover::SHUT_DOWN_BUTTON: + + next_select = Controls_security_user_passphrase_select::SHUT_DOWN_BUTTON; + break; + + case Controls_security_user_passphrase_hover::NONE: + + next_select = Controls_security_user_passphrase_select::NONE; + break; + } + if (next_select != prev_select) { + + _controls_security_user_passphrase_select = next_select; + update_dialog = true; + } + } + }); + event.handle_release([&] (Input::Keycode key) { + + if (key == Input::BTN_LEFT) { + + switch (_controls_security_user_passphrase_select) { + case Controls_security_user_passphrase_select::SHUT_DOWN_BUTTON: + + _controls_security_user_passphrase_select = Controls_security_user_passphrase_select::NONE; + _state = State::SHUTDOWN_ISSUE_DEINIT_REQUEST_AT_CBE; + + update_sandbox_config = true; + update_dialog = true; + break; + + default: + + break; + } + } + }); + break; + + default: + + break; + } + if (update_sandbox_config) { + _update_sandbox_config(); + } + if (update_dialog) { + _dialog.trigger_update(); + } +} + + +void File_vault::Main::_handle_hover(Xml_node const &node) +{ + bool update_dialog { false }; + + switch (_state) { + case State::SETUP_OBTAIN_PARAMETERS: + { + Setup_obtain_params_hover const prev_hover { _setup_obtain_params_hover }; + Setup_obtain_params_hover next_hover { Setup_obtain_params_hover::NONE }; + + node.with_sub_node("dialog", [&] (Xml_node const &node_0) { + node_0.with_sub_node("frame", [&] (Xml_node const &node_1) { + node_1.with_sub_node("vbox", [&] (Xml_node const &node_2) { + + node_2.with_sub_node("float", [&] (Xml_node const &node_3) { + if (_has_name(node_3, "ok")) { + next_hover = Setup_obtain_params_hover::START_BUTTON; + } + }); + node_2.with_sub_node("hbox", [&] (Xml_node const &node_3) { + node_3.with_sub_node("frame", [&] (Xml_node const &node_4) { + + if (_has_name(node_4, "Passphrase")) { + next_hover = Setup_obtain_params_hover::PASSPHRASE_INPUT; + } + }); + node_3.with_sub_node("float", [&] (Xml_node const &node_4) { + node_4.with_sub_node("button", [&] (Xml_node const &node_5) { + + if (_has_name(node_5, "Show Hide")) { + next_hover = Setup_obtain_params_hover::PASSPHRASE_SHOW_HIDE_BUTTON; + } + }); + }); + }); + node_2.with_sub_node("frame", [&] (Xml_node const &node_3) { + + if (_has_name(node_3, "Client FS Size")) { + next_hover = Setup_obtain_params_hover::CLIENT_FS_SIZE_INPUT; + + } if (_has_name(node_3, "Snapshot Buffer Size")) { + next_hover = Setup_obtain_params_hover::SNAPSHOT_BUFFER_SIZE_INPUT; + } + }); + }); + }); + }); + if (next_hover != prev_hover) { + + _setup_obtain_params_hover = next_hover; + update_dialog = true; + } + break; + } + case State::STARTUP_OBTAIN_PARAMETERS: + { + Setup_obtain_params_hover const prev_hover { _setup_obtain_params_hover }; + Setup_obtain_params_hover next_hover { Setup_obtain_params_hover::NONE }; + + node.with_sub_node("dialog", [&] (Xml_node const &node_0) { + node_0.with_sub_node("frame", [&] (Xml_node const &node_1) { + node_1.with_sub_node("vbox", [&] (Xml_node const &node_2) { + + node_2.with_sub_node("float", [&] (Xml_node const &node_3) { + if (_has_name(node_3, "ok")) { + next_hover = Setup_obtain_params_hover::START_BUTTON; + } + }); + node_2.with_sub_node("hbox", [&] (Xml_node const &node_3) { + node_3.with_sub_node("frame", [&] (Xml_node const &node_4) { + + if (_has_name(node_4, "Passphrase")) { + next_hover = Setup_obtain_params_hover::PASSPHRASE_INPUT; + } + }); + node_3.with_sub_node("float", [&] (Xml_node const &node_4) { + node_4.with_sub_node("button", [&] (Xml_node const &node_5) { + + if (_has_name(node_5, "Show Hide")) { + next_hover = Setup_obtain_params_hover::PASSPHRASE_SHOW_HIDE_BUTTON; + } + }); + }); + }); + }); + }); + }); + if (next_hover != prev_hover) { + + _setup_obtain_params_hover = next_hover; + update_dialog = true; + } + break; + } + case State::CONTROLS_ROOT: + { + Controls_root_hover const prev_hover { _controls_root_hover }; + Controls_root_hover next_hover { Controls_root_hover::NONE }; + + node.with_sub_node("dialog", [&] (Xml_node const &node_0) { + node_0.with_sub_node("frame", [&] (Xml_node const &node_1) { + node_1.with_sub_node("vbox", [&] (Xml_node const &node_2) { + node_2.with_sub_node("hbox", [&] (Xml_node const &node_3) { + node_3.with_sub_node("button", [&] (Xml_node const &node_4) { + + if (_has_name(node_4, "Shut down")) { + + next_hover = Controls_root_hover::SHUT_DOWN_BUTTON; + + } + }); + }); + node_2.with_sub_node("frame", [&] (Xml_node const &node_3) { + node_3.with_sub_node("vbox", [&] (Xml_node const &node_4) { + node_4.with_sub_node("vbox", [&] (Xml_node const &node_5) { + + if (_has_name(node_5, "Snapshots")) { + + next_hover = Controls_root_hover::SNAPSHOTS_EXPAND_BUTTON; + + } else if (_has_name(node_5, "Dimensions")) { + + next_hover = Controls_root_hover::DIMENSIONS_BUTTON; + + } else if (_has_name(node_5, "Security")) { + + next_hover = Controls_root_hover::SECURITY_EXPAND_BUTTON; + } + }); + }); + }); + }); + }); + }); + if (next_hover != prev_hover) { + + _controls_root_hover = next_hover; + update_dialog = true; + } + break; + } + case State::CONTROLS_SNAPSHOTS: + { + Controls_snapshots_hover const prev_hover { _controls_snapshots_hover }; + Controls_snapshots_hover next_hover { Controls_snapshots_hover::NONE }; + + Snapshot_pointer const prev_snapshots_hover { _snapshots_hover }; + Snapshot_pointer next_snapshots_hover { }; + + node.with_sub_node("dialog", [&] (Xml_node const &node_0) { + node_0.with_sub_node("frame", [&] (Xml_node const &node_1) { + node_1.with_sub_node("vbox", [&] (Xml_node const &node_2) { + node_2.with_sub_node("hbox", [&] (Xml_node const &node_3) { + node_3.with_sub_node("button", [&] (Xml_node const &node_4) { + + if (_has_name(node_4, "Shut down")) { + + next_hover = Controls_snapshots_hover::SHUT_DOWN_BUTTON; + } + }); + }); + node_2.with_sub_node("frame", [&] (Xml_node const &node_3) { + node_3.with_sub_node("vbox", [&] (Xml_node const &node_4) { + node_4.with_sub_node("vbox", [&] (Xml_node const &node_5) { + + if (_snapshots_select.valid()) { + + node_5.with_sub_node("hbox", [&] (Xml_node const &node_6) { + + if (_has_name(node_6, "Leave")) { + + next_hover = Controls_snapshots_hover::GENERATION_LEAVE_BUTTON; + } + }); + node_5.with_sub_node("button", [&] (Xml_node const &node_6) { + + if (_has_name(node_6, "Discard")) { + + next_hover = Controls_snapshots_hover::GENERATION_DISCARD_BUTTON; + } + }); + + } else { + + node_5.with_sub_node("hbox", [&] (Xml_node const &node_6) { + + if (_has_name(node_6, "Leave")) { + + next_hover = Controls_snapshots_hover::LEAVE_BUTTON; + } + }); + node_5.with_sub_node("vbox", [&] (Xml_node const &node_6) { + + if (_has_name(node_6, "Generations")) { + + node_6.with_sub_node("float", [&] (Xml_node const &node_7) { + + Generation const generation { + node_7.attribute_value( + "name", Generation { INVALID_GENERATION }) }; + + if (generation != INVALID_GENERATION) { + + _snapshots.for_each([&] (Snapshot const &snap) + { + if (generation == snap.generation()) { + next_snapshots_hover = snap; + } + }); + } + }); + } + }); + node_5.with_sub_node("button", [&] (Xml_node const &node_6) { + + if (_has_name(node_6, "Create")) { + + next_hover = Controls_snapshots_hover::CREATE_BUTTON; + } + }); + } + }); + }); + }); + }); + }); + }); + if (next_snapshots_hover != prev_snapshots_hover) { + + _snapshots_hover = next_snapshots_hover; + update_dialog = true; + } + if (next_hover != prev_hover) { + + _controls_snapshots_hover = next_hover; + update_dialog = true; + } + break; + } + case State::CONTROLS_DIMENSIONS: + { + Dimensions_hover const prev_hover { _dimensions_hover }; + Dimensions_hover next_hover { Dimensions_hover::NONE }; + + node.with_sub_node("dialog", [&] (Xml_node const &node_0) { + node_0.with_sub_node("frame", [&] (Xml_node const &node_1) { + node_1.with_sub_node("vbox", [&] (Xml_node const &node_2) { + node_2.with_sub_node("hbox", [&] (Xml_node const &node_3) { + node_3.with_sub_node("button", [&] (Xml_node const &node_4) { + + if (_has_name(node_4, "Shut down")) { + + next_hover = Dimensions_hover::SHUT_DOWN_BUTTON; + } + }); + }); + node_2.with_sub_node("frame", [&] (Xml_node const &node_3) { + node_3.with_sub_node("vbox", [&] (Xml_node const &node_4) { + node_4.with_sub_node("hbox", [&] (Xml_node const &node_5) { + + if (_has_name(node_5, "Leave")) { + + next_hover = Dimensions_hover::LEAVE_BUTTON; + } + }); + node_4.with_sub_node("vbox", [&] (Xml_node const &node_5) { + + if (_has_name(node_5, "Expand Client FS")) { + + next_hover = Dimensions_hover::EXPAND_CLIENT_FS_BUTTON; + + } else if (_has_name(node_5, + RENAME_SNAPSHOT_BUFFER_JOURNALING_BUFFER ? + "Expand Journaling Buffer" : + "Expand Snapshot Buffer")) { + + next_hover = Dimensions_hover::EXPAND_SNAPSHOT_BUF_BUTTON; + } + }); + }); + }); + }); + }); + }); + if (next_hover != prev_hover) { + + _dimensions_hover = next_hover; + update_dialog = true; + } + break; + } + case State::CONTROLS_EXPAND_CLIENT_FS: + { + Expand_client_fs_hover const prev_hover { _expand_client_fs_hover }; + Expand_client_fs_hover next_hover { Expand_client_fs_hover::NONE }; + + node.with_sub_node("dialog", [&] (Xml_node const &node_0) { + node_0.with_sub_node("frame", [&] (Xml_node const &node_1) { + node_1.with_sub_node("vbox", [&] (Xml_node const &node_2) { + node_2.with_sub_node("hbox", [&] (Xml_node const &node_3) { + node_3.with_sub_node("button", [&] (Xml_node const &node_4) { + + if (_has_name(node_4, "Shut down")) { + + next_hover = Expand_client_fs_hover::SHUT_DOWN_BUTTON; + + } + }); + }); + node_2.with_sub_node("frame", [&] (Xml_node const &node_3) { + node_3.with_sub_node("vbox", [&] (Xml_node const &node_4) { + node_4.with_sub_node("vbox", [&] (Xml_node const &node_5) { + node_5.with_sub_node("hbox", [&] (Xml_node const &node_6) { + + if (_has_name(node_6, "Leave")) { + + next_hover = Expand_client_fs_hover::LEAVE_BUTTON; + } + }); + node_5.with_sub_node("float", [&] (Xml_node const &node_6) { + + if (_has_name(node_6, "Start")) { + + next_hover = Expand_client_fs_hover::START_BUTTON; + } + }); + node_5.with_sub_node("frame", [&] (Xml_node const &node_6) { + + if (_has_name(node_6, "Contingent")) { + + next_hover = Expand_client_fs_hover::CONTINGENT_INPUT; + } + }); + }); + }); + }); + }); + }); + }); + if (next_hover != prev_hover) { + + _expand_client_fs_hover = next_hover; + update_dialog = true; + } + break; + } + case State::CONTROLS_EXPAND_SNAPSHOT_BUF: + { + Expand_snapshot_buf_hover const prev_hover { _expand_snapshot_buf_hover }; + Expand_snapshot_buf_hover next_hover { Expand_snapshot_buf_hover::NONE }; + + node.with_sub_node("dialog", [&] (Xml_node const &node_0) { + node_0.with_sub_node("frame", [&] (Xml_node const &node_1) { + node_1.with_sub_node("vbox", [&] (Xml_node const &node_2) { + node_2.with_sub_node("hbox", [&] (Xml_node const &node_3) { + + node_3.with_sub_node("button", [&] (Xml_node const &node_4) { + + if (_has_name(node_4, "Shut down")) { + + next_hover = Expand_snapshot_buf_hover::SHUT_DOWN_BUTTON; + + } + }); + }); + node_2.with_sub_node("frame", [&] (Xml_node const &node_3) { + node_3.with_sub_node("vbox", [&] (Xml_node const &node_4) { + node_4.with_sub_node("vbox", [&] (Xml_node const &node_5) { + + node_5.with_sub_node("hbox", [&] (Xml_node const &node_6) { + + if (_has_name(node_6, "Leave")) { + + next_hover = Expand_snapshot_buf_hover::LEAVE_BUTTON; + } + }); + node_5.with_sub_node("float", [&] (Xml_node const &node_6) { + + if (_has_name(node_6, "Start")) { + + next_hover = Expand_snapshot_buf_hover::START_BUTTON; + } + }); + node_5.with_sub_node("frame", [&] (Xml_node const &node_6) { + + if (_has_name(node_6, "Contingent")) { + + next_hover = Expand_snapshot_buf_hover::CONTINGENT_INPUT; + } + }); + }); + }); + }); + }); + }); + }); + if (next_hover != prev_hover) { + + _expand_snapshot_buf_hover = next_hover; + update_dialog = true; + } + break; + } + case State::CONTROLS_SECURITY: + { + Controls_security_hover const prev_hover { _controls_security_hover }; + Controls_security_hover next_hover { Controls_security_hover::NONE }; + + node.with_sub_node("dialog", [&] (Xml_node const &node_0) { + node_0.with_sub_node("frame", [&] (Xml_node const &node_1) { + node_1.with_sub_node("vbox", [&] (Xml_node const &node_2) { + node_2.with_sub_node("hbox", [&] (Xml_node const &node_3) { + node_3.with_sub_node("button", [&] (Xml_node const &node_4) { + + if (_has_name(node_4, "Shut down")) { + + next_hover = Controls_security_hover::SHUT_DOWN_BUTTON; + + } + }); + }); + node_2.with_sub_node("frame", [&] (Xml_node const &node_3) { + node_3.with_sub_node("vbox", [&] (Xml_node const &node_4) { + node_4.with_sub_node("hbox", [&] (Xml_node const &node_5) { + + if (_has_name(node_5, "Leave")) { + + next_hover = Controls_security_hover::SECURITY_EXPAND_BUTTON; + } + }); + node_4.with_sub_node("vbox", [&] (Xml_node const &node_5) { + + if (_has_name(node_5, "Block Encryption Key")) { + + next_hover = Controls_security_hover::BLOCK_ENCRYPTION_KEY_EXPAND_BUTTON; + + } else if (_has_name(node_5, "Master Key")) { + + next_hover = Controls_security_hover::MASTER_KEY_EXPAND_BUTTON; + + } else if (_has_name(node_5, "User Passphrase")) { + + next_hover = Controls_security_hover::USER_PASSPHRASE_EXPAND_BUTTON; + } + }); + }); + }); + }); + }); + }); + if (next_hover != prev_hover) { + + _controls_security_hover = next_hover; + update_dialog = true; + } + break; + } + case State::CONTROLS_SECURITY_BLOCK_ENCRYPTION_KEY: + { + Controls_security_block_encryption_key_hover const prev_hover { _controls_security_block_encryption_key_hover }; + Controls_security_block_encryption_key_hover next_hover { Controls_security_block_encryption_key_hover::NONE }; + + node.with_sub_node("dialog", [&] (Xml_node const &node_0) { + node_0.with_sub_node("frame", [&] (Xml_node const &node_1) { + node_1.with_sub_node("vbox", [&] (Xml_node const &node_2) { + node_2.with_sub_node("hbox", [&] (Xml_node const &node_3) { + node_3.with_sub_node("button", [&] (Xml_node const &node_4) { + + if (_has_name(node_4, "Shut down")) { + + next_hover = Controls_security_block_encryption_key_hover::SHUT_DOWN_BUTTON; + + } + }); + }); + node_2.with_sub_node("frame", [&] (Xml_node const &node_3) { + node_3.with_sub_node("vbox", [&] (Xml_node const &node_4) { + node_4.with_sub_node("button", [&] (Xml_node const &node_5) { + + if (_has_name(node_5, "Rekey")) { + + next_hover = Controls_security_block_encryption_key_hover::REPLACE_BUTTON; + } + }); + node_4.with_sub_node("hbox", [&] (Xml_node const &node_5) { + + if (_has_name(node_5, "Leave")) { + + next_hover = Controls_security_block_encryption_key_hover::LEAVE_BUTTON; + } + }); + }); + }); + }); + }); + }); + if (next_hover != prev_hover) { + + _controls_security_block_encryption_key_hover = next_hover; + update_dialog = true; + } + break; + } + case State::CONTROLS_SECURITY_MASTER_KEY: + { + Controls_security_master_key_hover const prev_hover { _controls_security_master_key_hover }; + Controls_security_master_key_hover next_hover { Controls_security_master_key_hover::NONE }; + + node.with_sub_node("dialog", [&] (Xml_node const &node_0) { + node_0.with_sub_node("frame", [&] (Xml_node const &node_1) { + node_1.with_sub_node("vbox", [&] (Xml_node const &node_2) { + node_2.with_sub_node("hbox", [&] (Xml_node const &node_3) { + node_3.with_sub_node("button", [&] (Xml_node const &node_4) { + + if (_has_name(node_4, "Shut down")) { + + next_hover = Controls_security_master_key_hover::SHUT_DOWN_BUTTON; + + } + }); + }); + node_2.with_sub_node("frame", [&] (Xml_node const &node_3) { + node_3.with_sub_node("vbox", [&] (Xml_node const &node_4) { + node_4.with_sub_node("hbox", [&] (Xml_node const &node_5) { + + if (_has_name(node_5, "Leave")) { + + next_hover = Controls_security_master_key_hover::LEAVE_BUTTON; + } + }); + }); + }); + }); + }); + }); + if (next_hover != prev_hover) { + + _controls_security_master_key_hover = next_hover; + update_dialog = true; + } + break; + } + case State::CONTROLS_SECURITY_USER_PASSPHRASE: + { + Controls_security_user_passphrase_hover const prev_hover { _controls_security_user_passphrase_hover }; + Controls_security_user_passphrase_hover next_hover { Controls_security_user_passphrase_hover::NONE }; + + node.with_sub_node("dialog", [&] (Xml_node const &node_0) { + node_0.with_sub_node("frame", [&] (Xml_node const &node_1) { + node_1.with_sub_node("vbox", [&] (Xml_node const &node_2) { + node_2.with_sub_node("hbox", [&] (Xml_node const &node_3) { + node_3.with_sub_node("button", [&] (Xml_node const &node_4) { + + if (_has_name(node_4, "Shut down")) { + + next_hover = Controls_security_user_passphrase_hover::SHUT_DOWN_BUTTON; + + } + }); + }); + node_2.with_sub_node("frame", [&] (Xml_node const &node_3) { + node_3.with_sub_node("vbox", [&] (Xml_node const &node_4) { + node_4.with_sub_node("hbox", [&] (Xml_node const &node_5) { + + if (_has_name(node_5, "Leave")) { + + next_hover = Controls_security_user_passphrase_hover::LEAVE_BUTTON; + } + }); + }); + }); + }); + }); + }); + if (next_hover != prev_hover) { + + _controls_security_user_passphrase_hover = next_hover; + update_dialog = true; + } + break; + } + default: + + break; + } + if (update_dialog) { + _dialog.trigger_update(); + } +} + + +/*********************** + ** Genode::Component ** + ***********************/ + +void Component::construct(Genode::Env &env) +{ + static File_vault::Main main { env }; +} diff --git a/repos/gems/src/app/file_vault/menu_view_dialog.cc b/repos/gems/src/app/file_vault/menu_view_dialog.cc new file mode 100644 index 0000000000..a154a05fae --- /dev/null +++ b/repos/gems/src/app/file_vault/menu_view_dialog.cc @@ -0,0 +1,389 @@ +/* + * \brief Local utilities for the menu view dialog + * \author Martin Stein + * \date 2021-02-24 + */ + +/* + * Copyright (C) 2021 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +/* local includes */ +#include +#include + +using namespace File_vault; + + +void File_vault::gen_normal_font_attribute(Xml_generator &xml) +{ + xml.attribute("font", "text/regular"); +} + + +void File_vault::gen_frame_title(Xml_generator &xml, + char const *name, + unsigned long min_width) +{ + + xml.node("float", [&] () { + xml.attribute("name", name); + xml.attribute("west", "yes"); + xml.attribute("north", "yes"); + + xml.node("label", [&] () { + xml.attribute("text", "" ); + xml.attribute("min_ex", min_width); + }); + }); +} + +void File_vault::gen_info_frame(Xml_generator &xml, + char const *name, + char const *info, + unsigned long min_width) +{ + gen_main_frame(xml, name, min_width, [&] (Xml_generator &xml) { + + gen_centered_info_line(xml, "info", info); + gen_info_line(xml, "pad_1", ""); + }); +} + +void File_vault::gen_action_button_at_bottom(Xml_generator &xml, + char const *name, + char const *label, + bool hovered, + bool selected) +{ + xml.node("float", [&] () { + xml.attribute("name", name); + xml.attribute("east", "yes"); + xml.attribute("west", "yes"); + xml.attribute("south", "yes"); + + xml.node("button", [&] () { + + if (hovered) { + xml.attribute("hovered", "yes"); + } + if (selected) { + xml.attribute("selected", "yes"); + } + + xml.node("float", [&] () { + + xml.node("label", [&] () { + gen_normal_font_attribute(xml); + xml.attribute("text", label); + }); + }); + }); + }); +} + +void File_vault::gen_action_button_at_bottom(Xml_generator &xml, + char const *label, + bool hovered, + bool selected) +{ + gen_action_button_at_bottom(xml, label, label, hovered, selected); +} + +void File_vault::gen_action_button(Xml_generator &xml, + char const *name, + char const *label, + bool hovered, + bool selected, + size_t min_ex) +{ + xml.node("button", [&] () { + xml.attribute("name", name); + + if (hovered) { + xml.attribute("hovered", "yes"); + } + if (selected) { + xml.attribute("selected", "yes"); + } + xml.node("label", [&] () { + + if (min_ex != 0) { + xml.attribute("min_ex", min_ex); + } + xml.attribute("text", label); + }); + }); +} + +void File_vault::gen_text_input(Xml_generator &xml, + char const *name, + String<256> const &text, + bool selected) +{ + String<256> const padded_text { " ", text }; + + xml.node("frame", [&] () { + xml.attribute("name", name); + xml.node("float", [&] () { + xml.attribute("west", "yes"); + xml.node("label", [&] () { + gen_normal_font_attribute(xml); + xml.attribute("text", padded_text); + + if (selected) { + xml.node("cursor", [&] () { + xml.attribute("at", padded_text.length() - 1 ); + }); + } + }); + }); + }); +} + +void +File_vault:: +gen_input_passphrase(Xml_generator &xml, + size_t max_width, + Input_passphrase const &passphrase, + bool input_selected, + bool show_hide_button_hovered, + bool show_hide_button_selected) +{ + char const *show_hide_button_label; + size_t cursor_at; + if (passphrase.hide()) { + + show_hide_button_label = "Show"; + cursor_at = passphrase.length() + 1; + + } else { + + show_hide_button_label = "Hide"; + cursor_at = passphrase.length() + 1; + } + xml.node("float", [&] () { + xml.attribute("name", "Passphrase Label"); + xml.attribute("west", "yes"); + + xml.node("label", [&] () { + gen_normal_font_attribute(xml); + xml.attribute("text", " Passphrase: "); + }); + }); + xml.node("hbox", [&] () { + + String<256> const padded_text { " ", passphrase, " " }; + xml.node("frame", [&] () { + xml.attribute("name", "Passphrase"); + xml.node("float", [&] () { + xml.attribute("west", "yes"); + xml.node("label", [&] () { + xml.attribute("min_ex", max_width - 11); + gen_normal_font_attribute(xml); + xml.attribute("text", padded_text); + + + if (input_selected) { + xml.node("cursor", [&] () { + xml.attribute("at", cursor_at ); + }); + } + }); + }); + }); + xml.node("float", [&] () { + xml.attribute("name", "1"); + xml.attribute("east", "yes"); + + gen_action_button( + xml, "Show Hide", show_hide_button_label, + show_hide_button_hovered, show_hide_button_selected, 5); + }); + }); +} + +void File_vault::gen_titled_text_input(Xml_generator &xml, + char const *name, + char const *title, + String<256> const &text, + bool selected) +{ + xml.node("float", [&] () { + xml.attribute("name", String<64> { name, "_label" }); + xml.attribute("west", "yes"); + + xml.node("label", [&] () { + gen_normal_font_attribute(xml); + xml.attribute("text", String<64> { " ", title, ": " }); + }); + }); + gen_text_input(xml, name, text, selected); +} + +void File_vault::gen_empty_line(Xml_generator &xml, + char const *name, + size_t min_width) +{ + xml.node("label", [&] () { + xml.attribute("name", name); + xml.attribute("min_ex", min_width); + xml.attribute("text", ""); + }); +} + +void File_vault::gen_info_line(Xml_generator &xml, + char const *name, + char const *text) +{ + xml.node("float", [&] () { + xml.attribute("name", name); + xml.attribute("west", "yes"); + xml.node("label", [&] () { + gen_normal_font_attribute(xml); + xml.attribute("text", String<256> { " ", text, " "}); + }); + }); +} + +void File_vault::gen_centered_info_line(Xml_generator &xml, + char const *name, + char const *text) +{ + xml.node("float", [&] () { + xml.attribute("name", name); + xml.node("label", [&] () { + gen_normal_font_attribute(xml); + xml.attribute("text", String<256> { " ", text, " "}); + }); + }); +} + +void File_vault::gen_multiple_choice_entry(Xml_generator &xml, + char const *name, + char const *text, + bool hovered, + bool selected) +{ + xml.node("float", [&] () { + xml.attribute("name", name); + xml.attribute("west", "yes"); + + xml.node("hbox", [&] () { + + xml.node("button", [&] () { + if (selected) { + xml.attribute("selected", "yes"); + } + if (hovered) { + xml.attribute("hovered", "yes"); + } + xml.attribute("style", "radio"); + + xml.node("hbox", [&] () { }); + }); + xml.node("label", [&] () { + gen_normal_font_attribute(xml); + xml.attribute("text", String<64> { " ", text }); + }); + }); + }); +} + +void File_vault::gen_menu_title(Xml_generator &xml, + char const *name, + char const *label, + char const *label_annex, + bool hovered, + bool selected) +{ + xml.node("hbox", [&] () { + xml.attribute("name", name); + + xml.node("float", [&] () { + xml.attribute("name", "0"); + xml.attribute("west", "yes"); + + xml.node("hbox", [&] () { + + xml.node("button", [&] () { + if (selected) { + xml.attribute("style", "back"); + xml.attribute("selected", "yes"); + } else { + xml.attribute("style", "radio"); + } + if (hovered) { + xml.attribute("hovered", "yes"); + } + xml.attribute("hovered", "no"); + + xml.node("hbox", [&] () { }); + }); + xml.node("label", [&] () { + if (selected) { + xml.attribute("font", "title/regular"); + } + xml.attribute("text", String<64> { " ", label }); + }); + }); + }); + xml.node("float", [&] () { + xml.attribute("name", "2"); + xml.attribute("east", "yes"); + + xml.node("label", [&] () { + xml.attribute("font", "title/regular"); + xml.attribute( + "text", label_annex); + }); + }); + }); +} + + +void File_vault::gen_closed_menu(Xml_generator &xml, + char const *label, + char const *label_annex, + bool hovered) +{ + xml.node("vbox", [&] () { + xml.attribute("name", label); + + gen_menu_title(xml, "Enter", label, label_annex, hovered, false); + }); +} + + +void File_vault::gen_global_controls(Xml_generator &xml, + size_t min_width, + size_t cbe_image_size, + size_t client_fs_size, + size_t nr_of_clients, + bool shut_down_button_hovered, + bool shut_down_button_selected) +{ + gen_empty_line(xml, "Status 0", min_width); + gen_centered_info_line(xml, "Status 1", + String<256> { + " Image: ", + Capacity_string { cbe_image_size }, + ", Client FS: ", + Capacity_string { client_fs_size }, + ", Clients: ", + nr_of_clients + }.string() + ); + + gen_empty_line(xml, "Status 3", 0); + + xml.node("hbox", [&] () { + gen_action_button( + xml, "Shut down", "Shut down", + shut_down_button_hovered, + shut_down_button_selected); + }); +} diff --git a/repos/gems/src/app/file_vault/menu_view_dialog.h b/repos/gems/src/app/file_vault/menu_view_dialog.h new file mode 100644 index 0000000000..7c66dfc270 --- /dev/null +++ b/repos/gems/src/app/file_vault/menu_view_dialog.h @@ -0,0 +1,181 @@ +/* + * \brief Local utilities for the menu view dialog + * \author Martin Stein + * \date 2021-02-24 + */ + +/* + * Copyright (C) 2021 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#ifndef _MENU_VIEW_DIALOG_H_ +#define _MENU_VIEW_DIALOG_H_ + +/* Genode includes */ +#include + +/* local includes */ +#include +#include + +namespace File_vault { + + void gen_normal_font_attribute(Xml_generator &xml); + + void gen_frame_title(Xml_generator &xml, + char const *name, + unsigned long min_width); + + template + void gen_main_frame(Xml_generator &xml, + char const *name, + unsigned long min_width, + GEN_FRAME_CONTENT const &gen_frame_content) + { + xml.node("frame", [&] () { + xml.attribute("name", name); + + xml.node("vbox", [&] () { + + gen_frame_title(xml, "title", min_width); + gen_frame_content(xml); + }); + }); + } + + template + void gen_controls_frame(Xml_generator &xml, + char const *name, + GEN_FRAME_CONTENT const &gen_frame_content) + { + xml.node("frame", [&] () { + xml.attribute("name", name); + + xml.node("vbox", [&] () { + + gen_frame_content(xml); + }); + }); + } + + template + void gen_untitled_frame(Xml_generator &xml, + char const *name, + GEN_FRAME_CONTENT const &gen_frame_content) + { + xml.node("frame", [&] () { + xml.attribute("name", name); + + xml.node("float", [&] () { + xml.attribute("name", "xxx"); + xml.attribute("east", "yes"); + xml.attribute("west", "yes"); + xml.attribute("north", "yes"); + + xml.node("vbox", [&] () { + + gen_frame_content(xml); + }); + }); + }); + } + + void gen_info_frame(Xml_generator &xml, + char const *name, + char const *info, + unsigned long min_width); + + void gen_action_button_at_bottom(Xml_generator &xml, + char const *name, + char const *label, + bool hovered, + bool selected); + + void gen_action_button_at_bottom(Xml_generator &xml, + char const *label, + bool hovered, + bool selected); + + void gen_text_input(Xml_generator &xml, + char const *name, + String<256> const &text, + bool selected); + + void gen_titled_text_input(Xml_generator &xml, + char const *name, + char const *title, + String<256> const &text, + bool selected); + + void gen_info_line(Xml_generator &xml, + char const *name, + char const *text); + + void gen_centered_info_line(Xml_generator &xml, + char const *name, + char const *text); + + void gen_empty_line(Xml_generator &xml, + char const *name, + size_t min_width); + + void gen_multiple_choice_entry(Xml_generator &xml, + char const *name, + char const *text, + bool hovered, + bool selected); + + void gen_menu_title(Xml_generator &xml, + char const *name, + char const *label, + char const *label_annex, + bool hovered, + bool selected); + + void gen_closed_menu(Xml_generator &xml, + char const *label, + char const *label_annex, + bool hovered); + + template + void gen_opened_menu(Xml_generator &xml, + char const *label, + char const *label_annex, + bool hovered, + GEN_CONTENT const &gen_content) + { + xml.node("vbox", [&] () { + xml.attribute("name", label); + + gen_menu_title(xml, "Leave", label, label_annex, hovered, true); + gen_content(xml); + }); + } + + void gen_input_passphrase(Xml_generator &xml, + size_t max_width, + Input_passphrase const &passphrase, + bool input_selected, + bool show_hide_button_hovered, + bool show_hide_button_selected); + + void gen_action_button(Xml_generator &xml, + char const *name, + char const *label, + bool hovered, + bool selected, + size_t min_ex = 0); + + void gen_global_controls(Xml_generator &xml, + size_t min_width, + size_t cbe_image_size, + size_t client_fs_size, + size_t nr_of_clients, + bool shut_down_button_hovered, + bool shut_down_button_selected); +} + +#endif /* _MENU_VIEW_DIALOG_H_ */ diff --git a/repos/gems/src/app/file_vault/report_session_component.h b/repos/gems/src/app/file_vault/report_session_component.h new file mode 100644 index 0000000000..2e1c6a63b2 --- /dev/null +++ b/repos/gems/src/app/file_vault/report_session_component.h @@ -0,0 +1,91 @@ +/* + * \brief Report session provided by the CBE manager + * \author Martin Stein + * \author Norman Feske + * \date 2021-02-25 + */ + +/* + * Copyright (C) 2021 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#ifndef _REPORT_SESSION_COMPONENT_H_ +#define _REPORT_SESSION_COMPONENT_H_ + +/* Genode includes */ +#include +#include +#include + +namespace Report { + + using namespace Genode; + + class Session_component; +} + + +class Report::Session_component : public Session_object +{ + public: + + struct Handler_base : Interface, Genode::Noncopyable + { + virtual void handle_report(char const *, size_t) = 0; + }; + + template + struct Xml_handler : Handler_base + { + T &_obj; + void (T::*_member) (Xml_node const &); + + Xml_handler(T &obj, void (T::*member)(Xml_node const &)) + : _obj(obj), _member(member) { } + + void handle_report(char const *start, size_t length) override + { + (_obj.*_member)(Xml_node(start, length)); + } + }; + + private: + + Attached_ram_dataspace _ds; + + Handler_base &_handler; + + + /******************************* + ** Report::Session interface ** + *******************************/ + + Dataspace_capability dataspace() override { return _ds.cap(); } + + void submit(size_t length) override + { + _handler.handle_report(_ds.local_addr(), + min(_ds.size(), length)); + } + + void response_sigh(Signal_context_capability) override { } + + size_t obtain_response() override { return 0; } + + public: + + template + Session_component(Env &env, Handler_base &handler, + Entrypoint &ep, Resources const &resources, + ARGS &&... args) + : + Session_object(ep, resources, args...), + _ds(env.ram(), env.rm(), resources.ram_quota.value), + _handler(handler) + { } +}; + +#endif /* _REPORT_SESSION_COMPONENT_H_ */ diff --git a/repos/gems/src/app/file_vault/sandbox.h b/repos/gems/src/app/file_vault/sandbox.h new file mode 100644 index 0000000000..cc579cb049 --- /dev/null +++ b/repos/gems/src/app/file_vault/sandbox.h @@ -0,0 +1,997 @@ +/* + * \brief Local utilities for the sandbox API + * \author Martin Stein + * \date 2021-02-24 + */ + +/* + * Copyright (C) 2021 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#ifndef _SANDBOX_H_ +#define _SANDBOX_H_ + +/* Genode includes */ +#include +#include + +/* local includes */ +#include + +namespace File_vault { + + template + void gen_arg(Xml_generator &xml, ARG const &arg) + { + xml.node("arg", [&] () { xml.attribute("value", arg); }); + } + + template + static inline void gen_named_node(Xml_generator &xml, + char const *type, char const *name, FN const &fn) + { + xml.node(type, [&] () { + xml.attribute("name", name); + fn(); + }); + } + + static inline void gen_common_start_content(Xml_generator &xml, + char const *name, + Cap_quota const caps, + Ram_quota const ram) + { + xml.attribute("name", name); + xml.attribute("caps", caps.value); + gen_named_node(xml, "resource", "RAM", [&] () { + xml.attribute("quantum", String<64>(Number_of_bytes(ram.value))); }); + } + + void route_to_child_service(Genode::Xml_generator &xml, + char const *child_name, + char const *service_name, + char const *service_label = "") + { + xml.node("service", [&] () { + xml.attribute("name", service_name); + if (Genode::strcmp(service_label, "")) { + xml.attribute("label", service_label); + } + xml.attribute("name", service_name); + xml.node("child", [&] () { + xml.attribute("name", child_name); + }); + }); + }; + + void route_to_parent_service(Genode::Xml_generator &xml, + char const *service_name, + char const *src_label = "", + char const *dst_label = "") + { + xml.node("service", [&] () { + xml.attribute("name", service_name); + if (Genode::strcmp(src_label, "")) { + xml.attribute("label", src_label); + } + xml.node("parent", [&] () { + if (Genode::strcmp(dst_label, "")) { + xml.attribute("label", dst_label); + } + }); + }); + }; + + void route_to_local_service(Genode::Xml_generator &xml, + char const *service_name, + char const *service_label = "") + { + xml.node("service", [&] () { + xml.attribute("name", service_name); + if (Genode::strcmp(service_label, "")) { + xml.attribute("label", service_label); + } + xml.node("local", [&] () { }); + }); + }; + + void service_node(Genode::Xml_generator &xml, + char const *service_name) + { + xml.node("service", [&] () { + xml.attribute("name", service_name); + }); + }; + + void gen_provides_service(Xml_generator &xml, + char const *service_name) + { + xml.node("provides", [&] () { + xml.node("service", [&] () { + xml.attribute("name", service_name); + }); + }); + } + + void gen_parent_routes_for_pd_rom_cpu_log(Xml_generator &xml) + { + route_to_parent_service(xml, "PD"); + route_to_parent_service(xml, "ROM"); + route_to_parent_service(xml, "CPU"); + route_to_parent_service(xml, "LOG"); + } + + void gen_parent_provides_and_report_nodes(Xml_generator &xml) + { + xml.attribute("verbose", "no"); + + xml.node("report", [&] () { + xml.attribute("provided", "yes"); + xml.attribute("child_ram", "yes"); + xml.attribute("child_caps", "yes"); + xml.attribute("delay_ms", 500); + }); + + xml.node("parent-provides", [&] () { + service_node(xml, "ROM"); + service_node(xml, "CPU"); + service_node(xml, "PD"); + service_node(xml, "LOG"); + service_node(xml, "RM"); + service_node(xml, "File_system"); + service_node(xml, "Gui"); + service_node(xml, "Timer"); + service_node(xml, "Report"); + }); + } + + void gen_menu_view_start_node(Xml_generator &xml, + Child_state const &child) + { + child.gen_start_node(xml, [&] () { + + xml.node("config", [&] () { + xml.attribute("xpos", "100"); + xml.attribute("ypos", "50"); + + xml.node("report", [&] () { + xml.attribute("hover", "yes"); }); + + xml.node("libc", [&] () { + xml.attribute("stderr", "/dev/log"); }); + + xml.node("vfs", [&] () { + xml.node("tar", [&] () { + xml.attribute("name", "menu_view_styles.tar"); }); + xml.node("dir", [&] () { + xml.attribute("name", "dev"); + xml.node("log", [&] () { }); + }); + xml.node("dir", [&] () { + xml.attribute("name", "fonts"); + xml.node("fs", [&] () { + xml.attribute("label", "fonts"); + }); + }); + }); + }); + + xml.node("route", [&] () { + route_to_local_service(xml, "ROM", "dialog"); + route_to_local_service(xml, "Report", "hover"); + route_to_local_service(xml, "Gui"); + route_to_parent_service(xml, "File_system", "fonts"); + route_to_parent_service(xml, "Timer"); + gen_parent_routes_for_pd_rom_cpu_log(xml); + }); + }); + } + + void gen_mke2fs_start_node(Xml_generator &xml, + Child_state const &child) + { + child.gen_start_node(xml, [&] () { + + xml.node("config", [&] () { + xml.node("libc", [&] () { + xml.attribute("stdout", "/dev/log"); + xml.attribute("stderr", "/dev/log"); + xml.attribute("stdin", "/dev/null"); + xml.attribute("rtc", "/dev/rtc"); + }); + xml.node("vfs", [&] () { + gen_named_node(xml, "dir", "dev", [&] () { + gen_named_node(xml, "block", "block", [&] () { + xml.attribute("label", "default"); + xml.attribute("block_buffer_count", 128); + }); + gen_named_node(xml, "inline", "rtc", [&] () { + xml.append("2018-01-01 00:01"); + }); + xml.node("null", [&] () {}); + xml.node("log", [&] () {}); + }); + }); + gen_arg(xml, "mkfs.ext2"); + gen_arg(xml, "-F"); + gen_arg(xml, "/dev/block"); + }); + + xml.node("route", [&] () { + route_to_child_service(xml, "vfs_block", "Block"); + route_to_parent_service(xml, "Timer"); + gen_parent_routes_for_pd_rom_cpu_log(xml); + }); + }); + } + + void gen_resize2fs_start_node(Xml_generator &xml, + Child_state const &child) + { + child.gen_start_node(xml, [&] () { + + xml.node("config", [&] () { + xml.node("libc", [&] () { + xml.attribute("stdout", "/dev/log"); + xml.attribute("stderr", "/dev/log"); + xml.attribute("stdin", "/dev/null"); + xml.attribute("rtc", "/dev/rtc"); + }); + xml.node("vfs", [&] () { + gen_named_node(xml, "dir", "dev", [&] () { + gen_named_node(xml, "block", "block", [&] () { + xml.attribute("label", "default"); + xml.attribute("block_buffer_count", 128); + }); + gen_named_node(xml, "inline", "rtc", [&] () { + xml.append("2018-01-01 00:01"); + }); + xml.node("null", [&] () {}); + xml.node("log", [&] () {}); + }); + }); + gen_arg(xml, "resize2fs"); + gen_arg(xml, "-f"); + gen_arg(xml, "-p"); + gen_arg(xml, "/dev/block"); + }); + + xml.node("route", [&] () { + route_to_child_service(xml, "vfs_block", "Block"); + route_to_parent_service(xml, "Timer"); + gen_parent_routes_for_pd_rom_cpu_log(xml); + }); + }); + } + + void gen_cbe_vfs_start_node(Xml_generator &xml, + Child_state const &child) + { + child.gen_start_node(xml, [&] () { + + gen_provides_service(xml, "File_system"); + xml.node("config", [&] () { + + xml.node("vfs", [&] () { + + xml.node("fs", [&] () { + xml.attribute("buffer_size", "1M"); + xml.attribute("label", "cbe_fs"); + }); + xml.node("cbe_crypto_aes_cbc", [&] () { + xml.attribute("name", "crypto"); + }); + xml.node("dir", [&] () { + xml.attribute("name", "trust_anchor"); + + xml.node("fs", [&] () { + xml.attribute("buffer_size", "1M"); + xml.attribute("label", "trust_anchor"); + }); + }); + xml.node("dir", [&] () { + xml.attribute("name", "dev"); + + xml.node("cbe", [&] () { + xml.attribute("name", "cbe"); + xml.attribute("verbose", "no"); + xml.attribute("debug", "no"); + xml.attribute("block", "/cbe.img"); + xml.attribute("crypto", "/crypto"); + xml.attribute("trust_anchor", "/trust_anchor"); + }); + }); + }); + + xml.node("policy", [&] () { + xml.attribute("label", "resizing_fs_tool -> "); + xml.attribute("root", "/dev"); + xml.attribute("writeable", "yes"); + }); + xml.node("policy", [&] () { + xml.attribute("label", "rekeying_fs_tool -> "); + xml.attribute("root", "/dev"); + xml.attribute("writeable", "yes"); + }); + xml.node("policy", [&] () { + xml.attribute("label", "shut_down_fs_tool -> "); + xml.attribute("root", "/dev"); + xml.attribute("writeable", "yes"); + }); + xml.node("policy", [&] () { + xml.attribute("label", "create_snap_fs_tool -> "); + xml.attribute("root", "/dev"); + xml.attribute("writeable", "yes"); + }); + xml.node("policy", [&] () { + xml.attribute("label", "discard_snap_fs_tool -> "); + xml.attribute("root", "/dev"); + xml.attribute("writeable", "yes"); + }); + xml.node("policy", [&] () { + xml.attribute("label", "snapshots_fs_query -> "); + xml.attribute("root", "/dev"); + xml.attribute("writeable", "yes"); + }); + xml.node("policy", [&] () { + xml.attribute("label", "resizing_fs_query -> "); + xml.attribute("root", "/dev"); + xml.attribute("writeable", "yes"); + }); + xml.node("policy", [&] () { + xml.attribute("label", "rekeying_fs_query -> "); + xml.attribute("root", "/dev"); + xml.attribute("writeable", "yes"); + }); + xml.node("policy", [&] () { + xml.attribute("label", "shut_down_fs_query -> "); + xml.attribute("root", "/dev"); + xml.attribute("writeable", "yes"); + }); + xml.node("policy", [&] () { + xml.attribute("label", "vfs_block -> "); + xml.attribute("root", "/dev/cbe/current"); + xml.attribute("writeable", "yes"); + }); + xml.node("policy", [&] () { + xml.attribute("label", "client_fs_fs_query -> "); + xml.attribute("root", "/dev/cbe/current"); + xml.attribute("writeable", "no"); + }); + xml.node("policy", [&] () { + xml.attribute("label", "sync_to_cbe_vfs_init -> "); + xml.attribute("root", "/dev"); + xml.attribute("writeable", "no"); + }); + }); + xml.node("route", [&] () { + route_to_child_service(xml, "cbe_trust_anchor_vfs", "File_system", "trust_anchor"); + route_to_parent_service(xml, "File_system", "cbe_fs"); + gen_parent_routes_for_pd_rom_cpu_log(xml); + }); + }); + } + + void gen_cbe_trust_anchor_vfs_start_node(Xml_generator &xml, + Child_state const &child) + { + child.gen_start_node(xml, [&] () { + + gen_provides_service(xml, "File_system"); + xml.node("config", [&] () { + + xml.node("vfs", [&] () { + + xml.node("dir", [&] () { + xml.attribute("name", "storage_dir"); + + xml.node("fs", [&] () { + xml.attribute("buffer_size", "1M"); + xml.attribute("label", "storage_dir"); + }); + }); + xml.node("dir", [&] () { + xml.attribute("name", "dev"); + + xml.node("cbe_trust_anchor", [&] () { + xml.attribute("name", "cbe_trust_anchor"); + xml.attribute("storage_dir", "/storage_dir"); + }); + + xml.node("jitterentropy", [&] () { + xml.attribute("name", "jitterentropy"); + }); + }); + }); + xml.node("policy", [&] () { + xml.attribute("label", "cbe_init_trust_anchor -> trust_anchor"); + xml.attribute("root", "/dev/cbe_trust_anchor"); + xml.attribute("writeable", "yes"); + }); + xml.node("policy", [&] () { + xml.attribute("label", "cbe_init -> trust_anchor"); + xml.attribute("root", "/dev/cbe_trust_anchor"); + xml.attribute("writeable", "yes"); + }); + xml.node("policy", [&] () { + xml.attribute("label", "cbe_vfs -> trust_anchor"); + xml.attribute("root", "/dev/cbe_trust_anchor"); + xml.attribute("writeable", "yes"); + }); + }); + xml.node("route", [&] () { + route_to_parent_service(xml, "File_system", "storage_dir"); + gen_parent_routes_for_pd_rom_cpu_log(xml); + }); + }); + } + + void gen_rump_vfs_start_node(Xml_generator &xml, + Child_state const &child) + { + child.gen_start_node(xml, [&] () { + + gen_provides_service(xml, "File_system"); + xml.node("config", [&] () { + + xml.node("vfs", [&] () { + xml.node("rump", [&] () { + xml.attribute("fs", "ext2fs"); + xml.attribute("ram", "10M"); + }); + }); + + xml.node("default-policy", [&] () { + xml.attribute("root", "/"); + xml.attribute("writeable", "yes"); + }); + }); + xml.node("route", [&] () { + route_to_child_service(xml, "vfs_block", "Block"); + route_to_parent_service(xml, "Timer"); + route_to_parent_service(xml, "RM"); + gen_parent_routes_for_pd_rom_cpu_log(xml); + }); + }); + } + + void gen_truncate_file_start_node(Xml_generator &xml, + Child_state const &child, + char const *path, + size_t size) + { + child.gen_start_node(xml, [&] () { + + xml.node("config", [&] () { + xml.attribute("size", size); + xml.attribute("path", path); + + xml.node("vfs", [&] () { + xml.node("dir", [&] () { + xml.attribute("name", "cbe"); + + xml.node("fs", [&] () { + xml.attribute("label", "cbe"); + }); + }); + }); + }); + xml.node("route", [&] () { + route_to_parent_service(xml, "File_system"); + gen_parent_routes_for_pd_rom_cpu_log(xml); + }); + }); + } + + void gen_sync_to_cbe_vfs_init_start_node(Xml_generator &xml, + Child_state const &child) + { + child.gen_start_node(xml, [&] () { + + xml.node("config", [&] () { + xml.attribute("ld_verbose", "no"); + + xml.node("libc", [&] () { + xml.attribute("stdin", "/dev/log"); + xml.attribute("stdout", "/dev/log"); + xml.attribute("stderr", "/dev/log"); + }); + xml.node("vfs", [&] () { + xml.node("dir", [&] () { + xml.attribute("name", "dev"); + xml.node("log", [&] () { }); + }); + xml.node("dir", [&] () { + xml.attribute("name", "cbe"); + + xml.node("fs", [&] () { + xml.attribute("writeable", "yes"); + }); + }); + }); + }); + xml.node("route", [&] () { + route_to_child_service(xml, "cbe_vfs", "File_system"); + gen_parent_routes_for_pd_rom_cpu_log(xml); + }); + }); + } + + void gen_cbe_vfs_block_start_node(Xml_generator &xml, + Child_state const &child) + { + child.gen_start_node(xml, [&] () { + + gen_provides_service(xml, "Block"); + xml.node("config", [&] () { + xml.node("vfs", [&] () { + xml.node("fs", [&] () { + xml.attribute("buffer_size", "1M"); + }); + }); + xml.node("policy", [&] () { + xml.attribute("label", "mke2fs -> default"); + xml.attribute("block_size", "512"); + xml.attribute("file", "/data"); + xml.attribute("writeable", "yes"); + }); + xml.node("policy", [&] () { + xml.attribute("label", "resize2fs -> default"); + xml.attribute("block_size", "512"); + xml.attribute("file", "/data"); + xml.attribute("writeable", "yes"); + }); + xml.node("policy", [&] () { + xml.attribute("label", "rump_vfs -> "); + xml.attribute("block_size", "512"); + xml.attribute("file", "/data"); + xml.attribute("writeable", "yes"); + }); + }); + xml.node("route", [&] () { + route_to_child_service(xml, "cbe_vfs", "File_system"); + gen_parent_routes_for_pd_rom_cpu_log(xml); + }); + }); + } + + void gen_image_fs_query_start_node(Xml_generator &xml, + Child_state const &child) + { + child.gen_start_node(xml, [&] () { + + xml.node("config", [&] () { + xml.node("vfs", [&] () { + xml.node("fs", [&] () { + xml.attribute("writeable", "no"); + }); + }); + xml.node("query", [&] () { + xml.attribute("path", "/"); + xml.attribute("content", "no"); + xml.attribute("size", "yes"); + }); + }); + xml.node("route", [&] () { + route_to_local_service(xml, "Report"); + route_to_parent_service(xml, "File_system"); + gen_parent_routes_for_pd_rom_cpu_log(xml); + }); + }); + } + + void gen_client_fs_fs_query_start_node(Xml_generator &xml, + Child_state const &child) + { + child.gen_start_node(xml, [&] () { + + xml.node("config", [&] () { + xml.node("vfs", [&] () { + xml.node("fs", [&] () { + xml.attribute("writeable", "no"); + }); + }); + xml.node("query", [&] () { + xml.attribute("path", "/"); + xml.attribute("content", "no"); + xml.attribute("size", "yes"); + }); + }); + xml.node("route", [&] () { + route_to_local_service(xml, "Report"); + route_to_child_service(xml, "cbe_vfs", "File_system"); + gen_parent_routes_for_pd_rom_cpu_log(xml); + }); + }); + } + + void gen_fs_query_start_node(Xml_generator &xml, + Child_state const &child) + { + child.gen_start_node(xml, [&] () { + + xml.node("config", [&] () { + xml.node("vfs", [&] () { + xml.node("fs", [&] () { + xml.attribute("writeable", "yes"); + }); + }); + xml.node("query", [&] () { + xml.attribute("path", "/file_vault"); + xml.attribute("content", "yes"); + }); + }); + xml.node("route", [&] () { + route_to_local_service(xml, "Report"); + route_to_parent_service(xml, "File_system"); + gen_parent_routes_for_pd_rom_cpu_log(xml); + }); + }); + } + + void gen_cbe_init_trust_anchor_start_node(Xml_generator &xml, + Child_state const &child, + Input_passphrase const &passphrase) + { + child.gen_start_node(xml, [&] () { + + xml.node("config", [&] () { + + xml.attribute("passphrase", passphrase.plaintext().string()); + xml.attribute("trust_anchor_dir", "/trust_anchor"); + xml.node("vfs", [&] () { + xml.node("dir", [&] () { + xml.attribute("name", "trust_anchor"); + xml.node("fs", [&] () { + xml.attribute("label", "trust_anchor"); + }); + }); + }); + }); + xml.node("route", [&] () { + route_to_child_service(xml, "cbe_trust_anchor_vfs", "File_system", "trust_anchor"); + gen_parent_routes_for_pd_rom_cpu_log(xml); + }); + }); + } + + void gen_cbe_image_vfs_block_start_node(Xml_generator &xml, + Child_state const &child) + { + child.gen_start_node(xml, [&] () { + + gen_provides_service(xml, "Block"); + xml.node("config", [&] () { + xml.node("vfs", [&] () { + xml.node("fs", [&] () { + xml.attribute("buffer_size", "1M"); + }); + }); + xml.node("policy", [&] () { + xml.attribute("label", "cbe_init -> "); + xml.attribute("block_size", "512"); + xml.attribute("file", "/cbe.img"); + xml.attribute("writeable", "yes"); + }); + }); + xml.node("route", [&] () { + route_to_parent_service(xml, "File_system"); + gen_parent_routes_for_pd_rom_cpu_log(xml); + }); + }); + } + + void gen_cbe_init_start_node(Xml_generator &xml, + Child_state const &child, + Tree_geometry const &vbd_geom, + Tree_geometry const &ft_geom) + { + child.gen_start_node(xml, [&] () { + + xml.node("config", [&] () { + xml.attribute("trust_anchor_dir", "/trust_anchor"); + + xml.node("vfs", [&] () { + xml.node("dir", [&] () { + xml.attribute("name", "trust_anchor"); + xml.node("fs", [&] () { + xml.attribute("label", "trust_anchor"); + }); + }); + }); + xml.node("key", [&] () { + xml.attribute("id", "12"); + }); + xml.node("virtual-block-device", [&] () { + xml.attribute("nr_of_levels", vbd_geom.nr_of_levels()); + xml.attribute("nr_of_children", vbd_geom.nr_of_children()); + xml.attribute("nr_of_leafs", vbd_geom.nr_of_leaves()); + }); + xml.node("free-tree", [&] () { + xml.attribute("nr_of_levels", ft_geom.nr_of_levels()); + xml.attribute("nr_of_children", ft_geom.nr_of_children()); + xml.attribute("nr_of_leafs", ft_geom.nr_of_leaves()); + }); + }); + xml.node("route", [&] () { + route_to_child_service(xml, "cbe_trust_anchor_vfs", "File_system", "trust_anchor"); + route_to_child_service(xml, "vfs_block", "Block"); + gen_parent_routes_for_pd_rom_cpu_log(xml); + }); + }); + } + + void gen_policy_for_child_service(Xml_generator &xml, + char const *service_name, + Child_state const &child) + { + xml.node("service", [&] () { + xml.attribute("name", service_name); + xml.node("default-policy", [&] () { + xml.node("child", [&] () { + xml.attribute("name", child.start_name()); + }); + }); + }); + } + + void gen_snapshots_fs_query_start_node(Xml_generator &xml, + Child_state const &child) + { + child.gen_start_node(xml, [&] () { + + xml.node("config", [&] () { + xml.node("vfs", [&] () { + xml.node("fs", [&] () { + xml.attribute("writeable", "yes"); + }); + }); + xml.node("query", [&] () { + xml.attribute("path", "/cbe/snapshots"); + xml.attribute("content", "yes"); + }); + }); + xml.node("route", [&] () { + route_to_local_service(xml, "Report"); + route_to_child_service(xml, "cbe_vfs", "File_system"); + gen_parent_routes_for_pd_rom_cpu_log(xml); + }); + }); + } + + void gen_resizing_fs_tool_start_node(Xml_generator &xml, + Child_state const &child, + char const *tree, + unsigned long nr_of_blocks) + { + child.gen_start_node(xml, [&] () { + + xml.node("config", [&] () { + xml.attribute("exit", "yes"); + xml.attribute("verbose", "no"); + + xml.node("vfs", [&] () { + xml.node("dir", [&] () { + xml.attribute("name", "cbe"); + + xml.node("fs", [&] () { + xml.attribute("writeable", "yes"); + }); + }); + }); + xml.node("new-file", [&] () { + xml.attribute("path", "/cbe/cbe/control/extend"); + xml.append_content("tree=", tree, ",blocks=", nr_of_blocks); + }); + }); + xml.node("route", [&] () { + + route_to_child_service(xml, "cbe_vfs", "File_system"); + gen_parent_routes_for_pd_rom_cpu_log(xml); + }); + }); + } + + void gen_resizing_fs_query_start_node(Xml_generator &xml, + Child_state const &child) + { + child.gen_start_node(xml, [&] () { + + xml.node("config", [&] () { + xml.node("vfs", [&] () { + xml.node("fs", [&] () { + xml.attribute("writeable", "yes"); + }); + }); + xml.node("query", [&] () { + xml.attribute("path", "/cbe/control"); + xml.attribute("content", "yes"); + }); + }); + xml.node("route", [&] () { + route_to_local_service(xml, "Report"); + route_to_child_service(xml, "cbe_vfs", "File_system"); + gen_parent_routes_for_pd_rom_cpu_log(xml); + }); + }); + } + + void gen_shut_down_fs_tool_start_node(Xml_generator &xml, + Child_state const &child) + { + child.gen_start_node(xml, [&] () { + + xml.node("config", [&] () { + xml.attribute("exit", "yes"); + xml.attribute("verbose", "no"); + + xml.node("vfs", [&] () { + xml.node("dir", [&] () { + xml.attribute("name", "cbe"); + + xml.node("fs", [&] () { + xml.attribute("writeable", "yes"); + }); + }); + }); + xml.node("new-file", [&] () { + xml.attribute("path", "/cbe/cbe/control/deinitialize"); + xml.append_content("true"); + }); + }); + xml.node("route", [&] () { + + route_to_child_service(xml, "cbe_vfs", "File_system"); + gen_parent_routes_for_pd_rom_cpu_log(xml); + }); + }); + } + + void gen_rekeying_fs_tool_start_node(Xml_generator &xml, + Child_state const &child) + { + child.gen_start_node(xml, [&] () { + + xml.node("config", [&] () { + xml.attribute("exit", "yes"); + xml.attribute("verbose", "no"); + + xml.node("vfs", [&] () { + xml.node("dir", [&] () { + xml.attribute("name", "cbe"); + + xml.node("fs", [&] () { + xml.attribute("writeable", "yes"); + }); + }); + }); + xml.node("new-file", [&] () { + xml.attribute("path", "/cbe/cbe/control/rekey"); + xml.append_content("true"); + }); + }); + xml.node("route", [&] () { + + route_to_child_service(xml, "cbe_vfs", "File_system"); + gen_parent_routes_for_pd_rom_cpu_log(xml); + }); + }); + } + + void gen_shut_down_fs_query_start_node(Xml_generator &xml, + Child_state const &child) + { + child.gen_start_node(xml, [&] () { + + xml.node("config", [&] () { + xml.node("vfs", [&] () { + xml.node("fs", [&] () { + xml.attribute("writeable", "yes"); + }); + }); + xml.node("query", [&] () { + xml.attribute("path", "/cbe/control"); + xml.attribute("content", "yes"); + }); + }); + xml.node("route", [&] () { + route_to_local_service(xml, "Report"); + route_to_child_service(xml, "cbe_vfs", "File_system"); + gen_parent_routes_for_pd_rom_cpu_log(xml); + }); + }); + } + + void gen_rekeying_fs_query_start_node(Xml_generator &xml, + Child_state const &child) + { + child.gen_start_node(xml, [&] () { + + xml.node("config", [&] () { + xml.node("vfs", [&] () { + xml.node("fs", [&] () { + xml.attribute("writeable", "yes"); + }); + }); + xml.node("query", [&] () { + xml.attribute("path", "/cbe/control"); + xml.attribute("content", "yes"); + }); + }); + xml.node("route", [&] () { + route_to_local_service(xml, "Report"); + route_to_child_service(xml, "cbe_vfs", "File_system"); + gen_parent_routes_for_pd_rom_cpu_log(xml); + }); + }); + } + + void gen_create_snap_fs_tool_start_node(Xml_generator &xml, + Child_state const &child) + { + child.gen_start_node(xml, [&] () { + + xml.node("config", [&] () { + xml.attribute("exit", "yes"); + xml.attribute("verbose", "no"); + + xml.node("vfs", [&] () { + xml.node("dir", [&] () { + xml.attribute("name", "cbe"); + + xml.node("fs", [&] () { + xml.attribute("writeable", "yes"); + }); + }); + }); + xml.node("new-file", [&] () { + xml.attribute("path", "/cbe/cbe/control/create_snapshot"); + xml.append_content("true"); + }); + }); + xml.node("route", [&] () { + + route_to_child_service(xml, "cbe_vfs", "File_system"); + gen_parent_routes_for_pd_rom_cpu_log(xml); + }); + }); + } + + void gen_discard_snap_fs_tool_start_node(Xml_generator &xml, + Child_state const &child, + Generation generation) + { + child.gen_start_node(xml, [&] () { + + xml.node("config", [&] () { + xml.attribute("exit", "yes"); + xml.attribute("verbose", "no"); + + xml.node("vfs", [&] () { + xml.node("dir", [&] () { + xml.attribute("name", "cbe"); + + xml.node("fs", [&] () { + xml.attribute("writeable", "yes"); + }); + }); + }); + xml.node("new-file", [&] () { + xml.attribute("path", "/cbe/cbe/control/discard_snapshot"); + xml.append_content(Generation_string(generation)); + }); + }); + xml.node("route", [&] () { + + route_to_child_service(xml, "cbe_vfs", "File_system"); + gen_parent_routes_for_pd_rom_cpu_log(xml); + }); + }); + } +} + + +#endif /* SANDBOX_H_ */ diff --git a/repos/gems/src/app/file_vault/snapshot.h b/repos/gems/src/app/file_vault/snapshot.h new file mode 100644 index 0000000000..84f5a3a5c0 --- /dev/null +++ b/repos/gems/src/app/file_vault/snapshot.h @@ -0,0 +1,45 @@ +/* + * \brief Pointer of const object safe against null dereferencing + * \author Martin Stein + * \date 2021-04-02 + */ + +/* + * Copyright (C) 2021 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#ifndef _SNAPSHOT_H_ +#define _SNAPSHOT_H_ + +namespace File_vault { + + class Snapshot; +} + +class File_vault::Snapshot +{ + private: + + Generation const _generation; + + public: + + Snapshot(Generation const &generation) + : + _generation { generation } + { } + + virtual ~Snapshot() { } + + + /*************** + ** Accessors ** + ***************/ + + Generation const &generation() const { return _generation; } +}; + +#endif /* _SNAPSHOT_H_ */ diff --git a/repos/gems/src/app/file_vault/sync_to_cbe_vfs_init/main.cc b/repos/gems/src/app/file_vault/sync_to_cbe_vfs_init/main.cc new file mode 100644 index 0000000000..087b0291f3 --- /dev/null +++ b/repos/gems/src/app/file_vault/sync_to_cbe_vfs_init/main.cc @@ -0,0 +1,36 @@ +/* + * \brief Helps synchronizing the CBE manager to the CBE-driver initialization + * \author Martin Stein + * \date 2021-03-19 + */ + +/* + * Copyright (C) 2021 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +/* libC includes */ +extern "C" { +#include +#include +#include +#include +} + +int main(int, char **) +{ + char const *file_path { "/cbe/cbe/current/data" }; + int const file_descriptor = open(file_path, O_RDONLY); + if (file_descriptor < 0) { + printf("Error: failed to open file %s\n", file_path); + exit(-1); + } + int const result { fsync(file_descriptor) }; + if (result != 0) { + printf("Error: fsync on file %s failed\n", file_path); + exit(-1); + } + exit(0); +} diff --git a/repos/gems/src/app/file_vault/sync_to_cbe_vfs_init/target.mk b/repos/gems/src/app/file_vault/sync_to_cbe_vfs_init/target.mk new file mode 100644 index 0000000000..e8d84b44b4 --- /dev/null +++ b/repos/gems/src/app/file_vault/sync_to_cbe_vfs_init/target.mk @@ -0,0 +1,3 @@ +TARGET = file_vault-sync_to_cbe_vfs_init +LIBS = posix +SRC_CC = main.cc diff --git a/repos/gems/src/app/file_vault/target.mk b/repos/gems/src/app/file_vault/target.mk new file mode 100644 index 0000000000..26b0a3db23 --- /dev/null +++ b/repos/gems/src/app/file_vault/target.mk @@ -0,0 +1,6 @@ +TARGET := file_vault +SRC_CC += main.cc menu_view_dialog.cc capacity.cc +INC_DIR += $(PRG_DIR) +LIBS += base sandbox vfs + +CC_OPT += -Os diff --git a/repos/gems/src/app/file_vault/truncate_file/main.cc b/repos/gems/src/app/file_vault/truncate_file/main.cc new file mode 100644 index 0000000000..6c929446dd --- /dev/null +++ b/repos/gems/src/app/file_vault/truncate_file/main.cc @@ -0,0 +1,85 @@ +/* + * \brief Helps synchronizing the CBE manager to the CBE-driver initialization + * \author Martin Stein + * \date 2021-03-19 + */ + +/* + * Copyright (C) 2021 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +/* Genode includes */ +#include +#include +#include +#include + +namespace Truncate_file { + + class Main; +} + +using namespace Truncate_file; +using namespace Genode; + + +class Truncate_file::Main +{ + private: + + Env &_env; + Heap _heap { _env.ram(), _env.rm() }; + Attached_rom_dataspace _config { _env, "config" }; + Root_directory _vfs { _env, _heap, _config.xml().sub_node("vfs") }; + Vfs::File_system &_fs { _vfs.root_dir() }; + Directory::Path const _path { _config.xml().attribute_value("path", Directory::Path { }) }; + Number_of_bytes const _size { _config.xml().attribute_value("size", Number_of_bytes { }) }; + + public: + + Main(Env &env); +}; + + +/************************* + ** Truncate_file::Main ** + *************************/ + +Main::Main(Env &env) +: + _env { env } +{ + unsigned mode = Vfs::Directory_service::OPEN_MODE_WRONLY; + + Vfs::Directory_service::Stat stat { }; + if (_fs.stat(_path.string(), stat) != Vfs::Directory_service::STAT_OK) { + mode |= Vfs::Directory_service::OPEN_MODE_CREATE; + } + + Vfs::Vfs_handle *handle_ptr = nullptr; + Vfs::Directory_service::Open_result const res = + _fs.open(_path.string(), mode, &handle_ptr, _heap); + + if (res != Vfs::Directory_service::OPEN_OK || (handle_ptr == nullptr)) { + + error("failed to create file '", _path, "'"); + class Create_failed { }; + throw Create_failed { }; + } + handle_ptr->fs().ftruncate(handle_ptr, _size); + handle_ptr->ds().close(handle_ptr); + _env.parent().exit(0); +} + + +/*********************** + ** Genode::Component ** + ***********************/ + +void Component::construct(Genode::Env &env) +{ + static Truncate_file::Main main { env }; +} diff --git a/repos/gems/src/app/file_vault/truncate_file/target.mk b/repos/gems/src/app/file_vault/truncate_file/target.mk new file mode 100644 index 0000000000..cbf1a24ec6 --- /dev/null +++ b/repos/gems/src/app/file_vault/truncate_file/target.mk @@ -0,0 +1,4 @@ +TARGET := file_vault-truncate_file +SRC_CC += main.cc +INC_DIR += $(PRG_DIR)/.. +LIBS += base vfs diff --git a/repos/gems/src/app/file_vault/types.h b/repos/gems/src/app/file_vault/types.h new file mode 100644 index 0000000000..2586a050ed --- /dev/null +++ b/repos/gems/src/app/file_vault/types.h @@ -0,0 +1,55 @@ +/* + * \brief Common types + * \author Martin Stein + * \date 2021-02-25 + */ + +/* + * Copyright (C) 2021 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#ifndef _TYPES_H_ +#define _TYPES_H_ + +/* Genode includes */ +#include + +namespace Genode { } + +namespace File_vault { + + using namespace Cbe; + using namespace Genode; + + using Node_name = String<32>; + + class Tree_geometry + { + private: + + uint64_t const _nr_of_levels; + uint64_t const _nr_of_children; + uint64_t const _nr_of_leaves; + + public: + + Tree_geometry( + uint64_t nr_of_levels, + uint64_t nr_of_children, + uint64_t nr_of_leaves) + : + _nr_of_levels { nr_of_levels }, + _nr_of_children { nr_of_children }, + _nr_of_leaves { nr_of_leaves } + { } + + uint64_t nr_of_levels() const { return _nr_of_levels ; } + uint64_t nr_of_children() const { return _nr_of_children; } + uint64_t nr_of_leaves() const { return _nr_of_leaves ; } + }; +} + +#endif /* _TYPES_H_ */ diff --git a/repos/gems/src/app/file_vault/utf8.h b/repos/gems/src/app/file_vault/utf8.h new file mode 100644 index 0000000000..2ab606b322 --- /dev/null +++ b/repos/gems/src/app/file_vault/utf8.h @@ -0,0 +1,32 @@ +/* + * \brief Local extension of Genodes UTF8 utilities + * \author Norman Feske + * \author Martin Stein + * \date 2021-03-04 + */ + +/* + * Copyright (C) 2021 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#ifndef _UTF8_H_ +#define _UTF8_H_ + +/* Genode includes */ +#include + +/* local includes */ +#include + +namespace File_vault { + + enum { + CODEPOINT_BACKSPACE = 8, + CODEPOINT_TAB = 9, + }; +} + +#endif /* _UTF8_H_ */