1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/utility/safe_browsing/mac/udif.h"
7 #include <hfs/hfs_format.h>
8 #include <libkern/OSByteOrder.h>
10 #include "base/files/file.h"
11 #include "base/strings/stringprintf.h"
12 #include "chrome/utility/safe_browsing/mac/dmg_test_utils.h"
13 #include "chrome/utility/safe_browsing/mac/read_stream.h"
14 #include "testing/gtest/include/gtest/gtest.h"
16 namespace safe_browsing
{
20 const char* kGPTExpectedPartitions
[] = {
32 const char* kNoPartitionMap
[] = {
37 const char* kAPMExpectedPartitions
[] = {
39 "Apple_partition_map",
46 enum ExpectedResults
: uint16_t {
49 GET_HFS_STREAM
= 1 << 2,
50 READ_UDIF_DATA
= 1 << 3,
52 ALL_PASS
= ~static_cast<uint16_t>(0),
55 // The disk image file to open.
56 const char* file_name
;
58 // The NULL-terminated C array of expected partition types.
59 const char** expected_partitions
;
61 // A bitmask of ExpectedResults. As the parser currently only supports
62 // certain UDIF features, this is used to properly test expectations.
65 // Generates a human-friendly name for the parameterized test.
66 static std::string
GetTestName(
67 const testing::TestParamInfo
<UDIFTestCase
>& test
) {
68 std::string file
= test
.param
.file_name
;
69 return file
.substr(0, file
.find('.'));
73 class UDIFParserTest
: public testing::TestWithParam
<UDIFTestCase
> {
75 void RunReadAllTest(size_t buffer_size
) {
76 const UDIFTestCase
& test_case
= GetParam();
77 if (!(test_case
.expected_results
& UDIFTestCase::READ_UDIF_DATA
)) {
82 ASSERT_NO_FATAL_FAILURE(test::GetTestFile(test_case
.file_name
, &file
));
84 safe_browsing::dmg::FileReadStream
file_stream(file
.GetPlatformFile());
85 safe_browsing::dmg::UDIFParser
udif(&file_stream
);
86 ASSERT_TRUE(udif
.Parse());
88 std::vector
<uint8_t> buffer(buffer_size
, 0);
90 for (size_t i
= 0; i
< udif
.GetNumberOfPartitions(); ++i
) {
91 SCOPED_TRACE(base::StringPrintf("partition %zu", i
));
93 size_t total_size
= udif
.GetPartitionSize(i
);
94 size_t total_bytes_read
= 0;
95 scoped_ptr
<ReadStream
> stream
= udif
.GetPartitionReadStream(i
);
99 size_t bytes_read
= 0;
100 success
= stream
->Read(&buffer
[0], buffer
.size(), &bytes_read
);
101 total_bytes_read
+= bytes_read
;
102 EXPECT_TRUE(success
);
103 EXPECT_TRUE(bytes_read
== buffer_size
||
104 total_bytes_read
== total_size
)
105 << "bytes_read = " << bytes_read
;
106 } while (total_bytes_read
< total_size
&& success
);
111 TEST_P(UDIFParserTest
, ParseUDIF
) {
112 const UDIFTestCase
& test_case
= GetParam();
115 ASSERT_NO_FATAL_FAILURE(test::GetTestFile(test_case
.file_name
, &file
));
117 safe_browsing::dmg::FileReadStream
file_stream(file
.GetPlatformFile());
118 safe_browsing::dmg::UDIFParser
udif(&file_stream
);
120 bool expected_parse_success
=
121 UDIFTestCase::UDIF_PARSE
& test_case
.expected_results
;
122 ASSERT_EQ(expected_parse_success
, udif
.Parse());
123 if (!expected_parse_success
)
126 size_t expected_partition_count
= 0;
127 for (; test_case
.expected_partitions
[expected_partition_count
];
128 ++expected_partition_count
) {
131 EXPECT_EQ(expected_partition_count
, udif
.GetNumberOfPartitions());
133 for (size_t i
= 0; i
< udif
.GetNumberOfPartitions(); ++i
) {
134 SCOPED_TRACE(base::StringPrintf("partition %zu", i
));
135 scoped_ptr
<ReadStream
> stream
= udif
.GetPartitionReadStream(i
);
137 // Apple_HFS will match both HFS and HFSX.
138 if (udif
.GetPartitionType(i
).find("Apple_HFS") != std::string::npos
) {
140 (UDIFTestCase::GET_HFS_STREAM
& test_case
.expected_results
) != 0,
141 stream
.get() != nullptr);
145 EXPECT_EQ(1024, stream
->Seek(1024, SEEK_SET
));
147 HFSPlusVolumeHeader header
= {0};
148 bool expect_read_success
=
149 test_case
.expected_results
& UDIFTestCase::READ_UDIF_DATA
;
150 EXPECT_EQ(expect_read_success
, stream
->ReadType(&header
));
151 if (!expect_read_success
)
154 size_t size
= udif
.GetPartitionSize(i
);
155 off_t offset
= stream
->Seek(-1024, SEEK_END
);
156 ASSERT_GE(offset
, 0);
157 EXPECT_EQ(size
- 1024, static_cast<size_t>(offset
));
159 HFSPlusVolumeHeader alternate_header
= {0};
160 EXPECT_TRUE(stream
->ReadType(&alternate_header
));
162 EXPECT_EQ(0, memcmp(&header
, &alternate_header
, sizeof(header
)));
163 EXPECT_EQ(kHFSPlusSigWord
, OSSwapBigToHostInt16(header
.signature
));
166 if (test_case
.expected_results
& UDIFTestCase::READ_UDIF_DATA
) {
167 EXPECT_EQ(0, stream
->Seek(0, SEEK_SET
));
168 size_t partition_size
= udif
.GetPartitionSize(i
);
169 std::vector
<uint8_t> data(partition_size
, 0);
170 EXPECT_TRUE(stream
->ReadExact(&data
[0], partition_size
));
176 // These tests ensure that reading the entire partition stream with different
177 // buffer sizes (and thus unaligned UDIF chunks) all succeed.
179 TEST_P(UDIFParserTest
, ReadAll_8
) {
183 TEST_P(UDIFParserTest
, ReadAll_512
) {
187 TEST_P(UDIFParserTest
, ReadAll_1000
) {
188 RunReadAllTest(1000);
191 TEST_P(UDIFParserTest
, ReadAll_4444
) {
192 RunReadAllTest(4444);
195 TEST_P(UDIFParserTest
, ReadAll_8181
) {
196 RunReadAllTest(8181);
199 TEST_P(UDIFParserTest
, ReadAll_100000
) {
200 RunReadAllTest(100000);
203 const UDIFTestCase cases
[] = {
204 {"dmg_UDBZ_GPTSPUD.dmg", kGPTExpectedPartitions
, UDIFTestCase::ALL_PASS
},
205 {"dmg_UDBZ_NONE.dmg", kNoPartitionMap
, UDIFTestCase::ALL_PASS
},
206 {"dmg_UDBZ_SPUD.dmg", kAPMExpectedPartitions
, UDIFTestCase::ALL_PASS
},
207 {"dmg_UDCO_GPTSPUD.dmg", kGPTExpectedPartitions
,
208 // ADC compression not supported.
209 UDIFTestCase::UDIF_PARSE
| UDIFTestCase::GET_HFS_STREAM
},
210 {"dmg_UDCO_NONE.dmg", kNoPartitionMap
,
211 // ADC compression not supported.
212 UDIFTestCase::UDIF_PARSE
| UDIFTestCase::GET_HFS_STREAM
},
213 {"dmg_UDCO_SPUD.dmg", kAPMExpectedPartitions
,
214 // ADC compression not supported.
215 UDIFTestCase::UDIF_PARSE
| UDIFTestCase::GET_HFS_STREAM
},
216 {"dmg_UDRO_GPTSPUD.dmg", kGPTExpectedPartitions
, UDIFTestCase::ALL_PASS
},
217 {"dmg_UDRO_NONE.dmg", kNoPartitionMap
, UDIFTestCase::ALL_PASS
},
218 {"dmg_UDRO_SPUD.dmg", kAPMExpectedPartitions
, UDIFTestCase::ALL_PASS
},
219 {"dmg_UDRW_GPTSPUD.dmg", kGPTExpectedPartitions
,
220 // UDRW not supported.
221 UDIFTestCase::ALL_FAIL
},
222 {"dmg_UDRW_NONE.dmg", kNoPartitionMap
,
223 // UDRW not supported.
224 UDIFTestCase::ALL_FAIL
},
225 {"dmg_UDRW_SPUD.dmg", kAPMExpectedPartitions
,
226 // UDRW not supported.
227 UDIFTestCase::ALL_FAIL
},
228 {"dmg_UDSP_GPTSPUD.sparseimage", kGPTExpectedPartitions
,
229 // Sparse images not supported.
230 UDIFTestCase::ALL_FAIL
},
231 {"dmg_UDSP_NONE.sparseimage", kNoPartitionMap
,
232 // UDRW not supported.
233 UDIFTestCase::ALL_FAIL
},
234 {"dmg_UDSP_SPUD.sparseimage", kAPMExpectedPartitions
,
235 // Sparse images not supported.
236 UDIFTestCase::ALL_FAIL
},
237 {"dmg_UDTO_GPTSPUD.cdr", kGPTExpectedPartitions
,
238 // CD/DVD format not supported.
239 UDIFTestCase::ALL_FAIL
},
240 {"dmg_UDTO_NONE.cdr", kNoPartitionMap
,
241 // CD/DVD format not supported.
242 UDIFTestCase::ALL_FAIL
},
243 {"dmg_UDTO_SPUD.cdr", kAPMExpectedPartitions
,
244 // CD/DVD format not supported.
245 UDIFTestCase::ALL_FAIL
},
246 {"dmg_UDZO_GPTSPUD.dmg", kGPTExpectedPartitions
, UDIFTestCase::ALL_PASS
},
247 {"dmg_UDZO_SPUD.dmg", kAPMExpectedPartitions
, UDIFTestCase::ALL_PASS
},
248 {"dmg_UFBI_GPTSPUD.dmg", kGPTExpectedPartitions
, UDIFTestCase::ALL_PASS
},
249 {"dmg_UFBI_SPUD.dmg", kAPMExpectedPartitions
, UDIFTestCase::ALL_PASS
},
252 INSTANTIATE_TEST_CASE_P(UDIFParserTest
, UDIFParserTest
,
253 testing::ValuesIn(cases
),
254 UDIFTestCase::GetTestName
);
258 } // namespace safe_browsing