Serenity Operating System
at master 150 lines 4.8 kB view raw
1/* 2 * Copyright (c) 2020-2022, Liav A. <liavalb@hotmail.co.il> 3 * 4 * SPDX-License-Identifier: BSD-2-Clause 5 */ 6 7#include <AK/Debug.h> 8#include <LibPartition/MBRPartitionTable.h> 9 10#ifndef KERNEL 11# include <LibCore/DeprecatedFile.h> 12#endif 13 14namespace Partition { 15 16#define MBR_SIGNATURE 0xaa55 17#define MBR_PROTECTIVE 0xEE 18#define EBR_CHS_CONTAINER 0x05 19#define EBR_LBA_CONTAINER 0x0F 20 21#ifdef KERNEL 22ErrorOr<NonnullOwnPtr<MBRPartitionTable>> MBRPartitionTable::try_to_initialize(Kernel::StorageDevice& device) 23{ 24 auto table = TRY(adopt_nonnull_own_or_enomem(new (nothrow) MBRPartitionTable(device))); 25#else 26ErrorOr<NonnullOwnPtr<MBRPartitionTable>> MBRPartitionTable::try_to_initialize(NonnullRefPtr<Core::DeprecatedFile> device_file) 27{ 28 auto table = TRY(adopt_nonnull_own_or_enomem(new (nothrow) MBRPartitionTable(move(device_file)))); 29#endif 30 if (table->contains_ebr()) 31 return Error::from_errno(ENOTSUP); 32 if (table->is_protective_mbr()) 33 return Error::from_errno(ENOTSUP); 34 if (!table->is_valid()) 35 return Error::from_errno(EINVAL); 36 return table; 37} 38 39#ifdef KERNEL 40OwnPtr<MBRPartitionTable> MBRPartitionTable::try_to_initialize(Kernel::StorageDevice& device, u32 start_lba) 41{ 42 auto table = adopt_nonnull_own_or_enomem(new (nothrow) MBRPartitionTable(device, start_lba)).release_value_but_fixme_should_propagate_errors(); 43#else 44OwnPtr<MBRPartitionTable> MBRPartitionTable::try_to_initialize(NonnullRefPtr<Core::DeprecatedFile> device_file, u32 start_lba) 45{ 46 auto table = adopt_nonnull_own_or_enomem(new (nothrow) MBRPartitionTable(move(device_file), start_lba)).release_value_but_fixme_should_propagate_errors(); 47#endif 48 if (!table->is_valid()) 49 return {}; 50 return table; 51} 52 53bool MBRPartitionTable::read_boot_record() 54{ 55#ifdef KERNEL 56 auto buffer = UserOrKernelBuffer::for_kernel_buffer(m_cached_header.data()); 57 if (!m_device->read_block(m_start_lba, buffer)) 58 return false; 59#else 60 m_device_file->seek(m_start_lba * m_block_size); 61 if (m_device_file->read(m_cached_header.data(), m_cached_header.size()) != 512) 62 return false; 63#endif 64 m_header_valid = true; 65 return m_header_valid; 66} 67 68#ifdef KERNEL 69MBRPartitionTable::MBRPartitionTable(Kernel::StorageDevice& device, u32 start_lba) 70 : PartitionTable(device) 71#else 72MBRPartitionTable::MBRPartitionTable(NonnullRefPtr<Core::DeprecatedFile> device_file, u32 start_lba) 73 : PartitionTable(move(device_file)) 74#endif 75 , m_start_lba(start_lba) 76 , 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. 77{ 78 if (!read_boot_record() || !initialize()) 79 return; 80 81 m_header_valid = true; 82 83 auto& header = this->header(); 84 for (size_t index = 0; index < 4; index++) { 85 auto& entry = header.entry[index]; 86 if (entry.offset == 0x00) { 87 continue; 88 } 89 MUST(m_partitions.try_empend(entry.offset, (entry.offset + entry.length) - 1, entry.type)); 90 } 91 m_valid = true; 92} 93 94#ifdef KERNEL 95MBRPartitionTable::MBRPartitionTable(Kernel::StorageDevice& device) 96 : PartitionTable(device) 97#else 98MBRPartitionTable::MBRPartitionTable(NonnullRefPtr<Core::DeprecatedFile> device_file) 99 : PartitionTable(move(device_file)) 100#endif 101 , m_start_lba(0) 102 , 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. 103{ 104 if (!read_boot_record() || contains_ebr() || is_protective_mbr() || !initialize()) 105 return; 106 107 auto& header = this->header(); 108 for (size_t index = 0; index < 4; index++) { 109 auto& entry = header.entry[index]; 110 if (entry.offset == 0x00) { 111 continue; 112 } 113 MUST(m_partitions.try_empend(entry.offset, (entry.offset + entry.length) - 1, entry.type)); 114 } 115 m_valid = true; 116} 117 118MBRPartitionTable::~MBRPartitionTable() = default; 119 120MBRPartitionTable::Header const& MBRPartitionTable::header() const 121{ 122 return *(MBRPartitionTable::Header const*)m_cached_header.data(); 123} 124 125bool MBRPartitionTable::initialize() 126{ 127 auto& header = this->header(); 128 dbgln_if(MBR_DEBUG, "Master Boot Record: mbr_signature={:#08x}", header.mbr_signature); 129 if (header.mbr_signature != MBR_SIGNATURE) { 130 dbgln("Master Boot Record: invalid signature"); 131 return false; 132 } 133 return true; 134} 135 136bool MBRPartitionTable::contains_ebr() const 137{ 138 for (int i = 0; i < 4; i++) { 139 if (header().entry[i].type == EBR_CHS_CONTAINER || header().entry[i].type == EBR_LBA_CONTAINER) 140 return true; 141 } 142 return false; 143} 144 145bool MBRPartitionTable::is_protective_mbr() const 146{ 147 return header().entry[0].type == MBR_PROTECTIVE; 148} 149 150}