Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/keepassxreboot/keepassxc.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/FileWatcher.cpp')
-rw-r--r--src/core/FileWatcher.cpp107
1 files changed, 65 insertions, 42 deletions
diff --git a/src/core/FileWatcher.cpp b/src/core/FileWatcher.cpp
index ae7878191..1b39e597d 100644
--- a/src/core/FileWatcher.cpp
+++ b/src/core/FileWatcher.cpp
@@ -19,6 +19,7 @@
#include "FileWatcher.h"
#include "core/Clock.h"
+#include <QCryptographicHash>
#include <QFileInfo>
#ifdef Q_OS_LINUX
@@ -27,36 +28,23 @@
namespace
{
- const int FileChangeDelay = 500;
- const int TimerResolution = 100;
+ const int FileChangeDelay = 200;
} // namespace
-DelayingFileWatcher::DelayingFileWatcher(QObject* parent)
+FileWatcher::FileWatcher(QObject* parent)
: QObject(parent)
, m_ignoreFileChange(false)
{
- connect(&m_fileWatcher, SIGNAL(fileChanged(QString)), this, SLOT(onWatchedFileChanged()));
- connect(&m_fileUnblockTimer, SIGNAL(timeout()), this, SLOT(observeFileChanges()));
- connect(&m_fileChangeDelayTimer, SIGNAL(timeout()), this, SIGNAL(fileChanged()));
+ connect(&m_fileWatcher, SIGNAL(fileChanged(QString)), SLOT(onWatchedFileChanged()));
+ connect(&m_fileChangeDelayTimer, SIGNAL(timeout()), SIGNAL(fileChanged()));
+ connect(&m_fileChecksumTimer, SIGNAL(timeout()), SLOT(checkFileChecksum()));
m_fileChangeDelayTimer.setSingleShot(true);
- m_fileUnblockTimer.setSingleShot(true);
+ m_fileIgnoreDelayTimer.setSingleShot(true);
}
-void DelayingFileWatcher::restart()
+void FileWatcher::start(const QString& filePath, int checksumInterval)
{
- m_fileWatcher.addPath(m_filePath);
-}
-
-void DelayingFileWatcher::stop()
-{
- m_fileWatcher.removePath(m_filePath);
-}
-
-void DelayingFileWatcher::start(const QString& filePath)
-{
- if (!m_filePath.isEmpty()) {
- m_fileWatcher.removePath(m_filePath);
- }
+ stop();
#if defined(Q_OS_LINUX)
struct statfs statfsBuf;
@@ -74,45 +62,80 @@ void DelayingFileWatcher::start(const QString& filePath)
#endif
m_fileWatcher.addPath(filePath);
+ m_filePath = filePath;
+ m_fileChecksum = calculateChecksum();
+ m_fileChecksumTimer.start(checksumInterval);
+ m_ignoreFileChange = false;
+}
- if (!filePath.isEmpty()) {
- m_filePath = filePath;
+void FileWatcher::stop()
+{
+ if (!m_filePath.isEmpty()) {
+ m_fileWatcher.removePath(m_filePath);
}
+ m_filePath.clear();
+ m_fileChecksum.clear();
+ m_fileChangeDelayTimer.stop();
}
-void DelayingFileWatcher::ignoreFileChanges()
+void FileWatcher::pause()
{
m_ignoreFileChange = true;
m_fileChangeDelayTimer.stop();
}
-void DelayingFileWatcher::observeFileChanges(bool delayed)
+void FileWatcher::resume()
{
- int timeout = 0;
- if (delayed) {
- timeout = FileChangeDelay;
- } else {
- m_ignoreFileChange = false;
- start(m_filePath);
- }
- if (timeout > 0 && !m_fileUnblockTimer.isActive()) {
- m_fileUnblockTimer.start(timeout);
+ m_ignoreFileChange = false;
+ // Add a short delay to start in the next event loop
+ if (!m_fileIgnoreDelayTimer.isActive()) {
+ m_fileIgnoreDelayTimer.start(0);
}
}
-void DelayingFileWatcher::onWatchedFileChanged()
+void FileWatcher::onWatchedFileChanged()
{
- if (m_ignoreFileChange) {
- // the client forcefully silenced us
+ // Don't notify if we are ignoring events or already started a notification chain
+ if (shouldIgnoreChanges()) {
return;
}
- if (m_fileChangeDelayTimer.isActive()) {
- // we are waiting to fire the delayed fileChanged event, so nothing
- // to do here
+
+ m_fileChecksum = calculateChecksum();
+ m_fileChangeDelayTimer.start(0);
+}
+
+bool FileWatcher::shouldIgnoreChanges()
+{
+ return m_filePath.isEmpty() || m_ignoreFileChange || m_fileIgnoreDelayTimer.isActive()
+ || m_fileChangeDelayTimer.isActive();
+}
+
+bool FileWatcher::hasSameFileChecksum()
+{
+ return calculateChecksum() == m_fileChecksum;
+}
+
+void FileWatcher::checkFileChecksum()
+{
+ if (shouldIgnoreChanges()) {
return;
}
- m_fileChangeDelayTimer.start(FileChangeDelay);
+ if (!hasSameFileChecksum()) {
+ onWatchedFileChanged();
+ }
+}
+
+QByteArray FileWatcher::calculateChecksum()
+{
+ QFile file(m_filePath);
+ if (file.open(QFile::ReadOnly)) {
+ QCryptographicHash hash(QCryptographicHash::Sha256);
+ if (hash.addData(&file)) {
+ return hash.result();
+ }
+ }
+ return {};
}
BulkFileWatcher::BulkFileWatcher(QObject* parent)
@@ -281,7 +304,7 @@ void BulkFileWatcher::observeFileChanges(bool delayed)
{
int timeout = 0;
if (delayed) {
- timeout = TimerResolution;
+ timeout = FileChangeDelay;
} else {
const QDateTime current = Clock::currentDateTimeUtc();
for (const QString& key : m_watchedFilesIgnored.keys()) {