Fix layout of the Connection Tab of the Origin Info Bubble.
[chromium-blink-merge.git] / components / sync_driver / generic_change_processor.cc
blobb86b92085611d43685268dd0519e4d073cad7b56
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 "base/thread_task_runner_handle.h"
11 #include "components/sync_driver/sync_api_component_factory.h"
12 #include "components/sync_driver/sync_client.h"
13 #include "sync/api/sync_change.h"
14 #include "sync/api/sync_error.h"
15 #include "sync/api/syncable_service.h"
16 #include "sync/internal_api/public/base_node.h"
17 #include "sync/internal_api/public/change_record.h"
18 #include "sync/internal_api/public/read_node.h"
19 #include "sync/internal_api/public/read_transaction.h"
20 #include "sync/internal_api/public/util/unrecoverable_error_handler.h"
21 #include "sync/internal_api/public/write_node.h"
22 #include "sync/internal_api/public/write_transaction.h"
23 #include "sync/syncable/entry.h" // TODO(tim): Bug 123674.
25 namespace sync_driver {
27 namespace {
29 const int kContextSizeLimit = 1024; // Datatype context size limit.
31 void SetNodeSpecifics(const sync_pb::EntitySpecifics& entity_specifics,
32 syncer::WriteNode* write_node) {
33 if (syncer::GetModelTypeFromSpecifics(entity_specifics) ==
34 syncer::PASSWORDS) {
35 write_node->SetPasswordSpecifics(
36 entity_specifics.password().client_only_encrypted_data());
37 } else {
38 write_node->SetEntitySpecifics(entity_specifics);
42 // Helper function to convert AttachmentId to AttachmentMetadataRecord.
43 sync_pb::AttachmentMetadataRecord AttachmentIdToRecord(
44 const syncer::AttachmentId& attachment_id) {
45 sync_pb::AttachmentMetadataRecord record;
46 *record.mutable_id() = attachment_id.GetProto();
47 return record;
50 // Replace |write_nodes|'s attachment ids with |attachment_ids|.
51 void SetAttachmentMetadata(const syncer::AttachmentIdList& attachment_ids,
52 syncer::WriteNode* write_node) {
53 DCHECK(write_node);
54 sync_pb::AttachmentMetadata attachment_metadata;
55 std::transform(
56 attachment_ids.begin(),
57 attachment_ids.end(),
58 RepeatedFieldBackInserter(attachment_metadata.mutable_record()),
59 AttachmentIdToRecord);
60 write_node->SetAttachmentMetadata(attachment_metadata);
63 syncer::SyncData BuildRemoteSyncData(
64 int64 sync_id,
65 const syncer::BaseNode& read_node,
66 const syncer::AttachmentServiceProxy& attachment_service_proxy) {
67 const syncer::AttachmentIdList& attachment_ids = read_node.GetAttachmentIds();
68 // Use the specifics of non-password datatypes directly (encryption has
69 // already been handled).
70 if (read_node.GetModelType() != syncer::PASSWORDS) {
71 return syncer::SyncData::CreateRemoteData(sync_id,
72 read_node.GetEntitySpecifics(),
73 read_node.GetModificationTime(),
74 attachment_ids,
75 attachment_service_proxy);
78 // Passwords must be accessed differently, to account for their encryption,
79 // and stored into a temporary EntitySpecifics.
80 sync_pb::EntitySpecifics password_holder;
81 password_holder.mutable_password()->mutable_client_only_encrypted_data()->
82 CopyFrom(read_node.GetPasswordSpecifics());
83 return syncer::SyncData::CreateRemoteData(sync_id,
84 password_holder,
85 read_node.GetModificationTime(),
86 attachment_ids,
87 attachment_service_proxy);
90 } // namespace
92 GenericChangeProcessor::GenericChangeProcessor(
93 syncer::ModelType type,
94 DataTypeErrorHandler* error_handler,
95 const base::WeakPtr<syncer::SyncableService>& local_service,
96 const base::WeakPtr<syncer::SyncMergeResult>& merge_result,
97 syncer::UserShare* user_share,
98 SyncClient* sync_client,
99 scoped_ptr<syncer::AttachmentStoreForSync> attachment_store)
100 : ChangeProcessor(error_handler),
101 type_(type),
102 local_service_(local_service),
103 merge_result_(merge_result),
104 share_handle_(user_share),
105 weak_ptr_factory_(this) {
106 DCHECK(CalledOnValidThread());
107 DCHECK_NE(type_, syncer::UNSPECIFIED);
108 if (attachment_store) {
109 std::string store_birthday;
111 syncer::ReadTransaction trans(FROM_HERE, share_handle());
112 store_birthday = trans.GetStoreBirthday();
114 attachment_service_ =
115 sync_client->GetSyncApiComponentFactory()->CreateAttachmentService(
116 attachment_store.Pass(), *user_share, store_birthday, type, this);
117 attachment_service_weak_ptr_factory_.reset(
118 new base::WeakPtrFactory<syncer::AttachmentService>(
119 attachment_service_.get()));
120 attachment_service_proxy_ = syncer::AttachmentServiceProxy(
121 base::ThreadTaskRunnerHandle::Get(),
122 attachment_service_weak_ptr_factory_->GetWeakPtr());
123 UploadAllAttachmentsNotOnServer();
124 } else {
125 attachment_service_proxy_ = syncer::AttachmentServiceProxy(
126 base::ThreadTaskRunnerHandle::Get(),
127 base::WeakPtr<syncer::AttachmentService>());
131 GenericChangeProcessor::~GenericChangeProcessor() {
132 DCHECK(CalledOnValidThread());
135 void GenericChangeProcessor::ApplyChangesFromSyncModel(
136 const syncer::BaseTransaction* trans,
137 int64 model_version,
138 const syncer::ImmutableChangeRecordList& changes) {
139 DCHECK(CalledOnValidThread());
140 DCHECK(syncer_changes_.empty());
141 for (syncer::ChangeRecordList::const_iterator it =
142 changes.Get().begin(); it != changes.Get().end(); ++it) {
143 if (it->action == syncer::ChangeRecord::ACTION_DELETE) {
144 scoped_ptr<sync_pb::EntitySpecifics> specifics;
145 if (it->specifics.has_password()) {
146 DCHECK(it->extra.get());
147 specifics.reset(new sync_pb::EntitySpecifics(it->specifics));
148 specifics->mutable_password()->mutable_client_only_encrypted_data()->
149 CopyFrom(it->extra->unencrypted());
151 const syncer::AttachmentIdList empty_list_of_attachment_ids;
152 syncer_changes_.push_back(syncer::SyncChange(
153 FROM_HERE, syncer::SyncChange::ACTION_DELETE,
154 syncer::SyncData::CreateRemoteData(
155 it->id, specifics ? *specifics : it->specifics, base::Time(),
156 empty_list_of_attachment_ids, attachment_service_proxy_)));
157 } else {
158 syncer::SyncChange::SyncChangeType action =
159 (it->action == syncer::ChangeRecord::ACTION_ADD) ?
160 syncer::SyncChange::ACTION_ADD : syncer::SyncChange::ACTION_UPDATE;
161 // Need to load specifics from node.
162 syncer::ReadNode read_node(trans);
163 if (read_node.InitByIdLookup(it->id) != syncer::BaseNode::INIT_OK) {
164 syncer::SyncError error(
165 FROM_HERE,
166 syncer::SyncError::DATATYPE_ERROR,
167 "Failed to look up data for received change with id " +
168 base::Int64ToString(it->id),
169 syncer::GetModelTypeFromSpecifics(it->specifics));
170 error_handler()->OnSingleDataTypeUnrecoverableError(error);
171 return;
173 syncer_changes_.push_back(syncer::SyncChange(
174 FROM_HERE, action,
175 BuildRemoteSyncData(it->id, read_node, attachment_service_proxy_)));
180 void GenericChangeProcessor::CommitChangesFromSyncModel() {
181 DCHECK(CalledOnValidThread());
182 if (syncer_changes_.empty())
183 return;
184 if (!local_service_.get()) {
185 syncer::ModelType type = syncer_changes_[0].sync_data().GetDataType();
186 syncer::SyncError error(FROM_HERE,
187 syncer::SyncError::DATATYPE_ERROR,
188 "Local service destroyed.",
189 type);
190 error_handler()->OnSingleDataTypeUnrecoverableError(error);
191 return;
193 syncer::SyncError error = local_service_->ProcessSyncChanges(FROM_HERE,
194 syncer_changes_);
195 syncer_changes_.clear();
196 if (error.IsSet())
197 error_handler()->OnSingleDataTypeUnrecoverableError(error);
200 syncer::SyncDataList GenericChangeProcessor::GetAllSyncData(
201 syncer::ModelType type) const {
202 DCHECK_EQ(type_, type);
203 // This is slow / memory intensive. Should be used sparingly by datatypes.
204 syncer::SyncDataList data;
205 GetAllSyncDataReturnError(&data);
206 return data;
209 syncer::SyncError GenericChangeProcessor::UpdateDataTypeContext(
210 syncer::ModelType type,
211 syncer::SyncChangeProcessor::ContextRefreshStatus refresh_status,
212 const std::string& context) {
213 DCHECK(syncer::ProtocolTypes().Has(type));
214 DCHECK_EQ(type_, type);
216 if (context.size() > static_cast<size_t>(kContextSizeLimit)) {
217 return syncer::SyncError(FROM_HERE,
218 syncer::SyncError::DATATYPE_ERROR,
219 "Context size limit exceeded.",
220 type);
223 syncer::WriteTransaction trans(FROM_HERE, share_handle());
224 trans.SetDataTypeContext(type, refresh_status, context);
226 // TODO(zea): plumb a pointer to the PSS or SyncManagerImpl here so we can
227 // trigger a datatype nudge if |refresh_status == REFRESH_NEEDED|.
229 return syncer::SyncError();
232 void GenericChangeProcessor::OnAttachmentUploaded(
233 const syncer::AttachmentId& attachment_id) {
234 syncer::WriteTransaction trans(FROM_HERE, share_handle());
235 trans.UpdateEntriesMarkAttachmentAsOnServer(attachment_id);
238 syncer::SyncError GenericChangeProcessor::GetAllSyncDataReturnError(
239 syncer::SyncDataList* current_sync_data) const {
240 DCHECK(CalledOnValidThread());
241 std::string type_name = syncer::ModelTypeToString(type_);
242 syncer::ReadTransaction trans(FROM_HERE, share_handle());
243 syncer::ReadNode root(&trans);
244 if (root.InitTypeRoot(type_) != syncer::BaseNode::INIT_OK) {
245 syncer::SyncError error(FROM_HERE,
246 syncer::SyncError::DATATYPE_ERROR,
247 "Server did not create the top-level " + type_name +
248 " node. We might be running against an out-of-"
249 "date server.",
250 type_);
251 return error;
254 // TODO(akalin): We'll have to do a tree traversal for bookmarks.
255 DCHECK_NE(type_, syncer::BOOKMARKS);
257 std::vector<int64> child_ids;
258 root.GetChildIds(&child_ids);
260 for (std::vector<int64>::iterator it = child_ids.begin();
261 it != child_ids.end(); ++it) {
262 syncer::ReadNode sync_child_node(&trans);
263 if (sync_child_node.InitByIdLookup(*it) !=
264 syncer::BaseNode::INIT_OK) {
265 syncer::SyncError error(
266 FROM_HERE,
267 syncer::SyncError::DATATYPE_ERROR,
268 "Failed to fetch child node for type " + type_name + ".",
269 type_);
270 return error;
272 current_sync_data->push_back(BuildRemoteSyncData(
273 sync_child_node.GetId(), sync_child_node, attachment_service_proxy_));
275 return syncer::SyncError();
278 bool GenericChangeProcessor::GetDataTypeContext(std::string* context) const {
279 syncer::ReadTransaction trans(FROM_HERE, share_handle());
280 sync_pb::DataTypeContext context_proto;
281 trans.GetDataTypeContext(type_, &context_proto);
282 if (!context_proto.has_context())
283 return false;
285 DCHECK_EQ(type_,
286 syncer::GetModelTypeFromSpecificsFieldNumber(
287 context_proto.data_type_id()));
288 *context = context_proto.context();
289 return true;
292 int GenericChangeProcessor::GetSyncCount() {
293 syncer::ReadTransaction trans(FROM_HERE, share_handle());
294 syncer::ReadNode root(&trans);
295 if (root.InitTypeRoot(type_) != syncer::BaseNode::INIT_OK)
296 return 0;
298 // Subtract one to account for type's root node.
299 return root.GetTotalNodeCount() - 1;
302 namespace {
304 // WARNING: this code is sensitive to compiler optimizations. Be careful
305 // modifying any code around an OnSingleDataTypeUnrecoverableError call, else
306 // the compiler attempts to merge it with other calls, losing useful information
307 // in breakpad uploads.
308 syncer::SyncError LogLookupFailure(
309 syncer::BaseNode::InitByLookupResult lookup_result,
310 const tracked_objects::Location& from_here,
311 const std::string& error_prefix,
312 syncer::ModelType type,
313 DataTypeErrorHandler* error_handler) {
314 switch (lookup_result) {
315 case syncer::BaseNode::INIT_FAILED_ENTRY_NOT_GOOD: {
316 syncer::SyncError error;
317 error.Reset(from_here,
318 error_prefix +
319 "could not find entry matching the lookup criteria.",
320 type);
321 error_handler->OnSingleDataTypeUnrecoverableError(error);
322 LOG(ERROR) << "Delete: Bad entry.";
323 return error;
325 case syncer::BaseNode::INIT_FAILED_ENTRY_IS_DEL: {
326 syncer::SyncError error;
327 error.Reset(from_here, error_prefix + "entry is already deleted.", type);
328 error_handler->OnSingleDataTypeUnrecoverableError(error);
329 LOG(ERROR) << "Delete: Deleted entry.";
330 return error;
332 case syncer::BaseNode::INIT_FAILED_DECRYPT_IF_NECESSARY: {
333 syncer::SyncError error;
334 error.Reset(from_here, error_prefix + "unable to decrypt", type);
335 error_handler->OnSingleDataTypeUnrecoverableError(error);
336 LOG(ERROR) << "Delete: Undecryptable entry.";
337 return error;
339 case syncer::BaseNode::INIT_FAILED_PRECONDITION: {
340 syncer::SyncError error;
341 error.Reset(from_here,
342 error_prefix + "a precondition was not met for calling init.",
343 type);
344 error_handler->OnSingleDataTypeUnrecoverableError(error);
345 LOG(ERROR) << "Delete: Failed precondition.";
346 return error;
348 default: {
349 syncer::SyncError error;
350 // Should have listed all the possible error cases above.
351 error.Reset(from_here, error_prefix + "unknown error", type);
352 error_handler->OnSingleDataTypeUnrecoverableError(error);
353 LOG(ERROR) << "Delete: Unknown error.";
354 return error;
359 syncer::SyncError AttemptDelete(const syncer::SyncChange& change,
360 syncer::ModelType type,
361 const std::string& type_str,
362 syncer::WriteNode* node,
363 DataTypeErrorHandler* error_handler) {
364 DCHECK_EQ(change.change_type(), syncer::SyncChange::ACTION_DELETE);
365 if (change.sync_data().IsLocal()) {
366 const std::string& tag = syncer::SyncDataLocal(change.sync_data()).GetTag();
367 if (tag.empty()) {
368 syncer::SyncError error(
369 FROM_HERE,
370 syncer::SyncError::DATATYPE_ERROR,
371 "Failed to delete " + type_str + " node. Local data, empty tag. " +
372 change.location().ToString(),
373 type);
374 error_handler->OnSingleDataTypeUnrecoverableError(error);
375 NOTREACHED();
376 return error;
379 syncer::BaseNode::InitByLookupResult result =
380 node->InitByClientTagLookup(change.sync_data().GetDataType(), tag);
381 if (result != syncer::BaseNode::INIT_OK) {
382 return LogLookupFailure(
383 result, FROM_HERE,
384 "Failed to delete " + type_str + " node. Local data. " +
385 change.location().ToString(),
386 type, error_handler);
388 } else {
389 syncer::BaseNode::InitByLookupResult result = node->InitByIdLookup(
390 syncer::SyncDataRemote(change.sync_data()).GetId());
391 if (result != syncer::BaseNode::INIT_OK) {
392 return LogLookupFailure(
393 result, FROM_HERE,
394 "Failed to delete " + type_str + " node. Non-local data. " +
395 change.location().ToString(),
396 type, error_handler);
399 if (IsActOnceDataType(type))
400 node->Drop();
401 else
402 node->Tombstone();
403 return syncer::SyncError();
406 } // namespace
408 syncer::SyncError GenericChangeProcessor::ProcessSyncChanges(
409 const tracked_objects::Location& from_here,
410 const syncer::SyncChangeList& list_of_changes) {
411 DCHECK(CalledOnValidThread());
413 if (list_of_changes.empty()) {
414 // No work. Exit without entering WriteTransaction.
415 return syncer::SyncError();
418 // Keep track of brand new attachments so we can persist them on this device
419 // and upload them to the server.
420 syncer::AttachmentIdSet new_attachments;
422 syncer::WriteTransaction trans(from_here, share_handle());
424 for (syncer::SyncChangeList::const_iterator iter = list_of_changes.begin();
425 iter != list_of_changes.end();
426 ++iter) {
427 const syncer::SyncChange& change = *iter;
428 DCHECK_EQ(change.sync_data().GetDataType(), type_);
429 std::string type_str = syncer::ModelTypeToString(type_);
430 syncer::WriteNode sync_node(&trans);
431 if (change.change_type() == syncer::SyncChange::ACTION_DELETE) {
432 syncer::SyncError error =
433 AttemptDelete(change, type_, type_str, &sync_node, error_handler());
434 if (error.IsSet()) {
435 NOTREACHED();
436 return error;
438 if (merge_result_.get()) {
439 merge_result_->set_num_items_deleted(
440 merge_result_->num_items_deleted() + 1);
442 } else if (change.change_type() == syncer::SyncChange::ACTION_ADD) {
443 syncer::SyncError error = HandleActionAdd(
444 change, type_str, trans, &sync_node, &new_attachments);
445 if (error.IsSet()) {
446 return error;
448 } else if (change.change_type() == syncer::SyncChange::ACTION_UPDATE) {
449 syncer::SyncError error = HandleActionUpdate(
450 change, type_str, trans, &sync_node, &new_attachments);
451 if (error.IsSet()) {
452 return error;
454 } else {
455 syncer::SyncError error(
456 FROM_HERE,
457 syncer::SyncError::DATATYPE_ERROR,
458 "Received unset SyncChange in the change processor, " +
459 change.location().ToString(),
460 type_);
461 error_handler()->OnSingleDataTypeUnrecoverableError(error);
462 NOTREACHED();
463 LOG(ERROR) << "Unset sync change.";
464 return error;
468 if (!new_attachments.empty()) {
469 // If datatype uses attachments it should have supplied attachment store
470 // which would initialize attachment_service_. Fail if it isn't so.
471 if (!attachment_service_.get()) {
472 syncer::SyncError error(
473 FROM_HERE,
474 syncer::SyncError::DATATYPE_ERROR,
475 "Datatype performs attachment operation without initializing "
476 "attachment store",
477 type_);
478 error_handler()->OnSingleDataTypeUnrecoverableError(error);
479 NOTREACHED();
480 return error;
482 syncer::AttachmentIdList ids_to_upload;
483 ids_to_upload.reserve(new_attachments.size());
484 std::copy(new_attachments.begin(), new_attachments.end(),
485 std::back_inserter(ids_to_upload));
486 attachment_service_->UploadAttachments(ids_to_upload);
489 return syncer::SyncError();
492 // WARNING: this code is sensitive to compiler optimizations. Be careful
493 // modifying any code around an OnSingleDataTypeUnrecoverableError call, else
494 // the compiler attempts to merge it with other calls, losing useful information
495 // in breakpad uploads.
496 syncer::SyncError GenericChangeProcessor::HandleActionAdd(
497 const syncer::SyncChange& change,
498 const std::string& type_str,
499 const syncer::WriteTransaction& trans,
500 syncer::WriteNode* sync_node,
501 syncer::AttachmentIdSet* new_attachments) {
502 // TODO(sync): Handle other types of creation (custom parents, folders,
503 // etc.).
504 const syncer::SyncDataLocal sync_data_local(change.sync_data());
505 syncer::WriteNode::InitUniqueByCreationResult result =
506 sync_node->InitUniqueByCreation(sync_data_local.GetDataType(),
507 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() + ", ";
511 switch (result) {
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.";
517 return error;
519 case syncer::WriteNode::INIT_FAILED_COULD_NOT_CREATE_ENTRY: {
520 syncer::SyncError error;
521 error.Reset(FROM_HERE, error_prefix + "failed to create entry", type_);
522 error_handler()->OnSingleDataTypeUnrecoverableError(error);
523 LOG(ERROR) << "Create: Could not create entry.";
524 return error;
526 case syncer::WriteNode::INIT_FAILED_SET_PREDECESSOR: {
527 syncer::SyncError error;
528 error.Reset(
529 FROM_HERE, error_prefix + "failed to set predecessor", type_);
530 error_handler()->OnSingleDataTypeUnrecoverableError(error);
531 LOG(ERROR) << "Create: Bad predecessor.";
532 return error;
534 default: {
535 syncer::SyncError error;
536 error.Reset(FROM_HERE, error_prefix + "unknown error", type_);
537 error_handler()->OnSingleDataTypeUnrecoverableError(error);
538 LOG(ERROR) << "Create: Unknown error.";
539 return error;
543 sync_node->SetTitle(change.sync_data().GetTitle());
544 SetNodeSpecifics(sync_data_local.GetSpecifics(), sync_node);
546 syncer::AttachmentIdList attachment_ids = sync_data_local.GetAttachmentIds();
547 SetAttachmentMetadata(attachment_ids, sync_node);
549 // Return any newly added attachments.
550 new_attachments->insert(attachment_ids.begin(), attachment_ids.end());
551 if (merge_result_.get()) {
552 merge_result_->set_num_items_added(merge_result_->num_items_added() + 1);
554 return syncer::SyncError();
556 // WARNING: this code is sensitive to compiler optimizations. Be careful
557 // modifying any code around an OnSingleDataTypeUnrecoverableError call, else
558 // the compiler attempts to merge it with other calls, losing useful information
559 // in breakpad uploads.
560 syncer::SyncError GenericChangeProcessor::HandleActionUpdate(
561 const syncer::SyncChange& change,
562 const std::string& type_str,
563 const syncer::WriteTransaction& trans,
564 syncer::WriteNode* sync_node,
565 syncer::AttachmentIdSet* new_attachments) {
566 const syncer::SyncDataLocal sync_data_local(change.sync_data());
567 syncer::BaseNode::InitByLookupResult result =
568 sync_node->InitByClientTagLookup(sync_data_local.GetDataType(),
569 sync_data_local.GetTag());
570 if (result != syncer::BaseNode::INIT_OK) {
571 std::string error_prefix = "Failed to load " + type_str + " node. " +
572 change.location().ToString() + ", ";
573 if (result == syncer::BaseNode::INIT_FAILED_PRECONDITION) {
574 syncer::SyncError error;
575 error.Reset(FROM_HERE, error_prefix + "empty tag", type_);
576 error_handler()->OnSingleDataTypeUnrecoverableError(error);
577 LOG(ERROR) << "Update: Empty tag.";
578 return error;
579 } else if (result == syncer::BaseNode::INIT_FAILED_ENTRY_NOT_GOOD) {
580 syncer::SyncError error;
581 error.Reset(FROM_HERE, error_prefix + "bad entry", type_);
582 error_handler()->OnSingleDataTypeUnrecoverableError(error);
583 LOG(ERROR) << "Update: bad entry.";
584 return error;
585 } else if (result == syncer::BaseNode::INIT_FAILED_ENTRY_IS_DEL) {
586 syncer::SyncError error;
587 error.Reset(FROM_HERE, error_prefix + "deleted entry", type_);
588 error_handler()->OnSingleDataTypeUnrecoverableError(error);
589 LOG(ERROR) << "Update: deleted entry.";
590 return error;
591 } else {
592 syncer::Cryptographer* crypto = trans.GetCryptographer();
593 syncer::ModelTypeSet encrypted_types(trans.GetEncryptedTypes());
594 const sync_pb::EntitySpecifics& specifics =
595 sync_node->GetEntry()->GetSpecifics();
596 CHECK(specifics.has_encrypted());
597 const bool can_decrypt = crypto->CanDecrypt(specifics.encrypted());
598 const bool agreement = encrypted_types.Has(type_);
599 if (!agreement && !can_decrypt) {
600 syncer::SyncError error;
601 error.Reset(FROM_HERE,
602 "Failed to load encrypted entry, missing key and "
603 "nigori mismatch for " +
604 type_str + ".",
605 type_);
606 error_handler()->OnSingleDataTypeUnrecoverableError(error);
607 LOG(ERROR) << "Update: encr case 1.";
608 return error;
609 } else if (agreement && can_decrypt) {
610 syncer::SyncError error;
611 error.Reset(FROM_HERE,
612 "Failed to load encrypted entry, we have the key "
613 "and the nigori matches (?!) for " +
614 type_str + ".",
615 type_);
616 error_handler()->OnSingleDataTypeUnrecoverableError(error);
617 LOG(ERROR) << "Update: encr case 2.";
618 return error;
619 } else if (agreement) {
620 syncer::SyncError error;
621 error.Reset(FROM_HERE,
622 "Failed to load encrypted entry, missing key and "
623 "the nigori matches for " +
624 type_str + ".",
625 type_);
626 error_handler()->OnSingleDataTypeUnrecoverableError(error);
627 LOG(ERROR) << "Update: encr case 3.";
628 return error;
629 } else {
630 syncer::SyncError error;
631 error.Reset(FROM_HERE,
632 "Failed to load encrypted entry, we have the key"
633 "(?!) and nigori mismatch for " +
634 type_str + ".",
635 type_);
636 error_handler()->OnSingleDataTypeUnrecoverableError(error);
637 LOG(ERROR) << "Update: encr case 4.";
638 return error;
643 sync_node->SetTitle(change.sync_data().GetTitle());
644 SetNodeSpecifics(sync_data_local.GetSpecifics(), sync_node);
645 syncer::AttachmentIdList attachment_ids = sync_data_local.GetAttachmentIds();
646 SetAttachmentMetadata(attachment_ids, sync_node);
648 // Return any newly added attachments.
649 new_attachments->insert(attachment_ids.begin(), attachment_ids.end());
651 if (merge_result_.get()) {
652 merge_result_->set_num_items_modified(merge_result_->num_items_modified() +
655 // TODO(sync): Support updating other parts of the sync node (title,
656 // successor, parent, etc.).
657 return syncer::SyncError();
660 bool GenericChangeProcessor::SyncModelHasUserCreatedNodes(bool* has_nodes) {
661 DCHECK(CalledOnValidThread());
662 DCHECK(has_nodes);
663 std::string type_name = syncer::ModelTypeToString(type_);
664 std::string err_str = "Server did not create the top-level " + type_name +
665 " node. We might be running against an out-of-date server.";
666 *has_nodes = false;
667 syncer::ReadTransaction trans(FROM_HERE, share_handle());
668 syncer::ReadNode type_root_node(&trans);
669 if (type_root_node.InitTypeRoot(type_) != syncer::BaseNode::INIT_OK) {
670 LOG(ERROR) << err_str;
671 return false;
674 // The sync model has user created nodes if the type's root node has any
675 // children.
676 *has_nodes = type_root_node.HasChildren();
677 return true;
680 bool GenericChangeProcessor::CryptoReadyIfNecessary() {
681 DCHECK(CalledOnValidThread());
682 // We only access the cryptographer while holding a transaction.
683 syncer::ReadTransaction trans(FROM_HERE, share_handle());
684 const syncer::ModelTypeSet encrypted_types = trans.GetEncryptedTypes();
685 return !encrypted_types.Has(type_) || trans.GetCryptographer()->is_ready();
688 void GenericChangeProcessor::StartImpl() {
691 syncer::UserShare* GenericChangeProcessor::share_handle() const {
692 DCHECK(CalledOnValidThread());
693 return share_handle_;
696 void GenericChangeProcessor::UploadAllAttachmentsNotOnServer() {
697 DCHECK(CalledOnValidThread());
698 DCHECK(attachment_service_.get());
699 syncer::AttachmentIdList ids;
701 syncer::ReadTransaction trans(FROM_HERE, share_handle());
702 trans.GetAttachmentIdsToUpload(type_, &ids);
704 if (!ids.empty()) {
705 attachment_service_->UploadAttachments(ids);
709 scoped_ptr<syncer::AttachmentService>
710 GenericChangeProcessor::GetAttachmentService() const {
711 return scoped_ptr<syncer::AttachmentService>(
712 new syncer::AttachmentServiceProxy(attachment_service_proxy_));
715 } // namespace sync_driver