| Index: chrome/browser/sync/engine/conflict_resolver.cc
|
| diff --git a/chrome/browser/sync/engine/conflict_resolver.cc b/chrome/browser/sync/engine/conflict_resolver.cc
|
| index ff0127a6dc4dcb3fa18c6f08b03edcd91a80defb..e37ac36e2b0ae21e5719e15a8a71d4d106ce9297 100644
|
| --- a/chrome/browser/sync/engine/conflict_resolver.cc
|
| +++ b/chrome/browser/sync/engine/conflict_resolver.cc
|
| @@ -12,10 +12,12 @@
|
| #include "base/metrics/histogram.h"
|
| #include "chrome/browser/sync/engine/syncer.h"
|
| #include "chrome/browser/sync/engine/syncer_util.h"
|
| +#include "chrome/browser/sync/protocol/nigori_specifics.pb.h"
|
| #include "chrome/browser/sync/protocol/service_constants.h"
|
| #include "chrome/browser/sync/sessions/status_controller.h"
|
| #include "chrome/browser/sync/syncable/directory_manager.h"
|
| #include "chrome/browser/sync/syncable/syncable.h"
|
| +#include "chrome/browser/sync/util/cryptographer.h"
|
|
|
| using std::map;
|
| using std::set;
|
| @@ -43,6 +45,7 @@ enum SimpleConflictResolutions {
|
| UNDELETE, // Resolved by undeleting local item.
|
| IGNORE_ENCRYPTION, // Resolved by ignoring an encryption-only server
|
| // change. TODO(zea): implement and use this.
|
| + NIGORI_MERGE, // Resolved by merging nigori nodes.
|
| CONFLICT_RESOLUTION_SIZE,
|
| };
|
|
|
| @@ -78,6 +81,7 @@ void ConflictResolver::OverwriteServerChanges(WriteTransaction* trans,
|
| ConflictResolver::ProcessSimpleConflictResult
|
| ConflictResolver::ProcessSimpleConflict(WriteTransaction* trans,
|
| const Id& id,
|
| + const Cryptographer* cryptographer,
|
| StatusController* status) {
|
| MutableEntry entry(trans, syncable::GET_BY_ID, id);
|
| // Must be good as the entry won't have been cleaned up.
|
| @@ -124,7 +128,40 @@ ConflictResolver::ProcessSimpleConflict(WriteTransaction* trans,
|
| entry.Get(syncable::SERVER_PARENT_ID);
|
| bool entry_deleted = entry.Get(syncable::IS_DEL);
|
|
|
| - if (!entry_deleted && name_matches && parent_matches) {
|
| + // We manually merge nigori data.
|
| + if (entry.GetModelType() == syncable::NIGORI) {
|
| + // Create a new set of specifics based on the server specifics (which
|
| + // preserves their encryption keys).
|
| + sync_pb::EntitySpecifics specifics =
|
| + entry.Get(syncable::SERVER_SPECIFICS);
|
| + sync_pb::NigoriSpecifics* nigori =
|
| + specifics.MutableExtension(sync_pb::nigori);
|
| + // Store the merged set of encrypted types (cryptographer->Update(..) will
|
| + // have merged the local types already).
|
| + cryptographer->UpdateNigoriFromEncryptedTypes(nigori);
|
| + // The local set of keys is already merged with the server's set within
|
| + // the cryptographer. If we don't have pending keys we can store the
|
| + // merged set back immediately. Else we preserve the server keys and will
|
| + // update the nigori when the user provides the pending passphrase via
|
| + // SetPassphrase(..).
|
| + if (cryptographer->is_ready()) {
|
| + cryptographer->GetKeys(nigori->mutable_encrypted());
|
| + }
|
| + // TODO(zea): Find a better way of doing this. As it stands, we have to
|
| + // update this code whenever we add a new non-cryptographer related field
|
| + // to the nigori node.
|
| + if (entry.Get(syncable::SPECIFICS).GetExtension(sync_pb::nigori)
|
| + .sync_tabs()) {
|
| + nigori->set_sync_tabs(true);
|
| + }
|
| + entry.Put(syncable::SPECIFICS, specifics);
|
| + DVLOG(1) << "Resovling simple conflict, merging nigori nodes: " << entry;
|
| + status->increment_num_server_overwrites();
|
| + OverwriteServerChanges(trans, &entry);
|
| + UMA_HISTOGRAM_ENUMERATION("Sync.ResolveSimpleConflict",
|
| + NIGORI_MERGE,
|
| + CONFLICT_RESOLUTION_SIZE);
|
| + } else if (!entry_deleted && name_matches && parent_matches) {
|
| // TODO(zea): We may prefer to choose the local changes over the server
|
| // if we know the local changes happened before (or vice versa).
|
| // See http://crbug.com/76596
|
| @@ -193,10 +230,10 @@ ConflictResolver::ProcessSimpleConflict(WriteTransaction* trans,
|
| }
|
|
|
| bool ConflictResolver::ResolveSimpleConflicts(
|
| - const ScopedDirLookup& dir,
|
| + syncable::WriteTransaction* trans,
|
| + const Cryptographer* cryptographer,
|
| const ConflictProgress& progress,
|
| sessions::StatusController* status) {
|
| - WriteTransaction trans(FROM_HERE, syncable::SYNCER, dir);
|
| bool forward_progress = false;
|
| // First iterate over simple conflict items (those that belong to no set).
|
| set<Id>::const_iterator conflicting_item_it;
|
| @@ -209,7 +246,7 @@ bool ConflictResolver::ResolveSimpleConflicts(
|
| if (item_set_it == progress.IdToConflictSetEnd() ||
|
| 0 == item_set_it->second) {
|
| // We have a simple conflict.
|
| - switch (ProcessSimpleConflict(&trans, id, status)) {
|
| + switch (ProcessSimpleConflict(trans, id, cryptographer, status)) {
|
| case NO_SYNC_PROGRESS:
|
| break;
|
| case SYNC_PROGRESS:
|
| @@ -221,7 +258,8 @@ bool ConflictResolver::ResolveSimpleConflicts(
|
| return forward_progress;
|
| }
|
|
|
| -bool ConflictResolver::ResolveConflicts(const ScopedDirLookup& dir,
|
| +bool ConflictResolver::ResolveConflicts(syncable::WriteTransaction* trans,
|
| + const Cryptographer* cryptographer,
|
| const ConflictProgress& progress,
|
| sessions::StatusController* status) {
|
| // TODO(rlarocque): A good amount of code related to the resolution of
|
| @@ -238,7 +276,7 @@ bool ConflictResolver::ResolveConflicts(const ScopedDirLookup& dir,
|
| << " unprocessed conflict sets.";
|
| }
|
|
|
| - return ResolveSimpleConflicts(dir, progress, status);
|
| + return ResolveSimpleConflicts(trans, cryptographer, progress, status);
|
| }
|
|
|
| } // namespace browser_sync
|
|
|