1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-14 06:14:58 +00:00

LibPartition: Migrate from DeprecatedFile to File

The implemented cloning mechanism should be sound:
- If a PartitionTable is passed a File with
  ShouldCloseFileDescriptor::Yes, then it will keep it alive until the
  PartitionTable is destroyed.
- If a PartitionTable is passed a File with
  ShouldCloseFileDescriptor::No, then the caller has to ensure that the
  file descriptor remains alive.
If the caller is EBRPartitionTable, the same consideration holds.
If the caller is PartitionEditor::PartitionModel, this is satisfied by
keeping an OwnPtr<Core::File> around which is the originally opened
file.

Therefore, we never leak any fds, and never access a Core::File or fd
after destroying it.
This commit is contained in:
Ben Wiederhake 2023-05-21 20:33:09 +02:00 committed by Jelle Raaijmakers
parent c197fb4037
commit 3d6b838df3
14 changed files with 221 additions and 177 deletions

View file

@ -545,6 +545,7 @@ set(PARTITION_SOURCES
../Userland/Libraries/LibPartition/EBRPartitionTable.cpp
../Userland/Libraries/LibPartition/GUIDPartitionTable.cpp
../Userland/Libraries/LibPartition/MBRPartitionTable.cpp
../Userland/Libraries/LibPartition/PartitionableDevice.cpp
../Userland/Libraries/LibPartition/PartitionTable.cpp
)

View file

@ -6,7 +6,6 @@
#include <AK/NumberFormat.h>
#include <Applications/PartitionEditor/PartitionModel.h>
#include <LibCore/DeprecatedFile.h>
#include <LibPartition/EBRPartitionTable.h>
#include <LibPartition/GUIDPartitionTable.h>
#include <LibPartition/MBRPartitionTable.h>
@ -68,28 +67,33 @@ GUI::Variant PartitionModel::data(GUI::ModelIndex const& index, GUI::ModelRole r
ErrorOr<void> PartitionModel::set_device_path(DeprecatedString const& path)
{
auto file = TRY(Core::DeprecatedFile::open(path, Core::OpenMode::ReadOnly));
auto strong_file = TRY(Core::File::open(path, Core::File::OpenMode::Read));
auto weak_file = TRY(Core::File::adopt_fd(strong_file->fd(), Core::File::OpenMode::Read, Core::File::ShouldCloseFileDescriptor::No));
auto device = TRY(Partition::PartitionableDevice::create(move(weak_file)));
auto mbr_table_or_error = Partition::MBRPartitionTable::try_to_initialize(file);
auto mbr_table_or_error = Partition::MBRPartitionTable::try_to_initialize(TRY(device.clone_owned()));
if (!mbr_table_or_error.is_error()) {
dbgln("Found MBR partition table on {}", path);
m_partition_table = move(mbr_table_or_error.value());
m_backing_file = move(strong_file);
invalidate();
return {};
}
auto ebr_table_or_error = Partition::EBRPartitionTable::try_to_initialize(file);
auto ebr_table_or_error = Partition::EBRPartitionTable::try_to_initialize(TRY(device.clone_owned()));
if (!ebr_table_or_error.is_error()) {
dbgln("Found EBR partition table on {}", path);
m_partition_table = move(ebr_table_or_error.value());
m_backing_file = move(strong_file);
invalidate();
return {};
}
auto guid_table_or_error = Partition::GUIDPartitionTable::try_to_initialize(file);
auto guid_table_or_error = Partition::GUIDPartitionTable::try_to_initialize(TRY(device.clone_owned()));
if (!guid_table_or_error.is_error()) {
dbgln("Found GUID partition table on {}", path);
m_partition_table = move(guid_table_or_error.value());
m_backing_file = move(strong_file);
invalidate();
return {};
}

View file

@ -6,6 +6,7 @@
#pragma once
#include <LibCore/File.h>
#include <LibGUI/Model.h>
#include <LibPartition/PartitionTable.h>
@ -36,6 +37,7 @@ private:
PartitionModel() = default;
OwnPtr<Partition::PartitionTable> m_partition_table;
OwnPtr<Core::File> m_backing_file;
};
}

View file

@ -3,6 +3,7 @@ set(SOURCES
EBRPartitionTable.cpp
GUIDPartitionTable.cpp
MBRPartitionTable.cpp
PartitionableDevice.cpp
PartitionTable.cpp
)

View file

@ -6,21 +6,11 @@
#include <LibPartition/EBRPartitionTable.h>
#ifndef KERNEL
# include <LibCore/DeprecatedFile.h>
#endif
namespace Partition {
#ifdef KERNEL
ErrorOr<NonnullOwnPtr<EBRPartitionTable>> EBRPartitionTable::try_to_initialize(Kernel::StorageDevice& device)
ErrorOr<NonnullOwnPtr<EBRPartitionTable>> EBRPartitionTable::try_to_initialize(PartitionableDevice device)
{
auto table = TRY(adopt_nonnull_own_or_enomem(new (nothrow) EBRPartitionTable(device)));
#else
ErrorOr<NonnullOwnPtr<EBRPartitionTable>> EBRPartitionTable::try_to_initialize(NonnullRefPtr<Core::DeprecatedFile> device_file)
{
auto table = TRY(adopt_nonnull_own_or_enomem(new (nothrow) EBRPartitionTable(move(device_file))));
#endif
auto table = TRY(adopt_nonnull_own_or_enomem(new (nothrow) EBRPartitionTable(move(device))));
if (table->is_protective_mbr())
return Error::from_errno(ENOTSUP);
if (!table->is_valid())
@ -28,16 +18,13 @@ ErrorOr<NonnullOwnPtr<EBRPartitionTable>> EBRPartitionTable::try_to_initialize(N
return table;
}
#ifdef KERNEL
void EBRPartitionTable::search_extended_partition(Kernel::StorageDevice& device, MBRPartitionTable& checked_ebr, u64 current_block_offset, size_t limit)
#else
void EBRPartitionTable::search_extended_partition(NonnullRefPtr<Core::DeprecatedFile> device, MBRPartitionTable& checked_ebr, u64 current_block_offset, size_t limit)
#endif
void EBRPartitionTable::search_extended_partition(MBRPartitionTable& checked_ebr, u64 current_block_offset, size_t limit)
{
if (limit == 0)
return;
// EBRs should not carry more than 2 partitions (because they need to form a linked list)
VERIFY(checked_ebr.partitions_count() <= 2);
// FIXME: We should not crash the Kernel or any apps when the EBR is malformed.
auto checked_logical_partition = checked_ebr.partition(0);
// If we are pointed to an invalid logical partition, something is seriously wrong.
@ -46,18 +33,15 @@ void EBRPartitionTable::search_extended_partition(NonnullRefPtr<Core::Deprecated
if (!checked_ebr.contains_ebr())
return;
current_block_offset += checked_ebr.partition(1).value().start_block();
auto next_ebr = MBRPartitionTable::try_to_initialize(device, current_block_offset);
auto next_ebr = MBRPartitionTable::try_to_initialize(m_device.clone_unowned(), current_block_offset);
if (!next_ebr)
return;
search_extended_partition(device, *next_ebr, current_block_offset, (limit - 1));
// FIXME: Should not rely on TCO here, since this might be called from inside the Kernel, where stack space isn't exactly free.
search_extended_partition(*next_ebr, current_block_offset, (limit - 1));
}
#ifdef KERNEL
EBRPartitionTable::EBRPartitionTable(Kernel::StorageDevice& device)
#else
EBRPartitionTable::EBRPartitionTable(NonnullRefPtr<Core::DeprecatedFile> device)
#endif
: MBRPartitionTable(device)
EBRPartitionTable::EBRPartitionTable(PartitionableDevice device)
: MBRPartitionTable(move(device))
{
if (!is_header_valid())
return;
@ -70,11 +54,11 @@ EBRPartitionTable::EBRPartitionTable(NonnullRefPtr<Core::DeprecatedFile> device)
auto& entry = header.entry[index];
// Start enumerating all logical partitions
if (entry.type == 0xf) {
auto checked_ebr = MBRPartitionTable::try_to_initialize(device, entry.offset);
auto checked_ebr = MBRPartitionTable::try_to_initialize(m_device.clone_unowned(), entry.offset);
if (!checked_ebr)
continue;
// It's quite unlikely to see that amount of partitions, so stop at 128 partitions.
search_extended_partition(device, *checked_ebr, entry.offset, 128);
search_extended_partition(*checked_ebr, entry.offset, 128);
continue;
}

View file

@ -15,13 +15,8 @@ class EBRPartitionTable : public MBRPartitionTable {
public:
~EBRPartitionTable();
#ifdef KERNEL
static ErrorOr<NonnullOwnPtr<EBRPartitionTable>> try_to_initialize(Kernel::StorageDevice&);
explicit EBRPartitionTable(Kernel::StorageDevice&);
#else
static ErrorOr<NonnullOwnPtr<EBRPartitionTable>> try_to_initialize(NonnullRefPtr<Core::DeprecatedFile>);
explicit EBRPartitionTable(NonnullRefPtr<Core::DeprecatedFile>);
#endif
static ErrorOr<NonnullOwnPtr<EBRPartitionTable>> try_to_initialize(PartitionableDevice);
explicit EBRPartitionTable(PartitionableDevice);
virtual bool is_valid() const override
{
@ -29,11 +24,7 @@ public:
}
private:
#ifdef KERNEL
void search_extended_partition(Kernel::StorageDevice&, MBRPartitionTable&, u64, size_t limit);
#else
void search_extended_partition(NonnullRefPtr<Core::DeprecatedFile>, MBRPartitionTable&, u64, size_t limit);
#endif
void search_extended_partition(MBRPartitionTable&, u64, size_t limit);
bool m_valid { false };
};

View file

@ -7,10 +7,6 @@
#include <AK/Debug.h>
#include <LibPartition/GUIDPartitionTable.h>
#ifndef KERNEL
# include <LibCore/DeprecatedFile.h>
#endif
namespace Partition {
#define GPT_SIGNATURE2 0x54524150
@ -48,30 +44,19 @@ struct [[gnu::packed]] GUIDPartitionHeader {
u32 crc32_entries_array;
};
#ifdef KERNEL
ErrorOr<NonnullOwnPtr<GUIDPartitionTable>> GUIDPartitionTable::try_to_initialize(Kernel::StorageDevice& device)
ErrorOr<NonnullOwnPtr<GUIDPartitionTable>> GUIDPartitionTable::try_to_initialize(PartitionableDevice device)
{
auto table = TRY(adopt_nonnull_own_or_enomem(new (nothrow) GUIDPartitionTable(device)));
#else
ErrorOr<NonnullOwnPtr<GUIDPartitionTable>> GUIDPartitionTable::try_to_initialize(NonnullRefPtr<Core::DeprecatedFile> device_file)
{
auto table = TRY(adopt_nonnull_own_or_enomem(new (nothrow) GUIDPartitionTable(move(device_file))));
#endif
auto table = TRY(adopt_nonnull_own_or_enomem(new (nothrow) GUIDPartitionTable(move(device))));
if (!table->is_valid())
return Error::from_errno(EINVAL);
return table;
}
#ifdef KERNEL
GUIDPartitionTable::GUIDPartitionTable(Kernel::StorageDevice& device)
: MBRPartitionTable(device)
#else
GUIDPartitionTable::GUIDPartitionTable(NonnullRefPtr<Core::DeprecatedFile> device_file)
: MBRPartitionTable(move(device_file))
#endif
GUIDPartitionTable::GUIDPartitionTable(PartitionableDevice device)
: MBRPartitionTable(move(device))
{
// FIXME: Handle OOM failure here.
m_cached_header = ByteBuffer::create_zeroed(m_block_size).release_value_but_fixme_should_propagate_errors();
m_cached_header = ByteBuffer::create_zeroed(block_size()).release_value_but_fixme_should_propagate_errors();
VERIFY(partitions_count() == 0);
if (!initialize())
m_valid = false;
@ -86,17 +71,11 @@ bool GUIDPartitionTable::initialize()
{
VERIFY(m_cached_header.data() != nullptr);
auto first_gpt_block = (m_block_size == 512) ? 1 : 0;
auto first_gpt_block = (block_size() == 512) ? 1 : 0;
#ifdef KERNEL
auto buffer = UserOrKernelBuffer::for_kernel_buffer(m_cached_header.data());
if (!m_device->read_block(first_gpt_block, buffer))
auto maybe_error = m_device.read_block(first_gpt_block, m_cached_header.bytes());
if (maybe_error.is_error())
return false;
#else
m_device_file->seek(first_gpt_block * m_block_size);
if (m_device_file->read(m_cached_header.data(), m_cached_header.size()) != (int)m_block_size)
return false;
#endif
dbgln_if(GPT_DEBUG, "GUIDPartitionTable: signature - {:#08x} {:#08x}", header().sig[1], header().sig[0]);
@ -105,28 +84,19 @@ bool GUIDPartitionTable::initialize()
return false;
}
auto entries_buffer_result = ByteBuffer::create_zeroed(m_block_size);
auto entries_buffer_result = ByteBuffer::create_zeroed(block_size());
if (entries_buffer_result.is_error()) {
dbgln("GUIDPartitionTable: not enough memory for entries buffer");
return false;
}
auto entries_buffer = entries_buffer_result.release_value();
#ifdef KERNEL
auto raw_entries_buffer = UserOrKernelBuffer::for_kernel_buffer(entries_buffer.data());
#endif
size_t raw_byte_index = header().partition_array_start_lba * m_block_size;
size_t raw_byte_index = header().partition_array_start_lba * block_size();
for (size_t entry_index = 0; entry_index < header().entries_count; entry_index++) {
#ifdef KERNEL
if (!m_device->read_block((raw_byte_index / m_block_size), raw_entries_buffer))
maybe_error = m_device.read_block(raw_byte_index / block_size(), entries_buffer.bytes());
if (maybe_error.is_error())
return false;
#else
m_device_file->seek(raw_byte_index);
if (m_device_file->read(entries_buffer.data(), entries_buffer.size()) != (int)m_block_size)
return false;
#endif
auto* entries = (GPTPartitionEntry const*)entries_buffer.data();
auto& entry = entries[entry_index % (m_block_size / (size_t)header().partition_entry_size)];
auto& entry = entries[entry_index % (block_size() / header().partition_entry_size)];
Array<u8, 16> partition_type {};
partition_type.span().overwrite(0, entry.partition_guid, partition_type.size());

View file

@ -15,13 +15,8 @@ class GUIDPartitionTable final : public MBRPartitionTable {
public:
virtual ~GUIDPartitionTable() = default;
#ifdef KERNEL
static ErrorOr<NonnullOwnPtr<GUIDPartitionTable>> try_to_initialize(Kernel::StorageDevice&);
explicit GUIDPartitionTable(Kernel::StorageDevice&);
#else
static ErrorOr<NonnullOwnPtr<GUIDPartitionTable>> try_to_initialize(NonnullRefPtr<Core::DeprecatedFile>);
explicit GUIDPartitionTable(NonnullRefPtr<Core::DeprecatedFile>);
#endif
static ErrorOr<NonnullOwnPtr<GUIDPartitionTable>> try_to_initialize(PartitionableDevice);
explicit GUIDPartitionTable(PartitionableDevice);
virtual bool is_valid() const override
{

View file

@ -7,10 +7,6 @@
#include <AK/Debug.h>
#include <LibPartition/MBRPartitionTable.h>
#ifndef KERNEL
# include <LibCore/DeprecatedFile.h>
#endif
namespace Partition {
#define MBR_SIGNATURE 0xaa55
@ -18,15 +14,9 @@ namespace Partition {
#define EBR_CHS_CONTAINER 0x05
#define EBR_LBA_CONTAINER 0x0F
#ifdef KERNEL
ErrorOr<NonnullOwnPtr<MBRPartitionTable>> MBRPartitionTable::try_to_initialize(Kernel::StorageDevice& device)
ErrorOr<NonnullOwnPtr<MBRPartitionTable>> MBRPartitionTable::try_to_initialize(PartitionableDevice device)
{
auto table = TRY(adopt_nonnull_own_or_enomem(new (nothrow) MBRPartitionTable(device)));
#else
ErrorOr<NonnullOwnPtr<MBRPartitionTable>> MBRPartitionTable::try_to_initialize(NonnullRefPtr<Core::DeprecatedFile> device_file)
{
auto table = TRY(adopt_nonnull_own_or_enomem(new (nothrow) MBRPartitionTable(move(device_file))));
#endif
auto table = TRY(adopt_nonnull_own_or_enomem(new (nothrow) MBRPartitionTable(move(device))));
if (table->contains_ebr())
return Error::from_errno(ENOTSUP);
if (table->is_protective_mbr())
@ -36,15 +26,9 @@ ErrorOr<NonnullOwnPtr<MBRPartitionTable>> MBRPartitionTable::try_to_initialize(N
return table;
}
#ifdef KERNEL
OwnPtr<MBRPartitionTable> MBRPartitionTable::try_to_initialize(Kernel::StorageDevice& device, u32 start_lba)
OwnPtr<MBRPartitionTable> MBRPartitionTable::try_to_initialize(PartitionableDevice device, u32 start_lba)
{
auto table = adopt_nonnull_own_or_enomem(new (nothrow) MBRPartitionTable(device, start_lba)).release_value_but_fixme_should_propagate_errors();
#else
OwnPtr<MBRPartitionTable> MBRPartitionTable::try_to_initialize(NonnullRefPtr<Core::DeprecatedFile> device_file, u32 start_lba)
{
auto table = adopt_nonnull_own_or_enomem(new (nothrow) MBRPartitionTable(move(device_file), start_lba)).release_value_but_fixme_should_propagate_errors();
#endif
auto table = adopt_nonnull_own_or_enomem(new (nothrow) MBRPartitionTable(move(device), start_lba)).release_value_but_fixme_should_propagate_errors();
if (!table->is_valid())
return {};
return table;
@ -52,28 +36,17 @@ OwnPtr<MBRPartitionTable> MBRPartitionTable::try_to_initialize(NonnullRefPtr<Cor
bool MBRPartitionTable::read_boot_record()
{
#ifdef KERNEL
auto buffer = UserOrKernelBuffer::for_kernel_buffer(m_cached_header.data());
if (!m_device->read_block(m_start_lba, buffer))
if (block_size() != 512)
return false;
#else
m_device_file->seek(m_start_lba * m_block_size);
if (m_device_file->read(m_cached_header.data(), m_cached_header.size()) != 512)
return false;
#endif
m_header_valid = true;
auto maybe_error = m_device.read_block(m_start_lba, m_cached_header.bytes());
m_header_valid = !maybe_error.is_error();
return m_header_valid;
}
#ifdef KERNEL
MBRPartitionTable::MBRPartitionTable(Kernel::StorageDevice& device, u32 start_lba)
: PartitionTable(device)
#else
MBRPartitionTable::MBRPartitionTable(NonnullRefPtr<Core::DeprecatedFile> device_file, u32 start_lba)
: PartitionTable(move(device_file))
#endif
MBRPartitionTable::MBRPartitionTable(PartitionableDevice device, u32 start_lba)
: PartitionTable(move(device))
, m_start_lba(start_lba)
, m_cached_header(ByteBuffer::create_zeroed(m_block_size).release_value_but_fixme_should_propagate_errors()) // FIXME: Do something sensible if this fails because of OOM.
, m_cached_header(ByteBuffer::create_zeroed(block_size()).release_value_but_fixme_should_propagate_errors()) // FIXME: Do something sensible if this fails because of OOM.
{
if (!read_boot_record() || !initialize())
return;
@ -91,15 +64,10 @@ MBRPartitionTable::MBRPartitionTable(NonnullRefPtr<Core::DeprecatedFile> device_
m_valid = true;
}
#ifdef KERNEL
MBRPartitionTable::MBRPartitionTable(Kernel::StorageDevice& device)
: PartitionTable(device)
#else
MBRPartitionTable::MBRPartitionTable(NonnullRefPtr<Core::DeprecatedFile> device_file)
: PartitionTable(move(device_file))
#endif
MBRPartitionTable::MBRPartitionTable(PartitionableDevice device)
: PartitionTable(move(device))
, m_start_lba(0)
, m_cached_header(ByteBuffer::create_zeroed(m_block_size).release_value_but_fixme_should_propagate_errors()) // FIXME: Do something sensible if this fails because of OOM.
, m_cached_header(ByteBuffer::create_zeroed(block_size()).release_value_but_fixme_should_propagate_errors()) // FIXME: Do something sensible if this fails because of OOM.
{
if (!read_boot_record() || contains_ebr() || is_protective_mbr() || !initialize())
return;

View file

@ -38,17 +38,10 @@ public:
public:
~MBRPartitionTable();
#ifdef KERNEL
static ErrorOr<NonnullOwnPtr<MBRPartitionTable>> try_to_initialize(Kernel::StorageDevice&);
static OwnPtr<MBRPartitionTable> try_to_initialize(Kernel::StorageDevice&, u32 start_lba);
explicit MBRPartitionTable(Kernel::StorageDevice&);
MBRPartitionTable(Kernel::StorageDevice&, u32 start_lba);
#else
static ErrorOr<NonnullOwnPtr<MBRPartitionTable>> try_to_initialize(NonnullRefPtr<Core::DeprecatedFile>);
static OwnPtr<MBRPartitionTable> try_to_initialize(NonnullRefPtr<Core::DeprecatedFile>, u32 start_lba);
explicit MBRPartitionTable(NonnullRefPtr<Core::DeprecatedFile>);
MBRPartitionTable(NonnullRefPtr<Core::DeprecatedFile>, u32 start_lba);
#endif
static ErrorOr<NonnullOwnPtr<MBRPartitionTable>> try_to_initialize(PartitionableDevice);
static OwnPtr<MBRPartitionTable> try_to_initialize(PartitionableDevice, u32 start_lba);
explicit MBRPartitionTable(PartitionableDevice);
MBRPartitionTable(PartitionableDevice, u32 start_lba);
bool is_protective_mbr() const;
bool contains_ebr() const;

View file

@ -7,25 +7,15 @@
#include <LibPartition/PartitionTable.h>
#ifndef KERNEL
# include <LibCore/DeprecatedFile.h>
# include <sys/ioctl.h>
#endif
namespace Partition {
#ifdef KERNEL
PartitionTable::PartitionTable(Kernel::StorageDevice& device)
: m_device(device)
, m_block_size(device.block_size())
PartitionTable::PartitionTable(PartitionableDevice&& device)
: m_device(move(device))
{
}
#else
PartitionTable::PartitionTable(NonnullRefPtr<Core::DeprecatedFile> device_file)
: m_device_file(device_file)
{
VERIFY(ioctl(m_device_file->leak_fd(), STORAGE_DEVICE_GET_BLOCK_SIZE, &m_block_size) >= 0);
}
#endif
Optional<DiskPartitionMetadata> PartitionTable::partition(unsigned index) const
{

View file

@ -8,12 +8,7 @@
#include <AK/NonnullRefPtr.h>
#include <LibPartition/DiskPartitionMetadata.h>
#ifdef KERNEL
# include <Kernel/Devices/Storage/StorageDevice.h>
#else
# include <LibCore/Forward.h>
#endif
#include <LibPartition/PartitionableDevice.h>
namespace Partition {
@ -25,19 +20,13 @@ public:
virtual bool is_valid() const = 0;
Vector<DiskPartitionMetadata> partitions() const { return m_partitions; }
size_t block_size() const { return m_block_size; }
size_t block_size() const { return m_device.block_size(); }
protected:
#ifdef KERNEL
explicit PartitionTable(Kernel::StorageDevice&);
NonnullRefPtr<Kernel::StorageDevice> m_device;
#else
explicit PartitionTable(NonnullRefPtr<Core::DeprecatedFile>);
NonnullRefPtr<Core::DeprecatedFile> m_device_file;
#endif
explicit PartitionTable(PartitionableDevice&&);
PartitionableDevice m_device;
Vector<DiskPartitionMetadata> m_partitions;
size_t m_block_size;
};
}

View file

@ -0,0 +1,102 @@
/*
* Copyright (c) 2023, Ben Wiederhake <BenWiederhake.GitHub@gmx.de>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <LibPartition/PartitionableDevice.h>
#ifndef KERNEL
# include <sys/ioctl.h>
#endif
namespace Partition {
#ifdef KERNEL
ErrorOr<PartitionableDevice> PartitionableDevice::create(Kernel::StorageDevice& device)
{
return PartitionableDevice(device);
}
#else
ErrorOr<PartitionableDevice> PartitionableDevice::create(MaybeOwned<Core::File> device_file)
{
VERIFY(device_file.ptr() != nullptr);
size_t block_size;
int rc = ioctl(device_file->fd(), STORAGE_DEVICE_GET_BLOCK_SIZE, &block_size);
if (rc < 0)
return Error::from_string_view("ioctl on device failed"sv);
return PartitionableDevice(move(device_file), block_size);
}
#endif
#ifdef KERNEL
PartitionableDevice::PartitionableDevice(Kernel::StorageDevice& device)
: m_device(device)
{
}
#else
PartitionableDevice::PartitionableDevice(MaybeOwned<Core::File> device_file, size_t block_size)
: m_device_file(move(device_file))
, m_block_size(block_size)
{
}
#endif
#ifdef KERNEL
PartitionableDevice PartitionableDevice::clone_unowned()
{
return PartitionableDevice(m_device);
}
#else
PartitionableDevice PartitionableDevice::clone_unowned()
{
return PartitionableDevice(MaybeOwned<Core::File>(*m_device_file), m_block_size);
}
#endif
#ifdef KERNEL
ErrorOr<PartitionableDevice> PartitionableDevice::clone_owned()
{
return PartitionableDevice(m_device);
}
#else
ErrorOr<PartitionableDevice> PartitionableDevice::clone_owned()
{
auto cloned_file = TRY(Core::File::adopt_fd(m_device_file->fd(), Core::File::OpenMode::Read, Core::File::ShouldCloseFileDescriptor::No));
return PartitionableDevice(move(cloned_file), m_block_size);
}
#endif
#ifdef KERNEL
size_t PartitionableDevice::block_size() const
{
return m_device.block_size();
}
#else
size_t PartitionableDevice::block_size() const
{
return m_block_size;
}
#endif
#ifdef KERNEL
ErrorOr<void> PartitionableDevice::read_block(size_t block_index, Bytes block_buffer)
{
VERIFY(block_buffer.size() == block_size());
auto buffer = UserOrKernelBuffer::for_kernel_buffer(block_buffer.data());
bool read_successful = m_device.read_block(block_index, buffer);
if (!read_successful)
return Error::from_errno(EIO);
return {};
}
#else
ErrorOr<void> PartitionableDevice::read_block(size_t block_index, Bytes block_buffer)
{
VERIFY(block_buffer.size() == block_size());
TRY(m_device_file->seek(block_index * block_size(), SeekMode::SetPosition));
TRY(m_device_file->read_until_filled(block_buffer));
return {};
}
#endif
}

View file

@ -0,0 +1,54 @@
/*
* Copyright (c) 2023, Ben Wiederhake <BenWiederhake.GitHub@gmx.de>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include <AK/Noncopyable.h>
#ifdef KERNEL
# include <Kernel/Devices/Storage/StorageDevice.h>
#else
# include <AK/MaybeOwned.h>
# include <LibCore/File.h>
#endif
namespace Partition {
class PartitionableDevice {
AK_MAKE_NONCOPYABLE(PartitionableDevice);
public:
#ifdef KERNEL
PartitionableDevice(Kernel::StorageDevice&);
// Userland doesn't get an implicit constructor.
#endif
PartitionableDevice(PartitionableDevice&&) = default;
// Unused, and "move out of reference" isn't well-defined anyway:
PartitionableDevice& operator=(PartitionableDevice&&) = delete;
#ifdef KERNEL
static ErrorOr<PartitionableDevice> create(Kernel::StorageDevice& device);
#else
static ErrorOr<PartitionableDevice> create(MaybeOwned<Core::File> device_file);
#endif
~PartitionableDevice() = default;
PartitionableDevice clone_unowned();
ErrorOr<PartitionableDevice> clone_owned();
size_t block_size() const;
ErrorOr<void> read_block(size_t block_index, Bytes block_buffer);
private:
#ifdef KERNEL
Kernel::StorageDevice& m_device;
#else
explicit PartitionableDevice(MaybeOwned<Core::File>, size_t block_size);
MaybeOwned<Core::File> m_device_file;
size_t m_block_size;
#endif
};
}