1 // Copyright 2013 The Chromium Authors
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_version_upgrade.h"
6
7 #include <stdint.h>
8 #include <string>
9
10 #include "base/files/file_path.h"
11 #include "base/files/file_util.h"
12 #include "base/files/scoped_temp_dir.h"
13 #include "base/format_macros.h"
14 #include "base/strings/stringprintf.h"
15 #include "net/base/net_errors.h"
16 #include "net/disk_cache/disk_cache.h"
17 #include "net/disk_cache/simple/simple_backend_version.h"
18 #include "net/disk_cache/simple/simple_entry_format_history.h"
19 #include "testing/gtest/include/gtest/gtest.h"
20
21 namespace {
22
23 // Same as |disk_cache::kSimpleInitialMagicNumber|.
24 const uint64_t kSimpleInitialMagicNumber = UINT64_C(0xfcfb6d1ba7725c30);
25
26 // The "fake index" file that cache backends use to distinguish whether the
27 // cache belongs to one backend or another.
28 const char kFakeIndexFileName[] = "index";
29
30 // Same as |SimpleIndexFile::kIndexDirectory|.
31 const char kIndexDirName[] = "index-dir";
32
33 // Same as |SimpleIndexFile::kIndexFileName|.
34 const char kIndexFileName[] = "the-real-index";
35
WriteFakeIndexFileV5(const base::FilePath & cache_path)36 bool WriteFakeIndexFileV5(const base::FilePath& cache_path) {
37 disk_cache::FakeIndexData data;
38 data.version = 5;
39 data.initial_magic_number = kSimpleInitialMagicNumber;
40 data.zero = 0;
41 data.zero2 = 0;
42 const base::FilePath file_name = cache_path.AppendASCII("index");
43 return base::WriteFile(file_name, base::as_bytes(base::make_span(&data, 1u)));
44 }
45
TEST(SimpleVersionUpgradeTest,FailsToMigrateBackwards)46 TEST(SimpleVersionUpgradeTest, FailsToMigrateBackwards) {
47 base::ScopedTempDir cache_dir;
48 ASSERT_TRUE(cache_dir.CreateUniqueTempDir());
49 const base::FilePath cache_path = cache_dir.GetPath();
50
51 disk_cache::FakeIndexData data;
52 data.version = 100500;
53 data.initial_magic_number = kSimpleInitialMagicNumber;
54 data.zero = 0;
55 data.zero2 = 0;
56 const base::FilePath file_name = cache_path.AppendASCII(kFakeIndexFileName);
57 ASSERT_TRUE(
58 base::WriteFile(file_name, base::as_bytes(base::make_span(&data, 1u))));
59 disk_cache::TrivialFileOperations file_operations;
60 EXPECT_EQ(disk_cache::SimpleCacheConsistencyResult::kVersionFromTheFuture,
61 disk_cache::UpgradeSimpleCacheOnDisk(&file_operations,
62 cache_dir.GetPath()));
63 }
64
TEST(SimpleVersionUpgradeTest,ExperimentBacktoDefault)65 TEST(SimpleVersionUpgradeTest, ExperimentBacktoDefault) {
66 base::ScopedTempDir cache_dir;
67 ASSERT_TRUE(cache_dir.CreateUniqueTempDir());
68 const base::FilePath cache_path = cache_dir.GetPath();
69
70 disk_cache::FakeIndexData data;
71 data.version = disk_cache::kSimpleVersion;
72 data.initial_magic_number = kSimpleInitialMagicNumber;
73 data.zero = 2;
74 data.zero2 = 4;
75 const base::FilePath file_name = cache_path.AppendASCII(kFakeIndexFileName);
76 ASSERT_TRUE(
77 base::WriteFile(file_name, base::as_bytes(base::make_span(&data, 1u))));
78
79 disk_cache::TrivialFileOperations file_operations;
80 // The cache needs to transition from a deprecated experiment back to not
81 // having one.
82 EXPECT_EQ(disk_cache::SimpleCacheConsistencyResult::kBadZeroCheck,
83 disk_cache::UpgradeSimpleCacheOnDisk(&file_operations,
84 cache_dir.GetPath()));
85 }
86
TEST(SimpleVersionUpgradeTest,FakeIndexVersionGetsUpdated)87 TEST(SimpleVersionUpgradeTest, FakeIndexVersionGetsUpdated) {
88 base::ScopedTempDir cache_dir;
89 ASSERT_TRUE(cache_dir.CreateUniqueTempDir());
90 const base::FilePath cache_path = cache_dir.GetPath();
91
92 WriteFakeIndexFileV5(cache_path);
93 const std::string file_contents("incorrectly serialized data");
94 const base::FilePath index_file = cache_path.AppendASCII(kIndexFileName);
95 ASSERT_TRUE(base::WriteFile(index_file, file_contents));
96
97 disk_cache::TrivialFileOperations file_operations;
98 // Upgrade.
99 ASSERT_EQ(disk_cache::SimpleCacheConsistencyResult::kOK,
100 disk_cache::UpgradeSimpleCacheOnDisk(&file_operations, cache_path));
101
102 // Check that the version in the fake index file is updated.
103 std::string new_fake_index_contents;
104 ASSERT_TRUE(base::ReadFileToString(cache_path.AppendASCII(kFakeIndexFileName),
105 &new_fake_index_contents));
106 const disk_cache::FakeIndexData* fake_index_header;
107 EXPECT_EQ(sizeof(*fake_index_header), new_fake_index_contents.size());
108 fake_index_header = reinterpret_cast<const disk_cache::FakeIndexData*>(
109 new_fake_index_contents.data());
110 EXPECT_EQ(disk_cache::kSimpleVersion, fake_index_header->version);
111 EXPECT_EQ(kSimpleInitialMagicNumber, fake_index_header->initial_magic_number);
112 }
113
TEST(SimpleVersionUpgradeTest,UpgradeV5V6IndexMustDisappear)114 TEST(SimpleVersionUpgradeTest, UpgradeV5V6IndexMustDisappear) {
115 base::ScopedTempDir cache_dir;
116 ASSERT_TRUE(cache_dir.CreateUniqueTempDir());
117 const base::FilePath cache_path = cache_dir.GetPath();
118
119 WriteFakeIndexFileV5(cache_path);
120 const std::string file_contents("incorrectly serialized data");
121 const base::FilePath index_file = cache_path.AppendASCII(kIndexFileName);
122 ASSERT_TRUE(base::WriteFile(index_file, file_contents));
123
124 // Create a few entry-like files.
125 const uint64_t kEntries = 5;
126 for (uint64_t entry_hash = 0; entry_hash < kEntries; ++entry_hash) {
127 for (int index = 0; index < 3; ++index) {
128 std::string file_name =
129 base::StringPrintf("%016" PRIx64 "_%1d", entry_hash, index);
130 std::string entry_contents =
131 file_contents +
132 base::StringPrintf(" %" PRIx64, static_cast<uint64_t>(entry_hash));
133 ASSERT_TRUE(
134 base::WriteFile(cache_path.AppendASCII(file_name), entry_contents));
135 }
136 }
137
138 disk_cache::TrivialFileOperations file_operations;
139 // Upgrade.
140 ASSERT_TRUE(disk_cache::UpgradeIndexV5V6(&file_operations, cache_path));
141
142 // Check that the old index disappeared but the files remain unchanged.
143 EXPECT_FALSE(base::PathExists(index_file));
144 for (uint64_t entry_hash = 0; entry_hash < kEntries; ++entry_hash) {
145 for (int index = 0; index < 3; ++index) {
146 std::string file_name =
147 base::StringPrintf("%016" PRIx64 "_%1d", entry_hash, index);
148 std::string expected_contents =
149 file_contents +
150 base::StringPrintf(" %" PRIx64, static_cast<uint64_t>(entry_hash));
151 std::string real_contents;
152 EXPECT_TRUE(base::ReadFileToString(cache_path.AppendASCII(file_name),
153 &real_contents));
154 EXPECT_EQ(expected_contents, real_contents);
155 }
156 }
157 }
158
TEST(SimpleVersionUpgradeTest,DeleteAllIndexFilesWhenCacheIsEmpty)159 TEST(SimpleVersionUpgradeTest, DeleteAllIndexFilesWhenCacheIsEmpty) {
160 const std::string kCorruptData("corrupt");
161
162 base::ScopedTempDir cache_dir;
163 ASSERT_TRUE(cache_dir.CreateUniqueTempDir());
164 const base::FilePath cache_path = cache_dir.GetPath();
165
166 const base::FilePath fake_index = cache_path.AppendASCII(kFakeIndexFileName);
167 ASSERT_TRUE(base::WriteFile(fake_index, kCorruptData));
168
169 const base::FilePath index_path = cache_path.AppendASCII(kIndexDirName);
170 ASSERT_TRUE(base::CreateDirectory(index_path));
171
172 const base::FilePath index = index_path.AppendASCII(kIndexFileName);
173 ASSERT_TRUE(base::WriteFile(index, kCorruptData));
174
175 EXPECT_TRUE(disk_cache::DeleteIndexFilesIfCacheIsEmpty(cache_path));
176 EXPECT_TRUE(base::PathExists(cache_path));
177 EXPECT_TRUE(base::IsDirectoryEmpty(cache_path));
178 }
179
TEST(SimpleVersionUpgradeTest,DoesNotDeleteIndexFilesWhenCacheIsNotEmpty)180 TEST(SimpleVersionUpgradeTest, DoesNotDeleteIndexFilesWhenCacheIsNotEmpty) {
181 const std::string kCorruptData("corrupt");
182
183 base::ScopedTempDir cache_dir;
184 ASSERT_TRUE(cache_dir.CreateUniqueTempDir());
185 const base::FilePath cache_path = cache_dir.GetPath();
186
187 const base::FilePath fake_index = cache_path.AppendASCII(kFakeIndexFileName);
188 ASSERT_TRUE(base::WriteFile(fake_index, kCorruptData));
189
190 const base::FilePath index_path = cache_path.AppendASCII(kIndexDirName);
191 ASSERT_TRUE(base::CreateDirectory(index_path));
192
193 const base::FilePath index = index_path.AppendASCII(kIndexFileName);
194 ASSERT_TRUE(base::WriteFile(index, kCorruptData));
195
196 const base::FilePath entry_file = cache_path.AppendASCII("01234567_0");
197 ASSERT_TRUE(base::WriteFile(entry_file, kCorruptData));
198
199 EXPECT_FALSE(disk_cache::DeleteIndexFilesIfCacheIsEmpty(cache_path));
200 EXPECT_TRUE(base::PathExists(cache_path));
201 EXPECT_FALSE(base::IsDirectoryEmpty(cache_path));
202 EXPECT_TRUE(base::PathExists(fake_index));
203 EXPECT_TRUE(base::PathExists(index_path));
204 EXPECT_TRUE(base::PathExists(index));
205 EXPECT_TRUE(base::PathExists(entry_file));
206 }
207
208 } // namespace
209