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/hfs.h"
7 #include "base/files/file.h"
8 #include "base/logging.h"
9 #include "base/strings/string_piece.h"
10 #include "base/strings/string_util.h"
11 #include "base/strings/utf_string_conversions.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 class HFSIteratorTest
: public testing::Test
{
22 void GetTargetFiles(bool case_sensitive
,
23 std::set
<base::string16
>* files
,
24 std::set
<base::string16
>* dirs
) {
25 const char* kBaseFiles
[] = {
26 "first/second/third/fourth/fifth/random",
27 "first/second/third/fourth/Hello World",
28 "first/second/third/symlink-random",
29 "first/second/goat-output.txt",
32 ".metadata_never_index",
35 const char* kBaseDirs
[] = {
36 "first/second/third/fourth/fifth",
37 "first/second/third/fourth",
44 const base::string16 dmg_name
= base::ASCIIToUTF16("SafeBrowsingDMG/");
46 for (size_t i
= 0; i
< arraysize(kBaseFiles
); ++i
)
47 files
->insert(dmg_name
+ base::ASCIIToUTF16(kBaseFiles
[i
]));
49 files
->insert(dmg_name
+ base::ASCIIToUTF16("first/second/") +
50 base::UTF8ToUTF16("Te\xCC\x86st\xCC\x88 \xF0\x9F\x90\x90 "));
52 dirs
->insert(dmg_name
.substr(0, dmg_name
.size() - 1));
53 for (size_t i
= 0; i
< arraysize(kBaseDirs
); ++i
)
54 dirs
->insert(dmg_name
+ base::ASCIIToUTF16(kBaseDirs
[i
]));
57 files
->insert(base::ASCIIToUTF16(
58 "SafeBrowsingDMG/first/second/third/fourth/hEllo wOrld"));
62 void TestTargetFiles(safe_browsing::dmg::HFSIterator
* hfs_reader
,
63 bool case_sensitive
) {
64 std::set
<base::string16
> files
, dirs
;
65 GetTargetFiles(case_sensitive
, &files
, &dirs
);
67 ASSERT_TRUE(hfs_reader
->Open());
68 while (hfs_reader
->Next()) {
69 base::string16 path
= hfs_reader
->GetPath();
70 // Skip over .fseventsd files.
71 if (path
.find(base::ASCIIToUTF16("SafeBrowsingDMG/.fseventsd")) !=
72 base::string16::npos
) {
75 if (hfs_reader
->IsDirectory())
76 EXPECT_TRUE(dirs
.erase(path
)) << path
;
78 EXPECT_TRUE(files
.erase(path
)) << path
;
81 EXPECT_EQ(0u, files
.size());
82 for (const auto& file
: files
) {
83 ADD_FAILURE() << "Unexpected missing file " << file
;
88 TEST_F(HFSIteratorTest
, HFSPlus
) {
90 ASSERT_NO_FATAL_FAILURE(test::GetTestFile("hfs_plus.img", &file
));
92 FileReadStream
stream(file
.GetPlatformFile());
93 HFSIterator
hfs_reader(&stream
);
94 TestTargetFiles(&hfs_reader
, false);
97 TEST_F(HFSIteratorTest
, HFSXCaseSensitive
) {
99 ASSERT_NO_FATAL_FAILURE(test::GetTestFile("hfsx_case_sensitive.img", &file
));
101 FileReadStream
stream(file
.GetPlatformFile());
102 HFSIterator
hfs_reader(&stream
);
103 TestTargetFiles(&hfs_reader
, true);
106 class HFSFileReadTest
: public testing::TestWithParam
<const char*> {
108 void SetUp() override
{
109 ASSERT_NO_FATAL_FAILURE(test::GetTestFile(GetParam(), &hfs_file_
));
111 hfs_stream_
.reset(new FileReadStream(hfs_file_
.GetPlatformFile()));
112 hfs_reader_
.reset(new HFSIterator(hfs_stream_
.get()));
113 ASSERT_TRUE(hfs_reader_
->Open());
116 bool GoToFile(const char* name
) {
117 while (hfs_reader_
->Next()) {
118 if (EndsWith(hfs_reader_
->GetPath(), base::ASCIIToUTF16(name
),
119 base::CompareCase::SENSITIVE
)) {
126 HFSIterator
* hfs_reader() { return hfs_reader_
.get(); }
129 base::File hfs_file_
;
130 scoped_ptr
<FileReadStream
> hfs_stream_
;
131 scoped_ptr
<HFSIterator
> hfs_reader_
;
134 TEST_P(HFSFileReadTest
, ReadReadme
) {
135 ASSERT_TRUE(GoToFile("README.txt"));
137 scoped_ptr
<ReadStream
> stream
= hfs_reader()->GetReadStream();
138 ASSERT_TRUE(stream
.get());
140 EXPECT_FALSE(hfs_reader()->IsSymbolicLink());
141 EXPECT_FALSE(hfs_reader()->IsHardLink());
142 EXPECT_FALSE(hfs_reader()->IsDecmpfsCompressed());
144 std::vector
<uint8_t> buffer(4, 0);
146 // Read the first four bytes.
147 EXPECT_TRUE(stream
->ReadExact(&buffer
[0], buffer
.size()));
148 const uint8_t expected
[] = { 'T', 'h', 'i', 's' };
149 EXPECT_EQ(0, memcmp(expected
, &buffer
[0], sizeof(expected
)));
152 // Rewind back to the start.
153 EXPECT_EQ(0, stream
->Seek(0, SEEK_SET
));
155 // Read the entire file now.
156 EXPECT_TRUE(test::ReadEntireStream(stream
.get(), &buffer
));
157 EXPECT_EQ("This is a test HFS+ filesystem generated by "
158 "chrome/test/data/safe_browsing/dmg/make_hfs.sh.\n",
159 base::StringPiece(reinterpret_cast<const char*>(&buffer
[0]),
161 EXPECT_EQ(92u, buffer
.size());
164 TEST_P(HFSFileReadTest
, ReadRandom
) {
165 ASSERT_TRUE(GoToFile("fifth/random"));
167 scoped_ptr
<ReadStream
> stream
= hfs_reader()->GetReadStream();
168 ASSERT_TRUE(stream
.get());
170 EXPECT_FALSE(hfs_reader()->IsSymbolicLink());
171 EXPECT_FALSE(hfs_reader()->IsHardLink());
172 EXPECT_FALSE(hfs_reader()->IsDecmpfsCompressed());
174 std::vector
<uint8_t> buffer
;
175 EXPECT_TRUE(test::ReadEntireStream(stream
.get(), &buffer
));
176 EXPECT_EQ(768u, buffer
.size());
179 TEST_P(HFSFileReadTest
, Symlink
) {
180 ASSERT_TRUE(GoToFile("symlink-random"));
182 scoped_ptr
<ReadStream
> stream
= hfs_reader()->GetReadStream();
183 ASSERT_TRUE(stream
.get());
185 EXPECT_TRUE(hfs_reader()->IsSymbolicLink());
186 EXPECT_FALSE(hfs_reader()->IsHardLink());
187 EXPECT_FALSE(hfs_reader()->IsDecmpfsCompressed());
189 std::vector
<uint8_t> buffer
;
190 EXPECT_TRUE(test::ReadEntireStream(stream
.get(), &buffer
));
192 EXPECT_EQ("fourth/fifth/random",
193 base::StringPiece(reinterpret_cast<const char*>(&buffer
[0]),
197 TEST_P(HFSFileReadTest
, HardLink
) {
198 ASSERT_TRUE(GoToFile("unicode_name"));
200 EXPECT_FALSE(hfs_reader()->IsSymbolicLink());
201 EXPECT_TRUE(hfs_reader()->IsHardLink());
202 EXPECT_FALSE(hfs_reader()->IsDecmpfsCompressed());
205 TEST_P(HFSFileReadTest
, DecmpfsFile
) {
206 ASSERT_TRUE(GoToFile("first/second/goat-output.txt"));
208 scoped_ptr
<ReadStream
> stream
= hfs_reader()->GetReadStream();
209 ASSERT_TRUE(stream
.get());
211 EXPECT_FALSE(hfs_reader()->IsSymbolicLink());
212 EXPECT_FALSE(hfs_reader()->IsHardLink());
213 EXPECT_TRUE(hfs_reader()->IsDecmpfsCompressed());
215 std::vector
<uint8_t> buffer
;
216 EXPECT_TRUE(test::ReadEntireStream(stream
.get(), &buffer
));
217 EXPECT_EQ(0u, buffer
.size());
220 INSTANTIATE_TEST_CASE_P(HFSIteratorTest
,
224 "hfsx_case_sensitive.img"));
228 } // namespace safe_browsing