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
RecordSyncOpenResult(net::CacheType cache_type,OpenEntryResult result,bool had_index)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
RecordWriteResult(net::CacheType cache_type,WriteResult result)90 void RecordWriteResult(net::CacheType cache_type, WriteResult result) {
91 SIMPLE_CACHE_UMA(ENUMERATION,
92 "SyncWriteResult", cache_type, result, WRITE_RESULT_MAX);
93 }
94
RecordCheckEOFResult(net::CacheType cache_type,CheckEOFResult result)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
RecordCloseResult(net::CacheType cache_type,CloseResult result)101 void RecordCloseResult(net::CacheType cache_type, CloseResult result) {
102 SIMPLE_CACHE_UMA(ENUMERATION,
103 "SyncCloseResult", cache_type, result, WRITE_RESULT_MAX);
104 }
105
CanOmitEmptyFile(int file_index)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
SimpleEntryStat(base::Time last_used,base::Time last_modified,const int32 data_size[],const int32 sparse_data_size)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
GetOffsetInFile(const std::string & key,int offset,int stream_index) const133 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
GetEOFOffsetInFile(const std::string & key,int stream_index) const142 int SimpleEntryStat::GetEOFOffsetInFile(const std::string& key,
143 int stream_index) const {
144 return GetOffsetInFile(key, data_size_[stream_index], stream_index);
145 }
146
GetLastEOFOffsetInFile(const std::string & key,int stream_index) const147 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
GetFileSize(const std::string & key,int file_index) const156 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
SimpleEntryCreationResults(SimpleEntryStat entry_stat)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
~SimpleEntryCreationResults()171 SimpleEntryCreationResults::~SimpleEntryCreationResults() {
172 }
173
CRCRecord()174 SimpleSynchronousEntry::CRCRecord::CRCRecord() : index(-1),
175 has_crc32(false),
176 data_crc32(0) {
177 }
178
CRCRecord(int index_p,bool has_crc32_p,uint32 data_crc32_p)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
EntryOperationData(int index_p,int offset_p,int buf_len_p)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
EntryOperationData(int index_p,int offset_p,int buf_len_p,bool truncate_p,bool doomed_p)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
EntryOperationData(int64 sparse_offset_p,int buf_len_p)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
OpenEntry(net::CacheType cache_type,const FilePath & path,const uint64 entry_hash,bool had_index,SimpleEntryCreationResults * out_results)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
CreateEntry(net::CacheType cache_type,const FilePath & path,const std::string & key,const uint64 entry_hash,bool had_index,SimpleEntryCreationResults * out_results)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
DoomEntry(const FilePath & path,uint64 entry_hash)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
DoomEntrySet(const std::vector<uint64> * key_hashes,const FilePath & path)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
ReadData(const EntryOperationData & in_entry_op,net::IOBuffer * out_buf,uint32 * out_crc32,SimpleEntryStat * entry_stat,int * out_result) const275 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
WriteData(const EntryOperationData & in_entry_op,net::IOBuffer * in_buf,SimpleEntryStat * out_entry_stat,int * out_result)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
ReadSparseData(const EntryOperationData & in_entry_op,net::IOBuffer * out_buf,base::Time * out_last_used,int * out_result)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
WriteSparseData(const EntryOperationData & in_entry_op,net::IOBuffer * in_buf,int64 max_sparse_data_size,SimpleEntryStat * out_entry_stat,int * out_result)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
GetAvailableRange(const EntryOperationData & in_entry_op,int64 * out_start,int * out_result)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
CheckEOFRecord(int index,const SimpleEntryStat & entry_stat,uint32 expected_crc32,int * out_result) const597 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
Close(const SimpleEntryStat & entry_stat,scoped_ptr<std::vector<CRCRecord>> crc32s_to_write,net::GrowableIOBuffer * stream_0_data)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
SimpleSynchronousEntry(net::CacheType cache_type,const FilePath & path,const std::string & key,const uint64 entry_hash)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
~SimpleSynchronousEntry()713 SimpleSynchronousEntry::~SimpleSynchronousEntry() {
714 DCHECK(!(have_open_files_ && initialized_));
715 if (have_open_files_)
716 CloseFiles();
717 }
718
MaybeOpenFile(int file_index,File::Error * out_error)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
MaybeCreateFile(int file_index,FileRequired file_required,File::Error * out_error)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
OpenFiles(bool had_index,SimpleEntryStat * out_entry_stat)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
CreateFiles(bool had_index,SimpleEntryStat * out_entry_stat)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
CloseFile(int index)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
CloseFiles()892 void SimpleSynchronousEntry::CloseFiles() {
893 for (int i = 0; i < kSimpleEntryFileCount; ++i)
894 CloseFile(i);
895 }
896
InitializeForOpen(bool had_index,SimpleEntryStat * out_entry_stat,scoped_refptr<net::GrowableIOBuffer> * stream_0_data,uint32 * out_stream_0_crc32)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
InitializeCreatedFile(int file_index,CreateEntryResult * out_result)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
InitializeForCreate(bool had_index,SimpleEntryStat * out_entry_stat)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
ReadAndValidateStream0(int total_data_size,SimpleEntryStat * out_entry_stat,scoped_refptr<net::GrowableIOBuffer> * stream_0_data,uint32 * out_stream_0_crc32) const1048 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
GetEOFRecordData(int index,const SimpleEntryStat & entry_stat,bool * out_has_crc32,uint32 * out_crc32,int * out_data_size) const1101 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
Doom() const1131 void SimpleSynchronousEntry::Doom() const {
1132 DeleteFilesForEntryHash(path_, entry_hash_);
1133 }
1134
1135 // static
DeleteFileForEntryHash(const FilePath & path,const uint64 entry_hash,const int file_index)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
DeleteFilesForEntryHash(const FilePath & path,const uint64 entry_hash)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
RecordSyncCreateResult(CreateEntryResult result,bool had_index)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
GetFilenameFromFileIndex(int file_index)1176 FilePath SimpleSynchronousEntry::GetFilenameFromFileIndex(int file_index) {
1177 return path_.AppendASCII(
1178 GetFilenameFromEntryHashAndFileIndex(entry_hash_, file_index));
1179 }
1180
OpenSparseFileIfExists(int32 * out_sparse_data_size)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
CreateSparseFile()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
CloseSparseFile()1208 void SimpleSynchronousEntry::CloseSparseFile() {
1209 DCHECK(sparse_file_open());
1210 sparse_file_.Close();
1211 }
1212
TruncateSparseFile()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
InitializeSparseFile()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
ScanSparseFile(int32 * out_sparse_data_size)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
ReadSparseRange(const SparseRange * range,int offset,int len,char * buf)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
WriteSparseRange(SparseRange * range,int offset,int len,const char * buf)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
AppendSparseRange(int64 offset,int len,const char * buf)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