diff options
author | hashimoto@chromium.org <hashimoto@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-04-17 09:16:46 +0000 |
---|---|---|
committer | hashimoto@chromium.org <hashimoto@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-04-17 09:16:46 +0000 |
commit | 74f678eddfd2c35556d6c4e448889c1d8460429e (patch) | |
tree | 56ad0bf1f7634dc1d9b7d3b7112243f2574da677 /chrome/browser/chromeos | |
parent | d40b5e91db2725e975149c7bf344b6eeeac062bb (diff) | |
download | chromium_src-74f678eddfd2c35556d6c4e448889c1d8460429e.zip chromium_src-74f678eddfd2c35556d6c4e448889c1d8460429e.tar.gz chromium_src-74f678eddfd2c35556d6c4e448889c1d8460429e.tar.bz2 |
chromeos: Check validity of loaded data in DriveResourceMetadataStorageDB::Initialize
Broken data should be detected and cleared during initialization to avoid fatal bugs.
BUG=232054
TEST=unit_tests
Review URL: https://codereview.chromium.org/14167009
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@194550 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/chromeos')
3 files changed, 133 insertions, 9 deletions
diff --git a/chrome/browser/chromeos/drive/drive_resource_metadata_storage.cc b/chrome/browser/chromeos/drive/drive_resource_metadata_storage.cc index 17bf4e9..7546b1c 100644 --- a/chrome/browser/chromeos/drive/drive_resource_metadata_storage.cc +++ b/chrome/browser/chromeos/drive/drive_resource_metadata_storage.cc @@ -201,12 +201,10 @@ bool DriveResourceMetadataStorageDB::Initialize() { if (status.ok()) child_map_.reset(db); - // Check the version of existing DB. + // Check the validity of existing DB. if (resource_map_ && child_map_) { - scoped_ptr<DriveResourceMetadataHeader> header = GetHeader(); - if (!header || - header->version() != kDBVersion) { - LOG(ERROR) << "Reject incompatible DB."; + if (!CheckValidity()) { + LOG(ERROR) << "Reject invalid DB."; resource_map_.reset(); child_map_.reset(); } @@ -429,4 +427,72 @@ DriveResourceMetadataStorageDB::GetHeader() { return header.Pass(); } +bool DriveResourceMetadataStorageDB::CheckValidity() { + base::ThreadRestrictions::AssertIOAllowed(); + + // Perform read with checksums verification enalbed. + leveldb::ReadOptions options; + options.verify_checksums = true; + + scoped_ptr<leveldb::Iterator> it(resource_map_->NewIterator(options)); + it->SeekToFirst(); + + // Check the header. + DriveResourceMetadataHeader header; + if (!it->Valid() || + it->key() != GetHeaderDBKey() || // Header entry must come first. + !header.ParseFromArray(it->value().data(), it->value().size()) || + header.version() != kDBVersion) { + DLOG(ERROR) << "Invalid header detected. version = " << header.version(); + return false; + } + + // Check all entires. + size_t num_checked_child_map_entries = 0; + DriveEntryProto entry; + std::string child_resource_id; + for (it->Next(); it->Valid(); it->Next()) { + // Check if stored data is broken. + if (!entry.ParseFromArray(it->value().data(), it->value().size()) || + entry.resource_id() != it->key()) { + DLOG(ERROR) << "Broken entry detected"; + return false; + } + + // Check if parent-child relationship is stored correctly. + if (!entry.parent_resource_id().empty()) { + leveldb::Status status = child_map_->Get( + options, + leveldb::Slice(GetChildMapKey(entry.parent_resource_id(), + entry.base_name())), + &child_resource_id); + if (!status.ok() || child_resource_id != entry.resource_id()) { + DLOG(ERROR) << "Child map is broken. status = " << status.ToString(); + return false; + } + ++num_checked_child_map_entries; + } + } + if (!it->status().ok()) { + DLOG(ERROR) << "Error during checking resource map. status = " + << it->status().ToString(); + return false; + } + + // Check all child map entries are referenced from |resource_map_|. + size_t num_child_map_entries = 0; + it.reset(child_map_->NewIterator(options)); + for (it->SeekToFirst(); it->Valid(); it->Next()) { + ++num_child_map_entries; + } + if (!it->status().ok() || + num_child_map_entries != num_checked_child_map_entries) { + DLOG(ERROR) << "Error during checking child map. status = " + << it->status().ToString(); + return false; + } + + return true; +} + } // namespace drive diff --git a/chrome/browser/chromeos/drive/drive_resource_metadata_storage.h b/chrome/browser/chromeos/drive/drive_resource_metadata_storage.h index fb78c4b..13da193 100644 --- a/chrome/browser/chromeos/drive/drive_resource_metadata_storage.h +++ b/chrome/browser/chromeos/drive/drive_resource_metadata_storage.h @@ -162,6 +162,9 @@ class DriveResourceMetadataStorageDB // Gets header. scoped_ptr<DriveResourceMetadataHeader> GetHeader(); + // Checks validity of the data. + bool CheckValidity(); + // Path to the directory where the data is stored. base::FilePath directory_path_; diff --git a/chrome/browser/chromeos/drive/drive_resource_metadata_storage_unittest.cc b/chrome/browser/chromeos/drive/drive_resource_metadata_storage_unittest.cc index 10dfd8f..f9f7c62 100644 --- a/chrome/browser/chromeos/drive/drive_resource_metadata_storage_unittest.cc +++ b/chrome/browser/chromeos/drive/drive_resource_metadata_storage_unittest.cc @@ -44,6 +44,10 @@ class DriveResourceMetadataStorageTest : public testing::Test { storage_->PutHeader(*header); } + bool CheckValidity() { + return storage_->CheckValidity(); + } + base::ScopedTempDir temp_dir_; scoped_ptr<DriveResourceMetadataStorageDB> storage_; }; @@ -199,23 +203,32 @@ TEST_F(DriveResourceMetadataStorageTest, OpenExistingDB) { DriveEntryProto entry1; entry1.set_resource_id(parent_id1); + DriveEntryProto entry2; + entry2.set_resource_id(child_id1); + entry2.set_parent_resource_id(parent_id1); + entry2.set_base_name(child_name1); // Put some data. storage_->PutEntry(entry1); + storage_->PutEntry(entry2); storage_->PutChild(parent_id1, child_name1, child_id1); - scoped_ptr<DriveEntryProto> result = storage_->GetEntry(parent_id1); - ASSERT_TRUE(result); - EXPECT_EQ(parent_id1, result->resource_id()); - EXPECT_EQ(child_id1, storage_->GetChild(parent_id1, child_name1)); // Close DB and reopen. storage_.reset(new DriveResourceMetadataStorageDB(temp_dir_.path())); ASSERT_TRUE(storage_->Initialize()); // Can read data. + scoped_ptr<DriveEntryProto> result; result = storage_->GetEntry(parent_id1); ASSERT_TRUE(result); EXPECT_EQ(parent_id1, result->resource_id()); + + result = storage_->GetEntry(child_id1); + ASSERT_TRUE(result); + EXPECT_EQ(child_id1, result->resource_id()); + EXPECT_EQ(parent_id1, result->parent_resource_id()); + EXPECT_EQ(child_name1, result->base_name()); + EXPECT_EQ(child_id1, storage_->GetChild(parent_id1, child_name1)); } @@ -251,4 +264,46 @@ TEST_F(DriveResourceMetadataStorageTest, WrongPath) { ASSERT_FALSE(storage_->Initialize()); } +TEST_F(DriveResourceMetadataStorageTest, CheckValidity) { + const std::string key1 = "foo"; + const std::string name1 = "hoge"; + const std::string key2 = "bar"; + const std::string name2 = "fuga"; + const std::string key3 = "boo"; + const std::string name3 = "piyo"; + + // Put entry with key1. + DriveEntryProto entry; + entry.set_resource_id(key1); + entry.set_base_name(name1); + storage_->PutEntry(entry); + EXPECT_TRUE(CheckValidity()); + + // Put entry with key2 under key1. + entry.set_resource_id(key2); + entry.set_parent_resource_id(key1); + entry.set_base_name(name2); + storage_->PutEntry(entry); + EXPECT_FALSE(CheckValidity()); // Missing parent-child relationship. + + // Add missing parent-child relationship between key1 and key2. + storage_->PutChild(key1, name2, key2); + EXPECT_TRUE(CheckValidity()); + + // Add parent-child relationship between key1 and key3. + storage_->PutChild(key1, name3, key3); + EXPECT_FALSE(CheckValidity()); // key3 is not stored in the storage. + + // Put entry with key3 under key1. + entry.set_resource_id(key3); + entry.set_parent_resource_id(key1); + entry.set_base_name(name3); + storage_->PutEntry(entry); + EXPECT_TRUE(CheckValidity()); + + // Parent-child relationship with wrong name. + storage_->PutChild(key1, name2, key3); + EXPECT_FALSE(CheckValidity()); +} + } // namespace drive |