• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #ifdef UNSAFE_BUFFERS_BUILD
6 // TODO(crbug.com/40284755): Remove this and spanify to fix the errors.
7 #pragma allow_unsafe_buffers
8 #endif
9 
10 #include "base/files/file.h"
11 
12 #include <stdint.h>
13 
14 #include <optional>
15 #include <utility>
16 
17 #include "base/files/file_util.h"
18 #include "base/files/memory_mapped_file.h"
19 #include "base/files/scoped_temp_dir.h"
20 #include "base/strings/string_util.h"
21 #include "base/time/time.h"
22 #include "build/build_config.h"
23 #include "build/buildflag.h"
24 #include "testing/gtest/include/gtest/gtest.h"
25 
26 #if BUILDFLAG(ENABLE_BASE_TRACING)
27 #include "third_party/perfetto/include/perfetto/test/traced_value_test_support.h"  // no-presubmit-check nogncheck
28 #endif  // BUILDFLAG(ENABLE_BASE_TRACING)
29 
30 #if BUILDFLAG(IS_WIN)
31 #include <windows.h>
32 
33 #include "base/environment.h"
34 #include "base/strings/utf_string_conversions.h"
35 #include "base/test/gtest_util.h"
36 #endif
37 
38 namespace base {
39 
TEST(FileTest,Create)40 TEST(FileTest, Create) {
41   ScopedTempDir temp_dir;
42   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
43   FilePath file_path = temp_dir.GetPath().AppendASCII("create_file_1");
44 
45   {
46     // Don't create a File at all.
47     File file;
48     EXPECT_FALSE(file.IsValid());
49     EXPECT_EQ(File::FILE_ERROR_FAILED, file.error_details());
50 
51     File file2(File::FILE_ERROR_TOO_MANY_OPENED);
52     EXPECT_FALSE(file2.IsValid());
53     EXPECT_EQ(File::FILE_ERROR_TOO_MANY_OPENED, file2.error_details());
54   }
55 
56   {
57     // Open a file that doesn't exist.
58     File file(file_path, File::FLAG_OPEN | File::FLAG_READ);
59     EXPECT_FALSE(file.IsValid());
60     EXPECT_EQ(File::FILE_ERROR_NOT_FOUND, file.error_details());
61     EXPECT_EQ(File::FILE_ERROR_NOT_FOUND, File::GetLastFileError());
62   }
63 
64   {
65     // Open or create a file.
66     File file(file_path, File::FLAG_OPEN_ALWAYS | File::FLAG_READ);
67     EXPECT_TRUE(file.IsValid());
68     EXPECT_TRUE(file.created());
69     EXPECT_EQ(File::FILE_OK, file.error_details());
70   }
71 
72   {
73     // Open an existing file.
74     File file(file_path, File::FLAG_OPEN | File::FLAG_READ);
75     EXPECT_TRUE(file.IsValid());
76     EXPECT_FALSE(file.created());
77     EXPECT_EQ(File::FILE_OK, file.error_details());
78 
79     // This time verify closing the file.
80     file.Close();
81     EXPECT_FALSE(file.IsValid());
82   }
83 
84   {
85     // Open an existing file through Initialize
86     File file;
87     file.Initialize(file_path, File::FLAG_OPEN | File::FLAG_READ);
88     EXPECT_TRUE(file.IsValid());
89     EXPECT_FALSE(file.created());
90     EXPECT_EQ(File::FILE_OK, file.error_details());
91 
92     // This time verify closing the file.
93     file.Close();
94     EXPECT_FALSE(file.IsValid());
95   }
96 
97   {
98     // Create a file that exists.
99     File file(file_path, File::FLAG_CREATE | File::FLAG_READ);
100     EXPECT_FALSE(file.IsValid());
101     EXPECT_FALSE(file.created());
102     EXPECT_EQ(File::FILE_ERROR_EXISTS, file.error_details());
103     EXPECT_EQ(File::FILE_ERROR_EXISTS, File::GetLastFileError());
104   }
105 
106   {
107     // Create or overwrite a file.
108     File file(file_path, File::FLAG_CREATE_ALWAYS | File::FLAG_WRITE);
109     EXPECT_TRUE(file.IsValid());
110     EXPECT_TRUE(file.created());
111     EXPECT_EQ(File::FILE_OK, file.error_details());
112   }
113 
114   {
115     // Create a delete-on-close file.
116     file_path = temp_dir.GetPath().AppendASCII("create_file_2");
117     File file(file_path, File::FLAG_OPEN_ALWAYS | File::FLAG_READ |
118                              File::FLAG_DELETE_ON_CLOSE);
119     EXPECT_TRUE(file.IsValid());
120     EXPECT_TRUE(file.created());
121     EXPECT_EQ(File::FILE_OK, file.error_details());
122   }
123 
124   EXPECT_FALSE(PathExists(file_path));
125 }
126 
TEST(FileTest,SelfSwap)127 TEST(FileTest, SelfSwap) {
128   ScopedTempDir temp_dir;
129   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
130   FilePath file_path = temp_dir.GetPath().AppendASCII("create_file_1");
131   File file(file_path, File::FLAG_OPEN_ALWAYS | File::FLAG_DELETE_ON_CLOSE);
132   std::swap(file, file);
133   EXPECT_TRUE(file.IsValid());
134 }
135 
TEST(FileTest,Async)136 TEST(FileTest, Async) {
137   ScopedTempDir temp_dir;
138   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
139   FilePath file_path = temp_dir.GetPath().AppendASCII("create_file");
140 
141   {
142     File file(file_path, File::FLAG_OPEN_ALWAYS | File::FLAG_ASYNC);
143     EXPECT_TRUE(file.IsValid());
144     EXPECT_TRUE(file.async());
145   }
146 
147   {
148     File file(file_path, File::FLAG_OPEN_ALWAYS);
149     EXPECT_TRUE(file.IsValid());
150     EXPECT_FALSE(file.async());
151   }
152 }
153 
TEST(FileTest,DeleteOpenFile)154 TEST(FileTest, DeleteOpenFile) {
155   ScopedTempDir temp_dir;
156   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
157   FilePath file_path = temp_dir.GetPath().AppendASCII("create_file_1");
158 
159   // Create a file.
160   File file(file_path, File::FLAG_OPEN_ALWAYS | File::FLAG_READ |
161                            File::FLAG_WIN_SHARE_DELETE);
162   EXPECT_TRUE(file.IsValid());
163   EXPECT_TRUE(file.created());
164   EXPECT_EQ(File::FILE_OK, file.error_details());
165 
166   // Open an existing file and mark it as delete on close.
167   File same_file(file_path, File::FLAG_OPEN | File::FLAG_DELETE_ON_CLOSE |
168                                 File::FLAG_READ);
169   EXPECT_TRUE(file.IsValid());
170   EXPECT_FALSE(same_file.created());
171   EXPECT_EQ(File::FILE_OK, same_file.error_details());
172 
173   // Close both handles and check that the file is gone.
174   file.Close();
175   same_file.Close();
176   EXPECT_FALSE(PathExists(file_path));
177 }
178 
TEST(FileTest,ReadWrite)179 TEST(FileTest, ReadWrite) {
180   ScopedTempDir temp_dir;
181   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
182   FilePath file_path = temp_dir.GetPath().AppendASCII("read_write_file");
183   File file(file_path, File::FLAG_CREATE | File::FLAG_READ | File::FLAG_WRITE);
184   ASSERT_TRUE(file.IsValid());
185 
186   char data_to_write[] = "test";
187   const int kTestDataSize = 4;
188 
189   // Write 0 bytes to the file.
190   int bytes_written = file.Write(0, data_to_write, 0);
191   EXPECT_EQ(0, bytes_written);
192 
193   // Write 0 bytes, with buf=nullptr.
194   bytes_written = file.Write(0, nullptr, 0);
195   EXPECT_EQ(0, bytes_written);
196 
197   // Write "test" to the file.
198   bytes_written = file.Write(0, data_to_write, kTestDataSize);
199   EXPECT_EQ(kTestDataSize, bytes_written);
200 
201   // Read from EOF.
202   char data_read_1[32];
203   int bytes_read = file.Read(kTestDataSize, data_read_1, kTestDataSize);
204   EXPECT_EQ(0, bytes_read);
205 
206   // Read from somewhere in the middle of the file.
207   const int kPartialReadOffset = 1;
208   bytes_read = file.Read(kPartialReadOffset, data_read_1, kTestDataSize);
209   EXPECT_EQ(kTestDataSize - kPartialReadOffset, bytes_read);
210   for (int i = 0; i < bytes_read; i++) {
211     EXPECT_EQ(data_to_write[i + kPartialReadOffset], data_read_1[i]);
212   }
213 
214   // Read 0 bytes.
215   bytes_read = file.Read(0, data_read_1, 0);
216   EXPECT_EQ(0, bytes_read);
217 
218   // Read the entire file.
219   bytes_read = file.Read(0, data_read_1, kTestDataSize);
220   EXPECT_EQ(kTestDataSize, bytes_read);
221   for (int i = 0; i < bytes_read; i++) {
222     EXPECT_EQ(data_to_write[i], data_read_1[i]);
223   }
224 
225   // Read again, but using the trivial native wrapper.
226   std::optional<size_t> maybe_bytes_read =
227       file.ReadNoBestEffort(0, as_writable_byte_span(data_read_1)
228                                    .first(static_cast<size_t>(kTestDataSize)));
229   ASSERT_TRUE(maybe_bytes_read.has_value());
230   EXPECT_LE(maybe_bytes_read.value(), static_cast<size_t>(kTestDataSize));
231   for (size_t i = 0; i < maybe_bytes_read.value(); i++) {
232     EXPECT_EQ(data_to_write[i], data_read_1[i]);
233   }
234 
235   // Write past the end of the file.
236   const int kOffsetBeyondEndOfFile = 10;
237   const int kPartialWriteLength = 2;
238   bytes_written =
239       file.Write(kOffsetBeyondEndOfFile, data_to_write, kPartialWriteLength);
240   EXPECT_EQ(kPartialWriteLength, bytes_written);
241 
242   // Make sure the file was extended.
243   std::optional<int64_t> file_size = GetFileSize(file_path);
244   ASSERT_TRUE(file_size.has_value());
245   EXPECT_EQ(kOffsetBeyondEndOfFile + kPartialWriteLength, file_size.value());
246 
247   // Make sure the file was zero-padded.
248   char data_read_2[32];
249   bytes_read = file.Read(0, data_read_2, static_cast<int>(file_size.value()));
250   EXPECT_EQ(file_size, bytes_read);
251   for (int i = 0; i < kTestDataSize; i++) {
252     EXPECT_EQ(data_to_write[i], data_read_2[i]);
253   }
254   for (int i = kTestDataSize; i < kOffsetBeyondEndOfFile; i++) {
255     EXPECT_EQ(0, data_read_2[i]);
256   }
257   for (int i = kOffsetBeyondEndOfFile; i < file_size; i++) {
258     EXPECT_EQ(data_to_write[i - kOffsetBeyondEndOfFile], data_read_2[i]);
259   }
260 }
261 
TEST(FileTest,ReadWriteSpans)262 TEST(FileTest, ReadWriteSpans) {
263   ScopedTempDir temp_dir;
264   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
265   FilePath file_path = temp_dir.GetPath().AppendASCII("read_write_file");
266   File file(file_path, File::FLAG_CREATE | File::FLAG_READ | File::FLAG_WRITE);
267   ASSERT_TRUE(file.IsValid());
268 
269   // Write 0 bytes to the file.
270   std::optional<size_t> bytes_written = file.Write(0, span<uint8_t>());
271   ASSERT_TRUE(bytes_written.has_value());
272   EXPECT_EQ(0u, bytes_written.value());
273 
274   // Write "test" to the file.
275   std::string data_to_write("test");
276   bytes_written = file.Write(0, as_byte_span(data_to_write));
277   ASSERT_TRUE(bytes_written.has_value());
278   EXPECT_EQ(data_to_write.size(), bytes_written.value());
279 
280   // Read from EOF.
281   uint8_t data_read_1[32];
282   std::optional<size_t> bytes_read =
283       file.Read(bytes_written.value(), data_read_1);
284   ASSERT_TRUE(bytes_read.has_value());
285   EXPECT_EQ(0u, bytes_read.value());
286 
287   // Read from somewhere in the middle of the file.
288   const int kPartialReadOffset = 1;
289   bytes_read = file.Read(kPartialReadOffset, data_read_1);
290   ASSERT_TRUE(bytes_read.has_value());
291   EXPECT_EQ(bytes_written.value() - kPartialReadOffset, bytes_read.value());
292   for (size_t i = 0; i < bytes_read.value(); i++) {
293     EXPECT_EQ(data_to_write[i + kPartialReadOffset], data_read_1[i]);
294   }
295 
296   // Read 0 bytes.
297   bytes_read = file.Read(0, span<uint8_t>());
298   ASSERT_TRUE(bytes_read.has_value());
299   EXPECT_EQ(0u, bytes_read.value());
300 
301   // Read the entire file.
302   bytes_read = file.Read(0, data_read_1);
303   ASSERT_TRUE(bytes_read.has_value());
304   EXPECT_EQ(data_to_write.size(), bytes_read.value());
305   for (int i = 0; i < bytes_read; i++) {
306     EXPECT_EQ(data_to_write[i], data_read_1[i]);
307   }
308 
309   // Write past the end of the file.
310   const size_t kOffsetBeyondEndOfFile = 10;
311   const size_t kPartialWriteLength = 2;
312   bytes_written =
313       file.Write(kOffsetBeyondEndOfFile,
314                  as_byte_span(data_to_write).first(kPartialWriteLength));
315   ASSERT_TRUE(bytes_written.has_value());
316   EXPECT_EQ(kPartialWriteLength, bytes_written.value());
317 
318   // Make sure the file was extended.
319   std::optional<int64_t> file_size = GetFileSize(file_path);
320   ASSERT_TRUE(file_size.has_value());
321   EXPECT_EQ(static_cast<int64_t>(kOffsetBeyondEndOfFile + kPartialWriteLength),
322             file_size.value());
323 
324   // Make sure the file was zero-padded.
325   uint8_t data_read_2[32];
326   bytes_read = file.Read(0, data_read_2);
327   ASSERT_TRUE(bytes_read.has_value());
328   EXPECT_EQ(file_size, static_cast<int64_t>(bytes_read.value()));
329   for (size_t i = 0; i < data_to_write.size(); i++) {
330     EXPECT_EQ(data_to_write[i], data_read_2[i]);
331   }
332   for (size_t i = data_to_write.size(); i < kOffsetBeyondEndOfFile; i++) {
333     EXPECT_EQ(0, data_read_2[i]);
334   }
335   for (size_t i = 0; i < kPartialWriteLength; i++) {
336     EXPECT_EQ(data_to_write[i], data_read_2[i + kOffsetBeyondEndOfFile]);
337   }
338 }
339 
TEST(FileTest,GetLastFileError)340 TEST(FileTest, GetLastFileError) {
341 #if BUILDFLAG(IS_WIN)
342   ::SetLastError(ERROR_ACCESS_DENIED);
343 #else
344   errno = EACCES;
345 #endif
346   EXPECT_EQ(File::FILE_ERROR_ACCESS_DENIED, File::GetLastFileError());
347 
348   ScopedTempDir temp_dir;
349   EXPECT_TRUE(temp_dir.CreateUniqueTempDir());
350 
351   FilePath nonexistent_path(temp_dir.GetPath().AppendASCII("nonexistent"));
352   File file(nonexistent_path, File::FLAG_OPEN | File::FLAG_READ);
353   File::Error last_error = File::GetLastFileError();
354   EXPECT_FALSE(file.IsValid());
355   EXPECT_EQ(File::FILE_ERROR_NOT_FOUND, file.error_details());
356   EXPECT_EQ(File::FILE_ERROR_NOT_FOUND, last_error);
357 }
358 
TEST(FileTest,Append)359 TEST(FileTest, Append) {
360   ScopedTempDir temp_dir;
361   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
362   FilePath file_path = temp_dir.GetPath().AppendASCII("append_file");
363   File file(file_path, File::FLAG_CREATE | File::FLAG_APPEND);
364   ASSERT_TRUE(file.IsValid());
365 
366   char data_to_write[] = "test";
367   const int kTestDataSize = 4;
368 
369   // Write 0 bytes to the file.
370   int bytes_written = file.Write(0, data_to_write, 0);
371   EXPECT_EQ(0, bytes_written);
372 
373   // Write 0 bytes, with buf=nullptr.
374   bytes_written = file.Write(0, nullptr, 0);
375   EXPECT_EQ(0, bytes_written);
376 
377   // Write "test" to the file.
378   bytes_written = file.Write(0, data_to_write, kTestDataSize);
379   EXPECT_EQ(kTestDataSize, bytes_written);
380 
381   file.Close();
382   File file2(file_path, File::FLAG_OPEN | File::FLAG_READ | File::FLAG_APPEND);
383   ASSERT_TRUE(file2.IsValid());
384 
385   // Test passing the file around.
386   file = std::move(file2);
387   EXPECT_FALSE(file2.IsValid());
388   ASSERT_TRUE(file.IsValid());
389 
390   char append_data_to_write[] = "78";
391   const int kAppendDataSize = 2;
392 
393   // Append "78" to the file.
394   bytes_written = file.Write(0, append_data_to_write, kAppendDataSize);
395   EXPECT_EQ(kAppendDataSize, bytes_written);
396 
397   // Read the entire file.
398   char data_read_1[32];
399   int bytes_read = file.Read(0, data_read_1, kTestDataSize + kAppendDataSize);
400   EXPECT_EQ(kTestDataSize + kAppendDataSize, bytes_read);
401   for (int i = 0; i < kTestDataSize; i++) {
402     EXPECT_EQ(data_to_write[i], data_read_1[i]);
403   }
404   for (int i = 0; i < kAppendDataSize; i++) {
405     EXPECT_EQ(append_data_to_write[i], data_read_1[kTestDataSize + i]);
406   }
407 }
408 
TEST(FileTest,Length)409 TEST(FileTest, Length) {
410   ScopedTempDir temp_dir;
411   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
412   FilePath file_path = temp_dir.GetPath().AppendASCII("truncate_file");
413   File file(file_path, File::FLAG_CREATE | File::FLAG_READ | File::FLAG_WRITE);
414   ASSERT_TRUE(file.IsValid());
415   EXPECT_EQ(0, file.GetLength());
416 
417   // Write "test" to the file.
418   char data_to_write[] = "test";
419   int kTestDataSize = 4;
420   int bytes_written = file.Write(0, data_to_write, kTestDataSize);
421   EXPECT_EQ(kTestDataSize, bytes_written);
422 
423   // Extend the file.
424   const int kExtendedFileLength = 10;
425   EXPECT_TRUE(file.SetLength(kExtendedFileLength));
426   EXPECT_EQ(kExtendedFileLength, file.GetLength());
427   std::optional<int64_t> file_size = GetFileSize(file_path);
428   ASSERT_TRUE(file_size.has_value());
429   EXPECT_EQ(kExtendedFileLength, file_size.value());
430 
431   // Make sure the file was zero-padded.
432   char data_read[32];
433   int bytes_read = file.Read(0, data_read, static_cast<int>(file_size.value()));
434   EXPECT_EQ(file_size, bytes_read);
435   for (int i = 0; i < kTestDataSize; i++) {
436     EXPECT_EQ(data_to_write[i], data_read[i]);
437   }
438   for (int i = kTestDataSize; i < file_size; i++) {
439     EXPECT_EQ(0, data_read[i]);
440   }
441 
442   // Truncate the file.
443   const int kTruncatedFileLength = 2;
444   EXPECT_TRUE(file.SetLength(kTruncatedFileLength));
445   EXPECT_EQ(kTruncatedFileLength, file.GetLength());
446 
447   file_size = GetFileSize(file_path);
448   ASSERT_TRUE(file_size.has_value());
449   EXPECT_EQ(kTruncatedFileLength, file_size.value());
450 
451   // Make sure the file was truncated.
452   bytes_read = file.Read(0, data_read, kTestDataSize);
453   EXPECT_EQ(file_size.value(), bytes_read);
454   for (int i = 0; i < file_size.value(); i++) {
455     EXPECT_EQ(data_to_write[i], data_read[i]);
456   }
457 
458 #if !BUILDFLAG(IS_FUCHSIA)  // Fuchsia doesn't seem to support big files.
459   // Expand the file past the 4 GB limit.
460   const int64_t kBigFileLength = 5'000'000'000;
461   EXPECT_TRUE(file.SetLength(kBigFileLength));
462   EXPECT_EQ(kBigFileLength, file.GetLength());
463   file_size = GetFileSize(file_path);
464   ASSERT_TRUE(file_size.has_value());
465   EXPECT_EQ(kBigFileLength, file_size.value());
466 #endif
467 
468   // Close the file and reopen with File::FLAG_CREATE_ALWAYS, and make
469   // sure the file is empty (old file was overridden).
470   file.Close();
471   file.Initialize(file_path, File::FLAG_CREATE_ALWAYS | File::FLAG_WRITE);
472   EXPECT_EQ(0, file.GetLength());
473 }
474 
475 // Flakily fails: http://crbug.com/86494
476 #if BUILDFLAG(IS_ANDROID)
TEST(FileTest,TouchGetInfo)477 TEST(FileTest, TouchGetInfo) {
478 #else
479 TEST(FileTest, DISABLED_TouchGetInfo) {
480 #endif
481   ScopedTempDir temp_dir;
482   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
483   File file(temp_dir.GetPath().AppendASCII("touch_get_info_file"),
484             File::FLAG_CREATE | File::FLAG_WRITE | File::FLAG_WRITE_ATTRIBUTES);
485   ASSERT_TRUE(file.IsValid());
486 
487   // Get info for a newly created file.
488   File::Info info;
489   EXPECT_TRUE(file.GetInfo(&info));
490 
491   // Add 2 seconds to account for possible rounding errors on
492   // filesystems that use a 1s or 2s timestamp granularity.
493   Time now = Time::Now() + Seconds(2);
494   EXPECT_EQ(0, info.size);
495   EXPECT_FALSE(info.is_directory);
496   EXPECT_FALSE(info.is_symbolic_link);
497   EXPECT_LE(info.last_accessed.ToInternalValue(), now.ToInternalValue());
498   EXPECT_LE(info.last_modified.ToInternalValue(), now.ToInternalValue());
499   EXPECT_LE(info.creation_time.ToInternalValue(), now.ToInternalValue());
500   Time creation_time = info.creation_time;
501 
502   // Write "test" to the file.
503   char data[] = "test";
504   const int kTestDataSize = 4;
505   int bytes_written = file.Write(0, data, kTestDataSize);
506   EXPECT_EQ(kTestDataSize, bytes_written);
507 
508   // Change the last_accessed and last_modified dates.
509   // It's best to add values that are multiples of 2 (in seconds)
510   // to the current last_accessed and last_modified times, because
511   // FATxx uses a 2s timestamp granularity.
512   Time new_last_accessed = info.last_accessed + Seconds(234);
513   Time new_last_modified = info.last_modified + Minutes(567);
514 
515   EXPECT_TRUE(file.SetTimes(new_last_accessed, new_last_modified));
516 
517   // Make sure the file info was updated accordingly.
518   EXPECT_TRUE(file.GetInfo(&info));
519   EXPECT_EQ(info.size, kTestDataSize);
520   EXPECT_FALSE(info.is_directory);
521   EXPECT_FALSE(info.is_symbolic_link);
522 
523   // ext2/ext3 and HPS/HPS+ seem to have a timestamp granularity of 1s.
524 #if BUILDFLAG(IS_POSIX)
525   EXPECT_EQ(info.last_accessed.ToTimeVal().tv_sec,
526             new_last_accessed.ToTimeVal().tv_sec);
527   EXPECT_EQ(info.last_modified.ToTimeVal().tv_sec,
528             new_last_modified.ToTimeVal().tv_sec);
529 #else
530   EXPECT_EQ(info.last_accessed.ToInternalValue(),
531             new_last_accessed.ToInternalValue());
532   EXPECT_EQ(info.last_modified.ToInternalValue(),
533             new_last_modified.ToInternalValue());
534 #endif
535 
536   EXPECT_EQ(info.creation_time.ToInternalValue(),
537             creation_time.ToInternalValue());
538 }
539 
540 // Test we can retrieve the file's creation time through File::GetInfo().
541 TEST(FileTest, GetInfoForCreationTime) {
542   int64_t before_creation_time_s =
543       Time::Now().ToDeltaSinceWindowsEpoch().InSeconds();
544 
545   ScopedTempDir temp_dir;
546   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
547   FilePath file_path = temp_dir.GetPath().AppendASCII("test_file");
548   File file(file_path, File::FLAG_CREATE | File::FLAG_READ | File::FLAG_WRITE);
549   EXPECT_TRUE(file.IsValid());
550 
551   int64_t after_creation_time_s =
552       Time::Now().ToDeltaSinceWindowsEpoch().InSeconds();
553 
554   File::Info info;
555   EXPECT_TRUE(file.GetInfo(&info));
556   EXPECT_GE(info.creation_time.ToDeltaSinceWindowsEpoch().InSeconds(),
557             before_creation_time_s);
558   EXPECT_LE(info.creation_time.ToDeltaSinceWindowsEpoch().InSeconds(),
559             after_creation_time_s);
560 }
561 
562 TEST(FileTest, ReadAtCurrentPosition) {
563   ScopedTempDir temp_dir;
564   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
565   FilePath file_path =
566       temp_dir.GetPath().AppendASCII("read_at_current_position");
567   File file(file_path, File::FLAG_CREATE | File::FLAG_READ | File::FLAG_WRITE);
568   EXPECT_TRUE(file.IsValid());
569 
570   const char kData[] = "test";
571   const int kDataSize = sizeof(kData) - 1;
572   EXPECT_EQ(kDataSize, file.Write(0, kData, kDataSize));
573 
574   EXPECT_EQ(0, file.Seek(File::FROM_BEGIN, 0));
575 
576   char buffer[kDataSize];
577   int first_chunk_size = kDataSize / 2;
578   EXPECT_EQ(first_chunk_size, file.ReadAtCurrentPos(buffer, first_chunk_size));
579   EXPECT_EQ(kDataSize - first_chunk_size,
580             file.ReadAtCurrentPos(buffer + first_chunk_size,
581                                   kDataSize - first_chunk_size));
582   EXPECT_EQ(std::string(buffer, buffer + kDataSize), std::string(kData));
583 }
584 
585 TEST(FileTest, ReadAtCurrentPositionSpans) {
586   ScopedTempDir temp_dir;
587   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
588   FilePath file_path =
589       temp_dir.GetPath().AppendASCII("read_at_current_position");
590   File file(file_path, File::FLAG_CREATE | File::FLAG_READ | File::FLAG_WRITE);
591   EXPECT_TRUE(file.IsValid());
592 
593   std::string data("test");
594   std::optional<size_t> result = file.Write(0, as_byte_span(data));
595   ASSERT_TRUE(result.has_value());
596   EXPECT_EQ(data.size(), result.value());
597 
598   EXPECT_EQ(0, file.Seek(File::FROM_BEGIN, 0));
599 
600   uint8_t buffer[4];
601   size_t first_chunk_size = 2;
602   const auto [chunk1, chunk2] = span(buffer).split_at(first_chunk_size);
603   EXPECT_EQ(chunk1.size(), file.ReadAtCurrentPos(chunk1));
604   EXPECT_EQ(chunk2.size(), file.ReadAtCurrentPos(chunk2));
605   for (size_t i = 0; i < data.size(); i++) {
606     EXPECT_EQ(data[i], static_cast<char>(buffer[i]));
607   }
608 }
609 
610 TEST(FileTest, WriteAtCurrentPosition) {
611   ScopedTempDir temp_dir;
612   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
613   FilePath file_path =
614       temp_dir.GetPath().AppendASCII("write_at_current_position");
615   File file(file_path, File::FLAG_CREATE | File::FLAG_READ | File::FLAG_WRITE);
616   EXPECT_TRUE(file.IsValid());
617 
618   const char kData[] = "test";
619   const int kDataSize = sizeof(kData) - 1;
620 
621   int first_chunk_size = kDataSize / 2;
622   EXPECT_EQ(first_chunk_size, file.WriteAtCurrentPos(kData, first_chunk_size));
623   EXPECT_EQ(kDataSize - first_chunk_size,
624             file.WriteAtCurrentPos(kData + first_chunk_size,
625                                    kDataSize - first_chunk_size));
626 
627   char buffer[kDataSize];
628   EXPECT_EQ(kDataSize, file.Read(0, buffer, kDataSize));
629   EXPECT_EQ(std::string(buffer, buffer + kDataSize), std::string(kData));
630 }
631 
632 TEST(FileTest, WriteAtCurrentPositionSpans) {
633   ScopedTempDir temp_dir;
634   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
635   FilePath file_path =
636       temp_dir.GetPath().AppendASCII("write_at_current_position");
637   File file(file_path, File::FLAG_CREATE | File::FLAG_READ | File::FLAG_WRITE);
638   EXPECT_TRUE(file.IsValid());
639 
640   std::string data("test");
641   size_t first_chunk_size = data.size() / 2;
642   std::optional<size_t> result =
643       file.WriteAtCurrentPos(as_byte_span(data).first(first_chunk_size));
644   ASSERT_TRUE(result.has_value());
645   EXPECT_EQ(first_chunk_size, result.value());
646 
647   result = file.WriteAtCurrentPos(as_byte_span(data).subspan(first_chunk_size));
648   ASSERT_TRUE(result.has_value());
649   EXPECT_EQ(first_chunk_size, result.value());
650 
651   const int kDataSize = 4;
652   char buffer[kDataSize];
653   EXPECT_EQ(kDataSize, file.Read(0, buffer, kDataSize));
654   EXPECT_EQ(std::string(buffer, buffer + kDataSize), data);
655 }
656 
657 TEST(FileTest, Seek) {
658   ScopedTempDir temp_dir;
659   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
660   FilePath file_path = temp_dir.GetPath().AppendASCII("seek_file");
661   File file(file_path, File::FLAG_CREATE | File::FLAG_READ | File::FLAG_WRITE);
662   ASSERT_TRUE(file.IsValid());
663 
664   const int64_t kOffset = 10;
665   EXPECT_EQ(kOffset, file.Seek(File::FROM_BEGIN, kOffset));
666   EXPECT_EQ(2 * kOffset, file.Seek(File::FROM_CURRENT, kOffset));
667   EXPECT_EQ(kOffset, file.Seek(File::FROM_CURRENT, -kOffset));
668   EXPECT_TRUE(file.SetLength(kOffset * 2));
669   EXPECT_EQ(kOffset, file.Seek(File::FROM_END, -kOffset));
670 }
671 
672 TEST(FileTest, Duplicate) {
673   ScopedTempDir temp_dir;
674   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
675   FilePath file_path = temp_dir.GetPath().AppendASCII("file");
676   File file(file_path,
677             (File::FLAG_CREATE | File::FLAG_READ | File::FLAG_WRITE));
678   ASSERT_TRUE(file.IsValid());
679 
680   File file2(file.Duplicate());
681   ASSERT_TRUE(file2.IsValid());
682 
683   // Write through one handle, close it, read through the other.
684   static const char kData[] = "now is a good time.";
685   static const int kDataLen = sizeof(kData) - 1;
686 
687   ASSERT_EQ(0, file.Seek(File::FROM_CURRENT, 0));
688   ASSERT_EQ(0, file2.Seek(File::FROM_CURRENT, 0));
689   ASSERT_EQ(kDataLen, file.WriteAtCurrentPos(kData, kDataLen));
690   ASSERT_EQ(kDataLen, file.Seek(File::FROM_CURRENT, 0));
691   ASSERT_EQ(kDataLen, file2.Seek(File::FROM_CURRENT, 0));
692   file.Close();
693   char buf[kDataLen];
694   ASSERT_EQ(kDataLen, file2.Read(0, &buf[0], kDataLen));
695   ASSERT_EQ(std::string(kData, kDataLen), std::string(&buf[0], kDataLen));
696 }
697 
698 TEST(FileTest, DuplicateDeleteOnClose) {
699   ScopedTempDir temp_dir;
700   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
701   FilePath file_path = temp_dir.GetPath().AppendASCII("file");
702   File file(file_path, (File::FLAG_CREATE | File::FLAG_READ | File::FLAG_WRITE |
703                         File::FLAG_DELETE_ON_CLOSE));
704   ASSERT_TRUE(file.IsValid());
705   File file2(file.Duplicate());
706   ASSERT_TRUE(file2.IsValid());
707   file.Close();
708   file2.Close();
709   ASSERT_FALSE(PathExists(file_path));
710 }
711 
712 #if BUILDFLAG(ENABLE_BASE_TRACING)
713 TEST(FileTest, TracedValueSupport) {
714   ScopedTempDir temp_dir;
715   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
716   FilePath file_path = temp_dir.GetPath().AppendASCII("file");
717 
718   File file(file_path, (File::FLAG_CREATE | File::FLAG_READ | File::FLAG_WRITE |
719                         File::FLAG_DELETE_ON_CLOSE));
720   ASSERT_TRUE(file.IsValid());
721 
722   EXPECT_EQ(perfetto::TracedValueToString(file),
723             "{is_valid:true,created:true,async:false,error_details:FILE_OK}");
724 }
725 #endif  // BUILDFLAG(ENABLE_BASE_TRACING)
726 
727 #if BUILDFLAG(IS_WIN)
728 // Flakily times out on Windows, see http://crbug.com/846276.
729 #define MAYBE_WriteDataToLargeOffset DISABLED_WriteDataToLargeOffset
730 #else
731 #define MAYBE_WriteDataToLargeOffset WriteDataToLargeOffset
732 #endif
733 TEST(FileTest, MAYBE_WriteDataToLargeOffset) {
734   ScopedTempDir temp_dir;
735   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
736   FilePath file_path = temp_dir.GetPath().AppendASCII("file");
737   File file(file_path, (File::FLAG_CREATE | File::FLAG_READ | File::FLAG_WRITE |
738                         File::FLAG_DELETE_ON_CLOSE));
739   ASSERT_TRUE(file.IsValid());
740 
741   const char kData[] = "this file is sparse.";
742   const int kDataLen = sizeof(kData) - 1;
743   const int64_t kLargeFileOffset = (1LL << 31);
744 
745   // If the file fails to write, it is probably we are running out of disk space
746   // and the file system doesn't support sparse file.
747   if (file.Write(kLargeFileOffset - kDataLen - 1, kData, kDataLen) < 0) {
748     return;
749   }
750 
751   ASSERT_EQ(kDataLen, file.Write(kLargeFileOffset + 1, kData, kDataLen));
752 }
753 
754 TEST(FileTest, AddFlagsForPassingToUntrustedProcess) {
755   {
756     uint32_t flags = File::FLAG_OPEN | File::FLAG_READ;
757     flags = File::AddFlagsForPassingToUntrustedProcess(flags);
758     EXPECT_EQ(flags, File::FLAG_OPEN | File::FLAG_READ);
759   }
760   {
761     uint32_t flags = File::FLAG_OPEN | File::FLAG_WRITE;
762     flags = File::AddFlagsForPassingToUntrustedProcess(flags);
763     EXPECT_EQ(flags,
764               File::FLAG_OPEN | File::FLAG_WRITE | File::FLAG_WIN_NO_EXECUTE);
765   }
766 }
767 
768 #if BUILDFLAG(IS_WIN)
769 TEST(FileTest, GetInfoForDirectory) {
770   ScopedTempDir temp_dir;
771   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
772   FilePath empty_dir =
773       temp_dir.GetPath().Append(FILE_PATH_LITERAL("gpfi_test"));
774   ASSERT_TRUE(CreateDirectory(empty_dir));
775 
776   File dir(
777       ::CreateFile(empty_dir.value().c_str(), GENERIC_READ | GENERIC_WRITE,
778                    FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL,
779                    OPEN_EXISTING,
780                    FILE_FLAG_BACKUP_SEMANTICS,  // Needed to open a directory.
781                    NULL));
782   ASSERT_TRUE(dir.IsValid());
783 
784   File::Info info;
785   EXPECT_TRUE(dir.GetInfo(&info));
786   EXPECT_TRUE(info.is_directory);
787   EXPECT_FALSE(info.is_symbolic_link);
788   EXPECT_EQ(0, info.size);
789 }
790 
791 TEST(FileTest, DeleteNoop) {
792   ScopedTempDir temp_dir;
793   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
794   FilePath file_path = temp_dir.GetPath().AppendASCII("file");
795 
796   // Creating and closing a file with DELETE perms should do nothing special.
797   File file(file_path, (File::FLAG_CREATE | File::FLAG_READ | File::FLAG_WRITE |
798                         File::FLAG_CAN_DELETE_ON_CLOSE));
799   ASSERT_TRUE(file.IsValid());
800   file.Close();
801   ASSERT_TRUE(PathExists(file_path));
802 }
803 
804 TEST(FileTest, Delete) {
805   ScopedTempDir temp_dir;
806   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
807   FilePath file_path = temp_dir.GetPath().AppendASCII("file");
808 
809   // Creating a file with DELETE and then marking for delete on close should
810   // delete it.
811   File file(file_path, (File::FLAG_CREATE | File::FLAG_READ | File::FLAG_WRITE |
812                         File::FLAG_CAN_DELETE_ON_CLOSE));
813   ASSERT_TRUE(file.IsValid());
814   ASSERT_TRUE(file.DeleteOnClose(true));
815   file.Close();
816   ASSERT_FALSE(PathExists(file_path));
817 }
818 
819 TEST(FileTest, DeleteThenRevoke) {
820   ScopedTempDir temp_dir;
821   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
822   FilePath file_path = temp_dir.GetPath().AppendASCII("file");
823 
824   // Creating a file with DELETE, marking it for delete, then clearing delete on
825   // close should not delete it.
826   File file(file_path, (File::FLAG_CREATE | File::FLAG_READ | File::FLAG_WRITE |
827                         File::FLAG_CAN_DELETE_ON_CLOSE));
828   ASSERT_TRUE(file.IsValid());
829   ASSERT_TRUE(file.DeleteOnClose(true));
830   ASSERT_TRUE(file.DeleteOnClose(false));
831   file.Close();
832   ASSERT_TRUE(PathExists(file_path));
833 }
834 
835 TEST(FileTest, IrrevokableDeleteOnClose) {
836   ScopedTempDir temp_dir;
837   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
838   FilePath file_path = temp_dir.GetPath().AppendASCII("file");
839 
840   // DELETE_ON_CLOSE cannot be revoked by this opener.
841   File file(file_path,
842             (File::FLAG_CREATE | File::FLAG_READ | File::FLAG_WRITE |
843              File::FLAG_DELETE_ON_CLOSE | File::FLAG_WIN_SHARE_DELETE |
844              File::FLAG_CAN_DELETE_ON_CLOSE));
845   ASSERT_TRUE(file.IsValid());
846   // https://msdn.microsoft.com/library/windows/desktop/aa364221.aspx says that
847   // setting the dispositon has no effect if the handle was opened with
848   // FLAG_DELETE_ON_CLOSE. Do not make the test's success dependent on whether
849   // or not SetFileInformationByHandle indicates success or failure. (It happens
850   // to indicate success on Windows 10.)
851   file.DeleteOnClose(false);
852   file.Close();
853   ASSERT_FALSE(PathExists(file_path));
854 }
855 
856 TEST(FileTest, IrrevokableDeleteOnCloseOther) {
857   ScopedTempDir temp_dir;
858   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
859   FilePath file_path = temp_dir.GetPath().AppendASCII("file");
860 
861   // DELETE_ON_CLOSE cannot be revoked by another opener.
862   File file(file_path,
863             (File::FLAG_CREATE | File::FLAG_READ | File::FLAG_WRITE |
864              File::FLAG_DELETE_ON_CLOSE | File::FLAG_WIN_SHARE_DELETE |
865              File::FLAG_CAN_DELETE_ON_CLOSE));
866   ASSERT_TRUE(file.IsValid());
867 
868   File file2(file_path,
869              (File::FLAG_OPEN | File::FLAG_READ | File::FLAG_WRITE |
870               File::FLAG_WIN_SHARE_DELETE | File::FLAG_CAN_DELETE_ON_CLOSE));
871   ASSERT_TRUE(file2.IsValid());
872 
873   file2.DeleteOnClose(false);
874   file2.Close();
875   ASSERT_TRUE(PathExists(file_path));
876   file.Close();
877   ASSERT_FALSE(PathExists(file_path));
878 }
879 
880 TEST(FileTest, DeleteWithoutPermission) {
881   ScopedTempDir temp_dir;
882   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
883   FilePath file_path = temp_dir.GetPath().AppendASCII("file");
884 
885   // It should not be possible to mark a file for deletion when it was not
886   // created/opened with DELETE.
887   File file(file_path,
888             (File::FLAG_CREATE | File::FLAG_READ | File::FLAG_WRITE));
889   ASSERT_TRUE(file.IsValid());
890   ASSERT_FALSE(file.DeleteOnClose(true));
891   file.Close();
892   ASSERT_TRUE(PathExists(file_path));
893 }
894 
895 TEST(FileTest, UnsharedDeleteOnClose) {
896   ScopedTempDir temp_dir;
897   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
898   FilePath file_path = temp_dir.GetPath().AppendASCII("file");
899 
900   // Opening with DELETE_ON_CLOSE when a previous opener hasn't enabled sharing
901   // will fail.
902   File file(file_path,
903             (File::FLAG_CREATE | File::FLAG_READ | File::FLAG_WRITE));
904   ASSERT_TRUE(file.IsValid());
905   File file2(file_path,
906              (File::FLAG_OPEN | File::FLAG_READ | File::FLAG_WRITE |
907               File::FLAG_DELETE_ON_CLOSE | File::FLAG_WIN_SHARE_DELETE));
908   ASSERT_FALSE(file2.IsValid());
909 
910   file.Close();
911   ASSERT_TRUE(PathExists(file_path));
912 }
913 
914 TEST(FileTest, NoDeleteOnCloseWithMappedFile) {
915   ScopedTempDir temp_dir;
916   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
917   FilePath file_path = temp_dir.GetPath().AppendASCII("file");
918 
919   // Mapping a file into memory blocks DeleteOnClose.
920   File file(file_path, (File::FLAG_CREATE | File::FLAG_READ | File::FLAG_WRITE |
921                         File::FLAG_CAN_DELETE_ON_CLOSE));
922   ASSERT_TRUE(file.IsValid());
923   ASSERT_EQ(5, file.WriteAtCurrentPos("12345", 5));
924 
925   {
926     MemoryMappedFile mapping;
927     ASSERT_TRUE(mapping.Initialize(file.Duplicate()));
928     ASSERT_EQ(5U, mapping.length());
929 
930     EXPECT_FALSE(file.DeleteOnClose(true));
931   }
932 
933   file.Close();
934   ASSERT_TRUE(PathExists(file_path));
935 }
936 
937 // Check that we handle the async bit being set incorrectly in a sane way.
938 TEST(FileTest, UseSyncApiWithAsyncFile) {
939   ScopedTempDir temp_dir;
940   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
941   FilePath file_path = temp_dir.GetPath().AppendASCII("file");
942 
943   File file(file_path, File::FLAG_CREATE | File::FLAG_WRITE | File::FLAG_ASYNC);
944   File lying_file(file.TakePlatformFile(), false /* async */);
945   ASSERT_TRUE(lying_file.IsValid());
946 
947   ASSERT_EQ(lying_file.WriteAtCurrentPos("12345", 5), -1);
948 }
949 
950 TEST(FileDeathTest, InvalidFlags) {
951   EXPECT_CHECK_DEATH_WITH(
952       {
953         // When this test is running as Admin, TMP gets ignored and temporary
954         // files/folders are created in %ProgramFiles%. This means that the
955         // temporary folder created by the death test never gets deleted, as it
956         // crashes before the `ScopedTempDir` goes out of scope and also
957         // does not get automatically cleaned by by the test runner.
958         //
959         // To avoid this from happening, this death test explicitly creates the
960         // temporary folder in TMP, which is set by the test runner parent
961         // process to a temporary folder for the test. This means that the
962         // folder created here is always deleted during test runner cleanup.
963         std::string tmp_folder;
964         ASSERT_TRUE(Environment::Create()->GetVar("TMP", &tmp_folder));
965         ScopedTempDir temp_dir;
966         ASSERT_TRUE(temp_dir.CreateUniqueTempDirUnderPath(
967             FilePath(UTF8ToWide(tmp_folder))));
968         FilePath file_path = temp_dir.GetPath().AppendASCII("file");
969 
970         File file(file_path, File::FLAG_CREATE | File::FLAG_WIN_EXECUTE |
971                                  File::FLAG_READ | File::FLAG_WIN_NO_EXECUTE);
972       },
973       "FLAG_WIN_NO_EXECUTE");
974 }
975 #endif  // BUILDFLAG(IS_WIN)
976 
977 }  // namespace base
978