Home | History | Annotate | Download | only in simple
      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