1 //
2 // Copyright (C) 2009 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 "update_engine/payload_consumer/extent_writer.h"
18 
19 #include <fcntl.h>
20 
21 #include <algorithm>
22 #include <memory>
23 #include <string>
24 #include <vector>
25 
26 #include <brillo/secure_blob.h>
27 #include <gtest/gtest.h>
28 
29 #include "update_engine/common/test_utils.h"
30 #include "update_engine/common/utils.h"
31 #include "update_engine/payload_consumer/payload_constants.h"
32 #include "update_engine/payload_generator/extent_ranges.h"
33 
34 using chromeos_update_engine::test_utils::ExpectVectorsEq;
35 using std::min;
36 using std::string;
37 using std::vector;
38 
39 namespace chromeos_update_engine {
40 
41 static_assert(sizeof(off_t) == 8, "off_t not 64 bit");
42 
43 namespace {
44 const size_t kBlockSize = 4096;
45 }
46 
47 class ExtentWriterTest : public ::testing::Test {
48  protected:
SetUp()49   void SetUp() override {
50     fd_.reset(new EintrSafeFileDescriptor);
51     ASSERT_TRUE(fd_->Open(temp_file_.path().c_str(), O_RDWR, 0600));
52   }
TearDown()53   void TearDown() override {
54     fd_->Close();
55   }
56 
57   // Writes data to an extent writer in 'chunk_size' chunks with
58   // the first chunk of size first_chunk_size. It calculates what the
59   // resultant file should look like and ensure that the extent writer
60   // wrote the file correctly.
61   void WriteAlignedExtents(size_t chunk_size, size_t first_chunk_size);
62   void TestZeroPad(bool aligned_size);
63 
64   FileDescriptorPtr fd_;
65   test_utils::ScopedTempFile temp_file_{"ExtentWriterTest-file.XXXXXX"};
66 };
67 
TEST_F(ExtentWriterTest,SimpleTest)68 TEST_F(ExtentWriterTest, SimpleTest) {
69   vector<Extent> extents = {ExtentForRange(1, 1)};
70   const string bytes = "1234";
71   DirectExtentWriter direct_writer;
72   EXPECT_TRUE(
73       direct_writer.Init(fd_, {extents.begin(), extents.end()}, kBlockSize));
74   EXPECT_TRUE(direct_writer.Write(bytes.data(), bytes.size()));
75   EXPECT_TRUE(direct_writer.End());
76 
77   EXPECT_EQ(static_cast<off_t>(kBlockSize + bytes.size()),
78             utils::FileSize(temp_file_.path()));
79 
80   brillo::Blob result_file;
81   EXPECT_TRUE(utils::ReadFile(temp_file_.path(), &result_file));
82 
83   brillo::Blob expected_file(kBlockSize);
84   expected_file.insert(expected_file.end(),
85                        bytes.data(), bytes.data() + bytes.size());
86   ExpectVectorsEq(expected_file, result_file);
87 }
88 
TEST_F(ExtentWriterTest,ZeroLengthTest)89 TEST_F(ExtentWriterTest, ZeroLengthTest) {
90   vector<Extent> extents = {ExtentForRange(1, 1)};
91   DirectExtentWriter direct_writer;
92   EXPECT_TRUE(
93       direct_writer.Init(fd_, {extents.begin(), extents.end()}, kBlockSize));
94   EXPECT_TRUE(direct_writer.Write(nullptr, 0));
95   EXPECT_TRUE(direct_writer.End());
96 }
97 
TEST_F(ExtentWriterTest,OverflowExtentTest)98 TEST_F(ExtentWriterTest, OverflowExtentTest) {
99   WriteAlignedExtents(kBlockSize * 3, kBlockSize * 3);
100 }
101 
TEST_F(ExtentWriterTest,UnalignedWriteTest)102 TEST_F(ExtentWriterTest, UnalignedWriteTest) {
103   WriteAlignedExtents(7, 7);
104 }
105 
TEST_F(ExtentWriterTest,LargeUnalignedWriteTest)106 TEST_F(ExtentWriterTest, LargeUnalignedWriteTest) {
107   WriteAlignedExtents(kBlockSize * 2, kBlockSize / 2);
108 }
109 
WriteAlignedExtents(size_t chunk_size,size_t first_chunk_size)110 void ExtentWriterTest::WriteAlignedExtents(size_t chunk_size,
111                                            size_t first_chunk_size) {
112   vector<Extent> extents = {
113       ExtentForRange(1, 1), ExtentForRange(0, 1), ExtentForRange(2, 1)};
114   brillo::Blob data(kBlockSize * 3);
115   test_utils::FillWithData(&data);
116 
117   DirectExtentWriter direct_writer;
118   EXPECT_TRUE(
119       direct_writer.Init(fd_, {extents.begin(), extents.end()}, kBlockSize));
120 
121   size_t bytes_written = 0;
122   while (bytes_written < data.size()) {
123     size_t bytes_to_write = min(data.size() - bytes_written, chunk_size);
124     if (bytes_written == 0) {
125       bytes_to_write = min(data.size() - bytes_written, first_chunk_size);
126     }
127     EXPECT_TRUE(direct_writer.Write(&data[bytes_written], bytes_to_write));
128     bytes_written += bytes_to_write;
129   }
130   EXPECT_TRUE(direct_writer.End());
131 
132   EXPECT_EQ(static_cast<off_t>(data.size()),
133             utils::FileSize(temp_file_.path()));
134 
135   brillo::Blob result_file;
136   EXPECT_TRUE(utils::ReadFile(temp_file_.path(), &result_file));
137 
138   brillo::Blob expected_file;
139   expected_file.insert(expected_file.end(),
140                        data.begin() + kBlockSize,
141                        data.begin() + kBlockSize * 2);
142   expected_file.insert(expected_file.end(),
143                        data.begin(), data.begin() + kBlockSize);
144   expected_file.insert(expected_file.end(),
145                        data.begin() + kBlockSize * 2, data.end());
146   ExpectVectorsEq(expected_file, result_file);
147 }
148 
TEST_F(ExtentWriterTest,ZeroPadNullTest)149 TEST_F(ExtentWriterTest, ZeroPadNullTest) {
150   TestZeroPad(true);
151 }
152 
TEST_F(ExtentWriterTest,ZeroPadFillTest)153 TEST_F(ExtentWriterTest, ZeroPadFillTest) {
154   TestZeroPad(false);
155 }
156 
TestZeroPad(bool aligned_size)157 void ExtentWriterTest::TestZeroPad(bool aligned_size) {
158   vector<Extent> extents = {ExtentForRange(1, 1), ExtentForRange(0, 1)};
159   brillo::Blob data(kBlockSize * 2);
160   test_utils::FillWithData(&data);
161 
162   ZeroPadExtentWriter zero_pad_writer(std::make_unique<DirectExtentWriter>());
163 
164   EXPECT_TRUE(
165       zero_pad_writer.Init(fd_, {extents.begin(), extents.end()}, kBlockSize));
166   size_t bytes_to_write = data.size();
167   const size_t missing_bytes = (aligned_size ? 0 : 9);
168   bytes_to_write -= missing_bytes;
169   fd_->Seek(kBlockSize - missing_bytes, SEEK_SET);
170   EXPECT_EQ(3, fd_->Write("xxx", 3));
171   ASSERT_TRUE(zero_pad_writer.Write(data.data(), bytes_to_write));
172   EXPECT_TRUE(zero_pad_writer.End());
173 
174   EXPECT_EQ(static_cast<off_t>(data.size()),
175             utils::FileSize(temp_file_.path()));
176 
177   brillo::Blob result_file;
178   EXPECT_TRUE(utils::ReadFile(temp_file_.path(), &result_file));
179 
180   brillo::Blob expected_file;
181   expected_file.insert(expected_file.end(),
182                        data.begin() + kBlockSize,
183                        data.begin() + kBlockSize * 2);
184   expected_file.insert(expected_file.end(),
185                        data.begin(), data.begin() + kBlockSize);
186   if (missing_bytes) {
187     memset(&expected_file[kBlockSize - missing_bytes], 0, missing_bytes);
188   }
189 
190   ExpectVectorsEq(expected_file, result_file);
191 }
192 
TEST_F(ExtentWriterTest,SparseFileTest)193 TEST_F(ExtentWriterTest, SparseFileTest) {
194   vector<Extent> extents = {ExtentForRange(1, 1),
195                             ExtentForRange(kSparseHole, 2),
196                             ExtentForRange(0, 1)};
197   const int block_count = 4;
198   const int on_disk_count = 2;
199 
200   brillo::Blob data(17);
201   test_utils::FillWithData(&data);
202 
203   DirectExtentWriter direct_writer;
204   EXPECT_TRUE(
205       direct_writer.Init(fd_, {extents.begin(), extents.end()}, kBlockSize));
206 
207   size_t bytes_written = 0;
208   while (bytes_written < (block_count * kBlockSize)) {
209     size_t bytes_to_write = min(block_count * kBlockSize - bytes_written,
210                                 data.size());
211     EXPECT_TRUE(direct_writer.Write(data.data(), bytes_to_write));
212     bytes_written += bytes_to_write;
213   }
214   EXPECT_TRUE(direct_writer.End());
215 
216   // check file size, then data inside
217   ASSERT_EQ(static_cast<off_t>(2 * kBlockSize),
218             utils::FileSize(temp_file_.path()));
219 
220   brillo::Blob resultant_data;
221   EXPECT_TRUE(utils::ReadFile(temp_file_.path(), &resultant_data));
222 
223   // Create expected data
224   brillo::Blob expected_data(on_disk_count * kBlockSize);
225   brillo::Blob big(block_count * kBlockSize);
226   for (brillo::Blob::size_type i = 0; i < big.size(); i++) {
227     big[i] = data[i % data.size()];
228   }
229   memcpy(&expected_data[kBlockSize], &big[0], kBlockSize);
230   memcpy(&expected_data[0], &big[3 * kBlockSize], kBlockSize);
231   ExpectVectorsEq(expected_data, resultant_data);
232 }
233 
234 }  // namespace chromeos_update_engine
235