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 "chrome/browser/safe_browsing/safe_browsing_store_file.h" | 5 #include "chrome/browser/safe_browsing/safe_browsing_store_file.h" |
6 | 6 |
7 #include "base/files/file_util.h" | 7 #include "base/files/file_util.h" |
8 #include "base/files/scoped_file.h" | 8 #include "base/files/scoped_file.h" |
9 #include "base/md5.h" | 9 #include "base/md5.h" |
10 #include "base/metrics/histogram.h" | 10 #include "base/metrics/histogram.h" |
(...skipping 540 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
551 | 551 |
552 return static_cast<int64>(ftell(file.get())) == size; | 552 return static_cast<int64>(ftell(file.get())) == size; |
553 } | 553 } |
554 | 554 |
555 } // namespace | 555 } // namespace |
556 | 556 |
557 SafeBrowsingStoreFile::SafeBrowsingStoreFile() | 557 SafeBrowsingStoreFile::SafeBrowsingStoreFile() |
558 : chunks_written_(0), empty_(false), corruption_seen_(false) {} | 558 : chunks_written_(0), empty_(false), corruption_seen_(false) {} |
559 | 559 |
560 SafeBrowsingStoreFile::~SafeBrowsingStoreFile() { | 560 SafeBrowsingStoreFile::~SafeBrowsingStoreFile() { |
| 561 DCHECK(CalledOnValidThread()); |
561 Close(); | 562 Close(); |
562 } | 563 } |
563 | 564 |
564 bool SafeBrowsingStoreFile::Delete() { | 565 bool SafeBrowsingStoreFile::Delete() { |
| 566 DCHECK(CalledOnValidThread()); |
| 567 |
565 // The database should not be open at this point. But, just in | 568 // The database should not be open at this point. But, just in |
566 // case, close everything before deleting. | 569 // case, close everything before deleting. |
567 if (!Close()) { | 570 if (!Close()) { |
568 NOTREACHED(); | 571 NOTREACHED(); |
569 return false; | 572 return false; |
570 } | 573 } |
571 | 574 |
572 return DeleteStore(filename_); | 575 return DeleteStore(filename_); |
573 } | 576 } |
574 | 577 |
575 bool SafeBrowsingStoreFile::CheckValidity() { | 578 bool SafeBrowsingStoreFile::CheckValidity() { |
| 579 DCHECK(CalledOnValidThread()); |
| 580 |
576 // The file was either empty or never opened. The empty case is | 581 // The file was either empty or never opened. The empty case is |
577 // presumed not to be invalid. The never-opened case can happen if | 582 // presumed not to be invalid. The never-opened case can happen if |
578 // BeginUpdate() fails for any databases, and should already have | 583 // BeginUpdate() fails for any databases, and should already have |
579 // caused the corruption callback to fire. | 584 // caused the corruption callback to fire. |
580 if (!file_.get()) | 585 if (!file_.get()) |
581 return true; | 586 return true; |
582 | 587 |
583 if (!FileRewind(file_.get())) | 588 if (!FileRewind(file_.get())) |
584 return OnCorruptDatabase(); | 589 return OnCorruptDatabase(); |
585 | 590 |
(...skipping 27 matching lines...) Expand all Loading... |
613 if (!ReadAndVerifyChecksum(file_.get(), &context)) { | 618 if (!ReadAndVerifyChecksum(file_.get(), &context)) { |
614 RecordFormatEvent(FORMAT_EVENT_VALIDITY_CHECKSUM_FAILURE); | 619 RecordFormatEvent(FORMAT_EVENT_VALIDITY_CHECKSUM_FAILURE); |
615 return OnCorruptDatabase(); | 620 return OnCorruptDatabase(); |
616 } | 621 } |
617 | 622 |
618 return true; | 623 return true; |
619 } | 624 } |
620 | 625 |
621 void SafeBrowsingStoreFile::Init(const base::FilePath& filename, | 626 void SafeBrowsingStoreFile::Init(const base::FilePath& filename, |
622 const base::Closure& corruption_callback) { | 627 const base::Closure& corruption_callback) { |
| 628 DCHECK(CalledOnValidThread()); |
623 filename_ = filename; | 629 filename_ = filename; |
624 corruption_callback_ = corruption_callback; | 630 corruption_callback_ = corruption_callback; |
625 } | 631 } |
626 | 632 |
627 bool SafeBrowsingStoreFile::BeginChunk() { | 633 bool SafeBrowsingStoreFile::BeginChunk() { |
| 634 DCHECK(CalledOnValidThread()); |
628 return ClearChunkBuffers(); | 635 return ClearChunkBuffers(); |
629 } | 636 } |
630 | 637 |
631 bool SafeBrowsingStoreFile::WriteAddPrefix(int32 chunk_id, SBPrefix prefix) { | 638 bool SafeBrowsingStoreFile::WriteAddPrefix(int32 chunk_id, SBPrefix prefix) { |
| 639 DCHECK(CalledOnValidThread()); |
632 add_prefixes_.push_back(SBAddPrefix(chunk_id, prefix)); | 640 add_prefixes_.push_back(SBAddPrefix(chunk_id, prefix)); |
633 return true; | 641 return true; |
634 } | 642 } |
635 | 643 |
636 bool SafeBrowsingStoreFile::GetAddPrefixes(SBAddPrefixes* add_prefixes) { | 644 bool SafeBrowsingStoreFile::GetAddPrefixes(SBAddPrefixes* add_prefixes) { |
| 645 DCHECK(CalledOnValidThread()); |
| 646 |
637 add_prefixes->clear(); | 647 add_prefixes->clear(); |
638 if (!base::PathExists(filename_)) | 648 if (!base::PathExists(filename_)) |
639 return true; | 649 return true; |
640 | 650 |
641 StateInternal db_state; | 651 StateInternal db_state; |
642 if (!ReadDbStateHelper(filename_, &db_state)) | 652 if (!ReadDbStateHelper(filename_, &db_state)) |
643 return OnCorruptDatabase(); | 653 return OnCorruptDatabase(); |
644 | 654 |
645 add_prefixes->swap(db_state.add_prefixes_); | 655 add_prefixes->swap(db_state.add_prefixes_); |
646 return true; | 656 return true; |
647 } | 657 } |
648 | 658 |
649 bool SafeBrowsingStoreFile::GetAddFullHashes( | 659 bool SafeBrowsingStoreFile::GetAddFullHashes( |
650 std::vector<SBAddFullHash>* add_full_hashes) { | 660 std::vector<SBAddFullHash>* add_full_hashes) { |
| 661 DCHECK(CalledOnValidThread()); |
| 662 |
651 add_full_hashes->clear(); | 663 add_full_hashes->clear(); |
652 if (!base::PathExists(filename_)) | 664 if (!base::PathExists(filename_)) |
653 return true; | 665 return true; |
654 | 666 |
655 StateInternal db_state; | 667 StateInternal db_state; |
656 if (!ReadDbStateHelper(filename_, &db_state)) | 668 if (!ReadDbStateHelper(filename_, &db_state)) |
657 return OnCorruptDatabase(); | 669 return OnCorruptDatabase(); |
658 | 670 |
659 add_full_hashes->swap(db_state.add_full_hashes_); | 671 add_full_hashes->swap(db_state.add_full_hashes_); |
660 return true; | 672 return true; |
661 } | 673 } |
662 | 674 |
663 bool SafeBrowsingStoreFile::WriteAddHash(int32 chunk_id, | 675 bool SafeBrowsingStoreFile::WriteAddHash(int32 chunk_id, |
664 const SBFullHash& full_hash) { | 676 const SBFullHash& full_hash) { |
| 677 DCHECK(CalledOnValidThread()); |
665 add_hashes_.push_back(SBAddFullHash(chunk_id, full_hash)); | 678 add_hashes_.push_back(SBAddFullHash(chunk_id, full_hash)); |
666 return true; | 679 return true; |
667 } | 680 } |
668 | 681 |
669 bool SafeBrowsingStoreFile::WriteSubPrefix(int32 chunk_id, | 682 bool SafeBrowsingStoreFile::WriteSubPrefix(int32 chunk_id, |
670 int32 add_chunk_id, | 683 int32 add_chunk_id, |
671 SBPrefix prefix) { | 684 SBPrefix prefix) { |
| 685 DCHECK(CalledOnValidThread()); |
672 sub_prefixes_.push_back(SBSubPrefix(chunk_id, add_chunk_id, prefix)); | 686 sub_prefixes_.push_back(SBSubPrefix(chunk_id, add_chunk_id, prefix)); |
673 return true; | 687 return true; |
674 } | 688 } |
675 | 689 |
676 bool SafeBrowsingStoreFile::WriteSubHash(int32 chunk_id, int32 add_chunk_id, | 690 bool SafeBrowsingStoreFile::WriteSubHash(int32 chunk_id, int32 add_chunk_id, |
677 const SBFullHash& full_hash) { | 691 const SBFullHash& full_hash) { |
| 692 DCHECK(CalledOnValidThread()); |
678 sub_hashes_.push_back(SBSubFullHash(chunk_id, add_chunk_id, full_hash)); | 693 sub_hashes_.push_back(SBSubFullHash(chunk_id, add_chunk_id, full_hash)); |
679 return true; | 694 return true; |
680 } | 695 } |
681 | 696 |
682 bool SafeBrowsingStoreFile::OnCorruptDatabase() { | 697 bool SafeBrowsingStoreFile::OnCorruptDatabase() { |
| 698 DCHECK(CalledOnValidThread()); |
| 699 |
683 if (!corruption_seen_) | 700 if (!corruption_seen_) |
684 RecordFormatEvent(FORMAT_EVENT_FILE_CORRUPT); | 701 RecordFormatEvent(FORMAT_EVENT_FILE_CORRUPT); |
685 corruption_seen_ = true; | 702 corruption_seen_ = true; |
686 | 703 |
687 corruption_callback_.Run(); | 704 corruption_callback_.Run(); |
688 | 705 |
689 // Return false as a convenience to callers. | 706 // Return false as a convenience to callers. |
690 return false; | 707 return false; |
691 } | 708 } |
692 | 709 |
693 bool SafeBrowsingStoreFile::Close() { | 710 bool SafeBrowsingStoreFile::Close() { |
| 711 DCHECK(CalledOnValidThread()); |
| 712 |
694 ClearUpdateBuffers(); | 713 ClearUpdateBuffers(); |
695 | 714 |
696 // Make sure the files are closed. | 715 // Make sure the files are closed. |
697 file_.reset(); | 716 file_.reset(); |
698 new_file_.reset(); | 717 new_file_.reset(); |
699 return true; | 718 return true; |
700 } | 719 } |
701 | 720 |
702 bool SafeBrowsingStoreFile::BeginUpdate() { | 721 bool SafeBrowsingStoreFile::BeginUpdate() { |
| 722 DCHECK(CalledOnValidThread()); |
703 DCHECK(!file_.get() && !new_file_.get()); | 723 DCHECK(!file_.get() && !new_file_.get()); |
704 | 724 |
705 // Structures should all be clear unless something bad happened. | 725 // Structures should all be clear unless something bad happened. |
706 DCHECK(add_chunks_cache_.empty()); | 726 DCHECK(add_chunks_cache_.empty()); |
707 DCHECK(sub_chunks_cache_.empty()); | 727 DCHECK(sub_chunks_cache_.empty()); |
708 DCHECK(add_del_cache_.empty()); | 728 DCHECK(add_del_cache_.empty()); |
709 DCHECK(sub_del_cache_.empty()); | 729 DCHECK(sub_del_cache_.empty()); |
710 DCHECK(add_prefixes_.empty()); | 730 DCHECK(add_prefixes_.empty()); |
711 DCHECK(sub_prefixes_.empty()); | 731 DCHECK(sub_prefixes_.empty()); |
712 DCHECK(add_hashes_.empty()); | 732 DCHECK(add_hashes_.empty()); |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
754 | 774 |
755 return OnCorruptDatabase(); | 775 return OnCorruptDatabase(); |
756 } | 776 } |
757 | 777 |
758 file_.swap(file); | 778 file_.swap(file); |
759 new_file_.swap(new_file); | 779 new_file_.swap(new_file); |
760 return true; | 780 return true; |
761 } | 781 } |
762 | 782 |
763 bool SafeBrowsingStoreFile::FinishChunk() { | 783 bool SafeBrowsingStoreFile::FinishChunk() { |
| 784 DCHECK(CalledOnValidThread()); |
| 785 |
764 if (!add_prefixes_.size() && !sub_prefixes_.size() && | 786 if (!add_prefixes_.size() && !sub_prefixes_.size() && |
765 !add_hashes_.size() && !sub_hashes_.size()) | 787 !add_hashes_.size() && !sub_hashes_.size()) |
766 return true; | 788 return true; |
767 | 789 |
768 ChunkHeader header; | 790 ChunkHeader header; |
769 header.add_prefix_count = add_prefixes_.size(); | 791 header.add_prefix_count = add_prefixes_.size(); |
770 header.sub_prefix_count = sub_prefixes_.size(); | 792 header.sub_prefix_count = sub_prefixes_.size(); |
771 header.add_hash_count = add_hashes_.size(); | 793 header.add_hash_count = add_hashes_.size(); |
772 header.sub_hash_count = sub_hashes_.size(); | 794 header.sub_hash_count = sub_hashes_.size(); |
773 if (!WriteItem(header, new_file_.get(), NULL)) | 795 if (!WriteItem(header, new_file_.get(), NULL)) |
774 return false; | 796 return false; |
775 | 797 |
776 if (!WriteContainer(add_prefixes_, new_file_.get(), NULL) || | 798 if (!WriteContainer(add_prefixes_, new_file_.get(), NULL) || |
777 !WriteContainer(sub_prefixes_, new_file_.get(), NULL) || | 799 !WriteContainer(sub_prefixes_, new_file_.get(), NULL) || |
778 !WriteContainer(add_hashes_, new_file_.get(), NULL) || | 800 !WriteContainer(add_hashes_, new_file_.get(), NULL) || |
779 !WriteContainer(sub_hashes_, new_file_.get(), NULL)) | 801 !WriteContainer(sub_hashes_, new_file_.get(), NULL)) |
780 return false; | 802 return false; |
781 | 803 |
782 ++chunks_written_; | 804 ++chunks_written_; |
783 | 805 |
784 // Clear everything to save memory. | 806 // Clear everything to save memory. |
785 return ClearChunkBuffers(); | 807 return ClearChunkBuffers(); |
786 } | 808 } |
787 | 809 |
788 bool SafeBrowsingStoreFile::DoUpdate( | 810 bool SafeBrowsingStoreFile::DoUpdate( |
789 safe_browsing::PrefixSetBuilder* builder, | 811 safe_browsing::PrefixSetBuilder* builder, |
790 std::vector<SBAddFullHash>* add_full_hashes_result) { | 812 std::vector<SBAddFullHash>* add_full_hashes_result) { |
| 813 DCHECK(CalledOnValidThread()); |
791 DCHECK(file_.get() || empty_); | 814 DCHECK(file_.get() || empty_); |
792 DCHECK(new_file_.get()); | 815 DCHECK(new_file_.get()); |
793 CHECK(builder); | 816 CHECK(builder); |
794 CHECK(add_full_hashes_result); | 817 CHECK(add_full_hashes_result); |
795 | 818 |
796 // Rewind the temporary storage. | 819 // Rewind the temporary storage. |
797 if (!FileRewind(new_file_.get())) | 820 if (!FileRewind(new_file_.get())) |
798 return false; | 821 return false; |
799 | 822 |
800 // Get chunk file's size for validating counts. | 823 // Get chunk file's size for validating counts. |
(...skipping 227 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1028 // Record counts before swapping to caller. | 1051 // Record counts before swapping to caller. |
1029 UMA_HISTOGRAM_COUNTS("SB2.AddPrefixes", add_prefix_count); | 1052 UMA_HISTOGRAM_COUNTS("SB2.AddPrefixes", add_prefix_count); |
1030 UMA_HISTOGRAM_COUNTS("SB2.SubPrefixes", sub_prefix_count); | 1053 UMA_HISTOGRAM_COUNTS("SB2.SubPrefixes", sub_prefix_count); |
1031 | 1054 |
1032 return true; | 1055 return true; |
1033 } | 1056 } |
1034 | 1057 |
1035 bool SafeBrowsingStoreFile::FinishUpdate( | 1058 bool SafeBrowsingStoreFile::FinishUpdate( |
1036 safe_browsing::PrefixSetBuilder* builder, | 1059 safe_browsing::PrefixSetBuilder* builder, |
1037 std::vector<SBAddFullHash>* add_full_hashes_result) { | 1060 std::vector<SBAddFullHash>* add_full_hashes_result) { |
| 1061 DCHECK(CalledOnValidThread()); |
1038 DCHECK(builder); | 1062 DCHECK(builder); |
1039 DCHECK(add_full_hashes_result); | 1063 DCHECK(add_full_hashes_result); |
1040 | 1064 |
1041 if (!DoUpdate(builder, add_full_hashes_result)) { | 1065 if (!DoUpdate(builder, add_full_hashes_result)) { |
1042 CancelUpdate(); | 1066 CancelUpdate(); |
1043 return false; | 1067 return false; |
1044 } | 1068 } |
1045 | 1069 |
1046 DCHECK(!new_file_.get()); | 1070 DCHECK(!new_file_.get()); |
1047 DCHECK(!file_.get()); | 1071 DCHECK(!file_.get()); |
1048 | 1072 |
1049 return Close(); | 1073 return Close(); |
1050 } | 1074 } |
1051 | 1075 |
1052 bool SafeBrowsingStoreFile::CancelUpdate() { | 1076 bool SafeBrowsingStoreFile::CancelUpdate() { |
| 1077 DCHECK(CalledOnValidThread()); |
1053 bool ret = Close(); | 1078 bool ret = Close(); |
1054 | 1079 |
1055 // Delete stale staging file. | 1080 // Delete stale staging file. |
1056 const base::FilePath new_filename = TemporaryFileForFilename(filename_); | 1081 const base::FilePath new_filename = TemporaryFileForFilename(filename_); |
1057 base::DeleteFile(new_filename, false); | 1082 base::DeleteFile(new_filename, false); |
1058 | 1083 |
1059 return ret; | 1084 return ret; |
1060 } | 1085 } |
1061 | 1086 |
1062 void SafeBrowsingStoreFile::SetAddChunk(int32 chunk_id) { | 1087 void SafeBrowsingStoreFile::SetAddChunk(int32 chunk_id) { |
| 1088 DCHECK(CalledOnValidThread()); |
1063 add_chunks_cache_.insert(chunk_id); | 1089 add_chunks_cache_.insert(chunk_id); |
1064 } | 1090 } |
1065 | 1091 |
1066 bool SafeBrowsingStoreFile::CheckAddChunk(int32 chunk_id) { | 1092 bool SafeBrowsingStoreFile::CheckAddChunk(int32 chunk_id) { |
| 1093 DCHECK(CalledOnValidThread()); |
1067 return add_chunks_cache_.count(chunk_id) > 0; | 1094 return add_chunks_cache_.count(chunk_id) > 0; |
1068 } | 1095 } |
1069 | 1096 |
1070 void SafeBrowsingStoreFile::GetAddChunks(std::vector<int32>* out) { | 1097 void SafeBrowsingStoreFile::GetAddChunks(std::vector<int32>* out) { |
| 1098 DCHECK(CalledOnValidThread()); |
1071 out->clear(); | 1099 out->clear(); |
1072 out->insert(out->end(), add_chunks_cache_.begin(), add_chunks_cache_.end()); | 1100 out->insert(out->end(), add_chunks_cache_.begin(), add_chunks_cache_.end()); |
1073 } | 1101 } |
1074 | 1102 |
1075 void SafeBrowsingStoreFile::SetSubChunk(int32 chunk_id) { | 1103 void SafeBrowsingStoreFile::SetSubChunk(int32 chunk_id) { |
| 1104 DCHECK(CalledOnValidThread()); |
1076 sub_chunks_cache_.insert(chunk_id); | 1105 sub_chunks_cache_.insert(chunk_id); |
1077 } | 1106 } |
1078 | 1107 |
1079 bool SafeBrowsingStoreFile::CheckSubChunk(int32 chunk_id) { | 1108 bool SafeBrowsingStoreFile::CheckSubChunk(int32 chunk_id) { |
| 1109 DCHECK(CalledOnValidThread()); |
1080 return sub_chunks_cache_.count(chunk_id) > 0; | 1110 return sub_chunks_cache_.count(chunk_id) > 0; |
1081 } | 1111 } |
1082 | 1112 |
1083 void SafeBrowsingStoreFile::GetSubChunks(std::vector<int32>* out) { | 1113 void SafeBrowsingStoreFile::GetSubChunks(std::vector<int32>* out) { |
| 1114 DCHECK(CalledOnValidThread()); |
1084 out->clear(); | 1115 out->clear(); |
1085 out->insert(out->end(), sub_chunks_cache_.begin(), sub_chunks_cache_.end()); | 1116 out->insert(out->end(), sub_chunks_cache_.begin(), sub_chunks_cache_.end()); |
1086 } | 1117 } |
1087 | 1118 |
1088 void SafeBrowsingStoreFile::DeleteAddChunk(int32 chunk_id) { | 1119 void SafeBrowsingStoreFile::DeleteAddChunk(int32 chunk_id) { |
| 1120 DCHECK(CalledOnValidThread()); |
1089 add_del_cache_.insert(chunk_id); | 1121 add_del_cache_.insert(chunk_id); |
1090 } | 1122 } |
1091 | 1123 |
1092 void SafeBrowsingStoreFile::DeleteSubChunk(int32 chunk_id) { | 1124 void SafeBrowsingStoreFile::DeleteSubChunk(int32 chunk_id) { |
| 1125 DCHECK(CalledOnValidThread()); |
1093 sub_del_cache_.insert(chunk_id); | 1126 sub_del_cache_.insert(chunk_id); |
1094 } | 1127 } |
1095 | 1128 |
1096 // static | 1129 // static |
1097 bool SafeBrowsingStoreFile::DeleteStore(const base::FilePath& basename) { | 1130 bool SafeBrowsingStoreFile::DeleteStore(const base::FilePath& basename) { |
1098 if (!base::DeleteFile(basename, false) && | 1131 if (!base::DeleteFile(basename, false) && |
1099 base::PathExists(basename)) { | 1132 base::PathExists(basename)) { |
1100 NOTREACHED(); | 1133 NOTREACHED(); |
1101 return false; | 1134 return false; |
1102 } | 1135 } |
1103 | 1136 |
1104 const base::FilePath new_filename = TemporaryFileForFilename(basename); | 1137 const base::FilePath new_filename = TemporaryFileForFilename(basename); |
1105 if (!base::DeleteFile(new_filename, false) && | 1138 if (!base::DeleteFile(new_filename, false) && |
1106 base::PathExists(new_filename)) { | 1139 base::PathExists(new_filename)) { |
1107 NOTREACHED(); | 1140 NOTREACHED(); |
1108 return false; | 1141 return false; |
1109 } | 1142 } |
1110 | 1143 |
1111 // With SQLite support gone, one way to get to this code is if the | 1144 // With SQLite support gone, one way to get to this code is if the |
1112 // existing file is a SQLite file. Make sure the journal file is | 1145 // existing file is a SQLite file. Make sure the journal file is |
1113 // also removed. | 1146 // also removed. |
1114 const base::FilePath journal_filename( | 1147 const base::FilePath journal_filename( |
1115 basename.value() + FILE_PATH_LITERAL("-journal")); | 1148 basename.value() + FILE_PATH_LITERAL("-journal")); |
1116 if (base::PathExists(journal_filename)) | 1149 if (base::PathExists(journal_filename)) |
1117 base::DeleteFile(journal_filename, false); | 1150 base::DeleteFile(journal_filename, false); |
1118 | 1151 |
1119 return true; | 1152 return true; |
1120 } | 1153 } |
OLD | NEW |