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