Updating trunk VERSION from 2139.0 to 2140.0
[chromium-blink-merge.git] / components / sync_driver / generic_change_processor.cc
blobc44ce72a1bd23d1fa5a8e377c50903bc9ef83a6a
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 {
25 namespace {
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) ==
32 syncer::PASSWORDS) {
33 write_node->SetPasswordSpecifics(
34 entity_specifics.password().client_only_encrypted_data());
35 } else {
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();
45 return record;
48 // Replace |write_nodes|'s attachment ids with |attachment_ids|.
49 void SetAttachmentMetadata(const syncer::AttachmentIdList& attachment_ids,
50 syncer::WriteNode* write_node) {
51 DCHECK(write_node);
52 sync_pb::AttachmentMetadata attachment_metadata;
53 std::transform(
54 attachment_ids.begin(),
55 attachment_ids.end(),
56 RepeatedFieldBackInserter(attachment_metadata.mutable_record()),
57 AttachmentIdToRecord);
58 write_node->SetAttachmentMetadata(attachment_metadata);
61 syncer::SyncData BuildRemoteSyncData(
62 int64 sync_id,
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(),
72 attachment_ids,
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,
82 password_holder,
83 read_node.GetModificationTime(),
84 attachment_ids,
85 attachment_service_proxy);
88 } // namespace
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),
100 attachment_service_(
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,
116 int64 model_version,
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(
135 it->id,
136 specifics ? *specifics : it->specifics,
137 base::Time(),
138 empty_list_of_attachment_ids,
139 attachment_service_proxy_)));
140 } else {
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(
148 FROM_HERE,
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);
154 return;
156 syncer_changes_.push_back(syncer::SyncChange(
157 FROM_HERE,
158 action,
159 BuildRemoteSyncData(it->id, read_node, attachment_service_proxy_)));
164 void GenericChangeProcessor::CommitChangesFromSyncModel() {
165 DCHECK(CalledOnValidThread());
166 if (syncer_changes_.empty())
167 return;
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.",
173 type);
174 error_handler()->OnSingleDataTypeUnrecoverableError(error);
175 return;
177 syncer::SyncError error = local_service_->ProcessSyncChanges(FROM_HERE,
178 syncer_changes_);
179 syncer_changes_.clear();
180 if (error.IsSet())
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);
189 return 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.",
202 type);
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-"
232 "date server.",
233 type);
234 return error;
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 " +
251 type_name + ".",
252 type);
253 return error;
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())
267 return false;
269 DCHECK_EQ(type,
270 syncer::GetModelTypeFromSpecificsFieldNumber(
271 context_proto.data_type_id()));
272 *context = context_proto.context();
273 return true;
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)
280 return 0;
282 // Subtract one to account for type's root node.
283 return root.GetTotalNodeCount() - 1;
286 namespace {
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,
302 error_prefix +
303 "could not find entry matching the lookup criteria.",
304 type);
305 error_handler->OnSingleDataTypeUnrecoverableError(error);
306 LOG(ERROR) << "Delete: Bad entry.";
307 return error;
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.";
314 return error;
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.";
321 return error;
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.",
327 type);
328 error_handler->OnSingleDataTypeUnrecoverableError(error);
329 LOG(ERROR) << "Delete: Failed precondition.";
330 return error;
332 default: {
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.";
338 return 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();
351 if (tag.empty()) {
352 syncer::SyncError error(
353 FROM_HERE,
354 syncer::SyncError::DATATYPE_ERROR,
355 "Failed to delete " + type_str + " node. Local data, empty tag. " +
356 change.location().ToString(),
357 type);
358 error_handler->OnSingleDataTypeUnrecoverableError(error);
359 NOTREACHED();
360 return error;
363 syncer::BaseNode::InitByLookupResult result =
364 node->InitByClientTagLookup(change.sync_data().GetDataType(), tag);
365 if (result != syncer::BaseNode::INIT_OK) {
366 return LogLookupFailure(
367 result, FROM_HERE,
368 "Failed to delete " + type_str + " node. Local data. " +
369 change.location().ToString(),
370 type, error_handler);
372 } else {
373 syncer::BaseNode::InitByLookupResult result = node->InitByIdLookup(
374 syncer::SyncDataRemote(change.sync_data()).GetId());
375 if (result != syncer::BaseNode::INIT_OK) {
376 return LogLookupFailure(
377 result, FROM_HERE,
378 "Failed to delete " + type_str + " node. Non-local data. " +
379 change.location().ToString(),
380 type, error_handler);
383 if (IsActOnceDataType(type))
384 node->Drop();
385 else
386 node->Tombstone();
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
398 // ids (bug 368353).
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);
409 } // namespace
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();
424 ++iter) {
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());
433 if (error.IsSet()) {
434 NOTREACHED();
435 return error;
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);
444 if (error.IsSet()) {
445 return error;
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);
450 if (error.IsSet()) {
451 return error;
453 } else {
454 syncer::SyncError error(
455 FROM_HERE,
456 syncer::SyncError::DATATYPE_ERROR,
457 "Received unset SyncChange in the change processor, " +
458 change.location().ToString(),
459 type);
460 error_handler()->OnSingleDataTypeUnrecoverableError(error);
461 NOTREACHED();
462 LOG(ERROR) << "Unset sync change.";
463 return error;
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,
486 // etc.).
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,
494 type);
495 error_handler()->OnSingleDataTypeUnrecoverableError(error);
496 NOTREACHED();
497 LOG(ERROR) << "Create: no root node.";
498 return error;
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() + ", ";
506 switch (result) {
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.";
512 return error;
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.";
519 return error;
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.";
526 return error;
528 case syncer::WriteNode::INIT_FAILED_SET_PREDECESSOR: {
529 syncer::SyncError error;
530 error.Reset(
531 FROM_HERE, error_prefix + "failed to set predecessor", type);
532 error_handler()->OnSingleDataTypeUnrecoverableError(error);
533 LOG(ERROR) << "Create: Bad predecessor.";
534 return error;
536 default: {
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.";
541 return 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.";
588 return error;
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.";
594 return error;
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.";
600 return error;
601 } else {
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 " +
614 type_str + ".",
615 type);
616 error_handler()->OnSingleDataTypeUnrecoverableError(error);
617 LOG(ERROR) << "Update: encr case 1.";
618 return error;
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 " +
624 type_str + ".",
625 type);
626 error_handler()->OnSingleDataTypeUnrecoverableError(error);
627 LOG(ERROR) << "Update: encr case 2.";
628 return error;
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 " +
634 type_str + ".",
635 type);
636 error_handler()->OnSingleDataTypeUnrecoverableError(error);
637 LOG(ERROR) << "Update: encr case 3.";
638 return error;
639 } else {
640 syncer::SyncError error;
641 error.Reset(FROM_HERE,
642 "Failed to load encrypted entry, we have the key"
643 "(?!) and nigori mismatch for " +
644 type_str + ".",
645 type);
646 error_handler()->OnSingleDataTypeUnrecoverableError(error);
647 LOG(ERROR) << "Update: encr case 4.";
648 return error;
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,
675 bool* has_nodes) {
676 DCHECK(CalledOnValidThread());
677 DCHECK(has_nodes);
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.";
682 *has_nodes = false;
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;
687 return false;
690 // The sync model has user created nodes if the type's root node has any
691 // children.
692 *has_nodes = type_root_node.HasChildren();
693 return true;
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