Merge pull request #1388 from hicknhack-software/hotfix/1387_entry-size

Add extend entry-size calculation (resolved #1387)
This commit is contained in:
TheZ3ro 2018-01-23 19:36:57 +01:00 committed by GitHub
commit 50beac2baf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 197 additions and 60 deletions

View File

@ -103,6 +103,15 @@ int AutoTypeAssociations::size() const
return m_associations.size(); return m_associations.size();
} }
int AutoTypeAssociations::associationsSize() const
{
int size = 0;
for (const Association &association : m_associations) {
size += association.sequence.toUtf8().size() + association.window.toUtf8().size();
}
return size;
}
void AutoTypeAssociations::clear() void AutoTypeAssociations::clear()
{ {
m_associations.clear(); m_associations.clear();

View File

@ -43,6 +43,7 @@ public:
AutoTypeAssociations::Association get(int index) const; AutoTypeAssociations::Association get(int index) const;
QList<AutoTypeAssociations::Association> getAll() const; QList<AutoTypeAssociations::Association> getAll() const;
int size() const; int size() const;
int associationsSize() const;
void clear(); void clear();
private: private:

View File

@ -582,22 +582,24 @@ void Entry::truncateHistory()
int histMaxSize = db->metadata()->historyMaxSize(); int histMaxSize = db->metadata()->historyMaxSize();
if (histMaxSize > -1) { if (histMaxSize > -1) {
int size = 0; int size = 0;
QSet<QByteArray> foundAttachments = attachments()->values().toSet(); QSet<QByteArray> foundAttachments = attachments()->values();
QMutableListIterator<Entry*> i(m_history); QMutableListIterator<Entry*> i(m_history);
i.toBack(); i.toBack();
const QRegularExpression delimiter(",|:|;");
while (i.hasPrevious()) { while (i.hasPrevious()) {
Entry* historyItem = i.previous(); Entry* historyItem = i.previous();
// don't calculate size if it's already above the maximum // don't calculate size if it's already above the maximum
if (size <= histMaxSize) { if (size <= histMaxSize) {
size += historyItem->attributes()->attributesSize(); size += historyItem->attributes()->attributesSize();
size += historyItem->autoTypeAssociations()->associationsSize();
const QSet<QByteArray> newAttachments = historyItem->attachments()->values().toSet() - foundAttachments; size += historyItem->attachments()->attachmentsSize();
for (const QByteArray& attachment : newAttachments) { const QStringList tags = historyItem->tags().split(delimiter, QString::SkipEmptyParts);
size += attachment.size(); for (const QString& tag : tags) {
size += tag.toUtf8().size();
} }
foundAttachments += newAttachments; foundAttachments += historyItem->attachments()->values();
} }
if (size > histMaxSize) { if (size > histMaxSize) {
@ -633,7 +635,7 @@ Entry* Entry::clone(CloneFlags flags) const
entry->m_attributes->set(EntryAttributes::PasswordKey, password.toUpper(), m_attributes->isProtected(EntryAttributes::PasswordKey)); entry->m_attributes->set(EntryAttributes::PasswordKey, password.toUpper(), m_attributes->isProtected(EntryAttributes::PasswordKey));
} }
entry->m_autoTypeAssociations->copyDataFrom(this->m_autoTypeAssociations); entry->m_autoTypeAssociations->copyDataFrom(m_autoTypeAssociations);
if (flags & CloneIncludeHistory) { if (flags & CloneIncludeHistory) {
for (Entry* historyItem : m_history) { for (Entry* historyItem : m_history) {
Entry* historyItemClone = historyItem->clone(flags & ~CloneIncludeHistory & ~CloneNewUuid); Entry* historyItemClone = historyItem->clone(flags & ~CloneIncludeHistory & ~CloneNewUuid);
@ -679,6 +681,7 @@ void Entry::beginUpdate()
m_tmpHistoryItem->m_data = m_data; m_tmpHistoryItem->m_data = m_data;
m_tmpHistoryItem->m_attributes->copyDataFrom(m_attributes); m_tmpHistoryItem->m_attributes->copyDataFrom(m_attributes);
m_tmpHistoryItem->m_attachments->copyDataFrom(m_attachments); m_tmpHistoryItem->m_attachments->copyDataFrom(m_attachments);
m_tmpHistoryItem->m_autoTypeAssociations->copyDataFrom(m_autoTypeAssociations);
m_modifiedSinceBegin = false; m_modifiedSinceBegin = false;
} }

View File

@ -18,6 +18,7 @@
#include "EntryAttachments.h" #include "EntryAttachments.h"
#include <QStringList> #include <QStringList>
#include <QSet>
EntryAttachments::EntryAttachments(QObject* parent) EntryAttachments::EntryAttachments(QObject* parent)
: QObject(parent) : QObject(parent)
@ -34,9 +35,9 @@ bool EntryAttachments::hasKey(const QString& key) const
return m_attachments.contains(key); return m_attachments.contains(key);
} }
QList<QByteArray> EntryAttachments::values() const QSet<QByteArray> EntryAttachments::values() const
{ {
return m_attachments.values(); return m_attachments.values().toSet();
} }
QByteArray EntryAttachments::value(const QString& key) const QByteArray EntryAttachments::value(const QString& key) const
@ -151,3 +152,12 @@ bool EntryAttachments::operator!=(const EntryAttachments& other) const
{ {
return m_attachments != other.m_attachments; return m_attachments != other.m_attachments;
} }
int EntryAttachments::attachmentsSize() const
{
int size = 0;
for (auto it = m_attachments.constBegin(); it != m_attachments.constEnd(); ++it) {
size += it.key().toUtf8().size() + it.value().size();
}
return size;
}

View File

@ -31,7 +31,7 @@ public:
explicit EntryAttachments(QObject* parent = nullptr); explicit EntryAttachments(QObject* parent = nullptr);
QList<QString> keys() const; QList<QString> keys() const;
bool hasKey(const QString& key) const; bool hasKey(const QString& key) const;
QList<QByteArray> values() const; QSet<QByteArray> values() const;
QByteArray value(const QString& key) const; QByteArray value(const QString& key) const;
void set(const QString& key, const QByteArray& value); void set(const QString& key, const QByteArray& value);
void remove(const QString& key); void remove(const QString& key);
@ -41,6 +41,7 @@ public:
void copyDataFrom(const EntryAttachments* other); void copyDataFrom(const EntryAttachments* other);
bool operator==(const EntryAttachments& other) const; bool operator==(const EntryAttachments& other) const;
bool operator!=(const EntryAttachments& other) const; bool operator!=(const EntryAttachments& other) const;
int attachmentsSize() const;
signals: signals:
void modified(); void modified();

View File

@ -283,14 +283,11 @@ void EntryAttributes::clear()
emit modified(); emit modified();
} }
int EntryAttributes::attributesSize() int EntryAttributes::attributesSize() const
{ {
int size = 0; int size = 0;
for (auto it = m_attributes.constBegin(); it != m_attributes.constEnd(); ++it) {
QMapIterator<QString, QString> i(m_attributes); size += it.key().toUtf8().size() + it.value().toUtf8().size();
while (i.hasNext()) {
i.next();
size += i.value().toUtf8().size();
} }
return size; return size;
} }

View File

@ -45,7 +45,7 @@ public:
void copyCustomKeysFrom(const EntryAttributes* other); void copyCustomKeysFrom(const EntryAttributes* other);
bool areCustomKeysDifferent(const EntryAttributes* other); bool areCustomKeysDifferent(const EntryAttributes* other);
void clear(); void clear();
int attributesSize(); int attributesSize() const;
void copyDataFrom(const EntryAttributes* other); void copyDataFrom(const EntryAttributes* other);
bool operator==(const EntryAttributes& other) const; bool operator==(const EntryAttributes& other) const;
bool operator!=(const EntryAttributes& other) const; bool operator!=(const EntryAttributes& other) const;

View File

@ -20,7 +20,6 @@
#include <QTest> #include <QTest>
#include "core/Database.h"
#include "core/Entry.h" #include "core/Entry.h"
#include "core/Group.h" #include "core/Group.h"
#include "crypto/Crypto.h" #include "crypto/Crypto.h"
@ -48,6 +47,7 @@ void TestEntry::testHistoryItemDeletion()
delete entry; delete entry;
} }
void TestEntry::testCopyDataFrom() void TestEntry::testCopyDataFrom()
{ {
Entry* entry = new Entry(); Entry* entry = new Entry();

View File

@ -288,14 +288,14 @@ void TestModified::testEntrySets()
delete db; delete db;
} }
void TestModified::testHistoryItem() void TestModified::testHistoryItems()
{ {
Entry* entry = new Entry(); QScopedPointer<Entry> entry(new Entry());
QDateTime created = entry->timeInfo().creationTime(); QDateTime created = entry->timeInfo().creationTime();
entry->setUuid(Uuid::random()); entry->setUuid(Uuid::random());
entry->setTitle("a"); entry->setTitle("a");
entry->setTags("a"); entry->setTags("a");
EntryAttributes* attributes = new EntryAttributes(); QScopedPointer<EntryAttributes> attributes(new EntryAttributes());
attributes->copyCustomKeysFrom(entry->attributes()); attributes->copyCustomKeysFrom(entry->attributes());
Entry* historyEntry; Entry* historyEntry;
@ -338,15 +338,12 @@ void TestModified::testHistoryItem()
attributes->set("k", "myvalue"); attributes->set("k", "myvalue");
entry->beginUpdate(); entry->beginUpdate();
entry->attributes()->copyCustomKeysFrom(attributes); entry->attributes()->copyCustomKeysFrom(attributes.data());
entry->endUpdate(); entry->endUpdate();
QCOMPARE(entry->historyItems().size(), ++historyItemsSize); QCOMPARE(entry->historyItems().size(), ++historyItemsSize);
QVERIFY(!entry->historyItems().at(historyItemsSize - 1)->attributes()->keys().contains("k")); QVERIFY(!entry->historyItems().at(historyItemsSize - 1)->attributes()->keys().contains("k"));
delete attributes; QScopedPointer<Database> db(new Database());
delete entry;
Database* db = new Database();
Group* root = db->rootGroup(); Group* root = db->rootGroup();
db->metadata()->setHistoryMaxItems(3); db->metadata()->setHistoryMaxItems(3);
db->metadata()->setHistoryMaxSize(-1); db->metadata()->setHistoryMaxSize(-1);
@ -400,12 +397,16 @@ void TestModified::testHistoryItem()
entry2->endUpdate(); entry2->endUpdate();
QCOMPARE(entry2->historyItems().size(), 0); QCOMPARE(entry2->historyItems().size(), 0);
db->metadata()->setHistoryMaxItems(-1); const int historyMaxSize = 19000;
db->metadata()->setHistoryMaxSize(17000);
db->metadata()->setHistoryMaxItems(-1);
db->metadata()->setHistoryMaxSize(historyMaxSize);
const QString key("test");
entry2->beginUpdate(); entry2->beginUpdate();
entry2->attachments()->set("test", QByteArray(18000, 'X')); entry2->attachments()->set(key, QByteArray(18000, 'X'));
entry2->endUpdate(); entry2->endUpdate();
QCOMPARE(entry2->attachments()->attachmentsSize(), 18000 + key.size());
QCOMPARE(entry2->historyItems().size(), 1); QCOMPARE(entry2->historyItems().size(), 1);
historyEntry2 = entry2->historyItems().at(0); historyEntry2 = entry2->historyItems().at(0);
@ -417,53 +418,167 @@ void TestModified::testHistoryItem()
QCOMPARE(entry2->historyItems().size(), 2); QCOMPARE(entry2->historyItems().size(), 2);
entry2->beginUpdate(); entry2->beginUpdate();
entry2->attachments()->remove("test"); entry2->attachments()->remove(key);
entry2->endUpdate(); entry2->endUpdate();
QCOMPARE(entry2->historyItems().size(), 0); QCOMPARE(entry2->attachments()->attachmentsSize(), 0);
QCOMPARE(entry2->historyItems().size(), 1);
entry2->beginUpdate(); entry2->beginUpdate();
entry2->attachments()->set("test2", QByteArray(6000, 'a')); entry2->attachments()->set("test2", QByteArray(6000, 'a'));
entry2->endUpdate(); entry2->endUpdate();
QCOMPARE(entry2->historyItems().size(), 1); QCOMPARE(entry2->attachments()->attachmentsSize(), 6000 + key.size() + 1);
QCOMPARE(entry2->historyItems().size(), 2);
entry2->beginUpdate(); entry2->beginUpdate();
entry2->attachments()->set("test3", QByteArray(6000, 'b')); entry2->attachments()->set("test3", QByteArray(6000, 'b'));
entry2->endUpdate(); entry2->endUpdate();
QCOMPARE(entry2->attachments()->attachmentsSize(), 12000 + (key.size() + 1) * 2);
QCOMPARE(entry2->historyItems().size(), 2); QCOMPARE(entry2->historyItems().size(), 2);
entry2->beginUpdate(); entry2->beginUpdate();
entry2->attachments()->set("test4", QByteArray(6000, 'c')); entry2->attachments()->set("test4", QByteArray(6000, 'c'));
entry2->endUpdate(); entry2->endUpdate();
QCOMPARE(entry2->attachments()->attachmentsSize(), 18000 + (key.size() + 1) * 3);
QCOMPARE(entry2->historyItems().size(), 3); QCOMPARE(entry2->historyItems().size(), 3);
entry2->beginUpdate(); entry2->beginUpdate();
entry2->attachments()->set("test5", QByteArray(6000, 'd')); entry2->attachments()->set("test5", QByteArray(6000, 'd'));
entry2->endUpdate(); entry2->endUpdate();
QCOMPARE(entry2->historyItems().size(), 4); QCOMPARE(entry2->attachments()->attachmentsSize(), 24000 + (key.size() + 1) * 4);
QCOMPARE(entry2->historyItems().size(), 1);
Entry* entry3 = new Entry(); }
entry3->setGroup(root);
QCOMPARE(entry3->historyItems().size(), 0); void TestModified::testHistoryMaxSize()
{
entry3->beginUpdate(); QScopedPointer<Database> db(new Database());
entry3->attachments()->set("test", QByteArray(6000, 'a')); const QString key("test");
entry3->endUpdate();
QCOMPARE(entry3->historyItems().size(), 1);
auto entry1 = new Entry();
entry3->beginUpdate(); entry1->setGroup(db->rootGroup());
entry3->attachments()->set("test", QByteArray(6000, 'b')); QCOMPARE(entry1->historyItems().size(), 0);
entry3->endUpdate();
QCOMPARE(entry3->historyItems().size(), 2); const int reservedSize1 = entry1->attributes()->attributesSize();
db->metadata()->setHistoryMaxItems(-1);
entry3->beginUpdate(); db->metadata()->setHistoryMaxSize(18000 + key.size() * 3 + reservedSize1 * 4);
entry3->attachments()->set("test", QByteArray(6000, 'c'));
entry3->endUpdate(); entry1->beginUpdate();
QCOMPARE(entry3->historyItems().size(), 3); entry1->attachments()->set(key, QByteArray(6000, 'a'));
entry1->endUpdate();
entry3->beginUpdate(); QCOMPARE(entry1->attachments()->attachmentsSize(), 6000 + key.size());
entry3->attachments()->set("test", QByteArray(6000, 'd')); QCOMPARE(entry1->historyItems().size(), 1);
entry3->endUpdate();
QCOMPARE(entry3->historyItems().size(), 2); entry1->beginUpdate();
entry1->attachments()->set(key, QByteArray(6000, 'b'));
delete db; entry1->endUpdate();
QCOMPARE(entry1->attachments()->attachmentsSize(), 6000 + key.size());
QCOMPARE(entry1->historyItems().size(), 2);
entry1->beginUpdate();
entry1->attachments()->set(key, QByteArray(6000, 'c'));
entry1->endUpdate();
QCOMPARE(entry1->attachments()->attachmentsSize(), 6000 + key.size());
QCOMPARE(entry1->historyItems().size(), 3);
entry1->beginUpdate();
entry1->attachments()->set(key, QByteArray(6000, 'd'));
entry1->endUpdate();
QCOMPARE(entry1->attachments()->attachmentsSize(), 6000 + key.size());
QCOMPARE(entry1->historyItems().size(), 4);
auto entry2 = new Entry();
entry2->setGroup(db->rootGroup());
QCOMPARE(entry2->historyItems().size(), 0);
const int historyMaxSize = 17000;
const int reservedSize2 = entry2->attributes()->attributesSize();
db->metadata()->setHistoryMaxSize(historyMaxSize);
entry2->beginUpdate();
entry2->attachments()->set(key, QByteArray(historyMaxSize - key.size() - reservedSize2 + 1, 'a'));
entry2->endUpdate();
QCOMPARE(entry2->attachments()->attachmentsSize(), historyMaxSize - reservedSize2 + 1);
QCOMPARE(entry2->historyItems().size(), 1);
// history size overflow
entry2->beginUpdate();
entry2->attachments()->set(key, QByteArray(historyMaxSize - key.size() - reservedSize2 + 1, 'b'));
entry2->endUpdate();
QCOMPARE(entry2->historyItems().size(), 0);
entry2->beginUpdate();
entry2->attachments()->remove(key);
entry2->endUpdate();
QCOMPARE(entry2->attachments()->attachmentsSize(), 0);
QCOMPARE(entry2->historyItems().size(), 0);
entry2->beginUpdate();
entry2->attachments()->set(key, QByteArray(historyMaxSize - key.size() - reservedSize2 + 1, 'a'));
entry2->endUpdate();
QCOMPARE(entry2->attachments()->attachmentsSize(), historyMaxSize - reservedSize2 + 1);
QCOMPARE(entry2->historyItems().size(), 1);
// history size overflow
entry2->beginUpdate();
entry2->attachments()->set(key, QByteArray(historyMaxSize - key.size() - reservedSize2 + 1, 'b'));
entry2->endUpdate();
QCOMPARE(entry2->historyItems().size(), 0);
entry2->beginUpdate();
entry2->attachments()->remove(key);
entry2->endUpdate();
QCOMPARE(entry2->attachments()->attachmentsSize(), 0);
QCOMPARE(entry2->historyItems().size(), 0);
entry2->beginUpdate();
entry2->setTags(QByteArray(historyMaxSize - reservedSize2 + 1, 'a'));
entry2->endUpdate();
QCOMPARE(entry2->tags().size(), historyMaxSize - reservedSize2 + 1);
QCOMPARE(entry2->historyItems().size(), 1);
// history size overflow
entry2->beginUpdate();
entry2->setTags(QByteArray(historyMaxSize - reservedSize2 + 1, 'b'));
entry2->endUpdate();
QCOMPARE(entry2->historyItems().size(), 0);
entry2->beginUpdate();
entry2->setTags("");
entry2->endUpdate();
QCOMPARE(entry2->historyItems().size(), 0);
entry2->beginUpdate();
entry2->attributes()->set(key, QByteArray(historyMaxSize - key.size() - reservedSize2 + 1, 'a'));
entry2->endUpdate();
QCOMPARE(entry2->attributes()->attributesSize(), historyMaxSize + 1);
QCOMPARE(entry2->historyItems().size(), 1);
// history size overflow
entry2->beginUpdate();
entry2->attributes()->set(key, QByteArray(historyMaxSize - key.size() - reservedSize2 + 1, 'b'));
entry2->endUpdate();
QCOMPARE(entry2->attributes()->attributesSize(), historyMaxSize + 1);
QCOMPARE(entry2->historyItems().size(), 0);
entry2->beginUpdate();
entry2->attributes()->remove(key);
entry2->endUpdate();
QCOMPARE(entry2->attributes()->attributesSize(), reservedSize2);
QCOMPARE(entry2->historyItems().size(), 0);
entry2->beginUpdate();
AutoTypeAssociations::Association association;
association.window = key;
association.sequence = QByteArray(historyMaxSize - key.size() - reservedSize2 + 1, 'a');
entry2->autoTypeAssociations()->add(association);
entry2->endUpdate();
QCOMPARE(entry2->autoTypeAssociations()->associationsSize(), historyMaxSize - reservedSize2 + 1);
QCOMPARE(entry2->historyItems().size(), 1);
entry2->beginUpdate();
entry2->autoTypeAssociations()->remove(0);
entry2->endUpdate();
QCOMPARE(entry2->autoTypeAssociations()->associationsSize(), 0);
QCOMPARE(entry2->historyItems().size(), 0);
} }

View File

@ -29,7 +29,8 @@ private slots:
void testSignals(); void testSignals();
void testGroupSets(); void testGroupSets();
void testEntrySets(); void testEntrySets();
void testHistoryItem(); void testHistoryItems();
void testHistoryMaxSize();
}; };
#endif // KEEPASSX_TESTMODIFIED_H #endif // KEEPASSX_TESTMODIFIED_H