xref: /aosp_15_r20/external/libbrillo/brillo/files/safe_fd_test.cc (revision 1a96fba65179ea7d3f56207137718607415c5953)
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