Loading fs_mgr/liblp/include/liblp/writer.h +19 −21 Original line number Diff line number Diff line Loading @@ -22,29 +22,27 @@ namespace android { namespace fs_mgr { // When flashing the initial logical partition layout, we also write geometry // information at the start and end of the big physical partition. This helps // locate metadata and backup metadata in the case of corruption or a failed // update. For normal changes to the metadata, we never modify the geometry. enum class SyncMode { // Write geometry information. Flash, // Normal update of a single slot. Update }; // Write the given partition table to the given block device, writing only // copies according to the given sync mode. // // This will perform some verification, such that the device has enough space // to store the metadata as well as all of its extents. // // The slot number indicates which metadata slot to use. bool WritePartitionTable(const char* block_device, const LpMetadata& metadata, SyncMode sync_mode, // Place an initial partition table on the device. This will overwrite the // 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, uint32_t slot_number); bool WritePartitionTable(int fd, const LpMetadata& metadata, SyncMode sync_mode, // Update the partition table for a given metadata slot number. False is // returned if an error occurs, which can include: // - Invalid slot number. // - 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); // 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, uint32_t slot_number); bool UpdatePartitionTable(int fd, const LpMetadata& metadata, 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); Loading fs_mgr/liblp/io_test.cpp +13 −13 Original line number Diff line number Diff line Loading @@ -102,7 +102,7 @@ static unique_fd CreateFlashedDisk() { if (!exported) { return {}; } if (!WritePartitionTable(fd, *exported.get(), SyncMode::Flash, 0)) { if (!FlashPartitionTable(fd, *exported.get(), 0)) { return {}; } return fd; Loading Loading @@ -131,7 +131,7 @@ TEST(liblp, ExportDiskTooSmall) { unique_fd fd = CreateFakeDisk(); ASSERT_GE(fd, 0); EXPECT_FALSE(WritePartitionTable(fd, *exported.get(), SyncMode::Flash, 0)); EXPECT_FALSE(FlashPartitionTable(fd, *exported.get(), 0)); } // Test the basics of flashing a partition and reading it back. Loading @@ -146,7 +146,7 @@ TEST(liblp, FlashAndReadback) { // Export and flash. unique_ptr<LpMetadata> exported = builder->Export(); ASSERT_NE(exported, nullptr); ASSERT_TRUE(WritePartitionTable(fd, *exported.get(), SyncMode::Flash, 0)); ASSERT_TRUE(FlashPartitionTable(fd, *exported.get(), 0)); // Read back. Note that some fields are only filled in during // serialization, so exported and imported will not be identical. For Loading Loading @@ -195,7 +195,7 @@ TEST(liblp, UpdateAnyMetadataSlot) { // 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)); ASSERT_TRUE(UpdatePartitionTable(fd, *imported.get(), 1)); // Read back the original slot, make sure it hasn't changed. imported = ReadMetadata(fd, 0); Loading Loading @@ -231,7 +231,7 @@ TEST(liblp, InvalidMetadataSlot) { 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)); ASSERT_TRUE(UpdatePartitionTable(fd, *metadata.get(), i)); } // Verify that we can't read unavailable slots. Loading @@ -246,25 +246,25 @@ TEST(liblp, NoChangingGeometry) { unique_ptr<LpMetadata> imported = ReadMetadata(fd, 0); ASSERT_NE(imported, nullptr); ASSERT_TRUE(WritePartitionTable(fd, *imported.get(), SyncMode::Update, 1)); ASSERT_TRUE(UpdatePartitionTable(fd, *imported.get(), 1)); imported->geometry.metadata_max_size += LP_SECTOR_SIZE; ASSERT_FALSE(WritePartitionTable(fd, *imported.get(), SyncMode::Update, 1)); ASSERT_FALSE(UpdatePartitionTable(fd, *imported.get(), 1)); imported = ReadMetadata(fd, 0); ASSERT_NE(imported, nullptr); imported->geometry.metadata_slot_count++; ASSERT_FALSE(WritePartitionTable(fd, *imported.get(), SyncMode::Update, 1)); ASSERT_FALSE(UpdatePartitionTable(fd, *imported.get(), 1)); imported = ReadMetadata(fd, 0); ASSERT_NE(imported, nullptr); imported->geometry.first_logical_sector++; ASSERT_FALSE(WritePartitionTable(fd, *imported.get(), SyncMode::Update, 1)); ASSERT_FALSE(UpdatePartitionTable(fd, *imported.get(), 1)); imported = ReadMetadata(fd, 0); ASSERT_NE(imported, nullptr); imported->geometry.last_logical_sector--; ASSERT_FALSE(WritePartitionTable(fd, *imported.get(), SyncMode::Update, 1)); ASSERT_FALSE(UpdatePartitionTable(fd, *imported.get(), 1)); } // Test that changing one bit of metadata is enough to break the checksum. Loading Loading @@ -353,8 +353,8 @@ TEST(liblp, TooManyPartitions) { 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)); ASSERT_TRUE(FlashPartitionTable(fd, *exported.get(), 0)); ASSERT_TRUE(UpdatePartitionTable(fd, *exported.get(), 1)); // Check that adding one more partition overflows the metadata allotment. partition = builder->AddPartition("final", TEST_GUID, LP_PARTITION_ATTR_NONE); Loading @@ -364,7 +364,7 @@ TEST(liblp, TooManyPartitions) { ASSERT_NE(exported, nullptr); // The new table should be too large to be written. ASSERT_FALSE(WritePartitionTable(fd, *exported.get(), SyncMode::Update, 1)); ASSERT_FALSE(UpdatePartitionTable(fd, *exported.get(), 1)); // Check that the first and last logical sectors weren't touched when we // wrote this almost-full metadata. Loading fs_mgr/liblp/writer.cpp +80 −57 Original line number Diff line number Diff line Loading @@ -73,8 +73,14 @@ static std::string SerializeMetadata(const LpMetadata& input) { // Perform sanity checks so we don't accidentally overwrite valid metadata // with potentially invalid metadata, or random partition data with metadata. static bool ValidateGeometryAndMetadata(const LpMetadata& metadata, uint64_t blockdevice_size, uint64_t metadata_size) { static bool ValidateAndSerializeMetadata(int fd, const LpMetadata& metadata, std::string* blob) { uint64_t blockdevice_size; if (!GetDescriptorSize(fd, &blockdevice_size)) { return false; } *blob = SerializeMetadata(metadata); const LpMetadataHeader& header = metadata.header; const LpMetadataGeometry& geometry = metadata.geometry; // Validate the usable sector range. Loading @@ -83,7 +89,7 @@ static bool ValidateGeometryAndMetadata(const LpMetadata& metadata, uint64_t blo return false; } // Make sure we're writing within the space reserved. if (metadata_size > geometry.metadata_max_size) { if (blob->size() > geometry.metadata_max_size) { LERROR << "Logical partition metadata is too large."; return false; } Loading Loading @@ -124,44 +130,54 @@ static bool ValidateGeometryAndMetadata(const LpMetadata& metadata, uint64_t blo return true; } bool WritePartitionTable(int fd, const LpMetadata& metadata, SyncMode sync_mode, uint32_t slot_number) { uint64_t size; if (!GetDescriptorSize(fd, &size)) { static bool WriteMetadata(int fd, const LpMetadataGeometry& geometry, uint32_t slot_number, const std::string& blob) { // Make sure we're writing to a valid metadata slot. if (slot_number >= geometry.metadata_slot_count) { LERROR << "Invalid logical partition metadata slot number."; return false; } const LpMetadataGeometry& geometry = metadata.geometry; if (sync_mode != SyncMode::Flash) { // 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(fd, &old_geometry)) { // Write the primary copy of the metadata. int64_t primary_offset = GetPrimaryMetadataOffset(geometry, slot_number); if (SeekFile64(fd, primary_offset, SEEK_SET) < 0) { PERROR << __PRETTY_FUNCTION__ << "lseek failed: offset " << primary_offset; return false; } if (!CompareGeometry(geometry, old_geometry)) { LERROR << "Incompatible geometry in new logical partition metadata"; if (!android::base::WriteFully(fd, blob.data(), blob.size())) { PERROR << __PRETTY_FUNCTION__ << "write " << blob.size() << " bytes failed"; return false; } } // Make sure we're writing to a valid metadata slot. if (slot_number >= geometry.metadata_slot_count) { LERROR << "Invalid logical partition metadata slot number."; // Write the backup copy of the metadata. int64_t backup_offset = GetBackupMetadataOffset(geometry, slot_number); int64_t abs_offset = SeekFile64(fd, backup_offset, SEEK_END); if (abs_offset == (int64_t)-1) { PERROR << __PRETTY_FUNCTION__ << "lseek failed: offset " << backup_offset; return false; } if (abs_offset < int64_t((geometry.last_logical_sector + 1) * LP_SECTOR_SIZE)) { PERROR << __PRETTY_FUNCTION__ << "backup offset " << abs_offset << " is within logical partition bounds, sector " << geometry.last_logical_sector; return false; } if (!android::base::WriteFully(fd, blob.data(), blob.size())) { PERROR << __PRETTY_FUNCTION__ << "backup write " << blob.size() << " bytes failed"; return false; } return true; } bool FlashPartitionTable(int fd, const LpMetadata& metadata, uint32_t slot_number) { // 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. std::string blob = SerializeMetadata(metadata); if (!ValidateGeometryAndMetadata(metadata, size, blob.size())) { std::string metadata_blob; if (!ValidateAndSerializeMetadata(fd, metadata, &metadata_blob)) { return false; } // First write geometry if this is a flash operation. It gets written to // the first and last 4096-byte regions of the device. if (sync_mode == SyncMode::Flash) { // Write geometry to the first and last 4096 bytes of the device. std::string blob = SerializeGeometry(metadata.geometry); if (SeekFile64(fd, 0, SEEK_SET) < 0) { PERROR << __PRETTY_FUNCTION__ << "lseek failed: offset 0"; Loading @@ -179,46 +195,53 @@ bool WritePartitionTable(int fd, const LpMetadata& metadata, SyncMode sync_mode, PERROR << __PRETTY_FUNCTION__ << "backup write " << blob.size() << " bytes failed"; return false; } } // Write the primary copy of the metadata. int64_t primary_offset = GetPrimaryMetadataOffset(geometry, slot_number); if (SeekFile64(fd, primary_offset, SEEK_SET) < 0) { PERROR << __PRETTY_FUNCTION__ << "lseek failed: offset " << primary_offset; return false; // Write metadata to the correct slot, now that geometry is in place. return WriteMetadata(fd, metadata.geometry, slot_number, metadata_blob); } if (!android::base::WriteFully(fd, blob.data(), blob.size())) { PERROR << __PRETTY_FUNCTION__ << "write " << blob.size() << " bytes failed"; bool UpdatePartitionTable(int fd, const LpMetadata& metadata, uint32_t slot_number) { // 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. std::string blob; if (!ValidateAndSerializeMetadata(fd, metadata, &blob)) { return false; } // Write the backup copy of the metadata. int64_t backup_offset = GetBackupMetadataOffset(geometry, slot_number); int64_t abs_offset = SeekFile64(fd, backup_offset, SEEK_END); if (abs_offset == (int64_t)-1) { PERROR << __PRETTY_FUNCTION__ << "lseek failed: offset " << backup_offset; // Verify that the old geometry is identical. If it's not, then we might be // writing a table that was built for a different device, so we must reject // it. const LpMetadataGeometry& geometry = metadata.geometry; LpMetadataGeometry old_geometry; if (!ReadLogicalPartitionGeometry(fd, &old_geometry)) { return false; } if (abs_offset < int64_t((geometry.last_logical_sector + 1) * LP_SECTOR_SIZE)) { PERROR << __PRETTY_FUNCTION__ << "backup offset " << abs_offset << " is within logical partition bounds, sector " << geometry.last_logical_sector; if (!CompareGeometry(geometry, old_geometry)) { LERROR << "Incompatible geometry in new logical partition metadata"; return false; } if (!android::base::WriteFully(fd, blob.data(), blob.size())) { PERROR << __PRETTY_FUNCTION__ << "backup write " << blob.size() << " bytes failed"; return WriteMetadata(fd, geometry, slot_number, blob); } bool FlashPartitionTable(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; } return true; return FlashPartitionTable(fd, metadata, slot_number); } bool WritePartitionTable(const char* block_device, const LpMetadata& metadata, SyncMode sync_mode, bool UpdatePartitionTable(const std::string& block_device, const LpMetadata& metadata, uint32_t slot_number) { android::base::unique_fd fd(open(block_device, O_RDWR | O_SYNC)); 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; } return WritePartitionTable(fd, metadata, sync_mode, slot_number); return UpdatePartitionTable(fd, metadata, slot_number); } bool WriteToImageFile(int fd, const LpMetadata& input) { Loading Loading
fs_mgr/liblp/include/liblp/writer.h +19 −21 Original line number Diff line number Diff line Loading @@ -22,29 +22,27 @@ namespace android { namespace fs_mgr { // When flashing the initial logical partition layout, we also write geometry // information at the start and end of the big physical partition. This helps // locate metadata and backup metadata in the case of corruption or a failed // update. For normal changes to the metadata, we never modify the geometry. enum class SyncMode { // Write geometry information. Flash, // Normal update of a single slot. Update }; // Write the given partition table to the given block device, writing only // copies according to the given sync mode. // // This will perform some verification, such that the device has enough space // to store the metadata as well as all of its extents. // // The slot number indicates which metadata slot to use. bool WritePartitionTable(const char* block_device, const LpMetadata& metadata, SyncMode sync_mode, // Place an initial partition table on the device. This will overwrite the // 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, uint32_t slot_number); bool WritePartitionTable(int fd, const LpMetadata& metadata, SyncMode sync_mode, // Update the partition table for a given metadata slot number. False is // returned if an error occurs, which can include: // - Invalid slot number. // - 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); // 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, uint32_t slot_number); bool UpdatePartitionTable(int fd, const LpMetadata& metadata, 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); Loading
fs_mgr/liblp/io_test.cpp +13 −13 Original line number Diff line number Diff line Loading @@ -102,7 +102,7 @@ static unique_fd CreateFlashedDisk() { if (!exported) { return {}; } if (!WritePartitionTable(fd, *exported.get(), SyncMode::Flash, 0)) { if (!FlashPartitionTable(fd, *exported.get(), 0)) { return {}; } return fd; Loading Loading @@ -131,7 +131,7 @@ TEST(liblp, ExportDiskTooSmall) { unique_fd fd = CreateFakeDisk(); ASSERT_GE(fd, 0); EXPECT_FALSE(WritePartitionTable(fd, *exported.get(), SyncMode::Flash, 0)); EXPECT_FALSE(FlashPartitionTable(fd, *exported.get(), 0)); } // Test the basics of flashing a partition and reading it back. Loading @@ -146,7 +146,7 @@ TEST(liblp, FlashAndReadback) { // Export and flash. unique_ptr<LpMetadata> exported = builder->Export(); ASSERT_NE(exported, nullptr); ASSERT_TRUE(WritePartitionTable(fd, *exported.get(), SyncMode::Flash, 0)); ASSERT_TRUE(FlashPartitionTable(fd, *exported.get(), 0)); // Read back. Note that some fields are only filled in during // serialization, so exported and imported will not be identical. For Loading Loading @@ -195,7 +195,7 @@ TEST(liblp, UpdateAnyMetadataSlot) { // 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)); ASSERT_TRUE(UpdatePartitionTable(fd, *imported.get(), 1)); // Read back the original slot, make sure it hasn't changed. imported = ReadMetadata(fd, 0); Loading Loading @@ -231,7 +231,7 @@ TEST(liblp, InvalidMetadataSlot) { 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)); ASSERT_TRUE(UpdatePartitionTable(fd, *metadata.get(), i)); } // Verify that we can't read unavailable slots. Loading @@ -246,25 +246,25 @@ TEST(liblp, NoChangingGeometry) { unique_ptr<LpMetadata> imported = ReadMetadata(fd, 0); ASSERT_NE(imported, nullptr); ASSERT_TRUE(WritePartitionTable(fd, *imported.get(), SyncMode::Update, 1)); ASSERT_TRUE(UpdatePartitionTable(fd, *imported.get(), 1)); imported->geometry.metadata_max_size += LP_SECTOR_SIZE; ASSERT_FALSE(WritePartitionTable(fd, *imported.get(), SyncMode::Update, 1)); ASSERT_FALSE(UpdatePartitionTable(fd, *imported.get(), 1)); imported = ReadMetadata(fd, 0); ASSERT_NE(imported, nullptr); imported->geometry.metadata_slot_count++; ASSERT_FALSE(WritePartitionTable(fd, *imported.get(), SyncMode::Update, 1)); ASSERT_FALSE(UpdatePartitionTable(fd, *imported.get(), 1)); imported = ReadMetadata(fd, 0); ASSERT_NE(imported, nullptr); imported->geometry.first_logical_sector++; ASSERT_FALSE(WritePartitionTable(fd, *imported.get(), SyncMode::Update, 1)); ASSERT_FALSE(UpdatePartitionTable(fd, *imported.get(), 1)); imported = ReadMetadata(fd, 0); ASSERT_NE(imported, nullptr); imported->geometry.last_logical_sector--; ASSERT_FALSE(WritePartitionTable(fd, *imported.get(), SyncMode::Update, 1)); ASSERT_FALSE(UpdatePartitionTable(fd, *imported.get(), 1)); } // Test that changing one bit of metadata is enough to break the checksum. Loading Loading @@ -353,8 +353,8 @@ TEST(liblp, TooManyPartitions) { 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)); ASSERT_TRUE(FlashPartitionTable(fd, *exported.get(), 0)); ASSERT_TRUE(UpdatePartitionTable(fd, *exported.get(), 1)); // Check that adding one more partition overflows the metadata allotment. partition = builder->AddPartition("final", TEST_GUID, LP_PARTITION_ATTR_NONE); Loading @@ -364,7 +364,7 @@ TEST(liblp, TooManyPartitions) { ASSERT_NE(exported, nullptr); // The new table should be too large to be written. ASSERT_FALSE(WritePartitionTable(fd, *exported.get(), SyncMode::Update, 1)); ASSERT_FALSE(UpdatePartitionTable(fd, *exported.get(), 1)); // Check that the first and last logical sectors weren't touched when we // wrote this almost-full metadata. Loading
fs_mgr/liblp/writer.cpp +80 −57 Original line number Diff line number Diff line Loading @@ -73,8 +73,14 @@ static std::string SerializeMetadata(const LpMetadata& input) { // Perform sanity checks so we don't accidentally overwrite valid metadata // with potentially invalid metadata, or random partition data with metadata. static bool ValidateGeometryAndMetadata(const LpMetadata& metadata, uint64_t blockdevice_size, uint64_t metadata_size) { static bool ValidateAndSerializeMetadata(int fd, const LpMetadata& metadata, std::string* blob) { uint64_t blockdevice_size; if (!GetDescriptorSize(fd, &blockdevice_size)) { return false; } *blob = SerializeMetadata(metadata); const LpMetadataHeader& header = metadata.header; const LpMetadataGeometry& geometry = metadata.geometry; // Validate the usable sector range. Loading @@ -83,7 +89,7 @@ static bool ValidateGeometryAndMetadata(const LpMetadata& metadata, uint64_t blo return false; } // Make sure we're writing within the space reserved. if (metadata_size > geometry.metadata_max_size) { if (blob->size() > geometry.metadata_max_size) { LERROR << "Logical partition metadata is too large."; return false; } Loading Loading @@ -124,44 +130,54 @@ static bool ValidateGeometryAndMetadata(const LpMetadata& metadata, uint64_t blo return true; } bool WritePartitionTable(int fd, const LpMetadata& metadata, SyncMode sync_mode, uint32_t slot_number) { uint64_t size; if (!GetDescriptorSize(fd, &size)) { static bool WriteMetadata(int fd, const LpMetadataGeometry& geometry, uint32_t slot_number, const std::string& blob) { // Make sure we're writing to a valid metadata slot. if (slot_number >= geometry.metadata_slot_count) { LERROR << "Invalid logical partition metadata slot number."; return false; } const LpMetadataGeometry& geometry = metadata.geometry; if (sync_mode != SyncMode::Flash) { // 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(fd, &old_geometry)) { // Write the primary copy of the metadata. int64_t primary_offset = GetPrimaryMetadataOffset(geometry, slot_number); if (SeekFile64(fd, primary_offset, SEEK_SET) < 0) { PERROR << __PRETTY_FUNCTION__ << "lseek failed: offset " << primary_offset; return false; } if (!CompareGeometry(geometry, old_geometry)) { LERROR << "Incompatible geometry in new logical partition metadata"; if (!android::base::WriteFully(fd, blob.data(), blob.size())) { PERROR << __PRETTY_FUNCTION__ << "write " << blob.size() << " bytes failed"; return false; } } // Make sure we're writing to a valid metadata slot. if (slot_number >= geometry.metadata_slot_count) { LERROR << "Invalid logical partition metadata slot number."; // Write the backup copy of the metadata. int64_t backup_offset = GetBackupMetadataOffset(geometry, slot_number); int64_t abs_offset = SeekFile64(fd, backup_offset, SEEK_END); if (abs_offset == (int64_t)-1) { PERROR << __PRETTY_FUNCTION__ << "lseek failed: offset " << backup_offset; return false; } if (abs_offset < int64_t((geometry.last_logical_sector + 1) * LP_SECTOR_SIZE)) { PERROR << __PRETTY_FUNCTION__ << "backup offset " << abs_offset << " is within logical partition bounds, sector " << geometry.last_logical_sector; return false; } if (!android::base::WriteFully(fd, blob.data(), blob.size())) { PERROR << __PRETTY_FUNCTION__ << "backup write " << blob.size() << " bytes failed"; return false; } return true; } bool FlashPartitionTable(int fd, const LpMetadata& metadata, uint32_t slot_number) { // 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. std::string blob = SerializeMetadata(metadata); if (!ValidateGeometryAndMetadata(metadata, size, blob.size())) { std::string metadata_blob; if (!ValidateAndSerializeMetadata(fd, metadata, &metadata_blob)) { return false; } // First write geometry if this is a flash operation. It gets written to // the first and last 4096-byte regions of the device. if (sync_mode == SyncMode::Flash) { // Write geometry to the first and last 4096 bytes of the device. std::string blob = SerializeGeometry(metadata.geometry); if (SeekFile64(fd, 0, SEEK_SET) < 0) { PERROR << __PRETTY_FUNCTION__ << "lseek failed: offset 0"; Loading @@ -179,46 +195,53 @@ bool WritePartitionTable(int fd, const LpMetadata& metadata, SyncMode sync_mode, PERROR << __PRETTY_FUNCTION__ << "backup write " << blob.size() << " bytes failed"; return false; } } // Write the primary copy of the metadata. int64_t primary_offset = GetPrimaryMetadataOffset(geometry, slot_number); if (SeekFile64(fd, primary_offset, SEEK_SET) < 0) { PERROR << __PRETTY_FUNCTION__ << "lseek failed: offset " << primary_offset; return false; // Write metadata to the correct slot, now that geometry is in place. return WriteMetadata(fd, metadata.geometry, slot_number, metadata_blob); } if (!android::base::WriteFully(fd, blob.data(), blob.size())) { PERROR << __PRETTY_FUNCTION__ << "write " << blob.size() << " bytes failed"; bool UpdatePartitionTable(int fd, const LpMetadata& metadata, uint32_t slot_number) { // 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. std::string blob; if (!ValidateAndSerializeMetadata(fd, metadata, &blob)) { return false; } // Write the backup copy of the metadata. int64_t backup_offset = GetBackupMetadataOffset(geometry, slot_number); int64_t abs_offset = SeekFile64(fd, backup_offset, SEEK_END); if (abs_offset == (int64_t)-1) { PERROR << __PRETTY_FUNCTION__ << "lseek failed: offset " << backup_offset; // Verify that the old geometry is identical. If it's not, then we might be // writing a table that was built for a different device, so we must reject // it. const LpMetadataGeometry& geometry = metadata.geometry; LpMetadataGeometry old_geometry; if (!ReadLogicalPartitionGeometry(fd, &old_geometry)) { return false; } if (abs_offset < int64_t((geometry.last_logical_sector + 1) * LP_SECTOR_SIZE)) { PERROR << __PRETTY_FUNCTION__ << "backup offset " << abs_offset << " is within logical partition bounds, sector " << geometry.last_logical_sector; if (!CompareGeometry(geometry, old_geometry)) { LERROR << "Incompatible geometry in new logical partition metadata"; return false; } if (!android::base::WriteFully(fd, blob.data(), blob.size())) { PERROR << __PRETTY_FUNCTION__ << "backup write " << blob.size() << " bytes failed"; return WriteMetadata(fd, geometry, slot_number, blob); } bool FlashPartitionTable(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; } return true; return FlashPartitionTable(fd, metadata, slot_number); } bool WritePartitionTable(const char* block_device, const LpMetadata& metadata, SyncMode sync_mode, bool UpdatePartitionTable(const std::string& block_device, const LpMetadata& metadata, uint32_t slot_number) { android::base::unique_fd fd(open(block_device, O_RDWR | O_SYNC)); 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; } return WritePartitionTable(fd, metadata, sync_mode, slot_number); return UpdatePartitionTable(fd, metadata, slot_number); } bool WriteToImageFile(int fd, const LpMetadata& input) { Loading