Index: chrome/browser/chromeos/drive/drive_resource_metadata_storage.cc |
diff --git a/chrome/browser/chromeos/drive/drive_resource_metadata_storage.cc b/chrome/browser/chromeos/drive/drive_resource_metadata_storage.cc |
index 17bf4e9224a1f9fc6d7c88ca29dc0f340ed058ed..7546b1c434ebc0652d31e9e31b4fbeb6ed126aef 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 |