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