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