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/safe_fd.h"
6
7 #include <fcntl.h>
8 #include <sys/stat.h>
9
10 #include <base/files/file_util.h>
11 #include <brillo/files/file_util_test.h>
12 #include <brillo/syslog_logging.h>
13 #include <gtest/gtest.h>
14
15 namespace brillo {
16
17 class SafeFDTest : public FileTest {};
18
TEST_F(SafeFDTest,SafeFD)19 TEST_F(SafeFDTest, SafeFD) {
20 EXPECT_FALSE(SafeFD().is_valid());
21 }
22
TEST_F(SafeFDTest,SafeFD_Move)23 TEST_F(SafeFDTest, SafeFD_Move) {
24 SafeFD moved_root = std::move(root_);
25 EXPECT_FALSE(root_.is_valid());
26 ASSERT_TRUE(moved_root.is_valid());
27
28 SafeFD moved_root2(std::move(moved_root));
29 EXPECT_FALSE(moved_root.is_valid());
30 ASSERT_TRUE(moved_root2.is_valid());
31 }
32
TEST_F(SafeFDTest,Root)33 TEST_F(SafeFDTest, Root) {
34 SafeFD::SafeFDResult result = SafeFD::Root();
35 EXPECT_TRUE(result.first.is_valid());
36 EXPECT_EQ(result.second, SafeFD::Error::kNoError);
37 }
38
TEST_F(SafeFDTest,reset)39 TEST_F(SafeFDTest, reset) {
40 root_.reset();
41 EXPECT_FALSE(root_.is_valid());
42 }
43
TEST_F(SafeFDTest,UnsafeReset)44 TEST_F(SafeFDTest, UnsafeReset) {
45 int fd =
46 HANDLE_EINTR(open(temp_dir_path_.data(),
47 O_NONBLOCK | O_DIRECTORY | O_RDONLY | O_CLOEXEC, 0777));
48 ASSERT_GE(fd, 0);
49
50 {
51 SafeFD safe_fd;
52 safe_fd.UnsafeReset(fd);
53 EXPECT_EQ(safe_fd.get(), fd);
54 }
55
56 // Verify the file descriptor is closed.
57 int result = fcntl(fd, F_GETFD);
58 int error = errno;
59 EXPECT_EQ(result, -1);
60 EXPECT_EQ(error, EBADF);
61 }
62
TEST_F(SafeFDTest,Write_Success)63 TEST_F(SafeFDTest, Write_Success) {
64 std::string random_data = GetRandomSuffix();
65 {
66 SafeFD::SafeFDResult file = root_.MakeFile(file_path_);
67 EXPECT_EQ(file.second, SafeFD::Error::kNoError);
68 ASSERT_TRUE(file.first.is_valid());
69
70 EXPECT_EQ(file.first.Write(random_data.data(), random_data.size()),
71 SafeFD::Error::kNoError);
72 }
73
74 ExpectFileContains(random_data);
75 ExpectPermissions(file_path_, SafeFD::kDefaultFilePermissions);
76 }
77
TEST_F(SafeFDTest,Write_NotInitialized)78 TEST_F(SafeFDTest, Write_NotInitialized) {
79 SafeFD invalid;
80 ASSERT_FALSE(invalid.is_valid());
81
82 std::string random_data = GetRandomSuffix();
83 EXPECT_EQ(invalid.Write(random_data.data(), random_data.size()),
84 SafeFD::Error::kNotInitialized);
85 }
86
TEST_F(SafeFDTest,Write_VerifyTruncate)87 TEST_F(SafeFDTest, Write_VerifyTruncate) {
88 std::string random_data = GetRandomSuffix();
89 ASSERT_TRUE(WriteFile(random_data));
90
91 {
92 SafeFD::SafeFDResult file = root_.OpenExistingFile(file_path_);
93 EXPECT_EQ(file.second, SafeFD::Error::kNoError);
94 ASSERT_TRUE(file.first.is_valid());
95
96 EXPECT_EQ(file.first.Write("", 0), SafeFD::Error::kNoError);
97 }
98
99 ExpectFileContains("");
100 }
101
TEST_F(SafeFDTest,Write_Failure)102 TEST_F(SafeFDTest, Write_Failure) {
103 std::string random_data = GetRandomSuffix();
104 EXPECT_EQ(root_.Write("", 1), SafeFD::Error::kIOError);
105 }
106
TEST_F(SafeFDTest,ReadContents_Success)107 TEST_F(SafeFDTest, ReadContents_Success) {
108 std::string random_data = GetRandomSuffix();
109 ASSERT_TRUE(WriteFile(random_data));
110
111 SafeFD::SafeFDResult file = root_.OpenExistingFile(file_path_);
112 EXPECT_EQ(file.second, SafeFD::Error::kNoError);
113 ASSERT_TRUE(file.first.is_valid());
114
115 auto result = file.first.ReadContents();
116 EXPECT_EQ(result.second, SafeFD::Error::kNoError);
117 ASSERT_EQ(random_data.size(), result.first.size());
118 EXPECT_EQ(memcmp(random_data.data(), result.first.data(), random_data.size()),
119 0);
120 }
121
TEST_F(SafeFDTest,ReadContents_ExceededMaximum)122 TEST_F(SafeFDTest, ReadContents_ExceededMaximum) {
123 std::string random_data = GetRandomSuffix();
124 ASSERT_TRUE(WriteFile(random_data));
125
126 SafeFD::SafeFDResult file = root_.OpenExistingFile(file_path_);
127 EXPECT_EQ(file.second, SafeFD::Error::kNoError);
128 ASSERT_TRUE(file.first.is_valid());
129
130 ASSERT_LT(1, random_data.size());
131 auto result = file.first.ReadContents(1);
132 EXPECT_EQ(result.second, SafeFD::Error::kExceededMaximum);
133 }
134
TEST_F(SafeFDTest,ReadContents_NotInitialized)135 TEST_F(SafeFDTest, ReadContents_NotInitialized) {
136 SafeFD invalid;
137 ASSERT_FALSE(invalid.is_valid());
138
139 auto result = invalid.ReadContents();
140 EXPECT_EQ(result.second, SafeFD::Error::kNotInitialized);
141 }
142
TEST_F(SafeFDTest,Read_Success)143 TEST_F(SafeFDTest, Read_Success) {
144 std::string random_data = GetRandomSuffix();
145 ASSERT_TRUE(WriteFile(random_data));
146
147 SafeFD::SafeFDResult file = root_.OpenExistingFile(file_path_);
148 EXPECT_EQ(file.second, SafeFD::Error::kNoError);
149 ASSERT_TRUE(file.first.is_valid());
150
151 std::vector<char> buffer(random_data.size(), '\0');
152 ASSERT_EQ(file.first.Read(buffer.data(), buffer.size()),
153 SafeFD::Error::kNoError);
154 EXPECT_EQ(memcmp(random_data.data(), buffer.data(), random_data.size()), 0);
155 }
156
TEST_F(SafeFDTest,Read_NotInitialized)157 TEST_F(SafeFDTest, Read_NotInitialized) {
158 SafeFD invalid;
159 ASSERT_FALSE(invalid.is_valid());
160
161 char to_read;
162 EXPECT_EQ(invalid.Read(&to_read, 1), SafeFD::Error::kNotInitialized);
163 }
164
TEST_F(SafeFDTest,Read_IOError)165 TEST_F(SafeFDTest, Read_IOError) {
166 std::string random_data = GetRandomSuffix();
167 ASSERT_TRUE(WriteFile(random_data));
168
169 SafeFD::SafeFDResult file = root_.OpenExistingFile(file_path_);
170 EXPECT_EQ(file.second, SafeFD::Error::kNoError);
171 ASSERT_TRUE(file.first.is_valid());
172
173 std::vector<char> buffer(random_data.size() * 2, '\0');
174 ASSERT_EQ(file.first.Read(buffer.data(), buffer.size()),
175 SafeFD::Error::kIOError);
176 }
177
TEST_F(SafeFDTest,OpenExistingFile_Success)178 TEST_F(SafeFDTest, OpenExistingFile_Success) {
179 std::string data = GetRandomSuffix();
180 ASSERT_TRUE(WriteFile(data));
181 {
182 SafeFD::SafeFDResult file = root_.OpenExistingFile(file_path_);
183 EXPECT_EQ(file.second, SafeFD::Error::kNoError);
184 ASSERT_TRUE(file.first.is_valid());
185 }
186 ExpectFileContains(data);
187 }
188
TEST_F(SafeFDTest,OpenExistingFile_NotInitialized)189 TEST_F(SafeFDTest, OpenExistingFile_NotInitialized) {
190 SafeFD::SafeFDResult file = SafeFD().OpenExistingFile(file_path_);
191 EXPECT_EQ(file.second, SafeFD::Error::kNotInitialized);
192 ASSERT_FALSE(file.first.is_valid());
193 }
194
TEST_F(SafeFDTest,OpenExistingFile_DoesNotExist)195 TEST_F(SafeFDTest, OpenExistingFile_DoesNotExist) {
196 SafeFD::SafeFDResult file = root_.OpenExistingFile(file_path_);
197 EXPECT_EQ(file.second, SafeFD::Error::kDoesNotExist);
198 ASSERT_FALSE(file.first.is_valid());
199 }
200
TEST_F(SafeFDTest,OpenExistingFile_IOError)201 TEST_F(SafeFDTest, OpenExistingFile_IOError) {
202 ASSERT_TRUE(WriteFile(""));
203 EXPECT_EQ(chmod(file_path_.value().c_str(), 0000), 0) << strerror(errno);
204
205 SafeFD::SafeFDResult file = root_.OpenExistingFile(file_path_);
206 EXPECT_EQ(file.second, SafeFD::Error::kIOError);
207 ASSERT_FALSE(file.first.is_valid());
208 }
209
TEST_F(SafeFDTest,OpenExistingFile_SymlinkDetected)210 TEST_F(SafeFDTest, OpenExistingFile_SymlinkDetected) {
211 ASSERT_TRUE(SetupSymlinks());
212 ASSERT_TRUE(WriteFile(""));
213 SafeFD::SafeFDResult file = root_.OpenExistingFile(symlink_file_path_);
214 EXPECT_EQ(file.second, SafeFD::Error::kSymlinkDetected);
215 ASSERT_FALSE(file.first.is_valid());
216 }
217
TEST_F(SafeFDTest,OpenExistingFile_WrongType)218 TEST_F(SafeFDTest, OpenExistingFile_WrongType) {
219 ASSERT_TRUE(SetupSymlinks());
220 ASSERT_TRUE(WriteFile(""));
221 SafeFD::SafeFDResult file =
222 root_.OpenExistingFile(symlink_dir_path_.Append(kFileName));
223 EXPECT_EQ(file.second, SafeFD::Error::kWrongType);
224 ASSERT_FALSE(file.first.is_valid());
225 }
226
TEST_F(SafeFDTest,OpenExistingDir_Success)227 TEST_F(SafeFDTest, OpenExistingDir_Success) {
228 SafeFD::SafeFDResult dir = root_.OpenExistingDir(temp_dir_.GetPath());
229 EXPECT_EQ(dir.second, SafeFD::Error::kNoError);
230 ASSERT_TRUE(dir.first.is_valid());
231 }
232
TEST_F(SafeFDTest,OpenExistingDir_NotInitialized)233 TEST_F(SafeFDTest, OpenExistingDir_NotInitialized) {
234 SafeFD::SafeFDResult dir = SafeFD().OpenExistingDir(temp_dir_.GetPath());
235 EXPECT_EQ(dir.second, SafeFD::Error::kNotInitialized);
236 ASSERT_FALSE(dir.first.is_valid());
237 }
238
TEST_F(SafeFDTest,OpenExistingDir_DoesNotExist)239 TEST_F(SafeFDTest, OpenExistingDir_DoesNotExist) {
240 SafeFD::SafeFDResult dir = root_.OpenExistingDir(sub_dir_path_);
241 EXPECT_EQ(dir.second, SafeFD::Error::kDoesNotExist);
242 ASSERT_FALSE(dir.first.is_valid());
243 }
244
TEST_F(SafeFDTest,OpenExistingDir_IOError)245 TEST_F(SafeFDTest, OpenExistingDir_IOError) {
246 ASSERT_TRUE(WriteFile(""));
247 ASSERT_EQ(chmod(sub_dir_path_.value().c_str(), 0000), 0) << strerror(errno);
248
249 SafeFD::SafeFDResult dir = root_.OpenExistingDir(sub_dir_path_);
250 EXPECT_EQ(dir.second, SafeFD::Error::kIOError);
251 ASSERT_FALSE(dir.first.is_valid());
252 }
253
TEST_F(SafeFDTest,OpenExistingDir_WrongType)254 TEST_F(SafeFDTest, OpenExistingDir_WrongType) {
255 ASSERT_TRUE(SetupSymlinks());
256 SafeFD::SafeFDResult dir = root_.OpenExistingDir(symlink_dir_path_);
257 EXPECT_EQ(dir.second, SafeFD::Error::kWrongType);
258 ASSERT_FALSE(dir.first.is_valid());
259 }
260
TEST_F(SafeFDTest,MakeFile_DoesNotExistSuccess)261 TEST_F(SafeFDTest, MakeFile_DoesNotExistSuccess) {
262 {
263 SafeFD::SafeFDResult file = root_.MakeFile(file_path_);
264 EXPECT_EQ(file.second, SafeFD::Error::kNoError);
265 ASSERT_TRUE(file.first.is_valid());
266 }
267
268 ExpectPermissions(file_path_, SafeFD::kDefaultFilePermissions);
269 }
270
TEST_F(SafeFDTest,MakeFile_LeadingSelfDirSuccess)271 TEST_F(SafeFDTest, MakeFile_LeadingSelfDirSuccess) {
272 ASSERT_TRUE(SetupSubdir());
273
274 SafeFD::Error err;
275 SafeFD dir;
276 std::tie(dir, err) = root_.OpenExistingDir(sub_dir_path_);
277 ASSERT_EQ(err, SafeFD::Error::kNoError);
278
279 {
280 SafeFD file;
281 std::tie(file, err) = dir.MakeFile(file_path_.BaseName());
282 EXPECT_EQ(err, SafeFD::Error::kNoError);
283 ASSERT_TRUE(file.is_valid());
284 }
285
286 ExpectPermissions(file_path_, SafeFD::kDefaultFilePermissions);
287 }
288
TEST_F(SafeFDTest,MakeFile_ExistsSuccess)289 TEST_F(SafeFDTest, MakeFile_ExistsSuccess) {
290 std::string data = GetRandomSuffix();
291 ASSERT_TRUE(WriteFile(data));
292 {
293 SafeFD::SafeFDResult file = root_.MakeFile(file_path_);
294 EXPECT_EQ(file.second, SafeFD::Error::kNoError);
295 ASSERT_TRUE(file.first.is_valid());
296 }
297 ExpectPermissions(file_path_, SafeFD::kDefaultFilePermissions);
298 ExpectFileContains(data);
299 }
300
TEST_F(SafeFDTest,MakeFile_IOError)301 TEST_F(SafeFDTest, MakeFile_IOError) {
302 ASSERT_TRUE(SetupSubdir());
303 ASSERT_EQ(mkfifo(file_path_.value().c_str(), 0), 0);
304 SafeFD::SafeFDResult file = root_.MakeFile(file_path_);
305 EXPECT_EQ(file.second, SafeFD::Error::kIOError);
306 ASSERT_FALSE(file.first.is_valid());
307 }
308
TEST_F(SafeFDTest,MakeFile_SymlinkDetected)309 TEST_F(SafeFDTest, MakeFile_SymlinkDetected) {
310 ASSERT_TRUE(SetupSymlinks());
311 SafeFD::SafeFDResult file = root_.MakeFile(symlink_file_path_);
312 EXPECT_EQ(file.second, SafeFD::Error::kSymlinkDetected);
313 ASSERT_FALSE(file.first.is_valid());
314 }
315
TEST_F(SafeFDTest,MakeFile_WrongType)316 TEST_F(SafeFDTest, MakeFile_WrongType) {
317 ASSERT_TRUE(SetupSubdir());
318 SafeFD::SafeFDResult file = root_.MakeFile(sub_dir_path_);
319 EXPECT_EQ(file.second, SafeFD::Error::kWrongType);
320 ASSERT_FALSE(file.first.is_valid());
321 }
322
TEST_F(SafeFDTest,MakeFile_WrongGID)323 TEST_F(SafeFDTest, MakeFile_WrongGID) {
324 ASSERT_TRUE(WriteFile(""));
325 ASSERT_EQ(chown(file_path_.value().c_str(), getuid(), 0), 0)
326 << strerror(errno);
327 {
328 SafeFD::SafeFDResult file = root_.MakeFile(file_path_);
329 EXPECT_EQ(file.second, SafeFD::Error::kWrongGID);
330 ASSERT_FALSE(file.first.is_valid());
331 }
332 }
333
TEST_F(SafeFDTest,MakeFile_WrongPermissions)334 TEST_F(SafeFDTest, MakeFile_WrongPermissions) {
335 ASSERT_TRUE(WriteFile(""));
336 ASSERT_EQ(chmod(file_path_.value().c_str(), 0777), 0) << strerror(errno);
337 {
338 SafeFD::SafeFDResult file = root_.MakeFile(file_path_);
339 EXPECT_EQ(file.second, SafeFD::Error::kWrongPermissions);
340 ASSERT_FALSE(file.first.is_valid());
341 }
342 ASSERT_EQ(chmod(file_path_.value().c_str(), SafeFD::kDefaultFilePermissions),
343 0)
344 << strerror(errno);
345
346 EXPECT_EQ(chmod(sub_dir_path_.value().c_str(), 0777), 0) << strerror(errno);
347 {
348 SafeFD::SafeFDResult file = root_.MakeFile(file_path_);
349 EXPECT_EQ(file.second, SafeFD::Error::kWrongPermissions);
350 ASSERT_FALSE(file.first.is_valid());
351 }
352 }
353
TEST_F(SafeFDTest,MakeDir_DoesNotExistSuccess)354 TEST_F(SafeFDTest, MakeDir_DoesNotExistSuccess) {
355 {
356 SafeFD::SafeFDResult dir = root_.MakeDir(sub_dir_path_);
357 EXPECT_EQ(dir.second, SafeFD::Error::kNoError);
358 ASSERT_TRUE(dir.first.is_valid());
359 }
360
361 ExpectPermissions(sub_dir_path_, SafeFD::kDefaultDirPermissions);
362 }
363
TEST_F(SafeFDTest,MakeFile_SingleComponentSuccess)364 TEST_F(SafeFDTest, MakeFile_SingleComponentSuccess) {
365 ASSERT_TRUE(SetupSubdir());
366
367 SafeFD::Error err;
368 SafeFD dir;
369 std::tie(dir, err) = root_.OpenExistingDir(temp_dir_.GetPath());
370 ASSERT_EQ(err, SafeFD::Error::kNoError);
371
372 {
373 SafeFD subdir;
374 std::tie(subdir, err) = dir.MakeDir(base::FilePath(kSubdirName));
375 EXPECT_EQ(err, SafeFD::Error::kNoError);
376 ASSERT_TRUE(subdir.is_valid());
377 }
378
379 ExpectPermissions(sub_dir_path_, SafeFD::kDefaultDirPermissions);
380 }
381
TEST_F(SafeFDTest,MakeDir_ExistsSuccess)382 TEST_F(SafeFDTest, MakeDir_ExistsSuccess) {
383 ASSERT_TRUE(SetupSubdir());
384 {
385 SafeFD::SafeFDResult dir = root_.MakeDir(sub_dir_path_);
386 EXPECT_EQ(dir.second, SafeFD::Error::kNoError);
387 ASSERT_TRUE(dir.first.is_valid());
388 }
389
390 ExpectPermissions(sub_dir_path_, SafeFD::kDefaultDirPermissions);
391 }
392
TEST_F(SafeFDTest,MakeDir_WrongType)393 TEST_F(SafeFDTest, MakeDir_WrongType) {
394 ASSERT_TRUE(SetupSymlinks());
395 SafeFD::SafeFDResult dir = root_.MakeDir(symlink_dir_path_);
396 EXPECT_EQ(dir.second, SafeFD::Error::kWrongType);
397 ASSERT_FALSE(dir.first.is_valid());
398 }
399
TEST_F(SafeFDTest,MakeDir_WrongGID)400 TEST_F(SafeFDTest, MakeDir_WrongGID) {
401 ASSERT_TRUE(SetupSubdir());
402 ASSERT_EQ(chown(sub_dir_path_.value().c_str(), getuid(), 0), 0)
403 << strerror(errno);
404 {
405 SafeFD::SafeFDResult dir = root_.MakeDir(sub_dir_path_);
406 EXPECT_EQ(dir.second, SafeFD::Error::kWrongGID);
407 ASSERT_FALSE(dir.first.is_valid());
408 }
409 }
410
TEST_F(SafeFDTest,MakeDir_WrongPermissions)411 TEST_F(SafeFDTest, MakeDir_WrongPermissions) {
412 ASSERT_TRUE(SetupSubdir());
413 ASSERT_EQ(chmod(sub_dir_path_.value().c_str(), 0777), 0) << strerror(errno);
414
415 SafeFD::SafeFDResult dir = root_.MakeDir(sub_dir_path_);
416 EXPECT_EQ(dir.second, SafeFD::Error::kWrongPermissions);
417 ASSERT_FALSE(dir.first.is_valid());
418 }
419
TEST_F(SafeFDTest,Link_Success)420 TEST_F(SafeFDTest, Link_Success) {
421 std::string data = GetRandomSuffix();
422 ASSERT_TRUE(WriteFile(data));
423
424 SafeFD::SafeFDResult dir = root_.OpenExistingDir(temp_dir_.GetPath());
425 ASSERT_EQ(dir.second, SafeFD::Error::kNoError);
426
427 SafeFD::SafeFDResult subdir = root_.OpenExistingDir(sub_dir_path_);
428 ASSERT_EQ(subdir.second, SafeFD::Error::kNoError);
429
430 EXPECT_EQ(dir.first.Link(subdir.first, kFileName, kFileName),
431 SafeFD::Error::kNoError);
432
433 SafeFD::SafeFDResult new_file = dir.first.OpenExistingFile(
434 base::FilePath(kFileName), O_RDONLY | O_CLOEXEC);
435 EXPECT_EQ(new_file.second, SafeFD::Error::kNoError);
436 std::pair<std::vector<char>, SafeFD::Error> contents =
437 new_file.first.ReadContents();
438 EXPECT_EQ(contents.second, SafeFD::Error::kNoError);
439 EXPECT_EQ(data.size(), contents.first.size());
440 EXPECT_EQ(memcmp(data.data(), contents.first.data(), data.size()), 0);
441 }
442
TEST_F(SafeFDTest,Link_NotInitialized)443 TEST_F(SafeFDTest, Link_NotInitialized) {
444 std::string data = GetRandomSuffix();
445 ASSERT_TRUE(WriteFile(data));
446
447 SafeFD::SafeFDResult dir = root_.OpenExistingDir(temp_dir_.GetPath());
448 ASSERT_EQ(dir.second, SafeFD::Error::kNoError);
449
450 SafeFD::SafeFDResult subdir = root_.OpenExistingDir(sub_dir_path_);
451 ASSERT_EQ(subdir.second, SafeFD::Error::kNoError);
452
453 EXPECT_EQ(SafeFD().Link(subdir.first, kFileName, kFileName),
454 SafeFD::Error::kNotInitialized);
455
456 EXPECT_EQ(dir.first.Link(SafeFD(), kFileName, kFileName),
457 SafeFD::Error::kNotInitialized);
458 }
459
TEST_F(SafeFDTest,Link_BadArgument)460 TEST_F(SafeFDTest, Link_BadArgument) {
461 ASSERT_TRUE(WriteFile(""));
462
463 SafeFD::SafeFDResult dir = root_.OpenExistingDir(temp_dir_.GetPath());
464 ASSERT_EQ(dir.second, SafeFD::Error::kNoError);
465
466 SafeFD::SafeFDResult subdir = root_.OpenExistingDir(sub_dir_path_);
467 ASSERT_EQ(subdir.second, SafeFD::Error::kNoError);
468
469 EXPECT_EQ(dir.first.Link(subdir.first, "a/a", kFileName),
470 SafeFD::Error::kBadArgument);
471 EXPECT_EQ(dir.first.Link(subdir.first, ".", kFileName),
472 SafeFD::Error::kBadArgument);
473 EXPECT_EQ(dir.first.Link(subdir.first, "..", kFileName),
474 SafeFD::Error::kBadArgument);
475 EXPECT_EQ(dir.first.Link(subdir.first, kFileName, "a/a"),
476 SafeFD::Error::kBadArgument);
477 EXPECT_EQ(dir.first.Link(subdir.first, kFileName, "."),
478 SafeFD::Error::kBadArgument);
479 EXPECT_EQ(dir.first.Link(subdir.first, kFileName, ".."),
480 SafeFD::Error::kBadArgument);
481 }
482
TEST_F(SafeFDTest,Link_IOError)483 TEST_F(SafeFDTest, Link_IOError) {
484 ASSERT_TRUE(SetupSubdir());
485
486 SafeFD::SafeFDResult dir = root_.OpenExistingDir(temp_dir_.GetPath());
487 ASSERT_EQ(dir.second, SafeFD::Error::kNoError);
488
489 SafeFD::SafeFDResult subdir = root_.OpenExistingDir(sub_dir_path_);
490 ASSERT_EQ(subdir.second, SafeFD::Error::kNoError);
491
492 EXPECT_EQ(dir.first.Link(subdir.first, kFileName, kFileName),
493 SafeFD::Error::kIOError);
494 }
495
TEST_F(SafeFDTest,Unlink_Success)496 TEST_F(SafeFDTest, Unlink_Success) {
497 ASSERT_TRUE(WriteFile(""));
498
499 SafeFD::SafeFDResult subdir = root_.OpenExistingDir(sub_dir_path_);
500 ASSERT_EQ(subdir.second, SafeFD::Error::kNoError);
501
502 EXPECT_EQ(subdir.first.Unlink(kFileName), SafeFD::Error::kNoError);
503 EXPECT_FALSE(base::PathExists(file_path_));
504 }
505
TEST_F(SafeFDTest,Unlink_NotInitialized)506 TEST_F(SafeFDTest, Unlink_NotInitialized) {
507 ASSERT_TRUE(WriteFile(""));
508
509 EXPECT_EQ(SafeFD().Unlink(kFileName), SafeFD::Error::kNotInitialized);
510 }
511
TEST_F(SafeFDTest,Unlink_BadArgument)512 TEST_F(SafeFDTest, Unlink_BadArgument) {
513 ASSERT_TRUE(WriteFile(""));
514
515 SafeFD::SafeFDResult subdir = root_.OpenExistingDir(sub_dir_path_);
516 ASSERT_EQ(subdir.second, SafeFD::Error::kNoError);
517
518 EXPECT_EQ(subdir.first.Unlink("a/a"), SafeFD::Error::kBadArgument);
519 EXPECT_EQ(subdir.first.Unlink("."), SafeFD::Error::kBadArgument);
520 EXPECT_EQ(subdir.first.Unlink(".."), SafeFD::Error::kBadArgument);
521 }
522
TEST_F(SafeFDTest,Unlink_IOError_Nonexistent)523 TEST_F(SafeFDTest, Unlink_IOError_Nonexistent) {
524 ASSERT_TRUE(SetupSubdir());
525
526 SafeFD::SafeFDResult subdir = root_.OpenExistingDir(sub_dir_path_);
527 ASSERT_EQ(subdir.second, SafeFD::Error::kNoError);
528
529 EXPECT_EQ(subdir.first.Unlink(kFileName), SafeFD::Error::kIOError);
530 }
531
TEST_F(SafeFDTest,Unlink_IOError_IsADir)532 TEST_F(SafeFDTest, Unlink_IOError_IsADir) {
533 ASSERT_TRUE(SetupSubdir());
534
535 SafeFD::SafeFDResult dir = root_.OpenExistingDir(temp_dir_.GetPath());
536 ASSERT_EQ(dir.second, SafeFD::Error::kNoError);
537
538 EXPECT_EQ(dir.first.Unlink(kSubdirName), SafeFD::Error::kIOError);
539 }
540
TEST_F(SafeFDTest,Rmdir_Recursive_Success)541 TEST_F(SafeFDTest, Rmdir_Recursive_Success) {
542 ASSERT_TRUE(WriteFile(""));
543
544 SafeFD::SafeFDResult dir = root_.OpenExistingDir(temp_dir_.GetPath());
545 ASSERT_EQ(dir.second, SafeFD::Error::kNoError);
546
547 EXPECT_EQ(dir.first.Rmdir(kSubdirName, true /*recursive*/),
548 SafeFD::Error::kNoError);
549 EXPECT_FALSE(base::PathExists(file_path_));
550 EXPECT_FALSE(base::PathExists(sub_dir_path_));
551 }
552
TEST_F(SafeFDTest,Rmdir_Recursive_SuccessMaxRecursion)553 TEST_F(SafeFDTest, Rmdir_Recursive_SuccessMaxRecursion) {
554 SafeFD::Error err;
555 SafeFD dir;
556
557 // Create directory with the maximum depth.
558 std::tie(dir, err) = root_.OpenExistingDir(temp_dir_.GetPath());
559 EXPECT_EQ(err, SafeFD::Error::kNoError);
560 ASSERT_TRUE(dir.is_valid());
561 for (size_t x = 0; x < SafeFD::kDefaultMaxPathDepth; ++x) {
562 std::tie(dir, err) = dir.MakeDir(base::FilePath(kSubdirName));
563 EXPECT_EQ(err, SafeFD::Error::kNoError);
564 ASSERT_TRUE(dir.is_valid());
565 }
566
567 // Check if recursive Rmdir succeeds (i.e. there isn't a stack overflow).
568 std::tie(dir, err) = root_.OpenExistingDir(temp_dir_.GetPath());
569 EXPECT_EQ(err, SafeFD::Error::kNoError);
570
571 EXPECT_EQ(dir.Rmdir(kSubdirName, true /*recursive*/),
572 SafeFD::Error::kNoError);
573 EXPECT_FALSE(base::PathExists(file_path_));
574 EXPECT_FALSE(base::PathExists(sub_dir_path_));
575 }
576
TEST_F(SafeFDTest,Rmdir_NotInitialized)577 TEST_F(SafeFDTest, Rmdir_NotInitialized) {
578 ASSERT_TRUE(WriteFile(""));
579
580 EXPECT_EQ(SafeFD().Rmdir(kSubdirName, true /*recursive*/),
581 SafeFD::Error::kNotInitialized);
582 }
583
TEST_F(SafeFDTest,Rmdir_BadArgument)584 TEST_F(SafeFDTest, Rmdir_BadArgument) {
585 ASSERT_TRUE(WriteFile(""));
586
587 SafeFD::SafeFDResult dir = root_.OpenExistingDir(temp_dir_.GetPath());
588 EXPECT_EQ(dir.second, SafeFD::Error::kNoError);
589
590 EXPECT_EQ(dir.first.Rmdir("a/a"), SafeFD::Error::kBadArgument);
591 EXPECT_EQ(dir.first.Rmdir("."), SafeFD::Error::kBadArgument);
592 EXPECT_EQ(dir.first.Rmdir(".."), SafeFD::Error::kBadArgument);
593 }
594
TEST_F(SafeFDTest,Rmdir_ExceededMaximum)595 TEST_F(SafeFDTest, Rmdir_ExceededMaximum) {
596 ASSERT_TRUE(SetupSubdir());
597 ASSERT_TRUE(base::CreateDirectory(sub_dir_path_.Append(kSubdirName)));
598
599 SafeFD::SafeFDResult dir = root_.OpenExistingDir(temp_dir_.GetPath());
600 ASSERT_EQ(dir.second, SafeFD::Error::kNoError);
601
602 EXPECT_EQ(dir.first.Rmdir(kSubdirName, true /*recursive*/, 1),
603 SafeFD::Error::kExceededMaximum);
604 }
605
TEST_F(SafeFDTest,Rmdir_IOError)606 TEST_F(SafeFDTest, Rmdir_IOError) {
607 SafeFD::SafeFDResult dir = root_.OpenExistingDir(temp_dir_.GetPath());
608 ASSERT_EQ(dir.second, SafeFD::Error::kNoError);
609
610 // Dir doesn't exist.
611 EXPECT_EQ(dir.first.Rmdir(kSubdirName), SafeFD::Error::kIOError);
612
613 // Dir not empty.
614 ASSERT_TRUE(WriteFile(""));
615 EXPECT_EQ(dir.first.Rmdir(kSubdirName), SafeFD::Error::kIOError);
616 }
617
TEST_F(SafeFDTest,Rmdir_WrongType)618 TEST_F(SafeFDTest, Rmdir_WrongType) {
619 ASSERT_TRUE(WriteFile(""));
620
621 SafeFD::SafeFDResult subdir = root_.OpenExistingDir(sub_dir_path_);
622 ASSERT_EQ(subdir.second, SafeFD::Error::kNoError);
623
624 EXPECT_EQ(subdir.first.Rmdir(kFileName), SafeFD::Error::kWrongType);
625 }
626
TEST_F(SafeFDTest,Rmdir_Recursive_KeepGoing)627 TEST_F(SafeFDTest, Rmdir_Recursive_KeepGoing) {
628 ASSERT_TRUE(SetupSubdir());
629
630 ASSERT_TRUE(base::CreateDirectory(sub_dir_path_.Append(kSubdirName)));
631
632 // Give us something to iterate over.
633 constexpr int kNumSentinel = 25;
634 for (int i = 0; i < kNumSentinel; i++) {
635 SafeFD::SafeFDResult file =
636 root_.MakeFile(sub_dir_path_.Append(GetRandomSuffix()));
637 EXPECT_EQ(file.second, SafeFD::Error::kNoError);
638 ASSERT_TRUE(file.first.is_valid());
639 }
640
641 // Recursively delete with a max level that is too small. Capture errno.
642 SafeFD::Error result = root_.Rmdir(kSubdirName, true /*recursive*/,
643 1 /*max_depth*/, true /*keep_going*/);
644 int rmdir_errno = errno;
645
646 EXPECT_EQ(result, SafeFD::Error::kExceededMaximum);
647
648 // If we keep going, the last operation will be the post-order unlink of
649 // the top-level directory. This has to fail with ENOTEMPTY since we did
650 // not delete the too-deep sub-directories. This particular behavior
651 // should not be part of the API contract and this can be relaxed if the
652 // implementation is changed.
653 EXPECT_EQ(rmdir_errno, ENOTEMPTY);
654
655 // The deep directory must still exist.
656 ASSERT_TRUE(
657 base::DeleteFile(sub_dir_path_.Append(kSubdirName), false /*recursive*/));
658
659 // We cannot control the iteration order so even if we incorrectly
660 // stopped early the directory might still be empty if the deep
661 // directories were last in the iteration order. But a non-empty
662 // directory is always incorrect.
663 ASSERT_TRUE(base::IsDirectoryEmpty(sub_dir_path_));
664 }
665
TEST_F(SafeFDTest,Rmdir_Recursive_StopOnError)666 TEST_F(SafeFDTest, Rmdir_Recursive_StopOnError) {
667 ASSERT_TRUE(SetupSubdir());
668
669 ASSERT_TRUE(base::CreateDirectory(sub_dir_path_.Append(kSubdirName)));
670
671 // Give us something to iterate over.
672 constexpr int kNumSentinel = 25;
673 for (int i = 0; i < kNumSentinel; i++) {
674 SafeFD::SafeFDResult file =
675 root_.MakeFile(sub_dir_path_.Append(GetRandomSuffix()));
676 EXPECT_EQ(file.second, SafeFD::Error::kNoError);
677 ASSERT_TRUE(file.first.is_valid());
678 }
679
680 // Recursively delete with a max level that is too small. Capture errno.
681 SafeFD::Error result = root_.Rmdir(kSubdirName, true /*recursive*/,
682 1 /*max_depth*/, false /*keep_going*/);
683 int rmdir_errno = errno;
684
685 EXPECT_EQ(result, SafeFD::Error::kExceededMaximum);
686
687 // If we stop on encountering a too-deep directory, we never actually
688 // make any libc calls that encounter errors. This particular behavior
689 // should not be part of the API contract and this can be relaxed if the
690 // implementation is changed.
691 EXPECT_EQ(rmdir_errno, 0);
692
693 // The deep directory must still exist.
694 ASSERT_TRUE(
695 base::DeleteFile(sub_dir_path_.Append(kSubdirName), false /*recursive*/));
696 }
697
698 } // namespace brillo
699