| 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> | 7 #include <unistd.h> |
| 8 #include <sys/ioctl.h> | |
| 9 #include <sys/xattr.h> | |
| 10 | 8 |
| 11 #include <queue> | 9 #include <queue> |
| 12 #include <vector> | 10 #include <vector> |
| 13 | 11 |
| 14 #include "base/bind.h" | 12 #include "base/bind.h" |
| 15 #include "base/bind_helpers.h" | 13 #include "base/bind_helpers.h" |
| 16 #include "base/callback_helpers.h" | 14 #include "base/callback_helpers.h" |
| 17 #include "base/files/file.h" | |
| 18 #include "base/files/file_enumerator.h" | 15 #include "base/files/file_enumerator.h" |
| 19 #include "base/files/file_util.h" | 16 #include "base/files/file_util.h" |
| 20 #include "base/location.h" | 17 #include "base/location.h" |
| 21 #include "base/logging.h" | 18 #include "base/logging.h" |
| 22 #include "base/metrics/histogram.h" | 19 #include "base/metrics/histogram.h" |
| 23 #include "base/stl_util.h" | |
| 24 #include "base/strings/string_util.h" | 20 #include "base/strings/string_util.h" |
| 25 #include "base/strings/stringprintf.h" | 21 #include "base/strings/stringprintf.h" |
| 26 #include "base/sys_info.h" | 22 #include "base/sys_info.h" |
| 27 #include "build/build_config.h" | 23 #include "build/build_config.h" |
| 28 #include "components/drive/drive.pb.h" | 24 #include "components/drive/drive.pb.h" |
| 29 #include "components/drive/drive_api_util.h" | 25 #include "components/drive/drive_api_util.h" |
| 30 #include "components/drive/file_system_core_util.h" | 26 #include "components/drive/file_system_core_util.h" |
| 31 #include "components/drive/resource_metadata_storage.h" | 27 #include "components/drive/resource_metadata_storage.h" |
| 32 #include "google_apis/drive/task_util.h" | 28 #include "google_apis/drive/task_util.h" |
| 33 #include "net/base/filename_util.h" | 29 #include "net/base/filename_util.h" |
| 34 #include "net/base/mime_sniffer.h" | 30 #include "net/base/mime_sniffer.h" |
| 35 #include "net/base/mime_util.h" | 31 #include "net/base/mime_util.h" |
| 36 | 32 |
| 37 namespace drive { | 33 namespace drive { |
| 38 namespace internal { | 34 namespace internal { |
| 39 namespace { | 35 namespace { |
| 40 | 36 |
| 41 typedef std::pair<base::File::Info, ResourceEntry> CacheInfo; | |
| 42 typedef long FileAttributes; // NOLINT(runtime/int) | |
| 43 | |
| 44 // Returns ID extracted from the path. | 37 // Returns ID extracted from the path. |
| 45 std::string GetIdFromPath(const base::FilePath& path) { | 38 std::string GetIdFromPath(const base::FilePath& path) { |
| 46 return util::UnescapeCacheFileName(path.BaseName().AsUTF8Unsafe()); | 39 return util::UnescapeCacheFileName(path.BaseName().AsUTF8Unsafe()); |
| 47 } | 40 } |
| 48 | 41 |
| 49 base::FilePath GetPathForId(const base::FilePath& cache_directory, | 42 base::FilePath GetPathForId(const base::FilePath& cache_directory, |
| 50 const std::string& id) { | 43 const std::string& id) { |
| 51 return cache_directory.Append( | 44 return cache_directory.Append( |
| 52 base::FilePath::FromUTF8Unsafe(util::EscapeCacheFileName(id))); | 45 base::FilePath::FromUTF8Unsafe(util::EscapeCacheFileName(id))); |
| 53 } | 46 } |
| 54 | 47 |
| 55 // Sets extended file attribute as |name| |value| pair. | 48 typedef std::pair<base::File::Info, ResourceEntry> CacheInfo; |
| 56 bool SetExtendedFileAttributes(const base::FilePath& path, | |
| 57 const std::string& name, const std::string& value) { | |
| 58 return setxattr(path.value().c_str(), name.c_str(), value.c_str(), | |
| 59 value.size() + 1, 0) == 0; | |
| 60 } | |
| 61 | |
| 62 // Changes attributes of the file with |flags|, e.g. FS_NODUMP_FL (cryptohome | |
| 63 // will remove Drive caches with this attribute). | |
| 64 // See linux/fs.h for available flags, and chattr(1) which does similar thing. | |
| 65 // Returns whether operation succeeded. | |
| 66 bool SetFileAttributes(const base::FilePath& path, FileAttributes flags) { | |
| 67 base::File file(path, base::File::FLAG_OPEN | base::File::FLAG_READ); | |
| 68 if (!file.IsValid()) { | |
| 69 PLOG(ERROR) << "Failed to open file: " << path.value(); | |
| 70 return false; | |
| 71 } | |
| 72 if (ioctl(file.GetPlatformFile(), FS_IOC_SETFLAGS, &flags) < 0) { | |
| 73 PLOG(ERROR) << "ioctl: " << path.value(); | |
| 74 return false; | |
| 75 } | |
| 76 return true; | |
| 77 } | |
| 78 | |
| 79 // Gets file attributes similarly to lsattr(1). Returns flags or -1 on error. | |
| 80 // See linux/fs.h for the definition of the returned flags e.g. FS_NODUMP_FL. | |
| 81 FileAttributes GetFileAttributes(const base::FilePath& path) { | |
| 82 base::File file(path, base::File::FLAG_OPEN | base::File::FLAG_READ); | |
| 83 if (!file.IsValid()) { | |
| 84 PLOG(ERROR) << "Failed to open file: " << path.value(); | |
| 85 return -1; | |
| 86 } | |
| 87 FileAttributes flags = 0; | |
| 88 if (ioctl(file.GetPlatformFile(), FS_IOC_GETFLAGS, &flags) < 0) { | |
| 89 PLOG(ERROR) << "ioctl: " << path.value(); | |
| 90 return -1; | |
| 91 } | |
| 92 return flags; | |
| 93 } | |
| 94 | |
| 95 // Marks the cache file to be removable by cryptohome. | |
| 96 bool SetRemovable(const base::FilePath& path) { | |
| 97 FileAttributes flags = GetFileAttributes(path); | |
| 98 if (flags < 0) return false; | |
| 99 if ((flags & FS_NODUMP_FL) == FS_NODUMP_FL) return true; | |
| 100 | |
| 101 return SetFileAttributes(path, flags | FS_NODUMP_FL); | |
| 102 } | |
| 103 | |
| 104 // Marks the cache file to be unremovable by cryptohome. | |
| 105 bool UnsetRemovable(const base::FilePath& path) { | |
| 106 FileAttributes flags = GetFileAttributes(path); | |
| 107 if (flags < 0) return false; | |
| 108 if ((flags & FS_NODUMP_FL) == 0) return true; | |
| 109 | |
| 110 return SetFileAttributes(path, flags & ~FS_NODUMP_FL); | |
| 111 } | |
| 112 | |
| 113 // Marks |path| as drive cache dir. | |
| 114 // Returns if the operation succeeded. | |
| 115 bool MarkAsDriveCacheDir(const base::FilePath& path) { | |
| 116 return SetRemovable(path) | |
| 117 && SetExtendedFileAttributes(path, FileCache::kGCacheFilesAttribute, ""); | |
| 118 } | |
| 119 | 49 |
| 120 class CacheInfoLatestCompare { | 50 class CacheInfoLatestCompare { |
| 121 public: | 51 public: |
| 122 bool operator()(const CacheInfo& info_a, const CacheInfo& info_b) { | 52 bool operator()(const CacheInfo& info_a, const CacheInfo& info_b) { |
| 123 return info_a.first.last_accessed < info_b.first.last_accessed; | 53 return info_a.first.last_accessed < info_b.first.last_accessed; |
| 124 } | 54 } |
| 125 }; | 55 }; |
| 126 | 56 |
| 127 const size_t kMaxNumOfEvictedCacheFiles = 30000; | 57 const size_t kMaxNumOfEvictedCacheFiles = 30000; |
| 128 | 58 |
| 129 } // namespace | 59 } // namespace |
| 130 | 60 |
| 131 // static | |
| 132 const char FileCache::kGCacheFilesAttribute[] = "user.GCacheFiles"; | |
| 133 | |
| 134 FileCache::FileCache(ResourceMetadataStorage* storage, | 61 FileCache::FileCache(ResourceMetadataStorage* storage, |
| 135 const base::FilePath& cache_file_directory, | 62 const base::FilePath& cache_file_directory, |
| 136 base::SequencedTaskRunner* blocking_task_runner, | 63 base::SequencedTaskRunner* blocking_task_runner, |
| 137 FreeDiskSpaceGetterInterface* free_disk_space_getter) | 64 FreeDiskSpaceGetterInterface* free_disk_space_getter) |
| 138 : cache_file_directory_(cache_file_directory), | 65 : cache_file_directory_(cache_file_directory), |
| 139 blocking_task_runner_(blocking_task_runner), | 66 blocking_task_runner_(blocking_task_runner), |
| 140 storage_(storage), | 67 storage_(storage), |
| 141 free_disk_space_getter_(free_disk_space_getter), | 68 free_disk_space_getter_(free_disk_space_getter), |
| 142 max_num_of_evicted_cache_files_(kMaxNumOfEvictedCacheFiles), | 69 max_num_of_evicted_cache_files_(kMaxNumOfEvictedCacheFiles), |
| 143 weak_ptr_factory_(this) { | 70 weak_ptr_factory_(this) { |
| (...skipping 204 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 348 return FILE_ERROR_FAILED; | 275 return FILE_ERROR_FAILED; |
| 349 } | 276 } |
| 350 | 277 |
| 351 // Now that file operations have completed, update metadata. | 278 // Now that file operations have completed, update metadata. |
| 352 FileCacheEntry* cache_state = | 279 FileCacheEntry* cache_state = |
| 353 entry.mutable_file_specific_info()->mutable_cache_state(); | 280 entry.mutable_file_specific_info()->mutable_cache_state(); |
| 354 cache_state->set_md5(md5); | 281 cache_state->set_md5(md5); |
| 355 cache_state->set_is_present(true); | 282 cache_state->set_is_present(true); |
| 356 if (md5.empty()) | 283 if (md5.empty()) |
| 357 cache_state->set_is_dirty(true); | 284 cache_state->set_is_dirty(true); |
| 358 | |
| 359 if (!cache_state->is_pinned() && !cache_state->is_dirty()) { | |
| 360 if (!SetRemovable(dest_path)) | |
| 361 return FILE_ERROR_FAILED; | |
| 362 } else { | |
| 363 if (!UnsetRemovable(dest_path)) | |
| 364 return FILE_ERROR_FAILED; | |
| 365 } | |
| 366 | |
| 367 return storage_->PutEntry(entry); | 285 return storage_->PutEntry(entry); |
| 368 } | 286 } |
| 369 | 287 |
| 370 FileError FileCache::Pin(const std::string& id) { | 288 FileError FileCache::Pin(const std::string& id) { |
| 371 AssertOnSequencedWorkerPool(); | 289 AssertOnSequencedWorkerPool(); |
| 372 | 290 |
| 373 ResourceEntry entry; | 291 ResourceEntry entry; |
| 374 FileError error = storage_->GetEntry(id, &entry); | 292 FileError error = storage_->GetEntry(id, &entry); |
| 375 if (error != FILE_ERROR_OK) | 293 if (error != FILE_ERROR_OK) |
| 376 return error; | 294 return error; |
| 377 | |
| 378 entry.mutable_file_specific_info()->mutable_cache_state()->set_is_pinned( | 295 entry.mutable_file_specific_info()->mutable_cache_state()->set_is_pinned( |
| 379 true); | 296 true); |
| 380 | |
| 381 base::FilePath file_path = GetCacheFilePath(entry.local_id()); | |
| 382 // Cache file can be created later. | |
| 383 if (entry.file_specific_info().cache_state().is_present()) { | |
| 384 if (!UnsetRemovable(file_path)) | |
| 385 return FILE_ERROR_FAILED; | |
| 386 } | |
| 387 | |
| 388 return storage_->PutEntry(entry); | 297 return storage_->PutEntry(entry); |
| 389 } | 298 } |
| 390 | 299 |
| 391 FileError FileCache::Unpin(const std::string& id) { | 300 FileError FileCache::Unpin(const std::string& id) { |
| 392 AssertOnSequencedWorkerPool(); | 301 AssertOnSequencedWorkerPool(); |
| 393 | 302 |
| 394 // Unpinning a file means its entry must exist in cache. | 303 // Unpinning a file means its entry must exist in cache. |
| 395 ResourceEntry entry; | 304 ResourceEntry entry; |
| 396 FileError error = storage_->GetEntry(id, &entry); | 305 FileError error = storage_->GetEntry(id, &entry); |
| 397 if (error != FILE_ERROR_OK) | 306 if (error != FILE_ERROR_OK) |
| 398 return error; | 307 return error; |
| 399 | 308 |
| 400 // Now that file operations have completed, update metadata. | 309 // Now that file operations have completed, update metadata. |
| 401 if (entry.file_specific_info().cache_state().is_present()) { | 310 if (entry.file_specific_info().cache_state().is_present()) { |
| 402 entry.mutable_file_specific_info()->mutable_cache_state()->set_is_pinned( | 311 entry.mutable_file_specific_info()->mutable_cache_state()->set_is_pinned( |
| 403 false); | 312 false); |
| 404 if (!entry.file_specific_info().cache_state().is_dirty()) { | |
| 405 if (!SetRemovable(GetCacheFilePath(entry.local_id()))) | |
| 406 return FILE_ERROR_FAILED; | |
| 407 } | |
| 408 } else { | 313 } else { |
| 409 // Remove the existing entry if we are unpinning a non-present file. | 314 // Remove the existing entry if we are unpinning a non-present file. |
| 410 entry.mutable_file_specific_info()->clear_cache_state(); | 315 entry.mutable_file_specific_info()->clear_cache_state(); |
| 411 } | 316 } |
| 412 error = storage_->PutEntry(entry); | 317 error = storage_->PutEntry(entry); |
| 413 if (error != FILE_ERROR_OK) | 318 if (error != FILE_ERROR_OK) |
| 414 return error; | 319 return error; |
| 415 | 320 |
| 416 // Now it's a chance to free up space if needed. | 321 // Now it's a chance to free up space if needed. |
| 417 FreeDiskSpaceIfNeededFor(0); | 322 FreeDiskSpaceIfNeededFor(0); |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 464 ResourceEntry entry; | 369 ResourceEntry entry; |
| 465 FileError error = storage_->GetEntry(id, &entry); | 370 FileError error = storage_->GetEntry(id, &entry); |
| 466 if (error != FILE_ERROR_OK) | 371 if (error != FILE_ERROR_OK) |
| 467 return error; | 372 return error; |
| 468 if (!entry.file_specific_info().cache_state().is_present()) { | 373 if (!entry.file_specific_info().cache_state().is_present()) { |
| 469 LOG(WARNING) << "Can't mark dirty a file that wasn't cached: " << id; | 374 LOG(WARNING) << "Can't mark dirty a file that wasn't cached: " << id; |
| 470 return FILE_ERROR_NOT_FOUND; | 375 return FILE_ERROR_NOT_FOUND; |
| 471 } | 376 } |
| 472 | 377 |
| 473 entry.mutable_file_specific_info()->mutable_cache_state()->set_is_dirty(true); | 378 entry.mutable_file_specific_info()->mutable_cache_state()->set_is_dirty(true); |
| 474 if (!UnsetRemovable(GetCacheFilePath(entry.local_id()))) | |
| 475 return FILE_ERROR_FAILED; | |
| 476 | |
| 477 entry.mutable_file_specific_info()->mutable_cache_state()->clear_md5(); | 379 entry.mutable_file_specific_info()->mutable_cache_state()->clear_md5(); |
| 478 error = storage_->PutEntry(entry); | 380 error = storage_->PutEntry(entry); |
| 479 if (error != FILE_ERROR_OK) | 381 if (error != FILE_ERROR_OK) |
| 480 return error; | 382 return error; |
| 481 | 383 |
| 482 write_opened_files_[id]++; | 384 write_opened_files_[id]++; |
| 483 file_closer->reset(new base::ScopedClosureRunner( | 385 file_closer->reset(new base::ScopedClosureRunner( |
| 484 base::Bind(&google_apis::RunTaskWithTaskRunner, | 386 base::Bind(&google_apis::RunTaskWithTaskRunner, |
| 485 blocking_task_runner_, | 387 blocking_task_runner_, |
| 486 base::Bind(&FileCache::CloseForWrite, | 388 base::Bind(&FileCache::CloseForWrite, |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 538 | 440 |
| 539 // If a file is not dirty (it should have been marked dirty via OpenForWrite), | 441 // If a file is not dirty (it should have been marked dirty via OpenForWrite), |
| 540 // clearing its dirty state is an invalid operation. | 442 // clearing its dirty state is an invalid operation. |
| 541 if (!entry.file_specific_info().cache_state().is_dirty()) { | 443 if (!entry.file_specific_info().cache_state().is_dirty()) { |
| 542 LOG(WARNING) << "Can't clear dirty state of a non-dirty file: " << id; | 444 LOG(WARNING) << "Can't clear dirty state of a non-dirty file: " << id; |
| 543 return FILE_ERROR_INVALID_OPERATION; | 445 return FILE_ERROR_INVALID_OPERATION; |
| 544 } | 446 } |
| 545 | 447 |
| 546 entry.mutable_file_specific_info()->mutable_cache_state()->set_is_dirty( | 448 entry.mutable_file_specific_info()->mutable_cache_state()->set_is_dirty( |
| 547 false); | 449 false); |
| 548 if (!entry.file_specific_info().cache_state().is_pinned()) { | |
| 549 if (!SetRemovable(GetCacheFilePath(entry.local_id()))) | |
| 550 return FILE_ERROR_FAILED; | |
| 551 } | |
| 552 | |
| 553 return storage_->PutEntry(entry); | 450 return storage_->PutEntry(entry); |
| 554 } | 451 } |
| 555 | 452 |
| 556 FileError FileCache::Remove(const std::string& id) { | 453 FileError FileCache::Remove(const std::string& id) { |
| 557 AssertOnSequencedWorkerPool(); | 454 AssertOnSequencedWorkerPool(); |
| 558 | 455 |
| 559 ResourceEntry entry; | 456 ResourceEntry entry; |
| 560 | 457 |
| 561 // If entry doesn't exist, nothing to do. | 458 // If entry doesn't exist, nothing to do. |
| 562 FileError error = storage_->GetEntry(id, &entry); | 459 FileError error = storage_->GetEntry(id, &entry); |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 609 clear_md5(); | 506 clear_md5(); |
| 610 if (storage_->PutEntry(new_entry) != FILE_ERROR_OK) | 507 if (storage_->PutEntry(new_entry) != FILE_ERROR_OK) |
| 611 return false; | 508 return false; |
| 612 } | 509 } |
| 613 } | 510 } |
| 614 if (it->HasError()) | 511 if (it->HasError()) |
| 615 return false; | 512 return false; |
| 616 | 513 |
| 617 if (!RenameCacheFilesToNewFormat()) | 514 if (!RenameCacheFilesToNewFormat()) |
| 618 return false; | 515 return false; |
| 619 | |
| 620 // Run this every time to resolve inconsistency between metadata | |
| 621 // and file attributes which possibly occurs on abrupt power failure. | |
| 622 if (!FixMetadataAndFileAttributes()) { | |
| 623 return false; | |
| 624 } | |
| 625 | |
| 626 return true; | 516 return true; |
| 627 } | 517 } |
| 628 | 518 |
| 629 void FileCache::Destroy() { | 519 void FileCache::Destroy() { |
| 630 DCHECK(thread_checker_.CalledOnValidThread()); | 520 DCHECK(thread_checker_.CalledOnValidThread()); |
| 631 | 521 |
| 632 in_shutdown_.Set(); | 522 in_shutdown_.Set(); |
| 633 | 523 |
| 634 // Destroy myself on the blocking pool. | 524 // Destroy myself on the blocking pool. |
| 635 // Note that base::DeletePointer<> cannot be used as the destructor of this | 525 // Note that base::DeletePointer<> cannot be used as the destructor of this |
| (...skipping 151 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 787 continue; | 677 continue; |
| 788 } | 678 } |
| 789 const std::string& id = GetIdFromPath(new_path); | 679 const std::string& id = GetIdFromPath(new_path); |
| 790 new_path = GetCacheFilePath(util::CanonicalizeResourceId(id)); | 680 new_path = GetCacheFilePath(util::CanonicalizeResourceId(id)); |
| 791 if (new_path != current && !base::Move(current, new_path)) | 681 if (new_path != current && !base::Move(current, new_path)) |
| 792 return false; | 682 return false; |
| 793 } | 683 } |
| 794 return true; | 684 return true; |
| 795 } | 685 } |
| 796 | 686 |
| 797 bool FileCache::FixMetadataAndFileAttributes() { | 687 // static |
| 688 bool FileCache::MigrateCacheFiles(const base::FilePath& from, |
| 689 const base::FilePath& to_files, |
| 690 const base::FilePath& to_links, |
| 691 ResourceMetadataStorage* metadata_storage) { |
| 798 std::unique_ptr<ResourceMetadataStorage::Iterator> it = | 692 std::unique_ptr<ResourceMetadataStorage::Iterator> it = |
| 799 storage_->GetIterator(); | 693 metadata_storage->GetIterator(); |
| 694 for (; !it->IsAtEnd(); it->Advance()) { |
| 695 const ResourceEntry& entry = it->GetValue(); |
| 696 if (!entry.file_specific_info().cache_state().is_present()) { |
| 697 continue; |
| 698 } |
| 800 | 699 |
| 801 for (; !it->IsAtEnd(); it->Advance()) { | 700 // Ignore missing cache file case since it never succeeds. |
| 802 ResourceEntry entry = it->GetValue(); | 701 // TODO(yawano): handle this case at metadata validation in FileCache. |
| 803 FileCacheEntry* file_cache_entry = | 702 const base::FilePath move_from = GetPathForId(from, entry.local_id()); |
| 804 entry.mutable_file_specific_info()->mutable_cache_state(); | 703 if (!base::PathExists(move_from)) { |
| 704 continue; |
| 705 } |
| 805 | 706 |
| 806 const base::FilePath filepath = GetPathForId(cache_file_directory_, | 707 // Create hard link to cache file if it's pinned or dirty. cryptohome will |
| 807 entry.local_id()); | 708 // not delete a cache file if there is a hard link to it. |
| 709 const FileCacheEntry& file_cache_entry = |
| 710 entry.file_specific_info().cache_state(); |
| 711 if (file_cache_entry.is_pinned() || file_cache_entry.is_dirty()) { |
| 712 const base::FilePath link_path = GetPathForId(to_links, entry.local_id()); |
| 713 int link_result = link(move_from.AsUTF8Unsafe().c_str(), |
| 714 link_path.AsUTF8Unsafe().c_str()); |
| 715 if (link_result != 0 && errno != EEXIST) { |
| 716 return false; |
| 717 } |
| 718 } |
| 808 | 719 |
| 809 if (base::PathExists(filepath)) { | 720 // Move cache file. |
| 810 if (file_cache_entry->is_present()) { | 721 const base::FilePath move_to = GetPathForId(to_files, entry.local_id()); |
| 811 // Update file attribues for cryptohome. | 722 if (!base::Move(move_from, move_to)) { |
| 812 if (file_cache_entry->is_pinned() || file_cache_entry->is_dirty()) { | 723 return false; |
| 813 if (!UnsetRemovable(filepath)) return false; | |
| 814 } else { | |
| 815 if (!SetRemovable(filepath)) return false; | |
| 816 } | |
| 817 } else { | |
| 818 // Delete file if the file is present but metadata says not. | |
| 819 // It happens only on abrupt shutdown. | |
| 820 LOG(WARNING) | |
| 821 << "File is present but metadata's state was inconsistent."; | |
| 822 | |
| 823 if (!base::DeleteFile(filepath, false /* recursive */)) | |
| 824 return false; | |
| 825 } | |
| 826 } else { | |
| 827 // Update metatadata if there is no file but metadata says there is. | |
| 828 // It happens when cryptohome removed the file. | |
| 829 // We don't clear is_pinned here, so that file download is restarted on | |
| 830 // the following scenario: | |
| 831 // 1. The file was pinned but not present. | |
| 832 // 2. Then the file was downloaded and became present. | |
| 833 // 3. Unclean shutdown happens, metadata update was saved to the disk, | |
| 834 // but the file move was not. | |
| 835 if (file_cache_entry->is_present()) { | |
| 836 file_cache_entry->set_is_present(false); | |
| 837 file_cache_entry->set_is_dirty(false); | |
| 838 file_cache_entry->clear_md5(); | |
| 839 if (storage_->PutEntry(entry) != FILE_ERROR_OK) | |
| 840 return false; | |
| 841 } | |
| 842 } | 724 } |
| 843 } | 725 } |
| 844 | 726 |
| 845 return MarkAsDriveCacheDir(cache_file_directory_); | 727 return true; |
| 846 } | 728 } |
| 847 | 729 |
| 848 void FileCache::CloseForWrite(const std::string& id) { | 730 void FileCache::CloseForWrite(const std::string& id) { |
| 849 AssertOnSequencedWorkerPool(); | 731 AssertOnSequencedWorkerPool(); |
| 850 | 732 |
| 851 std::map<std::string, int>::iterator it = write_opened_files_.find(id); | 733 std::map<std::string, int>::iterator it = write_opened_files_.find(id); |
| 852 if (it == write_opened_files_.end()) | 734 if (it == write_opened_files_.end()) |
| 853 return; | 735 return; |
| 854 | 736 |
| 855 DCHECK_LT(0, it->second); | 737 DCHECK_LT(0, it->second); |
| (...skipping 20 matching lines...) Expand all Loading... |
| 876 | 758 |
| 877 bool FileCache::IsEvictable(const std::string& id, const ResourceEntry& entry) { | 759 bool FileCache::IsEvictable(const std::string& id, const ResourceEntry& entry) { |
| 878 return entry.file_specific_info().has_cache_state() && | 760 return entry.file_specific_info().has_cache_state() && |
| 879 !entry.file_specific_info().cache_state().is_pinned() && | 761 !entry.file_specific_info().cache_state().is_pinned() && |
| 880 !entry.file_specific_info().cache_state().is_dirty() && | 762 !entry.file_specific_info().cache_state().is_dirty() && |
| 881 !mounted_files_.count(id); | 763 !mounted_files_.count(id); |
| 882 } | 764 } |
| 883 | 765 |
| 884 } // namespace internal | 766 } // namespace internal |
| 885 } // namespace drive | 767 } // namespace drive |
| OLD | NEW |