Android: Fix QSettings when using content URL

Using QSettings with Content URL in Android failed because of 3 issues:
* the lock file assumed that it could append ".lock" to the file name
for its name
* the lock file assumed that it could write in the same directory as the
file
* the QSaveFile used by QSettings requires direct write on content URL
but setDirectWriteFallback is set to false on QSettings by default

This patch fixes those issues by, when it is an Content URL in Android,
saving the lock file in QStandardPaths::CacheLocation and setting the
setDirectWriteFallback to true.
This does not break backwards compatibility because appending ".lock"
to the Content URL will always make an invalid URL, so it did not work
before.

Fixes: QTBUG-103455
Pick-to: 6.3 6.2
Change-Id: I92867577507b7069e4e6091d94e0931bb6dbcbed
Reviewed-by: Edward Welbourne <edward.welbourne@qt.io>
Reviewed-by: Assam Boudjelthia <assam.boudjelthia@qt.io>
This commit is contained in:
Samuel Mira 2022-06-01 15:59:29 +03:00
parent 3df23b1fe4
commit 140ca89a3c

View File

@ -48,8 +48,9 @@
#define Q_XDG_PLATFORM
#endif
#if !defined(QT_NO_STANDARDPATHS) && (defined(Q_XDG_PLATFORM) || defined(QT_PLATFORM_UIKIT))
#define QSETTINGS_USE_QSTANDARDPATHS
#if !defined(QT_NO_STANDARDPATHS) \
&& (defined(Q_XDG_PLATFORM) || defined(QT_PLATFORM_UIKIT) || defined(Q_OS_ANDROID))
# define QSETTINGS_USE_QSTANDARDPATHS
#endif
// ************************************************************************
@ -1331,6 +1332,15 @@ void QConfFileSettingsPrivate::syncConfFile(QConfFile *confFile)
}
#ifndef QT_BOOTSTRAPPED
QString lockFileName = confFile->name + ".lock"_L1;
# if defined(Q_OS_ANDROID) && defined(QSETTINGS_USE_QSTANDARDPATHS)
// On android and if it is a content URL put the lock file in a
// writable location to prevent permissions issues and invalid paths.
if (confFile->name.startsWith("content:"_L1))
lockFileName = QStandardPaths::writableLocation(QStandardPaths::CacheLocation)
+ QFileInfo(lockFileName).fileName();
# endif
/*
Use a lockfile in order to protect us against other QSettings instances
trying to write the same settings at the same time.
@ -1338,7 +1348,7 @@ void QConfFileSettingsPrivate::syncConfFile(QConfFile *confFile)
We only need to lock if we are actually writing as only concurrent writes are a problem.
Concurrent read and write are not a problem because the writing operation is atomic.
*/
QLockFile lockFile(confFile->name + ".lock"_L1);
QLockFile lockFile(lockFileName);
if (!readOnly && !lockFile.lock() && atomicSyncOnly) {
setStatus(QSettings::AccessError);
return;
@ -1416,6 +1426,11 @@ void QConfFileSettingsPrivate::syncConfFile(QConfFile *confFile)
#if !defined(QT_BOOTSTRAPPED) && QT_CONFIG(temporaryfile)
QSaveFile sf(confFile->name);
sf.setDirectWriteFallback(!atomicSyncOnly);
# ifdef Q_OS_ANDROID
// QSaveFile requires direct write when using content scheme URL in Android
if (confFile->name.startsWith("content:"_L1))
sf.setDirectWriteFallback(true);
# endif
#else
QFile sf(confFile->name);
#endif