diff options
author | tzik@chromium.org <tzik@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-03-29 16:45:48 +0000 |
---|---|---|
committer | tzik@chromium.org <tzik@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-03-29 16:45:48 +0000 |
commit | b9698776c4b3f2880286e81f9f4d9e3ef61ed14a (patch) | |
tree | e1df997c6daa798984e0d8ebfd7c767da83154be /webkit | |
parent | a1e5df4c62d629891eaf5e9fbb76fbe8ea13ab3d (diff) | |
download | chromium_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.cc | 103 | ||||
-rw-r--r-- | webkit/fileapi/file_system_directory_database.h | 12 | ||||
-rw-r--r-- | webkit/fileapi/file_system_directory_database_unittest.cc | 7 | ||||
-rw-r--r-- | webkit/fileapi/file_system_origin_database.cc | 119 | ||||
-rw-r--r-- | webkit/fileapi/file_system_origin_database.h | 13 | ||||
-rw-r--r-- | webkit/fileapi/file_system_origin_database_unittest.cc | 198 | ||||
-rw-r--r-- | webkit/fileapi/file_system_util.cc | 16 | ||||
-rw-r--r-- | webkit/fileapi/file_system_util.h | 13 | ||||
-rw-r--r-- | webkit/fileapi/obfuscated_file_util.cc | 8 |
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; } |