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 3 // found in the LICENSE file. 4 5 #include "net/disk_cache/simple/simple_synchronous_entry.h" 6 7 #include <algorithm> 8 #include <cstring> 9 #include <functional> 10 #include <limits> 11 12 #include "base/basictypes.h" 13 #include "base/compiler_specific.h" 14 #include "base/file_util.h" 15 #include "base/hash.h" 16 #include "base/location.h" 17 #include "base/metrics/histogram.h" 18 #include "base/sha1.h" 19 #include "base/strings/stringprintf.h" 20 #include "net/base/io_buffer.h" 21 #include "net/base/net_errors.h" 22 #include "net/disk_cache/simple/simple_util.h" 23 #include "third_party/zlib/zlib.h" 24 25 using base::kInvalidPlatformFileValue; 26 using base::ClosePlatformFile; 27 using base::FilePath; 28 using base::GetPlatformFileInfo; 29 using base::PlatformFileError; 30 using base::PlatformFileInfo; 31 using base::PLATFORM_FILE_CREATE; 32 using base::PLATFORM_FILE_ERROR_EXISTS; 33 using base::PLATFORM_FILE_OK; 34 using base::PLATFORM_FILE_OPEN; 35 using base::PLATFORM_FILE_READ; 36 using base::PLATFORM_FILE_WRITE; 37 using base::ReadPlatformFile; 38 using base::Time; 39 using base::TruncatePlatformFile; 40 using base::WritePlatformFile; 41 42 namespace { 43 44 // Used in histograms, please only add entries at the end. 45 enum OpenEntryResult { 46 OPEN_ENTRY_SUCCESS = 0, 47 OPEN_ENTRY_PLATFORM_FILE_ERROR = 1, 48 OPEN_ENTRY_CANT_READ_HEADER = 2, 49 OPEN_ENTRY_BAD_MAGIC_NUMBER = 3, 50 OPEN_ENTRY_BAD_VERSION = 4, 51 OPEN_ENTRY_CANT_READ_KEY = 5, 52 // OPEN_ENTRY_KEY_MISMATCH = 6, Deprecated. 53 OPEN_ENTRY_KEY_HASH_MISMATCH = 7, 54 OPEN_ENTRY_MAX = 8, 55 }; 56 57 // Used in histograms, please only add entries at the end. 58 enum CreateEntryResult { 59 CREATE_ENTRY_SUCCESS = 0, 60 CREATE_ENTRY_PLATFORM_FILE_ERROR = 1, 61 CREATE_ENTRY_CANT_WRITE_HEADER = 2, 62 CREATE_ENTRY_CANT_WRITE_KEY = 3, 63 CREATE_ENTRY_MAX = 4, 64 }; 65 66 // Used in histograms, please only add entries at the end. 67 enum WriteResult { 68 WRITE_RESULT_SUCCESS = 0, 69 WRITE_RESULT_PRETRUNCATE_FAILURE, 70 WRITE_RESULT_WRITE_FAILURE, 71 WRITE_RESULT_TRUNCATE_FAILURE, 72 WRITE_RESULT_MAX, 73 }; 74 75 // Used in histograms, please only add entries at the end. 76 enum CheckEOFResult { 77 CHECK_EOF_RESULT_SUCCESS, 78 CHECK_EOF_RESULT_READ_FAILURE, 79 CHECK_EOF_RESULT_MAGIC_NUMBER_MISMATCH, 80 CHECK_EOF_RESULT_CRC_MISMATCH, 81 CHECK_EOF_RESULT_MAX, 82 }; 83 84 // Used in histograms, please only add entries at the end. 85 enum CloseResult { 86 CLOSE_RESULT_SUCCESS, 87 CLOSE_RESULT_WRITE_FAILURE, 88 }; 89 90 void RecordSyncOpenResult(OpenEntryResult result, bool had_index) { 91 DCHECK_GT(OPEN_ENTRY_MAX, result); 92 UMA_HISTOGRAM_ENUMERATION( 93 "SimpleCache.SyncOpenResult", result, OPEN_ENTRY_MAX); 94 if (had_index) { 95 UMA_HISTOGRAM_ENUMERATION( 96 "SimpleCache.SyncOpenResult_WithIndex", result, OPEN_ENTRY_MAX); 97 } else { 98 UMA_HISTOGRAM_ENUMERATION( 99 "SimpleCache.SyncOpenResult_WithoutIndex", result, OPEN_ENTRY_MAX); 100 } 101 } 102 103 void RecordSyncCreateResult(CreateEntryResult result, bool had_index) { 104 DCHECK_GT(CREATE_ENTRY_MAX, result); 105 UMA_HISTOGRAM_ENUMERATION( 106 "SimpleCache.SyncCreateResult", result, CREATE_ENTRY_MAX); 107 if (had_index) { 108 UMA_HISTOGRAM_ENUMERATION( 109 "SimpleCache.SyncCreateResult_WithIndex", result, CREATE_ENTRY_MAX); 110 } else { 111 UMA_HISTOGRAM_ENUMERATION( 112 "SimpleCache.SyncCreateResult_WithoutIndex", result, CREATE_ENTRY_MAX); 113 } 114 } 115 116 void RecordWriteResult(WriteResult result) { 117 UMA_HISTOGRAM_ENUMERATION( 118 "SimpleCache.SyncWriteResult", result, WRITE_RESULT_MAX); 119 } 120 121 void RecordCheckEOFResult(CheckEOFResult result) { 122 UMA_HISTOGRAM_ENUMERATION( 123 "SimpleCache.SyncCheckEOFResult", result, CHECK_EOF_RESULT_MAX); 124 } 125 126 void RecordCloseResult(CloseResult result) { 127 UMA_HISTOGRAM_ENUMERATION( 128 "SimpleCache.SyncCloseResult", result, WRITE_RESULT_MAX); 129 } 130 131 } // namespace 132 133 namespace disk_cache { 134 135 using simple_util::ConvertEntryHashKeyToHexString; 136 using simple_util::GetEntryHashKey; 137 using simple_util::GetFilenameFromEntryHashAndIndex; 138 using simple_util::GetDataSizeFromKeyAndFileSize; 139 using simple_util::GetFileSizeFromKeyAndDataSize; 140 using simple_util::GetFileOffsetFromKeyAndDataOffset; 141 142 SimpleEntryStat::SimpleEntryStat() {} 143 144 SimpleEntryStat::SimpleEntryStat(base::Time last_used_p, 145 base::Time last_modified_p, 146 const int32 data_size_p[]) 147 : last_used(last_used_p), 148 last_modified(last_modified_p) { 149 memcpy(data_size, data_size_p, sizeof(data_size)); 150 } 151 152 SimpleEntryCreationResults::SimpleEntryCreationResults( 153 SimpleEntryStat entry_stat) 154 : sync_entry(NULL), 155 entry_stat(entry_stat), 156 result(net::OK) { 157 } 158 159 SimpleEntryCreationResults::~SimpleEntryCreationResults() { 160 } 161 162 SimpleSynchronousEntry::CRCRecord::CRCRecord() : index(-1), 163 has_crc32(false), 164 data_crc32(0) { 165 } 166 167 SimpleSynchronousEntry::CRCRecord::CRCRecord(int index_p, 168 bool has_crc32_p, 169 uint32 data_crc32_p) 170 : index(index_p), 171 has_crc32(has_crc32_p), 172 data_crc32(data_crc32_p) {} 173 174 SimpleSynchronousEntry::EntryOperationData::EntryOperationData(int index_p, 175 int offset_p, 176 int buf_len_p) 177 : index(index_p), 178 offset(offset_p), 179 buf_len(buf_len_p) {} 180 181 SimpleSynchronousEntry::EntryOperationData::EntryOperationData(int index_p, 182 int offset_p, 183 int buf_len_p, 184 bool truncate_p) 185 : index(index_p), 186 offset(offset_p), 187 buf_len(buf_len_p), 188 truncate(truncate_p) {} 189 190 // static 191 void SimpleSynchronousEntry::OpenEntry( 192 const FilePath& path, 193 const uint64 entry_hash, 194 bool had_index, 195 SimpleEntryCreationResults *out_results) { 196 SimpleSynchronousEntry* sync_entry = new SimpleSynchronousEntry(path, "", 197 entry_hash); 198 out_results->result = sync_entry->InitializeForOpen( 199 had_index, &out_results->entry_stat); 200 if (out_results->result != net::OK) { 201 sync_entry->Doom(); 202 delete sync_entry; 203 out_results->sync_entry = NULL; 204 return; 205 } 206 out_results->sync_entry = sync_entry; 207 } 208 209 // static 210 void SimpleSynchronousEntry::CreateEntry( 211 const FilePath& path, 212 const std::string& key, 213 const uint64 entry_hash, 214 bool had_index, 215 SimpleEntryCreationResults *out_results) { 216 DCHECK_EQ(entry_hash, GetEntryHashKey(key)); 217 SimpleSynchronousEntry* sync_entry = new SimpleSynchronousEntry(path, key, 218 entry_hash); 219 out_results->result = sync_entry->InitializeForCreate( 220 had_index, &out_results->entry_stat); 221 if (out_results->result != net::OK) { 222 if (out_results->result != net::ERR_FILE_EXISTS) 223 sync_entry->Doom(); 224 delete sync_entry; 225 out_results->sync_entry = NULL; 226 return; 227 } 228 out_results->sync_entry = sync_entry; 229 } 230 231 // TODO(gavinp): Move this function to its correct location in this .cc file. 232 // static 233 bool SimpleSynchronousEntry::DeleteFilesForEntryHash( 234 const FilePath& path, 235 const uint64 entry_hash) { 236 bool result = true; 237 for (int i = 0; i < kSimpleEntryFileCount; ++i) { 238 FilePath to_delete = path.AppendASCII( 239 GetFilenameFromEntryHashAndIndex(entry_hash, i)); 240 if (!base::DeleteFile(to_delete, false)) { 241 result = false; 242 DLOG(ERROR) << "Could not delete " << to_delete.MaybeAsASCII(); 243 } 244 } 245 return result; 246 } 247 248 // static 249 void SimpleSynchronousEntry::DoomEntry( 250 const FilePath& path, 251 const std::string& key, 252 uint64 entry_hash, 253 int* out_result) { 254 DCHECK_EQ(entry_hash, GetEntryHashKey(key)); 255 bool deleted_well = DeleteFilesForEntryHash(path, entry_hash); 256 *out_result = deleted_well ? net::OK : net::ERR_FAILED; 257 } 258 259 // static 260 int SimpleSynchronousEntry::DoomEntrySet( 261 scoped_ptr<std::vector<uint64> > key_hashes, 262 const FilePath& path) { 263 const size_t did_delete_count = std::count_if( 264 key_hashes->begin(), key_hashes->end(), std::bind1st( 265 std::ptr_fun(SimpleSynchronousEntry::DeleteFilesForEntryHash), path)); 266 return (did_delete_count == key_hashes->size()) ? net::OK : net::ERR_FAILED; 267 } 268 269 void SimpleSynchronousEntry::ReadData(const EntryOperationData& in_entry_op, 270 net::IOBuffer* out_buf, 271 uint32* out_crc32, 272 base::Time* out_last_used, 273 int* out_result) const { 274 DCHECK(initialized_); 275 int64 file_offset = 276 GetFileOffsetFromKeyAndDataOffset(key_, in_entry_op.offset); 277 int bytes_read = ReadPlatformFile(files_[in_entry_op.index], 278 file_offset, 279 out_buf->data(), 280 in_entry_op.buf_len); 281 if (bytes_read > 0) { 282 *out_last_used = Time::Now(); 283 *out_crc32 = crc32(crc32(0L, Z_NULL, 0), 284 reinterpret_cast<const Bytef*>(out_buf->data()), 285 bytes_read); 286 } 287 if (bytes_read >= 0) { 288 *out_result = bytes_read; 289 } else { 290 *out_result = net::ERR_CACHE_READ_FAILURE; 291 Doom(); 292 } 293 } 294 295 void SimpleSynchronousEntry::WriteData(const EntryOperationData& in_entry_op, 296 net::IOBuffer* in_buf, 297 SimpleEntryStat* out_entry_stat, 298 int* out_result) const { 299 DCHECK(initialized_); 300 int index = in_entry_op.index; 301 int offset = in_entry_op.offset; 302 int buf_len = in_entry_op.buf_len; 303 int truncate = in_entry_op.truncate; 304 305 bool extending_by_write = offset + buf_len > out_entry_stat->data_size[index]; 306 if (extending_by_write) { 307 // We are extending the file, and need to insure the EOF record is zeroed. 308 const int64 file_eof_offset = GetFileOffsetFromKeyAndDataOffset( 309 key_, out_entry_stat->data_size[index]); 310 if (!TruncatePlatformFile(files_[index], file_eof_offset)) { 311 RecordWriteResult(WRITE_RESULT_PRETRUNCATE_FAILURE); 312 Doom(); 313 *out_result = net::ERR_CACHE_WRITE_FAILURE; 314 return; 315 } 316 } 317 const int64 file_offset = GetFileOffsetFromKeyAndDataOffset(key_, offset); 318 if (buf_len > 0) { 319 if (WritePlatformFile( 320 files_[index], file_offset, in_buf->data(), buf_len) != buf_len) { 321 RecordWriteResult(WRITE_RESULT_WRITE_FAILURE); 322 Doom(); 323 *out_result = net::ERR_CACHE_WRITE_FAILURE; 324 return; 325 } 326 } 327 if (!truncate && (buf_len > 0 || !extending_by_write)) { 328 out_entry_stat->data_size[index] = 329 std::max(out_entry_stat->data_size[index], offset + buf_len); 330 } else { 331 if (!TruncatePlatformFile(files_[index], file_offset + buf_len)) { 332 RecordWriteResult(WRITE_RESULT_TRUNCATE_FAILURE); 333 Doom(); 334 *out_result = net::ERR_CACHE_WRITE_FAILURE; 335 return; 336 } 337 out_entry_stat->data_size[index] = offset + buf_len; 338 } 339 340 RecordWriteResult(WRITE_RESULT_SUCCESS); 341 out_entry_stat->last_used = out_entry_stat->last_modified = Time::Now(); 342 *out_result = buf_len; 343 } 344 345 void SimpleSynchronousEntry::CheckEOFRecord(int index, 346 int32 data_size, 347 uint32 expected_crc32, 348 int* out_result) const { 349 DCHECK(initialized_); 350 351 SimpleFileEOF eof_record; 352 int64 file_offset = GetFileOffsetFromKeyAndDataOffset(key_, data_size); 353 if (ReadPlatformFile(files_[index], 354 file_offset, 355 reinterpret_cast<char*>(&eof_record), 356 sizeof(eof_record)) != sizeof(eof_record)) { 357 RecordCheckEOFResult(CHECK_EOF_RESULT_READ_FAILURE); 358 Doom(); 359 *out_result = net::ERR_CACHE_CHECKSUM_READ_FAILURE; 360 return; 361 } 362 363 if (eof_record.final_magic_number != kSimpleFinalMagicNumber) { 364 RecordCheckEOFResult(CHECK_EOF_RESULT_MAGIC_NUMBER_MISMATCH); 365 DLOG(INFO) << "eof record had bad magic number."; 366 Doom(); 367 *out_result = net::ERR_CACHE_CHECKSUM_READ_FAILURE; 368 return; 369 } 370 371 const bool has_crc = (eof_record.flags & SimpleFileEOF::FLAG_HAS_CRC32) == 372 SimpleFileEOF::FLAG_HAS_CRC32; 373 UMA_HISTOGRAM_BOOLEAN("SimpleCache.SyncCheckEOFHasCrc", has_crc); 374 if (has_crc && eof_record.data_crc32 != expected_crc32) { 375 RecordCheckEOFResult(CHECK_EOF_RESULT_CRC_MISMATCH); 376 DLOG(INFO) << "eof record had bad crc."; 377 Doom(); 378 *out_result = net::ERR_CACHE_CHECKSUM_MISMATCH; 379 return; 380 } 381 382 RecordCheckEOFResult(CHECK_EOF_RESULT_SUCCESS); 383 *out_result = net::OK; 384 } 385 386 void SimpleSynchronousEntry::Close( 387 const SimpleEntryStat& entry_stat, 388 scoped_ptr<std::vector<CRCRecord> > crc32s_to_write) { 389 for (std::vector<CRCRecord>::const_iterator it = crc32s_to_write->begin(); 390 it != crc32s_to_write->end(); ++it) { 391 SimpleFileEOF eof_record; 392 eof_record.final_magic_number = kSimpleFinalMagicNumber; 393 eof_record.flags = 0; 394 if (it->has_crc32) 395 eof_record.flags |= SimpleFileEOF::FLAG_HAS_CRC32; 396 eof_record.data_crc32 = it->data_crc32; 397 int64 file_offset = GetFileOffsetFromKeyAndDataOffset( 398 key_, entry_stat.data_size[it->index]); 399 if (WritePlatformFile(files_[it->index], 400 file_offset, 401 reinterpret_cast<const char*>(&eof_record), 402 sizeof(eof_record)) != sizeof(eof_record)) { 403 RecordCloseResult(CLOSE_RESULT_WRITE_FAILURE); 404 DLOG(INFO) << "Could not write eof record."; 405 Doom(); 406 break; 407 } 408 const int64 file_size = file_offset + sizeof(eof_record); 409 UMA_HISTOGRAM_CUSTOM_COUNTS("SimpleCache.LastClusterSize", 410 file_size % 4096, 0, 4097, 50); 411 const int64 cluster_loss = file_size % 4096 ? 4096 - file_size % 4096 : 0; 412 UMA_HISTOGRAM_PERCENTAGE("SimpleCache.LastClusterLossPercent", 413 cluster_loss * 100 / (cluster_loss + file_size)); 414 } 415 416 for (int i = 0; i < kSimpleEntryFileCount; ++i) { 417 bool did_close_file = ClosePlatformFile(files_[i]); 418 CHECK(did_close_file); 419 } 420 RecordCloseResult(CLOSE_RESULT_SUCCESS); 421 have_open_files_ = false; 422 delete this; 423 } 424 425 SimpleSynchronousEntry::SimpleSynchronousEntry(const FilePath& path, 426 const std::string& key, 427 const uint64 entry_hash) 428 : path_(path), 429 entry_hash_(entry_hash), 430 key_(key), 431 have_open_files_(false), 432 initialized_(false) { 433 for (int i = 0; i < kSimpleEntryFileCount; ++i) { 434 files_[i] = kInvalidPlatformFileValue; 435 } 436 } 437 438 SimpleSynchronousEntry::~SimpleSynchronousEntry() { 439 DCHECK(!(have_open_files_ && initialized_)); 440 if (have_open_files_) 441 CloseFiles(); 442 } 443 444 bool SimpleSynchronousEntry::OpenOrCreateFiles( 445 bool create, 446 bool had_index, 447 SimpleEntryStat* out_entry_stat) { 448 for (int i = 0; i < kSimpleEntryFileCount; ++i) { 449 FilePath filename = path_.AppendASCII( 450 GetFilenameFromEntryHashAndIndex(entry_hash_, i)); 451 int flags = PLATFORM_FILE_READ | PLATFORM_FILE_WRITE; 452 if (create) 453 flags |= PLATFORM_FILE_CREATE; 454 else 455 flags |= PLATFORM_FILE_OPEN; 456 PlatformFileError error; 457 files_[i] = CreatePlatformFile(filename, flags, NULL, &error); 458 if (error != PLATFORM_FILE_OK) { 459 // TODO(ttuttle,gavinp): Remove one each of these triplets of histograms. 460 // We can calculate the third as the sum or difference of the other two. 461 if (create) { 462 RecordSyncCreateResult(CREATE_ENTRY_PLATFORM_FILE_ERROR, had_index); 463 UMA_HISTOGRAM_ENUMERATION("SimpleCache.SyncCreatePlatformFileError", 464 -error, -base::PLATFORM_FILE_ERROR_MAX); 465 if (had_index) { 466 UMA_HISTOGRAM_ENUMERATION( 467 "SimpleCache.SyncCreatePlatformFileError_WithIndex", 468 -error, -base::PLATFORM_FILE_ERROR_MAX); 469 } else { 470 UMA_HISTOGRAM_ENUMERATION( 471 "SimpleCache.SyncCreatePlatformFileError_WithoutIndex", 472 -error, -base::PLATFORM_FILE_ERROR_MAX); 473 } 474 } else { 475 RecordSyncOpenResult(OPEN_ENTRY_PLATFORM_FILE_ERROR, had_index); 476 UMA_HISTOGRAM_ENUMERATION("SimpleCache.SyncOpenPlatformFileError", 477 -error, -base::PLATFORM_FILE_ERROR_MAX); 478 if (had_index) { 479 UMA_HISTOGRAM_ENUMERATION( 480 "SimpleCache.SyncOpenPlatformFileError_WithIndex", 481 -error, -base::PLATFORM_FILE_ERROR_MAX); 482 } else { 483 UMA_HISTOGRAM_ENUMERATION( 484 "SimpleCache.SyncOpenPlatformFileError_WithoutIndex", 485 -error, -base::PLATFORM_FILE_ERROR_MAX); 486 } 487 } 488 while (--i >= 0) { 489 bool ALLOW_UNUSED did_close = ClosePlatformFile(files_[i]); 490 DLOG_IF(INFO, !did_close) << "Could not close file " 491 << filename.MaybeAsASCII(); 492 } 493 return false; 494 } 495 } 496 497 have_open_files_ = true; 498 if (create) { 499 out_entry_stat->last_modified = out_entry_stat->last_used = Time::Now(); 500 for (int i = 0; i < kSimpleEntryFileCount; ++i) 501 out_entry_stat->data_size[i] = 0; 502 } else { 503 for (int i = 0; i < kSimpleEntryFileCount; ++i) { 504 PlatformFileInfo file_info; 505 bool success = GetPlatformFileInfo(files_[i], &file_info); 506 base::Time file_last_modified; 507 if (!success) { 508 DLOG(WARNING) << "Could not get platform file info."; 509 continue; 510 } 511 out_entry_stat->last_used = file_info.last_accessed; 512 if (simple_util::GetMTime(path_, &file_last_modified)) 513 out_entry_stat->last_modified = file_last_modified; 514 else 515 out_entry_stat->last_modified = file_info.last_modified; 516 517 // Keep the file size in |data size_| briefly until the key is initialized 518 // properly. 519 out_entry_stat->data_size[i] = file_info.size; 520 } 521 } 522 523 return true; 524 } 525 526 void SimpleSynchronousEntry::CloseFiles() { 527 for (int i = 0; i < kSimpleEntryFileCount; ++i) { 528 DCHECK_NE(kInvalidPlatformFileValue, files_[i]); 529 bool did_close = ClosePlatformFile(files_[i]); 530 DCHECK(did_close); 531 } 532 } 533 534 int SimpleSynchronousEntry::InitializeForOpen(bool had_index, 535 SimpleEntryStat* out_entry_stat) { 536 DCHECK(!initialized_); 537 if (!OpenOrCreateFiles(false, had_index, out_entry_stat)) 538 return net::ERR_FAILED; 539 540 for (int i = 0; i < kSimpleEntryFileCount; ++i) { 541 SimpleFileHeader header; 542 int header_read_result = 543 ReadPlatformFile(files_[i], 0, reinterpret_cast<char*>(&header), 544 sizeof(header)); 545 if (header_read_result != sizeof(header)) { 546 DLOG(WARNING) << "Cannot read header from entry."; 547 RecordSyncOpenResult(OPEN_ENTRY_CANT_READ_HEADER, had_index); 548 return net::ERR_FAILED; 549 } 550 551 if (header.initial_magic_number != kSimpleInitialMagicNumber) { 552 // TODO(gavinp): This seems very bad; for now we log at WARNING, but we 553 // should give consideration to not saturating the log with these if that 554 // becomes a problem. 555 DLOG(WARNING) << "Magic number did not match."; 556 RecordSyncOpenResult(OPEN_ENTRY_BAD_MAGIC_NUMBER, had_index); 557 return net::ERR_FAILED; 558 } 559 560 if (header.version != kSimpleVersion) { 561 DLOG(WARNING) << "Unreadable version."; 562 RecordSyncOpenResult(OPEN_ENTRY_BAD_VERSION, had_index); 563 return net::ERR_FAILED; 564 } 565 566 scoped_ptr<char[]> key(new char[header.key_length]); 567 int key_read_result = ReadPlatformFile(files_[i], sizeof(header), 568 key.get(), header.key_length); 569 if (key_read_result != implicit_cast<int>(header.key_length)) { 570 DLOG(WARNING) << "Cannot read key from entry."; 571 RecordSyncOpenResult(OPEN_ENTRY_CANT_READ_KEY, had_index); 572 return net::ERR_FAILED; 573 } 574 575 key_ = std::string(key.get(), header.key_length); 576 out_entry_stat->data_size[i] = 577 GetDataSizeFromKeyAndFileSize(key_, out_entry_stat->data_size[i]); 578 if (out_entry_stat->data_size[i] < 0) { 579 // This entry can't possibly be valid, as it does not have enough space to 580 // store a valid SimpleFileEOF record. 581 return net::ERR_FAILED; 582 } 583 584 if (base::Hash(key.get(), header.key_length) != header.key_hash) { 585 DLOG(WARNING) << "Hash mismatch on key."; 586 RecordSyncOpenResult(OPEN_ENTRY_KEY_HASH_MISMATCH, had_index); 587 return net::ERR_FAILED; 588 } 589 } 590 RecordSyncOpenResult(OPEN_ENTRY_SUCCESS, had_index); 591 initialized_ = true; 592 return net::OK; 593 } 594 595 int SimpleSynchronousEntry::InitializeForCreate( 596 bool had_index, 597 SimpleEntryStat* out_entry_stat) { 598 DCHECK(!initialized_); 599 if (!OpenOrCreateFiles(true, had_index, out_entry_stat)) { 600 DLOG(WARNING) << "Could not create platform files."; 601 return net::ERR_FILE_EXISTS; 602 } 603 for (int i = 0; i < kSimpleEntryFileCount; ++i) { 604 SimpleFileHeader header; 605 header.initial_magic_number = kSimpleInitialMagicNumber; 606 header.version = kSimpleVersion; 607 608 header.key_length = key_.size(); 609 header.key_hash = base::Hash(key_); 610 611 if (WritePlatformFile(files_[i], 0, reinterpret_cast<char*>(&header), 612 sizeof(header)) != sizeof(header)) { 613 DLOG(WARNING) << "Could not write headers to new cache entry."; 614 RecordSyncCreateResult(CREATE_ENTRY_CANT_WRITE_HEADER, had_index); 615 return net::ERR_FAILED; 616 } 617 618 if (WritePlatformFile(files_[i], sizeof(header), key_.data(), 619 key_.size()) != implicit_cast<int>(key_.size())) { 620 DLOG(WARNING) << "Could not write keys to new cache entry."; 621 RecordSyncCreateResult(CREATE_ENTRY_CANT_WRITE_KEY, had_index); 622 return net::ERR_FAILED; 623 } 624 } 625 RecordSyncCreateResult(CREATE_ENTRY_SUCCESS, had_index); 626 initialized_ = true; 627 return net::OK; 628 } 629 630 void SimpleSynchronousEntry::Doom() const { 631 // TODO(gavinp): Consider if we should guard against redundant Doom() calls. 632 DeleteFilesForEntryHash(path_, entry_hash_); 633 } 634 635 } // namespace disk_cache 636