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 attachment_service_
= sync_factory
->CreateAttachmentService(
108 attachment_store
, *user_share
, this);
109 attachment_service_weak_ptr_factory_
.reset(
110 new base::WeakPtrFactory
<syncer::AttachmentService
>(
111 attachment_service_
.get()));
112 attachment_service_proxy_
.reset(new syncer::AttachmentServiceProxy(
113 base::MessageLoopProxy::current(),
114 attachment_service_weak_ptr_factory_
->GetWeakPtr()));
115 UploadAllAttachmentsNotOnServer();
117 attachment_service_proxy_
.reset(new syncer::AttachmentServiceProxy(
118 base::MessageLoopProxy::current(),
119 base::WeakPtr
<syncer::AttachmentService
>()));
123 GenericChangeProcessor::~GenericChangeProcessor() {
124 DCHECK(CalledOnValidThread());
127 void GenericChangeProcessor::ApplyChangesFromSyncModel(
128 const syncer::BaseTransaction
* trans
,
130 const syncer::ImmutableChangeRecordList
& changes
) {
131 DCHECK(CalledOnValidThread());
132 DCHECK(syncer_changes_
.empty());
133 for (syncer::ChangeRecordList::const_iterator it
=
134 changes
.Get().begin(); it
!= changes
.Get().end(); ++it
) {
135 if (it
->action
== syncer::ChangeRecord::ACTION_DELETE
) {
136 scoped_ptr
<sync_pb::EntitySpecifics
> specifics
;
137 if (it
->specifics
.has_password()) {
138 DCHECK(it
->extra
.get());
139 specifics
.reset(new sync_pb::EntitySpecifics(it
->specifics
));
140 specifics
->mutable_password()->mutable_client_only_encrypted_data()->
141 CopyFrom(it
->extra
->unencrypted());
143 const syncer::AttachmentIdList empty_list_of_attachment_ids
;
144 syncer_changes_
.push_back(
145 syncer::SyncChange(FROM_HERE
,
146 syncer::SyncChange::ACTION_DELETE
,
147 syncer::SyncData::CreateRemoteData(
149 specifics
? *specifics
: it
->specifics
,
151 empty_list_of_attachment_ids
,
152 *attachment_service_proxy_
)));
154 syncer::SyncChange::SyncChangeType action
=
155 (it
->action
== syncer::ChangeRecord::ACTION_ADD
) ?
156 syncer::SyncChange::ACTION_ADD
: syncer::SyncChange::ACTION_UPDATE
;
157 // Need to load specifics from node.
158 syncer::ReadNode
read_node(trans
);
159 if (read_node
.InitByIdLookup(it
->id
) != syncer::BaseNode::INIT_OK
) {
160 syncer::SyncError
error(
162 syncer::SyncError::DATATYPE_ERROR
,
163 "Failed to look up data for received change with id " +
164 base::Int64ToString(it
->id
),
165 syncer::GetModelTypeFromSpecifics(it
->specifics
));
166 error_handler()->OnSingleDataTypeUnrecoverableError(error
);
169 syncer_changes_
.push_back(syncer::SyncChange(
172 BuildRemoteSyncData(it
->id
, read_node
, *attachment_service_proxy_
)));
177 void GenericChangeProcessor::CommitChangesFromSyncModel() {
178 DCHECK(CalledOnValidThread());
179 if (syncer_changes_
.empty())
181 if (!local_service_
.get()) {
182 syncer::ModelType type
= syncer_changes_
[0].sync_data().GetDataType();
183 syncer::SyncError
error(FROM_HERE
,
184 syncer::SyncError::DATATYPE_ERROR
,
185 "Local service destroyed.",
187 error_handler()->OnSingleDataTypeUnrecoverableError(error
);
190 syncer::SyncError error
= local_service_
->ProcessSyncChanges(FROM_HERE
,
192 syncer_changes_
.clear();
194 error_handler()->OnSingleDataTypeUnrecoverableError(error
);
197 syncer::SyncDataList
GenericChangeProcessor::GetAllSyncData(
198 syncer::ModelType type
) const {
199 DCHECK_EQ(type_
, type
);
200 // This is slow / memory intensive. Should be used sparingly by datatypes.
201 syncer::SyncDataList data
;
202 GetAllSyncDataReturnError(&data
);
206 syncer::SyncError
GenericChangeProcessor::UpdateDataTypeContext(
207 syncer::ModelType type
,
208 syncer::SyncChangeProcessor::ContextRefreshStatus refresh_status
,
209 const std::string
& context
) {
210 DCHECK(syncer::ProtocolTypes().Has(type
));
211 DCHECK_EQ(type_
, type
);
213 if (context
.size() > static_cast<size_t>(kContextSizeLimit
)) {
214 return syncer::SyncError(FROM_HERE
,
215 syncer::SyncError::DATATYPE_ERROR
,
216 "Context size limit exceeded.",
220 syncer::WriteTransaction
trans(FROM_HERE
, share_handle());
221 trans
.SetDataTypeContext(type
, refresh_status
, context
);
223 // TODO(zea): plumb a pointer to the PSS or SyncManagerImpl here so we can
224 // trigger a datatype nudge if |refresh_status == REFRESH_NEEDED|.
226 return syncer::SyncError();
229 void GenericChangeProcessor::OnAttachmentUploaded(
230 const syncer::AttachmentId
& attachment_id
) {
231 syncer::WriteTransaction
trans(FROM_HERE
, share_handle());
232 trans
.UpdateEntriesMarkAttachmentAsOnServer(attachment_id
);
235 syncer::SyncError
GenericChangeProcessor::GetAllSyncDataReturnError(
236 syncer::SyncDataList
* current_sync_data
) const {
237 DCHECK(CalledOnValidThread());
238 std::string type_name
= syncer::ModelTypeToString(type_
);
239 syncer::ReadTransaction
trans(FROM_HERE
, share_handle());
240 syncer::ReadNode
root(&trans
);
241 if (root
.InitTypeRoot(type_
) != syncer::BaseNode::INIT_OK
) {
242 syncer::SyncError
error(FROM_HERE
,
243 syncer::SyncError::DATATYPE_ERROR
,
244 "Server did not create the top-level " + type_name
+
245 " node. We might be running against an out-of-"
251 // TODO(akalin): We'll have to do a tree traversal for bookmarks.
252 DCHECK_NE(type_
, syncer::BOOKMARKS
);
254 std::vector
<int64
> child_ids
;
255 root
.GetChildIds(&child_ids
);
257 for (std::vector
<int64
>::iterator it
= child_ids
.begin();
258 it
!= child_ids
.end(); ++it
) {
259 syncer::ReadNode
sync_child_node(&trans
);
260 if (sync_child_node
.InitByIdLookup(*it
) !=
261 syncer::BaseNode::INIT_OK
) {
262 syncer::SyncError
error(
264 syncer::SyncError::DATATYPE_ERROR
,
265 "Failed to fetch child node for type " + type_name
+ ".",
269 current_sync_data
->push_back(BuildRemoteSyncData(
270 sync_child_node
.GetId(), sync_child_node
, *attachment_service_proxy_
));
272 return syncer::SyncError();
275 bool GenericChangeProcessor::GetDataTypeContext(std::string
* context
) const {
276 syncer::ReadTransaction
trans(FROM_HERE
, share_handle());
277 sync_pb::DataTypeContext context_proto
;
278 trans
.GetDataTypeContext(type_
, &context_proto
);
279 if (!context_proto
.has_context())
283 syncer::GetModelTypeFromSpecificsFieldNumber(
284 context_proto
.data_type_id()));
285 *context
= context_proto
.context();
289 int GenericChangeProcessor::GetSyncCount() {
290 syncer::ReadTransaction
trans(FROM_HERE
, share_handle());
291 syncer::ReadNode
root(&trans
);
292 if (root
.InitTypeRoot(type_
) != syncer::BaseNode::INIT_OK
)
295 // Subtract one to account for type's root node.
296 return root
.GetTotalNodeCount() - 1;
301 // WARNING: this code is sensitive to compiler optimizations. Be careful
302 // modifying any code around an OnSingleDataTypeUnrecoverableError call, else
303 // the compiler attempts to merge it with other calls, losing useful information
304 // in breakpad uploads.
305 syncer::SyncError
LogLookupFailure(
306 syncer::BaseNode::InitByLookupResult lookup_result
,
307 const tracked_objects::Location
& from_here
,
308 const std::string
& error_prefix
,
309 syncer::ModelType type
,
310 DataTypeErrorHandler
* error_handler
) {
311 switch (lookup_result
) {
312 case syncer::BaseNode::INIT_FAILED_ENTRY_NOT_GOOD
: {
313 syncer::SyncError error
;
314 error
.Reset(from_here
,
316 "could not find entry matching the lookup criteria.",
318 error_handler
->OnSingleDataTypeUnrecoverableError(error
);
319 LOG(ERROR
) << "Delete: Bad entry.";
322 case syncer::BaseNode::INIT_FAILED_ENTRY_IS_DEL
: {
323 syncer::SyncError error
;
324 error
.Reset(from_here
, error_prefix
+ "entry is already deleted.", type
);
325 error_handler
->OnSingleDataTypeUnrecoverableError(error
);
326 LOG(ERROR
) << "Delete: Deleted entry.";
329 case syncer::BaseNode::INIT_FAILED_DECRYPT_IF_NECESSARY
: {
330 syncer::SyncError error
;
331 error
.Reset(from_here
, error_prefix
+ "unable to decrypt", type
);
332 error_handler
->OnSingleDataTypeUnrecoverableError(error
);
333 LOG(ERROR
) << "Delete: Undecryptable entry.";
336 case syncer::BaseNode::INIT_FAILED_PRECONDITION
: {
337 syncer::SyncError error
;
338 error
.Reset(from_here
,
339 error_prefix
+ "a precondition was not met for calling init.",
341 error_handler
->OnSingleDataTypeUnrecoverableError(error
);
342 LOG(ERROR
) << "Delete: Failed precondition.";
346 syncer::SyncError error
;
347 // Should have listed all the possible error cases above.
348 error
.Reset(from_here
, error_prefix
+ "unknown error", type
);
349 error_handler
->OnSingleDataTypeUnrecoverableError(error
);
350 LOG(ERROR
) << "Delete: Unknown error.";
356 syncer::SyncError
AttemptDelete(const syncer::SyncChange
& change
,
357 syncer::ModelType type
,
358 const std::string
& type_str
,
359 syncer::WriteNode
* node
,
360 DataTypeErrorHandler
* error_handler
) {
361 DCHECK_EQ(change
.change_type(), syncer::SyncChange::ACTION_DELETE
);
362 if (change
.sync_data().IsLocal()) {
363 const std::string
& tag
= syncer::SyncDataLocal(change
.sync_data()).GetTag();
365 syncer::SyncError
error(
367 syncer::SyncError::DATATYPE_ERROR
,
368 "Failed to delete " + type_str
+ " node. Local data, empty tag. " +
369 change
.location().ToString(),
371 error_handler
->OnSingleDataTypeUnrecoverableError(error
);
376 syncer::BaseNode::InitByLookupResult result
=
377 node
->InitByClientTagLookup(change
.sync_data().GetDataType(), tag
);
378 if (result
!= syncer::BaseNode::INIT_OK
) {
379 return LogLookupFailure(
381 "Failed to delete " + type_str
+ " node. Local data. " +
382 change
.location().ToString(),
383 type
, error_handler
);
386 syncer::BaseNode::InitByLookupResult result
= node
->InitByIdLookup(
387 syncer::SyncDataRemote(change
.sync_data()).GetId());
388 if (result
!= syncer::BaseNode::INIT_OK
) {
389 return LogLookupFailure(
391 "Failed to delete " + type_str
+ " node. Non-local data. " +
392 change
.location().ToString(),
393 type
, error_handler
);
396 if (IsActOnceDataType(type
))
400 return syncer::SyncError();
405 syncer::SyncError
GenericChangeProcessor::ProcessSyncChanges(
406 const tracked_objects::Location
& from_here
,
407 const syncer::SyncChangeList
& list_of_changes
) {
408 DCHECK(CalledOnValidThread());
410 // Keep track of brand new attachments so we can persist them on this device
411 // and upload them to the server.
412 syncer::AttachmentIdSet new_attachments
;
414 syncer::WriteTransaction
trans(from_here
, share_handle());
416 for (syncer::SyncChangeList::const_iterator iter
= list_of_changes
.begin();
417 iter
!= list_of_changes
.end();
419 const syncer::SyncChange
& change
= *iter
;
420 DCHECK_EQ(change
.sync_data().GetDataType(), type_
);
421 std::string type_str
= syncer::ModelTypeToString(type_
);
422 syncer::WriteNode
sync_node(&trans
);
423 if (change
.change_type() == syncer::SyncChange::ACTION_DELETE
) {
424 syncer::SyncError error
=
425 AttemptDelete(change
, type_
, type_str
, &sync_node
, error_handler());
430 if (merge_result_
.get()) {
431 merge_result_
->set_num_items_deleted(
432 merge_result_
->num_items_deleted() + 1);
434 } else if (change
.change_type() == syncer::SyncChange::ACTION_ADD
) {
435 syncer::SyncError error
= HandleActionAdd(
436 change
, type_str
, trans
, &sync_node
, &new_attachments
);
440 } else if (change
.change_type() == syncer::SyncChange::ACTION_UPDATE
) {
441 syncer::SyncError error
= HandleActionUpdate(
442 change
, type_str
, trans
, &sync_node
, &new_attachments
);
447 syncer::SyncError
error(
449 syncer::SyncError::DATATYPE_ERROR
,
450 "Received unset SyncChange in the change processor, " +
451 change
.location().ToString(),
453 error_handler()->OnSingleDataTypeUnrecoverableError(error
);
455 LOG(ERROR
) << "Unset sync change.";
460 if (!new_attachments
.empty()) {
461 // If datatype uses attachments it should have supplied attachment store
462 // which would initialize attachment_service_. Fail if it isn't so.
463 if (!attachment_service_
.get()) {
464 syncer::SyncError
error(
466 syncer::SyncError::DATATYPE_ERROR
,
467 "Datatype performs attachment operation without initializing "
470 error_handler()->OnSingleDataTypeUnrecoverableError(error
);
474 attachment_service_
->UploadAttachments(new_attachments
);
477 return syncer::SyncError();
480 // WARNING: this code is sensitive to compiler optimizations. Be careful
481 // modifying any code around an OnSingleDataTypeUnrecoverableError call, else
482 // the compiler attempts to merge it with other calls, losing useful information
483 // in breakpad uploads.
484 syncer::SyncError
GenericChangeProcessor::HandleActionAdd(
485 const syncer::SyncChange
& change
,
486 const std::string
& type_str
,
487 const syncer::WriteTransaction
& trans
,
488 syncer::WriteNode
* sync_node
,
489 syncer::AttachmentIdSet
* new_attachments
) {
490 // TODO(sync): Handle other types of creation (custom parents, folders,
492 syncer::ReadNode
root_node(&trans
);
493 const syncer::SyncDataLocal
sync_data_local(change
.sync_data());
494 if (root_node
.InitTypeRoot(sync_data_local
.GetDataType()) !=
495 syncer::BaseNode::INIT_OK
) {
496 syncer::SyncError
error(FROM_HERE
,
497 syncer::SyncError::DATATYPE_ERROR
,
498 "Failed to look up root node for type " + type_str
,
500 error_handler()->OnSingleDataTypeUnrecoverableError(error
);
502 LOG(ERROR
) << "Create: no root node.";
505 syncer::WriteNode::InitUniqueByCreationResult result
=
506 sync_node
->InitUniqueByCreation(
507 sync_data_local
.GetDataType(), root_node
, sync_data_local
.GetTag());
508 if (result
!= syncer::WriteNode::INIT_SUCCESS
) {
509 std::string error_prefix
= "Failed to create " + type_str
+ " node: " +
510 change
.location().ToString() + ", ";
512 case syncer::WriteNode::INIT_FAILED_EMPTY_TAG
: {
513 syncer::SyncError error
;
514 error
.Reset(FROM_HERE
, error_prefix
+ "empty tag", type_
);
515 error_handler()->OnSingleDataTypeUnrecoverableError(error
);
516 LOG(ERROR
) << "Create: Empty tag.";
519 case syncer::WriteNode::INIT_FAILED_ENTRY_ALREADY_EXISTS
: {
520 syncer::SyncError error
;
521 error
.Reset(FROM_HERE
, error_prefix
+ "entry already exists", type_
);
522 error_handler()->OnSingleDataTypeUnrecoverableError(error
);
523 LOG(ERROR
) << "Create: Entry exists.";
526 case syncer::WriteNode::INIT_FAILED_COULD_NOT_CREATE_ENTRY
: {
527 syncer::SyncError error
;
528 error
.Reset(FROM_HERE
, error_prefix
+ "failed to create entry", type_
);
529 error_handler()->OnSingleDataTypeUnrecoverableError(error
);
530 LOG(ERROR
) << "Create: Could not create entry.";
533 case syncer::WriteNode::INIT_FAILED_SET_PREDECESSOR
: {
534 syncer::SyncError error
;
536 FROM_HERE
, error_prefix
+ "failed to set predecessor", type_
);
537 error_handler()->OnSingleDataTypeUnrecoverableError(error
);
538 LOG(ERROR
) << "Create: Bad predecessor.";
542 syncer::SyncError error
;
543 error
.Reset(FROM_HERE
, error_prefix
+ "unknown error", type_
);
544 error_handler()->OnSingleDataTypeUnrecoverableError(error
);
545 LOG(ERROR
) << "Create: Unknown error.";
550 sync_node
->SetTitle(change
.sync_data().GetTitle());
551 SetNodeSpecifics(sync_data_local
.GetSpecifics(), sync_node
);
553 syncer::AttachmentIdList attachment_ids
= sync_data_local
.GetAttachmentIds();
554 SetAttachmentMetadata(attachment_ids
, sync_node
);
556 // Return any newly added attachments.
557 new_attachments
->insert(attachment_ids
.begin(), attachment_ids
.end());
558 if (merge_result_
.get()) {
559 merge_result_
->set_num_items_added(merge_result_
->num_items_added() + 1);
561 return syncer::SyncError();
563 // WARNING: this code is sensitive to compiler optimizations. Be careful
564 // modifying any code around an OnSingleDataTypeUnrecoverableError call, else
565 // the compiler attempts to merge it with other calls, losing useful information
566 // in breakpad uploads.
567 syncer::SyncError
GenericChangeProcessor::HandleActionUpdate(
568 const syncer::SyncChange
& change
,
569 const std::string
& type_str
,
570 const syncer::WriteTransaction
& trans
,
571 syncer::WriteNode
* sync_node
,
572 syncer::AttachmentIdSet
* new_attachments
) {
573 // TODO(zea): consider having this logic for all possible changes?
575 const syncer::SyncDataLocal
sync_data_local(change
.sync_data());
576 syncer::BaseNode::InitByLookupResult result
=
577 sync_node
->InitByClientTagLookup(sync_data_local
.GetDataType(),
578 sync_data_local
.GetTag());
579 if (result
!= syncer::BaseNode::INIT_OK
) {
580 std::string error_prefix
= "Failed to load " + type_str
+ " node. " +
581 change
.location().ToString() + ", ";
582 if (result
== syncer::BaseNode::INIT_FAILED_PRECONDITION
) {
583 syncer::SyncError error
;
584 error
.Reset(FROM_HERE
, error_prefix
+ "empty tag", type_
);
585 error_handler()->OnSingleDataTypeUnrecoverableError(error
);
586 LOG(ERROR
) << "Update: Empty tag.";
588 } else if (result
== syncer::BaseNode::INIT_FAILED_ENTRY_NOT_GOOD
) {
589 syncer::SyncError error
;
590 error
.Reset(FROM_HERE
, error_prefix
+ "bad entry", type_
);
591 error_handler()->OnSingleDataTypeUnrecoverableError(error
);
592 LOG(ERROR
) << "Update: bad entry.";
594 } else if (result
== syncer::BaseNode::INIT_FAILED_ENTRY_IS_DEL
) {
595 syncer::SyncError error
;
596 error
.Reset(FROM_HERE
, error_prefix
+ "deleted entry", type_
);
597 error_handler()->OnSingleDataTypeUnrecoverableError(error
);
598 LOG(ERROR
) << "Update: deleted entry.";
601 syncer::Cryptographer
* crypto
= trans
.GetCryptographer();
602 syncer::ModelTypeSet
encrypted_types(trans
.GetEncryptedTypes());
603 const sync_pb::EntitySpecifics
& specifics
=
604 sync_node
->GetEntry()->GetSpecifics();
605 CHECK(specifics
.has_encrypted());
606 const bool can_decrypt
= crypto
->CanDecrypt(specifics
.encrypted());
607 const bool agreement
= encrypted_types
.Has(type_
);
608 if (!agreement
&& !can_decrypt
) {
609 syncer::SyncError error
;
610 error
.Reset(FROM_HERE
,
611 "Failed to load encrypted entry, missing key and "
612 "nigori mismatch for " +
615 error_handler()->OnSingleDataTypeUnrecoverableError(error
);
616 LOG(ERROR
) << "Update: encr case 1.";
618 } else if (agreement
&& can_decrypt
) {
619 syncer::SyncError error
;
620 error
.Reset(FROM_HERE
,
621 "Failed to load encrypted entry, we have the key "
622 "and the nigori matches (?!) for " +
625 error_handler()->OnSingleDataTypeUnrecoverableError(error
);
626 LOG(ERROR
) << "Update: encr case 2.";
628 } else if (agreement
) {
629 syncer::SyncError error
;
630 error
.Reset(FROM_HERE
,
631 "Failed to load encrypted entry, missing key and "
632 "the nigori matches for " +
635 error_handler()->OnSingleDataTypeUnrecoverableError(error
);
636 LOG(ERROR
) << "Update: encr case 3.";
639 syncer::SyncError error
;
640 error
.Reset(FROM_HERE
,
641 "Failed to load encrypted entry, we have the key"
642 "(?!) and nigori mismatch for " +
645 error_handler()->OnSingleDataTypeUnrecoverableError(error
);
646 LOG(ERROR
) << "Update: encr case 4.";
652 sync_node
->SetTitle(change
.sync_data().GetTitle());
653 SetNodeSpecifics(sync_data_local
.GetSpecifics(), sync_node
);
654 syncer::AttachmentIdList attachment_ids
= sync_data_local
.GetAttachmentIds();
655 SetAttachmentMetadata(attachment_ids
, sync_node
);
657 // Return any newly added attachments.
658 new_attachments
->insert(attachment_ids
.begin(), attachment_ids
.end());
660 if (merge_result_
.get()) {
661 merge_result_
->set_num_items_modified(merge_result_
->num_items_modified() +
664 // TODO(sync): Support updating other parts of the sync node (title,
665 // successor, parent, etc.).
666 return syncer::SyncError();
669 bool GenericChangeProcessor::SyncModelHasUserCreatedNodes(bool* has_nodes
) {
670 DCHECK(CalledOnValidThread());
672 std::string type_name
= syncer::ModelTypeToString(type_
);
673 std::string err_str
= "Server did not create the top-level " + type_name
+
674 " node. We might be running against an out-of-date server.";
676 syncer::ReadTransaction
trans(FROM_HERE
, share_handle());
677 syncer::ReadNode
type_root_node(&trans
);
678 if (type_root_node
.InitTypeRoot(type_
) != syncer::BaseNode::INIT_OK
) {
679 LOG(ERROR
) << err_str
;
683 // The sync model has user created nodes if the type's root node has any
685 *has_nodes
= type_root_node
.HasChildren();
689 bool GenericChangeProcessor::CryptoReadyIfNecessary() {
690 DCHECK(CalledOnValidThread());
691 // We only access the cryptographer while holding a transaction.
692 syncer::ReadTransaction
trans(FROM_HERE
, share_handle());
693 const syncer::ModelTypeSet encrypted_types
= trans
.GetEncryptedTypes();
694 return !encrypted_types
.Has(type_
) || trans
.GetCryptographer()->is_ready();
697 void GenericChangeProcessor::StartImpl() {
700 syncer::UserShare
* GenericChangeProcessor::share_handle() const {
701 DCHECK(CalledOnValidThread());
702 return share_handle_
;
705 void GenericChangeProcessor::UploadAllAttachmentsNotOnServer() {
706 DCHECK(CalledOnValidThread());
707 DCHECK(attachment_service_
.get());
708 syncer::AttachmentIdSet id_set
;
710 syncer::ReadTransaction
trans(FROM_HERE
, share_handle());
711 trans
.GetAttachmentIdsToUpload(type_
, &id_set
);
713 if (!id_set
.empty()) {
714 attachment_service_
->UploadAttachments(id_set
);
718 } // namespace sync_driver