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

Commit ee35a818 authored by Daniel Zheng's avatar Daniel Zheng
Browse files

libsnapshot: Parser v3 implementation

Also adds a test for CowWriterV3 + CowParserV3.

Bug: 307452468
Test: read a header written by v3 writer
Change-Id: I77cf048604c82a010cfdbfb38d0f8beef597d112
parent c9c120e0
Loading
Loading
Loading
Loading
+4 −2
Original line number Diff line number Diff line
@@ -99,8 +99,10 @@ struct CowHeaderV3 : public CowHeader {
    uint64_t sequence_buffer_offset;
    // Size, in bytes, of the CowResumePoint buffer.
    uint32_t resume_buffer_size;
    // Size, in bytes, of the CowOperation buffer.
    uint32_t op_buffer_size;
    // Number of CowOperationV3 structs in the operation buffer, currently and total
    // region size.
    uint32_t op_count;
    uint32_t op_count_max;
    // Compression Algorithm
    uint32_t compression_algorithm;
} __attribute__((packed));
+2 −0
Original line number Diff line number Diff line
@@ -29,6 +29,7 @@

#include "cow_decompress.h"
#include "parser_v2.h"
#include "parser_v3.h"

namespace android {
namespace snapshot {
@@ -132,6 +133,7 @@ bool CowReader::Parse(android::base::borrowed_fd fd, std::optional<uint64_t> lab
            parser = std::make_unique<CowParserV2>();
            break;
        case 3:
            parser = std::make_unique<CowParserV3>();
            break;
        default:
            LOG(ERROR) << "Unknown version: " << header_.prefix.major_version;
+50 −7
Original line number Diff line number Diff line
@@ -24,16 +24,59 @@ namespace snapshot {
using android::base::borrowed_fd;

bool CowParserV3::Parse(borrowed_fd fd, const CowHeaderV3& header, std::optional<uint64_t> label) {
    LOG(ERROR) << "this function should never be called";
    if (fd.get() || sizeof(header) > 0 || label) return false;
    auto pos = lseek(fd.get(), 0, SEEK_END);
    if (pos < 0) {
        PLOG(ERROR) << "lseek end failed";
        return false;
    }
    fd_size_ = pos;
    header_ = header;

bool CowParserV3::ParseOps(android::base::borrowed_fd fd, std::optional<uint64_t> label) {
    LOG(ERROR) << "this function should never be called";
    if (fd.get() || label) return false;
    if (header_.footer_size != 0) {
        LOG(ERROR) << "Footer size isn't 0, read " << header_.footer_size;
        return false;
    }
    if (header_.op_size != sizeof(CowOperationV3)) {
        LOG(ERROR) << "Operation size unknown, read " << header_.op_size << ", expected "
                   << sizeof(CowOperationV3);
        return false;
    }
    if (header_.cluster_ops != 0) {
        LOG(ERROR) << "Cluster ops not supported in v3";
        return false;
    }

    if (header_.prefix.major_version != 3 || header_.prefix.minor_version != 0) {
        LOG(ERROR) << "Header version mismatch, "
                   << "major version: " << header_.prefix.major_version
                   << ", expected: " << kCowVersionMajor
                   << ", minor version: " << header_.prefix.minor_version
                   << ", expected: " << kCowVersionMinor;
        return false;
    }

    return ParseOps(fd, label);
}

bool CowParserV3::ParseOps(borrowed_fd fd, std::optional<uint64_t> label) {
    ops_ = std::make_shared<std::vector<CowOperationV3>>();
    ops_->resize(header_.op_count);

    const off_t offset = header_.prefix.header_size + header_.buffer_size;
    if (!android::base::ReadFullyAtOffset(fd, ops_->data(), ops_->size() * sizeof(CowOperationV3),
                                          offset)) {
        PLOG(ERROR) << "read ops failed";
        return false;
    }

    // :TODO: sequence buffer & resume buffer follow
    // Once we implement labels, we'll have to discard unused ops and adjust
    // the header as needed.
    CHECK(!label);

    ops_->shrink_to_fit();
    return true;
}

bool CowParserV3::Translate(TranslatedCowOps* out) {
    out->ops = ops_;
+21 −5
Original line number Diff line number Diff line
@@ -37,7 +37,7 @@ using testing::AssertionSuccess;
namespace android {
namespace snapshot {

class CowOperationV3Test : public ::testing::Test {
class CowTestV3 : public ::testing::Test {
  protected:
    virtual void SetUp() override {
        cow_ = std::make_unique<TemporaryFile>();
@@ -51,7 +51,7 @@ class CowOperationV3Test : public ::testing::Test {
    std::unique_ptr<TemporaryFile> cow_;
};

TEST_F(CowOperationV3Test, CowHeaderV2Test) {
TEST_F(CowTestV3, CowHeaderV2Test) {
    CowOptions options;
    options.cluster_ops = 5;
    options.num_merge_ops = 1;
@@ -67,11 +67,27 @@ TEST_F(CowOperationV3Test, CowHeaderV2Test) {

    const auto& header = reader.GetHeader();
    ASSERT_EQ(header.prefix.magic, kCowMagicNumber);
    ASSERT_EQ(header.prefix.major_version, kCowVersionMajor);
    ASSERT_EQ(header.prefix.minor_version, kCowVersionMinor);
    ASSERT_EQ(header.prefix.major_version, 2);
    ASSERT_EQ(header.prefix.minor_version, 0);
    ASSERT_EQ(header.block_size, options.block_size);
    ASSERT_EQ(header.cluster_ops, options.cluster_ops);
}

TEST_F(CowTestV3, Header) {
    CowOptions options;
    auto writer = CreateCowWriter(3, options, GetCowFd());
    ASSERT_TRUE(writer->Finalize());

    CowReader reader;
    ASSERT_TRUE(reader.Parse(cow_->fd));

    const auto& header = reader.GetHeader();
    ASSERT_EQ(header.prefix.magic, kCowMagicNumber);
    ASSERT_EQ(header.prefix.major_version, 3);
    ASSERT_EQ(header.prefix.minor_version, 0);
    ASSERT_EQ(header.block_size, options.block_size);
    ASSERT_EQ(header.cluster_ops, 0);
}

}  // namespace snapshot
}  // namespace android
+3 −7
Original line number Diff line number Diff line
@@ -78,7 +78,8 @@ void CowWriterV3::SetupHeaders() {
    // during COW size estimation
    header_.sequence_buffer_offset = 0;
    header_.resume_buffer_size = 0;
    header_.op_buffer_size = 0;
    header_.op_count = 0;
    header_.op_count_max = 0;
    header_.compression_algorithm = kCowCompressNone;
    return;
}
@@ -159,10 +160,6 @@ bool CowWriterV3::OpenForWrite() {
        LOG(ERROR) << "Header sync failed";
        return false;
    }

    next_op_pos_ = 0;
    next_data_pos_ = 0;

    return true;
}

@@ -205,8 +202,7 @@ bool CowWriterV3::EmitSequenceData(size_t num_ops, const uint32_t* data) {
}

bool CowWriterV3::Finalize() {
    LOG(ERROR) << __LINE__ << " " << __FILE__ << " <- function here should never be called";
    return false;
    return Sync();
}

uint64_t CowWriterV3::GetCowSize() {
Loading