Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 97d3fd8f authored by Treehugger Robot's avatar Treehugger Robot Committed by Gerrit Code Review
Browse files

Merge "liblp: Add a method to create sparse images of the super partition."

parents fcb0ef9c b36db4ba
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -34,6 +34,7 @@ cc_library_static {
        "liblog",
        "libcrypto",
        "libcrypto_utils",
        "libsparse",
    ],
    whole_static_libs: [
        "libext2_uuid",
+113 −0
Original line number Diff line number Diff line
@@ -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
+1 −0
Original line number Diff line number Diff line
@@ -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);