Index: webkit/fileapi/file_system_origin_database.cc |
diff --git a/webkit/fileapi/file_system_origin_database.cc b/webkit/fileapi/file_system_origin_database.cc |
index 125576ae38d1eda4f7dfeae35a63059f1b326c06..fd7a13a1e214e439a84309f54d89cf33376e3564 100644 |
--- a/webkit/fileapi/file_system_origin_database.cc |
+++ b/webkit/fileapi/file_system_origin_database.cc |
@@ -4,21 +4,43 @@ |
#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" |
#include "base/string_number_conversions.h" |
#include "base/stringprintf.h" |
#include "base/string_util.h" |
-#include "base/sys_string_conversions.h" |
+#include "base/utf_string_conversions.h" |
#include "third_party/leveldatabase/src/include/leveldb/iterator.h" |
#include "third_party/leveldatabase/src/include/leveldb/write_batch.h" |
namespace { |
+const FilePath::CharType kOriginDatabaseName[] = FILE_PATH_LITERAL("Origins"); |
const char kOriginKeyPrefix[] = "ORIGIN:"; |
const char kLastPathKey[] = "LAST_PATH"; |
+std::string FilePathToString(const FilePath& path) { |
+ // TODO(tzik): Unify this to FilePathToString in |
+ // third_party/leveldatabase/env_chromium.cc. |
+#if defined(OS_WIN) |
+ return UTF16ToUTF8(path.value()); |
+#elif defined(OS_POSIX) |
+ return path.value(); |
+#endif |
+} |
+ |
+FilePath StringToFilePath(const std::string& path_string) { |
+ // TODO(tzik): Unify this to CreateFilePath in |
+ // third_party/leveldatabase/env_chromium.cc. |
+#if defined(OS_WIN) |
+ return FilePath(UTF8ToUTF16(path_string)); |
+#elif defined(OS_POSIX) |
+ return FilePath(path_string); |
+#endif |
+} |
+ |
std::string OriginToOriginKey(const std::string& origin) { |
std::string key(kOriginKeyPrefix); |
return key + origin; |
@@ -43,31 +65,105 @@ 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); |
+ // TODO(tzik): Collect status metrics here. |
if (status.ok()) { |
db_.reset(db); |
return true; |
} |
HandleError(FROM_HERE, status); |
- return false; |
+ |
+ if (recovery_option == FAIL_ON_CORRUPTION) |
+ return false; |
+ |
+ if (recovery_option == REPAIR_ON_CORRUPTION) { |
+ LOG(WARNING) << "Attempting to repair FileSystemOriginDatabase."; |
+ if (RepairDatabase(path)) { |
+ LOG(WARNING) << "Repairing FileSystemOriginDatabase completed."; |
+ return true; |
+ } |
+ } |
+ |
+ DCHECK(DELETE_ON_CORRUPTION == recovery_option || |
+ REPAIR_ON_CORRUPTION == recovery_option); |
+ if (!file_util::Delete(file_system_directory_, true)) |
+ return false; |
+ if (!file_util::CreateDirectory(file_system_directory_)) |
+ return false; |
+ |
kinuko
2012/03/26 05:25:09
The lines 93-110 might look easier to follow in sw
tzik
2012/03/26 08:04:56
Done.
|
+ return Init(FAIL_ON_CORRUPTION); |
+} |
+ |
+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)); |
+ DCHECK(db_dir_itr != directories.end()); |
+ directories.erase(db_dir_itr); |
+ |
+ std::vector<OriginRecord> origins; |
+ if (!ListAllOrigins(&origins)) { |
+ DropDatabase(); |
+ return false; |
+ } |
+ 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( |
@@ -78,7 +174,7 @@ void FileSystemOriginDatabase::HandleError( |
} |
bool FileSystemOriginDatabase::HasOriginPath(const std::string& origin) { |
- if (!Init()) |
+ if (!Init(REPAIR_ON_CORRUPTION)) |
return false; |
if (origin.empty()) |
return false; |
@@ -95,7 +191,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()) |
@@ -120,11 +216,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); |
@@ -132,7 +224,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)); |
@@ -144,7 +236,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())); |
@@ -155,11 +247,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(); |
} |
@@ -171,7 +259,7 @@ void FileSystemOriginDatabase::DropDatabase() { |
} |
bool FileSystemOriginDatabase::GetLastPathNumber(int* number) { |
- if (!Init()) |
+ if (!Init(REPAIR_ON_CORRUPTION)) |
return false; |
DCHECK(number); |
std::string number_string; |