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