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