ladybird/Userland/Libraries/LibPartition/EBRPartitionTable.cpp
Samuel Bowman 2f8c20816e LibPartition: Fix end block off by one error
Previously, end block was inconsistent. GUIDPartitionTable treated
end block as an inclusive bound, while MBRPartitionTable and
EBRPartitionTable treated end block as an exclusive bound.
Now all three treat end block as an inclusive upper bound.
2022-07-21 20:13:44 +01:00

86 lines
3 KiB
C++

/*
* Copyright (c) 2020-2022, Liav A. <liavalb@hotmail.co.il>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <LibPartition/EBRPartitionTable.h>
namespace Partition {
#ifdef KERNEL
ErrorOr<NonnullOwnPtr<EBRPartitionTable>> EBRPartitionTable::try_to_initialize(Kernel::StorageDevice const& device)
{
auto table = TRY(adopt_nonnull_own_or_enomem(new (nothrow) EBRPartitionTable(device)));
#else
ErrorOr<NonnullOwnPtr<EBRPartitionTable>> EBRPartitionTable::try_to_initialize(NonnullRefPtr<Core::File> device_file)
{
auto table = TRY(adopt_nonnull_own_or_enomem(new (nothrow) EBRPartitionTable(move(device_file))));
#endif
if (table->is_protective_mbr())
return Error::from_errno(ENOTSUP);
if (!table->is_valid())
return Error::from_errno(EINVAL);
return table;
}
#ifdef KERNEL
void EBRPartitionTable::search_extended_partition(Kernel::StorageDevice const& device, MBRPartitionTable& checked_ebr, u64 current_block_offset, size_t limit)
#else
void EBRPartitionTable::search_extended_partition(NonnullRefPtr<Core::File> device, MBRPartitionTable& checked_ebr, u64 current_block_offset, size_t limit)
#endif
{
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);
auto checked_logical_partition = checked_ebr.partition(0);
// If we are pointed to an invalid logical partition, something is seriously wrong.
VERIFY(checked_logical_partition.has_value());
m_partitions.append(checked_logical_partition.value().offset(current_block_offset));
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);
if (!next_ebr)
return;
search_extended_partition(device, *next_ebr, current_block_offset, (limit - 1));
}
#ifdef KERNEL
EBRPartitionTable::EBRPartitionTable(Kernel::StorageDevice const& device)
#else
EBRPartitionTable::EBRPartitionTable(NonnullRefPtr<Core::File> device)
#endif
: MBRPartitionTable(device)
{
if (!is_header_valid())
return;
m_valid = true;
VERIFY(partitions_count() == 0);
auto& header = this->header();
for (size_t index = 0; index < 4; index++) {
auto& entry = header.entry[index];
// Start enumerating all logical partitions
if (entry.type == 0xf) {
auto checked_ebr = MBRPartitionTable::try_to_initialize(device, 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);
continue;
}
if (entry.offset == 0x00) {
continue;
}
MUST(m_partitions.try_empend(entry.offset, (entry.offset + entry.length) - 1, entry.type));
}
}
EBRPartitionTable::~EBRPartitionTable() = default;
}