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     if (cow == nullptr) {
97         return nullptr;
98     }
99 
100     auto reader = std::make_unique<CompressedSnapshotReader>();
101     if (!reader->SetCow(std::move(cow))) {
102         LOG(ERROR) << "Unable to initialize COW reader";
103         return nullptr;
104     }
105     if (source_device_) {
106         reader->SetSourceDevice(*source_device_);
107     }
108 
109     const auto& cow_options = options();
110     if (cow_options.max_blocks) {
111         reader->SetBlockDeviceSize(*cow_options.max_blocks * cow_options.block_size);
112     }
113 
114     return reader;
115 }
116 
EmitCopy(uint64_t new_block,uint64_t old_block,uint64_t num_blocks)117 bool CompressedSnapshotWriter::EmitCopy(uint64_t new_block, uint64_t old_block,
118                                         uint64_t num_blocks) {
119     return cow_->AddCopy(new_block, old_block, num_blocks);
120 }
121 
EmitRawBlocks(uint64_t new_block_start,const void * data,size_t size)122 bool CompressedSnapshotWriter::EmitRawBlocks(uint64_t new_block_start, const void* data,
123                                              size_t size) {
124     return cow_->AddRawBlocks(new_block_start, data, size);
125 }
126 
EmitXorBlocks(uint32_t new_block_start,const void * data,size_t size,uint32_t old_block,uint16_t offset)127 bool CompressedSnapshotWriter::EmitXorBlocks(uint32_t new_block_start, const void* data,
128                                              size_t size, uint32_t old_block, uint16_t offset) {
129     return cow_->AddXorBlocks(new_block_start, data, size, old_block, offset);
130 }
131 
EmitZeroBlocks(uint64_t new_block_start,uint64_t num_blocks)132 bool CompressedSnapshotWriter::EmitZeroBlocks(uint64_t new_block_start, uint64_t num_blocks) {
133     return cow_->AddZeroBlocks(new_block_start, num_blocks);
134 }
135 
EmitLabel(uint64_t label)136 bool CompressedSnapshotWriter::EmitLabel(uint64_t label) {
137     return cow_->AddLabel(label);
138 }
139 
EmitSequenceData(size_t num_ops,const uint32_t * data)140 bool CompressedSnapshotWriter::EmitSequenceData(size_t num_ops, const uint32_t* data) {
141     return cow_->AddSequenceData(num_ops, data);
142 }
143 
Initialize()144 bool CompressedSnapshotWriter::Initialize() {
145     return cow_->Initialize(cow_device_);
146 }
147 
InitializeAppend(uint64_t label)148 bool CompressedSnapshotWriter::InitializeAppend(uint64_t label) {
149     return cow_->InitializeAppend(cow_device_, label);
150 }
151 
OnlineKernelSnapshotWriter(const CowOptions & options)152 OnlineKernelSnapshotWriter::OnlineKernelSnapshotWriter(const CowOptions& options)
153     : ISnapshotWriter(options) {}
154 
SetSnapshotDevice(android::base::unique_fd && snapshot_fd,uint64_t cow_size)155 void OnlineKernelSnapshotWriter::SetSnapshotDevice(android::base::unique_fd&& snapshot_fd,
156                                                    uint64_t cow_size) {
157     snapshot_fd_ = std::move(snapshot_fd);
158     cow_size_ = cow_size;
159 }
160 
Finalize()161 bool OnlineKernelSnapshotWriter::Finalize() {
162     if (fsync(snapshot_fd_.get()) < 0) {
163         PLOG(ERROR) << "fsync";
164         return false;
165     }
166     return true;
167 }
168 
EmitRawBlocks(uint64_t new_block_start,const void * data,size_t size)169 bool OnlineKernelSnapshotWriter::EmitRawBlocks(uint64_t new_block_start, const void* data,
170                                                size_t size) {
171     uint64_t offset = new_block_start * options_.block_size;
172     if (lseek(snapshot_fd_.get(), offset, SEEK_SET) < 0) {
173         PLOG(ERROR) << "EmitRawBlocks lseek to offset " << offset;
174         return false;
175     }
176     if (!android::base::WriteFully(snapshot_fd_, data, size)) {
177         PLOG(ERROR) << "EmitRawBlocks write";
178         return false;
179     }
180     return true;
181 }
182 
EmitXorBlocks(uint32_t,const void *,size_t,uint32_t,uint16_t)183 bool OnlineKernelSnapshotWriter::EmitXorBlocks(uint32_t, const void*, size_t, uint32_t, uint16_t) {
184     LOG(ERROR) << "EmitXorBlocks not implemented.";
185     return false;
186 }
187 
EmitZeroBlocks(uint64_t new_block_start,uint64_t num_blocks)188 bool OnlineKernelSnapshotWriter::EmitZeroBlocks(uint64_t new_block_start, uint64_t num_blocks) {
189     std::string zeroes(options_.block_size, 0);
190     for (uint64_t i = 0; i < num_blocks; i++) {
191         if (!EmitRawBlocks(new_block_start + i, zeroes.data(), zeroes.size())) {
192             return false;
193         }
194     }
195     return true;
196 }
197 
EmitCopy(uint64_t new_block,uint64_t old_block,uint64_t num_blocks)198 bool OnlineKernelSnapshotWriter::EmitCopy(uint64_t new_block, uint64_t old_block,
199                                           uint64_t num_blocks) {
200     auto source_fd = GetSourceFd();
201     if (source_fd < 0) {
202         return false;
203     }
204 
205     CHECK(num_blocks != 0);
206 
207     for (size_t i = 0; i < num_blocks; i++) {
208         std::string buffer(options_.block_size, 0);
209         uint64_t offset = (old_block + i) * options_.block_size;
210         if (!android::base::ReadFullyAtOffset(source_fd, buffer.data(), buffer.size(), offset)) {
211             PLOG(ERROR) << "EmitCopy read";
212             return false;
213         }
214         if (!EmitRawBlocks(new_block + i, buffer.data(), buffer.size())) {
215             PLOG(ERROR) << "EmitRawBlocks failed";
216             return false;
217         }
218     }
219 
220     return true;
221 }
222 
EmitLabel(uint64_t)223 bool OnlineKernelSnapshotWriter::EmitLabel(uint64_t) {
224     // Not Needed
225     return true;
226 }
227 
EmitSequenceData(size_t,const uint32_t *)228 bool OnlineKernelSnapshotWriter::EmitSequenceData(size_t, const uint32_t*) {
229     // Not Needed
230     return true;
231 }
232 
OpenReader()233 std::unique_ptr<FileDescriptor> OnlineKernelSnapshotWriter::OpenReader() {
234     unique_fd fd(dup(snapshot_fd_.get()));
235     if (fd < 0) {
236         PLOG(ERROR) << "dup2 failed in OpenReader";
237         return nullptr;
238     }
239     return std::make_unique<ReadFdFileDescriptor>(std::move(fd));
240 }
241 
242 }  // namespace snapshot
243 }  // namespace android
244