1 // Copyright 2019 The Chromium OS 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.
4
5 #include "brillo/files/file_util_test.h"
6
7 #include <base/files/file_util.h>
8 #include <base/rand_util.h>
9 #include <base/stl_util.h>
10 #include <base/strings/string_number_conversions.h>
11 #include <brillo/files/file_util.h>
12 #include <brillo/files/safe_fd.h>
13
14 namespace brillo {
15
16 #define TO_STRING_HELPER(x) \
17 case brillo::SafeFD::Error::x: \
18 return #x;
to_string(brillo::SafeFD::Error err)19 std::string to_string(brillo::SafeFD::Error err) {
20 switch (err) {
21 TO_STRING_HELPER(kNoError)
22 TO_STRING_HELPER(kBadArgument)
23 TO_STRING_HELPER(kNotInitialized)
24 TO_STRING_HELPER(kIOError)
25 TO_STRING_HELPER(kDoesNotExist)
26 TO_STRING_HELPER(kSymlinkDetected)
27 TO_STRING_HELPER(kWrongType)
28 TO_STRING_HELPER(kWrongUID)
29 TO_STRING_HELPER(kWrongGID)
30 TO_STRING_HELPER(kWrongPermissions)
31 TO_STRING_HELPER(kExceededMaximum)
32 default:
33 return std::string("unknown (") + std::to_string(static_cast<int>(err)) +
34 ")";
35 }
36 }
37 #undef TO_STRING_HELPER
38
operator <<(std::ostream & os,const brillo::SafeFD::Error err)39 std::ostream& operator<<(std::ostream& os, const brillo::SafeFD::Error err) {
40 return os << to_string(err); // whatever needed to print bar to os
41 }
42
GetRandomSuffix()43 std::string GetRandomSuffix() {
44 const int kBufferSize = 6;
45 unsigned char buffer[kBufferSize];
46 base::RandBytes(buffer, base::size(buffer));
47 return base::HexEncode(buffer, base::size(buffer));
48 }
49
SetUpTestCase()50 void FileTest::SetUpTestCase() {
51 umask(0);
52 }
53
FileTest()54 FileTest::FileTest() {
55 CHECK(temp_dir_.CreateUniqueTempDir()) << strerror(errno);
56 sub_dir_path_ = temp_dir_.GetPath().Append(kSubdirName);
57 file_path_ = sub_dir_path_.Append(kFileName);
58
59 std::string path = temp_dir_.GetPath().value();
60 temp_dir_path_.reserve(path.size() + 1);
61 temp_dir_path_.assign(temp_dir_.GetPath().value().begin(),
62 temp_dir_.GetPath().value().end());
63 temp_dir_path_.push_back('\0');
64
65 CHECK_EQ(chmod(temp_dir_path_.data(), SafeFD::kDefaultDirPermissions), 0);
66 SafeFD::SetRootPathForTesting(temp_dir_path_.data());
67 root_ = SafeFD::Root().first;
68 CHECK(root_.is_valid());
69 }
70
SetupSubdir()71 bool FileTest::SetupSubdir() {
72 if (!base::CreateDirectory(sub_dir_path_)) {
73 PLOG(ERROR) << "Failed to create '" << sub_dir_path_.value() << "'";
74 return false;
75 }
76 if (chmod(sub_dir_path_.value().c_str(), SafeFD::kDefaultDirPermissions) !=
77 0) {
78 PLOG(ERROR) << "Failed to set permissions of '" << sub_dir_path_.value()
79 << "'";
80 return false;
81 }
82 return true;
83 }
84
SetupSymlinks()85 bool FileTest::SetupSymlinks() {
86 symlink_file_path_ = temp_dir_.GetPath().Append(kSymbolicFileName);
87 symlink_dir_path_ = temp_dir_.GetPath().Append(kSymbolicDirName);
88 if (!base::CreateSymbolicLink(file_path_, symlink_file_path_)) {
89 PLOG(ERROR) << "Failed to create symlink to '" << symlink_file_path_.value()
90 << "'";
91 return false;
92 }
93 if (!base::CreateSymbolicLink(temp_dir_.GetPath(), symlink_dir_path_)) {
94 PLOG(ERROR) << "Failed to create symlink to'" << symlink_dir_path_.value()
95 << "'";
96 return false;
97 }
98 return true;
99 }
100
WriteFile(const std::string & contents)101 bool FileTest::WriteFile(const std::string& contents) {
102 if (!SetupSubdir()) {
103 return false;
104 }
105 if (contents.length() !=
106 base::WriteFile(file_path_, contents.c_str(), contents.length())) {
107 PLOG(ERROR) << "base::WriteFile failed";
108 return false;
109 }
110 if (chmod(file_path_.value().c_str(), SafeFD::kDefaultFilePermissions) != 0) {
111 PLOG(ERROR) << "chmod failed";
112 return false;
113 }
114 return true;
115 }
116
ExpectFileContains(const std::string & contents)117 void FileTest::ExpectFileContains(const std::string& contents) {
118 EXPECT_TRUE(base::PathExists(file_path_));
119 std::string new_contents;
120 EXPECT_TRUE(base::ReadFileToString(file_path_, &new_contents));
121 EXPECT_EQ(contents, new_contents);
122 }
123
ExpectPermissions(base::FilePath path,int permissions)124 void FileTest::ExpectPermissions(base::FilePath path, int permissions) {
125 int actual_permissions = 0;
126 // This breaks out of the ExpectPermissions() call but not the test case.
127 ASSERT_TRUE(base::GetPosixFilePermissions(path, &actual_permissions));
128 EXPECT_EQ(permissions, actual_permissions);
129 }
130
131 // Creates a file with a random name in the temporary directory.
GetTempName()132 base::FilePath FileTest::GetTempName() {
133 return temp_dir_.GetPath().Append(GetRandomSuffix());
134 }
135
136 constexpr char FileTest::kFileName[];
137 constexpr char FileTest::kSubdirName[];
138 constexpr char FileTest::kSymbolicFileName[];
139 constexpr char FileTest::kSymbolicDirName[];
140
141 class FileUtilTest : public FileTest {};
142
TEST_F(FileUtilTest,GetFDPath_SimpleSuccess)143 TEST_F(FileUtilTest, GetFDPath_SimpleSuccess) {
144 EXPECT_EQ(GetFDPath(root_.get()), temp_dir_.GetPath());
145 }
146
TEST_F(FileUtilTest,GetFDPath_BadFD)147 TEST_F(FileUtilTest, GetFDPath_BadFD) {
148 base::FilePath path = GetFDPath(-1);
149 EXPECT_TRUE(path.empty());
150 }
151
TEST_F(FileUtilTest,OpenOrRemakeDir_SimpleSuccess)152 TEST_F(FileUtilTest, OpenOrRemakeDir_SimpleSuccess) {
153 SafeFD::Error err;
154 SafeFD dir;
155
156 std::tie(dir, err) = root_.OpenExistingDir(temp_dir_.GetPath());
157 EXPECT_EQ(err, SafeFD::Error::kNoError);
158 ASSERT_TRUE(dir.is_valid());
159
160 SafeFD subdir;
161 std::tie(subdir, err) = OpenOrRemakeDir(&dir, kSubdirName);
162 EXPECT_EQ(err, SafeFD::Error::kNoError);
163 EXPECT_TRUE(subdir.is_valid());
164 }
165
TEST_F(FileUtilTest,OpenOrRemakeDir_SuccessAfterRetry)166 TEST_F(FileUtilTest, OpenOrRemakeDir_SuccessAfterRetry) {
167 ASSERT_NE(base::WriteFile(sub_dir_path_, "", 0), -1);
168 SafeFD::Error err;
169 SafeFD dir;
170
171 std::tie(dir, err) = root_.OpenExistingDir(temp_dir_.GetPath());
172 EXPECT_EQ(err, SafeFD::Error::kNoError);
173 ASSERT_TRUE(dir.is_valid());
174
175 SafeFD subdir;
176 std::tie(subdir, err) = OpenOrRemakeDir(&dir, kSubdirName);
177 EXPECT_EQ(err, SafeFD::Error::kNoError);
178 EXPECT_TRUE(subdir.is_valid());
179 }
180
TEST_F(FileUtilTest,OpenOrRemakeDir_BadArgument)181 TEST_F(FileUtilTest, OpenOrRemakeDir_BadArgument) {
182 SafeFD::Error err;
183 SafeFD dir;
184
185 std::tie(dir, err) = root_.OpenExistingDir(temp_dir_.GetPath());
186 EXPECT_EQ(err, SafeFD::Error::kNoError);
187 ASSERT_TRUE(dir.is_valid());
188
189 SafeFD subdir;
190 std::tie(subdir, err) = OpenOrRemakeDir(&dir, ".");
191 EXPECT_EQ(err, SafeFD::Error::kBadArgument);
192 EXPECT_FALSE(subdir.is_valid());
193 std::tie(subdir, err) = OpenOrRemakeDir(&dir, "..");
194 EXPECT_EQ(err, SafeFD::Error::kBadArgument);
195 EXPECT_FALSE(subdir.is_valid());
196 std::tie(subdir, err) = OpenOrRemakeDir(&dir, "a/a");
197 EXPECT_EQ(err, SafeFD::Error::kBadArgument);
198 EXPECT_FALSE(subdir.is_valid());
199 }
200
TEST_F(FileUtilTest,OpenOrRemakeDir_NotInitialized)201 TEST_F(FileUtilTest, OpenOrRemakeDir_NotInitialized) {
202 SafeFD::Error err;
203 SafeFD dir;
204
205 SafeFD subdir;
206 std::tie(subdir, err) = OpenOrRemakeDir(&dir, kSubdirName);
207 EXPECT_EQ(err, SafeFD::Error::kNotInitialized);
208 EXPECT_FALSE(subdir.is_valid());
209 }
210
TEST_F(FileUtilTest,OpenOrRemakeDir_IOError)211 TEST_F(FileUtilTest, OpenOrRemakeDir_IOError) {
212 SafeFD::Error err;
213 SafeFD dir;
214
215 std::tie(dir, err) = root_.OpenExistingDir(temp_dir_.GetPath());
216 EXPECT_EQ(err, SafeFD::Error::kNoError);
217 ASSERT_TRUE(dir.is_valid());
218 ASSERT_EQ(chmod(temp_dir_path_.data(), 0000), 0);
219
220 SafeFD subdir;
221 std::tie(subdir, err) = OpenOrRemakeDir(&dir, kSubdirName);
222 EXPECT_EQ(err, SafeFD::Error::kIOError);
223 EXPECT_FALSE(subdir.is_valid());
224 }
225
TEST_F(FileUtilTest,OpenOrRemakeFile_SimpleSuccess)226 TEST_F(FileUtilTest, OpenOrRemakeFile_SimpleSuccess) {
227 ASSERT_TRUE(SetupSubdir());
228 SafeFD::Error err;
229 SafeFD dir;
230
231 std::tie(dir, err) = root_.OpenExistingDir(sub_dir_path_);
232 EXPECT_EQ(err, SafeFD::Error::kNoError);
233 ASSERT_TRUE(dir.is_valid());
234
235 SafeFD file;
236 std::tie(file, err) = OpenOrRemakeFile(&dir, kFileName);
237 EXPECT_EQ(err, SafeFD::Error::kNoError);
238 EXPECT_TRUE(file.is_valid());
239 }
240
TEST_F(FileUtilTest,OpenOrRemakeFile_SuccessAfterRetry)241 TEST_F(FileUtilTest, OpenOrRemakeFile_SuccessAfterRetry) {
242 ASSERT_TRUE(SetupSubdir());
243 ASSERT_TRUE(base::CreateDirectory(file_path_));
244 SafeFD::Error err;
245 SafeFD dir;
246
247 std::tie(dir, err) = root_.OpenExistingDir(sub_dir_path_);
248 EXPECT_EQ(err, SafeFD::Error::kNoError);
249 ASSERT_TRUE(dir.is_valid());
250
251 SafeFD file;
252 std::tie(file, err) = OpenOrRemakeFile(&dir, kFileName);
253 EXPECT_EQ(err, SafeFD::Error::kNoError);
254 EXPECT_TRUE(file.is_valid());
255 }
256
TEST_F(FileUtilTest,OpenOrRemakeFile_NotInitialized)257 TEST_F(FileUtilTest, OpenOrRemakeFile_NotInitialized) {
258 ASSERT_TRUE(SetupSubdir());
259 SafeFD::Error err;
260 SafeFD dir;
261
262 SafeFD file;
263 std::tie(file, err) = OpenOrRemakeFile(&dir, kFileName);
264 EXPECT_EQ(err, SafeFD::Error::kNotInitialized);
265 EXPECT_FALSE(file.is_valid());
266 }
267
TEST_F(FileUtilTest,OpenOrRemakeFile_IOError)268 TEST_F(FileUtilTest, OpenOrRemakeFile_IOError) {
269 ASSERT_TRUE(SetupSubdir());
270 SafeFD::Error err;
271 SafeFD dir;
272
273 std::tie(dir, err) = root_.OpenExistingDir(sub_dir_path_);
274 EXPECT_EQ(err, SafeFD::Error::kNoError);
275 ASSERT_TRUE(dir.is_valid());
276 ASSERT_EQ(chmod(sub_dir_path_.value().c_str(), 0000), 0);
277
278 SafeFD file;
279 std::tie(file, err) = OpenOrRemakeFile(&dir, kFileName);
280 EXPECT_EQ(err, SafeFD::Error::kIOError);
281 EXPECT_FALSE(file.is_valid());
282 }
283
284 } // namespace brillo
285