diff options
author | Samuel Bowman <sam@sambowman.tech> | 2022-06-27 22:48:30 -0400 |
---|---|---|
committer | Linus Groh <mail@linusgroh.de> | 2022-07-21 20:13:44 +0100 |
commit | 7a8953a833e5243df4809ae8b9bffc3a1bab10e1 (patch) | |
tree | dcb516fe7fb75f437061ba54716fab31dd401558 /Userland/Applications | |
parent | 7b8088c78d66f4d4a551c626971276d148907820 (diff) | |
download | serenity-7a8953a833e5243df4809ae8b9bffc3a1bab10e1.zip |
PartitionEditor: Add the beginnings of a partition editor :^)
This adds a new application PartitionEditor which will eventually be
used to create and edit partition tables. Since LibPartition does not
know how to write partition tables yet, it is currently read-only.
Devices are discovered by scanning /dev for block device files.
Since block devices are chmod 600, PartitionEditor be must run as root.
By default Serenity uses the entire disk for the ext2 filesystem
without a partition table. This isn't useful for testing as the
partition list for the default disk will be empty. To test properly,
I created a few disk images using various partitioning schemes
(MBR, EBR, and GPT) and attached them using the following command:
export SERENITY_EXTRA_QEMU_ARGS="
-drive file=/path/to/mbr.img,format=raw,index=1,media=disk
-drive file=/path/to/ebr.img,format=raw,index=2,media=disk
-drive file=/path/to/gpt.img,format=raw,index=3,media=disk"
Diffstat (limited to 'Userland/Applications')
6 files changed, 252 insertions, 0 deletions
diff --git a/Userland/Applications/CMakeLists.txt b/Userland/Applications/CMakeLists.txt index 58a21bd8d9..04c4046326 100644 --- a/Userland/Applications/CMakeLists.txt +++ b/Userland/Applications/CMakeLists.txt @@ -23,6 +23,7 @@ add_subdirectory(Mail) add_subdirectory(MailSettings) add_subdirectory(MouseSettings) add_subdirectory(NetworkSettings) +add_subdirectory(PartitionEditor) add_subdirectory(PDFViewer) add_subdirectory(Piano) add_subdirectory(PixelPaint) diff --git a/Userland/Applications/PartitionEditor/CMakeLists.txt b/Userland/Applications/PartitionEditor/CMakeLists.txt new file mode 100644 index 0000000000..67b9d19543 --- /dev/null +++ b/Userland/Applications/PartitionEditor/CMakeLists.txt @@ -0,0 +1,15 @@ +serenity_component( + PartitionEditor + TARGETS PartitionEditor +) + +compile_gml(PartitionEditorWindow.gml PartitionEditorWindowGML.h partition_editor_window_gml) + +set(SOURCES + main.cpp + PartitionEditorWindowGML.h + PartitionModel.cpp +) + +serenity_app(PartitionEditor ICON app-space-analyzer) +target_link_libraries(PartitionEditor LibMain LibGUI LibPartition) diff --git a/Userland/Applications/PartitionEditor/PartitionEditorWindow.gml b/Userland/Applications/PartitionEditor/PartitionEditorWindow.gml new file mode 100644 index 0000000000..fb1341be0e --- /dev/null +++ b/Userland/Applications/PartitionEditor/PartitionEditorWindow.gml @@ -0,0 +1,26 @@ +@GUI::Widget { + fill_with_background_color: true + layout: @GUI::VerticalBoxLayout {} + + @GUI::ToolbarContainer { + @GUI::Toolbar { + layout: @GUI::HorizontalBoxLayout { + margins: [0, 4] + } + + @GUI::Label { + text: "Device: " + autosize: true + } + + @GUI::ComboBox { + name: "device_combobox" + fixed_width: 100 + } + } + } + + @GUI::TableView { + name: "partition_table_view" + } +} diff --git a/Userland/Applications/PartitionEditor/PartitionModel.cpp b/Userland/Applications/PartitionEditor/PartitionModel.cpp new file mode 100644 index 0000000000..d0dae293a8 --- /dev/null +++ b/Userland/Applications/PartitionEditor/PartitionModel.cpp @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2022, Samuel Bowman <sam@sambowman.tech> + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include <Applications/PartitionEditor/PartitionModel.h> +#include <LibPartition/EBRPartitionTable.h> +#include <LibPartition/GUIDPartitionTable.h> +#include <LibPartition/MBRPartitionTable.h> + +namespace PartitionEditor { + +String PartitionModel::column_name(int column) const +{ + switch (column) { + case Column::Partition: + return "Partition"; + case Column::StartBlock: + return "Start Block"; + case Column::EndBlock: + return "End Block"; + default: + VERIFY_NOT_REACHED(); + } +} + +GUI::Variant PartitionModel::data(GUI::ModelIndex const& index, GUI::ModelRole role) const +{ + if (role != GUI::ModelRole::Display) + return {}; + if (!m_partition_table) + return {}; + + auto optional_partition = m_partition_table->partition(index.row()); + if (optional_partition.has_value()) { + auto partition = optional_partition.release_value(); + + switch (index.column()) { + case Column::Partition: + return index.row() + 1; + case Column::StartBlock: + return partition.start_block(); + case Column::EndBlock: + // FIXME: Either MBR end block is off by one (if supposed to be exclusive bound) + // or GPT end block is off by one (if supposed to be inclusive bound). + // This is an issue in LibPartition. + return partition.end_block(); + default: + VERIFY_NOT_REACHED(); + } + } + + return {}; +} + +ErrorOr<void> PartitionModel::set_device_path(String const& path) +{ + auto file = TRY(Core::File::open(path, Core::OpenMode::ReadOnly)); + + auto mbr_table_or_error = Partition::MBRPartitionTable::try_to_initialize(file); + if (!mbr_table_or_error.is_error()) { + dbgln("Found MBR partition table on {}", path); + m_partition_table = move(mbr_table_or_error.value()); + invalidate(); + return {}; + } + + auto ebr_table_or_error = Partition::EBRPartitionTable::try_to_initialize(file); + if (!ebr_table_or_error.is_error()) { + dbgln("Found EBR partition table on {}", path); + m_partition_table = move(ebr_table_or_error.value()); + invalidate(); + return {}; + } + + auto guid_table_or_error = Partition::GUIDPartitionTable::try_to_initialize(file); + if (!guid_table_or_error.is_error()) { + dbgln("Found GUID partition table on {}", path); + m_partition_table = move(guid_table_or_error.value()); + invalidate(); + return {}; + } + + return Error::from_errno(ENOTSUP); +} + +} diff --git a/Userland/Applications/PartitionEditor/PartitionModel.h b/Userland/Applications/PartitionEditor/PartitionModel.h new file mode 100644 index 0000000000..65be6dac7f --- /dev/null +++ b/Userland/Applications/PartitionEditor/PartitionModel.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2022, Samuel Bowman <sam@sambowman.tech> + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include <LibGUI/Model.h> +#include <LibPartition/PartitionTable.h> + +namespace PartitionEditor { + +class PartitionModel final : public GUI::Model { +public: + enum Column { + Partition, + StartBlock, + EndBlock, + __Count, + }; + + static NonnullRefPtr<PartitionModel> create() { return adopt_ref(*new PartitionModel()); } + virtual ~PartitionModel() override = default; + + virtual int row_count(GUI::ModelIndex const& = GUI::ModelIndex()) const override { return m_partition_table->partitions_count(); } + virtual int column_count(GUI::ModelIndex const& = GUI::ModelIndex()) const override { return Column::__Count; } + virtual String column_name(int) const override; + virtual GUI::Variant data(GUI::ModelIndex const&, GUI::ModelRole) const override; + + ErrorOr<void> set_device_path(String const&); + +private: + PartitionModel() = default; + + OwnPtr<Partition::PartitionTable> m_partition_table; +}; + +} diff --git a/Userland/Applications/PartitionEditor/main.cpp b/Userland/Applications/PartitionEditor/main.cpp new file mode 100644 index 0000000000..c8e53f4a27 --- /dev/null +++ b/Userland/Applications/PartitionEditor/main.cpp @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2022, Samuel Bowman <sam@sambowman.tech> + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include <Applications/PartitionEditor/PartitionEditorWindowGML.h> +#include <Applications/PartitionEditor/PartitionModel.h> +#include <LibCore/DirIterator.h> +#include <LibCore/System.h> +#include <LibGUI/Application.h> +#include <LibGUI/ComboBox.h> +#include <LibGUI/ItemListModel.h> +#include <LibGUI/Menu.h> +#include <LibGUI/MessageBox.h> +#include <LibGUI/TableView.h> + +static Vector<String> get_device_paths() +{ + auto device_paths = Vector<String>(); + Core::DirIterator iterator("/dev", Core::DirIterator::SkipParentAndBaseDir); + while (iterator.has_next()) { + auto path = iterator.next_full_path(); + if (Core::File::is_block_device(path)) + device_paths.append(path); + } + return device_paths; +} + +ErrorOr<int> serenity_main(Main::Arguments arguments) +{ + TRY(Core::System::pledge("stdio recvfd sendfd rpath unix")); + + auto app = TRY(GUI::Application::try_create(arguments)); + + TRY(Core::System::pledge("stdio recvfd sendfd rpath")); + TRY(Core::System::unveil("/dev", "r")); + TRY(Core::System::unveil("/res", "r")); + TRY(Core::System::unveil(nullptr, nullptr)); + + // FIXME: PartitionEditor needs its own icon. + auto app_icon = TRY(GUI::Icon::try_create_default_icon("app-space-analyzer"sv)); + + auto window = TRY(GUI::Window::try_create()); + window->set_title("Partition Editor"); + window->resize(640, 400); + window->set_icon(app_icon.bitmap_for_size(16)); + + // FIXME: Abort and show a dialog if not running as root. + + auto widget = TRY(window->try_set_main_widget<GUI::Widget>()); + widget->load_from_gml(partition_editor_window_gml); + + auto device_paths = get_device_paths(); + + auto partition_model = PartitionEditor::PartitionModel::create(); + TRY(partition_model->set_device_path(device_paths.first())); + + auto& device_combobox = *widget->find_descendant_of_type_named<GUI::ComboBox>("device_combobox"); + device_combobox.set_model(GUI::ItemListModel<String>::create(device_paths)); + device_combobox.set_only_allow_values_from_model(true); + device_combobox.set_selected_index(0); + device_combobox.on_change = [&](auto const& path, auto const&) { + auto result = partition_model->set_device_path(path); + if (result.is_error()) + GUI::MessageBox::show_error(window, String::formatted("No partition table found for device {}", path)); + }; + + auto& partition_table_view = *widget->find_descendant_of_type_named<GUI::TableView>("partition_table_view"); + partition_table_view.set_model(partition_model); + partition_table_view.set_focus(true); + + auto& file_menu = window->add_menu("&File"); + file_menu.add_action(GUI::CommonActions::make_quit_action([&](auto&) { + app->quit(); + })); + + auto help_menu = TRY(window->try_add_menu("&Help")); + TRY(help_menu->try_add_action(GUI::CommonActions::make_about_action("Partition Editor", app_icon, window))); + + window->show(); + return app->exec(); +} |