blob: 9da8adbf41fea0ba155ea7b141ecd3c7bda246b0 [file] [log] [blame]
Alex Deymoaea4c1c2015-08-19 20:24:43 -07001//
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//
Andrew de los Reyes80061062010-02-04 14:25:00 -080016
Alex Deymo161c4a12014-05-16 15:56:21 -070017#include "update_engine/extent_writer.h"
18
Nam T. Nguyenf1d582e2014-12-08 15:07:17 -080019#include <fcntl.h>
Andrew de los Reyes80061062010-02-04 14:25:00 -080020#include <sys/stat.h>
21#include <sys/types.h>
22#include <unistd.h>
Alex Deymo161c4a12014-05-16 15:56:21 -070023
Andrew de los Reyes80061062010-02-04 14:25:00 -080024#include <algorithm>
25#include <string>
26#include <vector>
Alex Deymo161c4a12014-05-16 15:56:21 -070027
Alex Vakulenkof68bbbc2015-02-09 12:53:18 -080028#include <chromeos/secure_blob.h>
Andrew de los Reyes80061062010-02-04 14:25:00 -080029#include <gtest/gtest.h>
Alex Deymo161c4a12014-05-16 15:56:21 -070030
31#include "update_engine/payload_constants.h"
Andrew de los Reyes80061062010-02-04 14:25:00 -080032#include "update_engine/test_utils.h"
33#include "update_engine/utils.h"
34
Alex Deymo10875d92014-11-10 21:52:57 -080035using chromeos_update_engine::test_utils::ExpectVectorsEq;
Andrew de los Reyes80061062010-02-04 14:25:00 -080036using std::min;
37using std::string;
38using std::vector;
39
40namespace chromeos_update_engine {
41
42COMPILE_ASSERT(sizeof(off_t) == 8, off_t_not_64_bit);
43
44namespace {
45const char kPathTemplate[] = "./ExtentWriterTest-file.XXXXXX";
46const size_t kBlockSize = 4096;
47}
48
49class ExtentWriterTest : public ::testing::Test {
50 protected:
Alex Deymo610277e2014-11-11 21:18:11 -080051 void SetUp() override {
Andrew de los Reyes80061062010-02-04 14:25:00 -080052 memcpy(path_, kPathTemplate, sizeof(kPathTemplate));
Nam T. Nguyenf1d582e2014-12-08 15:07:17 -080053 fd_.reset(new EintrSafeFileDescriptor);
54 int fd = mkstemp(path_);
55 ASSERT_TRUE(fd_->Open(path_, O_RDWR, 0600));
56 close(fd);
Andrew de los Reyes80061062010-02-04 14:25:00 -080057 }
Alex Deymo610277e2014-11-11 21:18:11 -080058 void TearDown() override {
Nam T. Nguyenf1d582e2014-12-08 15:07:17 -080059 fd_->Close();
Andrew de los Reyes80061062010-02-04 14:25:00 -080060 unlink(path_);
61 }
Chris Masonef8d037f2014-02-19 01:53:00 +000062
Andrew de los Reyes80061062010-02-04 14:25:00 -080063 // Writes data to an extent writer in 'chunk_size' chunks with
64 // the first chunk of size first_chunk_size. It calculates what the
65 // resultant file should look like and ensure that the extent writer
66 // wrote the file correctly.
67 void WriteAlignedExtents(size_t chunk_size, size_t first_chunk_size);
68 void TestZeroPad(bool aligned_size);
Nam T. Nguyenf1d582e2014-12-08 15:07:17 -080069
70 FileDescriptorPtr fd_;
Andrew de los Reyes80061062010-02-04 14:25:00 -080071 char path_[sizeof(kPathTemplate)];
72};
73
74TEST_F(ExtentWriterTest, SimpleTest) {
75 vector<Extent> extents;
76 Extent extent;
77 extent.set_start_block(1);
78 extent.set_num_blocks(1);
79 extents.push_back(extent);
Alex Deymo161c4a12014-05-16 15:56:21 -070080
Andrew de los Reyes80061062010-02-04 14:25:00 -080081 const string bytes = "1234";
82
83 DirectExtentWriter direct_writer;
Nam T. Nguyenf1d582e2014-12-08 15:07:17 -080084 EXPECT_TRUE(direct_writer.Init(fd_, extents, kBlockSize));
Andrew de los Reyes80061062010-02-04 14:25:00 -080085 EXPECT_TRUE(direct_writer.Write(bytes.data(), bytes.size()));
86 EXPECT_TRUE(direct_writer.End());
Alex Deymo161c4a12014-05-16 15:56:21 -070087
Nam T. Nguyenf1d582e2014-12-08 15:07:17 -080088 EXPECT_EQ(kBlockSize + bytes.size(), utils::FileSize(path_));
Alex Deymo161c4a12014-05-16 15:56:21 -070089
Alex Vakulenkof68bbbc2015-02-09 12:53:18 -080090 chromeos::Blob result_file;
Nam T. Nguyenf1d582e2014-12-08 15:07:17 -080091 EXPECT_TRUE(utils::ReadFile(path_, &result_file));
Alex Deymo161c4a12014-05-16 15:56:21 -070092
Alex Vakulenkof68bbbc2015-02-09 12:53:18 -080093 chromeos::Blob expected_file(kBlockSize);
Andrew de los Reyes80061062010-02-04 14:25:00 -080094 expected_file.insert(expected_file.end(),
95 bytes.data(), bytes.data() + bytes.size());
96 ExpectVectorsEq(expected_file, result_file);
97}
98
99TEST_F(ExtentWriterTest, ZeroLengthTest) {
100 vector<Extent> extents;
101 Extent extent;
102 extent.set_start_block(1);
103 extent.set_num_blocks(1);
104 extents.push_back(extent);
105
106 DirectExtentWriter direct_writer;
Nam T. Nguyenf1d582e2014-12-08 15:07:17 -0800107 EXPECT_TRUE(direct_writer.Init(fd_, extents, kBlockSize));
Alex Vakulenko88b591f2014-08-28 16:48:57 -0700108 EXPECT_TRUE(direct_writer.Write(nullptr, 0));
Andrew de los Reyes80061062010-02-04 14:25:00 -0800109 EXPECT_TRUE(direct_writer.End());
110}
111
112TEST_F(ExtentWriterTest, OverflowExtentTest) {
113 WriteAlignedExtents(kBlockSize * 3, kBlockSize * 3);
114}
115
116TEST_F(ExtentWriterTest, UnalignedWriteTest) {
117 WriteAlignedExtents(7, 7);
118}
119
120TEST_F(ExtentWriterTest, LargeUnalignedWriteTest) {
121 WriteAlignedExtents(kBlockSize * 2, kBlockSize / 2);
122}
123
124void ExtentWriterTest::WriteAlignedExtents(size_t chunk_size,
125 size_t first_chunk_size) {
126 vector<Extent> extents;
127 Extent extent;
128 extent.set_start_block(1);
129 extent.set_num_blocks(1);
130 extents.push_back(extent);
131 extent.set_start_block(0);
132 extent.set_num_blocks(1);
133 extents.push_back(extent);
134 extent.set_start_block(2);
135 extent.set_num_blocks(1);
136 extents.push_back(extent);
Alex Deymo161c4a12014-05-16 15:56:21 -0700137
Alex Vakulenkof68bbbc2015-02-09 12:53:18 -0800138 chromeos::Blob data(kBlockSize * 3);
Alex Deymo10875d92014-11-10 21:52:57 -0800139 test_utils::FillWithData(&data);
Alex Deymo161c4a12014-05-16 15:56:21 -0700140
Andrew de los Reyes80061062010-02-04 14:25:00 -0800141 DirectExtentWriter direct_writer;
Nam T. Nguyenf1d582e2014-12-08 15:07:17 -0800142 EXPECT_TRUE(direct_writer.Init(fd_, extents, kBlockSize));
Alex Deymo161c4a12014-05-16 15:56:21 -0700143
Andrew de los Reyes80061062010-02-04 14:25:00 -0800144 size_t bytes_written = 0;
145 while (bytes_written < data.size()) {
146 size_t bytes_to_write = min(data.size() - bytes_written, chunk_size);
147 if (bytes_written == 0) {
148 bytes_to_write = min(data.size() - bytes_written, first_chunk_size);
149 }
150 EXPECT_TRUE(direct_writer.Write(&data[bytes_written], bytes_to_write));
151 bytes_written += bytes_to_write;
152 }
153 EXPECT_TRUE(direct_writer.End());
Alex Deymo161c4a12014-05-16 15:56:21 -0700154
Nam T. Nguyenf1d582e2014-12-08 15:07:17 -0800155 EXPECT_EQ(data.size(), utils::FileSize(path_));
Alex Deymo161c4a12014-05-16 15:56:21 -0700156
Alex Vakulenkof68bbbc2015-02-09 12:53:18 -0800157 chromeos::Blob result_file;
Nam T. Nguyenf1d582e2014-12-08 15:07:17 -0800158 EXPECT_TRUE(utils::ReadFile(path_, &result_file));
Alex Deymo161c4a12014-05-16 15:56:21 -0700159
Alex Vakulenkof68bbbc2015-02-09 12:53:18 -0800160 chromeos::Blob expected_file;
Andrew de los Reyes80061062010-02-04 14:25:00 -0800161 expected_file.insert(expected_file.end(),
162 data.begin() + kBlockSize,
163 data.begin() + kBlockSize * 2);
164 expected_file.insert(expected_file.end(),
165 data.begin(), data.begin() + kBlockSize);
166 expected_file.insert(expected_file.end(),
167 data.begin() + kBlockSize * 2, data.end());
168 ExpectVectorsEq(expected_file, result_file);
169}
170
171TEST_F(ExtentWriterTest, ZeroPadNullTest) {
172 TestZeroPad(true);
173}
174
175TEST_F(ExtentWriterTest, ZeroPadFillTest) {
176 TestZeroPad(false);
177}
178
179void ExtentWriterTest::TestZeroPad(bool aligned_size) {
180 vector<Extent> extents;
181 Extent extent;
182 extent.set_start_block(1);
183 extent.set_num_blocks(1);
184 extents.push_back(extent);
185 extent.set_start_block(0);
186 extent.set_num_blocks(1);
187 extents.push_back(extent);
Alex Deymo161c4a12014-05-16 15:56:21 -0700188
Alex Vakulenkof68bbbc2015-02-09 12:53:18 -0800189 chromeos::Blob data(kBlockSize * 2);
Alex Deymo10875d92014-11-10 21:52:57 -0800190 test_utils::FillWithData(&data);
Alex Deymo161c4a12014-05-16 15:56:21 -0700191
Andrew de los Reyes80061062010-02-04 14:25:00 -0800192 DirectExtentWriter direct_writer;
193 ZeroPadExtentWriter zero_pad_writer(&direct_writer);
194
Nam T. Nguyenf1d582e2014-12-08 15:07:17 -0800195 EXPECT_TRUE(zero_pad_writer.Init(fd_, extents, kBlockSize));
Andrew de los Reyes80061062010-02-04 14:25:00 -0800196 size_t bytes_to_write = data.size();
197 const size_t missing_bytes = (aligned_size ? 0 : 9);
198 bytes_to_write -= missing_bytes;
Nam T. Nguyenf1d582e2014-12-08 15:07:17 -0800199 fd_->Seek(kBlockSize - missing_bytes, SEEK_SET);
200 EXPECT_EQ(3, fd_->Write("xxx", 3));
Alex Vakulenkof68bbbc2015-02-09 12:53:18 -0800201 ASSERT_TRUE(zero_pad_writer.Write(data.data(), bytes_to_write));
Andrew de los Reyes80061062010-02-04 14:25:00 -0800202 EXPECT_TRUE(zero_pad_writer.End());
Alex Deymo161c4a12014-05-16 15:56:21 -0700203
Nam T. Nguyenf1d582e2014-12-08 15:07:17 -0800204 EXPECT_EQ(data.size(), utils::FileSize(path_));
Alex Deymo161c4a12014-05-16 15:56:21 -0700205
Alex Vakulenkof68bbbc2015-02-09 12:53:18 -0800206 chromeos::Blob result_file;
Nam T. Nguyenf1d582e2014-12-08 15:07:17 -0800207 EXPECT_TRUE(utils::ReadFile(path_, &result_file));
Alex Deymo161c4a12014-05-16 15:56:21 -0700208
Alex Vakulenkof68bbbc2015-02-09 12:53:18 -0800209 chromeos::Blob expected_file;
Andrew de los Reyes80061062010-02-04 14:25:00 -0800210 expected_file.insert(expected_file.end(),
211 data.begin() + kBlockSize,
212 data.begin() + kBlockSize * 2);
213 expected_file.insert(expected_file.end(),
214 data.begin(), data.begin() + kBlockSize);
215 if (missing_bytes) {
216 memset(&expected_file[kBlockSize - missing_bytes], 0, missing_bytes);
217 }
218
219 ExpectVectorsEq(expected_file, result_file);
220}
221
222TEST_F(ExtentWriterTest, SparseFileTest) {
223 vector<Extent> extents;
224 Extent extent;
225 extent.set_start_block(1);
226 extent.set_num_blocks(1);
227 extents.push_back(extent);
228 extent.set_start_block(kSparseHole);
229 extent.set_num_blocks(2);
230 extents.push_back(extent);
231 extent.set_start_block(0);
232 extent.set_num_blocks(1);
233 extents.push_back(extent);
234 const int block_count = 4;
235 const int on_disk_count = 2;
236
Alex Vakulenkof68bbbc2015-02-09 12:53:18 -0800237 chromeos::Blob data(17);
Alex Deymo10875d92014-11-10 21:52:57 -0800238 test_utils::FillWithData(&data);
Andrew de los Reyes80061062010-02-04 14:25:00 -0800239
240 DirectExtentWriter direct_writer;
Nam T. Nguyenf1d582e2014-12-08 15:07:17 -0800241 EXPECT_TRUE(direct_writer.Init(fd_, extents, kBlockSize));
Alex Deymo161c4a12014-05-16 15:56:21 -0700242
Andrew de los Reyes80061062010-02-04 14:25:00 -0800243 size_t bytes_written = 0;
244 while (bytes_written < (block_count * kBlockSize)) {
245 size_t bytes_to_write = min(block_count * kBlockSize - bytes_written,
246 data.size());
Alex Vakulenkof68bbbc2015-02-09 12:53:18 -0800247 EXPECT_TRUE(direct_writer.Write(data.data(), bytes_to_write));
Andrew de los Reyes80061062010-02-04 14:25:00 -0800248 bytes_written += bytes_to_write;
249 }
250 EXPECT_TRUE(direct_writer.End());
Alex Deymo161c4a12014-05-16 15:56:21 -0700251
Andrew de los Reyes80061062010-02-04 14:25:00 -0800252 // check file size, then data inside
Nam T. Nguyenf1d582e2014-12-08 15:07:17 -0800253 ASSERT_EQ(2 * kBlockSize, utils::FileSize(path_));
Alex Deymo161c4a12014-05-16 15:56:21 -0700254
Alex Vakulenkof68bbbc2015-02-09 12:53:18 -0800255 chromeos::Blob resultant_data;
Nam T. Nguyenf1d582e2014-12-08 15:07:17 -0800256 EXPECT_TRUE(utils::ReadFile(path_, &resultant_data));
Alex Deymo161c4a12014-05-16 15:56:21 -0700257
Andrew de los Reyes80061062010-02-04 14:25:00 -0800258 // Create expected data
Alex Vakulenkof68bbbc2015-02-09 12:53:18 -0800259 chromeos::Blob expected_data(on_disk_count * kBlockSize);
260 chromeos::Blob big(block_count * kBlockSize);
261 for (chromeos::Blob::size_type i = 0; i < big.size(); i++) {
Andrew de los Reyes80061062010-02-04 14:25:00 -0800262 big[i] = data[i % data.size()];
263 }
264 memcpy(&expected_data[kBlockSize], &big[0], kBlockSize);
265 memcpy(&expected_data[0], &big[3 * kBlockSize], kBlockSize);
266 ExpectVectorsEq(expected_data, resultant_data);
267}
268
269} // namespace chromeos_update_engine