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,GetLastFileError)254 TEST(FileTest, GetLastFileError) {
255 #if BUILDFLAG(IS_WIN)
256 ::SetLastError(ERROR_ACCESS_DENIED);
257 #else
258 errno = EACCES;
259 #endif
260 EXPECT_EQ(File::FILE_ERROR_ACCESS_DENIED, File::GetLastFileError());
261
262 base::ScopedTempDir temp_dir;
263 EXPECT_TRUE(temp_dir.CreateUniqueTempDir());
264
265 FilePath nonexistent_path(temp_dir.GetPath().AppendASCII("nonexistent"));
266 File file(nonexistent_path, File::FLAG_OPEN | File::FLAG_READ);
267 File::Error last_error = File::GetLastFileError();
268 EXPECT_FALSE(file.IsValid());
269 EXPECT_EQ(File::FILE_ERROR_NOT_FOUND, file.error_details());
270 EXPECT_EQ(File::FILE_ERROR_NOT_FOUND, last_error);
271 }
272
TEST(FileTest,Append)273 TEST(FileTest, Append) {
274 base::ScopedTempDir temp_dir;
275 ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
276 FilePath file_path = temp_dir.GetPath().AppendASCII("append_file");
277 File file(file_path, base::File::FLAG_CREATE | base::File::FLAG_APPEND);
278 ASSERT_TRUE(file.IsValid());
279
280 char data_to_write[] = "test";
281 const int kTestDataSize = 4;
282
283 // Write 0 bytes to the file.
284 int bytes_written = file.Write(0, data_to_write, 0);
285 EXPECT_EQ(0, bytes_written);
286
287 // Write 0 bytes, with buf=nullptr.
288 bytes_written = file.Write(0, nullptr, 0);
289 EXPECT_EQ(0, bytes_written);
290
291 // Write "test" to the file.
292 bytes_written = file.Write(0, data_to_write, kTestDataSize);
293 EXPECT_EQ(kTestDataSize, bytes_written);
294
295 file.Close();
296 File file2(file_path,
297 base::File::FLAG_OPEN | base::File::FLAG_READ |
298 base::File::FLAG_APPEND);
299 ASSERT_TRUE(file2.IsValid());
300
301 // Test passing the file around.
302 file = std::move(file2);
303 EXPECT_FALSE(file2.IsValid());
304 ASSERT_TRUE(file.IsValid());
305
306 char append_data_to_write[] = "78";
307 const int kAppendDataSize = 2;
308
309 // Append "78" to the file.
310 bytes_written = file.Write(0, append_data_to_write, kAppendDataSize);
311 EXPECT_EQ(kAppendDataSize, bytes_written);
312
313 // Read the entire file.
314 char data_read_1[32];
315 int bytes_read = file.Read(0, data_read_1,
316 kTestDataSize + kAppendDataSize);
317 EXPECT_EQ(kTestDataSize + kAppendDataSize, bytes_read);
318 for (int i = 0; i < kTestDataSize; i++)
319 EXPECT_EQ(data_to_write[i], data_read_1[i]);
320 for (int i = 0; i < kAppendDataSize; i++)
321 EXPECT_EQ(append_data_to_write[i], data_read_1[kTestDataSize + i]);
322 }
323
324
TEST(FileTest,Length)325 TEST(FileTest, Length) {
326 base::ScopedTempDir temp_dir;
327 ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
328 FilePath file_path = temp_dir.GetPath().AppendASCII("truncate_file");
329 File file(file_path,
330 base::File::FLAG_CREATE | base::File::FLAG_READ |
331 base::File::FLAG_WRITE);
332 ASSERT_TRUE(file.IsValid());
333 EXPECT_EQ(0, file.GetLength());
334
335 // Write "test" to the file.
336 char data_to_write[] = "test";
337 int kTestDataSize = 4;
338 int bytes_written = file.Write(0, data_to_write, kTestDataSize);
339 EXPECT_EQ(kTestDataSize, bytes_written);
340
341 // Extend the file.
342 const int kExtendedFileLength = 10;
343 int64_t file_size = 0;
344 EXPECT_TRUE(file.SetLength(kExtendedFileLength));
345 EXPECT_EQ(kExtendedFileLength, file.GetLength());
346 EXPECT_TRUE(GetFileSize(file_path, &file_size));
347 EXPECT_EQ(kExtendedFileLength, file_size);
348
349 // Make sure the file was zero-padded.
350 char data_read[32];
351 int bytes_read = file.Read(0, data_read, static_cast<int>(file_size));
352 EXPECT_EQ(file_size, bytes_read);
353 for (int i = 0; i < kTestDataSize; i++)
354 EXPECT_EQ(data_to_write[i], data_read[i]);
355 for (int i = kTestDataSize; i < file_size; i++)
356 EXPECT_EQ(0, data_read[i]);
357
358 // Truncate the file.
359 const int kTruncatedFileLength = 2;
360 EXPECT_TRUE(file.SetLength(kTruncatedFileLength));
361 EXPECT_EQ(kTruncatedFileLength, file.GetLength());
362 EXPECT_TRUE(GetFileSize(file_path, &file_size));
363 EXPECT_EQ(kTruncatedFileLength, file_size);
364
365 // Make sure the file was truncated.
366 bytes_read = file.Read(0, data_read, kTestDataSize);
367 EXPECT_EQ(file_size, bytes_read);
368 for (int i = 0; i < file_size; i++)
369 EXPECT_EQ(data_to_write[i], data_read[i]);
370
371 #if !BUILDFLAG(IS_FUCHSIA) // Fuchsia doesn't seem to support big files.
372 // Expand the file past the 4 GB limit.
373 const int64_t kBigFileLength = 5'000'000'000;
374 EXPECT_TRUE(file.SetLength(kBigFileLength));
375 EXPECT_EQ(kBigFileLength, file.GetLength());
376 EXPECT_TRUE(GetFileSize(file_path, &file_size));
377 EXPECT_EQ(kBigFileLength, file_size);
378 #endif
379
380 // Close the file and reopen with base::File::FLAG_CREATE_ALWAYS, and make
381 // sure the file is empty (old file was overridden).
382 file.Close();
383 file.Initialize(file_path,
384 base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE);
385 EXPECT_EQ(0, file.GetLength());
386 }
387
388 // Flakily fails: http://crbug.com/86494
389 #if BUILDFLAG(IS_ANDROID)
TEST(FileTest,TouchGetInfo)390 TEST(FileTest, TouchGetInfo) {
391 #else
392 TEST(FileTest, DISABLED_TouchGetInfo) {
393 #endif
394 base::ScopedTempDir temp_dir;
395 ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
396 File file(temp_dir.GetPath().AppendASCII("touch_get_info_file"),
397 base::File::FLAG_CREATE | base::File::FLAG_WRITE |
398 base::File::FLAG_WRITE_ATTRIBUTES);
399 ASSERT_TRUE(file.IsValid());
400
401 // Get info for a newly created file.
402 base::File::Info info;
403 EXPECT_TRUE(file.GetInfo(&info));
404
405 // Add 2 seconds to account for possible rounding errors on
406 // filesystems that use a 1s or 2s timestamp granularity.
407 base::Time now = base::Time::Now() + base::Seconds(2);
408 EXPECT_EQ(0, info.size);
409 EXPECT_FALSE(info.is_directory);
410 EXPECT_FALSE(info.is_symbolic_link);
411 EXPECT_LE(info.last_accessed.ToInternalValue(), now.ToInternalValue());
412 EXPECT_LE(info.last_modified.ToInternalValue(), now.ToInternalValue());
413 EXPECT_LE(info.creation_time.ToInternalValue(), now.ToInternalValue());
414 base::Time creation_time = info.creation_time;
415
416 // Write "test" to the file.
417 char data[] = "test";
418 const int kTestDataSize = 4;
419 int bytes_written = file.Write(0, data, kTestDataSize);
420 EXPECT_EQ(kTestDataSize, bytes_written);
421
422 // Change the last_accessed and last_modified dates.
423 // It's best to add values that are multiples of 2 (in seconds)
424 // to the current last_accessed and last_modified times, because
425 // FATxx uses a 2s timestamp granularity.
426 base::Time new_last_accessed = info.last_accessed + base::Seconds(234);
427 base::Time new_last_modified = info.last_modified + base::Minutes(567);
428
429 EXPECT_TRUE(file.SetTimes(new_last_accessed, new_last_modified));
430
431 // Make sure the file info was updated accordingly.
432 EXPECT_TRUE(file.GetInfo(&info));
433 EXPECT_EQ(info.size, kTestDataSize);
434 EXPECT_FALSE(info.is_directory);
435 EXPECT_FALSE(info.is_symbolic_link);
436
437 // ext2/ext3 and HPS/HPS+ seem to have a timestamp granularity of 1s.
438 #if BUILDFLAG(IS_POSIX)
439 EXPECT_EQ(info.last_accessed.ToTimeVal().tv_sec,
440 new_last_accessed.ToTimeVal().tv_sec);
441 EXPECT_EQ(info.last_modified.ToTimeVal().tv_sec,
442 new_last_modified.ToTimeVal().tv_sec);
443 #else
444 EXPECT_EQ(info.last_accessed.ToInternalValue(),
445 new_last_accessed.ToInternalValue());
446 EXPECT_EQ(info.last_modified.ToInternalValue(),
447 new_last_modified.ToInternalValue());
448 #endif
449
450 EXPECT_EQ(info.creation_time.ToInternalValue(),
451 creation_time.ToInternalValue());
452 }
453
454 // Test we can retrieve the file's creation time through File::GetInfo().
455 TEST(FileTest, GetInfoForCreationTime) {
456 int64_t before_creation_time_s =
457 base::Time::Now().ToDeltaSinceWindowsEpoch().InSeconds();
458
459 base::ScopedTempDir temp_dir;
460 ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
461 FilePath file_path = temp_dir.GetPath().AppendASCII("test_file");
462 File file(file_path, base::File::FLAG_CREATE | base::File::FLAG_READ |
463 base::File::FLAG_WRITE);
464 EXPECT_TRUE(file.IsValid());
465
466 int64_t after_creation_time_s =
467 base::Time::Now().ToDeltaSinceWindowsEpoch().InSeconds();
468
469 base::File::Info info;
470 EXPECT_TRUE(file.GetInfo(&info));
471 EXPECT_GE(info.creation_time.ToDeltaSinceWindowsEpoch().InSeconds(),
472 before_creation_time_s);
473 EXPECT_LE(info.creation_time.ToDeltaSinceWindowsEpoch().InSeconds(),
474 after_creation_time_s);
475 }
476
477 TEST(FileTest, ReadAtCurrentPosition) {
478 base::ScopedTempDir temp_dir;
479 ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
480 FilePath file_path =
481 temp_dir.GetPath().AppendASCII("read_at_current_position");
482 File file(file_path,
483 base::File::FLAG_CREATE | base::File::FLAG_READ |
484 base::File::FLAG_WRITE);
485 EXPECT_TRUE(file.IsValid());
486
487 const char kData[] = "test";
488 const int kDataSize = sizeof(kData) - 1;
489 EXPECT_EQ(kDataSize, file.Write(0, kData, kDataSize));
490
491 EXPECT_EQ(0, file.Seek(base::File::FROM_BEGIN, 0));
492
493 char buffer[kDataSize];
494 int first_chunk_size = kDataSize / 2;
495 EXPECT_EQ(first_chunk_size, file.ReadAtCurrentPos(buffer, first_chunk_size));
496 EXPECT_EQ(kDataSize - first_chunk_size,
497 file.ReadAtCurrentPos(buffer + first_chunk_size,
498 kDataSize - first_chunk_size));
499 EXPECT_EQ(std::string(buffer, buffer + kDataSize), std::string(kData));
500 }
501
502 TEST(FileTest, WriteAtCurrentPosition) {
503 base::ScopedTempDir temp_dir;
504 ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
505 FilePath file_path =
506 temp_dir.GetPath().AppendASCII("write_at_current_position");
507 File file(file_path,
508 base::File::FLAG_CREATE | base::File::FLAG_READ |
509 base::File::FLAG_WRITE);
510 EXPECT_TRUE(file.IsValid());
511
512 const char kData[] = "test";
513 const int kDataSize = sizeof(kData) - 1;
514
515 int first_chunk_size = kDataSize / 2;
516 EXPECT_EQ(first_chunk_size, file.WriteAtCurrentPos(kData, first_chunk_size));
517 EXPECT_EQ(kDataSize - first_chunk_size,
518 file.WriteAtCurrentPos(kData + first_chunk_size,
519 kDataSize - first_chunk_size));
520
521 char buffer[kDataSize];
522 EXPECT_EQ(kDataSize, file.Read(0, buffer, kDataSize));
523 EXPECT_EQ(std::string(buffer, buffer + kDataSize), std::string(kData));
524 }
525
526 TEST(FileTest, Seek) {
527 base::ScopedTempDir temp_dir;
528 ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
529 FilePath file_path = temp_dir.GetPath().AppendASCII("seek_file");
530 File file(file_path,
531 base::File::FLAG_CREATE | base::File::FLAG_READ |
532 base::File::FLAG_WRITE);
533 ASSERT_TRUE(file.IsValid());
534
535 const int64_t kOffset = 10;
536 EXPECT_EQ(kOffset, file.Seek(base::File::FROM_BEGIN, kOffset));
537 EXPECT_EQ(2 * kOffset, file.Seek(base::File::FROM_CURRENT, kOffset));
538 EXPECT_EQ(kOffset, file.Seek(base::File::FROM_CURRENT, -kOffset));
539 EXPECT_TRUE(file.SetLength(kOffset * 2));
540 EXPECT_EQ(kOffset, file.Seek(base::File::FROM_END, -kOffset));
541 }
542
543 TEST(FileTest, Duplicate) {
544 base::ScopedTempDir temp_dir;
545 ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
546 FilePath file_path = temp_dir.GetPath().AppendASCII("file");
547 File file(file_path,(base::File::FLAG_CREATE |
548 base::File::FLAG_READ |
549 base::File::FLAG_WRITE));
550 ASSERT_TRUE(file.IsValid());
551
552 File file2(file.Duplicate());
553 ASSERT_TRUE(file2.IsValid());
554
555 // Write through one handle, close it, read through the other.
556 static const char kData[] = "now is a good time.";
557 static const int kDataLen = sizeof(kData) - 1;
558
559 ASSERT_EQ(0, file.Seek(base::File::FROM_CURRENT, 0));
560 ASSERT_EQ(0, file2.Seek(base::File::FROM_CURRENT, 0));
561 ASSERT_EQ(kDataLen, file.WriteAtCurrentPos(kData, kDataLen));
562 ASSERT_EQ(kDataLen, file.Seek(base::File::FROM_CURRENT, 0));
563 ASSERT_EQ(kDataLen, file2.Seek(base::File::FROM_CURRENT, 0));
564 file.Close();
565 char buf[kDataLen];
566 ASSERT_EQ(kDataLen, file2.Read(0, &buf[0], kDataLen));
567 ASSERT_EQ(std::string(kData, kDataLen), std::string(&buf[0], kDataLen));
568 }
569
570 TEST(FileTest, DuplicateDeleteOnClose) {
571 base::ScopedTempDir temp_dir;
572 ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
573 FilePath file_path = temp_dir.GetPath().AppendASCII("file");
574 File file(file_path,(base::File::FLAG_CREATE |
575 base::File::FLAG_READ |
576 base::File::FLAG_WRITE |
577 base::File::FLAG_DELETE_ON_CLOSE));
578 ASSERT_TRUE(file.IsValid());
579 File file2(file.Duplicate());
580 ASSERT_TRUE(file2.IsValid());
581 file.Close();
582 file2.Close();
583 ASSERT_FALSE(base::PathExists(file_path));
584 }
585
586 #if BUILDFLAG(ENABLE_BASE_TRACING)
587 TEST(FileTest, TracedValueSupport) {
588 base::ScopedTempDir temp_dir;
589 ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
590 FilePath file_path = temp_dir.GetPath().AppendASCII("file");
591
592 File file(file_path,
593 (base::File::FLAG_CREATE | base::File::FLAG_READ |
594 base::File::FLAG_WRITE | base::File::FLAG_DELETE_ON_CLOSE));
595 ASSERT_TRUE(file.IsValid());
596
597 EXPECT_EQ(perfetto::TracedValueToString(file),
598 "{is_valid:true,created:true,async:false,error_details:FILE_OK}");
599 }
600 #endif // BUILDFLAG(ENABLE_BASE_TRACING)
601
602 #if BUILDFLAG(IS_WIN)
603 // Flakily times out on Windows, see http://crbug.com/846276.
604 #define MAYBE_WriteDataToLargeOffset DISABLED_WriteDataToLargeOffset
605 #else
606 #define MAYBE_WriteDataToLargeOffset WriteDataToLargeOffset
607 #endif
608 TEST(FileTest, MAYBE_WriteDataToLargeOffset) {
609 base::ScopedTempDir temp_dir;
610 ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
611 FilePath file_path = temp_dir.GetPath().AppendASCII("file");
612 File file(file_path,
613 (base::File::FLAG_CREATE | base::File::FLAG_READ |
614 base::File::FLAG_WRITE | base::File::FLAG_DELETE_ON_CLOSE));
615 ASSERT_TRUE(file.IsValid());
616
617 const char kData[] = "this file is sparse.";
618 const int kDataLen = sizeof(kData) - 1;
619 const int64_t kLargeFileOffset = (1LL << 31);
620
621 // If the file fails to write, it is probably we are running out of disk space
622 // and the file system doesn't support sparse file.
623 if (file.Write(kLargeFileOffset - kDataLen - 1, kData, kDataLen) < 0)
624 return;
625
626 ASSERT_EQ(kDataLen, file.Write(kLargeFileOffset + 1, kData, kDataLen));
627 }
628
629 TEST(FileTest, AddFlagsForPassingToUntrustedProcess) {
630 {
631 uint32_t flags = base::File::FLAG_OPEN | base::File::FLAG_READ;
632 flags = base::File::AddFlagsForPassingToUntrustedProcess(flags);
633 EXPECT_EQ(flags, base::File::FLAG_OPEN | base::File::FLAG_READ);
634 }
635 {
636 uint32_t flags = base::File::FLAG_OPEN | base::File::FLAG_WRITE;
637 flags = base::File::AddFlagsForPassingToUntrustedProcess(flags);
638 EXPECT_EQ(flags, base::File::FLAG_OPEN | base::File::FLAG_WRITE |
639 base::File::FLAG_WIN_NO_EXECUTE);
640 }
641 }
642
643 #if BUILDFLAG(IS_WIN)
644 TEST(FileTest, GetInfoForDirectory) {
645 base::ScopedTempDir temp_dir;
646 ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
647 FilePath empty_dir =
648 temp_dir.GetPath().Append(FILE_PATH_LITERAL("gpfi_test"));
649 ASSERT_TRUE(CreateDirectory(empty_dir));
650
651 base::File dir(
652 ::CreateFile(empty_dir.value().c_str(), GENERIC_READ | GENERIC_WRITE,
653 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL,
654 OPEN_EXISTING,
655 FILE_FLAG_BACKUP_SEMANTICS, // Needed to open a directory.
656 NULL));
657 ASSERT_TRUE(dir.IsValid());
658
659 base::File::Info info;
660 EXPECT_TRUE(dir.GetInfo(&info));
661 EXPECT_TRUE(info.is_directory);
662 EXPECT_FALSE(info.is_symbolic_link);
663 EXPECT_EQ(0, info.size);
664 }
665
666 TEST(FileTest, DeleteNoop) {
667 base::ScopedTempDir temp_dir;
668 ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
669 FilePath file_path = temp_dir.GetPath().AppendASCII("file");
670
671 // Creating and closing a file with DELETE perms should do nothing special.
672 File file(file_path,
673 (base::File::FLAG_CREATE | base::File::FLAG_READ |
674 base::File::FLAG_WRITE | base::File::FLAG_CAN_DELETE_ON_CLOSE));
675 ASSERT_TRUE(file.IsValid());
676 file.Close();
677 ASSERT_TRUE(base::PathExists(file_path));
678 }
679
680 TEST(FileTest, Delete) {
681 base::ScopedTempDir temp_dir;
682 ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
683 FilePath file_path = temp_dir.GetPath().AppendASCII("file");
684
685 // Creating a file with DELETE and then marking for delete on close should
686 // delete it.
687 File file(file_path,
688 (base::File::FLAG_CREATE | base::File::FLAG_READ |
689 base::File::FLAG_WRITE | base::File::FLAG_CAN_DELETE_ON_CLOSE));
690 ASSERT_TRUE(file.IsValid());
691 ASSERT_TRUE(file.DeleteOnClose(true));
692 file.Close();
693 ASSERT_FALSE(base::PathExists(file_path));
694 }
695
696 TEST(FileTest, DeleteThenRevoke) {
697 base::ScopedTempDir temp_dir;
698 ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
699 FilePath file_path = temp_dir.GetPath().AppendASCII("file");
700
701 // Creating a file with DELETE, marking it for delete, then clearing delete on
702 // close should not delete it.
703 File file(file_path,
704 (base::File::FLAG_CREATE | base::File::FLAG_READ |
705 base::File::FLAG_WRITE | base::File::FLAG_CAN_DELETE_ON_CLOSE));
706 ASSERT_TRUE(file.IsValid());
707 ASSERT_TRUE(file.DeleteOnClose(true));
708 ASSERT_TRUE(file.DeleteOnClose(false));
709 file.Close();
710 ASSERT_TRUE(base::PathExists(file_path));
711 }
712
713 TEST(FileTest, IrrevokableDeleteOnClose) {
714 base::ScopedTempDir temp_dir;
715 ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
716 FilePath file_path = temp_dir.GetPath().AppendASCII("file");
717
718 // DELETE_ON_CLOSE cannot be revoked by this opener.
719 File file(file_path,
720 (base::File::FLAG_CREATE | base::File::FLAG_READ |
721 base::File::FLAG_WRITE | base::File::FLAG_DELETE_ON_CLOSE |
722 base::File::FLAG_WIN_SHARE_DELETE |
723 base::File::FLAG_CAN_DELETE_ON_CLOSE));
724 ASSERT_TRUE(file.IsValid());
725 // https://msdn.microsoft.com/library/windows/desktop/aa364221.aspx says that
726 // setting the dispositon has no effect if the handle was opened with
727 // FLAG_DELETE_ON_CLOSE. Do not make the test's success dependent on whether
728 // or not SetFileInformationByHandle indicates success or failure. (It happens
729 // to indicate success on Windows 10.)
730 file.DeleteOnClose(false);
731 file.Close();
732 ASSERT_FALSE(base::PathExists(file_path));
733 }
734
735 TEST(FileTest, IrrevokableDeleteOnCloseOther) {
736 base::ScopedTempDir temp_dir;
737 ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
738 FilePath file_path = temp_dir.GetPath().AppendASCII("file");
739
740 // DELETE_ON_CLOSE cannot be revoked by another opener.
741 File file(file_path,
742 (base::File::FLAG_CREATE | base::File::FLAG_READ |
743 base::File::FLAG_WRITE | base::File::FLAG_DELETE_ON_CLOSE |
744 base::File::FLAG_WIN_SHARE_DELETE |
745 base::File::FLAG_CAN_DELETE_ON_CLOSE));
746 ASSERT_TRUE(file.IsValid());
747
748 File file2(file_path,
749 (base::File::FLAG_OPEN | base::File::FLAG_READ |
750 base::File::FLAG_WRITE | base::File::FLAG_WIN_SHARE_DELETE |
751 base::File::FLAG_CAN_DELETE_ON_CLOSE));
752 ASSERT_TRUE(file2.IsValid());
753
754 file2.DeleteOnClose(false);
755 file2.Close();
756 ASSERT_TRUE(base::PathExists(file_path));
757 file.Close();
758 ASSERT_FALSE(base::PathExists(file_path));
759 }
760
761 TEST(FileTest, DeleteWithoutPermission) {
762 base::ScopedTempDir temp_dir;
763 ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
764 FilePath file_path = temp_dir.GetPath().AppendASCII("file");
765
766 // It should not be possible to mark a file for deletion when it was not
767 // created/opened with DELETE.
768 File file(file_path, (base::File::FLAG_CREATE | base::File::FLAG_READ |
769 base::File::FLAG_WRITE));
770 ASSERT_TRUE(file.IsValid());
771 ASSERT_FALSE(file.DeleteOnClose(true));
772 file.Close();
773 ASSERT_TRUE(base::PathExists(file_path));
774 }
775
776 TEST(FileTest, UnsharedDeleteOnClose) {
777 base::ScopedTempDir temp_dir;
778 ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
779 FilePath file_path = temp_dir.GetPath().AppendASCII("file");
780
781 // Opening with DELETE_ON_CLOSE when a previous opener hasn't enabled sharing
782 // will fail.
783 File file(file_path, (base::File::FLAG_CREATE | base::File::FLAG_READ |
784 base::File::FLAG_WRITE));
785 ASSERT_TRUE(file.IsValid());
786 File file2(
787 file_path,
788 (base::File::FLAG_OPEN | base::File::FLAG_READ | base::File::FLAG_WRITE |
789 base::File::FLAG_DELETE_ON_CLOSE | base::File::FLAG_WIN_SHARE_DELETE));
790 ASSERT_FALSE(file2.IsValid());
791
792 file.Close();
793 ASSERT_TRUE(base::PathExists(file_path));
794 }
795
796 TEST(FileTest, NoDeleteOnCloseWithMappedFile) {
797 base::ScopedTempDir temp_dir;
798 ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
799 FilePath file_path = temp_dir.GetPath().AppendASCII("file");
800
801 // Mapping a file into memory blocks DeleteOnClose.
802 File file(file_path,
803 (base::File::FLAG_CREATE | base::File::FLAG_READ |
804 base::File::FLAG_WRITE | base::File::FLAG_CAN_DELETE_ON_CLOSE));
805 ASSERT_TRUE(file.IsValid());
806 ASSERT_EQ(5, file.WriteAtCurrentPos("12345", 5));
807
808 {
809 base::MemoryMappedFile mapping;
810 ASSERT_TRUE(mapping.Initialize(file.Duplicate()));
811 ASSERT_EQ(5U, mapping.length());
812
813 EXPECT_FALSE(file.DeleteOnClose(true));
814 }
815
816 file.Close();
817 ASSERT_TRUE(base::PathExists(file_path));
818 }
819
820 // Check that we handle the async bit being set incorrectly in a sane way.
821 TEST(FileTest, UseSyncApiWithAsyncFile) {
822 base::ScopedTempDir temp_dir;
823 ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
824 FilePath file_path = temp_dir.GetPath().AppendASCII("file");
825
826 File file(file_path, base::File::FLAG_CREATE | base::File::FLAG_WRITE |
827 base::File::FLAG_ASYNC);
828 File lying_file(file.TakePlatformFile(), false /* async */);
829 ASSERT_TRUE(lying_file.IsValid());
830
831 ASSERT_EQ(lying_file.WriteAtCurrentPos("12345", 5), -1);
832 }
833
834 TEST(FileDeathTest, InvalidFlags) {
835 EXPECT_CHECK_DEATH_WITH(
836 {
837 // When this test is running as Admin, TMP gets ignored and temporary
838 // files/folders are created in %ProgramFiles%. This means that the
839 // temporary folder created by the death test never gets deleted, as it
840 // crashes before the `base::ScopedTempDir` goes out of scope and also
841 // does not get automatically cleaned by by the test runner.
842 //
843 // To avoid this from happening, this death test explicitly creates the
844 // temporary folder in TMP, which is set by the test runner parent
845 // process to a temporary folder for the test. This means that the
846 // folder created here is always deleted during test runner cleanup.
847 std::string tmp_folder;
848 ASSERT_TRUE(base::Environment::Create()->GetVar("TMP", &tmp_folder));
849 base::ScopedTempDir temp_dir;
850 ASSERT_TRUE(temp_dir.CreateUniqueTempDirUnderPath(
851 base::FilePath(base::UTF8ToWide(tmp_folder))));
852 FilePath file_path = temp_dir.GetPath().AppendASCII("file");
853
854 File file(file_path,
855 base::File::FLAG_CREATE | base::File::FLAG_WIN_EXECUTE |
856 base::File::FLAG_READ | base::File::FLAG_WIN_NO_EXECUTE);
857 },
858 "FLAG_WIN_NO_EXECUTE");
859 }
860 #endif // BUILDFLAG(IS_WIN)