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