1 //
2 // Copyright (C) 2020 The Android Open Source Project
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 // http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 //
16
17 #include <libsnapshot/snapshot_writer.h>
18
19 #include <android-base/file.h>
20 #include <android-base/logging.h>
21 #include <payload_consumer/file_descriptor.h>
22 #include "snapshot_reader.h"
23
24 namespace android {
25 namespace snapshot {
26
27 using android::base::borrowed_fd;
28 using android::base::unique_fd;
29 using chromeos_update_engine::FileDescriptor;
30
ISnapshotWriter(const CowOptions & options)31 ISnapshotWriter::ISnapshotWriter(const CowOptions& options) : ICowWriter(options) {}
32
SetSourceDevice(const std::string & source_device)33 void ISnapshotWriter::SetSourceDevice(const std::string& source_device) {
34 source_device_ = {source_device};
35 }
36
GetSourceFd()37 borrowed_fd ISnapshotWriter::GetSourceFd() {
38 if (!source_device_) {
39 LOG(ERROR) << "Attempted to read from source device but none was set";
40 return borrowed_fd{-1};
41 }
42
43 if (source_fd_ < 0) {
44 source_fd_.reset(open(source_device_->c_str(), O_RDONLY | O_CLOEXEC));
45 if (source_fd_ < 0) {
46 PLOG(ERROR) << "open " << *source_device_;
47 return borrowed_fd{-1};
48 }
49 }
50 return source_fd_;
51 }
52
CompressedSnapshotWriter(const CowOptions & options)53 CompressedSnapshotWriter::CompressedSnapshotWriter(const CowOptions& options)
54 : ISnapshotWriter(options) {}
55
SetCowDevice(android::base::unique_fd && cow_device)56 bool CompressedSnapshotWriter::SetCowDevice(android::base::unique_fd&& cow_device) {
57 cow_device_ = std::move(cow_device);
58 cow_ = std::make_unique<CowWriter>(options_);
59 return true;
60 }
61
Finalize()62 bool CompressedSnapshotWriter::Finalize() {
63 return cow_->Finalize();
64 }
65
GetCowSize()66 uint64_t CompressedSnapshotWriter::GetCowSize() {
67 return cow_->GetCowSize();
68 }
69
OpenCowReader() const70 std::unique_ptr<CowReader> CompressedSnapshotWriter::OpenCowReader() const {
71 unique_fd cow_fd(dup(cow_device_.get()));
72 if (cow_fd < 0) {
73 PLOG(ERROR) << "dup COW device";
74 return nullptr;
75 }
76
77 auto cow = std::make_unique<CowReader>();
78 if (!cow->Parse(std::move(cow_fd))) {
79 LOG(ERROR) << "Unable to read COW";
80 return nullptr;
81 }
82 return cow;
83 }
84
VerifyMergeOps() const85 bool CompressedSnapshotWriter::VerifyMergeOps() const noexcept {
86 auto cow_reader = OpenCowReader();
87 if (cow_reader == nullptr) {
88 LOG(ERROR) << "Couldn't open CowReader";
89 return false;
90 }
91 return cow_reader->VerifyMergeOps();
92 }
93
OpenReader()94 std::unique_ptr<FileDescriptor> CompressedSnapshotWriter::OpenReader() {
95 auto cow = OpenCowReader();
96
97 auto reader = std::make_unique<CompressedSnapshotReader>();
98 if (!reader->SetCow(std::move(cow))) {
99 LOG(ERROR) << "Unable to initialize COW reader";
100 return nullptr;
101 }
102 if (source_device_) {
103 reader->SetSourceDevice(*source_device_);
104 }
105
106 const auto& cow_options = options();
107 if (cow_options.max_blocks) {
108 reader->SetBlockDeviceSize(*cow_options.max_blocks * cow_options.block_size);
109 }
110
111 return reader;
112 }
113
EmitCopy(uint64_t new_block,uint64_t old_block)114 bool CompressedSnapshotWriter::EmitCopy(uint64_t new_block, uint64_t old_block) {
115 return cow_->AddCopy(new_block, old_block);
116 }
117
EmitRawBlocks(uint64_t new_block_start,const void * data,size_t size)118 bool CompressedSnapshotWriter::EmitRawBlocks(uint64_t new_block_start, const void* data,
119 size_t size) {
120 return cow_->AddRawBlocks(new_block_start, data, size);
121 }
122
EmitXorBlocks(uint32_t new_block_start,const void * data,size_t size,uint32_t old_block,uint16_t offset)123 bool CompressedSnapshotWriter::EmitXorBlocks(uint32_t new_block_start, const void* data,
124 size_t size, uint32_t old_block, uint16_t offset) {
125 return cow_->AddXorBlocks(new_block_start, data, size, old_block, offset);
126 }
127
EmitZeroBlocks(uint64_t new_block_start,uint64_t num_blocks)128 bool CompressedSnapshotWriter::EmitZeroBlocks(uint64_t new_block_start, uint64_t num_blocks) {
129 return cow_->AddZeroBlocks(new_block_start, num_blocks);
130 }
131
EmitLabel(uint64_t label)132 bool CompressedSnapshotWriter::EmitLabel(uint64_t label) {
133 return cow_->AddLabel(label);
134 }
135
EmitSequenceData(size_t num_ops,const uint32_t * data)136 bool CompressedSnapshotWriter::EmitSequenceData(size_t num_ops, const uint32_t* data) {
137 return cow_->AddSequenceData(num_ops, data);
138 }
139
Initialize()140 bool CompressedSnapshotWriter::Initialize() {
141 return cow_->Initialize(cow_device_);
142 }
143
InitializeAppend(uint64_t label)144 bool CompressedSnapshotWriter::InitializeAppend(uint64_t label) {
145 return cow_->InitializeAppend(cow_device_, label);
146 }
147
OnlineKernelSnapshotWriter(const CowOptions & options)148 OnlineKernelSnapshotWriter::OnlineKernelSnapshotWriter(const CowOptions& options)
149 : ISnapshotWriter(options) {}
150
SetSnapshotDevice(android::base::unique_fd && snapshot_fd,uint64_t cow_size)151 void OnlineKernelSnapshotWriter::SetSnapshotDevice(android::base::unique_fd&& snapshot_fd,
152 uint64_t cow_size) {
153 snapshot_fd_ = std::move(snapshot_fd);
154 cow_size_ = cow_size;
155 }
156
Finalize()157 bool OnlineKernelSnapshotWriter::Finalize() {
158 if (fsync(snapshot_fd_.get()) < 0) {
159 PLOG(ERROR) << "fsync";
160 return false;
161 }
162 return true;
163 }
164
EmitRawBlocks(uint64_t new_block_start,const void * data,size_t size)165 bool OnlineKernelSnapshotWriter::EmitRawBlocks(uint64_t new_block_start, const void* data,
166 size_t size) {
167 uint64_t offset = new_block_start * options_.block_size;
168 if (lseek(snapshot_fd_.get(), offset, SEEK_SET) < 0) {
169 PLOG(ERROR) << "EmitRawBlocks lseek to offset " << offset;
170 return false;
171 }
172 if (!android::base::WriteFully(snapshot_fd_, data, size)) {
173 PLOG(ERROR) << "EmitRawBlocks write";
174 return false;
175 }
176 return true;
177 }
178
EmitXorBlocks(uint32_t,const void *,size_t,uint32_t,uint16_t)179 bool OnlineKernelSnapshotWriter::EmitXorBlocks(uint32_t, const void*, size_t, uint32_t, uint16_t) {
180 LOG(ERROR) << "EmitXorBlocks not implemented.";
181 return false;
182 }
183
EmitZeroBlocks(uint64_t new_block_start,uint64_t num_blocks)184 bool OnlineKernelSnapshotWriter::EmitZeroBlocks(uint64_t new_block_start, uint64_t num_blocks) {
185 std::string zeroes(options_.block_size, 0);
186 for (uint64_t i = 0; i < num_blocks; i++) {
187 if (!EmitRawBlocks(new_block_start + i, zeroes.data(), zeroes.size())) {
188 return false;
189 }
190 }
191 return true;
192 }
193
EmitCopy(uint64_t new_block,uint64_t old_block)194 bool OnlineKernelSnapshotWriter::EmitCopy(uint64_t new_block, uint64_t old_block) {
195 auto source_fd = GetSourceFd();
196 if (source_fd < 0) {
197 return false;
198 }
199
200 std::string buffer(options_.block_size, 0);
201 uint64_t offset = old_block * options_.block_size;
202 if (!android::base::ReadFullyAtOffset(source_fd, buffer.data(), buffer.size(), offset)) {
203 PLOG(ERROR) << "EmitCopy read";
204 return false;
205 }
206 return EmitRawBlocks(new_block, buffer.data(), buffer.size());
207 }
208
EmitLabel(uint64_t)209 bool OnlineKernelSnapshotWriter::EmitLabel(uint64_t) {
210 // Not Needed
211 return true;
212 }
213
EmitSequenceData(size_t,const uint32_t *)214 bool OnlineKernelSnapshotWriter::EmitSequenceData(size_t, const uint32_t*) {
215 // Not Needed
216 return true;
217 }
218
OpenReader()219 std::unique_ptr<FileDescriptor> OnlineKernelSnapshotWriter::OpenReader() {
220 unique_fd fd(dup(snapshot_fd_.get()));
221 if (fd < 0) {
222 PLOG(ERROR) << "dup2 failed in OpenReader";
223 return nullptr;
224 }
225 return std::make_unique<ReadFdFileDescriptor>(std::move(fd));
226 }
227
228 } // namespace snapshot
229 } // namespace android
230