OLD | NEW |
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2013 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 "net/disk_cache/simple/simple_synchronous_entry.h" | 5 #include "net/disk_cache/simple/simple_synchronous_entry.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 #include <cstring> | 8 #include <cstring> |
9 #include <functional> | 9 #include <functional> |
10 #include <limits> | 10 #include <limits> |
11 | 11 |
| 12 #include "base/command_line.h" |
12 #include "base/compiler_specific.h" | 13 #include "base/compiler_specific.h" |
13 #include "base/files/file_util.h" | 14 #include "base/files/file_util.h" |
14 #include "base/hash.h" | 15 #include "base/hash.h" |
15 #include "base/location.h" | 16 #include "base/location.h" |
16 #include "base/metrics/histogram_macros.h" | 17 #include "base/metrics/histogram_macros.h" |
17 #include "base/numerics/safe_conversions.h" | 18 #include "base/numerics/safe_conversions.h" |
18 #include "base/sha1.h" | 19 #include "base/sha1.h" |
19 #include "base/timer/elapsed_timer.h" | 20 #include "base/timer/elapsed_timer.h" |
20 #include "crypto/secure_hash.h" | 21 #include "crypto/secure_hash.h" |
21 #include "net/base/hash_value.h" | 22 #include "net/base/hash_value.h" |
(...skipping 1063 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1085 if (key_ != key_from_header) { | 1086 if (key_ != key_from_header) { |
1086 RecordSyncOpenResult(cache_type_, OPEN_ENTRY_KEY_MISMATCH, had_index_); | 1087 RecordSyncOpenResult(cache_type_, OPEN_ENTRY_KEY_MISMATCH, had_index_); |
1087 return false; | 1088 return false; |
1088 } | 1089 } |
1089 } | 1090 } |
1090 | 1091 |
1091 header_and_key_check_needed_[file_index] = false; | 1092 header_and_key_check_needed_[file_index] = false; |
1092 return true; | 1093 return true; |
1093 } | 1094 } |
1094 | 1095 |
| 1096 bool SimpleSynchronousEntry::ReadStream0Data( |
| 1097 SimpleEntryStat* out_entry_stat, |
| 1098 scoped_refptr<net::GrowableIOBuffer>* stream_0_data, |
| 1099 uint32_t* out_stream_0_crc32) { |
| 1100 // How many bytes in the entry file are consumed by metadata. |
| 1101 const size_t header_overhead_bytes = sizeof(SimpleFileHeader) + key_.size(); |
| 1102 size_t total_overhead_bytes = header_overhead_bytes + 2 * sizeof(SimpleFileEOF
); |
| 1103 |
| 1104 int32_t file_size = out_entry_stat->data_size(1); |
| 1105 if (static_cast<int>(total_overhead_bytes) > file_size) |
| 1106 return false; |
| 1107 |
| 1108 // Initially make an aligned read of at least 32k (or read the entire file), |
| 1109 // which should be large enough to retrieve the stream 0 data and both EOF |
| 1110 // records. |
| 1111 std::vector<char> tail_data(std::min(file_size, |
| 1112 8192 + file_size % 4096)); |
| 1113 int bytes_read = files_[0].Read(file_size - tail_data.size(), |
| 1114 tail_data.data(), tail_data.size()); |
| 1115 if (bytes_read != static_cast<int>(tail_data.size())) |
| 1116 return false; |
| 1117 |
| 1118 const SimpleFileEOF* stream_0_eof = reinterpret_cast<const SimpleFileEOF*>(tai
l_data.data() + tail_data.size() - sizeof(SimpleFileEOF)); |
| 1119 |
| 1120 if (stream_0_eof->final_magic_number != kSimpleFinalMagicNumber) |
| 1121 return false; |
| 1122 if (!base::IsValueInRangeForNumericType<int32_t>(stream_0_eof->stream_size)) |
| 1123 return false; |
| 1124 const int32_t stream_0_size = stream_0_eof->stream_size; |
| 1125 |
| 1126 const bool has_key_sha256 = (stream_0_eof->flags & SimpleFileEOF::FLAG_HAS_KEY
_SHA256) == SimpleFileEOF::FLAG_HAS_KEY_SHA256; |
| 1127 const bool has_crc32 = (stream_0_eof->flags & SimpleFileEOF::FLAG_HAS_CRC32) =
= SimpleFileEOF::FLAG_HAS_CRC32; |
| 1128 const uint32_t data_crc32 = stream_0_eof->data_crc32; |
| 1129 // Clear |stream_0_eof| because subsequent vector resize operations may invali
date it. |
| 1130 stream_0_eof = nullptr; |
| 1131 |
| 1132 base::CheckedNumeric<size_t> tail_bytes_needed = 2 * sizeof(SimpleFileEOF); |
| 1133 if (has_key_sha256) { |
| 1134 total_overhead_bytes += sizeof(net::SHA256HashValue); |
| 1135 tail_bytes_needed += sizeof(net::SHA256HashValue); |
| 1136 } |
| 1137 if (stream_0_size > file_size - static_cast<int>(total_overhead_bytes)) |
| 1138 return false; |
| 1139 |
| 1140 tail_bytes_needed += stream_0_size; |
| 1141 if (!tail_bytes_needed.IsValid()) |
| 1142 return false; |
| 1143 size_t safe_tail_bytes_needed = tail_bytes_needed.ValueOrDie(); |
| 1144 if (safe_tail_bytes_needed > file_size - header_overhead_bytes) |
| 1145 return false; |
| 1146 if (safe_tail_bytes_needed > tail_data.size()) { |
| 1147 // The tail read was too short, we need to enlarge the buffer and read the e
xtra |
| 1148 // data. |
| 1149 size_t missing_bytes = safe_tail_bytes_needed - tail_data.size(); |
| 1150 if (!base::IsValueInRangeForNumericType<int>(missing_bytes)) |
| 1151 return false; |
| 1152 |
| 1153 LOG(INFO) << "doing a second read. Originally " << tail_data.size() << ", bu
t need " << safe_tail_bytes_needed << ", so reading " << missing_bytes; |
| 1154 LOG(INFO) << "key length " << key_.size(); |
| 1155 tail_data.resize(safe_tail_bytes_needed); |
| 1156 std::copy_backward(tail_data.begin(), tail_data.end() - missing_bytes, |
| 1157 tail_data.end()); |
| 1158 if (files_[0].Read(file_size - safe_tail_bytes_needed, |
| 1159 tail_data.data(), missing_bytes) != static_cast<int>(miss
ing_bytes)) { |
| 1160 return false; |
| 1161 } |
| 1162 } |
| 1163 |
| 1164 // Calculate and set the real values for data size. |
| 1165 out_entry_stat->set_data_size(0, stream_0_size); |
| 1166 out_entry_stat->set_data_size(1, file_size - total_overhead_bytes - stream_0_s
ize); |
| 1167 |
| 1168 // Copy stream 0 data. |
| 1169 *stream_0_data = new net::GrowableIOBuffer(); |
| 1170 (*stream_0_data)->SetCapacity(out_entry_stat->data_size(0)); |
| 1171 std::copy_n(tail_data.end() - safe_tail_bytes_needed + sizeof(SimpleFileEOF), |
| 1172 stream_0_size, (*stream_0_data)->data()); |
| 1173 |
| 1174 // Check the CRC32. |
| 1175 uint32_t expected_crc32 = crc32(0, Z_NULL, 0); |
| 1176 if (stream_0_size != 0) { |
| 1177 expected_crc32 = crc32(expected_crc32, |
| 1178 reinterpret_cast<const Bytef*>((*stream_0_data)->data
()), |
| 1179 stream_0_size); |
| 1180 } |
| 1181 if (has_crc32 && data_crc32 != expected_crc32) { |
| 1182 return false; |
| 1183 } |
| 1184 *out_stream_0_crc32 = expected_crc32; |
| 1185 |
| 1186 if (has_key_sha256) { |
| 1187 net::SHA256HashValue hash_value; |
| 1188 CalculateSHA256OfKey(key_, &hash_value); |
| 1189 bool matched = std::memcmp(&hash_value, tail_data.data() + tail_data.size()
- sizeof(SimpleFileEOF) - sizeof(hash_value), sizeof(hash_value)) == 0; |
| 1190 if (!matched) { |
| 1191 return false; |
| 1192 } |
| 1193 } |
| 1194 |
| 1195 if (!has_key_sha256 && header_and_key_check_needed_[0]) |
| 1196 CheckHeaderAndKey(0); |
| 1197 return true; |
| 1198 } |
| 1199 |
1095 int SimpleSynchronousEntry::InitializeForOpen( | 1200 int SimpleSynchronousEntry::InitializeForOpen( |
1096 SimpleEntryStat* out_entry_stat, | 1201 SimpleEntryStat* out_entry_stat, |
1097 scoped_refptr<net::GrowableIOBuffer>* stream_0_data, | 1202 scoped_refptr<net::GrowableIOBuffer>* stream_0_data, |
1098 uint32_t* out_stream_0_crc32) { | 1203 uint32_t* out_stream_0_crc32) { |
1099 DCHECK(!initialized_); | 1204 DCHECK(!initialized_); |
1100 if (!OpenFiles(out_entry_stat)) { | 1205 if (!OpenFiles(out_entry_stat)) { |
1101 DLOG(WARNING) << "Could not open platform files for entry."; | 1206 DLOG(WARNING) << "Could not open platform files for entry."; |
1102 return net::ERR_FAILED; | 1207 return net::ERR_FAILED; |
1103 } | 1208 } |
1104 for (int i = 0; i < kSimpleEntryFileCount; ++i) { | 1209 for (int i = 0; i < kSimpleEntryFileCount; ++i) { |
(...skipping 10 matching lines...) Expand all Loading... |
1115 } else { | 1220 } else { |
1116 // If we do know which key were are looking for, we still need to | 1221 // If we do know which key were are looking for, we still need to |
1117 // check that the file actually has it (rather than just being a hash | 1222 // check that the file actually has it (rather than just being a hash |
1118 // collision or some sort of file system accident), but that can be put | 1223 // collision or some sort of file system accident), but that can be put |
1119 // off until opportune time: either the read of the footer, or when we | 1224 // off until opportune time: either the read of the footer, or when we |
1120 // start reading in the data, depending on stream # and format revision. | 1225 // start reading in the data, depending on stream # and format revision. |
1121 header_and_key_check_needed_[i] = true; | 1226 header_and_key_check_needed_[i] = true; |
1122 } | 1227 } |
1123 | 1228 |
1124 if (i == 0) { | 1229 if (i == 0) { |
1125 // File size for stream 0 has been stored temporarily in data_size[1]. | 1230 if (base::CommandLine::ForCurrentProcess()->HasSwitch("backseek")) { |
1126 int ret_value_stream_0 = | 1231 if (!ReadStream0Data(out_entry_stat, stream_0_data, out_stream_0_crc32)) |
1127 ReadAndValidateStream0(out_entry_stat->data_size(1), out_entry_stat, | 1232 return net::ERR_FAILED; |
1128 stream_0_data, out_stream_0_crc32); | 1233 } else { |
1129 if (ret_value_stream_0 != net::OK) | 1234 // File size for stream 0 has been stored temporarily in data_size[1]. |
1130 return ret_value_stream_0; | 1235 int ret_value_stream_0 = |
| 1236 ReadAndValidateStream0(out_entry_stat->data_size(1), out_entry_stat, |
| 1237 stream_0_data, out_stream_0_crc32); |
| 1238 if (ret_value_stream_0 != net::OK) |
| 1239 return ret_value_stream_0; |
| 1240 } |
1131 } else { | 1241 } else { |
1132 out_entry_stat->set_data_size( | 1242 out_entry_stat->set_data_size( |
1133 2, | 1243 2, |
1134 GetDataSizeFromFileSize(key_.size(), out_entry_stat->data_size(2))); | 1244 GetDataSizeFromFileSize(key_.size(), out_entry_stat->data_size(2))); |
1135 if (out_entry_stat->data_size(2) < 0) { | 1245 if (out_entry_stat->data_size(2) < 0) { |
1136 DLOG(WARNING) << "Stream 2 file is too small."; | 1246 DLOG(WARNING) << "Stream 2 file is too small."; |
1137 return net::ERR_FAILED; | 1247 return net::ERR_FAILED; |
1138 } | 1248 } |
1139 } | 1249 } |
1140 } | 1250 } |
(...skipping 500 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1641 range.offset = offset; | 1751 range.offset = offset; |
1642 range.length = len; | 1752 range.length = len; |
1643 range.data_crc32 = data_crc32; | 1753 range.data_crc32 = data_crc32; |
1644 range.file_offset = data_file_offset; | 1754 range.file_offset = data_file_offset; |
1645 sparse_ranges_.insert(std::make_pair(offset, range)); | 1755 sparse_ranges_.insert(std::make_pair(offset, range)); |
1646 | 1756 |
1647 return true; | 1757 return true; |
1648 } | 1758 } |
1649 | 1759 |
1650 } // namespace disk_cache | 1760 } // namespace disk_cache |
OLD | NEW |