blob: e235ff73e7452bbb8a20e462d50aa104dbd3821d [file] [log] [blame]
// Copyright 2019 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <fcntl.h>
#include <limits.h>
#include <stdint.h>
#include <memory>
#include <string>
#include <utility>
#include <fbl/unique_fd.h>
#include <gpt/gpt.h>
#include <gpt/guid.h>
#include <mbr/mbr.h>
#include <ramdevice-client/ramdisk.h>
namespace gpt {
namespace {
constexpr uint32_t kBlockSize = 512;
constexpr uint64_t kBlockCount = 1 << 20;
constexpr uint64_t kAccptableMinimumSize = kBlockSize * kBlockCount;
constexpr uint64_t kGptMetadataSize = 1 << 18; // 256KiB for now. See comment in LibGptTest::Init
static_assert(kGptMetadataSize <= kAccptableMinimumSize,
"GPT size greater than kAccptableMinimumSize");
class LibGptTest {
// Test environment options.
struct Options {
// Path to the block device to use for the test. If empty, an internal ramdisk will
// be used for tests.
std::string disk_path;
// Block size and count for the test. Ignored if a block device is provided.
uint32_t block_size = kBlockSize;
uint64_t block_count = kBlockCount;
// Create a new test environment using the given options.
static std::unique_ptr<LibGptTest> Create(const Options& options);
// Returns total size of the disk under test.
uint64_t GetDiskSize() const { return blk_size_ * blk_count_; }
// Return block size of the disk under test.
uint32_t GetBlockSize() const { return blk_size_; }
// Returns total number of block in the disk.
uint64_t GetBlockCount() const { return blk_count_; }
// Return total number of block free in disk after GPT is created.
uint64_t GetUsableBlockCount() const { return usable_last_block_ - usable_start_block_; }
// First block that is free to use after GPT is created.
uint64_t GetUsableStartBlock() const { return usable_start_block_; }
// Last block that is free to use after GPT is created.
uint64_t GetUsableLastBlock() const { return usable_last_block_; }
// Returns number of block GPT uses.
uint64_t GptMetadataBlocksCount() const {
// See comment in LibGptTest::Init
return kGptMetadataSize / blk_size_;
// Returns the full device path.
const char* GetDevicePath() const { return disk_path_; }
// Remove all partition from GPT and keep device in GPT initialized state.
void Reset();
// Finalize uninitialized disk and verify.
void Finalize();
// Sync and verify.
void Sync();
// Get the Range from GPT.
void ReadRange();
// Read the MBR from the disk.
zx_status_t ReadMbr(mbr::Mbr* mbr) const;
// Prepare disk to run Add Partition tests.
// 1. initialize GPT
// 2. optionally sync
// 3. get the usable range
void PrepDisk(bool sync);
// gpt_ changes across Reset(). So we do not expose pointer to GptDevice to
// any of the test. Instead we expose following wrapper funtions for
// a few GptDevice methods.
bool IsGptValid() const { return gpt_->Valid(); }
zx_status_t GetDiffs(uint32_t partition_index, uint32_t* diffs) const {
return gpt_->GetDiffs(partition_index, diffs);
// Get's a partition at index pindex.
gpt_partition_t* GetPartition(uint32_t pindex) const { return gpt_->GetPartition(pindex); }
// Adds a partition
zx_status_t AddPartition(const char* name, const uint8_t* type, const uint8_t* guid,
uint64_t offset, uint64_t blocks, uint64_t flags) {
return gpt_->AddPartition(name, type, guid, offset, blocks, flags);
// removes a partition.
zx_status_t RemovePartition(const uint8_t* guid) { return gpt_->RemovePartition(guid); }
// removes all partitions.
zx_status_t RemoveAllPartitions() { return gpt_->RemoveAllPartitions(); }
// wrapper around GptDevice's SetPartitionType
zx_status_t SetPartitionType(uint32_t partition_index, const uint8_t* type) {
return gpt_->SetPartitionType(partition_index, type);
// wrapper around GptDevice's SetPartitionGuid
zx_status_t SetPartitionGuid(uint32_t partition_index, const uint8_t* guid) {
return gpt_->SetPartitionGuid(partition_index, guid);
// wrapper around GptDevice's SetPartitionRange
zx_status_t SetPartitionRange(uint32_t partition_index, uint64_t start, uint64_t end) {
return gpt_->SetPartitionRange(partition_index, start, end);
// wrapper around GptDevice's SetPartitionVisibility
zx_status_t SetPartitionVisibility(uint32_t index, bool visible) {
return gpt_->SetPartitionVisibility(index, visible);
// wrapper around GptDevice's GetPartitionFlags
zx_status_t GetPartitionFlags(uint32_t index, uint64_t* flags) {
return gpt_->GetPartitionFlags(index, flags);
// wrapper around GptDevice's SetPartitionFlags
zx_status_t SetPartitionFlags(uint32_t index, uint64_t flags) {
return gpt_->SetPartitionFlags(index, flags);
LibGptTest() {}
// Initialize a physical media.
void InitDisk(const char* disk_path);
// Create and initialize and ramdisk.
void InitRamDisk(const Options& options);
// Block size of the device.
uint32_t blk_size_ = kBlockSize;
// Number of block in the disk.
uint64_t blk_count_ = kBlockCount;
// disk path
char disk_path_[PATH_MAX] = {};
// pointer to read GptDevice.
std::unique_ptr<gpt::GptDevice> gpt_;
// Open file descriptor to block device.
fbl::unique_fd fd_;
// An optional ramdisk structure.
ramdisk_client_t* ramdisk_ = nullptr;
// usable start block offset.
uint64_t usable_start_block_ = UINT64_MAX;
// usable last block offset.
uint64_t usable_last_block_ = UINT64_MAX;
} // namespace
} // namespace gpt