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. 4 5 #include "components/sync_driver/generic_change_processor.h" 6 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. 22 23 namespace browser_sync { 24 25 namespace { 26 27 const int kContextSizeLimit = 1024; // Datatype context size limit. 28 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); 37 } 38 } 39 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; 46 } 47 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); 59 } 60 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); 74 } 75 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); 86 } 87 88 } // namespace 89 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_(sync_factory->CreateAttachmentService(this)), 101 attachment_service_weak_ptr_factory_(attachment_service_.get()), 102 attachment_service_proxy_( 103 base::MessageLoopProxy::current(), 104 attachment_service_weak_ptr_factory_.GetWeakPtr()) { 105 DCHECK(CalledOnValidThread()); 106 DCHECK(attachment_service_); 107 } 108 109 GenericChangeProcessor::~GenericChangeProcessor() { 110 DCHECK(CalledOnValidThread()); 111 } 112 113 void GenericChangeProcessor::ApplyChangesFromSyncModel( 114 const syncer::BaseTransaction* trans, 115 int64 model_version, 116 const syncer::ImmutableChangeRecordList& changes) { 117 DCHECK(CalledOnValidThread()); 118 DCHECK(syncer_changes_.empty()); 119 for (syncer::ChangeRecordList::const_iterator it = 120 changes.Get().begin(); it != changes.Get().end(); ++it) { 121 if (it->action == syncer::ChangeRecord::ACTION_DELETE) { 122 scoped_ptr<sync_pb::EntitySpecifics> specifics; 123 if (it->specifics.has_password()) { 124 DCHECK(it->extra.get()); 125 specifics.reset(new sync_pb::EntitySpecifics(it->specifics)); 126 specifics->mutable_password()->mutable_client_only_encrypted_data()-> 127 CopyFrom(it->extra->unencrypted()); 128 } 129 const syncer::AttachmentIdList empty_list_of_attachment_ids; 130 syncer_changes_.push_back( 131 syncer::SyncChange(FROM_HERE, 132 syncer::SyncChange::ACTION_DELETE, 133 syncer::SyncData::CreateRemoteData( 134 it->id, 135 specifics ? *specifics : it->specifics, 136 base::Time(), 137 empty_list_of_attachment_ids, 138 attachment_service_proxy_))); 139 } else { 140 syncer::SyncChange::SyncChangeType action = 141 (it->action == syncer::ChangeRecord::ACTION_ADD) ? 142 syncer::SyncChange::ACTION_ADD : syncer::SyncChange::ACTION_UPDATE; 143 // Need to load specifics from node. 144 syncer::ReadNode read_node(trans); 145 if (read_node.InitByIdLookup(it->id) != syncer::BaseNode::INIT_OK) { 146 error_handler()->OnSingleDatatypeUnrecoverableError( 147 FROM_HERE, 148 "Failed to look up data for received change with id " + 149 base::Int64ToString(it->id)); 150 return; 151 } 152 syncer_changes_.push_back(syncer::SyncChange( 153 FROM_HERE, 154 action, 155 BuildRemoteSyncData(it->id, read_node, attachment_service_proxy_))); 156 } 157 } 158 } 159 160 void GenericChangeProcessor::CommitChangesFromSyncModel() { 161 DCHECK(CalledOnValidThread()); 162 if (syncer_changes_.empty()) 163 return; 164 if (!local_service_.get()) { 165 syncer::ModelType type = syncer_changes_[0].sync_data().GetDataType(); 166 syncer::SyncError error(FROM_HERE, 167 syncer::SyncError::DATATYPE_ERROR, 168 "Local service destroyed.", 169 type); 170 error_handler()->OnSingleDatatypeUnrecoverableError(error.location(), 171 error.message()); 172 return; 173 } 174 syncer::SyncError error = local_service_->ProcessSyncChanges(FROM_HERE, 175 syncer_changes_); 176 syncer_changes_.clear(); 177 if (error.IsSet()) { 178 error_handler()->OnSingleDatatypeUnrecoverableError( 179 error.location(), error.message()); 180 } 181 } 182 183 syncer::SyncDataList GenericChangeProcessor::GetAllSyncData( 184 syncer::ModelType type) const { 185 // This is slow / memory intensive. Should be used sparingly by datatypes. 186 syncer::SyncDataList data; 187 GetAllSyncDataReturnError(type, &data); 188 return data; 189 } 190 191 syncer::SyncError GenericChangeProcessor::UpdateDataTypeContext( 192 syncer::ModelType type, 193 syncer::SyncChangeProcessor::ContextRefreshStatus refresh_status, 194 const std::string& context) { 195 DCHECK(syncer::ProtocolTypes().Has(type)); 196 197 if (context.size() > static_cast<size_t>(kContextSizeLimit)) { 198 return syncer::SyncError(FROM_HERE, 199 syncer::SyncError::DATATYPE_ERROR, 200 "Context size limit exceeded.", 201 type); 202 } 203 204 syncer::WriteTransaction trans(FROM_HERE, share_handle()); 205 trans.SetDataTypeContext(type, refresh_status, context); 206 207 // TODO(zea): plumb a pointer to the PSS or SyncManagerImpl here so we can 208 // trigger a datatype nudge if |refresh_status == REFRESH_NEEDED|. 209 210 return syncer::SyncError(); 211 } 212 213 void GenericChangeProcessor::OnAttachmentUploaded( 214 const syncer::AttachmentId& attachment_id) { 215 syncer::WriteTransaction trans(FROM_HERE, share_handle()); 216 trans.UpdateEntriesWithAttachmentId(attachment_id); 217 } 218 219 syncer::SyncError GenericChangeProcessor::GetAllSyncDataReturnError( 220 syncer::ModelType type, 221 syncer::SyncDataList* current_sync_data) const { 222 DCHECK(CalledOnValidThread()); 223 std::string type_name = syncer::ModelTypeToString(type); 224 syncer::ReadTransaction trans(FROM_HERE, share_handle()); 225 syncer::ReadNode root(&trans); 226 if (root.InitTypeRoot(type) != syncer::BaseNode::INIT_OK) { 227 syncer::SyncError error(FROM_HERE, 228 syncer::SyncError::DATATYPE_ERROR, 229 "Server did not create the top-level " + type_name + 230 " node. We might be running against an out-of-" 231 "date server.", 232 type); 233 return error; 234 } 235 236 // TODO(akalin): We'll have to do a tree traversal for bookmarks. 237 DCHECK_NE(type, syncer::BOOKMARKS); 238 239 std::vector<int64> child_ids; 240 root.GetChildIds(&child_ids); 241 242 for (std::vector<int64>::iterator it = child_ids.begin(); 243 it != child_ids.end(); ++it) { 244 syncer::ReadNode sync_child_node(&trans); 245 if (sync_child_node.InitByIdLookup(*it) != 246 syncer::BaseNode::INIT_OK) { 247 syncer::SyncError error(FROM_HERE, 248 syncer::SyncError::DATATYPE_ERROR, 249 "Failed to fetch child node for type " + 250 type_name + ".", 251 type); 252 return error; 253 } 254 current_sync_data->push_back(BuildRemoteSyncData( 255 sync_child_node.GetId(), sync_child_node, attachment_service_proxy_)); 256 } 257 return syncer::SyncError(); 258 } 259 260 bool GenericChangeProcessor::GetDataTypeContext(syncer::ModelType type, 261 std::string* context) const { 262 syncer::ReadTransaction trans(FROM_HERE, share_handle()); 263 sync_pb::DataTypeContext context_proto; 264 trans.GetDataTypeContext(type, &context_proto); 265 if (!context_proto.has_context()) 266 return false; 267 268 DCHECK_EQ(type, 269 syncer::GetModelTypeFromSpecificsFieldNumber( 270 context_proto.data_type_id())); 271 *context = context_proto.context(); 272 return true; 273 } 274 275 int GenericChangeProcessor::GetSyncCountForType(syncer::ModelType type) { 276 syncer::ReadTransaction trans(FROM_HERE, share_handle()); 277 syncer::ReadNode root(&trans); 278 if (root.InitTypeRoot(type) != syncer::BaseNode::INIT_OK) 279 return 0; 280 281 // Subtract one to account for type's root node. 282 return root.GetTotalNodeCount() - 1; 283 } 284 285 namespace { 286 287 // TODO(isherman): Investigating http://crbug.com/121592 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(FROM_HERE, 306 error.message()); 307 LOG(ERROR) << "Delete: Bad entry."; 308 return error; 309 } 310 case syncer::BaseNode::INIT_FAILED_ENTRY_IS_DEL: { 311 syncer::SyncError error; 312 error.Reset(from_here, error_prefix + "entry is already deleted.", type); 313 error_handler->OnSingleDatatypeUnrecoverableError(FROM_HERE, 314 error.message()); 315 LOG(ERROR) << "Delete: Deleted entry."; 316 return error; 317 } 318 case syncer::BaseNode::INIT_FAILED_DECRYPT_IF_NECESSARY: { 319 syncer::SyncError error; 320 error.Reset(from_here, error_prefix + "unable to decrypt", type); 321 error_handler->OnSingleDatatypeUnrecoverableError(FROM_HERE, 322 error.message()); 323 LOG(ERROR) << "Delete: Undecryptable entry."; 324 return error; 325 } 326 case syncer::BaseNode::INIT_FAILED_PRECONDITION: { 327 syncer::SyncError error; 328 error.Reset(from_here, 329 error_prefix + "a precondition was not met for calling init.", 330 type); 331 error_handler->OnSingleDatatypeUnrecoverableError(FROM_HERE, 332 error.message()); 333 LOG(ERROR) << "Delete: Failed precondition."; 334 return error; 335 } 336 default: { 337 syncer::SyncError error; 338 // Should have listed all the possible error cases above. 339 error.Reset(from_here, error_prefix + "unknown error", type); 340 error_handler->OnSingleDatatypeUnrecoverableError(FROM_HERE, 341 error.message()); 342 LOG(ERROR) << "Delete: Unknown error."; 343 return error; 344 } 345 } 346 } 347 348 syncer::SyncError AttemptDelete(const syncer::SyncChange& change, 349 syncer::ModelType type, 350 const std::string& type_str, 351 syncer::WriteNode* node, 352 DataTypeErrorHandler* error_handler) { 353 DCHECK_EQ(change.change_type(), syncer::SyncChange::ACTION_DELETE); 354 if (change.sync_data().IsLocal()) { 355 const std::string& tag = syncer::SyncDataLocal(change.sync_data()).GetTag(); 356 if (tag.empty()) { 357 syncer::SyncError error( 358 FROM_HERE, 359 syncer::SyncError::DATATYPE_ERROR, 360 "Failed to delete " + type_str + " node. Local data, empty tag. " + 361 change.location().ToString(), 362 type); 363 error_handler->OnSingleDatatypeUnrecoverableError(error.location(), 364 error.message()); 365 NOTREACHED(); 366 return error; 367 } 368 369 syncer::BaseNode::InitByLookupResult result = 370 node->InitByClientTagLookup(change.sync_data().GetDataType(), tag); 371 if (result != syncer::BaseNode::INIT_OK) { 372 return LogLookupFailure( 373 result, FROM_HERE, 374 "Failed to delete " + type_str + " node. Local data. " + 375 change.location().ToString(), 376 type, error_handler); 377 } 378 } else { 379 syncer::BaseNode::InitByLookupResult result = node->InitByIdLookup( 380 syncer::SyncDataRemote(change.sync_data()).GetId()); 381 if (result != syncer::BaseNode::INIT_OK) { 382 return LogLookupFailure( 383 result, FROM_HERE, 384 "Failed to delete " + type_str + " node. Non-local data. " + 385 change.location().ToString(), 386 type, error_handler); 387 } 388 } 389 if (IsActOnceDataType(type)) 390 node->Drop(); 391 else 392 node->Tombstone(); 393 return syncer::SyncError(); 394 } 395 396 // A callback invoked on completion of AttachmentService::StoreAttachment. 397 void IgnoreStoreResult(const syncer::AttachmentService::StoreResult&) { 398 // TODO(maniscalco): Here is where we're going to update the in-directory 399 // entry to indicate that the attachments have been successfully stored on 400 // disk. Why do we care? Because we might crash after persisting the 401 // directory to disk, but before we have persisted its attachments, leaving us 402 // with danging attachment ids. Having a flag that indicates we've stored the 403 // entry will allow us to detect and filter entries with dangling attachment 404 // ids (bug 368353). 405 } 406 407 void StoreAttachments(syncer::AttachmentService* attachment_service, 408 const syncer::AttachmentList& attachments) { 409 DCHECK(attachment_service); 410 syncer::AttachmentService::StoreCallback ignore_store_result = 411 base::Bind(&IgnoreStoreResult); 412 attachment_service->StoreAttachments(attachments, ignore_store_result); 413 } 414 415 } // namespace 416 417 syncer::SyncError GenericChangeProcessor::ProcessSyncChanges( 418 const tracked_objects::Location& from_here, 419 const syncer::SyncChangeList& list_of_changes) { 420 DCHECK(CalledOnValidThread()); 421 422 // Keep track of brand new attachments so we can persist them on this device 423 // and upload them to the server. 424 syncer::AttachmentList new_attachments; 425 426 syncer::WriteTransaction trans(from_here, share_handle()); 427 428 for (syncer::SyncChangeList::const_iterator iter = list_of_changes.begin(); 429 iter != list_of_changes.end(); 430 ++iter) { 431 const syncer::SyncChange& change = *iter; 432 DCHECK_NE(change.sync_data().GetDataType(), syncer::UNSPECIFIED); 433 syncer::ModelType type = change.sync_data().GetDataType(); 434 std::string type_str = syncer::ModelTypeToString(type); 435 syncer::WriteNode sync_node(&trans); 436 if (change.change_type() == syncer::SyncChange::ACTION_DELETE) { 437 syncer::SyncError error = 438 AttemptDelete(change, type, type_str, &sync_node, error_handler()); 439 if (error.IsSet()) { 440 NOTREACHED(); 441 return error; 442 } 443 if (merge_result_.get()) { 444 merge_result_->set_num_items_deleted( 445 merge_result_->num_items_deleted() + 1); 446 } 447 } else if (change.change_type() == syncer::SyncChange::ACTION_ADD) { 448 syncer::SyncError error = HandleActionAdd( 449 change, type_str, type, trans, &sync_node, &new_attachments); 450 if (error.IsSet()) { 451 return error; 452 } 453 } else if (change.change_type() == syncer::SyncChange::ACTION_UPDATE) { 454 syncer::SyncError error = HandleActionUpdate( 455 change, type_str, type, trans, &sync_node, &new_attachments); 456 if (error.IsSet()) { 457 return error; 458 } 459 } else { 460 syncer::SyncError error( 461 FROM_HERE, 462 syncer::SyncError::DATATYPE_ERROR, 463 "Received unset SyncChange in the change processor, " + 464 change.location().ToString(), 465 type); 466 error_handler()->OnSingleDatatypeUnrecoverableError(FROM_HERE, 467 error.message()); 468 NOTREACHED(); 469 LOG(ERROR) << "Unset sync change."; 470 return error; 471 } 472 } 473 474 if (!new_attachments.empty()) { 475 StoreAttachments(attachment_service_.get(), new_attachments); 476 } 477 478 return syncer::SyncError(); 479 } 480 481 // WARNING: this code is sensitive to compiler optimizations. Be careful 482 // modifying any code around an OnSingleDatatypeUnrecoverableError call, else 483 // the compiler attempts to merge it with other calls, losing useful information 484 // in breakpad uploads. 485 syncer::SyncError GenericChangeProcessor::HandleActionAdd( 486 const syncer::SyncChange& change, 487 const std::string& type_str, 488 const syncer::ModelType& type, 489 const syncer::WriteTransaction& trans, 490 syncer::WriteNode* sync_node, 491 syncer::AttachmentList* new_attachments) { 492 // TODO(sync): Handle other types of creation (custom parents, folders, 493 // etc.). 494 syncer::ReadNode root_node(&trans); 495 const syncer::SyncDataLocal sync_data_local(change.sync_data()); 496 if (root_node.InitTypeRoot(sync_data_local.GetDataType()) != 497 syncer::BaseNode::INIT_OK) { 498 syncer::SyncError error(FROM_HERE, 499 syncer::SyncError::DATATYPE_ERROR, 500 "Failed to look up root node for type " + type_str, 501 type); 502 error_handler()->OnSingleDatatypeUnrecoverableError(FROM_HERE, 503 error.message()); 504 NOTREACHED(); 505 LOG(ERROR) << "Create: no root node."; 506 return error; 507 } 508 syncer::WriteNode::InitUniqueByCreationResult result = 509 sync_node->InitUniqueByCreation( 510 sync_data_local.GetDataType(), root_node, sync_data_local.GetTag()); 511 if (result != syncer::WriteNode::INIT_SUCCESS) { 512 std::string error_prefix = "Failed to create " + type_str + " node: " + 513 change.location().ToString() + ", "; 514 switch (result) { 515 case syncer::WriteNode::INIT_FAILED_EMPTY_TAG: { 516 syncer::SyncError error; 517 error.Reset(FROM_HERE, error_prefix + "empty tag", type); 518 error_handler()->OnSingleDatatypeUnrecoverableError(FROM_HERE, 519 error.message()); 520 LOG(ERROR) << "Create: Empty tag."; 521 return error; 522 } 523 case syncer::WriteNode::INIT_FAILED_ENTRY_ALREADY_EXISTS: { 524 syncer::SyncError error; 525 error.Reset(FROM_HERE, error_prefix + "entry already exists", type); 526 error_handler()->OnSingleDatatypeUnrecoverableError(FROM_HERE, 527 error.message()); 528 LOG(ERROR) << "Create: Entry exists."; 529 return error; 530 } 531 case syncer::WriteNode::INIT_FAILED_COULD_NOT_CREATE_ENTRY: { 532 syncer::SyncError error; 533 error.Reset(FROM_HERE, error_prefix + "failed to create entry", type); 534 error_handler()->OnSingleDatatypeUnrecoverableError(FROM_HERE, 535 error.message()); 536 LOG(ERROR) << "Create: Could not create entry."; 537 return error; 538 } 539 case syncer::WriteNode::INIT_FAILED_SET_PREDECESSOR: { 540 syncer::SyncError error; 541 error.Reset( 542 FROM_HERE, error_prefix + "failed to set predecessor", type); 543 error_handler()->OnSingleDatatypeUnrecoverableError(FROM_HERE, 544 error.message()); 545 LOG(ERROR) << "Create: Bad predecessor."; 546 return error; 547 } 548 default: { 549 syncer::SyncError error; 550 error.Reset(FROM_HERE, error_prefix + "unknown error", type); 551 error_handler()->OnSingleDatatypeUnrecoverableError(FROM_HERE, 552 error.message()); 553 LOG(ERROR) << "Create: Unknown error."; 554 return error; 555 } 556 } 557 } 558 sync_node->SetTitle(change.sync_data().GetTitle()); 559 SetNodeSpecifics(sync_data_local.GetSpecifics(), sync_node); 560 561 syncer::AttachmentIdList attachment_ids = sync_data_local.GetAttachmentIds(); 562 SetAttachmentMetadata(attachment_ids, sync_node); 563 564 // Return any newly added attachments. 565 const syncer::AttachmentList& local_attachments_for_upload = 566 sync_data_local.GetLocalAttachmentsForUpload(); 567 new_attachments->insert(new_attachments->end(), 568 local_attachments_for_upload.begin(), 569 local_attachments_for_upload.end()); 570 571 if (merge_result_.get()) { 572 merge_result_->set_num_items_added(merge_result_->num_items_added() + 1); 573 } 574 return syncer::SyncError(); 575 } 576 // WARNING: this code is sensitive to compiler optimizations. Be careful 577 // modifying any code around an OnSingleDatatypeUnrecoverableError call, else 578 // the compiler attempts to merge it with other calls, losing useful information 579 // in breakpad uploads. 580 syncer::SyncError GenericChangeProcessor::HandleActionUpdate( 581 const syncer::SyncChange& change, 582 const std::string& type_str, 583 const syncer::ModelType& type, 584 const syncer::WriteTransaction& trans, 585 syncer::WriteNode* sync_node, 586 syncer::AttachmentList* new_attachments) { 587 // TODO(zea): consider having this logic for all possible changes? 588 589 const syncer::SyncDataLocal sync_data_local(change.sync_data()); 590 syncer::BaseNode::InitByLookupResult result = 591 sync_node->InitByClientTagLookup(sync_data_local.GetDataType(), 592 sync_data_local.GetTag()); 593 if (result != syncer::BaseNode::INIT_OK) { 594 std::string error_prefix = "Failed to load " + type_str + " node. " + 595 change.location().ToString() + ", "; 596 if (result == syncer::BaseNode::INIT_FAILED_PRECONDITION) { 597 syncer::SyncError error; 598 error.Reset(FROM_HERE, error_prefix + "empty tag", type); 599 error_handler()->OnSingleDatatypeUnrecoverableError(FROM_HERE, 600 error.message()); 601 LOG(ERROR) << "Update: Empty tag."; 602 return error; 603 } else if (result == syncer::BaseNode::INIT_FAILED_ENTRY_NOT_GOOD) { 604 syncer::SyncError error; 605 error.Reset(FROM_HERE, error_prefix + "bad entry", type); 606 error_handler()->OnSingleDatatypeUnrecoverableError(FROM_HERE, 607 error.message()); 608 LOG(ERROR) << "Update: bad entry."; 609 return error; 610 } else if (result == syncer::BaseNode::INIT_FAILED_ENTRY_IS_DEL) { 611 syncer::SyncError error; 612 error.Reset(FROM_HERE, error_prefix + "deleted entry", type); 613 error_handler()->OnSingleDatatypeUnrecoverableError(FROM_HERE, 614 error.message()); 615 LOG(ERROR) << "Update: deleted entry."; 616 return error; 617 } else { 618 syncer::Cryptographer* crypto = trans.GetCryptographer(); 619 syncer::ModelTypeSet encrypted_types(trans.GetEncryptedTypes()); 620 const sync_pb::EntitySpecifics& specifics = 621 sync_node->GetEntry()->GetSpecifics(); 622 CHECK(specifics.has_encrypted()); 623 const bool can_decrypt = crypto->CanDecrypt(specifics.encrypted()); 624 const bool agreement = encrypted_types.Has(type); 625 if (!agreement && !can_decrypt) { 626 syncer::SyncError error; 627 error.Reset(FROM_HERE, 628 "Failed to load encrypted entry, missing key and " 629 "nigori mismatch for " + 630 type_str + ".", 631 type); 632 error_handler()->OnSingleDatatypeUnrecoverableError(FROM_HERE, 633 error.message()); 634 LOG(ERROR) << "Update: encr case 1."; 635 return error; 636 } else if (agreement && can_decrypt) { 637 syncer::SyncError error; 638 error.Reset(FROM_HERE, 639 "Failed to load encrypted entry, we have the key " 640 "and the nigori matches (?!) for " + 641 type_str + ".", 642 type); 643 error_handler()->OnSingleDatatypeUnrecoverableError(FROM_HERE, 644 error.message()); 645 LOG(ERROR) << "Update: encr case 2."; 646 return error; 647 } else if (agreement) { 648 syncer::SyncError error; 649 error.Reset(FROM_HERE, 650 "Failed to load encrypted entry, missing key and " 651 "the nigori matches for " + 652 type_str + ".", 653 type); 654 error_handler()->OnSingleDatatypeUnrecoverableError(FROM_HERE, 655 error.message()); 656 LOG(ERROR) << "Update: encr case 3."; 657 return error; 658 } else { 659 syncer::SyncError error; 660 error.Reset(FROM_HERE, 661 "Failed to load encrypted entry, we have the key" 662 "(?!) and nigori mismatch for " + 663 type_str + ".", 664 type); 665 error_handler()->OnSingleDatatypeUnrecoverableError(FROM_HERE, 666 error.message()); 667 LOG(ERROR) << "Update: encr case 4."; 668 return error; 669 } 670 } 671 } 672 673 sync_node->SetTitle(change.sync_data().GetTitle()); 674 SetNodeSpecifics(sync_data_local.GetSpecifics(), sync_node); 675 SetAttachmentMetadata(sync_data_local.GetAttachmentIds(), sync_node); 676 677 // Return any newly added attachments. 678 const syncer::AttachmentList& local_attachments_for_upload = 679 sync_data_local.GetLocalAttachmentsForUpload(); 680 new_attachments->insert(new_attachments->end(), 681 local_attachments_for_upload.begin(), 682 local_attachments_for_upload.end()); 683 684 if (merge_result_.get()) { 685 merge_result_->set_num_items_modified(merge_result_->num_items_modified() + 686 1); 687 } 688 // TODO(sync): Support updating other parts of the sync node (title, 689 // successor, parent, etc.). 690 return syncer::SyncError(); 691 } 692 693 bool GenericChangeProcessor::SyncModelHasUserCreatedNodes( 694 syncer::ModelType type, 695 bool* has_nodes) { 696 DCHECK(CalledOnValidThread()); 697 DCHECK(has_nodes); 698 DCHECK_NE(type, syncer::UNSPECIFIED); 699 std::string type_name = syncer::ModelTypeToString(type); 700 std::string err_str = "Server did not create the top-level " + type_name + 701 " node. We might be running against an out-of-date server."; 702 *has_nodes = false; 703 syncer::ReadTransaction trans(FROM_HERE, share_handle()); 704 syncer::ReadNode type_root_node(&trans); 705 if (type_root_node.InitTypeRoot(type) != syncer::BaseNode::INIT_OK) { 706 LOG(ERROR) << err_str; 707 return false; 708 } 709 710 // The sync model has user created nodes if the type's root node has any 711 // children. 712 *has_nodes = type_root_node.HasChildren(); 713 return true; 714 } 715 716 bool GenericChangeProcessor::CryptoReadyIfNecessary(syncer::ModelType type) { 717 DCHECK(CalledOnValidThread()); 718 DCHECK_NE(type, syncer::UNSPECIFIED); 719 // We only access the cryptographer while holding a transaction. 720 syncer::ReadTransaction trans(FROM_HERE, share_handle()); 721 const syncer::ModelTypeSet encrypted_types = trans.GetEncryptedTypes(); 722 return !encrypted_types.Has(type) || 723 trans.GetCryptographer()->is_ready(); 724 } 725 726 void GenericChangeProcessor::StartImpl() { 727 } 728 729 syncer::UserShare* GenericChangeProcessor::share_handle() const { 730 DCHECK(CalledOnValidThread()); 731 return share_handle_; 732 } 733 734 } // namespace browser_sync 735