summaryrefslogtreecommitdiffstats
path: root/src/corelib/io/qstandardpaths_unix.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/corelib/io/qstandardpaths_unix.cpp')
-rw-r--r--src/corelib/io/qstandardpaths_unix.cpp319
1 files changed, 173 insertions, 146 deletions
diff --git a/src/corelib/io/qstandardpaths_unix.cpp b/src/corelib/io/qstandardpaths_unix.cpp
index 2623de0fe0..e38f670895 100644
--- a/src/corelib/io/qstandardpaths_unix.cpp
+++ b/src/corelib/io/qstandardpaths_unix.cpp
@@ -1,42 +1,6 @@
-/****************************************************************************
-**
-** 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.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2020 The Qt Company Ltd.
+// Copyright (C) 2020 Intel Corporation.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qstandardpaths.h"
#include <qdir.h>
@@ -58,42 +22,72 @@
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+
static void appendOrganizationAndApp(QString &path)
{
#ifndef QT_BOOTSTRAPPED
const QString org = QCoreApplication::organizationName();
if (!org.isEmpty())
- path += QLatin1Char('/') + org;
+ path += u'/' + org;
const QString appName = QCoreApplication::applicationName();
if (!appName.isEmpty())
- path += QLatin1Char('/') + appName;
+ path += u'/' + appName;
#else
Q_UNUSED(path);
#endif
}
#if QT_CONFIG(regularexpression)
-static QLatin1String xdg_key_name(QStandardPaths::StandardLocation type)
+static QLatin1StringView xdg_key_name(QStandardPaths::StandardLocation type)
{
switch (type) {
case QStandardPaths::DesktopLocation:
- return QLatin1String("DESKTOP");
+ return "DESKTOP"_L1;
case QStandardPaths::DocumentsLocation:
- return QLatin1String("DOCUMENTS");
+ return "DOCUMENTS"_L1;
case QStandardPaths::PicturesLocation:
- return QLatin1String("PICTURES");
+ return "PICTURES"_L1;
case QStandardPaths::MusicLocation:
- return QLatin1String("MUSIC");
+ return "MUSIC"_L1;
case QStandardPaths::MoviesLocation:
- return QLatin1String("VIDEOS");
+ return "VIDEOS"_L1;
case QStandardPaths::DownloadLocation:
- return QLatin1String("DOWNLOAD");
+ return "DOWNLOAD"_L1;
+ case QStandardPaths::PublicShareLocation:
+ return "PUBLICSHARE"_L1;
+ case QStandardPaths::TemplatesLocation:
+ return "TEMPLATES"_L1;
default:
- return QLatin1String();
+ return {};
}
}
#endif
+static QByteArray unixPermissionsText(QFile::Permissions permissions)
+{
+ mode_t perms = 0;
+ if (permissions & QFile::ReadOwner)
+ perms |= S_IRUSR;
+ if (permissions & QFile::WriteOwner)
+ perms |= S_IWUSR;
+ if (permissions & QFile::ExeOwner)
+ perms |= S_IXUSR;
+ if (permissions & QFile::ReadGroup)
+ perms |= S_IRGRP;
+ if (permissions & QFile::WriteGroup)
+ perms |= S_IWGRP;
+ if (permissions & QFile::ExeGroup)
+ perms |= S_IXGRP;
+ if (permissions & QFile::ReadOther)
+ perms |= S_IROTH;
+ if (permissions & QFile::WriteOther)
+ perms |= S_IWOTH;
+ if (permissions & QFile::ExeOther)
+ perms |= S_IXOTH;
+ return '0' + QByteArray::number(perms, 8);
+}
+
static bool checkXdgRuntimeDir(const QString &xdgRuntimeDir)
{
auto describeMetaData = [](const QFileSystemMetaData &metaData) -> QByteArray {
@@ -113,27 +107,7 @@ static bool checkXdgRuntimeDir(const QString &xdgRuntimeDir)
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);
+ description += " permissions " + unixPermissionsText(metaData.permissions());
return description
+ " owned by UID " + QByteArray::number(metaData.userId())
@@ -186,14 +160,11 @@ static bool checkXdgRuntimeDir(const QString &xdgRuntimeDir)
// "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;
- }
+ qWarning("QStandardPaths: wrong permissions on runtime directory %ls, %s instead of %s",
+ qUtf16Printable(xdgRuntimeDir),
+ unixPermissionsText(metaData.permissions()).constData(),
+ unixPermissionsText(wantedPerms).constData());
+ return false;
}
return true;
@@ -209,25 +180,56 @@ QString QStandardPaths::writableLocation(StandardLocation type)
case CacheLocation:
case GenericCacheLocation:
{
- // http://standards.freedesktop.org/basedir-spec/basedir-spec-0.6.html
- QString xdgCacheHome = QFile::decodeName(qgetenv("XDG_CACHE_HOME"));
- if (isTestModeEnabled())
- xdgCacheHome = QDir::homePath() + QLatin1String("/.qttest/cache");
- if (xdgCacheHome.isEmpty())
- xdgCacheHome = QDir::homePath() + QLatin1String("/.cache");
+ QString xdgCacheHome;
+ if (isTestModeEnabled()) {
+ xdgCacheHome = QDir::homePath() + "/.qttest/cache"_L1;
+ } else {
+ // http://standards.freedesktop.org/basedir-spec/basedir-spec-0.6.html
+ xdgCacheHome = QFile::decodeName(qgetenv("XDG_CACHE_HOME"));
+ if (!xdgCacheHome.startsWith(u'/'))
+ xdgCacheHome.clear(); // spec says relative paths should be ignored
+
+ if (xdgCacheHome.isEmpty())
+ xdgCacheHome = QDir::homePath() + "/.cache"_L1;
+ }
if (type == QStandardPaths::CacheLocation)
appendOrganizationAndApp(xdgCacheHome);
return xdgCacheHome;
}
+ case StateLocation:
+ case GenericStateLocation:
+ {
+ QString xdgStateHome;
+ if (isTestModeEnabled()) {
+ xdgStateHome = QDir::homePath() + "/.qttest/state"_L1;
+ } else {
+ // http://standards.freedesktop.org/basedir-spec/basedir-spec-0.8.html
+ xdgStateHome = QFile::decodeName(qgetenv("XDG_STATE_HOME"));
+ if (!xdgStateHome.startsWith(u'/'))
+ xdgStateHome.clear(); // spec says relative paths should be ignored
+
+ if (xdgStateHome.isEmpty())
+ xdgStateHome = QDir::homePath() + "/.local/state"_L1;
+ }
+ if (type == QStandardPaths::StateLocation)
+ appendOrganizationAndApp(xdgStateHome);
+ return xdgStateHome;
+ }
case AppDataLocation:
case AppLocalDataLocation:
case GenericDataLocation:
{
- QString xdgDataHome = QFile::decodeName(qgetenv("XDG_DATA_HOME"));
- if (isTestModeEnabled())
- xdgDataHome = QDir::homePath() + QLatin1String("/.qttest/share");
- if (xdgDataHome.isEmpty())
- xdgDataHome = QDir::homePath() + QLatin1String("/.local/share");
+ QString xdgDataHome;
+ if (isTestModeEnabled()) {
+ xdgDataHome = QDir::homePath() + "/.qttest/share"_L1;
+ } else {
+ xdgDataHome = QFile::decodeName(qgetenv("XDG_DATA_HOME"));
+ if (!xdgDataHome.startsWith(u'/'))
+ xdgDataHome.clear(); // spec says relative paths should be ignored
+
+ if (xdgDataHome.isEmpty())
+ xdgDataHome = QDir::homePath() + "/.local/share"_L1;
+ }
if (type == AppDataLocation || type == AppLocalDataLocation)
appendOrganizationAndApp(xdgDataHome);
return xdgDataHome;
@@ -236,12 +238,18 @@ QString QStandardPaths::writableLocation(StandardLocation type)
case GenericConfigLocation:
case AppConfigLocation:
{
- // http://standards.freedesktop.org/basedir-spec/latest/
- QString xdgConfigHome = QFile::decodeName(qgetenv("XDG_CONFIG_HOME"));
- if (isTestModeEnabled())
- xdgConfigHome = QDir::homePath() + QLatin1String("/.qttest/config");
- if (xdgConfigHome.isEmpty())
- xdgConfigHome = QDir::homePath() + QLatin1String("/.config");
+ QString xdgConfigHome;
+ if (isTestModeEnabled()) {
+ xdgConfigHome = QDir::homePath() + "/.qttest/config"_L1;
+ } else {
+ // http://standards.freedesktop.org/basedir-spec/latest/
+ xdgConfigHome = QFile::decodeName(qgetenv("XDG_CONFIG_HOME"));
+ if (!xdgConfigHome.startsWith(u'/'))
+ xdgConfigHome.clear(); // spec says relative paths should be ignored
+
+ if (xdgConfigHome.isEmpty())
+ xdgConfigHome = QDir::homePath() + "/.config"_L1;
+ }
if (type == AppConfigLocation)
appendOrganizationAndApp(xdgConfigHome);
return xdgConfigHome;
@@ -249,12 +257,15 @@ QString QStandardPaths::writableLocation(StandardLocation type)
case RuntimeLocation:
{
QString xdgRuntimeDir = QFile::decodeName(qgetenv("XDG_RUNTIME_DIR"));
+ if (!xdgRuntimeDir.startsWith(u'/'))
+ xdgRuntimeDir.clear(); // spec says relative paths should be ignored
+
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;
+ xdgRuntimeDir = QDir::tempPath() + "/runtime-"_L1 + userName;
if (!fromEnv) {
#ifndef Q_OS_WASM
@@ -275,30 +286,33 @@ QString QStandardPaths::writableLocation(StandardLocation type)
#if QT_CONFIG(regularexpression)
// http://www.freedesktop.org/wiki/Software/xdg-user-dirs
QString xdgConfigHome = QFile::decodeName(qgetenv("XDG_CONFIG_HOME"));
+ if (!xdgConfigHome.startsWith(u'/'))
+ xdgConfigHome.clear(); // spec says relative paths should be ignored
+
if (xdgConfigHome.isEmpty())
- xdgConfigHome = QDir::homePath() + QLatin1String("/.config");
- QFile file(xdgConfigHome + QLatin1String("/user-dirs.dirs"));
- const QLatin1String key = xdg_key_name(type);
+ xdgConfigHome = QDir::homePath() + "/.config"_L1;
+ QFile file(xdgConfigHome + "/user-dirs.dirs"_L1);
+ const QLatin1StringView key = xdg_key_name(type);
if (!key.isEmpty() && !isTestModeEnabled() && file.open(QIODevice::ReadOnly)) {
QTextStream stream(&file);
// Only look for lines like: XDG_DESKTOP_DIR="$HOME/Desktop"
- QRegularExpression exp(QLatin1String("^XDG_(.*)_DIR=(.*)$"));
+ static const QRegularExpression exp(u"^XDG_(.*)_DIR=(.*)$"_s);
QString result;
while (!stream.atEnd()) {
const QString &line = stream.readLine();
QRegularExpressionMatch match = exp.match(line);
if (match.hasMatch() && match.capturedView(1) == key) {
QStringView value = match.capturedView(2);
- if (value.length() > 2
- && value.startsWith(QLatin1Char('\"'))
- && value.endsWith(QLatin1Char('\"')))
- value = value.mid(1, value.length() - 2);
+ if (value.size() > 2
+ && value.startsWith(u'\"')
+ && value.endsWith(u'\"'))
+ value = value.mid(1, value.size() - 2);
// value can start with $HOME
- if (value.startsWith(QLatin1String("$HOME")))
+ if (value.startsWith("$HOME"_L1))
result = QDir::homePath() + value.mid(5);
else
result = value.toString();
- if (result.length() > 1 && result.endsWith(QLatin1Char('/')))
+ if (result.size() > 1 && result.endsWith(u'/'))
result.chop(1);
}
}
@@ -310,31 +324,39 @@ QString QStandardPaths::writableLocation(StandardLocation type)
QString path;
switch (type) {
case DesktopLocation:
- path = QDir::homePath() + QLatin1String("/Desktop");
+ path = QDir::homePath() + "/Desktop"_L1;
break;
case DocumentsLocation:
- path = QDir::homePath() + QLatin1String("/Documents");
+ path = QDir::homePath() + "/Documents"_L1;
break;
case PicturesLocation:
- path = QDir::homePath() + QLatin1String("/Pictures");
+ path = QDir::homePath() + "/Pictures"_L1;
break;
case FontsLocation:
- path = writableLocation(GenericDataLocation) + QLatin1String("/fonts");
+ path = writableLocation(GenericDataLocation) + "/fonts"_L1;
break;
case MusicLocation:
- path = QDir::homePath() + QLatin1String("/Music");
+ path = QDir::homePath() + "/Music"_L1;
break;
case MoviesLocation:
- path = QDir::homePath() + QLatin1String("/Videos");
+ path = QDir::homePath() + "/Videos"_L1;
break;
case DownloadLocation:
- path = QDir::homePath() + QLatin1String("/Downloads");
+ path = QDir::homePath() + "/Downloads"_L1;
break;
case ApplicationsLocation:
- path = writableLocation(GenericDataLocation) + QLatin1String("/applications");
+ path = writableLocation(GenericDataLocation) + "/applications"_L1;
+ break;
+
+ case PublicShareLocation:
+ path = QDir::homePath() + "/Public"_L1;
+ break;
+
+ case TemplatesLocation:
+ path = QDir::homePath() + "/Templates"_L1;
break;
default:
@@ -344,43 +366,48 @@ QString QStandardPaths::writableLocation(StandardLocation type)
return path;
}
-static QStringList xdgDataDirs()
+static QStringList dirsList(const QString &xdgEnvVar)
{
QStringList dirs;
// http://standards.freedesktop.org/basedir-spec/latest/
+ // Normalize paths, skip relative paths (the spec says relative paths
+ // should be ignored)
+ for (const auto dir : qTokenize(xdgEnvVar, u':'))
+ if (dir.startsWith(u'/'))
+ dirs.push_back(QDir::cleanPath(dir.toString()));
+
+ // Remove duplicates from the list, there's no use for duplicated paths
+ // in XDG_* env vars - if whatever is being looked for is not found in
+ // the given directory the first time, it won't be there the second time.
+ // Plus duplicate paths causes problems for example for mimetypes,
+ // where duplicate paths here lead to duplicated mime types returned
+ // for a file, eg "text/plain,text/plain" instead of "text/plain"
+ dirs.removeDuplicates();
+
+ return dirs;
+}
+
+static QStringList xdgDataDirs()
+{
+ // http://standards.freedesktop.org/basedir-spec/latest/
QString xdgDataDirsEnv = QFile::decodeName(qgetenv("XDG_DATA_DIRS"));
- if (xdgDataDirsEnv.isEmpty()) {
- dirs.append(QString::fromLatin1("/usr/local/share"));
- dirs.append(QString::fromLatin1("/usr/share"));
- } else {
- const auto parts = QStringView{xdgDataDirsEnv}.split(QLatin1Char(':'), Qt::SkipEmptyParts);
-
- // Normalize paths, skip relative paths
- for (const auto &dir : parts) {
- if (dir.startsWith(QLatin1Char('/')))
- dirs.push_back(QDir::cleanPath(dir.toString()));
- }
- // Remove duplicates from the list, there's no use for duplicated
- // paths in XDG_DATA_DIRS - if it's not found in the given
- // directory the first time, it won't be there the second time.
- // Plus duplicate paths causes problems for example for mimetypes,
- // where duplicate paths here lead to duplicated mime types returned
- // for a file, eg "text/plain,text/plain" instead of "text/plain"
- dirs.removeDuplicates();
- }
+ QStringList dirs = dirsList(xdgDataDirsEnv);
+ if (dirs.isEmpty())
+ dirs = QStringList{u"/usr/local/share"_s, u"/usr/share"_s};
+
return dirs;
}
static QStringList xdgConfigDirs()
{
- QStringList dirs;
// http://standards.freedesktop.org/basedir-spec/latest/
const QString xdgConfigDirs = QFile::decodeName(qgetenv("XDG_CONFIG_DIRS"));
- if (xdgConfigDirs.isEmpty())
- dirs.append(QString::fromLatin1("/etc/xdg"));
- else
- dirs = xdgConfigDirs.split(QLatin1Char(':'));
+
+ QStringList dirs = dirsList(xdgConfigDirs);
+ if (dirs.isEmpty())
+ dirs.push_back(u"/etc/xdg"_s);
+
return dirs;
}
@@ -394,7 +421,7 @@ QStringList QStandardPaths::standardLocations(StandardLocation type)
break;
case AppConfigLocation:
dirs = xdgConfigDirs();
- for (int i = 0; i < dirs.count(); ++i)
+ for (int i = 0; i < dirs.size(); ++i)
appendOrganizationAndApp(dirs[i]);
break;
case GenericDataLocation:
@@ -402,20 +429,20 @@ QStringList QStandardPaths::standardLocations(StandardLocation type)
break;
case ApplicationsLocation:
dirs = xdgDataDirs();
- for (int i = 0; i < dirs.count(); ++i)
- dirs[i].append(QLatin1String("/applications"));
+ for (int i = 0; i < dirs.size(); ++i)
+ dirs[i].append("/applications"_L1);
break;
case AppDataLocation:
case AppLocalDataLocation:
dirs = xdgDataDirs();
- for (int i = 0; i < dirs.count(); ++i)
+ for (int i = 0; i < dirs.size(); ++i)
appendOrganizationAndApp(dirs[i]);
break;
case FontsLocation:
- dirs += QDir::homePath() + QLatin1String("/.fonts");
+ dirs += QDir::homePath() + "/.fonts"_L1;
dirs += xdgDataDirs();
- for (int i = 1; i < dirs.count(); ++i)
- dirs[i].append(QLatin1String("/fonts"));
+ for (int i = 1; i < dirs.size(); ++i)
+ dirs[i].append("/fonts"_L1);
break;
default:
break;