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