Refactor off COW header v3
Cow reader will store header v3 in memory. ReadCowHeader can remain mostly unchanged since the cow prefix is the same. header->prefix.header_size will then tell us if we're reading a v3 or v2 header. v3 header is strictly a superset of v2 header so we can read a v2 header into a v3 struct. Added a test case to test_v3 where we write a header using v2_writer and ensure CowReader is able to read it. Test: cow_api_test Change-Id: I142f18d871322930b7dc341c342c8b63a481341c
This commit is contained in:
parent
f2270d2bb6
commit
7a9e007a01
6 changed files with 38 additions and 8 deletions
|
@ -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<CowFooter> footer_;
|
||||
uint64_t fd_size_;
|
||||
std::optional<uint64_t> 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
|
||||
|
|
|
@ -28,12 +28,13 @@
|
|||
#include <zlib.h>
|
||||
|
||||
#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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -26,7 +26,9 @@
|
|||
#include <libsnapshot/cow_writer.h>
|
||||
#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<TemporaryFile> 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<CowWriterV2>(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
|
|
@ -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})) {
|
||||
|
|
|
@ -3658,7 +3658,7 @@ std::unique_ptr<ICowWriter> SnapshotManager::OpenCompressedSnapshotWriter(
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
CowHeader header;
|
||||
CowHeaderV3 header;
|
||||
if (!ReadCowHeader(cow_fd, &header)) {
|
||||
LOG(ERROR) << "OpenCompressedSnapshotWriter: read header failed";
|
||||
return nullptr;
|
||||
|
|
Loading…
Reference in a new issue