blob: d405a9435e0b91036d3d812a8360c0a579e5e0f2 [file] [log] [blame]
// Copyright 2012 The ChromiumOS Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef INSTALLER_CGPT_MANAGER_H_
#define INSTALLER_CGPT_MANAGER_H_
#include <iostream>
#include <optional>
#include <string>
#include <base/files/file_path.h>
#include <vboot/gpt.h>
#include "installer/inst_util.h"
// This file defines a simple C++ wrapper class interface for the cgpt methods.
// These are the possible error codes that can be returned by the CgptManager.
enum class [[nodiscard]] CgptErrorCode {
kSuccess = 0,
kNotInitialized = 1,
kUnknownError = 2,
kInvalidArgument = 3,
};
std::ostream& operator<<(std::ostream& os, const CgptErrorCode& error);
// Range of sectors on disk.
struct SectorRange {
// First sector.
uint64_t start = 0;
// Number of sectors.
uint64_t count = 0;
};
// CgptManagerInterface provices methods to manipulate the Guid
// Partition Table as needed for ChromeOS scenarios.
//
// A concrete implementation is provided by `CgptManager`, and a mock
// for unit tests is provided in `mock_cgpt_manager.h`.
class CgptManagerInterface {
public:
// Destructor. Automatically closes any opened device.
virtual ~CgptManagerInterface() {}
// Opens the given device_name (e.g. "/dev/sdc") and initializes
// with the Guid Partition Table of that device. This is the first method
// that should be called on this class. Otherwise those methods will
// return kNotInitialized.
// Returns kSuccess or an appropriate error code.
// This device is automatically closed when this object is destructed.
virtual CgptErrorCode Initialize(const base::FilePath& device_name) = 0;
// Performs any necessary write-backs so that the GPT structs are written to
// the device. This method is called in the destructor but its error code is
// not checked. Therefore, it is best to call Finalize yourself and check the
// returned code.
virtual CgptErrorCode Finalize() = 0;
// Sets the "successful" attribute of the given kernelPartition to 0 or 1
// based on the value of is_successful being true (1) or false(0)
// Returns kSuccess or an appropriate error code.
virtual CgptErrorCode SetSuccessful(PartitionNum partition_number,
bool is_successful) = 0;
// Sets the "NumTriesLeft" attribute of the given kernelPartition to
// the given num_tries_left value.
// Returns kSuccess or an appropriate error code.
virtual CgptErrorCode SetNumTriesLeft(PartitionNum partition_number,
int num_tries_left) = 0;
// Sets the "Priority" attribute of the given kernelPartition to
// the given priority value.
// Returns kSuccess or an appropriate error code.
virtual CgptErrorCode SetPriority(PartitionNum partition_number,
uint8_t priority) = 0;
// Populates the unique_id parameter with the Guid that uniquely identifies
// the given partition_number.
// Returns kSuccess or an appropriate error code.
virtual CgptErrorCode GetPartitionUniqueId(PartitionNum partition_number,
Guid* unique_id) const = 0;
// Sets the "Priority" attribute of a partition to make it higher than all
// other partitions. If necessary, the priorities of other partitions are
// reduced to ensure no other partition has a higher priority.
//
// It preserves the relative ordering among the remaining partitions and
// doesn't touch the partitions whose priorities are zero.
//
// Returns kSuccess or an appropriate error code.
virtual CgptErrorCode SetHighestPriority(PartitionNum partition_number) = 0;
// Get the sectors used by the partition.
// Returns kCgptSuccess or an appropriate error code.
virtual CgptErrorCode GetSectorRange(PartitionNum partition_number,
SectorRange& sectors) const = 0;
// Set the sectors used by the partition. If |start| or |count| is
// |std::nullopt|, the corresponding partition value will not be
// updated. At least one of them must be set.
// Returns kCgptSuccess or an appropriate error code.
virtual CgptErrorCode SetSectorRange(PartitionNum partition_number,
std::optional<uint64_t> start,
std::optional<uint64_t> count) = 0;
// In some circumstances devices will have a damaged GPT (at least
// b/257478857, possibly other cases). This tries to fix it.
//
// Returns kSuccess or an appropriate error code.
virtual CgptErrorCode RepairPartitionTable() = 0;
// Get the device path (e.g. "/dev/sda") that was passed in to |Initialize|.
virtual const base::FilePath& DeviceName() const = 0;
};
class CgptManager : public CgptManagerInterface {
public:
// Default constructor. The Initialize method must be called before
// any other method can be called on this class.
CgptManager();
~CgptManager() override;
CgptErrorCode Initialize(const base::FilePath& device_name) override;
CgptErrorCode Finalize() override;
CgptErrorCode SetSuccessful(PartitionNum partition_number,
bool is_successful) override;
CgptErrorCode SetNumTriesLeft(PartitionNum partition_number,
int num_tries_left) override;
CgptErrorCode SetPriority(PartitionNum partition_number,
uint8_t priority) override;
CgptErrorCode GetPartitionUniqueId(PartitionNum partition_number,
Guid* unique_id) const override;
CgptErrorCode SetHighestPriority(PartitionNum partition_number) override;
CgptErrorCode GetSectorRange(PartitionNum partition_number,
SectorRange& sectors) const override;
CgptErrorCode SetSectorRange(PartitionNum partition_number,
std::optional<uint64_t> start,
std::optional<uint64_t> count) override;
CgptErrorCode RepairPartitionTable() override;
const base::FilePath& DeviceName() const override;
private:
// The device name that is passed to Initialize.
base::FilePath device_name_;
// The size of that device in case we store GPT structs off site (such as on
// NOR flash). Zero if we store GPT structs on the same device.
uint64_t device_size_;
bool is_initialized_;
CgptManager(const CgptManager&);
void operator=(const CgptManager&);
};
#endif // INSTALLER_CGPT_MANAGER_H_