// Copyright 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "sync/syncable/syncable_util.h" #include "base/base64.h" #include "base/location.h" #include "base/logging.h" #include "base/sha1.h" #include "sync/syncable/directory.h" #include "sync/syncable/entry.h" #include "sync/syncable/mutable_entry.h" #include "sync/syncable/syncable_id.h" #include "sync/syncable/syncable_write_transaction.h" namespace syncer { namespace syncable { // Returns the number of unsynced entries. int GetUnsyncedEntries(BaseTransaction* trans, std::vector<int64> *handles) { trans->directory()->GetUnsyncedMetaHandles(trans, handles); DVLOG_IF(1, !handles->empty()) << "Have " << handles->size() << " unsynced items."; return handles->size(); } bool IsLegalNewParent(BaseTransaction* trans, const Id& entry_id, const Id& new_parent_id) { if (entry_id.IsRoot()) return false; // we have to ensure that the entry is not an ancestor of the new parent. Id ancestor_id = new_parent_id; while (!ancestor_id.IsRoot()) { if (entry_id == ancestor_id) return false; Entry new_parent(trans, GET_BY_ID, ancestor_id); if (!SyncAssert(new_parent.good(), FROM_HERE, "Invalid new parent", trans)) return false; ancestor_id = new_parent.GetParentId(); } return true; } void ChangeEntryIDAndUpdateChildren( BaseWriteTransaction* trans, ModelNeutralMutableEntry* entry, const Id& new_id) { Id old_id = entry->GetId(); if (!entry->PutId(new_id)) { Entry old_entry(trans, GET_BY_ID, new_id); CHECK(old_entry.good()); LOG(FATAL) << "Attempt to change ID to " << new_id << " conflicts with existing entry.\n\n" << *entry << "\n\n" << old_entry; } if (entry->GetIsDir()) { // Get all child entries of the old id. Directory::Metahandles children; trans->directory()->GetChildHandlesById(trans, old_id, &children); Directory::Metahandles::iterator i = children.begin(); while (i != children.end()) { ModelNeutralMutableEntry child_entry(trans, GET_BY_HANDLE, *i++); CHECK(child_entry.good()); // Use the unchecked setter here to avoid touching the child's // UNIQUE_POSITION field. In this case, UNIQUE_POSITION among the // children will be valid after the loop, since we update all the children // at once. child_entry.PutParentIdPropertyOnly(new_id); } } } // Function to handle runtime failures on syncable code. Rather than crashing, // if the |condition| is false the following will happen: // 1. Sets unrecoverable error on transaction. // 2. Returns false. bool SyncAssert(bool condition, const tracked_objects::Location& location, const char* msg, BaseTransaction* trans) { if (!condition) { trans->OnUnrecoverableError(location, msg); return false; } return true; } std::string GenerateSyncableHash( ModelType model_type, const std::string& client_tag) { // Blank PB with just the field in it has termination symbol, // handy for delimiter. sync_pb::EntitySpecifics serialized_type; AddDefaultFieldValue(model_type, &serialized_type); std::string hash_input; serialized_type.AppendToString(&hash_input); hash_input.append(client_tag); std::string encode_output; base::Base64Encode(base::SHA1HashString(hash_input), &encode_output); return encode_output; } std::string GenerateSyncableBookmarkHash( const std::string& originator_cache_guid, const std::string& originator_client_item_id) { return syncable::GenerateSyncableHash( BOOKMARKS, originator_cache_guid + originator_client_item_id); } } // namespace syncable } // namespace syncer