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