1 // Copyright 2012 The Chromium Authors
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 "base/files/file_util.h"
6
7 #include <stddef.h>
8 #include <stdint.h>
9 #include <stdio.h>
10
11 #include <algorithm>
12 #include <fstream>
13 #include <initializer_list>
14 #include <memory>
15 #include <set>
16 #include <utility>
17 #include <vector>
18
19 #include "base/base_paths.h"
20 #include "base/command_line.h"
21 #include "base/environment.h"
22 #include "base/features.h"
23 #include "base/files/file.h"
24 #include "base/files/file_enumerator.h"
25 #include "base/files/file_path.h"
26 #include "base/files/platform_file.h"
27 #include "base/files/scoped_file.h"
28 #include "base/files/scoped_temp_dir.h"
29 #include "base/functional/bind.h"
30 #include "base/functional/callback_helpers.h"
31 #include "base/logging.h"
32 #include "base/path_service.h"
33 #include "base/rand_util.h"
34 #include "base/scoped_environment_variable_override.h"
35 #include "base/strings/string_util.h"
36 #include "base/strings/stringprintf.h"
37 #include "base/strings/utf_string_conversions.h"
38 #include "base/test/bind.h"
39 #include "base/test/multiprocess_test.h"
40 #include "base/test/scoped_feature_list.h"
41 #include "base/test/task_environment.h"
42 #include "base/test/test_file_util.h"
43 #include "base/test/test_timeouts.h"
44 #include "base/threading/platform_thread.h"
45 #include "base/threading/thread.h"
46 #include "base/time/time.h"
47 #include "base/uuid.h"
48 #include "build/branding_buildflags.h"
49 #include "build/build_config.h"
50 #include "testing/gtest/include/gtest/gtest.h"
51 #include "testing/multiprocess_func_list.h"
52 #include "testing/platform_test.h"
53
54 #if BUILDFLAG(IS_WIN)
55 #include <tchar.h>
56 #include <windows.h>
57
58 #include <shellapi.h>
59 #include <shlobj.h>
60
61 #include "base/scoped_native_library.h"
62 #include "base/strings/string_number_conversions.h"
63 #include "base/test/file_path_reparse_point_win.h"
64 #include "base/test/gtest_util.h"
65 #include "base/win/scoped_handle.h"
66 #include "base/win/win_util.h"
67 #endif
68
69 #if BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
70 #include <errno.h>
71 #include <fcntl.h>
72 #include <sys/ioctl.h>
73 #include <sys/types.h>
74 #include <unistd.h>
75 #endif
76
77 #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_ANDROID)
78 #include <sys/socket.h>
79 #endif
80
81 #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
82 #include <linux/fs.h>
83 #endif
84
85 #if BUILDFLAG(IS_ANDROID)
86 #include "base/android/content_uri_utils.h"
87 #endif
88
89 #if BUILDFLAG(IS_FUCHSIA)
90 #include "base/test/scoped_dev_zero_fuchsia.h"
91 #endif
92
93 // This macro helps avoid wrapped lines in the test structs.
94 #define FPL(x) FILE_PATH_LITERAL(x)
95
96 namespace base {
97
98 namespace {
99
100 const size_t kLargeFileSize = (1 << 16) + 3;
101
102 enum class CreateSymbolicLinkResult {
103 // The symbolic link creation failed because the platform does not support it.
104 // On Windows, that may be due to the lack of the required privilege.
105 kUnsupported = -1,
106
107 // The symbolic link creation failed.
108 kFailed,
109
110 // The symbolic link was created successfully.
111 kSucceeded,
112 };
113
114 #if BUILDFLAG(IS_WIN)
115 // Method that wraps the win32 GetShortPathName API. Returns an empty path on
116 // error.
MakeShortFilePath(const FilePath & input)117 FilePath MakeShortFilePath(const FilePath& input) {
118 DWORD path_short_len = ::GetShortPathName(input.value().c_str(), nullptr, 0);
119 if (path_short_len == 0UL)
120 return FilePath();
121
122 std::wstring path_short_str;
123 path_short_len = ::GetShortPathName(
124 input.value().c_str(), WriteInto(&path_short_str, path_short_len),
125 path_short_len);
126 if (path_short_len == 0UL)
127 return FilePath();
128
129 return FilePath(path_short_str);
130 }
131
CreateWinSymbolicLink(const FilePath & target,const FilePath & symlink)132 CreateSymbolicLinkResult CreateWinSymbolicLink(const FilePath& target,
133 const FilePath& symlink) {
134 // Determine whether the target is a directory. This is necessary because
135 // creating a symbolic link requires different flags depending on the type
136 // of the target (file vs. directory).
137 DWORD attrs = GetFileAttributes(target.value().c_str());
138 if (attrs == INVALID_FILE_ATTRIBUTES) {
139 // Unable to retrieve attributes for the target. It might not exist, or
140 // there may be a permissions issue. Either way, we cannot proceed.
141 return CreateSymbolicLinkResult::kFailed;
142 }
143
144 DWORD flags =
145 attrs & FILE_ATTRIBUTE_DIRECTORY ? SYMBOLIC_LINK_FLAG_DIRECTORY : 0;
146
147 if (!::CreateSymbolicLink(
148 symlink.value().c_str(), target.value().c_str(),
149 flags | SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE)) {
150 if (::GetLastError() == ERROR_PRIVILEGE_NOT_HELD) {
151 return CreateSymbolicLinkResult::kUnsupported;
152 }
153 return CreateSymbolicLinkResult::kFailed;
154 }
155
156 return CreateSymbolicLinkResult::kSucceeded;
157 }
158 #endif // BUILDFLAG(IS_WIN)
159
160 #if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_POSIX)
161
CreateSymbolicLinkForTesting(const FilePath & target,const FilePath & symlink)162 CreateSymbolicLinkResult CreateSymbolicLinkForTesting(const FilePath& target,
163 const FilePath& symlink) {
164 #if BUILDFLAG(IS_WIN)
165 return CreateWinSymbolicLink(target, symlink);
166 #else
167 if (!CreateSymbolicLink(target, symlink)) {
168 return CreateSymbolicLinkResult::kFailed;
169 }
170 return CreateSymbolicLinkResult::kSucceeded;
171 #endif // BUILDFLAG(IS_WIN)
172 }
173
174 #endif // BUILDFLAG(IS_WIN) || BUILDFLAG(IS_POSIX)
175
176 #if BUILDFLAG(IS_MAC)
177 // Provide a simple way to change the permissions bits on |path| in tests.
178 // ASSERT failures will return, but not stop the test. Caller should wrap
179 // calls to this function in ASSERT_NO_FATAL_FAILURE().
ChangePosixFilePermissions(const FilePath & path,int mode_bits_to_set,int mode_bits_to_clear)180 void ChangePosixFilePermissions(const FilePath& path,
181 int mode_bits_to_set,
182 int mode_bits_to_clear) {
183 ASSERT_FALSE(mode_bits_to_set & mode_bits_to_clear)
184 << "Can't set and clear the same bits.";
185
186 int mode = 0;
187 ASSERT_TRUE(GetPosixFilePermissions(path, &mode));
188 mode |= mode_bits_to_set;
189 mode &= ~mode_bits_to_clear;
190 ASSERT_TRUE(SetPosixFilePermissions(path, mode));
191 }
192 #endif // BUILDFLAG(IS_MAC)
193
194 // Fuchsia doesn't support file permissions.
195 #if !BUILDFLAG(IS_FUCHSIA)
196 // Sets the source file to read-only.
SetReadOnly(const FilePath & path,bool read_only)197 void SetReadOnly(const FilePath& path, bool read_only) {
198 #if BUILDFLAG(IS_WIN)
199 // On Windows, it involves setting/removing the 'readonly' bit.
200 DWORD attrs = GetFileAttributes(path.value().c_str());
201 ASSERT_NE(INVALID_FILE_ATTRIBUTES, attrs);
202 ASSERT_TRUE(SetFileAttributes(
203 path.value().c_str(), read_only ? (attrs | FILE_ATTRIBUTE_READONLY)
204 : (attrs & ~FILE_ATTRIBUTE_READONLY)));
205
206 DWORD expected =
207 read_only
208 ? ((attrs & (FILE_ATTRIBUTE_ARCHIVE | FILE_ATTRIBUTE_DIRECTORY)) |
209 FILE_ATTRIBUTE_READONLY)
210 : (attrs & (FILE_ATTRIBUTE_ARCHIVE | FILE_ATTRIBUTE_DIRECTORY));
211
212 // Ignore FILE_ATTRIBUTE_NOT_CONTENT_INDEXED and FILE_ATTRIBUTE_COMPRESSED
213 // if present. These flags are set by the operating system, depending on
214 // local configurations, such as compressing the file system. Not filtering
215 // out these flags could cause tests to fail even though they should pass.
216 attrs = GetFileAttributes(path.value().c_str()) &
217 ~(FILE_ATTRIBUTE_NOT_CONTENT_INDEXED | FILE_ATTRIBUTE_COMPRESSED);
218 ASSERT_EQ(expected, attrs);
219 #else
220 // On all other platforms, it involves removing/setting the write bit.
221 mode_t mode = read_only ? S_IRUSR : (S_IRUSR | S_IWUSR);
222 EXPECT_TRUE(SetPosixFilePermissions(
223 path, DirectoryExists(path) ? (mode | S_IXUSR) : mode));
224 #endif // BUILDFLAG(IS_WIN)
225 }
226
IsReadOnly(const FilePath & path)227 bool IsReadOnly(const FilePath& path) {
228 #if BUILDFLAG(IS_WIN)
229 DWORD attrs = GetFileAttributes(path.value().c_str());
230 EXPECT_NE(INVALID_FILE_ATTRIBUTES, attrs);
231 return attrs & FILE_ATTRIBUTE_READONLY;
232 #else
233 int mode = 0;
234 EXPECT_TRUE(GetPosixFilePermissions(path, &mode));
235 return !(mode & S_IWUSR);
236 #endif // BUILDFLAG(IS_WIN)
237 }
238
239 #endif // BUILDFLAG(IS_FUCHSIA)
240
241 const wchar_t bogus_content[] = L"I'm cannon fodder.";
242
243 const int FILES_AND_DIRECTORIES =
244 FileEnumerator::FILES | FileEnumerator::DIRECTORIES;
245
246 // file_util winds up using autoreleased objects on the Mac, so this needs
247 // to be a PlatformTest
248 class FileUtilTest : public PlatformTest {
249 protected:
SetUp()250 void SetUp() override {
251 PlatformTest::SetUp();
252 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
253 }
254
255 ScopedTempDir temp_dir_;
256 };
257
258 // Collects all the results from the given file enumerator, and provides an
259 // interface to query whether a given file is present.
260 class FindResultCollector {
261 public:
FindResultCollector(FileEnumerator * enumerator)262 explicit FindResultCollector(FileEnumerator* enumerator) {
263 FilePath cur_file;
264 while (!(cur_file = enumerator->Next()).value().empty()) {
265 FilePath::StringType path = cur_file.value();
266 // The file should not be returned twice.
267 EXPECT_TRUE(files_.end() == files_.find(path))
268 << "Same file returned twice";
269
270 // Save for later.
271 files_.insert(path);
272 }
273 }
274
275 // Returns true if the enumerator found the file.
HasFile(const FilePath & file) const276 bool HasFile(const FilePath& file) const {
277 return files_.find(file.value()) != files_.end();
278 }
279
size()280 int size() {
281 return static_cast<int>(files_.size());
282 }
283
284 private:
285 std::set<FilePath::StringType> files_;
286 };
287
288 // Simple function to dump some text into a new file.
CreateTextFile(const FilePath & filename,const std::wstring & contents)289 void CreateTextFile(const FilePath& filename,
290 const std::wstring& contents) {
291 std::wofstream file;
292 #if BUILDFLAG(IS_WIN)
293 file.open(filename.value().c_str());
294 #elif BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
295 file.open(filename.value());
296 #endif // BUILDFLAG(IS_WIN)
297 ASSERT_TRUE(file.is_open());
298 file << contents;
299 file.close();
300 }
301
302 // Simple function to take out some text from a file.
ReadTextFile(const FilePath & filename)303 std::wstring ReadTextFile(const FilePath& filename) {
304 wchar_t contents[64];
305 std::wifstream file;
306 #if BUILDFLAG(IS_WIN)
307 file.open(filename.value().c_str());
308 #elif BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
309 file.open(filename.value());
310 #endif // BUILDFLAG(IS_WIN)
311 EXPECT_TRUE(file.is_open());
312 file.getline(contents, std::size(contents));
313 file.close();
314 return std::wstring(contents);
315 }
316
317 // Sets |is_inheritable| to indicate whether or not |stream| is set up to be
318 // inerhited into child processes (i.e., HANDLE_FLAG_INHERIT is set on the
319 // underlying handle on Windows, or FD_CLOEXEC is not set on the underlying file
320 // descriptor on POSIX). Calls to this function must be wrapped with
321 // ASSERT_NO_FATAL_FAILURE to properly abort tests in case of fatal failure.
GetIsInheritable(FILE * stream,bool * is_inheritable)322 void GetIsInheritable(FILE* stream, bool* is_inheritable) {
323 #if BUILDFLAG(IS_WIN)
324 HANDLE handle = reinterpret_cast<HANDLE>(_get_osfhandle(_fileno(stream)));
325 ASSERT_NE(INVALID_HANDLE_VALUE, handle);
326
327 DWORD info = 0;
328 ASSERT_EQ(TRUE, ::GetHandleInformation(handle, &info));
329 *is_inheritable = ((info & HANDLE_FLAG_INHERIT) != 0);
330 #elif BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
331 int fd = fileno(stream);
332 ASSERT_NE(-1, fd);
333 int flags = fcntl(fd, F_GETFD, 0);
334 ASSERT_NE(-1, flags);
335 *is_inheritable = ((flags & FD_CLOEXEC) == 0);
336 #else
337 #error Not implemented
338 #endif
339 }
340
341 #if BUILDFLAG(IS_POSIX)
342 class ScopedWorkingDirectory {
343 public:
ScopedWorkingDirectory(const FilePath & new_working_dir)344 explicit ScopedWorkingDirectory(const FilePath& new_working_dir) {
345 CHECK(base::GetCurrentDirectory(&original_working_directory_));
346 CHECK(base::SetCurrentDirectory(new_working_dir));
347 }
348
~ScopedWorkingDirectory()349 ~ScopedWorkingDirectory() {
350 CHECK(base::SetCurrentDirectory(original_working_directory_));
351 }
352
353 private:
354 base::FilePath original_working_directory_;
355 };
356
TEST_F(FileUtilTest,MakeAbsoluteFilePathNoResolveSymbolicLinks)357 TEST_F(FileUtilTest, MakeAbsoluteFilePathNoResolveSymbolicLinks) {
358 FilePath cwd;
359 ASSERT_TRUE(GetCurrentDirectory(&cwd));
360 const std::pair<FilePath, std::optional<FilePath>> kExpectedResults[]{
361 {FilePath(), std::nullopt},
362 {FilePath("."), cwd},
363 {FilePath(".."), cwd.DirName()},
364 {FilePath("a/.."), cwd},
365 {FilePath("a/b/.."), cwd.Append(FPL("a"))},
366 {FilePath("/tmp/../.."), FilePath("/")},
367 {FilePath("/tmp/../"), FilePath("/")},
368 {FilePath("/tmp/a/b/../c/../.."), FilePath("/tmp")},
369 {FilePath("/././tmp/./a/./b/../c/./../.."), FilePath("/tmp")},
370 {FilePath("/.././../tmp"), FilePath("/tmp")},
371 {FilePath("/..///.////..////tmp"), FilePath("/tmp")},
372 {FilePath("//..///.////..////tmp"), FilePath("//tmp")},
373 {FilePath("///..///.////..////tmp"), FilePath("/tmp")},
374 };
375
376 for (auto& expected_result : kExpectedResults) {
377 EXPECT_EQ(MakeAbsoluteFilePathNoResolveSymbolicLinks(expected_result.first),
378 expected_result.second);
379 }
380
381 // Test that MakeAbsoluteFilePathNoResolveSymbolicLinks() returns an empty
382 // path if GetCurrentDirectory() fails.
383 const FilePath temp_dir_path = temp_dir_.GetPath();
384 ScopedWorkingDirectory scoped_cwd(temp_dir_path);
385 // Delete the cwd so that GetCurrentDirectory() fails.
386 ASSERT_TRUE(temp_dir_.Delete());
387 ASSERT_FALSE(
388 MakeAbsoluteFilePathNoResolveSymbolicLinks(FilePath("relative_file_path"))
389 .has_value());
390 }
391 #endif // BUILDFLAG(IS_POSIX)
392
TEST_F(FileUtilTest,FileAndDirectorySize)393 TEST_F(FileUtilTest, FileAndDirectorySize) {
394 // Create three files of 20, 30 and 3 chars (utf8). ComputeDirectorySize
395 // should return 53 bytes.
396 FilePath file_01 = temp_dir_.GetPath().Append(FPL("The file 01.txt"));
397 CreateTextFile(file_01, L"12345678901234567890");
398 int64_t size_f1 = 0;
399 ASSERT_TRUE(GetFileSize(file_01, &size_f1));
400 EXPECT_EQ(20ll, size_f1);
401
402 FilePath subdir_path = temp_dir_.GetPath().Append(FPL("Level2"));
403 CreateDirectory(subdir_path);
404
405 FilePath file_02 = subdir_path.Append(FPL("The file 02.txt"));
406 CreateTextFile(file_02, L"123456789012345678901234567890");
407 int64_t size_f2 = 0;
408 ASSERT_TRUE(GetFileSize(file_02, &size_f2));
409 EXPECT_EQ(30ll, size_f2);
410
411 FilePath subsubdir_path = subdir_path.Append(FPL("Level3"));
412 CreateDirectory(subsubdir_path);
413
414 FilePath file_03 = subsubdir_path.Append(FPL("The file 03.txt"));
415 CreateTextFile(file_03, L"123");
416
417 int64_t computed_size = ComputeDirectorySize(temp_dir_.GetPath());
418 EXPECT_EQ(size_f1 + size_f2 + 3, computed_size);
419 }
420
TEST_F(FileUtilTest,NormalizeFilePathBasic)421 TEST_F(FileUtilTest, NormalizeFilePathBasic) {
422 // Create a directory under the test dir. Because we create it,
423 // we know it is not a link.
424 FilePath file_a_path = temp_dir_.GetPath().Append(FPL("file_a"));
425 FilePath dir_path = temp_dir_.GetPath().Append(FPL("dir"));
426 FilePath file_b_path = dir_path.Append(FPL("file_b"));
427 CreateDirectory(dir_path);
428
429 FilePath normalized_file_a_path, normalized_file_b_path;
430 ASSERT_FALSE(PathExists(file_a_path));
431 ASSERT_FALSE(NormalizeFilePath(file_a_path, &normalized_file_a_path))
432 << "NormalizeFilePath() should fail on nonexistent paths.";
433
434 CreateTextFile(file_a_path, bogus_content);
435 ASSERT_TRUE(PathExists(file_a_path));
436 ASSERT_TRUE(NormalizeFilePath(file_a_path, &normalized_file_a_path));
437
438 CreateTextFile(file_b_path, bogus_content);
439 ASSERT_TRUE(PathExists(file_b_path));
440 ASSERT_TRUE(NormalizeFilePath(file_b_path, &normalized_file_b_path));
441
442 // Because this test created |dir_path|, we know it is not a link
443 // or junction. So, the real path of the directory holding file a
444 // must be the parent of the path holding file b.
445 ASSERT_TRUE(normalized_file_a_path.DirName()
446 .IsParent(normalized_file_b_path.DirName()));
447 }
448
449 #if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_POSIX)
450
TEST_F(FileUtilTest,IsLinkCreateSymbolicLinkOnFile)451 TEST_F(FileUtilTest, IsLinkCreateSymbolicLinkOnFile) {
452 FilePath target_file_path;
453 ASSERT_TRUE(CreateTemporaryFileInDir(temp_dir_.GetPath(), &target_file_path));
454 EXPECT_FALSE(IsLink(target_file_path));
455
456 base::FilePath symlink_path =
457 temp_dir_.GetPath().Append(FPL("symlink_to_target"));
458
459 CreateSymbolicLinkResult result =
460 CreateSymbolicLinkForTesting(target_file_path, symlink_path);
461 if (result == CreateSymbolicLinkResult::kUnsupported) {
462 GTEST_SKIP();
463 }
464 ASSERT_EQ(result, CreateSymbolicLinkResult::kSucceeded);
465
466 EXPECT_TRUE(IsLink(symlink_path));
467 }
468
TEST_F(FileUtilTest,IsLinkCreateSymbolicLinkOnDirectory)469 TEST_F(FileUtilTest, IsLinkCreateSymbolicLinkOnDirectory) {
470 FilePath target_path = temp_dir_.GetPath().Append(FPL("target"));
471 ASSERT_TRUE(CreateDirectory(target_path));
472 EXPECT_FALSE(IsLink(target_path));
473
474 base::FilePath symlink_path =
475 temp_dir_.GetPath().Append(FPL("symlink_to_target"));
476
477 CreateSymbolicLinkResult result =
478 CreateSymbolicLinkForTesting(target_path, symlink_path);
479 if (result == CreateSymbolicLinkResult::kUnsupported) {
480 GTEST_SKIP();
481 }
482 ASSERT_EQ(result, CreateSymbolicLinkResult::kSucceeded);
483
484 EXPECT_TRUE(IsLink(symlink_path));
485 }
486
TEST_F(FileUtilTest,IsLinkMissingFile)487 TEST_F(FileUtilTest, IsLinkMissingFile) {
488 EXPECT_FALSE(IsLink(FilePath()));
489 }
490
TEST_F(FileUtilTest,IsLinkWithDeletedTargetFile)491 TEST_F(FileUtilTest, IsLinkWithDeletedTargetFile) {
492 // Set up a symlink pointing to a temporary file.
493 FilePath target_file_path;
494 ASSERT_TRUE(CreateTemporaryFileInDir(temp_dir_.GetPath(), &target_file_path));
495 FilePath symlink_path =
496 temp_dir_.GetPath().Append(FPL("symlink_to_missing_target"));
497
498 CreateSymbolicLinkResult result =
499 CreateSymbolicLinkForTesting(target_file_path, symlink_path);
500 if (result == CreateSymbolicLinkResult::kUnsupported) {
501 GTEST_SKIP();
502 }
503 ASSERT_EQ(result, CreateSymbolicLinkResult::kSucceeded);
504
505 // Verify that the symlink is recognized correctly.
506 EXPECT_TRUE(IsLink(symlink_path));
507
508 // Delete the target file.
509 ASSERT_TRUE(DeleteFile(target_file_path));
510
511 // Verify that IsLink still returns true for the symlink, even though its
512 // target is missing.
513 EXPECT_TRUE(IsLink(symlink_path));
514 }
515
TEST_F(FileUtilTest,IsLinkWithDeletedTargetDirectory)516 TEST_F(FileUtilTest, IsLinkWithDeletedTargetDirectory) {
517 // Set up a symlink pointing to a temporary file.
518 FilePath target_path = temp_dir_.GetPath().Append(FPL("target"));
519 ASSERT_TRUE(CreateDirectory(target_path));
520 FilePath symlink_path =
521 temp_dir_.GetPath().Append(FPL("symlink_to_missing_target"));
522
523 CreateSymbolicLinkResult result =
524 CreateSymbolicLinkForTesting(target_path, symlink_path);
525 if (result == CreateSymbolicLinkResult::kUnsupported) {
526 GTEST_SKIP();
527 }
528 ASSERT_EQ(result, CreateSymbolicLinkResult::kSucceeded);
529
530 // Verify that the symlink is recognized correctly.
531 EXPECT_TRUE(IsLink(symlink_path));
532
533 // Delete the target file.
534 ASSERT_TRUE(DeleteFile(target_path));
535
536 // Verify that IsLink still returns true for the symlink, even though its
537 // target is missing.
538 EXPECT_TRUE(IsLink(symlink_path));
539 }
540
TEST_F(FileUtilTest,IsLinkWihtoutReparsePointAttributeOnDirectory)541 TEST_F(FileUtilTest, IsLinkWihtoutReparsePointAttributeOnDirectory) {
542 FilePath target_path = temp_dir_.GetPath().Append(FPL("target"));
543 ASSERT_TRUE(CreateDirectory(target_path));
544 EXPECT_FALSE(IsLink(target_path));
545 }
546
TEST_F(FileUtilTest,IsLinkWihtoutReparsePointAttributeOnFile)547 TEST_F(FileUtilTest, IsLinkWihtoutReparsePointAttributeOnFile) {
548 FilePath target_file_path;
549 ASSERT_TRUE(CreateTemporaryFileInDir(temp_dir_.GetPath(), &target_file_path));
550 EXPECT_FALSE(IsLink(target_file_path));
551 }
552
553 #endif // BUILDFLAG(IS_WIN) || BUILDFLAG(IS_POSIX)
554
555 #if BUILDFLAG(IS_WIN)
556
TEST_F(FileUtilTest,NormalizeFileEmptyFile)557 TEST_F(FileUtilTest, NormalizeFileEmptyFile) {
558 // Create a directory under the test dir. Because we create it,
559 // we know it is not a link.
560 const wchar_t empty_content[] = L"";
561
562 FilePath file_a_path = temp_dir_.GetPath().Append(FPL("file_empty_a"));
563 FilePath dir_path = temp_dir_.GetPath().Append(FPL("dir"));
564 FilePath file_b_path = dir_path.Append(FPL("file_empty_b"));
565 ASSERT_TRUE(CreateDirectory(dir_path));
566
567 FilePath normalized_file_a_path, normalized_file_b_path;
568 ASSERT_FALSE(PathExists(file_a_path));
569 EXPECT_FALSE(NormalizeFilePath(file_a_path, &normalized_file_a_path))
570 << "NormalizeFilePath() should fail on nonexistent paths.";
571
572 CreateTextFile(file_a_path, empty_content);
573 ASSERT_TRUE(PathExists(file_a_path));
574 EXPECT_TRUE(NormalizeFilePath(file_a_path, &normalized_file_a_path));
575
576 CreateTextFile(file_b_path, empty_content);
577 ASSERT_TRUE(PathExists(file_b_path));
578 EXPECT_TRUE(NormalizeFilePath(file_b_path, &normalized_file_b_path));
579
580 // Because this test created |dir_path|, we know it is not a link
581 // or junction. So, the real path of the directory holding file a
582 // must be the parent of the path holding file b.
583 EXPECT_TRUE(normalized_file_a_path.DirName().IsParent(
584 normalized_file_b_path.DirName()));
585 }
586
TEST_F(FileUtilTest,NormalizeFilePathReparsePoints)587 TEST_F(FileUtilTest, NormalizeFilePathReparsePoints) {
588 // Build the following directory structure:
589 //
590 // temp_dir
591 // |-> base_a
592 // | |-> sub_a
593 // | |-> file.txt
594 // | |-> long_name___... (Very long name.)
595 // | |-> sub_long
596 // | |-> deep.txt
597 // |-> base_b
598 // |-> to_sub_a (reparse point to temp_dir\base_a\sub_a)
599 // |-> to_base_b (reparse point to temp_dir\base_b)
600 // |-> to_sub_long (reparse point to temp_dir\sub_a\long_name_\sub_long)
601
602 FilePath base_a = temp_dir_.GetPath().Append(FPL("base_a"));
603 #if BUILDFLAG(IS_WIN)
604 // TEMP can have a lower case drive letter.
605 std::wstring temp_base_a = base_a.value();
606 ASSERT_FALSE(temp_base_a.empty());
607 temp_base_a[0] = ToUpperASCII(char16_t{temp_base_a[0]});
608 base_a = FilePath(temp_base_a);
609 #endif
610 ASSERT_TRUE(CreateDirectory(base_a));
611 #if BUILDFLAG(IS_WIN)
612 // TEMP might be a short name which is not normalized.
613 base_a = MakeLongFilePath(base_a);
614 #endif
615
616 FilePath sub_a = base_a.Append(FPL("sub_a"));
617 ASSERT_TRUE(CreateDirectory(sub_a));
618
619 FilePath file_txt = sub_a.Append(FPL("file.txt"));
620 CreateTextFile(file_txt, bogus_content);
621
622 // Want a directory whose name is long enough to make the path to the file
623 // inside just under MAX_PATH chars. This will be used to test that when
624 // a junction expands to a path over MAX_PATH chars in length,
625 // NormalizeFilePath() fails without crashing.
626 FilePath sub_long_rel(FPL("sub_long"));
627 FilePath deep_txt(FPL("deep.txt"));
628
629 int target_length = MAX_PATH;
630 target_length -= (sub_a.value().length() + 1); // +1 for the sepperator '\'.
631 target_length -= (sub_long_rel.Append(deep_txt).value().length() + 1);
632 // Without making the path a bit shorter, CreateDirectory() fails.
633 // the resulting path is still long enough to hit the failing case in
634 // NormalizePath().
635 const int kCreateDirLimit = 4;
636 target_length -= kCreateDirLimit;
637 FilePath::StringType long_name_str = FPL("long_name_");
638 long_name_str.resize(target_length, '_');
639
640 FilePath long_name = sub_a.Append(FilePath(long_name_str));
641 FilePath deep_file = long_name.Append(sub_long_rel).Append(deep_txt);
642 ASSERT_EQ(static_cast<size_t>(MAX_PATH - kCreateDirLimit),
643 deep_file.value().length());
644
645 FilePath sub_long = deep_file.DirName();
646 ASSERT_TRUE(CreateDirectory(sub_long));
647 CreateTextFile(deep_file, bogus_content);
648
649 FilePath base_b = temp_dir_.GetPath().Append(FPL("base_b"));
650 ASSERT_TRUE(CreateDirectory(base_b));
651 #if BUILDFLAG(IS_WIN)
652 // TEMP might be a short name which is not normalized.
653 base_b = MakeLongFilePath(base_b);
654 #endif
655
656 FilePath to_sub_a = base_b.Append(FPL("to_sub_a"));
657 ASSERT_TRUE(CreateDirectory(to_sub_a));
658 FilePath normalized_path;
659 {
660 auto reparse_to_sub_a = test::FilePathReparsePoint::Create(to_sub_a, sub_a);
661 ASSERT_TRUE(reparse_to_sub_a.has_value());
662
663 FilePath to_base_b = base_b.Append(FPL("to_base_b"));
664 ASSERT_TRUE(CreateDirectory(to_base_b));
665 auto reparse_to_base_b =
666 test::FilePathReparsePoint::Create(to_base_b, base_b);
667 ASSERT_TRUE(reparse_to_base_b.has_value());
668
669 FilePath to_sub_long = base_b.Append(FPL("to_sub_long"));
670 ASSERT_TRUE(CreateDirectory(to_sub_long));
671 auto reparse_to_sub_long =
672 test::FilePathReparsePoint::Create(to_sub_long, sub_long);
673 ASSERT_TRUE(reparse_to_sub_long.has_value());
674
675 // Normalize a junction free path: base_a\sub_a\file.txt .
676 ASSERT_TRUE(NormalizeFilePath(file_txt, &normalized_path));
677 ASSERT_EQ(file_txt.value(), normalized_path.value());
678
679 // Check that the path base_b\to_sub_a\file.txt can be normalized to exclude
680 // the junction to_sub_a.
681 ASSERT_TRUE(NormalizeFilePath(to_sub_a.Append(FPL("file.txt")),
682 &normalized_path));
683 ASSERT_EQ(file_txt.value(), normalized_path.value());
684
685 // Check that the path base_b\to_base_b\to_base_b\to_sub_a\file.txt can be
686 // normalized to exclude junctions to_base_b and to_sub_a .
687 ASSERT_TRUE(NormalizeFilePath(base_b.Append(FPL("to_base_b"))
688 .Append(FPL("to_base_b"))
689 .Append(FPL("to_sub_a"))
690 .Append(FPL("file.txt")),
691 &normalized_path));
692 ASSERT_EQ(file_txt.value(), normalized_path.value());
693
694 // A long enough path will cause NormalizeFilePath() to fail. Make a long
695 // path using to_base_b many times, and check that paths long enough to fail
696 // do not cause a crash.
697 FilePath long_path = base_b;
698 const int kLengthLimit = MAX_PATH + 200;
699 while (long_path.value().length() <= kLengthLimit) {
700 long_path = long_path.Append(FPL("to_base_b"));
701 }
702 long_path = long_path.Append(FPL("to_sub_a"))
703 .Append(FPL("file.txt"));
704
705 ASSERT_FALSE(NormalizeFilePath(long_path, &normalized_path));
706
707 // Normalizing the junction to deep.txt should fail, because the expanded
708 // path to deep.txt is longer than MAX_PATH.
709 ASSERT_FALSE(NormalizeFilePath(to_sub_long.Append(deep_txt),
710 &normalized_path));
711
712 // Delete the reparse points, and see that NormalizeFilePath() fails
713 // to traverse them.
714 }
715
716 ASSERT_FALSE(NormalizeFilePath(to_sub_a.Append(FPL("file.txt")),
717 &normalized_path));
718 }
719
TEST_F(FileUtilTest,DevicePathToDriveLetter)720 TEST_F(FileUtilTest, DevicePathToDriveLetter) {
721 // Get a drive letter.
722 std::wstring real_drive_letter = AsWString(
723 ToUpperASCII(AsStringPiece16(temp_dir_.GetPath().value().substr(0, 2))));
724 if (!IsAsciiAlpha(real_drive_letter[0]) || ':' != real_drive_letter[1]) {
725 LOG(ERROR) << "Can't get a drive letter to test with.";
726 return;
727 }
728
729 // Get the NT style path to that drive.
730 wchar_t device_path[MAX_PATH] = {'\0'};
731 ASSERT_TRUE(
732 ::QueryDosDevice(real_drive_letter.c_str(), device_path, MAX_PATH));
733 FilePath actual_device_path(device_path);
734 FilePath win32_path;
735
736 // Run DevicePathToDriveLetterPath() on the NT style path we got from
737 // QueryDosDevice(). Expect the drive letter we started with.
738 ASSERT_TRUE(DevicePathToDriveLetterPath(actual_device_path, &win32_path));
739 ASSERT_EQ(real_drive_letter, win32_path.value());
740
741 // Add some directories to the path. Expect those extra path componenets
742 // to be preserved.
743 FilePath kRelativePath(FPL("dir1\\dir2\\file.txt"));
744 ASSERT_TRUE(DevicePathToDriveLetterPath(
745 actual_device_path.Append(kRelativePath),
746 &win32_path));
747 EXPECT_EQ(FilePath(real_drive_letter + FILE_PATH_LITERAL("\\"))
748 .Append(kRelativePath)
749 .value(),
750 win32_path.value());
751
752 // Deform the real path so that it is invalid by removing the last four
753 // characters. The way windows names devices that are hard disks
754 // (\Device\HardDiskVolume${NUMBER}) guarantees that the string is longer
755 // than three characters. The only way the truncated string could be a
756 // real drive is if more than 10^3 disks are mounted:
757 // \Device\HardDiskVolume10000 would be truncated to \Device\HardDiskVolume1
758 // Check that DevicePathToDriveLetterPath fails.
759 size_t path_length = actual_device_path.value().length();
760 size_t new_length = path_length - 4;
761 ASSERT_GT(new_length, 0u);
762 FilePath prefix_of_real_device_path(
763 actual_device_path.value().substr(0, new_length));
764 ASSERT_FALSE(DevicePathToDriveLetterPath(prefix_of_real_device_path,
765 &win32_path));
766
767 ASSERT_FALSE(DevicePathToDriveLetterPath(
768 prefix_of_real_device_path.Append(kRelativePath),
769 &win32_path));
770
771 // Deform the real path so that it is invalid by adding some characters. For
772 // example, if C: maps to \Device\HardDiskVolume8, then we simulate a
773 // request for the drive letter whose native path is
774 // \Device\HardDiskVolume812345 . We assume such a device does not exist,
775 // because drives are numbered in order and mounting 112345 hard disks will
776 // never happen.
777 const FilePath::StringType kExtraChars = FPL("12345");
778
779 FilePath real_device_path_plus_numbers(
780 actual_device_path.value() + kExtraChars);
781
782 ASSERT_FALSE(DevicePathToDriveLetterPath(
783 real_device_path_plus_numbers,
784 &win32_path));
785
786 ASSERT_FALSE(DevicePathToDriveLetterPath(
787 real_device_path_plus_numbers.Append(kRelativePath),
788 &win32_path));
789 }
790
TEST_F(FileUtilTest,CreateTemporaryFileInDirLongPathTest)791 TEST_F(FileUtilTest, CreateTemporaryFileInDirLongPathTest) {
792 // Test that CreateTemporaryFileInDir() creates a path and returns a long path
793 // if it is available. This test requires that:
794 // - the filesystem at |temp_dir_| supports long filenames.
795 // - the account has FILE_LIST_DIRECTORY permission for all ancestor
796 // directories of |temp_dir_|.
797 constexpr FilePath::CharType kLongDirName[] = FPL("A long path");
798 constexpr FilePath::CharType kTestSubDirName[] = FPL("test");
799 FilePath long_test_dir = temp_dir_.GetPath().Append(kLongDirName);
800 ASSERT_TRUE(CreateDirectory(long_test_dir));
801
802 // kLongDirName is not a 8.3 component. So ::GetShortPathName() should give us
803 // a different short name.
804 FilePath short_test_dir = MakeShortFilePath(long_test_dir);
805 ASSERT_FALSE(short_test_dir.empty());
806 ASSERT_NE(kLongDirName, short_test_dir.BaseName().value());
807
808 FilePath temp_file;
809 ASSERT_TRUE(CreateTemporaryFileInDir(short_test_dir, &temp_file));
810 EXPECT_EQ(kLongDirName, temp_file.DirName().BaseName().value());
811 EXPECT_TRUE(PathExists(temp_file));
812
813 // Create a subdirectory of |long_test_dir| and make |long_test_dir|
814 // unreadable. We should still be able to create a temp file in the
815 // subdirectory, but we won't be able to determine the long path for it. This
816 // mimics the environment that some users run where their user profiles reside
817 // in a location where the don't have full access to the higher level
818 // directories. (Note that this assumption is true for NTFS, but not for some
819 // network file systems. E.g. AFS).
820 FilePath access_test_dir = long_test_dir.Append(kTestSubDirName);
821 ASSERT_TRUE(CreateDirectory(access_test_dir));
822 FilePermissionRestorer long_test_dir_restorer(long_test_dir);
823 ASSERT_TRUE(MakeFileUnreadable(long_test_dir));
824
825 // Use the short form of the directory to create a temporary filename.
826 ASSERT_TRUE(CreateTemporaryFileInDir(
827 short_test_dir.Append(kTestSubDirName), &temp_file));
828 EXPECT_TRUE(PathExists(temp_file));
829 EXPECT_TRUE(short_test_dir.IsParent(temp_file.DirName()));
830
831 // Check that the long path can't be determined for |temp_file|.
832 // Helper method base::MakeLongFilePath returns an empty path on error.
833 FilePath temp_file_long = MakeLongFilePath(temp_file);
834 ASSERT_TRUE(temp_file_long.empty());
835 }
836
TEST_F(FileUtilTest,MakeLongFilePathTest)837 TEST_F(FileUtilTest, MakeLongFilePathTest) {
838 // Tests helper function base::MakeLongFilePath
839
840 // If a username isn't a valid 8.3 short file name (even just a
841 // lengthy name like "user with long name"), Windows will set the TMP and TEMP
842 // environment variables to be 8.3 paths. ::GetTempPath (called in
843 // base::GetTempDir) just uses the value specified by TMP or TEMP, and so can
844 // return a short path. So from the start need to use MakeLongFilePath
845 // to normalize the path for such test environments.
846 FilePath temp_dir_long = MakeLongFilePath(temp_dir_.GetPath());
847 ASSERT_FALSE(temp_dir_long.empty());
848
849 FilePath long_test_dir = temp_dir_long.Append(FPL("A long directory name"));
850 ASSERT_TRUE(CreateDirectory(long_test_dir));
851
852 // Directory name is not a 8.3 component. So ::GetShortPathName() should give
853 // us a different short name.
854 FilePath short_test_dir = MakeShortFilePath(long_test_dir);
855 ASSERT_FALSE(short_test_dir.empty());
856
857 EXPECT_NE(long_test_dir, short_test_dir);
858 EXPECT_EQ(long_test_dir, MakeLongFilePath(short_test_dir));
859
860 FilePath long_test_file = long_test_dir.Append(FPL("A long file name.1234"));
861 CreateTextFile(long_test_file, bogus_content);
862 ASSERT_TRUE(PathExists(long_test_file));
863
864 // File name is not a 8.3 component. So ::GetShortPathName() should give us
865 // a different short name.
866 FilePath short_test_file = MakeShortFilePath(long_test_file);
867 ASSERT_FALSE(short_test_file.empty());
868
869 EXPECT_NE(long_test_file, short_test_file);
870 EXPECT_EQ(long_test_file, MakeLongFilePath(short_test_file));
871
872 // MakeLongFilePath should return empty path if file does not exist.
873 EXPECT_TRUE(DeleteFile(short_test_file));
874 EXPECT_TRUE(MakeLongFilePath(short_test_file).empty());
875
876 // MakeLongFilePath should return empty path if directory does not exist.
877 EXPECT_TRUE(DeleteFile(short_test_dir));
878 EXPECT_TRUE(MakeLongFilePath(short_test_dir).empty());
879 }
880
TEST_F(FileUtilTest,CreateWinHardlinkTest)881 TEST_F(FileUtilTest, CreateWinHardlinkTest) {
882 // Link to a different file name in a sub-directory of |temp_dir_|.
883 FilePath test_dir = temp_dir_.GetPath().Append(FPL("test"));
884 ASSERT_TRUE(CreateDirectory(test_dir));
885 FilePath temp_file;
886 ASSERT_TRUE(CreateTemporaryFileInDir(temp_dir_.GetPath(), &temp_file));
887 FilePath link_to_file = test_dir.Append(FPL("linked_name"));
888 EXPECT_TRUE(CreateWinHardLink(link_to_file, temp_file));
889 EXPECT_TRUE(PathExists(link_to_file));
890
891 // Link two directories. This should fail. Verify that failure is returned
892 // by CreateWinHardLink.
893 EXPECT_FALSE(CreateWinHardLink(temp_dir_.GetPath(), test_dir));
894 }
895
TEST_F(FileUtilTest,PreventExecuteMappingNewFile)896 TEST_F(FileUtilTest, PreventExecuteMappingNewFile) {
897 base::test::ScopedFeatureList enforcement_feature;
898 enforcement_feature.InitAndEnableFeature(
899 features::kEnforceNoExecutableFileHandles);
900 FilePath file = temp_dir_.GetPath().Append(FPL("afile.txt"));
901
902 ASSERT_FALSE(PathExists(file));
903 {
904 File new_file(file, File::FLAG_WRITE | File::FLAG_WIN_NO_EXECUTE |
905 File::FLAG_CREATE_ALWAYS);
906 ASSERT_TRUE(new_file.IsValid());
907 }
908
909 {
910 File open_file(file, File::FLAG_READ | File::FLAG_WIN_EXECUTE |
911 File::FLAG_OPEN_ALWAYS);
912 EXPECT_FALSE(open_file.IsValid());
913 }
914 // Verify the deny ACL did not prevent deleting the file.
915 EXPECT_TRUE(DeleteFile(file));
916 }
917
TEST_F(FileUtilTest,PreventExecuteMappingExisting)918 TEST_F(FileUtilTest, PreventExecuteMappingExisting) {
919 base::test::ScopedFeatureList enforcement_feature;
920 enforcement_feature.InitAndEnableFeature(
921 features::kEnforceNoExecutableFileHandles);
922 FilePath file = temp_dir_.GetPath().Append(FPL("afile.txt"));
923 CreateTextFile(file, bogus_content);
924 ASSERT_TRUE(PathExists(file));
925 {
926 File open_file(file, File::FLAG_READ | File::FLAG_WIN_EXECUTE |
927 File::FLAG_OPEN_ALWAYS);
928 EXPECT_TRUE(open_file.IsValid());
929 }
930 EXPECT_TRUE(PreventExecuteMapping(file));
931 {
932 File open_file(file, File::FLAG_READ | File::FLAG_WIN_EXECUTE |
933 File::FLAG_OPEN_ALWAYS);
934 EXPECT_FALSE(open_file.IsValid());
935 }
936 // Verify the deny ACL did not prevent deleting the file.
937 EXPECT_TRUE(DeleteFile(file));
938 }
939
TEST_F(FileUtilTest,PreventExecuteMappingOpenFile)940 TEST_F(FileUtilTest, PreventExecuteMappingOpenFile) {
941 base::test::ScopedFeatureList enforcement_feature;
942 enforcement_feature.InitAndEnableFeature(
943 features::kEnforceNoExecutableFileHandles);
944 FilePath file = temp_dir_.GetPath().Append(FPL("afile.txt"));
945 CreateTextFile(file, bogus_content);
946 ASSERT_TRUE(PathExists(file));
947 File open_file(file, File::FLAG_READ | File::FLAG_WRITE |
948 File::FLAG_WIN_EXECUTE | File::FLAG_OPEN_ALWAYS);
949 EXPECT_TRUE(open_file.IsValid());
950 // Verify ACE can be set even on an open file.
951 EXPECT_TRUE(PreventExecuteMapping(file));
952 {
953 File second_open_file(
954 file, File::FLAG_READ | File::FLAG_WRITE | File::FLAG_OPEN_ALWAYS);
955 EXPECT_TRUE(second_open_file.IsValid());
956 }
957 {
958 File third_open_file(file, File::FLAG_READ | File::FLAG_WIN_EXECUTE |
959 File::FLAG_OPEN_ALWAYS);
960 EXPECT_FALSE(third_open_file.IsValid());
961 }
962
963 open_file.Close();
964 // Verify the deny ACL did not prevent deleting the file.
965 EXPECT_TRUE(DeleteFile(file));
966 }
967
TEST(FileUtilDeathTest,DisallowNoExecuteOnUnsafeFile)968 TEST(FileUtilDeathTest, DisallowNoExecuteOnUnsafeFile) {
969 base::test::ScopedFeatureList enforcement_feature;
970 enforcement_feature.InitAndEnableFeature(
971 features::kEnforceNoExecutableFileHandles);
972 base::FilePath local_app_data;
973 // This test places a file in %LOCALAPPDATA% to verify that the checks in
974 // IsPathSafeToSetAclOn work correctly.
975 ASSERT_TRUE(
976 base::PathService::Get(base::DIR_LOCAL_APP_DATA, &local_app_data));
977
978 base::FilePath file_path;
979 EXPECT_DCHECK_DEATH_WITH(
980 {
981 {
982 base::File temp_file =
983 base::CreateAndOpenTemporaryFileInDir(local_app_data, &file_path);
984 }
985 File reopen_file(file_path, File::FLAG_READ | File::FLAG_WRITE |
986 File::FLAG_WIN_NO_EXECUTE |
987 File::FLAG_OPEN_ALWAYS |
988 File::FLAG_DELETE_ON_CLOSE);
989 },
990 "Unsafe to deny execute access to path");
991 }
992
MULTIPROCESS_TEST_MAIN(NoExecuteOnSafeFileMain)993 MULTIPROCESS_TEST_MAIN(NoExecuteOnSafeFileMain) {
994 base::FilePath temp_file;
995 CHECK(base::CreateTemporaryFile(&temp_file));
996
997 // A file with FLAG_WIN_NO_EXECUTE created in temp dir should always be
998 // permitted.
999 File reopen_file(temp_file, File::FLAG_READ | File::FLAG_WRITE |
1000 File::FLAG_WIN_NO_EXECUTE |
1001 File::FLAG_OPEN_ALWAYS |
1002 File::FLAG_DELETE_ON_CLOSE);
1003 return 0;
1004 }
1005
TEST_F(FileUtilTest,NoExecuteOnSafeFile)1006 TEST_F(FileUtilTest, NoExecuteOnSafeFile) {
1007 FilePath new_dir;
1008 ASSERT_TRUE(CreateTemporaryDirInDir(
1009 temp_dir_.GetPath(), FILE_PATH_LITERAL("NoExecuteOnSafeFileLongPath"),
1010 &new_dir));
1011
1012 FilePath short_dir = base::MakeShortFilePath(new_dir);
1013
1014 // Verify that the path really is 8.3 now.
1015 ASSERT_NE(new_dir.value(), short_dir.value());
1016
1017 LaunchOptions options;
1018 options.environment[L"TMP"] = short_dir.value();
1019
1020 CommandLine child_command_line(GetMultiProcessTestChildBaseCommandLine());
1021
1022 Process child_process = SpawnMultiProcessTestChild(
1023 "NoExecuteOnSafeFileMain", child_command_line, options);
1024 ASSERT_TRUE(child_process.IsValid());
1025 int rv = -1;
1026 ASSERT_TRUE(WaitForMultiprocessTestChildExit(
1027 child_process, TestTimeouts::action_timeout(), &rv));
1028 ASSERT_EQ(0, rv);
1029 }
1030
1031 class FileUtilExecuteEnforcementTest
1032 : public FileUtilTest,
1033 public ::testing::WithParamInterface<bool> {
1034 public:
FileUtilExecuteEnforcementTest()1035 FileUtilExecuteEnforcementTest() {
1036 if (IsEnforcementEnabled()) {
1037 enforcement_feature_.InitAndEnableFeature(
1038 features::kEnforceNoExecutableFileHandles);
1039 } else {
1040 enforcement_feature_.InitAndDisableFeature(
1041 features::kEnforceNoExecutableFileHandles);
1042 }
1043 }
1044
1045 protected:
IsEnforcementEnabled()1046 bool IsEnforcementEnabled() { return GetParam(); }
1047
1048 private:
1049 base::test::ScopedFeatureList enforcement_feature_;
1050 };
1051
1052 // This test verifies that if a file has been passed to `PreventExecuteMapping`
1053 // and enforcement is enabled, then it cannot be mapped as executable into
1054 // memory.
TEST_P(FileUtilExecuteEnforcementTest,Functional)1055 TEST_P(FileUtilExecuteEnforcementTest, Functional) {
1056 FilePath dir_exe;
1057 EXPECT_TRUE(PathService::Get(DIR_EXE, &dir_exe));
1058 // This DLL is built as part of base_unittests so is guaranteed to be present.
1059 FilePath test_dll(dir_exe.Append(FPL("scoped_handle_test_dll.dll")));
1060
1061 EXPECT_TRUE(base::PathExists(test_dll));
1062
1063 FilePath dll_copy_path = temp_dir_.GetPath().Append(FPL("test.dll"));
1064
1065 ASSERT_TRUE(CopyFile(test_dll, dll_copy_path));
1066 ASSERT_TRUE(PreventExecuteMapping(dll_copy_path));
1067 ScopedNativeLibrary module(dll_copy_path);
1068
1069 // If enforcement is enabled, then `PreventExecuteMapping` will have prevented
1070 // the load, and the module will be invalid.
1071 EXPECT_EQ(IsEnforcementEnabled(), !module.is_valid());
1072 }
1073
1074 INSTANTIATE_TEST_SUITE_P(EnforcementEnabled,
1075 FileUtilExecuteEnforcementTest,
1076 ::testing::Values(true));
1077 INSTANTIATE_TEST_SUITE_P(EnforcementDisabled,
1078 FileUtilExecuteEnforcementTest,
1079 ::testing::Values(false));
1080
1081 #endif // BUILDFLAG(IS_WIN)
1082
1083 #if BUILDFLAG(IS_POSIX)
1084
TEST_F(FileUtilTest,CreateAndReadSymlinks)1085 TEST_F(FileUtilTest, CreateAndReadSymlinks) {
1086 FilePath link_from = temp_dir_.GetPath().Append(FPL("from_file"));
1087 FilePath link_to = temp_dir_.GetPath().Append(FPL("to_file"));
1088 CreateTextFile(link_to, bogus_content);
1089
1090 ASSERT_TRUE(CreateSymbolicLink(link_to, link_from))
1091 << "Failed to create file symlink.";
1092
1093 // If we created the link properly, we should be able to read the contents
1094 // through it.
1095 EXPECT_EQ(bogus_content, ReadTextFile(link_from));
1096
1097 FilePath result;
1098 ASSERT_TRUE(ReadSymbolicLink(link_from, &result));
1099 EXPECT_EQ(link_to.value(), result.value());
1100
1101 // Link to a directory.
1102 link_from = temp_dir_.GetPath().Append(FPL("from_dir"));
1103 link_to = temp_dir_.GetPath().Append(FPL("to_dir"));
1104 ASSERT_TRUE(CreateDirectory(link_to));
1105 ASSERT_TRUE(CreateSymbolicLink(link_to, link_from))
1106 << "Failed to create directory symlink.";
1107
1108 // Test failures.
1109 EXPECT_FALSE(CreateSymbolicLink(link_to, link_to));
1110 EXPECT_FALSE(ReadSymbolicLink(link_to, &result));
1111 FilePath missing = temp_dir_.GetPath().Append(FPL("missing"));
1112 EXPECT_FALSE(ReadSymbolicLink(missing, &result));
1113 }
1114
TEST_F(FileUtilTest,CreateAndReadRelativeSymlinks)1115 TEST_F(FileUtilTest, CreateAndReadRelativeSymlinks) {
1116 FilePath link_from = temp_dir_.GetPath().Append(FPL("from_file"));
1117 FilePath filename_link_to("to_file");
1118 FilePath link_to = temp_dir_.GetPath().Append(filename_link_to);
1119 FilePath link_from_in_subdir =
1120 temp_dir_.GetPath().Append(FPL("subdir")).Append(FPL("from_file"));
1121 FilePath link_to_in_subdir = FilePath(FPL("..")).Append(filename_link_to);
1122 CreateTextFile(link_to, bogus_content);
1123
1124 ASSERT_TRUE(CreateDirectory(link_from_in_subdir.DirName()));
1125 ASSERT_TRUE(CreateSymbolicLink(link_to_in_subdir, link_from_in_subdir));
1126
1127 ASSERT_TRUE(CreateSymbolicLink(filename_link_to, link_from))
1128 << "Failed to create file symlink.";
1129
1130 // If we created the link properly, we should be able to read the contents
1131 // through it.
1132 EXPECT_EQ(bogus_content, ReadTextFile(link_from));
1133 EXPECT_EQ(bogus_content, ReadTextFile(link_from_in_subdir));
1134
1135 FilePath result;
1136 ASSERT_TRUE(ReadSymbolicLink(link_from, &result));
1137 EXPECT_EQ(filename_link_to.value(), result.value());
1138
1139 std::optional<FilePath> absolute_link = ReadSymbolicLinkAbsolute(link_from);
1140 ASSERT_TRUE(absolute_link);
1141 EXPECT_EQ(link_to.value(), absolute_link->value());
1142
1143 absolute_link = ReadSymbolicLinkAbsolute(link_from_in_subdir);
1144 ASSERT_TRUE(absolute_link);
1145 EXPECT_EQ(link_to.value(), absolute_link->value());
1146
1147 // Link to a directory.
1148 link_from = temp_dir_.GetPath().Append(FPL("from_dir"));
1149 filename_link_to = FilePath("to_dir");
1150 link_to = temp_dir_.GetPath().Append(filename_link_to);
1151 ASSERT_TRUE(CreateDirectory(link_to));
1152 ASSERT_TRUE(CreateSymbolicLink(filename_link_to, link_from))
1153 << "Failed to create relative directory symlink.";
1154
1155 ASSERT_TRUE(ReadSymbolicLink(link_from, &result));
1156 EXPECT_EQ(filename_link_to.value(), result.value());
1157
1158 absolute_link = ReadSymbolicLinkAbsolute(link_from);
1159 ASSERT_TRUE(absolute_link);
1160 EXPECT_EQ(link_to.value(), absolute_link->value());
1161
1162 // Test failures.
1163 EXPECT_FALSE(CreateSymbolicLink(link_to, link_to));
1164 EXPECT_FALSE(ReadSymbolicLink(link_to, &result));
1165 }
1166
1167 // The following test of NormalizeFilePath() require that we create a symlink.
1168 // This can not be done on Windows before Vista. On Vista, creating a symlink
1169 // requires privilege "SeCreateSymbolicLinkPrivilege".
1170 // TODO(skerner): Investigate the possibility of giving base_unittests the
1171 // privileges required to create a symlink.
TEST_F(FileUtilTest,NormalizeFilePathSymlinks)1172 TEST_F(FileUtilTest, NormalizeFilePathSymlinks) {
1173 // Link one file to another.
1174 FilePath link_from = temp_dir_.GetPath().Append(FPL("from_file"));
1175 FilePath link_to = temp_dir_.GetPath().Append(FPL("to_file"));
1176 CreateTextFile(link_to, bogus_content);
1177
1178 ASSERT_TRUE(CreateSymbolicLink(link_to, link_from))
1179 << "Failed to create file symlink.";
1180
1181 // Check that NormalizeFilePath sees the link.
1182 FilePath normalized_path;
1183 ASSERT_TRUE(NormalizeFilePath(link_from, &normalized_path));
1184 EXPECT_NE(link_from, link_to);
1185 EXPECT_EQ(link_to.BaseName().value(), normalized_path.BaseName().value());
1186 EXPECT_EQ(link_to.BaseName().value(), normalized_path.BaseName().value());
1187
1188 // Link to a directory.
1189 link_from = temp_dir_.GetPath().Append(FPL("from_dir"));
1190 link_to = temp_dir_.GetPath().Append(FPL("to_dir"));
1191 ASSERT_TRUE(CreateDirectory(link_to));
1192 ASSERT_TRUE(CreateSymbolicLink(link_to, link_from))
1193 << "Failed to create directory symlink.";
1194
1195 EXPECT_FALSE(NormalizeFilePath(link_from, &normalized_path))
1196 << "Links to directories should return false.";
1197
1198 // Test that a loop in the links causes NormalizeFilePath() to return false.
1199 link_from = temp_dir_.GetPath().Append(FPL("link_a"));
1200 link_to = temp_dir_.GetPath().Append(FPL("link_b"));
1201 ASSERT_TRUE(CreateSymbolicLink(link_to, link_from))
1202 << "Failed to create loop symlink a.";
1203 ASSERT_TRUE(CreateSymbolicLink(link_from, link_to))
1204 << "Failed to create loop symlink b.";
1205
1206 // Infinite loop!
1207 EXPECT_FALSE(NormalizeFilePath(link_from, &normalized_path));
1208 }
1209
TEST_F(FileUtilTest,DeleteSymlinkToExistentFile)1210 TEST_F(FileUtilTest, DeleteSymlinkToExistentFile) {
1211 // Create a file.
1212 FilePath file_name = temp_dir_.GetPath().Append(FPL("Test DeleteFile 2.txt"));
1213 CreateTextFile(file_name, bogus_content);
1214 ASSERT_TRUE(PathExists(file_name));
1215
1216 // Create a symlink to the file.
1217 FilePath file_link = temp_dir_.GetPath().Append("file_link_2");
1218 ASSERT_TRUE(CreateSymbolicLink(file_name, file_link))
1219 << "Failed to create symlink.";
1220
1221 // Delete the symbolic link.
1222 EXPECT_TRUE(DeleteFile(file_link));
1223
1224 // Make sure original file is not deleted.
1225 EXPECT_FALSE(PathExists(file_link));
1226 EXPECT_TRUE(PathExists(file_name));
1227 }
1228
TEST_F(FileUtilTest,DeleteSymlinkToNonExistentFile)1229 TEST_F(FileUtilTest, DeleteSymlinkToNonExistentFile) {
1230 // Create a non-existent file path.
1231 FilePath non_existent =
1232 temp_dir_.GetPath().Append(FPL("Test DeleteFile 3.txt"));
1233 EXPECT_FALSE(PathExists(non_existent));
1234
1235 // Create a symlink to the non-existent file.
1236 FilePath file_link = temp_dir_.GetPath().Append("file_link_3");
1237 ASSERT_TRUE(CreateSymbolicLink(non_existent, file_link))
1238 << "Failed to create symlink.";
1239
1240 // Make sure the symbolic link is exist.
1241 EXPECT_TRUE(IsLink(file_link));
1242 EXPECT_FALSE(PathExists(file_link));
1243
1244 // Delete the symbolic link.
1245 EXPECT_TRUE(DeleteFile(file_link));
1246
1247 // Make sure the symbolic link is deleted.
1248 EXPECT_FALSE(IsLink(file_link));
1249 }
1250
TEST_F(FileUtilTest,CopyFileFollowsSymlinks)1251 TEST_F(FileUtilTest, CopyFileFollowsSymlinks) {
1252 FilePath link_from = temp_dir_.GetPath().Append(FPL("from_file"));
1253 FilePath link_to = temp_dir_.GetPath().Append(FPL("to_file"));
1254 CreateTextFile(link_to, bogus_content);
1255
1256 ASSERT_TRUE(CreateSymbolicLink(link_to, link_from));
1257
1258 // If we created the link properly, we should be able to read the contents
1259 // through it.
1260 EXPECT_EQ(bogus_content, ReadTextFile(link_from));
1261
1262 FilePath result;
1263 ASSERT_TRUE(ReadSymbolicLink(link_from, &result));
1264 EXPECT_EQ(link_to.value(), result.value());
1265
1266 // Create another file and copy it to |link_from|.
1267 FilePath src_file = temp_dir_.GetPath().Append(FPL("src.txt"));
1268 const std::wstring file_contents(L"Gooooooooooooooooooooogle");
1269 CreateTextFile(src_file, file_contents);
1270 ASSERT_TRUE(CopyFile(src_file, link_from));
1271
1272 // Make sure |link_from| is still a symlink, and |link_to| has been written to
1273 // by CopyFile().
1274 EXPECT_TRUE(IsLink(link_from));
1275 EXPECT_EQ(file_contents, ReadTextFile(link_from));
1276 EXPECT_EQ(file_contents, ReadTextFile(link_to));
1277 }
1278
TEST_F(FileUtilTest,ChangeFilePermissionsAndRead)1279 TEST_F(FileUtilTest, ChangeFilePermissionsAndRead) {
1280 // Create a file path.
1281 FilePath file_name =
1282 temp_dir_.GetPath().Append(FPL("Test Readable File.txt"));
1283 EXPECT_FALSE(PathExists(file_name));
1284 EXPECT_FALSE(PathIsReadable(file_name));
1285
1286 static constexpr char kData[] = "hello";
1287 static constexpr int kDataSize = sizeof(kData) - 1;
1288 char buffer[kDataSize];
1289
1290 // Write file.
1291 EXPECT_TRUE(WriteFile(file_name, kData));
1292 EXPECT_TRUE(PathExists(file_name));
1293
1294 // Make sure the file is readable.
1295 int32_t mode = 0;
1296 EXPECT_TRUE(GetPosixFilePermissions(file_name, &mode));
1297 EXPECT_TRUE(mode & FILE_PERMISSION_READ_BY_USER);
1298 EXPECT_TRUE(PathIsReadable(file_name));
1299
1300 // Get rid of the read permission.
1301 EXPECT_TRUE(SetPosixFilePermissions(file_name, 0u));
1302 EXPECT_TRUE(GetPosixFilePermissions(file_name, &mode));
1303 EXPECT_FALSE(mode & FILE_PERMISSION_READ_BY_USER);
1304 EXPECT_FALSE(PathIsReadable(file_name));
1305 // Make sure the file can't be read.
1306 EXPECT_EQ(ReadFile(file_name, buffer), std::nullopt);
1307
1308 // Give the read permission.
1309 EXPECT_TRUE(SetPosixFilePermissions(file_name, FILE_PERMISSION_READ_BY_USER));
1310 EXPECT_TRUE(GetPosixFilePermissions(file_name, &mode));
1311 EXPECT_TRUE(mode & FILE_PERMISSION_READ_BY_USER);
1312 EXPECT_TRUE(PathIsReadable(file_name));
1313 // Make sure the file can be read.
1314 EXPECT_EQ(ReadFile(file_name, buffer), kDataSize);
1315
1316 // Delete the file.
1317 EXPECT_TRUE(DeleteFile(file_name));
1318 EXPECT_FALSE(PathExists(file_name));
1319 }
1320
TEST_F(FileUtilTest,ChangeFilePermissionsAndWrite)1321 TEST_F(FileUtilTest, ChangeFilePermissionsAndWrite) {
1322 // Create a file path.
1323 FilePath file_name =
1324 temp_dir_.GetPath().Append(FPL("Test Readable File.txt"));
1325 EXPECT_FALSE(PathExists(file_name));
1326
1327 const std::string kData("hello");
1328
1329 // Write file.
1330 EXPECT_TRUE(WriteFile(file_name, kData));
1331 EXPECT_TRUE(PathExists(file_name));
1332
1333 // Make sure the file is writable.
1334 int mode = 0;
1335 EXPECT_TRUE(GetPosixFilePermissions(file_name, &mode));
1336 EXPECT_TRUE(mode & FILE_PERMISSION_WRITE_BY_USER);
1337 EXPECT_TRUE(PathIsWritable(file_name));
1338
1339 // Get rid of the write permission.
1340 EXPECT_TRUE(SetPosixFilePermissions(file_name, 0u));
1341 EXPECT_TRUE(GetPosixFilePermissions(file_name, &mode));
1342 EXPECT_FALSE(mode & FILE_PERMISSION_WRITE_BY_USER);
1343 // Make sure the file can't be write.
1344 EXPECT_FALSE(WriteFile(file_name, kData));
1345 EXPECT_FALSE(PathIsWritable(file_name));
1346
1347 // Give read permission.
1348 EXPECT_TRUE(SetPosixFilePermissions(file_name,
1349 FILE_PERMISSION_WRITE_BY_USER));
1350 EXPECT_TRUE(GetPosixFilePermissions(file_name, &mode));
1351 EXPECT_TRUE(mode & FILE_PERMISSION_WRITE_BY_USER);
1352 // Make sure the file can be write.
1353 EXPECT_TRUE(WriteFile(file_name, kData));
1354 EXPECT_TRUE(PathIsWritable(file_name));
1355
1356 // Delete the file.
1357 EXPECT_TRUE(DeleteFile(file_name));
1358 EXPECT_FALSE(PathExists(file_name));
1359 }
1360
TEST_F(FileUtilTest,ChangeDirectoryPermissionsAndEnumerate)1361 TEST_F(FileUtilTest, ChangeDirectoryPermissionsAndEnumerate) {
1362 // Create a directory path.
1363 FilePath subdir_path = temp_dir_.GetPath().Append(FPL("PermissionTest1"));
1364 CreateDirectory(subdir_path);
1365 ASSERT_TRUE(PathExists(subdir_path));
1366
1367 // Create a dummy file to enumerate.
1368 FilePath file_name = subdir_path.Append(FPL("Test Readable File.txt"));
1369 EXPECT_FALSE(PathExists(file_name));
1370 const std::string kData("hello");
1371 EXPECT_TRUE(WriteFile(file_name, kData));
1372 EXPECT_TRUE(PathExists(file_name));
1373
1374 // Make sure the directory has the all permissions.
1375 int mode = 0;
1376 EXPECT_TRUE(GetPosixFilePermissions(subdir_path, &mode));
1377 EXPECT_EQ(FILE_PERMISSION_USER_MASK, mode & FILE_PERMISSION_USER_MASK);
1378
1379 // Get rid of the permissions from the directory.
1380 EXPECT_TRUE(SetPosixFilePermissions(subdir_path, 0u));
1381 EXPECT_TRUE(GetPosixFilePermissions(subdir_path, &mode));
1382 EXPECT_FALSE(mode & FILE_PERMISSION_USER_MASK);
1383
1384 // Make sure the file in the directory can't be enumerated.
1385 FileEnumerator f1(subdir_path, true, FileEnumerator::FILES);
1386 EXPECT_TRUE(PathExists(subdir_path));
1387 FindResultCollector c1(&f1);
1388 EXPECT_EQ(0, c1.size());
1389 EXPECT_FALSE(GetPosixFilePermissions(file_name, &mode));
1390
1391 // Give the permissions to the directory.
1392 EXPECT_TRUE(SetPosixFilePermissions(subdir_path, FILE_PERMISSION_USER_MASK));
1393 EXPECT_TRUE(GetPosixFilePermissions(subdir_path, &mode));
1394 EXPECT_EQ(FILE_PERMISSION_USER_MASK, mode & FILE_PERMISSION_USER_MASK);
1395
1396 // Make sure the file in the directory can be enumerated.
1397 FileEnumerator f2(subdir_path, true, FileEnumerator::FILES);
1398 FindResultCollector c2(&f2);
1399 EXPECT_TRUE(c2.HasFile(file_name));
1400 EXPECT_EQ(1, c2.size());
1401
1402 // Delete the file.
1403 EXPECT_TRUE(DeletePathRecursively(subdir_path));
1404 EXPECT_FALSE(PathExists(subdir_path));
1405 }
1406
TEST_F(FileUtilTest,ExecutableExistsInPath)1407 TEST_F(FileUtilTest, ExecutableExistsInPath) {
1408 // Create two directories that we will put in our PATH
1409 const FilePath::CharType kDir1[] = FPL("dir1");
1410 const FilePath::CharType kDir2[] = FPL("dir2");
1411
1412 FilePath dir1 = temp_dir_.GetPath().Append(kDir1);
1413 FilePath dir2 = temp_dir_.GetPath().Append(kDir2);
1414 ASSERT_TRUE(CreateDirectory(dir1));
1415 ASSERT_TRUE(CreateDirectory(dir2));
1416
1417 ScopedEnvironmentVariableOverride scoped_env(
1418 "PATH", dir1.value() + ":" + dir2.value());
1419 ASSERT_TRUE(scoped_env.IsOverridden());
1420
1421 const FilePath::CharType kRegularFileName[] = FPL("regular_file");
1422 const FilePath::CharType kExeFileName[] = FPL("exe");
1423 const FilePath::CharType kDneFileName[] = FPL("does_not_exist");
1424
1425 const FilePath kExePath = dir1.Append(kExeFileName);
1426 const FilePath kRegularFilePath = dir2.Append(kRegularFileName);
1427
1428 // Write file.
1429 const std::string kData("hello");
1430 ASSERT_TRUE(WriteFile(kExePath, kData));
1431 ASSERT_TRUE(PathExists(kExePath));
1432 ASSERT_TRUE(WriteFile(kRegularFilePath, kData));
1433 ASSERT_TRUE(PathExists(kRegularFilePath));
1434
1435 ASSERT_TRUE(SetPosixFilePermissions(dir1.Append(kExeFileName),
1436 FILE_PERMISSION_EXECUTE_BY_USER));
1437
1438 EXPECT_TRUE(ExecutableExistsInPath(scoped_env.GetEnv(), kExeFileName));
1439 EXPECT_FALSE(ExecutableExistsInPath(scoped_env.GetEnv(), kRegularFileName));
1440 EXPECT_FALSE(ExecutableExistsInPath(scoped_env.GetEnv(), kDneFileName));
1441 }
1442
TEST_F(FileUtilTest,CopyDirectoryPermissions)1443 TEST_F(FileUtilTest, CopyDirectoryPermissions) {
1444 // Create a directory.
1445 FilePath dir_name_from =
1446 temp_dir_.GetPath().Append(FILE_PATH_LITERAL("Copy_From_Subdir"));
1447 CreateDirectory(dir_name_from);
1448 ASSERT_TRUE(PathExists(dir_name_from));
1449
1450 // Create some regular files under the directory with various permissions.
1451 FilePath file_name_from =
1452 dir_name_from.Append(FILE_PATH_LITERAL("Reggy-1.txt"));
1453 CreateTextFile(file_name_from, L"Mordecai");
1454 ASSERT_TRUE(PathExists(file_name_from));
1455 ASSERT_TRUE(SetPosixFilePermissions(file_name_from, 0755));
1456
1457 FilePath file2_name_from =
1458 dir_name_from.Append(FILE_PATH_LITERAL("Reggy-2.txt"));
1459 CreateTextFile(file2_name_from, L"Rigby");
1460 ASSERT_TRUE(PathExists(file2_name_from));
1461 ASSERT_TRUE(SetPosixFilePermissions(file2_name_from, 0777));
1462
1463 FilePath file3_name_from =
1464 dir_name_from.Append(FILE_PATH_LITERAL("Reggy-3.txt"));
1465 CreateTextFile(file3_name_from, L"Benson");
1466 ASSERT_TRUE(PathExists(file3_name_from));
1467 ASSERT_TRUE(SetPosixFilePermissions(file3_name_from, 0400));
1468
1469 // Copy the directory recursively.
1470 FilePath dir_name_to =
1471 temp_dir_.GetPath().Append(FILE_PATH_LITERAL("Copy_To_Subdir"));
1472 FilePath file_name_to =
1473 dir_name_to.Append(FILE_PATH_LITERAL("Reggy-1.txt"));
1474 FilePath file2_name_to =
1475 dir_name_to.Append(FILE_PATH_LITERAL("Reggy-2.txt"));
1476 FilePath file3_name_to =
1477 dir_name_to.Append(FILE_PATH_LITERAL("Reggy-3.txt"));
1478
1479 ASSERT_FALSE(PathExists(dir_name_to));
1480
1481 EXPECT_TRUE(CopyDirectory(dir_name_from, dir_name_to, true));
1482 ASSERT_TRUE(PathExists(file_name_to));
1483 ASSERT_TRUE(PathExists(file2_name_to));
1484 ASSERT_TRUE(PathExists(file3_name_to));
1485
1486 int mode = 0;
1487 int expected_mode;
1488 ASSERT_TRUE(GetPosixFilePermissions(file_name_to, &mode));
1489 #if BUILDFLAG(IS_APPLE)
1490 expected_mode = 0755;
1491 #elif BUILDFLAG(IS_CHROMEOS)
1492 expected_mode = 0644;
1493 #else
1494 expected_mode = 0600;
1495 #endif
1496 EXPECT_EQ(expected_mode, mode);
1497
1498 ASSERT_TRUE(GetPosixFilePermissions(file2_name_to, &mode));
1499 #if BUILDFLAG(IS_APPLE)
1500 expected_mode = 0755;
1501 #elif BUILDFLAG(IS_CHROMEOS)
1502 expected_mode = 0644;
1503 #else
1504 expected_mode = 0600;
1505 #endif
1506 EXPECT_EQ(expected_mode, mode);
1507
1508 ASSERT_TRUE(GetPosixFilePermissions(file3_name_to, &mode));
1509 #if BUILDFLAG(IS_APPLE)
1510 expected_mode = 0600;
1511 #elif BUILDFLAG(IS_CHROMEOS)
1512 expected_mode = 0644;
1513 #else
1514 expected_mode = 0600;
1515 #endif
1516 EXPECT_EQ(expected_mode, mode);
1517 }
1518
TEST_F(FileUtilTest,CopyDirectoryPermissionsOverExistingFile)1519 TEST_F(FileUtilTest, CopyDirectoryPermissionsOverExistingFile) {
1520 // Create a directory.
1521 FilePath dir_name_from =
1522 temp_dir_.GetPath().Append(FILE_PATH_LITERAL("Copy_From_Subdir"));
1523 CreateDirectory(dir_name_from);
1524 ASSERT_TRUE(PathExists(dir_name_from));
1525
1526 // Create a file under the directory.
1527 FilePath file_name_from =
1528 dir_name_from.Append(FILE_PATH_LITERAL("Reggy-1.txt"));
1529 CreateTextFile(file_name_from, L"Mordecai");
1530 ASSERT_TRUE(PathExists(file_name_from));
1531 ASSERT_TRUE(SetPosixFilePermissions(file_name_from, 0644));
1532
1533 // Create a directory.
1534 FilePath dir_name_to =
1535 temp_dir_.GetPath().Append(FILE_PATH_LITERAL("Copy_To_Subdir"));
1536 CreateDirectory(dir_name_to);
1537 ASSERT_TRUE(PathExists(dir_name_to));
1538
1539 // Create a file under the directory with wider permissions.
1540 FilePath file_name_to =
1541 dir_name_to.Append(FILE_PATH_LITERAL("Reggy-1.txt"));
1542 CreateTextFile(file_name_to, L"Rigby");
1543 ASSERT_TRUE(PathExists(file_name_to));
1544 ASSERT_TRUE(SetPosixFilePermissions(file_name_to, 0777));
1545
1546 // Ensure that when we copy the directory, the file contents are copied
1547 // but the permissions on the destination are left alone.
1548 EXPECT_TRUE(CopyDirectory(dir_name_from, dir_name_to, false));
1549 ASSERT_TRUE(PathExists(file_name_to));
1550 ASSERT_EQ(L"Mordecai", ReadTextFile(file_name_to));
1551
1552 int mode = 0;
1553 ASSERT_TRUE(GetPosixFilePermissions(file_name_to, &mode));
1554 EXPECT_EQ(0777, mode);
1555 }
1556
TEST_F(FileUtilTest,CopyDirectoryExclDoesNotOverwrite)1557 TEST_F(FileUtilTest, CopyDirectoryExclDoesNotOverwrite) {
1558 // Create source directory.
1559 FilePath dir_name_from =
1560 temp_dir_.GetPath().Append(FILE_PATH_LITERAL("Copy_From_Subdir"));
1561 CreateDirectory(dir_name_from);
1562 ASSERT_TRUE(PathExists(dir_name_from));
1563
1564 // Create a file under the directory.
1565 FilePath file_name_from =
1566 dir_name_from.Append(FILE_PATH_LITERAL("Reggy-1.txt"));
1567 CreateTextFile(file_name_from, L"Mordecai");
1568 ASSERT_TRUE(PathExists(file_name_from));
1569
1570 // Create destination directory.
1571 FilePath dir_name_to =
1572 temp_dir_.GetPath().Append(FILE_PATH_LITERAL("Copy_To_Subdir"));
1573 CreateDirectory(dir_name_to);
1574 ASSERT_TRUE(PathExists(dir_name_to));
1575
1576 // Create a file under the directory with the same name.
1577 FilePath file_name_to = dir_name_to.Append(FILE_PATH_LITERAL("Reggy-1.txt"));
1578 CreateTextFile(file_name_to, L"Rigby");
1579 ASSERT_TRUE(PathExists(file_name_to));
1580
1581 // Ensure that copying failed and the file was not overwritten.
1582 EXPECT_FALSE(CopyDirectoryExcl(dir_name_from, dir_name_to, false));
1583 ASSERT_TRUE(PathExists(file_name_to));
1584 ASSERT_EQ(L"Rigby", ReadTextFile(file_name_to));
1585 }
1586
TEST_F(FileUtilTest,CopyDirectoryExclDirectoryOverExistingFile)1587 TEST_F(FileUtilTest, CopyDirectoryExclDirectoryOverExistingFile) {
1588 // Create source directory.
1589 FilePath dir_name_from =
1590 temp_dir_.GetPath().Append(FILE_PATH_LITERAL("Copy_From_Subdir"));
1591 CreateDirectory(dir_name_from);
1592 ASSERT_TRUE(PathExists(dir_name_from));
1593
1594 // Create a subdirectory.
1595 FilePath subdir_name_from = dir_name_from.Append(FILE_PATH_LITERAL("Subsub"));
1596 CreateDirectory(subdir_name_from);
1597 ASSERT_TRUE(PathExists(subdir_name_from));
1598
1599 // Create destination directory.
1600 FilePath dir_name_to =
1601 temp_dir_.GetPath().Append(FILE_PATH_LITERAL("Copy_To_Subdir"));
1602 CreateDirectory(dir_name_to);
1603 ASSERT_TRUE(PathExists(dir_name_to));
1604
1605 // Create a regular file under the directory with the same name.
1606 FilePath file_name_to = dir_name_to.Append(FILE_PATH_LITERAL("Subsub"));
1607 CreateTextFile(file_name_to, L"Rigby");
1608 ASSERT_TRUE(PathExists(file_name_to));
1609
1610 // Ensure that copying failed and the file was not overwritten.
1611 EXPECT_FALSE(CopyDirectoryExcl(dir_name_from, dir_name_to, false));
1612 ASSERT_TRUE(PathExists(file_name_to));
1613 ASSERT_EQ(L"Rigby", ReadTextFile(file_name_to));
1614 }
1615
TEST_F(FileUtilTest,CopyDirectoryExclDirectoryOverExistingDirectory)1616 TEST_F(FileUtilTest, CopyDirectoryExclDirectoryOverExistingDirectory) {
1617 // Create source directory.
1618 FilePath dir_name_from =
1619 temp_dir_.GetPath().Append(FILE_PATH_LITERAL("Copy_From_Subdir"));
1620 CreateDirectory(dir_name_from);
1621 ASSERT_TRUE(PathExists(dir_name_from));
1622
1623 // Create a subdirectory.
1624 FilePath subdir_name_from = dir_name_from.Append(FILE_PATH_LITERAL("Subsub"));
1625 CreateDirectory(subdir_name_from);
1626 ASSERT_TRUE(PathExists(subdir_name_from));
1627
1628 // Create destination directory.
1629 FilePath dir_name_to =
1630 temp_dir_.GetPath().Append(FILE_PATH_LITERAL("Copy_To_Subdir"));
1631 CreateDirectory(dir_name_to);
1632 ASSERT_TRUE(PathExists(dir_name_to));
1633
1634 // Create a subdirectory under the directory with the same name.
1635 FilePath subdir_name_to = dir_name_to.Append(FILE_PATH_LITERAL("Subsub"));
1636 CreateDirectory(subdir_name_to);
1637 ASSERT_TRUE(PathExists(subdir_name_to));
1638
1639 // Ensure that copying failed and the file was not overwritten.
1640 EXPECT_FALSE(CopyDirectoryExcl(dir_name_from, dir_name_to, false));
1641 }
1642
TEST_F(FileUtilTest,CopyFileExecutablePermission)1643 TEST_F(FileUtilTest, CopyFileExecutablePermission) {
1644 FilePath src = temp_dir_.GetPath().Append(FPL("src.txt"));
1645 const std::wstring file_contents(L"Gooooooooooooooooooooogle");
1646 CreateTextFile(src, file_contents);
1647
1648 ASSERT_TRUE(SetPosixFilePermissions(src, 0755));
1649 int mode = 0;
1650 ASSERT_TRUE(GetPosixFilePermissions(src, &mode));
1651 EXPECT_EQ(0755, mode);
1652
1653 FilePath dst = temp_dir_.GetPath().Append(FPL("dst.txt"));
1654 ASSERT_TRUE(CopyFile(src, dst));
1655 EXPECT_EQ(file_contents, ReadTextFile(dst));
1656
1657 ASSERT_TRUE(GetPosixFilePermissions(dst, &mode));
1658 int expected_mode;
1659 #if BUILDFLAG(IS_APPLE)
1660 expected_mode = 0755;
1661 #elif BUILDFLAG(IS_CHROMEOS)
1662 expected_mode = 0644;
1663 #else
1664 expected_mode = 0600;
1665 #endif
1666 EXPECT_EQ(expected_mode, mode);
1667 ASSERT_TRUE(DeleteFile(dst));
1668
1669 ASSERT_TRUE(SetPosixFilePermissions(src, 0777));
1670 ASSERT_TRUE(GetPosixFilePermissions(src, &mode));
1671 EXPECT_EQ(0777, mode);
1672
1673 ASSERT_TRUE(CopyFile(src, dst));
1674 EXPECT_EQ(file_contents, ReadTextFile(dst));
1675
1676 ASSERT_TRUE(GetPosixFilePermissions(dst, &mode));
1677 #if BUILDFLAG(IS_APPLE)
1678 expected_mode = 0755;
1679 #elif BUILDFLAG(IS_CHROMEOS)
1680 expected_mode = 0644;
1681 #else
1682 expected_mode = 0600;
1683 #endif
1684 EXPECT_EQ(expected_mode, mode);
1685 ASSERT_TRUE(DeleteFile(dst));
1686
1687 ASSERT_TRUE(SetPosixFilePermissions(src, 0400));
1688 ASSERT_TRUE(GetPosixFilePermissions(src, &mode));
1689 EXPECT_EQ(0400, mode);
1690
1691 ASSERT_TRUE(CopyFile(src, dst));
1692 EXPECT_EQ(file_contents, ReadTextFile(dst));
1693
1694 ASSERT_TRUE(GetPosixFilePermissions(dst, &mode));
1695 #if BUILDFLAG(IS_APPLE)
1696 expected_mode = 0600;
1697 #elif BUILDFLAG(IS_CHROMEOS)
1698 expected_mode = 0644;
1699 #else
1700 expected_mode = 0600;
1701 #endif
1702 EXPECT_EQ(expected_mode, mode);
1703
1704 // This time, do not delete |dst|. Instead set its permissions to 0777.
1705 ASSERT_TRUE(SetPosixFilePermissions(dst, 0777));
1706 ASSERT_TRUE(GetPosixFilePermissions(dst, &mode));
1707 EXPECT_EQ(0777, mode);
1708
1709 // Overwrite it and check the permissions again.
1710 ASSERT_TRUE(CopyFile(src, dst));
1711 EXPECT_EQ(file_contents, ReadTextFile(dst));
1712 ASSERT_TRUE(GetPosixFilePermissions(dst, &mode));
1713 EXPECT_EQ(0777, mode);
1714 }
1715
1716 #endif // BUILDFLAG(IS_POSIX)
1717
1718 #if !BUILDFLAG(IS_FUCHSIA)
1719
TEST_F(FileUtilTest,CopyFileACL)1720 TEST_F(FileUtilTest, CopyFileACL) {
1721 // While FileUtilTest.CopyFile asserts the content is correctly copied over,
1722 // this test case asserts the access control bits are meeting expectations in
1723 // CopyFile().
1724 FilePath src = temp_dir_.GetPath().Append(FILE_PATH_LITERAL("src.txt"));
1725 const std::wstring file_contents(L"Gooooooooooooooooooooogle");
1726 CreateTextFile(src, file_contents);
1727
1728 // Set the source file to read-only.
1729 ASSERT_FALSE(IsReadOnly(src));
1730 SetReadOnly(src, true);
1731 ASSERT_TRUE(IsReadOnly(src));
1732
1733 // Copy the file.
1734 FilePath dst = temp_dir_.GetPath().Append(FILE_PATH_LITERAL("dst.txt"));
1735 ASSERT_TRUE(CopyFile(src, dst));
1736 EXPECT_EQ(file_contents, ReadTextFile(dst));
1737
1738 ASSERT_FALSE(IsReadOnly(dst));
1739 }
1740
TEST_F(FileUtilTest,CopyDirectoryACL)1741 TEST_F(FileUtilTest, CopyDirectoryACL) {
1742 // Create source directories.
1743 FilePath src = temp_dir_.GetPath().Append(FILE_PATH_LITERAL("src"));
1744 FilePath src_subdir = src.Append(FILE_PATH_LITERAL("subdir"));
1745 CreateDirectory(src_subdir);
1746 ASSERT_TRUE(PathExists(src_subdir));
1747
1748 // Create a file under the directory.
1749 FilePath src_file = src.Append(FILE_PATH_LITERAL("src.txt"));
1750 CreateTextFile(src_file, L"Gooooooooooooooooooooogle");
1751 SetReadOnly(src_file, true);
1752 ASSERT_TRUE(IsReadOnly(src_file));
1753
1754 // Make directory read-only.
1755 SetReadOnly(src_subdir, true);
1756 ASSERT_TRUE(IsReadOnly(src_subdir));
1757
1758 // Copy the directory recursively.
1759 FilePath dst = temp_dir_.GetPath().Append(FILE_PATH_LITERAL("dst"));
1760 FilePath dst_file = dst.Append(FILE_PATH_LITERAL("src.txt"));
1761 EXPECT_TRUE(CopyDirectory(src, dst, true));
1762
1763 FilePath dst_subdir = dst.Append(FILE_PATH_LITERAL("subdir"));
1764 ASSERT_FALSE(IsReadOnly(dst_subdir));
1765 ASSERT_FALSE(IsReadOnly(dst_file));
1766
1767 // Give write permissions to allow deletion.
1768 SetReadOnly(src_subdir, false);
1769 ASSERT_FALSE(IsReadOnly(src_subdir));
1770 }
1771
1772 #endif // !BUILDFLAG(IS_FUCHSIA)
1773
TEST_F(FileUtilTest,DeleteNonExistent)1774 TEST_F(FileUtilTest, DeleteNonExistent) {
1775 FilePath non_existent =
1776 temp_dir_.GetPath().AppendASCII("bogus_file_dne.foobar");
1777 ASSERT_FALSE(PathExists(non_existent));
1778
1779 EXPECT_TRUE(DeleteFile(non_existent));
1780 ASSERT_FALSE(PathExists(non_existent));
1781 EXPECT_TRUE(DeletePathRecursively(non_existent));
1782 ASSERT_FALSE(PathExists(non_existent));
1783 }
1784
TEST_F(FileUtilTest,DeleteNonExistentWithNonExistentParent)1785 TEST_F(FileUtilTest, DeleteNonExistentWithNonExistentParent) {
1786 FilePath non_existent = temp_dir_.GetPath().AppendASCII("bogus_topdir");
1787 non_existent = non_existent.AppendASCII("bogus_subdir");
1788 ASSERT_FALSE(PathExists(non_existent));
1789
1790 EXPECT_TRUE(DeleteFile(non_existent));
1791 ASSERT_FALSE(PathExists(non_existent));
1792 EXPECT_TRUE(DeletePathRecursively(non_existent));
1793 ASSERT_FALSE(PathExists(non_existent));
1794 }
1795
TEST_F(FileUtilTest,DeleteFile)1796 TEST_F(FileUtilTest, DeleteFile) {
1797 // Create a file
1798 FilePath file_name = temp_dir_.GetPath().Append(FPL("Test DeleteFile 1.txt"));
1799 CreateTextFile(file_name, bogus_content);
1800 ASSERT_TRUE(PathExists(file_name));
1801
1802 // Make sure it's deleted
1803 EXPECT_TRUE(DeleteFile(file_name));
1804 EXPECT_FALSE(PathExists(file_name));
1805
1806 // Test recursive case, create a new file
1807 file_name = temp_dir_.GetPath().Append(FPL("Test DeleteFile 2.txt"));
1808 CreateTextFile(file_name, bogus_content);
1809 ASSERT_TRUE(PathExists(file_name));
1810
1811 // Make sure it's deleted
1812 EXPECT_TRUE(DeletePathRecursively(file_name));
1813 EXPECT_FALSE(PathExists(file_name));
1814 }
1815
1816 #if BUILDFLAG(IS_ANDROID)
TEST_F(FileUtilTest,DeleteContentUri)1817 TEST_F(FileUtilTest, DeleteContentUri) {
1818 // Get the path to the test file.
1819 FilePath data_dir;
1820 ASSERT_TRUE(PathService::Get(DIR_TEST_DATA, &data_dir));
1821 data_dir = data_dir.Append(FPL("file_util"));
1822 ASSERT_TRUE(PathExists(data_dir));
1823 FilePath image_file = data_dir.Append(FPL("red.png"));
1824 ASSERT_TRUE(PathExists(image_file));
1825
1826 // Make a copy (we don't want to delete the original red.png when deleting the
1827 // content URI).
1828 FilePath image_copy = data_dir.Append(FPL("redcopy.png"));
1829 ASSERT_TRUE(CopyFile(image_file, image_copy));
1830
1831 // Insert the image into MediaStore and get a content URI.
1832 FilePath uri_path = InsertImageIntoMediaStore(image_copy);
1833 ASSERT_TRUE(uri_path.IsContentUri());
1834 ASSERT_TRUE(PathExists(uri_path));
1835
1836 // Try deleting the content URI.
1837 EXPECT_TRUE(DeleteFile(uri_path));
1838 EXPECT_FALSE(PathExists(image_copy));
1839 EXPECT_FALSE(PathExists(uri_path));
1840 }
1841 #endif // BUILDFLAG(IS_ANDROID)
1842
1843 #if BUILDFLAG(IS_WIN)
1844 // Tests that the Delete function works for wild cards, especially
1845 // with the recursion flag. Also coincidentally tests PathExists.
1846 // TODO(erikkay): see if anyone's actually using this feature of the API
TEST_F(FileUtilTest,DeleteWildCard)1847 TEST_F(FileUtilTest, DeleteWildCard) {
1848 // Create a file and a directory
1849 FilePath file_name =
1850 temp_dir_.GetPath().Append(FPL("Test DeleteWildCard.txt"));
1851 CreateTextFile(file_name, bogus_content);
1852 ASSERT_TRUE(PathExists(file_name));
1853
1854 FilePath subdir_path = temp_dir_.GetPath().Append(FPL("DeleteWildCardDir"));
1855 CreateDirectory(subdir_path);
1856 ASSERT_TRUE(PathExists(subdir_path));
1857
1858 // Create the wildcard path
1859 FilePath directory_contents = temp_dir_.GetPath();
1860 directory_contents = directory_contents.Append(FPL("*"));
1861
1862 // Delete non-recursively and check that only the file is deleted
1863 EXPECT_TRUE(DeleteFile(directory_contents));
1864 EXPECT_FALSE(PathExists(file_name));
1865 EXPECT_TRUE(PathExists(subdir_path));
1866
1867 // Delete recursively and make sure all contents are deleted
1868 EXPECT_TRUE(DeletePathRecursively(directory_contents));
1869 EXPECT_FALSE(PathExists(file_name));
1870 EXPECT_FALSE(PathExists(subdir_path));
1871 }
1872
1873 // TODO(erikkay): see if anyone's actually using this feature of the API
TEST_F(FileUtilTest,DeleteNonExistantWildCard)1874 TEST_F(FileUtilTest, DeleteNonExistantWildCard) {
1875 // Create a file and a directory
1876 FilePath subdir_path =
1877 temp_dir_.GetPath().Append(FPL("DeleteNonExistantWildCard"));
1878 CreateDirectory(subdir_path);
1879 ASSERT_TRUE(PathExists(subdir_path));
1880
1881 // Create the wildcard path
1882 FilePath directory_contents = subdir_path;
1883 directory_contents = directory_contents.Append(FPL("*"));
1884
1885 // Delete non-recursively and check nothing got deleted
1886 EXPECT_TRUE(DeleteFile(directory_contents));
1887 EXPECT_TRUE(PathExists(subdir_path));
1888
1889 // Delete recursively and check nothing got deleted
1890 EXPECT_TRUE(DeletePathRecursively(directory_contents));
1891 EXPECT_TRUE(PathExists(subdir_path));
1892 }
1893 #endif
1894
1895 // Tests non-recursive Delete() for a directory.
TEST_F(FileUtilTest,DeleteDirNonRecursive)1896 TEST_F(FileUtilTest, DeleteDirNonRecursive) {
1897 // Create a subdirectory and put a file and two directories inside.
1898 FilePath test_subdir =
1899 temp_dir_.GetPath().Append(FPL("DeleteDirNonRecursive"));
1900 CreateDirectory(test_subdir);
1901 ASSERT_TRUE(PathExists(test_subdir));
1902
1903 FilePath file_name = test_subdir.Append(FPL("Test DeleteDir.txt"));
1904 CreateTextFile(file_name, bogus_content);
1905 ASSERT_TRUE(PathExists(file_name));
1906
1907 FilePath subdir_path1 = test_subdir.Append(FPL("TestSubDir1"));
1908 CreateDirectory(subdir_path1);
1909 ASSERT_TRUE(PathExists(subdir_path1));
1910
1911 FilePath subdir_path2 = test_subdir.Append(FPL("TestSubDir2"));
1912 CreateDirectory(subdir_path2);
1913 ASSERT_TRUE(PathExists(subdir_path2));
1914
1915 // Delete non-recursively and check that the empty dir got deleted
1916 EXPECT_TRUE(DeleteFile(subdir_path2));
1917 EXPECT_FALSE(PathExists(subdir_path2));
1918
1919 // Delete non-recursively and check that nothing got deleted
1920 EXPECT_FALSE(DeleteFile(test_subdir));
1921 EXPECT_TRUE(PathExists(test_subdir));
1922 EXPECT_TRUE(PathExists(file_name));
1923 EXPECT_TRUE(PathExists(subdir_path1));
1924 }
1925
1926 // Tests recursive Delete() for a directory.
TEST_F(FileUtilTest,DeleteDirRecursive)1927 TEST_F(FileUtilTest, DeleteDirRecursive) {
1928 // Create a subdirectory and put a file and two directories inside.
1929 FilePath test_subdir = temp_dir_.GetPath().Append(FPL("DeleteDirRecursive"));
1930 CreateDirectory(test_subdir);
1931 ASSERT_TRUE(PathExists(test_subdir));
1932
1933 FilePath file_name = test_subdir.Append(FPL("Test DeleteDirRecursive.txt"));
1934 CreateTextFile(file_name, bogus_content);
1935 ASSERT_TRUE(PathExists(file_name));
1936
1937 FilePath subdir_path1 = test_subdir.Append(FPL("TestSubDir1"));
1938 CreateDirectory(subdir_path1);
1939 ASSERT_TRUE(PathExists(subdir_path1));
1940
1941 FilePath subdir_path2 = test_subdir.Append(FPL("TestSubDir2"));
1942 CreateDirectory(subdir_path2);
1943 ASSERT_TRUE(PathExists(subdir_path2));
1944
1945 // Delete recursively and check that the empty dir got deleted
1946 EXPECT_TRUE(DeletePathRecursively(subdir_path2));
1947 EXPECT_FALSE(PathExists(subdir_path2));
1948
1949 // Delete recursively and check that everything got deleted
1950 EXPECT_TRUE(DeletePathRecursively(test_subdir));
1951 EXPECT_FALSE(PathExists(file_name));
1952 EXPECT_FALSE(PathExists(subdir_path1));
1953 EXPECT_FALSE(PathExists(test_subdir));
1954 }
1955
1956 // Tests recursive Delete() for a directory.
TEST_F(FileUtilTest,DeleteDirRecursiveWithOpenFile)1957 TEST_F(FileUtilTest, DeleteDirRecursiveWithOpenFile) {
1958 // Create a subdirectory and put a file and two directories inside.
1959 FilePath test_subdir = temp_dir_.GetPath().Append(FPL("DeleteWithOpenFile"));
1960 CreateDirectory(test_subdir);
1961 ASSERT_TRUE(PathExists(test_subdir));
1962
1963 FilePath file_name1 = test_subdir.Append(FPL("Undeletebable File1.txt"));
1964 File file1(file_name1,
1965 File::FLAG_CREATE | File::FLAG_READ | File::FLAG_WRITE);
1966 ASSERT_TRUE(PathExists(file_name1));
1967
1968 FilePath file_name2 = test_subdir.Append(FPL("Deleteable File2.txt"));
1969 CreateTextFile(file_name2, bogus_content);
1970 ASSERT_TRUE(PathExists(file_name2));
1971
1972 FilePath file_name3 = test_subdir.Append(FPL("Undeletebable File3.txt"));
1973 File file3(file_name3,
1974 File::FLAG_CREATE | File::FLAG_READ | File::FLAG_WRITE);
1975 ASSERT_TRUE(PathExists(file_name3));
1976
1977 #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
1978 // On Windows, holding the file open in sufficient to make it un-deletable.
1979 // The POSIX code is verifiable on Linux by creating an "immutable" file but
1980 // this is best-effort because it's not supported by all file systems. Both
1981 // files will have the same flags so no need to get them individually.
1982 int flags;
1983 bool file_attrs_supported =
1984 ioctl(file1.GetPlatformFile(), FS_IOC_GETFLAGS, &flags) == 0;
1985 // Some filesystems (e.g. tmpfs) don't support file attributes.
1986 if (file_attrs_supported) {
1987 flags |= FS_IMMUTABLE_FL;
1988 ioctl(file1.GetPlatformFile(), FS_IOC_SETFLAGS, &flags);
1989 ioctl(file3.GetPlatformFile(), FS_IOC_SETFLAGS, &flags);
1990 }
1991 #endif
1992
1993 // Delete recursively and check that at least the second file got deleted.
1994 // This ensures that un-deletable files don't impact those that can be.
1995 DeletePathRecursively(test_subdir);
1996 EXPECT_FALSE(PathExists(file_name2));
1997
1998 #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
1999 // Make sure that the test can clean up after itself.
2000 if (file_attrs_supported) {
2001 flags &= ~FS_IMMUTABLE_FL;
2002 ioctl(file1.GetPlatformFile(), FS_IOC_SETFLAGS, &flags);
2003 ioctl(file3.GetPlatformFile(), FS_IOC_SETFLAGS, &flags);
2004 }
2005 #endif
2006 }
2007
2008 #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
2009 // This test will validate that files which would block when read result in a
2010 // failure on a call to ReadFileToStringNonBlocking. To accomplish this we will
2011 // use a named pipe because it appears as a file on disk and we can control how
2012 // much data is available to read. This allows us to simulate a file which would
2013 // block.
TEST_F(FileUtilTest,TestNonBlockingFileReadLinux)2014 TEST_F(FileUtilTest, TestNonBlockingFileReadLinux) {
2015 FilePath fifo_path = temp_dir_.GetPath().Append(FPL("fifo"));
2016 int res = mkfifo(fifo_path.MaybeAsASCII().c_str(),
2017 S_IWUSR | S_IRUSR | S_IWGRP | S_IWGRP);
2018 ASSERT_NE(res, -1);
2019
2020 base::ScopedFD fd(open(fifo_path.MaybeAsASCII().c_str(), O_RDWR));
2021 ASSERT_TRUE(fd.is_valid());
2022
2023 std::string result;
2024 // We will try to read when nothing is available on the fifo, the output
2025 // string will be unmodified and it will fail with EWOULDBLOCK.
2026 ASSERT_FALSE(ReadFileToStringNonBlocking(fifo_path, &result));
2027 EXPECT_EQ(errno, EWOULDBLOCK);
2028 EXPECT_TRUE(result.empty());
2029
2030 // Make a single byte available to read on the FIFO.
2031 ASSERT_EQ(write(fd.get(), "a", 1), 1);
2032
2033 // Now the key part of the test we will call ReadFromFileNonBlocking which
2034 // should fail, errno will be EWOULDBLOCK and the output string will contain
2035 // the single 'a' byte.
2036 ASSERT_FALSE(ReadFileToStringNonBlocking(fifo_path, &result));
2037 EXPECT_EQ(errno, EWOULDBLOCK);
2038 ASSERT_EQ(result.size(), 1u);
2039 EXPECT_EQ(result[0], 'a');
2040 }
2041 #endif // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
2042
TEST_F(FileUtilTest,MoveFileNew)2043 TEST_F(FileUtilTest, MoveFileNew) {
2044 // Create a file
2045 FilePath file_name_from =
2046 temp_dir_.GetPath().Append(FILE_PATH_LITERAL("Move_Test_File.txt"));
2047 CreateTextFile(file_name_from, L"Gooooooooooooooooooooogle");
2048 ASSERT_TRUE(PathExists(file_name_from));
2049
2050 // The destination.
2051 FilePath file_name_to = temp_dir_.GetPath().Append(
2052 FILE_PATH_LITERAL("Move_Test_File_Destination.txt"));
2053 ASSERT_FALSE(PathExists(file_name_to));
2054
2055 EXPECT_TRUE(Move(file_name_from, file_name_to));
2056
2057 // Check everything has been moved.
2058 EXPECT_FALSE(PathExists(file_name_from));
2059 EXPECT_TRUE(PathExists(file_name_to));
2060 }
2061
TEST_F(FileUtilTest,MoveFileExists)2062 TEST_F(FileUtilTest, MoveFileExists) {
2063 // Create a file
2064 FilePath file_name_from =
2065 temp_dir_.GetPath().Append(FILE_PATH_LITERAL("Move_Test_File.txt"));
2066 CreateTextFile(file_name_from, L"Gooooooooooooooooooooogle");
2067 ASSERT_TRUE(PathExists(file_name_from));
2068
2069 // The destination name.
2070 FilePath file_name_to = temp_dir_.GetPath().Append(
2071 FILE_PATH_LITERAL("Move_Test_File_Destination.txt"));
2072 CreateTextFile(file_name_to, L"Old file content");
2073 ASSERT_TRUE(PathExists(file_name_to));
2074
2075 EXPECT_TRUE(Move(file_name_from, file_name_to));
2076
2077 // Check everything has been moved.
2078 EXPECT_FALSE(PathExists(file_name_from));
2079 EXPECT_TRUE(PathExists(file_name_to));
2080 EXPECT_TRUE(L"Gooooooooooooooooooooogle" == ReadTextFile(file_name_to));
2081 }
2082
TEST_F(FileUtilTest,MoveFileDirExists)2083 TEST_F(FileUtilTest, MoveFileDirExists) {
2084 // Create a file
2085 FilePath file_name_from =
2086 temp_dir_.GetPath().Append(FILE_PATH_LITERAL("Move_Test_File.txt"));
2087 CreateTextFile(file_name_from, L"Gooooooooooooooooooooogle");
2088 ASSERT_TRUE(PathExists(file_name_from));
2089
2090 // The destination directory
2091 FilePath dir_name_to =
2092 temp_dir_.GetPath().Append(FILE_PATH_LITERAL("Destination"));
2093 CreateDirectory(dir_name_to);
2094 ASSERT_TRUE(PathExists(dir_name_to));
2095
2096 EXPECT_FALSE(Move(file_name_from, dir_name_to));
2097 }
2098
2099
TEST_F(FileUtilTest,MoveNew)2100 TEST_F(FileUtilTest, MoveNew) {
2101 // Create a directory
2102 FilePath dir_name_from =
2103 temp_dir_.GetPath().Append(FILE_PATH_LITERAL("Move_From_Subdir"));
2104 CreateDirectory(dir_name_from);
2105 ASSERT_TRUE(PathExists(dir_name_from));
2106
2107 // Create a file under the directory
2108 FilePath txt_file_name(FILE_PATH_LITERAL("Move_Test_File.txt"));
2109 FilePath file_name_from = dir_name_from.Append(txt_file_name);
2110 CreateTextFile(file_name_from, L"Gooooooooooooooooooooogle");
2111 ASSERT_TRUE(PathExists(file_name_from));
2112
2113 // Move the directory.
2114 FilePath dir_name_to =
2115 temp_dir_.GetPath().Append(FILE_PATH_LITERAL("Move_To_Subdir"));
2116 FilePath file_name_to =
2117 dir_name_to.Append(FILE_PATH_LITERAL("Move_Test_File.txt"));
2118
2119 ASSERT_FALSE(PathExists(dir_name_to));
2120
2121 EXPECT_TRUE(Move(dir_name_from, dir_name_to));
2122
2123 // Check everything has been moved.
2124 EXPECT_FALSE(PathExists(dir_name_from));
2125 EXPECT_FALSE(PathExists(file_name_from));
2126 EXPECT_TRUE(PathExists(dir_name_to));
2127 EXPECT_TRUE(PathExists(file_name_to));
2128
2129 // Test path traversal.
2130 file_name_from = dir_name_to.Append(txt_file_name);
2131 file_name_to = dir_name_to.Append(FILE_PATH_LITERAL(".."));
2132 file_name_to = file_name_to.Append(txt_file_name);
2133 EXPECT_FALSE(Move(file_name_from, file_name_to));
2134 EXPECT_TRUE(PathExists(file_name_from));
2135 EXPECT_FALSE(PathExists(file_name_to));
2136 EXPECT_TRUE(internal::MoveUnsafe(file_name_from, file_name_to));
2137 EXPECT_FALSE(PathExists(file_name_from));
2138 EXPECT_TRUE(PathExists(file_name_to));
2139 }
2140
TEST_F(FileUtilTest,MoveExist)2141 TEST_F(FileUtilTest, MoveExist) {
2142 // Create a directory
2143 FilePath dir_name_from =
2144 temp_dir_.GetPath().Append(FILE_PATH_LITERAL("Move_From_Subdir"));
2145 CreateDirectory(dir_name_from);
2146 ASSERT_TRUE(PathExists(dir_name_from));
2147
2148 // Create a file under the directory
2149 FilePath file_name_from =
2150 dir_name_from.Append(FILE_PATH_LITERAL("Move_Test_File.txt"));
2151 CreateTextFile(file_name_from, L"Gooooooooooooooooooooogle");
2152 ASSERT_TRUE(PathExists(file_name_from));
2153
2154 // Move the directory
2155 FilePath dir_name_exists =
2156 temp_dir_.GetPath().Append(FILE_PATH_LITERAL("Destination"));
2157
2158 FilePath dir_name_to =
2159 dir_name_exists.Append(FILE_PATH_LITERAL("Move_To_Subdir"));
2160 FilePath file_name_to =
2161 dir_name_to.Append(FILE_PATH_LITERAL("Move_Test_File.txt"));
2162
2163 // Create the destination directory.
2164 CreateDirectory(dir_name_exists);
2165 ASSERT_TRUE(PathExists(dir_name_exists));
2166
2167 EXPECT_TRUE(Move(dir_name_from, dir_name_to));
2168
2169 // Check everything has been moved.
2170 EXPECT_FALSE(PathExists(dir_name_from));
2171 EXPECT_FALSE(PathExists(file_name_from));
2172 EXPECT_TRUE(PathExists(dir_name_to));
2173 EXPECT_TRUE(PathExists(file_name_to));
2174 }
2175
TEST_F(FileUtilTest,CopyDirectoryRecursivelyNew)2176 TEST_F(FileUtilTest, CopyDirectoryRecursivelyNew) {
2177 // Create a directory.
2178 FilePath dir_name_from =
2179 temp_dir_.GetPath().Append(FILE_PATH_LITERAL("Copy_From_Subdir"));
2180 CreateDirectory(dir_name_from);
2181 ASSERT_TRUE(PathExists(dir_name_from));
2182
2183 // Create a file under the directory.
2184 FilePath file_name_from =
2185 dir_name_from.Append(FILE_PATH_LITERAL("Copy_Test_File.txt"));
2186 CreateTextFile(file_name_from, L"Gooooooooooooooooooooogle");
2187 ASSERT_TRUE(PathExists(file_name_from));
2188
2189 // Create a subdirectory.
2190 FilePath subdir_name_from =
2191 dir_name_from.Append(FILE_PATH_LITERAL("Subdir"));
2192 CreateDirectory(subdir_name_from);
2193 ASSERT_TRUE(PathExists(subdir_name_from));
2194
2195 // Create a file under the subdirectory.
2196 FilePath file_name2_from =
2197 subdir_name_from.Append(FILE_PATH_LITERAL("Copy_Test_File.txt"));
2198 CreateTextFile(file_name2_from, L"Gooooooooooooooooooooogle");
2199 ASSERT_TRUE(PathExists(file_name2_from));
2200
2201 // Copy the directory recursively.
2202 FilePath dir_name_to =
2203 temp_dir_.GetPath().Append(FILE_PATH_LITERAL("Copy_To_Subdir"));
2204 FilePath file_name_to =
2205 dir_name_to.Append(FILE_PATH_LITERAL("Copy_Test_File.txt"));
2206 FilePath subdir_name_to =
2207 dir_name_to.Append(FILE_PATH_LITERAL("Subdir"));
2208 FilePath file_name2_to =
2209 subdir_name_to.Append(FILE_PATH_LITERAL("Copy_Test_File.txt"));
2210
2211 ASSERT_FALSE(PathExists(dir_name_to));
2212
2213 EXPECT_TRUE(CopyDirectory(dir_name_from, dir_name_to, true));
2214
2215 // Check everything has been copied.
2216 EXPECT_TRUE(PathExists(dir_name_from));
2217 EXPECT_TRUE(PathExists(file_name_from));
2218 EXPECT_TRUE(PathExists(subdir_name_from));
2219 EXPECT_TRUE(PathExists(file_name2_from));
2220 EXPECT_TRUE(PathExists(dir_name_to));
2221 EXPECT_TRUE(PathExists(file_name_to));
2222 EXPECT_TRUE(PathExists(subdir_name_to));
2223 EXPECT_TRUE(PathExists(file_name2_to));
2224 }
2225
TEST_F(FileUtilTest,CopyDirectoryRecursivelyExists)2226 TEST_F(FileUtilTest, CopyDirectoryRecursivelyExists) {
2227 // Create a directory.
2228 FilePath dir_name_from =
2229 temp_dir_.GetPath().Append(FILE_PATH_LITERAL("Copy_From_Subdir"));
2230 CreateDirectory(dir_name_from);
2231 ASSERT_TRUE(PathExists(dir_name_from));
2232
2233 // Create a file under the directory.
2234 FilePath file_name_from =
2235 dir_name_from.Append(FILE_PATH_LITERAL("Copy_Test_File.txt"));
2236 CreateTextFile(file_name_from, L"Gooooooooooooooooooooogle");
2237 ASSERT_TRUE(PathExists(file_name_from));
2238
2239 // Create a subdirectory.
2240 FilePath subdir_name_from =
2241 dir_name_from.Append(FILE_PATH_LITERAL("Subdir"));
2242 CreateDirectory(subdir_name_from);
2243 ASSERT_TRUE(PathExists(subdir_name_from));
2244
2245 // Create a file under the subdirectory.
2246 FilePath file_name2_from =
2247 subdir_name_from.Append(FILE_PATH_LITERAL("Copy_Test_File.txt"));
2248 CreateTextFile(file_name2_from, L"Gooooooooooooooooooooogle");
2249 ASSERT_TRUE(PathExists(file_name2_from));
2250
2251 // Copy the directory recursively.
2252 FilePath dir_name_exists =
2253 temp_dir_.GetPath().Append(FILE_PATH_LITERAL("Destination"));
2254
2255 FilePath dir_name_to =
2256 dir_name_exists.Append(FILE_PATH_LITERAL("Copy_From_Subdir"));
2257 FilePath file_name_to =
2258 dir_name_to.Append(FILE_PATH_LITERAL("Copy_Test_File.txt"));
2259 FilePath subdir_name_to =
2260 dir_name_to.Append(FILE_PATH_LITERAL("Subdir"));
2261 FilePath file_name2_to =
2262 subdir_name_to.Append(FILE_PATH_LITERAL("Copy_Test_File.txt"));
2263
2264 // Create the destination directory.
2265 CreateDirectory(dir_name_exists);
2266 ASSERT_TRUE(PathExists(dir_name_exists));
2267
2268 EXPECT_TRUE(CopyDirectory(dir_name_from, dir_name_exists, true));
2269
2270 // Check everything has been copied.
2271 EXPECT_TRUE(PathExists(dir_name_from));
2272 EXPECT_TRUE(PathExists(file_name_from));
2273 EXPECT_TRUE(PathExists(subdir_name_from));
2274 EXPECT_TRUE(PathExists(file_name2_from));
2275 EXPECT_TRUE(PathExists(dir_name_to));
2276 EXPECT_TRUE(PathExists(file_name_to));
2277 EXPECT_TRUE(PathExists(subdir_name_to));
2278 EXPECT_TRUE(PathExists(file_name2_to));
2279 }
2280
TEST_F(FileUtilTest,CopyDirectoryNew)2281 TEST_F(FileUtilTest, CopyDirectoryNew) {
2282 // Create a directory.
2283 FilePath dir_name_from =
2284 temp_dir_.GetPath().Append(FILE_PATH_LITERAL("Copy_From_Subdir"));
2285 CreateDirectory(dir_name_from);
2286 ASSERT_TRUE(PathExists(dir_name_from));
2287
2288 // Create a file under the directory.
2289 FilePath file_name_from =
2290 dir_name_from.Append(FILE_PATH_LITERAL("Copy_Test_File.txt"));
2291 CreateTextFile(file_name_from, L"Gooooooooooooooooooooogle");
2292 ASSERT_TRUE(PathExists(file_name_from));
2293
2294 // Create a subdirectory.
2295 FilePath subdir_name_from =
2296 dir_name_from.Append(FILE_PATH_LITERAL("Subdir"));
2297 CreateDirectory(subdir_name_from);
2298 ASSERT_TRUE(PathExists(subdir_name_from));
2299
2300 // Create a file under the subdirectory.
2301 FilePath file_name2_from =
2302 subdir_name_from.Append(FILE_PATH_LITERAL("Copy_Test_File.txt"));
2303 CreateTextFile(file_name2_from, L"Gooooooooooooooooooooogle");
2304 ASSERT_TRUE(PathExists(file_name2_from));
2305
2306 // Copy the directory not recursively.
2307 FilePath dir_name_to =
2308 temp_dir_.GetPath().Append(FILE_PATH_LITERAL("Copy_To_Subdir"));
2309 FilePath file_name_to =
2310 dir_name_to.Append(FILE_PATH_LITERAL("Copy_Test_File.txt"));
2311 FilePath subdir_name_to =
2312 dir_name_to.Append(FILE_PATH_LITERAL("Subdir"));
2313
2314 ASSERT_FALSE(PathExists(dir_name_to));
2315
2316 EXPECT_TRUE(CopyDirectory(dir_name_from, dir_name_to, false));
2317
2318 // Check everything has been copied.
2319 EXPECT_TRUE(PathExists(dir_name_from));
2320 EXPECT_TRUE(PathExists(file_name_from));
2321 EXPECT_TRUE(PathExists(subdir_name_from));
2322 EXPECT_TRUE(PathExists(file_name2_from));
2323 EXPECT_TRUE(PathExists(dir_name_to));
2324 EXPECT_TRUE(PathExists(file_name_to));
2325 EXPECT_FALSE(PathExists(subdir_name_to));
2326 }
2327
TEST_F(FileUtilTest,CopyDirectoryExists)2328 TEST_F(FileUtilTest, CopyDirectoryExists) {
2329 // Create a directory.
2330 FilePath dir_name_from =
2331 temp_dir_.GetPath().Append(FILE_PATH_LITERAL("Copy_From_Subdir"));
2332 CreateDirectory(dir_name_from);
2333 ASSERT_TRUE(PathExists(dir_name_from));
2334
2335 // Create a file under the directory.
2336 FilePath file_name_from =
2337 dir_name_from.Append(FILE_PATH_LITERAL("Copy_Test_File.txt"));
2338 CreateTextFile(file_name_from, L"Gooooooooooooooooooooogle");
2339 ASSERT_TRUE(PathExists(file_name_from));
2340
2341 // Create a subdirectory.
2342 FilePath subdir_name_from =
2343 dir_name_from.Append(FILE_PATH_LITERAL("Subdir"));
2344 CreateDirectory(subdir_name_from);
2345 ASSERT_TRUE(PathExists(subdir_name_from));
2346
2347 // Create a file under the subdirectory.
2348 FilePath file_name2_from =
2349 subdir_name_from.Append(FILE_PATH_LITERAL("Copy_Test_File.txt"));
2350 CreateTextFile(file_name2_from, L"Gooooooooooooooooooooogle");
2351 ASSERT_TRUE(PathExists(file_name2_from));
2352
2353 // Copy the directory not recursively.
2354 FilePath dir_name_to =
2355 temp_dir_.GetPath().Append(FILE_PATH_LITERAL("Copy_To_Subdir"));
2356 FilePath file_name_to =
2357 dir_name_to.Append(FILE_PATH_LITERAL("Copy_Test_File.txt"));
2358 FilePath subdir_name_to =
2359 dir_name_to.Append(FILE_PATH_LITERAL("Subdir"));
2360
2361 // Create the destination directory.
2362 CreateDirectory(dir_name_to);
2363 ASSERT_TRUE(PathExists(dir_name_to));
2364
2365 EXPECT_TRUE(CopyDirectory(dir_name_from, dir_name_to, false));
2366
2367 // Check everything has been copied.
2368 EXPECT_TRUE(PathExists(dir_name_from));
2369 EXPECT_TRUE(PathExists(file_name_from));
2370 EXPECT_TRUE(PathExists(subdir_name_from));
2371 EXPECT_TRUE(PathExists(file_name2_from));
2372 EXPECT_TRUE(PathExists(dir_name_to));
2373 EXPECT_TRUE(PathExists(file_name_to));
2374 EXPECT_FALSE(PathExists(subdir_name_to));
2375 }
2376
TEST_F(FileUtilTest,CopyFileWithCopyDirectoryRecursiveToNew)2377 TEST_F(FileUtilTest, CopyFileWithCopyDirectoryRecursiveToNew) {
2378 // Create a file
2379 FilePath file_name_from =
2380 temp_dir_.GetPath().Append(FILE_PATH_LITERAL("Copy_Test_File.txt"));
2381 CreateTextFile(file_name_from, L"Gooooooooooooooooooooogle");
2382 ASSERT_TRUE(PathExists(file_name_from));
2383
2384 // The destination name
2385 FilePath file_name_to = temp_dir_.GetPath().Append(
2386 FILE_PATH_LITERAL("Copy_Test_File_Destination.txt"));
2387 ASSERT_FALSE(PathExists(file_name_to));
2388
2389 EXPECT_TRUE(CopyDirectory(file_name_from, file_name_to, true));
2390
2391 // Check the has been copied
2392 EXPECT_TRUE(PathExists(file_name_to));
2393 }
2394
TEST_F(FileUtilTest,CopyFileWithCopyDirectoryRecursiveToExisting)2395 TEST_F(FileUtilTest, CopyFileWithCopyDirectoryRecursiveToExisting) {
2396 // Create a file
2397 FilePath file_name_from =
2398 temp_dir_.GetPath().Append(FILE_PATH_LITERAL("Copy_Test_File.txt"));
2399 CreateTextFile(file_name_from, L"Gooooooooooooooooooooogle");
2400 ASSERT_TRUE(PathExists(file_name_from));
2401
2402 // The destination name
2403 FilePath file_name_to = temp_dir_.GetPath().Append(
2404 FILE_PATH_LITERAL("Copy_Test_File_Destination.txt"));
2405 CreateTextFile(file_name_to, L"Old file content");
2406 ASSERT_TRUE(PathExists(file_name_to));
2407
2408 EXPECT_TRUE(CopyDirectory(file_name_from, file_name_to, true));
2409
2410 // Check the has been copied
2411 EXPECT_TRUE(PathExists(file_name_to));
2412 EXPECT_TRUE(L"Gooooooooooooooooooooogle" == ReadTextFile(file_name_to));
2413 }
2414
TEST_F(FileUtilTest,CopyFileWithCopyDirectoryRecursiveToExistingDirectory)2415 TEST_F(FileUtilTest, CopyFileWithCopyDirectoryRecursiveToExistingDirectory) {
2416 // Create a file
2417 FilePath file_name_from =
2418 temp_dir_.GetPath().Append(FILE_PATH_LITERAL("Copy_Test_File.txt"));
2419 CreateTextFile(file_name_from, L"Gooooooooooooooooooooogle");
2420 ASSERT_TRUE(PathExists(file_name_from));
2421
2422 // The destination
2423 FilePath dir_name_to =
2424 temp_dir_.GetPath().Append(FILE_PATH_LITERAL("Destination"));
2425 CreateDirectory(dir_name_to);
2426 ASSERT_TRUE(PathExists(dir_name_to));
2427 FilePath file_name_to =
2428 dir_name_to.Append(FILE_PATH_LITERAL("Copy_Test_File.txt"));
2429
2430 EXPECT_TRUE(CopyDirectory(file_name_from, dir_name_to, true));
2431
2432 // Check the has been copied
2433 EXPECT_TRUE(PathExists(file_name_to));
2434 }
2435
TEST_F(FileUtilTest,CopyFileFailureWithCopyDirectoryExcl)2436 TEST_F(FileUtilTest, CopyFileFailureWithCopyDirectoryExcl) {
2437 // Create a file
2438 FilePath file_name_from =
2439 temp_dir_.GetPath().Append(FILE_PATH_LITERAL("Copy_Test_File.txt"));
2440 CreateTextFile(file_name_from, L"Gooooooooooooooooooooogle");
2441 ASSERT_TRUE(PathExists(file_name_from));
2442
2443 // Make a destination file.
2444 FilePath file_name_to = temp_dir_.GetPath().Append(
2445 FILE_PATH_LITERAL("Copy_Test_File_Destination.txt"));
2446 CreateTextFile(file_name_to, L"Old file content");
2447 ASSERT_TRUE(PathExists(file_name_to));
2448
2449 // Overwriting the destination should fail.
2450 EXPECT_FALSE(CopyDirectoryExcl(file_name_from, file_name_to, true));
2451 EXPECT_EQ(L"Old file content", ReadTextFile(file_name_to));
2452 }
2453
TEST_F(FileUtilTest,CopyDirectoryWithTrailingSeparators)2454 TEST_F(FileUtilTest, CopyDirectoryWithTrailingSeparators) {
2455 // Create a directory.
2456 FilePath dir_name_from =
2457 temp_dir_.GetPath().Append(FILE_PATH_LITERAL("Copy_From_Subdir"));
2458 CreateDirectory(dir_name_from);
2459 ASSERT_TRUE(PathExists(dir_name_from));
2460
2461 // Create a file under the directory.
2462 FilePath file_name_from =
2463 dir_name_from.Append(FILE_PATH_LITERAL("Copy_Test_File.txt"));
2464 CreateTextFile(file_name_from, L"Gooooooooooooooooooooogle");
2465 ASSERT_TRUE(PathExists(file_name_from));
2466
2467 // Copy the directory recursively.
2468 FilePath dir_name_to =
2469 temp_dir_.GetPath().Append(FILE_PATH_LITERAL("Copy_To_Subdir"));
2470 FilePath file_name_to =
2471 dir_name_to.Append(FILE_PATH_LITERAL("Copy_Test_File.txt"));
2472
2473 // Create from path with trailing separators.
2474 #if BUILDFLAG(IS_WIN)
2475 FilePath from_path =
2476 temp_dir_.GetPath().Append(FILE_PATH_LITERAL("Copy_From_Subdir\\\\\\"));
2477 #elif BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
2478 FilePath from_path =
2479 temp_dir_.GetPath().Append(FILE_PATH_LITERAL("Copy_From_Subdir///"));
2480 #endif
2481
2482 EXPECT_TRUE(CopyDirectory(from_path, dir_name_to, true));
2483
2484 // Check everything has been copied.
2485 EXPECT_TRUE(PathExists(dir_name_from));
2486 EXPECT_TRUE(PathExists(file_name_from));
2487 EXPECT_TRUE(PathExists(dir_name_to));
2488 EXPECT_TRUE(PathExists(file_name_to));
2489 }
2490
2491 #if BUILDFLAG(IS_POSIX)
TEST_F(FileUtilTest,CopyDirectoryWithNonRegularFiles)2492 TEST_F(FileUtilTest, CopyDirectoryWithNonRegularFiles) {
2493 // Create a directory.
2494 FilePath dir_name_from =
2495 temp_dir_.GetPath().Append(FILE_PATH_LITERAL("Copy_From_Subdir"));
2496 ASSERT_TRUE(CreateDirectory(dir_name_from));
2497 ASSERT_TRUE(PathExists(dir_name_from));
2498
2499 // Create a file under the directory.
2500 FilePath file_name_from =
2501 dir_name_from.Append(FILE_PATH_LITERAL("Copy_Test_File.txt"));
2502 CreateTextFile(file_name_from, L"Gooooooooooooooooooooogle");
2503 ASSERT_TRUE(PathExists(file_name_from));
2504
2505 // Create a symbolic link under the directory pointing to that file.
2506 FilePath symlink_name_from =
2507 dir_name_from.Append(FILE_PATH_LITERAL("Symlink"));
2508 ASSERT_TRUE(CreateSymbolicLink(file_name_from, symlink_name_from));
2509 ASSERT_TRUE(PathExists(symlink_name_from));
2510
2511 // Create a fifo under the directory.
2512 FilePath fifo_name_from =
2513 dir_name_from.Append(FILE_PATH_LITERAL("Fifo"));
2514 ASSERT_EQ(0, mkfifo(fifo_name_from.value().c_str(), 0644));
2515 ASSERT_TRUE(PathExists(fifo_name_from));
2516
2517 // Copy the directory.
2518 FilePath dir_name_to =
2519 temp_dir_.GetPath().Append(FILE_PATH_LITERAL("Copy_To_Subdir"));
2520 FilePath file_name_to =
2521 dir_name_to.Append(FILE_PATH_LITERAL("Copy_Test_File.txt"));
2522 FilePath symlink_name_to =
2523 dir_name_to.Append(FILE_PATH_LITERAL("Symlink"));
2524 FilePath fifo_name_to =
2525 dir_name_to.Append(FILE_PATH_LITERAL("Fifo"));
2526
2527 ASSERT_FALSE(PathExists(dir_name_to));
2528
2529 EXPECT_TRUE(CopyDirectory(dir_name_from, dir_name_to, false));
2530
2531 // Check that only directories and regular files are copied.
2532 EXPECT_TRUE(PathExists(dir_name_from));
2533 EXPECT_TRUE(PathExists(file_name_from));
2534 EXPECT_TRUE(PathExists(symlink_name_from));
2535 EXPECT_TRUE(PathExists(fifo_name_from));
2536 EXPECT_TRUE(PathExists(dir_name_to));
2537 EXPECT_TRUE(PathExists(file_name_to));
2538 EXPECT_FALSE(PathExists(symlink_name_to));
2539 EXPECT_FALSE(PathExists(fifo_name_to));
2540 }
2541
TEST_F(FileUtilTest,CopyDirectoryExclFileOverSymlink)2542 TEST_F(FileUtilTest, CopyDirectoryExclFileOverSymlink) {
2543 // Create a directory.
2544 FilePath dir_name_from =
2545 temp_dir_.GetPath().Append(FILE_PATH_LITERAL("Copy_From_Subdir"));
2546 ASSERT_TRUE(CreateDirectory(dir_name_from));
2547 ASSERT_TRUE(PathExists(dir_name_from));
2548
2549 // Create a file under the directory.
2550 FilePath file_name_from =
2551 dir_name_from.Append(FILE_PATH_LITERAL("Copy_Test_File.txt"));
2552 CreateTextFile(file_name_from, L"Gooooooooooooooooooooogle");
2553 ASSERT_TRUE(PathExists(file_name_from));
2554
2555 // Create a destination directory with a symlink of the same name.
2556 FilePath dir_name_to =
2557 temp_dir_.GetPath().Append(FILE_PATH_LITERAL("Copy_To_Subdir"));
2558 ASSERT_TRUE(CreateDirectory(dir_name_to));
2559 ASSERT_TRUE(PathExists(dir_name_to));
2560
2561 FilePath symlink_target =
2562 dir_name_to.Append(FILE_PATH_LITERAL("Symlink_Target.txt"));
2563 CreateTextFile(symlink_target, L"asdf");
2564 ASSERT_TRUE(PathExists(symlink_target));
2565
2566 FilePath symlink_name_to =
2567 dir_name_to.Append(FILE_PATH_LITERAL("Copy_Test_File.txt"));
2568 ASSERT_TRUE(CreateSymbolicLink(symlink_target, symlink_name_to));
2569 ASSERT_TRUE(PathExists(symlink_name_to));
2570
2571 // Check that copying fails.
2572 EXPECT_FALSE(CopyDirectoryExcl(dir_name_from, dir_name_to, false));
2573 }
2574
TEST_F(FileUtilTest,CopyDirectoryExclDirectoryOverSymlink)2575 TEST_F(FileUtilTest, CopyDirectoryExclDirectoryOverSymlink) {
2576 // Create a directory.
2577 FilePath dir_name_from =
2578 temp_dir_.GetPath().Append(FILE_PATH_LITERAL("Copy_From_Subdir"));
2579 ASSERT_TRUE(CreateDirectory(dir_name_from));
2580 ASSERT_TRUE(PathExists(dir_name_from));
2581
2582 // Create a subdirectory.
2583 FilePath subdir_name_from = dir_name_from.Append(FILE_PATH_LITERAL("Subsub"));
2584 CreateDirectory(subdir_name_from);
2585 ASSERT_TRUE(PathExists(subdir_name_from));
2586
2587 // Create a destination directory with a symlink of the same name.
2588 FilePath dir_name_to =
2589 temp_dir_.GetPath().Append(FILE_PATH_LITERAL("Copy_To_Subdir"));
2590 ASSERT_TRUE(CreateDirectory(dir_name_to));
2591 ASSERT_TRUE(PathExists(dir_name_to));
2592
2593 FilePath symlink_target = dir_name_to.Append(FILE_PATH_LITERAL("Subsub"));
2594 CreateTextFile(symlink_target, L"asdf");
2595 ASSERT_TRUE(PathExists(symlink_target));
2596
2597 FilePath symlink_name_to =
2598 dir_name_to.Append(FILE_PATH_LITERAL("Copy_Test_File.txt"));
2599 ASSERT_TRUE(CreateSymbolicLink(symlink_target, symlink_name_to));
2600 ASSERT_TRUE(PathExists(symlink_name_to));
2601
2602 // Check that copying fails.
2603 EXPECT_FALSE(CopyDirectoryExcl(dir_name_from, dir_name_to, false));
2604 }
2605
TEST_F(FileUtilTest,CopyDirectoryExclFileOverDanglingSymlink)2606 TEST_F(FileUtilTest, CopyDirectoryExclFileOverDanglingSymlink) {
2607 // Create a directory.
2608 FilePath dir_name_from =
2609 temp_dir_.GetPath().Append(FILE_PATH_LITERAL("Copy_From_Subdir"));
2610 ASSERT_TRUE(CreateDirectory(dir_name_from));
2611 ASSERT_TRUE(PathExists(dir_name_from));
2612
2613 // Create a file under the directory.
2614 FilePath file_name_from =
2615 dir_name_from.Append(FILE_PATH_LITERAL("Copy_Test_File.txt"));
2616 CreateTextFile(file_name_from, L"Gooooooooooooooooooooogle");
2617 ASSERT_TRUE(PathExists(file_name_from));
2618
2619 // Create a destination directory with a dangling symlink of the same name.
2620 FilePath dir_name_to =
2621 temp_dir_.GetPath().Append(FILE_PATH_LITERAL("Copy_To_Subdir"));
2622 ASSERT_TRUE(CreateDirectory(dir_name_to));
2623 ASSERT_TRUE(PathExists(dir_name_to));
2624
2625 FilePath symlink_target =
2626 dir_name_to.Append(FILE_PATH_LITERAL("Symlink_Target.txt"));
2627 CreateTextFile(symlink_target, L"asdf");
2628 ASSERT_TRUE(PathExists(symlink_target));
2629
2630 FilePath symlink_name_to =
2631 dir_name_to.Append(FILE_PATH_LITERAL("Copy_Test_File.txt"));
2632 ASSERT_TRUE(CreateSymbolicLink(symlink_target, symlink_name_to));
2633 ASSERT_TRUE(PathExists(symlink_name_to));
2634 ASSERT_TRUE(DeleteFile(symlink_target));
2635
2636 // Check that copying fails and that no file was created for the symlink's
2637 // referent.
2638 EXPECT_FALSE(CopyDirectoryExcl(dir_name_from, dir_name_to, false));
2639 EXPECT_FALSE(PathExists(symlink_target));
2640 }
2641
TEST_F(FileUtilTest,CopyDirectoryExclDirectoryOverDanglingSymlink)2642 TEST_F(FileUtilTest, CopyDirectoryExclDirectoryOverDanglingSymlink) {
2643 // Create a directory.
2644 FilePath dir_name_from =
2645 temp_dir_.GetPath().Append(FILE_PATH_LITERAL("Copy_From_Subdir"));
2646 ASSERT_TRUE(CreateDirectory(dir_name_from));
2647 ASSERT_TRUE(PathExists(dir_name_from));
2648
2649 // Create a subdirectory.
2650 FilePath subdir_name_from = dir_name_from.Append(FILE_PATH_LITERAL("Subsub"));
2651 CreateDirectory(subdir_name_from);
2652 ASSERT_TRUE(PathExists(subdir_name_from));
2653
2654 // Create a destination directory with a dangling symlink of the same name.
2655 FilePath dir_name_to =
2656 temp_dir_.GetPath().Append(FILE_PATH_LITERAL("Copy_To_Subdir"));
2657 ASSERT_TRUE(CreateDirectory(dir_name_to));
2658 ASSERT_TRUE(PathExists(dir_name_to));
2659
2660 FilePath symlink_target =
2661 dir_name_to.Append(FILE_PATH_LITERAL("Symlink_Target.txt"));
2662 CreateTextFile(symlink_target, L"asdf");
2663 ASSERT_TRUE(PathExists(symlink_target));
2664
2665 FilePath symlink_name_to =
2666 dir_name_to.Append(FILE_PATH_LITERAL("Copy_Test_File.txt"));
2667 ASSERT_TRUE(CreateSymbolicLink(symlink_target, symlink_name_to));
2668 ASSERT_TRUE(PathExists(symlink_name_to));
2669 ASSERT_TRUE(DeleteFile(symlink_target));
2670
2671 // Check that copying fails and that no directory was created for the
2672 // symlink's referent.
2673 EXPECT_FALSE(CopyDirectoryExcl(dir_name_from, dir_name_to, false));
2674 EXPECT_FALSE(PathExists(symlink_target));
2675 }
2676
TEST_F(FileUtilTest,CopyDirectoryExclFileOverFifo)2677 TEST_F(FileUtilTest, CopyDirectoryExclFileOverFifo) {
2678 // Create a directory.
2679 FilePath dir_name_from =
2680 temp_dir_.GetPath().Append(FILE_PATH_LITERAL("Copy_From_Subdir"));
2681 ASSERT_TRUE(CreateDirectory(dir_name_from));
2682 ASSERT_TRUE(PathExists(dir_name_from));
2683
2684 // Create a file under the directory.
2685 FilePath file_name_from =
2686 dir_name_from.Append(FILE_PATH_LITERAL("Copy_Test_File.txt"));
2687 CreateTextFile(file_name_from, L"Gooooooooooooooooooooogle");
2688 ASSERT_TRUE(PathExists(file_name_from));
2689
2690 // Create a destination directory with a fifo of the same name.
2691 FilePath dir_name_to =
2692 temp_dir_.GetPath().Append(FILE_PATH_LITERAL("Copy_To_Subdir"));
2693 ASSERT_TRUE(CreateDirectory(dir_name_to));
2694 ASSERT_TRUE(PathExists(dir_name_to));
2695
2696 FilePath fifo_name_to =
2697 dir_name_to.Append(FILE_PATH_LITERAL("Copy_Test_File.txt"));
2698 ASSERT_EQ(0, mkfifo(fifo_name_to.value().c_str(), 0644));
2699 ASSERT_TRUE(PathExists(fifo_name_to));
2700
2701 // Check that copying fails.
2702 EXPECT_FALSE(CopyDirectoryExcl(dir_name_from, dir_name_to, false));
2703 }
2704 #endif // BUILDFLAG(IS_POSIX)
2705
TEST_F(FileUtilTest,CopyFile)2706 TEST_F(FileUtilTest, CopyFile) {
2707 // Create a directory
2708 FilePath dir_name_from =
2709 temp_dir_.GetPath().Append(FILE_PATH_LITERAL("Copy_From_Subdir"));
2710 ASSERT_TRUE(CreateDirectory(dir_name_from));
2711 ASSERT_TRUE(DirectoryExists(dir_name_from));
2712
2713 // Create a file under the directory
2714 FilePath file_name_from =
2715 dir_name_from.Append(FILE_PATH_LITERAL("Copy_Test_File.txt"));
2716 const std::wstring file_contents(L"Gooooooooooooooooooooogle");
2717 CreateTextFile(file_name_from, file_contents);
2718 ASSERT_TRUE(PathExists(file_name_from));
2719
2720 // Copy the file.
2721 FilePath dest_file = dir_name_from.Append(FILE_PATH_LITERAL("DestFile.txt"));
2722 ASSERT_TRUE(CopyFile(file_name_from, dest_file));
2723
2724 // Try to copy the file to another location using '..' in the path.
2725 FilePath dest_file2(dir_name_from);
2726 dest_file2 = dest_file2.AppendASCII("..");
2727 dest_file2 = dest_file2.AppendASCII("DestFile.txt");
2728 ASSERT_FALSE(CopyFile(file_name_from, dest_file2));
2729
2730 FilePath dest_file2_test(dir_name_from);
2731 dest_file2_test = dest_file2_test.DirName();
2732 dest_file2_test = dest_file2_test.AppendASCII("DestFile.txt");
2733
2734 // Check expected copy results.
2735 EXPECT_TRUE(PathExists(file_name_from));
2736 EXPECT_TRUE(PathExists(dest_file));
2737 EXPECT_EQ(file_contents, ReadTextFile(dest_file));
2738 EXPECT_FALSE(PathExists(dest_file2_test));
2739 EXPECT_FALSE(PathExists(dest_file2));
2740
2741 // Change |file_name_from| contents.
2742 const std::wstring new_file_contents(L"Moogle");
2743 CreateTextFile(file_name_from, new_file_contents);
2744 ASSERT_TRUE(PathExists(file_name_from));
2745 EXPECT_EQ(new_file_contents, ReadTextFile(file_name_from));
2746
2747 // Overwrite |dest_file|.
2748 ASSERT_TRUE(CopyFile(file_name_from, dest_file));
2749 EXPECT_TRUE(PathExists(dest_file));
2750 EXPECT_EQ(new_file_contents, ReadTextFile(dest_file));
2751
2752 // Create another directory.
2753 FilePath dest_dir = temp_dir_.GetPath().Append(FPL("dest_dir"));
2754 ASSERT_TRUE(CreateDirectory(dest_dir));
2755 EXPECT_TRUE(DirectoryExists(dest_dir));
2756 EXPECT_TRUE(IsDirectoryEmpty(dest_dir));
2757
2758 // Make sure CopyFile() cannot overwrite a directory.
2759 ASSERT_FALSE(CopyFile(file_name_from, dest_dir));
2760 EXPECT_TRUE(DirectoryExists(dest_dir));
2761 EXPECT_TRUE(IsDirectoryEmpty(dest_dir));
2762 }
2763
2764 // file_util winds up using autoreleased objects on the Mac, so this needs
2765 // to be a PlatformTest.
2766 typedef PlatformTest ReadOnlyFileUtilTest;
2767
TEST_F(ReadOnlyFileUtilTest,ContentsEqual)2768 TEST_F(ReadOnlyFileUtilTest, ContentsEqual) {
2769 FilePath data_dir;
2770 ASSERT_TRUE(PathService::Get(DIR_TEST_DATA, &data_dir));
2771 data_dir = data_dir.AppendASCII("file_util");
2772 ASSERT_TRUE(PathExists(data_dir));
2773
2774 FilePath original_file =
2775 data_dir.Append(FILE_PATH_LITERAL("original.txt"));
2776 FilePath same_file =
2777 data_dir.Append(FILE_PATH_LITERAL("same.txt"));
2778 FilePath same_length_file =
2779 data_dir.Append(FILE_PATH_LITERAL("same_length.txt"));
2780 FilePath different_file =
2781 data_dir.Append(FILE_PATH_LITERAL("different.txt"));
2782 FilePath different_first_file =
2783 data_dir.Append(FILE_PATH_LITERAL("different_first.txt"));
2784 FilePath different_last_file =
2785 data_dir.Append(FILE_PATH_LITERAL("different_last.txt"));
2786 FilePath empty1_file =
2787 data_dir.Append(FILE_PATH_LITERAL("empty1.txt"));
2788 FilePath empty2_file =
2789 data_dir.Append(FILE_PATH_LITERAL("empty2.txt"));
2790 FilePath shortened_file =
2791 data_dir.Append(FILE_PATH_LITERAL("shortened.txt"));
2792 FilePath binary_file =
2793 data_dir.Append(FILE_PATH_LITERAL("binary_file.bin"));
2794 FilePath binary_file_same =
2795 data_dir.Append(FILE_PATH_LITERAL("binary_file_same.bin"));
2796 FilePath binary_file_diff =
2797 data_dir.Append(FILE_PATH_LITERAL("binary_file_diff.bin"));
2798
2799 EXPECT_TRUE(ContentsEqual(original_file, original_file));
2800 EXPECT_TRUE(ContentsEqual(original_file, same_file));
2801 EXPECT_FALSE(ContentsEqual(original_file, same_length_file));
2802 EXPECT_FALSE(ContentsEqual(original_file, different_file));
2803 EXPECT_FALSE(ContentsEqual(FilePath(FILE_PATH_LITERAL("bogusname")),
2804 FilePath(FILE_PATH_LITERAL("bogusname"))));
2805 EXPECT_FALSE(ContentsEqual(original_file, different_first_file));
2806 EXPECT_FALSE(ContentsEqual(original_file, different_last_file));
2807 EXPECT_TRUE(ContentsEqual(empty1_file, empty2_file));
2808 EXPECT_FALSE(ContentsEqual(original_file, shortened_file));
2809 EXPECT_FALSE(ContentsEqual(shortened_file, original_file));
2810 EXPECT_TRUE(ContentsEqual(binary_file, binary_file_same));
2811 EXPECT_FALSE(ContentsEqual(binary_file, binary_file_diff));
2812 }
2813
TEST_F(ReadOnlyFileUtilTest,TextContentsEqual)2814 TEST_F(ReadOnlyFileUtilTest, TextContentsEqual) {
2815 FilePath data_dir;
2816 ASSERT_TRUE(PathService::Get(DIR_TEST_DATA, &data_dir));
2817 data_dir = data_dir.AppendASCII("file_util");
2818 ASSERT_TRUE(PathExists(data_dir));
2819
2820 FilePath original_file =
2821 data_dir.Append(FILE_PATH_LITERAL("original.txt"));
2822 FilePath same_file =
2823 data_dir.Append(FILE_PATH_LITERAL("same.txt"));
2824 FilePath crlf_file =
2825 data_dir.Append(FILE_PATH_LITERAL("crlf.txt"));
2826 FilePath shortened_file =
2827 data_dir.Append(FILE_PATH_LITERAL("shortened.txt"));
2828 FilePath different_file =
2829 data_dir.Append(FILE_PATH_LITERAL("different.txt"));
2830 FilePath different_first_file =
2831 data_dir.Append(FILE_PATH_LITERAL("different_first.txt"));
2832 FilePath different_last_file =
2833 data_dir.Append(FILE_PATH_LITERAL("different_last.txt"));
2834 FilePath first1_file =
2835 data_dir.Append(FILE_PATH_LITERAL("first1.txt"));
2836 FilePath first2_file =
2837 data_dir.Append(FILE_PATH_LITERAL("first2.txt"));
2838 FilePath empty1_file =
2839 data_dir.Append(FILE_PATH_LITERAL("empty1.txt"));
2840 FilePath empty2_file =
2841 data_dir.Append(FILE_PATH_LITERAL("empty2.txt"));
2842 FilePath blank_line_file =
2843 data_dir.Append(FILE_PATH_LITERAL("blank_line.txt"));
2844 FilePath blank_line_crlf_file =
2845 data_dir.Append(FILE_PATH_LITERAL("blank_line_crlf.txt"));
2846
2847 EXPECT_TRUE(TextContentsEqual(original_file, same_file));
2848 EXPECT_TRUE(TextContentsEqual(original_file, crlf_file));
2849 EXPECT_FALSE(TextContentsEqual(original_file, shortened_file));
2850 EXPECT_FALSE(TextContentsEqual(original_file, different_file));
2851 EXPECT_FALSE(TextContentsEqual(original_file, different_first_file));
2852 EXPECT_FALSE(TextContentsEqual(original_file, different_last_file));
2853 EXPECT_FALSE(TextContentsEqual(first1_file, first2_file));
2854 EXPECT_TRUE(TextContentsEqual(empty1_file, empty2_file));
2855 EXPECT_FALSE(TextContentsEqual(original_file, empty1_file));
2856 EXPECT_TRUE(TextContentsEqual(blank_line_file, blank_line_crlf_file));
2857 }
2858
2859 // We don't need equivalent functionality outside of Windows.
2860 #if BUILDFLAG(IS_WIN)
TEST_F(FileUtilTest,CopyAndDeleteDirectoryTest)2861 TEST_F(FileUtilTest, CopyAndDeleteDirectoryTest) {
2862 // Create a directory
2863 FilePath dir_name_from = temp_dir_.GetPath().Append(
2864 FILE_PATH_LITERAL("CopyAndDelete_From_Subdir"));
2865 CreateDirectory(dir_name_from);
2866 ASSERT_TRUE(PathExists(dir_name_from));
2867
2868 // Create a file under the directory
2869 FilePath file_name_from =
2870 dir_name_from.Append(FILE_PATH_LITERAL("CopyAndDelete_Test_File.txt"));
2871 CreateTextFile(file_name_from, L"Gooooooooooooooooooooogle");
2872 ASSERT_TRUE(PathExists(file_name_from));
2873
2874 // Move the directory by using CopyAndDeleteDirectory
2875 FilePath dir_name_to =
2876 temp_dir_.GetPath().Append(FILE_PATH_LITERAL("CopyAndDelete_To_Subdir"));
2877 FilePath file_name_to =
2878 dir_name_to.Append(FILE_PATH_LITERAL("CopyAndDelete_Test_File.txt"));
2879
2880 ASSERT_FALSE(PathExists(dir_name_to));
2881
2882 EXPECT_TRUE(internal::CopyAndDeleteDirectory(dir_name_from,
2883 dir_name_to));
2884
2885 // Check everything has been moved.
2886 EXPECT_FALSE(PathExists(dir_name_from));
2887 EXPECT_FALSE(PathExists(file_name_from));
2888 EXPECT_TRUE(PathExists(dir_name_to));
2889 EXPECT_TRUE(PathExists(file_name_to));
2890 }
2891
TEST_F(FileUtilTest,GetTempDirTest)2892 TEST_F(FileUtilTest, GetTempDirTest) {
2893 static const TCHAR* kTmpKey = _T("TMP");
2894 static const TCHAR* kTmpValues[] = {
2895 _T(""), _T("C:"), _T("C:\\"), _T("C:\\tmp"), _T("C:\\tmp\\")
2896 };
2897 // Save the original $TMP.
2898 size_t original_tmp_size;
2899 TCHAR* original_tmp;
2900 ASSERT_EQ(0, ::_tdupenv_s(&original_tmp, &original_tmp_size, kTmpKey));
2901 // original_tmp may be NULL.
2902
2903 for (unsigned int i = 0; i < std::size(kTmpValues); ++i) {
2904 FilePath path;
2905 ::_tputenv_s(kTmpKey, kTmpValues[i]);
2906 GetTempDir(&path);
2907 EXPECT_TRUE(path.IsAbsolute()) << "$TMP=" << kTmpValues[i] <<
2908 " result=" << path.value();
2909 }
2910
2911 // Restore the original $TMP.
2912 if (original_tmp) {
2913 ::_tputenv_s(kTmpKey, original_tmp);
2914 free(original_tmp);
2915 } else {
2916 ::_tputenv_s(kTmpKey, _T(""));
2917 }
2918 }
2919 #endif // BUILDFLAG(IS_WIN)
2920
2921 // Test that files opened by OpenFile are not set up for inheritance into child
2922 // procs.
TEST_F(FileUtilTest,OpenFileNoInheritance)2923 TEST_F(FileUtilTest, OpenFileNoInheritance) {
2924 FilePath file_path(temp_dir_.GetPath().Append(FPL("a_file")));
2925
2926 // Character set handling is leaking according to ASAN. http://crbug.com/883698
2927 #if defined(ADDRESS_SANITIZER)
2928 static constexpr const char* modes[] = {"wb", "r"};
2929 #else
2930 static constexpr const char* modes[] = {"wb", "r,ccs=UTF-8"};
2931 #endif
2932
2933 for (const char* mode : modes) {
2934 SCOPED_TRACE(mode);
2935 ASSERT_NO_FATAL_FAILURE(CreateTextFile(file_path, L"Geepers"));
2936 FILE* file = OpenFile(file_path, mode);
2937 ASSERT_NE(nullptr, file);
2938 {
2939 ScopedClosureRunner file_closer(BindOnce(IgnoreResult(&CloseFile), file));
2940 bool is_inheritable = true;
2941 ASSERT_NO_FATAL_FAILURE(GetIsInheritable(file, &is_inheritable));
2942 EXPECT_FALSE(is_inheritable);
2943 }
2944 ASSERT_TRUE(DeleteFile(file_path));
2945 }
2946 }
2947
TEST_F(FileUtilTest,CreateAndOpenTemporaryFileInDir)2948 TEST_F(FileUtilTest, CreateAndOpenTemporaryFileInDir) {
2949 // Create a temporary file.
2950 FilePath path;
2951 File file = CreateAndOpenTemporaryFileInDir(temp_dir_.GetPath(), &path);
2952 ASSERT_TRUE(file.IsValid());
2953 EXPECT_FALSE(path.empty());
2954
2955 // Try to open another handle to it.
2956 File file2(path,
2957 File::FLAG_OPEN | File::FLAG_READ | File::FLAG_WIN_SHARE_DELETE);
2958 #if BUILDFLAG(IS_WIN)
2959 // The file cannot be opened again on account of the exclusive access.
2960 EXPECT_FALSE(file2.IsValid());
2961 #else
2962 // Exclusive access isn't a thing on non-Windows platforms.
2963 EXPECT_TRUE(file2.IsValid());
2964 #endif
2965 }
2966
TEST_F(FileUtilTest,CreateTemporaryFileTest)2967 TEST_F(FileUtilTest, CreateTemporaryFileTest) {
2968 FilePath temp_files[3];
2969 for (auto& i : temp_files) {
2970 ASSERT_TRUE(CreateTemporaryFile(&i));
2971 EXPECT_TRUE(PathExists(i));
2972 EXPECT_FALSE(DirectoryExists(i));
2973 }
2974 for (int i = 0; i < 3; i++)
2975 EXPECT_FALSE(temp_files[i] == temp_files[(i+1)%3]);
2976 for (const auto& i : temp_files)
2977 EXPECT_TRUE(DeleteFile(i));
2978 }
2979
TEST_F(FileUtilTest,CreateAndOpenTemporaryStreamTest)2980 TEST_F(FileUtilTest, CreateAndOpenTemporaryStreamTest) {
2981 FilePath names[3];
2982 ScopedFILE fps[3];
2983 int i;
2984
2985 // Create; make sure they are open and exist.
2986 for (i = 0; i < 3; ++i) {
2987 fps[i] = CreateAndOpenTemporaryStream(&(names[i]));
2988 ASSERT_TRUE(fps[i]);
2989 EXPECT_TRUE(PathExists(names[i]));
2990 }
2991
2992 // Make sure all names are unique.
2993 for (i = 0; i < 3; ++i) {
2994 EXPECT_FALSE(names[i] == names[(i+1)%3]);
2995 }
2996
2997 // Close and delete.
2998 for (i = 0; i < 3; ++i) {
2999 fps[i].reset();
3000 EXPECT_TRUE(DeleteFile(names[i]));
3001 }
3002 }
3003
TEST_F(FileUtilTest,GetUniquePathTest)3004 TEST_F(FileUtilTest, GetUniquePathTest) {
3005 // Create a unique temp directory and use it to generate a unique file path.
3006 base::ScopedTempDir temp_dir;
3007 EXPECT_TRUE(temp_dir.CreateUniqueTempDir());
3008 EXPECT_TRUE(temp_dir.IsValid());
3009 FilePath base_name(FILE_PATH_LITERAL("Unique_Base_Name.txt"));
3010 FilePath base_path = temp_dir.GetPath().Append(base_name);
3011 EXPECT_FALSE(PathExists(base_path));
3012
3013 // GetUniquePath() should return unchanged path if file does not exist.
3014 EXPECT_EQ(base_path, GetUniquePath(base_path));
3015
3016 // Create the file.
3017 {
3018 File file(base_path,
3019 File::FLAG_CREATE | File::FLAG_READ | File::FLAG_WRITE);
3020 EXPECT_TRUE(PathExists(base_path));
3021 }
3022
3023 static const FilePath::CharType* const kExpectedNames[] = {
3024 FILE_PATH_LITERAL("Unique_Base_Name (1).txt"),
3025 FILE_PATH_LITERAL("Unique_Base_Name (2).txt"),
3026 FILE_PATH_LITERAL("Unique_Base_Name (3).txt"),
3027 };
3028
3029 // Call GetUniquePath() three times against this existing file name.
3030 for (const FilePath::CharType* expected_name : kExpectedNames) {
3031 FilePath expected_path = temp_dir.GetPath().Append(expected_name);
3032 FilePath path = GetUniquePath(base_path);
3033 EXPECT_EQ(expected_path, path);
3034
3035 // Verify that a file with this path indeed does not exist on the file
3036 // system.
3037 EXPECT_FALSE(PathExists(path));
3038
3039 // Create the file so it exists for the next call to GetUniquePath() in the
3040 // loop.
3041 File file(path, File::FLAG_CREATE | File::FLAG_READ | File::FLAG_WRITE);
3042 EXPECT_TRUE(PathExists(path));
3043 }
3044 }
3045
TEST_F(FileUtilTest,FileToFILE)3046 TEST_F(FileUtilTest, FileToFILE) {
3047 File file;
3048 FILE* stream = FileToFILE(std::move(file), "w");
3049 EXPECT_FALSE(stream);
3050
3051 FilePath file_name = temp_dir_.GetPath().Append(FPL("The file.txt"));
3052 file = File(file_name, File::FLAG_CREATE | File::FLAG_WRITE);
3053 EXPECT_TRUE(file.IsValid());
3054
3055 stream = FileToFILE(std::move(file), "w");
3056 EXPECT_TRUE(stream);
3057 EXPECT_FALSE(file.IsValid());
3058 EXPECT_TRUE(CloseFile(stream));
3059 }
3060
TEST_F(FileUtilTest,FILEToFile)3061 TEST_F(FileUtilTest, FILEToFile) {
3062 ScopedFILE stream;
3063 EXPECT_FALSE(FILEToFile(stream.get()).IsValid());
3064
3065 stream.reset(OpenFile(temp_dir_.GetPath().Append(FPL("hello.txt")), "wb+"));
3066 ASSERT_TRUE(stream);
3067 File file = FILEToFile(stream.get());
3068 EXPECT_TRUE(file.IsValid());
3069 ASSERT_EQ(fprintf(stream.get(), "there"), 5);
3070 ASSERT_EQ(fflush(stream.get()), 0);
3071 EXPECT_EQ(file.GetLength(), 5L);
3072 }
3073
3074 #if BUILDFLAG(IS_WIN)
TEST_F(FileUtilTest,GetSecureSystemTemp)3075 TEST_F(FileUtilTest, GetSecureSystemTemp) {
3076 FilePath secure_system_temp;
3077 ASSERT_EQ(GetSecureSystemTemp(&secure_system_temp), !!::IsUserAnAdmin());
3078 if (!::IsUserAnAdmin()) {
3079 GTEST_SKIP() << "This test must be run by an admin user";
3080 }
3081
3082 FilePath dir_windows;
3083 ASSERT_TRUE(PathService::Get(DIR_WINDOWS, &dir_windows));
3084 FilePath dir_program_files;
3085 ASSERT_TRUE(PathService::Get(DIR_PROGRAM_FILES, &dir_program_files));
3086
3087 ASSERT_TRUE((dir_windows.AppendASCII("SystemTemp") == secure_system_temp) ||
3088 (dir_program_files == secure_system_temp));
3089 }
3090 #endif // BUILDFLAG(IS_WIN)
3091
TEST_F(FileUtilTest,CreateNewTempDirectoryTest)3092 TEST_F(FileUtilTest, CreateNewTempDirectoryTest) {
3093 FilePath temp_dir;
3094 ASSERT_TRUE(CreateNewTempDirectory(FilePath::StringType(), &temp_dir));
3095 EXPECT_TRUE(PathExists(temp_dir));
3096 EXPECT_TRUE(DeleteFile(temp_dir));
3097 }
3098
3099 #if BUILDFLAG(IS_WIN)
TEST_F(FileUtilTest,TempDirectoryParentTest)3100 TEST_F(FileUtilTest, TempDirectoryParentTest) {
3101 if (!::IsUserAnAdmin()) {
3102 GTEST_SKIP() << "This test must be run by an admin user";
3103 }
3104 FilePath temp_dir;
3105 ASSERT_TRUE(CreateNewTempDirectory(FilePath::StringType(), &temp_dir));
3106 EXPECT_TRUE(PathExists(temp_dir));
3107
3108 FilePath expected_parent_dir;
3109 if (!GetSecureSystemTemp(&expected_parent_dir)) {
3110 EXPECT_TRUE(PathService::Get(DIR_TEMP, &expected_parent_dir));
3111 }
3112 EXPECT_TRUE(expected_parent_dir.IsParent(temp_dir));
3113 EXPECT_TRUE(DeleteFile(temp_dir));
3114 }
3115 #endif // BUILDFLAG(IS_WIN)
3116
TEST_F(FileUtilTest,CreateNewTemporaryDirInDirTest)3117 TEST_F(FileUtilTest, CreateNewTemporaryDirInDirTest) {
3118 FilePath new_dir;
3119 ASSERT_TRUE(CreateTemporaryDirInDir(
3120 temp_dir_.GetPath(), FILE_PATH_LITERAL("CreateNewTemporaryDirInDirTest"),
3121 &new_dir));
3122 EXPECT_TRUE(PathExists(new_dir));
3123 EXPECT_TRUE(temp_dir_.GetPath().IsParent(new_dir));
3124 EXPECT_TRUE(DeleteFile(new_dir));
3125 }
3126
3127 #if BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
TEST_F(FileUtilTest,GetShmemTempDirTest)3128 TEST_F(FileUtilTest, GetShmemTempDirTest) {
3129 FilePath dir;
3130 EXPECT_TRUE(GetShmemTempDir(false, &dir));
3131 EXPECT_TRUE(DirectoryExists(dir));
3132 }
3133
TEST_F(FileUtilTest,AllocateFileRegionTest_ZeroOffset)3134 TEST_F(FileUtilTest, AllocateFileRegionTest_ZeroOffset) {
3135 const int kTestFileLength = 9;
3136 char test_data[] = "test_data";
3137 FilePath file_path = temp_dir_.GetPath().Append(
3138 FILE_PATH_LITERAL("allocate_file_region_test_zero_offset"));
3139 WriteFile(file_path, test_data, kTestFileLength);
3140
3141 File file(file_path, base::File::FLAG_OPEN | base::File::FLAG_READ |
3142 base::File::FLAG_WRITE);
3143 ASSERT_TRUE(file.IsValid());
3144 ASSERT_EQ(file.GetLength(), kTestFileLength);
3145
3146 const int kExtendedFileLength = 23;
3147 ASSERT_TRUE(AllocateFileRegion(&file, 0, kExtendedFileLength));
3148 EXPECT_EQ(file.GetLength(), kExtendedFileLength);
3149
3150 char data_read[32];
3151 int bytes_read = file.Read(0, data_read, kExtendedFileLength);
3152 EXPECT_EQ(bytes_read, kExtendedFileLength);
3153 for (int i = 0; i < kTestFileLength; ++i)
3154 EXPECT_EQ(test_data[i], data_read[i]);
3155 for (int i = kTestFileLength; i < kExtendedFileLength; ++i)
3156 EXPECT_EQ(0, data_read[i]);
3157 }
3158
TEST_F(FileUtilTest,AllocateFileRegionTest_NonZeroOffset)3159 TEST_F(FileUtilTest, AllocateFileRegionTest_NonZeroOffset) {
3160 const int kTestFileLength = 9;
3161 char test_data[] = "test_data";
3162 FilePath file_path = temp_dir_.GetPath().Append(
3163 FILE_PATH_LITERAL("allocate_file_region_test_non_zero_offset"));
3164 WriteFile(file_path, test_data, kTestFileLength);
3165
3166 File file(file_path, base::File::FLAG_OPEN | base::File::FLAG_READ |
3167 base::File::FLAG_WRITE);
3168 ASSERT_TRUE(file.IsValid());
3169 ASSERT_EQ(file.GetLength(), kTestFileLength);
3170
3171 const int kExtensionOffset = 5;
3172 const int kExtensionSize = 10;
3173 ASSERT_TRUE(AllocateFileRegion(&file, kExtensionOffset, kExtensionSize));
3174 const int kExtendedFileLength = kExtensionOffset + kExtensionSize;
3175 EXPECT_EQ(file.GetLength(), kExtendedFileLength);
3176
3177 char data_read[32];
3178 int bytes_read = file.Read(0, data_read, kExtendedFileLength);
3179 EXPECT_EQ(bytes_read, kExtendedFileLength);
3180 for (int i = 0; i < kTestFileLength; ++i)
3181 EXPECT_EQ(test_data[i], data_read[i]);
3182 for (int i = kTestFileLength; i < kExtendedFileLength; ++i)
3183 EXPECT_EQ(0, data_read[i]);
3184 }
3185
TEST_F(FileUtilTest,AllocateFileRegionTest_DontTruncate)3186 TEST_F(FileUtilTest, AllocateFileRegionTest_DontTruncate) {
3187 const int kTestFileLength = 9;
3188 char test_data[] = "test_data";
3189 FilePath file_path = temp_dir_.GetPath().Append(
3190 FILE_PATH_LITERAL("allocate_file_region_test_dont_truncate"));
3191 WriteFile(file_path, test_data, kTestFileLength);
3192
3193 File file(file_path, base::File::FLAG_OPEN | base::File::FLAG_READ |
3194 base::File::FLAG_WRITE);
3195 ASSERT_TRUE(file.IsValid());
3196 ASSERT_EQ(file.GetLength(), kTestFileLength);
3197
3198 const int kTruncatedFileLength = 4;
3199 ASSERT_TRUE(AllocateFileRegion(&file, 0, kTruncatedFileLength));
3200 EXPECT_EQ(file.GetLength(), kTestFileLength);
3201 }
3202 #endif
3203
TEST_F(FileUtilTest,GetHomeDirTest)3204 TEST_F(FileUtilTest, GetHomeDirTest) {
3205 #if !BUILDFLAG(IS_ANDROID) // Not implemented on Android.
3206 // We don't actually know what the home directory is supposed to be without
3207 // calling some OS functions which would just duplicate the implementation.
3208 // So here we just test that it returns something "reasonable".
3209 FilePath home = GetHomeDir();
3210 ASSERT_FALSE(home.empty());
3211 ASSERT_TRUE(home.IsAbsolute());
3212 #endif
3213 }
3214
TEST_F(FileUtilTest,CreateDirectoryTest)3215 TEST_F(FileUtilTest, CreateDirectoryTest) {
3216 FilePath test_root =
3217 temp_dir_.GetPath().Append(FILE_PATH_LITERAL("create_directory_test"));
3218 #if BUILDFLAG(IS_WIN)
3219 FilePath test_path =
3220 test_root.Append(FILE_PATH_LITERAL("dir\\tree\\likely\\doesnt\\exist\\"));
3221 #elif BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
3222 FilePath test_path =
3223 test_root.Append(FILE_PATH_LITERAL("dir/tree/likely/doesnt/exist/"));
3224 #endif
3225
3226 EXPECT_FALSE(PathExists(test_path));
3227 EXPECT_TRUE(CreateDirectory(test_path));
3228 EXPECT_TRUE(PathExists(test_path));
3229 // CreateDirectory returns true if the DirectoryExists returns true.
3230 EXPECT_TRUE(CreateDirectory(test_path));
3231
3232 // Doesn't work to create it on top of a non-dir
3233 test_path = test_path.Append(FILE_PATH_LITERAL("foobar.txt"));
3234 EXPECT_FALSE(PathExists(test_path));
3235 CreateTextFile(test_path, L"test file");
3236 EXPECT_TRUE(PathExists(test_path));
3237 EXPECT_FALSE(CreateDirectory(test_path));
3238
3239 EXPECT_TRUE(DeletePathRecursively(test_root));
3240 EXPECT_FALSE(PathExists(test_root));
3241 EXPECT_FALSE(PathExists(test_path));
3242
3243 // Verify assumptions made by the Windows implementation:
3244 // 1. The current directory always exists.
3245 // 2. The root directory always exists.
3246 ASSERT_TRUE(DirectoryExists(FilePath(FilePath::kCurrentDirectory)));
3247 FilePath top_level = test_root;
3248 while (top_level != top_level.DirName()) {
3249 top_level = top_level.DirName();
3250 }
3251 ASSERT_TRUE(DirectoryExists(top_level));
3252
3253 // Given these assumptions hold, it should be safe to
3254 // test that "creating" these directories succeeds.
3255 EXPECT_TRUE(CreateDirectory(
3256 FilePath(FilePath::kCurrentDirectory)));
3257 EXPECT_TRUE(CreateDirectory(top_level));
3258
3259 #if BUILDFLAG(IS_WIN)
3260 FilePath invalid_drive(FILE_PATH_LITERAL("o:\\"));
3261 FilePath invalid_path =
3262 invalid_drive.Append(FILE_PATH_LITERAL("some\\inaccessible\\dir"));
3263 if (!PathExists(invalid_drive)) {
3264 EXPECT_FALSE(CreateDirectory(invalid_path));
3265 }
3266 #endif
3267 }
3268
TEST_F(FileUtilTest,DetectDirectoryTest)3269 TEST_F(FileUtilTest, DetectDirectoryTest) {
3270 // Check a directory
3271 FilePath test_root =
3272 temp_dir_.GetPath().Append(FILE_PATH_LITERAL("detect_directory_test"));
3273 EXPECT_FALSE(PathExists(test_root));
3274 EXPECT_TRUE(CreateDirectory(test_root));
3275 EXPECT_TRUE(PathExists(test_root));
3276 EXPECT_TRUE(DirectoryExists(test_root));
3277 // Check a file
3278 FilePath test_path =
3279 test_root.Append(FILE_PATH_LITERAL("foobar.txt"));
3280 EXPECT_FALSE(PathExists(test_path));
3281 CreateTextFile(test_path, L"test file");
3282 EXPECT_TRUE(PathExists(test_path));
3283 EXPECT_FALSE(DirectoryExists(test_path));
3284 EXPECT_TRUE(DeleteFile(test_path));
3285
3286 EXPECT_TRUE(DeletePathRecursively(test_root));
3287 }
3288
TEST_F(FileUtilTest,FileEnumeratorTest)3289 TEST_F(FileUtilTest, FileEnumeratorTest) {
3290 // Test an empty directory.
3291 FileEnumerator f0(temp_dir_.GetPath(), true, FILES_AND_DIRECTORIES);
3292 EXPECT_EQ(FPL(""), f0.Next().value());
3293 EXPECT_EQ(FPL(""), f0.Next().value());
3294
3295 // Test an empty directory, non-recursively, including "..".
3296 FileEnumerator f0_dotdot(
3297 temp_dir_.GetPath(), false,
3298 FILES_AND_DIRECTORIES | FileEnumerator::INCLUDE_DOT_DOT);
3299 EXPECT_EQ(temp_dir_.GetPath().Append(FPL("..")).value(),
3300 f0_dotdot.Next().value());
3301 EXPECT_EQ(FPL(""), f0_dotdot.Next().value());
3302
3303 // create the directories
3304 FilePath dir1 = temp_dir_.GetPath().Append(FPL("dir1"));
3305 EXPECT_TRUE(CreateDirectory(dir1));
3306 FilePath dir2 = temp_dir_.GetPath().Append(FPL("dir2"));
3307 EXPECT_TRUE(CreateDirectory(dir2));
3308 FilePath dir2inner = dir2.Append(FPL("inner"));
3309 EXPECT_TRUE(CreateDirectory(dir2inner));
3310
3311 // create the files
3312 FilePath dir2file = dir2.Append(FPL("dir2file.txt"));
3313 CreateTextFile(dir2file, std::wstring());
3314 FilePath dir2innerfile = dir2inner.Append(FPL("innerfile.txt"));
3315 CreateTextFile(dir2innerfile, std::wstring());
3316 FilePath file1 = temp_dir_.GetPath().Append(FPL("file1.txt"));
3317 CreateTextFile(file1, std::wstring());
3318 FilePath file2_rel = dir2.Append(FilePath::kParentDirectory)
3319 .Append(FPL("file2.txt"));
3320 CreateTextFile(file2_rel, std::wstring());
3321 FilePath file2_abs = temp_dir_.GetPath().Append(FPL("file2.txt"));
3322
3323 // Only enumerate files.
3324 FileEnumerator f1(temp_dir_.GetPath(), true, FileEnumerator::FILES);
3325 FindResultCollector c1(&f1);
3326 EXPECT_TRUE(c1.HasFile(file1));
3327 EXPECT_TRUE(c1.HasFile(file2_abs));
3328 EXPECT_TRUE(c1.HasFile(dir2file));
3329 EXPECT_TRUE(c1.HasFile(dir2innerfile));
3330 EXPECT_EQ(4, c1.size());
3331
3332 // Only enumerate directories.
3333 FileEnumerator f2(temp_dir_.GetPath(), true, FileEnumerator::DIRECTORIES);
3334 FindResultCollector c2(&f2);
3335 EXPECT_TRUE(c2.HasFile(dir1));
3336 EXPECT_TRUE(c2.HasFile(dir2));
3337 EXPECT_TRUE(c2.HasFile(dir2inner));
3338 EXPECT_EQ(3, c2.size());
3339
3340 // Only enumerate directories non-recursively.
3341 FileEnumerator f2_non_recursive(temp_dir_.GetPath(), false,
3342 FileEnumerator::DIRECTORIES);
3343 FindResultCollector c2_non_recursive(&f2_non_recursive);
3344 EXPECT_TRUE(c2_non_recursive.HasFile(dir1));
3345 EXPECT_TRUE(c2_non_recursive.HasFile(dir2));
3346 EXPECT_EQ(2, c2_non_recursive.size());
3347
3348 // Only enumerate directories, non-recursively, including "..".
3349 FileEnumerator f2_dotdot(
3350 temp_dir_.GetPath(), false,
3351 FileEnumerator::DIRECTORIES | FileEnumerator::INCLUDE_DOT_DOT);
3352 FindResultCollector c2_dotdot(&f2_dotdot);
3353 EXPECT_TRUE(c2_dotdot.HasFile(dir1));
3354 EXPECT_TRUE(c2_dotdot.HasFile(dir2));
3355 EXPECT_TRUE(c2_dotdot.HasFile(temp_dir_.GetPath().Append(FPL(".."))));
3356 EXPECT_EQ(3, c2_dotdot.size());
3357
3358 // Enumerate files and directories.
3359 FileEnumerator f3(temp_dir_.GetPath(), true, FILES_AND_DIRECTORIES);
3360 FindResultCollector c3(&f3);
3361 EXPECT_TRUE(c3.HasFile(dir1));
3362 EXPECT_TRUE(c3.HasFile(dir2));
3363 EXPECT_TRUE(c3.HasFile(file1));
3364 EXPECT_TRUE(c3.HasFile(file2_abs));
3365 EXPECT_TRUE(c3.HasFile(dir2file));
3366 EXPECT_TRUE(c3.HasFile(dir2inner));
3367 EXPECT_TRUE(c3.HasFile(dir2innerfile));
3368 EXPECT_EQ(7, c3.size());
3369
3370 // Non-recursive operation.
3371 FileEnumerator f4(temp_dir_.GetPath(), false, FILES_AND_DIRECTORIES);
3372 FindResultCollector c4(&f4);
3373 EXPECT_TRUE(c4.HasFile(dir2));
3374 EXPECT_TRUE(c4.HasFile(dir2));
3375 EXPECT_TRUE(c4.HasFile(file1));
3376 EXPECT_TRUE(c4.HasFile(file2_abs));
3377 EXPECT_EQ(4, c4.size());
3378
3379 // Enumerate with a pattern.
3380 FileEnumerator f5(temp_dir_.GetPath(), true, FILES_AND_DIRECTORIES,
3381 FPL("dir*"));
3382 FindResultCollector c5(&f5);
3383 EXPECT_TRUE(c5.HasFile(dir1));
3384 EXPECT_TRUE(c5.HasFile(dir2));
3385 EXPECT_TRUE(c5.HasFile(dir2file));
3386 EXPECT_TRUE(c5.HasFile(dir2inner));
3387 EXPECT_TRUE(c5.HasFile(dir2innerfile));
3388 EXPECT_EQ(5, c5.size());
3389
3390 #if BUILDFLAG(IS_WIN)
3391 {
3392 // Make dir1 point to dir2.
3393 auto reparse_point = test::FilePathReparsePoint::Create(dir1, dir2);
3394 EXPECT_TRUE(reparse_point.has_value());
3395
3396 // There can be a delay for the enumeration code to see the change on
3397 // the file system so skip this test for XP.
3398 // Enumerate the reparse point.
3399 FileEnumerator f6(dir1, true, FILES_AND_DIRECTORIES);
3400 FindResultCollector c6(&f6);
3401 FilePath inner2 = dir1.Append(FPL("inner"));
3402 EXPECT_TRUE(c6.HasFile(inner2));
3403 EXPECT_TRUE(c6.HasFile(inner2.Append(FPL("innerfile.txt"))));
3404 EXPECT_TRUE(c6.HasFile(dir1.Append(FPL("dir2file.txt"))));
3405 EXPECT_EQ(3, c6.size());
3406
3407 // No changes for non recursive operation.
3408 FileEnumerator f7(temp_dir_.GetPath(), false, FILES_AND_DIRECTORIES);
3409 FindResultCollector c7(&f7);
3410 EXPECT_TRUE(c7.HasFile(dir2));
3411 EXPECT_TRUE(c7.HasFile(dir2));
3412 EXPECT_TRUE(c7.HasFile(file1));
3413 EXPECT_TRUE(c7.HasFile(file2_abs));
3414 EXPECT_EQ(4, c7.size());
3415
3416 // Should not enumerate inside dir1 when using recursion.
3417 FileEnumerator f8(temp_dir_.GetPath(), true, FILES_AND_DIRECTORIES);
3418 FindResultCollector c8(&f8);
3419 EXPECT_TRUE(c8.HasFile(dir1));
3420 EXPECT_TRUE(c8.HasFile(dir2));
3421 EXPECT_TRUE(c8.HasFile(file1));
3422 EXPECT_TRUE(c8.HasFile(file2_abs));
3423 EXPECT_TRUE(c8.HasFile(dir2file));
3424 EXPECT_TRUE(c8.HasFile(dir2inner));
3425 EXPECT_TRUE(c8.HasFile(dir2innerfile));
3426 EXPECT_EQ(7, c8.size());
3427 }
3428 #endif
3429
3430 // Make sure the destructor closes the find handle while in the middle of a
3431 // query to allow TearDown to delete the directory.
3432 FileEnumerator f9(temp_dir_.GetPath(), true, FILES_AND_DIRECTORIES);
3433 EXPECT_FALSE(f9.Next().value().empty()); // Should have found something
3434 // (we don't care what).
3435 }
3436
TEST_F(FileUtilTest,AppendToFile)3437 TEST_F(FileUtilTest, AppendToFile) {
3438 FilePath data_dir =
3439 temp_dir_.GetPath().Append(FILE_PATH_LITERAL("FilePathTest"));
3440
3441 // Create a fresh, empty copy of this directory.
3442 if (PathExists(data_dir)) {
3443 ASSERT_TRUE(DeletePathRecursively(data_dir));
3444 }
3445 ASSERT_TRUE(CreateDirectory(data_dir));
3446
3447 // Create a fresh, empty copy of this directory.
3448 if (PathExists(data_dir)) {
3449 ASSERT_TRUE(DeletePathRecursively(data_dir));
3450 }
3451 ASSERT_TRUE(CreateDirectory(data_dir));
3452 FilePath foobar(data_dir.Append(FILE_PATH_LITERAL("foobar.txt")));
3453
3454 std::string data("hello");
3455 EXPECT_FALSE(AppendToFile(foobar, data));
3456 EXPECT_TRUE(WriteFile(foobar, data));
3457 EXPECT_TRUE(AppendToFile(foobar, data));
3458
3459 const std::wstring read_content = ReadTextFile(foobar);
3460 EXPECT_EQ(L"hellohello", read_content);
3461 }
3462
TEST_F(FileUtilTest,ReadFile)3463 TEST_F(FileUtilTest, ReadFile) {
3464 // Create a test file to be read.
3465 const std::string kTestData("The quick brown fox jumps over the lazy dog.");
3466 FilePath file_path =
3467 temp_dir_.GetPath().Append(FILE_PATH_LITERAL("ReadFileTest"));
3468
3469 ASSERT_TRUE(WriteFile(file_path, kTestData));
3470
3471 // Make buffers with various size.
3472 std::vector<char> small_buffer(kTestData.size() / 2);
3473 std::vector<char> exact_buffer(kTestData.size());
3474 std::vector<char> large_buffer(kTestData.size() * 2);
3475
3476 // Read the file with smaller buffer.
3477 EXPECT_EQ(ReadFile(file_path, small_buffer), small_buffer.size());
3478 EXPECT_EQ(
3479 std::string(kTestData.begin(), kTestData.begin() + small_buffer.size()),
3480 std::string(small_buffer.begin(), small_buffer.end()));
3481
3482 // Read the file with buffer which have exactly same size.
3483 EXPECT_EQ(ReadFile(file_path, exact_buffer), kTestData.size());
3484 EXPECT_EQ(kTestData, std::string(exact_buffer.begin(), exact_buffer.end()));
3485
3486 // Read the file with larger buffer.
3487 EXPECT_EQ(ReadFile(file_path, large_buffer), kTestData.size());
3488 EXPECT_EQ(kTestData, std::string(large_buffer.begin(),
3489 large_buffer.begin() + kTestData.size()));
3490
3491 // Make sure the read fails if the file doesn't exist.
3492 FilePath file_path_not_exist =
3493 temp_dir_.GetPath().Append(FILE_PATH_LITERAL("ReadFileNotExistTest"));
3494 EXPECT_EQ(ReadFile(file_path_not_exist, exact_buffer), std::nullopt);
3495 }
3496
TEST_F(FileUtilTest,ReadFileToBytes)3497 TEST_F(FileUtilTest, ReadFileToBytes) {
3498 const std::vector<uint8_t> kTestData = {'0', '1', '2', '3'};
3499
3500 FilePath file_path =
3501 temp_dir_.GetPath().Append(FILE_PATH_LITERAL("ReadFileToStringTest"));
3502 FilePath file_path_dangerous =
3503 temp_dir_.GetPath()
3504 .Append(FILE_PATH_LITERAL(".."))
3505 .Append(temp_dir_.GetPath().BaseName())
3506 .Append(FILE_PATH_LITERAL("ReadFileToStringTest"));
3507
3508 // Create test file.
3509 ASSERT_TRUE(WriteFile(file_path, kTestData));
3510
3511 std::optional<std::vector<uint8_t>> bytes = ReadFileToBytes(file_path);
3512 ASSERT_TRUE(bytes.has_value());
3513 EXPECT_EQ(kTestData, bytes);
3514
3515 // Write empty file.
3516 ASSERT_TRUE(WriteFile(file_path, ""));
3517 bytes = ReadFileToBytes(file_path);
3518 ASSERT_TRUE(bytes.has_value());
3519 EXPECT_TRUE(bytes->empty());
3520
3521 ASSERT_FALSE(ReadFileToBytes(file_path_dangerous));
3522 }
3523
TEST_F(FileUtilTest,ReadFileToString)3524 TEST_F(FileUtilTest, ReadFileToString) {
3525 const char kTestData[] = "0123";
3526 std::string data;
3527
3528 FilePath file_path =
3529 temp_dir_.GetPath().Append(FILE_PATH_LITERAL("ReadFileToStringTest"));
3530 FilePath file_path_dangerous =
3531 temp_dir_.GetPath()
3532 .Append(FILE_PATH_LITERAL(".."))
3533 .Append(temp_dir_.GetPath().BaseName())
3534 .Append(FILE_PATH_LITERAL("ReadFileToStringTest"));
3535
3536 // Create test file.
3537 ASSERT_TRUE(WriteFile(file_path, kTestData));
3538
3539 EXPECT_TRUE(ReadFileToString(file_path, &data));
3540 EXPECT_EQ(kTestData, data);
3541
3542 data = "temp";
3543 EXPECT_FALSE(ReadFileToStringWithMaxSize(file_path, &data, 0));
3544 EXPECT_EQ(0u, data.length());
3545
3546 data = "temp";
3547 EXPECT_FALSE(ReadFileToStringWithMaxSize(file_path, &data, 2));
3548 EXPECT_EQ("01", data);
3549
3550 data = "temp";
3551 EXPECT_FALSE(ReadFileToStringWithMaxSize(file_path, &data, 3));
3552 EXPECT_EQ("012", data);
3553
3554 data = "temp";
3555 EXPECT_TRUE(ReadFileToStringWithMaxSize(file_path, &data, 4));
3556 EXPECT_EQ("0123", data);
3557
3558 data = "temp";
3559 EXPECT_TRUE(ReadFileToStringWithMaxSize(file_path, &data, 6));
3560 EXPECT_EQ("0123", data);
3561
3562 EXPECT_TRUE(ReadFileToStringWithMaxSize(file_path, nullptr, 6));
3563
3564 EXPECT_TRUE(ReadFileToString(file_path, nullptr));
3565
3566 data = "temp";
3567 EXPECT_FALSE(ReadFileToString(file_path_dangerous, &data));
3568 EXPECT_EQ(0u, data.length());
3569
3570 // Delete test file.
3571 EXPECT_TRUE(DeleteFile(file_path));
3572
3573 data = "temp";
3574 EXPECT_FALSE(ReadFileToString(file_path, &data));
3575 EXPECT_EQ(0u, data.length());
3576
3577 data = "temp";
3578 EXPECT_FALSE(ReadFileToStringWithMaxSize(file_path, &data, 6));
3579 EXPECT_EQ(0u, data.length());
3580 }
3581
3582 #if !BUILDFLAG(IS_WIN)
TEST_F(FileUtilTest,ReadFileToStringWithUnknownFileSize)3583 TEST_F(FileUtilTest, ReadFileToStringWithUnknownFileSize) {
3584 #if BUILDFLAG(IS_FUCHSIA)
3585 test::TaskEnvironment task_environment;
3586 auto dev_zero = ScopedDevZero::Get();
3587 ASSERT_TRUE(dev_zero);
3588 #endif
3589 FilePath file_path("/dev/zero");
3590 std::string data = "temp";
3591
3592 EXPECT_FALSE(ReadFileToStringWithMaxSize(file_path, &data, 0));
3593 EXPECT_EQ(0u, data.length());
3594
3595 data = "temp";
3596 EXPECT_FALSE(ReadFileToStringWithMaxSize(file_path, &data, 2));
3597 EXPECT_EQ(std::string(2, '\0'), data);
3598
3599 EXPECT_FALSE(ReadFileToStringWithMaxSize(file_path, nullptr, 6));
3600
3601 // Read more than buffer size.
3602 data = "temp";
3603 EXPECT_FALSE(ReadFileToStringWithMaxSize(file_path, &data, kLargeFileSize));
3604 EXPECT_EQ(kLargeFileSize, data.length());
3605 EXPECT_EQ(std::string(kLargeFileSize, '\0'), data);
3606
3607 EXPECT_FALSE(ReadFileToStringWithMaxSize(file_path, nullptr, kLargeFileSize));
3608 }
3609 #endif // !BUILDFLAG(IS_WIN)
3610
3611 #if !BUILDFLAG(IS_WIN) && !BUILDFLAG(IS_NACL) && !BUILDFLAG(IS_FUCHSIA) && \
3612 !BUILDFLAG(IS_IOS)
3613 #define ChildMain WriteToPipeChildMain
3614 #define ChildMainString "WriteToPipeChildMain"
3615
MULTIPROCESS_TEST_MAIN(ChildMain)3616 MULTIPROCESS_TEST_MAIN(ChildMain) {
3617 const char kTestData[] = "0123";
3618 CommandLine* command_line = CommandLine::ForCurrentProcess();
3619 const FilePath pipe_path = command_line->GetSwitchValuePath("pipe-path");
3620
3621 int fd = open(pipe_path.value().c_str(), O_WRONLY);
3622 CHECK_NE(-1, fd);
3623 size_t written = 0;
3624 while (written < strlen(kTestData)) {
3625 ssize_t res = write(fd, kTestData + written, strlen(kTestData) - written);
3626 if (res == -1)
3627 break;
3628 written += res;
3629 }
3630 CHECK_EQ(strlen(kTestData), written);
3631 CHECK_EQ(0, close(fd));
3632 return 0;
3633 }
3634
3635 #define MoreThanBufferSizeChildMain WriteToPipeMoreThanBufferSizeChildMain
3636 #define MoreThanBufferSizeChildMainString \
3637 "WriteToPipeMoreThanBufferSizeChildMain"
3638
MULTIPROCESS_TEST_MAIN(MoreThanBufferSizeChildMain)3639 MULTIPROCESS_TEST_MAIN(MoreThanBufferSizeChildMain) {
3640 std::string data(kLargeFileSize, 'c');
3641 CommandLine* command_line = CommandLine::ForCurrentProcess();
3642 const FilePath pipe_path = command_line->GetSwitchValuePath("pipe-path");
3643
3644 int fd = open(pipe_path.value().c_str(), O_WRONLY);
3645 CHECK_NE(-1, fd);
3646
3647 size_t written = 0;
3648 while (written < data.size()) {
3649 ssize_t res = write(fd, data.c_str() + written, data.size() - written);
3650 if (res == -1) {
3651 // We are unable to write because reading process has already read
3652 // requested number of bytes and closed pipe.
3653 break;
3654 }
3655 written += res;
3656 }
3657 CHECK_EQ(0, close(fd));
3658 return 0;
3659 }
3660
TEST_F(FileUtilTest,ReadFileToStringWithNamedPipe)3661 TEST_F(FileUtilTest, ReadFileToStringWithNamedPipe) {
3662 FilePath pipe_path =
3663 temp_dir_.GetPath().Append(FILE_PATH_LITERAL("test_pipe"));
3664 ASSERT_EQ(0, mkfifo(pipe_path.value().c_str(), 0600));
3665
3666 CommandLine child_command_line(GetMultiProcessTestChildBaseCommandLine());
3667 child_command_line.AppendSwitchPath("pipe-path", pipe_path);
3668
3669 {
3670 Process child_process = SpawnMultiProcessTestChild(
3671 ChildMainString, child_command_line, LaunchOptions());
3672 ASSERT_TRUE(child_process.IsValid());
3673
3674 std::string data = "temp";
3675 EXPECT_FALSE(ReadFileToStringWithMaxSize(pipe_path, &data, 2));
3676 EXPECT_EQ("01", data);
3677
3678 int rv = -1;
3679 ASSERT_TRUE(WaitForMultiprocessTestChildExit(
3680 child_process, TestTimeouts::action_timeout(), &rv));
3681 ASSERT_EQ(0, rv);
3682 }
3683 {
3684 Process child_process = SpawnMultiProcessTestChild(
3685 ChildMainString, child_command_line, LaunchOptions());
3686 ASSERT_TRUE(child_process.IsValid());
3687
3688 std::string data = "temp";
3689 EXPECT_TRUE(ReadFileToStringWithMaxSize(pipe_path, &data, 6));
3690 EXPECT_EQ("0123", data);
3691
3692 int rv = -1;
3693 ASSERT_TRUE(WaitForMultiprocessTestChildExit(
3694 child_process, TestTimeouts::action_timeout(), &rv));
3695 ASSERT_EQ(0, rv);
3696 }
3697 {
3698 Process child_process = SpawnMultiProcessTestChild(
3699 MoreThanBufferSizeChildMainString, child_command_line, LaunchOptions());
3700 ASSERT_TRUE(child_process.IsValid());
3701
3702 std::string data = "temp";
3703 EXPECT_FALSE(ReadFileToStringWithMaxSize(pipe_path, &data, 6));
3704 EXPECT_EQ("cccccc", data);
3705
3706 int rv = -1;
3707 ASSERT_TRUE(WaitForMultiprocessTestChildExit(
3708 child_process, TestTimeouts::action_timeout(), &rv));
3709 ASSERT_EQ(0, rv);
3710 }
3711 {
3712 Process child_process = SpawnMultiProcessTestChild(
3713 MoreThanBufferSizeChildMainString, child_command_line, LaunchOptions());
3714 ASSERT_TRUE(child_process.IsValid());
3715
3716 std::string data = "temp";
3717 EXPECT_FALSE(
3718 ReadFileToStringWithMaxSize(pipe_path, &data, kLargeFileSize - 1));
3719 EXPECT_EQ(std::string(kLargeFileSize - 1, 'c'), data);
3720
3721 int rv = -1;
3722 ASSERT_TRUE(WaitForMultiprocessTestChildExit(
3723 child_process, TestTimeouts::action_timeout(), &rv));
3724 ASSERT_EQ(0, rv);
3725 }
3726 {
3727 Process child_process = SpawnMultiProcessTestChild(
3728 MoreThanBufferSizeChildMainString, child_command_line, LaunchOptions());
3729 ASSERT_TRUE(child_process.IsValid());
3730
3731 std::string data = "temp";
3732 EXPECT_TRUE(ReadFileToStringWithMaxSize(pipe_path, &data, kLargeFileSize));
3733 EXPECT_EQ(std::string(kLargeFileSize, 'c'), data);
3734
3735 int rv = -1;
3736 ASSERT_TRUE(WaitForMultiprocessTestChildExit(
3737 child_process, TestTimeouts::action_timeout(), &rv));
3738 ASSERT_EQ(0, rv);
3739 }
3740 {
3741 Process child_process = SpawnMultiProcessTestChild(
3742 MoreThanBufferSizeChildMainString, child_command_line, LaunchOptions());
3743 ASSERT_TRUE(child_process.IsValid());
3744
3745 std::string data = "temp";
3746 EXPECT_TRUE(
3747 ReadFileToStringWithMaxSize(pipe_path, &data, kLargeFileSize * 5));
3748 EXPECT_EQ(std::string(kLargeFileSize, 'c'), data);
3749
3750 int rv = -1;
3751 ASSERT_TRUE(WaitForMultiprocessTestChildExit(
3752 child_process, TestTimeouts::action_timeout(), &rv));
3753 ASSERT_EQ(0, rv);
3754 }
3755
3756 ASSERT_EQ(0, unlink(pipe_path.value().c_str()));
3757 }
3758 #endif // !BUILDFLAG(IS_WIN) && !BUILDFLAG(IS_NACL) && !BUILDFLAG(IS_FUCHSIA)
3759 // && !BUILDFLAG(IS_IOS)
3760
3761 #if BUILDFLAG(IS_WIN)
3762 #define ChildMain WriteToPipeChildMain
3763 #define ChildMainString "WriteToPipeChildMain"
3764
MULTIPROCESS_TEST_MAIN(ChildMain)3765 MULTIPROCESS_TEST_MAIN(ChildMain) {
3766 const char kTestData[] = "0123";
3767 CommandLine* command_line = CommandLine::ForCurrentProcess();
3768 const FilePath pipe_path = command_line->GetSwitchValuePath("pipe-path");
3769 std::string switch_string = command_line->GetSwitchValueASCII("sync_event");
3770 EXPECT_FALSE(switch_string.empty());
3771 unsigned int switch_uint = 0;
3772 EXPECT_TRUE(StringToUint(switch_string, &switch_uint));
3773 win::ScopedHandle sync_event(win::Uint32ToHandle(switch_uint));
3774
3775 HANDLE ph = CreateNamedPipe(pipe_path.value().c_str(), PIPE_ACCESS_OUTBOUND,
3776 PIPE_WAIT, 1, 0, 0, 0, NULL);
3777 EXPECT_NE(ph, INVALID_HANDLE_VALUE);
3778 EXPECT_TRUE(SetEvent(sync_event.get()));
3779 if (!::ConnectNamedPipe(ph, /*lpOverlapped=*/nullptr)) {
3780 // ERROR_PIPE_CONNECTED means that the other side has already connected.
3781 auto error = ::GetLastError();
3782 EXPECT_EQ(error, DWORD{ERROR_PIPE_CONNECTED});
3783 }
3784
3785 DWORD written;
3786 EXPECT_TRUE(::WriteFile(ph, kTestData, strlen(kTestData), &written, NULL));
3787 EXPECT_EQ(strlen(kTestData), written);
3788 CloseHandle(ph);
3789 return 0;
3790 }
3791
3792 #define MoreThanBufferSizeChildMain WriteToPipeMoreThanBufferSizeChildMain
3793 #define MoreThanBufferSizeChildMainString \
3794 "WriteToPipeMoreThanBufferSizeChildMain"
3795
MULTIPROCESS_TEST_MAIN(MoreThanBufferSizeChildMain)3796 MULTIPROCESS_TEST_MAIN(MoreThanBufferSizeChildMain) {
3797 std::string data(kLargeFileSize, 'c');
3798 CommandLine* command_line = CommandLine::ForCurrentProcess();
3799 const FilePath pipe_path = command_line->GetSwitchValuePath("pipe-path");
3800 std::string switch_string = command_line->GetSwitchValueASCII("sync_event");
3801 EXPECT_FALSE(switch_string.empty());
3802 unsigned int switch_uint = 0;
3803 EXPECT_TRUE(StringToUint(switch_string, &switch_uint));
3804 win::ScopedHandle sync_event(win::Uint32ToHandle(switch_uint));
3805
3806 HANDLE ph = CreateNamedPipe(pipe_path.value().c_str(), PIPE_ACCESS_OUTBOUND,
3807 PIPE_WAIT, 1, data.size(), data.size(), 0, NULL);
3808 EXPECT_NE(ph, INVALID_HANDLE_VALUE);
3809 EXPECT_TRUE(SetEvent(sync_event.get()));
3810 if (!::ConnectNamedPipe(ph, /*lpOverlapped=*/nullptr)) {
3811 // ERROR_PIPE_CONNECTED means that the other side has already connected.
3812 auto error = ::GetLastError();
3813 EXPECT_EQ(error, DWORD{ERROR_PIPE_CONNECTED});
3814 }
3815
3816 DWORD written;
3817 EXPECT_TRUE(::WriteFile(ph, data.c_str(), data.size(), &written, NULL));
3818 EXPECT_EQ(data.size(), written);
3819 CloseHandle(ph);
3820 return 0;
3821 }
3822
TEST_F(FileUtilTest,ReadFileToStringWithNamedPipe)3823 TEST_F(FileUtilTest, ReadFileToStringWithNamedPipe) {
3824 FilePath pipe_path(FILE_PATH_LITERAL("\\\\.\\pipe\\test_pipe"));
3825 win::ScopedHandle sync_event(CreateEvent(0, false, false, nullptr));
3826
3827 CommandLine child_command_line(GetMultiProcessTestChildBaseCommandLine());
3828 child_command_line.AppendSwitchPath("pipe-path", pipe_path);
3829 child_command_line.AppendSwitchASCII(
3830 "sync_event", NumberToString(win::HandleToUint32(sync_event.get())));
3831
3832 LaunchOptions options;
3833 options.handles_to_inherit.push_back(sync_event.get());
3834
3835 {
3836 Process child_process = SpawnMultiProcessTestChild(
3837 ChildMainString, child_command_line, options);
3838 ASSERT_TRUE(child_process.IsValid());
3839 // Wait for pipe creation in child process.
3840 EXPECT_EQ(WAIT_OBJECT_0, WaitForSingleObject(sync_event.get(), INFINITE));
3841
3842 std::string data = "temp";
3843 EXPECT_FALSE(ReadFileToStringWithMaxSize(pipe_path, &data, 2));
3844 EXPECT_EQ("01", data);
3845
3846 int rv = -1;
3847 ASSERT_TRUE(WaitForMultiprocessTestChildExit(
3848 child_process, TestTimeouts::action_timeout(), &rv));
3849 ASSERT_EQ(0, rv);
3850 }
3851 {
3852 Process child_process = SpawnMultiProcessTestChild(
3853 ChildMainString, child_command_line, options);
3854 ASSERT_TRUE(child_process.IsValid());
3855 // Wait for pipe creation in child process.
3856 EXPECT_EQ(WAIT_OBJECT_0, WaitForSingleObject(sync_event.get(), INFINITE));
3857
3858 std::string data = "temp";
3859 EXPECT_TRUE(ReadFileToStringWithMaxSize(pipe_path, &data, 6));
3860 EXPECT_EQ("0123", data);
3861
3862 int rv = -1;
3863 ASSERT_TRUE(WaitForMultiprocessTestChildExit(
3864 child_process, TestTimeouts::action_timeout(), &rv));
3865 ASSERT_EQ(0, rv);
3866 }
3867 {
3868 Process child_process = SpawnMultiProcessTestChild(
3869 MoreThanBufferSizeChildMainString, child_command_line, options);
3870 ASSERT_TRUE(child_process.IsValid());
3871 // Wait for pipe creation in child process.
3872 EXPECT_EQ(WAIT_OBJECT_0, WaitForSingleObject(sync_event.get(), INFINITE));
3873
3874 std::string data = "temp";
3875 EXPECT_FALSE(ReadFileToStringWithMaxSize(pipe_path, &data, 6));
3876 EXPECT_EQ("cccccc", data);
3877
3878 int rv = -1;
3879 ASSERT_TRUE(WaitForMultiprocessTestChildExit(
3880 child_process, TestTimeouts::action_timeout(), &rv));
3881 ASSERT_EQ(0, rv);
3882 }
3883 {
3884 Process child_process = SpawnMultiProcessTestChild(
3885 MoreThanBufferSizeChildMainString, child_command_line, options);
3886 ASSERT_TRUE(child_process.IsValid());
3887 // Wait for pipe creation in child process.
3888 EXPECT_EQ(WAIT_OBJECT_0, WaitForSingleObject(sync_event.get(), INFINITE));
3889
3890 std::string data = "temp";
3891 EXPECT_FALSE(
3892 ReadFileToStringWithMaxSize(pipe_path, &data, kLargeFileSize - 1));
3893 EXPECT_EQ(std::string(kLargeFileSize - 1, 'c'), data);
3894
3895 int rv = -1;
3896 ASSERT_TRUE(WaitForMultiprocessTestChildExit(
3897 child_process, TestTimeouts::action_timeout(), &rv));
3898 ASSERT_EQ(0, rv);
3899 }
3900 {
3901 Process child_process = SpawnMultiProcessTestChild(
3902 MoreThanBufferSizeChildMainString, child_command_line, options);
3903 ASSERT_TRUE(child_process.IsValid());
3904 // Wait for pipe creation in child process.
3905 EXPECT_EQ(WAIT_OBJECT_0, WaitForSingleObject(sync_event.get(), INFINITE));
3906
3907 std::string data = "temp";
3908 EXPECT_TRUE(ReadFileToStringWithMaxSize(pipe_path, &data, kLargeFileSize));
3909 EXPECT_EQ(std::string(kLargeFileSize, 'c'), data);
3910
3911 int rv = -1;
3912 ASSERT_TRUE(WaitForMultiprocessTestChildExit(
3913 child_process, TestTimeouts::action_timeout(), &rv));
3914 ASSERT_EQ(0, rv);
3915 }
3916 {
3917 Process child_process = SpawnMultiProcessTestChild(
3918 MoreThanBufferSizeChildMainString, child_command_line, options);
3919 ASSERT_TRUE(child_process.IsValid());
3920 // Wait for pipe creation in child process.
3921 EXPECT_EQ(WAIT_OBJECT_0, WaitForSingleObject(sync_event.get(), INFINITE));
3922
3923 std::string data = "temp";
3924 EXPECT_TRUE(
3925 ReadFileToStringWithMaxSize(pipe_path, &data, kLargeFileSize * 5));
3926 EXPECT_EQ(std::string(kLargeFileSize, 'c'), data);
3927
3928 int rv = -1;
3929 ASSERT_TRUE(WaitForMultiprocessTestChildExit(
3930 child_process, TestTimeouts::action_timeout(), &rv));
3931 ASSERT_EQ(0, rv);
3932 }
3933 }
3934 #endif // BUILDFLAG(IS_WIN)
3935
3936 #if BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_APPLE)
TEST_F(FileUtilTest,ReadFileToStringWithProcFileSystem)3937 TEST_F(FileUtilTest, ReadFileToStringWithProcFileSystem) {
3938 FilePath file_path("/proc/cpuinfo");
3939 std::string data = "temp";
3940
3941 EXPECT_FALSE(ReadFileToStringWithMaxSize(file_path, &data, 0));
3942 EXPECT_EQ(0u, data.length());
3943
3944 data = "temp";
3945 EXPECT_FALSE(ReadFileToStringWithMaxSize(file_path, &data, 2));
3946 EXPECT_TRUE(EqualsCaseInsensitiveASCII("pr", data));
3947
3948 data = "temp";
3949 EXPECT_FALSE(ReadFileToStringWithMaxSize(file_path, &data, 4));
3950 EXPECT_TRUE(EqualsCaseInsensitiveASCII("proc", data));
3951
3952 EXPECT_FALSE(ReadFileToStringWithMaxSize(file_path, nullptr, 4));
3953 }
3954 #endif // BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_APPLE)
3955
TEST_F(FileUtilTest,ReadFileToStringWithLargeFile)3956 TEST_F(FileUtilTest, ReadFileToStringWithLargeFile) {
3957 std::string data(kLargeFileSize, 'c');
3958
3959 FilePath file_path =
3960 temp_dir_.GetPath().Append(FILE_PATH_LITERAL("ReadFileToStringTest"));
3961
3962 // Create test file.
3963 ASSERT_TRUE(WriteFile(file_path, data));
3964
3965 std::string actual_data = "temp";
3966 EXPECT_TRUE(ReadFileToString(file_path, &actual_data));
3967 EXPECT_EQ(data, actual_data);
3968
3969 actual_data = "temp";
3970 EXPECT_FALSE(ReadFileToStringWithMaxSize(file_path, &actual_data, 0));
3971 EXPECT_EQ(0u, actual_data.length());
3972
3973 // Read more than buffer size.
3974 actual_data = "temp";
3975 EXPECT_FALSE(
3976 ReadFileToStringWithMaxSize(file_path, &actual_data, kLargeFileSize - 1));
3977 EXPECT_EQ(std::string(kLargeFileSize - 1, 'c'), actual_data);
3978 }
3979
TEST_F(FileUtilTest,ReadStreamToString)3980 TEST_F(FileUtilTest, ReadStreamToString) {
3981 ScopedFILE stream(
3982 OpenFile(temp_dir_.GetPath().Append(FPL("hello.txt")), "wb+"));
3983 ASSERT_TRUE(stream);
3984 File file = FILEToFile(stream.get());
3985 ASSERT_TRUE(file.IsValid());
3986 ASSERT_EQ(fprintf(stream.get(), "there"), 5);
3987 ASSERT_EQ(fflush(stream.get()), 0);
3988
3989 std::string contents;
3990 EXPECT_TRUE(ReadStreamToString(stream.get(), &contents));
3991 EXPECT_EQ(contents, std::string("there"));
3992 }
3993
3994 #if BUILDFLAG(IS_POSIX)
TEST_F(FileUtilTest,ReadStreamToString_ZeroLengthFile)3995 TEST_F(FileUtilTest, ReadStreamToString_ZeroLengthFile) {
3996 Thread write_thread("write thread");
3997 ASSERT_TRUE(write_thread.Start());
3998
3999 const size_t kSizes[] = {0, 1, 4095, 4096, 4097, 65535, 65536, 65537};
4000
4001 for (size_t size : kSizes) {
4002 ScopedFD read_fd, write_fd;
4003 // Pipes have a length of zero when stat()'d.
4004 ASSERT_TRUE(CreatePipe(&read_fd, &write_fd, false /* non_blocking */));
4005
4006 std::string random_data;
4007 if (size > 0) {
4008 random_data = RandBytesAsString(size);
4009 }
4010 EXPECT_EQ(size, random_data.size());
4011 write_thread.task_runner()->PostTask(
4012 FROM_HERE,
4013 BindLambdaForTesting([random_data, write_fd = std::move(write_fd)]() {
4014 ASSERT_TRUE(WriteFileDescriptor(write_fd.get(), random_data));
4015 }));
4016
4017 ScopedFILE read_file(fdopen(read_fd.release(), "r"));
4018 ASSERT_TRUE(read_file);
4019
4020 std::string contents;
4021 EXPECT_TRUE(ReadStreamToString(read_file.get(), &contents));
4022 EXPECT_EQ(contents, random_data);
4023 }
4024 }
4025 #endif
4026
TEST_F(FileUtilTest,ReadStreamToStringWithMaxSize)4027 TEST_F(FileUtilTest, ReadStreamToStringWithMaxSize) {
4028 ScopedFILE stream(
4029 OpenFile(temp_dir_.GetPath().Append(FPL("hello.txt")), "wb+"));
4030 ASSERT_TRUE(stream);
4031 File file = FILEToFile(stream.get());
4032 ASSERT_TRUE(file.IsValid());
4033 ASSERT_EQ(fprintf(stream.get(), "there"), 5);
4034 ASSERT_EQ(fflush(stream.get()), 0);
4035
4036 std::string contents;
4037 EXPECT_FALSE(ReadStreamToStringWithMaxSize(stream.get(), 2, &contents));
4038 }
4039
TEST_F(FileUtilTest,ReadStreamToStringNullStream)4040 TEST_F(FileUtilTest, ReadStreamToStringNullStream) {
4041 std::string contents;
4042 EXPECT_FALSE(ReadStreamToString(nullptr, &contents));
4043 }
4044
TEST_F(FileUtilTest,TouchFile)4045 TEST_F(FileUtilTest, TouchFile) {
4046 FilePath data_dir =
4047 temp_dir_.GetPath().Append(FILE_PATH_LITERAL("FilePathTest"));
4048
4049 // Create a fresh, empty copy of this directory.
4050 if (PathExists(data_dir)) {
4051 ASSERT_TRUE(DeletePathRecursively(data_dir));
4052 }
4053 ASSERT_TRUE(CreateDirectory(data_dir));
4054
4055 FilePath foobar(data_dir.Append(FILE_PATH_LITERAL("foobar.txt")));
4056 std::string data("hello");
4057 ASSERT_TRUE(WriteFile(foobar, data));
4058
4059 Time access_time;
4060 // This timestamp is divisible by one day (in local timezone),
4061 // to make it work on FAT too.
4062 ASSERT_TRUE(Time::FromString("Wed, 16 Nov 1994, 00:00:00",
4063 &access_time));
4064
4065 Time modification_time;
4066 // Note that this timestamp is divisible by two (seconds) - FAT stores
4067 // modification times with 2s resolution.
4068 ASSERT_TRUE(Time::FromString("Tue, 15 Nov 1994, 12:45:26 GMT",
4069 &modification_time));
4070
4071 ASSERT_TRUE(TouchFile(foobar, access_time, modification_time));
4072 File::Info file_info;
4073 ASSERT_TRUE(GetFileInfo(foobar, &file_info));
4074 #if !BUILDFLAG(IS_FUCHSIA)
4075 // Access time is not supported on Fuchsia, see https://crbug.com/735233.
4076 EXPECT_EQ(access_time.ToInternalValue(),
4077 file_info.last_accessed.ToInternalValue());
4078 #endif
4079 EXPECT_EQ(modification_time.ToInternalValue(),
4080 file_info.last_modified.ToInternalValue());
4081 }
4082
TEST_F(FileUtilTest,WriteFileSpanVariant)4083 TEST_F(FileUtilTest, WriteFileSpanVariant) {
4084 FilePath empty_file =
4085 temp_dir_.GetPath().Append(FILE_PATH_LITERAL("empty_file"));
4086 ASSERT_FALSE(PathExists(empty_file));
4087 EXPECT_TRUE(WriteFile(empty_file, base::span<const uint8_t>()));
4088 EXPECT_TRUE(PathExists(empty_file));
4089
4090 std::string data = "not empty";
4091 EXPECT_TRUE(ReadFileToString(empty_file, &data));
4092 EXPECT_TRUE(data.empty());
4093
4094 FilePath write_span_file =
4095 temp_dir_.GetPath().Append(FILE_PATH_LITERAL("write_span_file"));
4096 ASSERT_FALSE(PathExists(write_span_file));
4097 static constexpr uint8_t kInput[] = {'h', 'e', 'l', 'l', 'o'};
4098 EXPECT_TRUE(WriteFile(write_span_file, kInput));
4099 EXPECT_TRUE(PathExists(write_span_file));
4100
4101 data.clear();
4102 EXPECT_TRUE(ReadFileToString(write_span_file, &data));
4103 EXPECT_EQ("hello", data);
4104 }
4105
TEST_F(FileUtilTest,WriteFileStringVariant)4106 TEST_F(FileUtilTest, WriteFileStringVariant) {
4107 FilePath empty_file =
4108 temp_dir_.GetPath().Append(FILE_PATH_LITERAL("empty_file"));
4109 ASSERT_FALSE(PathExists(empty_file));
4110 EXPECT_TRUE(WriteFile(empty_file, ""));
4111 EXPECT_TRUE(PathExists(empty_file));
4112
4113 std::string data = "not empty";
4114 EXPECT_TRUE(ReadFileToString(empty_file, &data));
4115 EXPECT_TRUE(data.empty());
4116
4117 FilePath write_span_file =
4118 temp_dir_.GetPath().Append(FILE_PATH_LITERAL("write_string_file"));
4119 ASSERT_FALSE(PathExists(write_span_file));
4120 EXPECT_TRUE(WriteFile(write_span_file, "world"));
4121 EXPECT_TRUE(PathExists(write_span_file));
4122
4123 data.clear();
4124 EXPECT_TRUE(ReadFileToString(write_span_file, &data));
4125 EXPECT_EQ("world", data);
4126 }
4127
TEST_F(FileUtilTest,IsDirectoryEmpty)4128 TEST_F(FileUtilTest, IsDirectoryEmpty) {
4129 FilePath empty_dir =
4130 temp_dir_.GetPath().Append(FILE_PATH_LITERAL("EmptyDir"));
4131
4132 ASSERT_FALSE(PathExists(empty_dir));
4133
4134 ASSERT_TRUE(CreateDirectory(empty_dir));
4135
4136 EXPECT_TRUE(IsDirectoryEmpty(empty_dir));
4137
4138 FilePath foo(empty_dir.Append(FILE_PATH_LITERAL("foo.txt")));
4139 std::string bar("baz");
4140 ASSERT_TRUE(WriteFile(foo, bar));
4141
4142 EXPECT_FALSE(IsDirectoryEmpty(empty_dir));
4143 }
4144
4145 #if BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
4146
TEST_F(FileUtilTest,SetNonBlocking)4147 TEST_F(FileUtilTest, SetNonBlocking) {
4148 const int kBogusFd = 99999;
4149 EXPECT_FALSE(SetNonBlocking(kBogusFd));
4150
4151 FilePath path;
4152 ASSERT_TRUE(PathService::Get(DIR_TEST_DATA, &path));
4153 path = path.Append(FPL("file_util")).Append(FPL("original.txt"));
4154 ScopedFD fd(open(path.value().c_str(), O_RDONLY));
4155 ASSERT_GE(fd.get(), 0);
4156 EXPECT_TRUE(SetNonBlocking(fd.get()));
4157 }
4158
TEST_F(FileUtilTest,SetCloseOnExec)4159 TEST_F(FileUtilTest, SetCloseOnExec) {
4160 const int kBogusFd = 99999;
4161 EXPECT_FALSE(SetCloseOnExec(kBogusFd));
4162
4163 FilePath path;
4164 ASSERT_TRUE(PathService::Get(DIR_TEST_DATA, &path));
4165 path = path.Append(FPL("file_util")).Append(FPL("original.txt"));
4166 ScopedFD fd(open(path.value().c_str(), O_RDONLY));
4167 ASSERT_GE(fd.get(), 0);
4168 EXPECT_TRUE(SetCloseOnExec(fd.get()));
4169 }
4170
4171 #endif
4172
4173 #if BUILDFLAG(IS_MAC)
4174
4175 // Testing VerifyPathControlledByAdmin() is hard, because there is no
4176 // way a test can make a file owned by root, or change file paths
4177 // at the root of the file system. VerifyPathControlledByAdmin()
4178 // is implemented as a call to VerifyPathControlledByUser, which gives
4179 // us the ability to test with paths under the test's temp directory,
4180 // using a user id we control.
4181 // Pull tests of VerifyPathControlledByUserTest() into a separate test class
4182 // with a common SetUp() method.
4183 class VerifyPathControlledByUserTest : public FileUtilTest {
4184 protected:
SetUp()4185 void SetUp() override {
4186 FileUtilTest::SetUp();
4187
4188 // Create a basic structure used by each test.
4189 // base_dir_
4190 // |-> sub_dir_
4191 // |-> text_file_
4192
4193 base_dir_ = temp_dir_.GetPath().AppendASCII("base_dir");
4194 ASSERT_TRUE(CreateDirectory(base_dir_));
4195
4196 sub_dir_ = base_dir_.AppendASCII("sub_dir");
4197 ASSERT_TRUE(CreateDirectory(sub_dir_));
4198
4199 text_file_ = sub_dir_.AppendASCII("file.txt");
4200 CreateTextFile(text_file_, L"This text file has some text in it.");
4201
4202 // Get the user and group files are created with from |base_dir_|.
4203 stat_wrapper_t stat_buf;
4204 ASSERT_EQ(0, File::Stat(base_dir_.value().c_str(), &stat_buf));
4205 uid_ = stat_buf.st_uid;
4206 ok_gids_.insert(stat_buf.st_gid);
4207 bad_gids_.insert(stat_buf.st_gid + 1);
4208
4209 ASSERT_EQ(uid_, getuid()); // This process should be the owner.
4210
4211 // To ensure that umask settings do not cause the initial state
4212 // of permissions to be different from what we expect, explicitly
4213 // set permissions on the directories we create.
4214 // Make all files and directories non-world-writable.
4215
4216 // Users and group can read, write, traverse
4217 int enabled_permissions =
4218 FILE_PERMISSION_USER_MASK | FILE_PERMISSION_GROUP_MASK;
4219 // Other users can't read, write, traverse
4220 int disabled_permissions = FILE_PERMISSION_OTHERS_MASK;
4221
4222 ASSERT_NO_FATAL_FAILURE(
4223 ChangePosixFilePermissions(
4224 base_dir_, enabled_permissions, disabled_permissions));
4225 ASSERT_NO_FATAL_FAILURE(
4226 ChangePosixFilePermissions(
4227 sub_dir_, enabled_permissions, disabled_permissions));
4228 }
4229
4230 FilePath base_dir_;
4231 FilePath sub_dir_;
4232 FilePath text_file_;
4233 uid_t uid_;
4234
4235 std::set<gid_t> ok_gids_;
4236 std::set<gid_t> bad_gids_;
4237 };
4238
TEST_F(VerifyPathControlledByUserTest,BadPaths)4239 TEST_F(VerifyPathControlledByUserTest, BadPaths) {
4240 // File does not exist.
4241 FilePath does_not_exist = base_dir_.AppendASCII("does")
4242 .AppendASCII("not")
4243 .AppendASCII("exist");
4244 EXPECT_FALSE(
4245 VerifyPathControlledByUser(base_dir_, does_not_exist, uid_, ok_gids_));
4246
4247 // |base| not a subpath of |path|.
4248 EXPECT_FALSE(VerifyPathControlledByUser(sub_dir_, base_dir_, uid_, ok_gids_));
4249
4250 // An empty base path will fail to be a prefix for any path.
4251 FilePath empty;
4252 EXPECT_FALSE(VerifyPathControlledByUser(empty, base_dir_, uid_, ok_gids_));
4253
4254 // Finding that a bad call fails proves nothing unless a good call succeeds.
4255 EXPECT_TRUE(VerifyPathControlledByUser(base_dir_, sub_dir_, uid_, ok_gids_));
4256 }
4257
TEST_F(VerifyPathControlledByUserTest,Symlinks)4258 TEST_F(VerifyPathControlledByUserTest, Symlinks) {
4259 // Symlinks in the path should cause failure.
4260
4261 // Symlink to the file at the end of the path.
4262 FilePath file_link = base_dir_.AppendASCII("file_link");
4263 ASSERT_TRUE(CreateSymbolicLink(text_file_, file_link))
4264 << "Failed to create symlink.";
4265
4266 EXPECT_FALSE(
4267 VerifyPathControlledByUser(base_dir_, file_link, uid_, ok_gids_));
4268 EXPECT_FALSE(
4269 VerifyPathControlledByUser(file_link, file_link, uid_, ok_gids_));
4270
4271 // Symlink from one directory to another within the path.
4272 FilePath link_to_sub_dir = base_dir_.AppendASCII("link_to_sub_dir");
4273 ASSERT_TRUE(CreateSymbolicLink(sub_dir_, link_to_sub_dir))
4274 << "Failed to create symlink.";
4275
4276 FilePath file_path_with_link = link_to_sub_dir.AppendASCII("file.txt");
4277 ASSERT_TRUE(PathExists(file_path_with_link));
4278
4279 EXPECT_FALSE(VerifyPathControlledByUser(base_dir_, file_path_with_link, uid_,
4280 ok_gids_));
4281
4282 EXPECT_FALSE(VerifyPathControlledByUser(link_to_sub_dir, file_path_with_link,
4283 uid_, ok_gids_));
4284
4285 // Symlinks in parents of base path are allowed.
4286 EXPECT_TRUE(VerifyPathControlledByUser(file_path_with_link,
4287 file_path_with_link, uid_, ok_gids_));
4288 }
4289
TEST_F(VerifyPathControlledByUserTest,OwnershipChecks)4290 TEST_F(VerifyPathControlledByUserTest, OwnershipChecks) {
4291 // Get a uid that is not the uid of files we create.
4292 uid_t bad_uid = uid_ + 1;
4293
4294 // Make all files and directories non-world-writable.
4295 ASSERT_NO_FATAL_FAILURE(
4296 ChangePosixFilePermissions(base_dir_, 0u, S_IWOTH));
4297 ASSERT_NO_FATAL_FAILURE(
4298 ChangePosixFilePermissions(sub_dir_, 0u, S_IWOTH));
4299 ASSERT_NO_FATAL_FAILURE(
4300 ChangePosixFilePermissions(text_file_, 0u, S_IWOTH));
4301
4302 // We control these paths.
4303 EXPECT_TRUE(VerifyPathControlledByUser(base_dir_, sub_dir_, uid_, ok_gids_));
4304 EXPECT_TRUE(
4305 VerifyPathControlledByUser(base_dir_, text_file_, uid_, ok_gids_));
4306 EXPECT_TRUE(VerifyPathControlledByUser(sub_dir_, text_file_, uid_, ok_gids_));
4307
4308 // Another user does not control these paths.
4309 EXPECT_FALSE(
4310 VerifyPathControlledByUser(base_dir_, sub_dir_, bad_uid, ok_gids_));
4311 EXPECT_FALSE(
4312 VerifyPathControlledByUser(base_dir_, text_file_, bad_uid, ok_gids_));
4313 EXPECT_FALSE(
4314 VerifyPathControlledByUser(sub_dir_, text_file_, bad_uid, ok_gids_));
4315
4316 // Another group does not control the paths.
4317 EXPECT_FALSE(
4318 VerifyPathControlledByUser(base_dir_, sub_dir_, uid_, bad_gids_));
4319 EXPECT_FALSE(
4320 VerifyPathControlledByUser(base_dir_, text_file_, uid_, bad_gids_));
4321 EXPECT_FALSE(
4322 VerifyPathControlledByUser(sub_dir_, text_file_, uid_, bad_gids_));
4323 }
4324
TEST_F(VerifyPathControlledByUserTest,GroupWriteTest)4325 TEST_F(VerifyPathControlledByUserTest, GroupWriteTest) {
4326 // Make all files and directories writable only by their owner.
4327 ASSERT_NO_FATAL_FAILURE(
4328 ChangePosixFilePermissions(base_dir_, 0u, S_IWOTH|S_IWGRP));
4329 ASSERT_NO_FATAL_FAILURE(
4330 ChangePosixFilePermissions(sub_dir_, 0u, S_IWOTH|S_IWGRP));
4331 ASSERT_NO_FATAL_FAILURE(
4332 ChangePosixFilePermissions(text_file_, 0u, S_IWOTH|S_IWGRP));
4333
4334 // Any group is okay because the path is not group-writable.
4335 EXPECT_TRUE(VerifyPathControlledByUser(base_dir_, sub_dir_, uid_, ok_gids_));
4336 EXPECT_TRUE(
4337 VerifyPathControlledByUser(base_dir_, text_file_, uid_, ok_gids_));
4338 EXPECT_TRUE(VerifyPathControlledByUser(sub_dir_, text_file_, uid_, ok_gids_));
4339
4340 EXPECT_TRUE(VerifyPathControlledByUser(base_dir_, sub_dir_, uid_, bad_gids_));
4341 EXPECT_TRUE(
4342 VerifyPathControlledByUser(base_dir_, text_file_, uid_, bad_gids_));
4343 EXPECT_TRUE(
4344 VerifyPathControlledByUser(sub_dir_, text_file_, uid_, bad_gids_));
4345
4346 // No group is okay, because we don't check the group
4347 // if no group can write.
4348 std::set<gid_t> no_gids; // Empty set of gids.
4349 EXPECT_TRUE(VerifyPathControlledByUser(base_dir_, sub_dir_, uid_, no_gids));
4350 EXPECT_TRUE(VerifyPathControlledByUser(base_dir_, text_file_, uid_, no_gids));
4351 EXPECT_TRUE(VerifyPathControlledByUser(sub_dir_, text_file_, uid_, no_gids));
4352
4353 // Make all files and directories writable by their group.
4354 ASSERT_NO_FATAL_FAILURE(ChangePosixFilePermissions(base_dir_, S_IWGRP, 0u));
4355 ASSERT_NO_FATAL_FAILURE(ChangePosixFilePermissions(sub_dir_, S_IWGRP, 0u));
4356 ASSERT_NO_FATAL_FAILURE(ChangePosixFilePermissions(text_file_, S_IWGRP, 0u));
4357
4358 // Now |ok_gids_| works, but |bad_gids_| fails.
4359 EXPECT_TRUE(VerifyPathControlledByUser(base_dir_, sub_dir_, uid_, ok_gids_));
4360 EXPECT_TRUE(
4361 VerifyPathControlledByUser(base_dir_, text_file_, uid_, ok_gids_));
4362 EXPECT_TRUE(VerifyPathControlledByUser(sub_dir_, text_file_, uid_, ok_gids_));
4363
4364 EXPECT_FALSE(
4365 VerifyPathControlledByUser(base_dir_, sub_dir_, uid_, bad_gids_));
4366 EXPECT_FALSE(
4367 VerifyPathControlledByUser(base_dir_, text_file_, uid_, bad_gids_));
4368 EXPECT_FALSE(
4369 VerifyPathControlledByUser(sub_dir_, text_file_, uid_, bad_gids_));
4370
4371 // Because any group in the group set is allowed,
4372 // the union of good and bad gids passes.
4373
4374 std::set<gid_t> multiple_gids;
4375 std::set_union(
4376 ok_gids_.begin(), ok_gids_.end(),
4377 bad_gids_.begin(), bad_gids_.end(),
4378 std::inserter(multiple_gids, multiple_gids.begin()));
4379
4380 EXPECT_TRUE(
4381 VerifyPathControlledByUser(base_dir_, sub_dir_, uid_, multiple_gids));
4382 EXPECT_TRUE(
4383 VerifyPathControlledByUser(base_dir_, text_file_, uid_, multiple_gids));
4384 EXPECT_TRUE(
4385 VerifyPathControlledByUser(sub_dir_, text_file_, uid_, multiple_gids));
4386 }
4387
TEST_F(VerifyPathControlledByUserTest,WriteBitChecks)4388 TEST_F(VerifyPathControlledByUserTest, WriteBitChecks) {
4389 // Make all files and directories non-world-writable.
4390 ASSERT_NO_FATAL_FAILURE(
4391 ChangePosixFilePermissions(base_dir_, 0u, S_IWOTH));
4392 ASSERT_NO_FATAL_FAILURE(
4393 ChangePosixFilePermissions(sub_dir_, 0u, S_IWOTH));
4394 ASSERT_NO_FATAL_FAILURE(
4395 ChangePosixFilePermissions(text_file_, 0u, S_IWOTH));
4396
4397 // Initialy, we control all parts of the path.
4398 EXPECT_TRUE(VerifyPathControlledByUser(base_dir_, sub_dir_, uid_, ok_gids_));
4399 EXPECT_TRUE(
4400 VerifyPathControlledByUser(base_dir_, text_file_, uid_, ok_gids_));
4401 EXPECT_TRUE(VerifyPathControlledByUser(sub_dir_, text_file_, uid_, ok_gids_));
4402
4403 // Make base_dir_ world-writable.
4404 ASSERT_NO_FATAL_FAILURE(
4405 ChangePosixFilePermissions(base_dir_, S_IWOTH, 0u));
4406 EXPECT_FALSE(VerifyPathControlledByUser(base_dir_, sub_dir_, uid_, ok_gids_));
4407 EXPECT_FALSE(
4408 VerifyPathControlledByUser(base_dir_, text_file_, uid_, ok_gids_));
4409 EXPECT_TRUE(VerifyPathControlledByUser(sub_dir_, text_file_, uid_, ok_gids_));
4410
4411 // Make sub_dir_ world writable.
4412 ASSERT_NO_FATAL_FAILURE(
4413 ChangePosixFilePermissions(sub_dir_, S_IWOTH, 0u));
4414 EXPECT_FALSE(VerifyPathControlledByUser(base_dir_, sub_dir_, uid_, ok_gids_));
4415 EXPECT_FALSE(
4416 VerifyPathControlledByUser(base_dir_, text_file_, uid_, ok_gids_));
4417 EXPECT_FALSE(
4418 VerifyPathControlledByUser(sub_dir_, text_file_, uid_, ok_gids_));
4419
4420 // Make text_file_ world writable.
4421 ASSERT_NO_FATAL_FAILURE(
4422 ChangePosixFilePermissions(text_file_, S_IWOTH, 0u));
4423 EXPECT_FALSE(VerifyPathControlledByUser(base_dir_, sub_dir_, uid_, ok_gids_));
4424 EXPECT_FALSE(
4425 VerifyPathControlledByUser(base_dir_, text_file_, uid_, ok_gids_));
4426 EXPECT_FALSE(
4427 VerifyPathControlledByUser(sub_dir_, text_file_, uid_, ok_gids_));
4428
4429 // Make sub_dir_ non-world writable.
4430 ASSERT_NO_FATAL_FAILURE(
4431 ChangePosixFilePermissions(sub_dir_, 0u, S_IWOTH));
4432 EXPECT_FALSE(VerifyPathControlledByUser(base_dir_, sub_dir_, uid_, ok_gids_));
4433 EXPECT_FALSE(
4434 VerifyPathControlledByUser(base_dir_, text_file_, uid_, ok_gids_));
4435 EXPECT_FALSE(
4436 VerifyPathControlledByUser(sub_dir_, text_file_, uid_, ok_gids_));
4437
4438 // Make base_dir_ non-world-writable.
4439 ASSERT_NO_FATAL_FAILURE(
4440 ChangePosixFilePermissions(base_dir_, 0u, S_IWOTH));
4441 EXPECT_TRUE(VerifyPathControlledByUser(base_dir_, sub_dir_, uid_, ok_gids_));
4442 EXPECT_FALSE(
4443 VerifyPathControlledByUser(base_dir_, text_file_, uid_, ok_gids_));
4444 EXPECT_FALSE(
4445 VerifyPathControlledByUser(sub_dir_, text_file_, uid_, ok_gids_));
4446
4447 // Back to the initial state: Nothing is writable, so every path
4448 // should pass.
4449 ASSERT_NO_FATAL_FAILURE(
4450 ChangePosixFilePermissions(text_file_, 0u, S_IWOTH));
4451 EXPECT_TRUE(VerifyPathControlledByUser(base_dir_, sub_dir_, uid_, ok_gids_));
4452 EXPECT_TRUE(
4453 VerifyPathControlledByUser(base_dir_, text_file_, uid_, ok_gids_));
4454 EXPECT_TRUE(VerifyPathControlledByUser(sub_dir_, text_file_, uid_, ok_gids_));
4455 }
4456
4457 #endif // BUILDFLAG(IS_MAC)
4458
4459 // Flaky test: crbug/1054637
4460 #if BUILDFLAG(IS_ANDROID)
TEST_F(FileUtilTest,DISABLED_ValidContentUriTest)4461 TEST_F(FileUtilTest, DISABLED_ValidContentUriTest) {
4462 // Get the test image path.
4463 FilePath data_dir;
4464 ASSERT_TRUE(PathService::Get(DIR_TEST_DATA, &data_dir));
4465 data_dir = data_dir.AppendASCII("file_util");
4466 ASSERT_TRUE(PathExists(data_dir));
4467 FilePath image_file = data_dir.Append(FILE_PATH_LITERAL("red.png"));
4468 int64_t image_size;
4469 GetFileSize(image_file, &image_size);
4470 ASSERT_GT(image_size, 0);
4471
4472 // Insert the image into MediaStore. MediaStore will do some conversions, and
4473 // return the content URI.
4474 FilePath path = InsertImageIntoMediaStore(image_file);
4475 EXPECT_TRUE(path.IsContentUri());
4476 EXPECT_TRUE(PathExists(path));
4477 // The file size may not equal to the input image as MediaStore may convert
4478 // the image.
4479 int64_t content_uri_size;
4480 GetFileSize(path, &content_uri_size);
4481 EXPECT_EQ(image_size, content_uri_size);
4482
4483 // We should be able to read the file.
4484 File file = OpenContentUriForRead(path);
4485 EXPECT_TRUE(file.IsValid());
4486 auto buffer = std::make_unique<char[]>(image_size);
4487 EXPECT_TRUE(file.ReadAtCurrentPos(buffer.get(), image_size));
4488 }
4489
TEST_F(FileUtilTest,NonExistentContentUriTest)4490 TEST_F(FileUtilTest, NonExistentContentUriTest) {
4491 FilePath path("content://foo.bar");
4492 EXPECT_TRUE(path.IsContentUri());
4493 EXPECT_FALSE(PathExists(path));
4494 // Size should be smaller than 0.
4495 int64_t size;
4496 EXPECT_FALSE(GetFileSize(path, &size));
4497
4498 // We should not be able to read the file.
4499 File file = OpenContentUriForRead(path);
4500 EXPECT_FALSE(file.IsValid());
4501 }
4502 #endif
4503
TEST_F(FileUtilTest,GetUniquePathNumberNoFile)4504 TEST_F(FileUtilTest, GetUniquePathNumberNoFile) {
4505 // This file does not exist.
4506 const FilePath some_file = temp_dir_.GetPath().Append(FPL("SomeFile.txt"));
4507
4508 // The path is unique as-is.
4509 EXPECT_EQ(GetUniquePathNumber(some_file), 0);
4510 }
4511
TEST_F(FileUtilTest,GetUniquePathNumberFileExists)4512 TEST_F(FileUtilTest, GetUniquePathNumberFileExists) {
4513 // Create a file with the desired path.
4514 const FilePath some_file = temp_dir_.GetPath().Append(FPL("SomeFile.txt"));
4515 ASSERT_TRUE(File(some_file, File::FLAG_CREATE | File::FLAG_WRITE).IsValid());
4516
4517 // The file exists, so the number 1 is needed to make it unique.
4518 EXPECT_EQ(GetUniquePathNumber(some_file), 1);
4519 }
4520
TEST_F(FileUtilTest,GetUniquePathNumberFilesExist)4521 TEST_F(FileUtilTest, GetUniquePathNumberFilesExist) {
4522 // Create a file with the desired path and with it suffixed with " (1)"
4523 const FilePath some_file = temp_dir_.GetPath().Append(FPL("SomeFile.txt"));
4524 ASSERT_TRUE(File(some_file, File::FLAG_CREATE | File::FLAG_WRITE).IsValid());
4525 const FilePath some_file_one =
4526 temp_dir_.GetPath().Append(FPL("SomeFile (1).txt"));
4527 ASSERT_TRUE(
4528 File(some_file_one, File::FLAG_CREATE | File::FLAG_WRITE).IsValid());
4529
4530 // This time the number 2 is needed to make it unique.
4531 EXPECT_EQ(GetUniquePathNumber(some_file), 2);
4532 }
4533
TEST_F(FileUtilTest,GetUniquePathNumberTooManyFiles)4534 TEST_F(FileUtilTest, GetUniquePathNumberTooManyFiles) {
4535 // Create a file with the desired path.
4536 const FilePath some_file = temp_dir_.GetPath().Append(FPL("SomeFile.txt"));
4537 ASSERT_TRUE(File(some_file, File::FLAG_CREATE | File::FLAG_WRITE).IsValid());
4538
4539 // Now create 100 collisions.
4540 for (int i = 1; i <= kMaxUniqueFiles; ++i) {
4541 ASSERT_EQ(GetUniquePathNumber(some_file), i);
4542 ASSERT_TRUE(File(temp_dir_.GetPath().AppendASCII(
4543 StringPrintf("SomeFile (%d).txt", i)),
4544 File::FLAG_CREATE | File::FLAG_WRITE)
4545 .IsValid());
4546 }
4547
4548 // Verify that the limit has been reached.
4549 EXPECT_EQ(GetUniquePathNumber(some_file), -1);
4550 }
4551
4552 #if BUILDFLAG(IS_WIN) && BUILDFLAG(GOOGLE_CHROME_BRANDING) && \
4553 defined(ARCH_CPU_32_BITS)
4554 // TODO(crbug.com/327582285): Re-enable these tests. They may be failing due to
4555 // prefetching failing under memory pressure.
4556 #define FLAKY_327582285 1
4557 #endif
4558
4559 #if defined(FLAKY_327582285)
4560 #define MAYBE_PreReadFileExistingFileNoSize \
4561 DISABLED_PreReadFileExistingFileNoSize
4562 #else
4563 #define MAYBE_PreReadFileExistingFileNoSize PreReadFileExistingFileNoSize
4564 #endif
TEST_F(FileUtilTest,MAYBE_PreReadFileExistingFileNoSize)4565 TEST_F(FileUtilTest, MAYBE_PreReadFileExistingFileNoSize) {
4566 FilePath text_file = temp_dir_.GetPath().Append(FPL("text_file"));
4567 CreateTextFile(text_file, bogus_content);
4568
4569 EXPECT_TRUE(
4570 PreReadFile(text_file, /*is_executable=*/false, /*sequential=*/false));
4571 }
4572
4573 #if defined(FLAKY_327582285)
4574 #define MAYBE_PreReadFileExistingFileExactSize \
4575 DISABLED_PreReadFileExistingFileExactSize
4576 #else
4577 #define MAYBE_PreReadFileExistingFileExactSize PreReadFileExistingFileExactSize
4578 #endif
TEST_F(FileUtilTest,MAYBE_PreReadFileExistingFileExactSize)4579 TEST_F(FileUtilTest, MAYBE_PreReadFileExistingFileExactSize) {
4580 FilePath text_file = temp_dir_.GetPath().Append(FPL("text_file"));
4581 CreateTextFile(text_file, bogus_content);
4582
4583 EXPECT_TRUE(PreReadFile(text_file, /*is_executable=*/false,
4584 /*sequential=*/false, std::size(bogus_content)));
4585 }
4586
4587 #if defined(FLAKY_327582285)
4588 #define MAYBE_PreReadFileExistingFileOverSized \
4589 DISABLED_PreReadFileExistingFileOverSized
4590 #else
4591 #define MAYBE_PreReadFileExistingFileOverSized PreReadFileExistingFileOverSized
4592 #endif
TEST_F(FileUtilTest,MAYBE_PreReadFileExistingFileOverSized)4593 TEST_F(FileUtilTest, MAYBE_PreReadFileExistingFileOverSized) {
4594 FilePath text_file = temp_dir_.GetPath().Append(FPL("text_file"));
4595 CreateTextFile(text_file, bogus_content);
4596
4597 EXPECT_TRUE(PreReadFile(text_file, /*is_executable=*/false,
4598 /*sequential=*/false, std::size(bogus_content) * 2));
4599 }
4600
4601 #if defined(FLAKY_327582285)
4602 #define MAYBE_PreReadFileExistingFileUnderSized \
4603 DISABLED_PreReadFileExistingFileUnderSized
4604 #else
4605 #define MAYBE_PreReadFileExistingFileUnderSized \
4606 PreReadFileExistingFileUnderSized
4607 #endif
TEST_F(FileUtilTest,MAYBE_PreReadFileExistingFileUnderSized)4608 TEST_F(FileUtilTest, MAYBE_PreReadFileExistingFileUnderSized) {
4609 FilePath text_file = temp_dir_.GetPath().Append(FPL("text_file"));
4610 CreateTextFile(text_file, bogus_content);
4611
4612 EXPECT_TRUE(PreReadFile(text_file, /*is_executable=*/false,
4613 /*sequential=*/false, std::size(bogus_content) / 2));
4614 }
4615
TEST_F(FileUtilTest,PreReadFileExistingFileZeroSize)4616 TEST_F(FileUtilTest, PreReadFileExistingFileZeroSize) {
4617 FilePath text_file = temp_dir_.GetPath().Append(FPL("text_file"));
4618 CreateTextFile(text_file, bogus_content);
4619
4620 EXPECT_TRUE(PreReadFile(text_file, /*is_executable=*/false,
4621 /*sequential=*/false, /*max_bytes=*/0));
4622 }
4623
TEST_F(FileUtilTest,PreReadFileExistingEmptyFileNoSize)4624 TEST_F(FileUtilTest, PreReadFileExistingEmptyFileNoSize) {
4625 FilePath text_file = temp_dir_.GetPath().Append(FPL("text_file"));
4626 CreateTextFile(text_file, L"");
4627 // The test just asserts that this doesn't crash. The Windows implementation
4628 // fails in this case, due to the base::MemoryMappedFile implementation and
4629 // the limitations of ::MapViewOfFile().
4630 PreReadFile(text_file, /*is_executable=*/false, /*sequential=*/false);
4631 }
4632
TEST_F(FileUtilTest,PreReadFileExistingEmptyFileZeroSize)4633 TEST_F(FileUtilTest, PreReadFileExistingEmptyFileZeroSize) {
4634 FilePath text_file = temp_dir_.GetPath().Append(FPL("text_file"));
4635 CreateTextFile(text_file, L"");
4636 EXPECT_TRUE(PreReadFile(text_file, /*is_executable=*/false,
4637 /*sequential=*/false, /*max_bytes=*/0));
4638 }
4639
TEST_F(FileUtilTest,PreReadFileInexistentFile)4640 TEST_F(FileUtilTest, PreReadFileInexistentFile) {
4641 FilePath inexistent_file = temp_dir_.GetPath().Append(FPL("inexistent_file"));
4642 EXPECT_FALSE(PreReadFile(inexistent_file, /*is_executable=*/false,
4643 /*sequential=*/false));
4644 }
4645
4646 #if defined(FLAKY_327582285)
4647 #define MAYBE_PreReadFileExecutable DISABLED_PreReadFileExecutable
4648 #else
4649 #define MAYBE_PreReadFileExecutable PreReadFileExecutable
4650 #endif
TEST_F(FileUtilTest,MAYBE_PreReadFileExecutable)4651 TEST_F(FileUtilTest, MAYBE_PreReadFileExecutable) {
4652 FilePath exe_data_dir;
4653 ASSERT_TRUE(PathService::Get(DIR_TEST_DATA, &exe_data_dir));
4654 exe_data_dir = exe_data_dir.Append(FPL("pe_image_reader"));
4655 ASSERT_TRUE(PathExists(exe_data_dir));
4656
4657 // Load a sample executable and confirm that it was successfully prefetched.
4658 // `test_exe` is a Windows binary, which is fine in this case because only the
4659 // Windows implementation treats binaries differently from other files.
4660 const FilePath test_exe = exe_data_dir.Append(FPL("signed.exe"));
4661 EXPECT_TRUE(
4662 PreReadFile(test_exe, /*is_executable=*/true, /*sequential=*/false));
4663 }
4664
4665 #if defined(FLAKY_327582285)
4666 #define MAYBE_PreReadFileWithSequentialAccess \
4667 DISABLED_PreReadFileWithSequentialAccess
4668 #else
4669 #define MAYBE_PreReadFileWithSequentialAccess PreReadFileWithSequentialAccess
4670 #endif
TEST_F(FileUtilTest,MAYBE_PreReadFileWithSequentialAccess)4671 TEST_F(FileUtilTest, MAYBE_PreReadFileWithSequentialAccess) {
4672 FilePath text_file = temp_dir_.GetPath().Append(FPL("text_file"));
4673 CreateTextFile(text_file, bogus_content);
4674
4675 EXPECT_TRUE(
4676 PreReadFile(text_file, /*is_executable=*/false, /*sequential=*/true));
4677 }
4678
4679 #undef FLAKY_327582285
4680
4681 // Test that temp files obtained racily are all unique (no interference between
4682 // threads). Mimics file operations in DoLaunchChildTestProcess() to rule out
4683 // thread-safety issues @ https://crbug.com/826408#c17.
TEST(FileUtilMultiThreadedTest,MultiThreadedTempFiles)4684 TEST(FileUtilMultiThreadedTest, MultiThreadedTempFiles) {
4685 #if BUILDFLAG(IS_FUCHSIA)
4686 // TODO(crbug.com/844416): Too slow to run on infra due to QEMU overhead.
4687 constexpr int kNumThreads = 8;
4688 #else
4689 constexpr int kNumThreads = 64;
4690 #endif
4691 constexpr int kNumWritesPerThread = 32;
4692
4693 std::unique_ptr<Thread> threads[kNumThreads];
4694 for (auto& thread : threads) {
4695 thread = std::make_unique<Thread>("test worker");
4696 thread->Start();
4697 }
4698
4699 // Wait until all threads are started for max parallelism.
4700 for (auto& thread : threads)
4701 thread->WaitUntilThreadStarted();
4702
4703 const RepeatingClosure open_write_close_read = BindRepeating([]() {
4704 FilePath output_filename;
4705 ScopedFILE output_file(CreateAndOpenTemporaryStream(&output_filename));
4706 EXPECT_TRUE(output_file);
4707
4708 const std::string content = Uuid::GenerateRandomV4().AsLowercaseString();
4709 #if BUILDFLAG(IS_WIN)
4710 HANDLE handle =
4711 reinterpret_cast<HANDLE>(_get_osfhandle(_fileno(output_file.get())));
4712 DWORD bytes_written = 0;
4713 ::WriteFile(handle, content.c_str(), content.length(), &bytes_written,
4714 NULL);
4715 #else
4716 size_t bytes_written =
4717 ::write(::fileno(output_file.get()), content.c_str(), content.length());
4718 #endif
4719 EXPECT_EQ(content.length(), bytes_written);
4720 ::fflush(output_file.get());
4721 output_file.reset();
4722
4723 std::string output_file_contents;
4724 EXPECT_TRUE(ReadFileToString(output_filename, &output_file_contents))
4725 << output_filename;
4726
4727 EXPECT_EQ(content, output_file_contents);
4728
4729 DeleteFile(output_filename);
4730 });
4731
4732 // Post tasks to each thread in a round-robin fashion to ensure as much
4733 // parallelism as possible.
4734 for (int i = 0; i < kNumWritesPerThread; ++i) {
4735 for (auto& thread : threads) {
4736 thread->task_runner()->PostTask(FROM_HERE, open_write_close_read);
4737 }
4738 }
4739
4740 for (auto& thread : threads)
4741 thread->Stop();
4742 }
4743
4744 #if BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
4745
TEST(ScopedFD,ScopedFDDoesClose)4746 TEST(ScopedFD, ScopedFDDoesClose) {
4747 int fds[2];
4748 char c = 0;
4749 ASSERT_EQ(0, pipe(fds));
4750 const int write_end = fds[1];
4751 ScopedFD read_end_closer(fds[0]);
4752 {
4753 ScopedFD write_end_closer(fds[1]);
4754 }
4755 // This is the only thread. This file descriptor should no longer be valid.
4756 int ret = close(write_end);
4757 EXPECT_EQ(-1, ret);
4758 EXPECT_EQ(EBADF, errno);
4759 // Make sure read(2) won't block.
4760 ASSERT_EQ(0, fcntl(fds[0], F_SETFL, O_NONBLOCK));
4761 // Reading the pipe should EOF.
4762 EXPECT_EQ(0, read(fds[0], &c, 1));
4763 }
4764
4765 #if defined(GTEST_HAS_DEATH_TEST)
CloseWithScopedFD(int fd)4766 void CloseWithScopedFD(int fd) {
4767 ScopedFD fd_closer(fd);
4768 }
4769 #endif
4770
TEST(ScopedFD,ScopedFDCrashesOnCloseFailure)4771 TEST(ScopedFD, ScopedFDCrashesOnCloseFailure) {
4772 int fds[2];
4773 ASSERT_EQ(0, pipe(fds));
4774 ScopedFD read_end_closer(fds[0]);
4775 EXPECT_EQ(0, IGNORE_EINTR(close(fds[1])));
4776 #if defined(GTEST_HAS_DEATH_TEST)
4777 // This is the only thread. This file descriptor should no longer be valid.
4778 // Trying to close it should crash. This is important for security.
4779 EXPECT_DEATH(CloseWithScopedFD(fds[1]), "");
4780 #endif
4781 }
4782
4783 #endif // BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
4784
4785 #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_ANDROID)
TEST_F(FileUtilTest,CopyFileContentsWithSendfile)4786 TEST_F(FileUtilTest, CopyFileContentsWithSendfile) {
4787 // This test validates that sendfile(2) can be used to copy a file contents
4788 // and that it will honor the file offsets as CopyFileContents does.
4789 FilePath file_name_from = temp_dir_.GetPath().Append(
4790 FILE_PATH_LITERAL("copy_contents_file_in.txt"));
4791 FilePath file_name_to = temp_dir_.GetPath().Append(
4792 FILE_PATH_LITERAL("copy_contents_file_out.txt"));
4793
4794 const std::wstring from_contents(L"0123456789ABCDEF");
4795 CreateTextFile(file_name_from, from_contents);
4796 ASSERT_TRUE(PathExists(file_name_from));
4797
4798 const std::wstring to_contents(L"GHIJKL");
4799 CreateTextFile(file_name_to, to_contents);
4800 ASSERT_TRUE(PathExists(file_name_to));
4801
4802 File from(file_name_from, File::FLAG_OPEN | File::FLAG_READ);
4803 ASSERT_TRUE(from.IsValid());
4804
4805 File to(file_name_to, File::FLAG_OPEN | File::FLAG_WRITE);
4806 ASSERT_TRUE(to.IsValid());
4807
4808 // See to the 1st byte in each file.
4809 ASSERT_EQ(from.Seek(File::Whence::FROM_BEGIN, 1), 1);
4810 ASSERT_EQ(to.Seek(File::Whence::FROM_BEGIN, 1), 1);
4811
4812 bool retry_slow = false;
4813
4814 // Given the test setup there should never be a sendfile(2) failure.
4815 ASSERT_TRUE(internal::CopyFileContentsWithSendfile(from, to, retry_slow));
4816 from.Close();
4817 to.Close();
4818
4819 // Expect the output file contents to be: G123456789ABCDEF because both
4820 // file positions when we copied the file contents were at 1.
4821 EXPECT_EQ(L"G123456789ABCDEF", ReadTextFile(file_name_to));
4822 }
4823
TEST_F(FileUtilTest,CopyFileContentsWithSendfileEmpty)4824 TEST_F(FileUtilTest, CopyFileContentsWithSendfileEmpty) {
4825 FilePath file_name_from = temp_dir_.GetPath().Append(
4826 FILE_PATH_LITERAL("copy_contents_file_in.txt"));
4827 FilePath file_name_to = temp_dir_.GetPath().Append(
4828 FILE_PATH_LITERAL("copy_contents_file_out.txt"));
4829
4830 const std::wstring from_contents(L"");
4831 CreateTextFile(file_name_from, from_contents);
4832 ASSERT_TRUE(PathExists(file_name_from));
4833
4834 const std::wstring to_contents(L"");
4835 CreateTextFile(file_name_to, to_contents);
4836 ASSERT_TRUE(PathExists(file_name_to));
4837
4838 File from(file_name_from, File::FLAG_OPEN | File::FLAG_READ);
4839 ASSERT_TRUE(from.IsValid());
4840
4841 File to(file_name_to, File::FLAG_OPEN | File::FLAG_WRITE);
4842 ASSERT_TRUE(to.IsValid());
4843
4844 bool retry_slow = false;
4845
4846 ASSERT_FALSE(internal::CopyFileContentsWithSendfile(from, to, retry_slow));
4847 ASSERT_TRUE(retry_slow);
4848
4849 from.Close();
4850 to.Close();
4851
4852 EXPECT_EQ(L"", ReadTextFile(file_name_to));
4853 }
4854
TEST_F(FileUtilTest,CopyFileContentsWithSendfilePipe)4855 TEST_F(FileUtilTest, CopyFileContentsWithSendfilePipe) {
4856 FilePath file_name_to = temp_dir_.GetPath().Append(
4857 FILE_PATH_LITERAL("copy_contents_file_out.txt"));
4858
4859 File to(file_name_to,
4860 File::FLAG_OPEN | File::FLAG_WRITE | File::FLAG_CREATE_ALWAYS);
4861 ASSERT_TRUE(to.IsValid());
4862
4863 // This test validates that CopyFileContentsWithSendfile fails with a pipe and
4864 // retry_slow is set.
4865 int fd[2];
4866 ASSERT_EQ(pipe2(fd, O_CLOEXEC), 0);
4867
4868 // For good measure write some data into the pipe.
4869 const char* buf = "hello world";
4870 ASSERT_EQ(write(fd[1], buf, sizeof(buf)), static_cast<int>(sizeof(buf)));
4871
4872 // fd[0] refers to the read end of the pipe.
4873 bool retry_slow = false;
4874 base::PlatformFile pipe_read_end(fd[0]);
4875 base::File pipe_read(pipe_read_end);
4876 ASSERT_FALSE(
4877 internal::CopyFileContentsWithSendfile(pipe_read, to, retry_slow));
4878 ASSERT_TRUE(retry_slow);
4879 }
4880
TEST_F(FileUtilTest,CopyFileContentsWithSendfileSocket)4881 TEST_F(FileUtilTest, CopyFileContentsWithSendfileSocket) {
4882 // This test validates that CopyFileContentsWithSendfile fails with a socket
4883 // and retry_slow is set.
4884 int sock[2];
4885 ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, sock), 0);
4886
4887 FilePath file_name_from = temp_dir_.GetPath().Append(
4888 FILE_PATH_LITERAL("copy_contents_file_in.txt"));
4889 FilePath file_name_to = temp_dir_.GetPath().Append(
4890 FILE_PATH_LITERAL("copy_contents_file_out.txt"));
4891 const std::wstring from_contents(L"0123456789ABCDEF");
4892 CreateTextFile(file_name_from, from_contents);
4893 ASSERT_TRUE(PathExists(file_name_from));
4894
4895 File from(file_name_from, File::FLAG_OPEN | File::FLAG_READ);
4896 ASSERT_TRUE(from.IsValid());
4897
4898 base::PlatformFile to_file(sock[0]);
4899 base::File to_sock(to_file);
4900
4901 // Copying from a file to a socket will work.
4902 bool retry_slow = false;
4903 ASSERT_TRUE(
4904 internal::CopyFileContentsWithSendfile(from, to_sock, retry_slow));
4905
4906 // But copying for a socket to a file will not.
4907 base::PlatformFile from_sock_file(sock[1]);
4908 base::File from_sock(from_sock_file);
4909
4910 File to(file_name_to,
4911 File::FLAG_OPEN | File::FLAG_WRITE | File::FLAG_CREATE_ALWAYS);
4912 ASSERT_TRUE(to.IsValid());
4913 ASSERT_FALSE(
4914 internal::CopyFileContentsWithSendfile(from_sock, to, retry_slow));
4915 ASSERT_TRUE(retry_slow);
4916 }
4917
TEST_F(FileUtilTest,CopyFileContentsWithSendfileSeqFile)4918 TEST_F(FileUtilTest, CopyFileContentsWithSendfileSeqFile) {
4919 // This test verifies the special case where we have a regular file with zero
4920 // length that might actually have contents (such as a seq_file).
4921 for (auto* const file : {"/proc/meminfo", "/proc/self/cmdline",
4922 "/proc/self/environ", "/proc/self/auxv"}) {
4923 FilePath proc_file_from(file);
4924 File from(proc_file_from, File::FLAG_OPEN | File::FLAG_READ);
4925 ASSERT_TRUE(from.IsValid()) << "could not open " << file;
4926
4927 FilePath file_name_to = temp_dir_.GetPath().Append(
4928 FILE_PATH_LITERAL("copy_contents_file_out.txt"));
4929 File to(file_name_to,
4930 File::FLAG_OPEN | File::FLAG_WRITE | File::FLAG_CREATE_ALWAYS);
4931 ASSERT_TRUE(to.IsValid());
4932
4933 bool retry_slow = false;
4934 ASSERT_FALSE(internal::CopyFileContentsWithSendfile(from, to, retry_slow))
4935 << proc_file_from << " should have failed";
4936 ASSERT_TRUE(retry_slow)
4937 << "retry slow for " << proc_file_from << " should be set";
4938
4939 // Now let's make sure we can copy it the "slow" way.
4940 ASSERT_TRUE(base::CopyFileContents(from, to));
4941 ASSERT_GT(to.GetLength(), 0);
4942 ASSERT_TRUE(base::DeleteFile(file_name_to));
4943 }
4944 }
4945
4946 #endif // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) ||
4947 // BUILDFLAG(IS_ANDROID)
4948
4949 } // namespace
4950
4951 } // namespace base
4952