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 <sys/types.h>
18 #include <unistd.h>
19
20 #include <algorithm>
21 #include <optional>
22 #include <unordered_map>
23 #include <unordered_set>
24 #include <vector>
25
26 #include <android-base/file.h>
27 #include <android-base/logging.h>
28 #include <libsnapshot/cow_format.h>
29 #include <libsnapshot/cow_reader.h>
30 #include <storage_literals/storage_literals.h>
31 #include <zlib.h>
32
33 #include "cow_decompress.h"
34 #include "parser_v2.h"
35 #include "parser_v3.h"
36
37 namespace android {
38 namespace snapshot {
39
40 using namespace android::storage_literals;
41
ReadCowHeader(android::base::borrowed_fd fd,CowHeaderV3 * header)42 bool ReadCowHeader(android::base::borrowed_fd fd, CowHeaderV3* header) {
43 if (lseek(fd.get(), 0, SEEK_SET) < 0) {
44 PLOG(ERROR) << "lseek header failed";
45 return false;
46 }
47
48 memset(header, 0, sizeof(*header));
49
50 if (!android::base::ReadFully(fd, &header->prefix, sizeof(header->prefix))) {
51 return false;
52 }
53 if (header->prefix.magic != kCowMagicNumber) {
54 LOG(ERROR) << "Header Magic corrupted. Magic: " << header->prefix.magic
55 << "Expected: " << kCowMagicNumber;
56 return false;
57 }
58 if (header->prefix.header_size > sizeof(CowHeaderV3)) {
59 LOG(ERROR) << "Unknown CowHeader size (got " << header->prefix.header_size
60 << " bytes, expected at most " << sizeof(CowHeaderV3) << " bytes)";
61 return false;
62 }
63
64 if (lseek(fd.get(), 0, SEEK_SET) < 0) {
65 PLOG(ERROR) << "lseek header failed";
66 return false;
67 }
68 return android::base::ReadFully(fd, header, header->prefix.header_size);
69 }
70
CowReader(ReaderFlags reader_flag,bool is_merge)71 CowReader::CowReader(ReaderFlags reader_flag, bool is_merge)
72 : fd_(-1),
73 header_(),
74 fd_size_(0),
75 block_pos_index_(std::make_shared<std::vector<int>>()),
76 reader_flag_(reader_flag),
77 is_merge_(is_merge) {}
78
CloneCowReader()79 std::unique_ptr<CowReader> CowReader::CloneCowReader() {
80 auto cow = std::make_unique<CowReader>();
81 cow->owned_fd_.reset();
82 cow->header_ = header_;
83 cow->footer_ = footer_;
84 cow->fd_size_ = fd_size_;
85 cow->last_label_ = last_label_;
86 cow->ops_ = ops_;
87 cow->merge_op_start_ = merge_op_start_;
88 cow->num_total_data_ops_ = num_total_data_ops_;
89 cow->num_ordered_ops_to_merge_ = num_ordered_ops_to_merge_;
90 cow->xor_data_loc_ = xor_data_loc_;
91 cow->block_pos_index_ = block_pos_index_;
92 cow->is_merge_ = is_merge_;
93 return cow;
94 }
95
InitForMerge(android::base::unique_fd && fd)96 bool CowReader::InitForMerge(android::base::unique_fd&& fd) {
97 owned_fd_ = std::move(fd);
98 fd_ = owned_fd_.get();
99
100 auto pos = lseek(fd_.get(), 0, SEEK_END);
101 if (pos < 0) {
102 PLOG(ERROR) << "lseek end failed";
103 return false;
104 }
105 fd_size_ = pos;
106
107 if (lseek(fd_.get(), 0, SEEK_SET) < 0) {
108 PLOG(ERROR) << "lseek header failed";
109 return false;
110 }
111
112 CHECK_GE(header_.prefix.header_size, sizeof(CowHeader));
113 CHECK_LE(header_.prefix.header_size, sizeof(header_));
114
115 if (!android::base::ReadFully(fd_, &header_, header_.prefix.header_size)) {
116 PLOG(ERROR) << "read header failed";
117 return false;
118 }
119 return true;
120 }
121
Parse(android::base::unique_fd && fd,std::optional<uint64_t> label)122 bool CowReader::Parse(android::base::unique_fd&& fd, std::optional<uint64_t> label) {
123 owned_fd_ = std::move(fd);
124 return Parse(android::base::borrowed_fd{owned_fd_}, label);
125 }
126
Parse(android::base::borrowed_fd fd,std::optional<uint64_t> label)127 bool CowReader::Parse(android::base::borrowed_fd fd, std::optional<uint64_t> label) {
128 fd_ = fd;
129
130 if (!ReadCowHeader(fd, &header_)) {
131 return false;
132 }
133
134 std::unique_ptr<CowParserBase> parser;
135 switch (header_.prefix.major_version) {
136 case 1:
137 case 2:
138 parser = std::make_unique<CowParserV2>();
139 break;
140 case 3:
141 parser = std::make_unique<CowParserV3>();
142 break;
143 default:
144 LOG(ERROR) << "Unknown version: " << header_.prefix.major_version;
145 return false;
146 }
147 if (!parser->Parse(fd, header_, label)) {
148 return false;
149 }
150
151 TranslatedCowOps ops_info;
152 if (!parser->Translate(&ops_info)) {
153 return false;
154 }
155
156 header_ = ops_info.header;
157 ops_ = std::move(ops_info.ops);
158 footer_ = parser->footer();
159 fd_size_ = parser->fd_size();
160 last_label_ = parser->last_label();
161 xor_data_loc_ = parser->xor_data_loc();
162
163 // If we're resuming a write, we're not ready to merge
164 if (label.has_value()) return true;
165 return PrepMergeOps();
166 }
167
GetMaxCompressionSize()168 uint32_t CowReader::GetMaxCompressionSize() {
169 switch (header_.prefix.major_version) {
170 case 1:
171 case 2:
172 // Old versions supports only 4KB compression.
173 return header_.block_size;
174 ;
175 case 3:
176 return header_.max_compression_size;
177 default:
178 LOG(ERROR) << "Unknown version: " << header_.prefix.major_version;
179 return 0;
180 }
181 }
182
183 //
184 // This sets up the data needed for MergeOpIter. MergeOpIter presents
185 // data in the order we intend to merge in.
186 //
187 // We merge all order sensitive ops up front, and sort the rest to allow for
188 // batch merging. Order sensitive ops can either be presented in their proper
189 // order in the cow, or be ordered by sequence ops (kCowSequenceOp), in which
190 // case we want to merge those ops first, followed by any ops not specified by
191 // new_block value by the sequence op, in sorted order.
192 // We will re-arrange the vector in such a way that
193 // kernel can batch merge. Ex:
194 //
195 // Existing COW format; All the copy operations
196 // are at the beginning.
197 // =======================================
198 // Copy-op-1 - cow_op->new_block = 1
199 // Copy-op-2 - cow_op->new_block = 2
200 // Copy-op-3 - cow_op->new_block = 3
201 // Replace-op-4 - cow_op->new_block = 6
202 // Replace-op-5 - cow_op->new_block = 4
203 // Replace-op-6 - cow_op->new_block = 8
204 // Replace-op-7 - cow_op->new_block = 9
205 // Zero-op-8 - cow_op->new_block = 7
206 // Zero-op-9 - cow_op->new_block = 5
207 // =======================================
208 //
209 // First find the operation which isn't a copy-op
210 // and then sort all the operations in descending order
211 // with the key being cow_op->new_block (source block)
212 //
213 // The data-structure will look like:
214 //
215 // =======================================
216 // Copy-op-1 - cow_op->new_block = 1
217 // Copy-op-2 - cow_op->new_block = 2
218 // Copy-op-3 - cow_op->new_block = 3
219 // Replace-op-7 - cow_op->new_block = 9
220 // Replace-op-6 - cow_op->new_block = 8
221 // Zero-op-8 - cow_op->new_block = 7
222 // Replace-op-4 - cow_op->new_block = 6
223 // Zero-op-9 - cow_op->new_block = 5
224 // Replace-op-5 - cow_op->new_block = 4
225 // =======================================
226 //
227 // Daemon will read the above data-structure in reverse-order
228 // when reading metadata. Thus, kernel will get the metadata
229 // in the following order:
230 //
231 // ========================================
232 // Replace-op-5 - cow_op->new_block = 4
233 // Zero-op-9 - cow_op->new_block = 5
234 // Replace-op-4 - cow_op->new_block = 6
235 // Zero-op-8 - cow_op->new_block = 7
236 // Replace-op-6 - cow_op->new_block = 8
237 // Replace-op-7 - cow_op->new_block = 9
238 // Copy-op-3 - cow_op->new_block = 3
239 // Copy-op-2 - cow_op->new_block = 2
240 // Copy-op-1 - cow_op->new_block = 1
241 // ===========================================
242 //
243 // When merging begins, kernel will start from the last
244 // metadata which was read: In the above format, Copy-op-1
245 // will be the first merge operation.
246 //
247 // Now, batching of the merge operations happens only when
248 // 1: origin block numbers in the base device are contiguous
249 // (cow_op->new_block) and,
250 // 2: cow block numbers which are assigned by daemon in ReadMetadata()
251 // are contiguous. These are monotonically increasing numbers.
252 //
253 // When both (1) and (2) are true, kernel will batch merge the operations.
254 // In the above case, we have to ensure that the copy operations
255 // are merged first before replace operations are done. Hence,
256 // we will not change the order of copy operations. Since,
257 // cow_op->new_block numbers are contiguous, we will ensure that the
258 // cow block numbers assigned in ReadMetadata() for these respective copy
259 // operations are not contiguous forcing kernel to issue merge for each
260 // copy operations without batch merging.
261 //
262 // For all the other operations viz. Replace and Zero op, the cow block
263 // numbers assigned by daemon will be contiguous allowing kernel to batch
264 // merge.
265 //
266 // The final format after assiging COW block numbers by the daemon will
267 // look something like:
268 //
269 // =========================================================
270 // Replace-op-5 - cow_op->new_block = 4 cow-block-num = 2
271 // Zero-op-9 - cow_op->new_block = 5 cow-block-num = 3
272 // Replace-op-4 - cow_op->new_block = 6 cow-block-num = 4
273 // Zero-op-8 - cow_op->new_block = 7 cow-block-num = 5
274 // Replace-op-6 - cow_op->new_block = 8 cow-block-num = 6
275 // Replace-op-7 - cow_op->new_block = 9 cow-block-num = 7
276 // Copy-op-3 - cow_op->new_block = 3 cow-block-num = 9
277 // Copy-op-2 - cow_op->new_block = 2 cow-block-num = 11
278 // Copy-op-1 - cow_op->new_block = 1 cow-block-num = 13
279 // ==========================================================
280 //
281 // Merge sequence will look like:
282 //
283 // Merge-1 - Batch-merge { Copy-op-1, Copy-op-2, Copy-op-3 }
284 // Merge-2 - Batch-merge {Replace-op-7, Replace-op-6, Zero-op-8,
285 // Replace-op-4, Zero-op-9, Replace-op-5 }
286 //==============================================================
PrepMergeOps()287 bool CowReader::PrepMergeOps() {
288 std::vector<int> other_ops;
289 std::vector<uint32_t> merge_op_blocks;
290 std::unordered_map<uint32_t, int> block_map;
291
292 switch (header_.prefix.major_version) {
293 case 1:
294 case 2:
295 GetSequenceDataV2(&merge_op_blocks, &other_ops, &block_map);
296 break;
297 case 3:
298 GetSequenceData(&merge_op_blocks, &other_ops, &block_map);
299 break;
300 default:
301 break;
302 }
303
304 for (auto block : merge_op_blocks) {
305 if (block_map.count(block) == 0) {
306 LOG(ERROR) << "Invalid Sequence Ops. Could not find Cow Op for new block " << block;
307 return false;
308 }
309 }
310
311 if (merge_op_blocks.size() > header_.num_merge_ops) {
312 num_ordered_ops_to_merge_ = merge_op_blocks.size() - header_.num_merge_ops;
313 } else {
314 num_ordered_ops_to_merge_ = 0;
315 }
316
317 // Sort the vector in increasing order if merging in user-space as
318 // we can batch merge them when iterating from forward.
319 //
320 // dm-snapshot-merge requires decreasing order as we iterate the blocks
321 // in reverse order.
322 if (reader_flag_ == ReaderFlags::USERSPACE_MERGE) {
323 std::sort(other_ops.begin(), other_ops.end());
324 } else {
325 std::sort(other_ops.begin(), other_ops.end(), std::greater<int>());
326 }
327
328 merge_op_blocks.insert(merge_op_blocks.end(), other_ops.begin(), other_ops.end());
329
330 num_total_data_ops_ = merge_op_blocks.size();
331 if (header_.num_merge_ops > 0) {
332 merge_op_start_ = header_.num_merge_ops;
333 }
334
335 if (is_merge_) {
336 // Metadata ops are not required for merge. Thus, just re-arrange
337 // the ops vector as required for merge operations.
338 auto merge_ops_buffer = std::make_shared<std::vector<CowOperation>>();
339 merge_ops_buffer->reserve(num_total_data_ops_);
340 for (auto block : merge_op_blocks) {
341 merge_ops_buffer->emplace_back(ops_->data()[block_map.at(block)]);
342 }
343 ops_->clear();
344 ops_ = merge_ops_buffer;
345 ops_->shrink_to_fit();
346 } else {
347 for (auto block : merge_op_blocks) {
348 block_pos_index_->push_back(block_map.at(block));
349 }
350 }
351
352 block_map.clear();
353 merge_op_blocks.clear();
354
355 return true;
356 }
357
GetSequenceDataV2(std::vector<uint32_t> * merge_op_blocks,std::vector<int> * other_ops,std::unordered_map<uint32_t,int> * block_map)358 bool CowReader::GetSequenceDataV2(std::vector<uint32_t>* merge_op_blocks,
359 std::vector<int>* other_ops,
360 std::unordered_map<uint32_t, int>* block_map) {
361 auto seq_ops_set = std::unordered_set<uint32_t>();
362 size_t num_seqs = 0;
363 size_t read;
364 for (size_t i = 0; i < ops_->size(); i++) {
365 auto& current_op = ops_->data()[i];
366
367 if (current_op.type() == kCowSequenceOp) {
368 size_t seq_len = current_op.data_length / sizeof(uint32_t);
369
370 merge_op_blocks->resize(merge_op_blocks->size() + seq_len);
371 if (!GetRawBytes(¤t_op, &merge_op_blocks->data()[num_seqs],
372 current_op.data_length, &read)) {
373 PLOG(ERROR) << "Failed to read sequence op!";
374 return false;
375 }
376 for (size_t j = num_seqs; j < num_seqs + seq_len; j++) {
377 seq_ops_set.insert(merge_op_blocks->at(j));
378 }
379 num_seqs += seq_len;
380 }
381
382 if (IsMetadataOp(current_op)) {
383 continue;
384 }
385
386 // Sequence ops must be the first ops in the stream.
387 if (seq_ops_set.empty() && IsOrderedOp(current_op)) {
388 merge_op_blocks->emplace_back(current_op.new_block);
389 } else if (seq_ops_set.count(current_op.new_block) == 0) {
390 other_ops->push_back(current_op.new_block);
391 }
392 block_map->insert({current_op.new_block, i});
393 }
394 return false;
395 }
396
GetSequenceData(std::vector<uint32_t> * merge_op_blocks,std::vector<int> * other_ops,std::unordered_map<uint32_t,int> * block_map)397 bool CowReader::GetSequenceData(std::vector<uint32_t>* merge_op_blocks, std::vector<int>* other_ops,
398 std::unordered_map<uint32_t, int>* block_map) {
399 std::unordered_set<uint32_t> seq_ops_set;
400 // read sequence ops data
401 merge_op_blocks->resize(header_.sequence_data_count);
402 if (!android::base::ReadFullyAtOffset(
403 fd_, merge_op_blocks->data(),
404 header_.sequence_data_count * sizeof(merge_op_blocks->at(0)),
405 GetSequenceOffset(header_))) {
406 PLOG(ERROR) << "failed to read sequence buffer. seq_data_count: "
407 << header_.sequence_data_count << " at offset: " << GetSequenceOffset(header_);
408 return false;
409 }
410 seq_ops_set.reserve(merge_op_blocks->size());
411 for (auto& i : *merge_op_blocks) {
412 seq_ops_set.insert(i);
413 }
414 // read ordered op data
415 for (size_t i = 0; i < ops_->size(); i++) {
416 auto& current_op = ops_->data()[i];
417 // Sequence ops must be the first ops in the stream.
418 if (seq_ops_set.empty()) {
419 merge_op_blocks->emplace_back(current_op.new_block);
420 } else if (seq_ops_set.count(current_op.new_block) == 0) {
421 other_ops->push_back(current_op.new_block);
422 }
423 block_map->insert({current_op.new_block, i});
424 }
425 return true;
426 }
427
VerifyMergeOps()428 bool CowReader::VerifyMergeOps() {
429 auto itr = GetMergeOpIter(true);
430 std::unordered_map<uint64_t, const CowOperation*> overwritten_blocks;
431 bool non_ordered_op_found = false;
432
433 while (!itr->AtEnd()) {
434 const auto& op = itr->Get();
435 uint64_t offset;
436
437 // Op should not be a metadata
438 if (IsMetadataOp(*op)) {
439 LOG(ERROR) << "Metadata op: " << op << " found during merge sequence";
440 return false;
441 }
442
443 // Sequence ops should contain all the ordered ops followed
444 // by Replace and Zero ops. If we find the first op which
445 // is not ordered, that means all ordered ops processing
446 // has been completed.
447 if (!IsOrderedOp(*op)) {
448 non_ordered_op_found = true;
449 }
450
451 // Since, all ordered ops processing has been completed,
452 // check that the subsequent ops are not ordered.
453 if (non_ordered_op_found && IsOrderedOp(*op)) {
454 LOG(ERROR) << "Invalid sequence - non-ordered and ordered ops"
455 << " cannot be mixed during sequence generation";
456 return false;
457 }
458
459 if (!GetSourceOffset(op, &offset)) {
460 itr->Next();
461 continue;
462 }
463
464 uint64_t block = GetBlockFromOffset(header_, offset);
465 bool misaligned = (GetBlockRelativeOffset(header_, offset) != 0);
466
467 const CowOperation* overwrite = nullptr;
468 if (overwritten_blocks.count(block)) {
469 overwrite = overwritten_blocks[block];
470 LOG(ERROR) << "Invalid Sequence! Block needed for op:\n"
471 << op << "\noverwritten by previously merged op:\n"
472 << *overwrite;
473 }
474 if (misaligned && overwritten_blocks.count(block + 1)) {
475 overwrite = overwritten_blocks[block + 1];
476 LOG(ERROR) << "Invalid Sequence! Block needed for op:\n"
477 << op << "\noverwritten by previously merged op:\n"
478 << *overwrite;
479 }
480 if (overwrite != nullptr) return false;
481 overwritten_blocks[op->new_block] = op;
482 itr->Next();
483 }
484 return true;
485 }
486
GetFooter(CowFooter * footer)487 bool CowReader::GetFooter(CowFooter* footer) {
488 if (!footer_) return false;
489 *footer = footer_.value();
490 return true;
491 }
492
GetLastLabel(uint64_t * label)493 bool CowReader::GetLastLabel(uint64_t* label) {
494 if (!last_label_) return false;
495 *label = last_label_.value();
496 return true;
497 }
498
499 class CowOpIter final : public ICowOpIter {
500 public:
501 CowOpIter(std::shared_ptr<std::vector<CowOperation>>& ops, uint64_t start);
502
503 bool AtEnd() override;
504 const CowOperation* Get() override;
505 void Next() override;
506
507 void Prev() override;
508 bool AtBegin() override;
509
510 private:
511 std::shared_ptr<std::vector<CowOperation>> ops_;
512 std::vector<CowOperation>::iterator op_iter_;
513 };
514
CowOpIter(std::shared_ptr<std::vector<CowOperation>> & ops,uint64_t start)515 CowOpIter::CowOpIter(std::shared_ptr<std::vector<CowOperation>>& ops, uint64_t start) {
516 ops_ = ops;
517 op_iter_ = ops_->begin() + start;
518 }
519
AtBegin()520 bool CowOpIter::AtBegin() {
521 return op_iter_ == ops_->begin();
522 }
523
Prev()524 void CowOpIter::Prev() {
525 CHECK(!AtBegin());
526 op_iter_--;
527 }
528
AtEnd()529 bool CowOpIter::AtEnd() {
530 return op_iter_ == ops_->end();
531 }
532
Next()533 void CowOpIter::Next() {
534 CHECK(!AtEnd());
535 op_iter_++;
536 }
537
Get()538 const CowOperation* CowOpIter::Get() {
539 CHECK(!AtEnd());
540 return &(*op_iter_);
541 }
542
543 class CowRevMergeOpIter final : public ICowOpIter {
544 public:
545 explicit CowRevMergeOpIter(std::shared_ptr<std::vector<CowOperation>> ops,
546 std::shared_ptr<std::vector<int>> block_pos_index, uint64_t start);
547
548 bool AtEnd() override;
549 const CowOperation* Get() override;
550 void Next() override;
551
552 void Prev() override;
553 bool AtBegin() override;
554
555 private:
556 std::shared_ptr<std::vector<CowOperation>> ops_;
557 std::vector<int>::reverse_iterator block_riter_;
558 std::shared_ptr<std::vector<int>> cow_op_index_vec_;
559 uint64_t start_;
560 };
561
562 class CowMergeOpIter final : public ICowOpIter {
563 public:
564 explicit CowMergeOpIter(std::shared_ptr<std::vector<CowOperation>> ops,
565 std::shared_ptr<std::vector<int>> block_pos_index, uint64_t start);
566
567 bool AtEnd() override;
568 const CowOperation* Get() override;
569 void Next() override;
570
571 void Prev() override;
572 bool AtBegin() override;
573
574 private:
575 std::shared_ptr<std::vector<CowOperation>> ops_;
576 std::vector<int>::iterator block_iter_;
577 std::shared_ptr<std::vector<int>> cow_op_index_vec_;
578 uint64_t start_;
579 };
580
CowMergeOpIter(std::shared_ptr<std::vector<CowOperation>> ops,std::shared_ptr<std::vector<int>> block_pos_index,uint64_t start)581 CowMergeOpIter::CowMergeOpIter(std::shared_ptr<std::vector<CowOperation>> ops,
582 std::shared_ptr<std::vector<int>> block_pos_index, uint64_t start) {
583 ops_ = ops;
584 start_ = start;
585 cow_op_index_vec_ = block_pos_index;
586 block_iter_ = cow_op_index_vec_->begin() + start;
587 }
588
AtBegin()589 bool CowMergeOpIter::AtBegin() {
590 return block_iter_ == cow_op_index_vec_->begin();
591 }
592
Prev()593 void CowMergeOpIter::Prev() {
594 CHECK(!AtBegin());
595 block_iter_--;
596 }
597
AtEnd()598 bool CowMergeOpIter::AtEnd() {
599 return block_iter_ == cow_op_index_vec_->end();
600 }
601
Next()602 void CowMergeOpIter::Next() {
603 CHECK(!AtEnd());
604 block_iter_++;
605 }
606
Get()607 const CowOperation* CowMergeOpIter::Get() {
608 CHECK(!AtEnd());
609 return &ops_->data()[*block_iter_];
610 }
611
CowRevMergeOpIter(std::shared_ptr<std::vector<CowOperation>> ops,std::shared_ptr<std::vector<int>> block_pos_index,uint64_t start)612 CowRevMergeOpIter::CowRevMergeOpIter(std::shared_ptr<std::vector<CowOperation>> ops,
613 std::shared_ptr<std::vector<int>> block_pos_index,
614 uint64_t start) {
615 ops_ = ops;
616 start_ = start;
617 cow_op_index_vec_ = block_pos_index;
618 block_riter_ = cow_op_index_vec_->rbegin();
619 }
620
AtBegin()621 bool CowRevMergeOpIter::AtBegin() {
622 return block_riter_ == cow_op_index_vec_->rbegin();
623 }
624
Prev()625 void CowRevMergeOpIter::Prev() {
626 CHECK(!AtBegin());
627 block_riter_--;
628 }
629
AtEnd()630 bool CowRevMergeOpIter::AtEnd() {
631 return block_riter_ == cow_op_index_vec_->rend() - start_;
632 }
633
Next()634 void CowRevMergeOpIter::Next() {
635 CHECK(!AtEnd());
636 block_riter_++;
637 }
638
Get()639 const CowOperation* CowRevMergeOpIter::Get() {
640 CHECK(!AtEnd());
641 return &ops_->data()[*block_riter_];
642 }
643
GetOpIter(bool merge_progress)644 std::unique_ptr<ICowOpIter> CowReader::GetOpIter(bool merge_progress) {
645 return std::make_unique<CowOpIter>(ops_, merge_progress ? merge_op_start_ : 0);
646 }
647
GetRevMergeOpIter(bool ignore_progress)648 std::unique_ptr<ICowOpIter> CowReader::GetRevMergeOpIter(bool ignore_progress) {
649 return std::make_unique<CowRevMergeOpIter>(ops_, block_pos_index_,
650 ignore_progress ? 0 : merge_op_start_);
651 }
652
GetMergeOpIter(bool ignore_progress)653 std::unique_ptr<ICowOpIter> CowReader::GetMergeOpIter(bool ignore_progress) {
654 return std::make_unique<CowMergeOpIter>(ops_, block_pos_index_,
655 ignore_progress ? 0 : merge_op_start_);
656 }
657
GetRawBytes(const CowOperation * op,void * buffer,size_t len,size_t * read)658 bool CowReader::GetRawBytes(const CowOperation* op, void* buffer, size_t len, size_t* read) {
659 switch (op->type()) {
660 case kCowSequenceOp:
661 case kCowReplaceOp:
662 case kCowXorOp:
663 return GetRawBytes(op->source(), buffer, len, read);
664 default:
665 LOG(ERROR) << "Cannot get raw bytes of non-data op: " << *op;
666 return false;
667 }
668 }
669
GetRawBytes(uint64_t offset,void * buffer,size_t len,size_t * read)670 bool CowReader::GetRawBytes(uint64_t offset, void* buffer, size_t len, size_t* read) {
671 // Validate the offset, taking care to acknowledge possible overflow of offset+len.
672 if (offset < header_.prefix.header_size || offset >= fd_size_ || offset + len > fd_size_ ||
673 len >= fd_size_) {
674 LOG(ERROR) << "invalid data offset: " << offset << ", " << len << " bytes";
675 return false;
676 }
677 if (lseek(fd_.get(), offset, SEEK_SET) < 0) {
678 PLOG(ERROR) << "lseek to read raw bytes failed";
679 return false;
680 }
681 ssize_t rv = TEMP_FAILURE_RETRY(::read(fd_.get(), buffer, len));
682 if (rv < 0) {
683 PLOG(ERROR) << "read failed";
684 return false;
685 }
686 *read = rv;
687 return true;
688 }
689
690 class CowDataStream final : public IByteStream {
691 public:
CowDataStream(CowReader * reader,uint64_t offset,size_t data_length)692 CowDataStream(CowReader* reader, uint64_t offset, size_t data_length)
693 : reader_(reader), offset_(offset), data_length_(data_length) {
694 remaining_ = data_length_;
695 }
696
Read(void * buffer,size_t length)697 ssize_t Read(void* buffer, size_t length) override {
698 size_t to_read = std::min(length, remaining_);
699 if (!to_read) {
700 return 0;
701 }
702 size_t read;
703 if (!reader_->GetRawBytes(offset_, buffer, to_read, &read)) {
704 return -1;
705 }
706 offset_ += read;
707 remaining_ -= read;
708 return read;
709 }
710
Size() const711 size_t Size() const override { return data_length_; }
712
713 private:
714 CowReader* reader_;
715 uint64_t offset_;
716 size_t data_length_;
717 size_t remaining_;
718 };
719
GetCompressionType()720 uint8_t CowReader::GetCompressionType() {
721 return header_.compression_algorithm;
722 }
723
ReadData(const CowOperation * op,void * buffer,size_t buffer_size,size_t ignore_bytes)724 ssize_t CowReader::ReadData(const CowOperation* op, void* buffer, size_t buffer_size,
725 size_t ignore_bytes) {
726 std::unique_ptr<IDecompressor> decompressor;
727 const size_t op_buf_size = CowOpCompressionSize(op, header_.block_size);
728 if (!op_buf_size) {
729 LOG(ERROR) << "Compression size is zero. op: " << *op;
730 return -1;
731 }
732 switch (GetCompressionType()) {
733 case kCowCompressNone:
734 break;
735 case kCowCompressGz:
736 decompressor = IDecompressor::Gz();
737 break;
738 case kCowCompressBrotli:
739 decompressor = IDecompressor::Brotli();
740 break;
741 case kCowCompressZstd:
742 if (op_buf_size != op->data_length) {
743 decompressor = IDecompressor::Zstd();
744 }
745 break;
746 case kCowCompressLz4:
747 if (op_buf_size != op->data_length) {
748 decompressor = IDecompressor::Lz4();
749 }
750 break;
751 default:
752 LOG(ERROR) << "Unknown compression type: " << GetCompressionType();
753 return -1;
754 }
755
756 uint64_t offset;
757 if (op->type() == kCowXorOp) {
758 offset = xor_data_loc_->at(op->new_block);
759 } else {
760 offset = op->source();
761 }
762 if (!decompressor ||
763 ((op->data_length == op_buf_size) && (header_.prefix.major_version == 3))) {
764 CowDataStream stream(this, offset + ignore_bytes, op->data_length - ignore_bytes);
765 return stream.ReadFully(buffer, buffer_size);
766 }
767
768 CowDataStream stream(this, offset, op->data_length);
769 decompressor->set_stream(&stream);
770 return decompressor->Decompress(buffer, buffer_size, op_buf_size, ignore_bytes);
771 }
772
GetSourceOffset(const CowOperation * op,uint64_t * source_offset)773 bool CowReader::GetSourceOffset(const CowOperation* op, uint64_t* source_offset) {
774 switch (op->type()) {
775 case kCowCopyOp:
776 *source_offset = op->source() * header_.block_size;
777 return true;
778 case kCowXorOp:
779 *source_offset = op->source();
780 return true;
781 default:
782 return false;
783 }
784 }
785
786 } // namespace snapshot
787 } // namespace android
788