blob: 8fd6db9ff59cf94d50709bcfbdb76eb09fd19c6b [file] [log] [blame]
// Copyright 2017 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 "components/offline_pages/core/model/complete_offline_page_upgrade_task.h"
#include "base/bind.h"
#include "base/files/file_util.h"
#include "base/sys_info.h"
#include "components/offline_pages/core/offline_page_metadata_store.h"
#include "components/offline_pages/core/offline_store_utils.h"
#include "sql/connection.h"
#include "sql/statement.h"
#include "sql/transaction.h"
namespace offline_pages {
namespace {
CompleteUpgradeStatus CompleteOfflinePageUpgradeSync(
int64_t offline_id,
const base::FilePath& temporary_file_path,
const base::FilePath& target_file_path,
const std::string& digest,
int64_t file_size,
sql::Connection* db) {
if (!db)
return CompleteUpgradeStatus::DB_ERROR;
sql::Transaction transaction(db);
if (!transaction.Begin())
return CompleteUpgradeStatus::DB_ERROR;
// We need to remember the old file path, so that we can remove that file
// later on.
static const char kSql[] =
"SELECT file_path FROM offlinepages_v1 WHERE offline_id = ?";
sql::Statement select_statement(db->GetCachedStatement(SQL_FROM_HERE, kSql));
select_statement.BindInt64(0, offline_id);
if (!select_statement.Step()) {
return select_statement.Succeeded() ? CompleteUpgradeStatus::ITEM_MISSING
: CompleteUpgradeStatus::DB_ERROR;
}
base::FilePath old_file_path =
store_utils::FromDatabaseFilePath(select_statement.ColumnString(0));
// TODO(fgorski): Verify the digest and size of the temporary file.
// That requires moving ComputeDigest function to component and this is
// already in progress.
// Verify that the temporary file is there.
if (!base::PathExists(temporary_file_path))
return CompleteUpgradeStatus::TEMPORARY_FILE_MISSING;
// Verify that the target file name is not in use.
if (base::PathExists(target_file_path))
return CompleteUpgradeStatus::TARGET_FILE_NAME_IN_USE;
if (!base::Move(temporary_file_path, target_file_path))
return CompleteUpgradeStatus::RENAMING_FAILED;
// Conditions for upgrade are met here.
// Update remaining attempts in DB and complete task.
static const char kUpdateSql[] =
"UPDATE offlinepages_v1"
" SET upgrade_attempt = 0, file_path = ?, file_size = ?, digest = ?"
" WHERE offline_id = ?";
sql::Statement update_statement(
db->GetCachedStatement(SQL_FROM_HERE, kUpdateSql));
update_statement.BindString(
0, store_utils::ToDatabaseFilePath(target_file_path));
update_statement.BindInt64(1, file_size);
update_statement.BindString(2, digest);
update_statement.BindInt64(3, offline_id);
// This status might require special handling/reporting as the new file was
// renamed to its final name, but store item was not updated accordingly.
if (!update_statement.Run() || !transaction.Commit())
return CompleteUpgradeStatus::DB_ERROR_POST_FILE_RENAME;
// Make a best effort to delete the old file (will be cleaned up by
// consistency check otherwise).
base::DeleteFile(old_file_path, false /* recursive */);
return CompleteUpgradeStatus::SUCCESS;
}
} // namespace
CompleteOfflinePageUpgradeTask::CompleteOfflinePageUpgradeTask(
OfflinePageMetadataStore* store,
int64_t offline_id,
const base::FilePath& temporary_file_path,
const base::FilePath& target_file_path,
const std::string& digest,
int64_t file_size,
CompleteUpgradeCallback callback)
: store_(store),
offline_id_(offline_id),
temporary_file_path_(temporary_file_path),
target_file_path_(target_file_path),
digest_(digest),
file_size_(file_size),
callback_(std::move(callback)),
weak_ptr_factory_(this) {
DCHECK(store_);
DCHECK(!callback_.is_null());
}
CompleteOfflinePageUpgradeTask::~CompleteOfflinePageUpgradeTask() {}
void CompleteOfflinePageUpgradeTask::Run() {
store_->Execute(
base::BindOnce(&CompleteOfflinePageUpgradeSync, offline_id_,
temporary_file_path_, target_file_path_, digest_,
file_size_),
base::BindOnce(&CompleteOfflinePageUpgradeTask::InformUpgradeAttemptDone,
weak_ptr_factory_.GetWeakPtr()));
}
void CompleteOfflinePageUpgradeTask::InformUpgradeAttemptDone(
CompleteUpgradeStatus result) {
std::move(callback_).Run(result);
TaskComplete();
}
} // namespace offline_pages