• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
SetNodeSpecifics(const sync_pb::EntitySpecifics & entity_specifics,syncer::WriteNode * write_node)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.
AttachmentIdToRecord(const syncer::AttachmentId & attachment_id)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|.
SetAttachmentMetadata(const syncer::AttachmentIdList & attachment_ids,syncer::WriteNode * write_node)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 
BuildRemoteSyncData(int64 sync_id,const syncer::BaseNode & read_node,const syncer::AttachmentServiceProxy & attachment_service_proxy)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 
GenericChangeProcessor(DataTypeErrorHandler * error_handler,const base::WeakPtr<syncer::SyncableService> & local_service,const base::WeakPtr<syncer::SyncMergeResult> & merge_result,syncer::UserShare * user_share,SyncApiComponentFactory * sync_factory)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 
~GenericChangeProcessor()109 GenericChangeProcessor::~GenericChangeProcessor() {
110   DCHECK(CalledOnValidThread());
111 }
112 
ApplyChangesFromSyncModel(const syncer::BaseTransaction * trans,int64 model_version,const syncer::ImmutableChangeRecordList & changes)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 
CommitChangesFromSyncModel()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 
GetAllSyncData(syncer::ModelType type) const183 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 
UpdateDataTypeContext(syncer::ModelType type,syncer::SyncChangeProcessor::ContextRefreshStatus refresh_status,const std::string & context)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 
OnAttachmentUploaded(const syncer::AttachmentId & attachment_id)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 
GetAllSyncDataReturnError(syncer::ModelType type,syncer::SyncDataList * current_sync_data) const219 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 
GetDataTypeContext(syncer::ModelType type,std::string * context) const260 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 
GetSyncCountForType(syncer::ModelType type)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.
LogLookupFailure(syncer::BaseNode::InitByLookupResult lookup_result,const tracked_objects::Location & from_here,const std::string & error_prefix,syncer::ModelType type,DataTypeErrorHandler * error_handler)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 
AttemptDelete(const syncer::SyncChange & change,syncer::ModelType type,const std::string & type_str,syncer::WriteNode * node,DataTypeErrorHandler * error_handler)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.
IgnoreStoreResult(const syncer::AttachmentService::StoreResult &)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 
StoreAttachments(syncer::AttachmentService * attachment_service,const syncer::AttachmentList & attachments)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 
ProcessSyncChanges(const tracked_objects::Location & from_here,const syncer::SyncChangeList & list_of_changes)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.
HandleActionAdd(const syncer::SyncChange & change,const std::string & type_str,const syncer::ModelType & type,const syncer::WriteTransaction & trans,syncer::WriteNode * sync_node,syncer::AttachmentList * new_attachments)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.
HandleActionUpdate(const syncer::SyncChange & change,const std::string & type_str,const syncer::ModelType & type,const syncer::WriteTransaction & trans,syncer::WriteNode * sync_node,syncer::AttachmentList * new_attachments)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 
SyncModelHasUserCreatedNodes(syncer::ModelType type,bool * has_nodes)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 
CryptoReadyIfNecessary(syncer::ModelType type)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 
StartImpl()726 void GenericChangeProcessor::StartImpl() {
727 }
728 
share_handle() const729 syncer::UserShare* GenericChangeProcessor::share_handle() const {
730   DCHECK(CalledOnValidThread());
731   return share_handle_;
732 }
733 
734 }  // namespace browser_sync
735