// Copyright (c) 2010 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 "chrome/browser/sync/engine/verify_updates_command.h"
#include "chrome/browser/sync/engine/syncer.h"
#include "chrome/browser/sync/engine/syncer_proto_util.h"
#include "chrome/browser/sync/engine/syncer_types.h"
#include "chrome/browser/sync/engine/syncer_util.h"
#include "chrome/browser/sync/engine/syncproto.h"
#include "chrome/browser/sync/protocol/bookmark_specifics.pb.h"
#include "chrome/browser/sync/syncable/directory_manager.h"
#include "chrome/browser/sync/syncable/syncable.h"
namespace browser_sync {
using syncable::ScopedDirLookup;
using syncable::SyncName;
using syncable::WriteTransaction;
using syncable::GET_BY_ID;
using syncable::SYNCER;
VerifyUpdatesCommand::VerifyUpdatesCommand() {}
VerifyUpdatesCommand::~VerifyUpdatesCommand() {}
void VerifyUpdatesCommand::ModelChangingExecuteImpl(
sessions::SyncSession* session) {
VLOG(1) << "Beginning Update Verification";
ScopedDirLookup dir(session->context()->directory_manager(),
session->context()->account_name());
if (!dir.good()) {
LOG(ERROR) << "Scoped dir lookup failed!";
return;
}
WriteTransaction trans(dir, SYNCER, __FILE__, __LINE__);
sessions::StatusController* status = session->status_controller();
const GetUpdatesResponse& updates = status->updates_response().get_updates();
int update_count = updates.entries().size();
VLOG(1) << update_count << " entries to verify";
for (int i = 0; i < update_count; i++) {
const SyncEntity& update =
*reinterpret_cast<const SyncEntity *>(&(updates.entries(i)));
ModelSafeGroup g = GetGroupForModelType(update.GetModelType(),
session->routing_info());
if (g != status->group_restriction())
continue;
VerifyUpdateResult result = VerifyUpdate(&trans, update,
session->routing_info());
status->mutable_update_progress()->AddVerifyResult(result.value, update);
status->increment_num_updates_downloaded_by(1);
if (update.deleted())
status->increment_num_tombstone_updates_downloaded_by(1);
}
}
namespace {
// In the event that IDs match, but tags differ AttemptReuniteClient tag
// will have refused to unify the update.
// We should not attempt to apply it at all since it violates consistency
// rules.
VerifyResult VerifyTagConsistency(const SyncEntity& entry,
const syncable::MutableEntry& same_id) {
if (entry.has_client_defined_unique_tag() &&
entry.client_defined_unique_tag() !=
same_id.Get(syncable::UNIQUE_CLIENT_TAG)) {
return VERIFY_FAIL;
}
return VERIFY_UNDECIDED;
}
} // namespace
VerifyUpdatesCommand::VerifyUpdateResult VerifyUpdatesCommand::VerifyUpdate(
syncable::WriteTransaction* trans, const SyncEntity& entry,
const ModelSafeRoutingInfo& routes) {
syncable::Id id = entry.id();
VerifyUpdateResult result = {VERIFY_FAIL, GROUP_PASSIVE};
const bool deleted = entry.has_deleted() && entry.deleted();
const bool is_directory = entry.IsFolder();
const syncable::ModelType model_type = entry.GetModelType();
if (!id.ServerKnows()) {
LOG(ERROR) << "Illegal negative id in received updates";
return result;
}
{
const std::string name = SyncerProtoUtil::NameFromSyncEntity(entry);
if (name.empty() && !deleted) {
LOG(ERROR) << "Zero length name in non-deleted update";
return result;
}
}
syncable::MutableEntry same_id(trans, GET_BY_ID, id);
result.value = SyncerUtil::VerifyNewEntry(entry, &same_id, deleted);
syncable::ModelType placement_type = !deleted ? entry.GetModelType()
: same_id.good() ? same_id.GetModelType() : syncable::UNSPECIFIED;
result.placement = GetGroupForModelType(placement_type, routes);
if (VERIFY_UNDECIDED == result.value) {
result.value = VerifyTagConsistency(entry, same_id);
}
if (VERIFY_UNDECIDED == result.value) {
if (deleted)
result.value = VERIFY_SUCCESS;
}
// If we have an existing entry, we check here for updates that break
// consistency rules.
if (VERIFY_UNDECIDED == result.value) {
result.value = SyncerUtil::VerifyUpdateConsistency(trans, entry, &same_id,
deleted, is_directory, model_type);
}
if (VERIFY_UNDECIDED == result.value)
result.value = VERIFY_SUCCESS; // No news is good news.
return result; // This might be VERIFY_SUCCESS as well
}
} // namespace browser_sync