liblp: Add an abstraction layer for opening partitions.
This change introduces an IPartitionOpener abstraction. Methods that
interact with live metadata, such as ReadMetadata, UpdatePartitionTable,
and FlashPartitionTable, now require an IPartitionOpener object. Its
purpose is dependency injection: it will make these methods much easier
to test when the super partition spans multiple block devices.
All non-test consumers should be using PartitionOpener, and as such,
some helper methods have been added that automatically create one.
Bug: 116802789
Test: liblp_test gtest
device with super partition boots
Change-Id: I76725a5830ef643c5007c152c00ccaad8085151f
This commit is contained in:
parent
9a5324178e
commit
7a6c511a6d
15 changed files with 413 additions and 162 deletions
|
|
@ -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.
|
||||
|
|
|
|||
73
fs_mgr/liblp/include/liblp/partition_opener.h
Normal file
73
fs_mgr/liblp/include/liblp/partition_opener.h
Normal file
|
|
@ -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]));
|
||||
|
|
|
|||
93
fs_mgr/liblp/partition_opener.cpp
Normal file
93
fs_mgr/liblp/partition_opener.cpp
Normal file
|
|
@ -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);
|
||||
|
|
|
|||
51
fs_mgr/liblp/test_partition_opener.cpp
Normal file
51
fs_mgr/liblp/test_partition_opener.cpp
Normal file
|
|
@ -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
|
||||
42
fs_mgr/liblp/test_partition_opener.h
Normal file
42
fs_mgr/liblp/test_partition_opener.h
Normal file
|
|
@ -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…
Add table
Reference in a new issue