summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/corelib/io/qlockfile_win.cpp13
-rw-r--r--tests/auto/corelib/io/qlockfile/tst_qlockfile.cpp65
-rw-r--r--tests/auto/corelib/io/qlockfile/tst_qlockfile.pro1
3 files changed, 78 insertions, 1 deletions
diff --git a/src/corelib/io/qlockfile_win.cpp b/src/corelib/io/qlockfile_win.cpp
index a36e6e93b8..9fe86e1ad8 100644
--- a/src/corelib/io/qlockfile_win.cpp
+++ b/src/corelib/io/qlockfile_win.cpp
@@ -48,6 +48,12 @@ static inline QByteArray localHostName()
return qgetenv("COMPUTERNAME");
}
+static inline bool fileExists(const wchar_t *fileName)
+{
+ WIN32_FILE_ATTRIBUTE_DATA data;
+ return GetFileAttributesEx(fileName, GetFileExInfoStandard, &data);
+}
+
QLockFile::LockError QLockFilePrivate::tryLock_sys()
{
const QFileSystemEntry fileEntry(fileName);
@@ -79,8 +85,13 @@ QLockFile::LockError QLockFilePrivate::tryLock_sys()
case ERROR_SHARING_VIOLATION:
case ERROR_ALREADY_EXISTS:
case ERROR_FILE_EXISTS:
- case ERROR_ACCESS_DENIED: // readonly file, or file still in use by another process. Assume the latter, since we don't create it readonly.
return QLockFile::LockFailedError;
+ case ERROR_ACCESS_DENIED:
+ // readonly file, or file still in use by another process.
+ // Assume the latter if the file exists, since we don't create it readonly.
+ return fileExists((const wchar_t*)fileEntry.nativeFilePath().utf16())
+ ? QLockFile::LockFailedError
+ : QLockFile::PermissionError;
default:
qWarning() << "Got unexpected locking error" << lastError;
return QLockFile::UnknownError;
diff --git a/tests/auto/corelib/io/qlockfile/tst_qlockfile.cpp b/tests/auto/corelib/io/qlockfile/tst_qlockfile.cpp
index 90f65e9dbc..bef3d3a012 100644
--- a/tests/auto/corelib/io/qlockfile/tst_qlockfile.cpp
+++ b/tests/auto/corelib/io/qlockfile/tst_qlockfile.cpp
@@ -36,8 +36,11 @@
#include <QtConcurrentRun>
#include <qlockfile.h>
#include <qtemporarydir.h>
+#include <qsysinfo.h>
#if defined(Q_OS_UNIX) && !defined(Q_OS_VXWORKS)
#include <unistd.h>
+#elif defined(Q_OS_WIN) && !defined(Q_OS_WINCE) && !defined(Q_OS_WINRT)
+# include <qt_windows.h>
#endif
class tst_QLockFile : public QObject
@@ -58,6 +61,7 @@ private slots:
void staleLongLockFromBusyProcess();
void staleLockRace();
void noPermissions();
+ void noPermissionsWindows();
public:
QString m_helperApp;
@@ -415,5 +419,66 @@ void tst_QLockFile::noPermissions()
QCOMPARE(int(lockFile.error()), int(QLockFile::PermissionError));
}
+enum ProcessProperty {
+ ElevatedProcess = 0x1,
+ VirtualStore = 0x2
+};
+
+Q_DECLARE_FLAGS(ProcessProperties, ProcessProperty)
+Q_DECLARE_OPERATORS_FOR_FLAGS(ProcessProperties)
+
+static inline ProcessProperties processProperties()
+{
+ ProcessProperties result;
+#if defined(Q_OS_WIN) && !defined(Q_OS_WINCE) && !defined(Q_OS_WINRT)
+ HANDLE processToken = NULL;
+ if (OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &processToken)) {
+ DWORD elevation; // struct containing a DWORD, not present in some MinGW headers.
+ DWORD cbSize = sizeof(elevation);
+ if (GetTokenInformation(processToken, TokenElevation, &elevation, cbSize, &cbSize)
+ && elevation) {
+ result |= ElevatedProcess;
+ }
+ // Check for UAC virtualization (compatibility mode for old software
+ // allowing it to write to system folders by mirroring them under
+ // "\Users\...\AppData\Local\VirtualStore\", which is typically the case
+ // for MinGW).
+ DWORD virtualStoreEnabled = 0;
+ cbSize = sizeof(virtualStoreEnabled);
+ if (GetTokenInformation(processToken, TokenVirtualizationEnabled, &virtualStoreEnabled, cbSize, &cbSize)
+ && virtualStoreEnabled) {
+ result |= VirtualStore;
+ }
+ CloseHandle(processToken);
+ }
+#endif
+ return result;
+}
+
+void tst_QLockFile::noPermissionsWindows()
+{
+ // Windows: Do the permissions test in a system directory in which
+ // files cannot be created.
+#if !defined(Q_OS_WIN) || defined(Q_OS_WINCE) || defined(Q_OS_WINRT)
+ QSKIP("This test is for desktop Windows only");
+#endif
+#ifdef Q_OS_WIN
+ if (QSysInfo::windowsVersion() < QSysInfo::WV_WINDOWS7)
+ QSKIP("This test requires at least Windows 7");
+#endif
+ if (const int p = processProperties()) {
+ const QByteArray message = "This test cannot be run (properties=0x"
+ + QByteArray::number(p, 16) + ')';
+ QSKIP(message.constData());
+ }
+
+ const QString fileName = QFile::decodeName(qgetenv("ProgramFiles"))
+ + QLatin1Char('/') + QCoreApplication::applicationName()
+ + QDateTime::currentDateTime().toString(QStringLiteral("yyMMddhhmm"));
+ QLockFile lockFile(fileName);
+ QVERIFY(!lockFile.lock());
+ QCOMPARE(int(lockFile.error()), int(QLockFile::PermissionError));
+}
+
QTEST_MAIN(tst_QLockFile)
#include "tst_qlockfile.moc"
diff --git a/tests/auto/corelib/io/qlockfile/tst_qlockfile.pro b/tests/auto/corelib/io/qlockfile/tst_qlockfile.pro
index 2f7009b736..6eb72343bc 100644
--- a/tests/auto/corelib/io/qlockfile/tst_qlockfile.pro
+++ b/tests/auto/corelib/io/qlockfile/tst_qlockfile.pro
@@ -4,3 +4,4 @@ TARGET = tst_qlockfile
SOURCES += tst_qlockfile.cpp
QT = core testlib concurrent
+win32:!wince:!winrt:LIBS += -ladvapi32