liblp: Add unit tests for flashing and readback.

These tests check that various aspects of liblp's on-disk management
are functioning as intended. This checks redundancy, metadata slot
management, and metadata update and readback.

Bug: 79173901
Test: liblp_test gtest
Change-Id: Ib780676e0f34f44aa255e8fcfded2ceb71fe3dce
This commit is contained in:
David Anderson 2018-06-18 17:54:58 -07:00
parent e9619eb6d1
commit 0a186a834e
7 changed files with 482 additions and 41 deletions

View File

@ -55,6 +55,7 @@ cc_test {
],
srcs: [
"builder_test.cpp",
"io_test.cpp",
"utility_test.cpp",
],
}

View File

@ -306,3 +306,21 @@ TEST(liblp, ExportInvalidGuid) {
unique_ptr<LpMetadata> exported = builder->Export();
EXPECT_EQ(exported, nullptr);
}
TEST(liblp, MetadataTooLarge) {
static const size_t kDiskSize = 128 * 1024;
static const size_t kMetadataSize = 64 * 1024;
// No space to store metadata + geometry.
unique_ptr<MetadataBuilder> builder = MetadataBuilder::New(kDiskSize, kMetadataSize, 1);
EXPECT_EQ(builder, nullptr);
// No space to store metadata + geometry + one free sector.
builder = MetadataBuilder::New(kDiskSize + LP_METADATA_GEOMETRY_SIZE * 2, kMetadataSize, 1);
EXPECT_EQ(builder, nullptr);
// Space for metadata + geometry + one free sector.
builder = MetadataBuilder::New(kDiskSize + LP_METADATA_GEOMETRY_SIZE * 2 + LP_SECTOR_SIZE,
kMetadataSize, 1);
EXPECT_NE(builder, nullptr);
}

View File

@ -29,13 +29,16 @@ namespace fs_mgr {
// 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(int fd, uint32_t slot_number);
// Read and validate the logical partition geometry from a block device.
bool ReadLogicalPartitionGeometry(const char* block_device, LpMetadataGeometry* geometry);
bool ReadLogicalPartitionGeometry(int fd, LpMetadataGeometry* geometry);
// Read logical partition metadata from an image file that was created with
// WriteToImageFile().
std::unique_ptr<LpMetadata> ReadFromImageFile(const char* file);
std::unique_ptr<LpMetadata> ReadFromImageFile(int fd);
} // namespace fs_mgr
} // namespace android

View File

@ -42,10 +42,13 @@ enum class SyncMode {
// The slot number indicates which metadata slot to use.
bool WritePartitionTable(const char* block_device, const LpMetadata& metadata, SyncMode sync_mode,
uint32_t slot_number);
bool WritePartitionTable(int fd, const LpMetadata& metadata, SyncMode sync_mode,
uint32_t slot_number);
// Helper function to serialize geometry and metadata to a normal file, for
// flashing or debugging.
bool WriteToImageFile(const char* file, const LpMetadata& metadata);
bool WriteToImageFile(int fd, const LpMetadata& metadata);
} // namespace fs_mgr
} // namespace android

395
fs_mgr/liblp/io_test.cpp Normal file
View File

@ -0,0 +1,395 @@
/*
* 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 <fcntl.h>
#include <linux/memfd.h>
#include <stdio.h>
#include <sys/syscall.h>
#include <android-base/file.h>
#include <android-base/unique_fd.h>
#include <gtest/gtest.h>
#include <liblp/builder.h>
#include <liblp/reader.h>
#include <liblp/writer.h>
#include "utility.h"
using namespace std;
using namespace android::fs_mgr;
using unique_fd = android::base::unique_fd;
// Our tests assume a 128KiB disk with two 512 byte metadata slots.
static const size_t kDiskSize = 131072;
static const size_t kMetadataSize = 512;
static const size_t kMetadataSlots = 2;
static const char* TEST_GUID_BASE = "A799D1D6-669F-41D8-A3F0-EBB7572D830";
static const char* TEST_GUID = "A799D1D6-669F-41D8-A3F0-EBB7572D8302";
// Helper function for creating an in-memory file descriptor. This lets us
// simulate read/writing logical partition metadata as if we had a block device
// for a physical partition.
static unique_fd CreateFakeDisk(off_t size) {
unique_fd fd(syscall(__NR_memfd_create, "fake_disk", MFD_ALLOW_SEALING));
if (fd < 0) {
perror("memfd_create");
return {};
}
if (ftruncate(fd, size) < 0) {
perror("ftruncate");
return {};
}
// Prevent anything from accidentally growing/shrinking the file, as it
// would not be allowed on an actual partition.
if (fcntl(fd, F_ADD_SEALS, F_SEAL_GROW | F_SEAL_SHRINK) < 0) {
perror("fcntl");
return {};
}
// Write garbage to the "disk" so we can tell what has been zeroed or not.
unique_ptr<uint8_t[]> buffer = make_unique<uint8_t[]>(size);
memset(buffer.get(), 0xcc, size);
if (!android::base::WriteFully(fd, buffer.get(), size)) {
return {};
}
return fd;
}
// Create a disk of the default size.
static unique_fd CreateFakeDisk() {
return CreateFakeDisk(kDiskSize);
}
// Create a MetadataBuilder around some default sizes.
static unique_ptr<MetadataBuilder> CreateDefaultBuilder() {
unique_ptr<MetadataBuilder> builder =
MetadataBuilder::New(kDiskSize, kMetadataSize, kMetadataSlots);
return builder;
}
static bool AddDefaultPartitions(MetadataBuilder* builder) {
Partition* system = builder->AddPartition("system", TEST_GUID, LP_PARTITION_ATTR_NONE);
if (!system) {
return false;
}
return builder->GrowPartition(system, 24 * 1024);
}
// Create a temporary disk and flash it with the default partition setup.
static unique_fd CreateFlashedDisk() {
unique_ptr<MetadataBuilder> builder = CreateDefaultBuilder();
if (!builder || !AddDefaultPartitions(builder.get())) {
return {};
}
unique_fd fd = CreateFakeDisk();
if (fd < 0) {
return {};
}
// Export and flash.
unique_ptr<LpMetadata> exported = builder->Export();
if (!exported) {
return {};
}
if (!WritePartitionTable(fd, *exported.get(), SyncMode::Flash, 0)) {
return {};
}
return fd;
}
// Test that our CreateFakeDisk() function works.
TEST(liblp, CreateFakeDisk) {
unique_fd fd = CreateFakeDisk();
ASSERT_GE(fd, 0);
uint64_t size;
ASSERT_TRUE(GetDescriptorSize(fd, &size));
ASSERT_EQ(size, kDiskSize);
}
// Flashing metadata should not work if the metadata was created for a larger
// disk than the destination disk.
TEST(liblp, ExportDiskTooSmall) {
unique_ptr<MetadataBuilder> builder = MetadataBuilder::New(kDiskSize + 1024, 512, 2);
ASSERT_NE(builder, nullptr);
unique_ptr<LpMetadata> exported = builder->Export();
ASSERT_NE(exported, nullptr);
// A larger geometry should fail to flash, since there won't be enough
// space to store the logical partition range that was specified.
unique_fd fd = CreateFakeDisk();
ASSERT_GE(fd, 0);
EXPECT_FALSE(WritePartitionTable(fd, *exported.get(), SyncMode::Flash, 0));
}
// Test the basics of flashing a partition and reading it back.
TEST(liblp, FlashAndReadback) {
unique_ptr<MetadataBuilder> builder = CreateDefaultBuilder();
ASSERT_NE(builder, nullptr);
ASSERT_TRUE(AddDefaultPartitions(builder.get()));
unique_fd fd = CreateFakeDisk();
ASSERT_GE(fd, 0);
// Export and flash.
unique_ptr<LpMetadata> exported = builder->Export();
ASSERT_NE(exported, nullptr);
ASSERT_TRUE(WritePartitionTable(fd, *exported.get(), SyncMode::Flash, 0));
// 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);
ASSERT_NE(imported, nullptr);
// Check geometry and header.
EXPECT_EQ(exported->geometry.metadata_max_size, imported->geometry.metadata_max_size);
EXPECT_EQ(exported->geometry.metadata_slot_count, imported->geometry.metadata_slot_count);
EXPECT_EQ(exported->geometry.first_logical_sector, imported->geometry.first_logical_sector);
EXPECT_EQ(exported->geometry.last_logical_sector, imported->geometry.last_logical_sector);
EXPECT_EQ(exported->header.major_version, imported->header.major_version);
EXPECT_EQ(exported->header.minor_version, imported->header.minor_version);
EXPECT_EQ(exported->header.header_size, imported->header.header_size);
// Check partition tables.
ASSERT_EQ(exported->partitions.size(), imported->partitions.size());
EXPECT_EQ(GetPartitionName(exported->partitions[0]), GetPartitionName(imported->partitions[0]));
EXPECT_EQ(GetPartitionGuid(exported->partitions[0]), GetPartitionGuid(imported->partitions[0]));
EXPECT_EQ(exported->partitions[0].attributes, imported->partitions[0].attributes);
EXPECT_EQ(exported->partitions[0].first_extent_index,
imported->partitions[0].first_extent_index);
EXPECT_EQ(exported->partitions[0].num_extents, imported->partitions[0].num_extents);
// Check extent tables.
ASSERT_EQ(exported->extents.size(), imported->extents.size());
EXPECT_EQ(exported->extents[0].num_sectors, imported->extents[0].num_sectors);
EXPECT_EQ(exported->extents[0].target_type, imported->extents[0].target_type);
EXPECT_EQ(exported->extents[0].target_data, imported->extents[0].target_data);
}
// Test that we can update metadata slots without disturbing others.
TEST(liblp, UpdateAnyMetadataSlot) {
unique_fd fd = CreateFlashedDisk();
ASSERT_GE(fd, 0);
unique_ptr<LpMetadata> imported = ReadMetadata(fd, 0);
ASSERT_NE(imported, nullptr);
ASSERT_EQ(imported->partitions.size(), 1);
EXPECT_EQ(GetPartitionName(imported->partitions[0]), "system");
// Verify that we can't read unwritten metadata.
ASSERT_EQ(ReadMetadata(fd, 1), nullptr);
// Change the name before writing to the next slot.
strncpy(imported->partitions[0].name, "vendor", sizeof(imported->partitions[0].name));
ASSERT_TRUE(WritePartitionTable(fd, *imported.get(), SyncMode::Update, 1));
// Read back the original slot, make sure it hasn't changed.
imported = ReadMetadata(fd, 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);
ASSERT_NE(imported, nullptr);
ASSERT_EQ(imported->partitions.size(), 1);
EXPECT_EQ(GetPartitionName(imported->partitions[0]), "vendor");
// Verify that we didn't overwrite anything in the logical paritition area.
// We expect the disk to be filled with 0xcc on creation so we can read
// this back and compare it.
char expected[LP_SECTOR_SIZE];
memset(expected, 0xcc, sizeof(expected));
for (uint64_t i = imported->geometry.first_logical_sector;
i <= imported->geometry.last_logical_sector; i++) {
char buffer[LP_SECTOR_SIZE];
ASSERT_GE(lseek(fd, i * LP_SECTOR_SIZE, SEEK_SET), 0);
ASSERT_TRUE(android::base::ReadFully(fd, buffer, sizeof(buffer)));
ASSERT_EQ(memcmp(expected, buffer, LP_SECTOR_SIZE), 0);
}
}
TEST(liblp, InvalidMetadataSlot) {
unique_fd fd = CreateFlashedDisk();
ASSERT_GE(fd, 0);
// Make sure all slots are filled.
unique_ptr<LpMetadata> metadata = ReadMetadata(fd, 0);
ASSERT_NE(metadata, nullptr);
for (uint32_t i = 1; i < kMetadataSlots; i++) {
ASSERT_TRUE(WritePartitionTable(fd, *metadata.get(), SyncMode::Update, i));
}
// Verify that we can't read unavailable slots.
EXPECT_EQ(ReadMetadata(fd, kMetadataSlots), nullptr);
}
// Test that updating a metadata slot does not allow it to be computed based
// on mismatching geometry.
TEST(liblp, NoChangingGeometry) {
unique_fd fd = CreateFlashedDisk();
ASSERT_GE(fd, 0);
unique_ptr<LpMetadata> imported = ReadMetadata(fd, 0);
ASSERT_NE(imported, nullptr);
ASSERT_TRUE(WritePartitionTable(fd, *imported.get(), SyncMode::Update, 1));
imported->geometry.metadata_max_size += LP_SECTOR_SIZE;
ASSERT_FALSE(WritePartitionTable(fd, *imported.get(), SyncMode::Update, 1));
imported = ReadMetadata(fd, 0);
ASSERT_NE(imported, nullptr);
imported->geometry.metadata_slot_count++;
ASSERT_FALSE(WritePartitionTable(fd, *imported.get(), SyncMode::Update, 1));
imported = ReadMetadata(fd, 0);
ASSERT_NE(imported, nullptr);
imported->geometry.first_logical_sector++;
ASSERT_FALSE(WritePartitionTable(fd, *imported.get(), SyncMode::Update, 1));
imported = ReadMetadata(fd, 0);
ASSERT_NE(imported, nullptr);
imported->geometry.last_logical_sector--;
ASSERT_FALSE(WritePartitionTable(fd, *imported.get(), SyncMode::Update, 1));
}
// Test that changing one bit of metadata is enough to break the checksum.
TEST(liblp, BitFlipGeometry) {
unique_fd fd = CreateFlashedDisk();
ASSERT_GE(fd, 0);
LpMetadataGeometry geometry;
ASSERT_GE(lseek(fd, 0, SEEK_SET), 0);
ASSERT_TRUE(android::base::ReadFully(fd, &geometry, sizeof(geometry)));
LpMetadataGeometry bad_geometry = geometry;
bad_geometry.metadata_slot_count++;
ASSERT_TRUE(android::base::WriteFully(fd, &bad_geometry, sizeof(bad_geometry)));
unique_ptr<LpMetadata> metadata = ReadMetadata(fd, 0);
ASSERT_NE(metadata, nullptr);
EXPECT_EQ(metadata->geometry.metadata_slot_count, 2);
}
TEST(liblp, ReadBackupGeometry) {
unique_fd fd = CreateFlashedDisk();
ASSERT_GE(fd, 0);
char corruption[LP_METADATA_GEOMETRY_SIZE];
memset(corruption, 0xff, sizeof(corruption));
// Corrupt the first 4096 bytes of the disk.
ASSERT_GE(lseek(fd, 0, SEEK_SET), 0);
ASSERT_TRUE(android::base::WriteFully(fd, corruption, sizeof(corruption)));
EXPECT_NE(ReadMetadata(fd, 0), nullptr);
// Corrupt the last 4096 bytes too.
ASSERT_GE(lseek(fd, -LP_METADATA_GEOMETRY_SIZE, SEEK_END), 0);
ASSERT_TRUE(android::base::WriteFully(fd, corruption, sizeof(corruption)));
EXPECT_EQ(ReadMetadata(fd, 0), nullptr);
}
TEST(liblp, ReadBackupMetadata) {
unique_fd fd = CreateFlashedDisk();
ASSERT_GE(fd, 0);
unique_ptr<LpMetadata> metadata = ReadMetadata(fd, 0);
char corruption[kMetadataSize];
memset(corruption, 0xff, sizeof(corruption));
ASSERT_GE(lseek(fd, LP_METADATA_GEOMETRY_SIZE, SEEK_SET), 0);
ASSERT_TRUE(android::base::WriteFully(fd, corruption, sizeof(corruption)));
EXPECT_NE(ReadMetadata(fd, 0), nullptr);
off_t offset = LP_METADATA_GEOMETRY_SIZE + kMetadataSize * 2;
// Corrupt the backup metadata.
ASSERT_GE(lseek(fd, -offset, SEEK_END), 0);
ASSERT_TRUE(android::base::WriteFully(fd, corruption, sizeof(corruption)));
EXPECT_EQ(ReadMetadata(fd, 0), nullptr);
}
// Test that we don't attempt to write metadata if it would overflow its
// reserved space.
TEST(liblp, TooManyPartitions) {
unique_ptr<MetadataBuilder> builder = CreateDefaultBuilder();
ASSERT_NE(builder, nullptr);
// Compute the maximum number of partitions we can fit in 1024 bytes of metadata.
size_t max_partitions = (kMetadataSize - sizeof(LpMetadataHeader)) / sizeof(LpMetadataPartition);
EXPECT_LT(max_partitions, 10);
// Add this number of partitions.
Partition* partition = nullptr;
for (size_t i = 0; i < max_partitions; i++) {
std::string guid = std::string(TEST_GUID) + to_string(i);
partition = builder->AddPartition(to_string(i), TEST_GUID, LP_PARTITION_ATTR_NONE);
ASSERT_NE(partition, nullptr);
}
ASSERT_NE(partition, nullptr);
// Add one extent to any partition to fill up more space - we're at 508
// bytes after this, out of 512.
ASSERT_TRUE(builder->GrowPartition(partition, 1024));
unique_ptr<LpMetadata> exported = builder->Export();
ASSERT_NE(exported, nullptr);
unique_fd fd = CreateFakeDisk();
ASSERT_GE(fd, 0);
// Check that we are able to write our table.
ASSERT_TRUE(WritePartitionTable(fd, *exported.get(), SyncMode::Flash, 0));
ASSERT_TRUE(WritePartitionTable(fd, *exported.get(), SyncMode::Update, 1));
// Check that adding one more partition overflows the metadata allotment.
partition = builder->AddPartition("final", TEST_GUID, LP_PARTITION_ATTR_NONE);
EXPECT_NE(partition, nullptr);
exported = builder->Export();
ASSERT_NE(exported, nullptr);
// The new table should be too large to be written.
ASSERT_FALSE(WritePartitionTable(fd, *exported.get(), SyncMode::Update, 1));
// Check that the first and last logical sectors weren't touched when we
// wrote this almost-full metadata.
char expected[LP_SECTOR_SIZE];
memset(expected, 0xcc, sizeof(expected));
char buffer[LP_SECTOR_SIZE];
ASSERT_GE(lseek(fd, exported->geometry.first_logical_sector * LP_SECTOR_SIZE, SEEK_SET), 0);
ASSERT_TRUE(android::base::ReadFully(fd, buffer, sizeof(buffer)));
EXPECT_EQ(memcmp(expected, buffer, LP_SECTOR_SIZE), 0);
ASSERT_GE(lseek(fd, exported->geometry.last_logical_sector * LP_SECTOR_SIZE, SEEK_SET), 0);
ASSERT_TRUE(android::base::ReadFully(fd, buffer, sizeof(buffer)));
EXPECT_EQ(memcmp(expected, buffer, LP_SECTOR_SIZE), 0);
}
// Test that we can read and write image files.
TEST(liblp, ImageFiles) {
unique_ptr<MetadataBuilder> builder = CreateDefaultBuilder();
ASSERT_NE(builder, nullptr);
ASSERT_TRUE(AddDefaultPartitions(builder.get()));
unique_ptr<LpMetadata> exported = builder->Export();
unique_fd fd(syscall(__NR_memfd_create, "image_file", 0));
ASSERT_GE(fd, 0);
ASSERT_TRUE(WriteToImageFile(fd, *exported.get()));
unique_ptr<LpMetadata> imported = ReadFromImageFile(fd);
ASSERT_NE(imported, nullptr);
}

View File

@ -76,7 +76,7 @@ static bool ParseGeometry(const void* buffer, LpMetadataGeometry* geometry) {
// Read and validate geometry information from a block device that holds
// logical partitions. If the information is corrupted, this will attempt
// to read it from a secondary backup location.
static bool ReadLogicalPartitionGeometry(int fd, LpMetadataGeometry* geometry) {
bool ReadLogicalPartitionGeometry(int fd, LpMetadataGeometry* geometry) {
// Read the first 4096 bytes.
std::unique_ptr<uint8_t[]> buffer = std::make_unique<uint8_t[]>(LP_METADATA_GEOMETRY_SIZE);
if (SeekFile64(fd, 0, SEEK_SET) < 0) {
@ -236,43 +236,51 @@ static std::unique_ptr<LpMetadata> ParseMetadata(int fd) {
return metadata;
}
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;
}
std::unique_ptr<LpMetadata> ReadMetadata(int fd, uint32_t slot_number) {
LpMetadataGeometry geometry;
if (!ReadLogicalPartitionGeometry(fd, &geometry)) {
return nullptr;
}
if (slot_number >= geometry.metadata_slot_count) {
LERROR << __PRETTY_FUNCTION__ << "invalid metadata slot number";
return nullptr;
}
// First try the primary copy.
int64_t offset = GetPrimaryMetadataOffset(geometry, slot_number);
if (SeekFile64(fd, offset, SEEK_SET) < 0) {
PERROR << __PRETTY_FUNCTION__ << "lseek failed: offset " << offset;
return nullptr;
}
if (std::unique_ptr<LpMetadata> metadata = ParseMetadata(fd)) {
return metadata;
std::unique_ptr<LpMetadata> metadata = ParseMetadata(fd);
// If the primary copy failed, try the backup copy.
if (!metadata) {
offset = GetBackupMetadataOffset(geometry, slot_number);
if (SeekFile64(fd, offset, SEEK_END) < 0) {
PERROR << __PRETTY_FUNCTION__ << "lseek failed: offset " << offset;
return nullptr;
}
metadata = ParseMetadata(fd);
}
// Next try the backup copy.
offset = GetBackupMetadataOffset(geometry, slot_number);
if (SeekFile64(fd, offset, SEEK_END) < 0) {
PERROR << __PRETTY_FUNCTION__ << "lseek failed: offset " << offset;
return nullptr;
if (metadata) {
metadata->geometry = geometry;
}
return ParseMetadata(fd);
return metadata;
}
std::unique_ptr<LpMetadata> ReadFromImageFile(const char* file) {
android::base::unique_fd fd(open(file, O_RDONLY));
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: " << file;
PERROR << __PRETTY_FUNCTION__ << "open failed: " << block_device;
return nullptr;
}
return ReadMetadata(fd, slot_number);
}
std::unique_ptr<LpMetadata> ReadFromImageFile(int fd) {
LpMetadataGeometry geometry;
if (!ReadLogicalPartitionGeometry(fd, &geometry)) {
return nullptr;
@ -289,6 +297,15 @@ std::unique_ptr<LpMetadata> ReadFromImageFile(const char* file) {
return metadata;
}
std::unique_ptr<LpMetadata> ReadFromImageFile(const char* file) {
android::base::unique_fd fd(open(file, O_RDONLY));
if (fd < 0) {
PERROR << __PRETTY_FUNCTION__ << "open failed: " << file;
return nullptr;
}
return ReadFromImageFile(fd);
}
static std::string NameFromFixedArray(const char* name, size_t buffer_size) {
// If the end of the buffer has a null character, it's safe to assume the
// buffer is null terminated. Otherwise, we cap the string to the input

View File

@ -124,14 +124,8 @@ static bool ValidateGeometryAndMetadata(const LpMetadata& metadata, uint64_t blo
return true;
}
bool WritePartitionTable(const char* block_device, const LpMetadata& metadata, SyncMode sync_mode,
bool WritePartitionTable(int fd, const LpMetadata& metadata, SyncMode sync_mode,
uint32_t slot_number) {
android::base::unique_fd fd(open(block_device, O_RDWR | O_SYNC));
if (fd < 0) {
PERROR << __PRETTY_FUNCTION__ << "open failed: " << block_device;
return false;
}
uint64_t size;
if (!GetDescriptorSize(fd, &size)) {
return false;
@ -142,7 +136,7 @@ bool WritePartitionTable(const char* block_device, const LpMetadata& metadata, S
// Verify that the old geometry is identical. If it's not, then we've
// based this new metadata on invalid assumptions.
LpMetadataGeometry old_geometry;
if (!ReadLogicalPartitionGeometry(block_device, &old_geometry)) {
if (!ReadLogicalPartitionGeometry(fd, &old_geometry)) {
return false;
}
if (!CompareGeometry(geometry, old_geometry)) {
@ -174,8 +168,7 @@ bool WritePartitionTable(const char* block_device, const LpMetadata& metadata, S
return false;
}
if (!android::base::WriteFully(fd, blob.data(), blob.size())) {
PERROR << __PRETTY_FUNCTION__ << "write " << blob.size()
<< " bytes failed: " << block_device;
PERROR << __PRETTY_FUNCTION__ << "write " << blob.size() << " bytes failed";
return false;
}
if (SeekFile64(fd, -LP_METADATA_GEOMETRY_SIZE, SEEK_END) < 0) {
@ -183,8 +176,7 @@ bool WritePartitionTable(const char* block_device, const LpMetadata& metadata, S
return false;
}
if (!android::base::WriteFully(fd, blob.data(), blob.size())) {
PERROR << __PRETTY_FUNCTION__ << "backup write " << blob.size()
<< " bytes failed: " << block_device;
PERROR << __PRETTY_FUNCTION__ << "backup write " << blob.size() << " bytes failed";
return false;
}
}
@ -196,8 +188,7 @@ bool WritePartitionTable(const char* block_device, const LpMetadata& metadata, S
return false;
}
if (!android::base::WriteFully(fd, blob.data(), blob.size())) {
PERROR << __PRETTY_FUNCTION__ << "write " << blob.size()
<< " bytes failed: " << block_device;
PERROR << __PRETTY_FUNCTION__ << "write " << blob.size() << " bytes failed";
return false;
}
@ -214,31 +205,44 @@ bool WritePartitionTable(const char* block_device, const LpMetadata& metadata, S
return false;
}
if (!android::base::WriteFully(fd, blob.data(), blob.size())) {
PERROR << __PRETTY_FUNCTION__ << "backup write " << blob.size()
<< " bytes failed: " << block_device;
PERROR << __PRETTY_FUNCTION__ << "backup write " << blob.size() << " bytes failed";
return false;
}
return true;
}
bool WriteToImageFile(const char* file, const LpMetadata& input) {
bool WritePartitionTable(const char* block_device, const LpMetadata& metadata, SyncMode sync_mode,
uint32_t slot_number) {
android::base::unique_fd fd(open(block_device, O_RDWR | O_SYNC));
if (fd < 0) {
PERROR << __PRETTY_FUNCTION__ << "open failed: " << block_device;
return false;
}
return WritePartitionTable(fd, metadata, sync_mode, slot_number);
}
bool WriteToImageFile(int fd, const LpMetadata& input) {
std::string geometry = SerializeGeometry(input.geometry);
std::string padding(LP_METADATA_GEOMETRY_SIZE - geometry.size(), '\0');
std::string metadata = SerializeMetadata(input);
std::string everything = geometry + padding + metadata;
android::base::unique_fd fd(open(file, O_CREAT | O_RDWR | O_TRUNC, 0644));
if (fd < 0) {
PERROR << __PRETTY_FUNCTION__ << "open failed: " << file;
return false;
}
if (!android::base::WriteFully(fd, everything.data(), everything.size())) {
PERROR << __PRETTY_FUNCTION__ << "write " << everything.size() << " bytes failed: " << file;
PERROR << __PRETTY_FUNCTION__ << "write " << everything.size() << " bytes failed";
return false;
}
return true;
}
bool WriteToImageFile(const char* file, const LpMetadata& input) {
android::base::unique_fd fd(open(file, O_CREAT | O_RDWR | O_TRUNC, 0644));
if (fd < 0) {
PERROR << __PRETTY_FUNCTION__ << "open failed: " << file;
return false;
}
return WriteToImageFile(fd, input);
}
} // namespace fs_mgr
} // namespace android