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>bb10
parent
7beb2bc02b
commit
e1d7f7dfbc
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -568,6 +568,10 @@ void tst_QFileSystemWatcher::watchFileAndItsDirectory()
|
|||
QCOMPARE(fileChangedSpy.count(), 0);
|
||||
QCOMPARE(dirChangedSpy.count(), 1);
|
||||
|
||||
// QTBUG-61792, removal should succeed (bug on Windows which uses one change
|
||||
// notification per directory).
|
||||
QVERIFY(watcher.removePath(testDir.absolutePath()));
|
||||
|
||||
QVERIFY(temporaryDir.rmdir(testDirName));
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue