| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "components/drive/chromeos/file_cache.h" | 5 #include "components/drive/chromeos/file_cache.h" |
| 6 | 6 |
| 7 #include <linux/fs.h> | |
| 8 #include <stddef.h> | 7 #include <stddef.h> |
| 9 #include <stdint.h> | 8 #include <stdint.h> |
| 10 #include <sys/ioctl.h> | 9 #include <sys/stat.h> |
| 11 #include <sys/xattr.h> | 10 #include <sys/types.h> |
| 11 #include <unistd.h> |
| 12 | 12 |
| 13 #include <string> | 13 #include <string> |
| 14 #include <vector> | 14 #include <vector> |
| 15 | 15 |
| 16 #include "base/callback_helpers.h" | 16 #include "base/callback_helpers.h" |
| 17 #include "base/files/file.h" | |
| 18 #include "base/files/file_enumerator.h" | 17 #include "base/files/file_enumerator.h" |
| 19 #include "base/files/file_util.h" | 18 #include "base/files/file_util.h" |
| 20 #include "base/files/scoped_temp_dir.h" | 19 #include "base/files/scoped_temp_dir.h" |
| 21 #include "base/md5.h" | 20 #include "base/md5.h" |
| 22 #include "base/path_service.h" | 21 #include "base/path_service.h" |
| 23 #include "base/single_thread_task_runner.h" | 22 #include "base/single_thread_task_runner.h" |
| 24 #include "base/stl_util.h" | |
| 25 #include "base/strings/stringprintf.h" | 23 #include "base/strings/stringprintf.h" |
| 26 #include "base/threading/thread_task_runner_handle.h" | 24 #include "base/threading/thread_task_runner_handle.h" |
| 27 #include "base/time/time.h" | 25 #include "base/time/time.h" |
| 28 #include "components/drive/chromeos/drive_test_util.h" | 26 #include "components/drive/chromeos/drive_test_util.h" |
| 29 #include "components/drive/chromeos/fake_free_disk_space_getter.h" | 27 #include "components/drive/chromeos/fake_free_disk_space_getter.h" |
| 30 #include "components/drive/drive.pb.h" | 28 #include "components/drive/drive.pb.h" |
| 31 #include "components/drive/file_system_core_util.h" | 29 #include "components/drive/file_system_core_util.h" |
| 32 #include "components/drive/resource_metadata_storage.h" | 30 #include "components/drive/resource_metadata_storage.h" |
| 33 #include "content/public/test/test_browser_thread_bundle.h" | 31 #include "content/public/test/test_browser_thread_bundle.h" |
| 34 #include "google_apis/drive/test_util.h" | 32 #include "google_apis/drive/test_util.h" |
| 35 #include "testing/gtest/include/gtest/gtest.h" | 33 #include "testing/gtest/include/gtest/gtest.h" |
| 36 | 34 |
| 37 namespace drive { | 35 namespace drive { |
| 38 namespace internal { | 36 namespace internal { |
| 39 namespace { | 37 namespace { |
| 40 | 38 |
| 41 typedef long FileAttributes; // NOLINT(runtime/int) | |
| 42 | |
| 43 const base::FilePath::CharType kCacheFileDirectory[] = | 39 const base::FilePath::CharType kCacheFileDirectory[] = |
| 44 FILE_PATH_LITERAL("files"); | 40 FILE_PATH_LITERAL("files"); |
| 41 const base::FilePath::CharType kNewCacheFileDirectory[] = |
| 42 FILE_PATH_LITERAL("blobs"); |
| 43 const base::FilePath::CharType kLinkDirectory[] = FILE_PATH_LITERAL("links"); |
| 45 | 44 |
| 46 const int kTemporaryFileSizeInBytes = 10; | 45 const int kTemporaryFileSizeInBytes = 10; |
| 47 | 46 |
| 48 FileAttributes GetFileAttributes(const base::FilePath& file_path) { | 47 int GetNumberOfLinks(const base::FilePath& file_path) { |
| 49 base::File file(file_path, base::File::FLAG_OPEN | base::File::FLAG_READ); | 48 struct stat result; |
| 50 if (!file.IsValid()) { | 49 if (stat(file_path.AsUTF8Unsafe().c_str(), &result) != 0) { |
| 51 ADD_FAILURE() << "Failed to open file: " << file_path.value(); | |
| 52 return -1; | 50 return -1; |
| 53 } | 51 } |
| 54 FileAttributes flags = 0; | 52 return result.st_nlink; |
| 55 if (ioctl(file.GetPlatformFile(), FS_IOC_GETFLAGS, &flags) < 0) { | |
| 56 ADD_FAILURE() << "Failed to get attributes: " << file_path.value(); | |
| 57 return -1; | |
| 58 } | |
| 59 return flags; | |
| 60 } | |
| 61 | |
| 62 bool HasRemovableFlag(const base::FilePath& file_path) { | |
| 63 return (GetFileAttributes(file_path) & FS_NODUMP_FL) == FS_NODUMP_FL; | |
| 64 } | 53 } |
| 65 | 54 |
| 66 } // namespace | 55 } // namespace |
| 67 | 56 |
| 68 // Tests FileCache methods working with the blocking task runner. | 57 // Tests FileCache methods working with the blocking task runner. |
| 69 class FileCacheTest : public testing::Test { | 58 class FileCacheTest : public testing::Test { |
| 70 protected: | 59 protected: |
| 71 void SetUp() override { | 60 void SetUp() override { |
| 72 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); | 61 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); |
| 73 const base::FilePath metadata_dir = temp_dir_.path().AppendASCII("meta"); | 62 const base::FilePath metadata_dir = temp_dir_.path().AppendASCII("meta"); |
| (...skipping 12 matching lines...) Expand all Loading... |
| 86 cache_.reset(new FileCache(metadata_storage_.get(), cache_files_dir_, | 75 cache_.reset(new FileCache(metadata_storage_.get(), cache_files_dir_, |
| 87 base::ThreadTaskRunnerHandle::Get().get(), | 76 base::ThreadTaskRunnerHandle::Get().get(), |
| 88 fake_free_disk_space_getter_.get())); | 77 fake_free_disk_space_getter_.get())); |
| 89 ASSERT_TRUE(cache_->Initialize()); | 78 ASSERT_TRUE(cache_->Initialize()); |
| 90 } | 79 } |
| 91 | 80 |
| 92 static bool RenameCacheFilesToNewFormat(FileCache* cache) { | 81 static bool RenameCacheFilesToNewFormat(FileCache* cache) { |
| 93 return cache->RenameCacheFilesToNewFormat(); | 82 return cache->RenameCacheFilesToNewFormat(); |
| 94 } | 83 } |
| 95 | 84 |
| 96 base::FilePath GetCacheFilePath(const std::string& id) { | |
| 97 return cache_->GetCacheFilePath(id); | |
| 98 } | |
| 99 | |
| 100 base::FilePath AddTestEntry(const std::string id, | 85 base::FilePath AddTestEntry(const std::string id, |
| 101 const std::string md5, | 86 const std::string md5, |
| 102 const time_t last_accessed, | 87 const time_t last_accessed, |
| 103 const base::FilePath& src_file) { | 88 const base::FilePath& src_file) { |
| 104 ResourceEntry entry; | 89 ResourceEntry entry; |
| 105 entry.set_local_id(id); | 90 entry.set_local_id(id); |
| 106 entry.mutable_file_info()->set_last_accessed(last_accessed); | 91 entry.mutable_file_info()->set_last_accessed(last_accessed); |
| 107 EXPECT_EQ(FILE_ERROR_OK, metadata_storage_->PutEntry(entry)); | 92 EXPECT_EQ(FILE_ERROR_OK, metadata_storage_->PutEntry(entry)); |
| 108 EXPECT_EQ(FILE_ERROR_OK, | 93 EXPECT_EQ(FILE_ERROR_OK, |
| 109 cache_->Store(id, md5, src_file, FileCache::FILE_OPERATION_COPY)); | 94 cache_->Store(id, md5, src_file, FileCache::FILE_OPERATION_COPY)); |
| (...skipping 320 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 430 id, md5, src_file_path, FileCache::FILE_OPERATION_COPY)); | 415 id, md5, src_file_path, FileCache::FILE_OPERATION_COPY)); |
| 431 | 416 |
| 432 EXPECT_EQ(FILE_ERROR_OK, metadata_storage_->GetEntry(id, &entry)); | 417 EXPECT_EQ(FILE_ERROR_OK, metadata_storage_->GetEntry(id, &entry)); |
| 433 EXPECT_TRUE(entry.file_specific_info().cache_state().is_present()); | 418 EXPECT_TRUE(entry.file_specific_info().cache_state().is_present()); |
| 434 EXPECT_EQ(md5, entry.file_specific_info().cache_state().md5()); | 419 EXPECT_EQ(md5, entry.file_specific_info().cache_state().md5()); |
| 435 | 420 |
| 436 base::FilePath cache_file_path; | 421 base::FilePath cache_file_path; |
| 437 EXPECT_EQ(FILE_ERROR_OK, cache_->GetFile(id, &cache_file_path)); | 422 EXPECT_EQ(FILE_ERROR_OK, cache_->GetFile(id, &cache_file_path)); |
| 438 EXPECT_TRUE(base::ContentsEqual(src_file_path, cache_file_path)); | 423 EXPECT_TRUE(base::ContentsEqual(src_file_path, cache_file_path)); |
| 439 | 424 |
| 440 base::FilePath dest_file_path = GetCacheFilePath(id); | |
| 441 EXPECT_TRUE(HasRemovableFlag((dest_file_path))); | |
| 442 | |
| 443 // Store a non-existent file. | 425 // Store a non-existent file. |
| 444 EXPECT_EQ(FILE_ERROR_FAILED, cache_->Store( | 426 EXPECT_EQ(FILE_ERROR_FAILED, cache_->Store( |
| 445 id, md5, base::FilePath::FromUTF8Unsafe("non_existent_file"), | 427 id, md5, base::FilePath::FromUTF8Unsafe("non_existent_file"), |
| 446 FileCache::FILE_OPERATION_COPY)); | 428 FileCache::FILE_OPERATION_COPY)); |
| 447 | 429 |
| 448 // Passing empty MD5 marks the entry as dirty. | 430 // Passing empty MD5 marks the entry as dirty. |
| 449 EXPECT_EQ(FILE_ERROR_OK, cache_->Store( | 431 EXPECT_EQ(FILE_ERROR_OK, cache_->Store( |
| 450 id, std::string(), src_file_path, FileCache::FILE_OPERATION_COPY)); | 432 id, std::string(), src_file_path, FileCache::FILE_OPERATION_COPY)); |
| 451 | 433 |
| 452 EXPECT_EQ(FILE_ERROR_OK, metadata_storage_->GetEntry(id, &entry)); | 434 EXPECT_EQ(FILE_ERROR_OK, metadata_storage_->GetEntry(id, &entry)); |
| 453 EXPECT_TRUE(entry.file_specific_info().cache_state().is_present()); | 435 EXPECT_TRUE(entry.file_specific_info().cache_state().is_present()); |
| 454 EXPECT_TRUE(entry.file_specific_info().cache_state().md5().empty()); | 436 EXPECT_TRUE(entry.file_specific_info().cache_state().md5().empty()); |
| 455 EXPECT_TRUE(entry.file_specific_info().cache_state().is_dirty()); | 437 EXPECT_TRUE(entry.file_specific_info().cache_state().is_dirty()); |
| 456 EXPECT_FALSE(HasRemovableFlag((dest_file_path))); | |
| 457 | 438 |
| 458 // No free space available. | 439 // No free space available. |
| 459 fake_free_disk_space_getter_->set_default_value(0); | 440 fake_free_disk_space_getter_->set_default_value(0); |
| 460 | 441 |
| 461 EXPECT_EQ(FILE_ERROR_NO_LOCAL_SPACE, cache_->Store( | 442 EXPECT_EQ(FILE_ERROR_NO_LOCAL_SPACE, cache_->Store( |
| 462 id, md5, src_file_path, FileCache::FILE_OPERATION_COPY)); | 443 id, md5, src_file_path, FileCache::FILE_OPERATION_COPY)); |
| 463 } | 444 } |
| 464 | 445 |
| 465 TEST_F(FileCacheTest, PinAndUnpin) { | 446 TEST_F(FileCacheTest, PinAndUnpin) { |
| 466 const base::FilePath src_file_path = temp_dir_.path().Append("test.dat"); | 447 const base::FilePath src_file_path = temp_dir_.path().Append("test.dat"); |
| 467 const std::string src_contents = "test"; | 448 const std::string src_contents = "test"; |
| 468 EXPECT_TRUE(google_apis::test_util::WriteStringToFile(src_file_path, | 449 EXPECT_TRUE(google_apis::test_util::WriteStringToFile(src_file_path, |
| 469 src_contents)); | 450 src_contents)); |
| 470 std::string id("id_present"); | 451 std::string id("id_present"); |
| 471 std::string md5(base::MD5String(src_contents)); | 452 std::string md5(base::MD5String(src_contents)); |
| 472 | 453 |
| 473 // Store a file. | 454 // Store a file. |
| 474 ResourceEntry entry; | 455 ResourceEntry entry; |
| 475 entry.set_local_id(id); | 456 entry.set_local_id(id); |
| 476 EXPECT_EQ(FILE_ERROR_OK, metadata_storage_->PutEntry(entry)); | 457 EXPECT_EQ(FILE_ERROR_OK, metadata_storage_->PutEntry(entry)); |
| 477 EXPECT_EQ(FILE_ERROR_OK, cache_->Store( | 458 EXPECT_EQ(FILE_ERROR_OK, cache_->Store( |
| 478 id, md5, src_file_path, FileCache::FILE_OPERATION_COPY)); | 459 id, md5, src_file_path, FileCache::FILE_OPERATION_COPY)); |
| 479 | 460 |
| 480 const base::FilePath dest_file_path = GetCacheFilePath(id); | |
| 481 EXPECT_EQ(FILE_ERROR_OK, metadata_storage_->GetEntry(id, &entry)); | 461 EXPECT_EQ(FILE_ERROR_OK, metadata_storage_->GetEntry(id, &entry)); |
| 482 EXPECT_FALSE(entry.file_specific_info().cache_state().is_pinned()); | 462 EXPECT_FALSE(entry.file_specific_info().cache_state().is_pinned()); |
| 483 EXPECT_TRUE(HasRemovableFlag((dest_file_path))); | |
| 484 | 463 |
| 485 // Pin the existing file. | 464 // Pin the existing file. |
| 486 EXPECT_EQ(FILE_ERROR_OK, cache_->Pin(id)); | 465 EXPECT_EQ(FILE_ERROR_OK, cache_->Pin(id)); |
| 487 | 466 |
| 488 EXPECT_EQ(FILE_ERROR_OK, metadata_storage_->GetEntry(id, &entry)); | 467 EXPECT_EQ(FILE_ERROR_OK, metadata_storage_->GetEntry(id, &entry)); |
| 489 EXPECT_TRUE(entry.file_specific_info().cache_state().is_pinned()); | 468 EXPECT_TRUE(entry.file_specific_info().cache_state().is_pinned()); |
| 490 EXPECT_FALSE(HasRemovableFlag((dest_file_path))); | |
| 491 | 469 |
| 492 // Unpin the file. | 470 // Unpin the file. |
| 493 EXPECT_EQ(FILE_ERROR_OK, cache_->Unpin(id)); | 471 EXPECT_EQ(FILE_ERROR_OK, cache_->Unpin(id)); |
| 494 | 472 |
| 495 EXPECT_EQ(FILE_ERROR_OK, metadata_storage_->GetEntry(id, &entry)); | 473 EXPECT_EQ(FILE_ERROR_OK, metadata_storage_->GetEntry(id, &entry)); |
| 496 EXPECT_FALSE(entry.file_specific_info().cache_state().is_pinned()); | 474 EXPECT_FALSE(entry.file_specific_info().cache_state().is_pinned()); |
| 497 EXPECT_TRUE(HasRemovableFlag((dest_file_path))); | |
| 498 | 475 |
| 499 // Pin a non-present file. | 476 // Pin a non-present file. |
| 500 std::string id_non_present = "id_non_present"; | 477 std::string id_non_present = "id_non_present"; |
| 501 entry.Clear(); | 478 entry.Clear(); |
| 502 entry.set_local_id(id_non_present); | 479 entry.set_local_id(id_non_present); |
| 503 EXPECT_EQ(FILE_ERROR_OK, metadata_storage_->PutEntry(entry)); | 480 EXPECT_EQ(FILE_ERROR_OK, metadata_storage_->PutEntry(entry)); |
| 504 EXPECT_EQ(FILE_ERROR_OK, cache_->Pin(id_non_present)); | 481 EXPECT_EQ(FILE_ERROR_OK, cache_->Pin(id_non_present)); |
| 505 | 482 |
| 506 EXPECT_EQ(FILE_ERROR_OK, metadata_storage_->GetEntry(id_non_present, &entry)); | 483 EXPECT_EQ(FILE_ERROR_OK, metadata_storage_->GetEntry(id_non_present, &entry)); |
| 507 EXPECT_TRUE(entry.file_specific_info().cache_state().is_pinned()); | 484 EXPECT_TRUE(entry.file_specific_info().cache_state().is_pinned()); |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 556 EXPECT_EQ(FILE_ERROR_OK, metadata_storage_->PutEntry(entry)); | 533 EXPECT_EQ(FILE_ERROR_OK, metadata_storage_->PutEntry(entry)); |
| 557 ASSERT_EQ(FILE_ERROR_OK, cache_->Store(id, "md5", src_file, | 534 ASSERT_EQ(FILE_ERROR_OK, cache_->Store(id, "md5", src_file, |
| 558 FileCache::FILE_OPERATION_COPY)); | 535 FileCache::FILE_OPERATION_COPY)); |
| 559 EXPECT_EQ(0, entry.file_info().last_modified()); | 536 EXPECT_EQ(0, entry.file_info().last_modified()); |
| 560 | 537 |
| 561 // Entry is not dirty nor opened. | 538 // Entry is not dirty nor opened. |
| 562 EXPECT_FALSE(cache_->IsOpenedForWrite(id)); | 539 EXPECT_FALSE(cache_->IsOpenedForWrite(id)); |
| 563 EXPECT_EQ(FILE_ERROR_OK, metadata_storage_->GetEntry(id, &entry)); | 540 EXPECT_EQ(FILE_ERROR_OK, metadata_storage_->GetEntry(id, &entry)); |
| 564 EXPECT_FALSE(entry.file_specific_info().cache_state().is_dirty()); | 541 EXPECT_FALSE(entry.file_specific_info().cache_state().is_dirty()); |
| 565 | 542 |
| 566 const base::FilePath dest_file = GetCacheFilePath(id); | |
| 567 EXPECT_TRUE(HasRemovableFlag((dest_file))); | |
| 568 | |
| 569 // Open (1). | 543 // Open (1). |
| 570 std::unique_ptr<base::ScopedClosureRunner> file_closer1; | 544 std::unique_ptr<base::ScopedClosureRunner> file_closer1; |
| 571 EXPECT_EQ(FILE_ERROR_OK, cache_->OpenForWrite(id, &file_closer1)); | 545 EXPECT_EQ(FILE_ERROR_OK, cache_->OpenForWrite(id, &file_closer1)); |
| 572 EXPECT_TRUE(cache_->IsOpenedForWrite(id)); | 546 EXPECT_TRUE(cache_->IsOpenedForWrite(id)); |
| 573 | 547 |
| 574 // Entry is dirty. | 548 // Entry is dirty. |
| 575 EXPECT_EQ(FILE_ERROR_OK, metadata_storage_->GetEntry(id, &entry)); | 549 EXPECT_EQ(FILE_ERROR_OK, metadata_storage_->GetEntry(id, &entry)); |
| 576 EXPECT_TRUE(entry.file_specific_info().cache_state().is_dirty()); | 550 EXPECT_TRUE(entry.file_specific_info().cache_state().is_dirty()); |
| 577 EXPECT_FALSE(HasRemovableFlag((dest_file))); | |
| 578 | 551 |
| 579 // Open (2). | 552 // Open (2). |
| 580 std::unique_ptr<base::ScopedClosureRunner> file_closer2; | 553 std::unique_ptr<base::ScopedClosureRunner> file_closer2; |
| 581 EXPECT_EQ(FILE_ERROR_OK, cache_->OpenForWrite(id, &file_closer2)); | 554 EXPECT_EQ(FILE_ERROR_OK, cache_->OpenForWrite(id, &file_closer2)); |
| 582 EXPECT_TRUE(cache_->IsOpenedForWrite(id)); | 555 EXPECT_TRUE(cache_->IsOpenedForWrite(id)); |
| 583 | 556 |
| 584 // Close (1). | 557 // Close (1). |
| 585 file_closer1.reset(); | 558 file_closer1.reset(); |
| 586 base::RunLoop().RunUntilIdle(); | 559 base::RunLoop().RunUntilIdle(); |
| 587 EXPECT_TRUE(cache_->IsOpenedForWrite(id)); | 560 EXPECT_TRUE(cache_->IsOpenedForWrite(id)); |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 646 base::FilePath src_file; | 619 base::FilePath src_file; |
| 647 ASSERT_TRUE(base::CreateTemporaryFileInDir(temp_dir_.path(), &src_file)); | 620 ASSERT_TRUE(base::CreateTemporaryFileInDir(temp_dir_.path(), &src_file)); |
| 648 | 621 |
| 649 const std::string id = "id"; | 622 const std::string id = "id"; |
| 650 ResourceEntry entry; | 623 ResourceEntry entry; |
| 651 entry.set_local_id(id); | 624 entry.set_local_id(id); |
| 652 EXPECT_EQ(FILE_ERROR_OK, metadata_storage_->PutEntry(entry)); | 625 EXPECT_EQ(FILE_ERROR_OK, metadata_storage_->PutEntry(entry)); |
| 653 ASSERT_EQ(FILE_ERROR_OK, cache_->Store(id, "md5", src_file, | 626 ASSERT_EQ(FILE_ERROR_OK, cache_->Store(id, "md5", src_file, |
| 654 FileCache::FILE_OPERATION_COPY)); | 627 FileCache::FILE_OPERATION_COPY)); |
| 655 | 628 |
| 656 const base::FilePath dest_file = GetCacheFilePath(id); | |
| 657 EXPECT_TRUE(HasRemovableFlag((dest_file))); | |
| 658 | |
| 659 // Open the file. | 629 // Open the file. |
| 660 std::unique_ptr<base::ScopedClosureRunner> file_closer; | 630 std::unique_ptr<base::ScopedClosureRunner> file_closer; |
| 661 EXPECT_EQ(FILE_ERROR_OK, cache_->OpenForWrite(id, &file_closer)); | 631 EXPECT_EQ(FILE_ERROR_OK, cache_->OpenForWrite(id, &file_closer)); |
| 662 | 632 |
| 663 // Entry is dirty. | 633 // Entry is dirty. |
| 664 EXPECT_EQ(FILE_ERROR_OK, metadata_storage_->GetEntry(id, &entry)); | 634 EXPECT_EQ(FILE_ERROR_OK, metadata_storage_->GetEntry(id, &entry)); |
| 665 EXPECT_TRUE(entry.file_specific_info().cache_state().is_dirty()); | 635 EXPECT_TRUE(entry.file_specific_info().cache_state().is_dirty()); |
| 666 EXPECT_FALSE(HasRemovableFlag((dest_file))); | |
| 667 | 636 |
| 668 // Cannot clear the dirty bit of an opened entry. | 637 // Cannot clear the dirty bit of an opened entry. |
| 669 EXPECT_EQ(FILE_ERROR_IN_USE, cache_->ClearDirty(id)); | 638 EXPECT_EQ(FILE_ERROR_IN_USE, cache_->ClearDirty(id)); |
| 670 EXPECT_FALSE(HasRemovableFlag((dest_file))); | |
| 671 | 639 |
| 672 // Close the file and clear the dirty bit. | 640 // Close the file and clear the dirty bit. |
| 673 file_closer.reset(); | 641 file_closer.reset(); |
| 674 base::RunLoop().RunUntilIdle(); | 642 base::RunLoop().RunUntilIdle(); |
| 675 EXPECT_EQ(FILE_ERROR_OK, cache_->ClearDirty(id)); | 643 EXPECT_EQ(FILE_ERROR_OK, cache_->ClearDirty(id)); |
| 676 | 644 |
| 677 // Entry is not dirty. | 645 // Entry is not dirty. |
| 678 EXPECT_EQ(FILE_ERROR_OK, metadata_storage_->GetEntry(id, &entry)); | 646 EXPECT_EQ(FILE_ERROR_OK, metadata_storage_->GetEntry(id, &entry)); |
| 679 EXPECT_FALSE(entry.file_specific_info().cache_state().is_dirty()); | 647 EXPECT_FALSE(entry.file_specific_info().cache_state().is_dirty()); |
| 680 EXPECT_TRUE(HasRemovableFlag((dest_file))); | |
| 681 } | 648 } |
| 682 | 649 |
| 683 TEST_F(FileCacheTest, Remove) { | 650 TEST_F(FileCacheTest, Remove) { |
| 684 const base::FilePath src_file_path = temp_dir_.path().Append("test.dat"); | 651 const base::FilePath src_file_path = temp_dir_.path().Append("test.dat"); |
| 685 const std::string src_contents = "test"; | 652 const std::string src_contents = "test"; |
| 686 EXPECT_TRUE(google_apis::test_util::WriteStringToFile(src_file_path, | 653 EXPECT_TRUE(google_apis::test_util::WriteStringToFile(src_file_path, |
| 687 src_contents)); | 654 src_contents)); |
| 688 std::string id("id"); | 655 std::string id("id"); |
| 689 std::string md5(base::MD5String(src_contents)); | 656 std::string md5(base::MD5String(src_contents)); |
| 690 | 657 |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 737 contents.clear(); | 704 contents.clear(); |
| 738 EXPECT_TRUE(base::ReadFileToString(file_directory.AppendASCII("id_koo"), | 705 EXPECT_TRUE(base::ReadFileToString(file_directory.AppendASCII("id_koo"), |
| 739 &contents)); | 706 &contents)); |
| 740 EXPECT_EQ("koo", contents); | 707 EXPECT_EQ("koo", contents); |
| 741 contents.clear(); | 708 contents.clear(); |
| 742 EXPECT_TRUE(base::ReadFileToString(file_directory.AppendASCII("id_kyu"), | 709 EXPECT_TRUE(base::ReadFileToString(file_directory.AppendASCII("id_kyu"), |
| 743 &contents)); | 710 &contents)); |
| 744 EXPECT_EQ("kyu", contents); | 711 EXPECT_EQ("kyu", contents); |
| 745 } | 712 } |
| 746 | 713 |
| 747 TEST_F(FileCacheTest, FixMetadataAndFileAttributes) { | 714 // Test for migrating cache files from files to blobs. |
| 715 TEST_F(FileCacheTest, MigrateCacheFiles) { |
| 748 // Create test files and metadata. | 716 // Create test files and metadata. |
| 749 base::FilePath temp_file; | 717 base::FilePath temp_file; |
| 750 ASSERT_TRUE(base::CreateTemporaryFileInDir(temp_dir_.path(), &temp_file)); | 718 ASSERT_TRUE(base::CreateTemporaryFileInDir(temp_dir_.path(), &temp_file)); |
| 751 | 719 |
| 752 // Entry A: pinned cache file. | 720 const base::FilePath old_cache_dir = |
| 721 temp_dir_.path().Append(kCacheFileDirectory); |
| 722 const base::FilePath new_cache_dir = |
| 723 temp_dir_.path().Append(kNewCacheFileDirectory); |
| 724 const base::FilePath link_dir = temp_dir_.path().Append(kLinkDirectory); |
| 725 ASSERT_TRUE(base::CreateDirectory(old_cache_dir)); |
| 726 ASSERT_TRUE(base::CreateDirectory(new_cache_dir)); |
| 727 ASSERT_TRUE(base::CreateDirectory(link_dir)); |
| 728 |
| 729 // Entry A: cache file in old cache directory with metadata. |
| 753 const std::string id_a = "id_a"; | 730 const std::string id_a = "id_a"; |
| 754 ResourceEntry entry_a; | 731 ResourceEntry entry_a; |
| 755 entry_a.set_local_id(id_a); | 732 entry_a.set_local_id(id_a); |
| 756 FileCacheEntry* file_cache_entry_a = | 733 entry_a.mutable_file_specific_info()->mutable_cache_state()->set_is_present( |
| 757 entry_a.mutable_file_specific_info()->mutable_cache_state(); | 734 true); |
| 758 file_cache_entry_a->set_is_present(true); | |
| 759 file_cache_entry_a->set_is_pinned(true); | |
| 760 file_cache_entry_a->set_is_dirty(false); | |
| 761 ASSERT_EQ(FILE_ERROR_OK, metadata_storage_->PutEntry(entry_a)); | 735 ASSERT_EQ(FILE_ERROR_OK, metadata_storage_->PutEntry(entry_a)); |
| 762 const base::FilePath file_path_a = GetCacheFilePath(id_a); | 736 const base::FilePath old_file_path_a = old_cache_dir.AppendASCII(id_a); |
| 763 ASSERT_TRUE(base::CopyFile(temp_file, file_path_a)); | 737 const base::FilePath new_file_path_a = new_cache_dir.AppendASCII(id_a); |
| 738 ASSERT_TRUE(base::CopyFile(temp_file, old_file_path_a)); |
| 764 | 739 |
| 765 // Entry B: dirty cache file. | 740 // Entry B: cache file in old cache directory without metadata. |
| 766 const std::string id_b = "id_b"; | 741 const std::string id_b = "id_b"; |
| 767 ResourceEntry entry_b; | 742 const base::FilePath old_file_path_b = old_cache_dir.AppendASCII(id_b); |
| 768 entry_b.set_local_id(id_b); | 743 ASSERT_TRUE(base::CopyFile(temp_file, old_file_path_b)); |
| 769 FileCacheEntry* file_cache_entry_b = | |
| 770 entry_b.mutable_file_specific_info()->mutable_cache_state(); | |
| 771 file_cache_entry_b->set_is_present(true); | |
| 772 file_cache_entry_b->set_is_pinned(false); | |
| 773 file_cache_entry_b->set_is_dirty(true); | |
| 774 ASSERT_EQ(FILE_ERROR_OK, metadata_storage_->PutEntry(entry_b)); | |
| 775 const base::FilePath file_path_b = GetCacheFilePath(id_b); | |
| 776 ASSERT_TRUE(base::CopyFile(temp_file, file_path_b)); | |
| 777 | 744 |
| 778 // Entry C: not pinned nor dirty cache file. | 745 // Entry C: already migrated cache file. |
| 779 const std::string id_c = "id_c"; | 746 const std::string id_c = "id_c"; |
| 780 ResourceEntry entry_c; | 747 ResourceEntry entry_c; |
| 781 entry_c.set_local_id(id_c); | 748 entry_c.set_local_id(id_c); |
| 782 FileCacheEntry* file_cache_entry_c = | 749 entry_c.mutable_file_specific_info()->mutable_cache_state()->set_is_present( |
| 783 entry_c.mutable_file_specific_info()->mutable_cache_state(); | 750 true); |
| 784 file_cache_entry_c->set_is_present(true); | |
| 785 file_cache_entry_c->set_is_pinned(false); | |
| 786 file_cache_entry_c->set_is_dirty(false); | |
| 787 ASSERT_EQ(FILE_ERROR_OK, metadata_storage_->PutEntry(entry_c)); | 751 ASSERT_EQ(FILE_ERROR_OK, metadata_storage_->PutEntry(entry_c)); |
| 788 const base::FilePath file_path_c = GetCacheFilePath(id_c); | 752 const base::FilePath new_file_path_c = new_cache_dir.AppendASCII(id_c); |
| 789 ASSERT_TRUE(base::CopyFile(temp_file, file_path_c)); | 753 ASSERT_TRUE(base::CopyFile(temp_file, new_file_path_c)); |
| 790 | 754 |
| 791 // Entry D: pinned cache file somehow having removable flag. | 755 // Entry D: metadata entry without cache file. |
| 792 const std::string id_d = "id_d"; | 756 const std::string id_d = "id_d"; |
| 793 ResourceEntry entry_d; | 757 ResourceEntry entry_d; |
| 794 entry_d.set_local_id(id_d); | 758 entry_d.set_local_id(id_d); |
| 795 FileCacheEntry* file_cache_entry_d = | 759 entry_d.mutable_file_specific_info()->mutable_cache_state()->set_is_present( |
| 796 entry_d.mutable_file_specific_info()->mutable_cache_state(); | 760 true); |
| 797 file_cache_entry_d->set_is_present(true); | |
| 798 file_cache_entry_d->set_is_pinned(true); | |
| 799 file_cache_entry_d->set_is_dirty(false); | |
| 800 ASSERT_EQ(FILE_ERROR_OK, metadata_storage_->PutEntry(entry_d)); | 761 ASSERT_EQ(FILE_ERROR_OK, metadata_storage_->PutEntry(entry_d)); |
| 801 const base::FilePath file_path_d = GetCacheFilePath(id_d); | |
| 802 ASSERT_TRUE(base::CopyFile(temp_file, file_path_d)); | |
| 803 | 762 |
| 804 // Set removable flag. | 763 // Entry E: pinned cache file. |
| 805 FileAttributes flags = GetFileAttributes(file_path_d); | |
| 806 ASSERT_GE(flags, 0); | |
| 807 flags |= FS_NODUMP_FL; | |
| 808 base::File file_d(file_path_d, base::File::FLAG_OPEN | base::File::FLAG_READ); | |
| 809 ASSERT_EQ(ioctl(file_d.GetPlatformFile(), FS_IOC_SETFLAGS, &flags), 0); | |
| 810 | |
| 811 // Entry E: there is no file; removed by cryptohome. | |
| 812 const std::string id_e = "id_e"; | 764 const std::string id_e = "id_e"; |
| 813 ResourceEntry entry_e; | 765 ResourceEntry entry_e; |
| 814 entry_e.set_local_id(id_e); | 766 entry_e.set_local_id(id_e); |
| 815 FileCacheEntry* file_cache_entry_e = | 767 FileCacheEntry* file_cache_entry_e = |
| 816 entry_e.mutable_file_specific_info()->mutable_cache_state(); | 768 entry_e.mutable_file_specific_info()->mutable_cache_state(); |
| 817 file_cache_entry_e->set_is_present(true); | 769 file_cache_entry_e->set_is_present(true); |
| 818 file_cache_entry_e->set_is_pinned(false); | 770 file_cache_entry_e->set_is_pinned(true); |
| 819 file_cache_entry_e->set_is_dirty(false); | 771 file_cache_entry_e->set_is_dirty(false); |
| 820 ASSERT_EQ(FILE_ERROR_OK, metadata_storage_->PutEntry(entry_e)); | 772 ASSERT_EQ(FILE_ERROR_OK, metadata_storage_->PutEntry(entry_e)); |
| 821 const base::FilePath file_path_e = GetCacheFilePath(id_e); | 773 const base::FilePath old_file_path_e = old_cache_dir.AppendASCII(id_e); |
| 774 const base::FilePath new_file_path_e = new_cache_dir.AppendASCII(id_e); |
| 775 const base::FilePath link_path_e = link_dir.AppendASCII(id_e); |
| 776 ASSERT_TRUE(base::CopyFile(temp_file, old_file_path_e)); |
| 822 | 777 |
| 823 // Entry F: there is a file, but metadata says not. | 778 // Entry F: dirty cache file. |
| 824 const std::string id_f = "id_f"; | 779 const std::string id_f = "id_f"; |
| 825 ResourceEntry entry_f; | 780 ResourceEntry entry_f; |
| 826 entry_f.set_local_id(id_f); | 781 entry_f.set_local_id(id_f); |
| 827 entry_f.mutable_file_specific_info()->mutable_cache_state()->set_is_present( | 782 FileCacheEntry* file_cache_entry_f = |
| 828 false); | 783 entry_f.mutable_file_specific_info()->mutable_cache_state(); |
| 784 file_cache_entry_f->set_is_present(true); |
| 785 file_cache_entry_f->set_is_pinned(false); |
| 786 file_cache_entry_f->set_is_dirty(true); |
| 829 ASSERT_EQ(FILE_ERROR_OK, metadata_storage_->PutEntry(entry_f)); | 787 ASSERT_EQ(FILE_ERROR_OK, metadata_storage_->PutEntry(entry_f)); |
| 830 const base::FilePath file_path_f = GetCacheFilePath(id_f); | 788 const base::FilePath old_file_path_f = old_cache_dir.AppendASCII(id_f); |
| 831 ASSERT_TRUE(base::CopyFile(temp_file, file_path_f)); | 789 const base::FilePath new_file_path_f = new_cache_dir.AppendASCII(id_f); |
| 790 const base::FilePath link_path_f = link_dir.AppendASCII(id_f); |
| 791 ASSERT_TRUE(base::CopyFile(temp_file, old_file_path_f)); |
| 832 | 792 |
| 833 // Entry G: no file nor metadata. | 793 // Entry G: partially migrated pinned cache file. |
| 834 const std::string id_g = "id_g"; | 794 const std::string id_g = "id_g"; |
| 835 ResourceEntry entry_g; | 795 ResourceEntry entry_g; |
| 836 entry_g.set_local_id(id_g); | 796 entry_g.set_local_id(id_g); |
| 837 entry_f.mutable_file_specific_info()->mutable_cache_state()->set_is_present( | 797 FileCacheEntry* file_cache_entry_g = |
| 838 false); | 798 entry_g.mutable_file_specific_info()->mutable_cache_state(); |
| 839 ASSERT_EQ(FILE_ERROR_OK, metadata_storage_->PutEntry(entry_f)); | 799 file_cache_entry_g->set_is_present(true); |
| 800 file_cache_entry_g->set_is_pinned(true); |
| 801 file_cache_entry_g->set_is_dirty(false); |
| 802 ASSERT_EQ(FILE_ERROR_OK, metadata_storage_->PutEntry(entry_g)); |
| 803 const base::FilePath old_file_path_g = old_cache_dir.AppendASCII(id_g); |
| 804 const base::FilePath new_file_path_g = new_cache_dir.AppendASCII(id_g); |
| 805 const base::FilePath link_path_g = link_dir.AppendASCII(id_g); |
| 806 ASSERT_TRUE(base::CopyFile(temp_file, old_file_path_g)); |
| 807 ASSERT_EQ(0, link(old_file_path_g.AsUTF8Unsafe().c_str(), |
| 808 link_path_g.AsUTF8Unsafe().c_str())); |
| 840 | 809 |
| 841 // Initialize fixes inconsistency between metadata and cache file attributes | 810 // Entry H: pinned entry without cache file. |
| 842 // as well as adding specific file attributes to the cache directory. | 811 const std::string id_h = "id_h"; |
| 843 ASSERT_TRUE(cache_->Initialize()); | 812 ResourceEntry entry_h; |
| 813 entry_h.set_local_id(id_h); |
| 814 FileCacheEntry* file_cache_entry_h = |
| 815 entry_h.mutable_file_specific_info()->mutable_cache_state(); |
| 816 file_cache_entry_h->set_is_present(true); |
| 817 file_cache_entry_h->set_is_pinned(true); |
| 818 file_cache_entry_h->set_is_dirty(false); |
| 819 ASSERT_EQ(FILE_ERROR_OK, metadata_storage_->PutEntry(entry_h)); |
| 820 |
| 821 // Entry I: already migrated pinned cache file. |
| 822 const std::string id_i = "id_i"; |
| 823 ResourceEntry entry_i; |
| 824 entry_i.set_local_id(id_i); |
| 825 FileCacheEntry* file_cache_entry_i = |
| 826 entry_i.mutable_file_specific_info()->mutable_cache_state(); |
| 827 file_cache_entry_i->set_is_present(true); |
| 828 file_cache_entry_i->set_is_pinned(true); |
| 829 file_cache_entry_i->set_is_dirty(false); |
| 830 ASSERT_EQ(FILE_ERROR_OK, metadata_storage_->PutEntry(entry_i)); |
| 831 const base::FilePath new_file_path_i = new_cache_dir.AppendASCII(id_i); |
| 832 const base::FilePath link_path_i = link_dir.AppendASCII(id_i); |
| 833 ASSERT_TRUE(base::CopyFile(temp_file, new_file_path_i)); |
| 834 ASSERT_EQ(0, link(new_file_path_i.AsUTF8Unsafe().c_str(), |
| 835 link_path_i.AsUTF8Unsafe().c_str())); |
| 836 |
| 837 // Run migration. |
| 838 ASSERT_TRUE(FileCache::MigrateCacheFiles(old_cache_dir, new_cache_dir, |
| 839 link_dir, metadata_storage_.get())); |
| 844 | 840 |
| 845 // Check result. | 841 // Check result. |
| 846 EXPECT_FALSE(HasRemovableFlag(file_path_a)); | 842 EXPECT_FALSE(base::PathExists(old_file_path_a)); |
| 847 EXPECT_FALSE(HasRemovableFlag((file_path_b))); | 843 EXPECT_TRUE(base::PathExists(new_file_path_a)); |
| 848 EXPECT_TRUE(HasRemovableFlag((file_path_c))); | 844 EXPECT_EQ(1, GetNumberOfLinks(new_file_path_a)); |
| 849 EXPECT_FALSE(HasRemovableFlag((file_path_d))); | 845 // MigrateCacheFiles doesn't delete invalid cache file. |
| 850 EXPECT_FALSE(base::PathExists(file_path_f)); | 846 EXPECT_TRUE(base::PathExists(old_file_path_b)); |
| 851 | 847 EXPECT_TRUE(base::PathExists(new_file_path_c)); |
| 852 EXPECT_EQ(FILE_ERROR_OK, metadata_storage_->GetEntry(id_e, &entry_e)); | 848 EXPECT_EQ(1, GetNumberOfLinks(new_file_path_c)); |
| 853 EXPECT_FALSE(entry_e.file_specific_info().cache_state().is_present()); | 849 EXPECT_FALSE(base::PathExists(old_file_path_e)); |
| 854 EXPECT_EQ(FILE_ERROR_OK, metadata_storage_->GetEntry(id_f, &entry_f)); | 850 EXPECT_TRUE(base::PathExists(new_file_path_e)); |
| 855 EXPECT_FALSE(entry_f.file_specific_info().cache_state().is_present()); | 851 EXPECT_TRUE(base::PathExists(link_path_e)); |
| 856 | 852 EXPECT_EQ(2, GetNumberOfLinks(new_file_path_e)); |
| 857 // Check the cache dir has appropriate attributes. | 853 EXPECT_FALSE(base::PathExists(old_file_path_f)); |
| 858 EXPECT_TRUE(HasRemovableFlag((cache_files_dir_))); | 854 EXPECT_TRUE(base::PathExists(new_file_path_f)); |
| 859 EXPECT_GE(getxattr(cache_files_dir_.value().c_str(), | 855 EXPECT_TRUE(base::PathExists(link_path_f)); |
| 860 FileCache::kGCacheFilesAttribute, nullptr, 0), 0); | 856 EXPECT_EQ(2, GetNumberOfLinks(new_file_path_f)); |
| 857 EXPECT_FALSE(base::PathExists(old_file_path_g)); |
| 858 EXPECT_TRUE(base::PathExists(new_file_path_g)); |
| 859 EXPECT_TRUE(base::PathExists(link_path_g)); |
| 860 EXPECT_EQ(2, GetNumberOfLinks(new_file_path_g)); |
| 861 EXPECT_TRUE(base::PathExists(new_file_path_i)); |
| 862 EXPECT_TRUE(base::PathExists(link_path_i)); |
| 863 EXPECT_EQ(2, GetNumberOfLinks(new_file_path_i)); |
| 861 } | 864 } |
| 862 | 865 |
| 863 TEST_F(FileCacheTest, ClearAll) { | 866 TEST_F(FileCacheTest, ClearAll) { |
| 864 const std::string id("1a2b"); | 867 const std::string id("1a2b"); |
| 865 const std::string md5("abcdef0123456789"); | 868 const std::string md5("abcdef0123456789"); |
| 866 | 869 |
| 867 // Store an existing file. | 870 // Store an existing file. |
| 868 ResourceEntry entry; | 871 ResourceEntry entry; |
| 869 entry.set_local_id(id); | 872 entry.set_local_id(id); |
| 870 EXPECT_EQ(FILE_ERROR_OK, metadata_storage_->PutEntry(entry)); | 873 EXPECT_EQ(FILE_ERROR_OK, metadata_storage_->PutEntry(entry)); |
| 871 base::FilePath src_file; | 874 base::FilePath src_file; |
| 872 ASSERT_TRUE(base::CreateTemporaryFileInDir(temp_dir_.path(), &src_file)); | 875 ASSERT_TRUE(base::CreateTemporaryFileInDir(temp_dir_.path(), &src_file)); |
| 873 ASSERT_EQ(FILE_ERROR_OK, | 876 ASSERT_EQ(FILE_ERROR_OK, |
| 874 cache_->Store(id, md5, src_file, FileCache::FILE_OPERATION_COPY)); | 877 cache_->Store(id, md5, src_file, FileCache::FILE_OPERATION_COPY)); |
| 875 | 878 |
| 876 // Clear cache. | 879 // Clear cache. |
| 877 EXPECT_TRUE(cache_->ClearAll()); | 880 EXPECT_TRUE(cache_->ClearAll()); |
| 878 | 881 |
| 879 // Verify that the cache is removed. | 882 // Verify that the cache is removed. |
| 880 EXPECT_TRUE(base::IsDirectoryEmpty(cache_files_dir_)); | 883 EXPECT_TRUE(base::IsDirectoryEmpty(cache_files_dir_)); |
| 881 } | 884 } |
| 882 | 885 |
| 883 } // namespace internal | 886 } // namespace internal |
| 884 } // namespace drive | 887 } // namespace drive |
| OLD | NEW |