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 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 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 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 59 SandboxPrioritizedOriginDatabase::~SandboxPrioritizedOriginDatabase() { 60 } 61 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 82 std::string SandboxPrioritizedOriginDatabase::GetPrimaryOrigin() { 83 MaybeLoadPrimaryOrigin(); 84 if (primary_origin_database_) 85 return primary_origin_database_->origin(); 86 return std::string(); 87 } 88 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 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 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 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 137 void SandboxPrioritizedOriginDatabase::DropDatabase() { 138 primary_origin_database_.reset(); 139 origin_database_.reset(); 140 } 141 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 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 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 198 void SandboxPrioritizedOriginDatabase::MaybeInitializeDatabases( 199 bool create) { 200 MaybeLoadPrimaryOrigin(); 201 MaybeInitializeNonPrimaryDatabase(create); 202 } 203 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* 218 SandboxPrioritizedOriginDatabase::GetSandboxOriginDatabase() { 219 MaybeInitializeNonPrimaryDatabase(true); 220 return origin_database_.get(); 221 } 222 223 } // namespace fileapi 224