15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
51320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "storage/browser/fileapi/sandbox_origin_database.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <set>
8868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include <utility>
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/files/file_enumerator.h"
111320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "base/files/file_util.h"
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/format_macros.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/location.h"
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/metrics/histogram.h"
16c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/strings/string_number_conversions.h"
175e3f23d412006dc4db4e659864679f29341e113fTorne (Richard Coles)#include "base/strings/string_util.h"
185e3f23d412006dc4db4e659864679f29341e113fTorne (Richard Coles)#include "base/strings/stringprintf.h"
191320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "storage/common/fileapi/file_system_util.h"
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "third_party/leveldatabase/src/include/leveldb/db.h"
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "third_party/leveldatabase/src/include/leveldb/write_batch.h"
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const base::FilePath::CharType kOriginDatabaseName[] =
262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    FILE_PATH_LITERAL("Origins");
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kOriginKeyPrefix[] = "ORIGIN:";
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kLastPathKey[] = "LAST_PATH";
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int64 kMinimumReportIntervalHours = 1;
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kInitStatusHistogramLabel[] = "FileSystem.OriginDatabaseInit";
31c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)const char kDatabaseRepairHistogramLabel[] = "FileSystem.OriginDatabaseRepair";
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)enum InitStatus {
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  INIT_STATUS_OK = 0,
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  INIT_STATUS_CORRUPTION,
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  INIT_STATUS_IO_ERROR,
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  INIT_STATUS_UNKNOWN_ERROR,
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  INIT_STATUS_MAX
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
41c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)enum RepairResult {
42c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DB_REPAIR_SUCCEEDED = 0,
43c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DB_REPAIR_FAILED,
44c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DB_REPAIR_MAX
45c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)};
46c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::string OriginToOriginKey(const std::string& origin) {
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string key(kOriginKeyPrefix);
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return key + origin;
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char* LastPathKey() {
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return kLastPathKey;
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)namespace storage {
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)SandboxOriginDatabase::SandboxOriginDatabase(
615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const base::FilePath& file_system_directory,
625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    leveldb::Env* env_override)
635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    : file_system_directory_(file_system_directory),
645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      env_override_(env_override) {
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)SandboxOriginDatabase::~SandboxOriginDatabase() {
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
70868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)bool SandboxOriginDatabase::Init(InitOption init_option,
71868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                                 RecoveryOption recovery_option) {
72b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (db_)
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  base::FilePath db_path = GetDatabasePath();
767dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (init_option == FAIL_IF_NONEXISTENT && !base::PathExists(db_path))
77868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    return false;
78868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
79868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  std::string path = FilePathToString(db_path);
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  leveldb::Options options;
817dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  options.max_open_files = 0;  // Use minimum.
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  options.create_if_missing = true;
835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (env_override_)
845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    options.env = env_override_;
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  leveldb::DB* db;
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  leveldb::Status status = leveldb::DB::Open(options, path, &db);
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ReportInitStatus(status);
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (status.ok()) {
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    db_.reset(db);
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HandleError(FROM_HERE, status);
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
94c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Corruption due to missing necessary MANIFEST-* file causes IOError instead
95c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // of Corruption error.
96c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Try to repair database even when IOError case.
97c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!status.IsCorruption() && !status.IsIOError())
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  switch (recovery_option) {
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case FAIL_ON_CORRUPTION:
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case REPAIR_ON_CORRUPTION:
10490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      LOG(WARNING) << "Attempting to repair SandboxOriginDatabase.";
105c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (RepairDatabase(path)) {
107c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        UMA_HISTOGRAM_ENUMERATION(kDatabaseRepairHistogramLabel,
108c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                  DB_REPAIR_SUCCEEDED, DB_REPAIR_MAX);
10990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        LOG(WARNING) << "Repairing SandboxOriginDatabase completed.";
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return true;
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
112c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      UMA_HISTOGRAM_ENUMERATION(kDatabaseRepairHistogramLabel,
113c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                DB_REPAIR_FAILED, DB_REPAIR_MAX);
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // fall through
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case DELETE_ON_CORRUPTION:
1167dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      if (!base::DeleteFile(file_system_directory_, true))
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return false;
118a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      if (!base::CreateDirectory(file_system_directory_))
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return false;
120868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      return Init(init_option, FAIL_ON_CORRUPTION);
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  NOTREACHED();
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)bool SandboxOriginDatabase::RepairDatabase(const std::string& db_path) {
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!db_.get());
1287dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  leveldb::Options options;
1297dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  options.max_open_files = 0;  // Use minimum.
1305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (env_override_)
1315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    options.env = env_override_;
1327dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (!leveldb::RepairDB(db_path, options).ok() ||
133868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      !Init(FAIL_IF_NONEXISTENT, FAIL_ON_CORRUPTION)) {
13490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    LOG(WARNING) << "Failed to repair SandboxOriginDatabase.";
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // See if the repaired entries match with what we have on disk.
1392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::set<base::FilePath> directories;
140868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  base::FileEnumerator file_enum(file_system_directory_,
141868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                                 false /* recursive */,
142868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                                 base::FileEnumerator::DIRECTORIES);
1432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::FilePath path_each;
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while (!(path_each = file_enum.Next()).empty())
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    directories.insert(path_each.BaseName());
1462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::set<base::FilePath>::iterator db_dir_itr =
1472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      directories.find(base::FilePath(kOriginDatabaseName));
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Make sure we have the database file in its directory and therefore we are
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // working on the correct path.
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(db_dir_itr != directories.end());
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  directories.erase(db_dir_itr);
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<OriginRecord> origins;
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!ListAllOrigins(&origins)) {
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DropDatabase();
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Delete any obsolete entries from the origins database.
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (std::vector<OriginRecord>::iterator db_origin_itr = origins.begin();
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       db_origin_itr != origins.end();
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       ++db_origin_itr) {
1632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    std::set<base::FilePath>::iterator dir_itr =
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        directories.find(db_origin_itr->path);
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (dir_itr == directories.end()) {
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (!RemovePathForOrigin(db_origin_itr->origin)) {
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        DropDatabase();
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return false;
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      directories.erase(dir_itr);
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Delete any directories not listed in the origins database.
1762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (std::set<base::FilePath>::iterator dir_itr = directories.begin();
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       dir_itr != directories.end();
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       ++dir_itr) {
1797dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    if (!base::DeleteFile(file_system_directory_.Append(*dir_itr),
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           true /* recursive */)) {
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      DropDatabase();
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
18990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void SandboxOriginDatabase::HandleError(
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const tracked_objects::Location& from_here,
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const leveldb::Status& status) {
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_.reset();
19390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  LOG(ERROR) << "SandboxOriginDatabase failed at: "
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)             << from_here.ToString() << " with error: " << status.ToString();
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
19790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void SandboxOriginDatabase::ReportInitStatus(const leveldb::Status& status) {
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::Time now = base::Time::Now();
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::TimeDelta minimum_interval =
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::TimeDelta::FromHours(kMinimumReportIntervalHours);
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (last_reported_time_ + minimum_interval >= now)
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  last_reported_time_ = now;
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (status.ok()) {
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    UMA_HISTOGRAM_ENUMERATION(kInitStatusHistogramLabel,
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              INIT_STATUS_OK, INIT_STATUS_MAX);
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else if (status.IsCorruption()) {
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    UMA_HISTOGRAM_ENUMERATION(kInitStatusHistogramLabel,
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              INIT_STATUS_CORRUPTION, INIT_STATUS_MAX);
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else if (status.IsIOError()) {
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    UMA_HISTOGRAM_ENUMERATION(kInitStatusHistogramLabel,
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              INIT_STATUS_IO_ERROR, INIT_STATUS_MAX);
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    UMA_HISTOGRAM_ENUMERATION(kInitStatusHistogramLabel,
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              INIT_STATUS_UNKNOWN_ERROR, INIT_STATUS_MAX);
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
22090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)bool SandboxOriginDatabase::HasOriginPath(const std::string& origin) {
221868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (!Init(FAIL_IF_NONEXISTENT, REPAIR_ON_CORRUPTION))
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (origin.empty())
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string path;
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  leveldb::Status status =
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      db_->Get(leveldb::ReadOptions(), OriginToOriginKey(origin), &path);
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (status.ok())
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (status.IsNotFound())
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HandleError(FROM_HERE, status);
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
23690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)bool SandboxOriginDatabase::GetPathForOrigin(
2372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& origin, base::FilePath* directory) {
238868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (!Init(CREATE_IF_NONEXISTENT, REPAIR_ON_CORRUPTION))
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(directory);
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (origin.empty())
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string path_string;
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string origin_key = OriginToOriginKey(origin);
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  leveldb::Status status =
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      db_->Get(leveldb::ReadOptions(), origin_key, &path_string);
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (status.IsNotFound()) {
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int last_path_number;
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!GetLastPathNumber(&last_path_number))
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
2512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    path_string = base::StringPrintf("%03u", last_path_number + 1);
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // store both back as a single transaction
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    leveldb::WriteBatch batch;
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    batch.Put(LastPathKey(), path_string);
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    batch.Put(origin_key, path_string);
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    status = db_->Write(leveldb::WriteOptions(), &batch);
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!status.ok()) {
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      HandleError(FROM_HERE, status);
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (status.ok()) {
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *directory = StringToFilePath(path_string);
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HandleError(FROM_HERE, status);
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
27090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)bool SandboxOriginDatabase::RemovePathForOrigin(const std::string& origin) {
271868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (!Init(CREATE_IF_NONEXISTENT, REPAIR_ON_CORRUPTION))
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  leveldb::Status status =
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      db_->Delete(leveldb::WriteOptions(), OriginToOriginKey(origin));
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (status.ok() || status.IsNotFound())
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HandleError(FROM_HERE, status);
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
28190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)bool SandboxOriginDatabase::ListAllOrigins(
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::vector<OriginRecord>* origins) {
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(origins);
284868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (!Init(CREATE_IF_NONEXISTENT, REPAIR_ON_CORRUPTION)) {
285868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    origins->clear();
286868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    return false;
287868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<leveldb::Iterator> iter(db_->NewIterator(leveldb::ReadOptions()));
289c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  std::string origin_key_prefix = OriginToOriginKey(std::string());
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  iter->Seek(origin_key_prefix);
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  origins->clear();
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while (iter->Valid() &&
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      StartsWithASCII(iter->key().ToString(), origin_key_prefix, true)) {
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::string origin =
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      iter->key().ToString().substr(origin_key_prefix.length());
2962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::FilePath path = StringToFilePath(iter->value().ToString());
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    origins->push_back(OriginRecord(origin, path));
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    iter->Next();
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
30390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void SandboxOriginDatabase::DropDatabase() {
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_.reset();
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
307868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)base::FilePath SandboxOriginDatabase::GetDatabasePath() const {
308868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  return file_system_directory_.Append(kOriginDatabaseName);
309868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
310868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
311868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)void SandboxOriginDatabase::RemoveDatabase() {
312868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  DropDatabase();
3137dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  base::DeleteFile(GetDatabasePath(), true /* recursive */);
314868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
315868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
31690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)bool SandboxOriginDatabase::GetLastPathNumber(int* number) {
317868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  DCHECK(db_);
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(number);
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string number_string;
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  leveldb::Status status =
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      db_->Get(leveldb::ReadOptions(), LastPathKey(), &number_string);
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (status.ok())
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return base::StringToInt(number_string, number);
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!status.IsNotFound()) {
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    HandleError(FROM_HERE, status);
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Verify that this is a totally new database, and initialize it.
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<leveldb::Iterator> iter(db_->NewIterator(leveldb::ReadOptions()));
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  iter->SeekToFirst();
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (iter->Valid()) {  // DB was not empty, but had no last path number!
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << "File system origin database is corrupt!";
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // This is always the first write into the database.  If we ever add a
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // version number, they should go in in a single transaction.
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  status =
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      db_->Put(leveldb::WriteOptions(), LastPathKey(), std::string("-1"));
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!status.ok()) {
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    HandleError(FROM_HERE, status);
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *number = -1;
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
34703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)}  // namespace storage
348