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