Chromium Code Reviews| 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 <fcntl.h> | |
| 8 #include <linux/fs.h> | |
| 9 #include <sys/ioctl.h> | |
| 10 #include <sys/stat.h> | |
| 11 #include <sys/types.h> | |
| 12 #include <sys/xattr.h> | |
| 7 #include <unistd.h> | 13 #include <unistd.h> |
| 8 | 14 |
| 9 #include <queue> | 15 #include <queue> |
| 10 #include <vector> | 16 #include <vector> |
| 11 | 17 |
| 12 #include "base/bind.h" | 18 #include "base/bind.h" |
| 13 #include "base/bind_helpers.h" | 19 #include "base/bind_helpers.h" |
| 14 #include "base/callback_helpers.h" | 20 #include "base/callback_helpers.h" |
| 15 #include "base/files/file_enumerator.h" | 21 #include "base/files/file_enumerator.h" |
| 16 #include "base/files/file_util.h" | 22 #include "base/files/file_util.h" |
| 17 #include "base/location.h" | 23 #include "base/location.h" |
| 18 #include "base/logging.h" | 24 #include "base/logging.h" |
| 19 #include "base/metrics/histogram.h" | 25 #include "base/metrics/histogram.h" |
| 26 #include "base/stl_util.h" | |
| 20 #include "base/strings/string_util.h" | 27 #include "base/strings/string_util.h" |
| 21 #include "base/strings/stringprintf.h" | 28 #include "base/strings/stringprintf.h" |
| 22 #include "base/sys_info.h" | 29 #include "base/sys_info.h" |
| 23 #include "build/build_config.h" | 30 #include "build/build_config.h" |
| 24 #include "components/drive/drive.pb.h" | 31 #include "components/drive/drive.pb.h" |
| 25 #include "components/drive/drive_api_util.h" | 32 #include "components/drive/drive_api_util.h" |
| 26 #include "components/drive/file_system_core_util.h" | 33 #include "components/drive/file_system_core_util.h" |
| 27 #include "components/drive/resource_metadata_storage.h" | 34 #include "components/drive/resource_metadata_storage.h" |
| 28 #include "google_apis/drive/task_util.h" | 35 #include "google_apis/drive/task_util.h" |
| 29 #include "net/base/filename_util.h" | 36 #include "net/base/filename_util.h" |
| 30 #include "net/base/mime_sniffer.h" | 37 #include "net/base/mime_sniffer.h" |
| 31 #include "net/base/mime_util.h" | 38 #include "net/base/mime_util.h" |
| 32 | 39 |
| 33 namespace drive { | 40 namespace drive { |
| 34 namespace internal { | 41 namespace internal { |
| 35 namespace { | 42 namespace { |
| 36 | 43 |
| 37 // Returns ID extracted from the path. | 44 // Returns ID extracted from the path. |
| 38 std::string GetIdFromPath(const base::FilePath& path) { | 45 std::string GetIdFromPath(const base::FilePath& path) { |
| 39 return util::UnescapeCacheFileName(path.BaseName().AsUTF8Unsafe()); | 46 return util::UnescapeCacheFileName(path.BaseName().AsUTF8Unsafe()); |
| 40 } | 47 } |
| 41 | 48 |
| 42 base::FilePath GetPathForId(const base::FilePath& cache_directory, | 49 base::FilePath GetPathForId(const base::FilePath& cache_directory, |
| 43 const std::string& id) { | 50 const std::string& id) { |
| 44 return cache_directory.Append( | 51 return cache_directory.Append( |
| 45 base::FilePath::FromUTF8Unsafe(util::EscapeCacheFileName(id))); | 52 base::FilePath::FromUTF8Unsafe(util::EscapeCacheFileName(id))); |
| 46 } | 53 } |
| 47 | 54 |
| 55 // Set extended file attribute as |name| |value| pair. | |
|
hashimoto
2016/05/02 08:29:20
nit: "Set" -> "Sets"
The same goes for others.
oka
2016/05/09 14:27:39
Done.
| |
| 56 bool Setxattr(const std::string& path, const std::string& name, | |
|
hashimoto
2016/05/02 08:29:20
How about making the name more descriptive (e.g. S
oka
2016/05/09 14:27:39
Done.
| |
| 57 const std::string& value) { | |
| 58 return setxattr(path.c_str(), name.c_str(), value.c_str(), value.size() + 1, | |
| 59 0) == 0; | |
| 60 } | |
| 61 | |
| 62 // Get extended file attribute associated with |name| and set it to |value|. | |
| 63 // If nothing is associated with |name|, set "" to |value|. | |
| 64 bool Getxattr(const std::string& path, const std::string& name, | |
| 65 std::string* value, size_t size) { | |
|
hashimoto
2016/05/02 08:29:20
Do we actually care about the contents of the attr
oka
2016/05/09 14:27:40
That's a good idea. Though I removed the func, I'l
| |
| 66 value->resize(size - 1); | |
| 67 char* v = string_as_array(value); | |
| 68 ssize_t ret_size = getxattr(path.c_str(), name.c_str(), v, size); | |
| 69 if (ret_size < 0) { | |
| 70 if (errno == ENODATA) { | |
| 71 value->assign(""); | |
| 72 return true; | |
| 73 } else { | |
| 74 PLOG(ERROR) << "getxattr: " << name; | |
| 75 return false; | |
| 76 } | |
| 77 } | |
| 78 value->resize(ret_size - 1); | |
| 79 return true; | |
| 80 } | |
| 81 | |
| 82 // Change attributes of the file with |flags|, | |
| 83 // e.g. FS_UNRM_FL | FS_IMMUTABLE_FL. See linux/fs.h for available flags. | |
|
hashimoto
2016/05/02 08:29:20
nit: FS_UNRM_FL and FS_IMMUTABLE_FL are totally un
oka
2016/05/09 14:27:40
Done.
| |
| 84 // Returns whether operation succeeded. | |
| 85 bool Chattr(const std::string& path, int64_t flags) { | |
|
hashimoto
2016/05/02 08:29:20
Could you give this function a more readable name
oka
2016/05/09 14:27:40
Done.
| |
| 86 int fd = HANDLE_EINTR(open(path.c_str(), O_RDONLY)); | |
|
hashimoto
2016/05/02 08:29:20
Why don't you use base::File with which you don't
oka
2016/05/09 14:27:40
Done.
| |
| 87 if (fd < 0) { | |
| 88 PLOG(ERROR) << "open: " << path; | |
| 89 return false; | |
| 90 } | |
| 91 if (ioctl(fd, FS_IOC_SETFLAGS, &flags) < 0) { | |
| 92 PLOG(ERROR) << "ioctl" << path; | |
| 93 IGNORE_EINTR(close(fd)); | |
| 94 return false; | |
| 95 } | |
| 96 IGNORE_EINTR(close(fd)); | |
| 97 return true; | |
| 98 } | |
| 99 | |
| 100 int64_t Lsattr(const std::string& path) { | |
|
hashimoto
2016/05/02 08:29:20
Please add a comment.
oka
2016/05/09 14:27:40
Done.
| |
| 101 int fd = HANDLE_EINTR(open(path.c_str(), O_RDONLY)); | |
| 102 if (fd < 0) { | |
| 103 PLOG(ERROR) << "open: " << path; | |
| 104 return -1; | |
| 105 } | |
| 106 int64_t flags = 0; | |
| 107 if (ioctl(fd, FS_IOC_GETFLAGS, &flags) < 0) { | |
| 108 PLOG(ERROR) << "ioctl"; | |
| 109 IGNORE_EINTR(close(fd)); | |
| 110 return -1; | |
| 111 } | |
| 112 IGNORE_EINTR(close(fd)); | |
| 113 return flags; | |
| 114 } | |
| 115 | |
| 116 // Mark the cache file to be removable by cryptohome. | |
| 117 bool SetRemovable(const base::FilePath& path) { | |
| 118 int64_t flags = Lsattr(path.value()); | |
| 119 if (flags < 0) return false; | |
| 120 if ((flags & FS_NODUMP_FL) == FS_NODUMP_FL) return true; | |
| 121 | |
| 122 return Chattr(path.value(), flags | FS_NODUMP_FL); | |
| 123 } | |
| 124 | |
| 125 // Mark the cache file to be unremovable by cryptohome. | |
| 126 bool UnsetRemovable(const base::FilePath& path) { | |
| 127 // File is to be created. | |
| 128 if (!base::PathExists(path)) return true; | |
|
hashimoto
2016/05/02 08:29:20
This behavior is surprising, and not symmetric wit
oka
2016/05/09 14:27:40
Done. Added existence check to Pin.
| |
| 129 | |
| 130 int64_t flags = Lsattr(path.value()); | |
| 131 if (flags < 0) return false; | |
| 132 if ((flags & FS_NODUMP_FL) == 0) return true; | |
| 133 | |
| 134 return Chattr(path.value(), flags & ~(static_cast<int64_t>(FS_NODUMP_FL))); | |
| 135 } | |
| 136 | |
| 137 // Mark |path| as drive cache dir. | |
| 138 // Returns if the operation succeeded. | |
| 139 bool MarkAsDriveCacheDir(const base::FilePath& path) { | |
| 140 return SetRemovable(path) | |
| 141 && Setxattr(path.value(), "user.GCacheFiles", "true"); | |
|
hashimoto
2016/05/02 08:29:20
What is the point of using "true" instead of an em
oka
2016/05/09 14:27:39
Done.
| |
| 142 } | |
| 143 | |
| 48 typedef std::pair<base::File::Info, ResourceEntry> CacheInfo; | 144 typedef std::pair<base::File::Info, ResourceEntry> CacheInfo; |
| 49 | 145 |
| 50 class CacheInfoLatestCompare { | 146 class CacheInfoLatestCompare { |
| 51 public: | 147 public: |
| 52 bool operator()(const CacheInfo& info_a, const CacheInfo& info_b) { | 148 bool operator()(const CacheInfo& info_a, const CacheInfo& info_b) { |
| 53 return info_a.first.last_accessed < info_b.first.last_accessed; | 149 return info_a.first.last_accessed < info_b.first.last_accessed; |
| 54 } | 150 } |
| 55 }; | 151 }; |
| 56 | 152 |
| 57 const size_t kMaxNumOfEvictedCacheFiles = 30000; | 153 const size_t kMaxNumOfEvictedCacheFiles = 30000; |
| (...skipping 217 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 275 return FILE_ERROR_FAILED; | 371 return FILE_ERROR_FAILED; |
| 276 } | 372 } |
| 277 | 373 |
| 278 // Now that file operations have completed, update metadata. | 374 // Now that file operations have completed, update metadata. |
| 279 FileCacheEntry* cache_state = | 375 FileCacheEntry* cache_state = |
| 280 entry.mutable_file_specific_info()->mutable_cache_state(); | 376 entry.mutable_file_specific_info()->mutable_cache_state(); |
| 281 cache_state->set_md5(md5); | 377 cache_state->set_md5(md5); |
| 282 cache_state->set_is_present(true); | 378 cache_state->set_is_present(true); |
| 283 if (md5.empty()) | 379 if (md5.empty()) |
| 284 cache_state->set_is_dirty(true); | 380 cache_state->set_is_dirty(true); |
| 381 | |
| 382 if (!cache_state->is_pinned() && !cache_state->is_dirty()) { | |
| 383 if (!SetRemovable(dest_path)) | |
| 384 return FILE_ERROR_FAILED; | |
| 385 } else { | |
| 386 if (!UnsetRemovable(dest_path)) | |
| 387 return FILE_ERROR_FAILED; | |
| 388 } | |
| 389 | |
| 285 return storage_->PutEntry(entry); | 390 return storage_->PutEntry(entry); |
| 286 } | 391 } |
| 287 | 392 |
| 288 FileError FileCache::Pin(const std::string& id) { | 393 FileError FileCache::Pin(const std::string& id) { |
| 289 AssertOnSequencedWorkerPool(); | 394 AssertOnSequencedWorkerPool(); |
| 290 | 395 |
| 291 ResourceEntry entry; | 396 ResourceEntry entry; |
| 292 FileError error = storage_->GetEntry(id, &entry); | 397 FileError error = storage_->GetEntry(id, &entry); |
| 293 if (error != FILE_ERROR_OK) | 398 if (error != FILE_ERROR_OK) |
| 294 return error; | 399 return error; |
| 400 | |
| 295 entry.mutable_file_specific_info()->mutable_cache_state()->set_is_pinned( | 401 entry.mutable_file_specific_info()->mutable_cache_state()->set_is_pinned( |
| 296 true); | 402 true); |
| 403 if (!UnsetRemovable(GetCacheFilePath(entry.local_id()))) | |
| 404 return FILE_ERROR_FAILED; | |
| 405 | |
| 297 return storage_->PutEntry(entry); | 406 return storage_->PutEntry(entry); |
| 298 } | 407 } |
| 299 | 408 |
| 300 FileError FileCache::Unpin(const std::string& id) { | 409 FileError FileCache::Unpin(const std::string& id) { |
| 301 AssertOnSequencedWorkerPool(); | 410 AssertOnSequencedWorkerPool(); |
| 302 | 411 |
| 303 // Unpinning a file means its entry must exist in cache. | 412 // Unpinning a file means its entry must exist in cache. |
| 304 ResourceEntry entry; | 413 ResourceEntry entry; |
| 305 FileError error = storage_->GetEntry(id, &entry); | 414 FileError error = storage_->GetEntry(id, &entry); |
| 306 if (error != FILE_ERROR_OK) | 415 if (error != FILE_ERROR_OK) |
| 307 return error; | 416 return error; |
| 308 | 417 |
| 309 // Now that file operations have completed, update metadata. | 418 // Now that file operations have completed, update metadata. |
| 310 if (entry.file_specific_info().cache_state().is_present()) { | 419 if (entry.file_specific_info().cache_state().is_present()) { |
| 311 entry.mutable_file_specific_info()->mutable_cache_state()->set_is_pinned( | 420 entry.mutable_file_specific_info()->mutable_cache_state()->set_is_pinned( |
| 312 false); | 421 false); |
| 422 if (!entry.file_specific_info().cache_state().is_dirty()) { | |
| 423 if (!SetRemovable(GetCacheFilePath(entry.local_id()))) | |
| 424 return FILE_ERROR_FAILED; | |
| 425 } | |
| 313 } else { | 426 } else { |
| 314 // Remove the existing entry if we are unpinning a non-present file. | 427 // Remove the existing entry if we are unpinning a non-present file. |
| 315 entry.mutable_file_specific_info()->clear_cache_state(); | 428 entry.mutable_file_specific_info()->clear_cache_state(); |
| 316 } | 429 } |
| 317 error = storage_->PutEntry(entry); | 430 error = storage_->PutEntry(entry); |
| 318 if (error != FILE_ERROR_OK) | 431 if (error != FILE_ERROR_OK) |
| 319 return error; | 432 return error; |
| 320 | 433 |
| 321 // Now it's a chance to free up space if needed. | 434 // Now it's a chance to free up space if needed. |
| 322 FreeDiskSpaceIfNeededFor(0); | 435 FreeDiskSpaceIfNeededFor(0); |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 369 ResourceEntry entry; | 482 ResourceEntry entry; |
| 370 FileError error = storage_->GetEntry(id, &entry); | 483 FileError error = storage_->GetEntry(id, &entry); |
| 371 if (error != FILE_ERROR_OK) | 484 if (error != FILE_ERROR_OK) |
| 372 return error; | 485 return error; |
| 373 if (!entry.file_specific_info().cache_state().is_present()) { | 486 if (!entry.file_specific_info().cache_state().is_present()) { |
| 374 LOG(WARNING) << "Can't mark dirty a file that wasn't cached: " << id; | 487 LOG(WARNING) << "Can't mark dirty a file that wasn't cached: " << id; |
| 375 return FILE_ERROR_NOT_FOUND; | 488 return FILE_ERROR_NOT_FOUND; |
| 376 } | 489 } |
| 377 | 490 |
| 378 entry.mutable_file_specific_info()->mutable_cache_state()->set_is_dirty(true); | 491 entry.mutable_file_specific_info()->mutable_cache_state()->set_is_dirty(true); |
| 492 if (!UnsetRemovable(GetCacheFilePath(entry.local_id()))) | |
| 493 return FILE_ERROR_FAILED; | |
| 494 | |
| 379 entry.mutable_file_specific_info()->mutable_cache_state()->clear_md5(); | 495 entry.mutable_file_specific_info()->mutable_cache_state()->clear_md5(); |
| 380 error = storage_->PutEntry(entry); | 496 error = storage_->PutEntry(entry); |
| 381 if (error != FILE_ERROR_OK) | 497 if (error != FILE_ERROR_OK) |
| 382 return error; | 498 return error; |
| 383 | 499 |
| 384 write_opened_files_[id]++; | 500 write_opened_files_[id]++; |
| 385 file_closer->reset(new base::ScopedClosureRunner( | 501 file_closer->reset(new base::ScopedClosureRunner( |
| 386 base::Bind(&google_apis::RunTaskWithTaskRunner, | 502 base::Bind(&google_apis::RunTaskWithTaskRunner, |
| 387 blocking_task_runner_, | 503 blocking_task_runner_, |
| 388 base::Bind(&FileCache::CloseForWrite, | 504 base::Bind(&FileCache::CloseForWrite, |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 440 | 556 |
| 441 // If a file is not dirty (it should have been marked dirty via OpenForWrite), | 557 // If a file is not dirty (it should have been marked dirty via OpenForWrite), |
| 442 // clearing its dirty state is an invalid operation. | 558 // clearing its dirty state is an invalid operation. |
| 443 if (!entry.file_specific_info().cache_state().is_dirty()) { | 559 if (!entry.file_specific_info().cache_state().is_dirty()) { |
| 444 LOG(WARNING) << "Can't clear dirty state of a non-dirty file: " << id; | 560 LOG(WARNING) << "Can't clear dirty state of a non-dirty file: " << id; |
| 445 return FILE_ERROR_INVALID_OPERATION; | 561 return FILE_ERROR_INVALID_OPERATION; |
| 446 } | 562 } |
| 447 | 563 |
| 448 entry.mutable_file_specific_info()->mutable_cache_state()->set_is_dirty( | 564 entry.mutable_file_specific_info()->mutable_cache_state()->set_is_dirty( |
| 449 false); | 565 false); |
| 566 if (!entry.file_specific_info().cache_state().is_pinned()) { | |
| 567 if (!SetRemovable(GetCacheFilePath(entry.local_id()))) | |
| 568 return FILE_ERROR_FAILED; | |
| 569 } | |
| 570 | |
| 450 return storage_->PutEntry(entry); | 571 return storage_->PutEntry(entry); |
| 451 } | 572 } |
| 452 | 573 |
| 453 FileError FileCache::Remove(const std::string& id) { | 574 FileError FileCache::Remove(const std::string& id) { |
| 454 AssertOnSequencedWorkerPool(); | 575 AssertOnSequencedWorkerPool(); |
| 455 | 576 |
| 456 ResourceEntry entry; | 577 ResourceEntry entry; |
| 457 | 578 |
| 458 // If entry doesn't exist, nothing to do. | 579 // If entry doesn't exist, nothing to do. |
| 459 FileError error = storage_->GetEntry(id, &entry); | 580 FileError error = storage_->GetEntry(id, &entry); |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 506 clear_md5(); | 627 clear_md5(); |
| 507 if (storage_->PutEntry(new_entry) != FILE_ERROR_OK) | 628 if (storage_->PutEntry(new_entry) != FILE_ERROR_OK) |
| 508 return false; | 629 return false; |
| 509 } | 630 } |
| 510 } | 631 } |
| 511 if (it->HasError()) | 632 if (it->HasError()) |
| 512 return false; | 633 return false; |
| 513 | 634 |
| 514 if (!RenameCacheFilesToNewFormat()) | 635 if (!RenameCacheFilesToNewFormat()) |
| 515 return false; | 636 return false; |
| 637 | |
| 638 if (!ResolveMetadataInconsistency()) { | |
| 639 return false; | |
| 640 } | |
| 641 | |
| 642 if (ShouldStartDriveCacheMigration()) { | |
| 643 if (!MigrateCacheFiles()) { | |
| 644 return false; | |
| 645 } | |
| 646 } | |
| 647 | |
| 516 return true; | 648 return true; |
| 517 } | 649 } |
| 518 | 650 |
| 651 bool FileCache::ShouldStartDriveCacheMigration() { | |
|
hashimoto
2016/05/02 08:29:19
IIUC, because of IO scheduling, a system crash or
oka
2016/05/09 14:27:39
I experimentally confirmed setting attributes is n
| |
| 652 std::string value = ""; | |
| 653 if (!Getxattr(cache_file_directory_.value(), "user.GCacheFiles", &value, 5)) { | |
| 654 PLOG(WARNING) << "Getxattr: " << cache_file_directory_.value(); | |
| 655 } | |
| 656 int64_t flags = Lsattr(cache_file_directory_.value()); | |
| 657 if (flags < 0) return false; | |
| 658 | |
| 659 return value != "true" || ((flags & FS_NODUMP_FL) == 0); | |
| 660 } | |
| 661 | |
| 519 void FileCache::Destroy() { | 662 void FileCache::Destroy() { |
| 520 DCHECK(thread_checker_.CalledOnValidThread()); | 663 DCHECK(thread_checker_.CalledOnValidThread()); |
| 521 | 664 |
| 522 in_shutdown_.Set(); | 665 in_shutdown_.Set(); |
| 523 | 666 |
| 524 // Destroy myself on the blocking pool. | 667 // Destroy myself on the blocking pool. |
| 525 // Note that base::DeletePointer<> cannot be used as the destructor of this | 668 // Note that base::DeletePointer<> cannot be used as the destructor of this |
| 526 // class is private. | 669 // class is private. |
| 527 blocking_task_runner_->PostTask( | 670 blocking_task_runner_->PostTask( |
| 528 FROM_HERE, | 671 FROM_HERE, |
| (...skipping 148 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 677 continue; | 820 continue; |
| 678 } | 821 } |
| 679 const std::string& id = GetIdFromPath(new_path); | 822 const std::string& id = GetIdFromPath(new_path); |
| 680 new_path = GetCacheFilePath(util::CanonicalizeResourceId(id)); | 823 new_path = GetCacheFilePath(util::CanonicalizeResourceId(id)); |
| 681 if (new_path != current && !base::Move(current, new_path)) | 824 if (new_path != current && !base::Move(current, new_path)) |
| 682 return false; | 825 return false; |
| 683 } | 826 } |
| 684 return true; | 827 return true; |
| 685 } | 828 } |
| 686 | 829 |
| 687 // static | 830 bool FileCache::MigrateCacheFiles() { |
| 688 bool FileCache::MigrateCacheFiles(const base::FilePath& from, | |
| 689 const base::FilePath& to_files, | |
| 690 const base::FilePath& to_links, | |
| 691 ResourceMetadataStorage* metadata_storage) { | |
| 692 std::unique_ptr<ResourceMetadataStorage::Iterator> it = | 831 std::unique_ptr<ResourceMetadataStorage::Iterator> it = |
| 693 metadata_storage->GetIterator(); | 832 storage_->GetIterator(); |
| 833 | |
| 694 for (; !it->IsAtEnd(); it->Advance()) { | 834 for (; !it->IsAtEnd(); it->Advance()) { |
| 695 const ResourceEntry& entry = it->GetValue(); | 835 const ResourceEntry& entry = it->GetValue(); |
| 696 if (!entry.file_specific_info().cache_state().is_present()) { | 836 if (!entry.file_specific_info().cache_state().is_present()) { |
| 697 continue; | 837 continue; |
| 698 } | 838 } |
| 699 | 839 |
| 700 // Ignore missing cache file case since it never succeeds. | 840 const base::FilePath filepath = GetPathForId(cache_file_directory_, |
| 701 // TODO(yawano): handle this case at metadata validation in FileCache. | 841 entry.local_id()); |
| 702 const base::FilePath move_from = GetPathForId(from, entry.local_id()); | 842 |
| 703 if (!base::PathExists(move_from)) { | 843 if (!base::PathExists(filepath)) { |
| 844 PLOG(WARNING) << "Cache and metadata are inconsistent."; | |
|
hashimoto
2016/05/02 08:29:19
It's strange to abort the initialization with a wa
oka
2016/05/09 14:27:39
Merged two funcs, and removed this warning.
| |
| 845 return false; | |
| 846 } | |
| 847 | |
| 848 const FileCacheEntry& file_cache_entry = | |
| 849 entry.file_specific_info().cache_state(); | |
| 850 if (file_cache_entry.is_pinned() || file_cache_entry.is_dirty()) { | |
| 851 if (!UnsetRemovable(filepath)) return false; | |
| 852 } else { | |
| 853 if (!SetRemovable(filepath)) return false; | |
| 854 } | |
| 855 } | |
| 856 | |
| 857 return MarkAsDriveCacheDir(cache_file_directory_); | |
| 858 } | |
| 859 | |
| 860 bool FileCache::ResolveMetadataInconsistency() { | |
| 861 std::unique_ptr<ResourceMetadataStorage::Iterator> | |
| 862 it = storage_->GetIterator(); | |
| 863 for (; !it->IsAtEnd(); it->Advance()) { | |
| 864 ResourceEntry entry = it->GetValue(); | |
| 865 | |
| 866 if (!entry.file_specific_info().has_cache_state() || | |
| 867 !entry.file_specific_info().cache_state().is_present()) { | |
|
hashimoto
2016/05/02 08:29:20
Shouldn't we handle a case where !is_present but t
oka
2016/05/09 14:27:40
Done.
I merged ResolveMetadataInconsistency and Mi
| |
| 704 continue; | 868 continue; |
| 705 } | 869 } |
| 706 | 870 |
| 707 // Create hard link to cache file if it's pinned or dirty. cryptohome will | 871 if (base::PathExists(GetCacheFilePath(entry.local_id()))) { |
| 708 // not delete a cache file if there is a hard link to it. | 872 continue; |
| 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 } | 873 } |
| 719 | 874 |
| 720 // Move cache file. | 875 entry.mutable_file_specific_info()->mutable_cache_state()->set_is_present( |
| 721 const base::FilePath move_to = GetPathForId(to_files, entry.local_id()); | 876 false); |
| 722 if (!base::Move(move_from, move_to)) { | 877 |
| 878 if (storage_->PutEntry(entry) != FILE_ERROR_OK) | |
| 723 return false; | 879 return false; |
| 724 } | |
| 725 } | 880 } |
| 726 | |
| 727 return true; | 881 return true; |
| 728 } | 882 } |
| 729 | 883 |
| 730 void FileCache::CloseForWrite(const std::string& id) { | 884 void FileCache::CloseForWrite(const std::string& id) { |
| 731 AssertOnSequencedWorkerPool(); | 885 AssertOnSequencedWorkerPool(); |
| 732 | 886 |
| 733 std::map<std::string, int>::iterator it = write_opened_files_.find(id); | 887 std::map<std::string, int>::iterator it = write_opened_files_.find(id); |
| 734 if (it == write_opened_files_.end()) | 888 if (it == write_opened_files_.end()) |
| 735 return; | 889 return; |
| 736 | 890 |
| (...skipping 21 matching lines...) Expand all Loading... | |
| 758 | 912 |
| 759 bool FileCache::IsEvictable(const std::string& id, const ResourceEntry& entry) { | 913 bool FileCache::IsEvictable(const std::string& id, const ResourceEntry& entry) { |
| 760 return entry.file_specific_info().has_cache_state() && | 914 return entry.file_specific_info().has_cache_state() && |
| 761 !entry.file_specific_info().cache_state().is_pinned() && | 915 !entry.file_specific_info().cache_state().is_pinned() && |
| 762 !entry.file_specific_info().cache_state().is_dirty() && | 916 !entry.file_specific_info().cache_state().is_dirty() && |
| 763 !mounted_files_.count(id); | 917 !mounted_files_.count(id); |
| 764 } | 918 } |
| 765 | 919 |
| 766 } // namespace internal | 920 } // namespace internal |
| 767 } // namespace drive | 921 } // namespace drive |
| OLD | NEW |