summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/corelib/io/qstandardpaths_unix.cpp164
-rw-r--r--tests/auto/corelib/io/qstandardpaths/qstandardpaths.pro2
-rw-r--r--tests/auto/corelib/io/qstandardpaths/tst_qstandardpaths.cpp261
3 files changed, 321 insertions, 106 deletions
diff --git a/src/corelib/io/qstandardpaths_unix.cpp b/src/corelib/io/qstandardpaths_unix.cpp
index ca2a2689f1..2623de0fe0 100644
--- a/src/corelib/io/qstandardpaths_unix.cpp
+++ b/src/corelib/io/qstandardpaths_unix.cpp
@@ -1,6 +1,7 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2020 The Qt Company Ltd.
+** Copyright (C) 2020 Intel Corporation.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtCore module of the Qt Toolkit.
@@ -93,6 +94,111 @@ static QLatin1String xdg_key_name(QStandardPaths::StandardLocation type)
}
#endif
+static bool checkXdgRuntimeDir(const QString &xdgRuntimeDir)
+{
+ auto describeMetaData = [](const QFileSystemMetaData &metaData) -> QByteArray {
+ if (!metaData.exists())
+ return "a broken symlink";
+
+ QByteArray description;
+ if (metaData.isLink())
+ description = "a symbolic link to ";
+
+ if (metaData.isFile())
+ description += "a regular file";
+ else if (metaData.isDirectory())
+ description += "a directory";
+ else if (metaData.isSequential())
+ description += "a character device, socket or FIFO";
+ else
+ description += "a block device";
+
+ // convert QFileSystemMetaData permissions back to Unix
+ mode_t perms = 0;
+ if (metaData.permissions() & QFile::ReadOwner)
+ perms |= S_IRUSR;
+ if (metaData.permissions() & QFile::WriteOwner)
+ perms |= S_IWUSR;
+ if (metaData.permissions() & QFile::ExeOwner)
+ perms |= S_IXUSR;
+ if (metaData.permissions() & QFile::ReadGroup)
+ perms |= S_IRGRP;
+ if (metaData.permissions() & QFile::WriteGroup)
+ perms |= S_IWGRP;
+ if (metaData.permissions() & QFile::ExeGroup)
+ perms |= S_IXGRP;
+ if (metaData.permissions() & QFile::ReadOther)
+ perms |= S_IROTH;
+ if (metaData.permissions() & QFile::WriteOther)
+ perms |= S_IWOTH;
+ if (metaData.permissions() & QFile::ExeOther)
+ perms |= S_IXOTH;
+ description += " permissions 0" + QByteArray::number(perms, 8);
+
+ return description
+ + " owned by UID " + QByteArray::number(metaData.userId())
+ + " GID " + QByteArray::number(metaData.groupId());
+ };
+
+ // http://standards.freedesktop.org/basedir-spec/latest/
+ const uint myUid = uint(geteuid());
+ const QFile::Permissions wantedPerms = QFile::ReadOwner | QFile::WriteOwner | QFile::ExeOwner;
+ const QFileSystemMetaData::MetaDataFlags statFlags = QFileSystemMetaData::PosixStatFlags
+ | QFileSystemMetaData::LinkType;
+ QFileSystemMetaData metaData;
+ QFileSystemEntry entry(xdgRuntimeDir);
+
+ // Check that the xdgRuntimeDir is a directory by attempting to create it.
+ // A stat() before mkdir() that concluded it doesn't exist is a meaningless
+ // result: we'd race against someone else attempting to create it.
+ // ### QFileSystemEngine::createDirectory cannot take the extra mode argument.
+ if (QT_MKDIR(entry.nativeFilePath(), 0700) == 0)
+ return true;
+ if (errno != EEXIST) {
+ qErrnoWarning("QStandardPaths: error creating runtime directory '%ls'",
+ qUtf16Printable(xdgRuntimeDir));
+ return false;
+ }
+
+ // We use LinkType to force an lstat(), but fillMetaData() still returns error
+ // on broken symlinks.
+ if (!QFileSystemEngine::fillMetaData(entry, metaData, statFlags) && !metaData.isLink()) {
+ qErrnoWarning("QStandardPaths: error obtaining permissions of runtime directory '%ls'",
+ qUtf16Printable(xdgRuntimeDir));
+ return false;
+ }
+
+ // Checks:
+ // - is a directory
+ // - is not a symlink (even is pointing to a directory)
+ if (metaData.isLink() || !metaData.isDirectory()) {
+ qWarning("QStandardPaths: runtime directory '%ls' is not a directory, but %s",
+ qUtf16Printable(xdgRuntimeDir), describeMetaData(metaData).constData());
+ return false;
+ }
+
+ // - "The directory MUST be owned by the user"
+ if (metaData.userId() != myUid) {
+ qWarning("QStandardPaths: runtime directory '%ls' is not owned by UID %d, but %s",
+ qUtf16Printable(xdgRuntimeDir), myUid, describeMetaData(metaData).constData());
+ return false;
+ }
+
+ // "and he MUST be the only one having read and write access to it. Its Unix access mode MUST be 0700."
+ if (metaData.permissions() != wantedPerms) {
+ // attempt to correct:
+ QSystemError error;
+ if (!QFileSystemEngine::setPermissions(entry, wantedPerms, error)) {
+ qErrnoWarning("QStandardPaths: could not set correct permissions on runtime directory "
+ "'%ls', which is %s", qUtf16Printable(xdgRuntimeDir),
+ describeMetaData(metaData).constData());
+ return false;
+ }
+ }
+
+ return true;
+}
+
QString QStandardPaths::writableLocation(StandardLocation type)
{
switch (type) {
@@ -142,58 +248,22 @@ QString QStandardPaths::writableLocation(StandardLocation type)
}
case RuntimeLocation:
{
- // http://standards.freedesktop.org/basedir-spec/latest/
- const uint myUid = uint(geteuid());
- // since the current user is the owner, set both xxxUser and xxxOwner
- const QFile::Permissions wantedPerms = QFile::ReadUser | QFile::WriteUser | QFile::ExeUser
- | QFile::ReadOwner | QFile::WriteOwner | QFile::ExeOwner;
- QFileInfo fileInfo;
QString xdgRuntimeDir = QFile::decodeName(qgetenv("XDG_RUNTIME_DIR"));
- if (xdgRuntimeDir.isEmpty()) {
+ bool fromEnv = !xdgRuntimeDir.isEmpty();
+ if (xdgRuntimeDir.isEmpty() || !checkXdgRuntimeDir(xdgRuntimeDir)) {
+ // environment variable not set or is set to something unsuitable
+ const uint myUid = uint(geteuid());
const QString userName = QFileSystemEngine::resolveUserName(myUid);
xdgRuntimeDir = QDir::tempPath() + QLatin1String("/runtime-") + userName;
- fileInfo.setFile(xdgRuntimeDir);
+
+ if (!fromEnv) {
#ifndef Q_OS_WASM
- qWarning("QStandardPaths: XDG_RUNTIME_DIR not set, defaulting to '%ls'", qUtf16Printable(xdgRuntimeDir));
+ qWarning("QStandardPaths: XDG_RUNTIME_DIR not set, defaulting to '%ls'", qUtf16Printable(xdgRuntimeDir));
#endif
- } else {
- fileInfo.setFile(xdgRuntimeDir);
- }
- if (fileInfo.exists()) {
- if (!fileInfo.isDir()) {
- qWarning("QStandardPaths: XDG_RUNTIME_DIR points to '%ls' which is not a directory",
- qUtf16Printable(xdgRuntimeDir));
- return QString();
- }
- } else {
- QFileSystemEntry entry(xdgRuntimeDir);
- if (!QFileSystemEngine::createDirectory(entry, false)) {
- if (errno != EEXIST) {
- qErrnoWarning("QStandardPaths: error creating runtime directory %ls",
- qUtf16Printable(xdgRuntimeDir));
- return QString();
- }
- } else {
- QSystemError error;
- if (!QFileSystemEngine::setPermissions(entry, wantedPerms, error)) {
- qWarning("QStandardPaths: could not set correct permissions on runtime directory %ls: %ls",
- qUtf16Printable(xdgRuntimeDir), qUtf16Printable(error.toString()));
- return QString();
- }
}
- }
- // "The directory MUST be owned by the user"
- if (fileInfo.ownerId() != myUid) {
- qWarning("QStandardPaths: wrong ownership on runtime directory %ls, %d instead of %d",
- qUtf16Printable(xdgRuntimeDir),
- fileInfo.ownerId(), myUid);
- return QString();
- }
- // "and he MUST be the only one having read and write access to it. Its Unix access mode MUST be 0700."
- if (fileInfo.permissions() != wantedPerms) {
- qWarning("QStandardPaths: wrong permissions on runtime directory %ls, %x instead of %x",
- qUtf16Printable(xdgRuntimeDir), uint(fileInfo.permissions()), uint(wantedPerms));
- return QString();
+
+ if (!checkXdgRuntimeDir(xdgRuntimeDir))
+ xdgRuntimeDir.clear();
}
return xdgRuntimeDir;
diff --git a/tests/auto/corelib/io/qstandardpaths/qstandardpaths.pro b/tests/auto/corelib/io/qstandardpaths/qstandardpaths.pro
index 44b1ce8dd8..5c15ad84be 100644
--- a/tests/auto/corelib/io/qstandardpaths/qstandardpaths.pro
+++ b/tests/auto/corelib/io/qstandardpaths/qstandardpaths.pro
@@ -1,8 +1,6 @@
CONFIG += testcase
TARGET = tst_qstandardpaths
QT = core testlib
-INCLUDEPATH += ../../../../shared/
-HEADERS += ../../../../shared/emulationdetector.h
SOURCES = tst_qstandardpaths.cpp
TESTDATA += tst_qstandardpaths.cpp qstandardpaths.pro
diff --git a/tests/auto/corelib/io/qstandardpaths/tst_qstandardpaths.cpp b/tests/auto/corelib/io/qstandardpaths/tst_qstandardpaths.cpp
index cba7dfe9fc..16b4fb4423 100644
--- a/tests/auto/corelib/io/qstandardpaths/tst_qstandardpaths.cpp
+++ b/tests/auto/corelib/io/qstandardpaths/tst_qstandardpaths.cpp
@@ -1,6 +1,7 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2020 The Qt Company Ltd.
+** Copyright (C) 2020 Intel Corporation.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the test suite of the Qt Toolkit.
@@ -26,13 +27,13 @@
**
****************************************************************************/
-#include <QtTest/QtTest>
#include <qstandardpaths.h>
+#include <QtTest/QtTest>
#include <qdebug.h>
-#include <qstandardpaths.h>
#include <qfileinfo.h>
-#include <qsysinfo.h>
+#include <qplatformdefs.h>
#include <qregularexpression.h>
+#include <qsysinfo.h>
#if defined(Q_OS_WIN)
# include <qt_windows.h>
#endif
@@ -40,14 +41,13 @@
#ifdef Q_OS_UNIX
#include <unistd.h>
#include <sys/types.h>
+#include <pwd.h>
#endif
#if defined(Q_OS_UNIX) && !defined(Q_OS_MAC) && !defined(Q_OS_ANDROID)
#define Q_XDG_PLATFORM
#endif
-#include "emulationdetector.h"
-
// Update this when adding new enum values; update enumNames too
static const int MaxStandardLocation = QStandardPaths::AppConfigLocation;
@@ -68,6 +68,7 @@ private slots:
void testFindExecutable();
void testFindExecutableLinkToDirectory();
void testRuntimeDirectory();
+ void testCustomRuntimeDirectory_data();
void testCustomRuntimeDirectory();
void testAllWritableLocations_data();
void testAllWritableLocations();
@@ -455,6 +456,9 @@ void tst_qstandardpaths::testFindExecutableLinkToDirectory()
QFile::remove(target);
}
+using RuntimeDirSetup = QString (*)(QDir &);
+Q_DECLARE_METATYPE(RuntimeDirSetup);
+
void tst_qstandardpaths::testRuntimeDirectory()
{
#ifdef Q_XDG_PLATFORM
@@ -463,6 +467,174 @@ void tst_qstandardpaths::testRuntimeDirectory()
#endif
}
+#ifdef Q_XDG_PLATFORM
+static QString fallbackXdgRuntimeDir()
+{
+ static QString username = [] {
+ struct passwd *pw = getpwuid(geteuid());
+ return QString::fromLocal8Bit(pw->pw_name);
+ }();
+
+ // QDir::temp() might change from call to call
+ return QDir::temp().filePath("runtime-" + username);
+}
+#endif
+
+static QString updateRuntimeDir(const QString &path)
+{
+ qputenv("XDG_RUNTIME_DIR", QFile::encodeName(path));
+ return path;
+}
+
+static void clearRuntimeDir()
+{
+ qunsetenv("XDG_RUNTIME_DIR");
+#ifdef Q_XDG_PLATFORM
+#ifndef Q_OS_WASM
+ QTest::ignoreMessage(QtWarningMsg,
+ qPrintable("QStandardPaths: XDG_RUNTIME_DIR not set, defaulting to '"
+ + fallbackXdgRuntimeDir() + '\''));
+#endif
+#endif
+}
+
+void tst_qstandardpaths::testCustomRuntimeDirectory_data()
+{
+#if defined(Q_XDG_PLATFORM)
+ QTest::addColumn<RuntimeDirSetup>("setup");
+ auto addRow = [](const char *name, RuntimeDirSetup f) {
+ QTest::newRow(name) << f;
+ };
+
+
+# if defined(Q_OS_UNIX)
+ if (::getuid() == 0)
+ QSKIP("Running this test as root doesn't make sense");
+# endif
+
+ addRow("environment:non-existing", [](QDir &d) {
+ return updateRuntimeDir(d.filePath("runtime"));
+ });
+
+ addRow("environment:existing", [](QDir &d) {
+ QString p = d.filePath("runtime");
+ d.mkdir("runtime");
+ QFile::setPermissions(p, QFile::ReadOwner | QFile::WriteOwner | QFile::ExeOwner);
+ return updateRuntimeDir(p);
+ });
+
+ addRow("environment-to-existing-wrong-perm", [](QDir &d) {
+ QString p = d.filePath("runtime");
+ d.mkdir("runtime");
+ QFile::setPermissions(p, QFile::ReadOwner | QFile::WriteOwner | QFile::ExeOwner |
+ QFile::ExeGroup | QFile::ExeOther);
+ return updateRuntimeDir(p);
+ });
+
+ addRow("environment:wrong-owner", [](QDir &) {
+ QT_STATBUF st;
+ QT_STAT("/", &st);
+
+ updateRuntimeDir("/");
+ QTest::ignoreMessage(QtWarningMsg,
+ QString("QStandardPaths: runtime directory '/' is not owned by UID "
+ "%1, but a directory permissions %2 owned by UID %3 GID %4")
+ .arg(getuid())
+ .arg(st.st_mode & 07777, 4, 8, QChar('0'))
+ .arg(st.st_uid)
+ .arg(st.st_gid).toLatin1());
+ return fallbackXdgRuntimeDir();
+ });
+
+ addRow("environment:file", [](QDir &d) {
+ QString p = d.filePath("file");
+ QFile f(p);
+ f.open(QIODevice::WriteOnly);
+ f.setPermissions(QFile::ReadOwner | QFile::WriteOwner);
+
+ updateRuntimeDir(p);
+ QTest::ignoreMessage(QtWarningMsg,
+ QString("QStandardPaths: runtime directory '%1' is not a directory, "
+ "but a regular file permissions 0600 owned by UID %2 GID %3")
+ .arg(p).arg(getuid()).arg(getgid()).toLatin1());
+ return fallbackXdgRuntimeDir();
+ });
+
+ addRow("environment:broken-symlink", [](QDir &d) {
+ QString p = d.filePath("link");
+ QFile::link(d.filePath("this-goes-nowhere"), p);
+ updateRuntimeDir(p);
+ QTest::ignoreMessage(QtWarningMsg,
+ QString("QStandardPaths: runtime directory '%1' is not a directory, "
+ "but a broken symlink")
+ .arg(p).toLatin1());
+ return fallbackXdgRuntimeDir();
+ });
+
+ addRow("environment:symlink-to-dir", [](QDir &d) {
+ QString p = d.filePath("link");
+ d.mkdir("dir");
+ QFile::link(d.filePath("dir"), p);
+ QFile::setPermissions(p, QFile::ReadOwner | QFile::WriteOwner | QFile::ExeOwner);
+ updateRuntimeDir(p);
+ QTest::ignoreMessage(QtWarningMsg,
+ QString("QStandardPaths: runtime directory '%1' is not a directory, "
+ "but a symbolic link to a directory permissions 0700 owned by UID %2 GID %3")
+ .arg(p).arg(getuid()).arg(getgid()).toLatin1());
+ return fallbackXdgRuntimeDir();
+ });
+
+ addRow("no-environment:non-existing", [](QDir &) {
+ clearRuntimeDir();
+ return fallbackXdgRuntimeDir();
+ });
+
+ addRow("no-environment:existing", [](QDir &d) {
+ clearRuntimeDir();
+ QString p = fallbackXdgRuntimeDir();
+ d.mkdir(p); // probably has wrong permissions
+ return p;
+ });
+
+ addRow("no-environment:fallback-is-file", [](QDir &) {
+ QString p = fallbackXdgRuntimeDir();
+ QFile f(p);
+ f.open(QIODevice::WriteOnly);
+ f.setPermissions(QFile::ReadOwner | QFile::WriteOwner);
+
+ clearRuntimeDir();
+ QTest::ignoreMessage(QtWarningMsg,
+ QString("QStandardPaths: runtime directory '%1' is not a directory, "
+ "but a regular file permissions 0600 owned by UID %2 GID %3")
+ .arg(p).arg(getuid()).arg(getgid()).toLatin1());
+ return QString();
+ });
+
+ addRow("environment-and-fallback-are-files", [](QDir &d) {
+ QString p = d.filePath("file1");
+ QFile f(p);
+ f.open(QIODevice::WriteOnly);
+ f.setPermissions(QFile::ReadOwner | QFile::WriteOwner | QFile::ReadGroup);
+ updateRuntimeDir(p);
+ QTest::ignoreMessage(QtWarningMsg,
+ QString("QStandardPaths: runtime directory '%1' is not a directory, "
+ "but a regular file permissions 0640 owned by UID %2 GID %3")
+ .arg(p).arg(getuid()).arg(getgid()).toLatin1());
+
+ f.close();
+ f.setFileName(fallbackXdgRuntimeDir());
+ f.open(QIODevice::WriteOnly);
+ f.setPermissions(QFile::ReadOwner | QFile::WriteOwner | QFile::ReadGroup);
+ QTest::ignoreMessage(QtWarningMsg,
+ QString("QStandardPaths: runtime directory '%1' is not a directory, "
+ "but a regular file permissions 0640 owned by UID %2 GID %3")
+ .arg(f.fileName()).arg(getuid()).arg(getgid()).toLatin1());
+
+ return QString();
+ });
+#endif
+}
+
void tst_qstandardpaths::testCustomRuntimeDirectory()
{
#if defined(Q_OS_UNIX)
@@ -473,63 +645,38 @@ void tst_qstandardpaths::testCustomRuntimeDirectory()
#ifdef Q_XDG_PLATFORM
struct EnvVarRestorer
{
- EnvVarRestorer() : origRuntimeDir(qgetenv("XDG_RUNTIME_DIR")) {}
- ~EnvVarRestorer() { qputenv("XDG_RUNTIME_DIR", origRuntimeDir.constData()); }
- const QByteArray origRuntimeDir;
+ ~EnvVarRestorer()
+ {
+ qputenv("XDG_RUNTIME_DIR", origRuntimeDir);
+ qputenv("TMPDIR", origTempDir);
+ }
+ const QByteArray origRuntimeDir = qgetenv("XDG_RUNTIME_DIR");
+ const QByteArray origTempDir = qgetenv("TMPDIR");
};
EnvVarRestorer restorer;
- // When $XDG_RUNTIME_DIR points to a directory with wrong ownership, QStandardPaths should warn
- QByteArray rootOwnedFileName = "/tmp";
- if (EmulationDetector::isRunningArmOnX86()) {
- // Directory "tmp" under toolchain sysroot is detected by qemu and has same uid as current user.
- // Try /opt instead, it might not be located in the sysroot.
- QFileInfo rootOwnedFile = QFileInfo(QString::fromLatin1(rootOwnedFileName));
- if (rootOwnedFile.ownerId() == ::geteuid()) {
- rootOwnedFileName = "/opt";
- }
- }
- qputenv("XDG_RUNTIME_DIR", QFile::encodeName(rootOwnedFileName));
+ // set up the environment to point to a place we control
+ QTemporaryDir tempDir;
+ QVERIFY2(tempDir.isValid(), qPrintable(tempDir.errorString()));
- // It's very unlikely that /tmp is 0600 or that we can chmod it
- // The call below outputs
- // "QStandardPaths: wrong ownership on runtime directory /tmp, 0 instead of $UID"
- // but we can't reliably expect that it's owned by uid 0, I think.
- const uid_t uid = geteuid();
- QTest::ignoreMessage(QtWarningMsg,
- qPrintable(QString::fromLatin1("QStandardPaths: wrong ownership on runtime directory " + rootOwnedFileName + ", 0 instead of %1").arg(uid)));
- const QString runtimeDir = QStandardPaths::writableLocation(QStandardPaths::RuntimeLocation);
- QVERIFY2(runtimeDir.isEmpty(), qPrintable(runtimeDir));
+ QDir d(tempDir.path());
+ qputenv("TMPDIR", QFile::encodeName(tempDir.path()));
- // When $XDG_RUNTIME_DIR points to a directory with wrong permissions, QStandardPaths should warn
- const QByteArray wrongPermissionFileName = "wrong_permissions";
- QDir::current().mkdir(wrongPermissionFileName);
- QFile wrongPermissionFile(wrongPermissionFileName);
- const QFile::Permissions wantedPerms = QFile::ReadUser | QFile::WriteUser | QFile::ExeUser;
- QVERIFY(wrongPermissionFile.setPermissions(wantedPerms | QFile::ExeGroup));
+ QFETCH(RuntimeDirSetup, setup);
+ QString expected = setup(d);
- qputenv("XDG_RUNTIME_DIR", wrongPermissionFileName);
- QTest::ignoreMessage(QtWarningMsg,
- qPrintable(QString::fromLatin1("QStandardPaths: wrong permissions on runtime directory " + wrongPermissionFileName + ", 7710 instead of 7700")));
- const QString wrongPermissionRuntimeDir = QStandardPaths::writableLocation(QStandardPaths::RuntimeLocation);
- QVERIFY(wrongPermissionRuntimeDir.isEmpty());
- QDir::current().rmdir(wrongPermissionFileName);
-
- // When $XDG_RUNTIME_DIR points to a non-existing directory, QStandardPaths should create it first
- const QByteArray nonExistingDir = "does_not_exist";
- qputenv("XDG_RUNTIME_DIR", nonExistingDir);
- const QString nonExistingRuntimeDir = QStandardPaths::writableLocation(QStandardPaths::RuntimeLocation);
- QVERIFY2(!nonExistingRuntimeDir.compare(nonExistingDir), qPrintable(nonExistingRuntimeDir));
- QVERIFY(QDir::current().exists(nonExistingRuntimeDir));
- QDir::current().rmdir(nonExistingRuntimeDir);
-
- // When $XDG_RUNTIME_DIR points to a file, QStandardPaths should warn
- const QString file = QFINDTESTDATA("tst_qstandardpaths.cpp");
- QVERIFY(!file.isEmpty());
- qputenv("XDG_RUNTIME_DIR", QFile::encodeName(file));
- QTest::ignoreMessage(QtWarningMsg, qPrintable(QString::fromLatin1("QStandardPaths: XDG_RUNTIME_DIR points to '%1' which is not a directory").arg(file)));
- const QString noRuntimeDir = QStandardPaths::writableLocation(QStandardPaths::RuntimeLocation);
- QVERIFY2(noRuntimeDir.isEmpty(), qPrintable(file));
+ QString runtimeDir = QStandardPaths::writableLocation(QStandardPaths::RuntimeLocation);
+ QCOMPARE(runtimeDir, expected);
+
+ if (!runtimeDir.isEmpty()) {
+ QFileInfo runtimeInfo(runtimeDir);
+ QVERIFY(runtimeInfo.isDir());
+ QVERIFY(!runtimeInfo.isSymLink());
+ auto expectedPerms = QFile::ReadOwner | QFile::WriteOwner | QFile::ExeOwner
+ | QFile::ReadUser | QFile::WriteUser | QFile::ExeUser;
+ QCOMPARE(QString::number(runtimeInfo.permissions(), 16),
+ QString::number(expectedPerms, 16));
+ }
#endif
}