Merge "liblp: Add a method to create sparse images of the super partition."
am: 97d3fd8fb0
Change-Id: Ib9ff2dca5d1b4e5c5c714773f111076950996f12
This commit is contained in:
commit
1a2b2c4203
|
@ -34,6 +34,7 @@ cc_library_static {
|
|||
"liblog",
|
||||
"libcrypto",
|
||||
"libcrypto_utils",
|
||||
"libsparse",
|
||||
],
|
||||
whole_static_libs: [
|
||||
"libext2_uuid",
|
||||
|
|
|
@ -16,8 +16,11 @@
|
|||
|
||||
#include "images.h"
|
||||
|
||||
#include <limits.h>
|
||||
|
||||
#include <android-base/file.h>
|
||||
#include <android-base/unique_fd.h>
|
||||
#include <sparse/sparse.h>
|
||||
|
||||
#include "reader.h"
|
||||
#include "utility.h"
|
||||
|
@ -75,5 +78,115 @@ bool WriteToImageFile(const char* file, const LpMetadata& input) {
|
|||
return WriteToImageFile(fd, input);
|
||||
}
|
||||
|
||||
// We use an object to build the sparse file since it requires that data
|
||||
// pointers be held alive until the sparse file is destroyed. It's easier
|
||||
// to do this when the data pointers are all in one place.
|
||||
class SparseBuilder {
|
||||
public:
|
||||
explicit SparseBuilder(const LpMetadata& metadata);
|
||||
|
||||
bool Build();
|
||||
bool Export(const char* file);
|
||||
bool IsValid() const { return file_ != nullptr; }
|
||||
|
||||
private:
|
||||
bool AddData(const std::string& blob, uint32_t block);
|
||||
|
||||
const LpMetadata& metadata_;
|
||||
const LpMetadataGeometry& geometry_;
|
||||
std::unique_ptr<sparse_file, decltype(&sparse_file_destroy)> file_;
|
||||
std::string geometry_blob_;
|
||||
std::string metadata_blob_;
|
||||
};
|
||||
|
||||
SparseBuilder::SparseBuilder(const LpMetadata& metadata)
|
||||
: metadata_(metadata),
|
||||
geometry_(metadata.geometry),
|
||||
file_(sparse_file_new(LP_SECTOR_SIZE, geometry_.block_device_size), sparse_file_destroy) {}
|
||||
|
||||
bool SparseBuilder::Export(const char* file) {
|
||||
android::base::unique_fd fd(open(file, O_CREAT | O_RDWR | O_TRUNC, 0644));
|
||||
if (fd < 0) {
|
||||
PERROR << "open failed: " << file;
|
||||
return false;
|
||||
}
|
||||
// No gzip compression; sparseify; no checksum.
|
||||
int ret = sparse_file_write(file_.get(), fd, false, true, false);
|
||||
if (ret != 0) {
|
||||
LERROR << "sparse_file_write failed (error code " << ret << ")";
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SparseBuilder::AddData(const std::string& blob, uint32_t block) {
|
||||
void* data = const_cast<char*>(blob.data());
|
||||
int ret = sparse_file_add_data(file_.get(), data, blob.size(), block);
|
||||
if (ret != 0) {
|
||||
LERROR << "sparse_file_add_data failed (error code " << ret << ")";
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SparseBuilder::Build() {
|
||||
geometry_blob_ = SerializeGeometry(geometry_);
|
||||
geometry_blob_.resize(LP_METADATA_GEOMETRY_SIZE);
|
||||
if (!AddData(geometry_blob_, 0)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Metadata immediately follows geometry, and we write the same metadata
|
||||
// to all slots.
|
||||
uint32_t metadata_block = LP_METADATA_GEOMETRY_SIZE / LP_SECTOR_SIZE;
|
||||
metadata_blob_ = SerializeMetadata(metadata_);
|
||||
for (size_t i = 0; i < geometry_.metadata_slot_count; i++) {
|
||||
if (!AddData(metadata_blob_, metadata_block)) {
|
||||
return false;
|
||||
}
|
||||
metadata_block += geometry_.metadata_max_size / LP_SECTOR_SIZE;
|
||||
}
|
||||
|
||||
// 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);
|
||||
uint64_t backups_start = geometry_.block_device_size + backup_offset;
|
||||
uint64_t backup_sector = backups_start / LP_SECTOR_SIZE;
|
||||
for (size_t i = 0; i < geometry_.metadata_slot_count; i++) {
|
||||
if (!AddData(metadata_blob_, backup_sector)) {
|
||||
return false;
|
||||
}
|
||||
backup_sector += geometry_.metadata_max_size / LP_SECTOR_SIZE;
|
||||
}
|
||||
if (!AddData(geometry_blob_, backup_sector)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WriteToSparseFile(const char* file, const LpMetadata& metadata) {
|
||||
uint64_t num_blocks =
|
||||
AlignTo(metadata.geometry.block_device_size, LP_SECTOR_SIZE) / LP_SECTOR_SIZE;
|
||||
if (num_blocks >= UINT_MAX) {
|
||||
// libsparse counts blocks in unsigned 32-bit integers, but our block
|
||||
// size is rather low (512 bytes), since we operate in sectors.
|
||||
// Therefore the maximum block device size we can represent with a
|
||||
// sparse file is 2TB for now.
|
||||
LERROR << "Block device is too large to encode with libsparse.";
|
||||
return false;
|
||||
}
|
||||
|
||||
SparseBuilder builder(metadata);
|
||||
if (!builder.IsValid()) {
|
||||
LERROR << "Could not allocate sparse file of size " << metadata.geometry.block_device_size;
|
||||
return false;
|
||||
}
|
||||
if (!builder.Build()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return builder.Export(file);
|
||||
}
|
||||
|
||||
} // namespace fs_mgr
|
||||
} // namespace android
|
||||
|
|
|
@ -59,6 +59,7 @@ 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);
|
||||
bool WriteToImageFile(const char* file, const LpMetadata& metadata);
|
||||
std::unique_ptr<LpMetadata> ReadFromImageFile(const char* file);
|
||||
|
||||
|
|
Loading…
Reference in New Issue