summaryrefslogtreecommitdiffstats
path: root/src/corelib/io
diff options
context:
space:
mode:
authorFriedemann Kleint <Friedemann.Kleint@qt.io>2017-07-06 12:38:31 +0200
committerFriedemann Kleint <Friedemann.Kleint@qt.io>2017-07-07 07:02:45 +0000
commite1d7f7dfbc0191f585fde8695d315e3ffb98ccc5 (patch)
tree5bba7abf1240bb358f6c2116d9960f9478d4df26 /src/corelib/io
parent7beb2bc02bff9fa591eb60b978ed97d0601bedfd (diff)
QFileSystemWatcher/Windows: Recreate handle for files
QWindowsFileSystemWatcherEngine uses one change notification per directory to watch directories or files within that directory. Adding files and their directories in a sequence caused the value in QWindowsFileSystemWatcherEngineThread::HandleForDirHash to be overwritten. Relax the check for the flags (watcher attributes) to use >= and recreate the change notification of a directory should its flags be insufficient. This triggers when a file is added after its directory since files require more attributes. Task-number: QTBUG-61792 Change-Id: I371a72f1934fa82c53aaf84beb907825031f1c81 Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
Diffstat (limited to 'src/corelib/io')
-rw-r--r--src/corelib/io/qfilesystemwatcher_win.cpp47
1 files changed, 38 insertions, 9 deletions
diff --git a/src/corelib/io/qfilesystemwatcher_win.cpp b/src/corelib/io/qfilesystemwatcher_win.cpp
index c385a82fc5..ff0d45935c 100644
--- a/src/corelib/io/qfilesystemwatcher_win.cpp
+++ b/src/corelib/io/qfilesystemwatcher_win.cpp
@@ -71,6 +71,19 @@ QT_BEGIN_NAMESPACE
# define DEBUG if (false) qDebug
#endif
+static Qt::HANDLE createChangeNotification(const QString &path, uint flags)
+{
+ // Volume and folder paths need a trailing slash for proper notification
+ // (e.g. "c:" -> "c:/").
+ QString nativePath = QDir::toNativeSeparators(path);
+ if ((flags & FILE_NOTIFY_CHANGE_ATTRIBUTES) == 0 && !nativePath.endsWith(QLatin1Char('\\')))
+ nativePath.append(QLatin1Char('\\'));
+ const HANDLE result = FindFirstChangeNotification(reinterpret_cast<const wchar_t *>(nativePath.utf16()),
+ FALSE, flags);
+ DEBUG() << __FUNCTION__ << nativePath << hex <<showbase << flags << "returns" << result;
+ return result;
+}
+
#ifndef Q_OS_WINRT
///////////
// QWindowsRemovableDriveListener
@@ -404,8 +417,29 @@ QStringList QWindowsFileSystemWatcherEngine::addPaths(const QStringList &paths,
thread = *jt;
QMutexLocker locker(&(thread->mutex));
- handle = thread->handleForDir.value(QFileSystemWatcherPathKey(absolutePath));
- if (handle.handle != INVALID_HANDLE_VALUE && handle.flags == flags) {
+ const auto hit = thread->handleForDir.find(QFileSystemWatcherPathKey(absolutePath));
+ if (hit != thread->handleForDir.end() && hit.value().flags < flags) {
+ // Requesting to add a file whose directory has been added previously.
+ // Recreate the notification handle to add the missing notification attributes
+ // for files (FILE_NOTIFY_CHANGE_ATTRIBUTES...)
+ DEBUG() << "recreating" << absolutePath << hex << showbase << hit.value().flags
+ << "->" << flags;
+ const Qt::HANDLE fileHandle = createChangeNotification(absolutePath, flags);
+ if (fileHandle != INVALID_HANDLE_VALUE) {
+ const int index = thread->handles.indexOf(hit.value().handle);
+ const auto pit = thread->pathInfoForHandle.find(hit.value().handle);
+ Q_ASSERT(index != -1);
+ Q_ASSERT(pit != thread->pathInfoForHandle.end());
+ FindCloseChangeNotification(hit.value().handle);
+ thread->handles[index] = hit.value().handle = fileHandle;
+ hit.value().flags = flags;
+ thread->pathInfoForHandle.insert(fileHandle, pit.value());
+ thread->pathInfoForHandle.erase(pit);
+ }
+ }
+ // In addition, check on flags for sufficient notification attributes
+ if (hit != thread->handleForDir.end() && hit.value().flags >= flags) {
+ handle = hit.value();
// found a thread now insert...
DEBUG() << "Found a thread" << thread;
@@ -426,14 +460,9 @@ QStringList QWindowsFileSystemWatcherEngine::addPaths(const QStringList &paths,
}
// no thread found, first create a handle
- if (handle.handle == INVALID_HANDLE_VALUE || handle.flags != flags) {
+ if (handle.handle == INVALID_HANDLE_VALUE) {
DEBUG() << "No thread found";
- // Volume and folder paths need a trailing slash for proper notification
- // (e.g. "c:" -> "c:/").
- const QString effectiveAbsolutePath =
- isDir ? (absolutePath + QLatin1Char('/')) : absolutePath;
-
- handle.handle = FindFirstChangeNotification((wchar_t*) QDir::toNativeSeparators(effectiveAbsolutePath).utf16(), false, flags);
+ handle.handle = createChangeNotification(absolutePath, flags);
handle.flags = flags;
if (handle.handle == INVALID_HANDLE_VALUE)
continue;