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.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