Try to work around that clang/win bug in another file.
[chromium-blink-merge.git] / components / sync_driver / generic_change_processor.cc
blob114c6554ab9748bd850cbc4bc63b321f3fe6b3b8
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 "sync/api/sync_change.h"
13 #include "sync/api/sync_error.h"
14 #include "sync/api/syncable_service.h"
15 #include "sync/internal_api/public/base_node.h"
16 #include "sync/internal_api/public/change_record.h"
17 #include "sync/internal_api/public/read_node.h"
18 #include "sync/internal_api/public/read_transaction.h"
19 #include "sync/internal_api/public/util/unrecoverable_error_handler.h"
20 #include "sync/internal_api/public/write_node.h"
21 #include "sync/internal_api/public/write_transaction.h"
22 #include "sync/syncable/entry.h" // TODO(tim): Bug 123674.
24 namespace sync_driver {
26 namespace {
28 const int kContextSizeLimit = 1024; // Datatype context size limit.
30 void SetNodeSpecifics(const sync_pb::EntitySpecifics& entity_specifics,
31 syncer::WriteNode* write_node) {
32 if (syncer::GetModelTypeFromSpecifics(entity_specifics) ==
33 syncer::PASSWORDS) {
34 write_node->SetPasswordSpecifics(
35 entity_specifics.password().client_only_encrypted_data());
36 } else {
37 write_node->SetEntitySpecifics(entity_specifics);
41 // Helper function to convert AttachmentId to AttachmentMetadataRecord.
42 sync_pb::AttachmentMetadataRecord AttachmentIdToRecord(
43 const syncer::AttachmentId& attachment_id) {
44 sync_pb::AttachmentMetadataRecord record;
45 *record.mutable_id() = attachment_id.GetProto();
46 return record;
49 // Replace |write_nodes|'s attachment ids with |attachment_ids|.
50 void SetAttachmentMetadata(const syncer::AttachmentIdList& attachment_ids,
51 syncer::WriteNode* write_node) {
52 DCHECK(write_node);
53 sync_pb::AttachmentMetadata attachment_metadata;
54 std::transform(
55 attachment_ids.begin(),
56 attachment_ids.end(),
57 RepeatedFieldBackInserter(attachment_metadata.mutable_record()),
58 AttachmentIdToRecord);
59 write_node->SetAttachmentMetadata(attachment_metadata);
62 syncer::SyncData BuildRemoteSyncData(
63 int64 sync_id,
64 const syncer::BaseNode& read_node,
65 const syncer::AttachmentServiceProxy& attachment_service_proxy) {
66 const syncer::AttachmentIdList& attachment_ids = read_node.GetAttachmentIds();
67 // Use the specifics of non-password datatypes directly (encryption has
68 // already been handled).
69 if (read_node.GetModelType() != syncer::PASSWORDS) {
70 return syncer::SyncData::CreateRemoteData(sync_id,
71 read_node.GetEntitySpecifics(),
72 read_node.GetModificationTime(),
73 attachment_ids,
74 attachment_service_proxy);
77 // Passwords must be accessed differently, to account for their encryption,
78 // and stored into a temporary EntitySpecifics.
79 sync_pb::EntitySpecifics password_holder;
80 password_holder.mutable_password()->mutable_client_only_encrypted_data()->
81 CopyFrom(read_node.GetPasswordSpecifics());
82 return syncer::SyncData::CreateRemoteData(sync_id,
83 password_holder,
84 read_node.GetModificationTime(),
85 attachment_ids,
86 attachment_service_proxy);
89 } // namespace
91 GenericChangeProcessor::GenericChangeProcessor(
92 syncer::ModelType type,
93 DataTypeErrorHandler* error_handler,
94 const base::WeakPtr<syncer::SyncableService>& local_service,
95 const base::WeakPtr<syncer::SyncMergeResult>& merge_result,
96 syncer::UserShare* user_share,
97 SyncApiComponentFactory* sync_factory,
98 scoped_ptr<syncer::AttachmentStoreForSync> attachment_store)
99 : ChangeProcessor(error_handler),
100 type_(type),
101 local_service_(local_service),
102 merge_result_(merge_result),
103 share_handle_(user_share),
104 weak_ptr_factory_(this) {
105 DCHECK(CalledOnValidThread());
106 DCHECK_NE(type_, syncer::UNSPECIFIED);
107 if (attachment_store) {
108 std::string store_birthday;
110 syncer::ReadTransaction trans(FROM_HERE, share_handle());
111 store_birthday = trans.GetStoreBirthday();
113 attachment_service_ = sync_factory->CreateAttachmentService(
114 attachment_store.Pass(), *user_share, store_birthday, type, this);
115 attachment_service_weak_ptr_factory_.reset(
116 new base::WeakPtrFactory<syncer::AttachmentService>(
117 attachment_service_.get()));
118 attachment_service_proxy_ = syncer::AttachmentServiceProxy(
119 base::ThreadTaskRunnerHandle::Get(),
120 attachment_service_weak_ptr_factory_->GetWeakPtr());
121 UploadAllAttachmentsNotOnServer();
122 } else {
123 attachment_service_proxy_ = syncer::AttachmentServiceProxy(
124 base::ThreadTaskRunnerHandle::Get(),
125 base::WeakPtr<syncer::AttachmentService>());
129 GenericChangeProcessor::~GenericChangeProcessor() {
130 DCHECK(CalledOnValidThread());
133 void GenericChangeProcessor::ApplyChangesFromSyncModel(
134 const syncer::BaseTransaction* trans,
135 int64 model_version,
136 const syncer::ImmutableChangeRecordList& changes) {
137 DCHECK(CalledOnValidThread());
138 DCHECK(syncer_changes_.empty());
139 for (syncer::ChangeRecordList::const_iterator it =
140 changes.Get().begin(); it != changes.Get().end(); ++it) {
141 if (it->action == syncer::ChangeRecord::ACTION_DELETE) {
142 scoped_ptr<sync_pb::EntitySpecifics> specifics;
143 if (it->specifics.has_password()) {
144 DCHECK(it->extra.get());
145 specifics.reset(new sync_pb::EntitySpecifics(it->specifics));
146 specifics->mutable_password()->mutable_client_only_encrypted_data()->
147 CopyFrom(it->extra->unencrypted());
149 const syncer::AttachmentIdList empty_list_of_attachment_ids;
150 syncer_changes_.push_back(syncer::SyncChange(
151 FROM_HERE, syncer::SyncChange::ACTION_DELETE,
152 syncer::SyncData::CreateRemoteData(
153 it->id, specifics ? *specifics : it->specifics, base::Time(),
154 empty_list_of_attachment_ids, attachment_service_proxy_)));
155 } else {
156 syncer::SyncChange::SyncChangeType action =
157 (it->action == syncer::ChangeRecord::ACTION_ADD) ?
158 syncer::SyncChange::ACTION_ADD : syncer::SyncChange::ACTION_UPDATE;
159 // Need to load specifics from node.
160 syncer::ReadNode read_node(trans);
161 if (read_node.InitByIdLookup(it->id) != syncer::BaseNode::INIT_OK) {
162 syncer::SyncError error(
163 FROM_HERE,
164 syncer::SyncError::DATATYPE_ERROR,
165 "Failed to look up data for received change with id " +
166 base::Int64ToString(it->id),
167 syncer::GetModelTypeFromSpecifics(it->specifics));
168 error_handler()->OnSingleDataTypeUnrecoverableError(error);
169 return;
171 syncer_changes_.push_back(syncer::SyncChange(
172 FROM_HERE, action,
173 BuildRemoteSyncData(it->id, read_node, attachment_service_proxy_)));
178 void GenericChangeProcessor::CommitChangesFromSyncModel() {
179 DCHECK(CalledOnValidThread());
180 if (syncer_changes_.empty())
181 return;
182 if (!local_service_.get()) {
183 syncer::ModelType type = syncer_changes_[0].sync_data().GetDataType();
184 syncer::SyncError error(FROM_HERE,
185 syncer::SyncError::DATATYPE_ERROR,
186 "Local service destroyed.",
187 type);
188 error_handler()->OnSingleDataTypeUnrecoverableError(error);
189 return;
191 syncer::SyncError error = local_service_->ProcessSyncChanges(FROM_HERE,
192 syncer_changes_);
193 syncer_changes_.clear();
194 if (error.IsSet())
195 error_handler()->OnSingleDataTypeUnrecoverableError(error);
198 syncer::SyncDataList GenericChangeProcessor::GetAllSyncData(
199 syncer::ModelType type) const {
200 DCHECK_EQ(type_, type);
201 // This is slow / memory intensive. Should be used sparingly by datatypes.
202 syncer::SyncDataList data;
203 GetAllSyncDataReturnError(&data);
204 return data;
207 syncer::SyncError GenericChangeProcessor::UpdateDataTypeContext(
208 syncer::ModelType type,
209 syncer::SyncChangeProcessor::ContextRefreshStatus refresh_status,
210 const std::string& context) {
211 DCHECK(syncer::ProtocolTypes().Has(type));
212 DCHECK_EQ(type_, type);
214 if (context.size() > static_cast<size_t>(kContextSizeLimit)) {
215 return syncer::SyncError(FROM_HERE,
216 syncer::SyncError::DATATYPE_ERROR,
217 "Context size limit exceeded.",
218 type);
221 syncer::WriteTransaction trans(FROM_HERE, share_handle());
222 trans.SetDataTypeContext(type, refresh_status, context);
224 // TODO(zea): plumb a pointer to the PSS or SyncManagerImpl here so we can
225 // trigger a datatype nudge if |refresh_status == REFRESH_NEEDED|.
227 return syncer::SyncError();
230 void GenericChangeProcessor::OnAttachmentUploaded(
231 const syncer::AttachmentId& attachment_id) {
232 syncer::WriteTransaction trans(FROM_HERE, share_handle());
233 trans.UpdateEntriesMarkAttachmentAsOnServer(attachment_id);
236 syncer::SyncError GenericChangeProcessor::GetAllSyncDataReturnError(
237 syncer::SyncDataList* current_sync_data) const {
238 DCHECK(CalledOnValidThread());
239 std::string type_name = syncer::ModelTypeToString(type_);
240 syncer::ReadTransaction trans(FROM_HERE, share_handle());
241 syncer::ReadNode root(&trans);
242 if (root.InitTypeRoot(type_) != syncer::BaseNode::INIT_OK) {
243 syncer::SyncError error(FROM_HERE,
244 syncer::SyncError::DATATYPE_ERROR,
245 "Server did not create the top-level " + type_name +
246 " node. We might be running against an out-of-"
247 "date server.",
248 type_);
249 return error;
252 // TODO(akalin): We'll have to do a tree traversal for bookmarks.
253 DCHECK_NE(type_, syncer::BOOKMARKS);
255 std::vector<int64> child_ids;
256 root.GetChildIds(&child_ids);
258 for (std::vector<int64>::iterator it = child_ids.begin();
259 it != child_ids.end(); ++it) {
260 syncer::ReadNode sync_child_node(&trans);
261 if (sync_child_node.InitByIdLookup(*it) !=
262 syncer::BaseNode::INIT_OK) {
263 syncer::SyncError error(
264 FROM_HERE,
265 syncer::SyncError::DATATYPE_ERROR,
266 "Failed to fetch child node for type " + type_name + ".",
267 type_);
268 return error;
270 current_sync_data->push_back(BuildRemoteSyncData(
271 sync_child_node.GetId(), sync_child_node, attachment_service_proxy_));
273 return syncer::SyncError();
276 bool GenericChangeProcessor::GetDataTypeContext(std::string* context) const {
277 syncer::ReadTransaction trans(FROM_HERE, share_handle());
278 sync_pb::DataTypeContext context_proto;
279 trans.GetDataTypeContext(type_, &context_proto);
280 if (!context_proto.has_context())
281 return false;
283 DCHECK_EQ(type_,
284 syncer::GetModelTypeFromSpecificsFieldNumber(
285 context_proto.data_type_id()));
286 *context = context_proto.context();
287 return true;
290 int GenericChangeProcessor::GetSyncCount() {
291 syncer::ReadTransaction trans(FROM_HERE, share_handle());
292 syncer::ReadNode root(&trans);
293 if (root.InitTypeRoot(type_) != syncer::BaseNode::INIT_OK)
294 return 0;
296 // Subtract one to account for type's root node.
297 return root.GetTotalNodeCount() - 1;
300 namespace {
302 // WARNING: this code is sensitive to compiler optimizations. Be careful
303 // modifying any code around an OnSingleDataTypeUnrecoverableError call, else
304 // the compiler attempts to merge it with other calls, losing useful information
305 // in breakpad uploads.
306 syncer::SyncError LogLookupFailure(
307 syncer::BaseNode::InitByLookupResult lookup_result,
308 const tracked_objects::Location& from_here,
309 const std::string& error_prefix,
310 syncer::ModelType type,
311 DataTypeErrorHandler* error_handler) {
312 switch (lookup_result) {
313 case syncer::BaseNode::INIT_FAILED_ENTRY_NOT_GOOD: {
314 syncer::SyncError error;
315 error.Reset(from_here,
316 error_prefix +
317 "could not find entry matching the lookup criteria.",
318 type);
319 error_handler->OnSingleDataTypeUnrecoverableError(error);
320 LOG(ERROR) << "Delete: Bad entry.";
321 return error;
323 case syncer::BaseNode::INIT_FAILED_ENTRY_IS_DEL: {
324 syncer::SyncError error;
325 error.Reset(from_here, error_prefix + "entry is already deleted.", type);
326 error_handler->OnSingleDataTypeUnrecoverableError(error);
327 LOG(ERROR) << "Delete: Deleted entry.";
328 return error;
330 case syncer::BaseNode::INIT_FAILED_DECRYPT_IF_NECESSARY: {
331 syncer::SyncError error;
332 error.Reset(from_here, error_prefix + "unable to decrypt", type);
333 error_handler->OnSingleDataTypeUnrecoverableError(error);
334 LOG(ERROR) << "Delete: Undecryptable entry.";
335 return error;
337 case syncer::BaseNode::INIT_FAILED_PRECONDITION: {
338 syncer::SyncError error;
339 error.Reset(from_here,
340 error_prefix + "a precondition was not met for calling init.",
341 type);
342 error_handler->OnSingleDataTypeUnrecoverableError(error);
343 LOG(ERROR) << "Delete: Failed precondition.";
344 return error;
346 default: {
347 syncer::SyncError error;
348 // Should have listed all the possible error cases above.
349 error.Reset(from_here, error_prefix + "unknown error", type);
350 error_handler->OnSingleDataTypeUnrecoverableError(error);
351 LOG(ERROR) << "Delete: Unknown error.";
352 return error;
357 syncer::SyncError AttemptDelete(const syncer::SyncChange& change,
358 syncer::ModelType type,
359 const std::string& type_str,
360 syncer::WriteNode* node,
361 DataTypeErrorHandler* error_handler) {
362 DCHECK_EQ(change.change_type(), syncer::SyncChange::ACTION_DELETE);
363 if (change.sync_data().IsLocal()) {
364 const std::string& tag = syncer::SyncDataLocal(change.sync_data()).GetTag();
365 if (tag.empty()) {
366 syncer::SyncError error(
367 FROM_HERE,
368 syncer::SyncError::DATATYPE_ERROR,
369 "Failed to delete " + type_str + " node. Local data, empty tag. " +
370 change.location().ToString(),
371 type);
372 error_handler->OnSingleDataTypeUnrecoverableError(error);
373 NOTREACHED();
374 return error;
377 syncer::BaseNode::InitByLookupResult result =
378 node->InitByClientTagLookup(change.sync_data().GetDataType(), tag);
379 if (result != syncer::BaseNode::INIT_OK) {
380 return LogLookupFailure(
381 result, FROM_HERE,
382 "Failed to delete " + type_str + " node. Local data. " +
383 change.location().ToString(),
384 type, error_handler);
386 } else {
387 syncer::BaseNode::InitByLookupResult result = node->InitByIdLookup(
388 syncer::SyncDataRemote(change.sync_data()).GetId());
389 if (result != syncer::BaseNode::INIT_OK) {
390 return LogLookupFailure(
391 result, FROM_HERE,
392 "Failed to delete " + type_str + " node. Non-local data. " +
393 change.location().ToString(),
394 type, error_handler);
397 if (IsActOnceDataType(type))
398 node->Drop();
399 else
400 node->Tombstone();
401 return syncer::SyncError();
404 } // namespace
406 syncer::SyncError GenericChangeProcessor::ProcessSyncChanges(
407 const tracked_objects::Location& from_here,
408 const syncer::SyncChangeList& list_of_changes) {
409 DCHECK(CalledOnValidThread());
411 // Keep track of brand new attachments so we can persist them on this device
412 // and upload them to the server.
413 syncer::AttachmentIdSet new_attachments;
415 syncer::WriteTransaction trans(from_here, share_handle());
417 for (syncer::SyncChangeList::const_iterator iter = list_of_changes.begin();
418 iter != list_of_changes.end();
419 ++iter) {
420 const syncer::SyncChange& change = *iter;
421 DCHECK_EQ(change.sync_data().GetDataType(), type_);
422 std::string type_str = syncer::ModelTypeToString(type_);
423 syncer::WriteNode sync_node(&trans);
424 if (change.change_type() == syncer::SyncChange::ACTION_DELETE) {
425 syncer::SyncError error =
426 AttemptDelete(change, type_, type_str, &sync_node, error_handler());
427 if (error.IsSet()) {
428 NOTREACHED();
429 return error;
431 if (merge_result_.get()) {
432 merge_result_->set_num_items_deleted(
433 merge_result_->num_items_deleted() + 1);
435 } else if (change.change_type() == syncer::SyncChange::ACTION_ADD) {
436 syncer::SyncError error = HandleActionAdd(
437 change, type_str, trans, &sync_node, &new_attachments);
438 if (error.IsSet()) {
439 return error;
441 } else if (change.change_type() == syncer::SyncChange::ACTION_UPDATE) {
442 syncer::SyncError error = HandleActionUpdate(
443 change, type_str, trans, &sync_node, &new_attachments);
444 if (error.IsSet()) {
445 return error;
447 } else {
448 syncer::SyncError error(
449 FROM_HERE,
450 syncer::SyncError::DATATYPE_ERROR,
451 "Received unset SyncChange in the change processor, " +
452 change.location().ToString(),
453 type_);
454 error_handler()->OnSingleDataTypeUnrecoverableError(error);
455 NOTREACHED();
456 LOG(ERROR) << "Unset sync change.";
457 return error;
461 if (!new_attachments.empty()) {
462 // If datatype uses attachments it should have supplied attachment store
463 // which would initialize attachment_service_. Fail if it isn't so.
464 if (!attachment_service_.get()) {
465 syncer::SyncError error(
466 FROM_HERE,
467 syncer::SyncError::DATATYPE_ERROR,
468 "Datatype performs attachment operation without initializing "
469 "attachment store",
470 type_);
471 error_handler()->OnSingleDataTypeUnrecoverableError(error);
472 NOTREACHED();
473 return error;
475 syncer::AttachmentIdList ids_to_upload;
476 ids_to_upload.reserve(new_attachments.size());
477 std::copy(new_attachments.begin(), new_attachments.end(),
478 std::back_inserter(ids_to_upload));
479 attachment_service_->UploadAttachments(ids_to_upload);
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,
496 // etc.).
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,
504 type_);
505 error_handler()->OnSingleDataTypeUnrecoverableError(error);
506 NOTREACHED();
507 LOG(ERROR) << "Create: no root node.";
508 return error;
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() + ", ";
516 switch (result) {
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.";
522 return error;
524 case syncer::WriteNode::INIT_FAILED_COULD_NOT_CREATE_ENTRY: {
525 syncer::SyncError error;
526 error.Reset(FROM_HERE, error_prefix + "failed to create entry", type_);
527 error_handler()->OnSingleDataTypeUnrecoverableError(error);
528 LOG(ERROR) << "Create: Could not create entry.";
529 return error;
531 case syncer::WriteNode::INIT_FAILED_SET_PREDECESSOR: {
532 syncer::SyncError error;
533 error.Reset(
534 FROM_HERE, error_prefix + "failed to set predecessor", type_);
535 error_handler()->OnSingleDataTypeUnrecoverableError(error);
536 LOG(ERROR) << "Create: Bad predecessor.";
537 return error;
539 default: {
540 syncer::SyncError error;
541 error.Reset(FROM_HERE, error_prefix + "unknown error", type_);
542 error_handler()->OnSingleDataTypeUnrecoverableError(error);
543 LOG(ERROR) << "Create: Unknown error.";
544 return error;
548 sync_node->SetTitle(change.sync_data().GetTitle());
549 SetNodeSpecifics(sync_data_local.GetSpecifics(), sync_node);
551 syncer::AttachmentIdList attachment_ids = sync_data_local.GetAttachmentIds();
552 SetAttachmentMetadata(attachment_ids, sync_node);
554 // Return any newly added attachments.
555 new_attachments->insert(attachment_ids.begin(), attachment_ids.end());
556 if (merge_result_.get()) {
557 merge_result_->set_num_items_added(merge_result_->num_items_added() + 1);
559 return syncer::SyncError();
561 // WARNING: this code is sensitive to compiler optimizations. Be careful
562 // modifying any code around an OnSingleDataTypeUnrecoverableError call, else
563 // the compiler attempts to merge it with other calls, losing useful information
564 // in breakpad uploads.
565 syncer::SyncError GenericChangeProcessor::HandleActionUpdate(
566 const syncer::SyncChange& change,
567 const std::string& type_str,
568 const syncer::WriteTransaction& trans,
569 syncer::WriteNode* sync_node,
570 syncer::AttachmentIdSet* new_attachments) {
571 const syncer::SyncDataLocal sync_data_local(change.sync_data());
572 syncer::BaseNode::InitByLookupResult result =
573 sync_node->InitByClientTagLookup(sync_data_local.GetDataType(),
574 sync_data_local.GetTag());
575 if (result != syncer::BaseNode::INIT_OK) {
576 std::string error_prefix = "Failed to load " + type_str + " node. " +
577 change.location().ToString() + ", ";
578 if (result == syncer::BaseNode::INIT_FAILED_PRECONDITION) {
579 syncer::SyncError error;
580 error.Reset(FROM_HERE, error_prefix + "empty tag", type_);
581 error_handler()->OnSingleDataTypeUnrecoverableError(error);
582 LOG(ERROR) << "Update: Empty tag.";
583 return error;
584 } else if (result == syncer::BaseNode::INIT_FAILED_ENTRY_NOT_GOOD) {
585 syncer::SyncError error;
586 error.Reset(FROM_HERE, error_prefix + "bad entry", type_);
587 error_handler()->OnSingleDataTypeUnrecoverableError(error);
588 LOG(ERROR) << "Update: bad entry.";
589 return error;
590 } else if (result == syncer::BaseNode::INIT_FAILED_ENTRY_IS_DEL) {
591 syncer::SyncError error;
592 error.Reset(FROM_HERE, error_prefix + "deleted entry", type_);
593 error_handler()->OnSingleDataTypeUnrecoverableError(error);
594 LOG(ERROR) << "Update: deleted entry.";
595 return error;
596 } else {
597 syncer::Cryptographer* crypto = trans.GetCryptographer();
598 syncer::ModelTypeSet encrypted_types(trans.GetEncryptedTypes());
599 const sync_pb::EntitySpecifics& specifics =
600 sync_node->GetEntry()->GetSpecifics();
601 CHECK(specifics.has_encrypted());
602 const bool can_decrypt = crypto->CanDecrypt(specifics.encrypted());
603 const bool agreement = encrypted_types.Has(type_);
604 if (!agreement && !can_decrypt) {
605 syncer::SyncError error;
606 error.Reset(FROM_HERE,
607 "Failed to load encrypted entry, missing key and "
608 "nigori mismatch for " +
609 type_str + ".",
610 type_);
611 error_handler()->OnSingleDataTypeUnrecoverableError(error);
612 LOG(ERROR) << "Update: encr case 1.";
613 return error;
614 } else if (agreement && can_decrypt) {
615 syncer::SyncError error;
616 error.Reset(FROM_HERE,
617 "Failed to load encrypted entry, we have the key "
618 "and the nigori matches (?!) for " +
619 type_str + ".",
620 type_);
621 error_handler()->OnSingleDataTypeUnrecoverableError(error);
622 LOG(ERROR) << "Update: encr case 2.";
623 return error;
624 } else if (agreement) {
625 syncer::SyncError error;
626 error.Reset(FROM_HERE,
627 "Failed to load encrypted entry, missing key and "
628 "the nigori matches for " +
629 type_str + ".",
630 type_);
631 error_handler()->OnSingleDataTypeUnrecoverableError(error);
632 LOG(ERROR) << "Update: encr case 3.";
633 return error;
634 } else {
635 syncer::SyncError error;
636 error.Reset(FROM_HERE,
637 "Failed to load encrypted entry, we have the key"
638 "(?!) and nigori mismatch for " +
639 type_str + ".",
640 type_);
641 error_handler()->OnSingleDataTypeUnrecoverableError(error);
642 LOG(ERROR) << "Update: encr case 4.";
643 return error;
648 sync_node->SetTitle(change.sync_data().GetTitle());
649 SetNodeSpecifics(sync_data_local.GetSpecifics(), sync_node);
650 syncer::AttachmentIdList attachment_ids = sync_data_local.GetAttachmentIds();
651 SetAttachmentMetadata(attachment_ids, sync_node);
653 // Return any newly added attachments.
654 new_attachments->insert(attachment_ids.begin(), attachment_ids.end());
656 if (merge_result_.get()) {
657 merge_result_->set_num_items_modified(merge_result_->num_items_modified() +
660 // TODO(sync): Support updating other parts of the sync node (title,
661 // successor, parent, etc.).
662 return syncer::SyncError();
665 bool GenericChangeProcessor::SyncModelHasUserCreatedNodes(bool* has_nodes) {
666 DCHECK(CalledOnValidThread());
667 DCHECK(has_nodes);
668 std::string type_name = syncer::ModelTypeToString(type_);
669 std::string err_str = "Server did not create the top-level " + type_name +
670 " node. We might be running against an out-of-date server.";
671 *has_nodes = false;
672 syncer::ReadTransaction trans(FROM_HERE, share_handle());
673 syncer::ReadNode type_root_node(&trans);
674 if (type_root_node.InitTypeRoot(type_) != syncer::BaseNode::INIT_OK) {
675 LOG(ERROR) << err_str;
676 return false;
679 // The sync model has user created nodes if the type's root node has any
680 // children.
681 *has_nodes = type_root_node.HasChildren();
682 return true;
685 bool GenericChangeProcessor::CryptoReadyIfNecessary() {
686 DCHECK(CalledOnValidThread());
687 // We only access the cryptographer while holding a transaction.
688 syncer::ReadTransaction trans(FROM_HERE, share_handle());
689 const syncer::ModelTypeSet encrypted_types = trans.GetEncryptedTypes();
690 return !encrypted_types.Has(type_) || trans.GetCryptographer()->is_ready();
693 void GenericChangeProcessor::StartImpl() {
696 syncer::UserShare* GenericChangeProcessor::share_handle() const {
697 DCHECK(CalledOnValidThread());
698 return share_handle_;
701 void GenericChangeProcessor::UploadAllAttachmentsNotOnServer() {
702 DCHECK(CalledOnValidThread());
703 DCHECK(attachment_service_.get());
704 syncer::AttachmentIdList ids;
706 syncer::ReadTransaction trans(FROM_HERE, share_handle());
707 trans.GetAttachmentIdsToUpload(type_, &ids);
709 if (!ids.empty()) {
710 attachment_service_->UploadAttachments(ids);
714 scoped_ptr<syncer::AttachmentService>
715 GenericChangeProcessor::GetAttachmentService() const {
716 return scoped_ptr<syncer::AttachmentService>(
717 new syncer::AttachmentServiceProxy(attachment_service_proxy_));
720 } // namespace sync_driver