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 230