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