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

Commit c165e84b authored by David Anderson's avatar David Anderson Committed by Daniel Zheng
Browse files

libsnapshot: Add Parser base class

Add in Parser base class and refactor code to work with it. Base class
will have ops() method which returns a vector of v3 operations.
v2_parser translates it's v2 operations to v3 operations with this
method.

Bug: 307452468
Test: Test with critical OTA paths?
Change-Id: Iccc9755a892911a1638f5b62d7d6a2402c68ab20
parent dfe80e48
Loading
Loading
Loading
Loading
+0 −1
Original line number Diff line number Diff line
@@ -185,7 +185,6 @@ class CowReader final : public ICowReader {
    std::shared_ptr<std::unordered_map<uint64_t, uint64_t>> data_loc_;
    ReaderFlags reader_flag_;
    bool is_merge_{};
    uint8_t compression_type_ = kCowCompressNone;
};

// Though this function takes in a CowHeaderV3, the struct could be populated as a v1/v2 CowHeader.
+30 −46
Original line number Diff line number Diff line
@@ -28,7 +28,6 @@
#include <zlib.h>

#include "cow_decompress.h"
#include "libsnapshot/cow_format.h"
#include "parser_v2.h"

namespace android {
@@ -85,7 +84,6 @@ std::unique_ptr<CowReader> CowReader::CloneCowReader() {
    cow->data_loc_ = data_loc_;
    cow->block_pos_index_ = block_pos_index_;
    cow->is_merge_ = is_merge_;
    cow->compression_type_ = compression_type_;
    return cow;
}

@@ -104,11 +102,14 @@ bool CowReader::InitForMerge(android::base::unique_fd&& fd) {
        PLOG(ERROR) << "lseek header failed";
        return false;
    }
    if (!android::base::ReadFully(fd_, &header_, sizeof(header_))) {

    CHECK_GE(header_.prefix.header_size, sizeof(CowHeader));
    CHECK_LE(header_.prefix.header_size, sizeof(header_));

    if (!android::base::ReadFully(fd_, &header_, header_.prefix.header_size)) {
        PLOG(ERROR) << "read header failed";
        return false;
    }

    return true;
}

@@ -124,51 +125,34 @@ bool CowReader::Parse(android::base::borrowed_fd fd, std::optional<uint64_t> lab
        return false;
    }

    CowParserV2 parser;
    if (!parser.Parse(fd, header_, label)) {
    std::unique_ptr<CowParserBase> parser;
    switch (header_.prefix.major_version) {
        case 1:
        case 2:
            parser = std::make_unique<CowParserV2>();
            break;
        case 3:
            break;
        default:
            LOG(ERROR) << "Unknown version: " << header_.prefix.major_version;
            return false;
    }

    footer_ = parser.footer();
    fd_size_ = parser.fd_size();
    last_label_ = parser.last_label();
    data_loc_ = parser.data_loc();
    ops_ = std::make_shared<std::vector<CowOperation>>(parser.ops()->size());

    // Translate the operation buffer from on disk to in memory
    for (size_t i = 0; i < parser.ops()->size(); i++) {
        const auto& v2_op = parser.ops()->at(i);

        auto& new_op = ops_->at(i);
        new_op.type = v2_op.type;
        new_op.data_length = v2_op.data_length;

        if (v2_op.new_block > std::numeric_limits<uint32_t>::max()) {
            LOG(ERROR) << "Out-of-range new block in COW op: " << v2_op;
    if (!parser->Parse(fd, header_, label)) {
        return false;
    }
        new_op.new_block = v2_op.new_block;

        uint64_t source_info = v2_op.source;
        if (new_op.type != kCowLabelOp) {
            source_info &= kCowOpSourceInfoDataMask;
            if (source_info != v2_op.source) {
                LOG(ERROR) << "Out-of-range source value in COW op: " << v2_op;
                return false;
            }
        }
        if (v2_op.compression != kCowCompressNone) {
            if (compression_type_ == kCowCompressNone) {
                compression_type_ = v2_op.compression;
            } else if (compression_type_ != v2_op.compression) {
                LOG(ERROR) << "COW has mixed compression types which is not supported;"
                           << " previously saw " << compression_type_ << ", got "
                           << v2_op.compression << ", op: " << v2_op;
    TranslatedCowOps ops_info;
    if (!parser->Translate(&ops_info)) {
        return false;
    }
        }
        new_op.source_info = source_info;
    }

    header_ = ops_info.header;
    ops_ = std::move(ops_info.ops);
    footer_ = parser->footer();
    fd_size_ = parser->fd_size();
    last_label_ = parser->last_label();
    data_loc_ = parser->data_loc();

    // If we're resuming a write, we're not ready to merge
    if (label.has_value()) return true;
@@ -664,7 +648,7 @@ class CowDataStream final : public IByteStream {
};

uint8_t CowReader::GetCompressionType() {
    return compression_type_;
    return header_.compression_algorithm;
}

ssize_t CowReader::ReadData(const CowOperation* op, void* buffer, size_t buffer_size,
+2 −2
Original line number Diff line number Diff line
@@ -74,13 +74,13 @@ static void ShowBad(CowReader& reader, const CowOperation* op) {
    }
}

static bool ShowRawOpStreamV2(borrowed_fd fd, const CowHeader& header) {
static bool ShowRawOpStreamV2(borrowed_fd fd, const CowHeaderV3& header) {
    CowParserV2 parser;
    if (!parser.Parse(fd, header)) {
        LOG(ERROR) << "v2 parser failed";
        return false;
    }
    for (const auto& op : *parser.ops()) {
    for (const auto& op : *parser.get_v2ops()) {
        std::cout << op << "\n";
        if (auto iter = parser.data_loc()->find(op.new_block); iter != parser.data_loc()->end()) {
            std::cout << "    data loc: " << iter->second << "\n";
+53 −0
Original line number Diff line number Diff line
//
// Copyright (C) 2023 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

#pragma once

#include <optional>
#include <unordered_map>

#include <android-base/unique_fd.h>
#include <libsnapshot/cow_format.h>

namespace android {
namespace snapshot {

struct TranslatedCowOps {
    CowHeaderV3 header;
    std::shared_ptr<std::vector<CowOperationV3>> ops;
};

class CowParserBase {
  public:
    virtual ~CowParserBase() = default;

    virtual bool Parse(android::base::borrowed_fd fd, const CowHeaderV3& header,
                       std::optional<uint64_t> label = {}) = 0;
    virtual bool Translate(TranslatedCowOps* out) = 0;
    virtual std::optional<CowFooter> footer() const { return std::nullopt; }
    virtual std::shared_ptr<std::unordered_map<uint64_t, uint64_t>> data_loc() const = 0;

    uint64_t fd_size() const { return fd_size_; }
    const std::optional<uint64_t>& last_label() const { return last_label_; }

  protected:
    CowHeaderV3 header_ = {};
    uint64_t fd_size_;
    std::optional<uint64_t> last_label_;
};

}  // namespace snapshot
}  // namespace android
+51 −5
Original line number Diff line number Diff line
@@ -17,13 +17,14 @@

#include <android-base/file.h>
#include <android-base/logging.h>
#include "libsnapshot/cow_format.h"

namespace android {
namespace snapshot {

using android::base::borrowed_fd;

bool CowParserV2::Parse(borrowed_fd fd, const CowHeader& header, std::optional<uint64_t> label) {
bool CowParserV2::Parse(borrowed_fd fd, const CowHeaderV3& header, std::optional<uint64_t> label) {
    auto pos = lseek(fd.get(), 0, SEEK_END);
    if (pos < 0) {
        PLOG(ERROR) << "lseek end failed";
@@ -47,8 +48,7 @@ bool CowParserV2::Parse(borrowed_fd fd, const CowHeader& header, std::optional<u
        return false;
    }

    if ((header_.prefix.major_version > kCowVersionMajor) ||
        (header_.prefix.minor_version != kCowVersionMinor)) {
    if (header_.prefix.major_version > 2 || header_.prefix.minor_version != 0) {
        LOG(ERROR) << "Header version mismatch, "
                   << "major version: " << header_.prefix.major_version
                   << ", expected: " << kCowVersionMajor
@@ -190,11 +190,57 @@ bool CowParserV2::ParseOps(borrowed_fd fd, std::optional<uint64_t> label) {
        }
    }

    ops_ = ops_buffer;
    ops_->shrink_to_fit();
    v2_ops_ = ops_buffer;
    v2_ops_->shrink_to_fit();
    data_loc_ = data_loc;
    return true;
}

bool CowParserV2::Translate(TranslatedCowOps* out) {
    out->ops = std::make_shared<std::vector<CowOperationV3>>(v2_ops_->size());

    // Translate the operation buffer from on disk to in memory
    for (size_t i = 0; i < out->ops->size(); i++) {
        const auto& v2_op = v2_ops_->at(i);

        auto& new_op = out->ops->at(i);
        new_op.type = v2_op.type;
        new_op.data_length = v2_op.data_length;

        if (v2_op.new_block > std::numeric_limits<uint32_t>::max()) {
            LOG(ERROR) << "Out-of-range new block in COW op: " << v2_op;
            return false;
        }
        new_op.new_block = v2_op.new_block;

        uint64_t source_info = v2_op.source;
        if (new_op.type != kCowLabelOp) {
            source_info &= kCowOpSourceInfoDataMask;
            if (source_info != v2_op.source) {
                LOG(ERROR) << "Out-of-range source value in COW op: " << v2_op;
                return false;
            }
        }
        if (v2_op.compression != kCowCompressNone) {
            if (header_.compression_algorithm == kCowCompressNone) {
                header_.compression_algorithm = v2_op.compression;
            } else if (header_.compression_algorithm != v2_op.compression) {
                LOG(ERROR) << "COW has mixed compression types which is not supported;"
                           << " previously saw " << header_.compression_algorithm << ", got "
                           << v2_op.compression << ", op: " << v2_op;
                return false;
            }
        }
        new_op.source_info = source_info;
    }

    out->header = header_;
    return true;
}

std::shared_ptr<std::unordered_map<uint64_t, uint64_t>> CowParserV2::data_loc() const {
    return data_loc_;
}

}  // namespace snapshot
}  // namespace android
Loading