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 DataTypeErrorHandler
* error_handler
,
92 const base::WeakPtr
<syncer::SyncableService
>& local_service
,
93 const base::WeakPtr
<syncer::SyncMergeResult
>& merge_result
,
94 syncer::UserShare
* user_share
,
95 SyncApiComponentFactory
* sync_factory
)
96 : ChangeProcessor(error_handler
),
97 local_service_(local_service
),
98 merge_result_(merge_result
),
99 share_handle_(user_share
),
101 sync_factory
->CreateAttachmentService(*user_share
, this)),
102 attachment_service_weak_ptr_factory_(attachment_service_
.get()),
103 attachment_service_proxy_(
104 base::MessageLoopProxy::current(),
105 attachment_service_weak_ptr_factory_
.GetWeakPtr()) {
106 DCHECK(CalledOnValidThread());
107 DCHECK(attachment_service_
);
110 GenericChangeProcessor::~GenericChangeProcessor() {
111 DCHECK(CalledOnValidThread());
114 void GenericChangeProcessor::ApplyChangesFromSyncModel(
115 const syncer::BaseTransaction
* trans
,
117 const syncer::ImmutableChangeRecordList
& changes
) {
118 DCHECK(CalledOnValidThread());
119 DCHECK(syncer_changes_
.empty());
120 for (syncer::ChangeRecordList::const_iterator it
=
121 changes
.Get().begin(); it
!= changes
.Get().end(); ++it
) {
122 if (it
->action
== syncer::ChangeRecord::ACTION_DELETE
) {
123 scoped_ptr
<sync_pb::EntitySpecifics
> specifics
;
124 if (it
->specifics
.has_password()) {
125 DCHECK(it
->extra
.get());
126 specifics
.reset(new sync_pb::EntitySpecifics(it
->specifics
));
127 specifics
->mutable_password()->mutable_client_only_encrypted_data()->
128 CopyFrom(it
->extra
->unencrypted());
130 const syncer::AttachmentIdList empty_list_of_attachment_ids
;
131 syncer_changes_
.push_back(
132 syncer::SyncChange(FROM_HERE
,
133 syncer::SyncChange::ACTION_DELETE
,
134 syncer::SyncData::CreateRemoteData(
136 specifics
? *specifics
: it
->specifics
,
138 empty_list_of_attachment_ids
,
139 attachment_service_proxy_
)));
141 syncer::SyncChange::SyncChangeType action
=
142 (it
->action
== syncer::ChangeRecord::ACTION_ADD
) ?
143 syncer::SyncChange::ACTION_ADD
: syncer::SyncChange::ACTION_UPDATE
;
144 // Need to load specifics from node.
145 syncer::ReadNode
read_node(trans
);
146 if (read_node
.InitByIdLookup(it
->id
) != syncer::BaseNode::INIT_OK
) {
147 syncer::SyncError
error(
149 syncer::SyncError::DATATYPE_ERROR
,
150 "Failed to look up data for received change with id " +
151 base::Int64ToString(it
->id
),
152 syncer::GetModelTypeFromSpecifics(it
->specifics
));
153 error_handler()->OnSingleDataTypeUnrecoverableError(error
);
156 syncer_changes_
.push_back(syncer::SyncChange(
159 BuildRemoteSyncData(it
->id
, read_node
, attachment_service_proxy_
)));
164 void GenericChangeProcessor::CommitChangesFromSyncModel() {
165 DCHECK(CalledOnValidThread());
166 if (syncer_changes_
.empty())
168 if (!local_service_
.get()) {
169 syncer::ModelType type
= syncer_changes_
[0].sync_data().GetDataType();
170 syncer::SyncError
error(FROM_HERE
,
171 syncer::SyncError::DATATYPE_ERROR
,
172 "Local service destroyed.",
174 error_handler()->OnSingleDataTypeUnrecoverableError(error
);
177 syncer::SyncError error
= local_service_
->ProcessSyncChanges(FROM_HERE
,
179 syncer_changes_
.clear();
181 error_handler()->OnSingleDataTypeUnrecoverableError(error
);
184 syncer::SyncDataList
GenericChangeProcessor::GetAllSyncData(
185 syncer::ModelType type
) const {
186 // This is slow / memory intensive. Should be used sparingly by datatypes.
187 syncer::SyncDataList data
;
188 GetAllSyncDataReturnError(type
, &data
);
192 syncer::SyncError
GenericChangeProcessor::UpdateDataTypeContext(
193 syncer::ModelType type
,
194 syncer::SyncChangeProcessor::ContextRefreshStatus refresh_status
,
195 const std::string
& context
) {
196 DCHECK(syncer::ProtocolTypes().Has(type
));
198 if (context
.size() > static_cast<size_t>(kContextSizeLimit
)) {
199 return syncer::SyncError(FROM_HERE
,
200 syncer::SyncError::DATATYPE_ERROR
,
201 "Context size limit exceeded.",
205 syncer::WriteTransaction
trans(FROM_HERE
, share_handle());
206 trans
.SetDataTypeContext(type
, refresh_status
, context
);
208 // TODO(zea): plumb a pointer to the PSS or SyncManagerImpl here so we can
209 // trigger a datatype nudge if |refresh_status == REFRESH_NEEDED|.
211 return syncer::SyncError();
214 void GenericChangeProcessor::OnAttachmentUploaded(
215 const syncer::AttachmentId
& attachment_id
) {
216 syncer::WriteTransaction
trans(FROM_HERE
, share_handle());
217 trans
.UpdateEntriesMarkAttachmentAsOnServer(attachment_id
);
220 syncer::SyncError
GenericChangeProcessor::GetAllSyncDataReturnError(
221 syncer::ModelType type
,
222 syncer::SyncDataList
* current_sync_data
) const {
223 DCHECK(CalledOnValidThread());
224 std::string type_name
= syncer::ModelTypeToString(type
);
225 syncer::ReadTransaction
trans(FROM_HERE
, share_handle());
226 syncer::ReadNode
root(&trans
);
227 if (root
.InitTypeRoot(type
) != syncer::BaseNode::INIT_OK
) {
228 syncer::SyncError
error(FROM_HERE
,
229 syncer::SyncError::DATATYPE_ERROR
,
230 "Server did not create the top-level " + type_name
+
231 " node. We might be running against an out-of-"
237 // TODO(akalin): We'll have to do a tree traversal for bookmarks.
238 DCHECK_NE(type
, syncer::BOOKMARKS
);
240 std::vector
<int64
> child_ids
;
241 root
.GetChildIds(&child_ids
);
243 for (std::vector
<int64
>::iterator it
= child_ids
.begin();
244 it
!= child_ids
.end(); ++it
) {
245 syncer::ReadNode
sync_child_node(&trans
);
246 if (sync_child_node
.InitByIdLookup(*it
) !=
247 syncer::BaseNode::INIT_OK
) {
248 syncer::SyncError
error(FROM_HERE
,
249 syncer::SyncError::DATATYPE_ERROR
,
250 "Failed to fetch child node for type " +
255 current_sync_data
->push_back(BuildRemoteSyncData(
256 sync_child_node
.GetId(), sync_child_node
, attachment_service_proxy_
));
258 return syncer::SyncError();
261 bool GenericChangeProcessor::GetDataTypeContext(syncer::ModelType type
,
262 std::string
* context
) const {
263 syncer::ReadTransaction
trans(FROM_HERE
, share_handle());
264 sync_pb::DataTypeContext context_proto
;
265 trans
.GetDataTypeContext(type
, &context_proto
);
266 if (!context_proto
.has_context())
270 syncer::GetModelTypeFromSpecificsFieldNumber(
271 context_proto
.data_type_id()));
272 *context
= context_proto
.context();
276 int GenericChangeProcessor::GetSyncCountForType(syncer::ModelType type
) {
277 syncer::ReadTransaction
trans(FROM_HERE
, share_handle());
278 syncer::ReadNode
root(&trans
);
279 if (root
.InitTypeRoot(type
) != syncer::BaseNode::INIT_OK
)
282 // Subtract one to account for type's root node.
283 return root
.GetTotalNodeCount() - 1;
288 // WARNING: this code is sensitive to compiler optimizations. Be careful
289 // modifying any code around an OnSingleDataTypeUnrecoverableError call, else
290 // the compiler attempts to merge it with other calls, losing useful information
291 // in breakpad uploads.
292 syncer::SyncError
LogLookupFailure(
293 syncer::BaseNode::InitByLookupResult lookup_result
,
294 const tracked_objects::Location
& from_here
,
295 const std::string
& error_prefix
,
296 syncer::ModelType type
,
297 DataTypeErrorHandler
* error_handler
) {
298 switch (lookup_result
) {
299 case syncer::BaseNode::INIT_FAILED_ENTRY_NOT_GOOD
: {
300 syncer::SyncError error
;
301 error
.Reset(from_here
,
303 "could not find entry matching the lookup criteria.",
305 error_handler
->OnSingleDataTypeUnrecoverableError(error
);
306 LOG(ERROR
) << "Delete: Bad entry.";
309 case syncer::BaseNode::INIT_FAILED_ENTRY_IS_DEL
: {
310 syncer::SyncError error
;
311 error
.Reset(from_here
, error_prefix
+ "entry is already deleted.", type
);
312 error_handler
->OnSingleDataTypeUnrecoverableError(error
);
313 LOG(ERROR
) << "Delete: Deleted entry.";
316 case syncer::BaseNode::INIT_FAILED_DECRYPT_IF_NECESSARY
: {
317 syncer::SyncError error
;
318 error
.Reset(from_here
, error_prefix
+ "unable to decrypt", type
);
319 error_handler
->OnSingleDataTypeUnrecoverableError(error
);
320 LOG(ERROR
) << "Delete: Undecryptable entry.";
323 case syncer::BaseNode::INIT_FAILED_PRECONDITION
: {
324 syncer::SyncError error
;
325 error
.Reset(from_here
,
326 error_prefix
+ "a precondition was not met for calling init.",
328 error_handler
->OnSingleDataTypeUnrecoverableError(error
);
329 LOG(ERROR
) << "Delete: Failed precondition.";
333 syncer::SyncError error
;
334 // Should have listed all the possible error cases above.
335 error
.Reset(from_here
, error_prefix
+ "unknown error", type
);
336 error_handler
->OnSingleDataTypeUnrecoverableError(error
);
337 LOG(ERROR
) << "Delete: Unknown error.";
343 syncer::SyncError
AttemptDelete(const syncer::SyncChange
& change
,
344 syncer::ModelType type
,
345 const std::string
& type_str
,
346 syncer::WriteNode
* node
,
347 DataTypeErrorHandler
* error_handler
) {
348 DCHECK_EQ(change
.change_type(), syncer::SyncChange::ACTION_DELETE
);
349 if (change
.sync_data().IsLocal()) {
350 const std::string
& tag
= syncer::SyncDataLocal(change
.sync_data()).GetTag();
352 syncer::SyncError
error(
354 syncer::SyncError::DATATYPE_ERROR
,
355 "Failed to delete " + type_str
+ " node. Local data, empty tag. " +
356 change
.location().ToString(),
358 error_handler
->OnSingleDataTypeUnrecoverableError(error
);
363 syncer::BaseNode::InitByLookupResult result
=
364 node
->InitByClientTagLookup(change
.sync_data().GetDataType(), tag
);
365 if (result
!= syncer::BaseNode::INIT_OK
) {
366 return LogLookupFailure(
368 "Failed to delete " + type_str
+ " node. Local data. " +
369 change
.location().ToString(),
370 type
, error_handler
);
373 syncer::BaseNode::InitByLookupResult result
= node
->InitByIdLookup(
374 syncer::SyncDataRemote(change
.sync_data()).GetId());
375 if (result
!= syncer::BaseNode::INIT_OK
) {
376 return LogLookupFailure(
378 "Failed to delete " + type_str
+ " node. Non-local data. " +
379 change
.location().ToString(),
380 type
, error_handler
);
383 if (IsActOnceDataType(type
))
387 return syncer::SyncError();
390 // A callback invoked on completion of AttachmentService::StoreAttachment.
391 void IgnoreStoreResult(const syncer::AttachmentService::StoreResult
&) {
392 // TODO(maniscalco): Here is where we're going to update the in-directory
393 // entry to indicate that the attachments have been successfully stored on
394 // disk. Why do we care? Because we might crash after persisting the
395 // directory to disk, but before we have persisted its attachments, leaving us
396 // with danging attachment ids. Having a flag that indicates we've stored the
397 // entry will allow us to detect and filter entries with dangling attachment
401 void StoreAttachments(syncer::AttachmentService
* attachment_service
,
402 const syncer::AttachmentList
& attachments
) {
403 DCHECK(attachment_service
);
404 syncer::AttachmentService::StoreCallback ignore_store_result
=
405 base::Bind(&IgnoreStoreResult
);
406 attachment_service
->StoreAttachments(attachments
, ignore_store_result
);
411 syncer::SyncError
GenericChangeProcessor::ProcessSyncChanges(
412 const tracked_objects::Location
& from_here
,
413 const syncer::SyncChangeList
& list_of_changes
) {
414 DCHECK(CalledOnValidThread());
416 // Keep track of brand new attachments so we can persist them on this device
417 // and upload them to the server.
418 syncer::AttachmentList new_attachments
;
420 syncer::WriteTransaction
trans(from_here
, share_handle());
422 for (syncer::SyncChangeList::const_iterator iter
= list_of_changes
.begin();
423 iter
!= list_of_changes
.end();
425 const syncer::SyncChange
& change
= *iter
;
426 DCHECK_NE(change
.sync_data().GetDataType(), syncer::UNSPECIFIED
);
427 syncer::ModelType type
= change
.sync_data().GetDataType();
428 std::string type_str
= syncer::ModelTypeToString(type
);
429 syncer::WriteNode
sync_node(&trans
);
430 if (change
.change_type() == syncer::SyncChange::ACTION_DELETE
) {
431 syncer::SyncError error
=
432 AttemptDelete(change
, type
, type_str
, &sync_node
, error_handler());
437 if (merge_result_
.get()) {
438 merge_result_
->set_num_items_deleted(
439 merge_result_
->num_items_deleted() + 1);
441 } else if (change
.change_type() == syncer::SyncChange::ACTION_ADD
) {
442 syncer::SyncError error
= HandleActionAdd(
443 change
, type_str
, type
, trans
, &sync_node
, &new_attachments
);
447 } else if (change
.change_type() == syncer::SyncChange::ACTION_UPDATE
) {
448 syncer::SyncError error
= HandleActionUpdate(
449 change
, type_str
, type
, trans
, &sync_node
, &new_attachments
);
454 syncer::SyncError
error(
456 syncer::SyncError::DATATYPE_ERROR
,
457 "Received unset SyncChange in the change processor, " +
458 change
.location().ToString(),
460 error_handler()->OnSingleDataTypeUnrecoverableError(error
);
462 LOG(ERROR
) << "Unset sync change.";
467 if (!new_attachments
.empty()) {
468 StoreAttachments(attachment_service_
.get(), new_attachments
);
471 return syncer::SyncError();
474 // WARNING: this code is sensitive to compiler optimizations. Be careful
475 // modifying any code around an OnSingleDataTypeUnrecoverableError call, else
476 // the compiler attempts to merge it with other calls, losing useful information
477 // in breakpad uploads.
478 syncer::SyncError
GenericChangeProcessor::HandleActionAdd(
479 const syncer::SyncChange
& change
,
480 const std::string
& type_str
,
481 const syncer::ModelType
& type
,
482 const syncer::WriteTransaction
& trans
,
483 syncer::WriteNode
* sync_node
,
484 syncer::AttachmentList
* new_attachments
) {
485 // TODO(sync): Handle other types of creation (custom parents, folders,
487 syncer::ReadNode
root_node(&trans
);
488 const syncer::SyncDataLocal
sync_data_local(change
.sync_data());
489 if (root_node
.InitTypeRoot(sync_data_local
.GetDataType()) !=
490 syncer::BaseNode::INIT_OK
) {
491 syncer::SyncError
error(FROM_HERE
,
492 syncer::SyncError::DATATYPE_ERROR
,
493 "Failed to look up root node for type " + type_str
,
495 error_handler()->OnSingleDataTypeUnrecoverableError(error
);
497 LOG(ERROR
) << "Create: no root node.";
500 syncer::WriteNode::InitUniqueByCreationResult result
=
501 sync_node
->InitUniqueByCreation(
502 sync_data_local
.GetDataType(), root_node
, sync_data_local
.GetTag());
503 if (result
!= syncer::WriteNode::INIT_SUCCESS
) {
504 std::string error_prefix
= "Failed to create " + type_str
+ " node: " +
505 change
.location().ToString() + ", ";
507 case syncer::WriteNode::INIT_FAILED_EMPTY_TAG
: {
508 syncer::SyncError error
;
509 error
.Reset(FROM_HERE
, error_prefix
+ "empty tag", type
);
510 error_handler()->OnSingleDataTypeUnrecoverableError(error
);
511 LOG(ERROR
) << "Create: Empty tag.";
514 case syncer::WriteNode::INIT_FAILED_ENTRY_ALREADY_EXISTS
: {
515 syncer::SyncError error
;
516 error
.Reset(FROM_HERE
, error_prefix
+ "entry already exists", type
);
517 error_handler()->OnSingleDataTypeUnrecoverableError(error
);
518 LOG(ERROR
) << "Create: Entry exists.";
521 case syncer::WriteNode::INIT_FAILED_COULD_NOT_CREATE_ENTRY
: {
522 syncer::SyncError error
;
523 error
.Reset(FROM_HERE
, error_prefix
+ "failed to create entry", type
);
524 error_handler()->OnSingleDataTypeUnrecoverableError(error
);
525 LOG(ERROR
) << "Create: Could not create entry.";
528 case syncer::WriteNode::INIT_FAILED_SET_PREDECESSOR
: {
529 syncer::SyncError error
;
531 FROM_HERE
, error_prefix
+ "failed to set predecessor", type
);
532 error_handler()->OnSingleDataTypeUnrecoverableError(error
);
533 LOG(ERROR
) << "Create: Bad predecessor.";
537 syncer::SyncError error
;
538 error
.Reset(FROM_HERE
, error_prefix
+ "unknown error", type
);
539 error_handler()->OnSingleDataTypeUnrecoverableError(error
);
540 LOG(ERROR
) << "Create: Unknown error.";
545 sync_node
->SetTitle(change
.sync_data().GetTitle());
546 SetNodeSpecifics(sync_data_local
.GetSpecifics(), sync_node
);
548 syncer::AttachmentIdList attachment_ids
= sync_data_local
.GetAttachmentIds();
549 SetAttachmentMetadata(attachment_ids
, sync_node
);
551 // Return any newly added attachments.
552 const syncer::AttachmentList
& local_attachments_for_upload
=
553 sync_data_local
.GetLocalAttachmentsForUpload();
554 new_attachments
->insert(new_attachments
->end(),
555 local_attachments_for_upload
.begin(),
556 local_attachments_for_upload
.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::ModelType
& type
,
571 const syncer::WriteTransaction
& trans
,
572 syncer::WriteNode
* sync_node
,
573 syncer::AttachmentList
* new_attachments
) {
574 // TODO(zea): consider having this logic for all possible changes?
576 const syncer::SyncDataLocal
sync_data_local(change
.sync_data());
577 syncer::BaseNode::InitByLookupResult result
=
578 sync_node
->InitByClientTagLookup(sync_data_local
.GetDataType(),
579 sync_data_local
.GetTag());
580 if (result
!= syncer::BaseNode::INIT_OK
) {
581 std::string error_prefix
= "Failed to load " + type_str
+ " node. " +
582 change
.location().ToString() + ", ";
583 if (result
== syncer::BaseNode::INIT_FAILED_PRECONDITION
) {
584 syncer::SyncError error
;
585 error
.Reset(FROM_HERE
, error_prefix
+ "empty tag", type
);
586 error_handler()->OnSingleDataTypeUnrecoverableError(error
);
587 LOG(ERROR
) << "Update: Empty tag.";
589 } else if (result
== syncer::BaseNode::INIT_FAILED_ENTRY_NOT_GOOD
) {
590 syncer::SyncError error
;
591 error
.Reset(FROM_HERE
, error_prefix
+ "bad entry", type
);
592 error_handler()->OnSingleDataTypeUnrecoverableError(error
);
593 LOG(ERROR
) << "Update: bad entry.";
595 } else if (result
== syncer::BaseNode::INIT_FAILED_ENTRY_IS_DEL
) {
596 syncer::SyncError error
;
597 error
.Reset(FROM_HERE
, error_prefix
+ "deleted entry", type
);
598 error_handler()->OnSingleDataTypeUnrecoverableError(error
);
599 LOG(ERROR
) << "Update: deleted entry.";
602 syncer::Cryptographer
* crypto
= trans
.GetCryptographer();
603 syncer::ModelTypeSet
encrypted_types(trans
.GetEncryptedTypes());
604 const sync_pb::EntitySpecifics
& specifics
=
605 sync_node
->GetEntry()->GetSpecifics();
606 CHECK(specifics
.has_encrypted());
607 const bool can_decrypt
= crypto
->CanDecrypt(specifics
.encrypted());
608 const bool agreement
= encrypted_types
.Has(type
);
609 if (!agreement
&& !can_decrypt
) {
610 syncer::SyncError error
;
611 error
.Reset(FROM_HERE
,
612 "Failed to load encrypted entry, missing key and "
613 "nigori mismatch for " +
616 error_handler()->OnSingleDataTypeUnrecoverableError(error
);
617 LOG(ERROR
) << "Update: encr case 1.";
619 } else if (agreement
&& can_decrypt
) {
620 syncer::SyncError error
;
621 error
.Reset(FROM_HERE
,
622 "Failed to load encrypted entry, we have the key "
623 "and the nigori matches (?!) for " +
626 error_handler()->OnSingleDataTypeUnrecoverableError(error
);
627 LOG(ERROR
) << "Update: encr case 2.";
629 } else if (agreement
) {
630 syncer::SyncError error
;
631 error
.Reset(FROM_HERE
,
632 "Failed to load encrypted entry, missing key and "
633 "the nigori matches for " +
636 error_handler()->OnSingleDataTypeUnrecoverableError(error
);
637 LOG(ERROR
) << "Update: encr case 3.";
640 syncer::SyncError error
;
641 error
.Reset(FROM_HERE
,
642 "Failed to load encrypted entry, we have the key"
643 "(?!) and nigori mismatch for " +
646 error_handler()->OnSingleDataTypeUnrecoverableError(error
);
647 LOG(ERROR
) << "Update: encr case 4.";
653 sync_node
->SetTitle(change
.sync_data().GetTitle());
654 SetNodeSpecifics(sync_data_local
.GetSpecifics(), sync_node
);
655 SetAttachmentMetadata(sync_data_local
.GetAttachmentIds(), sync_node
);
657 // Return any newly added attachments.
658 const syncer::AttachmentList
& local_attachments_for_upload
=
659 sync_data_local
.GetLocalAttachmentsForUpload();
660 new_attachments
->insert(new_attachments
->end(),
661 local_attachments_for_upload
.begin(),
662 local_attachments_for_upload
.end());
664 if (merge_result_
.get()) {
665 merge_result_
->set_num_items_modified(merge_result_
->num_items_modified() +
668 // TODO(sync): Support updating other parts of the sync node (title,
669 // successor, parent, etc.).
670 return syncer::SyncError();
673 bool GenericChangeProcessor::SyncModelHasUserCreatedNodes(
674 syncer::ModelType type
,
676 DCHECK(CalledOnValidThread());
678 DCHECK_NE(type
, syncer::UNSPECIFIED
);
679 std::string type_name
= syncer::ModelTypeToString(type
);
680 std::string err_str
= "Server did not create the top-level " + type_name
+
681 " node. We might be running against an out-of-date server.";
683 syncer::ReadTransaction
trans(FROM_HERE
, share_handle());
684 syncer::ReadNode
type_root_node(&trans
);
685 if (type_root_node
.InitTypeRoot(type
) != syncer::BaseNode::INIT_OK
) {
686 LOG(ERROR
) << err_str
;
690 // The sync model has user created nodes if the type's root node has any
692 *has_nodes
= type_root_node
.HasChildren();
696 bool GenericChangeProcessor::CryptoReadyIfNecessary(syncer::ModelType type
) {
697 DCHECK(CalledOnValidThread());
698 DCHECK_NE(type
, syncer::UNSPECIFIED
);
699 // We only access the cryptographer while holding a transaction.
700 syncer::ReadTransaction
trans(FROM_HERE
, share_handle());
701 const syncer::ModelTypeSet encrypted_types
= trans
.GetEncryptedTypes();
702 return !encrypted_types
.Has(type
) ||
703 trans
.GetCryptographer()->is_ready();
706 void GenericChangeProcessor::StartImpl() {
709 syncer::UserShare
* GenericChangeProcessor::share_handle() const {
710 DCHECK(CalledOnValidThread());
711 return share_handle_
;
714 } // namespace sync_driver