summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/corelib/io/qfilesystemwatcher_inotify.cpp21
-rw-r--r--src/corelib/io/qfilesystemwatcher_inotify_p.h5
-rw-r--r--tests/auto/corelib/io/qfilesystemwatcher/tst_qfilesystemwatcher.cpp81
3 files changed, 102 insertions, 5 deletions
diff --git a/src/corelib/io/qfilesystemwatcher_inotify.cpp b/src/corelib/io/qfilesystemwatcher_inotify.cpp
index 024af79c33..c731f3d417 100644
--- a/src/corelib/io/qfilesystemwatcher_inotify.cpp
+++ b/src/corelib/io/qfilesystemwatcher_inotify.cpp
@@ -365,11 +365,11 @@ void QInotifyFileSystemWatcherEngine::readFromInotify()
// qDebug() << "inotify event, wd" << event.wd << "mask" << hex << event.mask;
int id = event.wd;
- QString path = idToPath.value(id);
+ QString path = getPathFromID(id);
if (path.isEmpty()) {
// perhaps a directory?
id = -id;
- path = idToPath.value(id);
+ path = getPathFromID(id);
if (path.isEmpty())
continue;
}
@@ -378,8 +378,9 @@ void QInotifyFileSystemWatcherEngine::readFromInotify()
if ((event.mask & (IN_DELETE_SELF | IN_MOVE_SELF | IN_UNMOUNT)) != 0) {
pathToID.remove(path);
- idToPath.remove(id);
- inotify_rm_watch(inotifyFd, event.wd);
+ idToPath.remove(id, getPathFromID(id));
+ if (!idToPath.contains(id))
+ inotify_rm_watch(inotifyFd, event.wd);
if (id < 0)
emit directoryChanged(path, true);
@@ -394,6 +395,18 @@ void QInotifyFileSystemWatcherEngine::readFromInotify()
}
}
+QString QInotifyFileSystemWatcherEngine::getPathFromID(int id) const
+{
+ QHash<int, QString>::const_iterator i = idToPath.find(id);
+ while (i != idToPath.constEnd() && i.key() == id) {
+ if ((i + 1) == idToPath.constEnd() || (i + 1).key() != id) {
+ return i.value();
+ }
+ ++i;
+ }
+ return QString();
+}
+
QT_END_NAMESPACE
#endif // QT_NO_FILESYSTEMWATCHER
diff --git a/src/corelib/io/qfilesystemwatcher_inotify_p.h b/src/corelib/io/qfilesystemwatcher_inotify_p.h
index 959d9edc12..d02f04eed6 100644
--- a/src/corelib/io/qfilesystemwatcher_inotify_p.h
+++ b/src/corelib/io/qfilesystemwatcher_inotify_p.h
@@ -79,10 +79,13 @@ private Q_SLOTS:
void readFromInotify();
private:
+ QString getPathFromID(int id) const;
+
+private:
QInotifyFileSystemWatcherEngine(int fd, QObject *parent);
int inotifyFd;
QHash<QString, int> pathToID;
- QHash<int, QString> idToPath;
+ QMultiHash<int, QString> idToPath;
QSocketNotifier notifier;
};
diff --git a/tests/auto/corelib/io/qfilesystemwatcher/tst_qfilesystemwatcher.cpp b/tests/auto/corelib/io/qfilesystemwatcher/tst_qfilesystemwatcher.cpp
index 4105a43735..20ef7b5a76 100644
--- a/tests/auto/corelib/io/qfilesystemwatcher/tst_qfilesystemwatcher.cpp
+++ b/tests/auto/corelib/io/qfilesystemwatcher/tst_qfilesystemwatcher.cpp
@@ -79,6 +79,8 @@ private slots:
void QTBUG2331();
void QTBUG2331_data() { basicTest_data(); }
+ void signalsEmittedAfterFileMoved();
+
private:
QString m_tempDirPattern;
};
@@ -596,5 +598,84 @@ void tst_QFileSystemWatcher::QTBUG2331()
QCOMPARE(watcher.directories(), QStringList());
}
+class SignalReceiver : public QObject
+{
+ Q_OBJECT
+public:
+ SignalReceiver(const QDir &moveSrcDir,
+ const QString &moveDestination,
+ QFileSystemWatcher *watcher,
+ QObject *parent = 0)
+ : QObject(parent),
+ added(false),
+ moveSrcDir(moveSrcDir),
+ moveDestination(QDir(moveDestination)),
+ watcher(watcher)
+ {}
+
+public slots:
+ void fileChanged(const QString &path)
+ {
+ QFileInfo finfo(path);
+
+ QCOMPARE(finfo.absolutePath(), moveSrcDir.absolutePath());
+
+ if (!added) {
+ foreach (const QFileInfo &fi, moveDestination.entryInfoList(QDir::Files | QDir::NoSymLinks))
+ watcher->addPath(fi.absoluteFilePath());
+ added = true;
+ }
+ }
+
+private:
+ bool added;
+ QDir moveSrcDir;
+ QDir moveDestination;
+ QFileSystemWatcher *watcher;
+};
+
+// regression test for QTBUG-33211.
+// using inotify backend if a file is moved and then added to the watcher
+// before all the fileChanged signals are emitted the remaining signals are
+// emitted with the destination path instead of the starting path
+void tst_QFileSystemWatcher::signalsEmittedAfterFileMoved()
+{
+ QTemporaryDir temporaryDirectory(m_tempDirPattern);
+ QVERIFY(temporaryDirectory.isValid());
+ QDir testDir(temporaryDirectory.path());
+ QVERIFY(testDir.mkdir("movehere"));
+ QString movePath = testDir.filePath("movehere");
+
+ for (int i = 0; i < 10; i++) {
+ QFile f(testDir.filePath(QString("test%1.txt").arg(i)));
+ QVERIFY(f.open(QIODevice::WriteOnly));
+ f.write(QByteArray("i am " + i));
+ f.close();
+ }
+
+ QFileSystemWatcher watcher;
+ QVERIFY(watcher.addPath(testDir.path()));
+ QVERIFY(watcher.addPath(movePath));
+
+ // add files to watcher
+ QFileInfoList files = testDir.entryInfoList(QDir::Files | QDir::NoSymLinks);
+ foreach (const QFileInfo &finfo, files)
+ QVERIFY(watcher.addPath(finfo.absoluteFilePath()));
+
+ // create the signal receiver
+ SignalReceiver signalReceiver(testDir, movePath, &watcher);
+ connect(&watcher, SIGNAL(fileChanged(QString)), &signalReceiver, SLOT(fileChanged(QString)));
+
+ // watch signals
+ QSignalSpy changedSpy(&watcher, SIGNAL(fileChanged(QString)));
+ QVERIFY(changedSpy.isValid());
+
+ // move files to second directory
+ foreach (const QFileInfo &finfo, files)
+ QVERIFY(testDir.rename(finfo.fileName(), QString("movehere/%2").arg(finfo.fileName())));
+
+ QTRY_COMPARE(changedSpy.count(), 10);
+}
+
QTEST_MAIN(tst_QFileSystemWatcher)
#include "tst_qfilesystemwatcher.moc"