diff --git a/fs_mgr/libsnapshot/include/libsnapshot/cow_reader.h b/fs_mgr/libsnapshot/include/libsnapshot/cow_reader.h index 272193796..debaf3683 100644 --- a/fs_mgr/libsnapshot/include/libsnapshot/cow_reader.h +++ b/fs_mgr/libsnapshot/include/libsnapshot/cow_reader.h @@ -172,7 +172,7 @@ class CowReader final : public ICowReader { android::base::unique_fd owned_fd_; android::base::borrowed_fd fd_; - CowHeader header_; + CowHeaderV3 header_; std::optional footer_; uint64_t fd_size_; std::optional last_label_; @@ -188,7 +188,10 @@ class CowReader final : public ICowReader { uint8_t compression_type_ = kCowCompressNone; }; -bool ReadCowHeader(android::base::borrowed_fd fd, CowHeader* header); +// Though this function takes in a CowHeaderV3, the struct could be populated as a v1/v2 CowHeader. +// The extra fields will just be filled as 0. V3 header is strictly a superset of v1/v2 header and +// contains all of the latter's field +bool ReadCowHeader(android::base::borrowed_fd fd, CowHeaderV3* header); } // namespace snapshot } // namespace android diff --git a/fs_mgr/libsnapshot/libsnapshot_cow/cow_reader.cpp b/fs_mgr/libsnapshot/libsnapshot_cow/cow_reader.cpp index 607d61084..3b84c95cc 100644 --- a/fs_mgr/libsnapshot/libsnapshot_cow/cow_reader.cpp +++ b/fs_mgr/libsnapshot/libsnapshot_cow/cow_reader.cpp @@ -28,12 +28,13 @@ #include #include "cow_decompress.h" +#include "libsnapshot/cow_format.h" #include "parser_v2.h" namespace android { namespace snapshot { -bool ReadCowHeader(android::base::borrowed_fd fd, CowHeader* header) { +bool ReadCowHeader(android::base::borrowed_fd fd, CowHeaderV3* header) { if (lseek(fd.get(), 0, SEEK_SET) < 0) { PLOG(ERROR) << "lseek header failed"; return false; @@ -49,9 +50,9 @@ bool ReadCowHeader(android::base::borrowed_fd fd, CowHeader* header) { << "Expected: " << kCowMagicNumber; return false; } - if (header->prefix.header_size > sizeof(CowHeader)) { + if (header->prefix.header_size > sizeof(CowHeaderV3)) { LOG(ERROR) << "Unknown CowHeader size (got " << header->prefix.header_size - << " bytes, expected at most " << sizeof(CowHeader) << " bytes)"; + << " bytes, expected at most " << sizeof(CowHeaderV3) << " bytes)"; return false; } diff --git a/fs_mgr/libsnapshot/libsnapshot_cow/inspect_cow.cpp b/fs_mgr/libsnapshot/libsnapshot_cow/inspect_cow.cpp index 83b5a1295..a29146985 100644 --- a/fs_mgr/libsnapshot/libsnapshot_cow/inspect_cow.cpp +++ b/fs_mgr/libsnapshot/libsnapshot_cow/inspect_cow.cpp @@ -90,7 +90,7 @@ static bool ShowRawOpStreamV2(borrowed_fd fd, const CowHeader& header) { } static bool ShowRawOpStream(borrowed_fd fd) { - CowHeader header; + CowHeaderV3 header; if (!ReadCowHeader(fd, &header)) { LOG(ERROR) << "parse header failed"; return false; diff --git a/fs_mgr/libsnapshot/libsnapshot_cow/test_v3.cpp b/fs_mgr/libsnapshot/libsnapshot_cow/test_v3.cpp index 2373d4df5..cc8dd8360 100644 --- a/fs_mgr/libsnapshot/libsnapshot_cow/test_v3.cpp +++ b/fs_mgr/libsnapshot/libsnapshot_cow/test_v3.cpp @@ -26,7 +26,9 @@ #include #include "cow_decompress.h" #include "libsnapshot/cow_format.h" +#include "writer_v2.h" #include "writer_v3.h" + using android::base::unique_fd; using testing::AssertionFailure; using testing::AssertionResult; @@ -49,5 +51,27 @@ class CowOperationV3Test : public ::testing::Test { std::unique_ptr cow_; }; +TEST_F(CowOperationV3Test, CowHeaderV2Test) { + CowOptions options; + options.cluster_ops = 5; + options.num_merge_ops = 1; + options.block_size = 4096; + std::string data = "This is some data, believe it"; + data.resize(options.block_size, '\0'); + auto writer_v2 = std::make_unique(options, GetCowFd()); + ASSERT_TRUE(writer_v2->Initialize()); + ASSERT_TRUE(writer_v2->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, kCowVersionMajor); + ASSERT_EQ(header.prefix.minor_version, kCowVersionMinor); + ASSERT_EQ(header.block_size, options.block_size); + ASSERT_EQ(header.cluster_ops, options.cluster_ops); +} + } // namespace snapshot } // namespace android \ No newline at end of file diff --git a/fs_mgr/libsnapshot/libsnapshot_cow/writer_v2.cpp b/fs_mgr/libsnapshot/libsnapshot_cow/writer_v2.cpp index 63bed0741..83a9b1b22 100644 --- a/fs_mgr/libsnapshot/libsnapshot_cow/writer_v2.cpp +++ b/fs_mgr/libsnapshot/libsnapshot_cow/writer_v2.cpp @@ -269,9 +269,11 @@ bool CowWriterV2::OpenForWrite() { } bool CowWriterV2::OpenForAppend(uint64_t label) { - if (!ReadCowHeader(fd_, &header_)) { + CowHeaderV3 header_v3; + if (!ReadCowHeader(fd_, &header_v3)) { return false; } + header_ = header_v3; CowParserV2 parser; if (!parser.Parse(fd_, header_, {label})) { diff --git a/fs_mgr/libsnapshot/snapshot.cpp b/fs_mgr/libsnapshot/snapshot.cpp index f5732fc90..eb4beb780 100644 --- a/fs_mgr/libsnapshot/snapshot.cpp +++ b/fs_mgr/libsnapshot/snapshot.cpp @@ -3658,7 +3658,7 @@ std::unique_ptr SnapshotManager::OpenCompressedSnapshotWriter( return nullptr; } - CowHeader header; + CowHeaderV3 header; if (!ReadCowHeader(cow_fd, &header)) { LOG(ERROR) << "OpenCompressedSnapshotWriter: read header failed"; return nullptr;