1 // Copyright 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 "webkit/browser/fileapi/sandbox_prioritized_origin_database.h"
6
7 #include "base/file_util.h"
8 #include "base/files/file_path.h"
9 #include "base/files/scoped_platform_file_closer.h"
10 #include "base/logging.h"
11 #include "base/pickle.h"
12 #include "base/platform_file.h"
13 #include "webkit/browser/fileapi/sandbox_isolated_origin_database.h"
14 #include "webkit/browser/fileapi/sandbox_origin_database.h"
15
16 namespace fileapi {
17
18 namespace {
19
20 const base::FilePath::CharType kPrimaryDirectory[] =
21 FILE_PATH_LITERAL("primary");
22 const base::FilePath::CharType kPrimaryOriginFile[] =
23 FILE_PATH_LITERAL("primary.origin");
24
WritePrimaryOriginFile(const base::FilePath & path,const std::string & origin)25 bool WritePrimaryOriginFile(const base::FilePath& path,
26 const std::string& origin) {
27 base::PlatformFileError error = base::PLATFORM_FILE_ERROR_FAILED;
28 bool created;
29 base::PlatformFile file = base::CreatePlatformFile(
30 path,
31 base::PLATFORM_FILE_OPEN_ALWAYS |
32 base::PLATFORM_FILE_WRITE,
33 &created, &error);
34 base::ScopedPlatformFileCloser closer(&file);
35 if (error != base::PLATFORM_FILE_OK ||
36 file == base::kInvalidPlatformFileValue)
37 return false;
38 base::TruncatePlatformFile(file, 0);
39 Pickle pickle;
40 pickle.WriteString(origin);
41 base::WritePlatformFile(file, 0, static_cast<const char*>(pickle.data()),
42 pickle.size());
43 base::FlushPlatformFile(file);
44 return true;
45 }
46
ReadPrimaryOriginFile(const base::FilePath & path,std::string * origin)47 bool ReadPrimaryOriginFile(const base::FilePath& path,
48 std::string* origin) {
49 std::string buffer;
50 if (!base::ReadFileToString(path, &buffer))
51 return false;
52 Pickle pickle(buffer.data(), buffer.size());
53 PickleIterator iter(pickle);
54 return pickle.ReadString(&iter, origin) && !origin->empty();
55 }
56
57 } // namespace
58
SandboxPrioritizedOriginDatabase(const base::FilePath & file_system_directory)59 SandboxPrioritizedOriginDatabase::SandboxPrioritizedOriginDatabase(
60 const base::FilePath& file_system_directory)
61 : file_system_directory_(file_system_directory),
62 primary_origin_file_(
63 file_system_directory_.Append(kPrimaryOriginFile)) {
64 }
65
~SandboxPrioritizedOriginDatabase()66 SandboxPrioritizedOriginDatabase::~SandboxPrioritizedOriginDatabase() {
67 }
68
InitializePrimaryOrigin(const std::string & origin)69 bool SandboxPrioritizedOriginDatabase::InitializePrimaryOrigin(
70 const std::string& origin) {
71 if (!primary_origin_database_) {
72 if (!MaybeLoadPrimaryOrigin() && ResetPrimaryOrigin(origin)) {
73 MaybeMigrateDatabase(origin);
74 primary_origin_database_.reset(
75 new SandboxIsolatedOriginDatabase(
76 origin,
77 file_system_directory_,
78 base::FilePath(kPrimaryDirectory)));
79 return true;
80 }
81 }
82
83 if (primary_origin_database_)
84 return primary_origin_database_->HasOriginPath(origin);
85
86 return false;
87 }
88
GetPrimaryOrigin()89 std::string SandboxPrioritizedOriginDatabase::GetPrimaryOrigin() {
90 MaybeLoadPrimaryOrigin();
91 if (primary_origin_database_)
92 return primary_origin_database_->origin();
93 return std::string();
94 }
95
HasOriginPath(const std::string & origin)96 bool SandboxPrioritizedOriginDatabase::HasOriginPath(
97 const std::string& origin) {
98 MaybeInitializeDatabases(false);
99 if (primary_origin_database_ &&
100 primary_origin_database_->HasOriginPath(origin))
101 return true;
102 if (origin_database_)
103 return origin_database_->HasOriginPath(origin);
104 return false;
105 }
106
GetPathForOrigin(const std::string & origin,base::FilePath * directory)107 bool SandboxPrioritizedOriginDatabase::GetPathForOrigin(
108 const std::string& origin, base::FilePath* directory) {
109 MaybeInitializeDatabases(true);
110 if (primary_origin_database_ &&
111 primary_origin_database_->GetPathForOrigin(origin, directory))
112 return true;
113 DCHECK(origin_database_);
114 return origin_database_->GetPathForOrigin(origin, directory);
115 }
116
RemovePathForOrigin(const std::string & origin)117 bool SandboxPrioritizedOriginDatabase::RemovePathForOrigin(
118 const std::string& origin) {
119 MaybeInitializeDatabases(false);
120 if (primary_origin_database_ &&
121 primary_origin_database_->HasOriginPath(origin)) {
122 primary_origin_database_.reset();
123 base::DeleteFile(file_system_directory_.Append(kPrimaryOriginFile),
124 true /* recursive */);
125 return true;
126 }
127 if (origin_database_)
128 return origin_database_->RemovePathForOrigin(origin);
129 return true;
130 }
131
ListAllOrigins(std::vector<OriginRecord> * origins)132 bool SandboxPrioritizedOriginDatabase::ListAllOrigins(
133 std::vector<OriginRecord>* origins) {
134 // SandboxOriginDatabase may clear the |origins|, so call this before
135 // primary_origin_database_.
136 MaybeInitializeDatabases(false);
137 if (origin_database_ && !origin_database_->ListAllOrigins(origins))
138 return false;
139 if (primary_origin_database_)
140 return primary_origin_database_->ListAllOrigins(origins);
141 return true;
142 }
143
DropDatabase()144 void SandboxPrioritizedOriginDatabase::DropDatabase() {
145 primary_origin_database_.reset();
146 origin_database_.reset();
147 }
148
MaybeLoadPrimaryOrigin()149 bool SandboxPrioritizedOriginDatabase::MaybeLoadPrimaryOrigin() {
150 if (primary_origin_database_)
151 return true;
152 std::string saved_origin;
153 if (!ReadPrimaryOriginFile(primary_origin_file_, &saved_origin))
154 return false;
155 primary_origin_database_.reset(
156 new SandboxIsolatedOriginDatabase(
157 saved_origin,
158 file_system_directory_,
159 base::FilePath(kPrimaryDirectory)));
160 return true;
161 }
162
ResetPrimaryOrigin(const std::string & origin)163 bool SandboxPrioritizedOriginDatabase::ResetPrimaryOrigin(
164 const std::string& origin) {
165 DCHECK(!primary_origin_database_);
166 if (!WritePrimaryOriginFile(primary_origin_file_, origin))
167 return false;
168 // We reset the primary origin directory too.
169 // (This means the origin file corruption causes data loss
170 // We could keep the directory there as the same origin will likely
171 // become the primary origin, but let's play conservatively.)
172 base::DeleteFile(file_system_directory_.Append(kPrimaryDirectory),
173 true /* recursive */);
174 return true;
175 }
176
MaybeMigrateDatabase(const std::string & origin)177 void SandboxPrioritizedOriginDatabase::MaybeMigrateDatabase(
178 const std::string& origin) {
179 MaybeInitializeNonPrimaryDatabase(false);
180 if (!origin_database_)
181 return;
182 if (origin_database_->HasOriginPath(origin)) {
183 base::FilePath directory_name;
184 if (origin_database_->GetPathForOrigin(origin, &directory_name) &&
185 directory_name != base::FilePath(kPrimaryOriginFile)) {
186 base::FilePath from_path = file_system_directory_.Append(directory_name);
187 base::FilePath to_path = file_system_directory_.Append(kPrimaryDirectory);
188
189 if (base::PathExists(to_path))
190 base::DeleteFile(to_path, true /* recursive */);
191 base::Move(from_path, to_path);
192 }
193
194 origin_database_->RemovePathForOrigin(origin);
195 }
196
197 std::vector<OriginRecord> origins;
198 origin_database_->ListAllOrigins(&origins);
199 if (origins.empty()) {
200 origin_database_->RemoveDatabase();
201 origin_database_.reset();
202 }
203 }
204
MaybeInitializeDatabases(bool create)205 void SandboxPrioritizedOriginDatabase::MaybeInitializeDatabases(
206 bool create) {
207 MaybeLoadPrimaryOrigin();
208 MaybeInitializeNonPrimaryDatabase(create);
209 }
210
MaybeInitializeNonPrimaryDatabase(bool create)211 void SandboxPrioritizedOriginDatabase::MaybeInitializeNonPrimaryDatabase(
212 bool create) {
213 if (origin_database_)
214 return;
215
216 origin_database_.reset(new SandboxOriginDatabase(file_system_directory_));
217 if (!create && !base::DirectoryExists(origin_database_->GetDatabasePath())) {
218 origin_database_.reset();
219 return;
220 }
221 }
222
223 SandboxOriginDatabase*
GetSandboxOriginDatabase()224 SandboxPrioritizedOriginDatabase::GetSandboxOriginDatabase() {
225 MaybeInitializeNonPrimaryDatabase(true);
226 return origin_database_.get();
227 }
228
229 } // namespace fileapi
230