From 223a8e9a5e1500995dd419564383b2f20c81de18 Mon Sep 17 00:00:00 2001 From: J-Jamet Date: Wed, 19 Jan 2022 19:12:44 +0100 Subject: [PATCH] Fix concurrent modification exception --- .../database/element/entry/EntryKDB.kt | 5 +-- .../database/element/entry/EntryKDBX.kt | 6 ++-- .../database/element/group/GroupKDB.kt | 5 +-- .../database/element/group/GroupKDBX.kt | 5 +-- .../database/element/group/GroupVersioned.kt | 13 ++++--- .../database/element/node/NodeVersioned.kt | 7 ++-- .../database/merge/DatabaseKDBXMerger.kt | 34 ++++++++++++------- 7 files changed, 47 insertions(+), 28 deletions(-) diff --git a/app/src/main/java/com/kunzisoft/keepass/database/element/entry/EntryKDB.kt b/app/src/main/java/com/kunzisoft/keepass/database/element/entry/EntryKDB.kt index d2ff9312e..4a2d7f7ca 100644 --- a/app/src/main/java/com/kunzisoft/keepass/database/element/entry/EntryKDB.kt +++ b/app/src/main/java/com/kunzisoft/keepass/database/element/entry/EntryKDB.kt @@ -139,8 +139,9 @@ class EntryKDB : EntryVersioned, NodeKDBInterface dest.writeInt(binaryDataId ?: -1) } - fun updateWith(source: EntryKDB) { - super.updateWith(source) + fun updateWith(source: EntryKDB, + updateParents: Boolean = true) { + super.updateWith(source, updateParents) title = source.title username = source.username password = source.password diff --git a/app/src/main/java/com/kunzisoft/keepass/database/element/entry/EntryKDBX.kt b/app/src/main/java/com/kunzisoft/keepass/database/element/entry/EntryKDBX.kt index 43d48fbed..638db71c2 100644 --- a/app/src/main/java/com/kunzisoft/keepass/database/element/entry/EntryKDBX.kt +++ b/app/src/main/java/com/kunzisoft/keepass/database/element/entry/EntryKDBX.kt @@ -110,8 +110,10 @@ class EntryKDBX : EntryVersioned, NodeKDBXInte * Update with deep copy of each entry element * @param source */ - fun updateWith(source: EntryKDBX, copyHistory: Boolean = true) { - super.updateWith(source) + fun updateWith(source: EntryKDBX, + copyHistory: Boolean = true, + updateParents: Boolean = true) { + super.updateWith(source, updateParents) usageCount = source.usageCount locationChanged = DateInstant(source.locationChanged) customData = CustomData(source.customData) diff --git a/app/src/main/java/com/kunzisoft/keepass/database/element/group/GroupKDB.kt b/app/src/main/java/com/kunzisoft/keepass/database/element/group/GroupKDB.kt index 3d25c255f..e74fcd016 100644 --- a/app/src/main/java/com/kunzisoft/keepass/database/element/group/GroupKDB.kt +++ b/app/src/main/java/com/kunzisoft/keepass/database/element/group/GroupKDB.kt @@ -53,8 +53,9 @@ class GroupKDB : GroupVersioned, NodeKDBInterface dest.writeInt(groupFlags) } - fun updateWith(source: GroupKDB) { - super.updateWith(source) + fun updateWith(source: GroupKDB, + updateParents: Boolean = true) { + super.updateWith(source, updateParents) groupFlags = source.groupFlags } diff --git a/app/src/main/java/com/kunzisoft/keepass/database/element/group/GroupKDBX.kt b/app/src/main/java/com/kunzisoft/keepass/database/element/group/GroupKDBX.kt index d2bc674f2..172091432 100644 --- a/app/src/main/java/com/kunzisoft/keepass/database/element/group/GroupKDBX.kt +++ b/app/src/main/java/com/kunzisoft/keepass/database/element/group/GroupKDBX.kt @@ -102,8 +102,9 @@ class GroupKDBX : GroupVersioned, NodeKDBXInte dest.writeParcelable(ParcelUuid(previousParentGroup), flags) } - fun updateWith(source: GroupKDBX) { - super.updateWith(source) + fun updateWith(source: GroupKDBX, + updateParents: Boolean = true) { + super.updateWith(source, updateParents) usageCount = source.usageCount locationChanged = DateInstant(source.locationChanged) // Add all custom elements in map diff --git a/app/src/main/java/com/kunzisoft/keepass/database/element/group/GroupVersioned.kt b/app/src/main/java/com/kunzisoft/keepass/database/element/group/GroupVersioned.kt index c137d1979..e1ed865da 100644 --- a/app/src/main/java/com/kunzisoft/keepass/database/element/group/GroupVersioned.kt +++ b/app/src/main/java/com/kunzisoft/keepass/database/element/group/GroupVersioned.kt @@ -51,12 +51,15 @@ abstract class GroupVersioned dest.writeString(titleGroup) } - protected fun updateWith(source: GroupVersioned) { - super.updateWith(source) + protected fun updateWith(source: GroupVersioned, + updateParents: Boolean = true) { + super.updateWith(source, updateParents) titleGroup = source.titleGroup - removeChildren() - childGroups.addAll(source.childGroups) - childEntries.addAll(source.childEntries) + if (updateParents) { + removeChildren() + childGroups.addAll(source.childGroups) + childEntries.addAll(source.childEntries) + } } override var title: String diff --git a/app/src/main/java/com/kunzisoft/keepass/database/element/node/NodeVersioned.kt b/app/src/main/java/com/kunzisoft/keepass/database/element/node/NodeVersioned.kt index d2b5b4e6b..5bbd81cf9 100644 --- a/app/src/main/java/com/kunzisoft/keepass/database/element/node/NodeVersioned.kt +++ b/app/src/main/java/com/kunzisoft/keepass/database/element/node/NodeVersioned.kt @@ -68,9 +68,12 @@ abstract class NodeVersioned) { + protected fun updateWith(source: NodeVersioned, + updateParents: Boolean = true) { this.nodeId = copyNodeId(source.nodeId) - this.parent = source.parent + if (updateParents) { + this.parent = source.parent + } this.icon = source.icon this.creationTime = DateInstant(source.creationTime) this.lastModificationTime = DateInstant(source.lastModificationTime) diff --git a/app/src/main/java/com/kunzisoft/keepass/database/merge/DatabaseKDBXMerger.kt b/app/src/main/java/com/kunzisoft/keepass/database/merge/DatabaseKDBXMerger.kt index 920ff8e8c..392d6123d 100644 --- a/app/src/main/java/com/kunzisoft/keepass/database/merge/DatabaseKDBXMerger.kt +++ b/app/src/main/java/com/kunzisoft/keepass/database/merge/DatabaseKDBXMerger.kt @@ -80,7 +80,8 @@ class DatabaseKDBXMerger(private var database: DatabaseKDBX) { database.settingsChanged = databaseToMerge.settingsChanged } - val rootGroupId = database.rootGroup?.nodeId + val rootGroup = database.rootGroup + val rootGroupId = rootGroup?.nodeId val rootGroupToMerge = databaseToMerge.rootGroup val rootGroupIdToMerge = rootGroupToMerge?.nodeId @@ -91,16 +92,18 @@ class DatabaseKDBXMerger(private var database: DatabaseKDBX) { // UUID of the root group to merge is unknown if (database.getGroupById(rootGroupIdToMerge) == null) { // Change it to copy children database root - // TODO Test merge root databaseToMerge.removeGroupIndex(rootGroupToMerge) rootGroupToMerge.nodeId = rootGroupId databaseToMerge.addGroupIndex(rootGroupToMerge) } // Merge root group - mergeGroup(rootGroupToMerge, databaseToMerge) + if (rootGroup.lastModificationTime.date + .before(rootGroupToMerge.lastModificationTime.date)) { + rootGroup.updateWith(rootGroupToMerge, updateParents = false) + } // Merge children - databaseToMerge.rootGroup?.doForEachChild( + rootGroupToMerge.doForEachChild( object : NodeHandler() { override fun operate(node: EntryKDBX): Boolean { mergeEntry(node, databaseToMerge) @@ -206,16 +209,19 @@ class DatabaseKDBXMerger(private var database: DatabaseKDBX) { private fun mergeEntry(nodeToMerge: EntryKDBX, databaseToMerge: DatabaseKDBX) { val entryId = nodeToMerge.nodeId - val entryToMerge = databaseToMerge.getEntryById(entryId) val entry = database.getEntryById(entryId) val deletedObject = database.getDeletedObject(entryId) - if (entryToMerge != null) { + databaseToMerge.getEntryById(entryId)?.let { srcEntryToMerge -> // Retrieve parent in current database var parentEntryToMerge: GroupKDBX? = null - entryToMerge.parent?.nodeId?.let { + srcEntryToMerge.parent?.nodeId?.let { parentEntryToMerge = database.getGroupById(it) } + val entryToMerge = EntryKDBX().apply { + updateWith(srcEntryToMerge, copyHistory = true, updateParents = false) + } + // Copy attachments in main pool val newAttachments = mutableListOf() entryToMerge.getAttachments(databaseToMerge.attachmentPool).forEach { attachment -> @@ -257,7 +263,7 @@ class DatabaseKDBXMerger(private var database: DatabaseKDBX) { ) { addHistory(entry, entryToMerge) if (parentEntryToMerge == entry.parent) { - entry.updateWith(entryToMerge) + entry.updateWith(entryToMerge, copyHistory = true, updateParents = false) } else { // Update entry with databaseEntryToMerge and merge history database.removeEntryFrom(entry, entry.parent) @@ -289,7 +295,7 @@ class DatabaseKDBXMerger(private var database: DatabaseKDBX) { it.lastModificationTime == entryA.lastModificationTime } == null) { val history = EntryKDBX().apply { - updateWith(entryA, false) + updateWith(entryA, copyHistory = false, updateParents = false) parent = null } entryB.addEntryToHistory(history) @@ -298,16 +304,18 @@ class DatabaseKDBXMerger(private var database: DatabaseKDBX) { private fun mergeGroup(nodeToMerge: GroupKDBX, databaseToMerge: DatabaseKDBX) { val groupId = nodeToMerge.nodeId - val groupToMerge = databaseToMerge.getGroupById(groupId) val group = database.getGroupById(groupId) val deletedObject = database.getDeletedObject(groupId) - if (groupToMerge != null) { + databaseToMerge.getGroupById(groupId)?.let { srcGroupToMerge -> // Retrieve parent in current database var parentGroupToMerge: GroupKDBX? = null - groupToMerge.parent?.nodeId?.let { + srcGroupToMerge.parent?.nodeId?.let { parentGroupToMerge = database.getGroupById(it) } + val groupToMerge = GroupKDBX().apply { + updateWith(srcGroupToMerge, updateParents = false) + } if (group == null) { // If group parent to add exists and in current database @@ -325,7 +333,7 @@ class DatabaseKDBXMerger(private var database: DatabaseKDBX) { .before(groupToMerge.lastModificationTime.date) ) { if (parentGroupToMerge == group.parent) { - group.updateWith(groupToMerge) + group.updateWith(groupToMerge, false) } else { database.removeGroupFrom(group, group.parent) if (parentGroupToMerge != null) {