| Index: net/disk_cache/simple/simple_synchronous_entry.cc
|
| diff --git a/net/disk_cache/simple/simple_synchronous_entry.cc b/net/disk_cache/simple/simple_synchronous_entry.cc
|
| index cb9700211d977052eb75623fd41d4b8832d98e8b..9e2e6e9f433d8d90e2680b2a68a5edecaa804676 100644
|
| --- a/net/disk_cache/simple/simple_synchronous_entry.cc
|
| +++ b/net/disk_cache/simple/simple_synchronous_entry.cc
|
| @@ -9,6 +9,7 @@
|
| #include <functional>
|
| #include <limits>
|
|
|
| +#include "base/command_line.h"
|
| #include "base/compiler_specific.h"
|
| #include "base/files/file_util.h"
|
| #include "base/hash.h"
|
| @@ -1092,6 +1093,110 @@ bool SimpleSynchronousEntry::CheckHeaderAndKey(int file_index) {
|
| return true;
|
| }
|
|
|
| +bool SimpleSynchronousEntry::ReadStream0Data(
|
| + SimpleEntryStat* out_entry_stat,
|
| + scoped_refptr<net::GrowableIOBuffer>* stream_0_data,
|
| + uint32_t* out_stream_0_crc32) {
|
| + // How many bytes in the entry file are consumed by metadata.
|
| + const size_t header_overhead_bytes = sizeof(SimpleFileHeader) + key_.size();
|
| + size_t total_overhead_bytes = header_overhead_bytes + 2 * sizeof(SimpleFileEOF);
|
| +
|
| + int32_t file_size = out_entry_stat->data_size(1);
|
| + if (static_cast<int>(total_overhead_bytes) > file_size)
|
| + return false;
|
| +
|
| + // Initially make an aligned read of at least 32k (or read the entire file),
|
| + // which should be large enough to retrieve the stream 0 data and both EOF
|
| + // records.
|
| + std::vector<char> tail_data(std::min(file_size,
|
| + 8192 + file_size % 4096));
|
| + int bytes_read = files_[0].Read(file_size - tail_data.size(),
|
| + tail_data.data(), tail_data.size());
|
| + if (bytes_read != static_cast<int>(tail_data.size()))
|
| + return false;
|
| +
|
| + const SimpleFileEOF* stream_0_eof = reinterpret_cast<const SimpleFileEOF*>(tail_data.data() + tail_data.size() - sizeof(SimpleFileEOF));
|
| +
|
| + if (stream_0_eof->final_magic_number != kSimpleFinalMagicNumber)
|
| + return false;
|
| + if (!base::IsValueInRangeForNumericType<int32_t>(stream_0_eof->stream_size))
|
| + return false;
|
| + const int32_t stream_0_size = stream_0_eof->stream_size;
|
| +
|
| + const bool has_key_sha256 = (stream_0_eof->flags & SimpleFileEOF::FLAG_HAS_KEY_SHA256) == SimpleFileEOF::FLAG_HAS_KEY_SHA256;
|
| + const bool has_crc32 = (stream_0_eof->flags & SimpleFileEOF::FLAG_HAS_CRC32) == SimpleFileEOF::FLAG_HAS_CRC32;
|
| + const uint32_t data_crc32 = stream_0_eof->data_crc32;
|
| + // Clear |stream_0_eof| because subsequent vector resize operations may invalidate it.
|
| + stream_0_eof = nullptr;
|
| +
|
| + base::CheckedNumeric<size_t> tail_bytes_needed = 2 * sizeof(SimpleFileEOF);
|
| + if (has_key_sha256) {
|
| + total_overhead_bytes += sizeof(net::SHA256HashValue);
|
| + tail_bytes_needed += sizeof(net::SHA256HashValue);
|
| + }
|
| + if (stream_0_size > file_size - static_cast<int>(total_overhead_bytes))
|
| + return false;
|
| +
|
| + tail_bytes_needed += stream_0_size;
|
| + if (!tail_bytes_needed.IsValid())
|
| + return false;
|
| + size_t safe_tail_bytes_needed = tail_bytes_needed.ValueOrDie();
|
| + if (safe_tail_bytes_needed > file_size - header_overhead_bytes)
|
| + return false;
|
| + if (safe_tail_bytes_needed > tail_data.size()) {
|
| + // The tail read was too short, we need to enlarge the buffer and read the extra
|
| + // data.
|
| + size_t missing_bytes = safe_tail_bytes_needed - tail_data.size();
|
| + if (!base::IsValueInRangeForNumericType<int>(missing_bytes))
|
| + return false;
|
| +
|
| + LOG(INFO) << "doing a second read. Originally " << tail_data.size() << ", but need " << safe_tail_bytes_needed << ", so reading " << missing_bytes;
|
| + LOG(INFO) << "key length " << key_.size();
|
| + tail_data.resize(safe_tail_bytes_needed);
|
| + std::copy_backward(tail_data.begin(), tail_data.end() - missing_bytes,
|
| + tail_data.end());
|
| + if (files_[0].Read(file_size - safe_tail_bytes_needed,
|
| + tail_data.data(), missing_bytes) != static_cast<int>(missing_bytes)) {
|
| + return false;
|
| + }
|
| + }
|
| +
|
| + // Calculate and set the real values for data size.
|
| + out_entry_stat->set_data_size(0, stream_0_size);
|
| + out_entry_stat->set_data_size(1, file_size - total_overhead_bytes - stream_0_size);
|
| +
|
| + // Copy stream 0 data.
|
| + *stream_0_data = new net::GrowableIOBuffer();
|
| + (*stream_0_data)->SetCapacity(out_entry_stat->data_size(0));
|
| + std::copy_n(tail_data.end() - safe_tail_bytes_needed + sizeof(SimpleFileEOF),
|
| + stream_0_size, (*stream_0_data)->data());
|
| +
|
| + // Check the CRC32.
|
| + uint32_t expected_crc32 = crc32(0, Z_NULL, 0);
|
| + if (stream_0_size != 0) {
|
| + expected_crc32 = crc32(expected_crc32,
|
| + reinterpret_cast<const Bytef*>((*stream_0_data)->data()),
|
| + stream_0_size);
|
| + }
|
| + if (has_crc32 && data_crc32 != expected_crc32) {
|
| + return false;
|
| + }
|
| + *out_stream_0_crc32 = expected_crc32;
|
| +
|
| + if (has_key_sha256) {
|
| + net::SHA256HashValue hash_value;
|
| + CalculateSHA256OfKey(key_, &hash_value);
|
| + bool matched = std::memcmp(&hash_value, tail_data.data() + tail_data.size() - sizeof(SimpleFileEOF) - sizeof(hash_value), sizeof(hash_value)) == 0;
|
| + if (!matched) {
|
| + return false;
|
| + }
|
| + }
|
| +
|
| + if (!has_key_sha256 && header_and_key_check_needed_[0])
|
| + CheckHeaderAndKey(0);
|
| + return true;
|
| +}
|
| +
|
| int SimpleSynchronousEntry::InitializeForOpen(
|
| SimpleEntryStat* out_entry_stat,
|
| scoped_refptr<net::GrowableIOBuffer>* stream_0_data,
|
| @@ -1122,12 +1227,17 @@ int SimpleSynchronousEntry::InitializeForOpen(
|
| }
|
|
|
| if (i == 0) {
|
| - // File size for stream 0 has been stored temporarily in data_size[1].
|
| - int ret_value_stream_0 =
|
| - ReadAndValidateStream0(out_entry_stat->data_size(1), out_entry_stat,
|
| - stream_0_data, out_stream_0_crc32);
|
| - if (ret_value_stream_0 != net::OK)
|
| - return ret_value_stream_0;
|
| + if (base::CommandLine::ForCurrentProcess()->HasSwitch("backseek")) {
|
| + if (!ReadStream0Data(out_entry_stat, stream_0_data, out_stream_0_crc32))
|
| + return net::ERR_FAILED;
|
| + } else {
|
| + // File size for stream 0 has been stored temporarily in data_size[1].
|
| + int ret_value_stream_0 =
|
| + ReadAndValidateStream0(out_entry_stat->data_size(1), out_entry_stat,
|
| + stream_0_data, out_stream_0_crc32);
|
| + if (ret_value_stream_0 != net::OK)
|
| + return ret_value_stream_0;
|
| + }
|
| } else {
|
| out_entry_stat->set_data_size(
|
| 2,
|
|
|