// Copyright 2013 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "webkit/browser/fileapi/sandbox_prioritized_origin_database.h" #include "base/file_util.h" #include "base/files/file.h" #include "base/files/file_path.h" #include "base/logging.h" #include "base/pickle.h" #include "webkit/browser/fileapi/sandbox_isolated_origin_database.h" #include "webkit/browser/fileapi/sandbox_origin_database.h" namespace fileapi { namespace { const base::FilePath::CharType kPrimaryDirectory[] = FILE_PATH_LITERAL("primary"); const base::FilePath::CharType kPrimaryOriginFile[] = FILE_PATH_LITERAL("primary.origin"); bool WritePrimaryOriginFile(const base::FilePath& path, const std::string& origin) { base::File file(path, base::File::FLAG_OPEN_ALWAYS | base::File::FLAG_WRITE); if (!file.IsValid()) return false; if (!file.created()) file.SetLength(0); Pickle pickle; pickle.WriteString(origin); file.Write(0, static_cast(pickle.data()), pickle.size()); file.Flush(); return true; } bool ReadPrimaryOriginFile(const base::FilePath& path, std::string* origin) { std::string buffer; if (!base::ReadFileToString(path, &buffer)) return false; Pickle pickle(buffer.data(), buffer.size()); PickleIterator iter(pickle); return pickle.ReadString(&iter, origin) && !origin->empty(); } } // namespace SandboxPrioritizedOriginDatabase::SandboxPrioritizedOriginDatabase( const base::FilePath& file_system_directory, leveldb::Env* env_override) : file_system_directory_(file_system_directory), env_override_(env_override), primary_origin_file_( file_system_directory_.Append(kPrimaryOriginFile)) { } SandboxPrioritizedOriginDatabase::~SandboxPrioritizedOriginDatabase() { } bool SandboxPrioritizedOriginDatabase::InitializePrimaryOrigin( const std::string& origin) { if (!primary_origin_database_) { if (!MaybeLoadPrimaryOrigin() && ResetPrimaryOrigin(origin)) { MaybeMigrateDatabase(origin); primary_origin_database_.reset( new SandboxIsolatedOriginDatabase( origin, file_system_directory_, base::FilePath(kPrimaryDirectory))); return true; } } if (primary_origin_database_) return primary_origin_database_->HasOriginPath(origin); return false; } std::string SandboxPrioritizedOriginDatabase::GetPrimaryOrigin() { MaybeLoadPrimaryOrigin(); if (primary_origin_database_) return primary_origin_database_->origin(); return std::string(); } bool SandboxPrioritizedOriginDatabase::HasOriginPath( const std::string& origin) { MaybeInitializeDatabases(false); if (primary_origin_database_ && primary_origin_database_->HasOriginPath(origin)) return true; if (origin_database_) return origin_database_->HasOriginPath(origin); return false; } bool SandboxPrioritizedOriginDatabase::GetPathForOrigin( const std::string& origin, base::FilePath* directory) { MaybeInitializeDatabases(true); if (primary_origin_database_ && primary_origin_database_->GetPathForOrigin(origin, directory)) return true; DCHECK(origin_database_); return origin_database_->GetPathForOrigin(origin, directory); } bool SandboxPrioritizedOriginDatabase::RemovePathForOrigin( const std::string& origin) { MaybeInitializeDatabases(false); if (primary_origin_database_ && primary_origin_database_->HasOriginPath(origin)) { primary_origin_database_.reset(); base::DeleteFile(file_system_directory_.Append(kPrimaryOriginFile), true /* recursive */); return true; } if (origin_database_) return origin_database_->RemovePathForOrigin(origin); return true; } bool SandboxPrioritizedOriginDatabase::ListAllOrigins( std::vector* origins) { // SandboxOriginDatabase may clear the |origins|, so call this before // primary_origin_database_. MaybeInitializeDatabases(false); if (origin_database_ && !origin_database_->ListAllOrigins(origins)) return false; if (primary_origin_database_) return primary_origin_database_->ListAllOrigins(origins); return true; } void SandboxPrioritizedOriginDatabase::DropDatabase() { primary_origin_database_.reset(); origin_database_.reset(); } bool SandboxPrioritizedOriginDatabase::MaybeLoadPrimaryOrigin() { if (primary_origin_database_) return true; std::string saved_origin; if (!ReadPrimaryOriginFile(primary_origin_file_, &saved_origin)) return false; primary_origin_database_.reset( new SandboxIsolatedOriginDatabase( saved_origin, file_system_directory_, base::FilePath(kPrimaryDirectory))); return true; } bool SandboxPrioritizedOriginDatabase::ResetPrimaryOrigin( const std::string& origin) { DCHECK(!primary_origin_database_); if (!WritePrimaryOriginFile(primary_origin_file_, origin)) return false; // We reset the primary origin directory too. // (This means the origin file corruption causes data loss // We could keep the directory there as the same origin will likely // become the primary origin, but let's play conservatively.) base::DeleteFile(file_system_directory_.Append(kPrimaryDirectory), true /* recursive */); return true; } void SandboxPrioritizedOriginDatabase::MaybeMigrateDatabase( const std::string& origin) { MaybeInitializeNonPrimaryDatabase(false); if (!origin_database_) return; if (origin_database_->HasOriginPath(origin)) { base::FilePath directory_name; if (origin_database_->GetPathForOrigin(origin, &directory_name) && directory_name != base::FilePath(kPrimaryOriginFile)) { base::FilePath from_path = file_system_directory_.Append(directory_name); base::FilePath to_path = file_system_directory_.Append(kPrimaryDirectory); if (base::PathExists(to_path)) base::DeleteFile(to_path, true /* recursive */); base::Move(from_path, to_path); } origin_database_->RemovePathForOrigin(origin); } std::vector origins; origin_database_->ListAllOrigins(&origins); if (origins.empty()) { origin_database_->RemoveDatabase(); origin_database_.reset(); } } void SandboxPrioritizedOriginDatabase::MaybeInitializeDatabases( bool create) { MaybeLoadPrimaryOrigin(); MaybeInitializeNonPrimaryDatabase(create); } void SandboxPrioritizedOriginDatabase::MaybeInitializeNonPrimaryDatabase( bool create) { if (origin_database_) return; origin_database_.reset(new SandboxOriginDatabase(file_system_directory_, env_override_)); if (!create && !base::DirectoryExists(origin_database_->GetDatabasePath())) { origin_database_.reset(); return; } } SandboxOriginDatabase* SandboxPrioritizedOriginDatabase::GetSandboxOriginDatabase() { MaybeInitializeNonPrimaryDatabase(true); return origin_database_.get(); } } // namespace fileapi