1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "components/sync_driver/generic_change_processor.h"
7 #include "base/location.h"
8 #include "base/strings/string_number_conversions.h"
9 #include "base/strings/utf_string_conversions.h"
10 #include "components/sync_driver/sync_api_component_factory.h"
11 #include "sync/api/sync_change.h"
12 #include "sync/api/sync_error.h"
13 #include "sync/api/syncable_service.h"
14 #include "sync/internal_api/public/base_node.h"
15 #include "sync/internal_api/public/change_record.h"
16 #include "sync/internal_api/public/read_node.h"
17 #include "sync/internal_api/public/read_transaction.h"
18 #include "sync/internal_api/public/util/unrecoverable_error_handler.h"
19 #include "sync/internal_api/public/write_node.h"
20 #include "sync/internal_api/public/write_transaction.h"
21 #include "sync/syncable/entry.h" // TODO(tim): Bug 123674.
23 namespace sync_driver
{
27 const int kContextSizeLimit
= 1024; // Datatype context size limit.
29 void SetNodeSpecifics(const sync_pb::EntitySpecifics
& entity_specifics
,
30 syncer::WriteNode
* write_node
) {
31 if (syncer::GetModelTypeFromSpecifics(entity_specifics
) ==
33 write_node
->SetPasswordSpecifics(
34 entity_specifics
.password().client_only_encrypted_data());
36 write_node
->SetEntitySpecifics(entity_specifics
);
40 // Helper function to convert AttachmentId to AttachmentMetadataRecord.
41 sync_pb::AttachmentMetadataRecord
AttachmentIdToRecord(
42 const syncer::AttachmentId
& attachment_id
) {
43 sync_pb::AttachmentMetadataRecord record
;
44 *record
.mutable_id() = attachment_id
.GetProto();
48 // Replace |write_nodes|'s attachment ids with |attachment_ids|.
49 void SetAttachmentMetadata(const syncer::AttachmentIdList
& attachment_ids
,
50 syncer::WriteNode
* write_node
) {
52 sync_pb::AttachmentMetadata attachment_metadata
;
54 attachment_ids
.begin(),
56 RepeatedFieldBackInserter(attachment_metadata
.mutable_record()),
57 AttachmentIdToRecord
);
58 write_node
->SetAttachmentMetadata(attachment_metadata
);
61 syncer::SyncData
BuildRemoteSyncData(
63 const syncer::BaseNode
& read_node
,
64 const syncer::AttachmentServiceProxy
& attachment_service_proxy
) {
65 const syncer::AttachmentIdList
& attachment_ids
= read_node
.GetAttachmentIds();
66 // Use the specifics of non-password datatypes directly (encryption has
67 // already been handled).
68 if (read_node
.GetModelType() != syncer::PASSWORDS
) {
69 return syncer::SyncData::CreateRemoteData(sync_id
,
70 read_node
.GetEntitySpecifics(),
71 read_node
.GetModificationTime(),
73 attachment_service_proxy
);
76 // Passwords must be accessed differently, to account for their encryption,
77 // and stored into a temporary EntitySpecifics.
78 sync_pb::EntitySpecifics password_holder
;
79 password_holder
.mutable_password()->mutable_client_only_encrypted_data()->
80 CopyFrom(read_node
.GetPasswordSpecifics());
81 return syncer::SyncData::CreateRemoteData(sync_id
,
83 read_node
.GetModificationTime(),
85 attachment_service_proxy
);
90 GenericChangeProcessor::GenericChangeProcessor(
91 syncer::ModelType type
,
92 DataTypeErrorHandler
* error_handler
,
93 const base::WeakPtr
<syncer::SyncableService
>& local_service
,
94 const base::WeakPtr
<syncer::SyncMergeResult
>& merge_result
,
95 syncer::UserShare
* user_share
,
96 SyncApiComponentFactory
* sync_factory
,
97 const scoped_refptr
<syncer::AttachmentStore
>& attachment_store
)
98 : ChangeProcessor(error_handler
),
100 local_service_(local_service
),
101 merge_result_(merge_result
),
102 share_handle_(user_share
),
103 weak_ptr_factory_(this) {
104 DCHECK(CalledOnValidThread());
105 DCHECK_NE(type_
, syncer::UNSPECIFIED
);
106 if (attachment_store
.get()) {
107 std::string store_birthday
;
109 syncer::ReadTransaction
trans(FROM_HERE
, share_handle());
110 store_birthday
= trans
.GetStoreBirthday();
112 attachment_service_
= sync_factory
->CreateAttachmentService(
113 attachment_store
, *user_share
, store_birthday
, this);
114 attachment_service_weak_ptr_factory_
.reset(
115 new base::WeakPtrFactory
<syncer::AttachmentService
>(
116 attachment_service_
.get()));
117 attachment_service_proxy_
.reset(new syncer::AttachmentServiceProxy(
118 base::MessageLoopProxy::current(),
119 attachment_service_weak_ptr_factory_
->GetWeakPtr()));
120 UploadAllAttachmentsNotOnServer();
122 attachment_service_proxy_
.reset(new syncer::AttachmentServiceProxy(
123 base::MessageLoopProxy::current(),
124 base::WeakPtr
<syncer::AttachmentService
>()));
128 GenericChangeProcessor::~GenericChangeProcessor() {
129 DCHECK(CalledOnValidThread());
132 void GenericChangeProcessor::ApplyChangesFromSyncModel(
133 const syncer::BaseTransaction
* trans
,
135 const syncer::ImmutableChangeRecordList
& changes
) {
136 DCHECK(CalledOnValidThread());
137 DCHECK(syncer_changes_
.empty());
138 for (syncer::ChangeRecordList::const_iterator it
=
139 changes
.Get().begin(); it
!= changes
.Get().end(); ++it
) {
140 if (it
->action
== syncer::ChangeRecord::ACTION_DELETE
) {
141 scoped_ptr
<sync_pb::EntitySpecifics
> specifics
;
142 if (it
->specifics
.has_password()) {
143 DCHECK(it
->extra
.get());
144 specifics
.reset(new sync_pb::EntitySpecifics(it
->specifics
));
145 specifics
->mutable_password()->mutable_client_only_encrypted_data()->
146 CopyFrom(it
->extra
->unencrypted());
148 const syncer::AttachmentIdList empty_list_of_attachment_ids
;
149 syncer_changes_
.push_back(
150 syncer::SyncChange(FROM_HERE
,
151 syncer::SyncChange::ACTION_DELETE
,
152 syncer::SyncData::CreateRemoteData(
154 specifics
? *specifics
: it
->specifics
,
156 empty_list_of_attachment_ids
,
157 *attachment_service_proxy_
)));
159 syncer::SyncChange::SyncChangeType action
=
160 (it
->action
== syncer::ChangeRecord::ACTION_ADD
) ?
161 syncer::SyncChange::ACTION_ADD
: syncer::SyncChange::ACTION_UPDATE
;
162 // Need to load specifics from node.
163 syncer::ReadNode
read_node(trans
);
164 if (read_node
.InitByIdLookup(it
->id
) != syncer::BaseNode::INIT_OK
) {
165 syncer::SyncError
error(
167 syncer::SyncError::DATATYPE_ERROR
,
168 "Failed to look up data for received change with id " +
169 base::Int64ToString(it
->id
),
170 syncer::GetModelTypeFromSpecifics(it
->specifics
));
171 error_handler()->OnSingleDataTypeUnrecoverableError(error
);
174 syncer_changes_
.push_back(syncer::SyncChange(
177 BuildRemoteSyncData(it
->id
, read_node
, *attachment_service_proxy_
)));
182 void GenericChangeProcessor::CommitChangesFromSyncModel() {
183 DCHECK(CalledOnValidThread());
184 if (syncer_changes_
.empty())
186 if (!local_service_
.get()) {
187 syncer::ModelType type
= syncer_changes_
[0].sync_data().GetDataType();
188 syncer::SyncError
error(FROM_HERE
,
189 syncer::SyncError::DATATYPE_ERROR
,
190 "Local service destroyed.",
192 error_handler()->OnSingleDataTypeUnrecoverableError(error
);
195 syncer::SyncError error
= local_service_
->ProcessSyncChanges(FROM_HERE
,
197 syncer_changes_
.clear();
199 error_handler()->OnSingleDataTypeUnrecoverableError(error
);
202 syncer::SyncDataList
GenericChangeProcessor::GetAllSyncData(
203 syncer::ModelType type
) const {
204 DCHECK_EQ(type_
, type
);
205 // This is slow / memory intensive. Should be used sparingly by datatypes.
206 syncer::SyncDataList data
;
207 GetAllSyncDataReturnError(&data
);
211 syncer::SyncError
GenericChangeProcessor::UpdateDataTypeContext(
212 syncer::ModelType type
,
213 syncer::SyncChangeProcessor::ContextRefreshStatus refresh_status
,
214 const std::string
& context
) {
215 DCHECK(syncer::ProtocolTypes().Has(type
));
216 DCHECK_EQ(type_
, type
);
218 if (context
.size() > static_cast<size_t>(kContextSizeLimit
)) {
219 return syncer::SyncError(FROM_HERE
,
220 syncer::SyncError::DATATYPE_ERROR
,
221 "Context size limit exceeded.",
225 syncer::WriteTransaction
trans(FROM_HERE
, share_handle());
226 trans
.SetDataTypeContext(type
, refresh_status
, context
);
228 // TODO(zea): plumb a pointer to the PSS or SyncManagerImpl here so we can
229 // trigger a datatype nudge if |refresh_status == REFRESH_NEEDED|.
231 return syncer::SyncError();
234 void GenericChangeProcessor::OnAttachmentUploaded(
235 const syncer::AttachmentId
& attachment_id
) {
236 syncer::WriteTransaction
trans(FROM_HERE
, share_handle());
237 trans
.UpdateEntriesMarkAttachmentAsOnServer(attachment_id
);
240 syncer::SyncError
GenericChangeProcessor::GetAllSyncDataReturnError(
241 syncer::SyncDataList
* current_sync_data
) const {
242 DCHECK(CalledOnValidThread());
243 std::string type_name
= syncer::ModelTypeToString(type_
);
244 syncer::ReadTransaction
trans(FROM_HERE
, share_handle());
245 syncer::ReadNode
root(&trans
);
246 if (root
.InitTypeRoot(type_
) != syncer::BaseNode::INIT_OK
) {
247 syncer::SyncError
error(FROM_HERE
,
248 syncer::SyncError::DATATYPE_ERROR
,
249 "Server did not create the top-level " + type_name
+
250 " node. We might be running against an out-of-"
256 // TODO(akalin): We'll have to do a tree traversal for bookmarks.
257 DCHECK_NE(type_
, syncer::BOOKMARKS
);
259 std::vector
<int64
> child_ids
;
260 root
.GetChildIds(&child_ids
);
262 for (std::vector
<int64
>::iterator it
= child_ids
.begin();
263 it
!= child_ids
.end(); ++it
) {
264 syncer::ReadNode
sync_child_node(&trans
);
265 if (sync_child_node
.InitByIdLookup(*it
) !=
266 syncer::BaseNode::INIT_OK
) {
267 syncer::SyncError
error(
269 syncer::SyncError::DATATYPE_ERROR
,
270 "Failed to fetch child node for type " + type_name
+ ".",
274 current_sync_data
->push_back(BuildRemoteSyncData(
275 sync_child_node
.GetId(), sync_child_node
, *attachment_service_proxy_
));
277 return syncer::SyncError();
280 bool GenericChangeProcessor::GetDataTypeContext(std::string
* context
) const {
281 syncer::ReadTransaction
trans(FROM_HERE
, share_handle());
282 sync_pb::DataTypeContext context_proto
;
283 trans
.GetDataTypeContext(type_
, &context_proto
);
284 if (!context_proto
.has_context())
288 syncer::GetModelTypeFromSpecificsFieldNumber(
289 context_proto
.data_type_id()));
290 *context
= context_proto
.context();
294 int GenericChangeProcessor::GetSyncCount() {
295 syncer::ReadTransaction
trans(FROM_HERE
, share_handle());
296 syncer::ReadNode
root(&trans
);
297 if (root
.InitTypeRoot(type_
) != syncer::BaseNode::INIT_OK
)
300 // Subtract one to account for type's root node.
301 return root
.GetTotalNodeCount() - 1;
306 // WARNING: this code is sensitive to compiler optimizations. Be careful
307 // modifying any code around an OnSingleDataTypeUnrecoverableError call, else
308 // the compiler attempts to merge it with other calls, losing useful information
309 // in breakpad uploads.
310 syncer::SyncError
LogLookupFailure(
311 syncer::BaseNode::InitByLookupResult lookup_result
,
312 const tracked_objects::Location
& from_here
,
313 const std::string
& error_prefix
,
314 syncer::ModelType type
,
315 DataTypeErrorHandler
* error_handler
) {
316 switch (lookup_result
) {
317 case syncer::BaseNode::INIT_FAILED_ENTRY_NOT_GOOD
: {
318 syncer::SyncError error
;
319 error
.Reset(from_here
,
321 "could not find entry matching the lookup criteria.",
323 error_handler
->OnSingleDataTypeUnrecoverableError(error
);
324 LOG(ERROR
) << "Delete: Bad entry.";
327 case syncer::BaseNode::INIT_FAILED_ENTRY_IS_DEL
: {
328 syncer::SyncError error
;
329 error
.Reset(from_here
, error_prefix
+ "entry is already deleted.", type
);
330 error_handler
->OnSingleDataTypeUnrecoverableError(error
);
331 LOG(ERROR
) << "Delete: Deleted entry.";
334 case syncer::BaseNode::INIT_FAILED_DECRYPT_IF_NECESSARY
: {
335 syncer::SyncError error
;
336 error
.Reset(from_here
, error_prefix
+ "unable to decrypt", type
);
337 error_handler
->OnSingleDataTypeUnrecoverableError(error
);
338 LOG(ERROR
) << "Delete: Undecryptable entry.";
341 case syncer::BaseNode::INIT_FAILED_PRECONDITION
: {
342 syncer::SyncError error
;
343 error
.Reset(from_here
,
344 error_prefix
+ "a precondition was not met for calling init.",
346 error_handler
->OnSingleDataTypeUnrecoverableError(error
);
347 LOG(ERROR
) << "Delete: Failed precondition.";
351 syncer::SyncError error
;
352 // Should have listed all the possible error cases above.
353 error
.Reset(from_here
, error_prefix
+ "unknown error", type
);
354 error_handler
->OnSingleDataTypeUnrecoverableError(error
);
355 LOG(ERROR
) << "Delete: Unknown error.";
361 syncer::SyncError
AttemptDelete(const syncer::SyncChange
& change
,
362 syncer::ModelType type
,
363 const std::string
& type_str
,
364 syncer::WriteNode
* node
,
365 DataTypeErrorHandler
* error_handler
) {
366 DCHECK_EQ(change
.change_type(), syncer::SyncChange::ACTION_DELETE
);
367 if (change
.sync_data().IsLocal()) {
368 const std::string
& tag
= syncer::SyncDataLocal(change
.sync_data()).GetTag();
370 syncer::SyncError
error(
372 syncer::SyncError::DATATYPE_ERROR
,
373 "Failed to delete " + type_str
+ " node. Local data, empty tag. " +
374 change
.location().ToString(),
376 error_handler
->OnSingleDataTypeUnrecoverableError(error
);
381 syncer::BaseNode::InitByLookupResult result
=
382 node
->InitByClientTagLookup(change
.sync_data().GetDataType(), tag
);
383 if (result
!= syncer::BaseNode::INIT_OK
) {
384 return LogLookupFailure(
386 "Failed to delete " + type_str
+ " node. Local data. " +
387 change
.location().ToString(),
388 type
, error_handler
);
391 syncer::BaseNode::InitByLookupResult result
= node
->InitByIdLookup(
392 syncer::SyncDataRemote(change
.sync_data()).GetId());
393 if (result
!= syncer::BaseNode::INIT_OK
) {
394 return LogLookupFailure(
396 "Failed to delete " + type_str
+ " node. Non-local data. " +
397 change
.location().ToString(),
398 type
, error_handler
);
401 if (IsActOnceDataType(type
))
405 return syncer::SyncError();
410 syncer::SyncError
GenericChangeProcessor::ProcessSyncChanges(
411 const tracked_objects::Location
& from_here
,
412 const syncer::SyncChangeList
& list_of_changes
) {
413 DCHECK(CalledOnValidThread());
415 // Keep track of brand new attachments so we can persist them on this device
416 // and upload them to the server.
417 syncer::AttachmentIdSet new_attachments
;
419 syncer::WriteTransaction
trans(from_here
, share_handle());
421 for (syncer::SyncChangeList::const_iterator iter
= list_of_changes
.begin();
422 iter
!= list_of_changes
.end();
424 const syncer::SyncChange
& change
= *iter
;
425 DCHECK_EQ(change
.sync_data().GetDataType(), type_
);
426 std::string type_str
= syncer::ModelTypeToString(type_
);
427 syncer::WriteNode
sync_node(&trans
);
428 if (change
.change_type() == syncer::SyncChange::ACTION_DELETE
) {
429 syncer::SyncError error
=
430 AttemptDelete(change
, type_
, type_str
, &sync_node
, error_handler());
435 if (merge_result_
.get()) {
436 merge_result_
->set_num_items_deleted(
437 merge_result_
->num_items_deleted() + 1);
439 } else if (change
.change_type() == syncer::SyncChange::ACTION_ADD
) {
440 syncer::SyncError error
= HandleActionAdd(
441 change
, type_str
, trans
, &sync_node
, &new_attachments
);
445 } else if (change
.change_type() == syncer::SyncChange::ACTION_UPDATE
) {
446 syncer::SyncError error
= HandleActionUpdate(
447 change
, type_str
, trans
, &sync_node
, &new_attachments
);
452 syncer::SyncError
error(
454 syncer::SyncError::DATATYPE_ERROR
,
455 "Received unset SyncChange in the change processor, " +
456 change
.location().ToString(),
458 error_handler()->OnSingleDataTypeUnrecoverableError(error
);
460 LOG(ERROR
) << "Unset sync change.";
465 if (!new_attachments
.empty()) {
466 // If datatype uses attachments it should have supplied attachment store
467 // which would initialize attachment_service_. Fail if it isn't so.
468 if (!attachment_service_
.get()) {
469 syncer::SyncError
error(
471 syncer::SyncError::DATATYPE_ERROR
,
472 "Datatype performs attachment operation without initializing "
475 error_handler()->OnSingleDataTypeUnrecoverableError(error
);
479 attachment_service_
->UploadAttachments(new_attachments
);
482 return syncer::SyncError();
485 // WARNING: this code is sensitive to compiler optimizations. Be careful
486 // modifying any code around an OnSingleDataTypeUnrecoverableError call, else
487 // the compiler attempts to merge it with other calls, losing useful information
488 // in breakpad uploads.
489 syncer::SyncError
GenericChangeProcessor::HandleActionAdd(
490 const syncer::SyncChange
& change
,
491 const std::string
& type_str
,
492 const syncer::WriteTransaction
& trans
,
493 syncer::WriteNode
* sync_node
,
494 syncer::AttachmentIdSet
* new_attachments
) {
495 // TODO(sync): Handle other types of creation (custom parents, folders,
497 syncer::ReadNode
root_node(&trans
);
498 const syncer::SyncDataLocal
sync_data_local(change
.sync_data());
499 if (root_node
.InitTypeRoot(sync_data_local
.GetDataType()) !=
500 syncer::BaseNode::INIT_OK
) {
501 syncer::SyncError
error(FROM_HERE
,
502 syncer::SyncError::DATATYPE_ERROR
,
503 "Failed to look up root node for type " + type_str
,
505 error_handler()->OnSingleDataTypeUnrecoverableError(error
);
507 LOG(ERROR
) << "Create: no root node.";
510 syncer::WriteNode::InitUniqueByCreationResult result
=
511 sync_node
->InitUniqueByCreation(
512 sync_data_local
.GetDataType(), root_node
, sync_data_local
.GetTag());
513 if (result
!= syncer::WriteNode::INIT_SUCCESS
) {
514 std::string error_prefix
= "Failed to create " + type_str
+ " node: " +
515 change
.location().ToString() + ", ";
517 case syncer::WriteNode::INIT_FAILED_EMPTY_TAG
: {
518 syncer::SyncError error
;
519 error
.Reset(FROM_HERE
, error_prefix
+ "empty tag", type_
);
520 error_handler()->OnSingleDataTypeUnrecoverableError(error
);
521 LOG(ERROR
) << "Create: Empty tag.";
524 case syncer::WriteNode::INIT_FAILED_ENTRY_ALREADY_EXISTS
: {
525 syncer::SyncError error
;
526 error
.Reset(FROM_HERE
, error_prefix
+ "entry already exists", type_
);
527 error_handler()->OnSingleDataTypeUnrecoverableError(error
);
528 LOG(ERROR
) << "Create: Entry exists.";
531 case syncer::WriteNode::INIT_FAILED_COULD_NOT_CREATE_ENTRY
: {
532 syncer::SyncError error
;
533 error
.Reset(FROM_HERE
, error_prefix
+ "failed to create entry", type_
);
534 error_handler()->OnSingleDataTypeUnrecoverableError(error
);
535 LOG(ERROR
) << "Create: Could not create entry.";
538 case syncer::WriteNode::INIT_FAILED_SET_PREDECESSOR
: {
539 syncer::SyncError error
;
541 FROM_HERE
, error_prefix
+ "failed to set predecessor", type_
);
542 error_handler()->OnSingleDataTypeUnrecoverableError(error
);
543 LOG(ERROR
) << "Create: Bad predecessor.";
547 syncer::SyncError error
;
548 error
.Reset(FROM_HERE
, error_prefix
+ "unknown error", type_
);
549 error_handler()->OnSingleDataTypeUnrecoverableError(error
);
550 LOG(ERROR
) << "Create: Unknown error.";
555 sync_node
->SetTitle(change
.sync_data().GetTitle());
556 SetNodeSpecifics(sync_data_local
.GetSpecifics(), sync_node
);
558 syncer::AttachmentIdList attachment_ids
= sync_data_local
.GetAttachmentIds();
559 SetAttachmentMetadata(attachment_ids
, sync_node
);
561 // Return any newly added attachments.
562 new_attachments
->insert(attachment_ids
.begin(), attachment_ids
.end());
563 if (merge_result_
.get()) {
564 merge_result_
->set_num_items_added(merge_result_
->num_items_added() + 1);
566 return syncer::SyncError();
568 // WARNING: this code is sensitive to compiler optimizations. Be careful
569 // modifying any code around an OnSingleDataTypeUnrecoverableError call, else
570 // the compiler attempts to merge it with other calls, losing useful information
571 // in breakpad uploads.
572 syncer::SyncError
GenericChangeProcessor::HandleActionUpdate(
573 const syncer::SyncChange
& change
,
574 const std::string
& type_str
,
575 const syncer::WriteTransaction
& trans
,
576 syncer::WriteNode
* sync_node
,
577 syncer::AttachmentIdSet
* new_attachments
) {
578 // TODO(zea): consider having this logic for all possible changes?
580 const syncer::SyncDataLocal
sync_data_local(change
.sync_data());
581 syncer::BaseNode::InitByLookupResult result
=
582 sync_node
->InitByClientTagLookup(sync_data_local
.GetDataType(),
583 sync_data_local
.GetTag());
584 if (result
!= syncer::BaseNode::INIT_OK
) {
585 std::string error_prefix
= "Failed to load " + type_str
+ " node. " +
586 change
.location().ToString() + ", ";
587 if (result
== syncer::BaseNode::INIT_FAILED_PRECONDITION
) {
588 syncer::SyncError error
;
589 error
.Reset(FROM_HERE
, error_prefix
+ "empty tag", type_
);
590 error_handler()->OnSingleDataTypeUnrecoverableError(error
);
591 LOG(ERROR
) << "Update: Empty tag.";
593 } else if (result
== syncer::BaseNode::INIT_FAILED_ENTRY_NOT_GOOD
) {
594 syncer::SyncError error
;
595 error
.Reset(FROM_HERE
, error_prefix
+ "bad entry", type_
);
596 error_handler()->OnSingleDataTypeUnrecoverableError(error
);
597 LOG(ERROR
) << "Update: bad entry.";
599 } else if (result
== syncer::BaseNode::INIT_FAILED_ENTRY_IS_DEL
) {
600 syncer::SyncError error
;
601 error
.Reset(FROM_HERE
, error_prefix
+ "deleted entry", type_
);
602 error_handler()->OnSingleDataTypeUnrecoverableError(error
);
603 LOG(ERROR
) << "Update: deleted entry.";
606 syncer::Cryptographer
* crypto
= trans
.GetCryptographer();
607 syncer::ModelTypeSet
encrypted_types(trans
.GetEncryptedTypes());
608 const sync_pb::EntitySpecifics
& specifics
=
609 sync_node
->GetEntry()->GetSpecifics();
610 CHECK(specifics
.has_encrypted());
611 const bool can_decrypt
= crypto
->CanDecrypt(specifics
.encrypted());
612 const bool agreement
= encrypted_types
.Has(type_
);
613 if (!agreement
&& !can_decrypt
) {
614 syncer::SyncError error
;
615 error
.Reset(FROM_HERE
,
616 "Failed to load encrypted entry, missing key and "
617 "nigori mismatch for " +
620 error_handler()->OnSingleDataTypeUnrecoverableError(error
);
621 LOG(ERROR
) << "Update: encr case 1.";
623 } else if (agreement
&& can_decrypt
) {
624 syncer::SyncError error
;
625 error
.Reset(FROM_HERE
,
626 "Failed to load encrypted entry, we have the key "
627 "and the nigori matches (?!) for " +
630 error_handler()->OnSingleDataTypeUnrecoverableError(error
);
631 LOG(ERROR
) << "Update: encr case 2.";
633 } else if (agreement
) {
634 syncer::SyncError error
;
635 error
.Reset(FROM_HERE
,
636 "Failed to load encrypted entry, missing key and "
637 "the nigori matches for " +
640 error_handler()->OnSingleDataTypeUnrecoverableError(error
);
641 LOG(ERROR
) << "Update: encr case 3.";
644 syncer::SyncError error
;
645 error
.Reset(FROM_HERE
,
646 "Failed to load encrypted entry, we have the key"
647 "(?!) and nigori mismatch for " +
650 error_handler()->OnSingleDataTypeUnrecoverableError(error
);
651 LOG(ERROR
) << "Update: encr case 4.";
657 sync_node
->SetTitle(change
.sync_data().GetTitle());
658 SetNodeSpecifics(sync_data_local
.GetSpecifics(), sync_node
);
659 syncer::AttachmentIdList attachment_ids
= sync_data_local
.GetAttachmentIds();
660 SetAttachmentMetadata(attachment_ids
, sync_node
);
662 // Return any newly added attachments.
663 new_attachments
->insert(attachment_ids
.begin(), attachment_ids
.end());
665 if (merge_result_
.get()) {
666 merge_result_
->set_num_items_modified(merge_result_
->num_items_modified() +
669 // TODO(sync): Support updating other parts of the sync node (title,
670 // successor, parent, etc.).
671 return syncer::SyncError();
674 bool GenericChangeProcessor::SyncModelHasUserCreatedNodes(bool* has_nodes
) {
675 DCHECK(CalledOnValidThread());
677 std::string type_name
= syncer::ModelTypeToString(type_
);
678 std::string err_str
= "Server did not create the top-level " + type_name
+
679 " node. We might be running against an out-of-date server.";
681 syncer::ReadTransaction
trans(FROM_HERE
, share_handle());
682 syncer::ReadNode
type_root_node(&trans
);
683 if (type_root_node
.InitTypeRoot(type_
) != syncer::BaseNode::INIT_OK
) {
684 LOG(ERROR
) << err_str
;
688 // The sync model has user created nodes if the type's root node has any
690 *has_nodes
= type_root_node
.HasChildren();
694 bool GenericChangeProcessor::CryptoReadyIfNecessary() {
695 DCHECK(CalledOnValidThread());
696 // We only access the cryptographer while holding a transaction.
697 syncer::ReadTransaction
trans(FROM_HERE
, share_handle());
698 const syncer::ModelTypeSet encrypted_types
= trans
.GetEncryptedTypes();
699 return !encrypted_types
.Has(type_
) || trans
.GetCryptographer()->is_ready();
702 void GenericChangeProcessor::StartImpl() {
705 syncer::UserShare
* GenericChangeProcessor::share_handle() const {
706 DCHECK(CalledOnValidThread());
707 return share_handle_
;
710 void GenericChangeProcessor::UploadAllAttachmentsNotOnServer() {
711 DCHECK(CalledOnValidThread());
712 DCHECK(attachment_service_
.get());
713 syncer::AttachmentIdSet id_set
;
715 syncer::ReadTransaction
trans(FROM_HERE
, share_handle());
716 trans
.GetAttachmentIdsToUpload(type_
, &id_set
);
718 if (!id_set
.empty()) {
719 attachment_service_
->UploadAttachments(id_set
);
723 } // namespace sync_driver