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/sha1.h" 18 #include "base/strings/stringprintf.h" 19 #include "net/base/io_buffer.h" 20 #include "net/base/net_errors.h" 21 #include "net/disk_cache/simple/simple_backend_version.h" 22 #include "net/disk_cache/simple/simple_histogram_macros.h" 23 #include "net/disk_cache/simple/simple_util.h" 24 #include "third_party/zlib/zlib.h" 25 26 using base::kInvalidPlatformFileValue; 27 using base::ClosePlatformFile; 28 using base::FilePath; 29 using base::GetPlatformFileInfo; 30 using base::PlatformFileError; 31 using base::PlatformFileInfo; 32 using base::PLATFORM_FILE_CREATE; 33 using base::PLATFORM_FILE_ERROR_EXISTS; 34 using base::PLATFORM_FILE_ERROR_NOT_FOUND; 35 using base::PLATFORM_FILE_OK; 36 using base::PLATFORM_FILE_OPEN; 37 using base::PLATFORM_FILE_OPEN_ALWAYS; 38 using base::PLATFORM_FILE_READ; 39 using base::PLATFORM_FILE_WRITE; 40 using base::ReadPlatformFile; 41 using base::Time; 42 using base::TruncatePlatformFile; 43 using base::WritePlatformFile; 44 45 namespace { 46 47 // Used in histograms, please only add entries at the end. 48 enum OpenEntryResult { 49 OPEN_ENTRY_SUCCESS = 0, 50 OPEN_ENTRY_PLATFORM_FILE_ERROR = 1, 51 OPEN_ENTRY_CANT_READ_HEADER = 2, 52 OPEN_ENTRY_BAD_MAGIC_NUMBER = 3, 53 OPEN_ENTRY_BAD_VERSION = 4, 54 OPEN_ENTRY_CANT_READ_KEY = 5, 55 // OPEN_ENTRY_KEY_MISMATCH = 6, Deprecated. 56 OPEN_ENTRY_KEY_HASH_MISMATCH = 7, 57 OPEN_ENTRY_SPARSE_OPEN_FAILED = 8, 58 OPEN_ENTRY_MAX = 9, 59 }; 60 61 // Used in histograms, please only add entries at the end. 62 enum WriteResult { 63 WRITE_RESULT_SUCCESS = 0, 64 WRITE_RESULT_PRETRUNCATE_FAILURE, 65 WRITE_RESULT_WRITE_FAILURE, 66 WRITE_RESULT_TRUNCATE_FAILURE, 67 WRITE_RESULT_LAZY_STREAM_ENTRY_DOOMED, 68 WRITE_RESULT_LAZY_CREATE_FAILURE, 69 WRITE_RESULT_LAZY_INITIALIZE_FAILURE, 70 WRITE_RESULT_MAX, 71 }; 72 73 // Used in histograms, please only add entries at the end. 74 enum CheckEOFResult { 75 CHECK_EOF_RESULT_SUCCESS, 76 CHECK_EOF_RESULT_READ_FAILURE, 77 CHECK_EOF_RESULT_MAGIC_NUMBER_MISMATCH, 78 CHECK_EOF_RESULT_CRC_MISMATCH, 79 CHECK_EOF_RESULT_MAX, 80 }; 81 82 // Used in histograms, please only add entries at the end. 83 enum CloseResult { 84 CLOSE_RESULT_SUCCESS, 85 CLOSE_RESULT_WRITE_FAILURE, 86 }; 87 88 void RecordSyncOpenResult(net::CacheType cache_type, 89 OpenEntryResult result, 90 bool had_index) { 91 DCHECK_GT(OPEN_ENTRY_MAX, result); 92 SIMPLE_CACHE_UMA(ENUMERATION, 93 "SyncOpenResult", cache_type, result, OPEN_ENTRY_MAX); 94 if (had_index) { 95 SIMPLE_CACHE_UMA(ENUMERATION, 96 "SyncOpenResult_WithIndex", cache_type, 97 result, OPEN_ENTRY_MAX); 98 } else { 99 SIMPLE_CACHE_UMA(ENUMERATION, 100 "SyncOpenResult_WithoutIndex", cache_type, 101 result, OPEN_ENTRY_MAX); 102 } 103 } 104 105 void RecordWriteResult(net::CacheType cache_type, WriteResult result) { 106 SIMPLE_CACHE_UMA(ENUMERATION, 107 "SyncWriteResult", cache_type, result, WRITE_RESULT_MAX); 108 } 109 110 void RecordCheckEOFResult(net::CacheType cache_type, CheckEOFResult result) { 111 SIMPLE_CACHE_UMA(ENUMERATION, 112 "SyncCheckEOFResult", cache_type, 113 result, CHECK_EOF_RESULT_MAX); 114 } 115 116 void RecordCloseResult(net::CacheType cache_type, CloseResult result) { 117 SIMPLE_CACHE_UMA(ENUMERATION, 118 "SyncCloseResult", cache_type, result, WRITE_RESULT_MAX); 119 } 120 121 bool CanOmitEmptyFile(int file_index) { 122 DCHECK_LE(0, file_index); 123 DCHECK_GT(disk_cache::kSimpleEntryFileCount, file_index); 124 return file_index == disk_cache::simple_util::GetFileIndexFromStreamIndex(2); 125 } 126 127 } // namespace 128 129 namespace disk_cache { 130 131 using simple_util::GetEntryHashKey; 132 using simple_util::GetFilenameFromEntryHashAndFileIndex; 133 using simple_util::GetSparseFilenameFromEntryHash; 134 using simple_util::GetDataSizeFromKeyAndFileSize; 135 using simple_util::GetFileSizeFromKeyAndDataSize; 136 using simple_util::GetFileIndexFromStreamIndex; 137 138 SimpleEntryStat::SimpleEntryStat(base::Time last_used, 139 base::Time last_modified, 140 const int32 data_size[], 141 const int32 sparse_data_size) 142 : last_used_(last_used), 143 last_modified_(last_modified), 144 sparse_data_size_(sparse_data_size) { 145 memcpy(data_size_, data_size, sizeof(data_size_)); 146 } 147 148 int SimpleEntryStat::GetOffsetInFile(const std::string& key, 149 int offset, 150 int stream_index) const { 151 const int64 headers_size = sizeof(SimpleFileHeader) + key.size(); 152 const int64 additional_offset = 153 stream_index == 0 ? data_size_[1] + sizeof(SimpleFileEOF) : 0; 154 return headers_size + offset + additional_offset; 155 } 156 157 int SimpleEntryStat::GetEOFOffsetInFile(const std::string& key, 158 int stream_index) const { 159 return GetOffsetInFile(key, data_size_[stream_index], stream_index); 160 } 161 162 int SimpleEntryStat::GetLastEOFOffsetInFile(const std::string& key, 163 int stream_index) const { 164 const int file_index = GetFileIndexFromStreamIndex(stream_index); 165 const int eof_data_offset = 166 file_index == 0 ? data_size_[0] + data_size_[1] + sizeof(SimpleFileEOF) 167 : data_size_[2]; 168 return GetOffsetInFile(key, eof_data_offset, stream_index); 169 } 170 171 int SimpleEntryStat::GetFileSize(const std::string& key, int file_index) const { 172 const int total_data_size = 173 file_index == 0 ? data_size_[0] + data_size_[1] + sizeof(SimpleFileEOF) 174 : data_size_[2]; 175 return GetFileSizeFromKeyAndDataSize(key, total_data_size); 176 } 177 178 SimpleEntryCreationResults::SimpleEntryCreationResults( 179 SimpleEntryStat entry_stat) 180 : sync_entry(NULL), 181 entry_stat(entry_stat), 182 stream_0_crc32(crc32(0, Z_NULL, 0)), 183 result(net::OK) { 184 } 185 186 SimpleEntryCreationResults::~SimpleEntryCreationResults() { 187 } 188 189 SimpleSynchronousEntry::CRCRecord::CRCRecord() : index(-1), 190 has_crc32(false), 191 data_crc32(0) { 192 } 193 194 SimpleSynchronousEntry::CRCRecord::CRCRecord(int index_p, 195 bool has_crc32_p, 196 uint32 data_crc32_p) 197 : index(index_p), 198 has_crc32(has_crc32_p), 199 data_crc32(data_crc32_p) {} 200 201 SimpleSynchronousEntry::EntryOperationData::EntryOperationData(int index_p, 202 int offset_p, 203 int buf_len_p) 204 : index(index_p), 205 offset(offset_p), 206 buf_len(buf_len_p) {} 207 208 SimpleSynchronousEntry::EntryOperationData::EntryOperationData(int index_p, 209 int offset_p, 210 int buf_len_p, 211 bool truncate_p, 212 bool doomed_p) 213 : index(index_p), 214 offset(offset_p), 215 buf_len(buf_len_p), 216 truncate(truncate_p), 217 doomed(doomed_p) {} 218 219 SimpleSynchronousEntry::EntryOperationData::EntryOperationData( 220 int64 sparse_offset_p, 221 int buf_len_p) 222 : sparse_offset(sparse_offset_p), 223 buf_len(buf_len_p) {} 224 225 // static 226 void SimpleSynchronousEntry::OpenEntry( 227 net::CacheType cache_type, 228 const FilePath& path, 229 const uint64 entry_hash, 230 bool had_index, 231 SimpleEntryCreationResults *out_results) { 232 SimpleSynchronousEntry* sync_entry = 233 new SimpleSynchronousEntry(cache_type, path, "", entry_hash); 234 out_results->result = 235 sync_entry->InitializeForOpen(had_index, 236 &out_results->entry_stat, 237 &out_results->stream_0_data, 238 &out_results->stream_0_crc32); 239 if (out_results->result != net::OK) { 240 sync_entry->Doom(); 241 delete sync_entry; 242 out_results->sync_entry = NULL; 243 out_results->stream_0_data = NULL; 244 return; 245 } 246 out_results->sync_entry = sync_entry; 247 } 248 249 // static 250 void SimpleSynchronousEntry::CreateEntry( 251 net::CacheType cache_type, 252 const FilePath& path, 253 const std::string& key, 254 const uint64 entry_hash, 255 bool had_index, 256 SimpleEntryCreationResults *out_results) { 257 DCHECK_EQ(entry_hash, GetEntryHashKey(key)); 258 SimpleSynchronousEntry* sync_entry = 259 new SimpleSynchronousEntry(cache_type, path, key, entry_hash); 260 out_results->result = sync_entry->InitializeForCreate( 261 had_index, &out_results->entry_stat); 262 if (out_results->result != net::OK) { 263 if (out_results->result != net::ERR_FILE_EXISTS) 264 sync_entry->Doom(); 265 delete sync_entry; 266 out_results->sync_entry = NULL; 267 return; 268 } 269 out_results->sync_entry = sync_entry; 270 } 271 272 // static 273 int SimpleSynchronousEntry::DoomEntry( 274 const FilePath& path, 275 uint64 entry_hash) { 276 const bool deleted_well = DeleteFilesForEntryHash(path, entry_hash); 277 return deleted_well ? net::OK : net::ERR_FAILED; 278 } 279 280 // static 281 int SimpleSynchronousEntry::DoomEntrySet( 282 const std::vector<uint64>* key_hashes, 283 const FilePath& path) { 284 const size_t did_delete_count = std::count_if( 285 key_hashes->begin(), key_hashes->end(), std::bind1st( 286 std::ptr_fun(SimpleSynchronousEntry::DeleteFilesForEntryHash), path)); 287 return (did_delete_count == key_hashes->size()) ? net::OK : net::ERR_FAILED; 288 } 289 290 void SimpleSynchronousEntry::ReadData(const EntryOperationData& in_entry_op, 291 net::IOBuffer* out_buf, 292 uint32* out_crc32, 293 SimpleEntryStat* entry_stat, 294 int* out_result) const { 295 DCHECK(initialized_); 296 DCHECK_NE(0, in_entry_op.index); 297 const int64 file_offset = 298 entry_stat->GetOffsetInFile(key_, in_entry_op.offset, in_entry_op.index); 299 int file_index = GetFileIndexFromStreamIndex(in_entry_op.index); 300 // Zero-length reads and reads to the empty streams of omitted files should 301 // be handled in the SimpleEntryImpl. 302 DCHECK_LT(0, in_entry_op.buf_len); 303 DCHECK(!empty_file_omitted_[file_index]); 304 int bytes_read = ReadPlatformFile( 305 files_[file_index], file_offset, out_buf->data(), in_entry_op.buf_len); 306 if (bytes_read > 0) { 307 entry_stat->set_last_used(Time::Now()); 308 *out_crc32 = crc32(crc32(0L, Z_NULL, 0), 309 reinterpret_cast<const Bytef*>(out_buf->data()), 310 bytes_read); 311 } 312 if (bytes_read >= 0) { 313 *out_result = bytes_read; 314 } else { 315 *out_result = net::ERR_CACHE_READ_FAILURE; 316 Doom(); 317 } 318 } 319 320 void SimpleSynchronousEntry::WriteData(const EntryOperationData& in_entry_op, 321 net::IOBuffer* in_buf, 322 SimpleEntryStat* out_entry_stat, 323 int* out_result) { 324 DCHECK(initialized_); 325 DCHECK_NE(0, in_entry_op.index); 326 int index = in_entry_op.index; 327 int file_index = GetFileIndexFromStreamIndex(index); 328 int offset = in_entry_op.offset; 329 int buf_len = in_entry_op.buf_len; 330 bool truncate = in_entry_op.truncate; 331 bool doomed = in_entry_op.doomed; 332 const int64 file_offset = out_entry_stat->GetOffsetInFile( 333 key_, in_entry_op.offset, in_entry_op.index); 334 bool extending_by_write = offset + buf_len > out_entry_stat->data_size(index); 335 336 if (empty_file_omitted_[file_index]) { 337 // Don't create a new file if the entry has been doomed, to avoid it being 338 // mixed up with a newly-created entry with the same key. 339 if (doomed) { 340 DLOG(WARNING) << "Rejecting write to lazily omitted stream " 341 << in_entry_op.index << " of doomed cache entry."; 342 RecordWriteResult(cache_type_, WRITE_RESULT_LAZY_STREAM_ENTRY_DOOMED); 343 *out_result = net::ERR_CACHE_WRITE_FAILURE; 344 return; 345 } 346 PlatformFileError error; 347 if (!MaybeCreateFile(file_index, FILE_REQUIRED, &error)) { 348 RecordWriteResult(cache_type_, WRITE_RESULT_LAZY_CREATE_FAILURE); 349 Doom(); 350 *out_result = net::ERR_CACHE_WRITE_FAILURE; 351 return; 352 } 353 CreateEntryResult result; 354 if (!InitializeCreatedFile(file_index, &result)) { 355 RecordWriteResult(cache_type_, WRITE_RESULT_LAZY_INITIALIZE_FAILURE); 356 Doom(); 357 *out_result = net::ERR_CACHE_WRITE_FAILURE; 358 return; 359 } 360 } 361 DCHECK(!empty_file_omitted_[file_index]); 362 363 if (extending_by_write) { 364 // The EOF record and the eventual stream afterward need to be zeroed out. 365 const int64 file_eof_offset = 366 out_entry_stat->GetEOFOffsetInFile(key_, index); 367 if (!TruncatePlatformFile(files_[file_index], file_eof_offset)) { 368 RecordWriteResult(cache_type_, WRITE_RESULT_PRETRUNCATE_FAILURE); 369 Doom(); 370 *out_result = net::ERR_CACHE_WRITE_FAILURE; 371 return; 372 } 373 } 374 if (buf_len > 0) { 375 if (WritePlatformFile( 376 files_[file_index], file_offset, in_buf->data(), buf_len) != 377 buf_len) { 378 RecordWriteResult(cache_type_, WRITE_RESULT_WRITE_FAILURE); 379 Doom(); 380 *out_result = net::ERR_CACHE_WRITE_FAILURE; 381 return; 382 } 383 } 384 if (!truncate && (buf_len > 0 || !extending_by_write)) { 385 out_entry_stat->set_data_size( 386 index, std::max(out_entry_stat->data_size(index), offset + buf_len)); 387 } else { 388 out_entry_stat->set_data_size(index, offset + buf_len); 389 int file_eof_offset = out_entry_stat->GetLastEOFOffsetInFile(key_, index); 390 if (!TruncatePlatformFile(files_[file_index], file_eof_offset)) { 391 RecordWriteResult(cache_type_, WRITE_RESULT_TRUNCATE_FAILURE); 392 Doom(); 393 *out_result = net::ERR_CACHE_WRITE_FAILURE; 394 return; 395 } 396 } 397 398 RecordWriteResult(cache_type_, WRITE_RESULT_SUCCESS); 399 base::Time modification_time = Time::Now(); 400 out_entry_stat->set_last_used(modification_time); 401 out_entry_stat->set_last_modified(modification_time); 402 *out_result = buf_len; 403 } 404 405 void SimpleSynchronousEntry::ReadSparseData( 406 const EntryOperationData& in_entry_op, 407 net::IOBuffer* out_buf, 408 base::Time* out_last_used, 409 int* out_result) { 410 DCHECK(initialized_); 411 int64 offset = in_entry_op.sparse_offset; 412 int buf_len = in_entry_op.buf_len; 413 414 char* buf = out_buf->data(); 415 int read_so_far = 0; 416 417 // Find the first sparse range at or after the requested offset. 418 SparseRangeIterator it = sparse_ranges_.lower_bound(offset); 419 420 if (it != sparse_ranges_.begin()) { 421 // Hop back one range and read the one overlapping with the start. 422 --it; 423 SparseRange* found_range = &it->second; 424 DCHECK_EQ(it->first, found_range->offset); 425 if (found_range->offset + found_range->length > offset) { 426 DCHECK_LE(0, found_range->length); 427 DCHECK_GE(kint32max, found_range->length); 428 DCHECK_LE(0, offset - found_range->offset); 429 DCHECK_GE(kint32max, offset - found_range->offset); 430 int range_len_after_offset = found_range->length - 431 (offset - found_range->offset); 432 DCHECK_LE(0, range_len_after_offset); 433 434 int len_to_read = std::min(buf_len, range_len_after_offset); 435 if (!ReadSparseRange(found_range, 436 offset - found_range->offset, 437 len_to_read, 438 buf)) { 439 *out_result = net::ERR_CACHE_READ_FAILURE; 440 return; 441 } 442 read_so_far += len_to_read; 443 } 444 ++it; 445 } 446 447 // Keep reading until the buffer is full or there is not another contiguous 448 // range. 449 while (read_so_far < buf_len && 450 it != sparse_ranges_.end() && 451 it->second.offset == offset + read_so_far) { 452 SparseRange* found_range = &it->second; 453 DCHECK_EQ(it->first, found_range->offset); 454 int range_len = (found_range->length > kint32max) ? 455 kint32max : found_range->length; 456 int len_to_read = std::min(buf_len - read_so_far, range_len); 457 if (!ReadSparseRange(found_range, 0, len_to_read, buf + read_so_far)) { 458 *out_result = net::ERR_CACHE_READ_FAILURE; 459 return; 460 } 461 read_so_far += len_to_read; 462 ++it; 463 } 464 465 *out_result = read_so_far; 466 } 467 468 void SimpleSynchronousEntry::WriteSparseData( 469 const EntryOperationData& in_entry_op, 470 net::IOBuffer* in_buf, 471 int64 max_sparse_data_size, 472 SimpleEntryStat* out_entry_stat, 473 int* out_result) { 474 DCHECK(initialized_); 475 int64 offset = in_entry_op.sparse_offset; 476 int buf_len = in_entry_op.buf_len; 477 478 const char* buf = in_buf->data(); 479 int written_so_far = 0; 480 int appended_so_far = 0; 481 482 if (!sparse_file_open() && !CreateSparseFile()) { 483 *out_result = net::ERR_CACHE_WRITE_FAILURE; 484 return; 485 } 486 487 int64 sparse_data_size = out_entry_stat->sparse_data_size(); 488 // This is a pessimistic estimate; it assumes the entire buffer is going to 489 // be appended as a new range, not written over existing ranges. 490 if (sparse_data_size + buf_len > max_sparse_data_size) { 491 DLOG(INFO) << "Truncating sparse data file (" << sparse_data_size << " + " 492 << buf_len << " > " << max_sparse_data_size << ")"; 493 TruncateSparseFile(); 494 } 495 496 SparseRangeIterator it = sparse_ranges_.lower_bound(offset); 497 498 if (it != sparse_ranges_.begin()) { 499 --it; 500 SparseRange* found_range = &it->second; 501 if (found_range->offset + found_range->length > offset) { 502 DCHECK_LE(0, found_range->length); 503 DCHECK_GE(kint32max, found_range->length); 504 DCHECK_LE(0, offset - found_range->offset); 505 DCHECK_GE(kint32max, offset - found_range->offset); 506 int range_len_after_offset = found_range->length - 507 (offset - found_range->offset); 508 DCHECK_LE(0, range_len_after_offset); 509 510 int len_to_write = std::min(buf_len, range_len_after_offset); 511 if (!WriteSparseRange(found_range, 512 offset - found_range->offset, 513 len_to_write, 514 buf)) { 515 *out_result = net::ERR_CACHE_WRITE_FAILURE; 516 return; 517 } 518 written_so_far += len_to_write; 519 } 520 ++it; 521 } 522 523 while (written_so_far < buf_len && 524 it != sparse_ranges_.end() && 525 it->second.offset < offset + buf_len) { 526 SparseRange* found_range = &it->second; 527 if (offset + written_so_far < found_range->offset) { 528 int len_to_append = found_range->offset - (offset + written_so_far); 529 if (!AppendSparseRange(offset + written_so_far, 530 len_to_append, 531 buf + written_so_far)) { 532 *out_result = net::ERR_CACHE_WRITE_FAILURE; 533 return; 534 } 535 written_so_far += len_to_append; 536 appended_so_far += len_to_append; 537 } 538 int range_len = (found_range->length > kint32max) ? 539 kint32max : found_range->length; 540 int len_to_write = std::min(buf_len - written_so_far, range_len); 541 if (!WriteSparseRange(found_range, 542 0, 543 len_to_write, 544 buf + written_so_far)) { 545 *out_result = net::ERR_CACHE_WRITE_FAILURE; 546 return; 547 } 548 written_so_far += len_to_write; 549 ++it; 550 } 551 552 if (written_so_far < buf_len) { 553 int len_to_append = buf_len - written_so_far; 554 if (!AppendSparseRange(offset + written_so_far, 555 len_to_append, 556 buf + written_so_far)) { 557 *out_result = net::ERR_CACHE_WRITE_FAILURE; 558 return; 559 } 560 written_so_far += len_to_append; 561 appended_so_far += len_to_append; 562 } 563 564 DCHECK_EQ(buf_len, written_so_far); 565 566 base::Time modification_time = Time::Now(); 567 out_entry_stat->set_last_used(modification_time); 568 out_entry_stat->set_last_modified(modification_time); 569 int32 old_sparse_data_size = out_entry_stat->sparse_data_size(); 570 out_entry_stat->set_sparse_data_size(old_sparse_data_size + appended_so_far); 571 *out_result = written_so_far; 572 } 573 574 void SimpleSynchronousEntry::GetAvailableRange( 575 const EntryOperationData& in_entry_op, 576 int64* out_start, 577 int* out_result) { 578 DCHECK(initialized_); 579 int64 offset = in_entry_op.sparse_offset; 580 int len = in_entry_op.buf_len; 581 582 SparseRangeIterator it = sparse_ranges_.lower_bound(offset); 583 584 int64 start = offset; 585 int avail_so_far = 0; 586 587 if (it != sparse_ranges_.end() && it->second.offset < offset + len) 588 start = it->second.offset; 589 590 if ((it == sparse_ranges_.end() || it->second.offset > offset) && 591 it != sparse_ranges_.begin()) { 592 --it; 593 if (it->second.offset + it->second.length > offset) { 594 start = offset; 595 avail_so_far = (it->second.offset + it->second.length) - offset; 596 } 597 ++it; 598 } 599 600 while (start + avail_so_far < offset + len && 601 it != sparse_ranges_.end() && 602 it->second.offset == start + avail_so_far) { 603 avail_so_far += it->second.length; 604 ++it; 605 } 606 607 int len_from_start = len - (start - offset); 608 *out_start = start; 609 *out_result = std::min(avail_so_far, len_from_start); 610 } 611 612 void SimpleSynchronousEntry::CheckEOFRecord(int index, 613 const SimpleEntryStat& entry_stat, 614 uint32 expected_crc32, 615 int* out_result) const { 616 DCHECK(initialized_); 617 uint32 crc32; 618 bool has_crc32; 619 int stream_size; 620 *out_result = 621 GetEOFRecordData(index, entry_stat, &has_crc32, &crc32, &stream_size); 622 if (*out_result != net::OK) { 623 Doom(); 624 return; 625 } 626 if (has_crc32 && crc32 != expected_crc32) { 627 DLOG(INFO) << "EOF record had bad crc."; 628 *out_result = net::ERR_CACHE_CHECKSUM_MISMATCH; 629 RecordCheckEOFResult(cache_type_, CHECK_EOF_RESULT_CRC_MISMATCH); 630 Doom(); 631 return; 632 } 633 RecordCheckEOFResult(cache_type_, CHECK_EOF_RESULT_SUCCESS); 634 } 635 636 void SimpleSynchronousEntry::Close( 637 const SimpleEntryStat& entry_stat, 638 scoped_ptr<std::vector<CRCRecord> > crc32s_to_write, 639 net::GrowableIOBuffer* stream_0_data) { 640 DCHECK(stream_0_data); 641 // Write stream 0 data. 642 int stream_0_offset = entry_stat.GetOffsetInFile(key_, 0, 0); 643 if (WritePlatformFile(files_[0], 644 stream_0_offset, 645 stream_0_data->data(), 646 entry_stat.data_size(0)) != entry_stat.data_size(0)) { 647 RecordCloseResult(cache_type_, CLOSE_RESULT_WRITE_FAILURE); 648 DLOG(INFO) << "Could not write stream 0 data."; 649 Doom(); 650 } 651 652 for (std::vector<CRCRecord>::const_iterator it = crc32s_to_write->begin(); 653 it != crc32s_to_write->end(); ++it) { 654 const int stream_index = it->index; 655 const int file_index = GetFileIndexFromStreamIndex(stream_index); 656 if (empty_file_omitted_[file_index]) 657 continue; 658 659 SimpleFileEOF eof_record; 660 eof_record.stream_size = entry_stat.data_size(stream_index); 661 eof_record.final_magic_number = kSimpleFinalMagicNumber; 662 eof_record.flags = 0; 663 if (it->has_crc32) 664 eof_record.flags |= SimpleFileEOF::FLAG_HAS_CRC32; 665 eof_record.data_crc32 = it->data_crc32; 666 int eof_offset = entry_stat.GetEOFOffsetInFile(key_, stream_index); 667 // If stream 0 changed size, the file needs to be resized, otherwise the 668 // next open will yield wrong stream sizes. On stream 1 and stream 2 proper 669 // resizing of the file is handled in SimpleSynchronousEntry::WriteData(). 670 if (stream_index == 0 && 671 !TruncatePlatformFile(files_[file_index], eof_offset)) { 672 RecordCloseResult(cache_type_, CLOSE_RESULT_WRITE_FAILURE); 673 DLOG(INFO) << "Could not truncate stream 0 file."; 674 Doom(); 675 break; 676 } 677 if (WritePlatformFile(files_[file_index], 678 eof_offset, 679 reinterpret_cast<const char*>(&eof_record), 680 sizeof(eof_record)) != sizeof(eof_record)) { 681 RecordCloseResult(cache_type_, CLOSE_RESULT_WRITE_FAILURE); 682 DLOG(INFO) << "Could not write eof record."; 683 Doom(); 684 break; 685 } 686 } 687 for (int i = 0; i < kSimpleEntryFileCount; ++i) { 688 if (empty_file_omitted_[i]) 689 continue; 690 691 bool did_close_file = ClosePlatformFile(files_[i]); 692 DCHECK(did_close_file); 693 const int64 file_size = entry_stat.GetFileSize(key_, i); 694 SIMPLE_CACHE_UMA(CUSTOM_COUNTS, 695 "LastClusterSize", cache_type_, 696 file_size % 4096, 0, 4097, 50); 697 const int64 cluster_loss = file_size % 4096 ? 4096 - file_size % 4096 : 0; 698 SIMPLE_CACHE_UMA(PERCENTAGE, 699 "LastClusterLossPercent", cache_type_, 700 cluster_loss * 100 / (cluster_loss + file_size)); 701 } 702 703 if (sparse_file_open()) { 704 bool did_close_file = ClosePlatformFile(sparse_file_); 705 CHECK(did_close_file); 706 } 707 708 if (files_created_) { 709 const int stream2_file_index = GetFileIndexFromStreamIndex(2); 710 SIMPLE_CACHE_UMA(BOOLEAN, "EntryCreatedAndStream2Omitted", cache_type_, 711 empty_file_omitted_[stream2_file_index]); 712 } 713 RecordCloseResult(cache_type_, CLOSE_RESULT_SUCCESS); 714 have_open_files_ = false; 715 delete this; 716 } 717 718 SimpleSynchronousEntry::SimpleSynchronousEntry(net::CacheType cache_type, 719 const FilePath& path, 720 const std::string& key, 721 const uint64 entry_hash) 722 : cache_type_(cache_type), 723 path_(path), 724 entry_hash_(entry_hash), 725 key_(key), 726 have_open_files_(false), 727 initialized_(false), 728 sparse_file_(kInvalidPlatformFileValue) { 729 for (int i = 0; i < kSimpleEntryFileCount; ++i) { 730 files_[i] = kInvalidPlatformFileValue; 731 empty_file_omitted_[i] = false; 732 } 733 } 734 735 SimpleSynchronousEntry::~SimpleSynchronousEntry() { 736 DCHECK(!(have_open_files_ && initialized_)); 737 if (have_open_files_) 738 CloseFiles(); 739 } 740 741 bool SimpleSynchronousEntry::MaybeOpenFile( 742 int file_index, 743 PlatformFileError* out_error) { 744 DCHECK(out_error); 745 746 FilePath filename = GetFilenameFromFileIndex(file_index); 747 int flags = PLATFORM_FILE_OPEN | PLATFORM_FILE_READ | PLATFORM_FILE_WRITE; 748 files_[file_index] = CreatePlatformFile(filename, flags, NULL, out_error); 749 750 if (CanOmitEmptyFile(file_index) && 751 *out_error == PLATFORM_FILE_ERROR_NOT_FOUND) { 752 empty_file_omitted_[file_index] = true; 753 return true; 754 } 755 756 return *out_error == PLATFORM_FILE_OK; 757 } 758 759 bool SimpleSynchronousEntry::MaybeCreateFile( 760 int file_index, 761 FileRequired file_required, 762 PlatformFileError* out_error) { 763 DCHECK(out_error); 764 765 if (CanOmitEmptyFile(file_index) && file_required == FILE_NOT_REQUIRED) { 766 empty_file_omitted_[file_index] = true; 767 return true; 768 } 769 770 FilePath filename = GetFilenameFromFileIndex(file_index); 771 int flags = PLATFORM_FILE_CREATE | PLATFORM_FILE_READ | PLATFORM_FILE_WRITE; 772 files_[file_index] = CreatePlatformFile(filename, flags, NULL, out_error); 773 774 empty_file_omitted_[file_index] = false; 775 776 return *out_error == PLATFORM_FILE_OK; 777 } 778 779 bool SimpleSynchronousEntry::OpenFiles( 780 bool had_index, 781 SimpleEntryStat* out_entry_stat) { 782 for (int i = 0; i < kSimpleEntryFileCount; ++i) { 783 PlatformFileError error; 784 if (!MaybeOpenFile(i, &error)) { 785 // TODO(ttuttle,gavinp): Remove one each of these triplets of histograms. 786 // We can calculate the third as the sum or difference of the other two. 787 RecordSyncOpenResult( 788 cache_type_, OPEN_ENTRY_PLATFORM_FILE_ERROR, had_index); 789 SIMPLE_CACHE_UMA(ENUMERATION, 790 "SyncOpenPlatformFileError", cache_type_, 791 -error, -base::PLATFORM_FILE_ERROR_MAX); 792 if (had_index) { 793 SIMPLE_CACHE_UMA(ENUMERATION, 794 "SyncOpenPlatformFileError_WithIndex", cache_type_, 795 -error, -base::PLATFORM_FILE_ERROR_MAX); 796 } else { 797 SIMPLE_CACHE_UMA(ENUMERATION, 798 "SyncOpenPlatformFileError_WithoutIndex", 799 cache_type_, 800 -error, -base::PLATFORM_FILE_ERROR_MAX); 801 } 802 while (--i >= 0) 803 CloseFile(i); 804 return false; 805 } 806 } 807 808 have_open_files_ = true; 809 810 base::TimeDelta entry_age = base::Time::Now() - base::Time::UnixEpoch(); 811 for (int i = 0; i < kSimpleEntryFileCount; ++i) { 812 if (empty_file_omitted_[i]) { 813 out_entry_stat->set_data_size(i + 1, 0); 814 continue; 815 } 816 817 PlatformFileInfo file_info; 818 bool success = GetPlatformFileInfo(files_[i], &file_info); 819 base::Time file_last_modified; 820 if (!success) { 821 DLOG(WARNING) << "Could not get platform file info."; 822 continue; 823 } 824 out_entry_stat->set_last_used(file_info.last_accessed); 825 if (simple_util::GetMTime(path_, &file_last_modified)) 826 out_entry_stat->set_last_modified(file_last_modified); 827 else 828 out_entry_stat->set_last_modified(file_info.last_modified); 829 830 base::TimeDelta stream_age = 831 base::Time::Now() - out_entry_stat->last_modified(); 832 if (stream_age < entry_age) 833 entry_age = stream_age; 834 835 // Two things prevent from knowing the right values for |data_size|: 836 // 1) The key is not known, hence its length is unknown. 837 // 2) Stream 0 and stream 1 are in the same file, and the exact size for 838 // each will only be known when reading the EOF record for stream 0. 839 // 840 // The size for file 0 and 1 is temporarily kept in 841 // |data_size(1)| and |data_size(2)| respectively. Reading the key in 842 // InitializeForOpen yields the data size for each file. In the case of 843 // file hash_1, this is the total size of stream 2, and is assigned to 844 // data_size(2). In the case of file 0, it is the combined size of stream 845 // 0, stream 1 and one EOF record. The exact distribution of sizes between 846 // stream 1 and stream 0 is only determined after reading the EOF record 847 // for stream 0 in ReadAndValidateStream0. 848 out_entry_stat->set_data_size(i + 1, file_info.size); 849 } 850 SIMPLE_CACHE_UMA(CUSTOM_COUNTS, 851 "SyncOpenEntryAge", cache_type_, 852 entry_age.InHours(), 1, 1000, 50); 853 854 files_created_ = false; 855 856 return true; 857 } 858 859 bool SimpleSynchronousEntry::CreateFiles( 860 bool had_index, 861 SimpleEntryStat* out_entry_stat) { 862 for (int i = 0; i < kSimpleEntryFileCount; ++i) { 863 PlatformFileError error; 864 if (!MaybeCreateFile(i, FILE_NOT_REQUIRED, &error)) { 865 // TODO(ttuttle,gavinp): Remove one each of these triplets of histograms. 866 // We can calculate the third as the sum or difference of the other two. 867 RecordSyncCreateResult(CREATE_ENTRY_PLATFORM_FILE_ERROR, had_index); 868 SIMPLE_CACHE_UMA(ENUMERATION, 869 "SyncCreatePlatformFileError", cache_type_, 870 -error, -base::PLATFORM_FILE_ERROR_MAX); 871 if (had_index) { 872 SIMPLE_CACHE_UMA(ENUMERATION, 873 "SyncCreatePlatformFileError_WithIndex", cache_type_, 874 -error, -base::PLATFORM_FILE_ERROR_MAX); 875 } else { 876 SIMPLE_CACHE_UMA(ENUMERATION, 877 "SyncCreatePlatformFileError_WithoutIndex", 878 cache_type_, 879 -error, -base::PLATFORM_FILE_ERROR_MAX); 880 } 881 while (--i >= 0) 882 CloseFile(i); 883 return false; 884 } 885 } 886 887 have_open_files_ = true; 888 889 base::Time creation_time = Time::Now(); 890 out_entry_stat->set_last_modified(creation_time); 891 out_entry_stat->set_last_used(creation_time); 892 for (int i = 0; i < kSimpleEntryStreamCount; ++i) 893 out_entry_stat->set_data_size(i, 0); 894 895 files_created_ = true; 896 897 return true; 898 } 899 900 void SimpleSynchronousEntry::CloseFile(int index) { 901 if (empty_file_omitted_[index]) { 902 empty_file_omitted_[index] = false; 903 } else { 904 DCHECK_NE(kInvalidPlatformFileValue, files_[index]); 905 bool did_close = ClosePlatformFile(files_[index]); 906 DCHECK(did_close); 907 files_[index] = kInvalidPlatformFileValue; 908 } 909 910 if (sparse_file_open()) { 911 bool did_close = CloseSparseFile(); 912 DCHECK(did_close); 913 } 914 } 915 916 void SimpleSynchronousEntry::CloseFiles() { 917 for (int i = 0; i < kSimpleEntryFileCount; ++i) 918 CloseFile(i); 919 } 920 921 int SimpleSynchronousEntry::InitializeForOpen( 922 bool had_index, 923 SimpleEntryStat* out_entry_stat, 924 scoped_refptr<net::GrowableIOBuffer>* stream_0_data, 925 uint32* out_stream_0_crc32) { 926 DCHECK(!initialized_); 927 if (!OpenFiles(had_index, out_entry_stat)) { 928 DLOG(WARNING) << "Could not open platform files for entry."; 929 return net::ERR_FAILED; 930 } 931 for (int i = 0; i < kSimpleEntryFileCount; ++i) { 932 if (empty_file_omitted_[i]) 933 continue; 934 935 SimpleFileHeader header; 936 int header_read_result = 937 ReadPlatformFile(files_[i], 0, reinterpret_cast<char*>(&header), 938 sizeof(header)); 939 if (header_read_result != sizeof(header)) { 940 DLOG(WARNING) << "Cannot read header from entry."; 941 RecordSyncOpenResult(cache_type_, OPEN_ENTRY_CANT_READ_HEADER, had_index); 942 return net::ERR_FAILED; 943 } 944 945 if (header.initial_magic_number != kSimpleInitialMagicNumber) { 946 // TODO(gavinp): This seems very bad; for now we log at WARNING, but we 947 // should give consideration to not saturating the log with these if that 948 // becomes a problem. 949 DLOG(WARNING) << "Magic number did not match."; 950 RecordSyncOpenResult(cache_type_, OPEN_ENTRY_BAD_MAGIC_NUMBER, had_index); 951 return net::ERR_FAILED; 952 } 953 954 if (header.version != kSimpleEntryVersionOnDisk) { 955 DLOG(WARNING) << "Unreadable version."; 956 RecordSyncOpenResult(cache_type_, OPEN_ENTRY_BAD_VERSION, had_index); 957 return net::ERR_FAILED; 958 } 959 960 scoped_ptr<char[]> key(new char[header.key_length]); 961 int key_read_result = ReadPlatformFile(files_[i], sizeof(header), 962 key.get(), header.key_length); 963 if (key_read_result != implicit_cast<int>(header.key_length)) { 964 DLOG(WARNING) << "Cannot read key from entry."; 965 RecordSyncOpenResult(cache_type_, OPEN_ENTRY_CANT_READ_KEY, had_index); 966 return net::ERR_FAILED; 967 } 968 969 key_ = std::string(key.get(), header.key_length); 970 if (i == 0) { 971 // File size for stream 0 has been stored temporarily in data_size[1]. 972 int total_data_size = 973 GetDataSizeFromKeyAndFileSize(key_, out_entry_stat->data_size(1)); 974 int ret_value_stream_0 = ReadAndValidateStream0( 975 total_data_size, out_entry_stat, stream_0_data, out_stream_0_crc32); 976 if (ret_value_stream_0 != net::OK) 977 return ret_value_stream_0; 978 } else { 979 out_entry_stat->set_data_size( 980 2, GetDataSizeFromKeyAndFileSize(key_, out_entry_stat->data_size(2))); 981 if (out_entry_stat->data_size(2) < 0) { 982 DLOG(WARNING) << "Stream 2 file is too small."; 983 return net::ERR_FAILED; 984 } 985 } 986 987 if (base::Hash(key.get(), header.key_length) != header.key_hash) { 988 DLOG(WARNING) << "Hash mismatch on key."; 989 RecordSyncOpenResult( 990 cache_type_, OPEN_ENTRY_KEY_HASH_MISMATCH, had_index); 991 return net::ERR_FAILED; 992 } 993 } 994 995 int32 sparse_data_size = 0; 996 if (!OpenSparseFileIfExists(&sparse_data_size)) { 997 RecordSyncOpenResult( 998 cache_type_, OPEN_ENTRY_SPARSE_OPEN_FAILED, had_index); 999 return net::ERR_FAILED; 1000 } 1001 out_entry_stat->set_sparse_data_size(sparse_data_size); 1002 1003 bool removed_stream2 = false; 1004 const int stream2_file_index = GetFileIndexFromStreamIndex(2); 1005 DCHECK(CanOmitEmptyFile(stream2_file_index)); 1006 if (!empty_file_omitted_[stream2_file_index] && 1007 out_entry_stat->data_size(2) == 0) { 1008 DLOG(INFO) << "Removing empty stream 2 file."; 1009 CloseFile(stream2_file_index); 1010 DeleteFileForEntryHash(path_, entry_hash_, stream2_file_index); 1011 empty_file_omitted_[stream2_file_index] = true; 1012 removed_stream2 = true; 1013 } 1014 1015 SIMPLE_CACHE_UMA(BOOLEAN, "EntryOpenedAndStream2Removed", cache_type_, 1016 removed_stream2); 1017 1018 RecordSyncOpenResult(cache_type_, OPEN_ENTRY_SUCCESS, had_index); 1019 initialized_ = true; 1020 return net::OK; 1021 } 1022 1023 bool SimpleSynchronousEntry::InitializeCreatedFile( 1024 int file_index, 1025 CreateEntryResult* out_result) { 1026 SimpleFileHeader header; 1027 header.initial_magic_number = kSimpleInitialMagicNumber; 1028 header.version = kSimpleEntryVersionOnDisk; 1029 1030 header.key_length = key_.size(); 1031 header.key_hash = base::Hash(key_); 1032 1033 int bytes_written = WritePlatformFile( 1034 files_[file_index], 0, reinterpret_cast<char*>(&header), sizeof(header)); 1035 if (bytes_written != sizeof(header)) { 1036 *out_result = CREATE_ENTRY_CANT_WRITE_HEADER; 1037 return false; 1038 } 1039 1040 bytes_written = WritePlatformFile( 1041 files_[file_index], sizeof(header), key_.data(), key_.size()); 1042 if (bytes_written != implicit_cast<int>(key_.size())) { 1043 *out_result = CREATE_ENTRY_CANT_WRITE_KEY; 1044 return false; 1045 } 1046 1047 return true; 1048 } 1049 1050 int SimpleSynchronousEntry::InitializeForCreate( 1051 bool had_index, 1052 SimpleEntryStat* out_entry_stat) { 1053 DCHECK(!initialized_); 1054 if (!CreateFiles(had_index, out_entry_stat)) { 1055 DLOG(WARNING) << "Could not create platform files."; 1056 return net::ERR_FILE_EXISTS; 1057 } 1058 for (int i = 0; i < kSimpleEntryFileCount; ++i) { 1059 if (empty_file_omitted_[i]) 1060 continue; 1061 1062 CreateEntryResult result; 1063 if (!InitializeCreatedFile(i, &result)) { 1064 RecordSyncCreateResult(result, had_index); 1065 return net::ERR_FAILED; 1066 } 1067 } 1068 RecordSyncCreateResult(CREATE_ENTRY_SUCCESS, had_index); 1069 initialized_ = true; 1070 return net::OK; 1071 } 1072 1073 int SimpleSynchronousEntry::ReadAndValidateStream0( 1074 int total_data_size, 1075 SimpleEntryStat* out_entry_stat, 1076 scoped_refptr<net::GrowableIOBuffer>* stream_0_data, 1077 uint32* out_stream_0_crc32) const { 1078 // Temporarily assign all the data size to stream 1 in order to read the 1079 // EOF record for stream 0, which contains the size of stream 0. 1080 out_entry_stat->set_data_size(0, 0); 1081 out_entry_stat->set_data_size(1, total_data_size - sizeof(SimpleFileEOF)); 1082 1083 bool has_crc32; 1084 uint32 read_crc32; 1085 int stream_0_size; 1086 int ret_value_crc32 = GetEOFRecordData( 1087 0, *out_entry_stat, &has_crc32, &read_crc32, &stream_0_size); 1088 if (ret_value_crc32 != net::OK) 1089 return ret_value_crc32; 1090 1091 if (stream_0_size > out_entry_stat->data_size(1)) 1092 return net::ERR_FAILED; 1093 1094 // These are the real values of data size. 1095 out_entry_stat->set_data_size(0, stream_0_size); 1096 out_entry_stat->set_data_size( 1097 1, out_entry_stat->data_size(1) - stream_0_size); 1098 1099 // Put stream 0 data in memory. 1100 *stream_0_data = new net::GrowableIOBuffer(); 1101 (*stream_0_data)->SetCapacity(stream_0_size); 1102 int file_offset = out_entry_stat->GetOffsetInFile(key_, 0, 0); 1103 int bytes_read = ReadPlatformFile( 1104 files_[0], file_offset, (*stream_0_data)->data(), stream_0_size); 1105 if (bytes_read != stream_0_size) 1106 return net::ERR_FAILED; 1107 1108 // Check the CRC32. 1109 uint32 expected_crc32 = 1110 stream_0_size == 0 1111 ? crc32(0, Z_NULL, 0) 1112 : crc32(crc32(0, Z_NULL, 0), 1113 reinterpret_cast<const Bytef*>((*stream_0_data)->data()), 1114 stream_0_size); 1115 if (has_crc32 && read_crc32 != expected_crc32) { 1116 DLOG(INFO) << "EOF record had bad crc."; 1117 RecordCheckEOFResult(cache_type_, CHECK_EOF_RESULT_CRC_MISMATCH); 1118 return net::ERR_FAILED; 1119 } 1120 *out_stream_0_crc32 = expected_crc32; 1121 RecordCheckEOFResult(cache_type_, CHECK_EOF_RESULT_SUCCESS); 1122 return net::OK; 1123 } 1124 1125 int SimpleSynchronousEntry::GetEOFRecordData(int index, 1126 const SimpleEntryStat& entry_stat, 1127 bool* out_has_crc32, 1128 uint32* out_crc32, 1129 int* out_data_size) const { 1130 SimpleFileEOF eof_record; 1131 int file_offset = entry_stat.GetEOFOffsetInFile(key_, index); 1132 int file_index = GetFileIndexFromStreamIndex(index); 1133 if (ReadPlatformFile(files_[file_index], 1134 file_offset, 1135 reinterpret_cast<char*>(&eof_record), 1136 sizeof(eof_record)) != sizeof(eof_record)) { 1137 RecordCheckEOFResult(cache_type_, CHECK_EOF_RESULT_READ_FAILURE); 1138 return net::ERR_CACHE_CHECKSUM_READ_FAILURE; 1139 } 1140 1141 if (eof_record.final_magic_number != kSimpleFinalMagicNumber) { 1142 RecordCheckEOFResult(cache_type_, CHECK_EOF_RESULT_MAGIC_NUMBER_MISMATCH); 1143 DLOG(INFO) << "EOF record had bad magic number."; 1144 return net::ERR_CACHE_CHECKSUM_READ_FAILURE; 1145 } 1146 1147 *out_has_crc32 = (eof_record.flags & SimpleFileEOF::FLAG_HAS_CRC32) == 1148 SimpleFileEOF::FLAG_HAS_CRC32; 1149 *out_crc32 = eof_record.data_crc32; 1150 *out_data_size = eof_record.stream_size; 1151 SIMPLE_CACHE_UMA(BOOLEAN, "SyncCheckEOFHasCrc", cache_type_, *out_has_crc32); 1152 return net::OK; 1153 } 1154 1155 void SimpleSynchronousEntry::Doom() const { 1156 DeleteFilesForEntryHash(path_, entry_hash_); 1157 } 1158 1159 // static 1160 bool SimpleSynchronousEntry::DeleteFileForEntryHash( 1161 const FilePath& path, 1162 const uint64 entry_hash, 1163 const int file_index) { 1164 FilePath to_delete = path.AppendASCII( 1165 GetFilenameFromEntryHashAndFileIndex(entry_hash, file_index)); 1166 return base::DeleteFile(to_delete, false); 1167 } 1168 1169 // static 1170 bool SimpleSynchronousEntry::DeleteFilesForEntryHash( 1171 const FilePath& path, 1172 const uint64 entry_hash) { 1173 bool result = true; 1174 for (int i = 0; i < kSimpleEntryFileCount; ++i) { 1175 if (!DeleteFileForEntryHash(path, entry_hash, i) && !CanOmitEmptyFile(i)) 1176 result = false; 1177 } 1178 FilePath to_delete = path.AppendASCII( 1179 GetSparseFilenameFromEntryHash(entry_hash)); 1180 base::DeleteFile(to_delete, false); 1181 return result; 1182 } 1183 1184 void SimpleSynchronousEntry::RecordSyncCreateResult(CreateEntryResult result, 1185 bool had_index) { 1186 DCHECK_GT(CREATE_ENTRY_MAX, result); 1187 SIMPLE_CACHE_UMA(ENUMERATION, 1188 "SyncCreateResult", cache_type_, result, CREATE_ENTRY_MAX); 1189 if (had_index) { 1190 SIMPLE_CACHE_UMA(ENUMERATION, 1191 "SyncCreateResult_WithIndex", cache_type_, 1192 result, CREATE_ENTRY_MAX); 1193 } else { 1194 SIMPLE_CACHE_UMA(ENUMERATION, 1195 "SyncCreateResult_WithoutIndex", cache_type_, 1196 result, CREATE_ENTRY_MAX); 1197 } 1198 } 1199 1200 FilePath SimpleSynchronousEntry::GetFilenameFromFileIndex(int file_index) { 1201 return path_.AppendASCII( 1202 GetFilenameFromEntryHashAndFileIndex(entry_hash_, file_index)); 1203 } 1204 1205 bool SimpleSynchronousEntry::OpenSparseFileIfExists( 1206 int32* out_sparse_data_size) { 1207 DCHECK(!sparse_file_open()); 1208 1209 FilePath filename = path_.AppendASCII( 1210 GetSparseFilenameFromEntryHash(entry_hash_)); 1211 int flags = PLATFORM_FILE_OPEN | PLATFORM_FILE_READ | PLATFORM_FILE_WRITE; 1212 bool created; 1213 PlatformFileError error; 1214 sparse_file_ = CreatePlatformFile(filename, flags, &created, &error); 1215 if (error == PLATFORM_FILE_ERROR_NOT_FOUND) 1216 return true; 1217 1218 return ScanSparseFile(out_sparse_data_size); 1219 } 1220 1221 bool SimpleSynchronousEntry::CreateSparseFile() { 1222 DCHECK(!sparse_file_open()); 1223 1224 FilePath filename = path_.AppendASCII( 1225 GetSparseFilenameFromEntryHash(entry_hash_)); 1226 int flags = PLATFORM_FILE_CREATE | PLATFORM_FILE_READ | PLATFORM_FILE_WRITE; 1227 bool created; 1228 PlatformFileError error; 1229 sparse_file_ = CreatePlatformFile(filename, flags, &created, &error); 1230 if (error != PLATFORM_FILE_OK) 1231 return false; 1232 1233 return InitializeSparseFile(); 1234 } 1235 1236 bool SimpleSynchronousEntry::CloseSparseFile() { 1237 DCHECK(sparse_file_open()); 1238 1239 bool did_close = ClosePlatformFile(sparse_file_); 1240 if (did_close) 1241 sparse_file_ = kInvalidPlatformFileValue; 1242 return did_close; 1243 } 1244 1245 bool SimpleSynchronousEntry::TruncateSparseFile() { 1246 DCHECK(sparse_file_open()); 1247 1248 int64 header_and_key_length = sizeof(SimpleFileHeader) + key_.size(); 1249 if (!TruncatePlatformFile(sparse_file_, header_and_key_length)) { 1250 DLOG(WARNING) << "Could not truncate sparse file"; 1251 return false; 1252 } 1253 1254 sparse_ranges_.clear(); 1255 1256 return true; 1257 } 1258 1259 bool SimpleSynchronousEntry::InitializeSparseFile() { 1260 DCHECK(sparse_file_open()); 1261 1262 SimpleFileHeader header; 1263 header.initial_magic_number = kSimpleInitialMagicNumber; 1264 header.version = kSimpleVersion; 1265 header.key_length = key_.size(); 1266 header.key_hash = base::Hash(key_); 1267 1268 int header_write_result = 1269 WritePlatformFile(sparse_file_, 0, reinterpret_cast<char*>(&header), 1270 sizeof(header)); 1271 if (header_write_result != sizeof(header)) { 1272 DLOG(WARNING) << "Could not write sparse file header"; 1273 return false; 1274 } 1275 1276 int key_write_result = WritePlatformFile(sparse_file_, sizeof(header), 1277 key_.data(), key_.size()); 1278 if (key_write_result != implicit_cast<int>(key_.size())) { 1279 DLOG(WARNING) << "Could not write sparse file key"; 1280 return false; 1281 } 1282 1283 sparse_ranges_.clear(); 1284 sparse_tail_offset_ = sizeof(header) + key_.size(); 1285 1286 return true; 1287 } 1288 1289 bool SimpleSynchronousEntry::ScanSparseFile(int32* out_sparse_data_size) { 1290 DCHECK(sparse_file_open()); 1291 1292 int32 sparse_data_size = 0; 1293 1294 SimpleFileHeader header; 1295 int header_read_result = 1296 ReadPlatformFile(sparse_file_, 0, reinterpret_cast<char*>(&header), 1297 sizeof(header)); 1298 if (header_read_result != sizeof(header)) { 1299 DLOG(WARNING) << "Could not read header from sparse file."; 1300 return false; 1301 } 1302 1303 if (header.initial_magic_number != kSimpleInitialMagicNumber) { 1304 DLOG(WARNING) << "Sparse file magic number did not match."; 1305 return false; 1306 } 1307 1308 if (header.version != kSimpleVersion) { 1309 DLOG(WARNING) << "Sparse file unreadable version."; 1310 return false; 1311 } 1312 1313 sparse_ranges_.clear(); 1314 1315 int64 range_header_offset = sizeof(header) + key_.size(); 1316 while (1) { 1317 SimpleFileSparseRangeHeader range_header; 1318 int range_header_read_result = 1319 ReadPlatformFile(sparse_file_, 1320 range_header_offset, 1321 reinterpret_cast<char*>(&range_header), 1322 sizeof(range_header)); 1323 if (range_header_read_result == 0) 1324 break; 1325 if (range_header_read_result != sizeof(range_header)) { 1326 DLOG(WARNING) << "Could not read sparse range header."; 1327 return false; 1328 } 1329 1330 if (range_header.sparse_range_magic_number != 1331 kSimpleSparseRangeMagicNumber) { 1332 DLOG(WARNING) << "Invalid sparse range header magic number."; 1333 return false; 1334 } 1335 1336 SparseRange range; 1337 range.offset = range_header.offset; 1338 range.length = range_header.length; 1339 range.data_crc32 = range_header.data_crc32; 1340 range.file_offset = range_header_offset + sizeof(range_header); 1341 sparse_ranges_.insert(std::make_pair(range.offset, range)); 1342 1343 range_header_offset += sizeof(range_header) + range.length; 1344 1345 DCHECK_LE(sparse_data_size, sparse_data_size + range.length); 1346 sparse_data_size += range.length; 1347 } 1348 1349 *out_sparse_data_size = sparse_data_size; 1350 sparse_tail_offset_ = range_header_offset; 1351 1352 return true; 1353 } 1354 1355 bool SimpleSynchronousEntry::ReadSparseRange(const SparseRange* range, 1356 int offset, int len, char* buf) { 1357 DCHECK(range); 1358 DCHECK(buf); 1359 DCHECK_GE(range->length, offset); 1360 DCHECK_GE(range->length, offset + len); 1361 1362 int bytes_read = ReadPlatformFile(sparse_file_, 1363 range->file_offset + offset, 1364 buf, len); 1365 if (bytes_read < len) { 1366 DLOG(WARNING) << "Could not read sparse range."; 1367 return false; 1368 } 1369 1370 // If we read the whole range and we have a crc32, check it. 1371 if (offset == 0 && len == range->length && range->data_crc32 != 0) { 1372 uint32 actual_crc32 = crc32(crc32(0L, Z_NULL, 0), 1373 reinterpret_cast<const Bytef*>(buf), 1374 len); 1375 if (actual_crc32 != range->data_crc32) { 1376 DLOG(WARNING) << "Sparse range crc32 mismatch."; 1377 return false; 1378 } 1379 } 1380 // TODO(ttuttle): Incremental crc32 calculation? 1381 1382 return true; 1383 } 1384 1385 bool SimpleSynchronousEntry::WriteSparseRange(SparseRange* range, 1386 int offset, int len, 1387 const char* buf) { 1388 DCHECK(range); 1389 DCHECK(buf); 1390 DCHECK_GE(range->length, offset); 1391 DCHECK_GE(range->length, offset + len); 1392 1393 uint32 new_crc32 = 0; 1394 if (offset == 0 && len == range->length) { 1395 new_crc32 = crc32(crc32(0L, Z_NULL, 0), 1396 reinterpret_cast<const Bytef*>(buf), 1397 len); 1398 } 1399 1400 if (new_crc32 != range->data_crc32) { 1401 range->data_crc32 = new_crc32; 1402 1403 SimpleFileSparseRangeHeader header; 1404 header.sparse_range_magic_number = kSimpleSparseRangeMagicNumber; 1405 header.offset = range->offset; 1406 header.length = range->length; 1407 header.data_crc32 = range->data_crc32; 1408 1409 int bytes_written = WritePlatformFile(sparse_file_, 1410 range->file_offset - sizeof(header), 1411 reinterpret_cast<char*>(&header), 1412 sizeof(header)); 1413 if (bytes_written != implicit_cast<int>(sizeof(header))) { 1414 DLOG(WARNING) << "Could not rewrite sparse range header."; 1415 return false; 1416 } 1417 } 1418 1419 int bytes_written = WritePlatformFile(sparse_file_, 1420 range->file_offset + offset, 1421 buf, len); 1422 if (bytes_written < len) { 1423 DLOG(WARNING) << "Could not write sparse range."; 1424 return false; 1425 } 1426 1427 return true; 1428 } 1429 1430 bool SimpleSynchronousEntry::AppendSparseRange(int64 offset, 1431 int len, 1432 const char* buf) { 1433 DCHECK_LE(0, offset); 1434 DCHECK_LT(0, len); 1435 DCHECK(buf); 1436 1437 uint32 data_crc32 = crc32(crc32(0L, Z_NULL, 0), 1438 reinterpret_cast<const Bytef*>(buf), 1439 len); 1440 1441 SimpleFileSparseRangeHeader header; 1442 header.sparse_range_magic_number = kSimpleSparseRangeMagicNumber; 1443 header.offset = offset; 1444 header.length = len; 1445 header.data_crc32 = data_crc32; 1446 1447 int bytes_written = WritePlatformFile(sparse_file_, 1448 sparse_tail_offset_, 1449 reinterpret_cast<char*>(&header), 1450 sizeof(header)); 1451 if (bytes_written != implicit_cast<int>(sizeof(header))) { 1452 DLOG(WARNING) << "Could not append sparse range header."; 1453 return false; 1454 } 1455 sparse_tail_offset_ += bytes_written; 1456 1457 bytes_written = WritePlatformFile(sparse_file_, 1458 sparse_tail_offset_, 1459 buf, 1460 len); 1461 if (bytes_written < len) { 1462 DLOG(WARNING) << "Could not append sparse range data."; 1463 return false; 1464 } 1465 int64 data_file_offset = sparse_tail_offset_; 1466 sparse_tail_offset_ += bytes_written; 1467 1468 SparseRange range; 1469 range.offset = offset; 1470 range.length = len; 1471 range.data_crc32 = data_crc32; 1472 range.file_offset = data_file_offset; 1473 sparse_ranges_.insert(std::make_pair(offset, range)); 1474 1475 return true; 1476 } 1477 1478 } // namespace disk_cache 1479