Index: chrome/browser/sync/engine/syncer_util.cc |
diff --git a/chrome/browser/sync/engine/syncer_util.cc b/chrome/browser/sync/engine/syncer_util.cc |
index 20391686a6998a67428369181bd147711da5f52f..bf1456e662da5ebf12deedafce8c683dbf9486d9 100644 |
--- a/chrome/browser/sync/engine/syncer_util.cc |
+++ b/chrome/browser/sync/engine/syncer_util.cc |
@@ -10,6 +10,7 @@ |
#include <vector> |
#include "base/location.h" |
+#include "base/metrics/histogram.h" |
#include "chrome/browser/sync/engine/conflict_resolver.h" |
#include "chrome/browser/sync/engine/nigori_util.h" |
#include "chrome/browser/sync/engine/syncer_proto_util.h" |
@@ -23,6 +24,7 @@ |
#include "chrome/browser/sync/syncable/model_type.h" |
#include "chrome/browser/sync/syncable/syncable.h" |
#include "chrome/browser/sync/syncable/syncable_changes_version.h" |
+#include "chrome/browser/sync/util/cryptographer.h" |
#include "chrome/browser/sync/util/time.h" |
using syncable::BASE_VERSION; |
@@ -33,6 +35,7 @@ using syncable::CREATE_NEW_UPDATE_ITEM; |
using syncable::CTIME; |
using syncable::Directory; |
using syncable::Entry; |
+using syncable::GetModelTypeFromSpecifics; |
using syncable::GET_BY_HANDLE; |
using syncable::GET_BY_ID; |
using syncable::ID; |
@@ -41,11 +44,13 @@ using syncable::IS_DIR; |
using syncable::IS_UNAPPLIED_UPDATE; |
using syncable::IS_UNSYNCED; |
using syncable::Id; |
+using syncable::IsRealDataType; |
using syncable::META_HANDLE; |
using syncable::MTIME; |
using syncable::MutableEntry; |
using syncable::NEXT_ID; |
using syncable::NON_UNIQUE_NAME; |
+using syncable::BASE_SERVER_SPECIFICS; |
using syncable::PARENT_ID; |
using syncable::PREV_ID; |
using syncable::ReadTransaction; |
@@ -301,6 +306,33 @@ UpdateAttemptResponse SyncerUtil::AttemptToUpdateEntry( |
} |
} |
+ // Only apply updates that we can decrypt. If we can't decrypt the update, it |
+ // is likely because the passphrase has not arrived yet. Because the |
+ // passphrase may not arrive within this GetUpdates, we can't just return |
+ // conflict, else we try to perform normal conflict resolution prematurely or |
+ // the syncer may get stuck. As such, we return CONFLICT_ENCRYPTION, which is |
+ // treated as a non-blocking conflict. See the description in syncer_types.h. |
+ // This prevents any unsynced changes from commiting and postpones conflict |
+ // resolution until all data can be decrypted. |
+ if (specifics.has_encrypted() && |
+ !cryptographer->CanDecrypt(specifics.encrypted())) { |
+ // We can't decrypt this node yet. |
+ DVLOG(1) << "Received an undecryptable " |
+ << syncable::ModelTypeToString(entry->GetServerModelType()) |
+ << " update, returning encryption_conflict."; |
+ return CONFLICT_ENCRYPTION; |
+ } else if (specifics.HasExtension(sync_pb::password) && |
+ entry->Get(UNIQUE_SERVER_TAG).empty()) { |
+ // Passwords use their own legacy encryption scheme. |
+ const sync_pb::PasswordSpecifics& password = |
+ specifics.GetExtension(sync_pb::password); |
+ if (!cryptographer->CanDecrypt(password.encrypted())) { |
+ DVLOG(1) << "Received an undecryptable password update, returning " |
+ << "encryption_conflict."; |
+ return CONFLICT_ENCRYPTION; |
+ } |
+ } |
+ |
if (entry->Get(IS_UNSYNCED)) { |
DVLOG(1) << "Skipping update, returning conflict for: " << id |
<< " ; it's unsynced."; |
@@ -336,39 +368,14 @@ UpdateAttemptResponse SyncerUtil::AttemptToUpdateEntry( |
} |
} |
- // Only apply updates that we can decrypt. If we can't decrypt the update, it |
- // is likely because the passphrase has not arrived yet. Because the |
- // passphrase may not arrive within this GetUpdates, we can't just return |
- // conflict, else the syncer gets stuck. As such, we return |
- // CONFLICT_ENCRYPTION, which is treated as a non-blocking conflict. See the |
- // description in syncer_types.h. |
- if (specifics.has_encrypted() && |
- !cryptographer->CanDecrypt(specifics.encrypted())) { |
- // We can't decrypt this node yet. |
- DVLOG(1) << "Received an undecryptable " |
+ if (specifics.has_encrypted()) { |
+ DVLOG(2) << "Received a decryptable " |
<< syncable::ModelTypeToString(entry->GetServerModelType()) |
- << " update, returning encryption_conflict."; |
- return CONFLICT_ENCRYPTION; |
- } else if (specifics.HasExtension(sync_pb::password) && |
- entry->Get(UNIQUE_SERVER_TAG).empty()) { |
- // Passwords use their own legacy encryption scheme. |
- const sync_pb::PasswordSpecifics& password = |
- specifics.GetExtension(sync_pb::password); |
- if (!cryptographer->CanDecrypt(password.encrypted())) { |
- DVLOG(1) << "Received an undecryptable password update, returning " |
- << "encryption_conflict."; |
- return CONFLICT_ENCRYPTION; |
- } |
+ << " update, applying normally."; |
} else { |
- if (specifics.has_encrypted()) { |
- DVLOG(2) << "Received a decryptable " |
- << syncable::ModelTypeToString(entry->GetServerModelType()) |
- << " update, applying normally."; |
- } else { |
- DVLOG(2) << "Received an unencrypted " |
- << syncable::ModelTypeToString(entry->GetServerModelType()) |
- << " update, applying normally."; |
- } |
+ DVLOG(2) << "Received an unencrypted " |
+ << syncable::ModelTypeToString(entry->GetServerModelType()) |
+ << " update, applying normally."; |
} |
SyncerUtil::UpdateLocalDataFromServerData(trans, entry); |
@@ -475,7 +482,7 @@ void SyncerUtil::UpdateServerFieldsFromUpdate( |
// static |
void SyncerUtil::CreateNewEntry(syncable::WriteTransaction *trans, |
const syncable::Id& id) { |
- syncable::MutableEntry entry(trans, syncable::GET_BY_ID, id); |
+ syncable::MutableEntry entry(trans, GET_BY_ID, id); |
if (!entry.good()) { |
syncable::MutableEntry new_entry(trans, syncable::CREATE_NEW_UPDATE_ITEM, |
id); |
@@ -510,6 +517,8 @@ void SyncerUtil::UpdateLocalDataFromServerData( |
DVLOG(2) << "Updating entry : " << *entry; |
// Start by setting the properties that determine the model_type. |
entry->Put(SPECIFICS, entry->Get(SERVER_SPECIFICS)); |
+ // Clear the previous server specifics now that we're applying successfully. |
+ entry->Put(BASE_SERVER_SPECIFICS, sync_pb::EntitySpecifics()); |
entry->Put(IS_DIR, entry->Get(SERVER_IS_DIR)); |
// This strange dance around the IS_DEL flag avoids problems when setting |
// the name. |