This source file includes following definitions.
- db_path_
- RecoveryImpl
- ExecuteImpl
- last_errno_
- RecordSqliteError
- has_error
- FormatError
- MakeSqliteAppCacheDbTest
- MakeSqliteArchivedHistoryDbTest
- MakeSqliteCookiesDbTest
- MakeSqliteWebDatabaseTrackerDbTest
- MakeSqliteHistoryDbTest
- MakeSqliteNssCertDbTest
- MakeSqliteNssKeyDbTest
- MakeSqliteThumbnailsDbTest
- MakeSqliteWebDataDbTest
#include "chrome/browser/diagnostics/sqlite_diagnostics.h"
#include "base/file_util.h"
#include "base/logging.h"
#include "base/memory/ref_counted.h"
#include "base/memory/singleton.h"
#include "base/memory/weak_ptr.h"
#include "base/metrics/histogram.h"
#include "base/path_service.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "chrome/common/chrome_constants.h"
#include "chrome/common/chrome_paths.h"
#include "chromeos/chromeos_constants.h"
#include "components/webdata/common/webdata_constants.h"
#include "content/public/common/content_constants.h"
#include "sql/connection.h"
#include "sql/statement.h"
#include "third_party/sqlite/sqlite3.h"
#include "webkit/browser/database/database_tracker.h"
#include "webkit/common/appcache/appcache_interfaces.h"
namespace diagnostics {
namespace {
class SqliteIntegrityTest : public DiagnosticsTest {
public:
enum Flags {
NO_FLAGS_SET = 0,
CRITICAL = 0x01,
REMOVE_IF_CORRUPT = 0x02,
};
SqliteIntegrityTest(uint32 flags,
DiagnosticsTestId id,
const base::FilePath& db_path)
: DiagnosticsTest(id), flags_(flags), db_path_(db_path) {}
virtual bool RecoveryImpl(DiagnosticsModel::Observer* observer) OVERRIDE {
int outcome_code = GetOutcomeCode();
if (flags_ & REMOVE_IF_CORRUPT) {
switch (outcome_code) {
case DIAG_SQLITE_ERROR_HANDLER_CALLED:
case DIAG_SQLITE_CANNOT_OPEN_DB:
case DIAG_SQLITE_DB_LOCKED:
case DIAG_SQLITE_PRAGMA_FAILED:
case DIAG_SQLITE_DB_CORRUPTED:
LOG(WARNING) << "Removing broken SQLite database: "
<< db_path_.value();
base::DeleteFile(db_path_, false);
break;
case DIAG_SQLITE_SUCCESS:
case DIAG_SQLITE_FILE_NOT_FOUND_OK:
case DIAG_SQLITE_FILE_NOT_FOUND:
break;
default:
DCHECK(false) << "Invalid outcome code: " << outcome_code;
break;
}
}
return true;
}
virtual bool ExecuteImpl(DiagnosticsModel::Observer* observer) OVERRIDE {
base::FilePath path;
if (!db_path_.IsAbsolute())
path = GetUserDefaultProfileDir().Append(db_path_);
else
path = db_path_;
if (!base::PathExists(path)) {
if (flags_ & CRITICAL) {
RecordOutcome(DIAG_SQLITE_FILE_NOT_FOUND,
"File not found",
DiagnosticsModel::TEST_FAIL_CONTINUE);
} else {
RecordOutcome(DIAG_SQLITE_FILE_NOT_FOUND_OK,
"File not found (but that is OK)",
DiagnosticsModel::TEST_OK);
}
return true;
}
int errors = 0;
{
sql::Connection database;
database.set_exclusive_locking();
scoped_refptr<ErrorRecorder> recorder(new ErrorRecorder);
database.set_error_callback(
base::Bind(&SqliteIntegrityTest::ErrorRecorder::RecordSqliteError,
recorder->AsWeakPtr(),
&database));
if (!database.Open(path)) {
RecordFailure(DIAG_SQLITE_CANNOT_OPEN_DB,
"Cannot open DB. Possibly corrupted");
return true;
}
if (recorder->has_error()) {
RecordFailure(DIAG_SQLITE_ERROR_HANDLER_CALLED,
recorder->FormatError());
return true;
}
sql::Statement statement(
database.GetUniqueStatement("PRAGMA integrity_check;"));
if (recorder->has_error()) {
RecordFailure(DIAG_SQLITE_ERROR_HANDLER_CALLED,
recorder->FormatError());
return true;
}
if (!statement.is_valid()) {
int error = database.GetErrorCode();
if (SQLITE_BUSY == error) {
RecordFailure(DIAG_SQLITE_DB_LOCKED,
"Database locked by another process");
} else {
std::string str("Pragma failed. Error: ");
str += base::IntToString(error);
RecordFailure(DIAG_SQLITE_PRAGMA_FAILED, str);
}
return false;
}
while (statement.Step()) {
std::string result(statement.ColumnString(0));
if ("ok" != result)
++errors;
}
if (recorder->has_error()) {
RecordFailure(DIAG_SQLITE_ERROR_HANDLER_CALLED,
recorder->FormatError());
return true;
}
}
if (errors != 0) {
std::string str("Database corruption detected: ");
str += base::IntToString(errors) + " errors";
RecordFailure(DIAG_SQLITE_DB_CORRUPTED, str);
return true;
}
RecordSuccess("No corruption detected");
return true;
}
private:
class ErrorRecorder : public base::RefCounted<ErrorRecorder>,
public base::SupportsWeakPtr<ErrorRecorder> {
public:
ErrorRecorder() : has_error_(false), sqlite_error_(0), last_errno_(0) {}
void RecordSqliteError(sql::Connection* connection,
int sqlite_error,
sql::Statement* statement) {
has_error_ = true;
sqlite_error_ = sqlite_error;
last_errno_ = connection->GetLastErrno();
message_ = connection->GetErrorMessage();
}
bool has_error() const { return has_error_; }
std::string FormatError() {
return base::StringPrintf("SQLite error: %d, Last Errno: %d: %s",
sqlite_error_,
last_errno_,
message_.c_str());
}
private:
friend class base::RefCounted<ErrorRecorder>;
~ErrorRecorder() {}
bool has_error_;
int sqlite_error_;
int last_errno_;
std::string message_;
DISALLOW_COPY_AND_ASSIGN(ErrorRecorder);
};
uint32 flags_;
base::FilePath db_path_;
DISALLOW_COPY_AND_ASSIGN(SqliteIntegrityTest);
};
}
DiagnosticsTest* MakeSqliteAppCacheDbTest() {
base::FilePath appcache_dir(content::kAppCacheDirname);
base::FilePath appcache_db =
appcache_dir.Append(appcache::kAppCacheDatabaseName);
return new SqliteIntegrityTest(SqliteIntegrityTest::NO_FLAGS_SET,
DIAGNOSTICS_SQLITE_INTEGRITY_APP_CACHE_TEST,
appcache_db);
}
DiagnosticsTest* MakeSqliteArchivedHistoryDbTest() {
return new SqliteIntegrityTest(
SqliteIntegrityTest::NO_FLAGS_SET,
DIAGNOSTICS_SQLITE_INTEGRITY_ARCHIVED_HISTORY_TEST,
base::FilePath(chrome::kArchivedHistoryFilename));
}
DiagnosticsTest* MakeSqliteCookiesDbTest() {
return new SqliteIntegrityTest(SqliteIntegrityTest::CRITICAL,
DIAGNOSTICS_SQLITE_INTEGRITY_COOKIE_TEST,
base::FilePath(chrome::kCookieFilename));
}
DiagnosticsTest* MakeSqliteWebDatabaseTrackerDbTest() {
base::FilePath databases_dir(webkit_database::kDatabaseDirectoryName);
base::FilePath tracker_db =
databases_dir.Append(webkit_database::kTrackerDatabaseFileName);
return new SqliteIntegrityTest(
SqliteIntegrityTest::NO_FLAGS_SET,
DIAGNOSTICS_SQLITE_INTEGRITY_DATABASE_TRACKER_TEST,
tracker_db);
}
DiagnosticsTest* MakeSqliteHistoryDbTest() {
return new SqliteIntegrityTest(SqliteIntegrityTest::CRITICAL,
DIAGNOSTICS_SQLITE_INTEGRITY_HISTORY_TEST,
base::FilePath(chrome::kHistoryFilename));
}
#if defined(OS_CHROMEOS)
DiagnosticsTest* MakeSqliteNssCertDbTest() {
base::FilePath home_dir = base::GetHomeDir();
return new SqliteIntegrityTest(SqliteIntegrityTest::REMOVE_IF_CORRUPT,
DIAGNOSTICS_SQLITE_INTEGRITY_NSS_CERT_TEST,
home_dir.Append(chromeos::kNssCertDbPath));
}
DiagnosticsTest* MakeSqliteNssKeyDbTest() {
base::FilePath home_dir = base::GetHomeDir();
return new SqliteIntegrityTest(SqliteIntegrityTest::REMOVE_IF_CORRUPT,
DIAGNOSTICS_SQLITE_INTEGRITY_NSS_KEY_TEST,
home_dir.Append(chromeos::kNssKeyDbPath));
}
#endif
DiagnosticsTest* MakeSqliteThumbnailsDbTest() {
return new SqliteIntegrityTest(SqliteIntegrityTest::NO_FLAGS_SET,
DIAGNOSTICS_SQLITE_INTEGRITY_THUMBNAILS_TEST,
base::FilePath(chrome::kThumbnailsFilename));
}
DiagnosticsTest* MakeSqliteWebDataDbTest() {
return new SqliteIntegrityTest(SqliteIntegrityTest::CRITICAL,
DIAGNOSTICS_SQLITE_INTEGRITY_WEB_DATA_TEST,
base::FilePath(kWebDataFilename));
}
}