Chromium Code Reviews| 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/prefix_set.h" | 5 #include "chrome/browser/safe_browsing/prefix_set.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 | 8 |
| 9 #include "base/files/file_util.h" | 9 #include "base/files/file_util.h" |
| 10 #include "base/files/scoped_file.h" | 10 #include "base/files/scoped_file.h" |
| (...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 150 SBPrefix current = index_[ii].first; | 150 SBPrefix current = index_[ii].first; |
| 151 prefixes->push_back(current); | 151 prefixes->push_back(current); |
| 152 for (size_t di = index_[ii].second; di < deltas_end; ++di) { | 152 for (size_t di = index_[ii].second; di < deltas_end; ++di) { |
| 153 current += deltas_[di]; | 153 current += deltas_[di]; |
| 154 prefixes->push_back(current); | 154 prefixes->push_back(current); |
| 155 } | 155 } |
| 156 } | 156 } |
| 157 } | 157 } |
| 158 | 158 |
| 159 // static | 159 // static |
| 160 scoped_ptr<PrefixSet> PrefixSet::LoadFile(const base::FilePath& filter_name) { | 160 scoped_ptr<const PrefixSet> PrefixSet::LoadFile( |
| 161 const base::FilePath& filter_name) { | |
| 161 int64 size_64; | 162 int64 size_64; |
| 162 if (!base::GetFileSize(filter_name, &size_64)) | 163 if (!base::GetFileSize(filter_name, &size_64)) |
| 163 return scoped_ptr<PrefixSet>(); | 164 return scoped_ptr<const PrefixSet>(); |
|
mattm
2014/12/03 23:08:19
can these all be changed to "return nullptr;"?
gab
2014/12/04 20:30:20
Yep :)
| |
| 164 using base::MD5Digest; | 165 using base::MD5Digest; |
| 165 if (size_64 < static_cast<int64>(sizeof(FileHeader) + sizeof(MD5Digest))) | 166 if (size_64 < static_cast<int64>(sizeof(FileHeader) + sizeof(MD5Digest))) |
| 166 return scoped_ptr<PrefixSet>(); | 167 return scoped_ptr<const PrefixSet>(); |
| 167 | 168 |
| 168 base::ScopedFILE file(base::OpenFile(filter_name, "rb")); | 169 base::ScopedFILE file(base::OpenFile(filter_name, "rb")); |
| 169 if (!file.get()) | 170 if (!file.get()) |
| 170 return scoped_ptr<PrefixSet>(); | 171 return scoped_ptr<const PrefixSet>(); |
| 171 | 172 |
| 172 FileHeader header; | 173 FileHeader header; |
| 173 size_t read = fread(&header, sizeof(header), 1, file.get()); | 174 size_t read = fread(&header, sizeof(header), 1, file.get()); |
| 174 if (read != 1) | 175 if (read != 1) |
| 175 return scoped_ptr<PrefixSet>(); | 176 return scoped_ptr<const PrefixSet>(); |
| 176 | 177 |
| 177 // The file looks valid, start building the digest. | 178 // The file looks valid, start building the digest. |
| 178 base::MD5Context context; | 179 base::MD5Context context; |
| 179 base::MD5Init(&context); | 180 base::MD5Init(&context); |
| 180 base::MD5Update(&context, base::StringPiece(reinterpret_cast<char*>(&header), | 181 base::MD5Update(&context, base::StringPiece(reinterpret_cast<char*>(&header), |
| 181 sizeof(header))); | 182 sizeof(header))); |
| 182 | 183 |
| 183 if (header.magic != kMagic) | 184 if (header.magic != kMagic) |
| 184 return scoped_ptr<PrefixSet>(); | 185 return scoped_ptr<const PrefixSet>(); |
| 185 | 186 |
| 186 // Track version read to inform removal of support for older versions. | 187 // Track version read to inform removal of support for older versions. |
| 187 UMA_HISTOGRAM_SPARSE_SLOWLY("SB2.PrefixSetVersionRead", header.version); | 188 UMA_HISTOGRAM_SPARSE_SLOWLY("SB2.PrefixSetVersionRead", header.version); |
| 188 | 189 |
| 189 if (header.version <= kDeprecatedVersion) { | 190 if (header.version <= kDeprecatedVersion) { |
| 190 return scoped_ptr<PrefixSet>(); | 191 return scoped_ptr<const PrefixSet>(); |
| 191 } else if (header.version != kVersion) { | 192 } else if (header.version != kVersion) { |
| 192 return scoped_ptr<PrefixSet>(); | 193 return scoped_ptr<const PrefixSet>(); |
| 193 } | 194 } |
| 194 | 195 |
| 195 IndexVector index; | 196 IndexVector index; |
| 196 const size_t index_bytes = sizeof(index[0]) * header.index_size; | 197 const size_t index_bytes = sizeof(index[0]) * header.index_size; |
| 197 | 198 |
| 198 std::vector<uint16> deltas; | 199 std::vector<uint16> deltas; |
| 199 const size_t deltas_bytes = sizeof(deltas[0]) * header.deltas_size; | 200 const size_t deltas_bytes = sizeof(deltas[0]) * header.deltas_size; |
| 200 | 201 |
| 201 std::vector<SBFullHash> full_hashes; | 202 std::vector<SBFullHash> full_hashes; |
| 202 const size_t full_hashes_bytes = | 203 const size_t full_hashes_bytes = |
| 203 sizeof(full_hashes[0]) * header.full_hashes_size; | 204 sizeof(full_hashes[0]) * header.full_hashes_size; |
| 204 | 205 |
| 205 // Check for bogus sizes before allocating any space. | 206 // Check for bogus sizes before allocating any space. |
| 206 const size_t expected_bytes = sizeof(header) + | 207 const size_t expected_bytes = sizeof(header) + |
| 207 index_bytes + deltas_bytes + full_hashes_bytes + sizeof(MD5Digest); | 208 index_bytes + deltas_bytes + full_hashes_bytes + sizeof(MD5Digest); |
| 208 if (static_cast<int64>(expected_bytes) != size_64) | 209 if (static_cast<int64>(expected_bytes) != size_64) |
| 209 return scoped_ptr<PrefixSet>(); | 210 return scoped_ptr<const PrefixSet>(); |
| 210 | 211 |
| 211 // Read the index vector. Herb Sutter indicates that vectors are | 212 // Read the index vector. Herb Sutter indicates that vectors are |
| 212 // guaranteed to be contiuguous, so reading to where element 0 lives | 213 // guaranteed to be contiuguous, so reading to where element 0 lives |
| 213 // is valid. | 214 // is valid. |
| 214 if (header.index_size) { | 215 if (header.index_size) { |
| 215 index.resize(header.index_size); | 216 index.resize(header.index_size); |
| 216 read = fread(&(index[0]), sizeof(index[0]), index.size(), file.get()); | 217 read = fread(&(index[0]), sizeof(index[0]), index.size(), file.get()); |
| 217 if (read != index.size()) | 218 if (read != index.size()) |
| 218 return scoped_ptr<PrefixSet>(); | 219 return scoped_ptr<const PrefixSet>(); |
| 219 base::MD5Update(&context, | 220 base::MD5Update(&context, |
| 220 base::StringPiece(reinterpret_cast<char*>(&(index[0])), | 221 base::StringPiece(reinterpret_cast<char*>(&(index[0])), |
| 221 index_bytes)); | 222 index_bytes)); |
| 222 } | 223 } |
| 223 | 224 |
| 224 // Read vector of deltas. | 225 // Read vector of deltas. |
| 225 if (header.deltas_size) { | 226 if (header.deltas_size) { |
| 226 deltas.resize(header.deltas_size); | 227 deltas.resize(header.deltas_size); |
| 227 read = fread(&(deltas[0]), sizeof(deltas[0]), deltas.size(), file.get()); | 228 read = fread(&(deltas[0]), sizeof(deltas[0]), deltas.size(), file.get()); |
| 228 if (read != deltas.size()) | 229 if (read != deltas.size()) |
| 229 return scoped_ptr<PrefixSet>(); | 230 return scoped_ptr<const PrefixSet>(); |
| 230 base::MD5Update(&context, | 231 base::MD5Update(&context, |
| 231 base::StringPiece(reinterpret_cast<char*>(&(deltas[0])), | 232 base::StringPiece(reinterpret_cast<char*>(&(deltas[0])), |
| 232 deltas_bytes)); | 233 deltas_bytes)); |
| 233 } | 234 } |
| 234 | 235 |
| 235 // Read vector of full hashes. | 236 // Read vector of full hashes. |
| 236 if (header.full_hashes_size) { | 237 if (header.full_hashes_size) { |
| 237 full_hashes.resize(header.full_hashes_size); | 238 full_hashes.resize(header.full_hashes_size); |
| 238 read = fread(&(full_hashes[0]), sizeof(full_hashes[0]), full_hashes.size(), | 239 read = fread(&(full_hashes[0]), sizeof(full_hashes[0]), full_hashes.size(), |
| 239 file.get()); | 240 file.get()); |
| 240 if (read != full_hashes.size()) | 241 if (read != full_hashes.size()) |
| 241 return scoped_ptr<PrefixSet>(); | 242 return scoped_ptr<const PrefixSet>(); |
| 242 base::MD5Update(&context, | 243 base::MD5Update(&context, |
| 243 base::StringPiece( | 244 base::StringPiece( |
| 244 reinterpret_cast<char*>(&(full_hashes[0])), | 245 reinterpret_cast<char*>(&(full_hashes[0])), |
| 245 full_hashes_bytes)); | 246 full_hashes_bytes)); |
| 246 } | 247 } |
| 247 | 248 |
| 248 base::MD5Digest calculated_digest; | 249 base::MD5Digest calculated_digest; |
| 249 base::MD5Final(&calculated_digest, &context); | 250 base::MD5Final(&calculated_digest, &context); |
| 250 | 251 |
| 251 base::MD5Digest file_digest; | 252 base::MD5Digest file_digest; |
| 252 read = fread(&file_digest, sizeof(file_digest), 1, file.get()); | 253 read = fread(&file_digest, sizeof(file_digest), 1, file.get()); |
| 253 if (read != 1) | 254 if (read != 1) |
| 254 return scoped_ptr<PrefixSet>(); | 255 return scoped_ptr<const PrefixSet>(); |
| 255 | 256 |
| 256 if (0 != memcmp(&file_digest, &calculated_digest, sizeof(file_digest))) | 257 if (0 != memcmp(&file_digest, &calculated_digest, sizeof(file_digest))) |
| 257 return scoped_ptr<PrefixSet>(); | 258 return scoped_ptr<const PrefixSet>(); |
| 258 | 259 |
| 259 // Steals vector contents using swap(). | 260 // Steals vector contents using swap(). |
| 260 return scoped_ptr<PrefixSet>(new PrefixSet(&index, &deltas, &full_hashes)); | 261 return scoped_ptr<const PrefixSet>( |
|
mattm
2014/12/03 23:08:19
does make_scoped_ptr work here?
gab
2014/12/04 20:30:20
Surprisingly, yes :-)!
(I expected it to fail as
| |
| 262 new PrefixSet(&index, &deltas, &full_hashes)); | |
| 261 } | 263 } |
| 262 | 264 |
| 263 bool PrefixSet::WriteFile(const base::FilePath& filter_name) const { | 265 bool PrefixSet::WriteFile(const base::FilePath& filter_name) const { |
| 264 FileHeader header; | 266 FileHeader header; |
| 265 header.magic = kMagic; | 267 header.magic = kMagic; |
| 266 header.version = kVersion; | 268 header.version = kVersion; |
| 267 header.index_size = static_cast<uint32>(index_.size()); | 269 header.index_size = static_cast<uint32>(index_.size()); |
| 268 header.deltas_size = static_cast<uint32>(deltas_.size()); | 270 header.deltas_size = static_cast<uint32>(deltas_.size()); |
| 269 header.full_hashes_size = static_cast<uint32>(full_hashes_.size()); | 271 header.full_hashes_size = static_cast<uint32>(full_hashes_.size()); |
| 270 | 272 |
| (...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 362 PrefixSetBuilder::PrefixSetBuilder(const std::vector<SBPrefix>& prefixes) | 364 PrefixSetBuilder::PrefixSetBuilder(const std::vector<SBPrefix>& prefixes) |
| 363 : prefix_set_(new PrefixSet()) { | 365 : prefix_set_(new PrefixSet()) { |
| 364 for (size_t i = 0; i < prefixes.size(); ++i) { | 366 for (size_t i = 0; i < prefixes.size(); ++i) { |
| 365 AddPrefix(prefixes[i]); | 367 AddPrefix(prefixes[i]); |
| 366 } | 368 } |
| 367 } | 369 } |
| 368 | 370 |
| 369 PrefixSetBuilder::~PrefixSetBuilder() { | 371 PrefixSetBuilder::~PrefixSetBuilder() { |
| 370 } | 372 } |
| 371 | 373 |
| 372 scoped_ptr<PrefixSet> PrefixSetBuilder::GetPrefixSet( | 374 scoped_ptr<const PrefixSet> PrefixSetBuilder::GetPrefixSet( |
| 373 const std::vector<SBFullHash>& hashes) { | 375 const std::vector<SBFullHash>& hashes) { |
| 374 DCHECK(prefix_set_.get()); | 376 DCHECK(prefix_set_.get()); |
| 375 | 377 |
| 376 // Flush runs until buffered data is gone. | 378 // Flush runs until buffered data is gone. |
| 377 while (!buffer_.empty()) { | 379 while (!buffer_.empty()) { |
| 378 EmitRun(); | 380 EmitRun(); |
| 379 } | 381 } |
| 380 | 382 |
| 381 // Precisely size |index_| for read-only. It's 50k-60k, so minor savings, but | 383 // Precisely size |index_| for read-only. It's 50k-60k, so minor savings, but |
| 382 // they're almost free. | 384 // they're almost free. |
| 383 PrefixSet::IndexVector(prefix_set_->index_).swap(prefix_set_->index_); | 385 PrefixSet::IndexVector(prefix_set_->index_).swap(prefix_set_->index_); |
| 384 | 386 |
| 385 prefix_set_->full_hashes_ = hashes; | 387 prefix_set_->full_hashes_ = hashes; |
| 386 std::sort(prefix_set_->full_hashes_.begin(), prefix_set_->full_hashes_.end(), | 388 std::sort(prefix_set_->full_hashes_.begin(), prefix_set_->full_hashes_.end(), |
| 387 SBFullHashLess); | 389 SBFullHashLess); |
| 388 | 390 |
| 389 return prefix_set_.Pass(); | 391 return prefix_set_.Pass(); |
| 390 } | 392 } |
| 391 | 393 |
| 392 scoped_ptr<PrefixSet> PrefixSetBuilder::GetPrefixSetNoHashes() { | 394 scoped_ptr<const PrefixSet> PrefixSetBuilder::GetPrefixSetNoHashes() { |
| 393 return GetPrefixSet(std::vector<SBFullHash>()).Pass(); | 395 return GetPrefixSet(std::vector<SBFullHash>()).Pass(); |
| 394 } | 396 } |
| 395 | 397 |
| 396 void PrefixSetBuilder::EmitRun() { | 398 void PrefixSetBuilder::EmitRun() { |
| 397 DCHECK(prefix_set_.get()); | 399 DCHECK(prefix_set_.get()); |
| 398 | 400 |
| 399 SBPrefix prev_prefix = buffer_[0]; | 401 SBPrefix prev_prefix = buffer_[0]; |
| 400 uint16 run[PrefixSet::kMaxRun]; | 402 uint16 run[PrefixSet::kMaxRun]; |
| 401 size_t run_pos = 0; | 403 size_t run_pos = 0; |
| 402 | 404 |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 437 } | 439 } |
| 438 buffer_.push_back(prefix); | 440 buffer_.push_back(prefix); |
| 439 | 441 |
| 440 // Flush buffer when a run can be constructed. +1 for the index item, and +1 | 442 // Flush buffer when a run can be constructed. +1 for the index item, and +1 |
| 441 // to leave at least one item in the buffer for dropping duplicates. | 443 // to leave at least one item in the buffer for dropping duplicates. |
| 442 if (buffer_.size() > PrefixSet::kMaxRun + 2) | 444 if (buffer_.size() > PrefixSet::kMaxRun + 2) |
| 443 EmitRun(); | 445 EmitRun(); |
| 444 } | 446 } |
| 445 | 447 |
| 446 } // namespace safe_browsing | 448 } // namespace safe_browsing |
| OLD | NEW |