Loading fs_mgr/liblp/Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -34,6 +34,7 @@ cc_library_static { "liblog", "libcrypto", "libcrypto_utils", "libsparse", ], whole_static_libs: [ "libext2_uuid", Loading fs_mgr/liblp/images.cpp +113 −0 Original line number Diff line number Diff line Loading @@ -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" Loading Loading @@ -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 fs_mgr/liblp/include/liblp/liblp.h +1 −0 Original line number Diff line number Diff line Loading @@ -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 Loading
fs_mgr/liblp/Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -34,6 +34,7 @@ cc_library_static { "liblog", "libcrypto", "libcrypto_utils", "libsparse", ], whole_static_libs: [ "libext2_uuid", Loading
fs_mgr/liblp/images.cpp +113 −0 Original line number Diff line number Diff line Loading @@ -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" Loading Loading @@ -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
fs_mgr/liblp/include/liblp/liblp.h +1 −0 Original line number Diff line number Diff line Loading @@ -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