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) { 37d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) if (entry_->GetIsDir() == folder) 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; // Skip redundant changes. 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 40d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) entry_->PutIsDir(folder); 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MarkForSyncing(); 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 440529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochvoid WriteNode::SetTitle(const std::string& 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) || 50d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) entry_->GetSpecifics().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 { 60cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) DCHECK(base::IsStringUTF8(title)); 610529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch SyncAPINameToServerName(title, &new_legal_title); 62a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) base::TruncateUTF8ToByteSize(new_legal_title, 255, &new_legal_title); 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string current_legal_title; 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (BOOKMARKS == type && 67d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) entry_->GetSpecifics().has_encrypted()) { 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Encrypted bookmarks only have their title in the unencrypted specifics. 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) current_legal_title = GetBookmarkSpecifics().title(); 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Non-bookmarks and legacy bookmarks (those with no title in their 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // specifics) store their title in NON_UNIQUE_NAME. Non-legacy bookmarks 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // store their title in specifics as well as NON_UNIQUE_NAME. 74d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) current_legal_title = entry_->GetNonUniqueName(); 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool title_matches = (current_legal_title == new_legal_title); 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool encrypted_without_overwriting_name = (needs_encryption && 79d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) entry_->GetNonUniqueName() != kEncryptedString); 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If the title matches and the NON_UNIQUE_NAME is properly overwritten as 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // necessary, nothing needs to change. 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (title_matches && !encrypted_without_overwriting_name) { 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DVLOG(2) << "Title matches, dropping change."; 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // For bookmarks, we also set the title field in the specifics. 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // TODO(zea): refactor bookmarks to not need this functionality. 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (GetModelType() == BOOKMARKS) { 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sync_pb::EntitySpecifics specifics = GetEntitySpecifics(); 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) specifics.mutable_bookmark()->set_title(new_legal_title); 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SetEntitySpecifics(specifics); // Does it's own encryption checking. 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // For bookmarks, this has to happen after we set the title in the specifics, 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // because the presence of a title in the NON_UNIQUE_NAME is what controls 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // the logic deciding whether this is an empty node or a legacy bookmark. 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // See BaseNode::GetUnencryptedSpecific(..). 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (needs_encryption) 101d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) entry_->PutNonUniqueName(kEncryptedString); 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else 103d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) entry_->PutNonUniqueName(new_legal_title); 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DVLOG(1) << "Overwriting title of type " 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) << ModelTypeToString(type) 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) << " and marking for syncing."; 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MarkForSyncing(); 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WriteNode::SetAppSpecifics( 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const sync_pb::AppSpecifics& new_value) { 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sync_pb::EntitySpecifics entity_specifics; 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) entity_specifics.mutable_app()->CopyFrom(new_value); 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SetEntitySpecifics(entity_specifics); 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WriteNode::SetAutofillSpecifics( 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const sync_pb::AutofillSpecifics& new_value) { 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sync_pb::EntitySpecifics entity_specifics; 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) entity_specifics.mutable_autofill()->CopyFrom(new_value); 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SetEntitySpecifics(entity_specifics); 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WriteNode::SetAutofillProfileSpecifics( 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const sync_pb::AutofillProfileSpecifics& new_value) { 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sync_pb::EntitySpecifics entity_specifics; 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) entity_specifics.mutable_autofill_profile()-> 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CopyFrom(new_value); 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SetEntitySpecifics(entity_specifics); 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WriteNode::SetBookmarkSpecifics( 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const sync_pb::BookmarkSpecifics& new_value) { 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sync_pb::EntitySpecifics entity_specifics; 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) entity_specifics.mutable_bookmark()->CopyFrom(new_value); 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SetEntitySpecifics(entity_specifics); 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WriteNode::SetNigoriSpecifics( 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const sync_pb::NigoriSpecifics& new_value) { 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sync_pb::EntitySpecifics entity_specifics; 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) entity_specifics.mutable_nigori()->CopyFrom(new_value); 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SetEntitySpecifics(entity_specifics); 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WriteNode::SetPasswordSpecifics( 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const sync_pb::PasswordSpecificsData& data) { 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK_EQ(GetModelType(), PASSWORDS); 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Cryptographer* cryptographer = GetTransaction()->GetCryptographer(); 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We have to do the idempotency check here (vs in UpdateEntryWithEncryption) 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // because Passwords have their encrypted data within the PasswordSpecifics, 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // vs within the EntitySpecifics like all the other types. 156d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) const sync_pb::EntitySpecifics& old_specifics = GetEntry()->GetSpecifics(); 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sync_pb::EntitySpecifics entity_specifics; 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Copy over the old specifics if they exist. 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (GetModelTypeFromSpecifics(old_specifics) == PASSWORDS) { 1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) entity_specifics.CopyFrom(old_specifics); 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AddDefaultFieldValue(PASSWORDS, &entity_specifics); 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sync_pb::PasswordSpecifics* password_specifics = 1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) entity_specifics.mutable_password(); 1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // This will only update password_specifics if the underlying unencrypted blob 1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // was different from |data| or was not encrypted with the proper passphrase. 1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!cryptographer->Encrypt(data, password_specifics->mutable_encrypted())) { 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOTREACHED() << "Failed to encrypt password, possibly due to sync node " 1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) << "corruption"; 1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SetEntitySpecifics(entity_specifics); 1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WriteNode::SetThemeSpecifics( 1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const sync_pb::ThemeSpecifics& new_value) { 1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sync_pb::EntitySpecifics entity_specifics; 1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) entity_specifics.mutable_theme()->CopyFrom(new_value); 1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SetEntitySpecifics(entity_specifics); 1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WriteNode::SetSessionSpecifics( 1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const sync_pb::SessionSpecifics& new_value) { 1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sync_pb::EntitySpecifics entity_specifics; 1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) entity_specifics.mutable_session()->CopyFrom(new_value); 1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SetEntitySpecifics(entity_specifics); 1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WriteNode::SetDeviceInfoSpecifics( 1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const sync_pb::DeviceInfoSpecifics& new_value) { 1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sync_pb::EntitySpecifics entity_specifics; 1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) entity_specifics.mutable_device_info()->CopyFrom(new_value); 1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SetEntitySpecifics(entity_specifics); 1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WriteNode::SetExperimentsSpecifics( 1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const sync_pb::ExperimentsSpecifics& new_value) { 1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sync_pb::EntitySpecifics entity_specifics; 2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) entity_specifics.mutable_experiments()->CopyFrom(new_value); 2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SetEntitySpecifics(entity_specifics); 2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void WriteNode::SetPriorityPreferenceSpecifics( 2052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const sync_pb::PriorityPreferenceSpecifics& new_value) { 2062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) sync_pb::EntitySpecifics entity_specifics; 2072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) entity_specifics.mutable_priority_preference()->CopyFrom(new_value); 2082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) SetEntitySpecifics(entity_specifics); 2092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 2102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WriteNode::SetEntitySpecifics( 2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const sync_pb::EntitySpecifics& new_value) { 2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ModelType new_specifics_type = 2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GetModelTypeFromSpecifics(new_value); 2157dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch CHECK(!new_value.password().has_client_only_encrypted_data()); 2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK_NE(new_specifics_type, UNSPECIFIED); 2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DVLOG(1) << "Writing entity specifics of type " 2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) << ModelTypeToString(new_specifics_type); 2192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK_EQ(new_specifics_type, GetModelType()); 2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Preserve unknown fields. 222d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) const sync_pb::EntitySpecifics& old_specifics = entry_->GetSpecifics(); 2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sync_pb::EntitySpecifics new_specifics; 2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) new_specifics.CopyFrom(new_value); 2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) new_specifics.mutable_unknown_fields()->MergeFrom( 2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) old_specifics.unknown_fields()); 2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Will update the entry if encryption was necessary. 2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!UpdateEntryWithEncryption(GetTransaction()->GetWrappedTrans(), 2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) new_specifics, 2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) entry_)) { 2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 234d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) if (entry_->GetSpecifics().has_encrypted()) { 2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // EncryptIfNecessary already updated the entry for us and marked for 2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // syncing if it was needed. Now we just make a copy of the unencrypted 2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // specifics so that if this node is updated, we do not have to decrypt the 2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // old data. Note that this only modifies the node's local data, not the 2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // entry itself. 2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SetUnencryptedSpecifics(new_value); 2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK_EQ(new_specifics_type, GetModelType()); 2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WriteNode::ResetFromSpecifics() { 2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SetEntitySpecifics(GetEntitySpecifics()); 2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WriteNode::SetTypedUrlSpecifics( 2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const sync_pb::TypedUrlSpecifics& new_value) { 2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sync_pb::EntitySpecifics entity_specifics; 2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) entity_specifics.mutable_typed_url()->CopyFrom(new_value); 2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SetEntitySpecifics(entity_specifics); 2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WriteNode::SetExtensionSpecifics( 2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const sync_pb::ExtensionSpecifics& new_value) { 2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sync_pb::EntitySpecifics entity_specifics; 2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) entity_specifics.mutable_extension()->CopyFrom(new_value); 2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SetEntitySpecifics(entity_specifics); 2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WriteNode::SetExternalId(int64 id) { 2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (GetExternalId() != id) 266d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) entry_->PutLocalExternalId(id); 2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)WriteNode::WriteNode(WriteTransaction* transaction) 2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : entry_(NULL), transaction_(transaction) { 2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(transaction); 2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)WriteNode::~WriteNode() { 2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) delete entry_; 2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Find an existing node matching the ID |id|, and bind this WriteNode to it. 2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Return true on success. 2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)BaseNode::InitByLookupResult WriteNode::InitByIdLookup(int64 id) { 2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(!entry_) << "Init called twice"; 2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK_NE(id, kInvalidId); 2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) entry_ = new syncable::MutableEntry(transaction_->GetWrappedWriteTrans(), 2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) syncable::GET_BY_HANDLE, id); 2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!entry_->good()) 2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return INIT_FAILED_ENTRY_NOT_GOOD; 287d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) if (entry_->GetIsDel()) 2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return INIT_FAILED_ENTRY_IS_DEL; 2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return DecryptIfNecessary() ? INIT_OK : INIT_FAILED_DECRYPT_IF_NECESSARY; 2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Find a node by client tag, and bind this WriteNode to it. 2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Return true if the write node was found, and was not deleted. 2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Undeleting a deleted node is possible by ClientTag. 2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)BaseNode::InitByLookupResult WriteNode::InitByClientTagLookup( 2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ModelType model_type, 2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string& tag) { 2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(!entry_) << "Init called twice"; 2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (tag.empty()) 3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return INIT_FAILED_PRECONDITION; 3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const std::string hash = syncable::GenerateSyncableHash(model_type, tag); 3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) entry_ = new syncable::MutableEntry(transaction_->GetWrappedWriteTrans(), 3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) syncable::GET_BY_CLIENT_TAG, hash); 3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!entry_->good()) 3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return INIT_FAILED_ENTRY_NOT_GOOD; 308d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) if (entry_->GetIsDel()) 3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return INIT_FAILED_ENTRY_IS_DEL; 3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return DecryptIfNecessary() ? INIT_OK : INIT_FAILED_DECRYPT_IF_NECESSARY; 3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 31346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)BaseNode::InitByLookupResult WriteNode::InitTypeRoot(ModelType type) { 3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(!entry_) << "Init called twice"; 31546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) if (!IsRealDataType(type)) 3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return INIT_FAILED_PRECONDITION; 3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) entry_ = new syncable::MutableEntry(transaction_->GetWrappedWriteTrans(), 31846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) syncable::GET_TYPE_ROOT, type); 3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!entry_->good()) 3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return INIT_FAILED_ENTRY_NOT_GOOD; 321d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) if (entry_->GetIsDel()) 3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return INIT_FAILED_ENTRY_IS_DEL; 3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ModelType model_type = GetModelType(); 3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK_EQ(model_type, NIGORI); 3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return INIT_OK; 3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Create a new node with default properties, and bind this WriteNode to it. 3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Return true on success. 3302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool WriteNode::InitBookmarkByCreation(const BaseNode& parent, 3312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const BaseNode* predecessor) { 3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(!entry_) << "Init called twice"; 3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // |predecessor| must be a child of |parent| or NULL. 3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (predecessor && predecessor->GetParentId() != parent.GetId()) { 3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(false); 3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 339d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) syncable::Id parent_id = parent.GetEntry()->GetId(); 3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Start out with a dummy name. We expect 3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // the caller to set a meaningful name after creation. 3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) string dummy(kDefaultNameForNewNodes); 3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) entry_ = new syncable::MutableEntry(transaction_->GetWrappedWriteTrans(), 3462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) syncable::CREATE, BOOKMARKS, 3472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) parent_id, dummy); 3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!entry_->good()) 3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Entries are untitled folders by default. 353d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) entry_->PutIsDir(true); 3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Now set the predecessor, which sets IS_UNSYNCED as necessary. 3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return PutPredecessor(predecessor); 3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Create a new node with default properties and a client defined unique tag, 3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// and bind this WriteNode to it. 3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Return true on success. If the tag exists in the database, then 3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// we will attempt to undelete the node. 3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// TODO(chron): Code datatype into hash tag. 3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// TODO(chron): Is model type ever lost? 3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)WriteNode::InitUniqueByCreationResult WriteNode::InitUniqueByCreation( 3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ModelType model_type, 3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const BaseNode& parent, 3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string& tag) { 3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // This DCHECK will only fail if init is called twice. 3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(!entry_); 3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (tag.empty()) { 3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LOG(WARNING) << "InitUniqueByCreation failed due to empty tag."; 3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return INIT_FAILED_EMPTY_TAG; 3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const std::string hash = syncable::GenerateSyncableHash(model_type, tag); 3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 378d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) syncable::Id parent_id = parent.GetEntry()->GetId(); 3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Start out with a dummy name. We expect 3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // the caller to set a meaningful name after creation. 3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) string dummy(kDefaultNameForNewNodes); 3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Check if we have this locally and need to undelete it. 3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scoped_ptr<syncable::MutableEntry> existing_entry( 3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) new syncable::MutableEntry(transaction_->GetWrappedWriteTrans(), 3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) syncable::GET_BY_CLIENT_TAG, hash)); 3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (existing_entry->good()) { 390d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) if (existing_entry->GetIsDel()) { 3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Rules for undelete: 3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // BASE_VERSION: Must keep the same. 3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // ID: Essential to keep the same. 3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // META_HANDLE: Must be the same, so we can't "split" the entry. 3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // IS_DEL: Must be set to false, will cause reindexing. 3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // This one is weird because IS_DEL is true for "update only" 3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // items. It should be OK to undelete an update only. 3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // MTIME/CTIME: Seems reasonable to just leave them alone. 3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // IS_UNSYNCED: Must set this to true or face database insurrection. 4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We do this below this block. 4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // IS_UNAPPLIED_UPDATE: Either keep it the same or also set BASE_VERSION 4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // to SERVER_VERSION. We keep it the same here. 4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // IS_DIR: We'll leave it the same. 4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // SPECIFICS: Reset it. 4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 406d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) existing_entry->PutIsDel(false); 4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Client tags are immutable and must be paired with the ID. 4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If a server update comes down with an ID and client tag combo, 4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // and it already exists, always overwrite it and store only one copy. 4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We have to undelete entries because we can't disassociate IDs from 4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // tags and updates. 4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 414d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) existing_entry->PutNonUniqueName(dummy); 415d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) existing_entry->PutParentId(parent_id); 4165f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 4175f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // Put specifics to handle the case where this is not actually an 4185f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // undeletion, but instead a collision with a newly downloaded, 4195f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // processed, and unapplied server update. This is a fix for 4205f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // http://crbug.com/397766. 4215f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) sync_pb::EntitySpecifics specifics; 4225f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) AddDefaultFieldValue(model_type, &specifics); 4235f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) existing_entry->PutSpecifics(specifics); 4245f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) entry_ = existing_entry.release(); 4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return INIT_FAILED_ENTRY_ALREADY_EXISTS; 4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) entry_ = new syncable::MutableEntry(transaction_->GetWrappedWriteTrans(), 4312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) syncable::CREATE, 4322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) model_type, parent_id, dummy); 4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!entry_->good()) 4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return INIT_FAILED_COULD_NOT_CREATE_ENTRY; 4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Only set IS_DIR for new entries. Don't bitflip undeleted ones. 437d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) entry_->PutUniqueClientTag(hash); 4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We don't support directory and tag combinations. 441d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) entry_->PutIsDir(false); 4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Now set the predecessor, which sets IS_UNSYNCED as necessary. 4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool success = PutPredecessor(NULL); 4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!success) 4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return INIT_FAILED_SET_PREDECESSOR; 4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return INIT_SUCCESS; 4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool WriteNode::SetPosition(const BaseNode& new_parent, 4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const BaseNode* predecessor) { 4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // |predecessor| must be a child of |new_parent| or NULL. 4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (predecessor && predecessor->GetParentId() != new_parent.GetId()) { 4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(false); 4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 459d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) syncable::Id new_parent_id = new_parent.GetEntry()->GetId(); 4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Filter out redundant changes if both the parent and the predecessor match. 462d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) if (new_parent_id == entry_->GetParentId()) { 4632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const syncable::Id& old = entry_->GetPredecessorId(); 4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ((!predecessor && old.IsRoot()) || 465d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) (predecessor && (old == predecessor->GetEntry()->GetId()))) { 4665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 4675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 470d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) entry_->PutParentId(new_parent_id); 4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Now set the predecessor, which sets IS_UNSYNCED as necessary. 4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return PutPredecessor(predecessor); 4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 476010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)void WriteNode::SetAttachmentMetadata( 477010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) const sync_pb::AttachmentMetadata& attachment_metadata) { 478010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) entry_->PutAttachmentMetadata(attachment_metadata); 479010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)} 480010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) 4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const syncable::Entry* WriteNode::GetEntry() const { 4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return entry_; 4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const BaseTransaction* WriteNode::GetTransaction() const { 4865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return transaction_; 4875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)syncable::MutableEntry* WriteNode::GetMutableEntryForTest() { 4905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return entry_; 4915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void WriteNode::Tombstone() { 4945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // These lines must be in this order. The call to Put(IS_DEL) might choose to 4955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // unset the IS_UNSYNCED bit if the item was not known to the server at the 4965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // time of deletion. It's important that the bit not be reset in that case. 4975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MarkForSyncing(); 498d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) entry_->PutIsDel(true); 4995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void WriteNode::Drop() { 502d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) if (entry_->GetId().ServerKnows()) { 503d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) entry_->PutIsDel(true); 5042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 5052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 5062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 5075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool WriteNode::PutPredecessor(const BaseNode* predecessor) { 5085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) syncable::Id predecessor_id = predecessor ? 509d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) predecessor->GetEntry()->GetId() : syncable::Id(); 5105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!entry_->PutPredecessor(predecessor_id)) 5115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 5125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Mark this entry as unsynced, to wake up the syncer. 5135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MarkForSyncing(); 5145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 5165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WriteNode::MarkForSyncing() { 5195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) syncable::MarkForSyncing(entry_); 5205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace syncer 523