summaryrefslogtreecommitdiffstats
path: root/webkit
diff options
context:
space:
mode:
authortzik@chromium.org <tzik@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-03-29 16:45:48 +0000
committertzik@chromium.org <tzik@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-03-29 16:45:48 +0000
commitb9698776c4b3f2880286e81f9f4d9e3ef61ed14a (patch)
treee1df997c6daa798984e0d8ebfd7c767da83154be /webkit
parenta1e5df4c62d629891eaf5e9fbb76fbe8ea13ab3d (diff)
downloadchromium_src-b9698776c4b3f2880286e81f9f4d9e3ef61ed14a.zip
chromium_src-b9698776c4b3f2880286e81f9f4d9e3ef61ed14a.tar.gz
chromium_src-b9698776c4b3f2880286e81f9f4d9e3ef61ed14a.tar.bz2
Add database recovery for FileSystemOriginDatabase
BUG=103018,116615 TEST=FileSystemOriginDatabase.DatabaseRecoveryTest Review URL: http://codereview.chromium.org/9663021 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@129631 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'webkit')
-rw-r--r--webkit/fileapi/file_system_directory_database.cc103
-rw-r--r--webkit/fileapi/file_system_directory_database.h12
-rw-r--r--webkit/fileapi/file_system_directory_database_unittest.cc7
-rw-r--r--webkit/fileapi/file_system_origin_database.cc119
-rw-r--r--webkit/fileapi/file_system_origin_database.h13
-rw-r--r--webkit/fileapi/file_system_origin_database_unittest.cc198
-rw-r--r--webkit/fileapi/file_system_util.cc16
-rw-r--r--webkit/fileapi/file_system_util.h13
-rw-r--r--webkit/fileapi/obfuscated_file_util.cc8
9 files changed, 375 insertions, 114 deletions
diff --git a/webkit/fileapi/file_system_directory_database.cc b/webkit/fileapi/file_system_directory_database.cc
index db95d63..6eb1df9 100644
--- a/webkit/fileapi/file_system_directory_database.cc
+++ b/webkit/fileapi/file_system_directory_database.cc
@@ -6,12 +6,12 @@
#include <math.h>
+#include "base/file_util.h"
#include "base/location.h"
#include "base/metrics/histogram.h"
#include "base/pickle.h"
#include "base/string_number_conversions.h"
#include "base/string_util.h"
-#include "base/sys_string_conversions.h"
#include "third_party/leveldatabase/src/include/leveldb/db.h"
#include "third_party/leveldatabase/src/include/leveldb/write_batch.h"
#include "webkit/fileapi/file_system_util.h"
@@ -28,13 +28,9 @@ bool PickleFromFileInfo(
base::Time::FromDoubleT(floor(info.modification_time.ToDoubleT()));
std::string name;
-#if defined(OS_POSIX)
- data_path = info.data_path.value();
- name = info.name;
-#elif defined(OS_WIN)
- data_path = base::SysWideToUTF8(info.data_path.value());
- name = base::SysWideToUTF8(info.name);
-#endif
+ data_path = fileapi::FilePathToString(info.data_path);
+ name = fileapi::FilePathToString(FilePath(info.name));
+
if (pickle->WriteInt64(info.parent_id) &&
pickle->WriteString(data_path) &&
pickle->WriteString(name) &&
@@ -57,13 +53,9 @@ bool FileInfoFromPickle(
pickle.ReadString(&iter, &data_path) &&
pickle.ReadString(&iter, &name) &&
pickle.ReadInt64(&iter, &internal_time)) {
-#if defined(OS_POSIX)
- info->data_path = FilePath(data_path);
- info->name = name;
-#elif defined(OS_WIN)
- info->data_path = FilePath(base::SysUTF8ToWide(data_path));
- info->name = base::SysUTF8ToWide(name);
-#endif
+
+ info->data_path = fileapi::StringToFilePath(data_path);
+ info->name = fileapi::StringToFilePath(name).value();
info->modification_time = base::Time::FromInternalValue(internal_time);
return true;
}
@@ -71,6 +63,7 @@ bool FileInfoFromPickle(
return false;
}
+const FilePath::CharType kDirectoryDatabaseName[] = FILE_PATH_LITERAL("Paths");
const char kChildLookupPrefix[] = "CHILD_OF:";
const char kChildLookupSeparator[] = ":";
const char kLastFileIdKey[] = "LAST_FILE_ID";
@@ -88,11 +81,7 @@ std::string GetChildLookupKey(
fileapi::FileSystemDirectoryDatabase::FileId parent_id,
const FilePath::StringType& child_name) {
std::string name;
-#if defined(OS_POSIX)
- name = child_name;
-#elif defined(OS_WIN)
- name = base::SysWideToUTF8(child_name);
-#endif
+ name = fileapi::FilePathToString(FilePath(child_name));
return std::string(kChildLookupPrefix) + base::Int64ToString(parent_id) +
std::string(kChildLookupSeparator) + name;
}
@@ -126,12 +115,9 @@ FileSystemDirectoryDatabase::FileInfo::FileInfo() : parent_id(0) {
FileSystemDirectoryDatabase::FileInfo::~FileInfo() {
}
-FileSystemDirectoryDatabase::FileSystemDirectoryDatabase(const FilePath& path) {
-#if defined(OS_POSIX)
- path_ = path.value();
-#elif defined(OS_WIN)
- path_ = base::SysWideToUTF8(path.value());
-#endif
+FileSystemDirectoryDatabase::FileSystemDirectoryDatabase(
+ const FilePath& filesystem_data_directory)
+ : filesystem_data_directory_(filesystem_data_directory) {
}
FileSystemDirectoryDatabase::~FileSystemDirectoryDatabase() {
@@ -139,7 +125,7 @@ FileSystemDirectoryDatabase::~FileSystemDirectoryDatabase() {
bool FileSystemDirectoryDatabase::GetChildWithName(
FileId parent_id, const FilePath::StringType& name, FileId* child_id) {
- if (!Init())
+ if (!Init(FAIL_ON_CORRUPTION))
return false;
DCHECK(child_id);
std::string child_key = GetChildLookupKey(parent_id, name);
@@ -180,7 +166,7 @@ bool FileSystemDirectoryDatabase::GetFileWithPath(
bool FileSystemDirectoryDatabase::ListChildren(
FileId parent_id, std::vector<FileId>* children) {
// Check to add later: fail if parent is a file, at least in debug builds.
- if (!Init())
+ if (!Init(FAIL_ON_CORRUPTION))
return false;
DCHECK(children);
std::string child_key_prefix = GetChildListingKeyPrefix(parent_id);
@@ -203,7 +189,7 @@ bool FileSystemDirectoryDatabase::ListChildren(
}
bool FileSystemDirectoryDatabase::GetFileInfo(FileId file_id, FileInfo* info) {
- if (!Init())
+ if (!Init(FAIL_ON_CORRUPTION))
return false;
DCHECK(info);
std::string file_key = GetFileLookupKey(file_id);
@@ -230,7 +216,7 @@ bool FileSystemDirectoryDatabase::GetFileInfo(FileId file_id, FileInfo* info) {
bool FileSystemDirectoryDatabase::AddFileInfo(
const FileInfo& info, FileId* file_id) {
- if (!Init())
+ if (!Init(FAIL_ON_CORRUPTION))
return false;
DCHECK(file_id);
std::string child_key = GetChildLookupKey(info.parent_id, info.name);
@@ -272,7 +258,7 @@ bool FileSystemDirectoryDatabase::AddFileInfo(
}
bool FileSystemDirectoryDatabase::RemoveFileInfo(FileId file_id) {
- if (!Init())
+ if (!Init(FAIL_ON_CORRUPTION))
return false;
leveldb::WriteBatch batch;
if (!RemoveFileInfoHelper(file_id, &batch))
@@ -289,7 +275,7 @@ bool FileSystemDirectoryDatabase::UpdateFileInfo(
FileId file_id, const FileInfo& new_info) {
// TODO: We should also check to see that this doesn't create a loop, but
// perhaps only in a debug build.
- if (!Init())
+ if (!Init(FAIL_ON_CORRUPTION))
return false;
DCHECK(file_id); // You can't remove the root, ever. Just delete the DB.
FileInfo old_info;
@@ -373,7 +359,7 @@ bool FileSystemDirectoryDatabase::OverwritingMoveFile(
}
bool FileSystemDirectoryDatabase::GetNextInteger(int64* next) {
- if (!Init())
+ if (!Init(FAIL_ON_CORRUPTION))
return false;
DCHECK(next);
std::string int_string;
@@ -408,12 +394,7 @@ bool FileSystemDirectoryDatabase::GetNextInteger(int64* next) {
// static
bool FileSystemDirectoryDatabase::DestroyDatabase(const FilePath& path) {
- std::string name;
-#if defined(OS_POSIX)
- name = path.value();
-#elif defined(OS_WIN)
- name = base::SysWideToUTF8(path.value());
-#endif
+ std::string name = FilePathToString(path.Append(kDirectoryDatabaseName));
leveldb::Status status = leveldb::DestroyDB(name, leveldb::Options());
if (status.ok())
return true;
@@ -422,21 +403,33 @@ bool FileSystemDirectoryDatabase::DestroyDatabase(const FilePath& path) {
return false;
}
-bool FileSystemDirectoryDatabase::Init() {
- if (db_.get())
- return true;
-
- leveldb::Options options;
- options.create_if_missing = true;
- leveldb::DB* db;
- leveldb::Status status = leveldb::DB::Open(options, path_, &db);
- ReportInitStatus(status);
- if (status.ok()) {
- db_.reset(db);
- return true;
- }
- HandleError(FROM_HERE, status);
- return false;
+bool FileSystemDirectoryDatabase::Init(RecoveryOption recovery_option) {
+ if (db_.get())
+ return true;
+
+ std::string path =
+ FilePathToString(filesystem_data_directory_.Append(
+ kDirectoryDatabaseName));
+ leveldb::Options options;
+ options.create_if_missing = true;
+ leveldb::DB* db;
+ leveldb::Status status = leveldb::DB::Open(options, path, &db);
+ ReportInitStatus(status);
+ if (status.ok()) {
+ db_.reset(db);
+ return true;
+ }
+ HandleError(FROM_HERE, status);
+
+ if (recovery_option == FAIL_ON_CORRUPTION)
+ return false;
+
+ DCHECK_EQ(DELETE_ON_CORRUPTION, recovery_option);
+ if (!file_util::Delete(filesystem_data_directory_, true))
+ return false;
+ if (!file_util::CreateDirectory(filesystem_data_directory_))
+ return false;
+ return Init(FAIL_ON_CORRUPTION);
}
void FileSystemDirectoryDatabase::ReportInitStatus(
@@ -484,7 +477,7 @@ bool FileSystemDirectoryDatabase::StoreDefaultValues() {
}
bool FileSystemDirectoryDatabase::GetLastFileId(FileId* file_id) {
- if (!Init())
+ if (!Init(FAIL_ON_CORRUPTION))
return false;
DCHECK(file_id);
std::string id_string;
diff --git a/webkit/fileapi/file_system_directory_database.h b/webkit/fileapi/file_system_directory_database.h
index dae587a..47ac60a 100644
--- a/webkit/fileapi/file_system_directory_database.h
+++ b/webkit/fileapi/file_system_directory_database.h
@@ -56,7 +56,8 @@ class FileSystemDirectoryDatabase {
base::Time modification_time;
};
- explicit FileSystemDirectoryDatabase(const FilePath& path);
+ explicit FileSystemDirectoryDatabase(
+ const FilePath& filesystem_data_directory);
~FileSystemDirectoryDatabase();
bool GetChildWithName(
@@ -88,7 +89,12 @@ class FileSystemDirectoryDatabase {
static bool DestroyDatabase(const FilePath& path);
private:
- bool Init();
+ enum RecoveryOption {
+ DELETE_ON_CORRUPTION,
+ FAIL_ON_CORRUPTION,
+ };
+
+ bool Init(RecoveryOption recovery_option);
void ReportInitStatus(const leveldb::Status& status);
bool StoreDefaultValues();
bool GetLastFileId(FileId* file_id);
@@ -99,7 +105,7 @@ class FileSystemDirectoryDatabase {
void HandleError(const tracked_objects::Location& from_here,
const leveldb::Status& status);
- std::string path_;
+ FilePath filesystem_data_directory_;
scoped_ptr<leveldb::DB> db_;
base::Time last_reported_time_;
DISALLOW_COPY_AND_ASSIGN(FileSystemDirectoryDatabase);
diff --git a/webkit/fileapi/file_system_directory_database_unittest.cc b/webkit/fileapi/file_system_directory_database_unittest.cc
index 3a47c91..2f78449 100644
--- a/webkit/fileapi/file_system_directory_database_unittest.cc
+++ b/webkit/fileapi/file_system_directory_database_unittest.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Copyright (c) 2012 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.
@@ -29,9 +29,10 @@ class FileSystemDirectoryDatabaseTest : public testing::Test {
}
void InitDatabase() {
+ // First reset() is to avoid multiple database instance for single
+ // directory at once.
db_.reset();
- FilePath path = base_.path().AppendASCII("db");
- db_.reset(new FileSystemDirectoryDatabase(path));
+ db_.reset(new FileSystemDirectoryDatabase(base_.path()));
}
bool AddFileInfo(FileId parent_id, const FilePath::StringType& name) {
diff --git a/webkit/fileapi/file_system_origin_database.cc b/webkit/fileapi/file_system_origin_database.cc
index 42cf8f6..279e4a0 100644
--- a/webkit/fileapi/file_system_origin_database.cc
+++ b/webkit/fileapi/file_system_origin_database.cc
@@ -4,6 +4,7 @@
#include "webkit/fileapi/file_system_origin_database.h"
+#include "base/file_util.h"
#include "base/format_macros.h"
#include "base/location.h"
#include "base/logging.h"
@@ -11,12 +12,13 @@
#include "base/string_number_conversions.h"
#include "base/stringprintf.h"
#include "base/string_util.h"
-#include "base/sys_string_conversions.h"
#include "third_party/leveldatabase/src/include/leveldb/db.h"
#include "third_party/leveldatabase/src/include/leveldb/write_batch.h"
+#include "webkit/fileapi/file_system_util.h"
namespace {
+const FilePath::CharType kOriginDatabaseName[] = FILE_PATH_LITERAL("Origins");
const char kOriginKeyPrefix[] = "ORIGIN:";
const char kLastPathKey[] = "LAST_PATH";
const int64 kMinimumReportIntervalHours = 1;
@@ -52,34 +54,111 @@ FileSystemOriginDatabase::OriginRecord::OriginRecord(
FileSystemOriginDatabase::OriginRecord::~OriginRecord() {
}
-FileSystemOriginDatabase::FileSystemOriginDatabase(const FilePath& path) {
-#if defined(OS_POSIX)
- path_ = path.value();
-#elif defined(OS_WIN)
- path_ = base::SysWideToUTF8(path.value());
-#endif
+FileSystemOriginDatabase::FileSystemOriginDatabase(
+ const FilePath& file_system_directory)
+ : file_system_directory_(file_system_directory) {
}
FileSystemOriginDatabase::~FileSystemOriginDatabase() {
}
-bool FileSystemOriginDatabase::Init() {
+bool FileSystemOriginDatabase::Init(RecoveryOption recovery_option) {
if (db_.get())
return true;
+ std::string path =
+ FilePathToString(file_system_directory_.Append(kOriginDatabaseName));
leveldb::Options options;
options.create_if_missing = true;
leveldb::DB* db;
- leveldb::Status status = leveldb::DB::Open(options, path_, &db);
+ leveldb::Status status = leveldb::DB::Open(options, path, &db);
ReportInitStatus(status);
if (status.ok()) {
db_.reset(db);
return true;
}
HandleError(FROM_HERE, status);
+
+ switch (recovery_option) {
+ case FAIL_ON_CORRUPTION:
+ return false;
+ case REPAIR_ON_CORRUPTION:
+ LOG(WARNING) << "Attempting to repair FileSystemOriginDatabase.";
+ if (RepairDatabase(path)) {
+ LOG(WARNING) << "Repairing FileSystemOriginDatabase completed.";
+ return true;
+ }
+ // fall through
+ case DELETE_ON_CORRUPTION:
+ if (!file_util::Delete(file_system_directory_, true))
+ return false;
+ if (!file_util::CreateDirectory(file_system_directory_))
+ return false;
+ return Init(FAIL_ON_CORRUPTION);
+ }
+ NOTREACHED();
return false;
}
+bool FileSystemOriginDatabase::RepairDatabase(const std::string& db_path) {
+ DCHECK(!db_.get());
+ if (!leveldb::RepairDB(db_path, leveldb::Options()).ok() ||
+ !Init(FAIL_ON_CORRUPTION)) {
+ LOG(WARNING) << "Failed to repair FileSystemOriginDatabase.";
+ return false;
+ }
+
+ // See if the repaired entries match with what we have on disk.
+ std::set<FilePath> directories;
+ file_util::FileEnumerator file_enum(file_system_directory_,
+ false /* recursive */,
+ file_util::FileEnumerator::DIRECTORIES);
+ FilePath path_each;
+ while (!(path_each = file_enum.Next()).empty())
+ directories.insert(path_each.BaseName());
+ std::set<FilePath>::iterator db_dir_itr =
+ directories.find(FilePath(kOriginDatabaseName));
+ // Make sure we have the database file in its directory and therefore we are
+ // working on the correct path.
+ DCHECK(db_dir_itr != directories.end());
+ directories.erase(db_dir_itr);
+
+ std::vector<OriginRecord> origins;
+ if (!ListAllOrigins(&origins)) {
+ DropDatabase();
+ return false;
+ }
+
+ // Delete any obsolete entries from the origins database.
+ for (std::vector<OriginRecord>::iterator db_origin_itr = origins.begin();
+ db_origin_itr != origins.end();
+ ++db_origin_itr) {
+ std::set<FilePath>::iterator dir_itr =
+ directories.find(db_origin_itr->path);
+ if (dir_itr == directories.end()) {
+ if (!RemovePathForOrigin(db_origin_itr->origin)) {
+ DropDatabase();
+ return false;
+ }
+ } else {
+ directories.erase(dir_itr);
+ }
+ }
+
+ // Delete any directories not listed in the origins database.
+ for (std::set<FilePath>::iterator dir_itr = directories.begin();
+ dir_itr != directories.end();
+ ++dir_itr) {
+ if (!file_util::Delete(file_system_directory_.Append(*dir_itr),
+ true /* recursive */)) {
+ DropDatabase();
+ return false;
+ }
+ }
+
+ return true;
+}
+
void FileSystemOriginDatabase::HandleError(
const tracked_objects::Location& from_here,
const leveldb::Status& status) {
@@ -106,7 +185,7 @@ void FileSystemOriginDatabase::ReportInitStatus(const leveldb::Status& status) {
}
bool FileSystemOriginDatabase::HasOriginPath(const std::string& origin) {
- if (!Init())
+ if (!Init(REPAIR_ON_CORRUPTION))
return false;
if (origin.empty())
return false;
@@ -123,7 +202,7 @@ bool FileSystemOriginDatabase::HasOriginPath(const std::string& origin) {
bool FileSystemOriginDatabase::GetPathForOrigin(
const std::string& origin, FilePath* directory) {
- if (!Init())
+ if (!Init(REPAIR_ON_CORRUPTION))
return false;
DCHECK(directory);
if (origin.empty())
@@ -148,11 +227,7 @@ bool FileSystemOriginDatabase::GetPathForOrigin(
}
}
if (status.ok()) {
-#if defined(OS_POSIX)
- *directory = FilePath(path_string);
-#elif defined(OS_WIN)
- *directory = FilePath(base::SysUTF8ToWide(path_string));
-#endif
+ *directory = StringToFilePath(path_string);
return true;
}
HandleError(FROM_HERE, status);
@@ -160,7 +235,7 @@ bool FileSystemOriginDatabase::GetPathForOrigin(
}
bool FileSystemOriginDatabase::RemovePathForOrigin(const std::string& origin) {
- if (!Init())
+ if (!Init(REPAIR_ON_CORRUPTION))
return false;
leveldb::Status status =
db_->Delete(leveldb::WriteOptions(), OriginToOriginKey(origin));
@@ -172,7 +247,7 @@ bool FileSystemOriginDatabase::RemovePathForOrigin(const std::string& origin) {
bool FileSystemOriginDatabase::ListAllOrigins(
std::vector<OriginRecord>* origins) {
- if (!Init())
+ if (!Init(REPAIR_ON_CORRUPTION))
return false;
DCHECK(origins);
scoped_ptr<leveldb::Iterator> iter(db_->NewIterator(leveldb::ReadOptions()));
@@ -183,11 +258,7 @@ bool FileSystemOriginDatabase::ListAllOrigins(
StartsWithASCII(iter->key().ToString(), origin_key_prefix, true)) {
std::string origin =
iter->key().ToString().substr(origin_key_prefix.length());
-#if defined(OS_POSIX)
- FilePath path = FilePath(iter->value().ToString());
-#elif defined(OS_WIN)
- FilePath path = FilePath(base::SysUTF8ToWide(iter->value().ToString()));
-#endif
+ FilePath path = StringToFilePath(iter->value().ToString());
origins->push_back(OriginRecord(origin, path));
iter->Next();
}
@@ -199,7 +270,7 @@ void FileSystemOriginDatabase::DropDatabase() {
}
bool FileSystemOriginDatabase::GetLastPathNumber(int* number) {
- if (!Init())
+ if (!Init(REPAIR_ON_CORRUPTION))
return false;
DCHECK(number);
std::string number_string;
diff --git a/webkit/fileapi/file_system_origin_database.h b/webkit/fileapi/file_system_origin_database.h
index 10247a7..fddd369 100644
--- a/webkit/fileapi/file_system_origin_database.h
+++ b/webkit/fileapi/file_system_origin_database.h
@@ -39,7 +39,7 @@ class FileSystemOriginDatabase {
// Only one instance of FileSystemOriginDatabase should exist for a given path
// at a given time.
- explicit FileSystemOriginDatabase(const FilePath& path);
+ explicit FileSystemOriginDatabase(const FilePath& file_system_directory);
~FileSystemOriginDatabase();
bool HasOriginPath(const std::string& origin);
@@ -57,13 +57,20 @@ class FileSystemOriginDatabase {
void DropDatabase();
private:
- bool Init();
+ enum RecoveryOption {
+ REPAIR_ON_CORRUPTION,
+ DELETE_ON_CORRUPTION,
+ FAIL_ON_CORRUPTION,
+ };
+
+ bool Init(RecoveryOption recovery_option);
+ bool RepairDatabase(const std::string& db_path);
void HandleError(const tracked_objects::Location& from_here,
const leveldb::Status& status);
void ReportInitStatus(const leveldb::Status& status);
bool GetLastPathNumber(int* number);
- std::string path_;
+ FilePath file_system_directory_;
scoped_ptr<leveldb::DB> db_;
base::Time last_reported_time_;
DISALLOW_COPY_AND_ASSIGN(FileSystemOriginDatabase);
diff --git a/webkit/fileapi/file_system_origin_database_unittest.cc b/webkit/fileapi/file_system_origin_database_unittest.cc
index c34e636..77bd3a8 100644
--- a/webkit/fileapi/file_system_origin_database_unittest.cc
+++ b/webkit/fileapi/file_system_origin_database_unittest.cc
@@ -1,24 +1,105 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Copyright (c) 2012 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 "testing/gtest/include/gtest/gtest.h"
+#include <algorithm>
#include <string>
+#include "base/file_path.h"
#include "base/file_util.h"
+#include "base/platform_file.h"
#include "base/scoped_temp_dir.h"
+#include "base/stl_util.h"
+#include "third_party/leveldatabase/src/db/filename.h"
+#include "third_party/leveldatabase/src/include/leveldb/db.h"
#include "webkit/fileapi/file_system_origin_database.h"
+#include "webkit/fileapi/file_system_util.h"
namespace fileapi {
+namespace {
+const FilePath::CharType kFileSystemDirName[] =
+ FILE_PATH_LITERAL("File System");
+const FilePath::CharType kOriginDatabaseName[] = FILE_PATH_LITERAL("Origins");
+
+void CorruptDatabase(const FilePath& db_path,
+ leveldb::FileType type,
+ ptrdiff_t offset,
+ size_t size) {
+ file_util::FileEnumerator file_enum(
+ db_path, false /* recursive */,
+ static_cast<file_util::FileEnumerator::FileType>(
+ file_util::FileEnumerator::DIRECTORIES |
+ file_util::FileEnumerator::FILES));
+ FilePath file_path;
+ FilePath picked_file_path;
+ uint64 picked_file_number = kuint64max;
+
+ while (!(file_path = file_enum.Next()).empty()) {
+ uint64 number = kuint64max;
+ leveldb::FileType file_type;
+ EXPECT_TRUE(leveldb::ParseFileName(FilePathToString(file_path.BaseName()),
+ &number, &file_type));
+ if (file_type == type &&
+ (picked_file_number == kuint64max || picked_file_number < number)) {
+ picked_file_path = file_path;
+ picked_file_number = number;
+ }
+ }
+
+ EXPECT_FALSE(picked_file_path.empty());
+ EXPECT_NE(kuint64max, picked_file_number);
+
+ bool created = true;
+ base::PlatformFileError error = base::PLATFORM_FILE_ERROR_FAILED;
+ base::PlatformFile file =
+ CreatePlatformFile(picked_file_path,
+ base::PLATFORM_FILE_OPEN |
+ base::PLATFORM_FILE_READ |
+ base::PLATFORM_FILE_WRITE,
+ &created, &error);
+ EXPECT_EQ(base::PLATFORM_FILE_OK, error);
+ EXPECT_FALSE(created);
+
+ base::PlatformFileInfo file_info;
+ EXPECT_TRUE(base::GetPlatformFileInfo(file, &file_info));
+ if (offset < 0)
+ offset += file_info.size;
+ EXPECT_GE(offset, 0);
+ EXPECT_LE(offset, file_info.size);
+
+ size = std::min(size, static_cast<size_t>(file_info.size - offset));
+
+ std::vector<char> buf(size);
+ int read_size = base::ReadPlatformFile(file, offset,
+ vector_as_array(&buf), buf.size());
+ EXPECT_LT(0, read_size);
+ EXPECT_GE(buf.size(), static_cast<size_t>(read_size));
+ buf.resize(read_size);
+
+ std::transform(buf.begin(), buf.end(), buf.begin(),
+ std::logical_not<char>());
+
+ int written_size = base::WritePlatformFile(file, offset,
+ vector_as_array(&buf), buf.size());
+ EXPECT_GT(written_size, 0);
+ EXPECT_EQ(buf.size(), static_cast<size_t>(written_size));
+
+ base::ClosePlatformFile(file);
+}
+
+}
+
TEST(FileSystemOriginDatabaseTest, BasicTest) {
ScopedTempDir dir;
ASSERT_TRUE(dir.CreateUniqueTempDir());
- const FilePath kDBFile = dir.path().AppendASCII("fsod.db");
- EXPECT_FALSE(file_util::PathExists(kDBFile));
+ const FilePath kFSDir = dir.path().Append(kFileSystemDirName);
+ EXPECT_FALSE(file_util::PathExists(kFSDir));
+ EXPECT_TRUE(file_util::CreateDirectory(kFSDir));
- FileSystemOriginDatabase database(kDBFile);
+ FileSystemOriginDatabase database(kFSDir);
std::string origin("origin");
EXPECT_FALSE(database.HasOriginPath(origin));
@@ -38,16 +119,17 @@ TEST(FileSystemOriginDatabaseTest, BasicTest) {
EXPECT_FALSE(path1.empty());
EXPECT_EQ(path0, path1);
- EXPECT_TRUE(file_util::PathExists(kDBFile));
+ EXPECT_TRUE(file_util::PathExists(kFSDir.Append(kOriginDatabaseName)));
}
TEST(FileSystemOriginDatabaseTest, TwoPathTest) {
ScopedTempDir dir;
ASSERT_TRUE(dir.CreateUniqueTempDir());
- const FilePath kDBFile = dir.path().AppendASCII("fsod.db");
- EXPECT_FALSE(file_util::PathExists(kDBFile));
+ const FilePath kFSDir = dir.path().Append(kFileSystemDirName);
+ EXPECT_FALSE(file_util::PathExists(kFSDir));
+ EXPECT_TRUE(file_util::CreateDirectory(kFSDir));
- FileSystemOriginDatabase database(kDBFile);
+ FileSystemOriginDatabase database(kFSDir);
std::string origin0("origin0");
std::string origin1("origin1");
@@ -65,16 +147,17 @@ TEST(FileSystemOriginDatabaseTest, TwoPathTest) {
EXPECT_FALSE(path1.empty());
EXPECT_NE(path0, path1);
- EXPECT_TRUE(file_util::PathExists(kDBFile));
+ EXPECT_TRUE(file_util::PathExists(kFSDir.Append(kOriginDatabaseName)));
}
TEST(FileSystemOriginDatabaseTest, DropDatabaseTest) {
ScopedTempDir dir;
ASSERT_TRUE(dir.CreateUniqueTempDir());
- const FilePath kDBFile = dir.path().AppendASCII("fsod.db");
- EXPECT_FALSE(file_util::PathExists(kDBFile));
+ const FilePath kFSDir = dir.path().Append(kFileSystemDirName);
+ EXPECT_FALSE(file_util::PathExists(kFSDir));
+ EXPECT_TRUE(file_util::CreateDirectory(kFSDir));
- FileSystemOriginDatabase database(kDBFile);
+ FileSystemOriginDatabase database(kFSDir);
std::string origin("origin");
EXPECT_FALSE(database.HasOriginPath(origin));
@@ -84,7 +167,7 @@ TEST(FileSystemOriginDatabaseTest, DropDatabaseTest) {
EXPECT_TRUE(database.HasOriginPath(origin));
EXPECT_FALSE(path0.empty());
- EXPECT_TRUE(file_util::PathExists(kDBFile));
+ EXPECT_TRUE(file_util::PathExists(kFSDir.Append(kOriginDatabaseName)));
database.DropDatabase();
@@ -98,10 +181,11 @@ TEST(FileSystemOriginDatabaseTest, DropDatabaseTest) {
TEST(FileSystemOriginDatabaseTest, DeleteOriginTest) {
ScopedTempDir dir;
ASSERT_TRUE(dir.CreateUniqueTempDir());
- const FilePath kDBFile = dir.path().AppendASCII("fsod.db");
- EXPECT_FALSE(file_util::PathExists(kDBFile));
+ const FilePath kFSDir = dir.path().Append(kFileSystemDirName);
+ EXPECT_FALSE(file_util::PathExists(kFSDir));
+ EXPECT_TRUE(file_util::CreateDirectory(kFSDir));
- FileSystemOriginDatabase database(kDBFile);
+ FileSystemOriginDatabase database(kFSDir);
std::string origin("origin");
EXPECT_FALSE(database.HasOriginPath(origin));
@@ -124,12 +208,13 @@ TEST(FileSystemOriginDatabaseTest, DeleteOriginTest) {
TEST(FileSystemOriginDatabaseTest, ListOriginsTest) {
ScopedTempDir dir;
ASSERT_TRUE(dir.CreateUniqueTempDir());
- const FilePath kDBFile = dir.path().AppendASCII("fsod.db");
- EXPECT_FALSE(file_util::PathExists(kDBFile));
+ const FilePath kFSDir = dir.path().Append(kFileSystemDirName);
+ EXPECT_FALSE(file_util::PathExists(kFSDir));
+ EXPECT_TRUE(file_util::CreateDirectory(kFSDir));
std::vector<FileSystemOriginDatabase::OriginRecord> origins;
- FileSystemOriginDatabase database(kDBFile);
+ FileSystemOriginDatabase database(kFSDir);
EXPECT_TRUE(database.ListAllOrigins(&origins));
EXPECT_TRUE(origins.empty());
origins.clear();
@@ -163,4 +248,79 @@ TEST(FileSystemOriginDatabaseTest, ListOriginsTest) {
}
}
+TEST(FileSystemOriginDatabaseTest, DatabaseRecoveryTest) {
+ // Checks if FileSystemOriginDatabase properly handles database corruption.
+ // In this test, we'll register some origins to the origin database, then
+ // corrupt database and its log file.
+ // After repairing, the origin database should be consistent even when some
+ // entries lost.
+
+ ScopedTempDir dir;
+ ASSERT_TRUE(dir.CreateUniqueTempDir());
+ const FilePath kFSDir = dir.path().Append(kFileSystemDirName);
+ const FilePath kDBDir = kFSDir.Append(kOriginDatabaseName);
+ EXPECT_FALSE(file_util::PathExists(kFSDir));
+ EXPECT_TRUE(file_util::CreateDirectory(kFSDir));
+
+ const std::string kOrigins[] = {
+ "foo.example.com",
+ "bar.example.com",
+ "baz.example.com",
+ "hoge.example.com",
+ "fuga.example.com",
+ };
+
+ scoped_ptr<FileSystemOriginDatabase> database(
+ new FileSystemOriginDatabase(kFSDir));
+ for (size_t i = 0; i < arraysize(kOrigins); ++i) {
+ FilePath path;
+ EXPECT_FALSE(database->HasOriginPath(kOrigins[i]));
+ EXPECT_TRUE(database->GetPathForOrigin(kOrigins[i], &path));
+ EXPECT_FALSE(path.empty());
+ EXPECT_TRUE(database->GetPathForOrigin(kOrigins[i], &path));
+
+ if (i != 1)
+ EXPECT_TRUE(file_util::CreateDirectory(kFSDir.Append(path)));
+ }
+ database.reset();
+
+ const FilePath kGarbageDir = kFSDir.AppendASCII("foo");
+ const FilePath kGarbageFile = kGarbageDir.AppendASCII("bar");
+ EXPECT_TRUE(file_util::CreateDirectory(kGarbageDir));
+ bool created = false;
+ base::PlatformFileError error;
+ base::PlatformFile file = base::CreatePlatformFile(
+ kGarbageFile,
+ base::PLATFORM_FILE_CREATE | base::PLATFORM_FILE_WRITE,
+ &created, &error);
+ EXPECT_EQ(base::PLATFORM_FILE_OK, error);
+ EXPECT_TRUE(created);
+ EXPECT_TRUE(base::ClosePlatformFile(file));
+
+ // Corrupt database itself and last log entry to drop last 1 database
+ // operation. The database should detect the corruption and should recover
+ // its consistency after recovery.
+ CorruptDatabase(kDBDir, leveldb::kDescriptorFile,
+ 0, std::numeric_limits<size_t>::max());
+ CorruptDatabase(kDBDir, leveldb::kLogFile, -1, 1);
+
+ FilePath path;
+ database.reset(new FileSystemOriginDatabase(kFSDir));
+ std::vector<FileSystemOriginDatabase::OriginRecord> origins_in_db;
+ EXPECT_TRUE(database->ListAllOrigins(&origins_in_db));
+
+ // Expect all but last added origin will be repaired back, and kOrigins[1]
+ // should be dropped due to absence of backing directory.
+ EXPECT_EQ(arraysize(kOrigins) - 2, origins_in_db.size());
+
+ const std::string kOrigin("piyo.example.org");
+ EXPECT_FALSE(database->HasOriginPath(kOrigin));
+ EXPECT_TRUE(database->GetPathForOrigin(kOrigin, &path));
+ EXPECT_FALSE(path.empty());
+ EXPECT_TRUE(database->HasOriginPath(kOrigin));
+
+ EXPECT_FALSE(file_util::PathExists(kGarbageFile));
+ EXPECT_FALSE(file_util::PathExists(kGarbageDir));
+}
+
} // namespace fileapi
diff --git a/webkit/fileapi/file_system_util.cc b/webkit/fileapi/file_system_util.cc
index c5a3047..ab145f1 100644
--- a/webkit/fileapi/file_system_util.cc
+++ b/webkit/fileapi/file_system_util.cc
@@ -224,4 +224,20 @@ std::string GetFileSystemTypeString(FileSystemType type) {
}
}
+std::string FilePathToString(const FilePath& file_path) {
+#if defined(OS_WIN)
+ return UTF16ToUTF8(file_path.value());
+#elif defined(OS_POSIX)
+ return file_path.value();
+#endif
+}
+
+FilePath StringToFilePath(const std::string& file_path_string) {
+#if defined(OS_WIN)
+ return FilePath(UTF8ToUTF16(file_path_string));
+#elif defined(OS_POSIX)
+ return FilePath(file_path_string);
+#endif
+}
+
} // namespace fileapi
diff --git a/webkit/fileapi/file_system_util.h b/webkit/fileapi/file_system_util.h
index 247d5ce..730cc55 100644
--- a/webkit/fileapi/file_system_util.h
+++ b/webkit/fileapi/file_system_util.h
@@ -92,6 +92,19 @@ GURL GetOriginURLFromIdentifier(const std::string& origin_identifier);
// Returns an empty string if the |type| is invalid.
std::string GetFileSystemTypeString(FileSystemType type);
+// Encodes |file_path| to a string.
+// Following conditions should be held:
+// - StringToFilePath(FilePathToString(path)) == path
+// - StringToFilePath(FilePathToString(path) + "/" + "SubDirectory") ==
+// path.AppendASCII("SubDirectory");
+//
+// TODO(tzik): Replace CreateFilePath and FilePathToString in
+// third_party/leveldatabase/env_chromium.cc with them.
+std::string FilePathToString(const FilePath& file_path);
+
+// Decode a file path from |file_path_string|.
+FilePath StringToFilePath(const std::string& file_path_string);
+
} // namespace fileapi
#endif // WEBKIT_FILEAPI_FILE_SYSTEM_UTIL_H_
diff --git a/webkit/fileapi/obfuscated_file_util.cc b/webkit/fileapi/obfuscated_file_util.cc
index 2a30dc0..b9a3334 100644
--- a/webkit/fileapi/obfuscated_file_util.cc
+++ b/webkit/fileapi/obfuscated_file_util.cc
@@ -31,9 +31,6 @@ namespace {
const int64 kFlushDelaySeconds = 10 * 60; // 10 minutes
-const char kOriginDatabaseName[] = "Origins";
-const char kDirectoryDatabaseName[] = "Paths";
-
void InitFileInfo(
FileSystemDirectoryDatabase::FileInfo* file_info,
FileSystemDirectoryDatabase::FileId parent_id,
@@ -991,7 +988,6 @@ bool ObfuscatedFileUtil::DestroyDirectoryDatabase(
return true;
if (!file_util::DirectoryExists(path))
return true;
- path = path.AppendASCII(kDirectoryDatabaseName);
return FileSystemDirectoryDatabase::DestroyDatabase(path);
}
@@ -1202,7 +1198,6 @@ FileSystemDirectoryDatabase* ObfuscatedFileUtil::GetDirectoryDatabase(
}
}
MarkUsed();
- path = path.AppendASCII(kDirectoryDatabaseName);
FileSystemDirectoryDatabase* database = new FileSystemDirectoryDatabase(path);
directories_[key] = database;
return database;
@@ -1262,8 +1257,7 @@ bool ObfuscatedFileUtil::InitOriginDatabase(bool create) {
return false;
}
origin_database_.reset(
- new FileSystemOriginDatabase(
- file_system_directory_.AppendASCII(kOriginDatabaseName)));
+ new FileSystemOriginDatabase(file_system_directory_));
}
return true;
}