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