1
/****************************************************************************
3
** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
4
** Contact: http://www.qt-project.org/legal
6
** This file is part of the QtCore module of the Qt Toolkit.
8
** $QT_BEGIN_LICENSE:LGPL$
9
** Commercial License Usage
10
** Licensees holding valid commercial Qt licenses may use this file in
11
** accordance with the commercial license agreement provided with the
12
** Software or, alternatively, in accordance with the terms contained in
13
** a written agreement between you and Digia. For licensing terms and
14
** conditions see http://qt.digia.com/licensing. For further information
15
** use the contact form at http://qt.digia.com/contact-us.
17
** GNU Lesser General Public License Usage
18
** Alternatively, this file may be used under the terms of the GNU Lesser
19
** General Public License version 2.1 as published by the Free Software
20
** Foundation and appearing in the file LICENSE.LGPL included in the
21
** packaging of this file. Please review the following information to
22
** ensure the GNU Lesser General Public License version 2.1 requirements
23
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25
** In addition, as a special exception, Digia gives you certain additional
26
** rights. These rights are described in the Digia Qt LGPL Exception
27
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29
** GNU General Public License Usage
30
** Alternatively, this file may be used under the terms of the GNU
31
** General Public License version 3.0 as published by the Free Software
32
** Foundation and appearing in the file LICENSE.GPL included in the
33
** packaging of this file. Please review the following information to
34
** ensure the GNU General Public License version 3.0 requirements will be
35
** met: http://www.gnu.org/copyleft/gpl.html.
40
****************************************************************************/
42
#include "qstandardpaths.h"
46
#include <qtextstream.h>
47
#include <private/qfilesystemengine_p.h>
51
#ifndef QT_BOOTSTRAPPED
52
#include <qcoreapplication.h>
55
#ifndef QT_NO_STANDARDPATHS
59
static void appendOrganizationAndApp(QString &path)
61
#ifndef QT_BOOTSTRAPPED
62
const QString org = QCoreApplication::organizationName();
64
path += QLatin1Char('/') + org;
65
const QString appName = QCoreApplication::applicationName();
66
if (!appName.isEmpty())
67
path += QLatin1Char('/') + appName;
73
QString QStandardPaths::writableLocation(StandardLocation type)
77
return QDir::homePath();
79
return QDir::tempPath();
81
case GenericCacheLocation:
83
// http://standards.freedesktop.org/basedir-spec/basedir-spec-0.6.html
84
QString xdgCacheHome = QFile::decodeName(qgetenv("XDG_CACHE_HOME"));
85
if (isTestModeEnabled())
86
xdgCacheHome = QDir::homePath() + QLatin1String("/.qttest/cache");
87
if (xdgCacheHome.isEmpty())
88
xdgCacheHome = QDir::homePath() + QLatin1String("/.cache");
89
if (type == QStandardPaths::CacheLocation)
90
appendOrganizationAndApp(xdgCacheHome);
94
case GenericDataLocation:
96
QString xdgDataHome = QFile::decodeName(qgetenv("XDG_DATA_HOME"));
97
if (isTestModeEnabled())
98
xdgDataHome = QDir::homePath() + QLatin1String("/.qttest/share");
99
if (xdgDataHome.isEmpty())
100
xdgDataHome = QDir::homePath() + QLatin1String("/.local/share");
101
if (type == QStandardPaths::DataLocation)
102
appendOrganizationAndApp(xdgDataHome);
107
// http://standards.freedesktop.org/basedir-spec/latest/
108
QString xdgConfigHome = QFile::decodeName(qgetenv("XDG_CONFIG_HOME"));
109
if (isTestModeEnabled())
110
xdgConfigHome = QDir::homePath() + QLatin1String("/.qttest/config");
111
if (xdgConfigHome.isEmpty())
112
xdgConfigHome = QDir::homePath() + QLatin1String("/.config");
113
return xdgConfigHome;
115
case RuntimeLocation:
117
const uid_t myUid = geteuid();
118
// http://standards.freedesktop.org/basedir-spec/latest/
119
QString xdgRuntimeDir = QFile::decodeName(qgetenv("XDG_RUNTIME_DIR"));
120
if (xdgRuntimeDir.isEmpty()) {
121
const QString userName = QFileSystemEngine::resolveUserName(myUid);
122
xdgRuntimeDir = QDir::tempPath() + QLatin1String("/runtime-") + userName;
123
QDir dir(xdgRuntimeDir);
125
if (!QDir().mkdir(xdgRuntimeDir)) {
126
qWarning("QStandardPaths: error creating runtime directory %s: %s", qPrintable(xdgRuntimeDir), qPrintable(qt_error_string(errno)));
130
qWarning("QStandardPaths: XDG_RUNTIME_DIR not set, defaulting to '%s'", qPrintable(xdgRuntimeDir));
132
// "The directory MUST be owned by the user"
133
QFileInfo fileInfo(xdgRuntimeDir);
134
if (fileInfo.ownerId() != myUid) {
135
qWarning("QStandardPaths: wrong ownership on runtime directory %s, %d instead of %d", qPrintable(xdgRuntimeDir),
136
fileInfo.ownerId(), myUid);
139
// "and he MUST be the only one having read and write access to it. Its Unix access mode MUST be 0700."
140
QFile file(xdgRuntimeDir);
141
const QFile::Permissions wantedPerms = QFile::ReadUser | QFile::WriteUser | QFile::ExeUser;
142
if (file.permissions() != wantedPerms && !file.setPermissions(wantedPerms)) {
143
qWarning("QStandardPaths: wrong permissions on runtime directory %s", qPrintable(xdgRuntimeDir));
146
return xdgRuntimeDir;
152
#ifndef QT_BOOTSTRAPPED
153
// http://www.freedesktop.org/wiki/Software/xdg-user-dirs
154
QString xdgConfigHome = QFile::decodeName(qgetenv("XDG_CONFIG_HOME"));
155
if (xdgConfigHome.isEmpty())
156
xdgConfigHome = QDir::homePath() + QLatin1String("/.config");
157
QFile file(xdgConfigHome + QLatin1String("/user-dirs.dirs"));
158
if (!isTestModeEnabled() && file.open(QIODevice::ReadOnly)) {
159
QHash<QString, QString> lines;
160
QTextStream stream(&file);
161
// Only look for lines like: XDG_DESKTOP_DIR="$HOME/Desktop"
162
QRegExp exp(QLatin1String("^XDG_(.*)_DIR=(.*)$"));
163
while (!stream.atEnd()) {
164
const QString &line = stream.readLine();
165
if (exp.indexIn(line) != -1) {
166
const QStringList lst = exp.capturedTexts();
167
const QString key = lst.at(1);
168
QString value = lst.at(2);
169
if (value.length() > 2
170
&& value.startsWith(QLatin1Char('\"'))
171
&& value.endsWith(QLatin1Char('\"')))
172
value = value.mid(1, value.length() - 2);
173
// Store the key and value: "DESKTOP", "$HOME/Desktop"
180
case DesktopLocation:
181
key = QLatin1String("DESKTOP");
183
case DocumentsLocation:
184
key = QLatin1String("DOCUMENTS");
186
case PicturesLocation:
187
key = QLatin1String("PICTURES");
190
key = QLatin1String("MUSIC");
193
key = QLatin1String("VIDEOS");
195
case DownloadLocation:
196
key = QLatin1String("DOWNLOAD");
201
if (!key.isEmpty()) {
202
QString value = lines.value(key);
203
if (!value.isEmpty()) {
204
// value can start with $HOME
205
if (value.startsWith(QLatin1String("$HOME")))
206
value = QDir::homePath() + value.mid(5);
215
case DesktopLocation:
216
path = QDir::homePath() + QLatin1String("/Desktop");
218
case DocumentsLocation:
219
path = QDir::homePath() + QLatin1String("/Documents");
221
case PicturesLocation:
222
path = QDir::homePath() + QLatin1String("/Pictures");
226
path = QDir::homePath() + QLatin1String("/.fonts");
230
path = QDir::homePath() + QLatin1String("/Music");
234
path = QDir::homePath() + QLatin1String("/Videos");
236
case DownloadLocation:
237
path = QDir::homePath() + QLatin1String("/Downloads");
239
case ApplicationsLocation:
240
path = writableLocation(GenericDataLocation) + QLatin1String("/applications");
250
static QStringList xdgDataDirs()
253
// http://standards.freedesktop.org/basedir-spec/latest/
254
QString xdgDataDirsEnv = QFile::decodeName(qgetenv("XDG_DATA_DIRS"));
255
if (xdgDataDirsEnv.isEmpty()) {
256
dirs.append(QString::fromLatin1("/usr/local/share"));
257
dirs.append(QString::fromLatin1("/usr/share"));
259
dirs = xdgDataDirsEnv.split(QLatin1Char(':'));
264
QStringList QStandardPaths::standardLocations(StandardLocation type)
270
// http://standards.freedesktop.org/basedir-spec/latest/
271
const QString xdgConfigDirs = QFile::decodeName(qgetenv("XDG_CONFIG_DIRS"));
272
if (xdgConfigDirs.isEmpty())
273
dirs.append(QString::fromLatin1("/etc/xdg"));
275
dirs = xdgConfigDirs.split(QLatin1Char(':'));
278
case GenericDataLocation:
279
dirs = xdgDataDirs();
281
case ApplicationsLocation:
282
dirs = xdgDataDirs();
283
for (int i = 0; i < dirs.count(); ++i)
284
dirs[i].append(QLatin1String("/applications"));
287
dirs = xdgDataDirs();
288
for (int i = 0; i < dirs.count(); ++i)
289
appendOrganizationAndApp(dirs[i]);
294
const QString localDir = writableLocation(type);
295
dirs.prepend(localDir);
301
#endif // QT_NO_STANDARDPATHS