libsnapshot: Remove ISnapshotWriter.
This only added one real method to ICowWriter, so let's just fold it
into ICowWriter. CompressedSnapshotWriter goes away as well.
CompressedSnapshotReader is now part of libsnapshot_cow.
Bug: 280529365
Test: m otapackage
apply ota
Change-Id: I55358c3c9be111d5aee1a0c22c29cb1539d05494
This commit is contained in:
parent
4ac7d0e82e
commit
5eae2cb450
21 changed files with 159 additions and 520 deletions
|
|
@ -85,11 +85,9 @@ filegroup {
|
|||
"android/snapshot/snapshot.proto",
|
||||
"device_info.cpp",
|
||||
"snapshot.cpp",
|
||||
"snapshot_reader.cpp",
|
||||
"snapshot_stats.cpp",
|
||||
"snapshot_stub.cpp",
|
||||
"snapshot_metadata_updater.cpp",
|
||||
"snapshot_writer.cpp",
|
||||
"partition_cow_creator.cpp",
|
||||
"return.cpp",
|
||||
"utility.cpp",
|
||||
|
|
@ -165,6 +163,9 @@ cc_defaults {
|
|||
"liblz4",
|
||||
"libzstd",
|
||||
],
|
||||
header_libs: [
|
||||
"libupdate_engine_headers",
|
||||
],
|
||||
export_include_dirs: ["include"],
|
||||
}
|
||||
|
||||
|
|
@ -179,6 +180,7 @@ cc_library_static {
|
|||
"libsnapshot_cow/cow_format.cpp",
|
||||
"libsnapshot_cow/cow_reader.cpp",
|
||||
"libsnapshot_cow/parser_v2.cpp",
|
||||
"libsnapshot_cow/snapshot_reader.cpp",
|
||||
"libsnapshot_cow/writer_base.cpp",
|
||||
"libsnapshot_cow/writer_v2.cpp",
|
||||
],
|
||||
|
|
@ -224,9 +226,7 @@ cc_defaults {
|
|||
srcs: [
|
||||
"partition_cow_creator_test.cpp",
|
||||
"snapshot_metadata_updater_test.cpp",
|
||||
"snapshot_reader_test.cpp",
|
||||
"snapshot_test.cpp",
|
||||
"snapshot_writer_test.cpp",
|
||||
],
|
||||
shared_libs: [
|
||||
"libbinder",
|
||||
|
|
@ -372,6 +372,7 @@ cc_test {
|
|||
"libsnapshot_cow_defaults",
|
||||
],
|
||||
srcs: [
|
||||
"libsnapshot_cow/snapshot_reader_test.cpp",
|
||||
"libsnapshot_cow/test_v2.cpp",
|
||||
],
|
||||
cflags: [
|
||||
|
|
|
|||
|
|
@ -24,6 +24,10 @@
|
|||
#include <android-base/unique_fd.h>
|
||||
#include <libsnapshot/cow_format.h>
|
||||
|
||||
namespace chromeos_update_engine {
|
||||
class FileDescriptor;
|
||||
} // namespace chromeos_update_engine
|
||||
|
||||
namespace android {
|
||||
namespace snapshot {
|
||||
|
||||
|
|
@ -32,6 +36,8 @@ class ICowOpIter;
|
|||
// Interface for reading from a snapuserd COW.
|
||||
class ICowReader {
|
||||
public:
|
||||
using FileDescriptor = chromeos_update_engine::FileDescriptor;
|
||||
|
||||
virtual ~ICowReader() {}
|
||||
|
||||
// Return the file header.
|
||||
|
|
@ -109,10 +115,9 @@ class CowReader final : public ICowReader {
|
|||
bool Parse(android::base::borrowed_fd fd, std::optional<uint64_t> label = {});
|
||||
|
||||
bool InitForMerge(android::base::unique_fd&& fd);
|
||||
|
||||
bool VerifyMergeOps() override;
|
||||
|
||||
bool GetFooter(CowFooter* footer) override;
|
||||
|
||||
bool GetLastLabel(uint64_t* label) override;
|
||||
|
||||
// Create a CowOpIter object which contains footer_.num_ops
|
||||
|
|
|
|||
|
|
@ -61,6 +61,8 @@ struct CowOptions {
|
|||
// will occur in the sequence they were added to the COW.
|
||||
class ICowWriter {
|
||||
public:
|
||||
using FileDescriptor = chromeos_update_engine::FileDescriptor;
|
||||
|
||||
virtual ~ICowWriter() {}
|
||||
|
||||
// Encode an operation that copies the contents of |old_block| to the
|
||||
|
|
@ -93,6 +95,17 @@ class ICowWriter {
|
|||
|
||||
virtual uint32_t GetBlockSize() const = 0;
|
||||
virtual std::optional<uint32_t> GetMaxBlocks() const = 0;
|
||||
|
||||
// Open an ICowReader for this writer. The reader will be a snapshot of the
|
||||
// current operations in the writer; new writes after OpenReader() will not
|
||||
// be reflected.
|
||||
virtual std::unique_ptr<ICowReader> OpenReader() = 0;
|
||||
|
||||
// Open a file descriptor. This allows reading and seeing through the cow
|
||||
// as if it were a normal file. The optional source_device must be a valid
|
||||
// path if the CowReader contains any copy or xor operations.
|
||||
virtual std::unique_ptr<FileDescriptor> OpenFileDescriptor(
|
||||
const std::optional<std::string>& source_device) = 0;
|
||||
};
|
||||
|
||||
class CompressWorker {
|
||||
|
|
|
|||
|
|
@ -15,17 +15,16 @@
|
|||
//
|
||||
|
||||
#include <gmock/gmock.h>
|
||||
#include <libsnapshot/snapshot_writer.h>
|
||||
#include <libsnapshot/cow_writer.h>
|
||||
|
||||
namespace android::snapshot {
|
||||
|
||||
class MockSnapshotWriter : public ISnapshotWriter {
|
||||
class MockCowWriter : public ICowWriter {
|
||||
public:
|
||||
using FileDescriptor = ISnapshotWriter::FileDescriptor;
|
||||
using FileDescriptor = chromeos_update_engine::FileDescriptor;
|
||||
|
||||
MOCK_METHOD(bool, Finalize, (), (override));
|
||||
|
||||
// Return number of bytes the cow image occupies on disk.
|
||||
MOCK_METHOD(uint64_t, GetCowSize, (), (override));
|
||||
|
||||
MOCK_METHOD(bool, AddCopy, (uint64_t, uint64_t, uint64_t), (override));
|
||||
|
|
@ -35,11 +34,12 @@ class MockSnapshotWriter : public ISnapshotWriter {
|
|||
MOCK_METHOD(bool, AddZeroBlocks, (uint64_t, uint64_t), (override));
|
||||
MOCK_METHOD(bool, AddLabel, (uint64_t), (override));
|
||||
MOCK_METHOD(bool, AddSequenceData, (size_t, const uint32_t*), (override));
|
||||
MOCK_METHOD(bool, Initialize, (), (override));
|
||||
MOCK_METHOD(bool, InitializeAppend, (uint64_t), (override));
|
||||
MOCK_METHOD(bool, VerifyMergeOps, (), (override, const, noexcept));
|
||||
MOCK_METHOD(std::unique_ptr<FileDescriptor>, OpenReader, (), (override));
|
||||
MOCK_METHOD(uint32_t, GetBlockSize, (), (override, const));
|
||||
MOCK_METHOD(std::optional<uint32_t>, GetMaxBlocks, (), (override, const));
|
||||
|
||||
MOCK_METHOD(std::unique_ptr<ICowReader>, OpenReader, (), (override));
|
||||
MOCK_METHOD(std::unique_ptr<FileDescriptor>, OpenFileDescriptor,
|
||||
(const std::optional<std::string>&), (override));
|
||||
};
|
||||
|
||||
} // namespace android::snapshot
|
||||
|
|
@ -42,9 +42,9 @@ class MockSnapshotManager : public ISnapshotManager {
|
|||
(const android::fs_mgr::CreateLogicalPartitionParams& params,
|
||||
std::string* snapshot_path),
|
||||
(override));
|
||||
MOCK_METHOD(std::unique_ptr<ISnapshotWriter>, OpenSnapshotWriter,
|
||||
MOCK_METHOD(std::unique_ptr<ICowWriter>, OpenSnapshotWriter,
|
||||
(const android::fs_mgr::CreateLogicalPartitionParams& params,
|
||||
const std::optional<std::string>&),
|
||||
std::optional<uint64_t>),
|
||||
(override));
|
||||
MOCK_METHOD(bool, UnmapUpdateSnapshot, (const std::string& target_partition_name), (override));
|
||||
MOCK_METHOD(bool, NeedSnapshotsInFirstStageMount, (), (override));
|
||||
|
|
|
|||
|
|
@ -33,12 +33,11 @@
|
|||
#include <libfiemap/image_manager.h>
|
||||
#include <liblp/builder.h>
|
||||
#include <liblp/liblp.h>
|
||||
#include <update_engine/update_metadata.pb.h>
|
||||
|
||||
#include <libsnapshot/auto_device.h>
|
||||
#include <libsnapshot/cow_writer.h>
|
||||
#include <libsnapshot/return.h>
|
||||
#include <libsnapshot/snapshot_writer.h>
|
||||
#include <snapuserd/snapuserd_client.h>
|
||||
#include <update_engine/update_metadata.pb.h>
|
||||
|
||||
#ifndef FRIEND_TEST
|
||||
#define FRIEND_TEST(test_set_name, individual_test) \
|
||||
|
|
@ -211,16 +210,13 @@ class ISnapshotManager {
|
|||
virtual bool MapUpdateSnapshot(const android::fs_mgr::CreateLogicalPartitionParams& params,
|
||||
std::string* snapshot_path) = 0;
|
||||
|
||||
// Create an ISnapshotWriter to build a snapshot against a target partition. The partition name
|
||||
// Create an ICowWriter to build a snapshot against a target partition. The partition name
|
||||
// must be suffixed. If a source partition exists, it must be specified as well. The source
|
||||
// partition will only be used if raw bytes are needed. The source partition should be an
|
||||
// absolute path to the device, not a partition name.
|
||||
//
|
||||
// After calling OpenSnapshotWriter, the caller must invoke Initialize or InitializeForAppend
|
||||
// before invoking write operations.
|
||||
virtual std::unique_ptr<ISnapshotWriter> OpenSnapshotWriter(
|
||||
virtual std::unique_ptr<ICowWriter> OpenSnapshotWriter(
|
||||
const android::fs_mgr::CreateLogicalPartitionParams& params,
|
||||
const std::optional<std::string>& source_device) = 0;
|
||||
std::optional<uint64_t> label = {}) = 0;
|
||||
|
||||
// Unmap a snapshot device or CowWriter that was previously opened with MapUpdateSnapshot,
|
||||
// OpenSnapshotWriter. All outstanding open descriptors, writers, or
|
||||
|
|
@ -362,9 +358,9 @@ class SnapshotManager final : public ISnapshotManager {
|
|||
Return CreateUpdateSnapshots(const DeltaArchiveManifest& manifest) override;
|
||||
bool MapUpdateSnapshot(const CreateLogicalPartitionParams& params,
|
||||
std::string* snapshot_path) override;
|
||||
std::unique_ptr<ISnapshotWriter> OpenSnapshotWriter(
|
||||
std::unique_ptr<ICowWriter> OpenSnapshotWriter(
|
||||
const android::fs_mgr::CreateLogicalPartitionParams& params,
|
||||
const std::optional<std::string>& source_device) override;
|
||||
std::optional<uint64_t> label) override;
|
||||
bool UnmapUpdateSnapshot(const std::string& target_partition_name) override;
|
||||
bool NeedSnapshotsInFirstStageMount() override;
|
||||
bool CreateLogicalAndSnapshotPartitions(
|
||||
|
|
@ -693,10 +689,10 @@ class SnapshotManager final : public ISnapshotManager {
|
|||
};
|
||||
|
||||
// Helpers for OpenSnapshotWriter.
|
||||
std::unique_ptr<ISnapshotWriter> OpenCompressedSnapshotWriter(
|
||||
LockedFile* lock, const std::optional<std::string>& source_device,
|
||||
const std::string& partition_name, const SnapshotStatus& status,
|
||||
const SnapshotPaths& paths);
|
||||
std::unique_ptr<ICowWriter> OpenCompressedSnapshotWriter(LockedFile* lock,
|
||||
const SnapshotStatus& status,
|
||||
const SnapshotPaths& paths,
|
||||
std::optional<uint64_t> label);
|
||||
|
||||
// Map the base device, COW devices, and snapshot device.
|
||||
bool MapPartitionWithSnapshot(LockedFile* lock, CreateLogicalPartitionParams params,
|
||||
|
|
@ -743,7 +739,7 @@ class SnapshotManager final : public ISnapshotManager {
|
|||
// Initialize snapshots so that they can be mapped later.
|
||||
// Map the COW partition and zero-initialize the header.
|
||||
Return InitializeUpdateSnapshots(
|
||||
LockedFile* lock, MetadataBuilder* target_metadata,
|
||||
LockedFile* lock, uint32_t cow_version, MetadataBuilder* target_metadata,
|
||||
const LpMetadata* exported_target_metadata, const std::string& target_suffix,
|
||||
const std::map<std::string, SnapshotStatus>& all_snapshot_status);
|
||||
|
||||
|
|
|
|||
|
|
@ -40,9 +40,9 @@ class SnapshotManagerStub : public ISnapshotManager {
|
|||
const chromeos_update_engine::DeltaArchiveManifest& manifest) override;
|
||||
bool MapUpdateSnapshot(const android::fs_mgr::CreateLogicalPartitionParams& params,
|
||||
std::string* snapshot_path) override;
|
||||
std::unique_ptr<ISnapshotWriter> OpenSnapshotWriter(
|
||||
std::unique_ptr<ICowWriter> OpenSnapshotWriter(
|
||||
const android::fs_mgr::CreateLogicalPartitionParams& params,
|
||||
const std::optional<std::string>& source_device) override;
|
||||
std::optional<uint64_t> label) override;
|
||||
bool UnmapUpdateSnapshot(const std::string& target_partition_name) override;
|
||||
bool NeedSnapshotsInFirstStageMount() override;
|
||||
bool CreateLogicalAndSnapshotPartitions(
|
||||
|
|
|
|||
|
|
@ -1,93 +0,0 @@
|
|||
// Copyright (C) 2020 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 <android-base/unique_fd.h>
|
||||
|
||||
#include <libsnapshot/cow_writer.h>
|
||||
|
||||
namespace chromeos_update_engine {
|
||||
class FileDescriptor;
|
||||
} // namespace chromeos_update_engine
|
||||
|
||||
namespace android {
|
||||
namespace snapshot {
|
||||
|
||||
class ISnapshotWriter : public ICowWriter {
|
||||
public:
|
||||
using FileDescriptor = chromeos_update_engine::FileDescriptor;
|
||||
|
||||
virtual ~ISnapshotWriter() {}
|
||||
|
||||
// Open the writer in write mode (no append).
|
||||
virtual bool Initialize() = 0;
|
||||
|
||||
// Open the writer in append mode, with the last label to resume
|
||||
// from. See CowWriter::InitializeAppend.
|
||||
virtual bool InitializeAppend(uint64_t label) = 0;
|
||||
|
||||
virtual std::unique_ptr<FileDescriptor> OpenReader() = 0;
|
||||
|
||||
virtual bool VerifyMergeOps() const noexcept = 0;
|
||||
};
|
||||
|
||||
// Send writes to a COW or a raw device directly, based on a threshold.
|
||||
class CompressedSnapshotWriter final : public ISnapshotWriter {
|
||||
public:
|
||||
CompressedSnapshotWriter(const CowOptions& options);
|
||||
|
||||
void SetSourceDevice(const std::string& source_device);
|
||||
|
||||
// Sets the COW device; this is required.
|
||||
bool SetCowDevice(android::base::unique_fd&& cow_device);
|
||||
|
||||
bool Initialize() override;
|
||||
bool InitializeAppend(uint64_t label) override;
|
||||
bool Finalize() override;
|
||||
uint64_t GetCowSize() override;
|
||||
uint32_t GetBlockSize() const override;
|
||||
std::optional<uint32_t> GetMaxBlocks() const override;
|
||||
std::unique_ptr<FileDescriptor> OpenReader() override;
|
||||
bool VerifyMergeOps() const noexcept;
|
||||
|
||||
bool AddCopy(uint64_t new_block, uint64_t old_block, uint64_t num_blocks = 1) override;
|
||||
bool AddRawBlocks(uint64_t new_block_start, const void* data, size_t size) override;
|
||||
bool AddXorBlocks(uint32_t new_block_start, const void* data, size_t size, uint32_t old_block,
|
||||
uint16_t offset) override;
|
||||
bool AddZeroBlocks(uint64_t new_block_start, uint64_t num_blocks) override;
|
||||
bool AddLabel(uint64_t label) override;
|
||||
bool AddSequenceData(size_t num_ops, const uint32_t* data) override;
|
||||
|
||||
private:
|
||||
std::unique_ptr<CowReader> OpenCowReader() const;
|
||||
android::base::borrowed_fd GetSourceFd();
|
||||
|
||||
CowOptions options_;
|
||||
|
||||
// Set the source device. This is used for AddCopy() operations, if the
|
||||
// underlying writer needs the original bytes (for example if backed by
|
||||
// dm-snapshot or if writing directly to an unsnapshotted region). The
|
||||
// device is only opened on the first operation that requires it.
|
||||
std::optional<std::string> source_device_;
|
||||
android::base::unique_fd source_fd_;
|
||||
|
||||
android::base::unique_fd cow_device_;
|
||||
std::unique_ptr<ICowWriter> cow_;
|
||||
};
|
||||
|
||||
} // namespace snapshot
|
||||
} // namespace android
|
||||
|
|
@ -198,7 +198,7 @@ void DeleteBackingImage(android::fiemap::IImageManager* manager, const std::stri
|
|||
// Expect space of |path| is multiple of 4K.
|
||||
bool WriteRandomData(const std::string& path, std::optional<size_t> expect_size = std::nullopt,
|
||||
std::string* hash = nullptr);
|
||||
std::string HashSnapshot(ISnapshotWriter* writer);
|
||||
std::string HashSnapshot(ICowWriter::FileDescriptor* writer);
|
||||
|
||||
std::string ToHexString(const uint8_t* buf, size_t len);
|
||||
|
||||
|
|
|
|||
|
|
@ -18,73 +18,24 @@
|
|||
|
||||
#include <android-base/file.h>
|
||||
#include <android-base/logging.h>
|
||||
#include <ext4_utils/ext4_utils.h>
|
||||
|
||||
namespace android {
|
||||
namespace snapshot {
|
||||
|
||||
using android::base::borrowed_fd;
|
||||
|
||||
// Not supported.
|
||||
bool ReadOnlyFileDescriptor::Open(const char*, int, mode_t) {
|
||||
errno = EINVAL;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ReadOnlyFileDescriptor::Open(const char*, int) {
|
||||
errno = EINVAL;
|
||||
return false;
|
||||
}
|
||||
|
||||
ssize_t ReadOnlyFileDescriptor::Write(const void*, size_t) {
|
||||
errno = EINVAL;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ReadOnlyFileDescriptor::BlkIoctl(int, uint64_t, uint64_t, int*) {
|
||||
errno = EINVAL;
|
||||
return false;
|
||||
}
|
||||
|
||||
ReadFdFileDescriptor::ReadFdFileDescriptor(android::base::unique_fd&& fd) : fd_(std::move(fd)) {}
|
||||
|
||||
ssize_t ReadFdFileDescriptor::Read(void* buf, size_t count) {
|
||||
return read(fd_.get(), buf, count);
|
||||
}
|
||||
|
||||
off64_t ReadFdFileDescriptor::Seek(off64_t offset, int whence) {
|
||||
return lseek(fd_.get(), offset, whence);
|
||||
}
|
||||
|
||||
uint64_t ReadFdFileDescriptor::BlockDevSize() {
|
||||
return get_block_device_size(fd_.get());
|
||||
}
|
||||
|
||||
bool ReadFdFileDescriptor::Close() {
|
||||
fd_ = {};
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ReadFdFileDescriptor::IsSettingErrno() {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ReadFdFileDescriptor::IsOpen() {
|
||||
return fd_ >= 0;
|
||||
}
|
||||
|
||||
bool ReadFdFileDescriptor::Flush() {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CompressedSnapshotReader::SetCow(std::unique_ptr<CowReader>&& cow) {
|
||||
cow_ = std::move(cow);
|
||||
|
||||
CompressedSnapshotReader::CompressedSnapshotReader(std::unique_ptr<ICowReader>&& cow,
|
||||
const std::optional<std::string>& source_device,
|
||||
std::optional<uint64_t> block_dev_size)
|
||||
: cow_(std::move(cow)),
|
||||
block_size_(cow_->GetHeader().block_size),
|
||||
source_device_(source_device),
|
||||
block_device_size_(block_dev_size.value_or(0)) {
|
||||
const auto& header = cow_->GetHeader();
|
||||
block_size_ = header.block_size;
|
||||
|
||||
// Populate the operation map.
|
||||
op_iter_ = cow_->GetOpIter();
|
||||
op_iter_ = cow_->GetOpIter(false);
|
||||
while (!op_iter_->AtEnd()) {
|
||||
const CowOperation* op = op_iter_->Get();
|
||||
if (IsMetadataOp(*op)) {
|
||||
|
|
@ -97,16 +48,27 @@ bool CompressedSnapshotReader::SetCow(std::unique_ptr<CowReader>&& cow) {
|
|||
ops_[op->new_block] = op;
|
||||
op_iter_->Next();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CompressedSnapshotReader::SetSourceDevice(const std::string& source_device) {
|
||||
source_device_ = {source_device};
|
||||
// Not supported.
|
||||
bool CompressedSnapshotReader::Open(const char*, int, mode_t) {
|
||||
errno = EINVAL;
|
||||
return false;
|
||||
}
|
||||
|
||||
void CompressedSnapshotReader::SetBlockDeviceSize(uint64_t block_device_size) {
|
||||
block_device_size_ = block_device_size;
|
||||
bool CompressedSnapshotReader::Open(const char*, int) {
|
||||
errno = EINVAL;
|
||||
return false;
|
||||
}
|
||||
|
||||
ssize_t CompressedSnapshotReader::Write(const void*, size_t) {
|
||||
errno = EINVAL;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CompressedSnapshotReader::BlkIoctl(int, uint64_t, uint64_t, int*) {
|
||||
errno = EINVAL;
|
||||
return false;
|
||||
}
|
||||
|
||||
borrowed_fd CompressedSnapshotReader::GetSourceFd() {
|
||||
|
|
@ -26,36 +26,16 @@
|
|||
namespace android {
|
||||
namespace snapshot {
|
||||
|
||||
class ReadOnlyFileDescriptor : public chromeos_update_engine::FileDescriptor {
|
||||
class CompressedSnapshotReader : public chromeos_update_engine::FileDescriptor {
|
||||
public:
|
||||
CompressedSnapshotReader(std::unique_ptr<ICowReader>&& cow,
|
||||
const std::optional<std::string>& source_device,
|
||||
std::optional<uint64_t> block_dev_size);
|
||||
|
||||
bool Open(const char* path, int flags, mode_t mode) override;
|
||||
bool Open(const char* path, int flags) override;
|
||||
ssize_t Write(const void* buf, size_t count) override;
|
||||
bool BlkIoctl(int request, uint64_t start, uint64_t length, int* result) override;
|
||||
};
|
||||
|
||||
class ReadFdFileDescriptor : public ReadOnlyFileDescriptor {
|
||||
public:
|
||||
explicit ReadFdFileDescriptor(android::base::unique_fd&& fd);
|
||||
|
||||
ssize_t Read(void* buf, size_t count) override;
|
||||
off64_t Seek(off64_t offset, int whence) override;
|
||||
uint64_t BlockDevSize() override;
|
||||
bool Close() override;
|
||||
bool IsSettingErrno() override;
|
||||
bool IsOpen() override;
|
||||
bool Flush() override;
|
||||
|
||||
private:
|
||||
android::base::unique_fd fd_;
|
||||
};
|
||||
|
||||
class CompressedSnapshotReader : public ReadOnlyFileDescriptor {
|
||||
public:
|
||||
bool SetCow(std::unique_ptr<CowReader>&& cow);
|
||||
void SetSourceDevice(const std::string& source_device);
|
||||
void SetBlockDeviceSize(uint64_t block_device_size);
|
||||
|
||||
ssize_t Read(void* buf, size_t count) override;
|
||||
off64_t Seek(off64_t offset, int whence) override;
|
||||
uint64_t BlockDevSize() override;
|
||||
|
|
@ -68,7 +48,7 @@ class CompressedSnapshotReader : public ReadOnlyFileDescriptor {
|
|||
ssize_t ReadBlock(uint64_t chunk, size_t start_offset, void* buffer, size_t size);
|
||||
android::base::borrowed_fd GetSourceFd();
|
||||
|
||||
std::unique_ptr<CowReader> cow_;
|
||||
std::unique_ptr<ICowReader> cow_;
|
||||
std::unique_ptr<ICowOpIter> op_iter_;
|
||||
uint32_t block_size_ = 0;
|
||||
|
||||
|
|
@ -12,8 +12,6 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <libsnapshot/snapshot.h>
|
||||
|
||||
#include <unordered_set>
|
||||
|
||||
#include <android-base/file.h>
|
||||
|
|
@ -61,7 +59,7 @@ class OfflineSnapshotTest : public ::testing::Test {
|
|||
ASSERT_EQ(fsync(base_->fd), 0);
|
||||
}
|
||||
|
||||
void WriteCow(ISnapshotWriter* writer) {
|
||||
void WriteCow(ICowWriter* writer) {
|
||||
std::string new_block = MakeNewBlockString();
|
||||
std::string xor_block = MakeXorBlockString();
|
||||
|
||||
|
|
@ -72,8 +70,8 @@ class OfflineSnapshotTest : public ::testing::Test {
|
|||
ASSERT_TRUE(writer->Finalize());
|
||||
}
|
||||
|
||||
void TestBlockReads(ISnapshotWriter* writer) {
|
||||
auto reader = writer->OpenReader();
|
||||
void TestBlockReads(ICowWriter* writer) {
|
||||
auto reader = writer->OpenFileDescriptor(base_->path);
|
||||
ASSERT_NE(reader, nullptr);
|
||||
|
||||
// Test that unchanged blocks are not modified.
|
||||
|
|
@ -117,8 +115,8 @@ class OfflineSnapshotTest : public ::testing::Test {
|
|||
ASSERT_EQ(two_blocks, zeroes);
|
||||
}
|
||||
|
||||
void TestByteReads(ISnapshotWriter* writer) {
|
||||
auto reader = writer->OpenReader();
|
||||
void TestByteReads(ICowWriter* writer) {
|
||||
auto reader = writer->OpenFileDescriptor(base_->path);
|
||||
ASSERT_NE(reader, nullptr);
|
||||
|
||||
std::string blob(kBlockSize * 3, 'x');
|
||||
|
|
@ -154,7 +152,7 @@ class OfflineSnapshotTest : public ::testing::Test {
|
|||
ASSERT_EQ(got, expected);
|
||||
}
|
||||
|
||||
void TestReads(ISnapshotWriter* writer) {
|
||||
void TestReads(ICowWriter* writer) {
|
||||
ASSERT_NO_FATAL_FAILURE(TestBlockReads(writer));
|
||||
ASSERT_NO_FATAL_FAILURE(TestByteReads(writer));
|
||||
}
|
||||
|
|
@ -186,10 +184,7 @@ TEST_F(OfflineSnapshotTest, CompressedSnapshot) {
|
|||
unique_fd cow_fd(dup(cow_->fd));
|
||||
ASSERT_GE(cow_fd, 0);
|
||||
|
||||
auto writer = std::make_unique<CompressedSnapshotWriter>(options);
|
||||
writer->SetSourceDevice(base_->path);
|
||||
ASSERT_TRUE(writer->SetCowDevice(std::move(cow_fd)));
|
||||
ASSERT_TRUE(writer->Initialize());
|
||||
auto writer = CreateCowWriter(kDefaultCowVersion, options, std::move(cow_fd));
|
||||
ASSERT_NO_FATAL_FAILURE(WriteCow(writer.get()));
|
||||
ASSERT_NO_FATAL_FAILURE(TestReads(writer.get()));
|
||||
}
|
||||
|
|
@ -21,6 +21,7 @@
|
|||
#include <unistd.h>
|
||||
|
||||
#include <android-base/logging.h>
|
||||
#include "snapshot_reader.h"
|
||||
|
||||
// The info messages here are spammy, but as useful for update_engine. Disable
|
||||
// them when running on the host.
|
||||
|
|
@ -159,5 +160,36 @@ bool CowWriterBase::ValidateNewBlock(uint64_t new_block) {
|
|||
return true;
|
||||
}
|
||||
|
||||
std::unique_ptr<ICowReader> CowWriterBase::OpenReader() {
|
||||
unique_fd cow_fd(fcntl(fd_.get(), F_DUPFD | F_DUPFD_CLOEXEC, 0));
|
||||
if (cow_fd < 0) {
|
||||
PLOG(ERROR) << "CowWriterV2::OpenReander: dup COW device";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto cow = std::make_unique<CowReader>();
|
||||
if (!cow->Parse(std::move(cow_fd))) {
|
||||
LOG(ERROR) << "CowWriterV2::OpenReader: unable to read COW";
|
||||
return nullptr;
|
||||
}
|
||||
return cow;
|
||||
}
|
||||
|
||||
std::unique_ptr<chromeos_update_engine::FileDescriptor> CowWriterBase::OpenFileDescriptor(
|
||||
const std::optional<std::string>& source_device) {
|
||||
auto reader = OpenReader();
|
||||
if (!reader) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::optional<uint64_t> block_dev_size;
|
||||
if (options_.max_blocks) {
|
||||
block_dev_size = {*options_.max_blocks * options_.block_size};
|
||||
}
|
||||
|
||||
return std::make_unique<CompressedSnapshotReader>(std::move(reader), source_device,
|
||||
block_dev_size);
|
||||
}
|
||||
|
||||
} // namespace snapshot
|
||||
} // namespace android
|
||||
|
|
|
|||
|
|
@ -43,6 +43,9 @@ class CowWriterBase : public ICowWriter {
|
|||
bool AddSequenceData(size_t num_ops, const uint32_t* data) override;
|
||||
uint32_t GetBlockSize() const override { return options_.block_size; }
|
||||
std::optional<uint32_t> GetMaxBlocks() const override { return options_.max_blocks; }
|
||||
std::unique_ptr<ICowReader> OpenReader() override;
|
||||
std::unique_ptr<FileDescriptor> OpenFileDescriptor(
|
||||
const std::optional<std::string>& source_device) override;
|
||||
|
||||
const CowOptions& options() const { return options_; }
|
||||
|
||||
|
|
|
|||
|
|
@ -45,10 +45,9 @@
|
|||
#include <android/snapshot/snapshot.pb.h>
|
||||
#include <libsnapshot/snapshot_stats.h>
|
||||
#include "device_info.h"
|
||||
#include "libsnapshot_cow/writer_v2.h"
|
||||
#include "libsnapshot_cow/parser_v2.h"
|
||||
#include "partition_cow_creator.h"
|
||||
#include "snapshot_metadata_updater.h"
|
||||
#include "snapshot_reader.h"
|
||||
#include "utility.h"
|
||||
|
||||
namespace android {
|
||||
|
|
@ -3288,7 +3287,7 @@ Return SnapshotManager::CreateUpdateSnapshots(const DeltaArchiveManifest& manife
|
|||
return Return::Error();
|
||||
}
|
||||
|
||||
ret = InitializeUpdateSnapshots(lock.get(), target_metadata.get(),
|
||||
ret = InitializeUpdateSnapshots(lock.get(), dap_metadata.cow_version(), target_metadata.get(),
|
||||
exported_target_metadata.get(), target_suffix,
|
||||
all_snapshot_status);
|
||||
if (!ret.is_ok()) return ret;
|
||||
|
|
@ -3510,7 +3509,7 @@ Return SnapshotManager::CreateUpdateSnapshotsInternal(
|
|||
}
|
||||
|
||||
Return SnapshotManager::InitializeUpdateSnapshots(
|
||||
LockedFile* lock, MetadataBuilder* target_metadata,
|
||||
LockedFile* lock, uint32_t cow_version, MetadataBuilder* target_metadata,
|
||||
const LpMetadata* exported_target_metadata, const std::string& target_suffix,
|
||||
const std::map<std::string, SnapshotStatus>& all_snapshot_status) {
|
||||
CHECK(lock);
|
||||
|
|
@ -3558,8 +3557,8 @@ Return SnapshotManager::InitializeUpdateSnapshots(
|
|||
}
|
||||
options.compression = it->second.compression_algorithm();
|
||||
|
||||
CowWriterV2 writer(options, std::move(fd));
|
||||
if (!writer.Initialize(std::nullopt) || !writer.Finalize()) {
|
||||
auto writer = CreateCowWriter(cow_version, options, std::move(fd));
|
||||
if (!writer->Finalize()) {
|
||||
LOG(ERROR) << "Could not initialize COW device for " << target_partition->name();
|
||||
return Return::Error();
|
||||
}
|
||||
|
|
@ -3609,12 +3608,12 @@ bool SnapshotManager::MapUpdateSnapshot(const CreateLogicalPartitionParams& para
|
|||
return true;
|
||||
}
|
||||
|
||||
std::unique_ptr<ISnapshotWriter> SnapshotManager::OpenSnapshotWriter(
|
||||
std::unique_ptr<ICowWriter> SnapshotManager::OpenSnapshotWriter(
|
||||
const android::fs_mgr::CreateLogicalPartitionParams& params,
|
||||
const std::optional<std::string>& source_device) {
|
||||
std::optional<uint64_t> label) {
|
||||
#if defined(LIBSNAPSHOT_NO_COW_WRITE)
|
||||
(void)params;
|
||||
(void)source_device;
|
||||
(void)label;
|
||||
|
||||
LOG(ERROR) << "Snapshots cannot be written in first-stage init or recovery";
|
||||
return nullptr;
|
||||
|
|
@ -3653,16 +3652,14 @@ std::unique_ptr<ISnapshotWriter> SnapshotManager::OpenSnapshotWriter(
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
return OpenCompressedSnapshotWriter(lock.get(), source_device, params.GetPartitionName(),
|
||||
status, paths);
|
||||
return OpenCompressedSnapshotWriter(lock.get(), status, paths, label);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if !defined(LIBSNAPSHOT_NO_COW_WRITE)
|
||||
std::unique_ptr<ISnapshotWriter> SnapshotManager::OpenCompressedSnapshotWriter(
|
||||
LockedFile* lock, const std::optional<std::string>& source_device,
|
||||
[[maybe_unused]] const std::string& partition_name, const SnapshotStatus& status,
|
||||
const SnapshotPaths& paths) {
|
||||
std::unique_ptr<ICowWriter> SnapshotManager::OpenCompressedSnapshotWriter(
|
||||
LockedFile* lock, const SnapshotStatus& status, const SnapshotPaths& paths,
|
||||
std::optional<uint64_t> label) {
|
||||
CHECK(lock);
|
||||
|
||||
CowOptions cow_options;
|
||||
|
|
@ -3679,11 +3676,6 @@ std::unique_ptr<ISnapshotWriter> SnapshotManager::OpenCompressedSnapshotWriter(
|
|||
// never creates this scenario.
|
||||
CHECK(status.snapshot_size() == status.device_size());
|
||||
|
||||
auto writer = std::make_unique<CompressedSnapshotWriter>(cow_options);
|
||||
if (source_device) {
|
||||
writer->SetSourceDevice(*source_device);
|
||||
}
|
||||
|
||||
std::string cow_path;
|
||||
if (!GetMappedImageDevicePath(paths.cow_device_name, &cow_path)) {
|
||||
LOG(ERROR) << "Could not determine path for " << paths.cow_device_name;
|
||||
|
|
@ -3695,12 +3687,14 @@ std::unique_ptr<ISnapshotWriter> SnapshotManager::OpenCompressedSnapshotWriter(
|
|||
PLOG(ERROR) << "OpenCompressedSnapshotWriter: open " << cow_path;
|
||||
return nullptr;
|
||||
}
|
||||
if (!writer->SetCowDevice(std::move(cow_fd))) {
|
||||
LOG(ERROR) << "Could not create COW writer from " << cow_path;
|
||||
|
||||
CowHeader header;
|
||||
if (!ReadCowHeader(cow_fd, &header)) {
|
||||
LOG(ERROR) << "OpenCompressedSnapshotWriter: read header failed";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return writer;
|
||||
return CreateCowWriter(header.prefix.major_version, cow_options, std::move(cow_fd), label);
|
||||
}
|
||||
#endif // !defined(LIBSNAPSHOT_NO_COW_WRITE)
|
||||
|
||||
|
|
|
|||
|
|
@ -154,8 +154,8 @@ ISnapshotMergeStats* SnapshotManagerStub::GetSnapshotMergeStatsInstance() {
|
|||
return &snapshot_merge_stats;
|
||||
}
|
||||
|
||||
std::unique_ptr<ISnapshotWriter> SnapshotManagerStub::OpenSnapshotWriter(
|
||||
const CreateLogicalPartitionParams&, const std::optional<std::string>&) {
|
||||
std::unique_ptr<ICowWriter> SnapshotManagerStub::OpenSnapshotWriter(
|
||||
const CreateLogicalPartitionParams&, std::optional<uint64_t>) {
|
||||
LOG(ERROR) << __FUNCTION__ << " should never be called.";
|
||||
return nullptr;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -345,7 +345,7 @@ class SnapshotTest : public ::testing::Test {
|
|||
}
|
||||
|
||||
AssertionResult MapUpdateSnapshot(const std::string& name,
|
||||
std::unique_ptr<ISnapshotWriter>* writer) {
|
||||
std::unique_ptr<ICowWriter>* writer) {
|
||||
TestPartitionOpener opener(fake_super);
|
||||
CreateLogicalPartitionParams params{
|
||||
.block_device = fake_super,
|
||||
|
|
@ -355,14 +355,10 @@ class SnapshotTest : public ::testing::Test {
|
|||
.partition_opener = &opener,
|
||||
};
|
||||
|
||||
auto old_partition = "/dev/block/mapper/" + GetOtherPartitionName(name);
|
||||
auto result = sm->OpenSnapshotWriter(params, {old_partition});
|
||||
auto result = sm->OpenSnapshotWriter(params, {});
|
||||
if (!result) {
|
||||
return AssertionFailure() << "Cannot open snapshot for writing: " << name;
|
||||
}
|
||||
if (!result->Initialize()) {
|
||||
return AssertionFailure() << "Cannot initialize snapshot for writing: " << name;
|
||||
}
|
||||
|
||||
if (writer) {
|
||||
*writer = std::move(result);
|
||||
|
|
@ -440,7 +436,7 @@ class SnapshotTest : public ::testing::Test {
|
|||
|
||||
// Prepare A/B slot for a partition named "test_partition".
|
||||
AssertionResult PrepareOneSnapshot(uint64_t device_size,
|
||||
std::unique_ptr<ISnapshotWriter>* writer = nullptr) {
|
||||
std::unique_ptr<ICowWriter>* writer = nullptr) {
|
||||
lock_ = nullptr;
|
||||
|
||||
DeltaArchiveManifest manifest;
|
||||
|
|
@ -651,7 +647,7 @@ TEST_F(SnapshotTest, Merge) {
|
|||
|
||||
bool userspace_snapshots = false;
|
||||
if (snapuserd_required_) {
|
||||
std::unique_ptr<ISnapshotWriter> writer;
|
||||
std::unique_ptr<ICowWriter> writer;
|
||||
ASSERT_TRUE(PrepareOneSnapshot(kDeviceSize, &writer));
|
||||
|
||||
userspace_snapshots = sm->UpdateUsesUserSnapshots(lock_.get());
|
||||
|
|
@ -1160,7 +1156,7 @@ class SnapshotUpdateTest : public SnapshotTest {
|
|||
|
||||
AssertionResult MapOneUpdateSnapshot(const std::string& name) {
|
||||
if (snapuserd_required_) {
|
||||
std::unique_ptr<ISnapshotWriter> writer;
|
||||
std::unique_ptr<ICowWriter> writer;
|
||||
return MapUpdateSnapshot(name, &writer);
|
||||
} else {
|
||||
std::string path;
|
||||
|
|
@ -1181,7 +1177,7 @@ class SnapshotUpdateTest : public SnapshotTest {
|
|||
AssertionResult WriteSnapshotAndHash(PartitionUpdate* partition) {
|
||||
std::string name = partition->partition_name() + "_b";
|
||||
if (snapuserd_required_) {
|
||||
std::unique_ptr<ISnapshotWriter> writer;
|
||||
std::unique_ptr<ICowWriter> writer;
|
||||
auto res = MapUpdateSnapshot(name, &writer);
|
||||
if (!res) {
|
||||
return res;
|
||||
|
|
@ -1250,7 +1246,7 @@ class SnapshotUpdateTest : public SnapshotTest {
|
|||
// It doesn't really matter the order, we just want copies that reference
|
||||
// blocks that won't exist if the partition shrinks.
|
||||
AssertionResult ShiftAllSnapshotBlocks(const std::string& name, uint64_t old_size) {
|
||||
std::unique_ptr<ISnapshotWriter> writer;
|
||||
std::unique_ptr<ICowWriter> writer;
|
||||
if (auto res = MapUpdateSnapshot(name, &writer); !res) {
|
||||
return res;
|
||||
}
|
||||
|
|
@ -1273,7 +1269,13 @@ class SnapshotUpdateTest : public SnapshotTest {
|
|||
return AssertionFailure() << "Unable to finalize writer for " << name;
|
||||
}
|
||||
|
||||
auto hash = HashSnapshot(writer.get());
|
||||
auto old_partition = "/dev/block/mapper/" + GetOtherPartitionName(name);
|
||||
auto reader = writer->OpenFileDescriptor(old_partition);
|
||||
if (!reader) {
|
||||
return AssertionFailure() << "Could not open file descriptor for " << name;
|
||||
}
|
||||
|
||||
auto hash = HashSnapshot(reader.get());
|
||||
if (hash.empty()) {
|
||||
return AssertionFailure() << "Unable to hash snapshot writer for " << name;
|
||||
}
|
||||
|
|
@ -1428,7 +1430,7 @@ TEST_F(SnapshotUpdateTest, DuplicateOps) {
|
|||
for (auto* partition : partitions) {
|
||||
AddOperation(partition);
|
||||
|
||||
std::unique_ptr<ISnapshotWriter> writer;
|
||||
std::unique_ptr<ICowWriter> writer;
|
||||
auto res = MapUpdateSnapshot(partition->partition_name() + "_b", &writer);
|
||||
ASSERT_TRUE(res);
|
||||
ASSERT_TRUE(writer->AddZeroBlocks(0, 1));
|
||||
|
|
|
|||
|
|
@ -1,179 +0,0 @@
|
|||
//
|
||||
// Copyright (C) 2020 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.
|
||||
//
|
||||
|
||||
#include <libsnapshot/snapshot_writer.h>
|
||||
|
||||
#include <android-base/file.h>
|
||||
#include <android-base/logging.h>
|
||||
#include <payload_consumer/file_descriptor.h>
|
||||
#include "libsnapshot_cow/writer_v2.h"
|
||||
#include "snapshot_reader.h"
|
||||
|
||||
namespace android {
|
||||
namespace snapshot {
|
||||
|
||||
using android::base::borrowed_fd;
|
||||
using android::base::unique_fd;
|
||||
using chromeos_update_engine::FileDescriptor;
|
||||
|
||||
void CompressedSnapshotWriter::SetSourceDevice(const std::string& source_device) {
|
||||
source_device_ = {source_device};
|
||||
}
|
||||
|
||||
borrowed_fd CompressedSnapshotWriter::GetSourceFd() {
|
||||
if (!source_device_) {
|
||||
LOG(ERROR) << "Attempted to read from source device but none was set";
|
||||
return borrowed_fd{-1};
|
||||
}
|
||||
|
||||
if (source_fd_ < 0) {
|
||||
source_fd_.reset(open(source_device_->c_str(), O_RDONLY | O_CLOEXEC));
|
||||
if (source_fd_ < 0) {
|
||||
PLOG(ERROR) << "open " << *source_device_;
|
||||
return borrowed_fd{-1};
|
||||
}
|
||||
}
|
||||
return source_fd_;
|
||||
}
|
||||
|
||||
CompressedSnapshotWriter::CompressedSnapshotWriter(const CowOptions& options) : options_(options) {}
|
||||
|
||||
bool CompressedSnapshotWriter::SetCowDevice(android::base::unique_fd&& cow_device) {
|
||||
cow_device_ = std::move(cow_device);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CompressedSnapshotWriter::Finalize() {
|
||||
return cow_->Finalize();
|
||||
}
|
||||
|
||||
uint64_t CompressedSnapshotWriter::GetCowSize() {
|
||||
return cow_->GetCowSize();
|
||||
}
|
||||
|
||||
std::unique_ptr<CowReader> CompressedSnapshotWriter::OpenCowReader() const {
|
||||
unique_fd cow_fd(dup(cow_device_.get()));
|
||||
if (cow_fd < 0) {
|
||||
PLOG(ERROR) << "dup COW device";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto cow = std::make_unique<CowReader>();
|
||||
if (!cow->Parse(std::move(cow_fd))) {
|
||||
LOG(ERROR) << "Unable to read COW";
|
||||
return nullptr;
|
||||
}
|
||||
return cow;
|
||||
}
|
||||
|
||||
bool CompressedSnapshotWriter::VerifyMergeOps() const noexcept {
|
||||
auto cow_reader = OpenCowReader();
|
||||
if (cow_reader == nullptr) {
|
||||
LOG(ERROR) << "Couldn't open CowReader";
|
||||
return false;
|
||||
}
|
||||
return cow_reader->VerifyMergeOps();
|
||||
}
|
||||
|
||||
std::unique_ptr<FileDescriptor> CompressedSnapshotWriter::OpenReader() {
|
||||
auto cow = OpenCowReader();
|
||||
if (cow == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto reader = std::make_unique<CompressedSnapshotReader>();
|
||||
if (!reader->SetCow(std::move(cow))) {
|
||||
LOG(ERROR) << "Unable to initialize COW reader";
|
||||
return nullptr;
|
||||
}
|
||||
if (source_device_) {
|
||||
reader->SetSourceDevice(*source_device_);
|
||||
}
|
||||
|
||||
if (options_.max_blocks) {
|
||||
reader->SetBlockDeviceSize(*options_.max_blocks * options_.block_size);
|
||||
}
|
||||
|
||||
return reader;
|
||||
}
|
||||
|
||||
bool CompressedSnapshotWriter::AddCopy(uint64_t new_block, uint64_t old_block,
|
||||
uint64_t num_blocks) {
|
||||
return cow_->AddCopy(new_block, old_block, num_blocks);
|
||||
}
|
||||
|
||||
bool CompressedSnapshotWriter::AddRawBlocks(uint64_t new_block_start, const void* data,
|
||||
size_t size) {
|
||||
return cow_->AddRawBlocks(new_block_start, data, size);
|
||||
}
|
||||
|
||||
bool CompressedSnapshotWriter::AddXorBlocks(uint32_t new_block_start, const void* data, size_t size,
|
||||
uint32_t old_block, uint16_t offset) {
|
||||
return cow_->AddXorBlocks(new_block_start, data, size, old_block, offset);
|
||||
}
|
||||
|
||||
bool CompressedSnapshotWriter::AddZeroBlocks(uint64_t new_block_start, uint64_t num_blocks) {
|
||||
return cow_->AddZeroBlocks(new_block_start, num_blocks);
|
||||
}
|
||||
|
||||
bool CompressedSnapshotWriter::AddLabel(uint64_t label) {
|
||||
return cow_->AddLabel(label);
|
||||
}
|
||||
|
||||
bool CompressedSnapshotWriter::AddSequenceData(size_t num_ops, const uint32_t* data) {
|
||||
return cow_->AddSequenceData(num_ops, data);
|
||||
}
|
||||
|
||||
bool CompressedSnapshotWriter::Initialize() {
|
||||
unique_fd cow_fd(dup(cow_device_.get()));
|
||||
if (cow_fd < 0) {
|
||||
PLOG(ERROR) << "dup COW device";
|
||||
return false;
|
||||
}
|
||||
|
||||
auto cow = std::make_unique<CowWriterV2>(options_, std::move(cow_fd));
|
||||
if (!cow->Initialize(std::nullopt)) {
|
||||
return false;
|
||||
}
|
||||
cow_ = std::move(cow);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CompressedSnapshotWriter::InitializeAppend(uint64_t label) {
|
||||
unique_fd cow_fd(dup(cow_device_.get()));
|
||||
if (cow_fd < 0) {
|
||||
PLOG(ERROR) << "dup COW device";
|
||||
return false;
|
||||
}
|
||||
|
||||
auto cow = std::make_unique<CowWriterV2>(options_, std::move(cow_fd));
|
||||
if (!cow->Initialize(label)) {
|
||||
return false;
|
||||
}
|
||||
cow_ = std::move(cow);
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32_t CompressedSnapshotWriter::GetBlockSize() const {
|
||||
return cow_->GetBlockSize();
|
||||
}
|
||||
|
||||
std::optional<uint32_t> CompressedSnapshotWriter::GetMaxBlocks() const {
|
||||
return cow_->GetMaxBlocks();
|
||||
}
|
||||
|
||||
} // namespace snapshot
|
||||
} // namespace android
|
||||
|
|
@ -1,62 +0,0 @@
|
|||
//
|
||||
// Copyright (C) 2021 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.
|
||||
//
|
||||
|
||||
#include <libsnapshot/snapshot.h>
|
||||
|
||||
#include <unordered_set>
|
||||
|
||||
#include <android-base/file.h>
|
||||
#include <gtest/gtest.h>
|
||||
#include <libsnapshot/snapshot_writer.h>
|
||||
#include <payload_consumer/file_descriptor.h>
|
||||
|
||||
namespace android::snapshot {
|
||||
class CompressedSnapshotWriterTest : public ::testing::Test {
|
||||
public:
|
||||
static constexpr size_t BLOCK_SIZE = 4096;
|
||||
};
|
||||
|
||||
TEST_F(CompressedSnapshotWriterTest, ReadAfterWrite) {
|
||||
TemporaryFile cow_device_file{};
|
||||
android::snapshot::CowOptions options{.block_size = BLOCK_SIZE};
|
||||
android::snapshot::CompressedSnapshotWriter snapshot_writer{options};
|
||||
ASSERT_TRUE(snapshot_writer.SetCowDevice(android::base::unique_fd{cow_device_file.fd}));
|
||||
ASSERT_TRUE(snapshot_writer.Initialize());
|
||||
std::vector<unsigned char> buffer;
|
||||
buffer.resize(BLOCK_SIZE);
|
||||
std::fill(buffer.begin(), buffer.end(), 123);
|
||||
|
||||
ASSERT_TRUE(snapshot_writer.AddRawBlocks(0, buffer.data(), buffer.size()));
|
||||
ASSERT_TRUE(snapshot_writer.Finalize());
|
||||
auto cow_reader = snapshot_writer.OpenReader();
|
||||
ASSERT_NE(cow_reader, nullptr);
|
||||
ASSERT_TRUE(snapshot_writer.AddRawBlocks(1, buffer.data(), buffer.size()));
|
||||
ASSERT_TRUE(snapshot_writer.AddRawBlocks(2, buffer.data(), buffer.size()));
|
||||
ASSERT_TRUE(snapshot_writer.Finalize());
|
||||
// After wrigin some data, if we call OpenReader() again, writes should
|
||||
// be visible to the newly opened reader. update_engine relies on this
|
||||
// behavior for verity writes.
|
||||
cow_reader = snapshot_writer.OpenReader();
|
||||
ASSERT_NE(cow_reader, nullptr);
|
||||
std::vector<unsigned char> read_back;
|
||||
read_back.resize(buffer.size());
|
||||
cow_reader->Seek(BLOCK_SIZE, SEEK_SET);
|
||||
const auto bytes_read = cow_reader->Read(read_back.data(), read_back.size());
|
||||
ASSERT_EQ((size_t)(bytes_read), BLOCK_SIZE);
|
||||
ASSERT_EQ(read_back, buffer);
|
||||
}
|
||||
|
||||
} // namespace android::snapshot
|
||||
|
|
@ -133,7 +133,6 @@ bool CreateTestUpdate(SnapshotManager* sm) {
|
|||
|
||||
// Write the "new" system partition.
|
||||
auto system_target_name = "system" + target_slot;
|
||||
auto source_device = "/dev/block/mapper/" + system_source_name;
|
||||
CreateLogicalPartitionParams clpp = {
|
||||
.block_device = fs_mgr_get_super_partition_name(target_slot_number),
|
||||
.metadata_slot = {target_slot_number},
|
||||
|
|
@ -141,15 +140,11 @@ bool CreateTestUpdate(SnapshotManager* sm) {
|
|||
.partition_opener = &opener,
|
||||
.timeout_ms = 10s,
|
||||
};
|
||||
auto writer = sm->OpenSnapshotWriter(clpp, {source_device});
|
||||
auto writer = sm->OpenSnapshotWriter(clpp, std::nullopt);
|
||||
if (!writer) {
|
||||
std::cerr << "Could not open snapshot writer.\n";
|
||||
return false;
|
||||
}
|
||||
if (!writer->Initialize()) {
|
||||
std::cerr << "Could not initialize snapshot for writing.\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
for (uint64_t block = 0; block < system_source_size / 4096; block++) {
|
||||
if (!writer->AddCopy(block, block)) {
|
||||
|
|
|
|||
|
|
@ -130,12 +130,7 @@ bool WriteRandomData(const std::string& path, std::optional<size_t> expect_size,
|
|||
return true;
|
||||
}
|
||||
|
||||
std::string HashSnapshot(ISnapshotWriter* writer) {
|
||||
auto reader = writer->OpenReader();
|
||||
if (!reader) {
|
||||
return {};
|
||||
}
|
||||
|
||||
std::string HashSnapshot(ICowWriter::FileDescriptor* reader) {
|
||||
SHA256_CTX ctx;
|
||||
SHA256_Init(&ctx);
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue