Avoid potential data races caused by qt_ntfs_permission_lookup
qt_ntfs_permission_lookup is a global, non-atomic variable which could cause problems in case of multiple threads. Introduce a new atomic variable to handle permission lookups but instead of manual incrementation/decrementation, implement a class to manage the variable. Since the atomic variable is not directly available to the user, implement helper functions to increase/decrease/check the status of the variable. Task-number: QTBUG-105804 Change-Id: If6cbcdd653c7f50ad9853a5c309e24fdeb520788 Reviewed-by: Thiago Macieira <thiago.macieira@intel.com> Reviewed-by: Marc Mutz <marc.mutz@qt.io>
This commit is contained in:
parent
214c3a033a
commit
84f0596c0c
@ -11,3 +11,18 @@ qt_ntfs_permission_lookup++; // turn checking on
|
|||||||
qt_ntfs_permission_lookup--; // turn it off again
|
qt_ntfs_permission_lookup--; // turn it off again
|
||||||
//! [1]
|
//! [1]
|
||||||
|
|
||||||
|
//! [raii]
|
||||||
|
void complexFunction()
|
||||||
|
{
|
||||||
|
QNtfsPermissionCheckGuard permissionGuard; // check is enabled
|
||||||
|
|
||||||
|
// do complex things here that need permission check enabled
|
||||||
|
|
||||||
|
} // as the guard goes out of scope the check is disabled
|
||||||
|
//! [raii]
|
||||||
|
|
||||||
|
//! [free-funcs]
|
||||||
|
qAreNtfsPermissionChecksEnabled(); // check status
|
||||||
|
qEnableNtfsPermissionChecks(); // turn checking on
|
||||||
|
qDisableNtfsPermissionChecks(); // turn it off again
|
||||||
|
//! [free-funcs]
|
||||||
|
@ -26,6 +26,27 @@ namespace std {
|
|||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
|
#ifdef Q_OS_WIN
|
||||||
|
Q_CORE_EXPORT bool qEnableNtfsPermissionChecks() noexcept;
|
||||||
|
Q_CORE_EXPORT bool qDisableNtfsPermissionChecks() noexcept;
|
||||||
|
Q_CORE_EXPORT bool qAreNtfsPermissionChecksEnabled() noexcept;
|
||||||
|
|
||||||
|
class [[nodiscard]] QNtfsPermissionCheckGuard
|
||||||
|
{
|
||||||
|
Q_DISABLE_COPY_MOVE(QNtfsPermissionCheckGuard)
|
||||||
|
public:
|
||||||
|
QNtfsPermissionCheckGuard()
|
||||||
|
{
|
||||||
|
qEnableNtfsPermissionChecks();
|
||||||
|
}
|
||||||
|
|
||||||
|
~QNtfsPermissionCheckGuard()
|
||||||
|
{
|
||||||
|
qDisableNtfsPermissionChecks();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#endif // Q_OS_WIN
|
||||||
|
|
||||||
#if QT_CONFIG(cxx17_filesystem)
|
#if QT_CONFIG(cxx17_filesystem)
|
||||||
namespace QtPrivate {
|
namespace QtPrivate {
|
||||||
inline QString fromFilesystemPath(const std::filesystem::path &path)
|
inline QString fromFilesystemPath(const std::filesystem::path &path)
|
||||||
|
@ -114,6 +114,20 @@ void QFileDevicePrivate::setError(QFileDevice::FileError err, int errNum)
|
|||||||
to increment or decrement \c qt_ntfs_permission_lookup before any
|
to increment or decrement \c qt_ntfs_permission_lookup before any
|
||||||
threads other than the main thread have started or after every thread
|
threads other than the main thread have started or after every thread
|
||||||
other than the main thread has ended.
|
other than the main thread has ended.
|
||||||
|
|
||||||
|
\note From Qt 6.6 the variable \c qt_ntfs_permission_lookup is
|
||||||
|
deprecated. Please use the following alternatives.
|
||||||
|
|
||||||
|
The safe and easy way to manage permission checks is to use the RAII class
|
||||||
|
\c QNtfsPermissionCheckGuard.
|
||||||
|
|
||||||
|
\snippet ntfsp.cpp raii
|
||||||
|
|
||||||
|
If you need more fine-grained control, it is possible to manage the permission
|
||||||
|
with the following functions instead:
|
||||||
|
|
||||||
|
\snippet ntfsp.cpp free-funcs
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
//************* QFileDevice
|
//************* QFileDevice
|
||||||
|
@ -278,6 +278,19 @@ QDateTime &QFileInfoPrivate::getFileTime(QAbstractFileEngine::FileTime request)
|
|||||||
threads other than the main thread have started or after every thread
|
threads other than the main thread have started or after every thread
|
||||||
other than the main thread has ended.
|
other than the main thread has ended.
|
||||||
|
|
||||||
|
\note From Qt 6.6 the variable \c qt_ntfs_permission_lookup is
|
||||||
|
deprecated. Please use the following alternatives.
|
||||||
|
|
||||||
|
The safe and easy way to manage permission checks is to use the RAII class
|
||||||
|
\c QNtfsPermissionCheckGuard.
|
||||||
|
|
||||||
|
\snippet ntfsp.cpp raii
|
||||||
|
|
||||||
|
If you need more fine-grained control, it is possible to manage the permission
|
||||||
|
with the following functions instead:
|
||||||
|
|
||||||
|
\snippet ntfsp.cpp free-funcs
|
||||||
|
|
||||||
\section1 Performance Considerations
|
\section1 Performance Considerations
|
||||||
|
|
||||||
Some of QFileInfo's functions query the file system, but for
|
Some of QFileInfo's functions query the file system, but for
|
||||||
|
@ -384,6 +384,46 @@ constexpr QFileDevice::Permissions toSpecificPermissions(PermissionTag tag,
|
|||||||
|
|
||||||
Q_CORE_EXPORT int qt_ntfs_permission_lookup = 0;
|
Q_CORE_EXPORT int qt_ntfs_permission_lookup = 0;
|
||||||
|
|
||||||
|
static QBasicAtomicInt qt_ntfs_permission_lookup_v2 = Q_BASIC_ATOMIC_INITIALIZER(0);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\internal
|
||||||
|
|
||||||
|
Returns true if the check was previously enabled.
|
||||||
|
*/
|
||||||
|
|
||||||
|
bool qEnableNtfsPermissionChecks() noexcept
|
||||||
|
{
|
||||||
|
return qt_ntfs_permission_lookup_v2.fetchAndAddRelaxed(1)
|
||||||
|
+ qt_ntfs_permission_lookup
|
||||||
|
!= 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\internal
|
||||||
|
|
||||||
|
Returns true if the check is disabled, i.e. there are no more users.
|
||||||
|
*/
|
||||||
|
|
||||||
|
bool qDisableNtfsPermissionChecks() noexcept
|
||||||
|
{
|
||||||
|
return qt_ntfs_permission_lookup_v2.fetchAndSubRelaxed(1)
|
||||||
|
+ qt_ntfs_permission_lookup
|
||||||
|
== 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\internal
|
||||||
|
|
||||||
|
Returns true if the check is enabled.
|
||||||
|
*/
|
||||||
|
|
||||||
|
bool qAreNtfsPermissionChecksEnabled() noexcept
|
||||||
|
{
|
||||||
|
return qt_ntfs_permission_lookup_v2.loadRelaxed()
|
||||||
|
+ qt_ntfs_permission_lookup;
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\class QNativeFilePermissions
|
\class QNativeFilePermissions
|
||||||
\internal
|
\internal
|
||||||
@ -1078,8 +1118,7 @@ QString QFileSystemEngine::owner(const QFileSystemEntry &entry, QAbstractFileEng
|
|||||||
{
|
{
|
||||||
QString name;
|
QString name;
|
||||||
#if QT_CONFIG(fslibs)
|
#if QT_CONFIG(fslibs)
|
||||||
extern int qt_ntfs_permission_lookup;
|
if (qAreNtfsPermissionChecksEnabled()) {
|
||||||
if (qt_ntfs_permission_lookup > 0) {
|
|
||||||
initGlobalSid();
|
initGlobalSid();
|
||||||
{
|
{
|
||||||
PSID pOwner = 0;
|
PSID pOwner = 0;
|
||||||
@ -1133,7 +1172,7 @@ bool QFileSystemEngine::fillPermissions(const QFileSystemEntry &entry, QFileSyst
|
|||||||
QFileSystemMetaData::MetaDataFlags what)
|
QFileSystemMetaData::MetaDataFlags what)
|
||||||
{
|
{
|
||||||
#if QT_CONFIG(fslibs)
|
#if QT_CONFIG(fslibs)
|
||||||
if (qt_ntfs_permission_lookup > 0) {
|
if (qAreNtfsPermissionChecksEnabled()) {
|
||||||
initGlobalSid();
|
initGlobalSid();
|
||||||
|
|
||||||
QString fname = entry.nativeFilePath();
|
QString fname = entry.nativeFilePath();
|
||||||
|
@ -12,7 +12,6 @@
|
|||||||
#include <qdebug.h>
|
#include <qdebug.h>
|
||||||
#include <qdir.h>
|
#include <qdir.h>
|
||||||
#include <qfileinfo.h>
|
#include <qfileinfo.h>
|
||||||
#include <qscopedvaluerollback.h>
|
|
||||||
#include <qstringlist.h>
|
#include <qstringlist.h>
|
||||||
|
|
||||||
#if defined(Q_OS_WIN)
|
#if defined(Q_OS_WIN)
|
||||||
@ -40,7 +39,6 @@
|
|||||||
|
|
||||||
#ifdef Q_OS_WIN
|
#ifdef Q_OS_WIN
|
||||||
#define DRIVE "Q:"
|
#define DRIVE "Q:"
|
||||||
extern Q_CORE_EXPORT int qt_ntfs_permission_lookup;
|
|
||||||
#else
|
#else
|
||||||
#define DRIVE
|
#define DRIVE
|
||||||
#endif
|
#endif
|
||||||
@ -453,8 +451,7 @@ void tst_QDir::mkdirWithPermissions()
|
|||||||
QFETCH(QFile::Permissions, permissions);
|
QFETCH(QFile::Permissions, permissions);
|
||||||
|
|
||||||
#ifdef Q_OS_WIN
|
#ifdef Q_OS_WIN
|
||||||
QScopedValueRollback<int> ntfsMode(qt_ntfs_permission_lookup);
|
QNtfsPermissionCheckGuard permissionGuard;
|
||||||
++qt_ntfs_permission_lookup;
|
|
||||||
#endif
|
#endif
|
||||||
#ifdef Q_OS_UNIX
|
#ifdef Q_OS_UNIX
|
||||||
auto restoreMask = qScopeGuard([oldMask = umask(0)] { umask(oldMask); });
|
auto restoreMask = qScopeGuard([oldMask = umask(0)] { umask(oldMask); });
|
||||||
|
@ -171,6 +171,7 @@ private slots:
|
|||||||
#ifdef Q_OS_WIN
|
#ifdef Q_OS_WIN
|
||||||
void permissionsNtfs_data();
|
void permissionsNtfs_data();
|
||||||
void permissionsNtfs();
|
void permissionsNtfs();
|
||||||
|
void deprecatedNtfsPermissionCheck();
|
||||||
#endif
|
#endif
|
||||||
void setPermissions_data();
|
void setPermissions_data();
|
||||||
void setPermissions();
|
void setPermissions();
|
||||||
@ -1267,8 +1268,7 @@ void tst_QFile::createFilePermissions()
|
|||||||
QFETCH(QFile::Permissions, permissions);
|
QFETCH(QFile::Permissions, permissions);
|
||||||
|
|
||||||
#ifdef Q_OS_WIN
|
#ifdef Q_OS_WIN
|
||||||
QScopedValueRollback<int> ntfsMode(qt_ntfs_permission_lookup);
|
QNtfsPermissionCheckGuard permissionGuard;
|
||||||
++qt_ntfs_permission_lookup;
|
|
||||||
#endif
|
#endif
|
||||||
#ifdef Q_OS_UNIX
|
#ifdef Q_OS_UNIX
|
||||||
auto restoreMask = qScopeGuard([oldMask = umask(0)] { umask(oldMask); });
|
auto restoreMask = qScopeGuard([oldMask = umask(0)] { umask(oldMask); });
|
||||||
@ -1392,7 +1392,7 @@ void tst_QFile::permissions()
|
|||||||
}
|
}
|
||||||
|
|
||||||
#if defined(Q_OS_WIN)
|
#if defined(Q_OS_WIN)
|
||||||
if (qt_ntfs_permission_lookup)
|
if (qAreNtfsPermissionChecksEnabled())
|
||||||
QEXPECT_FAIL("readonly", "QTBUG-25630", Abort);
|
QEXPECT_FAIL("readonly", "QTBUG-25630", Abort);
|
||||||
#endif
|
#endif
|
||||||
#ifdef Q_OS_UNIX
|
#ifdef Q_OS_UNIX
|
||||||
@ -1414,10 +1414,21 @@ void tst_QFile::permissionsNtfs_data()
|
|||||||
|
|
||||||
void tst_QFile::permissionsNtfs()
|
void tst_QFile::permissionsNtfs()
|
||||||
{
|
{
|
||||||
QScopedValueRollback<int> ntfsMode(qt_ntfs_permission_lookup);
|
QNtfsPermissionCheckGuard permissionGuard;
|
||||||
qt_ntfs_permission_lookup++;
|
|
||||||
permissions();
|
permissions();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void tst_QFile::deprecatedNtfsPermissionCheck()
|
||||||
|
{
|
||||||
|
QScopedValueRollback<int> guard(qt_ntfs_permission_lookup);
|
||||||
|
|
||||||
|
QCOMPARE(qAreNtfsPermissionChecksEnabled(), false);
|
||||||
|
qt_ntfs_permission_lookup++;
|
||||||
|
QCOMPARE(qAreNtfsPermissionChecksEnabled(), true);
|
||||||
|
qt_ntfs_permission_lookup--;
|
||||||
|
QCOMPARE(qAreNtfsPermissionChecksEnabled(), false);
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void tst_QFile::setPermissions_data()
|
void tst_QFile::setPermissions_data()
|
||||||
|
@ -4,7 +4,6 @@
|
|||||||
#include <QTest>
|
#include <QTest>
|
||||||
#include <QStandardPaths>
|
#include <QStandardPaths>
|
||||||
#include <QScopeGuard>
|
#include <QScopeGuard>
|
||||||
#include <QScopedValueRollback>
|
|
||||||
|
|
||||||
#include <qfile.h>
|
#include <qfile.h>
|
||||||
#include <qdir.h>
|
#include <qdir.h>
|
||||||
@ -43,9 +42,6 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(Q_OS_WIN)
|
#if defined(Q_OS_WIN)
|
||||||
QT_BEGIN_NAMESPACE
|
|
||||||
extern Q_CORE_EXPORT int qt_ntfs_permission_lookup;
|
|
||||||
QT_END_NAMESPACE
|
|
||||||
bool IsUserAdmin();
|
bool IsUserAdmin();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -1905,8 +1901,7 @@ void tst_QFileInfo::isWritable()
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined (Q_OS_WIN)
|
#if defined (Q_OS_WIN)
|
||||||
QScopedValueRollback<int> ntfsMode(qt_ntfs_permission_lookup);
|
QNtfsPermissionCheckGuard permissionGuard;
|
||||||
qt_ntfs_permission_lookup = 1;
|
|
||||||
QFileInfo fi2(QFile::decodeName(qgetenv("SystemRoot") + "/system.ini"));
|
QFileInfo fi2(QFile::decodeName(qgetenv("SystemRoot") + "/system.ini"));
|
||||||
QVERIFY(fi2.exists());
|
QVERIFY(fi2.exists());
|
||||||
QCOMPARE(fi2.isWritable(), IsUserAdmin());
|
QCOMPARE(fi2.isWritable(), IsUserAdmin());
|
||||||
@ -2156,7 +2151,7 @@ void tst_QFileInfo::owner()
|
|||||||
NetApiBufferFree(pBuf);
|
NetApiBufferFree(pBuf);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
qt_ntfs_permission_lookup = 1;
|
QNtfsPermissionCheckGuard permissionGuard;
|
||||||
#endif
|
#endif
|
||||||
if (userName.isEmpty())
|
if (userName.isEmpty())
|
||||||
QSKIP("Can't retrieve the user name");
|
QSKIP("Can't retrieve the user name");
|
||||||
@ -2173,9 +2168,6 @@ void tst_QFileInfo::owner()
|
|||||||
QCOMPARE(fi.owner(), userName);
|
QCOMPARE(fi.owner(), userName);
|
||||||
|
|
||||||
QFile::remove(fileName);
|
QFile::remove(fileName);
|
||||||
#if defined(Q_OS_WIN)
|
|
||||||
qt_ntfs_permission_lookup = 0;
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void tst_QFileInfo::group()
|
void tst_QFileInfo::group()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user