Merge "liblp: Add an abstraction layer for opening partitions."
This commit is contained in:
commit
89eb017780
|
@ -25,6 +25,7 @@ cc_library {
|
|||
srcs: [
|
||||
"builder.cpp",
|
||||
"images.cpp",
|
||||
"partition_opener.cpp",
|
||||
"reader.cpp",
|
||||
"utility.cpp",
|
||||
"writer.cpp",
|
||||
|
@ -59,6 +60,7 @@ cc_test {
|
|||
srcs: [
|
||||
"builder_test.cpp",
|
||||
"io_test.cpp",
|
||||
"test_partition_opener.cpp",
|
||||
"utility_test.cpp",
|
||||
],
|
||||
}
|
||||
|
|
|
@ -16,11 +16,7 @@
|
|||
|
||||
#include "liblp/builder.h"
|
||||
|
||||
#if defined(__linux__)
|
||||
#include <linux/fs.h>
|
||||
#endif
|
||||
#include <string.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
|
@ -33,43 +29,6 @@
|
|||
namespace android {
|
||||
namespace fs_mgr {
|
||||
|
||||
bool GetBlockDeviceInfo(const std::string& block_device, BlockDeviceInfo* device_info) {
|
||||
#if defined(__linux__)
|
||||
android::base::unique_fd fd(open(block_device.c_str(), O_RDONLY));
|
||||
if (fd < 0) {
|
||||
PERROR << __PRETTY_FUNCTION__ << "open '" << block_device << "' failed";
|
||||
return false;
|
||||
}
|
||||
if (!GetDescriptorSize(fd, &device_info->size)) {
|
||||
return false;
|
||||
}
|
||||
if (ioctl(fd, BLKIOMIN, &device_info->alignment) < 0) {
|
||||
PERROR << __PRETTY_FUNCTION__ << "BLKIOMIN failed";
|
||||
return false;
|
||||
}
|
||||
|
||||
int alignment_offset;
|
||||
if (ioctl(fd, BLKALIGNOFF, &alignment_offset) < 0) {
|
||||
PERROR << __PRETTY_FUNCTION__ << "BLKIOMIN failed";
|
||||
return false;
|
||||
}
|
||||
int logical_block_size;
|
||||
if (ioctl(fd, BLKSSZGET, &logical_block_size) < 0) {
|
||||
PERROR << __PRETTY_FUNCTION__ << "BLKSSZGET failed";
|
||||
return false;
|
||||
}
|
||||
|
||||
device_info->alignment_offset = static_cast<uint32_t>(alignment_offset);
|
||||
device_info->logical_block_size = static_cast<uint32_t>(logical_block_size);
|
||||
return true;
|
||||
#else
|
||||
(void)block_device;
|
||||
(void)device_info;
|
||||
LERROR << __PRETTY_FUNCTION__ << ": Not supported on this operating system.";
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
void LinearExtent::AddTo(LpMetadata* out) const {
|
||||
out->extents.push_back(LpMetadataExtent{num_sectors_, LP_TARGET_TYPE_LINEAR, physical_sector_});
|
||||
}
|
||||
|
@ -138,9 +97,10 @@ uint64_t Partition::BytesOnDisk() const {
|
|||
return sectors * LP_SECTOR_SIZE;
|
||||
}
|
||||
|
||||
std::unique_ptr<MetadataBuilder> MetadataBuilder::New(const std::string& block_device,
|
||||
std::unique_ptr<MetadataBuilder> MetadataBuilder::New(const IPartitionOpener& opener,
|
||||
const std::string& super_partition,
|
||||
uint32_t slot_number) {
|
||||
std::unique_ptr<LpMetadata> metadata = ReadMetadata(block_device.c_str(), slot_number);
|
||||
std::unique_ptr<LpMetadata> metadata = ReadMetadata(opener, super_partition, slot_number);
|
||||
if (!metadata) {
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -149,12 +109,17 @@ std::unique_ptr<MetadataBuilder> MetadataBuilder::New(const std::string& block_d
|
|||
return nullptr;
|
||||
}
|
||||
BlockDeviceInfo device_info;
|
||||
if (fs_mgr::GetBlockDeviceInfo(block_device, &device_info)) {
|
||||
if (opener.GetInfo(super_partition, &device_info)) {
|
||||
builder->UpdateBlockDeviceInfo(device_info);
|
||||
}
|
||||
return builder;
|
||||
}
|
||||
|
||||
std::unique_ptr<MetadataBuilder> MetadataBuilder::New(const std::string& super_partition,
|
||||
uint32_t slot_number) {
|
||||
return New(PartitionOpener(), super_partition, slot_number);
|
||||
}
|
||||
|
||||
std::unique_ptr<MetadataBuilder> MetadataBuilder::New(const BlockDeviceInfo& device_info,
|
||||
uint32_t metadata_max_size,
|
||||
uint32_t metadata_slot_count) {
|
||||
|
|
|
@ -424,13 +424,10 @@ TEST(liblp, block_device_info) {
|
|||
fs_mgr_free_fstab);
|
||||
ASSERT_NE(fstab, nullptr);
|
||||
|
||||
// This should read from the "super" partition once we have a well-defined
|
||||
// way to access it.
|
||||
struct fstab_rec* rec = fs_mgr_get_entry_for_mount_point(fstab.get(), "/data");
|
||||
ASSERT_NE(rec, nullptr);
|
||||
PartitionOpener opener;
|
||||
|
||||
BlockDeviceInfo device_info;
|
||||
ASSERT_TRUE(GetBlockDeviceInfo(rec->blk_device, &device_info));
|
||||
ASSERT_TRUE(opener.GetInfo(fs_mgr_get_super_partition_name(), &device_info));
|
||||
|
||||
// Sanity check that the device doesn't give us some weird inefficient
|
||||
// alignment.
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include <memory>
|
||||
|
||||
#include "liblp.h"
|
||||
#include "partition_opener.h"
|
||||
|
||||
namespace android {
|
||||
namespace fs_mgr {
|
||||
|
@ -34,27 +35,6 @@ class LinearExtent;
|
|||
static const uint32_t kDefaultPartitionAlignment = 1024 * 1024;
|
||||
static const uint32_t kDefaultBlockSize = 4096;
|
||||
|
||||
struct BlockDeviceInfo {
|
||||
BlockDeviceInfo() : size(0), alignment(0), alignment_offset(0), logical_block_size(0) {}
|
||||
BlockDeviceInfo(uint64_t size, uint32_t alignment, uint32_t alignment_offset,
|
||||
uint32_t logical_block_size)
|
||||
: size(size),
|
||||
alignment(alignment),
|
||||
alignment_offset(alignment_offset),
|
||||
logical_block_size(logical_block_size) {}
|
||||
// Size of the block device, in bytes.
|
||||
uint64_t size;
|
||||
// Optimal target alignment, in bytes. Partition extents will be aligned to
|
||||
// this value by default. This value must be 0 or a multiple of 512.
|
||||
uint32_t alignment;
|
||||
// Alignment offset to parent device (if any), in bytes. The sector at
|
||||
// |alignment_offset| on the target device is correctly aligned on its
|
||||
// parent device. This value must be 0 or a multiple of 512.
|
||||
uint32_t alignment_offset;
|
||||
// Block size, for aligning extent sizes and partition sizes.
|
||||
uint32_t logical_block_size;
|
||||
};
|
||||
|
||||
// Abstraction around dm-targets that can be encoded into logical partition tables.
|
||||
class Extent {
|
||||
public:
|
||||
|
@ -157,7 +137,12 @@ class MetadataBuilder {
|
|||
// Import an existing table for modification. This reads metadata off the
|
||||
// given block device and imports it. It also adjusts alignment information
|
||||
// based on run-time values in the operating system.
|
||||
static std::unique_ptr<MetadataBuilder> New(const std::string& block_device,
|
||||
static std::unique_ptr<MetadataBuilder> New(const IPartitionOpener& opener,
|
||||
const std::string& super_partition,
|
||||
uint32_t slot_number);
|
||||
|
||||
// Same as above, but use the default PartitionOpener.
|
||||
static std::unique_ptr<MetadataBuilder> New(const std::string& super_partition,
|
||||
uint32_t slot_number);
|
||||
|
||||
// Import an existing table for modification. If the table is not valid, for
|
||||
|
|
|
@ -24,7 +24,10 @@
|
|||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include <android-base/unique_fd.h>
|
||||
|
||||
#include "metadata_format.h"
|
||||
#include "partition_opener.h"
|
||||
|
||||
namespace android {
|
||||
namespace fs_mgr {
|
||||
|
@ -44,7 +47,8 @@ struct LpMetadata {
|
|||
// existing geometry, and should not be used for normal partition table
|
||||
// updates. False can be returned if the geometry is incompatible with the
|
||||
// block device or an I/O error occurs.
|
||||
bool FlashPartitionTable(const std::string& block_device, const LpMetadata& metadata);
|
||||
bool FlashPartitionTable(const IPartitionOpener& opener, const std::string& super_partition,
|
||||
const LpMetadata& metadata);
|
||||
|
||||
// Update the partition table for a given metadata slot number. False is
|
||||
// returned if an error occurs, which can include:
|
||||
|
@ -52,12 +56,19 @@ bool FlashPartitionTable(const std::string& block_device, const LpMetadata& meta
|
|||
// - I/O error.
|
||||
// - Corrupt or missing metadata geometry on disk.
|
||||
// - Incompatible geometry.
|
||||
bool UpdatePartitionTable(const std::string& block_device, const LpMetadata& metadata,
|
||||
uint32_t slot_number);
|
||||
bool UpdatePartitionTable(const IPartitionOpener& opener, const std::string& super_partition,
|
||||
const LpMetadata& metadata, uint32_t slot_number);
|
||||
|
||||
// Read logical partition metadata from its predetermined location on a block
|
||||
// device. If readback fails, we also attempt to load from a backup copy.
|
||||
std::unique_ptr<LpMetadata> ReadMetadata(const char* block_device, uint32_t slot_number);
|
||||
std::unique_ptr<LpMetadata> ReadMetadata(const IPartitionOpener& opener,
|
||||
const std::string& super_partition, uint32_t slot_number);
|
||||
|
||||
// Helper functions that use the default PartitionOpener.
|
||||
bool FlashPartitionTable(const std::string& super_partition, const LpMetadata& metadata);
|
||||
bool UpdatePartitionTable(const std::string& super_partition, const LpMetadata& metadata,
|
||||
uint32_t slot_number);
|
||||
std::unique_ptr<LpMetadata> ReadMetadata(const std::string& super_partition, uint32_t slot_number);
|
||||
|
||||
// Read/Write logical partition metadata to an image file, for diagnostics or
|
||||
// flashing.
|
||||
|
|
|
@ -0,0 +1,73 @@
|
|||
//
|
||||
// Copyright (C) 2018 The Android Open Source Project
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
#include <android-base/unique_fd.h>
|
||||
|
||||
namespace android {
|
||||
namespace fs_mgr {
|
||||
|
||||
struct BlockDeviceInfo {
|
||||
BlockDeviceInfo() : size(0), alignment(0), alignment_offset(0), logical_block_size(0) {}
|
||||
BlockDeviceInfo(uint64_t size, uint32_t alignment, uint32_t alignment_offset,
|
||||
uint32_t logical_block_size)
|
||||
: size(size),
|
||||
alignment(alignment),
|
||||
alignment_offset(alignment_offset),
|
||||
logical_block_size(logical_block_size) {}
|
||||
// Size of the block device, in bytes.
|
||||
uint64_t size;
|
||||
// Optimal target alignment, in bytes. Partition extents will be aligned to
|
||||
// this value by default. This value must be 0 or a multiple of 512.
|
||||
uint32_t alignment;
|
||||
// Alignment offset to parent device (if any), in bytes. The sector at
|
||||
// |alignment_offset| on the target device is correctly aligned on its
|
||||
// parent device. This value must be 0 or a multiple of 512.
|
||||
uint32_t alignment_offset;
|
||||
// Block size, for aligning extent sizes and partition sizes.
|
||||
uint32_t logical_block_size;
|
||||
};
|
||||
|
||||
// Test-friendly interface for interacting with partitions.
|
||||
class IPartitionOpener {
|
||||
public:
|
||||
virtual ~IPartitionOpener() = default;
|
||||
|
||||
// Open the given named physical partition with the provided open() flags.
|
||||
// The name can be an absolute path if the full path is already known.
|
||||
virtual android::base::unique_fd Open(const std::string& partition_name, int flags) const = 0;
|
||||
|
||||
// Return block device information about the given named physical partition.
|
||||
// The name can be an absolute path if the full path is already known.
|
||||
virtual bool GetInfo(const std::string& partition_name, BlockDeviceInfo* info) const = 0;
|
||||
};
|
||||
|
||||
// Helper class to implement IPartitionOpener. If |partition_name| is not an
|
||||
// absolute path, /dev/block/by-name/ will be prepended.
|
||||
class PartitionOpener : public IPartitionOpener {
|
||||
public:
|
||||
virtual android::base::unique_fd Open(const std::string& partition_name,
|
||||
int flags) const override;
|
||||
virtual bool GetInfo(const std::string& partition_name, BlockDeviceInfo* info) const override;
|
||||
};
|
||||
|
||||
} // namespace fs_mgr
|
||||
} // namespace android
|
|
@ -26,6 +26,7 @@
|
|||
|
||||
#include "images.h"
|
||||
#include "reader.h"
|
||||
#include "test_partition_opener.h"
|
||||
#include "utility.h"
|
||||
#include "writer.h"
|
||||
|
||||
|
@ -101,7 +102,9 @@ static unique_fd CreateFlashedDisk() {
|
|||
if (!exported) {
|
||||
return {};
|
||||
}
|
||||
if (!FlashPartitionTable(fd, *exported.get())) {
|
||||
|
||||
TestPartitionOpener opener({{"super", fd}});
|
||||
if (!FlashPartitionTable(opener, "super", *exported.get())) {
|
||||
return {};
|
||||
}
|
||||
return fd;
|
||||
|
@ -116,8 +119,10 @@ TEST(liblp, CreateFakeDisk) {
|
|||
ASSERT_TRUE(GetDescriptorSize(fd, &size));
|
||||
ASSERT_EQ(size, kDiskSize);
|
||||
|
||||
TestPartitionOpener opener({{"super", fd}});
|
||||
|
||||
// Verify that we can't read unwritten metadata.
|
||||
ASSERT_EQ(ReadMetadata(fd, 1), nullptr);
|
||||
ASSERT_EQ(ReadMetadata(opener, "super", 1), nullptr);
|
||||
}
|
||||
|
||||
// Flashing metadata should not work if the metadata was created for a larger
|
||||
|
@ -133,7 +138,9 @@ TEST(liblp, ExportDiskTooSmall) {
|
|||
unique_fd fd = CreateFakeDisk();
|
||||
ASSERT_GE(fd, 0);
|
||||
|
||||
EXPECT_FALSE(FlashPartitionTable(fd, *exported.get()));
|
||||
TestPartitionOpener opener({{"super", fd}});
|
||||
|
||||
EXPECT_FALSE(FlashPartitionTable(opener, "super", *exported.get()));
|
||||
}
|
||||
|
||||
// Test the basics of flashing a partition and reading it back.
|
||||
|
@ -145,16 +152,18 @@ TEST(liblp, FlashAndReadback) {
|
|||
unique_fd fd = CreateFakeDisk();
|
||||
ASSERT_GE(fd, 0);
|
||||
|
||||
TestPartitionOpener opener({{"super", fd}});
|
||||
|
||||
// Export and flash.
|
||||
unique_ptr<LpMetadata> exported = builder->Export();
|
||||
ASSERT_NE(exported, nullptr);
|
||||
ASSERT_TRUE(FlashPartitionTable(fd, *exported.get()));
|
||||
ASSERT_TRUE(FlashPartitionTable(opener, "super", *exported.get()));
|
||||
|
||||
// Read back. Note that some fields are only filled in during
|
||||
// serialization, so exported and imported will not be identical. For
|
||||
// example, table sizes and checksums are computed in WritePartitionTable.
|
||||
// Therefore we check on a field-by-field basis.
|
||||
unique_ptr<LpMetadata> imported = ReadMetadata(fd, 0);
|
||||
unique_ptr<LpMetadata> imported = ReadMetadata(opener, "super", 0);
|
||||
ASSERT_NE(imported, nullptr);
|
||||
|
||||
// Check geometry and header.
|
||||
|
@ -189,23 +198,25 @@ TEST(liblp, UpdateAnyMetadataSlot) {
|
|||
unique_fd fd = CreateFlashedDisk();
|
||||
ASSERT_GE(fd, 0);
|
||||
|
||||
unique_ptr<LpMetadata> imported = ReadMetadata(fd, 0);
|
||||
TestPartitionOpener opener({{"super", fd}});
|
||||
|
||||
unique_ptr<LpMetadata> imported = ReadMetadata(opener, "super", 0);
|
||||
ASSERT_NE(imported, nullptr);
|
||||
ASSERT_EQ(imported->partitions.size(), 1);
|
||||
EXPECT_EQ(GetPartitionName(imported->partitions[0]), "system");
|
||||
|
||||
// Change the name before writing to the next slot.
|
||||
strncpy(imported->partitions[0].name, "vendor", sizeof(imported->partitions[0].name));
|
||||
ASSERT_TRUE(UpdatePartitionTable(fd, *imported.get(), 1));
|
||||
ASSERT_TRUE(UpdatePartitionTable(opener, "super", *imported.get(), 1));
|
||||
|
||||
// Read back the original slot, make sure it hasn't changed.
|
||||
imported = ReadMetadata(fd, 0);
|
||||
imported = ReadMetadata(opener, "super", 0);
|
||||
ASSERT_NE(imported, nullptr);
|
||||
ASSERT_EQ(imported->partitions.size(), 1);
|
||||
EXPECT_EQ(GetPartitionName(imported->partitions[0]), "system");
|
||||
|
||||
// Now read back the new slot, and verify that it has a different name.
|
||||
imported = ReadMetadata(fd, 1);
|
||||
imported = ReadMetadata(opener, "super", 1);
|
||||
ASSERT_NE(imported, nullptr);
|
||||
ASSERT_EQ(imported->partitions.size(), 1);
|
||||
EXPECT_EQ(GetPartitionName(imported->partitions[0]), "vendor");
|
||||
|
@ -232,15 +243,17 @@ TEST(liblp, InvalidMetadataSlot) {
|
|||
unique_fd fd = CreateFlashedDisk();
|
||||
ASSERT_GE(fd, 0);
|
||||
|
||||
TestPartitionOpener opener({{"super", fd}});
|
||||
|
||||
// Make sure all slots are filled.
|
||||
unique_ptr<LpMetadata> metadata = ReadMetadata(fd, 0);
|
||||
unique_ptr<LpMetadata> metadata = ReadMetadata(opener, "super", 0);
|
||||
ASSERT_NE(metadata, nullptr);
|
||||
for (uint32_t i = 1; i < kMetadataSlots; i++) {
|
||||
ASSERT_TRUE(UpdatePartitionTable(fd, *metadata.get(), i));
|
||||
ASSERT_TRUE(UpdatePartitionTable(opener, "super", *metadata.get(), i));
|
||||
}
|
||||
|
||||
// Verify that we can't read unavailable slots.
|
||||
EXPECT_EQ(ReadMetadata(fd, kMetadataSlots), nullptr);
|
||||
EXPECT_EQ(ReadMetadata(opener, "super", kMetadataSlots), nullptr);
|
||||
}
|
||||
|
||||
// Test that updating a metadata slot does not allow it to be computed based
|
||||
|
@ -249,25 +262,27 @@ TEST(liblp, NoChangingGeometry) {
|
|||
unique_fd fd = CreateFlashedDisk();
|
||||
ASSERT_GE(fd, 0);
|
||||
|
||||
unique_ptr<LpMetadata> imported = ReadMetadata(fd, 0);
|
||||
TestPartitionOpener opener({{"super", fd}});
|
||||
|
||||
unique_ptr<LpMetadata> imported = ReadMetadata(opener, "super", 0);
|
||||
ASSERT_NE(imported, nullptr);
|
||||
ASSERT_TRUE(UpdatePartitionTable(fd, *imported.get(), 1));
|
||||
ASSERT_TRUE(UpdatePartitionTable(opener, "super", *imported.get(), 1));
|
||||
|
||||
imported->geometry.metadata_max_size += LP_SECTOR_SIZE;
|
||||
ASSERT_FALSE(UpdatePartitionTable(fd, *imported.get(), 1));
|
||||
ASSERT_FALSE(UpdatePartitionTable(opener, "super", *imported.get(), 1));
|
||||
|
||||
imported = ReadMetadata(fd, 0);
|
||||
imported = ReadMetadata(opener, "super", 0);
|
||||
ASSERT_NE(imported, nullptr);
|
||||
imported->geometry.metadata_slot_count++;
|
||||
ASSERT_FALSE(UpdatePartitionTable(fd, *imported.get(), 1));
|
||||
ASSERT_FALSE(UpdatePartitionTable(opener, "super", *imported.get(), 1));
|
||||
|
||||
imported = ReadMetadata(fd, 0);
|
||||
imported = ReadMetadata(opener, "super", 0);
|
||||
ASSERT_NE(imported, nullptr);
|
||||
ASSERT_EQ(imported->block_devices.size(), 1);
|
||||
imported->block_devices[0].first_logical_sector++;
|
||||
ASSERT_FALSE(UpdatePartitionTable(fd, *imported.get(), 1));
|
||||
ASSERT_FALSE(UpdatePartitionTable(opener, "super", *imported.get(), 1));
|
||||
|
||||
imported = ReadMetadata(fd, 0);
|
||||
imported = ReadMetadata(opener, "super", 0);
|
||||
ASSERT_NE(imported, nullptr);
|
||||
}
|
||||
|
||||
|
@ -276,6 +291,8 @@ TEST(liblp, BitFlipGeometry) {
|
|||
unique_fd fd = CreateFlashedDisk();
|
||||
ASSERT_GE(fd, 0);
|
||||
|
||||
TestPartitionOpener opener({{"super", fd}});
|
||||
|
||||
LpMetadataGeometry geometry;
|
||||
ASSERT_GE(lseek(fd, 0, SEEK_SET), 0);
|
||||
ASSERT_TRUE(android::base::ReadFully(fd, &geometry, sizeof(geometry)));
|
||||
|
@ -284,7 +301,7 @@ TEST(liblp, BitFlipGeometry) {
|
|||
bad_geometry.metadata_slot_count++;
|
||||
ASSERT_TRUE(android::base::WriteFully(fd, &bad_geometry, sizeof(bad_geometry)));
|
||||
|
||||
unique_ptr<LpMetadata> metadata = ReadMetadata(fd, 0);
|
||||
unique_ptr<LpMetadata> metadata = ReadMetadata(opener, "super", 0);
|
||||
ASSERT_NE(metadata, nullptr);
|
||||
EXPECT_EQ(metadata->geometry.metadata_slot_count, 2);
|
||||
}
|
||||
|
@ -293,25 +310,29 @@ TEST(liblp, ReadBackupGeometry) {
|
|||
unique_fd fd = CreateFlashedDisk();
|
||||
ASSERT_GE(fd, 0);
|
||||
|
||||
TestPartitionOpener opener({{"super", fd}});
|
||||
|
||||
char corruption[LP_METADATA_GEOMETRY_SIZE];
|
||||
memset(corruption, 0xff, sizeof(corruption));
|
||||
|
||||
// Corrupt the primary geometry.
|
||||
ASSERT_GE(lseek(fd, GetPrimaryGeometryOffset(), SEEK_SET), 0);
|
||||
ASSERT_TRUE(android::base::WriteFully(fd, corruption, sizeof(corruption)));
|
||||
EXPECT_NE(ReadMetadata(fd, 0), nullptr);
|
||||
EXPECT_NE(ReadMetadata(opener, "super", 0), nullptr);
|
||||
|
||||
// Corrupt the backup geometry.
|
||||
ASSERT_GE(lseek(fd, GetBackupGeometryOffset(), SEEK_SET), 0);
|
||||
ASSERT_TRUE(android::base::WriteFully(fd, corruption, sizeof(corruption)));
|
||||
EXPECT_EQ(ReadMetadata(fd, 0), nullptr);
|
||||
EXPECT_EQ(ReadMetadata(opener, "super", 0), nullptr);
|
||||
}
|
||||
|
||||
TEST(liblp, ReadBackupMetadata) {
|
||||
unique_fd fd = CreateFlashedDisk();
|
||||
ASSERT_GE(fd, 0);
|
||||
|
||||
unique_ptr<LpMetadata> metadata = ReadMetadata(fd, 0);
|
||||
TestPartitionOpener opener({{"super", fd}});
|
||||
|
||||
unique_ptr<LpMetadata> metadata = ReadMetadata(opener, "super", 0);
|
||||
|
||||
char corruption[kMetadataSize];
|
||||
memset(corruption, 0xff, sizeof(corruption));
|
||||
|
@ -320,14 +341,14 @@ TEST(liblp, ReadBackupMetadata) {
|
|||
|
||||
ASSERT_GE(lseek(fd, offset, SEEK_SET), 0);
|
||||
ASSERT_TRUE(android::base::WriteFully(fd, corruption, sizeof(corruption)));
|
||||
EXPECT_NE(ReadMetadata(fd, 0), nullptr);
|
||||
EXPECT_NE(ReadMetadata(opener, "super", 0), nullptr);
|
||||
|
||||
offset = GetBackupMetadataOffset(metadata->geometry, 0);
|
||||
|
||||
// Corrupt the backup metadata.
|
||||
ASSERT_GE(lseek(fd, offset, SEEK_SET), 0);
|
||||
ASSERT_TRUE(android::base::WriteFully(fd, corruption, sizeof(corruption)));
|
||||
EXPECT_EQ(ReadMetadata(fd, 0), nullptr);
|
||||
EXPECT_EQ(ReadMetadata(opener, "super", 0), nullptr);
|
||||
}
|
||||
|
||||
// Test that we don't attempt to write metadata if it would overflow its
|
||||
|
@ -357,8 +378,10 @@ TEST(liblp, TooManyPartitions) {
|
|||
unique_fd fd = CreateFakeDisk();
|
||||
ASSERT_GE(fd, 0);
|
||||
|
||||
TestPartitionOpener opener({{"super", fd}});
|
||||
|
||||
// Check that we are able to write our table.
|
||||
ASSERT_TRUE(FlashPartitionTable(fd, *exported.get()));
|
||||
ASSERT_TRUE(FlashPartitionTable(opener, "super", *exported.get()));
|
||||
|
||||
// Check that adding one more partition overflows the metadata allotment.
|
||||
partition = builder->AddPartition("final", LP_PARTITION_ATTR_NONE);
|
||||
|
@ -368,7 +391,7 @@ TEST(liblp, TooManyPartitions) {
|
|||
ASSERT_NE(exported, nullptr);
|
||||
|
||||
// The new table should be too large to be written.
|
||||
ASSERT_FALSE(UpdatePartitionTable(fd, *exported.get(), 1));
|
||||
ASSERT_FALSE(UpdatePartitionTable(opener, "super", *exported.get(), 1));
|
||||
|
||||
auto super_device = GetMetadataSuperBlockDevice(*exported.get());
|
||||
ASSERT_NE(super_device, nullptr);
|
||||
|
@ -464,23 +487,25 @@ TEST(liblp, UpdatePrimaryMetadataFailure) {
|
|||
unique_fd fd = CreateFlashedDisk();
|
||||
ASSERT_GE(fd, 0);
|
||||
|
||||
TestPartitionOpener opener({{"super", fd}});
|
||||
|
||||
BadWriter writer;
|
||||
|
||||
// Read and write it back.
|
||||
writer.FailOnWrite(1);
|
||||
unique_ptr<LpMetadata> imported = ReadMetadata(fd, 0);
|
||||
unique_ptr<LpMetadata> imported = ReadMetadata(opener, "super", 0);
|
||||
ASSERT_NE(imported, nullptr);
|
||||
ASSERT_FALSE(UpdatePartitionTable(fd, *imported.get(), 0, writer));
|
||||
ASSERT_FALSE(UpdatePartitionTable(opener, "super", *imported.get(), 0, writer));
|
||||
|
||||
// We should still be able to read the backup copy.
|
||||
imported = ReadMetadata(fd, 0);
|
||||
imported = ReadMetadata(opener, "super", 0);
|
||||
ASSERT_NE(imported, nullptr);
|
||||
|
||||
// Flash again, this time fail the backup copy. We should still be able
|
||||
// to read the primary.
|
||||
writer.FailOnWrite(3);
|
||||
ASSERT_FALSE(UpdatePartitionTable(fd, *imported.get(), 0, writer));
|
||||
imported = ReadMetadata(fd, 0);
|
||||
ASSERT_FALSE(UpdatePartitionTable(opener, "super", *imported.get(), 0, writer));
|
||||
imported = ReadMetadata(opener, "super", 0);
|
||||
ASSERT_NE(imported, nullptr);
|
||||
}
|
||||
|
||||
|
@ -490,23 +515,25 @@ TEST(liblp, UpdateBackupMetadataFailure) {
|
|||
unique_fd fd = CreateFlashedDisk();
|
||||
ASSERT_GE(fd, 0);
|
||||
|
||||
TestPartitionOpener opener({{"super", fd}});
|
||||
|
||||
BadWriter writer;
|
||||
|
||||
// Read and write it back.
|
||||
writer.FailOnWrite(2);
|
||||
unique_ptr<LpMetadata> imported = ReadMetadata(fd, 0);
|
||||
unique_ptr<LpMetadata> imported = ReadMetadata(opener, "super", 0);
|
||||
ASSERT_NE(imported, nullptr);
|
||||
ASSERT_FALSE(UpdatePartitionTable(fd, *imported.get(), 0, writer));
|
||||
ASSERT_FALSE(UpdatePartitionTable(opener, "super", *imported.get(), 0, writer));
|
||||
|
||||
// We should still be able to read the primary copy.
|
||||
imported = ReadMetadata(fd, 0);
|
||||
imported = ReadMetadata(opener, "super", 0);
|
||||
ASSERT_NE(imported, nullptr);
|
||||
|
||||
// Flash again, this time fail the primary copy. We should still be able
|
||||
// to read the primary.
|
||||
writer.FailOnWrite(2);
|
||||
ASSERT_FALSE(UpdatePartitionTable(fd, *imported.get(), 0, writer));
|
||||
imported = ReadMetadata(fd, 0);
|
||||
ASSERT_FALSE(UpdatePartitionTable(opener, "super", *imported.get(), 0, writer));
|
||||
imported = ReadMetadata(opener, "super", 0);
|
||||
ASSERT_NE(imported, nullptr);
|
||||
}
|
||||
|
||||
|
@ -517,20 +544,22 @@ TEST(liblp, UpdateMetadataCleanFailure) {
|
|||
unique_fd fd = CreateFlashedDisk();
|
||||
ASSERT_GE(fd, 0);
|
||||
|
||||
TestPartitionOpener opener({{"super", fd}});
|
||||
|
||||
BadWriter writer;
|
||||
|
||||
// Change the name of the existing partition.
|
||||
unique_ptr<LpMetadata> new_table = ReadMetadata(fd, 0);
|
||||
unique_ptr<LpMetadata> new_table = ReadMetadata(opener, "super", 0);
|
||||
ASSERT_NE(new_table, nullptr);
|
||||
ASSERT_GE(new_table->partitions.size(), 1);
|
||||
new_table->partitions[0].name[0]++;
|
||||
|
||||
// Flash it, but fail to write the backup copy.
|
||||
writer.FailAfterWrite(2);
|
||||
ASSERT_FALSE(UpdatePartitionTable(fd, *new_table.get(), 0, writer));
|
||||
ASSERT_FALSE(UpdatePartitionTable(opener, "super", *new_table.get(), 0, writer));
|
||||
|
||||
// When we read back, we should get the updated primary copy.
|
||||
unique_ptr<LpMetadata> imported = ReadMetadata(fd, 0);
|
||||
unique_ptr<LpMetadata> imported = ReadMetadata(opener, "super", 0);
|
||||
ASSERT_NE(imported, nullptr);
|
||||
ASSERT_GE(new_table->partitions.size(), 1);
|
||||
ASSERT_EQ(GetPartitionName(new_table->partitions[0]), GetPartitionName(imported->partitions[0]));
|
||||
|
@ -539,9 +568,9 @@ TEST(liblp, UpdateMetadataCleanFailure) {
|
|||
// Note that the sync step should have used the primary to sync, not
|
||||
// the backup.
|
||||
writer.Reset();
|
||||
ASSERT_TRUE(UpdatePartitionTable(fd, *new_table.get(), 0, writer));
|
||||
ASSERT_TRUE(UpdatePartitionTable(opener, "super", *new_table.get(), 0, writer));
|
||||
|
||||
imported = ReadMetadata(fd, 0);
|
||||
imported = ReadMetadata(opener, "super", 0);
|
||||
ASSERT_NE(imported, nullptr);
|
||||
ASSERT_GE(new_table->partitions.size(), 1);
|
||||
ASSERT_EQ(GetPartitionName(new_table->partitions[0]), GetPartitionName(imported->partitions[0]));
|
||||
|
|
|
@ -0,0 +1,93 @@
|
|||
/*
|
||||
* Copyright (C) 2018 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "liblp/partition_opener.h"
|
||||
|
||||
#if defined(__linux__)
|
||||
#include <linux/fs.h>
|
||||
#endif
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "utility.h"
|
||||
|
||||
namespace android {
|
||||
namespace fs_mgr {
|
||||
|
||||
using android::base::unique_fd;
|
||||
|
||||
namespace {
|
||||
|
||||
std::string GetPartitionAbsolutePath(const std::string& path) {
|
||||
if (path[0] == '/') {
|
||||
return path;
|
||||
}
|
||||
return "/dev/block/by-name/" + path;
|
||||
}
|
||||
|
||||
bool GetBlockDeviceInfo(const std::string& block_device, BlockDeviceInfo* device_info) {
|
||||
#if defined(__linux__)
|
||||
unique_fd fd(open(block_device.c_str(), O_RDONLY));
|
||||
if (fd < 0) {
|
||||
PERROR << __PRETTY_FUNCTION__ << "open '" << block_device << "' failed";
|
||||
return false;
|
||||
}
|
||||
if (!GetDescriptorSize(fd, &device_info->size)) {
|
||||
return false;
|
||||
}
|
||||
if (ioctl(fd, BLKIOMIN, &device_info->alignment) < 0) {
|
||||
PERROR << __PRETTY_FUNCTION__ << "BLKIOMIN failed";
|
||||
return false;
|
||||
}
|
||||
|
||||
int alignment_offset;
|
||||
if (ioctl(fd, BLKALIGNOFF, &alignment_offset) < 0) {
|
||||
PERROR << __PRETTY_FUNCTION__ << "BLKIOMIN failed";
|
||||
return false;
|
||||
}
|
||||
int logical_block_size;
|
||||
if (ioctl(fd, BLKSSZGET, &logical_block_size) < 0) {
|
||||
PERROR << __PRETTY_FUNCTION__ << "BLKSSZGET failed";
|
||||
return false;
|
||||
}
|
||||
|
||||
device_info->alignment_offset = static_cast<uint32_t>(alignment_offset);
|
||||
device_info->logical_block_size = static_cast<uint32_t>(logical_block_size);
|
||||
return true;
|
||||
#else
|
||||
(void)block_device;
|
||||
(void)device_info;
|
||||
LERROR << __PRETTY_FUNCTION__ << ": Not supported on this operating system.";
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
unique_fd PartitionOpener::Open(const std::string& partition_name, int flags) const {
|
||||
std::string path = GetPartitionAbsolutePath(partition_name);
|
||||
return unique_fd{open(path.c_str(), flags)};
|
||||
}
|
||||
|
||||
bool PartitionOpener::GetInfo(const std::string& partition_name, BlockDeviceInfo* info) const {
|
||||
std::string path = GetPartitionAbsolutePath(partition_name);
|
||||
return GetBlockDeviceInfo(path, info);
|
||||
}
|
||||
|
||||
} // namespace fs_mgr
|
||||
} // namespace android
|
|
@ -342,7 +342,14 @@ std::unique_ptr<LpMetadata> ReadBackupMetadata(int fd, const LpMetadataGeometry&
|
|||
return ParseMetadata(geometry, fd);
|
||||
}
|
||||
|
||||
std::unique_ptr<LpMetadata> ReadMetadata(int fd, uint32_t slot_number) {
|
||||
std::unique_ptr<LpMetadata> ReadMetadata(const IPartitionOpener& opener,
|
||||
const std::string& super_partition, uint32_t slot_number) {
|
||||
android::base::unique_fd fd = opener.Open(super_partition, O_RDONLY);
|
||||
if (fd < 0) {
|
||||
PERROR << __PRETTY_FUNCTION__ << " open failed: " << super_partition;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
LpMetadataGeometry geometry;
|
||||
if (!ReadLogicalPartitionGeometry(fd, &geometry)) {
|
||||
return nullptr;
|
||||
|
@ -361,13 +368,8 @@ std::unique_ptr<LpMetadata> ReadMetadata(int fd, uint32_t slot_number) {
|
|||
return ReadBackupMetadata(fd, geometry, slot_number);
|
||||
}
|
||||
|
||||
std::unique_ptr<LpMetadata> ReadMetadata(const char* block_device, uint32_t slot_number) {
|
||||
android::base::unique_fd fd(open(block_device, O_RDONLY));
|
||||
if (fd < 0) {
|
||||
PERROR << __PRETTY_FUNCTION__ << " open failed: " << block_device;
|
||||
return nullptr;
|
||||
}
|
||||
return ReadMetadata(fd, slot_number);
|
||||
std::unique_ptr<LpMetadata> ReadMetadata(const std::string& super_partition, uint32_t slot_number) {
|
||||
return ReadMetadata(PartitionOpener(), super_partition, slot_number);
|
||||
}
|
||||
|
||||
static std::string NameFromFixedArray(const char* name, size_t buffer_size) {
|
||||
|
|
|
@ -31,7 +31,6 @@ namespace fs_mgr {
|
|||
bool ParseGeometry(const void* buffer, LpMetadataGeometry* geometry);
|
||||
|
||||
// Helper functions for manually reading geometry and metadata.
|
||||
std::unique_ptr<LpMetadata> ReadMetadata(int fd, uint32_t slot_number);
|
||||
std::unique_ptr<LpMetadata> ParseMetadata(const LpMetadataGeometry& geometry, int fd);
|
||||
std::unique_ptr<LpMetadata> ParseMetadata(const LpMetadataGeometry& geometry, const void* buffer,
|
||||
size_t size);
|
||||
|
|
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
* Copyright (C) 2018 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "test_partition_opener.h"
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
namespace android {
|
||||
namespace fs_mgr {
|
||||
|
||||
using android::base::unique_fd;
|
||||
|
||||
TestPartitionOpener::TestPartitionOpener(
|
||||
const std::map<std::string, int>& partition_map,
|
||||
const std::map<std::string, BlockDeviceInfo>& partition_info)
|
||||
: partition_map_(partition_map), partition_info_(partition_info) {}
|
||||
|
||||
unique_fd TestPartitionOpener::Open(const std::string& partition_name, int flags) const {
|
||||
auto iter = partition_map_.find(partition_name);
|
||||
if (iter == partition_map_.end()) {
|
||||
errno = ENOENT;
|
||||
return {};
|
||||
}
|
||||
return unique_fd{dup(iter->second)};
|
||||
}
|
||||
|
||||
bool TestPartitionOpener::GetInfo(const std::string& partition_name, BlockDeviceInfo* info) const {
|
||||
auto iter = partition_info_.find(partition_name);
|
||||
if (iter == partition_info_.end()) {
|
||||
errno = ENOENT;
|
||||
return false;
|
||||
}
|
||||
*info = iter->second;
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace fs_mgr
|
||||
} // namespace android
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* Copyright (C) 2018 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
#include <android-base/unique_fd.h>
|
||||
#include <liblp/partition_opener.h>
|
||||
|
||||
namespace android {
|
||||
namespace fs_mgr {
|
||||
|
||||
class TestPartitionOpener : public PartitionOpener {
|
||||
public:
|
||||
explicit TestPartitionOpener(const std::map<std::string, int>& partition_map,
|
||||
const std::map<std::string, BlockDeviceInfo>& partition_info = {});
|
||||
|
||||
android::base::unique_fd Open(const std::string& partition_name, int flags) const override;
|
||||
bool GetInfo(const std::string& partition_name, BlockDeviceInfo* info) const override;
|
||||
|
||||
private:
|
||||
std::map<std::string, int> partition_map_;
|
||||
std::map<std::string, BlockDeviceInfo> partition_info_;
|
||||
};
|
||||
|
||||
} // namespace fs_mgr
|
||||
} // namespace android
|
|
@ -16,7 +16,6 @@
|
|||
|
||||
#include <fcntl.h>
|
||||
#include <stdint.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
|
|
|
@ -218,7 +218,14 @@ static bool DefaultWriter(int fd, const std::string& blob) {
|
|||
return android::base::WriteFully(fd, blob.data(), blob.size());
|
||||
}
|
||||
|
||||
bool FlashPartitionTable(int fd, const LpMetadata& metadata) {
|
||||
bool FlashPartitionTable(const IPartitionOpener& opener, const std::string& super_partition,
|
||||
const LpMetadata& metadata) {
|
||||
android::base::unique_fd fd = opener.Open(super_partition, O_RDWR | O_SYNC);
|
||||
if (fd < 0) {
|
||||
PERROR << __PRETTY_FUNCTION__ << " open failed: " << super_partition;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Before writing geometry and/or logical partition tables, perform some
|
||||
// basic checks that the geometry and tables are coherent, and will fit
|
||||
// on the given block device.
|
||||
|
@ -238,6 +245,8 @@ bool FlashPartitionTable(int fd, const LpMetadata& metadata) {
|
|||
return false;
|
||||
}
|
||||
|
||||
LWARN << "Flashing new logical partition geometry to " << super_partition;
|
||||
|
||||
// Write geometry to the primary and backup locations.
|
||||
std::string blob = SerializeGeometry(metadata.geometry);
|
||||
if (SeekFile64(fd, GetPrimaryGeometryOffset(), SEEK_SET) < 0) {
|
||||
|
@ -264,13 +273,24 @@ bool FlashPartitionTable(int fd, const LpMetadata& metadata) {
|
|||
return ok;
|
||||
}
|
||||
|
||||
bool FlashPartitionTable(const std::string& super_partition, const LpMetadata& metadata) {
|
||||
return FlashPartitionTable(PartitionOpener(), super_partition, metadata);
|
||||
}
|
||||
|
||||
static bool CompareMetadata(const LpMetadata& a, const LpMetadata& b) {
|
||||
return !memcmp(a.header.header_checksum, b.header.header_checksum,
|
||||
sizeof(a.header.header_checksum));
|
||||
}
|
||||
|
||||
bool UpdatePartitionTable(int fd, const LpMetadata& metadata, uint32_t slot_number,
|
||||
bool UpdatePartitionTable(const IPartitionOpener& opener, const std::string& super_partition,
|
||||
const LpMetadata& metadata, uint32_t slot_number,
|
||||
const std::function<bool(int, const std::string&)>& writer) {
|
||||
android::base::unique_fd fd = opener.Open(super_partition, O_RDWR | O_SYNC);
|
||||
if (fd < 0) {
|
||||
PERROR << __PRETTY_FUNCTION__ << " open failed: " << super_partition;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Before writing geometry and/or logical partition tables, perform some
|
||||
// basic checks that the geometry and tables are coherent, and will fit
|
||||
// on the given block device.
|
||||
|
@ -330,39 +350,24 @@ bool UpdatePartitionTable(int fd, const LpMetadata& metadata, uint32_t slot_numb
|
|||
}
|
||||
|
||||
// Both copies should now be in sync, so we can continue the update.
|
||||
return WriteMetadata(fd, metadata, slot_number, blob, writer);
|
||||
}
|
||||
if (!WriteMetadata(fd, metadata, slot_number, blob, writer)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool FlashPartitionTable(const std::string& block_device, const LpMetadata& metadata) {
|
||||
android::base::unique_fd fd(open(block_device.c_str(), O_RDWR | O_SYNC));
|
||||
if (fd < 0) {
|
||||
PERROR << __PRETTY_FUNCTION__ << " open failed: " << block_device;
|
||||
return false;
|
||||
}
|
||||
if (!FlashPartitionTable(fd, metadata)) {
|
||||
return false;
|
||||
}
|
||||
LWARN << "Flashed new logical partition geometry to " << block_device;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool UpdatePartitionTable(const std::string& block_device, const LpMetadata& metadata,
|
||||
uint32_t slot_number) {
|
||||
android::base::unique_fd fd(open(block_device.c_str(), O_RDWR | O_SYNC));
|
||||
if (fd < 0) {
|
||||
PERROR << __PRETTY_FUNCTION__ << " open failed: " << block_device;
|
||||
return false;
|
||||
}
|
||||
if (!UpdatePartitionTable(fd, metadata, slot_number)) {
|
||||
return false;
|
||||
}
|
||||
LINFO << "Updated logical partition table at slot " << slot_number << " on device "
|
||||
<< block_device;
|
||||
<< super_partition;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool UpdatePartitionTable(int fd, const LpMetadata& metadata, uint32_t slot_number) {
|
||||
return UpdatePartitionTable(fd, metadata, slot_number, DefaultWriter);
|
||||
bool UpdatePartitionTable(const IPartitionOpener& opener, const std::string& super_partition,
|
||||
const LpMetadata& metadata, uint32_t slot_number) {
|
||||
return UpdatePartitionTable(opener, super_partition, metadata, slot_number, DefaultWriter);
|
||||
}
|
||||
|
||||
bool UpdatePartitionTable(const std::string& super_partition, const LpMetadata& metadata,
|
||||
uint32_t slot_number) {
|
||||
PartitionOpener opener;
|
||||
return UpdatePartitionTable(opener, super_partition, metadata, slot_number, DefaultWriter);
|
||||
}
|
||||
|
||||
} // namespace fs_mgr
|
||||
|
|
|
@ -30,10 +30,8 @@ std::string SerializeMetadata(const LpMetadata& input);
|
|||
|
||||
// These variants are for testing only. The path-based functions should be used
|
||||
// for actual operation, so that open() is called with the correct flags.
|
||||
bool FlashPartitionTable(int fd, const LpMetadata& metadata);
|
||||
bool UpdatePartitionTable(int fd, const LpMetadata& metadata, uint32_t slot_number);
|
||||
|
||||
bool UpdatePartitionTable(int fd, const LpMetadata& metadata, uint32_t slot_number,
|
||||
bool UpdatePartitionTable(const IPartitionOpener& opener, const std::string& super_partition,
|
||||
const LpMetadata& metadata, uint32_t slot_number,
|
||||
const std::function<bool(int, const std::string&)>& writer);
|
||||
|
||||
} // namespace fs_mgr
|
||||
|
|
Loading…
Reference in New Issue