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