1// Copyright 2012 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 "sync/syncable/syncable_util.h"
6
7#include "base/base64.h"
8#include "base/location.h"
9#include "base/logging.h"
10#include "base/sha1.h"
11#include "sync/syncable/directory.h"
12#include "sync/syncable/entry.h"
13#include "sync/syncable/mutable_entry.h"
14#include "sync/syncable/syncable_id.h"
15#include "sync/syncable/syncable_write_transaction.h"
16
17namespace syncer {
18namespace syncable {
19
20// Returns the number of unsynced entries.
21int GetUnsyncedEntries(BaseTransaction* trans,
22                       std::vector<int64> *handles) {
23  trans->directory()->GetUnsyncedMetaHandles(trans, handles);
24  DVLOG_IF(1, !handles->empty()) << "Have " << handles->size()
25                                 << " unsynced items.";
26  return handles->size();
27}
28
29bool IsLegalNewParent(BaseTransaction* trans, const Id& entry_id,
30                      const Id& new_parent_id) {
31  if (entry_id.IsRoot())
32    return false;
33  // we have to ensure that the entry is not an ancestor of the new parent.
34  Id ancestor_id = new_parent_id;
35  while (!ancestor_id.IsRoot()) {
36    if (entry_id == ancestor_id)
37      return false;
38    Entry new_parent(trans, GET_BY_ID, ancestor_id);
39    if (!SyncAssert(new_parent.good(),
40                    FROM_HERE,
41                    "Invalid new parent",
42                    trans))
43      return false;
44    ancestor_id = new_parent.GetParentId();
45  }
46  return true;
47}
48
49void ChangeEntryIDAndUpdateChildren(
50    BaseWriteTransaction* trans,
51    ModelNeutralMutableEntry* entry,
52    const Id& new_id) {
53  Id old_id = entry->GetId();
54  if (!entry->PutId(new_id)) {
55    Entry old_entry(trans, GET_BY_ID, new_id);
56    CHECK(old_entry.good());
57    LOG(FATAL) << "Attempt to change ID to " << new_id
58               << " conflicts with existing entry.\n\n"
59               << *entry << "\n\n" << old_entry;
60  }
61  if (entry->GetIsDir()) {
62    // Get all child entries of the old id.
63    Directory::Metahandles children;
64    trans->directory()->GetChildHandlesById(trans, old_id, &children);
65    Directory::Metahandles::iterator i = children.begin();
66    while (i != children.end()) {
67      ModelNeutralMutableEntry child_entry(trans, GET_BY_HANDLE, *i++);
68      CHECK(child_entry.good());
69      // Use the unchecked setter here to avoid touching the child's
70      // UNIQUE_POSITION field.  In this case, UNIQUE_POSITION among the
71      // children will be valid after the loop, since we update all the children
72      // at once.
73      child_entry.PutParentIdPropertyOnly(new_id);
74    }
75  }
76}
77
78// Function to handle runtime failures on syncable code. Rather than crashing,
79// if the |condition| is false the following will happen:
80// 1. Sets unrecoverable error on transaction.
81// 2. Returns false.
82bool SyncAssert(bool condition,
83                const tracked_objects::Location& location,
84                const char* msg,
85                BaseTransaction* trans) {
86  if (!condition) {
87    trans->OnUnrecoverableError(location, msg);
88    return false;
89  }
90  return true;
91}
92
93std::string GenerateSyncableHash(
94    ModelType model_type, const std::string& client_tag) {
95  // Blank PB with just the field in it has termination symbol,
96  // handy for delimiter.
97  sync_pb::EntitySpecifics serialized_type;
98  AddDefaultFieldValue(model_type, &serialized_type);
99  std::string hash_input;
100  serialized_type.AppendToString(&hash_input);
101  hash_input.append(client_tag);
102
103  std::string encode_output;
104  base::Base64Encode(base::SHA1HashString(hash_input), &encode_output);
105  return encode_output;
106}
107
108std::string GenerateSyncableBookmarkHash(
109    const std::string& originator_cache_guid,
110    const std::string& originator_client_item_id) {
111  return syncable::GenerateSyncableHash(
112      BOOKMARKS, originator_cache_guid + originator_client_item_id);
113}
114
115}  // namespace syncable
116}  // namespace syncer
117