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_ */