2014-11-13 01:04:59 +02:00
|
|
|
/* This file is part of the KDE libraries
|
|
|
|
Copyright (C) 1999 Sirtaj Singh Kang <taj@kde.org>
|
|
|
|
Copyright (C) 1999,2007 Stephan Kulow <coolo@kde.org>
|
|
|
|
Copyright (C) 1999 Waldo Bastian <bastian@kde.org>
|
|
|
|
Copyright (C) 2009 David Faure <faure@kde.org>
|
|
|
|
|
|
|
|
This library is free software; you can redistribute it and/or
|
|
|
|
modify it under the terms of the GNU Library General Public
|
|
|
|
License version 2 as published by the Free Software Foundation.
|
|
|
|
|
|
|
|
This library is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
Library General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU Library General Public License
|
|
|
|
along with this library; see the file COPYING.LIB. If not, write to
|
|
|
|
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
|
|
|
Boston, MA 02110-1301, USA.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Author: Stephan Kulow <coolo@kde.org> and Sirtaj Singh Kang <taj@kde.org>
|
|
|
|
* Generated: Thu Mar 5 16:05:28 EST 1998
|
|
|
|
*/
|
|
|
|
|
2022-09-23 07:37:22 +03:00
|
|
|
#include <config.h>
|
|
|
|
#include <config-prefix.h>
|
|
|
|
#include <config-kstandarddirs.h>
|
|
|
|
|
2014-11-13 01:04:59 +02:00
|
|
|
#include "kstandarddirs.h"
|
|
|
|
#include "kconfig.h"
|
|
|
|
#include "kconfiggroup.h"
|
|
|
|
#include "kdebug.h"
|
|
|
|
#include "kcomponentdata.h"
|
|
|
|
#include "kshell.h"
|
|
|
|
#include "kuser.h"
|
|
|
|
#include "kde_file.h"
|
|
|
|
#include "klocale.h"
|
|
|
|
|
2022-09-23 07:37:22 +03:00
|
|
|
#include <QtCore/QRegExp>
|
|
|
|
#include <QtCore/QDir>
|
|
|
|
#include <QtCore/QCache>
|
|
|
|
#include <QtCore/QFileInfo>
|
|
|
|
#include <QtCore/QSettings>
|
|
|
|
#include <QtCore/QStandardPaths>
|
2014-11-13 01:04:59 +02:00
|
|
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <assert.h>
|
2021-08-08 21:55:14 +03:00
|
|
|
#include <string.h>
|
2014-11-13 01:04:59 +02:00
|
|
|
#include <errno.h>
|
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <sys/param.h>
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <dirent.h>
|
2021-07-22 01:24:13 +03:00
|
|
|
#include <mutex>
|
|
|
|
|
2016-03-04 20:51:02 +02:00
|
|
|
#define case_sensitivity Qt::CaseSensitive
|
2014-11-13 01:04:59 +02:00
|
|
|
|
2021-02-01 04:13:11 +02:00
|
|
|
#ifndef PATH_MAX
|
|
|
|
# define PATH_MAX _POSIX_PATH_MAX
|
|
|
|
#endif
|
|
|
|
|
2022-09-23 12:59:38 +03:00
|
|
|
// same as KPATH_SEPARATOR
|
|
|
|
static const QString s_pathseparator = QString::fromLatin1(":");
|
|
|
|
static const QChar s_pathseparatorchar = QChar::fromLatin1(KPATH_SEPARATOR);
|
|
|
|
|
|
|
|
static QString readEnvPath(const char *env)
|
|
|
|
{
|
|
|
|
QByteArray c_path;
|
|
|
|
c_path = qgetenv(env);
|
|
|
|
if (c_path.isEmpty())
|
|
|
|
return QString();
|
|
|
|
return QDir::fromNativeSeparators(QFile::decodeName(c_path));
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline QStringList splitPath(const QString &path)
|
|
|
|
{
|
|
|
|
const int len = path.length();
|
|
|
|
QString token;
|
|
|
|
QStringList tokens;
|
|
|
|
|
|
|
|
for(int index = 0; index < len; index++) {
|
|
|
|
if (path.at(index) == s_pathseparatorchar) {
|
|
|
|
tokens.append(token);
|
|
|
|
token.clear();
|
|
|
|
} else {
|
|
|
|
token += path.at(index);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!token.isEmpty()) {
|
|
|
|
tokens.append(token);
|
|
|
|
}
|
|
|
|
|
|
|
|
return tokens;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void priorityAdd(QStringList &prefixes, const QString& dir, bool priority)
|
|
|
|
{
|
|
|
|
if (priority && !prefixes.isEmpty())
|
|
|
|
{
|
|
|
|
// Add in front but behind $KDEHOME
|
|
|
|
QStringList::iterator it = prefixes.begin();
|
|
|
|
++it;
|
|
|
|
prefixes.insert(it, dir);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
prefixes.append(dir);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static QString checkExecutable( const QString& path, bool ignoreExecBit )
|
|
|
|
{
|
|
|
|
QFileInfo info( path );
|
|
|
|
QFileInfo orig = info;
|
|
|
|
if( info.exists() && info.isSymLink() )
|
|
|
|
info = QFileInfo( info.canonicalFilePath() );
|
|
|
|
if( info.exists() && ( ignoreExecBit || info.isExecutable() ) && info.isFile() ) {
|
|
|
|
// return absolute path, but without symlinks resolved in order to prevent
|
|
|
|
// problems with executables that work differently depending on name they are
|
|
|
|
// run as (for example gunzip)
|
|
|
|
orig.makeAbsolute();
|
|
|
|
return orig.filePath();
|
|
|
|
}
|
|
|
|
//kDebug(180) << "checkExecutable(): failed, returning empty string";
|
|
|
|
return QString();
|
|
|
|
}
|
|
|
|
|
|
|
|
static quint32 updateHash(const QString &file, quint32 hash)
|
|
|
|
{
|
|
|
|
KDE_struct_stat buff;
|
|
|
|
if ((KDE::access(file, R_OK) == 0) && (KDE::stat(file, &buff) == 0) && (S_ISREG(buff.st_mode))) {
|
|
|
|
hash = hash + static_cast<quint32>(buff.st_ctime);
|
|
|
|
}
|
|
|
|
return hash;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void lookupDirectory(const QString& path, const QString &relPart,
|
|
|
|
const QRegExp ®exp,
|
|
|
|
QStringList& list,
|
|
|
|
QStringList& relList,
|
|
|
|
bool recursive, bool unique)
|
|
|
|
{
|
|
|
|
const QString pattern = regexp.pattern();
|
|
|
|
if (recursive || pattern.contains(QLatin1Char('?')) || pattern.contains(QLatin1Char('*')))
|
|
|
|
{
|
|
|
|
if (path.isEmpty()) //for sanity
|
|
|
|
return;
|
|
|
|
// We look for a set of files.
|
|
|
|
DIR *dp = opendir( QFile::encodeName(path));
|
|
|
|
if (!dp)
|
|
|
|
return;
|
|
|
|
|
|
|
|
assert(path.endsWith(QLatin1Char('/')));
|
|
|
|
|
|
|
|
struct dirent *ep;
|
|
|
|
|
|
|
|
while( ( ep = readdir( dp ) ) != 0L )
|
|
|
|
{
|
|
|
|
QString fn( QFile::decodeName(ep->d_name));
|
|
|
|
if (fn == QString::fromLatin1(".") || fn == QString::fromLatin1("..") || fn.at(fn.length() - 1) == QLatin1Char('~'))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (!recursive && !regexp.exactMatch(fn))
|
|
|
|
continue; // No match
|
|
|
|
|
|
|
|
bool isDir;
|
|
|
|
bool isReg;
|
|
|
|
|
|
|
|
QString pathfn = path + fn;
|
|
|
|
#ifdef HAVE_DIRENT_D_TYPE
|
|
|
|
isDir = ep->d_type == DT_DIR;
|
|
|
|
isReg = ep->d_type == DT_REG;
|
|
|
|
|
|
|
|
if (ep->d_type == DT_UNKNOWN || ep->d_type == DT_LNK)
|
|
|
|
#endif
|
|
|
|
{
|
|
|
|
KDE_struct_stat buff;
|
|
|
|
if ( KDE::stat( pathfn, &buff ) != 0 ) {
|
|
|
|
kDebug(180) << "Error stat'ing " << pathfn << " : " << ::strerror(errno);
|
|
|
|
continue; // Couldn't stat (e.g. no read permissions)
|
|
|
|
}
|
|
|
|
isReg = S_ISREG (buff.st_mode);
|
|
|
|
isDir = S_ISDIR (buff.st_mode);
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( recursive ) {
|
|
|
|
if ( isDir ) {
|
|
|
|
lookupDirectory(pathfn + QLatin1Char('/'), relPart + fn + QLatin1Char('/'), regexp, list, relList, recursive, unique);
|
|
|
|
}
|
|
|
|
if (!regexp.exactMatch(fn))
|
|
|
|
continue; // No match
|
|
|
|
}
|
|
|
|
if ( isReg )
|
|
|
|
{
|
|
|
|
if (!unique || !relList.contains(relPart + fn, case_sensitivity))
|
|
|
|
{
|
|
|
|
list.append( pathfn );
|
|
|
|
relList.append( relPart + fn );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
closedir( dp );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// We look for a single file.
|
|
|
|
QString fn = pattern;
|
|
|
|
QString pathfn = path + fn;
|
|
|
|
KDE_struct_stat buff;
|
|
|
|
if ( KDE::stat( pathfn, &buff ) != 0 )
|
|
|
|
return; // File not found
|
|
|
|
if ( S_ISREG( buff.st_mode))
|
|
|
|
{
|
|
|
|
if (!unique || !relList.contains(relPart + fn, case_sensitivity))
|
|
|
|
{
|
|
|
|
list.append( pathfn );
|
|
|
|
relList.append( relPart + fn );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void lookupPrefix(const QString& prefix, const QString& relpath,
|
|
|
|
const QString& relPart,
|
|
|
|
const QRegExp ®exp,
|
|
|
|
QStringList& list,
|
|
|
|
QStringList& relList,
|
|
|
|
bool recursive, bool unique)
|
|
|
|
{
|
|
|
|
if (relpath.isEmpty()) {
|
|
|
|
if (recursive)
|
|
|
|
Q_ASSERT(prefix != QLatin1String("/")); // we don't want to recursively list the whole disk!
|
|
|
|
lookupDirectory(prefix, relPart, regexp, list,
|
|
|
|
relList, recursive, unique);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
QString path;
|
|
|
|
QString rest;
|
|
|
|
|
|
|
|
int slash = relpath.indexOf(QLatin1Char('/'));
|
|
|
|
if (slash < 0)
|
|
|
|
rest = relpath.left(relpath.length() - 1);
|
|
|
|
else {
|
|
|
|
path = relpath.left(slash);
|
|
|
|
rest = relpath.mid(slash + 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (prefix.isEmpty()) //for sanity
|
|
|
|
return;
|
|
|
|
// what does this assert check ?
|
|
|
|
assert(prefix.endsWith(QLatin1Char('/')));
|
|
|
|
if (path.contains(QLatin1Char('*')) || path.contains(QLatin1Char('?'))) {
|
|
|
|
|
|
|
|
QRegExp pathExp(path, Qt::CaseSensitive, QRegExp::Wildcard);
|
|
|
|
|
|
|
|
DIR *dp = opendir( QFile::encodeName(prefix) );
|
|
|
|
if (!dp) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct dirent *ep;
|
|
|
|
|
|
|
|
while( ( ep = readdir( dp ) ) != 0L )
|
|
|
|
{
|
|
|
|
QString fn( QFile::decodeName(ep->d_name));
|
|
|
|
if (fn == QLatin1String(".") || fn == QLatin1String("..") || fn.at(fn.length() - 1) == QLatin1Char('~'))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if ( !pathExp.exactMatch(fn) )
|
|
|
|
continue; // No match
|
|
|
|
QString rfn = relPart+fn;
|
|
|
|
fn = prefix + fn;
|
|
|
|
|
|
|
|
bool isDir;
|
|
|
|
|
|
|
|
#ifdef HAVE_DIRENT_D_TYPE
|
|
|
|
isDir = ep->d_type == DT_DIR;
|
|
|
|
|
|
|
|
if (ep->d_type == DT_UNKNOWN || ep->d_type == DT_LNK)
|
|
|
|
#endif
|
|
|
|
{
|
|
|
|
QString pathfn = path + fn;
|
|
|
|
KDE_struct_stat buff;
|
|
|
|
if ( KDE::stat( fn, &buff ) != 0 ) {
|
|
|
|
kDebug(180) << "Error stat'ing " << fn << " : " << ::strerror(errno);
|
|
|
|
continue; // Couldn't stat (e.g. no read permissions)
|
|
|
|
}
|
|
|
|
isDir = S_ISDIR (buff.st_mode);
|
|
|
|
}
|
|
|
|
if ( isDir )
|
|
|
|
lookupPrefix(fn + QLatin1Char('/'), rest, rfn + QLatin1Char('/'), regexp, list, relList, recursive, unique);
|
|
|
|
}
|
|
|
|
|
|
|
|
closedir( dp );
|
|
|
|
} else {
|
|
|
|
// Don't stat, if the dir doesn't exist we will find out
|
|
|
|
// when we try to open it.
|
|
|
|
lookupPrefix(prefix + path + QLatin1Char('/'), rest,
|
|
|
|
relPart + path + QLatin1Char('/'), regexp, list,
|
|
|
|
relList, recursive, unique);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef Q_OS_LINUX
|
|
|
|
static QString executablePrefix()
|
|
|
|
{
|
|
|
|
char path_buffer[PATH_MAX + 1];
|
|
|
|
path_buffer[PATH_MAX] = 0;
|
|
|
|
int length = readlink ("/proc/self/exe", path_buffer, PATH_MAX);
|
|
|
|
if (length == -1)
|
|
|
|
return QString();
|
|
|
|
|
|
|
|
path_buffer[length] = '\0';
|
|
|
|
|
|
|
|
QString path = QFile::decodeName(path_buffer);
|
|
|
|
|
|
|
|
if(path.isEmpty())
|
|
|
|
return QString();
|
|
|
|
|
|
|
|
int pos = path.lastIndexOf(QLatin1Char('/')); // Skip filename
|
|
|
|
if(pos <= 0)
|
|
|
|
return QString();
|
|
|
|
pos = path.lastIndexOf(QLatin1Char('/'), pos - 1); // Skip last directory
|
|
|
|
if(pos <= 0)
|
|
|
|
return QString();
|
|
|
|
|
|
|
|
return path.left(pos);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
2014-11-13 01:04:59 +02:00
|
|
|
class KStandardDirs::KStandardDirsPrivate
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
KStandardDirsPrivate(KStandardDirs* qq)
|
2022-06-05 14:46:22 +03:00
|
|
|
: q(qq)
|
2020-01-12 16:29:33 +00:00
|
|
|
{ }
|
2014-11-13 01:04:59 +02:00
|
|
|
|
|
|
|
QStringList resourceDirs(const char* type, const QString& subdirForRestrictions);
|
|
|
|
void createSpecialResource(const char*);
|
2015-10-17 18:53:50 +03:00
|
|
|
bool exists(const QString &fullPath);
|
|
|
|
QString realPath(const QString &dirname);
|
2014-11-13 01:04:59 +02:00
|
|
|
|
|
|
|
QStringList xdgdata_prefixes;
|
|
|
|
QStringList xdgconf_prefixes;
|
|
|
|
QStringList m_prefixes;
|
|
|
|
|
|
|
|
// Directory dictionaries
|
|
|
|
QMap<QByteArray, QStringList> m_absolutes; // For each resource type, the list of absolute paths, from most local (most priority) to most global
|
|
|
|
QMap<QByteArray, QStringList> m_relatives; // Same with relative paths
|
|
|
|
// The search path is "all relative paths" < "all absolute paths", from most priority to least priority.
|
|
|
|
|
|
|
|
// Caches (protected by mutex in const methods, cf ctor docu)
|
|
|
|
QMap<QByteArray, QStringList> m_dircache;
|
|
|
|
QMap<QByteArray, QString> m_savelocations;
|
2021-07-22 01:24:13 +03:00
|
|
|
std::recursive_mutex m_cacheMutex; // resourceDirs is recursive
|
2014-11-13 01:04:59 +02:00
|
|
|
|
|
|
|
KStandardDirs* q;
|
|
|
|
};
|
|
|
|
|
|
|
|
/* If you add a new resource type here, make sure to
|
2015-05-20 23:32:01 +00:00
|
|
|
* 1) regenerate using "generate_string_table.pl types < tmpfile" with the data below in tmpfile.
|
2014-11-13 01:04:59 +02:00
|
|
|
* 2) update the KStandardDirs class documentation
|
|
|
|
* 3) update the list in kde-config.cpp
|
|
|
|
|
|
|
|
data
|
|
|
|
share/apps
|
|
|
|
html
|
|
|
|
share/doc/HTML
|
|
|
|
icon
|
|
|
|
share/icons
|
|
|
|
config
|
|
|
|
share/config
|
|
|
|
pixmap
|
|
|
|
share/pixmaps
|
|
|
|
sound
|
|
|
|
share/sounds
|
|
|
|
locale
|
|
|
|
share/locale
|
|
|
|
services
|
2015-06-14 18:49:20 +03:00
|
|
|
share/kde4/services
|
2014-11-13 01:04:59 +02:00
|
|
|
servicetypes
|
2015-06-14 18:49:20 +03:00
|
|
|
share/kde4/servicetypes
|
2014-11-13 01:04:59 +02:00
|
|
|
wallpaper
|
|
|
|
share/wallpapers
|
|
|
|
templates
|
|
|
|
share/templates
|
|
|
|
exe
|
|
|
|
bin
|
|
|
|
module
|
2015-06-14 18:49:20 +03:00
|
|
|
%lib/kde4
|
2014-11-13 01:04:59 +02:00
|
|
|
qtplugins
|
2015-06-14 18:49:20 +03:00
|
|
|
%lib/kde4/plugins
|
2014-11-13 01:04:59 +02:00
|
|
|
kcfg
|
|
|
|
share/config.kcfg
|
|
|
|
xdgdata-apps
|
|
|
|
applications
|
|
|
|
xdgdata-icon
|
|
|
|
icons
|
|
|
|
xdgdata-pixmap
|
|
|
|
pixmaps
|
|
|
|
xdgdata-dirs
|
|
|
|
desktop-directories
|
|
|
|
xdgdata-mime
|
|
|
|
mime
|
|
|
|
xdgconf-menu
|
|
|
|
menus
|
|
|
|
xdgconf-autostart
|
|
|
|
autostart
|
|
|
|
*/
|
|
|
|
|
|
|
|
static const char types_string[] =
|
|
|
|
"data\0"
|
|
|
|
"share/apps\0"
|
|
|
|
"html\0"
|
|
|
|
"share/doc/HTML\0"
|
|
|
|
"icon\0"
|
|
|
|
"share/icons\0"
|
|
|
|
"config\0"
|
|
|
|
"share/config\0"
|
|
|
|
"pixmap\0"
|
|
|
|
"share/pixmaps\0"
|
|
|
|
"sound\0"
|
|
|
|
"share/sounds\0"
|
|
|
|
"locale\0"
|
|
|
|
"share/locale\0"
|
|
|
|
"services\0"
|
2015-06-14 18:49:20 +03:00
|
|
|
"share/kde4/services\0"
|
2014-11-13 01:04:59 +02:00
|
|
|
"servicetypes\0"
|
2015-06-14 18:49:20 +03:00
|
|
|
"share/kde4/servicetypes\0"
|
2014-11-13 01:04:59 +02:00
|
|
|
"wallpaper\0"
|
|
|
|
"share/wallpapers\0"
|
|
|
|
"templates\0"
|
|
|
|
"share/templates\0"
|
|
|
|
"exe\0"
|
|
|
|
"bin\0"
|
|
|
|
"module\0"
|
2015-06-14 18:49:20 +03:00
|
|
|
"%lib/kde4\0"
|
2014-11-13 01:04:59 +02:00
|
|
|
"qtplugins\0"
|
2015-06-14 18:49:20 +03:00
|
|
|
"%lib/kde4/plugins\0"
|
2014-11-13 01:04:59 +02:00
|
|
|
"kcfg\0"
|
|
|
|
"share/config.kcfg\0"
|
|
|
|
"xdgdata-apps\0"
|
|
|
|
"applications\0"
|
|
|
|
"xdgdata-icon\0"
|
|
|
|
"icons\0"
|
|
|
|
"xdgdata-pixmap\0"
|
|
|
|
"pixmaps\0"
|
|
|
|
"xdgdata-dirs\0"
|
|
|
|
"desktop-directories\0"
|
|
|
|
"xdgdata-mime\0"
|
2021-02-28 15:01:11 +02:00
|
|
|
"mime\0"
|
2014-11-13 01:04:59 +02:00
|
|
|
"xdgconf-menu\0"
|
|
|
|
"menus\0"
|
|
|
|
"xdgconf-autostart\0"
|
|
|
|
"autostart\0"
|
|
|
|
"\0";
|
|
|
|
|
|
|
|
static const int types_indices[] = {
|
2015-05-20 23:32:01 +00:00
|
|
|
0, 5, 16, 21, 36, 41, 53, 60,
|
2015-09-06 14:42:29 +03:00
|
|
|
73, 80, 94, 100, 113, 120, 133, 142,
|
2021-02-28 15:01:11 +02:00
|
|
|
162, 175, 199, 209, 226, 236, 252, 256,
|
2022-03-08 00:41:39 +02:00
|
|
|
260, 267, 277, 287, 305, 310, 328, 341,
|
|
|
|
354, 367, 373, 388, 396, 409, 429, 442,
|
|
|
|
447, 460, 466, 484, -1
|
2014-11-13 01:04:59 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
KStandardDirs::KStandardDirs()
|
|
|
|
: d(new KStandardDirsPrivate(this))
|
|
|
|
{
|
|
|
|
addKDEDefaults();
|
|
|
|
}
|
|
|
|
|
|
|
|
KStandardDirs::~KStandardDirs()
|
|
|
|
{
|
|
|
|
delete d;
|
|
|
|
}
|
|
|
|
|
|
|
|
QStringList KStandardDirs::allTypes() const
|
|
|
|
{
|
|
|
|
QStringList list;
|
|
|
|
for (int i = 0; types_indices[i] != -1; i += 2)
|
|
|
|
list.append(QLatin1String(types_string + types_indices[i]));
|
|
|
|
// Those are added manually by addKDEDefaults
|
|
|
|
list.append(QString::fromLatin1("lib"));
|
|
|
|
//list.append(QString::fromLatin1("home")); // undocumented on purpose, said Waldo in r113855.
|
|
|
|
|
|
|
|
// Those are handled by resourceDirs() itself
|
|
|
|
list.append(QString::fromLatin1("tmp"));
|
|
|
|
list.append(QString::fromLatin1("cache"));
|
|
|
|
// Those are handled by installPath()
|
|
|
|
list.append(QString::fromLatin1("include"));
|
|
|
|
|
|
|
|
// If you add anything here, make sure kde-config.cpp has a description for it.
|
|
|
|
|
|
|
|
return list;
|
|
|
|
}
|
|
|
|
|
|
|
|
void KStandardDirs::addPrefix( const QString& _dir )
|
|
|
|
{
|
|
|
|
addPrefix(_dir, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
void KStandardDirs::addPrefix( const QString& _dir, bool priority )
|
|
|
|
{
|
|
|
|
if (_dir.isEmpty())
|
|
|
|
return;
|
|
|
|
|
|
|
|
QString dir = _dir;
|
|
|
|
if (dir.at(dir.length() - 1) != QLatin1Char('/'))
|
|
|
|
dir += QLatin1Char('/');
|
|
|
|
|
2016-03-04 20:51:02 +02:00
|
|
|
if (!d->m_prefixes.contains(dir, case_sensitivity)) {
|
2014-11-13 01:04:59 +02:00
|
|
|
priorityAdd(d->m_prefixes, dir, priority);
|
|
|
|
d->m_dircache.clear();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void KStandardDirs::addXdgConfigPrefix( const QString& _dir )
|
|
|
|
{
|
|
|
|
addXdgConfigPrefix(_dir, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
void KStandardDirs::addXdgConfigPrefix( const QString& _dir, bool priority )
|
|
|
|
{
|
|
|
|
if (_dir.isEmpty())
|
|
|
|
return;
|
|
|
|
|
|
|
|
QString dir = _dir;
|
|
|
|
if (dir.at(dir.length() - 1) != QLatin1Char('/'))
|
|
|
|
dir += QLatin1Char('/');
|
|
|
|
|
2016-03-04 20:51:02 +02:00
|
|
|
if (!d->xdgconf_prefixes.contains(dir, case_sensitivity)) {
|
2014-11-13 01:04:59 +02:00
|
|
|
priorityAdd(d->xdgconf_prefixes, dir, priority);
|
|
|
|
d->m_dircache.clear();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void KStandardDirs::addXdgDataPrefix( const QString& _dir )
|
|
|
|
{
|
|
|
|
addXdgDataPrefix(_dir, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
void KStandardDirs::addXdgDataPrefix( const QString& _dir, bool priority )
|
|
|
|
{
|
|
|
|
if (_dir.isEmpty())
|
|
|
|
return;
|
|
|
|
|
|
|
|
QString dir = _dir;
|
|
|
|
if (dir.at(dir.length() - 1) != QLatin1Char('/'))
|
|
|
|
dir += QLatin1Char('/');
|
|
|
|
|
2016-03-04 20:51:02 +02:00
|
|
|
if (!d->xdgdata_prefixes.contains(dir, case_sensitivity)) {
|
2014-11-13 01:04:59 +02:00
|
|
|
priorityAdd(d->xdgdata_prefixes, dir, priority);
|
|
|
|
d->m_dircache.clear();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
QString KStandardDirs::kfsstnd_prefixes()
|
|
|
|
{
|
2022-09-23 12:59:38 +03:00
|
|
|
return d->m_prefixes.join(s_pathseparator);
|
2014-11-13 01:04:59 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
QString KStandardDirs::kfsstnd_xdg_conf_prefixes()
|
|
|
|
{
|
2022-09-23 12:59:38 +03:00
|
|
|
return d->xdgconf_prefixes.join(s_pathseparator);
|
2014-11-13 01:04:59 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
QString KStandardDirs::kfsstnd_xdg_data_prefixes()
|
|
|
|
{
|
2022-09-23 12:59:38 +03:00
|
|
|
return d->xdgdata_prefixes.join(s_pathseparator);
|
2014-11-13 01:04:59 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool KStandardDirs::addResourceType( const char *type,
|
|
|
|
const char *basetype,
|
|
|
|
const QString& relativename,
|
|
|
|
bool priority )
|
|
|
|
{
|
|
|
|
if (relativename.isEmpty())
|
|
|
|
return false;
|
|
|
|
|
|
|
|
QString copy = relativename;
|
|
|
|
if (basetype)
|
|
|
|
copy = QLatin1Char('%') + QString::fromLatin1(basetype) + QLatin1Char('/') + relativename;
|
|
|
|
|
|
|
|
if (!copy.endsWith(QLatin1Char('/')))
|
|
|
|
copy += QLatin1Char('/');
|
|
|
|
|
|
|
|
QByteArray typeBa = type;
|
|
|
|
QStringList& rels = d->m_relatives[typeBa]; // find or insert
|
|
|
|
|
2016-03-04 20:51:02 +02:00
|
|
|
if (!rels.contains(copy, case_sensitivity)) {
|
2014-11-13 01:04:59 +02:00
|
|
|
if (priority)
|
|
|
|
rels.prepend(copy);
|
|
|
|
else
|
|
|
|
rels.append(copy);
|
|
|
|
// clean the caches
|
|
|
|
d->m_dircache.remove(typeBa);
|
|
|
|
d->m_savelocations.remove(typeBa);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool KStandardDirs::addResourceDir( const char *type,
|
|
|
|
const QString& absdir,
|
|
|
|
bool priority)
|
|
|
|
{
|
|
|
|
if (absdir.isEmpty() || !type)
|
|
|
|
return false;
|
|
|
|
// find or insert entry in the map
|
|
|
|
QString copy = absdir;
|
|
|
|
if (copy.at(copy.length() - 1) != QLatin1Char('/'))
|
|
|
|
copy += QLatin1Char('/');
|
|
|
|
|
|
|
|
QByteArray typeBa = type;
|
|
|
|
QStringList &paths = d->m_absolutes[typeBa];
|
2016-03-04 20:51:02 +02:00
|
|
|
if (!paths.contains(copy, case_sensitivity)) {
|
2014-11-13 01:04:59 +02:00
|
|
|
if (priority)
|
|
|
|
paths.prepend(copy);
|
|
|
|
else
|
|
|
|
paths.append(copy);
|
|
|
|
// clean the caches
|
|
|
|
d->m_dircache.remove(typeBa);
|
|
|
|
d->m_savelocations.remove(typeBa);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
QString KStandardDirs::findResource( const char *type,
|
2021-01-20 14:32:42 +02:00
|
|
|
const QString& filename ) const
|
2014-11-13 01:04:59 +02:00
|
|
|
{
|
2021-01-20 14:32:42 +02:00
|
|
|
if (!QDir::isRelativePath(filename))
|
|
|
|
return !KGlobal::hasLocale() ? filename // absolute dirs are absolute dirs, right? :-/
|
|
|
|
: KGlobal::locale()->localizedFilePath(filename); // -- almost.
|
2014-11-13 01:04:59 +02:00
|
|
|
|
|
|
|
#if 0
|
|
|
|
kDebug(180) << "Find resource: " << type;
|
2021-01-20 14:32:42 +02:00
|
|
|
foreach (const QString &it, d->m_prefixes) {
|
|
|
|
kDebug(180) << "Prefix: " << it;
|
2014-11-13 01:04:59 +02:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
const QString dir = findResourceDir(type, filename);
|
|
|
|
if (dir.isEmpty())
|
2021-01-20 14:32:42 +02:00
|
|
|
return dir;
|
|
|
|
return !KGlobal::hasLocale() ? dir + filename
|
|
|
|
: KGlobal::locale()->localizedFilePath(dir + filename);
|
2022-09-23 12:59:38 +03:00
|
|
|
}
|
2014-11-13 01:04:59 +02:00
|
|
|
|
2022-09-23 12:59:38 +03:00
|
|
|
quint32 KStandardDirs::calcResourceHash( const char *type,
|
|
|
|
const QString& filename,
|
|
|
|
SearchOptions options ) const
|
|
|
|
{
|
|
|
|
quint32 hash = 0;
|
2014-11-13 01:04:59 +02:00
|
|
|
|
2022-09-23 12:59:38 +03:00
|
|
|
if (!QDir::isRelativePath(filename))
|
|
|
|
{
|
|
|
|
// absolute dirs are absolute dirs, right? :-/
|
|
|
|
return updateHash(filename, hash);
|
|
|
|
}
|
|
|
|
|
|
|
|
foreach ( const QString & it, d->resourceDirs(type, filename) )
|
|
|
|
{
|
|
|
|
hash = updateHash(it + filename, hash);
|
|
|
|
if ( !( options & Recursive ) && hash ) {
|
|
|
|
return hash;
|
2014-11-13 01:04:59 +02:00
|
|
|
}
|
2022-09-23 12:59:38 +03:00
|
|
|
}
|
|
|
|
return hash;
|
|
|
|
}
|
2014-11-13 01:04:59 +02:00
|
|
|
|
|
|
|
|
2022-09-23 12:59:38 +03:00
|
|
|
QStringList KStandardDirs::findDirs( const char *type,
|
|
|
|
const QString& reldir ) const
|
|
|
|
{
|
|
|
|
QDir testdir;
|
|
|
|
QStringList list;
|
|
|
|
if (!QDir::isRelativePath(reldir))
|
|
|
|
{
|
|
|
|
testdir.setPath(reldir);
|
|
|
|
if (testdir.exists())
|
2014-11-13 01:04:59 +02:00
|
|
|
{
|
2022-09-23 12:59:38 +03:00
|
|
|
if (reldir.endsWith(QLatin1Char('/')))
|
|
|
|
list.append(reldir);
|
|
|
|
else
|
|
|
|
list.append(reldir+QLatin1Char('/'));
|
|
|
|
}
|
|
|
|
return list;
|
|
|
|
}
|
2014-11-13 01:04:59 +02:00
|
|
|
|
2022-09-23 12:59:38 +03:00
|
|
|
const QStringList candidates = d->resourceDirs(type, reldir);
|
2014-11-13 01:04:59 +02:00
|
|
|
|
2022-09-23 12:59:38 +03:00
|
|
|
for (QStringList::ConstIterator it = candidates.begin();
|
|
|
|
it != candidates.end(); ++it) {
|
|
|
|
testdir.setPath(*it + reldir);
|
|
|
|
if (testdir.exists())
|
|
|
|
list.append(testdir.absolutePath() + QLatin1Char('/'));
|
|
|
|
}
|
2014-11-13 01:04:59 +02:00
|
|
|
|
2022-09-23 12:59:38 +03:00
|
|
|
return list;
|
|
|
|
}
|
2014-11-13 01:04:59 +02:00
|
|
|
|
2022-09-23 12:59:38 +03:00
|
|
|
QString KStandardDirs::findResourceDir( const char *type,
|
|
|
|
const QString& filename) const
|
|
|
|
{
|
|
|
|
#ifndef NDEBUG
|
|
|
|
if (filename.isEmpty()) {
|
|
|
|
kWarning() << "filename for type " << type << " in KStandardDirs::findResourceDir is not supposed to be empty!!";
|
|
|
|
return QString();
|
|
|
|
}
|
2014-11-13 01:04:59 +02:00
|
|
|
#endif
|
2022-09-23 12:59:38 +03:00
|
|
|
|
|
|
|
const QStringList candidates = d->resourceDirs(type, filename);
|
|
|
|
|
|
|
|
for (QStringList::ConstIterator it = candidates.begin();
|
|
|
|
it != candidates.end(); ++it) {
|
|
|
|
if (exists(*it + filename)) {
|
|
|
|
return *it;
|
2014-11-13 01:04:59 +02:00
|
|
|
}
|
2022-09-23 12:59:38 +03:00
|
|
|
}
|
2014-11-13 01:04:59 +02:00
|
|
|
|
2022-09-23 12:59:38 +03:00
|
|
|
#ifndef NDEBUG
|
|
|
|
if(false && strcmp(type, "locale"))
|
|
|
|
kDebug(180) << "KStdDirs::findResDir(): can't find \"" << filename << "\" in type \"" << type << "\".";
|
|
|
|
#endif
|
|
|
|
|
|
|
|
return QString();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool KStandardDirs::exists(const QString &fullPath) const
|
|
|
|
{
|
|
|
|
return d->exists(fullPath);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool KStandardDirs::KStandardDirsPrivate::exists(const QString &fullPath)
|
|
|
|
{
|
|
|
|
QFileInfo fileinfo(fullPath);
|
|
|
|
if (!fileinfo.isReadable()) {
|
|
|
|
return false;
|
|
|
|
} else if (!fullPath.endsWith(QLatin1Char('/'))) {
|
|
|
|
return !fileinfo.isDir() && fileinfo.exists();
|
2014-11-13 01:04:59 +02:00
|
|
|
} else {
|
2022-09-23 12:59:38 +03:00
|
|
|
return fileinfo.isDir() && fileinfo.exists();
|
2014-11-13 01:04:59 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
QStringList
|
|
|
|
KStandardDirs::findAllResources( const char *type,
|
|
|
|
const QString& filter,
|
|
|
|
SearchOptions options,
|
|
|
|
QStringList &relList) const
|
|
|
|
{
|
|
|
|
QString filterPath;
|
|
|
|
QString filterFile;
|
|
|
|
|
|
|
|
if ( !filter.isEmpty() )
|
|
|
|
{
|
|
|
|
int slash = filter.lastIndexOf(QLatin1Char('/'));
|
|
|
|
if (slash < 0) {
|
|
|
|
filterFile = filter;
|
|
|
|
} else {
|
|
|
|
filterPath = filter.left(slash + 1);
|
|
|
|
filterFile = filter.mid(slash + 1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
QStringList candidates;
|
|
|
|
if ( !QDir::isRelativePath(filter) ) // absolute path
|
|
|
|
{
|
|
|
|
candidates << QString::fromLatin1("/");
|
|
|
|
filterPath = filterPath.mid(1);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
candidates = d->resourceDirs(type, filter);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (filterFile.isEmpty()) {
|
|
|
|
filterFile = QString(QLatin1Char('*'));
|
|
|
|
}
|
|
|
|
|
|
|
|
QRegExp regExp(filterFile, Qt::CaseSensitive, QRegExp::Wildcard);
|
|
|
|
|
|
|
|
QStringList list;
|
|
|
|
foreach ( const QString& candidate, candidates )
|
|
|
|
{
|
|
|
|
lookupPrefix(candidate, filterPath, QString(), regExp, list,
|
|
|
|
relList, options & Recursive, options & NoDuplicates);
|
|
|
|
}
|
|
|
|
|
|
|
|
return list;
|
|
|
|
}
|
|
|
|
|
|
|
|
QStringList
|
|
|
|
KStandardDirs::findAllResources( const char *type,
|
|
|
|
const QString& filter,
|
|
|
|
SearchOptions options ) const
|
|
|
|
{
|
|
|
|
QStringList relList;
|
|
|
|
return findAllResources(type, filter, options, relList);
|
|
|
|
}
|
|
|
|
|
|
|
|
// ####### KDE4: should this be removed, in favor of QDir::canonicalPath()?
|
|
|
|
// aseigo: QDir::canonicalPath returns QString() if the dir doesn't exist
|
|
|
|
// and this method is often used with the expectation for it to work
|
|
|
|
// even if the directory doesn't exist. so ... no, we can't drop this
|
|
|
|
// yet
|
|
|
|
QString
|
2015-10-17 18:53:50 +03:00
|
|
|
KStandardDirs::KStandardDirsPrivate::realPath(const QString &dirname)
|
2014-11-13 01:04:59 +02:00
|
|
|
{
|
|
|
|
if (dirname.isEmpty() || (dirname.size() == 1 && dirname.at(0) == QLatin1Char('/')))
|
|
|
|
return dirname;
|
|
|
|
|
|
|
|
if (dirname.at(0) != QLatin1Char('/')) {
|
|
|
|
qWarning("realPath called with a relative path '%s', please fix", qPrintable(dirname));
|
|
|
|
return dirname;
|
|
|
|
}
|
|
|
|
|
2021-02-01 04:13:11 +02:00
|
|
|
char realpath_buffer[PATH_MAX + 1];
|
|
|
|
memset(realpath_buffer, 0, PATH_MAX + 1);
|
2014-11-13 01:04:59 +02:00
|
|
|
|
|
|
|
/* If the path contains symlinks, get the real name */
|
|
|
|
if (realpath( QFile::encodeName(dirname).constData(), realpath_buffer) != 0) {
|
|
|
|
// success, use result from realpath
|
|
|
|
int len = strlen(realpath_buffer);
|
|
|
|
realpath_buffer[len] = '/';
|
|
|
|
realpath_buffer[len+1] = 0;
|
|
|
|
return QFile::decodeName(realpath_buffer);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Does not exist yet; resolve symlinks in parent dirs then.
|
|
|
|
// This ensures that once the directory exists, it will still be resolved
|
|
|
|
// the same way, so that the general rule that KStandardDirs always returns
|
|
|
|
// canonical paths stays true, and app code can compare paths more easily.
|
|
|
|
QString dir = dirname;
|
|
|
|
if (!dir.endsWith(QLatin1Char('/')))
|
|
|
|
dir += QLatin1Char('/');
|
|
|
|
QString relative;
|
2015-10-17 18:53:50 +03:00
|
|
|
while (!exists(dir)) {
|
2014-11-13 01:04:59 +02:00
|
|
|
//qDebug() << "does not exist:" << dir;
|
|
|
|
const int pos = dir.lastIndexOf(QLatin1Char('/'), -2);
|
|
|
|
Q_ASSERT(pos >= 0); // what? even "/" doesn't exist?
|
|
|
|
relative.prepend(dir.mid(pos+1)); // keep "subdir/"
|
|
|
|
dir = dir.left(pos+1);
|
|
|
|
Q_ASSERT(dir.endsWith(QLatin1Char('/')));
|
|
|
|
}
|
|
|
|
Q_ASSERT(!relative.isEmpty()); // infinite recursion ahead
|
|
|
|
if (!relative.isEmpty()) {
|
|
|
|
//qDebug() << "done, resolving" << dir << "and adding" << relative;
|
|
|
|
dir = realPath(dir) + relative;
|
|
|
|
}
|
|
|
|
return dir;
|
|
|
|
}
|
|
|
|
|
2015-10-17 18:53:50 +03:00
|
|
|
QString
|
|
|
|
KStandardDirs::realPath(const QString &dirname) const
|
|
|
|
{
|
|
|
|
return d->realPath(dirname);
|
|
|
|
}
|
|
|
|
|
2014-11-13 01:04:59 +02:00
|
|
|
// ####### KDE4: should this be removed, in favor of QDir::canonicalPath()?
|
|
|
|
// aseigo: QDir::canonicalPath returns QString() if the dir doesn't exist
|
|
|
|
// and this method is often used with the expectation for it to work
|
|
|
|
// even if the directory doesn't exist. so ... no, we can't drop this
|
|
|
|
// yet
|
|
|
|
QString
|
|
|
|
KStandardDirs::realFilePath(const QString &filename)
|
|
|
|
{
|
2021-02-01 04:13:11 +02:00
|
|
|
char realpath_buffer[PATH_MAX + 1];
|
|
|
|
memset(realpath_buffer, 0, PATH_MAX + 1);
|
2014-11-13 01:04:59 +02:00
|
|
|
|
|
|
|
/* If the path contains symlinks, get the real name */
|
|
|
|
if (realpath( QFile::encodeName(filename).constData(), realpath_buffer) != 0) {
|
|
|
|
// success, use result from realpath
|
|
|
|
return QFile::decodeName(realpath_buffer);
|
|
|
|
}
|
|
|
|
|
|
|
|
return filename;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void KStandardDirs::KStandardDirsPrivate::createSpecialResource(const char *type)
|
|
|
|
{
|
2022-05-25 10:42:27 +03:00
|
|
|
QString resourceDir;
|
|
|
|
if (qstrcmp(type, "cache") == 0) {
|
|
|
|
resourceDir = QStandardPaths::writableLocation(QStandardPaths::CacheLocation);
|
|
|
|
resourceDir.append(QDir::separator());
|
|
|
|
resourceDir.append(QLatin1String("katana"));
|
|
|
|
} else if (qstrcmp(type, "tmp") == 0) {
|
|
|
|
resourceDir = QStandardPaths::writableLocation(QStandardPaths::RuntimeLocation);
|
|
|
|
// if the base directory is /tmp not /run/user/<uid> make sure it is user specific
|
|
|
|
resourceDir.append(QDir::separator());
|
|
|
|
resourceDir.append(QLatin1String("katana-"));
|
|
|
|
resourceDir.append(QString::number(::getuid()));
|
|
|
|
} else {
|
|
|
|
Q_ASSERT(false);
|
|
|
|
}
|
2022-05-26 14:16:35 +03:00
|
|
|
// NOTE: QStandardPaths::writableLocation() should create the base directory
|
|
|
|
const QString cleanPath = QDir::cleanPath(resourceDir) + QLatin1Char('/');
|
|
|
|
KStandardDirs::makeDir(cleanPath, 0700);
|
|
|
|
q->addResourceDir(type, cleanPath, false);
|
2014-11-13 01:04:59 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
QStringList KStandardDirs::resourceDirs(const char *type) const
|
|
|
|
{
|
|
|
|
return d->resourceDirs(type, QString());
|
|
|
|
}
|
|
|
|
|
|
|
|
QStringList KStandardDirs::KStandardDirsPrivate::resourceDirs(const char* type, const QString& subdirForRestrictions)
|
|
|
|
{
|
2021-07-22 01:24:13 +03:00
|
|
|
std::lock_guard<std::recursive_mutex> lock(m_cacheMutex);
|
2014-11-13 01:04:59 +02:00
|
|
|
|
|
|
|
QMap<QByteArray, QStringList>::const_iterator dirCacheIt = m_dircache.constFind(type);
|
|
|
|
|
|
|
|
QStringList candidates;
|
|
|
|
|
2022-06-05 14:46:22 +03:00
|
|
|
if (dirCacheIt != m_dircache.constEnd()) {
|
2014-11-13 01:04:59 +02:00
|
|
|
//qDebug() << this << "resourceDirs(" << type << "), in cache already";
|
|
|
|
candidates = *dirCacheIt;
|
|
|
|
}
|
|
|
|
else // filling cache
|
|
|
|
{
|
|
|
|
//qDebug() << this << "resourceDirs(" << type << "), not in cache";
|
2022-05-25 10:42:27 +03:00
|
|
|
if (strcmp(type, "tmp") == 0 || strcmp(type, "cache") == 0)
|
2014-11-13 01:04:59 +02:00
|
|
|
createSpecialResource(type);
|
|
|
|
|
|
|
|
QDir testdir;
|
|
|
|
|
|
|
|
const QStringList dirs = m_relatives.value(type);
|
|
|
|
const QString typeInstallPath = installPath(type); // could be empty
|
|
|
|
const QString installdir = typeInstallPath.isEmpty() ? QString() : realPath(typeInstallPath);
|
|
|
|
const QString installprefix = installPath("kdedir");
|
|
|
|
if (!dirs.isEmpty())
|
|
|
|
{
|
|
|
|
bool local = true;
|
|
|
|
|
|
|
|
for (QStringList::ConstIterator it = dirs.constBegin();
|
|
|
|
it != dirs.constEnd(); ++it)
|
|
|
|
{
|
|
|
|
if ((*it).startsWith(QLatin1Char('%'))) {
|
|
|
|
// grab the "data" from "%data/apps"
|
|
|
|
const int pos = (*it).indexOf(QLatin1Char('/'));
|
2022-05-26 14:08:02 +03:00
|
|
|
QByteArray rel = (*it).mid(1, pos - 1).toUtf8();
|
2014-11-13 01:04:59 +02:00
|
|
|
QString rest = (*it).mid(pos + 1);
|
2022-05-26 14:08:02 +03:00
|
|
|
const QStringList basedirs = resourceDirs(rel.constData(), subdirForRestrictions);
|
2014-11-13 01:04:59 +02:00
|
|
|
for (QStringList::ConstIterator it2 = basedirs.begin();
|
|
|
|
it2 != basedirs.end(); ++it2)
|
|
|
|
{
|
|
|
|
const QString path = realPath( *it2 + rest );
|
|
|
|
testdir.setPath(path);
|
2016-03-04 20:51:02 +02:00
|
|
|
if ((local || testdir.exists()) && !candidates.contains(path, case_sensitivity))
|
2014-11-13 01:04:59 +02:00
|
|
|
candidates.append(path);
|
|
|
|
local = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
const QStringList *prefixList = 0;
|
|
|
|
if (strncmp(type, "xdgdata-", 8) == 0)
|
|
|
|
prefixList = &(xdgdata_prefixes);
|
|
|
|
else if (strncmp(type, "xdgconf-", 8) == 0)
|
|
|
|
prefixList = &(xdgconf_prefixes);
|
|
|
|
else
|
|
|
|
prefixList = &m_prefixes;
|
|
|
|
|
|
|
|
for (QStringList::ConstIterator pit = prefixList->begin();
|
|
|
|
pit != prefixList->end();
|
|
|
|
++pit)
|
|
|
|
{
|
2016-03-04 20:51:02 +02:00
|
|
|
if((*pit).compare(installprefix, case_sensitivity) != 0 || installdir.isEmpty())
|
2014-11-13 01:04:59 +02:00
|
|
|
{
|
|
|
|
for (QStringList::ConstIterator it = dirs.constBegin();
|
|
|
|
it != dirs.constEnd(); ++it)
|
|
|
|
{
|
|
|
|
if ((*it).startsWith(QLatin1Char('%')))
|
|
|
|
continue;
|
|
|
|
const QString path = realPath( *pit + *it );
|
|
|
|
testdir.setPath(path);
|
2016-03-04 20:51:02 +02:00
|
|
|
if ((local || testdir.exists()) && !candidates.contains(path, case_sensitivity))
|
2014-11-13 01:04:59 +02:00
|
|
|
candidates.append(path);
|
|
|
|
}
|
|
|
|
local = false;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// we have a custom install path, so use this instead of <installprefix>/<relative dir>
|
|
|
|
testdir.setPath(installdir);
|
2016-03-04 20:51:02 +02:00
|
|
|
if(testdir.exists() && ! candidates.contains(installdir, case_sensitivity))
|
2014-11-13 01:04:59 +02:00
|
|
|
candidates.append(installdir);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// make sure we find the path where it's installed
|
|
|
|
if (!installdir.isEmpty()) {
|
|
|
|
bool ok = true;
|
|
|
|
foreach (const QString &s, candidates) {
|
2016-03-04 20:51:02 +02:00
|
|
|
if (installdir.startsWith(s, case_sensitivity)) {
|
2014-11-13 01:04:59 +02:00
|
|
|
ok = false;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (ok)
|
|
|
|
candidates.append(installdir);
|
|
|
|
}
|
|
|
|
|
|
|
|
const QStringList absDirs = m_absolutes.value(type);
|
|
|
|
for (QStringList::ConstIterator it = absDirs.constBegin();
|
|
|
|
it != absDirs.constEnd(); ++it)
|
|
|
|
{
|
|
|
|
testdir.setPath(*it);
|
|
|
|
if (testdir.exists()) {
|
|
|
|
const QString filename = realPath( *it );
|
2016-03-04 20:51:02 +02:00
|
|
|
if (!candidates.contains(filename, case_sensitivity)) {
|
2014-11-13 01:04:59 +02:00
|
|
|
candidates.append(filename);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Insert result into the cache for next time.
|
2022-06-05 14:46:22 +03:00
|
|
|
//kDebug() << this << "Inserting" << type << candidates << "into dircache";
|
|
|
|
m_dircache.insert(type, candidates);
|
2014-11-13 01:04:59 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
kDebug(180) << "found dirs for resource" << type << ":" << candidates;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
return candidates;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
QStringList KStandardDirs::systemPaths( const QString& pstr )
|
|
|
|
{
|
|
|
|
QStringList tokens;
|
|
|
|
|
2022-09-23 12:59:38 +03:00
|
|
|
if( pstr.isEmpty() ) {
|
|
|
|
tokens = splitPath( QString::fromLocal8Bit( qgetenv( "PATH" ) ) );
|
|
|
|
} else {
|
|
|
|
tokens = splitPath( pstr );
|
2014-11-13 01:04:59 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
QStringList exePaths;
|
2022-09-23 12:59:38 +03:00
|
|
|
// split path using : as delimiters
|
2014-11-13 01:04:59 +02:00
|
|
|
for( int i = 0; i < tokens.count(); i++ )
|
|
|
|
{
|
2022-09-23 12:59:38 +03:00
|
|
|
exePaths << KShell::tildeExpand( tokens.at(i) );
|
2014-11-13 01:04:59 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return exePaths;
|
|
|
|
}
|
|
|
|
|
|
|
|
QString KStandardDirs::findExe( const QString& appname,
|
|
|
|
const QString& pstr,
|
|
|
|
SearchOptions options )
|
|
|
|
{
|
|
|
|
//kDebug(180) << "findExe(" << appname << ", pstr, " << ignoreExecBit << ") called";
|
|
|
|
|
|
|
|
QFileInfo info;
|
|
|
|
|
|
|
|
// absolute or relative path?
|
|
|
|
if (appname.contains(QDir::separator()))
|
|
|
|
{
|
|
|
|
//kDebug(180) << "findExe(): absolute path given";
|
2021-06-08 05:38:21 +03:00
|
|
|
return checkExecutable(appname, options & IgnoreExecBit);
|
2014-11-13 01:04:59 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
//kDebug(180) << "findExe(): relative path given";
|
|
|
|
|
|
|
|
QString p = installPath("libexec") + appname;
|
|
|
|
QString result = checkExecutable(p, options & IgnoreExecBit);
|
|
|
|
if (!result.isEmpty()) {
|
|
|
|
//kDebug(180) << "findExe(): returning " << result;
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
//kDebug(180) << "findExe(): checking system paths";
|
2021-06-08 05:38:21 +03:00
|
|
|
foreach (const QString &it, systemPaths( pstr ))
|
2014-11-13 01:04:59 +02:00
|
|
|
{
|
2021-06-08 05:38:21 +03:00
|
|
|
p = it + QLatin1Char('/') + appname;
|
2014-11-13 01:04:59 +02:00
|
|
|
|
|
|
|
// Check for executable in this tokenized path
|
|
|
|
result = checkExecutable(p, options & IgnoreExecBit);
|
|
|
|
if (!result.isEmpty()) {
|
|
|
|
//kDebug(180) << "findExe(): returning " << result;
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Not found in PATH, look into the KDE-specific bin dir ("exe" resource)
|
2021-06-08 05:38:21 +03:00
|
|
|
p = installPath("exe") + appname;
|
2014-11-13 01:04:59 +02:00
|
|
|
result = checkExecutable(p, options & IgnoreExecBit);
|
|
|
|
if (!result.isEmpty()) {
|
|
|
|
//kDebug(180) << "findExe(): returning " << result;
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
// If we reach here, the executable wasn't found.
|
|
|
|
// So return empty string.
|
|
|
|
|
|
|
|
//kDebug(180) << "findExe(): failed, nothing matched";
|
|
|
|
return QString();
|
|
|
|
}
|
|
|
|
|
2021-02-16 22:09:23 +02:00
|
|
|
QString KStandardDirs::findRootExe( const QString& appname,
|
|
|
|
const QString& pstr,
|
|
|
|
SearchOptions options )
|
|
|
|
{
|
|
|
|
QStringList exePaths = systemPaths( pstr );
|
|
|
|
static const QStringList rootPaths = QStringList()
|
|
|
|
<< QLatin1String("/sbin")
|
|
|
|
<< QLatin1String("/usr/sbin")
|
|
|
|
<< QLatin1String("/usr/local/sbin")
|
2021-02-23 05:40:24 +02:00
|
|
|
<< QLatin1String(KDEDIR "/sbin");
|
2021-02-16 22:09:23 +02:00
|
|
|
|
|
|
|
foreach (const QString &rootPath, rootPaths) {
|
|
|
|
if (exePaths.contains(rootPath) || !QDir(rootPath).exists()) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
exePaths << rootPath;
|
|
|
|
}
|
|
|
|
|
2022-09-23 12:59:38 +03:00
|
|
|
return findExe(appname, exePaths.join(s_pathseparator), options);
|
2021-02-16 22:09:23 +02:00
|
|
|
}
|
|
|
|
|
2014-11-13 01:04:59 +02:00
|
|
|
int KStandardDirs::findAllExe( QStringList& list, const QString& appname,
|
|
|
|
const QString& pstr, SearchOptions options )
|
|
|
|
{
|
|
|
|
QFileInfo info;
|
|
|
|
QString p;
|
|
|
|
list.clear();
|
|
|
|
|
|
|
|
const QStringList exePaths = systemPaths( pstr );
|
|
|
|
for (QStringList::ConstIterator it = exePaths.begin(); it != exePaths.end(); ++it)
|
|
|
|
{
|
|
|
|
p = (*it) + QLatin1Char('/');
|
|
|
|
p += appname;
|
|
|
|
|
|
|
|
|
|
|
|
info.setFile( p );
|
|
|
|
|
|
|
|
if( info.exists() && ( ( options & IgnoreExecBit ) || info.isExecutable())
|
|
|
|
&& info.isFile() ) {
|
|
|
|
list.append( p );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return list.count();
|
|
|
|
}
|
|
|
|
|
|
|
|
QString KStandardDirs::saveLocation(const char *type,
|
|
|
|
const QString& suffix,
|
|
|
|
bool create) const
|
|
|
|
{
|
2021-07-22 01:24:13 +03:00
|
|
|
std::lock_guard<std::recursive_mutex> lock(d->m_cacheMutex);
|
2014-11-13 01:04:59 +02:00
|
|
|
QString path = d->m_savelocations.value(type);
|
|
|
|
if (path.isEmpty())
|
|
|
|
{
|
|
|
|
QStringList dirs = d->m_relatives.value(type);
|
2022-05-25 10:42:27 +03:00
|
|
|
if (dirs.isEmpty() && (strcmp(type, "tmp") == 0 || strcmp(type, "cache") == 0))
|
2014-11-13 01:04:59 +02:00
|
|
|
{
|
2022-05-25 10:42:27 +03:00
|
|
|
(void) resourceDirs(type); // Generate tmp|cache resource.
|
2014-11-13 01:04:59 +02:00
|
|
|
dirs = d->m_relatives.value(type); // Search again.
|
|
|
|
}
|
|
|
|
if (!dirs.isEmpty())
|
|
|
|
{
|
|
|
|
path = dirs.first();
|
|
|
|
|
|
|
|
if (path.startsWith(QLatin1Char('%'))) {
|
|
|
|
// grab the "data" from "%data/apps"
|
|
|
|
const int pos = path.indexOf(QLatin1Char('/'));
|
2022-05-26 14:08:02 +03:00
|
|
|
QByteArray rel = path.mid(1, pos - 1).toUtf8();
|
2014-11-13 01:04:59 +02:00
|
|
|
QString rest = path.mid(pos + 1);
|
2022-05-26 14:08:02 +03:00
|
|
|
QString basepath = saveLocation(rel.constData());
|
2014-11-13 01:04:59 +02:00
|
|
|
path = basepath + rest;
|
|
|
|
} else
|
|
|
|
|
|
|
|
// Check for existence of typed directory + suffix
|
|
|
|
if (strncmp(type, "xdgdata-", 8) == 0) {
|
|
|
|
path = realPath( localxdgdatadir() + path ) ;
|
|
|
|
} else if (strncmp(type, "xdgconf-", 8) == 0) {
|
|
|
|
path = realPath( localxdgconfdir() + path );
|
|
|
|
} else {
|
|
|
|
path = realPath( localkdedir() + path );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
dirs = d->m_absolutes.value(type);
|
|
|
|
if (dirs.isEmpty()) {
|
|
|
|
qFatal("KStandardDirs: The resource type %s is not registered", type);
|
|
|
|
} else {
|
|
|
|
path = realPath(dirs.first());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
d->m_savelocations.insert(type, path.endsWith(QLatin1Char('/')) ? path : path + QLatin1Char('/'));
|
|
|
|
}
|
|
|
|
QString fullPath = path + suffix;
|
|
|
|
|
|
|
|
KDE_struct_stat st;
|
|
|
|
if (KDE::stat(fullPath, &st) != 0 || !(S_ISDIR(st.st_mode))) {
|
|
|
|
if(!create) {
|
|
|
|
#ifndef NDEBUG
|
|
|
|
// Too much noise from kbuildsycoca4 -- it's fine if this happens from KConfig
|
|
|
|
// when parsing global files without a local equivalent.
|
|
|
|
//kDebug(180) << QString("save location %1 doesn't exist").arg(fullPath);
|
|
|
|
#endif
|
|
|
|
return fullPath;
|
|
|
|
}
|
2022-05-26 14:16:35 +03:00
|
|
|
if(!KStandardDirs::makeDir(fullPath, 0700)) {
|
2014-11-13 01:04:59 +02:00
|
|
|
return fullPath;
|
|
|
|
}
|
|
|
|
d->m_dircache.remove(type);
|
|
|
|
}
|
|
|
|
if (!fullPath.endsWith(QLatin1Char('/')))
|
|
|
|
fullPath += QLatin1Char('/');
|
|
|
|
return fullPath;
|
|
|
|
}
|
|
|
|
|
2022-09-20 13:41:05 +03:00
|
|
|
QString KStandardDirs::relativeLocation(const char *type, const QString &absPath) const
|
2014-11-13 01:04:59 +02:00
|
|
|
{
|
|
|
|
QString fullPath = absPath;
|
|
|
|
int i = absPath.lastIndexOf(QLatin1Char('/'));
|
|
|
|
if (i != -1) {
|
|
|
|
fullPath = realFilePath(absPath); // Normalize
|
|
|
|
}
|
|
|
|
|
2022-09-20 13:41:05 +03:00
|
|
|
foreach (const QString &it, resourceDirs(type)) {
|
|
|
|
if (fullPath.startsWith(it, case_sensitivity)) {
|
|
|
|
return fullPath.mid(it.length());
|
2014-11-13 01:04:59 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return absPath;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool KStandardDirs::makeDir(const QString& dir, int mode)
|
|
|
|
{
|
|
|
|
// we want an absolute path
|
|
|
|
if (QDir::isRelativePath(dir))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
QString target = dir;
|
|
|
|
uint len = target.length();
|
|
|
|
|
|
|
|
// append trailing slash if missing
|
|
|
|
if (dir.at(len - 1) != QLatin1Char('/'))
|
|
|
|
target += QLatin1Char('/');
|
|
|
|
|
|
|
|
QString base;
|
|
|
|
uint i = 1;
|
|
|
|
|
|
|
|
while( i < len )
|
|
|
|
{
|
|
|
|
KDE_struct_stat st;
|
|
|
|
int pos = target.indexOf(QLatin1Char('/'), i);
|
|
|
|
base += target.mid(i - 1, pos - i + 1);
|
|
|
|
QByteArray baseEncoded = QFile::encodeName(base);
|
|
|
|
// bail out if we encountered a problem
|
|
|
|
if (KDE_stat(baseEncoded, &st) != 0)
|
|
|
|
{
|
|
|
|
// Directory does not exist....
|
|
|
|
// Or maybe a dangling symlink ?
|
|
|
|
if (KDE_lstat(baseEncoded, &st) == 0)
|
|
|
|
(void)unlink(baseEncoded); // try removing
|
|
|
|
|
|
|
|
if (KDE_mkdir(baseEncoded, static_cast<mode_t>(mode)) != 0) {
|
|
|
|
baseEncoded.prepend( "trying to create local folder " );
|
|
|
|
perror(baseEncoded.constData());
|
|
|
|
return false; // Couldn't create it :-(
|
|
|
|
}
|
|
|
|
}
|
|
|
|
i = pos + 1;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void KStandardDirs::addKDEDefaults()
|
|
|
|
{
|
|
|
|
QStringList kdedirList;
|
|
|
|
// begin KDEDIRS
|
|
|
|
QString kdedirs = readEnvPath("KDEDIRS");
|
|
|
|
|
|
|
|
if (!kdedirs.isEmpty())
|
|
|
|
{
|
2022-09-23 12:59:38 +03:00
|
|
|
kdedirList = splitPath(kdedirs);
|
2014-11-13 01:04:59 +02:00
|
|
|
}
|
|
|
|
kdedirList.append(installPath("kdedir"));
|
|
|
|
|
|
|
|
QString execPrefix(QFile::decodeName(EXEC_INSTALL_PREFIX));
|
2016-03-04 20:51:02 +02:00
|
|
|
if (!execPrefix.isEmpty() && !kdedirList.contains(execPrefix, case_sensitivity))
|
2014-11-13 01:04:59 +02:00
|
|
|
kdedirList.append(execPrefix);
|
2016-05-03 15:26:28 +00:00
|
|
|
#ifdef Q_OS_LINUX
|
2014-11-13 01:04:59 +02:00
|
|
|
const QString linuxExecPrefix = executablePrefix();
|
|
|
|
if ( !linuxExecPrefix.isEmpty() )
|
|
|
|
kdedirList.append( linuxExecPrefix );
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// We treat root differently to prevent a "su" shell messing up the
|
|
|
|
// file permissions in the user's home directory.
|
|
|
|
QString localKdeDir = readEnvPath(getuid() ? "KDEHOME" : "KDEROOTHOME");
|
|
|
|
if (!localKdeDir.isEmpty()) {
|
|
|
|
if (!localKdeDir.endsWith(QLatin1Char('/')))
|
|
|
|
localKdeDir += QLatin1Char('/');
|
|
|
|
} else {
|
|
|
|
// TODO KDE5: make localKdeDir equal to localXdgDir (which is determined further below and
|
|
|
|
// defaults to ~/.config) + '/' + $KDECONFIG (which would default to e.g. "KDE")
|
|
|
|
// This would mean ~/.config/KDE/ by default, more xdg-compliant.
|
|
|
|
|
|
|
|
localKdeDir = QDir::homePath() + QLatin1Char('/') + QString::fromLatin1(KDE_DEFAULT_HOME) + QLatin1Char('/');
|
|
|
|
}
|
|
|
|
|
2016-05-03 15:26:28 +00:00
|
|
|
if (localKdeDir != QLatin1String("-/")) {
|
2014-11-13 01:04:59 +02:00
|
|
|
localKdeDir = KShell::tildeExpand(localKdeDir);
|
|
|
|
addPrefix(localKdeDir);
|
|
|
|
}
|
|
|
|
|
2022-06-05 15:22:02 +03:00
|
|
|
foreach (const QString &it, kdedirList) {
|
|
|
|
addPrefix(KShell::tildeExpand(it));
|
2014-11-13 01:04:59 +02:00
|
|
|
}
|
|
|
|
// end KDEDIRS
|
|
|
|
|
|
|
|
// begin XDG_CONFIG_XXX
|
|
|
|
QStringList xdgdirList;
|
|
|
|
QString xdgdirs = readEnvPath("XDG_CONFIG_DIRS");
|
|
|
|
if (!xdgdirs.isEmpty())
|
|
|
|
{
|
2022-09-23 12:59:38 +03:00
|
|
|
xdgdirList = splitPath(xdgdirs);
|
2014-11-13 01:04:59 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
xdgdirList.clear();
|
|
|
|
xdgdirList.append(QString::fromLatin1("/etc/xdg"));
|
2020-02-18 21:06:45 +00:00
|
|
|
xdgdirList.append(QFile::decodeName(SYSCONF_INSTALL_DIR "/xdg"));
|
2014-11-13 01:04:59 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
QString localXdgDir = readEnvPath("XDG_CONFIG_HOME");
|
|
|
|
if (!localXdgDir.isEmpty()) {
|
|
|
|
if (!localXdgDir.endsWith(QLatin1Char('/')))
|
|
|
|
localXdgDir += QLatin1Char('/');
|
|
|
|
} else {
|
|
|
|
localXdgDir = QDir::homePath() + QString::fromLatin1("/.config/");
|
|
|
|
}
|
|
|
|
|
|
|
|
localXdgDir = KShell::tildeExpand(localXdgDir);
|
|
|
|
addXdgConfigPrefix(localXdgDir);
|
|
|
|
|
|
|
|
for (QStringList::ConstIterator it = xdgdirList.constBegin();
|
|
|
|
it != xdgdirList.constEnd(); ++it)
|
|
|
|
{
|
|
|
|
QString dir = KShell::tildeExpand(*it);
|
|
|
|
addXdgConfigPrefix(dir);
|
|
|
|
}
|
|
|
|
// end XDG_CONFIG_XXX
|
|
|
|
|
|
|
|
// begin XDG_DATA_XXX
|
|
|
|
QStringList kdedirDataDirs;
|
2022-06-05 15:22:02 +03:00
|
|
|
foreach (const QString &it, kdedirList) {
|
2016-05-03 15:26:28 +00:00
|
|
|
if (!it.endsWith(QLatin1Char('/'))) {
|
|
|
|
kdedirDataDirs.append(it + QLatin1String("/share/"));
|
|
|
|
} else {
|
|
|
|
kdedirDataDirs.append(it + QLatin1String("share/"));
|
|
|
|
}
|
2014-11-13 01:04:59 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
xdgdirs = readEnvPath("XDG_DATA_DIRS");
|
|
|
|
if (!xdgdirs.isEmpty()) {
|
2022-09-23 12:59:38 +03:00
|
|
|
xdgdirList = splitPath(xdgdirs);
|
2014-11-13 01:04:59 +02:00
|
|
|
// Ensure the kdedirDataDirs are in there too,
|
2015-06-14 18:49:20 +03:00
|
|
|
// otherwise resourceDirs() will add kdedir/share/applications/kde4
|
2014-11-13 01:04:59 +02:00
|
|
|
// as returned by installPath(), and that's incorrect.
|
|
|
|
Q_FOREACH(const QString& dir, kdedirDataDirs) {
|
2016-03-04 20:51:02 +02:00
|
|
|
if (!xdgdirList.contains(dir, case_sensitivity))
|
2014-11-13 01:04:59 +02:00
|
|
|
xdgdirList.append(dir);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
xdgdirList = kdedirDataDirs;
|
|
|
|
xdgdirList.append(QString::fromLatin1("/usr/local/share/"));
|
|
|
|
xdgdirList.append(QString::fromLatin1("/usr/share/"));
|
2015-05-20 23:32:01 +00:00
|
|
|
xdgdirList.append(QString::fromLatin1("/share/"));
|
2014-11-13 01:04:59 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
localXdgDir = readEnvPath("XDG_DATA_HOME");
|
|
|
|
if (!localXdgDir.isEmpty())
|
|
|
|
{
|
|
|
|
if (localXdgDir[localXdgDir.length()-1] != QLatin1Char('/'))
|
|
|
|
localXdgDir += QLatin1Char('/');
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
localXdgDir = QDir::homePath() + QLatin1String("/.local/share/");
|
|
|
|
}
|
|
|
|
|
|
|
|
localXdgDir = KShell::tildeExpand(localXdgDir);
|
|
|
|
addXdgDataPrefix(localXdgDir);
|
|
|
|
|
|
|
|
for (QStringList::ConstIterator it = xdgdirList.constBegin();
|
|
|
|
it != xdgdirList.constEnd(); ++it)
|
|
|
|
{
|
|
|
|
QString dir = KShell::tildeExpand(*it);
|
|
|
|
addXdgDataPrefix(dir);
|
|
|
|
}
|
|
|
|
// end XDG_DATA_XXX
|
|
|
|
|
2020-02-08 20:46:43 +00:00
|
|
|
addResourceDir("lib", QLatin1String(LIB_INSTALL_DIR "/"), true);
|
|
|
|
addResourceDir("exe", QLatin1String(LIBEXEC_INSTALL_DIR), true );
|
2014-11-13 01:04:59 +02:00
|
|
|
|
2016-05-03 15:26:28 +00:00
|
|
|
addResourceType("qtplugins", "lib", QLatin1String("plugins"));
|
2014-11-13 01:04:59 +02:00
|
|
|
|
|
|
|
uint index = 0;
|
|
|
|
while (types_indices[index] != -1) {
|
2016-05-03 15:26:28 +00:00
|
|
|
addResourceType(types_string + types_indices[index], 0,
|
|
|
|
QLatin1String(types_string + types_indices[index+1]), true);
|
2014-11-13 01:04:59 +02:00
|
|
|
index+=2;
|
|
|
|
}
|
|
|
|
|
|
|
|
addResourceDir("home", QDir::homePath(), false);
|
|
|
|
|
2016-05-03 15:26:28 +00:00
|
|
|
addResourceType("autostart", "xdgconf-autostart", QLatin1String("/")); // merge them, start with xdg autostart
|
|
|
|
addResourceType("autostart", NULL, QLatin1String("share/autostart")); // KDE ones are higher priority
|
2014-11-13 01:04:59 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
QString KStandardDirs::localkdedir() const
|
|
|
|
{
|
|
|
|
// Return the prefix to use for saving
|
|
|
|
return d->m_prefixes.first();
|
|
|
|
}
|
|
|
|
|
|
|
|
QString KStandardDirs::localxdgdatadir() const
|
|
|
|
{
|
|
|
|
// Return the prefix to use for saving
|
|
|
|
return d->xdgdata_prefixes.first();
|
|
|
|
}
|
|
|
|
|
|
|
|
QString KStandardDirs::localxdgconfdir() const
|
|
|
|
{
|
|
|
|
// Return the prefix to use for saving
|
|
|
|
return d->xdgconf_prefixes.first();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// just to make code more readable without macros
|
|
|
|
QString KStandardDirs::locate( const char *type,
|
|
|
|
const QString& filename, const KComponentData &cData)
|
|
|
|
{
|
|
|
|
return cData.dirs()->findResource(type, filename);
|
|
|
|
}
|
|
|
|
|
|
|
|
QString KStandardDirs::locateLocal( const char *type,
|
|
|
|
const QString& filename, const KComponentData &cData)
|
|
|
|
{
|
|
|
|
return locateLocal(type, filename, true, cData);
|
|
|
|
}
|
|
|
|
|
|
|
|
QString KStandardDirs::locateLocal( const char *type,
|
|
|
|
const QString& filename, bool createDir,
|
|
|
|
const KComponentData &cData)
|
|
|
|
{
|
|
|
|
// try to find slashes. If there are some, we have to
|
|
|
|
// create the subdir first
|
|
|
|
int slash = filename.lastIndexOf(QLatin1Char('/')) + 1;
|
|
|
|
if (!slash) { // only one filename
|
|
|
|
return cData.dirs()->saveLocation(type, QString(), createDir) + filename;
|
|
|
|
}
|
|
|
|
|
|
|
|
// split path from filename
|
|
|
|
QString dir = filename.left(slash);
|
|
|
|
QString file = filename.mid(slash);
|
|
|
|
return cData.dirs()->saveLocation(type, dir, createDir) + file;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool KStandardDirs::checkAccess(const QString& pathname, int mode)
|
|
|
|
{
|
|
|
|
int accessOK = KDE::access( pathname, mode );
|
|
|
|
if ( accessOK == 0 )
|
|
|
|
return true; // OK, I can really access the file
|
|
|
|
|
|
|
|
// else
|
|
|
|
// if we want to write the file would be created. Check, if the
|
|
|
|
// user may write to the directory to create the file.
|
|
|
|
if ( (mode & W_OK) == 0 )
|
|
|
|
return false; // Check for write access is not part of mode => bail out
|
|
|
|
|
|
|
|
|
|
|
|
if (!KDE::access( pathname, F_OK)) // if it already exists
|
|
|
|
return false;
|
|
|
|
|
|
|
|
//strip the filename (everything until '/' from the end
|
|
|
|
QString dirName(pathname);
|
|
|
|
int pos = dirName.lastIndexOf(QLatin1Char('/'));
|
|
|
|
if ( pos == -1 )
|
|
|
|
return false; // No path in argument. This is evil, we won't allow this
|
|
|
|
else if ( pos == 0 ) // don't turn e.g. /root into an empty string
|
|
|
|
pos = 1;
|
|
|
|
|
|
|
|
dirName.truncate(pos); // strip everything starting from the last '/'
|
|
|
|
|
|
|
|
accessOK = KDE::access( dirName, W_OK );
|
|
|
|
// -?- Can I write to the accessed diretory
|
|
|
|
if ( accessOK == 0 )
|
|
|
|
return true; // Yes
|
|
|
|
else
|
|
|
|
return false; // No
|
|
|
|
}
|
|
|
|
|