• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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::byte_span_from_ref(data));
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(base::WriteFile(file_name, base::byte_span_from_ref(data)));
58   disk_cache::TrivialFileOperations file_operations;
59   EXPECT_EQ(disk_cache::SimpleCacheConsistencyResult::kVersionFromTheFuture,
60             disk_cache::UpgradeSimpleCacheOnDisk(&file_operations,
61                                                  cache_dir.GetPath()));
62 }
63 
TEST(SimpleVersionUpgradeTest,ExperimentBacktoDefault)64 TEST(SimpleVersionUpgradeTest, ExperimentBacktoDefault) {
65   base::ScopedTempDir cache_dir;
66   ASSERT_TRUE(cache_dir.CreateUniqueTempDir());
67   const base::FilePath cache_path = cache_dir.GetPath();
68 
69   disk_cache::FakeIndexData data;
70   data.version = disk_cache::kSimpleVersion;
71   data.initial_magic_number = kSimpleInitialMagicNumber;
72   data.zero = 2;
73   data.zero2 = 4;
74   const base::FilePath file_name = cache_path.AppendASCII(kFakeIndexFileName);
75   ASSERT_TRUE(base::WriteFile(file_name, base::byte_span_from_ref(data)));
76 
77   disk_cache::TrivialFileOperations file_operations;
78   // The cache needs to transition from a deprecated experiment back to not
79   // having one.
80   EXPECT_EQ(disk_cache::SimpleCacheConsistencyResult::kBadZeroCheck,
81             disk_cache::UpgradeSimpleCacheOnDisk(&file_operations,
82                                                  cache_dir.GetPath()));
83 }
84 
TEST(SimpleVersionUpgradeTest,FakeIndexVersionGetsUpdated)85 TEST(SimpleVersionUpgradeTest, FakeIndexVersionGetsUpdated) {
86   base::ScopedTempDir cache_dir;
87   ASSERT_TRUE(cache_dir.CreateUniqueTempDir());
88   const base::FilePath cache_path = cache_dir.GetPath();
89 
90   WriteFakeIndexFileV5(cache_path);
91   const std::string file_contents("incorrectly serialized data");
92   const base::FilePath index_file = cache_path.AppendASCII(kIndexFileName);
93   ASSERT_TRUE(base::WriteFile(index_file, file_contents));
94 
95   disk_cache::TrivialFileOperations file_operations;
96   // Upgrade.
97   ASSERT_EQ(disk_cache::SimpleCacheConsistencyResult::kOK,
98             disk_cache::UpgradeSimpleCacheOnDisk(&file_operations, cache_path));
99 
100   // Check that the version in the fake index file is updated.
101   std::string new_fake_index_contents;
102   ASSERT_TRUE(base::ReadFileToString(cache_path.AppendASCII(kFakeIndexFileName),
103                                      &new_fake_index_contents));
104   const disk_cache::FakeIndexData* fake_index_header;
105   EXPECT_EQ(sizeof(*fake_index_header), new_fake_index_contents.size());
106   fake_index_header = reinterpret_cast<const disk_cache::FakeIndexData*>(
107       new_fake_index_contents.data());
108   EXPECT_EQ(disk_cache::kSimpleVersion, fake_index_header->version);
109   EXPECT_EQ(kSimpleInitialMagicNumber, fake_index_header->initial_magic_number);
110 }
111 
TEST(SimpleVersionUpgradeTest,UpgradeV5V6IndexMustDisappear)112 TEST(SimpleVersionUpgradeTest, UpgradeV5V6IndexMustDisappear) {
113   base::ScopedTempDir cache_dir;
114   ASSERT_TRUE(cache_dir.CreateUniqueTempDir());
115   const base::FilePath cache_path = cache_dir.GetPath();
116 
117   WriteFakeIndexFileV5(cache_path);
118   const std::string file_contents("incorrectly serialized data");
119   const base::FilePath index_file = cache_path.AppendASCII(kIndexFileName);
120   ASSERT_TRUE(base::WriteFile(index_file, file_contents));
121 
122   // Create a few entry-like files.
123   const uint64_t kEntries = 5;
124   for (uint64_t entry_hash = 0; entry_hash < kEntries; ++entry_hash) {
125     for (int index = 0; index < 3; ++index) {
126       std::string file_name =
127           base::StringPrintf("%016" PRIx64 "_%1d", entry_hash, index);
128       std::string entry_contents =
129           file_contents +
130           base::StringPrintf(" %" PRIx64, static_cast<uint64_t>(entry_hash));
131       ASSERT_TRUE(
132           base::WriteFile(cache_path.AppendASCII(file_name), entry_contents));
133     }
134   }
135 
136   disk_cache::TrivialFileOperations file_operations;
137   // Upgrade.
138   ASSERT_TRUE(disk_cache::UpgradeIndexV5V6(&file_operations, cache_path));
139 
140   // Check that the old index disappeared but the files remain unchanged.
141   EXPECT_FALSE(base::PathExists(index_file));
142   for (uint64_t entry_hash = 0; entry_hash < kEntries; ++entry_hash) {
143     for (int index = 0; index < 3; ++index) {
144       std::string file_name =
145           base::StringPrintf("%016" PRIx64 "_%1d", entry_hash, index);
146       std::string expected_contents =
147           file_contents +
148           base::StringPrintf(" %" PRIx64, static_cast<uint64_t>(entry_hash));
149       std::string real_contents;
150       EXPECT_TRUE(base::ReadFileToString(cache_path.AppendASCII(file_name),
151                                          &real_contents));
152       EXPECT_EQ(expected_contents, real_contents);
153     }
154   }
155 }
156 
TEST(SimpleVersionUpgradeTest,DeleteAllIndexFilesWhenCacheIsEmpty)157 TEST(SimpleVersionUpgradeTest, DeleteAllIndexFilesWhenCacheIsEmpty) {
158   const std::string kCorruptData("corrupt");
159 
160   base::ScopedTempDir cache_dir;
161   ASSERT_TRUE(cache_dir.CreateUniqueTempDir());
162   const base::FilePath cache_path = cache_dir.GetPath();
163 
164   const base::FilePath fake_index = cache_path.AppendASCII(kFakeIndexFileName);
165   ASSERT_TRUE(base::WriteFile(fake_index, kCorruptData));
166 
167   const base::FilePath index_path = cache_path.AppendASCII(kIndexDirName);
168   ASSERT_TRUE(base::CreateDirectory(index_path));
169 
170   const base::FilePath index = index_path.AppendASCII(kIndexFileName);
171   ASSERT_TRUE(base::WriteFile(index, kCorruptData));
172 
173   EXPECT_TRUE(disk_cache::DeleteIndexFilesIfCacheIsEmpty(cache_path));
174   EXPECT_TRUE(base::PathExists(cache_path));
175   EXPECT_TRUE(base::IsDirectoryEmpty(cache_path));
176 }
177 
TEST(SimpleVersionUpgradeTest,DoesNotDeleteIndexFilesWhenCacheIsNotEmpty)178 TEST(SimpleVersionUpgradeTest, DoesNotDeleteIndexFilesWhenCacheIsNotEmpty) {
179   const std::string kCorruptData("corrupt");
180 
181   base::ScopedTempDir cache_dir;
182   ASSERT_TRUE(cache_dir.CreateUniqueTempDir());
183   const base::FilePath cache_path = cache_dir.GetPath();
184 
185   const base::FilePath fake_index = cache_path.AppendASCII(kFakeIndexFileName);
186   ASSERT_TRUE(base::WriteFile(fake_index, kCorruptData));
187 
188   const base::FilePath index_path = cache_path.AppendASCII(kIndexDirName);
189   ASSERT_TRUE(base::CreateDirectory(index_path));
190 
191   const base::FilePath index = index_path.AppendASCII(kIndexFileName);
192   ASSERT_TRUE(base::WriteFile(index, kCorruptData));
193 
194   const base::FilePath entry_file = cache_path.AppendASCII("01234567_0");
195   ASSERT_TRUE(base::WriteFile(entry_file, kCorruptData));
196 
197   EXPECT_FALSE(disk_cache::DeleteIndexFilesIfCacheIsEmpty(cache_path));
198   EXPECT_TRUE(base::PathExists(cache_path));
199   EXPECT_FALSE(base::IsDirectoryEmpty(cache_path));
200   EXPECT_TRUE(base::PathExists(fake_index));
201   EXPECT_TRUE(base::PathExists(index_path));
202   EXPECT_TRUE(base::PathExists(index));
203   EXPECT_TRUE(base::PathExists(entry_file));
204 }
205 
206 }  // namespace
207