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