- add sources.
[platform/framework/web/crosswalk.git] / src / webkit / browser / fileapi / sandbox_prioritized_origin_database.cc
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
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
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
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
66 SandboxPrioritizedOriginDatabase::~SandboxPrioritizedOriginDatabase() {
67 }
68
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
89 std::string SandboxPrioritizedOriginDatabase::GetPrimaryOrigin() {
90   MaybeLoadPrimaryOrigin();
91   if (primary_origin_database_)
92     return primary_origin_database_->origin();
93   return std::string();
94 }
95
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
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
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
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
144 void SandboxPrioritizedOriginDatabase::DropDatabase() {
145   primary_origin_database_.reset();
146   origin_database_.reset();
147 }
148
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
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
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
205 void SandboxPrioritizedOriginDatabase::MaybeInitializeDatabases(
206     bool create) {
207   MaybeLoadPrimaryOrigin();
208   MaybeInitializeNonPrimaryDatabase(create);
209 }
210
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*
224 SandboxPrioritizedOriginDatabase::GetSandboxOriginDatabase() {
225   MaybeInitializeNonPrimaryDatabase(true);
226   return origin_database_.get();
227 }
228
229 }  // namespace fileapi