diff options
author | shess@chromium.org <shess@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-02-09 05:42:33 +0000 |
---|---|---|
committer | shess@chromium.org <shess@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-02-09 05:42:33 +0000 |
commit | 5388e2d3221ad13455602b2afb5e6961245c9c85 (patch) | |
tree | 5fc759da9276502057ae278111b29c899ca0d8c6 /chrome | |
parent | a6e9077e9b31c10b339aef3b81a2b550a3e33d23 (diff) | |
download | chromium_src-5388e2d3221ad13455602b2afb5e6961245c9c85.zip chromium_src-5388e2d3221ad13455602b2afb5e6961245c9c85.tar.gz chromium_src-5388e2d3221ad13455602b2afb5e6961245c9c85.tar.bz2 |
Remove SQLite safe-browsing backing store.
In October 2010, 7.0 rolled to stable with the safe-browsing database
configured to read-from-sqlite and write-to-new-file-format. There is
still a long tail of SQLite-format databases in the wild, but very
small (and possibly due to a systemic issue with updating, so it may
not get smaller).
This change flips the switch to no longer support reading the SQLite
files. Those users will do a full re-sync with the safe-browsing
servers.
BUG=58552
TEST=none
Review URL: http://codereview.chromium.org/6413022
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@74253 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome')
11 files changed, 25 insertions, 1374 deletions
diff --git a/chrome/browser/safe_browsing/safe_browsing_database.cc b/chrome/browser/safe_browsing/safe_browsing_database.cc index 16e4c55..1e645ce 100644 --- a/chrome/browser/safe_browsing/safe_browsing_database.cc +++ b/chrome/browser/safe_browsing/safe_browsing_database.cc @@ -13,8 +13,6 @@ #include "base/sha2.h" #include "chrome/browser/safe_browsing/bloom_filter.h" #include "chrome/browser/safe_browsing/safe_browsing_store_file.h" -#include "chrome/browser/safe_browsing/safe_browsing_store_sqlite.h" -#include "chrome/browser/safe_browsing/safe_browsing_util.h" #include "googleurl/src/gurl.h" namespace { @@ -206,11 +204,9 @@ SafeBrowsingDatabaseFactory* SafeBrowsingDatabase::factory_ = NULL; // Factory method, non-thread safe. Caller has to make sure this s called // on SafeBrowsing Thread. -// TODO(shess): Milestone-7 is converting from SQLite-based -// SafeBrowsingDatabaseBloom to the new file format with -// SafeBrowsingDatabaseNew. Once that conversion is too far along to -// consider reversing, circle back and lift SafeBrowsingDatabaseNew up -// to SafeBrowsingDatabase and get rid of the abstract class. +// TODO(shess): There's no need for a factory any longer. Convert +// SafeBrowsingDatabaseNew to SafeBrowsingDatabase, and have Create() +// callers just construct things directly. SafeBrowsingDatabase* SafeBrowsingDatabase::Create( bool enable_download_protection) { if (!factory_) @@ -259,7 +255,7 @@ void SafeBrowsingDatabase::RecordFailure(FailureType failure_type) { SafeBrowsingDatabaseNew::SafeBrowsingDatabaseNew() : creation_loop_(MessageLoop::current()), - browse_store_(new SafeBrowsingStoreSqlite), + browse_store_(new SafeBrowsingStoreFile), download_store_(NULL), ALLOW_THIS_IN_INITIALIZER_LIST(reset_factory_(this)) { DCHECK(browse_store_.get()); diff --git a/chrome/browser/safe_browsing/safe_browsing_database_unittest.cc b/chrome/browser/safe_browsing/safe_browsing_database_unittest.cc index 8b0cb76..8491212 100644 --- a/chrome/browser/safe_browsing/safe_browsing_database_unittest.cc +++ b/chrome/browser/safe_browsing/safe_browsing_database_unittest.cc @@ -14,7 +14,6 @@ #include "base/time.h" #include "chrome/browser/safe_browsing/safe_browsing_database.h" #include "chrome/browser/safe_browsing/safe_browsing_store_file.h" -#include "chrome/browser/safe_browsing/safe_browsing_store_sqlite.h" #include "chrome/browser/safe_browsing/safe_browsing_store_unittest_helper.h" #include "googleurl/src/gurl.h" #include "testing/gtest/include/gtest/gtest.h" @@ -218,57 +217,6 @@ class ScopedLogMessageIgnorer { } }; -// Helper function which corrupts the root page of the indicated -// table. After this the table can be opened successfully, and -// queries to other tables work, and possibly queries to this table -// which only hit an index may work, but queries which hit the table -// itself should not. Returns |true| on success. -bool CorruptSqliteTable(const FilePath& filename, - const std::string& table_name) { - size_t root_page; // Root page of the table. - size_t page_size; // Page size of the database. - - sql::Connection db; - if (!db.Open(filename)) - return false; - - sql::Statement stmt(db.GetUniqueStatement("PRAGMA page_size")); - if (!stmt.Step()) - return false; - page_size = stmt.ColumnInt(0); - - stmt.Assign(db.GetUniqueStatement( - "SELECT rootpage FROM sqlite_master WHERE name = ?")); - stmt.BindString(0, "sub_prefix"); - if (!stmt.Step()) - return false; - root_page = stmt.ColumnInt(0); - - // The page numbers are 1-based. - const size_t root_page_offset = (root_page - 1) * page_size; - - // Corrupt the file by overwriting the table's root page. - FILE* fp = file_util::OpenFile(filename, "r+"); - if (!fp) - return false; - - file_util::ScopedFILE file_closer(fp); - if (fseek(fp, root_page_offset, SEEK_SET) == -1) - return false; - - for (size_t i = 0; i < page_size; ++i) { - fputc('!', fp); // Character experimentally verified. - } - - // Close the file manually because if there is an error in the - // close, it's likely because the data could not be flushed to the - // file. - if (!file_util::CloseFile(file_closer.release())) - return false; - - return true; -} - } // namespace class SafeBrowsingDatabaseTest : public PlatformTest { @@ -1088,84 +1036,6 @@ TEST_F(SafeBrowsingDatabaseTest, HashCaching) { // corruption is detected in the midst of the update. // TODO(shess): Disabled until ScopedLogMessageIgnorer resolved. // http://crbug.com/56448 -TEST_F(SafeBrowsingDatabaseTest, DISABLED_SqliteCorruptionHandling) { - // Re-create the database in a captive message loop so that we can - // influence task-posting. Database specifically needs to the - // SQLite-backed. - database_.reset(); - MessageLoop loop(MessageLoop::TYPE_DEFAULT); - SafeBrowsingStoreSqlite* store = new SafeBrowsingStoreSqlite(); - database_.reset(new SafeBrowsingDatabaseNew(store, NULL)); - database_->Init(database_filename_); - - // This will cause an empty database to be created. - std::vector<SBListChunkRanges> lists; - EXPECT_TRUE(database_->UpdateStarted(&lists)); - database_->UpdateFinished(true); - - // Create a sub chunk to insert. - SBChunkList chunks; - SBChunk chunk; - SBChunkHost host; - host.host = Sha256Prefix("www.subbed.com/"); - host.entry = SBEntry::Create(SBEntry::SUB_PREFIX, 1); - host.entry->set_chunk_id(7); - host.entry->SetChunkIdAtPrefix(0, 19); - host.entry->SetPrefixAt(0, Sha256Prefix("www.subbed.com/notevil1.html")); - chunk.chunk_number = 7; - chunk.is_add = false; - chunk.hosts.clear(); - chunk.hosts.push_back(host); - chunks.clear(); - chunks.push_back(chunk); - - // Corrupt the |sub_prefix| table. - ASSERT_TRUE(CorruptSqliteTable(database_filename_, "sub_prefix")); - - { - // The following code will cause DCHECKs, so suppress the crashes. - ScopedLogMessageIgnorer ignorer; - - // Start an update. The insert will fail due to corruption. - EXPECT_TRUE(database_->UpdateStarted(&lists)); - VLOG(1) << "Expect failed check on: sqlite error 11"; - database_->InsertChunks(safe_browsing_util::kMalwareList, chunks); - - // Database file still exists until the corruption handler has run. - EXPECT_TRUE(file_util::PathExists(database_filename_)); - - // Flush through the corruption-handler task. - VLOG(1) << "Expect failed check on: SafeBrowsing database reset"; - MessageLoop::current()->RunAllPending(); - } - - // Database file should not exist. - EXPECT_FALSE(file_util::PathExists(database_filename_)); - - // Finish the transaction. This should short-circuit, so no - // DCHECKs. - database_->InsertChunks(safe_browsing_util::kMalwareList, chunks); - database_->UpdateFinished(true); - - // Flush through any posted tasks. - MessageLoop::current()->RunAllPending(); - - // Database file should still not exist. - EXPECT_FALSE(file_util::PathExists(database_filename_)); - - // Run the update again successfully. - EXPECT_TRUE(database_->UpdateStarted(&lists)); - database_->InsertChunks(safe_browsing_util::kMalwareList, chunks); - database_->UpdateFinished(true); - EXPECT_TRUE(file_util::PathExists(database_filename_)); - - database_.reset(); -} - -// Test that corrupt databases are appropriately handled, even if the -// corruption is detected in the midst of the update. -// TODO(shess): Disabled until ScopedLogMessageIgnorer resolved. -// http://crbug.com/56448 TEST_F(SafeBrowsingDatabaseTest, DISABLED_FileCorruptionHandling) { // Re-create the database in a captive message loop so that we can // influence task-posting. Database specifically needs to the diff --git a/chrome/browser/safe_browsing/safe_browsing_service.h b/chrome/browser/safe_browsing/safe_browsing_service.h index 85255e5..ec05f5d 100644 --- a/chrome/browser/safe_browsing/safe_browsing_service.h +++ b/chrome/browser/safe_browsing/safe_browsing_service.h @@ -348,8 +348,8 @@ class SafeBrowsingService // Used for issuing only one GetHash request for a given prefix. GetHashRequests gethash_requests_; - // The sqlite database. We don't use a scoped_ptr because it needs to be - // destructed on a different thread than this object. + // The persistent database. We don't use a scoped_ptr because it + // needs to be destructed on a different thread than this object. SafeBrowsingDatabase* database_; // Lock used to prevent possible data races due to compiler optimizations. diff --git a/chrome/browser/safe_browsing/safe_browsing_store_file.cc b/chrome/browser/safe_browsing/safe_browsing_store_file.cc index cc8ae87..5171426 100644 --- a/chrome/browser/safe_browsing/safe_browsing_store_file.cc +++ b/chrome/browser/safe_browsing/safe_browsing_store_file.cc @@ -8,9 +8,6 @@ #include "base/metrics/histogram.h" #include "base/md5.h" -// TODO(shess): Remove after migration. -#include "chrome/browser/safe_browsing/safe_browsing_store_sqlite.h" - namespace { // NOTE(shess): kFileMagic should not be a byte-wise palindrome, so @@ -261,16 +258,13 @@ bool SafeBrowsingStoreFile::Delete() { return false; } - // Also make sure any SQLite data is deleted. This should only be - // needed if a journal file is left from a crash and the database is - // reset before SQLite gets a chance to straighten things out. - // TODO(shess): Remove after migration. - SafeBrowsingStoreSqlite old_store; - old_store.Init( - filename_, - NewCallback(this, &SafeBrowsingStoreFile::HandleCorruptDatabase)); - if (!old_store.Delete()) - return false; + // With SQLite support gone, one way to get to this code is if the + // existing file is a SQLite file. Make sure the journal file is + // also removed. + const FilePath journal_filename( + filename_.value() + FILE_PATH_LITERAL("-journal")); + if (file_util::PathExists(journal_filename)) + file_util::Delete(journal_filename, false); return true; } @@ -344,27 +338,17 @@ bool SafeBrowsingStoreFile::OnCorruptDatabase() { return false; } -void SafeBrowsingStoreFile::HandleCorruptDatabase() { - if (!corruption_seen_) - RecordFormatEvent(FORMAT_EVENT_SQLITE_CORRUPT); - corruption_seen_ = true; - - if (corruption_callback_.get()) - corruption_callback_->Run(); -} - bool SafeBrowsingStoreFile::Close() { ClearUpdateBuffers(); // Make sure the files are closed. file_.reset(); new_file_.reset(); - old_store_.reset(); return true; } bool SafeBrowsingStoreFile::BeginUpdate() { - DCHECK(!file_.get() && !new_file_.get() && !old_store_.get()); + DCHECK(!file_.get() && !new_file_.get()); // Structures should all be clear unless something bad happened. DCHECK(add_chunks_cache_.empty()); @@ -412,32 +396,10 @@ bool SafeBrowsingStoreFile::BeginUpdate() { RecordFormatEvent(FORMAT_EVENT_FOUND_UNKNOWN); } - // Something about having the file open causes a problem with - // SQLite opening it. Perhaps PRAGMA locking_mode = EXCLUSIVE? + // Close the file so that it can be deleted. file.reset(); - // Magic numbers didn't match, maybe it's a SQLite database. - scoped_ptr<SafeBrowsingStoreSqlite> - sqlite_store(new SafeBrowsingStoreSqlite()); - sqlite_store->Init( - filename_, - NewCallback(this, &SafeBrowsingStoreFile::HandleCorruptDatabase)); - if (!sqlite_store->BeginUpdate()) - return OnCorruptDatabase(); - - // Pull chunks-seen data into local structures, rather than - // optionally wiring various calls through to the SQLite store. - std::vector<int32> chunks; - sqlite_store->GetAddChunks(&chunks); - add_chunks_cache_.insert(chunks.begin(), chunks.end()); - - sqlite_store->GetSubChunks(&chunks); - sub_chunks_cache_.insert(chunks.begin(), chunks.end()); - - new_file_.swap(new_file); - old_store_.swap(sqlite_store); - - return true; + return OnCorruptDatabase(); } // TODO(shess): Under POSIX it is possible that this could size a @@ -489,7 +451,7 @@ bool SafeBrowsingStoreFile::DoUpdate( const std::set<SBPrefix>& prefix_misses, std::vector<SBAddPrefix>* add_prefixes_result, std::vector<SBAddFullHash>* add_full_hashes_result) { - DCHECK(old_store_.get() || file_.get() || empty_); + DCHECK(file_.get() || empty_); DCHECK(new_file_.get()); CHECK(add_prefixes_result); CHECK(add_full_hashes_result); @@ -499,29 +461,8 @@ bool SafeBrowsingStoreFile::DoUpdate( std::vector<SBAddFullHash> add_full_hashes; std::vector<SBSubFullHash> sub_full_hashes; - // Read |old_store_| into the vectors. - if (old_store_.get()) { - // Push deletions to |old_store_| so they can be applied to the - // data being read. - for (base::hash_set<int32>::const_iterator iter = add_del_cache_.begin(); - iter != add_del_cache_.end(); ++iter) { - old_store_->DeleteAddChunk(*iter); - } - for (base::hash_set<int32>::const_iterator iter = sub_del_cache_.begin(); - iter != sub_del_cache_.end(); ++iter) { - old_store_->DeleteSubChunk(*iter); - } - - if (!old_store_->ReadAddPrefixes(&add_prefixes) || - !old_store_->ReadSubPrefixes(&sub_prefixes) || - !old_store_->ReadAddHashes(&add_full_hashes) || - !old_store_->ReadSubHashes(&sub_full_hashes)) - return OnCorruptDatabase(); - - // Do not actually update the old store. - if (!old_store_->CancelUpdate()) - return OnCorruptDatabase(); - } else if (!empty_) { + // Read original data into the vectors. + if (!empty_) { DCHECK(file_.get()); if (!FileRewind(file_.get())) @@ -677,19 +618,9 @@ bool SafeBrowsingStoreFile::DoUpdate( // Close the file handle and swizzle the file into place. new_file_.reset(); - if (old_store_.get()) { - const bool deleted = old_store_->Delete(); - old_store_.reset(); - if (!deleted) { - RecordFormatEvent(FORMAT_EVENT_SQLITE_DELETE_FAILED); - return false; - } - RecordFormatEvent(FORMAT_EVENT_SQLITE_DELETED); - } else { - if (!file_util::Delete(filename_, false) && - file_util::PathExists(filename_)) - return false; - } + if (!file_util::Delete(filename_, false) && + file_util::PathExists(filename_)) + return false; const FilePath new_filename = TemporaryFileForFilename(filename_); if (!file_util::Move(new_filename, filename_)) @@ -724,13 +655,11 @@ bool SafeBrowsingStoreFile::FinishUpdate( DCHECK(!new_file_.get()); DCHECK(!file_.get()); - DCHECK(!old_store_.get()); return Close(); } bool SafeBrowsingStoreFile::CancelUpdate() { - old_store_.reset(); return Close(); } diff --git a/chrome/browser/safe_browsing/safe_browsing_store_file.h b/chrome/browser/safe_browsing/safe_browsing_store_file.h index 02a2920..88e1b2f 100644 --- a/chrome/browser/safe_browsing/safe_browsing_store_file.h +++ b/chrome/browser/safe_browsing/safe_browsing_store_file.h @@ -14,12 +14,6 @@ #include "base/callback.h" #include "base/file_util.h" -// TODO(shess): Data is migrated from SafeBrowsingStoreSqlite as part -// of the next update. That way everyone doesn't pull a new database -// when the code rolls out (and the migration code isn't gnarly). -// After substantially everyone has migrated, the migration code can -// be removed. Make sure that it deletes any journal file. - // Implement SafeBrowsingStore in terms of a flat file. The file // format is pretty literal: // @@ -110,9 +104,6 @@ // often, consider retaining the last known-good file for recovery // purposes, rather than deleting it. -// TODO(shess): Remove after migration. -class SafeBrowsingStoreSqlite; - class SafeBrowsingStoreFile : public SafeBrowsingStore { public: SafeBrowsingStoreFile(); @@ -176,7 +167,7 @@ class SafeBrowsingStoreFile : public SafeBrowsingStore { enum FormatEventType { // Corruption detected, broken down by file format. FORMAT_EVENT_FILE_CORRUPT, - FORMAT_EVENT_SQLITE_CORRUPT, + FORMAT_EVENT_SQLITE_CORRUPT, // Obsolete // The type of format found in the file. The expected case (new // file format) is intentionally not covered. @@ -186,8 +177,8 @@ class SafeBrowsingStoreFile : public SafeBrowsingStore { // The number of SQLite-format files deleted should be the same as // FORMAT_EVENT_FOUND_SQLITE. It can differ if the delete fails, // or if a failure prevents the update from succeeding. - FORMAT_EVENT_SQLITE_DELETED, - FORMAT_EVENT_SQLITE_DELETE_FAILED, + FORMAT_EVENT_SQLITE_DELETED, // Obsolete + FORMAT_EVENT_SQLITE_DELETE_FAILED, // Obsolete // Found and deleted (or failed to delete) the ancient "Safe // Browsing" file. @@ -263,11 +254,6 @@ class SafeBrowsingStoreFile : public SafeBrowsingStore { file_util::ScopedFILE new_file_; bool empty_; - // If the main file existed, but was an SQLite store, this is a - // handle to it. - // TODO(shess): Remove this (and all references) after migration. - scoped_ptr<SafeBrowsingStoreSqlite> old_store_; - // Cache of chunks which have been seen. Loaded from the database // on BeginUpdate() so that it can be queried during the // transaction. diff --git a/chrome/browser/safe_browsing/safe_browsing_store_file_unittest.cc b/chrome/browser/safe_browsing/safe_browsing_store_file_unittest.cc index 01977a7..39fe53a 100644 --- a/chrome/browser/safe_browsing/safe_browsing_store_file_unittest.cc +++ b/chrome/browser/safe_browsing/safe_browsing_store_file_unittest.cc @@ -3,7 +3,6 @@ // found in the LICENSE file. #include "chrome/browser/safe_browsing/safe_browsing_store_file.h" -#include "chrome/browser/safe_browsing/safe_browsing_store_sqlite.h" #include "base/callback.h" #include "chrome/browser/safe_browsing/safe_browsing_store_unittest_helper.h" @@ -146,169 +145,4 @@ TEST_F(SafeBrowsingStoreFileTest, DetectsCorruption) { EXPECT_TRUE(corruption_detected_); } -// Info to build a trivial store for migration testing. -const int kAddChunk1 = 1; -const int kAddChunk2 = 3; -const int kAddChunk3 = 5; -const int kSubChunk1 = 2; -const int kSubChunk2 = 4; -const SBFullHash kHash1 = SBFullHashFromString("one"); -const SBFullHash kHash2 = SBFullHashFromString("two"); -const SBPrefix kPrefix1 = kHash1.prefix; -const SBPrefix kPrefix2 = kHash2.prefix; -const SBPrefix kPrefix3 = SBFullHashFromString("three").prefix; -const SBPrefix kPrefix4 = SBFullHashFromString("four").prefix; -const SBPrefix kPrefix5 = SBFullHashFromString("five").prefix; - -// Load the store with some data. -void LoadStore(SafeBrowsingStore* store) { - EXPECT_TRUE(store->BeginUpdate()); - EXPECT_TRUE(store->BeginChunk()); - - store->SetAddChunk(kAddChunk1); - store->SetSubChunk(kSubChunk1); - store->SetAddChunk(kAddChunk2); - - EXPECT_TRUE(store->WriteAddPrefix(kAddChunk1, kPrefix1)); - EXPECT_TRUE(store->WriteAddPrefix(kAddChunk1, kPrefix2)); - EXPECT_TRUE(store->WriteAddPrefix(kAddChunk2, kPrefix3)); - EXPECT_TRUE(store->WriteSubPrefix(kSubChunk1, kAddChunk3, kPrefix4)); - EXPECT_TRUE(store->WriteAddHash(kAddChunk1, base::Time::Now(), kHash1)); - EXPECT_TRUE(store->WriteSubHash(kSubChunk1, kAddChunk1, kHash2)); - - EXPECT_TRUE(store->FinishChunk()); - - std::vector<SBAddFullHash> pending_adds; - std::set<SBPrefix> prefix_misses; - std::vector<SBAddPrefix> add_prefixes; - std::vector<SBAddFullHash> add_hashes; - EXPECT_TRUE(store->FinishUpdate(pending_adds, prefix_misses, - &add_prefixes, &add_hashes)); - EXPECT_EQ(3U, add_prefixes.size()); - EXPECT_EQ(1U, add_hashes.size()); - - // Make sure add prefixes are correct. - std::vector<SBAddPrefix> in_store_add_prefixes; - EXPECT_TRUE(store->GetAddPrefixes(&in_store_add_prefixes)); - ASSERT_EQ(3U, in_store_add_prefixes.size()); - EXPECT_EQ(kPrefix1, in_store_add_prefixes[0].prefix); - EXPECT_EQ(kAddChunk1, in_store_add_prefixes[0].chunk_id); - EXPECT_EQ(kPrefix2, in_store_add_prefixes[1].prefix); - EXPECT_EQ(kAddChunk1, in_store_add_prefixes[1].chunk_id); - EXPECT_EQ(kPrefix3, in_store_add_prefixes[2].prefix); - EXPECT_EQ(kAddChunk2, in_store_add_prefixes[2].chunk_id); -} - -// Verify that the store looks like what results from LoadStore(), and -// update it. -void UpdateStore(SafeBrowsingStore* store) { - EXPECT_TRUE(store->BeginUpdate()); - EXPECT_TRUE(store->BeginChunk()); - - // The chunks in the database should be the same. - std::vector<int> add_chunks; - store->GetAddChunks(&add_chunks); - ASSERT_EQ(2U, add_chunks.size()); - EXPECT_EQ(kAddChunk1, add_chunks[0]); - EXPECT_EQ(kAddChunk2, add_chunks[1]); - - std::vector<int> sub_chunks; - store->GetSubChunks(&sub_chunks); - ASSERT_EQ(1U, sub_chunks.size()); - EXPECT_EQ(kSubChunk1, sub_chunks[0]); - - EXPECT_TRUE(store->CheckAddChunk(kAddChunk1)); - EXPECT_TRUE(store->CheckSubChunk(kSubChunk1)); - EXPECT_TRUE(store->CheckAddChunk(kAddChunk2)); - - EXPECT_FALSE(store->CheckAddChunk(kAddChunk3)); - store->SetAddChunk(kAddChunk3); - // This one already has a sub. - EXPECT_TRUE(store->WriteAddPrefix(kAddChunk3, kPrefix4)); - EXPECT_TRUE(store->WriteAddPrefix(kAddChunk3, kPrefix5)); - - EXPECT_FALSE(store->CheckSubChunk(kSubChunk2)); - store->SetSubChunk(kSubChunk2); - EXPECT_TRUE(store->WriteSubPrefix(kSubChunk2, kAddChunk1, kPrefix1)); - - EXPECT_TRUE(store->FinishChunk()); - - store->DeleteAddChunk(kAddChunk2); - - std::vector<SBAddFullHash> pending_adds; - std::set<SBPrefix> prefix_misses; - std::vector<SBAddPrefix> add_prefixes; - std::vector<SBAddFullHash> add_hashes; - EXPECT_TRUE(store->FinishUpdate(pending_adds, prefix_misses, - &add_prefixes, &add_hashes)); - EXPECT_EQ(2U, add_prefixes.size()); - EXPECT_EQ(0U, add_hashes.size()); -} - -// Verify that the expected UpdateStore() data is present. -void CheckStore(SafeBrowsingStore* store) { - EXPECT_TRUE(store->BeginUpdate()); - - // The chunks in the database should be the same. - std::vector<int> add_chunks; - store->GetAddChunks(&add_chunks); - ASSERT_EQ(2U, add_chunks.size()); - EXPECT_EQ(kAddChunk1, add_chunks[0]); - EXPECT_EQ(kAddChunk3, add_chunks[1]); - - std::vector<int> sub_chunks; - store->GetSubChunks(&sub_chunks); - ASSERT_EQ(2U, sub_chunks.size()); - EXPECT_EQ(kSubChunk1, sub_chunks[0]); - EXPECT_EQ(kSubChunk2, sub_chunks[1]); - - EXPECT_TRUE(store->CancelUpdate()); - - // Make sure add prefixes are correct. - std::vector<SBAddPrefix> add_prefixes; - EXPECT_TRUE(store->GetAddPrefixes(&add_prefixes)); - ASSERT_EQ(2U, add_prefixes.size()); - EXPECT_EQ(kPrefix2, add_prefixes[0].prefix); - EXPECT_EQ(kAddChunk1, add_prefixes[0].chunk_id); - EXPECT_EQ(kPrefix5, add_prefixes[1].prefix); - EXPECT_EQ(kAddChunk3, add_prefixes[1].chunk_id); -} - -// Verify that the migration sequence works as expected in the -// non-migration cases. -TEST_F(SafeBrowsingStoreFileTest, MigrateBaselineFile) { - LoadStore(store_.get()); - UpdateStore(store_.get()); - CheckStore(store_.get()); -} -TEST_F(SafeBrowsingStoreFileTest, MigrateBaselineSqlite) { - SafeBrowsingStoreSqlite sqlite_store; - sqlite_store.Init(filename_, NULL); - - LoadStore(&sqlite_store); - UpdateStore(&sqlite_store); - CheckStore(&sqlite_store); -} - -// The sequence should work exactly the same when we migrate from -// SQLite to file. -TEST_F(SafeBrowsingStoreFileTest, Migrate) { - // No existing store. - EXPECT_FALSE(file_util::PathExists(filename_)); - - { - SafeBrowsingStoreSqlite sqlite_store; - sqlite_store.Init(filename_, NULL); - - LoadStore(&sqlite_store); - } - - // At this point |filename_| references a SQLite store. - EXPECT_TRUE(file_util::PathExists(filename_)); - - // Update and check using a file store. - UpdateStore(store_.get()); - CheckStore(store_.get()); -} - } // namespace diff --git a/chrome/browser/safe_browsing/safe_browsing_store_sqlite.cc b/chrome/browser/safe_browsing/safe_browsing_store_sqlite.cc deleted file mode 100644 index c9cf026..0000000 --- a/chrome/browser/safe_browsing/safe_browsing_store_sqlite.cc +++ /dev/null @@ -1,749 +0,0 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/browser/safe_browsing/safe_browsing_store_sqlite.h" - -#include <string> - -#include "base/callback.h" -#include "base/file_util.h" -#include "base/metrics/histogram.h" -#include "base/string_util.h" -#include "base/utf_string_conversions.h" -#include "chrome/common/sqlite_compiled_statement.h" -#include "chrome/common/sqlite_utils.h" - -namespace { - -// Database version. If this is different than what's stored on disk, the -// database is reset. -const int kDatabaseVersion = 6; - -// Used for reading full hashes from the database. -SBFullHash ReadFullHash(SqliteCompiledStatement* statement, int column) { - std::vector<unsigned char> blob; - (*statement)->column_blob_as_vector(column, &blob); - - SBFullHash ret; - DCHECK_EQ(blob.size(), sizeof(ret)); - memcpy(ret.full_hash, &blob[0], sizeof(ret)); - return ret; -} - -void DeleteChunksFromSet(const base::hash_set<int32>& deleted, - std::set<int32>* chunks) { - for (std::set<int32>::iterator iter = chunks->begin(); - iter != chunks->end();) { - std::set<int32>::iterator prev = iter++; - if (deleted.count(*prev) > 0) - chunks->erase(prev); - } -} - -} // namespace - -SafeBrowsingStoreSqlite::SafeBrowsingStoreSqlite() - : db_(NULL), - statement_cache_(NULL), - insert_transaction_(NULL) { -} -SafeBrowsingStoreSqlite::~SafeBrowsingStoreSqlite() { - Close(); -} - -bool SafeBrowsingStoreSqlite::Delete() { - // The file must be closed, both so that the journal file is deleted - // by SQLite, and because open files cannot be deleted on Windows. - if (!Close()) { - NOTREACHED(); - return false; - } - - // Just in case, delete the journal file, because associating the - // wrong journal file with a database is very bad. - const FilePath journal_file = JournalFileForFilename(filename_); - if (!file_util::Delete(journal_file, false) && - file_util::PathExists(journal_file)) { - NOTREACHED(); - return false; - } - - if (!file_util::Delete(filename_, false) && - file_util::PathExists(filename_)) { - NOTREACHED(); - return false; - } - - return true; -} - -void SafeBrowsingStoreSqlite::Init(const FilePath& filename, - Callback0::Type* corruption_callback) { - filename_ = filename; - corruption_callback_.reset(corruption_callback); -} - -bool SafeBrowsingStoreSqlite::BeginChunk() { - return true; -} - -bool SafeBrowsingStoreSqlite::GetAddPrefixes( - std::vector<SBAddPrefix>* add_prefixes) { - add_prefixes->clear(); - if (!Open()) return false; - bool ret = ReadAddPrefixes(add_prefixes); - Close(); - return ret; -} - -bool SafeBrowsingStoreSqlite::WriteAddPrefix(int32 chunk_id, SBPrefix prefix) { - const std::vector<SBAddPrefix> prefixes(1, SBAddPrefix(chunk_id, prefix)); - return WriteAddPrefixes(prefixes); -} - -bool SafeBrowsingStoreSqlite::WriteAddHash(int32 chunk_id, - base::Time receive_time, - const SBFullHash& full_hash) { - const std::vector<SBAddFullHash> - hashes(1, SBAddFullHash(chunk_id, receive_time, full_hash)); - return WriteAddHashes(hashes); -} - -bool SafeBrowsingStoreSqlite::WriteSubPrefix(int32 chunk_id, - int32 add_chunk_id, - SBPrefix prefix) { - const std::vector<SBSubPrefix> - prefixes(1, SBSubPrefix(chunk_id, add_chunk_id, prefix)); - return WriteSubPrefixes(prefixes); -} - -bool SafeBrowsingStoreSqlite::WriteSubHash(int32 chunk_id, - int32 add_chunk_id, - const SBFullHash& full_hash) { - const std::vector<SBSubFullHash> - hashes(1, SBSubFullHash(chunk_id, add_chunk_id, full_hash)); - return WriteSubHashes(hashes); -} - -bool SafeBrowsingStoreSqlite::FinishChunk() { - return true; -} - -bool SafeBrowsingStoreSqlite::OnCorruptDatabase() { - if (corruption_callback_.get()) - corruption_callback_->Run(); - return false; -} - -bool SafeBrowsingStoreSqlite::Open() { - // This case should never happen, but if it does we shouldn't leak - // handles. - if (db_) { - NOTREACHED() << " Database was already open in Open()."; - return true; - } - - if (sqlite_utils::OpenSqliteDb(filename_, &db_) != SQLITE_OK) { - sqlite3_close(db_); - db_ = NULL; - return false; - } - - // Run the database in exclusive mode. Nobody else should be accessing the - // database while we're running, and this will give somewhat improved perf. - ExecSql("PRAGMA locking_mode = EXCLUSIVE"); - ExecSql("PRAGMA cache_size = 100"); - - statement_cache_.reset(new SqliteStatementCache(db_)); - - if (!sqlite_utils::DoesSqliteTableExist(db_, "add_prefix")) - return SetupDatabase(); - - return CheckCompatibleVersion(); -} - -bool SafeBrowsingStoreSqlite::ExecSql(const char* sql) { - DCHECK(db_); - - int rv = sqlite3_exec(db_, sql, NULL, NULL, NULL); - if (rv == SQLITE_CORRUPT) - return OnCorruptDatabase(); - DCHECK(rv == SQLITE_OK); - return true; -} - -bool SafeBrowsingStoreSqlite::Close() { - if (!db_) - return true; - - add_chunks_cache_.clear(); - sub_chunks_cache_.clear(); - - add_del_cache_.clear(); - sub_del_cache_.clear(); - - insert_transaction_.reset(); - statement_cache_.reset(); // Must free statements before closing DB. - bool result = sqlite3_close(db_) == SQLITE_OK; - db_ = NULL; - - return result; -} - -bool SafeBrowsingStoreSqlite::CreateTables() { - DCHECK(db_); - - // Store 32 bit add prefixes here. - if (!ExecSql("CREATE TABLE add_prefix (" - " chunk INTEGER," - " prefix INTEGER" - ")")) - return false; - - // Store 32 bit sub prefixes here. - if (!ExecSql("CREATE TABLE sub_prefix (" - " chunk INTEGER," - " add_chunk INTEGER," - " prefix INTEGER" - ")")) - return false; - - // Store 256 bit add full hashes (and GetHash results) here. - if (!ExecSql("CREATE TABLE add_full_hash (" - " chunk INTEGER," - " prefix INTEGER," - " receive_time INTEGER," - " full_hash BLOB" - ")")) - return false; - - // Store 256 bit sub full hashes here. - if (!ExecSql("CREATE TABLE sub_full_hash (" - " chunk INTEGER," - " add_chunk INTEGER," - " prefix INTEGER," - " full_hash BLOB" - ")")) - return false; - - // Store all the add and sub chunk numbers we receive. We cannot - // just rely on the prefix tables to generate these lists, since - // some chunks will have zero entries (and thus no prefixes), or - // potentially an add chunk can have all of its entries sub'd - // without receiving an AddDel, or a sub chunk might have been - // entirely consumed by adds. In these cases, we still have to - // report the chunk number but it will not have any prefixes in the - // prefix tables. - // - // TODO(paulg): Investigate storing the chunks as a string of - // ChunkRanges, one string for each of phish-add, phish-sub, - // malware-add, malware-sub. This might be better performance when - // the number of chunks is large, and is the natural format for the - // update request. - if (!ExecSql("CREATE TABLE add_chunks (" - " chunk INTEGER PRIMARY KEY" - ")")) - return false; - - if (!ExecSql("CREATE TABLE sub_chunks (" - " chunk INTEGER PRIMARY KEY" - ")")) - return false; - - return true; -} - -bool SafeBrowsingStoreSqlite::SetupDatabase() { - DCHECK(db_); - - SQLTransaction transaction(db_); - if (transaction.Begin() != SQLITE_OK) { - NOTREACHED(); - return false; - } - - if (!CreateTables()) - return false; - - // PRAGMA does not support bind parameters... - const std::string version = - StringPrintf("PRAGMA user_version = %d", kDatabaseVersion); - if (!ExecSql(version.c_str())) - return false; - - if (transaction.Commit() != SQLITE_OK) - return false; - - return true; -} - -bool SafeBrowsingStoreSqlite::CheckCompatibleVersion() { - DCHECK(db_); - - SQLITE_UNIQUE_STATEMENT(statement, *statement_cache_, - "PRAGMA user_version"); - if (!statement.is_valid()) { - NOTREACHED(); - return false; - } - - int result = statement->step(); - if (result != SQLITE_ROW) - return false; - - return statement->column_int(0) == kDatabaseVersion; -} - -bool SafeBrowsingStoreSqlite::ReadAddChunks() { - DCHECK(db_); - - add_chunks_cache_.clear(); - - SQLITE_UNIQUE_STATEMENT(statement, *statement_cache_, - "SELECT chunk FROM add_chunks"); - if (!statement.is_valid()) { - NOTREACHED(); - return false; - } - - int rv; - while ((rv = statement->step()) == SQLITE_ROW) { - add_chunks_cache_.insert(statement->column_int(0)); - } - if (rv == SQLITE_CORRUPT) - return OnCorruptDatabase(); - DCHECK_EQ(rv, SQLITE_DONE); - return rv == SQLITE_DONE; -} - -bool SafeBrowsingStoreSqlite::WriteAddChunks() { - DCHECK(db_); - - SQLITE_UNIQUE_STATEMENT(statement, *statement_cache_, - "INSERT INTO add_chunks (chunk) VALUES (?)"); - if (!statement.is_valid()) { - NOTREACHED(); - return false; - } - - for (std::set<int32>::const_iterator iter = add_chunks_cache_.begin(); - iter != add_chunks_cache_.end(); ++iter) { - statement->bind_int(0, *iter); - int rv = statement->step(); - if (rv == SQLITE_CORRUPT) - return OnCorruptDatabase(); - DCHECK(rv == SQLITE_DONE); - statement->reset(); - } - return true; -} - -bool SafeBrowsingStoreSqlite::ReadSubChunks() { - DCHECK(db_); - - sub_chunks_cache_.clear(); - - SQLITE_UNIQUE_STATEMENT(statement, *statement_cache_, - "SELECT chunk FROM sub_chunks"); - if (!statement.is_valid()) { - NOTREACHED(); - return false; - } - - int rv; - while ((rv = statement->step()) == SQLITE_ROW) { - sub_chunks_cache_.insert(statement->column_int(0)); - } - if (rv == SQLITE_CORRUPT) - return OnCorruptDatabase(); - return rv == SQLITE_DONE; -} - -bool SafeBrowsingStoreSqlite::WriteSubChunks() { - DCHECK(db_); - - SQLITE_UNIQUE_STATEMENT(statement, *statement_cache_, - "INSERT INTO sub_chunks (chunk) VALUES (?)"); - if (!statement.is_valid()) { - NOTREACHED(); - return false; - } - - for (std::set<int32>::const_iterator iter = sub_chunks_cache_.begin(); - iter != sub_chunks_cache_.end(); ++iter) { - statement->bind_int(0, *iter); - int rv = statement->step(); - if (rv == SQLITE_CORRUPT) - return OnCorruptDatabase(); - DCHECK(rv == SQLITE_DONE); - statement->reset(); - } - return true; -} - -bool SafeBrowsingStoreSqlite::ReadAddPrefixes( - std::vector<SBAddPrefix>* add_prefixes) { - DCHECK(db_); - - SQLITE_UNIQUE_STATEMENT(statement, *statement_cache_, - "SELECT chunk, prefix FROM add_prefix"); - if (!statement.is_valid()) { - NOTREACHED(); - return false; - } - - int rv; - while ((rv = statement->step()) == SQLITE_ROW) { - const int32 chunk_id = statement->column_int(0); - const SBPrefix prefix = statement->column_int(1); - add_prefixes->push_back(SBAddPrefix(chunk_id, prefix)); - } - if (rv == SQLITE_CORRUPT) - return OnCorruptDatabase(); - DCHECK_EQ(rv, SQLITE_DONE); - return true; -} - -bool SafeBrowsingStoreSqlite::WriteAddPrefixes( - const std::vector<SBAddPrefix>& add_prefixes) { - DCHECK(db_); - - SQLITE_UNIQUE_STATEMENT(statement, *statement_cache_, - "INSERT INTO add_prefix " - "(chunk, prefix) VALUES (?,?)"); - if (!statement.is_valid()) { - NOTREACHED(); - return false; - } - - for (std::vector<SBAddPrefix>::const_iterator iter = add_prefixes.begin(); - iter != add_prefixes.end(); ++iter) { - statement->bind_int(0, iter->chunk_id); - statement->bind_int(1, iter->prefix); - int rv = statement->step(); - if (rv == SQLITE_CORRUPT) - return OnCorruptDatabase(); - DCHECK(rv == SQLITE_DONE); - statement->reset(); - } - return true; -} - -bool SafeBrowsingStoreSqlite::ReadSubPrefixes( - std::vector<SBSubPrefix>* sub_prefixes) { - DCHECK(db_); - - SQLITE_UNIQUE_STATEMENT(statement, *statement_cache_, - "SELECT chunk, add_chunk, prefix " - "FROM sub_prefix"); - if (!statement.is_valid()) { - NOTREACHED(); - return false; - } - - int rv; - while ((rv = statement->step()) == SQLITE_ROW) { - const int32 chunk_id = statement->column_int(0); - const int32 add_chunk_id = statement->column_int(1); - const SBPrefix add_prefix = statement->column_int(2); - sub_prefixes->push_back(SBSubPrefix(chunk_id, add_chunk_id, add_prefix)); - } - if (rv == SQLITE_CORRUPT) - return OnCorruptDatabase(); - DCHECK_EQ(rv, SQLITE_DONE); - return true; -} - -bool SafeBrowsingStoreSqlite::WriteSubPrefixes( - const std::vector<SBSubPrefix>& sub_prefixes) { - DCHECK(db_); - - SQLITE_UNIQUE_STATEMENT(statement, *statement_cache_, - "INSERT INTO sub_prefix " - "(chunk, add_chunk, prefix) VALUES (?,?, ?)"); - if (!statement.is_valid()) { - NOTREACHED(); - return false; - } - - for (std::vector<SBSubPrefix>::const_iterator iter = sub_prefixes.begin(); - iter != sub_prefixes.end(); ++iter) { - statement->bind_int(0, iter->chunk_id); - statement->bind_int(1, iter->add_chunk_id); - statement->bind_int(2, iter->add_prefix); - int rv = statement->step(); - if (rv == SQLITE_CORRUPT) - return OnCorruptDatabase(); - DCHECK(rv == SQLITE_DONE); - statement->reset(); - } - return true; -} - -bool SafeBrowsingStoreSqlite::ReadAddHashes( - std::vector<SBAddFullHash>* add_hashes) { - DCHECK(db_); - - SQLITE_UNIQUE_STATEMENT(statement, *statement_cache_, - "SELECT chunk, prefix, receive_time, full_hash " - "FROM add_full_hash"); - if (!statement.is_valid()) { - NOTREACHED(); - return false; - } - - int rv; - while ((rv = statement->step()) == SQLITE_ROW) { - const int32 chunk_id = statement->column_int(0); - // NOTE: Legacy format duplicated |hash.prefix| in column 1. - const SBPrefix prefix = statement->column_int(1); - const int32 received = statement->column_int(2); - const SBFullHash full_hash = ReadFullHash(&statement, 3); - DCHECK_EQ(prefix, full_hash.prefix); - add_hashes->push_back(SBAddFullHash(chunk_id, received, full_hash)); - } - if (rv == SQLITE_CORRUPT) - return OnCorruptDatabase(); - DCHECK_EQ(rv, SQLITE_DONE); - return true; -} - -bool SafeBrowsingStoreSqlite::WriteAddHashes( - const std::vector<SBAddFullHash>& add_hashes) { - DCHECK(db_); - - SQLITE_UNIQUE_STATEMENT(statement, *statement_cache_, - "INSERT INTO add_full_hash " - "(chunk, prefix, receive_time, full_hash) " - "VALUES (?,?, ?, ?)"); - if (!statement.is_valid()) { - NOTREACHED(); - return false; - } - - for (std::vector<SBAddFullHash>::const_iterator iter = add_hashes.begin(); - iter != add_hashes.end(); ++iter) { - // NOTE: Legacy format duplicated |hash.prefix| in column 1. - statement->bind_int(0, iter->chunk_id); - statement->bind_int(1, iter->full_hash.prefix); - statement->bind_int(2, iter->received); - statement->bind_blob(3, iter->full_hash.full_hash, - sizeof(iter->full_hash.full_hash)); - int rv = statement->step(); - if (rv == SQLITE_CORRUPT) - return OnCorruptDatabase(); - DCHECK(rv == SQLITE_DONE); - statement->reset(); - } - return true; -} - -bool SafeBrowsingStoreSqlite::ReadSubHashes( - std::vector<SBSubFullHash>* sub_hashes) { - DCHECK(db_); - - SQLITE_UNIQUE_STATEMENT(statement, *statement_cache_, - "SELECT chunk, add_chunk, prefix, full_hash " - "FROM sub_full_hash"); - if (!statement.is_valid()) { - NOTREACHED(); - return false; - } - - int rv; - while ((rv = statement->step()) == SQLITE_ROW) { - const int32 chunk_id = statement->column_int(0); - // NOTE: Legacy format duplicated |hash.prefix| in column 2. - const int32 add_chunk_id = statement->column_int(1); - const SBPrefix add_prefix = statement->column_int(2); - const SBFullHash full_hash = ReadFullHash(&statement, 3); - DCHECK_EQ(add_prefix, full_hash.prefix); - sub_hashes->push_back(SBSubFullHash(chunk_id, add_chunk_id, full_hash)); - } - if (rv == SQLITE_CORRUPT) - return OnCorruptDatabase(); - DCHECK_EQ(rv, SQLITE_DONE); - return true; -} - -bool SafeBrowsingStoreSqlite::WriteSubHashes( - const std::vector<SBSubFullHash>& sub_hashes) { - DCHECK(db_); - - SQLITE_UNIQUE_STATEMENT(statement, *statement_cache_, - "INSERT INTO sub_full_hash " - "(chunk, add_chunk, prefix, full_hash) " - "VALUES (?,?,?,?)"); - if (!statement.is_valid()) { - NOTREACHED(); - return false; - } - - for (std::vector<SBSubFullHash>::const_iterator iter = sub_hashes.begin(); - iter != sub_hashes.end(); ++iter) { - // NOTE: Legacy format duplicated |hash.prefix| in column 2. - statement->bind_int(0, iter->chunk_id); - statement->bind_int(1, iter->add_chunk_id); - statement->bind_int(2, iter->full_hash.prefix); - statement->bind_blob(3, iter->full_hash.full_hash, - sizeof(iter->full_hash.full_hash)); - int rv = statement->step(); - if (rv == SQLITE_CORRUPT) - return OnCorruptDatabase(); - DCHECK(rv == SQLITE_DONE); - statement->reset(); - } - return true; -} - -bool SafeBrowsingStoreSqlite::ResetTables() { - DCHECK(db_); - - if (!ExecSql("DELETE FROM add_prefix") || - !ExecSql("DELETE FROM sub_prefix") || - !ExecSql("DELETE FROM add_full_hash") || - !ExecSql("DELETE FROM sub_full_hash") || - !ExecSql("DELETE FROM add_chunks") || - !ExecSql("DELETE FROM sub_chunks")) - return false; - - return true; -} - -bool SafeBrowsingStoreSqlite::BeginUpdate() { - DCHECK(!db_); - - if (!Open()) - return false; - - insert_transaction_.reset(new SQLTransaction(db_)); - if (insert_transaction_->Begin() != SQLITE_OK) { - DCHECK(false) << "Safe browsing store couldn't start transaction"; - Close(); - return false; - } - - if (!ReadAddChunks() || !ReadSubChunks()) - return false; - - return true; -} - -bool SafeBrowsingStoreSqlite::DoUpdate( - const std::vector<SBAddFullHash>& pending_adds, - std::vector<SBAddPrefix>* add_prefixes_result, - std::vector<SBAddFullHash>* add_full_hashes_result) { - DCHECK(db_); - - std::vector<SBAddPrefix> add_prefixes; - std::vector<SBAddFullHash> add_full_hashes; - std::vector<SBSubPrefix> sub_prefixes; - std::vector<SBSubFullHash> sub_full_hashes; - - if (!ReadAddPrefixes(&add_prefixes) || - !ReadAddHashes(&add_full_hashes) || - !ReadSubPrefixes(&sub_prefixes) || - !ReadSubHashes(&sub_full_hashes)) - return false; - - // Append items from |pending_adds|. - add_full_hashes.insert(add_full_hashes.end(), - pending_adds.begin(), pending_adds.end()); - - // Knock the subs from the adds and process deleted chunks. - SBProcessSubs(&add_prefixes, &sub_prefixes, - &add_full_hashes, &sub_full_hashes, - add_del_cache_, sub_del_cache_); - - DeleteChunksFromSet(add_del_cache_, &add_chunks_cache_); - DeleteChunksFromSet(sub_del_cache_, &sub_chunks_cache_); - - // Clear the existing tables before rewriting them. - if (!ResetTables()) - return false; - - if (!WriteAddChunks() || - !WriteSubChunks() || - !WriteAddPrefixes(add_prefixes) || - !WriteSubPrefixes(sub_prefixes) || - !WriteAddHashes(add_full_hashes) || - !WriteSubHashes(sub_full_hashes)) - return false; - - // Commit all the changes to the database. - int rv = insert_transaction_->Commit(); - if (rv != SQLITE_OK) { - NOTREACHED() << "SafeBrowsing update transaction failed to commit."; - UMA_HISTOGRAM_COUNTS("SB2.FailedUpdate", 1); - return false; - } - - // Record counts before swapping to caller. - UMA_HISTOGRAM_COUNTS("SB2.AddPrefixes", add_prefixes.size()); - UMA_HISTOGRAM_COUNTS("SB2.SubPrefixes", sub_prefixes.size()); - - add_prefixes_result->swap(add_prefixes); - add_full_hashes_result->swap(add_full_hashes); - - return true; -} - -bool SafeBrowsingStoreSqlite::FinishUpdate( - const std::vector<SBAddFullHash>& pending_adds, - const std::set<SBPrefix>& prefix_misses, - std::vector<SBAddPrefix>* add_prefixes_result, - std::vector<SBAddFullHash>* add_full_hashes_result) { - bool ret = DoUpdate(pending_adds, - add_prefixes_result, add_full_hashes_result); - - // Make sure everything is closed even if DoUpdate() fails. - if (!Close()) - return false; - - return ret; -} - -bool SafeBrowsingStoreSqlite::CancelUpdate() { - return Close(); -} - -void SafeBrowsingStoreSqlite::SetAddChunk(int32 chunk_id) { - add_chunks_cache_.insert(chunk_id); -} - -bool SafeBrowsingStoreSqlite::CheckAddChunk(int32 chunk_id) { - return add_chunks_cache_.count(chunk_id) > 0; -} - -void SafeBrowsingStoreSqlite::GetAddChunks(std::vector<int32>* out) { - out->clear(); - out->insert(out->end(), add_chunks_cache_.begin(), add_chunks_cache_.end()); -} - -void SafeBrowsingStoreSqlite::SetSubChunk(int32 chunk_id) { - sub_chunks_cache_.insert(chunk_id); -} - -bool SafeBrowsingStoreSqlite::CheckSubChunk(int32 chunk_id) { - return sub_chunks_cache_.count(chunk_id) > 0; -} - -void SafeBrowsingStoreSqlite::GetSubChunks(std::vector<int32>* out) { - out->clear(); - out->insert(out->end(), sub_chunks_cache_.begin(), sub_chunks_cache_.end()); -} - -void SafeBrowsingStoreSqlite::DeleteAddChunk(int32 chunk_id) { - add_del_cache_.insert(chunk_id); -} - -void SafeBrowsingStoreSqlite::DeleteSubChunk(int32 chunk_id) { - sub_del_cache_.insert(chunk_id); -} - -// static -const FilePath SafeBrowsingStoreSqlite::JournalFileForFilename( - const FilePath& filename) { - return FilePath(filename.value() + FILE_PATH_LITERAL("-journal")); -} diff --git a/chrome/browser/safe_browsing/safe_browsing_store_sqlite.h b/chrome/browser/safe_browsing/safe_browsing_store_sqlite.h deleted file mode 100644 index f9d4381..0000000 --- a/chrome/browser/safe_browsing/safe_browsing_store_sqlite.h +++ /dev/null @@ -1,159 +0,0 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_BROWSER_SAFE_BROWSING_SAFE_BROWSING_STORE_SQLITE_H_ -#define CHROME_BROWSER_SAFE_BROWSING_SAFE_BROWSING_STORE_SQLITE_H_ -#pragma once - -#include <set> -#include <vector> - -#include "base/callback.h" -#include "base/file_path.h" -#include "base/scoped_ptr.h" -#include "chrome/browser/safe_browsing/safe_browsing_store.h" -#include "testing/gtest/include/gtest/gtest_prod.h" - -struct sqlite3; -class SqliteStatementCache; -class SQLTransaction; - -class SafeBrowsingStoreSqlite : public SafeBrowsingStore { - public: - SafeBrowsingStoreSqlite(); - virtual ~SafeBrowsingStoreSqlite(); - - virtual bool Delete(); - - virtual void Init(const FilePath& filename, - Callback0::Type* corruption_callback); - - virtual bool BeginChunk(); - - // Get all Add prefixes out from the store. - virtual bool GetAddPrefixes(std::vector<SBAddPrefix>* add_prefixes); - virtual bool WriteAddPrefix(int32 chunk_id, SBPrefix prefix); - virtual bool WriteAddHash(int32 chunk_id, - base::Time receive_time, - const SBFullHash& full_hash); - virtual bool WriteSubPrefix(int32 chunk_id, - int32 add_chunk_id, SBPrefix prefix); - virtual bool WriteSubHash(int32 chunk_id, int32 add_chunk_id, - const SBFullHash& full_hash); - virtual bool FinishChunk(); - - virtual bool BeginUpdate(); - // TODO(shess): Should not be public. - virtual bool DoUpdate(const std::vector<SBAddFullHash>& pending_adds, - std::vector<SBAddPrefix>* add_prefixes_result, - std::vector<SBAddFullHash>* add_full_hashes_result); - // NOTE: |prefix_misses| is ignored, as it will be handled in - // |SafeBrowsingStoreFile::DoUpdate()|. - virtual bool FinishUpdate(const std::vector<SBAddFullHash>& pending_adds, - const std::set<SBPrefix>& prefix_misses, - std::vector<SBAddPrefix>* add_prefixes_result, - std::vector<SBAddFullHash>* add_full_hashes_result); - virtual bool CancelUpdate(); - - virtual void SetAddChunk(int32 chunk_id); - virtual bool CheckAddChunk(int32 chunk_id); - virtual void GetAddChunks(std::vector<int32>* out); - - virtual void SetSubChunk(int32 chunk_id); - virtual bool CheckSubChunk(int32 chunk_id); - virtual void GetSubChunks(std::vector<int32>* out); - - virtual void DeleteAddChunk(int32 chunk_id); - virtual void DeleteSubChunk(int32 chunk_id); - - // Returns the name of the SQLite journal file for |filename|. - // Exported for unit tests. - static const FilePath JournalFileForFilename(const FilePath& filename); - - private: - // For on-the-fly migration. - // TODO(shess): Remove (entire class) after migration. - friend class SafeBrowsingStoreFile; - - // The following routines return true on success, or false on - // failure. Failure is presumed to be persistent, so the caller - // should stop trying and unwind the transaction. - // OnCorruptDatabase() is called if SQLite returns SQLITE_CORRUPT. - - // Open |db_| from |filename_|, creating if necessary. - bool Open(); - - // Close |db_|, rolling back any in-progress transaction. - bool Close(); - - // Execute all statements in sql, returning true if every one of - // them returns SQLITE_OK. - bool ExecSql(const char* sql); - - bool SetupDatabase(); - bool CheckCompatibleVersion(); - - bool CreateTables(); - - // Clear the old safe-browsing data from the tables. - bool ResetTables(); - - // Read and write the chunks-seen data from |*_chunks_cache_|. - // Chunk deletions are not accounted for. - bool ReadAddChunks(); - bool ReadSubChunks(); - bool WriteAddChunks(); - bool WriteSubChunks(); - - // Read the various types of data, skipping items which belong to - // deleted chunks. New data is appended to the vectors. - bool ReadAddPrefixes(std::vector<SBAddPrefix>* add_prefixes); - bool ReadSubPrefixes(std::vector<SBSubPrefix>* sub_prefixes); - bool ReadAddHashes(std::vector<SBAddFullHash>* add_hashes); - bool ReadSubHashes(std::vector<SBSubFullHash>* sub_hashes); - - // Write the various types of data. The existing data is not - // cleared. - bool WriteAddPrefixes(const std::vector<SBAddPrefix>& add_prefixes); - bool WriteSubPrefixes(const std::vector<SBSubPrefix>& sub_prefixes); - bool WriteAddHashes(const std::vector<SBAddFullHash>& add_hashes); - bool WriteSubHashes(const std::vector<SBSubFullHash>& sub_hashes); - - // Calls |corruption_callback_| if non-NULL, always returns false as - // a convenience to the caller. - bool OnCorruptDatabase(); - - // The database path from Init(). - FilePath filename_; - - // Between BeginUpdate() and FinishUpdate(), this will be the SQLite - // database connection. Otherwise NULL. - sqlite3 *db_; - - // Cache of compiled statements for |db_|. - // TODO(shess): Probably doesn't gain us much. - scoped_ptr<SqliteStatementCache> statement_cache_; - - // Transaction for protecting database integrity between - // BeginUpdate() and FinishUpdate(). - scoped_ptr<SQLTransaction> insert_transaction_; - - // The set of chunks which the store has seen. Elements are added - // by SetAddChunk() and SetSubChunk(), and deleted on write for - // chunks that have been deleted. - std::set<int32> add_chunks_cache_; - std::set<int32> sub_chunks_cache_; - - // Cache the DeletedAddChunk() and DeleteSubChunk() chunks for later - // use in FinishUpdate(). - base::hash_set<int32> add_del_cache_; - base::hash_set<int32> sub_del_cache_; - - // Called when SQLite returns SQLITE_CORRUPT. - scoped_ptr<Callback0::Type> corruption_callback_; - - DISALLOW_COPY_AND_ASSIGN(SafeBrowsingStoreSqlite); -}; - -#endif // CHROME_BROWSER_SAFE_BROWSING_SAFE_BROWSING_STORE_SQLITE_H_ diff --git a/chrome/browser/safe_browsing/safe_browsing_store_sqlite_unittest.cc b/chrome/browser/safe_browsing/safe_browsing_store_sqlite_unittest.cc deleted file mode 100644 index 8364cf2..0000000 --- a/chrome/browser/safe_browsing/safe_browsing_store_sqlite_unittest.cc +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/browser/safe_browsing/safe_browsing_store_sqlite.h" - -#include "chrome/browser/safe_browsing/safe_browsing_store_unittest_helper.h" -#include "chrome/test/file_test_utils.h" -#include "testing/gtest/include/gtest/gtest.h" -#include "testing/platform_test.h" - -namespace { - -const FilePath::CharType kFolderPrefix[] = - FILE_PATH_LITERAL("SafeBrowsingTestStoreSqlite"); - -class SafeBrowsingStoreSqliteTest : public PlatformTest { - public: - virtual void SetUp() { - PlatformTest::SetUp(); - - FilePath temp_dir; - ASSERT_TRUE(file_util::CreateNewTempDirectory(kFolderPrefix, &temp_dir)); - - file_deleter_.reset(new FileAutoDeleter(temp_dir)); - - filename_ = temp_dir; - filename_ = filename_.AppendASCII("SafeBrowsingTestStore"); - file_util::Delete(filename_, false); - - const FilePath journal_file = - SafeBrowsingStoreSqlite::JournalFileForFilename(filename_); - file_util::Delete(journal_file, false); - - store_.reset(new SafeBrowsingStoreSqlite()); - store_->Init(filename_, NULL); - } - virtual void TearDown() { - store_->Delete(); - store_.reset(); - file_deleter_.reset(); - - PlatformTest::TearDown(); - } - - scoped_ptr<FileAutoDeleter> file_deleter_; - FilePath filename_; - scoped_ptr<SafeBrowsingStoreSqlite> store_; -}; - -TEST_STORE(SafeBrowsingStoreSqliteTest, store_.get(), filename_); - -} // namespace diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi index 0f32820..55a212b 100644 --- a/chrome/chrome_browser.gypi +++ b/chrome/chrome_browser.gypi @@ -2058,8 +2058,6 @@ 'browser/safe_browsing/safe_browsing_store.h', 'browser/safe_browsing/safe_browsing_store_file.cc', 'browser/safe_browsing/safe_browsing_store_file.h', - 'browser/safe_browsing/safe_browsing_store_sqlite.cc', - 'browser/safe_browsing/safe_browsing_store_sqlite.h', 'browser/safe_browsing/safe_browsing_util.cc', 'browser/safe_browsing/safe_browsing_util.h', 'browser/search_engines/edit_search_engine_controller.cc', diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi index d09fd65..2208713 100644 --- a/chrome/chrome_tests.gypi +++ b/chrome/chrome_tests.gypi @@ -1390,7 +1390,6 @@ 'browser/safe_browsing/safe_browsing_blocking_page_unittest.cc', 'browser/safe_browsing/safe_browsing_database_unittest.cc', 'browser/safe_browsing/safe_browsing_store_file_unittest.cc', - 'browser/safe_browsing/safe_browsing_store_sqlite_unittest.cc', 'browser/safe_browsing/safe_browsing_store_unittest.cc', 'browser/safe_browsing/safe_browsing_store_unittest_helper.cc', 'browser/safe_browsing/safe_browsing_util_unittest.cc', |