liblp: Allow packing partition data into super images.
This change allows partition data to be included in the sparse image for the super partition. The data is specified as a map from partition name to partition image file. The image file can either be a normal file or a sparse image. If it is sparse, it is unpacked into a temporary file and then re-packed into the super image. Bug: 79173901 Test: (1) lpmake -S with a partition image flashes to walleye. (2) The image can be mounted if it contains a filesystem. (3) simg2img will successfully unpack the image. Change-Id: I98e9af3bfec9863143c1b95a1712b1d435942542
This commit is contained in:
parent
ce483b6f06
commit
9555f3dcf6
|
@ -82,7 +82,8 @@ bool WriteToImageFile(const char* file, const LpMetadata& input) {
|
|||
// to do this when the data pointers are all in one place.
|
||||
class SparseBuilder {
|
||||
public:
|
||||
SparseBuilder(const LpMetadata& metadata, uint32_t block_size);
|
||||
SparseBuilder(const LpMetadata& metadata, uint32_t block_size,
|
||||
const std::map<std::string, std::string>& images);
|
||||
|
||||
bool Build();
|
||||
bool Export(const char* file);
|
||||
|
@ -90,6 +91,8 @@ class SparseBuilder {
|
|||
|
||||
private:
|
||||
bool AddData(const std::string& blob, uint64_t sector);
|
||||
bool AddPartitionImage(const LpMetadataPartition& partition, const std::string& file);
|
||||
int OpenImageFile(const std::string& file);
|
||||
bool SectorToBlock(uint64_t sector, uint32_t* block);
|
||||
|
||||
const LpMetadata& metadata_;
|
||||
|
@ -98,13 +101,17 @@ class SparseBuilder {
|
|||
std::unique_ptr<sparse_file, decltype(&sparse_file_destroy)> file_;
|
||||
std::string primary_blob_;
|
||||
std::string backup_blob_;
|
||||
std::map<std::string, std::string> images_;
|
||||
std::vector<android::base::unique_fd> temp_fds_;
|
||||
};
|
||||
|
||||
SparseBuilder::SparseBuilder(const LpMetadata& metadata, uint32_t block_size)
|
||||
SparseBuilder::SparseBuilder(const LpMetadata& metadata, uint32_t block_size,
|
||||
const std::map<std::string, std::string>& images)
|
||||
: metadata_(metadata),
|
||||
geometry_(metadata.geometry),
|
||||
block_size_(block_size),
|
||||
file_(sparse_file_new(block_size_, geometry_.block_device_size), sparse_file_destroy) {}
|
||||
file_(sparse_file_new(block_size_, geometry_.block_device_size), sparse_file_destroy),
|
||||
images_(images) {}
|
||||
|
||||
bool SparseBuilder::Export(const char* file) {
|
||||
android::base::unique_fd fd(open(file, O_CREAT | O_RDWR | O_TRUNC, 0644));
|
||||
|
@ -168,6 +175,22 @@ bool SparseBuilder::Build() {
|
|||
return false;
|
||||
}
|
||||
|
||||
for (const auto& partition : metadata_.partitions) {
|
||||
auto iter = images_.find(GetPartitionName(partition));
|
||||
if (iter == images_.end()) {
|
||||
continue;
|
||||
}
|
||||
if (!AddPartitionImage(partition, iter->second)) {
|
||||
return false;
|
||||
}
|
||||
images_.erase(iter);
|
||||
}
|
||||
|
||||
if (!images_.empty()) {
|
||||
LERROR << "Partition image was specified but no partition was found.";
|
||||
return false;
|
||||
}
|
||||
|
||||
// The backup area contains all metadata slots, and then geometry. Similar
|
||||
// to before we write the metadata to every slot.
|
||||
int64_t backup_offset = GetBackupMetadataOffset(geometry_, 0);
|
||||
|
@ -181,7 +204,126 @@ bool SparseBuilder::Build() {
|
|||
return true;
|
||||
}
|
||||
|
||||
bool WriteToSparseFile(const char* file, const LpMetadata& metadata, uint32_t block_size) {
|
||||
static inline bool HasFillValue(uint32_t* buffer, size_t count) {
|
||||
uint32_t fill_value = buffer[0];
|
||||
for (size_t i = 1; i < count; i++) {
|
||||
if (fill_value != buffer[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SparseBuilder::AddPartitionImage(const LpMetadataPartition& partition,
|
||||
const std::string& file) {
|
||||
if (partition.num_extents != 1) {
|
||||
LERROR << "Partition for new tables should not have more than one extent: "
|
||||
<< GetPartitionName(partition);
|
||||
return false;
|
||||
}
|
||||
|
||||
const LpMetadataExtent& extent = metadata_.extents[partition.first_extent_index];
|
||||
if (extent.target_type != LP_TARGET_TYPE_LINEAR) {
|
||||
LERROR << "Partition should only have linear extents: " << GetPartitionName(partition);
|
||||
return false;
|
||||
}
|
||||
|
||||
int fd = OpenImageFile(file);
|
||||
if (fd < 0) {
|
||||
LERROR << "Could not open image for partition: " << GetPartitionName(partition);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Make sure the image does not exceed the partition size.
|
||||
uint64_t file_length;
|
||||
if (!GetDescriptorSize(fd, &file_length)) {
|
||||
LERROR << "Could not compute image size";
|
||||
return false;
|
||||
}
|
||||
if (file_length > extent.num_sectors * LP_SECTOR_SIZE) {
|
||||
LERROR << "Image for partition '" << GetPartitionName(partition)
|
||||
<< "' is greater than its size";
|
||||
return false;
|
||||
}
|
||||
if (SeekFile64(fd, 0, SEEK_SET)) {
|
||||
PERROR << "lseek failed";
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t output_block;
|
||||
if (!SectorToBlock(extent.target_data, &output_block)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint64_t pos = 0;
|
||||
uint64_t remaining = file_length;
|
||||
while (remaining) {
|
||||
uint32_t buffer[block_size_ / sizeof(uint32_t)];
|
||||
size_t read_size = remaining >= sizeof(buffer) ? sizeof(buffer) : size_t(remaining);
|
||||
if (!android::base::ReadFully(fd, buffer, sizeof(buffer))) {
|
||||
PERROR << "read failed";
|
||||
return false;
|
||||
}
|
||||
if (read_size != sizeof(buffer) || !HasFillValue(buffer, read_size / sizeof(uint32_t))) {
|
||||
int rv = sparse_file_add_fd(file_.get(), fd, pos, read_size, output_block);
|
||||
if (rv) {
|
||||
LERROR << "sparse_file_add_fd failed with code: " << rv;
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
int rv = sparse_file_add_fill(file_.get(), buffer[0], read_size, output_block);
|
||||
if (rv) {
|
||||
LERROR << "sparse_file_add_fill failed with code: " << rv;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
pos += read_size;
|
||||
remaining -= read_size;
|
||||
output_block++;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int SparseBuilder::OpenImageFile(const std::string& file) {
|
||||
android::base::unique_fd source_fd(open(file.c_str(), O_RDONLY));
|
||||
if (source_fd < 0) {
|
||||
PERROR << "open image file failed: " << file;
|
||||
return -1;
|
||||
}
|
||||
|
||||
std::unique_ptr<sparse_file, decltype(&sparse_file_destroy)> source(
|
||||
sparse_file_import(source_fd, true, true), sparse_file_destroy);
|
||||
if (!source) {
|
||||
int fd = source_fd.get();
|
||||
temp_fds_.push_back(std::move(source_fd));
|
||||
return fd;
|
||||
}
|
||||
|
||||
char temp_file[PATH_MAX];
|
||||
snprintf(temp_file, sizeof(temp_file), "%s/imageXXXXXX", P_tmpdir);
|
||||
android::base::unique_fd temp_fd(mkstemp(temp_file));
|
||||
if (temp_fd < 0) {
|
||||
PERROR << "mkstemp failed";
|
||||
return -1;
|
||||
}
|
||||
if (unlink(temp_file) < 0) {
|
||||
PERROR << "unlink failed";
|
||||
return -1;
|
||||
}
|
||||
|
||||
// We temporarily unsparse the file, rather than try to merge its chunks.
|
||||
int rv = sparse_file_write(source.get(), temp_fd, false, false, false);
|
||||
if (rv) {
|
||||
LERROR << "sparse_file_write failed with code: " << rv;
|
||||
return -1;
|
||||
}
|
||||
temp_fds_.push_back(std::move(temp_fd));
|
||||
return temp_fds_.back().get();
|
||||
}
|
||||
|
||||
bool WriteToSparseFile(const char* file, const LpMetadata& metadata, uint32_t block_size,
|
||||
const std::map<std::string, std::string>& images) {
|
||||
if (block_size % LP_SECTOR_SIZE != 0) {
|
||||
LERROR << "Block size must be a multiple of the sector size, " << LP_SECTOR_SIZE;
|
||||
return false;
|
||||
|
@ -198,7 +340,7 @@ bool WriteToSparseFile(const char* file, const LpMetadata& metadata, uint32_t bl
|
|||
return false;
|
||||
}
|
||||
|
||||
SparseBuilder builder(metadata, block_size);
|
||||
SparseBuilder builder(metadata, block_size, images);
|
||||
if (!builder.IsValid()) {
|
||||
LERROR << "Could not allocate sparse file of size " << metadata.geometry.block_device_size;
|
||||
return false;
|
||||
|
@ -206,7 +348,6 @@ bool WriteToSparseFile(const char* file, const LpMetadata& metadata, uint32_t bl
|
|||
if (!builder.Build()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return builder.Export(file);
|
||||
}
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
|
@ -59,7 +60,8 @@ std::unique_ptr<LpMetadata> ReadMetadata(const char* block_device, uint32_t slot
|
|||
|
||||
// Read/Write logical partition metadata to an image file, for diagnostics or
|
||||
// flashing.
|
||||
bool WriteToSparseFile(const char* file, const LpMetadata& metadata, uint32_t block_size);
|
||||
bool WriteToSparseFile(const char* file, const LpMetadata& metadata, uint32_t block_size,
|
||||
const std::map<std::string, std::string>& images);
|
||||
bool WriteToImageFile(const char* file, const LpMetadata& metadata);
|
||||
std::unique_ptr<LpMetadata> ReadFromImageFile(const char* file);
|
||||
|
||||
|
|
Loading…
Reference in New Issue