15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sync/internal_api/public/write_node.h" 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/string_util.h" 8868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/utf_string_conversions.h" 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/values.h" 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sync/internal_api/public/base_transaction.h" 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sync/internal_api/public/write_transaction.h" 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sync/internal_api/syncapi_internal.h" 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sync/protocol/app_specifics.pb.h" 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sync/protocol/autofill_specifics.pb.h" 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sync/protocol/bookmark_specifics.pb.h" 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sync/protocol/extension_specifics.pb.h" 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sync/protocol/password_specifics.pb.h" 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sync/protocol/session_specifics.pb.h" 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sync/protocol/theme_specifics.pb.h" 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sync/protocol/typed_url_specifics.pb.h" 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sync/syncable/mutable_entry.h" 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sync/syncable/nigori_util.h" 232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "sync/syncable/syncable_util.h" 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sync/util/cryptographer.h" 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using std::string; 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using std::vector; 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace syncer { 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using syncable::kEncryptedString; 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using syncable::SPECIFICS; 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const char kDefaultNameForNewNodes[] = " "; 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WriteNode::SetIsFolder(bool folder) { 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (entry_->Get(syncable::IS_DIR) == folder) 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; // Skip redundant changes. 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) entry_->Put(syncable::IS_DIR, folder); 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MarkForSyncing(); 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WriteNode::SetTitle(const std::wstring& title) { 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK_NE(GetModelType(), UNSPECIFIED); 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ModelType type = GetModelType(); 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // It's possible the nigori lost the set of encrypted types. If the current 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // specifics are already encrypted, we want to ensure we continue encrypting. 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool needs_encryption = GetTransaction()->GetEncryptedTypes().Has(type) || 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) entry_->Get(SPECIFICS).has_encrypted(); 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If this datatype is encrypted and is not a bookmark, we disregard the 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // specified title in favor of kEncryptedString. For encrypted bookmarks the 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // NON_UNIQUE_NAME will still be kEncryptedString, but we store the real title 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // into the specifics. All strings compared are server legal strings. 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string new_legal_title; 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (type != BOOKMARKS && needs_encryption) { 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) new_legal_title = kEncryptedString; 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SyncAPINameToServerName(WideToUTF8(title), &new_legal_title); 61c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) TruncateUTF8ToByteSize(new_legal_title, 255, &new_legal_title); 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string current_legal_title; 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (BOOKMARKS == type && 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) entry_->Get(syncable::SPECIFICS).has_encrypted()) { 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Encrypted bookmarks only have their title in the unencrypted specifics. 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) current_legal_title = GetBookmarkSpecifics().title(); 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Non-bookmarks and legacy bookmarks (those with no title in their 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // specifics) store their title in NON_UNIQUE_NAME. Non-legacy bookmarks 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // store their title in specifics as well as NON_UNIQUE_NAME. 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) current_legal_title = entry_->Get(syncable::NON_UNIQUE_NAME); 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool title_matches = (current_legal_title == new_legal_title); 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool encrypted_without_overwriting_name = (needs_encryption && 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) entry_->Get(syncable::NON_UNIQUE_NAME) != kEncryptedString); 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If the title matches and the NON_UNIQUE_NAME is properly overwritten as 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // necessary, nothing needs to change. 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (title_matches && !encrypted_without_overwriting_name) { 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DVLOG(2) << "Title matches, dropping change."; 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // For bookmarks, we also set the title field in the specifics. 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // TODO(zea): refactor bookmarks to not need this functionality. 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (GetModelType() == BOOKMARKS) { 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sync_pb::EntitySpecifics specifics = GetEntitySpecifics(); 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) specifics.mutable_bookmark()->set_title(new_legal_title); 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SetEntitySpecifics(specifics); // Does it's own encryption checking. 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // For bookmarks, this has to happen after we set the title in the specifics, 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // because the presence of a title in the NON_UNIQUE_NAME is what controls 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // the logic deciding whether this is an empty node or a legacy bookmark. 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // See BaseNode::GetUnencryptedSpecific(..). 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (needs_encryption) 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) entry_->Put(syncable::NON_UNIQUE_NAME, kEncryptedString); 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) entry_->Put(syncable::NON_UNIQUE_NAME, new_legal_title); 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DVLOG(1) << "Overwriting title of type " 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) << ModelTypeToString(type) 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) << " and marking for syncing."; 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MarkForSyncing(); 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WriteNode::SetAppSpecifics( 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const sync_pb::AppSpecifics& new_value) { 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sync_pb::EntitySpecifics entity_specifics; 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) entity_specifics.mutable_app()->CopyFrom(new_value); 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SetEntitySpecifics(entity_specifics); 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WriteNode::SetAutofillSpecifics( 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const sync_pb::AutofillSpecifics& new_value) { 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sync_pb::EntitySpecifics entity_specifics; 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) entity_specifics.mutable_autofill()->CopyFrom(new_value); 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SetEntitySpecifics(entity_specifics); 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WriteNode::SetAutofillProfileSpecifics( 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const sync_pb::AutofillProfileSpecifics& new_value) { 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sync_pb::EntitySpecifics entity_specifics; 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) entity_specifics.mutable_autofill_profile()-> 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CopyFrom(new_value); 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SetEntitySpecifics(entity_specifics); 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WriteNode::SetBookmarkSpecifics( 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const sync_pb::BookmarkSpecifics& new_value) { 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sync_pb::EntitySpecifics entity_specifics; 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) entity_specifics.mutable_bookmark()->CopyFrom(new_value); 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SetEntitySpecifics(entity_specifics); 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WriteNode::SetNigoriSpecifics( 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const sync_pb::NigoriSpecifics& new_value) { 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sync_pb::EntitySpecifics entity_specifics; 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) entity_specifics.mutable_nigori()->CopyFrom(new_value); 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SetEntitySpecifics(entity_specifics); 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WriteNode::SetPasswordSpecifics( 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const sync_pb::PasswordSpecificsData& data) { 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK_EQ(GetModelType(), PASSWORDS); 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Cryptographer* cryptographer = GetTransaction()->GetCryptographer(); 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We have to do the idempotency check here (vs in UpdateEntryWithEncryption) 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // because Passwords have their encrypted data within the PasswordSpecifics, 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // vs within the EntitySpecifics like all the other types. 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const sync_pb::EntitySpecifics& old_specifics = GetEntry()->Get(SPECIFICS); 1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sync_pb::EntitySpecifics entity_specifics; 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Copy over the old specifics if they exist. 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (GetModelTypeFromSpecifics(old_specifics) == PASSWORDS) { 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) entity_specifics.CopyFrom(old_specifics); 1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AddDefaultFieldValue(PASSWORDS, &entity_specifics); 1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sync_pb::PasswordSpecifics* password_specifics = 1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) entity_specifics.mutable_password(); 1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // This will only update password_specifics if the underlying unencrypted blob 1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // was different from |data| or was not encrypted with the proper passphrase. 1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!cryptographer->Encrypt(data, password_specifics->mutable_encrypted())) { 1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOTREACHED() << "Failed to encrypt password, possibly due to sync node " 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) << "corruption"; 1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SetEntitySpecifics(entity_specifics); 1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WriteNode::SetThemeSpecifics( 1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const sync_pb::ThemeSpecifics& new_value) { 1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sync_pb::EntitySpecifics entity_specifics; 1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) entity_specifics.mutable_theme()->CopyFrom(new_value); 1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SetEntitySpecifics(entity_specifics); 1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WriteNode::SetSessionSpecifics( 1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const sync_pb::SessionSpecifics& new_value) { 1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sync_pb::EntitySpecifics entity_specifics; 1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) entity_specifics.mutable_session()->CopyFrom(new_value); 1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SetEntitySpecifics(entity_specifics); 1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 189c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void WriteNode::SetManagedUserSettingSpecifics( 190c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) const sync_pb::ManagedUserSettingSpecifics& new_value) { 191c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) sync_pb::EntitySpecifics entity_specifics; 192c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) entity_specifics.mutable_managed_user_setting()->CopyFrom(new_value); 193c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) SetEntitySpecifics(entity_specifics); 194c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 195c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 19690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void WriteNode::SetManagedUserSpecifics( 19790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) const sync_pb::ManagedUserSpecifics& new_value) { 19890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) sync_pb::EntitySpecifics entity_specifics; 19990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) entity_specifics.mutable_managed_user()->CopyFrom(new_value); 20090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) SetEntitySpecifics(entity_specifics); 20190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)} 20290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WriteNode::SetDeviceInfoSpecifics( 2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const sync_pb::DeviceInfoSpecifics& new_value) { 2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sync_pb::EntitySpecifics entity_specifics; 2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) entity_specifics.mutable_device_info()->CopyFrom(new_value); 2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SetEntitySpecifics(entity_specifics); 2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WriteNode::SetExperimentsSpecifics( 2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const sync_pb::ExperimentsSpecifics& new_value) { 2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sync_pb::EntitySpecifics entity_specifics; 2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) entity_specifics.mutable_experiments()->CopyFrom(new_value); 2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SetEntitySpecifics(entity_specifics); 2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void WriteNode::SetPriorityPreferenceSpecifics( 2182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const sync_pb::PriorityPreferenceSpecifics& new_value) { 2192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) sync_pb::EntitySpecifics entity_specifics; 2202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) entity_specifics.mutable_priority_preference()->CopyFrom(new_value); 2212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) SetEntitySpecifics(entity_specifics); 2222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 2232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WriteNode::SetEntitySpecifics( 2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const sync_pb::EntitySpecifics& new_value) { 2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ModelType new_specifics_type = 2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GetModelTypeFromSpecifics(new_value); 2287dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch CHECK(!new_value.password().has_client_only_encrypted_data()); 2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK_NE(new_specifics_type, UNSPECIFIED); 2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DVLOG(1) << "Writing entity specifics of type " 2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) << ModelTypeToString(new_specifics_type); 2322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK_EQ(new_specifics_type, GetModelType()); 2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Preserve unknown fields. 2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const sync_pb::EntitySpecifics& old_specifics = entry_->Get(SPECIFICS); 2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sync_pb::EntitySpecifics new_specifics; 2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) new_specifics.CopyFrom(new_value); 2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) new_specifics.mutable_unknown_fields()->MergeFrom( 2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) old_specifics.unknown_fields()); 2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Will update the entry if encryption was necessary. 2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!UpdateEntryWithEncryption(GetTransaction()->GetWrappedTrans(), 2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) new_specifics, 2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) entry_)) { 2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (entry_->Get(SPECIFICS).has_encrypted()) { 2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // EncryptIfNecessary already updated the entry for us and marked for 2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // syncing if it was needed. Now we just make a copy of the unencrypted 2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // specifics so that if this node is updated, we do not have to decrypt the 2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // old data. Note that this only modifies the node's local data, not the 2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // entry itself. 2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SetUnencryptedSpecifics(new_value); 2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK_EQ(new_specifics_type, GetModelType()); 2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WriteNode::ResetFromSpecifics() { 2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SetEntitySpecifics(GetEntitySpecifics()); 2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WriteNode::SetTypedUrlSpecifics( 2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const sync_pb::TypedUrlSpecifics& new_value) { 2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sync_pb::EntitySpecifics entity_specifics; 2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) entity_specifics.mutable_typed_url()->CopyFrom(new_value); 2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SetEntitySpecifics(entity_specifics); 2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WriteNode::SetExtensionSpecifics( 2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const sync_pb::ExtensionSpecifics& new_value) { 2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sync_pb::EntitySpecifics entity_specifics; 2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) entity_specifics.mutable_extension()->CopyFrom(new_value); 2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SetEntitySpecifics(entity_specifics); 2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WriteNode::SetExternalId(int64 id) { 2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (GetExternalId() != id) 2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) entry_->Put(syncable::LOCAL_EXTERNAL_ID, id); 2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)WriteNode::WriteNode(WriteTransaction* transaction) 2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : entry_(NULL), transaction_(transaction) { 2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(transaction); 2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)WriteNode::~WriteNode() { 2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) delete entry_; 2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Find an existing node matching the ID |id|, and bind this WriteNode to it. 2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Return true on success. 2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)BaseNode::InitByLookupResult WriteNode::InitByIdLookup(int64 id) { 2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(!entry_) << "Init called twice"; 2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK_NE(id, kInvalidId); 2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) entry_ = new syncable::MutableEntry(transaction_->GetWrappedWriteTrans(), 2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) syncable::GET_BY_HANDLE, id); 2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!entry_->good()) 2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return INIT_FAILED_ENTRY_NOT_GOOD; 3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (entry_->Get(syncable::IS_DEL)) 3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return INIT_FAILED_ENTRY_IS_DEL; 3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return DecryptIfNecessary() ? INIT_OK : INIT_FAILED_DECRYPT_IF_NECESSARY; 3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Find a node by client tag, and bind this WriteNode to it. 3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Return true if the write node was found, and was not deleted. 3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Undeleting a deleted node is possible by ClientTag. 3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)BaseNode::InitByLookupResult WriteNode::InitByClientTagLookup( 3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ModelType model_type, 3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string& tag) { 3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(!entry_) << "Init called twice"; 3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (tag.empty()) 3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return INIT_FAILED_PRECONDITION; 3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const std::string hash = syncable::GenerateSyncableHash(model_type, tag); 3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) entry_ = new syncable::MutableEntry(transaction_->GetWrappedWriteTrans(), 3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) syncable::GET_BY_CLIENT_TAG, hash); 3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!entry_->good()) 3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return INIT_FAILED_ENTRY_NOT_GOOD; 3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (entry_->Get(syncable::IS_DEL)) 3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return INIT_FAILED_ENTRY_IS_DEL; 3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return DecryptIfNecessary() ? INIT_OK : INIT_FAILED_DECRYPT_IF_NECESSARY; 3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)BaseNode::InitByLookupResult WriteNode::InitByTagLookup( 3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string& tag) { 3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(!entry_) << "Init called twice"; 3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (tag.empty()) 3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return INIT_FAILED_PRECONDITION; 3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) entry_ = new syncable::MutableEntry(transaction_->GetWrappedWriteTrans(), 3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) syncable::GET_BY_SERVER_TAG, tag); 3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!entry_->good()) 3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return INIT_FAILED_ENTRY_NOT_GOOD; 3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (entry_->Get(syncable::IS_DEL)) 3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return INIT_FAILED_ENTRY_IS_DEL; 3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ModelType model_type = GetModelType(); 3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK_EQ(model_type, NIGORI); 3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return INIT_OK; 3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Create a new node with default properties, and bind this WriteNode to it. 3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Return true on success. 3442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool WriteNode::InitBookmarkByCreation(const BaseNode& parent, 3452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const BaseNode* predecessor) { 3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(!entry_) << "Init called twice"; 3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // |predecessor| must be a child of |parent| or NULL. 3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (predecessor && predecessor->GetParentId() != parent.GetId()) { 3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(false); 3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) syncable::Id parent_id = parent.GetEntry()->Get(syncable::ID); 3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Start out with a dummy name. We expect 3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // the caller to set a meaningful name after creation. 3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) string dummy(kDefaultNameForNewNodes); 3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) entry_ = new syncable::MutableEntry(transaction_->GetWrappedWriteTrans(), 3602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) syncable::CREATE, BOOKMARKS, 3612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) parent_id, dummy); 3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!entry_->good()) 3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Entries are untitled folders by default. 3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) entry_->Put(syncable::IS_DIR, true); 3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Now set the predecessor, which sets IS_UNSYNCED as necessary. 3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return PutPredecessor(predecessor); 3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Create a new node with default properties and a client defined unique tag, 3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// and bind this WriteNode to it. 3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Return true on success. If the tag exists in the database, then 3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// we will attempt to undelete the node. 3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// TODO(chron): Code datatype into hash tag. 3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// TODO(chron): Is model type ever lost? 3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)WriteNode::InitUniqueByCreationResult WriteNode::InitUniqueByCreation( 3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ModelType model_type, 3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const BaseNode& parent, 3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string& tag) { 3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // This DCHECK will only fail if init is called twice. 3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(!entry_); 3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (tag.empty()) { 3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LOG(WARNING) << "InitUniqueByCreation failed due to empty tag."; 3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return INIT_FAILED_EMPTY_TAG; 3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const std::string hash = syncable::GenerateSyncableHash(model_type, tag); 3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) syncable::Id parent_id = parent.GetEntry()->Get(syncable::ID); 3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Start out with a dummy name. We expect 3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // the caller to set a meaningful name after creation. 3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) string dummy(kDefaultNameForNewNodes); 3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Check if we have this locally and need to undelete it. 3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scoped_ptr<syncable::MutableEntry> existing_entry( 4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) new syncable::MutableEntry(transaction_->GetWrappedWriteTrans(), 4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) syncable::GET_BY_CLIENT_TAG, hash)); 4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (existing_entry->good()) { 4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (existing_entry->Get(syncable::IS_DEL)) { 4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Rules for undelete: 4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // BASE_VERSION: Must keep the same. 4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // ID: Essential to keep the same. 4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // META_HANDLE: Must be the same, so we can't "split" the entry. 4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // IS_DEL: Must be set to false, will cause reindexing. 4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // This one is weird because IS_DEL is true for "update only" 4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // items. It should be OK to undelete an update only. 4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // MTIME/CTIME: Seems reasonable to just leave them alone. 4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // IS_UNSYNCED: Must set this to true or face database insurrection. 4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We do this below this block. 4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // IS_UNAPPLIED_UPDATE: Either keep it the same or also set BASE_VERSION 4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // to SERVER_VERSION. We keep it the same here. 4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // IS_DIR: We'll leave it the same. 4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // SPECIFICS: Reset it. 4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) existing_entry->Put(syncable::IS_DEL, false); 4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Client tags are immutable and must be paired with the ID. 4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If a server update comes down with an ID and client tag combo, 4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // and it already exists, always overwrite it and store only one copy. 4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We have to undelete entries because we can't disassociate IDs from 4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // tags and updates. 4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) existing_entry->Put(syncable::NON_UNIQUE_NAME, dummy); 4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) existing_entry->Put(syncable::PARENT_ID, parent_id); 4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) entry_ = existing_entry.release(); 4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return INIT_FAILED_ENTRY_ALREADY_EXISTS; 4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) entry_ = new syncable::MutableEntry(transaction_->GetWrappedWriteTrans(), 4362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) syncable::CREATE, 4372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) model_type, parent_id, dummy); 4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!entry_->good()) 4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return INIT_FAILED_COULD_NOT_CREATE_ENTRY; 4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Only set IS_DIR for new entries. Don't bitflip undeleted ones. 4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) entry_->Put(syncable::UNIQUE_CLIENT_TAG, hash); 4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We don't support directory and tag combinations. 4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) entry_->Put(syncable::IS_DIR, false); 4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Now set the predecessor, which sets IS_UNSYNCED as necessary. 4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool success = PutPredecessor(NULL); 4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!success) 4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return INIT_FAILED_SET_PREDECESSOR; 4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return INIT_SUCCESS; 4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool WriteNode::SetPosition(const BaseNode& new_parent, 4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const BaseNode* predecessor) { 4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // |predecessor| must be a child of |new_parent| or NULL. 4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (predecessor && predecessor->GetParentId() != new_parent.GetId()) { 4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(false); 4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) syncable::Id new_parent_id = new_parent.GetEntry()->Get(syncable::ID); 4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Filter out redundant changes if both the parent and the predecessor match. 4675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (new_parent_id == entry_->Get(syncable::PARENT_ID)) { 4682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const syncable::Id& old = entry_->GetPredecessorId(); 4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ((!predecessor && old.IsRoot()) || 4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (predecessor && (old == predecessor->GetEntry()->Get(syncable::ID)))) { 4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Atomically change the parent. This will fail if it would 4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // introduce a cycle in the hierarchy. 4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!entry_->Put(syncable::PARENT_ID, new_parent_id)) 4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 4795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Now set the predecessor, which sets IS_UNSYNCED as necessary. 4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return PutPredecessor(predecessor); 4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const syncable::Entry* WriteNode::GetEntry() const { 4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return entry_; 4865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const BaseTransaction* WriteNode::GetTransaction() const { 4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return transaction_; 4905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)syncable::MutableEntry* WriteNode::GetMutableEntryForTest() { 4935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return entry_; 4945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void WriteNode::Tombstone() { 4975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // These lines must be in this order. The call to Put(IS_DEL) might choose to 4985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // unset the IS_UNSYNCED bit if the item was not known to the server at the 4995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // time of deletion. It's important that the bit not be reset in that case. 5005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MarkForSyncing(); 5015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) entry_->Put(syncable::IS_DEL, true); 5025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void WriteNode::Drop() { 5052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (entry_->Get(syncable::ID).ServerKnows()) { 5062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) entry_->Put(syncable::IS_DEL, true); 5072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 5082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 5092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 5105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool WriteNode::PutPredecessor(const BaseNode* predecessor) { 5115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) syncable::Id predecessor_id = predecessor ? 5125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) predecessor->GetEntry()->Get(syncable::ID) : syncable::Id(); 5135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!entry_->PutPredecessor(predecessor_id)) 5145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 5155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Mark this entry as unsynced, to wake up the syncer. 5165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MarkForSyncing(); 5175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 5195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WriteNode::MarkForSyncing() { 5225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) syncable::MarkForSyncing(entry_); 5235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace syncer 526