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