|
|
|
@ -0,0 +1,308 @@
|
|
|
|
|
/*
|
|
|
|
|
* 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 <gtest/gtest.h>
|
|
|
|
|
#include <liblp/builder.h>
|
|
|
|
|
|
|
|
|
|
using namespace std;
|
|
|
|
|
using namespace android::fs_mgr;
|
|
|
|
|
|
|
|
|
|
static const char* TEST_GUID = "A799D1D6-669F-41D8-A3F0-EBB7572D8302";
|
|
|
|
|
static const char* TEST_GUID2 = "A799D1D6-669F-41D8-A3F0-EBB7572D8303";
|
|
|
|
|
|
|
|
|
|
TEST(liblp, BuildBasic) {
|
|
|
|
|
unique_ptr<MetadataBuilder> builder = MetadataBuilder::New(1024 * 1024, 1024, 2);
|
|
|
|
|
|
|
|
|
|
Partition* partition = builder->AddPartition("system", TEST_GUID, LP_PARTITION_ATTR_READONLY);
|
|
|
|
|
ASSERT_NE(partition, nullptr);
|
|
|
|
|
EXPECT_EQ(partition->name(), "system");
|
|
|
|
|
EXPECT_EQ(partition->guid(), TEST_GUID);
|
|
|
|
|
EXPECT_EQ(partition->attributes(), LP_PARTITION_ATTR_READONLY);
|
|
|
|
|
EXPECT_EQ(partition->size(), 0);
|
|
|
|
|
EXPECT_EQ(builder->FindPartition("system"), partition);
|
|
|
|
|
|
|
|
|
|
builder->RemovePartition("system");
|
|
|
|
|
EXPECT_EQ(builder->FindPartition("system"), nullptr);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST(liblp, ResizePartition) {
|
|
|
|
|
unique_ptr<MetadataBuilder> builder = MetadataBuilder::New(1024 * 1024, 1024, 2);
|
|
|
|
|
|
|
|
|
|
Partition* system = builder->AddPartition("system", TEST_GUID, LP_PARTITION_ATTR_READONLY);
|
|
|
|
|
ASSERT_NE(system, nullptr);
|
|
|
|
|
EXPECT_EQ(builder->GrowPartition(system, 65536), true);
|
|
|
|
|
EXPECT_EQ(system->size(), 65536);
|
|
|
|
|
ASSERT_EQ(system->extents().size(), 1);
|
|
|
|
|
|
|
|
|
|
LinearExtent* extent = system->extents()[0]->AsLinearExtent();
|
|
|
|
|
ASSERT_NE(extent, nullptr);
|
|
|
|
|
EXPECT_EQ(extent->num_sectors(), 65536 / LP_SECTOR_SIZE);
|
|
|
|
|
// The first logical sector will be (4096+1024*2)/512 = 12.
|
|
|
|
|
EXPECT_EQ(extent->physical_sector(), 12);
|
|
|
|
|
|
|
|
|
|
// Test growing to the same size.
|
|
|
|
|
EXPECT_EQ(builder->GrowPartition(system, 65536), true);
|
|
|
|
|
EXPECT_EQ(system->size(), 65536);
|
|
|
|
|
EXPECT_EQ(system->extents().size(), 1);
|
|
|
|
|
EXPECT_EQ(system->extents()[0]->num_sectors(), 65536 / LP_SECTOR_SIZE);
|
|
|
|
|
// Test growing to a smaller size.
|
|
|
|
|
EXPECT_EQ(builder->GrowPartition(system, 0), true);
|
|
|
|
|
EXPECT_EQ(system->size(), 65536);
|
|
|
|
|
EXPECT_EQ(system->extents().size(), 1);
|
|
|
|
|
EXPECT_EQ(system->extents()[0]->num_sectors(), 65536 / LP_SECTOR_SIZE);
|
|
|
|
|
// Test shrinking to a greater size.
|
|
|
|
|
builder->ShrinkPartition(system, 131072);
|
|
|
|
|
EXPECT_EQ(system->size(), 65536);
|
|
|
|
|
EXPECT_EQ(system->extents().size(), 1);
|
|
|
|
|
EXPECT_EQ(system->extents()[0]->num_sectors(), 65536 / LP_SECTOR_SIZE);
|
|
|
|
|
|
|
|
|
|
// Test shrinking within the same extent.
|
|
|
|
|
builder->ShrinkPartition(system, 32768);
|
|
|
|
|
EXPECT_EQ(system->size(), 32768);
|
|
|
|
|
EXPECT_EQ(system->extents().size(), 1);
|
|
|
|
|
extent = system->extents()[0]->AsLinearExtent();
|
|
|
|
|
ASSERT_NE(extent, nullptr);
|
|
|
|
|
EXPECT_EQ(extent->num_sectors(), 32768 / LP_SECTOR_SIZE);
|
|
|
|
|
EXPECT_EQ(extent->physical_sector(), 12);
|
|
|
|
|
|
|
|
|
|
// Test shrinking to 0.
|
|
|
|
|
builder->ShrinkPartition(system, 0);
|
|
|
|
|
EXPECT_EQ(system->size(), 0);
|
|
|
|
|
EXPECT_EQ(system->extents().size(), 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST(liblp, PartitionAlignment) {
|
|
|
|
|
unique_ptr<MetadataBuilder> builder = MetadataBuilder::New(1024 * 1024, 1024, 2);
|
|
|
|
|
|
|
|
|
|
// Test that we align up to one sector.
|
|
|
|
|
Partition* system = builder->AddPartition("system", TEST_GUID, LP_PARTITION_ATTR_READONLY);
|
|
|
|
|
ASSERT_NE(system, nullptr);
|
|
|
|
|
EXPECT_EQ(builder->GrowPartition(system, 10000), true);
|
|
|
|
|
EXPECT_EQ(system->size(), 10240);
|
|
|
|
|
EXPECT_EQ(system->extents().size(), 1);
|
|
|
|
|
|
|
|
|
|
builder->ShrinkPartition(system, 9000);
|
|
|
|
|
EXPECT_EQ(system->size(), 9216);
|
|
|
|
|
EXPECT_EQ(system->extents().size(), 1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST(liblp, DiskAlignment) {
|
|
|
|
|
static const uint64_t kDiskSize = 1000000;
|
|
|
|
|
static const uint32_t kMetadataSize = 1024;
|
|
|
|
|
static const uint32_t kMetadataSlots = 2;
|
|
|
|
|
|
|
|
|
|
// If the disk size is not aligned to 512 bytes, make sure it still leaves
|
|
|
|
|
// space at the end for backup metadata, and that it doesn't overlap with
|
|
|
|
|
// the space for logical partitions.
|
|
|
|
|
unique_ptr<MetadataBuilder> builder =
|
|
|
|
|
MetadataBuilder::New(kDiskSize, kMetadataSize, kMetadataSlots);
|
|
|
|
|
unique_ptr<LpMetadata> exported = builder->Export();
|
|
|
|
|
ASSERT_NE(exported, nullptr);
|
|
|
|
|
|
|
|
|
|
static const size_t kMetadataSpace =
|
|
|
|
|
(kMetadataSize * kMetadataSlots) + LP_METADATA_GEOMETRY_SIZE;
|
|
|
|
|
uint64_t space_at_end =
|
|
|
|
|
kDiskSize - (exported->geometry.last_logical_sector + 1) * LP_SECTOR_SIZE;
|
|
|
|
|
EXPECT_GE(space_at_end, kMetadataSpace);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST(liblp, MetadataAlignment) {
|
|
|
|
|
// Make sure metadata sizes get aligned up.
|
|
|
|
|
unique_ptr<MetadataBuilder> builder = MetadataBuilder::New(1024 * 1024, 1000, 2);
|
|
|
|
|
unique_ptr<LpMetadata> exported = builder->Export();
|
|
|
|
|
ASSERT_NE(exported, nullptr);
|
|
|
|
|
EXPECT_EQ(exported->geometry.metadata_max_size, 1024);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST(liblp, UseAllDiskSpace) {
|
|
|
|
|
unique_ptr<MetadataBuilder> builder = MetadataBuilder::New(1024 * 1024, 1024, 2);
|
|
|
|
|
EXPECT_EQ(builder->AllocatableSpace(), 1036288);
|
|
|
|
|
|
|
|
|
|
Partition* system = builder->AddPartition("system", TEST_GUID, LP_PARTITION_ATTR_READONLY);
|
|
|
|
|
ASSERT_NE(system, nullptr);
|
|
|
|
|
EXPECT_EQ(builder->GrowPartition(system, 1036288), true);
|
|
|
|
|
EXPECT_EQ(system->size(), 1036288);
|
|
|
|
|
EXPECT_EQ(builder->GrowPartition(system, 1036289), false);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST(liblp, BuildComplex) {
|
|
|
|
|
unique_ptr<MetadataBuilder> builder = MetadataBuilder::New(1024 * 1024, 1024, 2);
|
|
|
|
|
|
|
|
|
|
Partition* system = builder->AddPartition("system", TEST_GUID, LP_PARTITION_ATTR_READONLY);
|
|
|
|
|
Partition* vendor = builder->AddPartition("vendor", TEST_GUID2, LP_PARTITION_ATTR_READONLY);
|
|
|
|
|
ASSERT_NE(system, nullptr);
|
|
|
|
|
ASSERT_NE(vendor, nullptr);
|
|
|
|
|
EXPECT_EQ(builder->GrowPartition(system, 65536), true);
|
|
|
|
|
EXPECT_EQ(builder->GrowPartition(vendor, 32768), true);
|
|
|
|
|
EXPECT_EQ(builder->GrowPartition(system, 98304), true);
|
|
|
|
|
EXPECT_EQ(system->size(), 98304);
|
|
|
|
|
EXPECT_EQ(vendor->size(), 32768);
|
|
|
|
|
|
|
|
|
|
// We now expect to have 3 extents total: 2 for system, 1 for vendor, since
|
|
|
|
|
// our allocation strategy is greedy/first-fit.
|
|
|
|
|
ASSERT_EQ(system->extents().size(), 2);
|
|
|
|
|
ASSERT_EQ(vendor->extents().size(), 1);
|
|
|
|
|
|
|
|
|
|
LinearExtent* system1 = system->extents()[0]->AsLinearExtent();
|
|
|
|
|
LinearExtent* system2 = system->extents()[1]->AsLinearExtent();
|
|
|
|
|
LinearExtent* vendor1 = vendor->extents()[0]->AsLinearExtent();
|
|
|
|
|
ASSERT_NE(system1, nullptr);
|
|
|
|
|
ASSERT_NE(system2, nullptr);
|
|
|
|
|
ASSERT_NE(vendor1, nullptr);
|
|
|
|
|
EXPECT_EQ(system1->num_sectors(), 65536 / LP_SECTOR_SIZE);
|
|
|
|
|
EXPECT_EQ(system1->physical_sector(), 12);
|
|
|
|
|
EXPECT_EQ(system2->num_sectors(), 32768 / LP_SECTOR_SIZE);
|
|
|
|
|
EXPECT_EQ(system2->physical_sector(), 204);
|
|
|
|
|
EXPECT_EQ(vendor1->num_sectors(), 32768 / LP_SECTOR_SIZE);
|
|
|
|
|
EXPECT_EQ(vendor1->physical_sector(), 140);
|
|
|
|
|
EXPECT_EQ(system1->physical_sector() + system1->num_sectors(), vendor1->physical_sector());
|
|
|
|
|
EXPECT_EQ(vendor1->physical_sector() + vendor1->num_sectors(), system2->physical_sector());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST(liblp, AddInvalidPartition) {
|
|
|
|
|
unique_ptr<MetadataBuilder> builder = MetadataBuilder::New(1024 * 1024, 1024, 2);
|
|
|
|
|
|
|
|
|
|
Partition* partition = builder->AddPartition("system", TEST_GUID, LP_PARTITION_ATTR_READONLY);
|
|
|
|
|
ASSERT_NE(partition, nullptr);
|
|
|
|
|
|
|
|
|
|
// Duplicate name.
|
|
|
|
|
partition = builder->AddPartition("system", TEST_GUID, LP_PARTITION_ATTR_READONLY);
|
|
|
|
|
EXPECT_EQ(partition, nullptr);
|
|
|
|
|
|
|
|
|
|
// Empty name.
|
|
|
|
|
partition = builder->AddPartition("", TEST_GUID, LP_PARTITION_ATTR_READONLY);
|
|
|
|
|
EXPECT_EQ(partition, nullptr);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST(liblp, BuilderExport) {
|
|
|
|
|
static const uint64_t kDiskSize = 1024 * 1024;
|
|
|
|
|
static const uint32_t kMetadataSize = 1024;
|
|
|
|
|
static const uint32_t kMetadataSlots = 2;
|
|
|
|
|
unique_ptr<MetadataBuilder> builder =
|
|
|
|
|
MetadataBuilder::New(kDiskSize, kMetadataSize, kMetadataSlots);
|
|
|
|
|
|
|
|
|
|
Partition* system = builder->AddPartition("system", TEST_GUID, LP_PARTITION_ATTR_READONLY);
|
|
|
|
|
Partition* vendor = builder->AddPartition("vendor", TEST_GUID2, LP_PARTITION_ATTR_READONLY);
|
|
|
|
|
ASSERT_NE(system, nullptr);
|
|
|
|
|
ASSERT_NE(vendor, nullptr);
|
|
|
|
|
EXPECT_EQ(builder->GrowPartition(system, 65536), true);
|
|
|
|
|
EXPECT_EQ(builder->GrowPartition(vendor, 32768), true);
|
|
|
|
|
EXPECT_EQ(builder->GrowPartition(system, 98304), true);
|
|
|
|
|
|
|
|
|
|
unique_ptr<LpMetadata> exported = builder->Export();
|
|
|
|
|
EXPECT_NE(exported, nullptr);
|
|
|
|
|
|
|
|
|
|
// Verify geometry. Some details of this may change if we change the
|
|
|
|
|
// metadata structures. So in addition to checking the exact values, we
|
|
|
|
|
// also check that they are internally consistent after.
|
|
|
|
|
const LpMetadataGeometry& geometry = exported->geometry;
|
|
|
|
|
EXPECT_EQ(geometry.magic, LP_METADATA_GEOMETRY_MAGIC);
|
|
|
|
|
EXPECT_EQ(geometry.struct_size, sizeof(geometry));
|
|
|
|
|
EXPECT_EQ(geometry.metadata_max_size, 1024);
|
|
|
|
|
EXPECT_EQ(geometry.metadata_slot_count, 2);
|
|
|
|
|
EXPECT_EQ(geometry.first_logical_sector, 12);
|
|
|
|
|
EXPECT_EQ(geometry.last_logical_sector, 2035);
|
|
|
|
|
|
|
|
|
|
static const size_t kMetadataSpace =
|
|
|
|
|
(kMetadataSize * kMetadataSlots) + LP_METADATA_GEOMETRY_SIZE;
|
|
|
|
|
uint64_t space_at_end = kDiskSize - (geometry.last_logical_sector + 1) * LP_SECTOR_SIZE;
|
|
|
|
|
EXPECT_GE(space_at_end, kMetadataSpace);
|
|
|
|
|
EXPECT_GE(geometry.first_logical_sector * LP_SECTOR_SIZE, kMetadataSpace);
|
|
|
|
|
|
|
|
|
|
// Verify header.
|
|
|
|
|
const LpMetadataHeader& header = exported->header;
|
|
|
|
|
EXPECT_EQ(header.magic, LP_METADATA_HEADER_MAGIC);
|
|
|
|
|
EXPECT_EQ(header.major_version, LP_METADATA_MAJOR_VERSION);
|
|
|
|
|
EXPECT_EQ(header.minor_version, LP_METADATA_MINOR_VERSION);
|
|
|
|
|
|
|
|
|
|
ASSERT_EQ(exported->partitions.size(), 2);
|
|
|
|
|
ASSERT_EQ(exported->extents.size(), 3);
|
|
|
|
|
|
|
|
|
|
for (const auto& partition : exported->partitions) {
|
|
|
|
|
Partition* original = builder->FindPartition(GetPartitionName(partition));
|
|
|
|
|
ASSERT_NE(original, nullptr);
|
|
|
|
|
EXPECT_EQ(original->guid(), GetPartitionGuid(partition));
|
|
|
|
|
for (size_t i = 0; i < partition.num_extents; i++) {
|
|
|
|
|
const auto& extent = exported->extents[partition.first_extent_index + i];
|
|
|
|
|
LinearExtent* original_extent = original->extents()[i]->AsLinearExtent();
|
|
|
|
|
EXPECT_EQ(extent.num_sectors, original_extent->num_sectors());
|
|
|
|
|
EXPECT_EQ(extent.target_type, LP_TARGET_TYPE_LINEAR);
|
|
|
|
|
EXPECT_EQ(extent.target_data, original_extent->physical_sector());
|
|
|
|
|
}
|
|
|
|
|
EXPECT_EQ(partition.attributes, original->attributes());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST(liblp, BuilderImport) {
|
|
|
|
|
unique_ptr<MetadataBuilder> builder = MetadataBuilder::New(1024 * 1024, 1024, 2);
|
|
|
|
|
|
|
|
|
|
Partition* system = builder->AddPartition("system", TEST_GUID, LP_PARTITION_ATTR_READONLY);
|
|
|
|
|
Partition* vendor = builder->AddPartition("vendor", TEST_GUID2, LP_PARTITION_ATTR_READONLY);
|
|
|
|
|
ASSERT_NE(system, nullptr);
|
|
|
|
|
ASSERT_NE(vendor, nullptr);
|
|
|
|
|
EXPECT_EQ(builder->GrowPartition(system, 65536), true);
|
|
|
|
|
EXPECT_EQ(builder->GrowPartition(vendor, 32768), true);
|
|
|
|
|
EXPECT_EQ(builder->GrowPartition(system, 98304), true);
|
|
|
|
|
|
|
|
|
|
unique_ptr<LpMetadata> exported = builder->Export();
|
|
|
|
|
ASSERT_NE(exported, nullptr);
|
|
|
|
|
|
|
|
|
|
builder = MetadataBuilder::New(*exported.get());
|
|
|
|
|
ASSERT_NE(builder, nullptr);
|
|
|
|
|
system = builder->FindPartition("system");
|
|
|
|
|
ASSERT_NE(system, nullptr);
|
|
|
|
|
vendor = builder->FindPartition("vendor");
|
|
|
|
|
ASSERT_NE(vendor, nullptr);
|
|
|
|
|
|
|
|
|
|
EXPECT_EQ(system->size(), 98304);
|
|
|
|
|
ASSERT_EQ(system->extents().size(), 2);
|
|
|
|
|
EXPECT_EQ(system->guid(), TEST_GUID);
|
|
|
|
|
EXPECT_EQ(system->attributes(), LP_PARTITION_ATTR_READONLY);
|
|
|
|
|
EXPECT_EQ(vendor->size(), 32768);
|
|
|
|
|
ASSERT_EQ(vendor->extents().size(), 1);
|
|
|
|
|
EXPECT_EQ(vendor->guid(), TEST_GUID2);
|
|
|
|
|
EXPECT_EQ(vendor->attributes(), LP_PARTITION_ATTR_READONLY);
|
|
|
|
|
|
|
|
|
|
LinearExtent* system1 = system->extents()[0]->AsLinearExtent();
|
|
|
|
|
LinearExtent* system2 = system->extents()[1]->AsLinearExtent();
|
|
|
|
|
LinearExtent* vendor1 = vendor->extents()[0]->AsLinearExtent();
|
|
|
|
|
EXPECT_EQ(system1->num_sectors(), 65536 / LP_SECTOR_SIZE);
|
|
|
|
|
EXPECT_EQ(system1->physical_sector(), 12);
|
|
|
|
|
EXPECT_EQ(system2->num_sectors(), 32768 / LP_SECTOR_SIZE);
|
|
|
|
|
EXPECT_EQ(system2->physical_sector(), 204);
|
|
|
|
|
EXPECT_EQ(vendor1->num_sectors(), 32768 / LP_SECTOR_SIZE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST(liblp, ExportNameTooLong) {
|
|
|
|
|
unique_ptr<MetadataBuilder> builder = MetadataBuilder::New(1024 * 1024, 1024, 2);
|
|
|
|
|
|
|
|
|
|
std::string name = "abcdefghijklmnopqrstuvwxyz0123456789";
|
|
|
|
|
Partition* system = builder->AddPartition(name + name, TEST_GUID, LP_PARTITION_ATTR_READONLY);
|
|
|
|
|
EXPECT_NE(system, nullptr);
|
|
|
|
|
|
|
|
|
|
unique_ptr<LpMetadata> exported = builder->Export();
|
|
|
|
|
EXPECT_EQ(exported, nullptr);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST(liblp, ExportInvalidGuid) {
|
|
|
|
|
unique_ptr<MetadataBuilder> builder = MetadataBuilder::New(1024 * 1024, 1024, 2);
|
|
|
|
|
|
|
|
|
|
Partition* system = builder->AddPartition("system", "bad", LP_PARTITION_ATTR_READONLY);
|
|
|
|
|
EXPECT_NE(system, nullptr);
|
|
|
|
|
|
|
|
|
|
unique_ptr<LpMetadata> exported = builder->Export();
|
|
|
|
|
EXPECT_EQ(exported, nullptr);
|
|
|
|
|
}
|