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::File;
     27 using base::FilePath;
     28 using base::Time;
     29 
     30 namespace {
     31 
     32 // Used in histograms, please only add entries at the end.
     33 enum 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.
     47 enum 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.
     59 enum 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.
     68 enum CloseResult {
     69   CLOSE_RESULT_SUCCESS,
     70   CLOSE_RESULT_WRITE_FAILURE,
     71 };
     72 
     73 void 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 
     90 void RecordWriteResult(net::CacheType cache_type, WriteResult result) {
     91   SIMPLE_CACHE_UMA(ENUMERATION,
     92                    "SyncWriteResult", cache_type, result, WRITE_RESULT_MAX);
     93 }
     94 
     95 void RecordCheckEOFResult(net::CacheType cache_type, CheckEOFResult result) {
     96   SIMPLE_CACHE_UMA(ENUMERATION,
     97                    "SyncCheckEOFResult", cache_type,
     98                    result, CHECK_EOF_RESULT_MAX);
     99 }
    100 
    101 void RecordCloseResult(net::CacheType cache_type, CloseResult result) {
    102   SIMPLE_CACHE_UMA(ENUMERATION,
    103                    "SyncCloseResult", cache_type, result, WRITE_RESULT_MAX);
    104 }
    105 
    106 bool 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 
    114 namespace disk_cache {
    115 
    116 using simple_util::GetEntryHashKey;
    117 using simple_util::GetFilenameFromEntryHashAndFileIndex;
    118 using simple_util::GetSparseFilenameFromEntryHash;
    119 using simple_util::GetDataSizeFromKeyAndFileSize;
    120 using simple_util::GetFileSizeFromKeyAndDataSize;
    121 using simple_util::GetFileIndexFromStreamIndex;
    122 
    123 SimpleEntryStat::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 
    133 int 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 
    142 int SimpleEntryStat::GetEOFOffsetInFile(const std::string& key,
    143                                         int stream_index) const {
    144   return GetOffsetInFile(key, data_size_[stream_index], stream_index);
    145 }
    146 
    147 int 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 
    156 int 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 
    163 SimpleEntryCreationResults::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 
    171 SimpleEntryCreationResults::~SimpleEntryCreationResults() {
    172 }
    173 
    174 SimpleSynchronousEntry::CRCRecord::CRCRecord() : index(-1),
    175                                                  has_crc32(false),
    176                                                  data_crc32(0) {
    177 }
    178 
    179 SimpleSynchronousEntry::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 
    186 SimpleSynchronousEntry::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 
    193 SimpleSynchronousEntry::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 
    204 SimpleSynchronousEntry::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
    211 void 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
    235 void 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
    258 int 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
    266 int 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 
    275 void 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 
    306 void 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 
    390 void 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 
    453 void 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 
    559 void 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 
    597 void 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 
    621 void 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 
    699 SimpleSynchronousEntry::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 
    713 SimpleSynchronousEntry::~SimpleSynchronousEntry() {
    714   DCHECK(!(have_open_files_ && initialized_));
    715   if (have_open_files_)
    716     CloseFiles();
    717 }
    718 
    719 bool 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 
    738 bool 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 
    759 bool 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 
    839 bool 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 
    880 void 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 
    892 void SimpleSynchronousEntry::CloseFiles() {
    893   for (int i = 0; i < kSimpleEntryFileCount; ++i)
    894     CloseFile(i);
    895 }
    896 
    897 int 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 
    998 bool 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 
   1025 int 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 
   1048 int 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 
   1101 int 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 
   1131 void SimpleSynchronousEntry::Doom() const {
   1132   DeleteFilesForEntryHash(path_, entry_hash_);
   1133 }
   1134 
   1135 // static
   1136 bool 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
   1146 bool 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 
   1160 void 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 
   1176 FilePath SimpleSynchronousEntry::GetFilenameFromFileIndex(int file_index) {
   1177   return path_.AppendASCII(
   1178       GetFilenameFromEntryHashAndFileIndex(entry_hash_, file_index));
   1179 }
   1180 
   1181 bool 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 
   1195 bool 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 
   1208 void SimpleSynchronousEntry::CloseSparseFile() {
   1209   DCHECK(sparse_file_open());
   1210   sparse_file_.Close();
   1211 }
   1212 
   1213 bool 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 
   1227 bool 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 
   1256 bool 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 
   1320 bool 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 
   1348 bool 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 
   1390 bool 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