1 // Copyright (C) 2018 The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //      http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include <sys/stat.h>
16 
17 #include <cstdio>
18 #include <iostream>
19 #include <memory>
20 #include <string_view>
21 
22 #include <android-base/file.h>
23 #include <android-base/logging.h>
24 #include <gtest/gtest.h>
25 #include <libsnapshot/cow_reader.h>
26 #include <libsnapshot/cow_writer.h>
27 
28 using testing::AssertionFailure;
29 using testing::AssertionResult;
30 using testing::AssertionSuccess;
31 
32 namespace android {
33 namespace snapshot {
34 
35 class CowTest : public ::testing::Test {
36   protected:
SetUp()37     virtual void SetUp() override {
38         cow_ = std::make_unique<TemporaryFile>();
39         ASSERT_GE(cow_->fd, 0) << strerror(errno);
40     }
41 
TearDown()42     virtual void TearDown() override { cow_ = nullptr; }
43 
44     std::unique_ptr<TemporaryFile> cow_;
45 };
46 
47 // Sink that always appends to the end of a string.
48 class StringSink : public IByteSink {
49   public:
GetBuffer(size_t requested,size_t * actual)50     void* GetBuffer(size_t requested, size_t* actual) override {
51         size_t old_size = stream_.size();
52         stream_.resize(old_size + requested, '\0');
53         *actual = requested;
54         return stream_.data() + old_size;
55     }
ReturnData(void *,size_t)56     bool ReturnData(void*, size_t) override { return true; }
Reset()57     void Reset() { stream_.clear(); }
58 
stream()59     std::string& stream() { return stream_; }
60 
61   private:
62     std::string stream_;
63 };
64 
TEST_F(CowTest,ReadWrite)65 TEST_F(CowTest, ReadWrite) {
66     CowOptions options;
67     options.cluster_ops = 0;
68     CowWriter writer(options);
69 
70     ASSERT_TRUE(writer.Initialize(cow_->fd));
71 
72     std::string data = "This is some data, believe it";
73     data.resize(options.block_size, '\0');
74 
75     ASSERT_TRUE(writer.AddCopy(10, 20));
76     ASSERT_TRUE(writer.AddRawBlocks(50, data.data(), data.size()));
77     ASSERT_TRUE(writer.AddZeroBlocks(51, 2));
78     ASSERT_TRUE(writer.Finalize());
79 
80     ASSERT_EQ(lseek(cow_->fd, 0, SEEK_SET), 0);
81 
82     CowReader reader;
83     CowHeader header;
84     CowFooter footer;
85     ASSERT_TRUE(reader.Parse(cow_->fd));
86     ASSERT_TRUE(reader.GetHeader(&header));
87     ASSERT_TRUE(reader.GetFooter(&footer));
88     ASSERT_EQ(header.magic, kCowMagicNumber);
89     ASSERT_EQ(header.major_version, kCowVersionMajor);
90     ASSERT_EQ(header.minor_version, kCowVersionMinor);
91     ASSERT_EQ(header.block_size, options.block_size);
92     ASSERT_EQ(footer.op.num_ops, 4);
93 
94     auto iter = reader.GetOpIter();
95     ASSERT_NE(iter, nullptr);
96     ASSERT_FALSE(iter->Done());
97     auto op = &iter->Get();
98 
99     ASSERT_EQ(op->type, kCowCopyOp);
100     ASSERT_EQ(op->compression, kCowCompressNone);
101     ASSERT_EQ(op->data_length, 0);
102     ASSERT_EQ(op->new_block, 10);
103     ASSERT_EQ(op->source, 20);
104 
105     StringSink sink;
106 
107     iter->Next();
108     ASSERT_FALSE(iter->Done());
109     op = &iter->Get();
110 
111     ASSERT_EQ(op->type, kCowReplaceOp);
112     ASSERT_EQ(op->compression, kCowCompressNone);
113     ASSERT_EQ(op->data_length, 4096);
114     ASSERT_EQ(op->new_block, 50);
115     ASSERT_TRUE(reader.ReadData(*op, &sink));
116     ASSERT_EQ(sink.stream(), data);
117 
118     iter->Next();
119     ASSERT_FALSE(iter->Done());
120     op = &iter->Get();
121 
122     // Note: the zero operation gets split into two blocks.
123     ASSERT_EQ(op->type, kCowZeroOp);
124     ASSERT_EQ(op->compression, kCowCompressNone);
125     ASSERT_EQ(op->data_length, 0);
126     ASSERT_EQ(op->new_block, 51);
127     ASSERT_EQ(op->source, 0);
128 
129     iter->Next();
130     ASSERT_FALSE(iter->Done());
131     op = &iter->Get();
132 
133     ASSERT_EQ(op->type, kCowZeroOp);
134     ASSERT_EQ(op->compression, kCowCompressNone);
135     ASSERT_EQ(op->data_length, 0);
136     ASSERT_EQ(op->new_block, 52);
137     ASSERT_EQ(op->source, 0);
138 
139     iter->Next();
140     ASSERT_TRUE(iter->Done());
141 }
142 
TEST_F(CowTest,CompressGz)143 TEST_F(CowTest, CompressGz) {
144     CowOptions options;
145     options.cluster_ops = 0;
146     options.compression = "gz";
147     CowWriter writer(options);
148 
149     ASSERT_TRUE(writer.Initialize(cow_->fd));
150 
151     std::string data = "This is some data, believe it";
152     data.resize(options.block_size, '\0');
153 
154     ASSERT_TRUE(writer.AddRawBlocks(50, data.data(), data.size()));
155     ASSERT_TRUE(writer.Finalize());
156 
157     ASSERT_EQ(lseek(cow_->fd, 0, SEEK_SET), 0);
158 
159     CowReader reader;
160     ASSERT_TRUE(reader.Parse(cow_->fd));
161 
162     auto iter = reader.GetOpIter();
163     ASSERT_NE(iter, nullptr);
164     ASSERT_FALSE(iter->Done());
165     auto op = &iter->Get();
166 
167     StringSink sink;
168 
169     ASSERT_EQ(op->type, kCowReplaceOp);
170     ASSERT_EQ(op->compression, kCowCompressGz);
171     ASSERT_EQ(op->data_length, 56);  // compressed!
172     ASSERT_EQ(op->new_block, 50);
173     ASSERT_TRUE(reader.ReadData(*op, &sink));
174     ASSERT_EQ(sink.stream(), data);
175 
176     iter->Next();
177     ASSERT_TRUE(iter->Done());
178 }
179 
TEST_F(CowTest,ClusterCompressGz)180 TEST_F(CowTest, ClusterCompressGz) {
181     CowOptions options;
182     options.compression = "gz";
183     options.cluster_ops = 2;
184     CowWriter writer(options);
185 
186     ASSERT_TRUE(writer.Initialize(cow_->fd));
187 
188     std::string data = "This is some data, believe it";
189     data.resize(options.block_size, '\0');
190     ASSERT_TRUE(writer.AddRawBlocks(50, data.data(), data.size()));
191 
192     std::string data2 = "More data!";
193     data2.resize(options.block_size, '\0');
194     ASSERT_TRUE(writer.AddRawBlocks(51, data2.data(), data2.size()));
195 
196     ASSERT_TRUE(writer.Finalize());
197 
198     ASSERT_EQ(lseek(cow_->fd, 0, SEEK_SET), 0);
199 
200     CowReader reader;
201     ASSERT_TRUE(reader.Parse(cow_->fd));
202 
203     auto iter = reader.GetOpIter();
204     ASSERT_NE(iter, nullptr);
205     ASSERT_FALSE(iter->Done());
206     auto op = &iter->Get();
207 
208     StringSink sink;
209 
210     ASSERT_EQ(op->type, kCowReplaceOp);
211     ASSERT_EQ(op->compression, kCowCompressGz);
212     ASSERT_EQ(op->data_length, 56);  // compressed!
213     ASSERT_EQ(op->new_block, 50);
214     ASSERT_TRUE(reader.ReadData(*op, &sink));
215     ASSERT_EQ(sink.stream(), data);
216 
217     iter->Next();
218     ASSERT_FALSE(iter->Done());
219     op = &iter->Get();
220 
221     ASSERT_EQ(op->type, kCowClusterOp);
222 
223     iter->Next();
224     ASSERT_FALSE(iter->Done());
225     op = &iter->Get();
226 
227     sink.Reset();
228     ASSERT_EQ(op->compression, kCowCompressGz);
229     ASSERT_EQ(op->data_length, 41);  // compressed!
230     ASSERT_EQ(op->new_block, 51);
231     ASSERT_TRUE(reader.ReadData(*op, &sink));
232     ASSERT_EQ(sink.stream(), data2);
233 
234     iter->Next();
235     ASSERT_FALSE(iter->Done());
236     op = &iter->Get();
237 
238     ASSERT_EQ(op->type, kCowClusterOp);
239 
240     iter->Next();
241     ASSERT_TRUE(iter->Done());
242 }
243 
TEST_F(CowTest,CompressTwoBlocks)244 TEST_F(CowTest, CompressTwoBlocks) {
245     CowOptions options;
246     options.compression = "gz";
247     options.cluster_ops = 0;
248     CowWriter writer(options);
249 
250     ASSERT_TRUE(writer.Initialize(cow_->fd));
251 
252     std::string data = "This is some data, believe it";
253     data.resize(options.block_size * 2, '\0');
254 
255     ASSERT_TRUE(writer.AddRawBlocks(50, data.data(), data.size()));
256     ASSERT_TRUE(writer.Finalize());
257 
258     ASSERT_EQ(lseek(cow_->fd, 0, SEEK_SET), 0);
259 
260     CowReader reader;
261     ASSERT_TRUE(reader.Parse(cow_->fd));
262 
263     auto iter = reader.GetOpIter();
264     ASSERT_NE(iter, nullptr);
265     ASSERT_FALSE(iter->Done());
266     iter->Next();
267     ASSERT_FALSE(iter->Done());
268 
269     StringSink sink;
270 
271     auto op = &iter->Get();
272     ASSERT_EQ(op->type, kCowReplaceOp);
273     ASSERT_EQ(op->compression, kCowCompressGz);
274     ASSERT_EQ(op->new_block, 51);
275     ASSERT_TRUE(reader.ReadData(*op, &sink));
276 }
277 
278 // Only return 1-byte buffers, to stress test the partial read logic in
279 // CowReader.
280 class HorribleStringSink : public StringSink {
281   public:
GetBuffer(size_t,size_t * actual)282     void* GetBuffer(size_t, size_t* actual) override { return StringSink::GetBuffer(1, actual); }
283 };
284 
285 class CompressionTest : public CowTest, public testing::WithParamInterface<const char*> {};
286 
TEST_P(CompressionTest,HorribleSink)287 TEST_P(CompressionTest, HorribleSink) {
288     CowOptions options;
289     options.compression = GetParam();
290     options.cluster_ops = 0;
291     CowWriter writer(options);
292 
293     ASSERT_TRUE(writer.Initialize(cow_->fd));
294 
295     std::string data = "This is some data, believe it";
296     data.resize(options.block_size, '\0');
297 
298     ASSERT_TRUE(writer.AddRawBlocks(50, data.data(), data.size()));
299     ASSERT_TRUE(writer.Finalize());
300 
301     ASSERT_EQ(lseek(cow_->fd, 0, SEEK_SET), 0);
302 
303     CowReader reader;
304     ASSERT_TRUE(reader.Parse(cow_->fd));
305 
306     auto iter = reader.GetOpIter();
307     ASSERT_NE(iter, nullptr);
308     ASSERT_FALSE(iter->Done());
309 
310     HorribleStringSink sink;
311     auto op = &iter->Get();
312     ASSERT_TRUE(reader.ReadData(*op, &sink));
313     ASSERT_EQ(sink.stream(), data);
314 }
315 
316 INSTANTIATE_TEST_SUITE_P(CowApi, CompressionTest, testing::Values("none", "gz", "brotli"));
317 
TEST_F(CowTest,GetSize)318 TEST_F(CowTest, GetSize) {
319     CowOptions options;
320     options.cluster_ops = 0;
321     CowWriter writer(options);
322     if (ftruncate(cow_->fd, 0) < 0) {
323         perror("Fails to set temp file size");
324         FAIL();
325     }
326     ASSERT_TRUE(writer.Initialize(cow_->fd));
327 
328     std::string data = "This is some data, believe it";
329     data.resize(options.block_size, '\0');
330 
331     ASSERT_TRUE(writer.AddCopy(10, 20));
332     ASSERT_TRUE(writer.AddRawBlocks(50, data.data(), data.size()));
333     ASSERT_TRUE(writer.AddZeroBlocks(51, 2));
334     auto size_before = writer.GetCowSize();
335     ASSERT_TRUE(writer.Finalize());
336     auto size_after = writer.GetCowSize();
337     ASSERT_EQ(size_before, size_after);
338     struct stat buf;
339 
340     ASSERT_GE(fstat(cow_->fd, &buf), 0) << strerror(errno);
341     ASSERT_EQ(buf.st_size, writer.GetCowSize());
342 }
343 
TEST_F(CowTest,AppendLabelSmall)344 TEST_F(CowTest, AppendLabelSmall) {
345     CowOptions options;
346     options.cluster_ops = 0;
347     auto writer = std::make_unique<CowWriter>(options);
348     ASSERT_TRUE(writer->Initialize(cow_->fd));
349 
350     std::string data = "This is some data, believe it";
351     data.resize(options.block_size, '\0');
352     ASSERT_TRUE(writer->AddRawBlocks(50, data.data(), data.size()));
353     ASSERT_TRUE(writer->AddLabel(3));
354     ASSERT_TRUE(writer->Finalize());
355 
356     ASSERT_EQ(lseek(cow_->fd, 0, SEEK_SET), 0);
357 
358     writer = std::make_unique<CowWriter>(options);
359     ASSERT_TRUE(writer->InitializeAppend(cow_->fd, 3));
360 
361     std::string data2 = "More data!";
362     data2.resize(options.block_size, '\0');
363     ASSERT_TRUE(writer->AddRawBlocks(51, data2.data(), data2.size()));
364     ASSERT_TRUE(writer->Finalize());
365 
366     ASSERT_EQ(lseek(cow_->fd, 0, SEEK_SET), 0);
367 
368     struct stat buf;
369     ASSERT_EQ(fstat(cow_->fd, &buf), 0);
370     ASSERT_EQ(buf.st_size, writer->GetCowSize());
371 
372     // Read back both operations, and label.
373     CowReader reader;
374     uint64_t label;
375     ASSERT_TRUE(reader.Parse(cow_->fd));
376     ASSERT_TRUE(reader.GetLastLabel(&label));
377     ASSERT_EQ(label, 3);
378 
379     StringSink sink;
380 
381     auto iter = reader.GetOpIter();
382     ASSERT_NE(iter, nullptr);
383 
384     ASSERT_FALSE(iter->Done());
385     auto op = &iter->Get();
386     ASSERT_EQ(op->type, kCowReplaceOp);
387     ASSERT_TRUE(reader.ReadData(*op, &sink));
388     ASSERT_EQ(sink.stream(), data);
389 
390     iter->Next();
391     sink.Reset();
392 
393     ASSERT_FALSE(iter->Done());
394     op = &iter->Get();
395     ASSERT_EQ(op->type, kCowLabelOp);
396     ASSERT_EQ(op->source, 3);
397 
398     iter->Next();
399 
400     ASSERT_FALSE(iter->Done());
401     op = &iter->Get();
402     ASSERT_EQ(op->type, kCowReplaceOp);
403     ASSERT_TRUE(reader.ReadData(*op, &sink));
404     ASSERT_EQ(sink.stream(), data2);
405 
406     iter->Next();
407     ASSERT_TRUE(iter->Done());
408 }
409 
TEST_F(CowTest,AppendLabelMissing)410 TEST_F(CowTest, AppendLabelMissing) {
411     CowOptions options;
412     options.cluster_ops = 0;
413     auto writer = std::make_unique<CowWriter>(options);
414     ASSERT_TRUE(writer->Initialize(cow_->fd));
415 
416     ASSERT_TRUE(writer->AddLabel(0));
417     std::string data = "This is some data, believe it";
418     data.resize(options.block_size, '\0');
419     ASSERT_TRUE(writer->AddRawBlocks(50, data.data(), data.size()));
420     ASSERT_TRUE(writer->AddLabel(1));
421     // Drop the tail end of the last op header, corrupting it.
422     ftruncate(cow_->fd, writer->GetCowSize() - sizeof(CowFooter) - 3);
423 
424     ASSERT_EQ(lseek(cow_->fd, 0, SEEK_SET), 0);
425 
426     writer = std::make_unique<CowWriter>(options);
427     ASSERT_FALSE(writer->InitializeAppend(cow_->fd, 1));
428     ASSERT_TRUE(writer->InitializeAppend(cow_->fd, 0));
429 
430     ASSERT_TRUE(writer->AddZeroBlocks(51, 1));
431     ASSERT_TRUE(writer->Finalize());
432 
433     ASSERT_EQ(lseek(cow_->fd, 0, SEEK_SET), 0);
434 
435     struct stat buf;
436     ASSERT_EQ(fstat(cow_->fd, &buf), 0);
437     ASSERT_EQ(buf.st_size, writer->GetCowSize());
438 
439     // Read back both operations.
440     CowReader reader;
441     ASSERT_TRUE(reader.Parse(cow_->fd));
442 
443     StringSink sink;
444 
445     auto iter = reader.GetOpIter();
446     ASSERT_NE(iter, nullptr);
447 
448     ASSERT_FALSE(iter->Done());
449     auto op = &iter->Get();
450     ASSERT_EQ(op->type, kCowLabelOp);
451     ASSERT_EQ(op->source, 0);
452 
453     iter->Next();
454 
455     ASSERT_FALSE(iter->Done());
456     op = &iter->Get();
457     ASSERT_EQ(op->type, kCowZeroOp);
458 
459     iter->Next();
460 
461     ASSERT_TRUE(iter->Done());
462 }
463 
TEST_F(CowTest,AppendExtendedCorrupted)464 TEST_F(CowTest, AppendExtendedCorrupted) {
465     CowOptions options;
466     options.cluster_ops = 0;
467     auto writer = std::make_unique<CowWriter>(options);
468     ASSERT_TRUE(writer->Initialize(cow_->fd));
469 
470     ASSERT_TRUE(writer->AddLabel(5));
471 
472     std::string data = "This is some data, believe it";
473     data.resize(options.block_size * 2, '\0');
474     ASSERT_TRUE(writer->AddRawBlocks(50, data.data(), data.size()));
475     ASSERT_TRUE(writer->AddLabel(6));
476 
477     // fail to write the footer. Cow Format does not know if Label 6 is valid
478 
479     ASSERT_EQ(lseek(cow_->fd, 0, SEEK_SET), 0);
480 
481     // Get the last known good label
482     CowReader label_reader;
483     uint64_t label;
484     ASSERT_TRUE(label_reader.Parse(cow_->fd, {5}));
485     ASSERT_TRUE(label_reader.GetLastLabel(&label));
486     ASSERT_EQ(label, 5);
487 
488     ASSERT_EQ(lseek(cow_->fd, 0, SEEK_SET), 0);
489 
490     writer = std::make_unique<CowWriter>(options);
491     ASSERT_TRUE(writer->InitializeAppend(cow_->fd, 5));
492 
493     ASSERT_TRUE(writer->Finalize());
494 
495     struct stat buf;
496     ASSERT_EQ(fstat(cow_->fd, &buf), 0);
497     ASSERT_EQ(buf.st_size, writer->GetCowSize());
498 
499     // Read back all valid operations
500     CowReader reader;
501     ASSERT_TRUE(reader.Parse(cow_->fd));
502 
503     StringSink sink;
504 
505     auto iter = reader.GetOpIter();
506     ASSERT_NE(iter, nullptr);
507 
508     ASSERT_FALSE(iter->Done());
509     auto op = &iter->Get();
510     ASSERT_EQ(op->type, kCowLabelOp);
511     ASSERT_EQ(op->source, 5);
512 
513     iter->Next();
514     ASSERT_TRUE(iter->Done());
515 }
516 
TEST_F(CowTest,AppendbyLabel)517 TEST_F(CowTest, AppendbyLabel) {
518     CowOptions options;
519     options.cluster_ops = 0;
520     auto writer = std::make_unique<CowWriter>(options);
521     ASSERT_TRUE(writer->Initialize(cow_->fd));
522 
523     std::string data = "This is some data, believe it";
524     data.resize(options.block_size * 2, '\0');
525     ASSERT_TRUE(writer->AddRawBlocks(50, data.data(), data.size()));
526 
527     ASSERT_TRUE(writer->AddLabel(4));
528 
529     ASSERT_TRUE(writer->AddZeroBlocks(50, 2));
530 
531     ASSERT_TRUE(writer->AddLabel(5));
532 
533     ASSERT_TRUE(writer->AddCopy(5, 6));
534 
535     ASSERT_TRUE(writer->AddLabel(6));
536 
537     ASSERT_EQ(lseek(cow_->fd, 0, SEEK_SET), 0);
538 
539     writer = std::make_unique<CowWriter>(options);
540     ASSERT_FALSE(writer->InitializeAppend(cow_->fd, 12));
541     ASSERT_TRUE(writer->InitializeAppend(cow_->fd, 5));
542 
543     // This should drop label 6
544     ASSERT_TRUE(writer->Finalize());
545 
546     struct stat buf;
547     ASSERT_EQ(fstat(cow_->fd, &buf), 0);
548     ASSERT_EQ(buf.st_size, writer->GetCowSize());
549 
550     // Read back all ops
551     CowReader reader;
552     ASSERT_TRUE(reader.Parse(cow_->fd));
553 
554     StringSink sink;
555 
556     auto iter = reader.GetOpIter();
557     ASSERT_NE(iter, nullptr);
558 
559     ASSERT_FALSE(iter->Done());
560     auto op = &iter->Get();
561     ASSERT_EQ(op->type, kCowReplaceOp);
562     ASSERT_TRUE(reader.ReadData(*op, &sink));
563     ASSERT_EQ(sink.stream(), data.substr(0, options.block_size));
564 
565     iter->Next();
566     sink.Reset();
567 
568     ASSERT_FALSE(iter->Done());
569     op = &iter->Get();
570     ASSERT_EQ(op->type, kCowReplaceOp);
571     ASSERT_TRUE(reader.ReadData(*op, &sink));
572     ASSERT_EQ(sink.stream(), data.substr(options.block_size, 2 * options.block_size));
573 
574     iter->Next();
575     sink.Reset();
576 
577     ASSERT_FALSE(iter->Done());
578     op = &iter->Get();
579     ASSERT_EQ(op->type, kCowLabelOp);
580     ASSERT_EQ(op->source, 4);
581 
582     iter->Next();
583 
584     ASSERT_FALSE(iter->Done());
585     op = &iter->Get();
586     ASSERT_EQ(op->type, kCowZeroOp);
587 
588     iter->Next();
589 
590     ASSERT_FALSE(iter->Done());
591     op = &iter->Get();
592     ASSERT_EQ(op->type, kCowZeroOp);
593 
594     iter->Next();
595     ASSERT_FALSE(iter->Done());
596     op = &iter->Get();
597     ASSERT_EQ(op->type, kCowLabelOp);
598     ASSERT_EQ(op->source, 5);
599 
600     iter->Next();
601 
602     ASSERT_TRUE(iter->Done());
603 }
604 
TEST_F(CowTest,ClusterTest)605 TEST_F(CowTest, ClusterTest) {
606     CowOptions options;
607     options.cluster_ops = 4;
608     auto writer = std::make_unique<CowWriter>(options);
609     ASSERT_TRUE(writer->Initialize(cow_->fd));
610 
611     std::string data = "This is some data, believe it";
612     data.resize(options.block_size, '\0');
613     ASSERT_TRUE(writer->AddRawBlocks(50, data.data(), data.size()));
614 
615     ASSERT_TRUE(writer->AddLabel(4));
616 
617     ASSERT_TRUE(writer->AddZeroBlocks(50, 2));  // Cluster split in middle
618 
619     ASSERT_TRUE(writer->AddLabel(5));
620 
621     ASSERT_TRUE(writer->AddCopy(5, 6));
622 
623     // Cluster split
624 
625     ASSERT_TRUE(writer->AddLabel(6));
626 
627     ASSERT_TRUE(writer->Finalize());  // No data for cluster, so no cluster split needed
628 
629     ASSERT_EQ(lseek(cow_->fd, 0, SEEK_SET), 0);
630 
631     // Read back all ops
632     CowReader reader;
633     ASSERT_TRUE(reader.Parse(cow_->fd));
634 
635     StringSink sink;
636 
637     auto iter = reader.GetOpIter();
638     ASSERT_NE(iter, nullptr);
639 
640     ASSERT_FALSE(iter->Done());
641     auto op = &iter->Get();
642     ASSERT_EQ(op->type, kCowReplaceOp);
643     ASSERT_TRUE(reader.ReadData(*op, &sink));
644     ASSERT_EQ(sink.stream(), data.substr(0, options.block_size));
645 
646     iter->Next();
647     sink.Reset();
648 
649     ASSERT_FALSE(iter->Done());
650     op = &iter->Get();
651     ASSERT_EQ(op->type, kCowLabelOp);
652     ASSERT_EQ(op->source, 4);
653 
654     iter->Next();
655 
656     ASSERT_FALSE(iter->Done());
657     op = &iter->Get();
658     ASSERT_EQ(op->type, kCowZeroOp);
659 
660     iter->Next();
661 
662     ASSERT_FALSE(iter->Done());
663     op = &iter->Get();
664     ASSERT_EQ(op->type, kCowClusterOp);
665 
666     iter->Next();
667 
668     ASSERT_FALSE(iter->Done());
669     op = &iter->Get();
670     ASSERT_EQ(op->type, kCowZeroOp);
671 
672     iter->Next();
673 
674     ASSERT_FALSE(iter->Done());
675     op = &iter->Get();
676     ASSERT_EQ(op->type, kCowLabelOp);
677     ASSERT_EQ(op->source, 5);
678 
679     iter->Next();
680 
681     ASSERT_FALSE(iter->Done());
682     op = &iter->Get();
683     ASSERT_EQ(op->type, kCowCopyOp);
684 
685     iter->Next();
686 
687     ASSERT_FALSE(iter->Done());
688     op = &iter->Get();
689     ASSERT_EQ(op->type, kCowClusterOp);
690 
691     iter->Next();
692 
693     ASSERT_FALSE(iter->Done());
694     op = &iter->Get();
695     ASSERT_EQ(op->type, kCowLabelOp);
696     ASSERT_EQ(op->source, 6);
697 
698     iter->Next();
699 
700     ASSERT_TRUE(iter->Done());
701 }
702 
TEST_F(CowTest,ClusterAppendTest)703 TEST_F(CowTest, ClusterAppendTest) {
704     CowOptions options;
705     options.cluster_ops = 3;
706     auto writer = std::make_unique<CowWriter>(options);
707     ASSERT_TRUE(writer->Initialize(cow_->fd));
708 
709     ASSERT_TRUE(writer->AddLabel(50));
710     ASSERT_TRUE(writer->Finalize());  // Adds a cluster op, should be dropped on append
711 
712     ASSERT_EQ(lseek(cow_->fd, 0, SEEK_SET), 0);
713 
714     writer = std::make_unique<CowWriter>(options);
715     ASSERT_TRUE(writer->InitializeAppend(cow_->fd, 50));
716 
717     std::string data2 = "More data!";
718     data2.resize(options.block_size, '\0');
719     ASSERT_TRUE(writer->AddRawBlocks(51, data2.data(), data2.size()));
720     ASSERT_TRUE(writer->Finalize());  // Adds a cluster op
721 
722     ASSERT_EQ(lseek(cow_->fd, 0, SEEK_SET), 0);
723 
724     struct stat buf;
725     ASSERT_EQ(fstat(cow_->fd, &buf), 0);
726     ASSERT_EQ(buf.st_size, writer->GetCowSize());
727 
728     // Read back both operations, plus cluster op at end
729     CowReader reader;
730     uint64_t label;
731     ASSERT_TRUE(reader.Parse(cow_->fd));
732     ASSERT_TRUE(reader.GetLastLabel(&label));
733     ASSERT_EQ(label, 50);
734 
735     StringSink sink;
736 
737     auto iter = reader.GetOpIter();
738     ASSERT_NE(iter, nullptr);
739 
740     ASSERT_FALSE(iter->Done());
741     auto op = &iter->Get();
742     ASSERT_EQ(op->type, kCowLabelOp);
743     ASSERT_EQ(op->source, 50);
744 
745     iter->Next();
746 
747     ASSERT_FALSE(iter->Done());
748     op = &iter->Get();
749     ASSERT_EQ(op->type, kCowReplaceOp);
750     ASSERT_TRUE(reader.ReadData(*op, &sink));
751     ASSERT_EQ(sink.stream(), data2);
752 
753     iter->Next();
754 
755     ASSERT_FALSE(iter->Done());
756     op = &iter->Get();
757     ASSERT_EQ(op->type, kCowClusterOp);
758 
759     iter->Next();
760 
761     ASSERT_TRUE(iter->Done());
762 }
763 
TEST_F(CowTest,AppendAfterFinalize)764 TEST_F(CowTest, AppendAfterFinalize) {
765     CowOptions options;
766     options.cluster_ops = 0;
767     auto writer = std::make_unique<CowWriter>(options);
768     ASSERT_TRUE(writer->Initialize(cow_->fd));
769 
770     std::string data = "This is some data, believe it";
771     data.resize(options.block_size, '\0');
772     ASSERT_TRUE(writer->AddRawBlocks(50, data.data(), data.size()));
773     ASSERT_TRUE(writer->AddLabel(3));
774     ASSERT_TRUE(writer->Finalize());
775 
776     std::string data2 = "More data!";
777     data2.resize(options.block_size, '\0');
778     ASSERT_TRUE(writer->AddRawBlocks(51, data2.data(), data2.size()));
779     ASSERT_TRUE(writer->Finalize());
780 
781     ASSERT_EQ(lseek(cow_->fd, 0, SEEK_SET), 0);
782 
783     // COW should be valid.
784     CowReader reader;
785     ASSERT_TRUE(reader.Parse(cow_->fd));
786 }
787 
WriteDataBlock(CowWriter * writer,uint64_t new_block,std::string data)788 AssertionResult WriteDataBlock(CowWriter* writer, uint64_t new_block, std::string data) {
789     data.resize(writer->options().block_size, '\0');
790     if (!writer->AddRawBlocks(new_block, data.data(), data.size())) {
791         return AssertionFailure() << "Failed to add raw block";
792     }
793     return AssertionSuccess();
794 }
795 
CompareDataBlock(CowReader * reader,const CowOperation & op,const std::string & data)796 AssertionResult CompareDataBlock(CowReader* reader, const CowOperation& op,
797                                  const std::string& data) {
798     CowHeader header;
799     reader->GetHeader(&header);
800 
801     std::string cmp = data;
802     cmp.resize(header.block_size, '\0');
803 
804     StringSink sink;
805     if (!reader->ReadData(op, &sink)) {
806         return AssertionFailure() << "Failed to read data block";
807     }
808     if (cmp != sink.stream()) {
809         return AssertionFailure() << "Data blocks did not match, expected " << cmp << ", got "
810                                   << sink.stream();
811     }
812 
813     return AssertionSuccess();
814 }
815 
TEST_F(CowTest,ResumeMidCluster)816 TEST_F(CowTest, ResumeMidCluster) {
817     CowOptions options;
818     options.cluster_ops = 7;
819     auto writer = std::make_unique<CowWriter>(options);
820     ASSERT_TRUE(writer->Initialize(cow_->fd));
821 
822     ASSERT_TRUE(WriteDataBlock(writer.get(), 1, "Block 1"));
823     ASSERT_TRUE(WriteDataBlock(writer.get(), 2, "Block 2"));
824     ASSERT_TRUE(WriteDataBlock(writer.get(), 3, "Block 3"));
825     ASSERT_TRUE(writer->AddLabel(1));
826     ASSERT_TRUE(writer->Finalize());
827     ASSERT_TRUE(WriteDataBlock(writer.get(), 4, "Block 4"));
828     ASSERT_EQ(lseek(cow_->fd, 0, SEEK_SET), 0);
829 
830     writer = std::make_unique<CowWriter>(options);
831     ASSERT_TRUE(writer->InitializeAppend(cow_->fd, 1));
832     ASSERT_TRUE(WriteDataBlock(writer.get(), 4, "Block 4"));
833     ASSERT_TRUE(WriteDataBlock(writer.get(), 5, "Block 5"));
834     ASSERT_TRUE(WriteDataBlock(writer.get(), 6, "Block 6"));
835     ASSERT_TRUE(WriteDataBlock(writer.get(), 7, "Block 7"));
836     ASSERT_TRUE(WriteDataBlock(writer.get(), 8, "Block 8"));
837     ASSERT_TRUE(writer->AddLabel(2));
838     ASSERT_TRUE(writer->Finalize());
839     ASSERT_EQ(lseek(cow_->fd, 0, SEEK_SET), 0);
840 
841     CowReader reader;
842     ASSERT_TRUE(reader.Parse(cow_->fd));
843 
844     auto iter = reader.GetOpIter();
845     size_t num_replace = 0;
846     size_t max_in_cluster = 0;
847     size_t num_in_cluster = 0;
848     size_t num_clusters = 0;
849     while (!iter->Done()) {
850         const auto& op = iter->Get();
851 
852         num_in_cluster++;
853         max_in_cluster = std::max(max_in_cluster, num_in_cluster);
854 
855         if (op.type == kCowReplaceOp) {
856             num_replace++;
857 
858             ASSERT_EQ(op.new_block, num_replace);
859             ASSERT_TRUE(CompareDataBlock(&reader, op, "Block " + std::to_string(num_replace)));
860         } else if (op.type == kCowClusterOp) {
861             num_in_cluster = 0;
862             num_clusters++;
863         }
864 
865         iter->Next();
866     }
867     ASSERT_EQ(num_replace, 8);
868     ASSERT_EQ(max_in_cluster, 7);
869     ASSERT_EQ(num_clusters, 2);
870 }
871 
TEST_F(CowTest,ResumeEndCluster)872 TEST_F(CowTest, ResumeEndCluster) {
873     CowOptions options;
874     int cluster_ops = 5;
875     options.cluster_ops = cluster_ops;
876     auto writer = std::make_unique<CowWriter>(options);
877     ASSERT_TRUE(writer->Initialize(cow_->fd));
878 
879     ASSERT_TRUE(WriteDataBlock(writer.get(), 1, "Block 1"));
880     ASSERT_TRUE(WriteDataBlock(writer.get(), 2, "Block 2"));
881     ASSERT_TRUE(WriteDataBlock(writer.get(), 3, "Block 3"));
882     ASSERT_TRUE(writer->AddLabel(1));
883     ASSERT_TRUE(writer->Finalize());
884     ASSERT_TRUE(WriteDataBlock(writer.get(), 4, "Block 4"));
885     ASSERT_TRUE(WriteDataBlock(writer.get(), 5, "Block 5"));
886     ASSERT_TRUE(WriteDataBlock(writer.get(), 6, "Block 6"));
887     ASSERT_TRUE(WriteDataBlock(writer.get(), 7, "Block 7"));
888     ASSERT_TRUE(WriteDataBlock(writer.get(), 8, "Block 8"));
889     ASSERT_EQ(lseek(cow_->fd, 0, SEEK_SET), 0);
890 
891     writer = std::make_unique<CowWriter>(options);
892     ASSERT_TRUE(writer->InitializeAppend(cow_->fd, 1));
893     ASSERT_TRUE(WriteDataBlock(writer.get(), 4, "Block 4"));
894     ASSERT_TRUE(WriteDataBlock(writer.get(), 5, "Block 5"));
895     ASSERT_TRUE(WriteDataBlock(writer.get(), 6, "Block 6"));
896     ASSERT_TRUE(WriteDataBlock(writer.get(), 7, "Block 7"));
897     ASSERT_TRUE(WriteDataBlock(writer.get(), 8, "Block 8"));
898     ASSERT_TRUE(writer->AddLabel(2));
899     ASSERT_TRUE(writer->Finalize());
900     ASSERT_EQ(lseek(cow_->fd, 0, SEEK_SET), 0);
901 
902     CowReader reader;
903     ASSERT_TRUE(reader.Parse(cow_->fd));
904 
905     auto iter = reader.GetOpIter();
906     size_t num_replace = 0;
907     size_t max_in_cluster = 0;
908     size_t num_in_cluster = 0;
909     size_t num_clusters = 0;
910     while (!iter->Done()) {
911         const auto& op = iter->Get();
912 
913         num_in_cluster++;
914         max_in_cluster = std::max(max_in_cluster, num_in_cluster);
915 
916         if (op.type == kCowReplaceOp) {
917             num_replace++;
918 
919             ASSERT_EQ(op.new_block, num_replace);
920             ASSERT_TRUE(CompareDataBlock(&reader, op, "Block " + std::to_string(num_replace)));
921         } else if (op.type == kCowClusterOp) {
922             num_in_cluster = 0;
923             num_clusters++;
924         }
925 
926         iter->Next();
927     }
928     ASSERT_EQ(num_replace, 8);
929     ASSERT_EQ(max_in_cluster, cluster_ops);
930     ASSERT_EQ(num_clusters, 3);
931 }
932 
TEST_F(CowTest,DeleteMidCluster)933 TEST_F(CowTest, DeleteMidCluster) {
934     CowOptions options;
935     options.cluster_ops = 7;
936     auto writer = std::make_unique<CowWriter>(options);
937     ASSERT_TRUE(writer->Initialize(cow_->fd));
938 
939     ASSERT_TRUE(WriteDataBlock(writer.get(), 1, "Block 1"));
940     ASSERT_TRUE(WriteDataBlock(writer.get(), 2, "Block 2"));
941     ASSERT_TRUE(WriteDataBlock(writer.get(), 3, "Block 3"));
942     ASSERT_TRUE(writer->AddLabel(1));
943     ASSERT_TRUE(writer->Finalize());
944     ASSERT_TRUE(WriteDataBlock(writer.get(), 4, "Block 4"));
945     ASSERT_TRUE(WriteDataBlock(writer.get(), 5, "Block 5"));
946     ASSERT_TRUE(WriteDataBlock(writer.get(), 6, "Block 6"));
947     ASSERT_EQ(lseek(cow_->fd, 0, SEEK_SET), 0);
948 
949     writer = std::make_unique<CowWriter>(options);
950     ASSERT_TRUE(writer->InitializeAppend(cow_->fd, 1));
951     ASSERT_TRUE(writer->Finalize());
952     ASSERT_EQ(lseek(cow_->fd, 0, SEEK_SET), 0);
953 
954     CowReader reader;
955     ASSERT_TRUE(reader.Parse(cow_->fd));
956 
957     auto iter = reader.GetOpIter();
958     size_t num_replace = 0;
959     size_t max_in_cluster = 0;
960     size_t num_in_cluster = 0;
961     size_t num_clusters = 0;
962     while (!iter->Done()) {
963         const auto& op = iter->Get();
964 
965         num_in_cluster++;
966         max_in_cluster = std::max(max_in_cluster, num_in_cluster);
967         if (op.type == kCowReplaceOp) {
968             num_replace++;
969 
970             ASSERT_EQ(op.new_block, num_replace);
971             ASSERT_TRUE(CompareDataBlock(&reader, op, "Block " + std::to_string(num_replace)));
972         } else if (op.type == kCowClusterOp) {
973             num_in_cluster = 0;
974             num_clusters++;
975         }
976 
977         iter->Next();
978     }
979     ASSERT_EQ(num_replace, 3);
980     ASSERT_EQ(max_in_cluster, 5);  // 3 data, 1 label, 1 cluster op
981     ASSERT_EQ(num_clusters, 1);
982 }
983 
984 }  // namespace snapshot
985 }  // namespace android
986 
main(int argc,char ** argv)987 int main(int argc, char** argv) {
988     ::testing::InitGoogleTest(&argc, argv);
989     return RUN_ALL_TESTS();
990 }
991