Home | History | Annotate | Download | only in fileapi
      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