1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
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/time/time.h"
15 #include "build/build_config.h"
16 #include "testing/gtest/include/gtest/gtest.h"
17
18 using base::File;
19 using base::FilePath;
20
TEST(FileTest,Create)21 TEST(FileTest, Create) {
22 base::ScopedTempDir temp_dir;
23 ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
24 FilePath file_path = temp_dir.GetPath().AppendASCII("create_file_1");
25
26 {
27 // Don't create a File at all.
28 File file;
29 EXPECT_FALSE(file.IsValid());
30 EXPECT_EQ(base::File::FILE_ERROR_FAILED, file.error_details());
31
32 File file2(base::File::FILE_ERROR_TOO_MANY_OPENED);
33 EXPECT_FALSE(file2.IsValid());
34 EXPECT_EQ(base::File::FILE_ERROR_TOO_MANY_OPENED, file2.error_details());
35 }
36
37 {
38 // Open a file that doesn't exist.
39 File file(file_path, base::File::FLAG_OPEN | base::File::FLAG_READ);
40 EXPECT_FALSE(file.IsValid());
41 EXPECT_EQ(base::File::FILE_ERROR_NOT_FOUND, file.error_details());
42 EXPECT_EQ(base::File::FILE_ERROR_NOT_FOUND, base::File::GetLastFileError());
43 }
44
45 {
46 // Open or create a file.
47 File file(file_path, base::File::FLAG_OPEN_ALWAYS | base::File::FLAG_READ);
48 EXPECT_TRUE(file.IsValid());
49 EXPECT_TRUE(file.created());
50 EXPECT_EQ(base::File::FILE_OK, file.error_details());
51 }
52
53 {
54 // Open an existing file.
55 File file(file_path, base::File::FLAG_OPEN | base::File::FLAG_READ);
56 EXPECT_TRUE(file.IsValid());
57 EXPECT_FALSE(file.created());
58 EXPECT_EQ(base::File::FILE_OK, file.error_details());
59
60 // This time verify closing the file.
61 file.Close();
62 EXPECT_FALSE(file.IsValid());
63 }
64
65 {
66 // Open an existing file through Initialize
67 File file;
68 file.Initialize(file_path, base::File::FLAG_OPEN | base::File::FLAG_READ);
69 EXPECT_TRUE(file.IsValid());
70 EXPECT_FALSE(file.created());
71 EXPECT_EQ(base::File::FILE_OK, file.error_details());
72
73 // This time verify closing the file.
74 file.Close();
75 EXPECT_FALSE(file.IsValid());
76 }
77
78 {
79 // Create a file that exists.
80 File file(file_path, base::File::FLAG_CREATE | base::File::FLAG_READ);
81 EXPECT_FALSE(file.IsValid());
82 EXPECT_FALSE(file.created());
83 EXPECT_EQ(base::File::FILE_ERROR_EXISTS, file.error_details());
84 EXPECT_EQ(base::File::FILE_ERROR_EXISTS, base::File::GetLastFileError());
85 }
86
87 {
88 // Create or overwrite a file.
89 File file(file_path,
90 base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE);
91 EXPECT_TRUE(file.IsValid());
92 EXPECT_TRUE(file.created());
93 EXPECT_EQ(base::File::FILE_OK, file.error_details());
94 }
95
96 {
97 // Create a delete-on-close file.
98 file_path = temp_dir.GetPath().AppendASCII("create_file_2");
99 File file(file_path,
100 base::File::FLAG_OPEN_ALWAYS | base::File::FLAG_READ |
101 base::File::FLAG_DELETE_ON_CLOSE);
102 EXPECT_TRUE(file.IsValid());
103 EXPECT_TRUE(file.created());
104 EXPECT_EQ(base::File::FILE_OK, file.error_details());
105 }
106
107 EXPECT_FALSE(base::PathExists(file_path));
108 }
109
TEST(FileTest,SelfSwap)110 TEST(FileTest, SelfSwap) {
111 base::ScopedTempDir temp_dir;
112 ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
113 FilePath file_path = temp_dir.GetPath().AppendASCII("create_file_1");
114 File file(file_path,
115 base::File::FLAG_OPEN_ALWAYS | base::File::FLAG_DELETE_ON_CLOSE);
116 std::swap(file, file);
117 EXPECT_TRUE(file.IsValid());
118 }
119
TEST(FileTest,Async)120 TEST(FileTest, Async) {
121 base::ScopedTempDir temp_dir;
122 ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
123 FilePath file_path = temp_dir.GetPath().AppendASCII("create_file");
124
125 {
126 File file(file_path, base::File::FLAG_OPEN_ALWAYS | base::File::FLAG_ASYNC);
127 EXPECT_TRUE(file.IsValid());
128 EXPECT_TRUE(file.async());
129 }
130
131 {
132 File file(file_path, base::File::FLAG_OPEN_ALWAYS);
133 EXPECT_TRUE(file.IsValid());
134 EXPECT_FALSE(file.async());
135 }
136 }
137
TEST(FileTest,DeleteOpenFile)138 TEST(FileTest, DeleteOpenFile) {
139 base::ScopedTempDir temp_dir;
140 ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
141 FilePath file_path = temp_dir.GetPath().AppendASCII("create_file_1");
142
143 // Create a file.
144 File file(file_path,
145 base::File::FLAG_OPEN_ALWAYS | base::File::FLAG_READ |
146 base::File::FLAG_SHARE_DELETE);
147 EXPECT_TRUE(file.IsValid());
148 EXPECT_TRUE(file.created());
149 EXPECT_EQ(base::File::FILE_OK, file.error_details());
150
151 // Open an existing file and mark it as delete on close.
152 File same_file(file_path,
153 base::File::FLAG_OPEN | base::File::FLAG_DELETE_ON_CLOSE |
154 base::File::FLAG_READ);
155 EXPECT_TRUE(file.IsValid());
156 EXPECT_FALSE(same_file.created());
157 EXPECT_EQ(base::File::FILE_OK, same_file.error_details());
158
159 // Close both handles and check that the file is gone.
160 file.Close();
161 same_file.Close();
162 EXPECT_FALSE(base::PathExists(file_path));
163 }
164
TEST(FileTest,ReadWrite)165 TEST(FileTest, ReadWrite) {
166 base::ScopedTempDir temp_dir;
167 ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
168 FilePath file_path = temp_dir.GetPath().AppendASCII("read_write_file");
169 File file(file_path,
170 base::File::FLAG_CREATE | base::File::FLAG_READ |
171 base::File::FLAG_WRITE);
172 ASSERT_TRUE(file.IsValid());
173
174 char data_to_write[] = "test";
175 const int kTestDataSize = 4;
176
177 // Write 0 bytes to the file.
178 int bytes_written = file.Write(0, data_to_write, 0);
179 EXPECT_EQ(0, bytes_written);
180
181 // Write 0 bytes, with buf=nullptr.
182 bytes_written = file.Write(0, nullptr, 0);
183 EXPECT_EQ(0, bytes_written);
184
185 // Write "test" to the file.
186 bytes_written = file.Write(0, data_to_write, kTestDataSize);
187 EXPECT_EQ(kTestDataSize, bytes_written);
188
189 // Read from EOF.
190 char data_read_1[32];
191 int bytes_read = file.Read(kTestDataSize, data_read_1, kTestDataSize);
192 EXPECT_EQ(0, bytes_read);
193
194 // Read from somewhere in the middle of the file.
195 const int kPartialReadOffset = 1;
196 bytes_read = file.Read(kPartialReadOffset, data_read_1, kTestDataSize);
197 EXPECT_EQ(kTestDataSize - kPartialReadOffset, bytes_read);
198 for (int i = 0; i < bytes_read; i++)
199 EXPECT_EQ(data_to_write[i + kPartialReadOffset], data_read_1[i]);
200
201 // Read 0 bytes.
202 bytes_read = file.Read(0, data_read_1, 0);
203 EXPECT_EQ(0, bytes_read);
204
205 // Read the entire file.
206 bytes_read = file.Read(0, data_read_1, kTestDataSize);
207 EXPECT_EQ(kTestDataSize, bytes_read);
208 for (int i = 0; i < bytes_read; i++)
209 EXPECT_EQ(data_to_write[i], data_read_1[i]);
210
211 // Read again, but using the trivial native wrapper.
212 bytes_read = file.ReadNoBestEffort(0, data_read_1, kTestDataSize);
213 EXPECT_LE(bytes_read, kTestDataSize);
214 for (int i = 0; i < bytes_read; i++)
215 EXPECT_EQ(data_to_write[i], data_read_1[i]);
216
217 // Write past the end of the file.
218 const int kOffsetBeyondEndOfFile = 10;
219 const int kPartialWriteLength = 2;
220 bytes_written = file.Write(kOffsetBeyondEndOfFile,
221 data_to_write, kPartialWriteLength);
222 EXPECT_EQ(kPartialWriteLength, bytes_written);
223
224 // Make sure the file was extended.
225 int64_t file_size = 0;
226 EXPECT_TRUE(GetFileSize(file_path, &file_size));
227 EXPECT_EQ(kOffsetBeyondEndOfFile + kPartialWriteLength, file_size);
228
229 // Make sure the file was zero-padded.
230 char data_read_2[32];
231 bytes_read = file.Read(0, data_read_2, static_cast<int>(file_size));
232 EXPECT_EQ(file_size, bytes_read);
233 for (int i = 0; i < kTestDataSize; i++)
234 EXPECT_EQ(data_to_write[i], data_read_2[i]);
235 for (int i = kTestDataSize; i < kOffsetBeyondEndOfFile; i++)
236 EXPECT_EQ(0, data_read_2[i]);
237 for (int i = kOffsetBeyondEndOfFile; i < file_size; i++)
238 EXPECT_EQ(data_to_write[i - kOffsetBeyondEndOfFile], data_read_2[i]);
239 }
240
TEST(FileTest,GetLastFileError)241 TEST(FileTest, GetLastFileError) {
242 #if defined(OS_WIN)
243 ::SetLastError(ERROR_ACCESS_DENIED);
244 #else
245 errno = EACCES;
246 #endif
247 EXPECT_EQ(File::FILE_ERROR_ACCESS_DENIED, File::GetLastFileError());
248
249 base::ScopedTempDir temp_dir;
250 EXPECT_TRUE(temp_dir.CreateUniqueTempDir());
251
252 FilePath nonexistent_path(temp_dir.GetPath().AppendASCII("nonexistent"));
253 File file(nonexistent_path, File::FLAG_OPEN | File::FLAG_READ);
254 File::Error last_error = File::GetLastFileError();
255 EXPECT_FALSE(file.IsValid());
256 EXPECT_EQ(File::FILE_ERROR_NOT_FOUND, file.error_details());
257 EXPECT_EQ(File::FILE_ERROR_NOT_FOUND, last_error);
258 }
259
TEST(FileTest,Append)260 TEST(FileTest, Append) {
261 base::ScopedTempDir temp_dir;
262 ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
263 FilePath file_path = temp_dir.GetPath().AppendASCII("append_file");
264 File file(file_path, base::File::FLAG_CREATE | base::File::FLAG_APPEND);
265 ASSERT_TRUE(file.IsValid());
266
267 char data_to_write[] = "test";
268 const int kTestDataSize = 4;
269
270 // Write 0 bytes to the file.
271 int bytes_written = file.Write(0, data_to_write, 0);
272 EXPECT_EQ(0, bytes_written);
273
274 // Write 0 bytes, with buf=nullptr.
275 bytes_written = file.Write(0, nullptr, 0);
276 EXPECT_EQ(0, bytes_written);
277
278 // Write "test" to the file.
279 bytes_written = file.Write(0, data_to_write, kTestDataSize);
280 EXPECT_EQ(kTestDataSize, bytes_written);
281
282 file.Close();
283 File file2(file_path,
284 base::File::FLAG_OPEN | base::File::FLAG_READ |
285 base::File::FLAG_APPEND);
286 ASSERT_TRUE(file2.IsValid());
287
288 // Test passing the file around.
289 file = std::move(file2);
290 EXPECT_FALSE(file2.IsValid());
291 ASSERT_TRUE(file.IsValid());
292
293 char append_data_to_write[] = "78";
294 const int kAppendDataSize = 2;
295
296 // Append "78" to the file.
297 bytes_written = file.Write(0, append_data_to_write, kAppendDataSize);
298 EXPECT_EQ(kAppendDataSize, bytes_written);
299
300 // Read the entire file.
301 char data_read_1[32];
302 int bytes_read = file.Read(0, data_read_1,
303 kTestDataSize + kAppendDataSize);
304 EXPECT_EQ(kTestDataSize + kAppendDataSize, bytes_read);
305 for (int i = 0; i < kTestDataSize; i++)
306 EXPECT_EQ(data_to_write[i], data_read_1[i]);
307 for (int i = 0; i < kAppendDataSize; i++)
308 EXPECT_EQ(append_data_to_write[i], data_read_1[kTestDataSize + i]);
309 }
310
311
TEST(FileTest,Length)312 TEST(FileTest, Length) {
313 base::ScopedTempDir temp_dir;
314 ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
315 FilePath file_path = temp_dir.GetPath().AppendASCII("truncate_file");
316 File file(file_path,
317 base::File::FLAG_CREATE | base::File::FLAG_READ |
318 base::File::FLAG_WRITE);
319 ASSERT_TRUE(file.IsValid());
320 EXPECT_EQ(0, file.GetLength());
321
322 // Write "test" to the file.
323 char data_to_write[] = "test";
324 int kTestDataSize = 4;
325 int bytes_written = file.Write(0, data_to_write, kTestDataSize);
326 EXPECT_EQ(kTestDataSize, bytes_written);
327
328 // Extend the file.
329 const int kExtendedFileLength = 10;
330 int64_t file_size = 0;
331 EXPECT_TRUE(file.SetLength(kExtendedFileLength));
332 EXPECT_EQ(kExtendedFileLength, file.GetLength());
333 EXPECT_TRUE(GetFileSize(file_path, &file_size));
334 EXPECT_EQ(kExtendedFileLength, file_size);
335
336 // Make sure the file was zero-padded.
337 char data_read[32];
338 int bytes_read = file.Read(0, data_read, static_cast<int>(file_size));
339 EXPECT_EQ(file_size, bytes_read);
340 for (int i = 0; i < kTestDataSize; i++)
341 EXPECT_EQ(data_to_write[i], data_read[i]);
342 for (int i = kTestDataSize; i < file_size; i++)
343 EXPECT_EQ(0, data_read[i]);
344
345 // Truncate the file.
346 const int kTruncatedFileLength = 2;
347 EXPECT_TRUE(file.SetLength(kTruncatedFileLength));
348 EXPECT_EQ(kTruncatedFileLength, file.GetLength());
349 EXPECT_TRUE(GetFileSize(file_path, &file_size));
350 EXPECT_EQ(kTruncatedFileLength, file_size);
351
352 // Make sure the file was truncated.
353 bytes_read = file.Read(0, data_read, kTestDataSize);
354 EXPECT_EQ(file_size, bytes_read);
355 for (int i = 0; i < file_size; i++)
356 EXPECT_EQ(data_to_write[i], data_read[i]);
357
358 // Close the file and reopen with base::File::FLAG_CREATE_ALWAYS, and make
359 // sure the file is empty (old file was overridden).
360 file.Close();
361 file.Initialize(file_path,
362 base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE);
363 EXPECT_EQ(0, file.GetLength());
364 }
365
366 // Flakily fails: http://crbug.com/86494
367 #if defined(OS_ANDROID)
TEST(FileTest,TouchGetInfo)368 TEST(FileTest, TouchGetInfo) {
369 #else
370 TEST(FileTest, DISABLED_TouchGetInfo) {
371 #endif
372 base::ScopedTempDir temp_dir;
373 ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
374 File file(temp_dir.GetPath().AppendASCII("touch_get_info_file"),
375 base::File::FLAG_CREATE | base::File::FLAG_WRITE |
376 base::File::FLAG_WRITE_ATTRIBUTES);
377 ASSERT_TRUE(file.IsValid());
378
379 // Get info for a newly created file.
380 base::File::Info info;
381 EXPECT_TRUE(file.GetInfo(&info));
382
383 // Add 2 seconds to account for possible rounding errors on
384 // filesystems that use a 1s or 2s timestamp granularity.
385 base::Time now = base::Time::Now() + base::TimeDelta::FromSeconds(2);
386 EXPECT_EQ(0, info.size);
387 EXPECT_FALSE(info.is_directory);
388 EXPECT_FALSE(info.is_symbolic_link);
389 EXPECT_LE(info.last_accessed.ToInternalValue(), now.ToInternalValue());
390 EXPECT_LE(info.last_modified.ToInternalValue(), now.ToInternalValue());
391 EXPECT_LE(info.creation_time.ToInternalValue(), now.ToInternalValue());
392 base::Time creation_time = info.creation_time;
393
394 // Write "test" to the file.
395 char data[] = "test";
396 const int kTestDataSize = 4;
397 int bytes_written = file.Write(0, data, kTestDataSize);
398 EXPECT_EQ(kTestDataSize, bytes_written);
399
400 // Change the last_accessed and last_modified dates.
401 // It's best to add values that are multiples of 2 (in seconds)
402 // to the current last_accessed and last_modified times, because
403 // FATxx uses a 2s timestamp granularity.
404 base::Time new_last_accessed =
405 info.last_accessed + base::TimeDelta::FromSeconds(234);
406 base::Time new_last_modified =
407 info.last_modified + base::TimeDelta::FromMinutes(567);
408
409 EXPECT_TRUE(file.SetTimes(new_last_accessed, new_last_modified));
410
411 // Make sure the file info was updated accordingly.
412 EXPECT_TRUE(file.GetInfo(&info));
413 EXPECT_EQ(info.size, kTestDataSize);
414 EXPECT_FALSE(info.is_directory);
415 EXPECT_FALSE(info.is_symbolic_link);
416
417 // ext2/ext3 and HPS/HPS+ seem to have a timestamp granularity of 1s.
418 #if defined(OS_POSIX)
419 EXPECT_EQ(info.last_accessed.ToTimeVal().tv_sec,
420 new_last_accessed.ToTimeVal().tv_sec);
421 EXPECT_EQ(info.last_modified.ToTimeVal().tv_sec,
422 new_last_modified.ToTimeVal().tv_sec);
423 #else
424 EXPECT_EQ(info.last_accessed.ToInternalValue(),
425 new_last_accessed.ToInternalValue());
426 EXPECT_EQ(info.last_modified.ToInternalValue(),
427 new_last_modified.ToInternalValue());
428 #endif
429
430 EXPECT_EQ(info.creation_time.ToInternalValue(),
431 creation_time.ToInternalValue());
432 }
433
434 TEST(FileTest, ReadAtCurrentPosition) {
435 base::ScopedTempDir temp_dir;
436 ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
437 FilePath file_path =
438 temp_dir.GetPath().AppendASCII("read_at_current_position");
439 File file(file_path,
440 base::File::FLAG_CREATE | base::File::FLAG_READ |
441 base::File::FLAG_WRITE);
442 EXPECT_TRUE(file.IsValid());
443
444 const char kData[] = "test";
445 const int kDataSize = sizeof(kData) - 1;
446 EXPECT_EQ(kDataSize, file.Write(0, kData, kDataSize));
447
448 EXPECT_EQ(0, file.Seek(base::File::FROM_BEGIN, 0));
449
450 char buffer[kDataSize];
451 int first_chunk_size = kDataSize / 2;
452 EXPECT_EQ(first_chunk_size, file.ReadAtCurrentPos(buffer, first_chunk_size));
453 EXPECT_EQ(kDataSize - first_chunk_size,
454 file.ReadAtCurrentPos(buffer + first_chunk_size,
455 kDataSize - first_chunk_size));
456 EXPECT_EQ(std::string(buffer, buffer + kDataSize), std::string(kData));
457 }
458
459 TEST(FileTest, WriteAtCurrentPosition) {
460 base::ScopedTempDir temp_dir;
461 ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
462 FilePath file_path =
463 temp_dir.GetPath().AppendASCII("write_at_current_position");
464 File file(file_path,
465 base::File::FLAG_CREATE | base::File::FLAG_READ |
466 base::File::FLAG_WRITE);
467 EXPECT_TRUE(file.IsValid());
468
469 const char kData[] = "test";
470 const int kDataSize = sizeof(kData) - 1;
471
472 int first_chunk_size = kDataSize / 2;
473 EXPECT_EQ(first_chunk_size, file.WriteAtCurrentPos(kData, first_chunk_size));
474 EXPECT_EQ(kDataSize - first_chunk_size,
475 file.WriteAtCurrentPos(kData + first_chunk_size,
476 kDataSize - first_chunk_size));
477
478 char buffer[kDataSize];
479 EXPECT_EQ(kDataSize, file.Read(0, buffer, kDataSize));
480 EXPECT_EQ(std::string(buffer, buffer + kDataSize), std::string(kData));
481 }
482
483 TEST(FileTest, Seek) {
484 base::ScopedTempDir temp_dir;
485 ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
486 FilePath file_path = temp_dir.GetPath().AppendASCII("seek_file");
487 File file(file_path,
488 base::File::FLAG_CREATE | base::File::FLAG_READ |
489 base::File::FLAG_WRITE);
490 ASSERT_TRUE(file.IsValid());
491
492 const int64_t kOffset = 10;
493 EXPECT_EQ(kOffset, file.Seek(base::File::FROM_BEGIN, kOffset));
494 EXPECT_EQ(2 * kOffset, file.Seek(base::File::FROM_CURRENT, kOffset));
495 EXPECT_EQ(kOffset, file.Seek(base::File::FROM_CURRENT, -kOffset));
496 EXPECT_TRUE(file.SetLength(kOffset * 2));
497 EXPECT_EQ(kOffset, file.Seek(base::File::FROM_END, -kOffset));
498 }
499
500 TEST(FileTest, Duplicate) {
501 base::ScopedTempDir temp_dir;
502 ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
503 FilePath file_path = temp_dir.GetPath().AppendASCII("file");
504 File file(file_path,(base::File::FLAG_CREATE |
505 base::File::FLAG_READ |
506 base::File::FLAG_WRITE));
507 ASSERT_TRUE(file.IsValid());
508
509 File file2(file.Duplicate());
510 ASSERT_TRUE(file2.IsValid());
511
512 // Write through one handle, close it, read through the other.
513 static const char kData[] = "now is a good time.";
514 static const int kDataLen = sizeof(kData) - 1;
515
516 ASSERT_EQ(0, file.Seek(base::File::FROM_CURRENT, 0));
517 ASSERT_EQ(0, file2.Seek(base::File::FROM_CURRENT, 0));
518 ASSERT_EQ(kDataLen, file.WriteAtCurrentPos(kData, kDataLen));
519 ASSERT_EQ(kDataLen, file.Seek(base::File::FROM_CURRENT, 0));
520 ASSERT_EQ(kDataLen, file2.Seek(base::File::FROM_CURRENT, 0));
521 file.Close();
522 char buf[kDataLen];
523 ASSERT_EQ(kDataLen, file2.Read(0, &buf[0], kDataLen));
524 ASSERT_EQ(std::string(kData, kDataLen), std::string(&buf[0], kDataLen));
525 }
526
527 TEST(FileTest, DuplicateDeleteOnClose) {
528 base::ScopedTempDir temp_dir;
529 ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
530 FilePath file_path = temp_dir.GetPath().AppendASCII("file");
531 File file(file_path,(base::File::FLAG_CREATE |
532 base::File::FLAG_READ |
533 base::File::FLAG_WRITE |
534 base::File::FLAG_DELETE_ON_CLOSE));
535 ASSERT_TRUE(file.IsValid());
536 File file2(file.Duplicate());
537 ASSERT_TRUE(file2.IsValid());
538 file.Close();
539 file2.Close();
540 ASSERT_FALSE(base::PathExists(file_path));
541 }
542
543 #if defined(OS_WIN)
544 // Flakily times out on Windows, see http://crbug.com/846276.
545 #define MAYBE_WriteDataToLargeOffset DISABLED_WriteDataToLargeOffset
546 #else
547 #define MAYBE_WriteDataToLargeOffset WriteDataToLargeOffset
548 #endif
549 TEST(FileTest, MAYBE_WriteDataToLargeOffset) {
550 base::ScopedTempDir temp_dir;
551 ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
552 FilePath file_path = temp_dir.GetPath().AppendASCII("file");
553 File file(file_path,
554 (base::File::FLAG_CREATE | base::File::FLAG_READ |
555 base::File::FLAG_WRITE | base::File::FLAG_DELETE_ON_CLOSE));
556 ASSERT_TRUE(file.IsValid());
557
558 const char kData[] = "this file is sparse.";
559 const int kDataLen = sizeof(kData) - 1;
560 const int64_t kLargeFileOffset = (1LL << 31);
561
562 // If the file fails to write, it is probably we are running out of disk space
563 // and the file system doesn't support sparse file.
564 if (file.Write(kLargeFileOffset - kDataLen - 1, kData, kDataLen) < 0)
565 return;
566
567 ASSERT_EQ(kDataLen, file.Write(kLargeFileOffset + 1, kData, kDataLen));
568 }
569
570 #if defined(OS_WIN)
571 TEST(FileTest, GetInfoForDirectory) {
572 base::ScopedTempDir temp_dir;
573 ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
574 FilePath empty_dir =
575 temp_dir.GetPath().Append(FILE_PATH_LITERAL("gpfi_test"));
576 ASSERT_TRUE(CreateDirectory(empty_dir));
577
578 base::File dir(
579 ::CreateFile(empty_dir.value().c_str(),
580 GENERIC_READ | GENERIC_WRITE,
581 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
582 NULL,
583 OPEN_EXISTING,
584 FILE_FLAG_BACKUP_SEMANTICS, // Needed to open a directory.
585 NULL));
586 ASSERT_TRUE(dir.IsValid());
587
588 base::File::Info info;
589 EXPECT_TRUE(dir.GetInfo(&info));
590 EXPECT_TRUE(info.is_directory);
591 EXPECT_FALSE(info.is_symbolic_link);
592 EXPECT_EQ(0, info.size);
593 }
594
595 TEST(FileTest, DeleteNoop) {
596 base::ScopedTempDir temp_dir;
597 ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
598 FilePath file_path = temp_dir.GetPath().AppendASCII("file");
599
600 // Creating and closing a file with DELETE perms should do nothing special.
601 File file(file_path,
602 (base::File::FLAG_CREATE | base::File::FLAG_READ |
603 base::File::FLAG_WRITE | base::File::FLAG_CAN_DELETE_ON_CLOSE));
604 ASSERT_TRUE(file.IsValid());
605 file.Close();
606 ASSERT_TRUE(base::PathExists(file_path));
607 }
608
609 TEST(FileTest, Delete) {
610 base::ScopedTempDir temp_dir;
611 ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
612 FilePath file_path = temp_dir.GetPath().AppendASCII("file");
613
614 // Creating a file with DELETE and then marking for delete on close should
615 // delete it.
616 File file(file_path,
617 (base::File::FLAG_CREATE | base::File::FLAG_READ |
618 base::File::FLAG_WRITE | base::File::FLAG_CAN_DELETE_ON_CLOSE));
619 ASSERT_TRUE(file.IsValid());
620 ASSERT_TRUE(file.DeleteOnClose(true));
621 file.Close();
622 ASSERT_FALSE(base::PathExists(file_path));
623 }
624
625 TEST(FileTest, DeleteThenRevoke) {
626 base::ScopedTempDir temp_dir;
627 ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
628 FilePath file_path = temp_dir.GetPath().AppendASCII("file");
629
630 // Creating a file with DELETE, marking it for delete, then clearing delete on
631 // close should not delete it.
632 File file(file_path,
633 (base::File::FLAG_CREATE | base::File::FLAG_READ |
634 base::File::FLAG_WRITE | base::File::FLAG_CAN_DELETE_ON_CLOSE));
635 ASSERT_TRUE(file.IsValid());
636 ASSERT_TRUE(file.DeleteOnClose(true));
637 ASSERT_TRUE(file.DeleteOnClose(false));
638 file.Close();
639 ASSERT_TRUE(base::PathExists(file_path));
640 }
641
642 TEST(FileTest, IrrevokableDeleteOnClose) {
643 base::ScopedTempDir temp_dir;
644 ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
645 FilePath file_path = temp_dir.GetPath().AppendASCII("file");
646
647 // DELETE_ON_CLOSE cannot be revoked by this opener.
648 File file(
649 file_path,
650 (base::File::FLAG_CREATE | base::File::FLAG_READ |
651 base::File::FLAG_WRITE | base::File::FLAG_DELETE_ON_CLOSE |
652 base::File::FLAG_SHARE_DELETE | base::File::FLAG_CAN_DELETE_ON_CLOSE));
653 ASSERT_TRUE(file.IsValid());
654 // https://msdn.microsoft.com/library/windows/desktop/aa364221.aspx says that
655 // setting the dispositon has no effect if the handle was opened with
656 // FLAG_DELETE_ON_CLOSE. Do not make the test's success dependent on whether
657 // or not SetFileInformationByHandle indicates success or failure. (It happens
658 // to indicate success on Windows 10.)
659 file.DeleteOnClose(false);
660 file.Close();
661 ASSERT_FALSE(base::PathExists(file_path));
662 }
663
664 TEST(FileTest, IrrevokableDeleteOnCloseOther) {
665 base::ScopedTempDir temp_dir;
666 ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
667 FilePath file_path = temp_dir.GetPath().AppendASCII("file");
668
669 // DELETE_ON_CLOSE cannot be revoked by another opener.
670 File file(
671 file_path,
672 (base::File::FLAG_CREATE | base::File::FLAG_READ |
673 base::File::FLAG_WRITE | base::File::FLAG_DELETE_ON_CLOSE |
674 base::File::FLAG_SHARE_DELETE | base::File::FLAG_CAN_DELETE_ON_CLOSE));
675 ASSERT_TRUE(file.IsValid());
676
677 File file2(
678 file_path,
679 (base::File::FLAG_OPEN | base::File::FLAG_READ | base::File::FLAG_WRITE |
680 base::File::FLAG_SHARE_DELETE | base::File::FLAG_CAN_DELETE_ON_CLOSE));
681 ASSERT_TRUE(file2.IsValid());
682
683 file2.DeleteOnClose(false);
684 file2.Close();
685 ASSERT_TRUE(base::PathExists(file_path));
686 file.Close();
687 ASSERT_FALSE(base::PathExists(file_path));
688 }
689
690 TEST(FileTest, DeleteWithoutPermission) {
691 base::ScopedTempDir temp_dir;
692 ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
693 FilePath file_path = temp_dir.GetPath().AppendASCII("file");
694
695 // It should not be possible to mark a file for deletion when it was not
696 // created/opened with DELETE.
697 File file(file_path, (base::File::FLAG_CREATE | base::File::FLAG_READ |
698 base::File::FLAG_WRITE));
699 ASSERT_TRUE(file.IsValid());
700 ASSERT_FALSE(file.DeleteOnClose(true));
701 file.Close();
702 ASSERT_TRUE(base::PathExists(file_path));
703 }
704
705 TEST(FileTest, UnsharedDeleteOnClose) {
706 base::ScopedTempDir temp_dir;
707 ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
708 FilePath file_path = temp_dir.GetPath().AppendASCII("file");
709
710 // Opening with DELETE_ON_CLOSE when a previous opener hasn't enabled sharing
711 // will fail.
712 File file(file_path, (base::File::FLAG_CREATE | base::File::FLAG_READ |
713 base::File::FLAG_WRITE));
714 ASSERT_TRUE(file.IsValid());
715 File file2(
716 file_path,
717 (base::File::FLAG_OPEN | base::File::FLAG_READ | base::File::FLAG_WRITE |
718 base::File::FLAG_DELETE_ON_CLOSE | base::File::FLAG_SHARE_DELETE));
719 ASSERT_FALSE(file2.IsValid());
720
721 file.Close();
722 ASSERT_TRUE(base::PathExists(file_path));
723 }
724
725 TEST(FileTest, NoDeleteOnCloseWithMappedFile) {
726 base::ScopedTempDir temp_dir;
727 ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
728 FilePath file_path = temp_dir.GetPath().AppendASCII("file");
729
730 // Mapping a file into memory blocks DeleteOnClose.
731 File file(file_path,
732 (base::File::FLAG_CREATE | base::File::FLAG_READ |
733 base::File::FLAG_WRITE | base::File::FLAG_CAN_DELETE_ON_CLOSE));
734 ASSERT_TRUE(file.IsValid());
735 ASSERT_EQ(5, file.WriteAtCurrentPos("12345", 5));
736
737 {
738 base::MemoryMappedFile mapping;
739 ASSERT_TRUE(mapping.Initialize(file.Duplicate()));
740 ASSERT_EQ(5U, mapping.length());
741
742 EXPECT_FALSE(file.DeleteOnClose(true));
743 }
744
745 file.Close();
746 ASSERT_TRUE(base::PathExists(file_path));
747 }
748
749 // Check that we handle the async bit being set incorrectly in a sane way.
750 TEST(FileTest, UseSyncApiWithAsyncFile) {
751 base::ScopedTempDir temp_dir;
752 ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
753 FilePath file_path = temp_dir.GetPath().AppendASCII("file");
754
755 File file(file_path, base::File::FLAG_CREATE | base::File::FLAG_WRITE |
756 base::File::FLAG_ASYNC);
757 File lying_file(file.TakePlatformFile(), false /* async */);
758 ASSERT_TRUE(lying_file.IsValid());
759
760 ASSERT_EQ(lying_file.WriteAtCurrentPos("12345", 5), -1);
761 }
762 #endif // defined(OS_WIN)
763