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 17 namespace syncer { 18 namespace syncable { 19 20 // Returns the number of unsynced entries. 21 int 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 29 bool 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.Get(PARENT_ID); 45 } 46 return true; 47 } 48 49 void ChangeEntryIDAndUpdateChildren( 50 WriteTransaction* trans, 51 MutableEntry* entry, 52 const Id& new_id) { 53 Id old_id = entry->Get(ID); 54 if (!entry->Put(ID, 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->Get(IS_DIR)) { 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 MutableEntry 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. 82 bool 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 93 std::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 CHECK(base::Base64Encode(base::SHA1HashString(hash_input), &encode_output)); 105 return encode_output; 106 } 107 108 std::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