Index: chrome/browser/safe_browsing/prefix_set.cc |
diff --git a/chrome/browser/safe_browsing/prefix_set.cc b/chrome/browser/safe_browsing/prefix_set.cc |
index 007f8b82f10ab58e1d2f6d939b97f704647fc5fd..21335e156373d309a4e2a3c4be72ce7c3ee36cc2 100644 |
--- a/chrome/browser/safe_browsing/prefix_set.cc |
+++ b/chrome/browser/safe_browsing/prefix_set.cc |
@@ -24,16 +24,26 @@ static uint32 kMagic = 0x864088dd; |
// Version history: |
// Version 1: b6cb7cfe/r74487 by shess@chromium.org on 2011-02-10 |
// Version 2: 2b59b0a6/r253924 by shess@chromium.org on 2014-02-27 |
+// Version 3: ????????/r?????? by shess@chromium.org on 2014-04-?? |
// Version 2 layout is identical to version 1. The sort order of |index_| |
// changed from |int32| to |uint32| to match the change of |SBPrefix|. |
-static uint32 kVersion = 0x2; |
+// Version 3 adds storage for full hashes. |
+static uint32 kVersion = 0x3; |
typedef struct { |
uint32 magic; |
uint32 version; |
uint32 index_size; |
uint32 deltas_size; |
+} FileHeader_v2; |
+ |
+typedef struct { |
+ uint32 magic; |
+ uint32 version; |
+ uint32 index_size; |
+ uint32 deltas_size; |
+ uint32 full_hashes_size; |
} FileHeader; |
// Common std::vector<> implementations add capacity by multiplying from the |
@@ -84,10 +94,13 @@ bool PrefixSet::PrefixLess(const IndexPair& a, const IndexPair& b) { |
PrefixSet::PrefixSet() { |
} |
-PrefixSet::PrefixSet(IndexVector* index, std::vector<uint16>* deltas) { |
- DCHECK(index && deltas); |
+PrefixSet::PrefixSet(IndexVector* index, |
+ std::vector<uint16>* deltas, |
+ std::vector<SBFullHash>* full_hashes) { |
+ DCHECK(index && deltas && full_hashes); |
index_.swap(*index); |
deltas_.swap(*deltas); |
+ full_hashes_.swap(*full_hashes); |
} |
PrefixSet::~PrefixSet() {} |
@@ -156,7 +169,9 @@ scoped_ptr<PrefixSet> PrefixSet::LoadFile(const base::FilePath& filter_name) { |
if (!base::GetFileSize(filter_name, &size_64)) |
return scoped_ptr<PrefixSet>(); |
using base::MD5Digest; |
- if (size_64 < static_cast<int64>(sizeof(FileHeader) + sizeof(MD5Digest))) |
+ // TODO(shess): Revert to sizeof(FileHeader) for sanity check once v2 is |
+ // deprecated. |
+ if (size_64 < static_cast<int64>(sizeof(FileHeader_v2) + sizeof(MD5Digest))) |
return scoped_ptr<PrefixSet>(); |
base::ScopedFILE file(base::OpenFile(filter_name, "rb")); |
@@ -168,6 +183,12 @@ scoped_ptr<PrefixSet> PrefixSet::LoadFile(const base::FilePath& filter_name) { |
if (read != 1) |
return scoped_ptr<PrefixSet>(); |
+ // The file looks valid, start building the digest. |
+ base::MD5Context context; |
+ base::MD5Init(&context); |
+ base::MD5Update(&context, base::StringPiece(reinterpret_cast<char*>(&header), |
+ sizeof(header))); |
+ |
if (header.magic != kMagic) |
return scoped_ptr<PrefixSet>(); |
@@ -176,9 +197,36 @@ scoped_ptr<PrefixSet> PrefixSet::LoadFile(const base::FilePath& filter_name) { |
// TODO(shess): Version 1 and 2 use the same file structure, with version 1 |
// data using a signed sort. For M-35, the data is re-sorted before return. |
- // After M-35, just drop v1 support. <http://crbug.com/346405> |
- if (header.version != kVersion && header.version != 1) |
+ // After M-36, just drop v1 support. <http://crbug.com/346405> |
+ // TODO(shess): <http://crbug.com/368044> for removing v2 support. |
+ size_t header_size = sizeof(header); |
+ if (header.version == 2 || header.version == 1) { |
+ // Rewind the file and restart building the digest with the old header |
+ // structure. |
+ FileHeader_v2 v2_header; |
+ if (0 != fseek(file.get(), 0, SEEK_SET)) |
+ return scoped_ptr<PrefixSet>(); |
+ |
+ size_t read = fread(&v2_header, sizeof(v2_header), 1, file.get()); |
+ if (read != 1) |
+ return scoped_ptr<PrefixSet>(); |
+ |
+ base::MD5Init(&context); |
+ base::MD5Update(&context, |
+ base::StringPiece(reinterpret_cast<char*>(&v2_header), |
+ sizeof(v2_header))); |
+ |
+ // The current header is a superset of the old header, fill it in with the |
+ // information read. |
+ header.magic = v2_header.magic; |
+ header.version = v2_header.version; |
+ header.index_size = v2_header.index_size; |
+ header.deltas_size = v2_header.deltas_size; |
+ header.full_hashes_size = 0; |
+ header_size = sizeof(v2_header); |
+ } else if (header.version != kVersion) { |
return scoped_ptr<PrefixSet>(); |
+ } |
IndexVector index; |
const size_t index_bytes = sizeof(index[0]) * header.index_size; |
@@ -186,18 +234,16 @@ scoped_ptr<PrefixSet> PrefixSet::LoadFile(const base::FilePath& filter_name) { |
std::vector<uint16> deltas; |
const size_t deltas_bytes = sizeof(deltas[0]) * header.deltas_size; |
+ std::vector<SBFullHash> full_hashes; |
+ const size_t full_hashes_bytes = |
+ sizeof(full_hashes[0]) * header.full_hashes_size; |
+ |
// Check for bogus sizes before allocating any space. |
- const size_t expected_bytes = |
- sizeof(header) + index_bytes + deltas_bytes + sizeof(MD5Digest); |
+ const size_t expected_bytes = header_size + |
+ index_bytes + deltas_bytes + full_hashes_bytes + sizeof(MD5Digest); |
if (static_cast<int64>(expected_bytes) != size_64) |
return scoped_ptr<PrefixSet>(); |
- // The file looks valid, start building the digest. |
- base::MD5Context context; |
- base::MD5Init(&context); |
- base::MD5Update(&context, base::StringPiece(reinterpret_cast<char*>(&header), |
- sizeof(header))); |
- |
// Read the index vector. Herb Sutter indicates that vectors are |
// guaranteed to be contiuguous, so reading to where element 0 lives |
// is valid. |
@@ -222,6 +268,19 @@ scoped_ptr<PrefixSet> PrefixSet::LoadFile(const base::FilePath& filter_name) { |
deltas_bytes)); |
} |
+ // Read vector of full hashes. |
+ if (header.full_hashes_size) { |
+ full_hashes.resize(header.full_hashes_size); |
+ read = fread(&(full_hashes[0]), sizeof(full_hashes[0]), full_hashes.size(), |
+ file.get()); |
+ if (read != full_hashes.size()) |
+ return scoped_ptr<PrefixSet>(); |
+ base::MD5Update(&context, |
+ base::StringPiece( |
+ reinterpret_cast<char*>(&(full_hashes[0])), |
+ full_hashes_bytes)); |
+ } |
+ |
base::MD5Digest calculated_digest; |
base::MD5Final(&calculated_digest, &context); |
@@ -236,13 +295,15 @@ scoped_ptr<PrefixSet> PrefixSet::LoadFile(const base::FilePath& filter_name) { |
// For version 1, fetch the prefixes and re-sort. |
if (header.version == 1) { |
std::vector<SBPrefix> prefixes; |
- PrefixSet(&index, &deltas).GetPrefixes(&prefixes); |
+ PrefixSet(&index, &deltas, &full_hashes).GetPrefixes(&prefixes); |
std::sort(prefixes.begin(), prefixes.end()); |
+ |
+ // v1 cannot have full hashes, so no need to propagate a copy here. |
return PrefixSetBuilder(prefixes).GetPrefixSetNoHashes().Pass(); |
} |
- // Steals contents of |index| and |deltas| via swap(). |
- return scoped_ptr<PrefixSet>(new PrefixSet(&index, &deltas)); |
+ // Steals vector contents using swap(). |
+ return scoped_ptr<PrefixSet>(new PrefixSet(&index, &deltas, &full_hashes)); |
} |
bool PrefixSet::WriteFile(const base::FilePath& filter_name) const { |
@@ -251,10 +312,12 @@ bool PrefixSet::WriteFile(const base::FilePath& filter_name) const { |
header.version = kVersion; |
header.index_size = static_cast<uint32>(index_.size()); |
header.deltas_size = static_cast<uint32>(deltas_.size()); |
+ header.full_hashes_size = static_cast<uint32>(full_hashes_.size()); |
// Sanity check that the 32-bit values never mess things up. |
if (static_cast<size_t>(header.index_size) != index_.size() || |
- static_cast<size_t>(header.deltas_size) != deltas_.size()) { |
+ static_cast<size_t>(header.deltas_size) != deltas_.size() || |
+ static_cast<size_t>(header.full_hashes_size) != full_hashes_.size()) { |
NOTREACHED(); |
return false; |
} |
@@ -300,6 +363,19 @@ bool PrefixSet::WriteFile(const base::FilePath& filter_name) const { |
deltas_bytes)); |
} |
+ if (full_hashes_.size()) { |
+ const size_t elt_size = sizeof(full_hashes_[0]); |
+ const size_t elts = full_hashes_.size(); |
+ const size_t full_hashes_bytes = elt_size * elts; |
+ written = fwrite(&(full_hashes_[0]), elt_size, elts, file.get()); |
+ if (written != elts) |
+ return false; |
+ base::MD5Update(&context, |
+ base::StringPiece( |
+ reinterpret_cast<const char*>(&(full_hashes_[0])), |
+ full_hashes_bytes)); |
+ } |
+ |
base::MD5Digest digest; |
base::MD5Final(&digest, &context); |
written = fwrite(&digest, sizeof(digest), 1, file.get()); |