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