diff --git a/autotests/unit/file/kinotifytest.cpp b/autotests/unit/file/kinotifytest.cpp --- a/autotests/unit/file/kinotifytest.cpp +++ b/autotests/unit/file/kinotifytest.cpp @@ -44,6 +44,7 @@ void testMoveFile(); void testRenameFolder(); void testMoveFolder(); + void testMoveFromUnwatchedFolder(); void testMoveRootFolder(); void testFileClosedAfterWrite(); }; @@ -351,6 +352,42 @@ QCOMPARE(createdSpy.takeFirst().at(0).toString(), f4); } +void KInotifyTest::testMoveFromUnwatchedFolder() +{ + // create some test folders + QTemporaryDir dir; + const QString src(QStringLiteral("%1/randomJunk1").arg(dir.path())); + const QString dest(QStringLiteral("%1/randomJunk2").arg(dir.path())); + mkdir(src); + mkdir(dest); + + // Start watching only for destination + KInotify kn(nullptr); + kn.addWatch(dest, KInotify::EventAll); + QSignalSpy spy(&kn, &KInotify::created); + + // Create stuff inside src + mkdir(QStringLiteral("%1/sub").arg(src)); + touchFile(QStringLiteral("%1/sub/file1").arg(src)); + mkdir(QStringLiteral("%1/sub/sub1").arg(src)); + touchFile(QStringLiteral("%1/sub/sub1/file2").arg(src)); + + // Now move + QFile::rename(QStringLiteral("%1/sub").arg(src), + QStringLiteral("%1/sub").arg(dest)); + + QVERIFY(spy.wait()); + QCOMPARE(spy.count(), 4); + + // Checking if watches are installed + QSignalSpy spy1(&kn, &KInotify::deleted); + QDir dstdir(QStringLiteral("%1/sub").arg(dest)); + dstdir.removeRecursively(); + + QVERIFY(spy1.wait()); + QCOMPARE(spy1.count(), 4); +} + void KInotifyTest::testMoveRootFolder() { diff --git a/src/file/kinotify.h b/src/file/kinotify.h --- a/src/file/kinotify.h +++ b/src/file/kinotify.h @@ -191,6 +191,13 @@ class Private; Private* const d; + /** + * Recursively iterates over all files/folders inside @param path; + * emits created() signal for each entry (excluding @param path) + * and installs watches for all subdirectories (including @param path) + */ + void handleDirCreated(const QString& path); + Q_PRIVATE_SLOT(d, bool _k_addWatches()) }; diff --git a/src/file/kinotify.cpp b/src/file/kinotify.cpp --- a/src/file/kinotify.cpp +++ b/src/file/kinotify.cpp @@ -309,6 +309,20 @@ return true; } +void KInotify::handleDirCreated(const QString& path) +{ + Baloo::FilteredDirIterator it(d->config, path); + // First entry is the directory itself (if not excluded) + if (!it.next().isEmpty()) { + d->addWatch(it.filePath()); + } + while (!it.next().isEmpty()) { + Q_EMIT created(it.filePath(), it.fileInfo().isDir()); + if (it.fileInfo().isDir()) { + d->addWatch(it.filePath()); + } + } +} void KInotify::slotEvent(int socket) { @@ -369,11 +383,12 @@ } if (event->mask & EventCreate) { // qCDebug(BALOO) << path << "EventCreate"; + Q_EMIT created(QFile::decodeName(path), event->mask & IN_ISDIR); if (event->mask & IN_ISDIR) { - // FIXME: store the mode and flags somewhere - addWatch(QString::fromUtf8(path), d->mode, d->flags); + // Files/directories inside the new directory may be created before the watch + // is installed. Ensure created events for all children are issued at least once + handleDirCreated(QFile::decodeName(path)); } - Q_EMIT created(QFile::decodeName(path), event->mask & IN_ISDIR); } if (event->mask & EventDeleteSelf) { // qCDebug(BALOO) << path << "EventDeleteSelf"; @@ -421,7 +436,10 @@ Q_EMIT moved(QFile::decodeName(oldPath), QFile::decodeName(path)); } else { // qCDebug(BALOO) << "No cookie for move information of" << path << "simulating new file event"; - Q_EMIT created(QString::fromUtf8(path), event->mask & IN_ISDIR); + Q_EMIT created(QFile::decodeName(path), event->mask & IN_ISDIR); + if (event->mask & IN_ISDIR) { + handleDirCreated(QFile::decodeName(path)); + } } } if (event->mask & EventOpen) {