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: 48 void SetUp() override { 49 fd_.reset(new EintrSafeFileDescriptor); 50 ASSERT_TRUE(fd_->Open(temp_file_.path().c_str(), O_RDWR, 0600)); 51 } 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 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 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 106 TEST_F(ExtentWriterTest, OverflowExtentTest) { 107 WriteAlignedExtents(kBlockSize * 3, kBlockSize * 3); 108 } 109 110 TEST_F(ExtentWriterTest, UnalignedWriteTest) { 111 WriteAlignedExtents(7, 7); 112 } 113 114 TEST_F(ExtentWriterTest, LargeUnalignedWriteTest) { 115 WriteAlignedExtents(kBlockSize * 2, kBlockSize / 2); 116 } 117 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 166 TEST_F(ExtentWriterTest, ZeroPadNullTest) { 167 TestZeroPad(true); 168 } 169 170 TEST_F(ExtentWriterTest, ZeroPadFillTest) { 171 TestZeroPad(false); 172 } 173 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 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