summaryrefslogtreecommitdiffstats
path: root/chromium/sync/internal_api/write_node.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/sync/internal_api/write_node.cc')
-rw-r--r--chromium/sync/internal_api/write_node.cc522
1 files changed, 0 insertions, 522 deletions
diff --git a/chromium/sync/internal_api/write_node.cc b/chromium/sync/internal_api/write_node.cc
deleted file mode 100644
index 55f56b78d3f..00000000000
--- a/chromium/sync/internal_api/write_node.cc
+++ /dev/null
@@ -1,522 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "sync/internal_api/public/write_node.h"
-
-#include "base/strings/string_util.h"
-#include "base/strings/utf_string_conversions.h"
-#include "base/values.h"
-#include "sync/internal_api/public/base_transaction.h"
-#include "sync/internal_api/public/write_transaction.h"
-#include "sync/internal_api/syncapi_internal.h"
-#include "sync/protocol/app_specifics.pb.h"
-#include "sync/protocol/autofill_specifics.pb.h"
-#include "sync/protocol/bookmark_specifics.pb.h"
-#include "sync/protocol/extension_specifics.pb.h"
-#include "sync/protocol/password_specifics.pb.h"
-#include "sync/protocol/session_specifics.pb.h"
-#include "sync/protocol/theme_specifics.pb.h"
-#include "sync/protocol/typed_url_specifics.pb.h"
-#include "sync/syncable/mutable_entry.h"
-#include "sync/syncable/nigori_util.h"
-#include "sync/syncable/syncable_util.h"
-#include "sync/util/cryptographer.h"
-
-using std::string;
-using std::vector;
-
-namespace syncer {
-
-using syncable::kEncryptedString;
-using syncable::SPECIFICS;
-
-static const char kDefaultNameForNewNodes[] = " ";
-
-void WriteNode::SetIsFolder(bool folder) {
- if (entry_->GetIsDir() == folder)
- return; // Skip redundant changes.
-
- entry_->PutIsDir(folder);
- MarkForSyncing();
-}
-
-void WriteNode::SetTitle(const std::wstring& title) {
- DCHECK_NE(GetModelType(), UNSPECIFIED);
- ModelType type = GetModelType();
- // It's possible the nigori lost the set of encrypted types. If the current
- // specifics are already encrypted, we want to ensure we continue encrypting.
- bool needs_encryption = GetTransaction()->GetEncryptedTypes().Has(type) ||
- entry_->GetSpecifics().has_encrypted();
-
- // If this datatype is encrypted and is not a bookmark, we disregard the
- // specified title in favor of kEncryptedString. For encrypted bookmarks the
- // NON_UNIQUE_NAME will still be kEncryptedString, but we store the real title
- // into the specifics. All strings compared are server legal strings.
- std::string new_legal_title;
- if (type != BOOKMARKS && needs_encryption) {
- new_legal_title = kEncryptedString;
- } else {
- SyncAPINameToServerName(WideToUTF8(title), &new_legal_title);
- base::TruncateUTF8ToByteSize(new_legal_title, 255, &new_legal_title);
- }
-
- std::string current_legal_title;
- if (BOOKMARKS == type &&
- entry_->GetSpecifics().has_encrypted()) {
- // Encrypted bookmarks only have their title in the unencrypted specifics.
- current_legal_title = GetBookmarkSpecifics().title();
- } else {
- // Non-bookmarks and legacy bookmarks (those with no title in their
- // specifics) store their title in NON_UNIQUE_NAME. Non-legacy bookmarks
- // store their title in specifics as well as NON_UNIQUE_NAME.
- current_legal_title = entry_->GetNonUniqueName();
- }
-
- bool title_matches = (current_legal_title == new_legal_title);
- bool encrypted_without_overwriting_name = (needs_encryption &&
- entry_->GetNonUniqueName() != kEncryptedString);
-
- // If the title matches and the NON_UNIQUE_NAME is properly overwritten as
- // necessary, nothing needs to change.
- if (title_matches && !encrypted_without_overwriting_name) {
- DVLOG(2) << "Title matches, dropping change.";
- return;
- }
-
- // For bookmarks, we also set the title field in the specifics.
- // TODO(zea): refactor bookmarks to not need this functionality.
- if (GetModelType() == BOOKMARKS) {
- sync_pb::EntitySpecifics specifics = GetEntitySpecifics();
- specifics.mutable_bookmark()->set_title(new_legal_title);
- SetEntitySpecifics(specifics); // Does it's own encryption checking.
- }
-
- // For bookmarks, this has to happen after we set the title in the specifics,
- // because the presence of a title in the NON_UNIQUE_NAME is what controls
- // the logic deciding whether this is an empty node or a legacy bookmark.
- // See BaseNode::GetUnencryptedSpecific(..).
- if (needs_encryption)
- entry_->PutNonUniqueName(kEncryptedString);
- else
- entry_->PutNonUniqueName(new_legal_title);
-
- DVLOG(1) << "Overwriting title of type "
- << ModelTypeToString(type)
- << " and marking for syncing.";
- MarkForSyncing();
-}
-
-void WriteNode::SetAppSpecifics(
- const sync_pb::AppSpecifics& new_value) {
- sync_pb::EntitySpecifics entity_specifics;
- entity_specifics.mutable_app()->CopyFrom(new_value);
- SetEntitySpecifics(entity_specifics);
-}
-
-void WriteNode::SetAutofillSpecifics(
- const sync_pb::AutofillSpecifics& new_value) {
- sync_pb::EntitySpecifics entity_specifics;
- entity_specifics.mutable_autofill()->CopyFrom(new_value);
- SetEntitySpecifics(entity_specifics);
-}
-
-void WriteNode::SetAutofillProfileSpecifics(
- const sync_pb::AutofillProfileSpecifics& new_value) {
- sync_pb::EntitySpecifics entity_specifics;
- entity_specifics.mutable_autofill_profile()->
- CopyFrom(new_value);
- SetEntitySpecifics(entity_specifics);
-}
-
-void WriteNode::SetBookmarkSpecifics(
- const sync_pb::BookmarkSpecifics& new_value) {
- sync_pb::EntitySpecifics entity_specifics;
- entity_specifics.mutable_bookmark()->CopyFrom(new_value);
- SetEntitySpecifics(entity_specifics);
-}
-
-void WriteNode::SetNigoriSpecifics(
- const sync_pb::NigoriSpecifics& new_value) {
- sync_pb::EntitySpecifics entity_specifics;
- entity_specifics.mutable_nigori()->CopyFrom(new_value);
- SetEntitySpecifics(entity_specifics);
-}
-
-void WriteNode::SetPasswordSpecifics(
- const sync_pb::PasswordSpecificsData& data) {
- DCHECK_EQ(GetModelType(), PASSWORDS);
-
- Cryptographer* cryptographer = GetTransaction()->GetCryptographer();
-
- // We have to do the idempotency check here (vs in UpdateEntryWithEncryption)
- // because Passwords have their encrypted data within the PasswordSpecifics,
- // vs within the EntitySpecifics like all the other types.
- const sync_pb::EntitySpecifics& old_specifics = GetEntry()->GetSpecifics();
- sync_pb::EntitySpecifics entity_specifics;
- // Copy over the old specifics if they exist.
- if (GetModelTypeFromSpecifics(old_specifics) == PASSWORDS) {
- entity_specifics.CopyFrom(old_specifics);
- } else {
- AddDefaultFieldValue(PASSWORDS, &entity_specifics);
- }
- sync_pb::PasswordSpecifics* password_specifics =
- entity_specifics.mutable_password();
- // This will only update password_specifics if the underlying unencrypted blob
- // was different from |data| or was not encrypted with the proper passphrase.
- if (!cryptographer->Encrypt(data, password_specifics->mutable_encrypted())) {
- NOTREACHED() << "Failed to encrypt password, possibly due to sync node "
- << "corruption";
- return;
- }
- SetEntitySpecifics(entity_specifics);
-}
-
-void WriteNode::SetThemeSpecifics(
- const sync_pb::ThemeSpecifics& new_value) {
- sync_pb::EntitySpecifics entity_specifics;
- entity_specifics.mutable_theme()->CopyFrom(new_value);
- SetEntitySpecifics(entity_specifics);
-}
-
-void WriteNode::SetSessionSpecifics(
- const sync_pb::SessionSpecifics& new_value) {
- sync_pb::EntitySpecifics entity_specifics;
- entity_specifics.mutable_session()->CopyFrom(new_value);
- SetEntitySpecifics(entity_specifics);
-}
-
-void WriteNode::SetManagedUserSettingSpecifics(
- const sync_pb::ManagedUserSettingSpecifics& new_value) {
- sync_pb::EntitySpecifics entity_specifics;
- entity_specifics.mutable_managed_user_setting()->CopyFrom(new_value);
- SetEntitySpecifics(entity_specifics);
-}
-
-void WriteNode::SetManagedUserSpecifics(
- const sync_pb::ManagedUserSpecifics& new_value) {
- sync_pb::EntitySpecifics entity_specifics;
- entity_specifics.mutable_managed_user()->CopyFrom(new_value);
- SetEntitySpecifics(entity_specifics);
-}
-
-void WriteNode::SetDeviceInfoSpecifics(
- const sync_pb::DeviceInfoSpecifics& new_value) {
- sync_pb::EntitySpecifics entity_specifics;
- entity_specifics.mutable_device_info()->CopyFrom(new_value);
- SetEntitySpecifics(entity_specifics);
-}
-
-void WriteNode::SetExperimentsSpecifics(
- const sync_pb::ExperimentsSpecifics& new_value) {
- sync_pb::EntitySpecifics entity_specifics;
- entity_specifics.mutable_experiments()->CopyFrom(new_value);
- SetEntitySpecifics(entity_specifics);
-}
-
-void WriteNode::SetPriorityPreferenceSpecifics(
- const sync_pb::PriorityPreferenceSpecifics& new_value) {
- sync_pb::EntitySpecifics entity_specifics;
- entity_specifics.mutable_priority_preference()->CopyFrom(new_value);
- SetEntitySpecifics(entity_specifics);
-}
-
-void WriteNode::SetEntitySpecifics(
- const sync_pb::EntitySpecifics& new_value) {
- ModelType new_specifics_type =
- GetModelTypeFromSpecifics(new_value);
- CHECK(!new_value.password().has_client_only_encrypted_data());
- DCHECK_NE(new_specifics_type, UNSPECIFIED);
- DVLOG(1) << "Writing entity specifics of type "
- << ModelTypeToString(new_specifics_type);
- DCHECK_EQ(new_specifics_type, GetModelType());
-
- // Preserve unknown fields.
- const sync_pb::EntitySpecifics& old_specifics = entry_->GetSpecifics();
- sync_pb::EntitySpecifics new_specifics;
- new_specifics.CopyFrom(new_value);
- new_specifics.mutable_unknown_fields()->MergeFrom(
- old_specifics.unknown_fields());
-
- // Will update the entry if encryption was necessary.
- if (!UpdateEntryWithEncryption(GetTransaction()->GetWrappedTrans(),
- new_specifics,
- entry_)) {
- return;
- }
- if (entry_->GetSpecifics().has_encrypted()) {
- // EncryptIfNecessary already updated the entry for us and marked for
- // syncing if it was needed. Now we just make a copy of the unencrypted
- // specifics so that if this node is updated, we do not have to decrypt the
- // old data. Note that this only modifies the node's local data, not the
- // entry itself.
- SetUnencryptedSpecifics(new_value);
- }
-
- DCHECK_EQ(new_specifics_type, GetModelType());
-}
-
-void WriteNode::ResetFromSpecifics() {
- SetEntitySpecifics(GetEntitySpecifics());
-}
-
-void WriteNode::SetTypedUrlSpecifics(
- const sync_pb::TypedUrlSpecifics& new_value) {
- sync_pb::EntitySpecifics entity_specifics;
- entity_specifics.mutable_typed_url()->CopyFrom(new_value);
- SetEntitySpecifics(entity_specifics);
-}
-
-void WriteNode::SetExtensionSpecifics(
- const sync_pb::ExtensionSpecifics& new_value) {
- sync_pb::EntitySpecifics entity_specifics;
- entity_specifics.mutable_extension()->CopyFrom(new_value);
- SetEntitySpecifics(entity_specifics);
-}
-
-void WriteNode::SetExternalId(int64 id) {
- if (GetExternalId() != id)
- entry_->PutLocalExternalId(id);
-}
-
-WriteNode::WriteNode(WriteTransaction* transaction)
- : entry_(NULL), transaction_(transaction) {
- DCHECK(transaction);
-}
-
-WriteNode::~WriteNode() {
- delete entry_;
-}
-
-// Find an existing node matching the ID |id|, and bind this WriteNode to it.
-// Return true on success.
-BaseNode::InitByLookupResult WriteNode::InitByIdLookup(int64 id) {
- DCHECK(!entry_) << "Init called twice";
- DCHECK_NE(id, kInvalidId);
- entry_ = new syncable::MutableEntry(transaction_->GetWrappedWriteTrans(),
- syncable::GET_BY_HANDLE, id);
- if (!entry_->good())
- return INIT_FAILED_ENTRY_NOT_GOOD;
- if (entry_->GetIsDel())
- return INIT_FAILED_ENTRY_IS_DEL;
- return DecryptIfNecessary() ? INIT_OK : INIT_FAILED_DECRYPT_IF_NECESSARY;
-}
-
-// Find a node by client tag, and bind this WriteNode to it.
-// Return true if the write node was found, and was not deleted.
-// Undeleting a deleted node is possible by ClientTag.
-BaseNode::InitByLookupResult WriteNode::InitByClientTagLookup(
- ModelType model_type,
- const std::string& tag) {
- DCHECK(!entry_) << "Init called twice";
- if (tag.empty())
- return INIT_FAILED_PRECONDITION;
-
- const std::string hash = syncable::GenerateSyncableHash(model_type, tag);
-
- entry_ = new syncable::MutableEntry(transaction_->GetWrappedWriteTrans(),
- syncable::GET_BY_CLIENT_TAG, hash);
- if (!entry_->good())
- return INIT_FAILED_ENTRY_NOT_GOOD;
- if (entry_->GetIsDel())
- return INIT_FAILED_ENTRY_IS_DEL;
- return DecryptIfNecessary() ? INIT_OK : INIT_FAILED_DECRYPT_IF_NECESSARY;
-}
-
-BaseNode::InitByLookupResult WriteNode::InitByTagLookup(
- const std::string& tag) {
- DCHECK(!entry_) << "Init called twice";
- if (tag.empty())
- return INIT_FAILED_PRECONDITION;
- entry_ = new syncable::MutableEntry(transaction_->GetWrappedWriteTrans(),
- syncable::GET_BY_SERVER_TAG, tag);
- if (!entry_->good())
- return INIT_FAILED_ENTRY_NOT_GOOD;
- if (entry_->GetIsDel())
- return INIT_FAILED_ENTRY_IS_DEL;
- ModelType model_type = GetModelType();
- DCHECK_EQ(model_type, NIGORI);
- return INIT_OK;
-}
-
-// Create a new node with default properties, and bind this WriteNode to it.
-// Return true on success.
-bool WriteNode::InitBookmarkByCreation(const BaseNode& parent,
- const BaseNode* predecessor) {
- DCHECK(!entry_) << "Init called twice";
- // |predecessor| must be a child of |parent| or NULL.
- if (predecessor && predecessor->GetParentId() != parent.GetId()) {
- DCHECK(false);
- return false;
- }
-
- syncable::Id parent_id = parent.GetEntry()->GetId();
-
- // Start out with a dummy name. We expect
- // the caller to set a meaningful name after creation.
- string dummy(kDefaultNameForNewNodes);
-
- entry_ = new syncable::MutableEntry(transaction_->GetWrappedWriteTrans(),
- syncable::CREATE, BOOKMARKS,
- parent_id, dummy);
-
- if (!entry_->good())
- return false;
-
- // Entries are untitled folders by default.
- entry_->PutIsDir(true);
-
- // Now set the predecessor, which sets IS_UNSYNCED as necessary.
- return PutPredecessor(predecessor);
-}
-
-// Create a new node with default properties and a client defined unique tag,
-// and bind this WriteNode to it.
-// Return true on success. If the tag exists in the database, then
-// we will attempt to undelete the node.
-// TODO(chron): Code datatype into hash tag.
-// TODO(chron): Is model type ever lost?
-WriteNode::InitUniqueByCreationResult WriteNode::InitUniqueByCreation(
- ModelType model_type,
- const BaseNode& parent,
- const std::string& tag) {
- // This DCHECK will only fail if init is called twice.
- DCHECK(!entry_);
- if (tag.empty()) {
- LOG(WARNING) << "InitUniqueByCreation failed due to empty tag.";
- return INIT_FAILED_EMPTY_TAG;
- }
-
- const std::string hash = syncable::GenerateSyncableHash(model_type, tag);
-
- syncable::Id parent_id = parent.GetEntry()->GetId();
-
- // Start out with a dummy name. We expect
- // the caller to set a meaningful name after creation.
- string dummy(kDefaultNameForNewNodes);
-
- // Check if we have this locally and need to undelete it.
- scoped_ptr<syncable::MutableEntry> existing_entry(
- new syncable::MutableEntry(transaction_->GetWrappedWriteTrans(),
- syncable::GET_BY_CLIENT_TAG, hash));
-
- if (existing_entry->good()) {
- if (existing_entry->GetIsDel()) {
- // Rules for undelete:
- // BASE_VERSION: Must keep the same.
- // ID: Essential to keep the same.
- // META_HANDLE: Must be the same, so we can't "split" the entry.
- // IS_DEL: Must be set to false, will cause reindexing.
- // This one is weird because IS_DEL is true for "update only"
- // items. It should be OK to undelete an update only.
- // MTIME/CTIME: Seems reasonable to just leave them alone.
- // IS_UNSYNCED: Must set this to true or face database insurrection.
- // We do this below this block.
- // IS_UNAPPLIED_UPDATE: Either keep it the same or also set BASE_VERSION
- // to SERVER_VERSION. We keep it the same here.
- // IS_DIR: We'll leave it the same.
- // SPECIFICS: Reset it.
-
- existing_entry->PutIsDel(false);
-
- // Client tags are immutable and must be paired with the ID.
- // If a server update comes down with an ID and client tag combo,
- // and it already exists, always overwrite it and store only one copy.
- // We have to undelete entries because we can't disassociate IDs from
- // tags and updates.
-
- existing_entry->PutNonUniqueName(dummy);
- existing_entry->PutParentId(parent_id);
- entry_ = existing_entry.release();
- } else {
- return INIT_FAILED_ENTRY_ALREADY_EXISTS;
- }
- } else {
- entry_ = new syncable::MutableEntry(transaction_->GetWrappedWriteTrans(),
- syncable::CREATE,
- model_type, parent_id, dummy);
- if (!entry_->good())
- return INIT_FAILED_COULD_NOT_CREATE_ENTRY;
-
- // Only set IS_DIR for new entries. Don't bitflip undeleted ones.
- entry_->PutUniqueClientTag(hash);
- }
-
- // We don't support directory and tag combinations.
- entry_->PutIsDir(false);
-
- // Now set the predecessor, which sets IS_UNSYNCED as necessary.
- bool success = PutPredecessor(NULL);
- if (!success)
- return INIT_FAILED_SET_PREDECESSOR;
-
- return INIT_SUCCESS;
-}
-
-bool WriteNode::SetPosition(const BaseNode& new_parent,
- const BaseNode* predecessor) {
- // |predecessor| must be a child of |new_parent| or NULL.
- if (predecessor && predecessor->GetParentId() != new_parent.GetId()) {
- DCHECK(false);
- return false;
- }
-
- syncable::Id new_parent_id = new_parent.GetEntry()->GetId();
-
- // Filter out redundant changes if both the parent and the predecessor match.
- if (new_parent_id == entry_->GetParentId()) {
- const syncable::Id& old = entry_->GetPredecessorId();
- if ((!predecessor && old.IsRoot()) ||
- (predecessor && (old == predecessor->GetEntry()->GetId()))) {
- return true;
- }
- }
-
- entry_->PutParentId(new_parent_id);
-
- // Now set the predecessor, which sets IS_UNSYNCED as necessary.
- return PutPredecessor(predecessor);
-}
-
-const syncable::Entry* WriteNode::GetEntry() const {
- return entry_;
-}
-
-const BaseTransaction* WriteNode::GetTransaction() const {
- return transaction_;
-}
-
-syncable::MutableEntry* WriteNode::GetMutableEntryForTest() {
- return entry_;
-}
-
-void WriteNode::Tombstone() {
- // These lines must be in this order. The call to Put(IS_DEL) might choose to
- // unset the IS_UNSYNCED bit if the item was not known to the server at the
- // time of deletion. It's important that the bit not be reset in that case.
- MarkForSyncing();
- entry_->PutIsDel(true);
-}
-
-void WriteNode::Drop() {
- if (entry_->GetId().ServerKnows()) {
- entry_->PutIsDel(true);
- }
-}
-
-bool WriteNode::PutPredecessor(const BaseNode* predecessor) {
- syncable::Id predecessor_id = predecessor ?
- predecessor->GetEntry()->GetId() : syncable::Id();
- if (!entry_->PutPredecessor(predecessor_id))
- return false;
- // Mark this entry as unsynced, to wake up the syncer.
- MarkForSyncing();
-
- return true;
-}
-
-void WriteNode::MarkForSyncing() {
- syncable::MarkForSyncing(entry_);
-}
-
-} // namespace syncer