1
/* This file is part of the KDE libraries
2
Copyright (C) 1999 Sirtaj Singh Kang <taj@kde.org>
3
Copyright (C) 1999,2007 Stephan Kulow <coolo@kde.org>
4
Copyright (C) 1999 Waldo Bastian <bastian@kde.org>
5
Copyright (C) 2009 David Faure <faure@kde.org>
7
This library is free software; you can redistribute it and/or
8
modify it under the terms of the GNU Library General Public
9
License version 2 as published by the Free Software Foundation.
11
This library is distributed in the hope that it will be useful,
12
but WITHOUT ANY WARRANTY; without even the implied warranty of
13
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14
Library General Public License for more details.
16
You should have received a copy of the GNU Library General Public License
17
along with this library; see the file COPYING.LIB. If not, write to
18
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19
Boston, MA 02110-1301, USA.
23
* Author: Stephan Kulow <coolo@kde.org> and Sirtaj Singh Kang <taj@kde.org>
24
* Generated: Thu Mar 5 16:05:28 EST 1998
27
#include "kstandarddirs.h"
29
#include "kconfiggroup.h"
31
#include "kcomponentdata.h"
35
#include "kkernel_win.h"
36
#include "kkernel_mac.h"
40
#include <config-prefix.h>
41
#include <config-kstandarddirs.h>
46
#ifdef HAVE_SYS_STAT_H
52
#include <sys/param.h>
53
#include <sys/types.h>
63
// FIXME: did not find a reliable way to fix with kdewin mingw header
64
#define interface struct
67
#include <QtCore/QVarLengthArray>
70
#include <QtCore/QMutex>
71
#include <QtCore/QRegExp>
72
#include <QtCore/QDir>
73
#include <QtCore/QFileInfo>
74
#include <QtCore/QSettings>
76
class KStandardDirs::KStandardDirsPrivate
79
KStandardDirsPrivate(KStandardDirs* qq)
80
: m_restrictionsActive(false),
81
m_checkRestrictions(true),
82
m_cacheMutex(QMutex::Recursive), // resourceDirs is recursive
86
bool hasDataRestrictions(const QString &relPath) const;
87
QStringList resourceDirs(const char* type, const QString& subdirForRestrictions);
88
void createSpecialResource(const char*);
90
bool m_restrictionsActive : 1;
91
bool m_checkRestrictions : 1;
92
QMap<QByteArray, bool> m_restrictions;
94
QStringList xdgdata_prefixes;
95
QStringList xdgconf_prefixes;
96
QStringList m_prefixes;
98
// Directory dictionaries
99
QMap<QByteArray, QStringList> m_absolutes; // For each resource type, the list of absolute paths, from most local (most priority) to most global
100
QMap<QByteArray, QStringList> m_relatives; // Same with relative paths
101
// The search path is "all relative paths" < "all absolute paths", from most priority to least priority.
103
// Caches (protected by mutex in const methods, cf ctor docu)
104
QMap<QByteArray, QStringList> m_dircache;
105
QMap<QByteArray, QString> m_savelocations;
111
/* If you add a new resource type here, make sure to
112
* 1) regenerate using "kdesdk/scripts/generate_string_table.pl types < tmpfile" with the data below in tmpfile.
113
* 2) update the KStandardDirs class documentation
114
* 3) update the list in kde-config.cpp
135
share/kde4/servicetypes
170
static const char types_string[] =
188
"share/kde4/services\0"
190
"share/kde4/servicetypes\0"
204
"%lib/kde4/plugins\0"
206
"share/config.kcfg\0"
216
"desktop-directories\0"
220
"xdgconf-autostart\0"
224
static const int types_indices[] = {
225
0, 5, 16, 21, 36, 41, 53, 60,
226
73, 80, 94, 99, 112, 118, 131, 138,
227
151, 160, 180, 193, 217, 222, 236, 240,
228
248, 258, 275, 285, 301, 305, 309, 316,
229
326, 336, 354, 359, 377, 387, 403, 416,
230
429, 442, 448, 463, 471, 484, 504, 217,
231
517, 530, 536, 554, -1
234
static void tokenize(QStringList& token, const QString& str,
235
const QString& delim);
237
KStandardDirs::KStandardDirs()
238
: d(new KStandardDirsPrivate(this))
243
KStandardDirs::~KStandardDirs()
248
bool KStandardDirs::isRestrictedResource(const char *type, const QString& relPath) const
250
if (!d->m_restrictionsActive)
253
if (d->m_restrictions.value(type, false))
256
if (strcmp(type, "data")==0 && d->hasDataRestrictions(relPath))
262
bool KStandardDirs::KStandardDirsPrivate::hasDataRestrictions(const QString &relPath) const
265
const int i = relPath.indexOf(QLatin1Char('/'));
267
key = QString::fromLatin1("data_") + relPath.left(i);
269
key = QString::fromLatin1("data_") + relPath;
271
return m_restrictions.value(key.toLatin1(), false);
275
QStringList KStandardDirs::allTypes() const
278
for (int i = 0; types_indices[i] != -1; i += 2)
279
list.append(QLatin1String(types_string + types_indices[i]));
280
// Those are added manually by addKDEDefaults
281
list.append(QString::fromLatin1("lib"));
282
//list.append(QString::fromLatin1("home")); // undocumented on purpose, said Waldo in r113855.
284
// Those are handled by resourceDirs() itself
285
list.append(QString::fromLatin1("socket"));
286
list.append(QString::fromLatin1("tmp"));
287
list.append(QString::fromLatin1("cache"));
288
// Those are handled by installPath()
289
list.append(QString::fromLatin1("include"));
291
// If you add anything here, make sure kde-config.cpp has a description for it.
296
static void priorityAdd(QStringList &prefixes, const QString& dir, bool priority)
298
if (priority && !prefixes.isEmpty())
300
// Add in front but behind $KDEHOME
301
QStringList::iterator it = prefixes.begin();
303
prefixes.insert(it, dir);
307
prefixes.append(dir);
311
void KStandardDirs::addPrefix( const QString& _dir )
313
addPrefix(_dir, false);
316
void KStandardDirs::addPrefix( const QString& _dir, bool priority )
322
if (dir.at(dir.length() - 1) != QLatin1Char('/'))
323
dir += QLatin1Char('/');
325
if (!d->m_prefixes.contains(dir)) {
326
priorityAdd(d->m_prefixes, dir, priority);
327
d->m_dircache.clear();
331
void KStandardDirs::addXdgConfigPrefix( const QString& _dir )
333
addXdgConfigPrefix(_dir, false);
336
void KStandardDirs::addXdgConfigPrefix( const QString& _dir, bool priority )
342
if (dir.at(dir.length() - 1) != QLatin1Char('/'))
343
dir += QLatin1Char('/');
345
if (!d->xdgconf_prefixes.contains(dir)) {
346
priorityAdd(d->xdgconf_prefixes, dir, priority);
347
d->m_dircache.clear();
351
void KStandardDirs::addXdgDataPrefix( const QString& _dir )
353
addXdgDataPrefix(_dir, false);
356
void KStandardDirs::addXdgDataPrefix( const QString& _dir, bool priority )
362
if (dir.at(dir.length() - 1) != QLatin1Char('/'))
363
dir += QLatin1Char('/');
365
if (!d->xdgdata_prefixes.contains(dir)) {
366
priorityAdd(d->xdgdata_prefixes, dir, priority);
367
d->m_dircache.clear();
371
QString KStandardDirs::kfsstnd_prefixes()
373
return d->m_prefixes.join(QString(QLatin1Char(KPATH_SEPARATOR)));
376
QString KStandardDirs::kfsstnd_xdg_conf_prefixes()
378
return d->xdgconf_prefixes.join(QString(QLatin1Char(KPATH_SEPARATOR)));
381
QString KStandardDirs::kfsstnd_xdg_data_prefixes()
383
return d->xdgdata_prefixes.join(QString(QLatin1Char(KPATH_SEPARATOR)));
386
#ifndef KDE_NO_DEPRECATED
387
bool KStandardDirs::addResourceType( const char *type,
388
const QString& relativename,
391
return addResourceType( type, 0, relativename, priority);
395
bool KStandardDirs::addResourceType( const char *type,
396
const char *basetype,
397
const QString& relativename,
400
if (relativename.isEmpty())
403
QString copy = relativename;
405
copy = QLatin1Char('%') + QString::fromLatin1(basetype) + QLatin1Char('/') + relativename;
407
if (!copy.endsWith(QLatin1Char('/')))
408
copy += QLatin1Char('/');
410
QStringList& rels = d->m_relatives[type]; // find or insert
412
if (!rels.contains(copy)) {
418
d->m_dircache.remove(type);
419
d->m_savelocations.remove(type);
425
bool KStandardDirs::addResourceDir( const char *type,
426
const QString& absdir,
429
if (absdir.isEmpty() || !type)
431
// find or insert entry in the map
432
QString copy = absdir;
433
if (copy.at(copy.length() - 1) != QLatin1Char('/'))
434
copy += QLatin1Char('/');
436
QStringList &paths = d->m_absolutes[type];
437
if (!paths.contains(copy)) {
443
d->m_dircache.remove(type);
444
d->m_savelocations.remove(type);
450
QString KStandardDirs::findResource( const char *type,
451
const QString& _filename ) const
453
if (!QDir::isRelativePath(_filename))
454
return !KGlobal::hasLocale() ? _filename // absolute dirs are absolute dirs, right? :-/
455
: KGlobal::locale()->localizedFilePath(_filename); // -- almost.
458
kDebug(180) << "Find resource: " << type;
459
for (QStringList::ConstIterator pit = m_prefixes.begin();
460
pit != m_prefixes.end();
463
kDebug(180) << "Prefix: " << *pit;
467
QString filename(_filename);
469
if(strcmp(type, "exe") == 0) {
470
if(!filename.endsWith(QLatin1String(".exe")))
471
filename += QLatin1String(".exe");
474
const QString dir = findResourceDir(type, filename);
478
return !KGlobal::hasLocale() ? dir + filename
479
: KGlobal::locale()->localizedFilePath(dir + filename);
482
static quint32 updateHash(const QString &file, quint32 hash)
484
KDE_struct_stat buff;
485
if ((KDE::access(file, R_OK) == 0) && (KDE::stat(file, &buff) == 0) && (S_ISREG(buff.st_mode))) {
486
hash = hash + static_cast<quint32>(buff.st_ctime);
491
quint32 KStandardDirs::calcResourceHash( const char *type,
492
const QString& filename,
493
SearchOptions options ) const
497
if (!QDir::isRelativePath(filename))
499
// absolute dirs are absolute dirs, right? :-/
500
return updateHash(filename, hash);
502
QStringList candidates = d->resourceDirs(type, filename);
504
foreach ( const QString& candidate, candidates )
506
hash = updateHash(candidate + filename, hash);
507
if ( !( options & Recursive ) && hash ) {
515
QStringList KStandardDirs::findDirs( const char *type,
516
const QString& reldir ) const
520
if (!QDir::isRelativePath(reldir))
522
testdir.setPath(reldir);
523
if (testdir.exists())
525
if (reldir.endsWith(QLatin1Char('/')))
528
list.append(reldir+QLatin1Char('/'));
533
const QStringList candidates = d->resourceDirs(type, reldir);
535
for (QStringList::ConstIterator it = candidates.begin();
536
it != candidates.end(); ++it) {
537
testdir.setPath(*it + reldir);
538
if (testdir.exists())
539
list.append(testdir.absolutePath() + QLatin1Char('/'));
545
QString KStandardDirs::findResourceDir( const char *type,
546
const QString& _filename) const
549
if (_filename.isEmpty()) {
550
kWarning() << "filename for type " << type << " in KStandardDirs::findResourceDir is not supposed to be empty!!";
555
QString filename(_filename);
557
if(strcmp(type, "exe") == 0) {
558
if(!filename.endsWith(QLatin1String(".exe")))
559
filename += QLatin1String(".exe");
562
const QStringList candidates = d->resourceDirs(type, filename);
564
for (QStringList::ConstIterator it = candidates.begin();
565
it != candidates.end(); ++it) {
566
if (exists(*it + filename)) {
572
if(false && strcmp(type, "locale"))
573
kDebug(180) << "KStdDirs::findResDir(): can't find \"" << filename << "\" in type \"" << type << "\".";
579
bool KStandardDirs::exists(const QString &fullPath)
582
// access() and stat() give a stupid error message to the user
583
// if the path is not accessible at all (e.g. no disk in A:/ and
584
// we do stat("A:/.directory")
585
if (fullPath.endsWith(QLatin1Char('/')))
586
return QDir(fullPath).exists();
587
return QFileInfo(fullPath).exists();
589
KDE_struct_stat buff;
590
QByteArray cFullPath = QFile::encodeName(fullPath);
591
if (access(cFullPath, R_OK) == 0 && KDE_stat( cFullPath, &buff ) == 0) {
592
if (!fullPath.endsWith(QLatin1Char('/'))) {
593
if (S_ISREG( buff.st_mode ))
596
if (S_ISDIR( buff.st_mode ))
603
static void lookupDirectory(const QString& path, const QString &relPart,
604
const QRegExp ®exp,
606
QStringList& relList,
607
bool recursive, bool unique)
609
const QString pattern = regexp.pattern();
610
if (recursive || pattern.contains(QLatin1Char('?')) || pattern.contains(QLatin1Char('*')))
612
if (path.isEmpty()) //for sanity
615
QString path_ = path + QLatin1String( "*.*" );
616
WIN32_FIND_DATA findData;
617
HANDLE hFile = FindFirstFile( (LPWSTR)path_.utf16(), &findData );
618
if( hFile == INVALID_HANDLE_VALUE )
621
const int len = wcslen( findData.cFileName );
622
if (!( findData.cFileName[0] == '.' &&
623
findData.cFileName[1] == '\0' ) &&
624
!( findData.cFileName[0] == '.' &&
625
findData.cFileName[1] == '.' &&
626
findData.cFileName[2] == '\0' ) &&
627
( findData.cFileName[len-1] != '~' ) ) {
628
QString fn = QString::fromUtf16( (const unsigned short*)findData.cFileName );
629
if (!recursive && !regexp.exactMatch(fn))
630
continue; // No match
631
QString pathfn = path + fn;
632
bool bIsDir = ( ( findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) == FILE_ATTRIBUTE_DIRECTORY );
635
lookupDirectory(pathfn + QLatin1Char('/'),
636
relPart + fn + QLatin1Char('/'),
637
regexp, list, relList, recursive, unique);
639
if (!regexp.exactMatch(fn))
640
continue; // No match
644
if ( !unique || !relList.contains(relPart + fn) )
646
list.append( pathfn );
647
relList.append( relPart + fn );
651
} while( FindNextFile( hFile, &findData ) != 0 );
654
// We look for a set of files.
655
DIR *dp = opendir( QFile::encodeName(path));
659
assert(path.endsWith(QLatin1Char('/')));
663
while( ( ep = readdir( dp ) ) != 0L )
665
QString fn( QFile::decodeName(ep->d_name));
666
if (fn == QString::fromLatin1(".") || fn == QString::fromLatin1("..") || fn.at(fn.length() - 1) == QLatin1Char('~'))
669
if (!recursive && !regexp.exactMatch(fn))
670
continue; // No match
675
QString pathfn = path + fn;
676
#ifdef HAVE_DIRENT_D_TYPE
677
isDir = ep->d_type == DT_DIR;
678
isReg = ep->d_type == DT_REG;
680
if (ep->d_type == DT_UNKNOWN || ep->d_type == DT_LNK)
683
KDE_struct_stat buff;
684
if ( KDE::stat( pathfn, &buff ) != 0 ) {
685
kDebug(180) << "Error stat'ing " << pathfn << " : " << perror;
686
continue; // Couldn't stat (e.g. no read permissions)
688
isReg = S_ISREG (buff.st_mode);
689
isDir = S_ISDIR (buff.st_mode);
694
lookupDirectory(pathfn + QLatin1Char('/'), relPart + fn + QLatin1Char('/'), regexp, list, relList, recursive, unique);
696
if (!regexp.exactMatch(fn))
697
continue; // No match
701
if (!unique || !relList.contains(relPart + fn))
703
list.append( pathfn );
704
relList.append( relPart + fn );
713
// We look for a single file.
714
QString fn = pattern;
715
QString pathfn = path + fn;
716
KDE_struct_stat buff;
717
if ( KDE::stat( pathfn, &buff ) != 0 )
718
return; // File not found
719
if ( S_ISREG( buff.st_mode))
721
if (!unique || !relList.contains(relPart + fn))
723
list.append( pathfn );
724
relList.append( relPart + fn );
730
static void lookupPrefix(const QString& prefix, const QString& relpath,
731
const QString& relPart,
732
const QRegExp ®exp,
734
QStringList& relList,
735
bool recursive, bool unique)
737
if (relpath.isEmpty()) {
739
Q_ASSERT(prefix != QLatin1String("/")); // we don't want to recursively list the whole disk!
740
lookupDirectory(prefix, relPart, regexp, list,
741
relList, recursive, unique);
747
int slash = relpath.indexOf(QLatin1Char('/'));
749
rest = relpath.left(relpath.length() - 1);
751
path = relpath.left(slash);
752
rest = relpath.mid(slash + 1);
755
if (prefix.isEmpty()) //for sanity
758
// what does this assert check ?
759
assert(prefix.endsWith(QLatin1Char('/')));
761
if (path.contains(QLatin1Char('*')) || path.contains(QLatin1Char('?'))) {
763
QRegExp pathExp(path, Qt::CaseSensitive, QRegExp::Wildcard);
766
QString prefix_ = prefix + QLatin1String( "*.*" );
767
WIN32_FIND_DATA findData;
768
HANDLE hFile = FindFirstFile( (LPWSTR)prefix_.utf16(), &findData );
769
if( hFile == INVALID_HANDLE_VALUE )
772
const int len = wcslen( findData.cFileName );
773
if (!( findData.cFileName[0] == '.' &&
774
findData.cFileName[1] == '\0' ) &&
775
!( findData.cFileName[0] == '.' &&
776
findData.cFileName[1] == '.' &&
777
findData.cFileName[2] == '\0' ) &&
778
( findData.cFileName[len-1] != '~' ) ) {
779
const QString fn = QString::fromUtf16( (const unsigned short*)findData.cFileName );
780
if ( !pathExp.exactMatch(fn) )
781
continue; // No match
782
if ( ( findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) == FILE_ATTRIBUTE_DIRECTORY )
783
lookupPrefix(prefix + fn + QLatin1Char('/'),
784
rest, relPart + fn + QLatin1Char('/'),
785
regexp, list, relList, recursive, unique);
787
} while( FindNextFile( hFile, &findData ) != 0 );
790
DIR *dp = opendir( QFile::encodeName(prefix) );
797
while( ( ep = readdir( dp ) ) != 0L )
799
QString fn( QFile::decodeName(ep->d_name));
800
if (fn == QLatin1String(".") || fn == QLatin1String("..") || fn.at(fn.length() - 1) == QLatin1Char('~'))
803
if ( !pathExp.exactMatch(fn) )
804
continue; // No match
805
QString rfn = relPart+fn;
810
#ifdef HAVE_DIRENT_D_TYPE
811
isDir = ep->d_type == DT_DIR;
813
if (ep->d_type == DT_UNKNOWN || ep->d_type == DT_LNK)
816
QString pathfn = path + fn;
817
KDE_struct_stat buff;
818
if ( KDE::stat( fn, &buff ) != 0 ) {
819
kDebug(180) << "Error stat'ing " << fn << " : " << perror;
820
continue; // Couldn't stat (e.g. no read permissions)
822
isDir = S_ISDIR (buff.st_mode);
825
lookupPrefix(fn + QLatin1Char('/'), rest, rfn + QLatin1Char('/'), regexp, list, relList, recursive, unique);
831
// Don't stat, if the dir doesn't exist we will find out
832
// when we try to open it.
833
lookupPrefix(prefix + path + QLatin1Char('/'), rest,
834
relPart + path + QLatin1Char('/'), regexp, list,
835
relList, recursive, unique);
840
KStandardDirs::findAllResources( const char *type,
841
const QString& filter,
842
SearchOptions options,
843
QStringList &relList) const
848
if ( !filter.isEmpty() )
850
int slash = filter.lastIndexOf(QLatin1Char('/'));
854
filterPath = filter.left(slash + 1);
855
filterFile = filter.mid(slash + 1);
859
QStringList candidates;
860
if ( !QDir::isRelativePath(filter) ) // absolute path
863
candidates << filterPath.left(3); //e.g. "C:\"
864
filterPath = filterPath.mid(3);
866
candidates << QString::fromLatin1("/");
867
filterPath = filterPath.mid(1);
872
candidates = d->resourceDirs(type, filter);
875
if (filterFile.isEmpty()) {
876
filterFile = QString(QLatin1Char('*'));
879
QRegExp regExp(filterFile, Qt::CaseSensitive, QRegExp::Wildcard);
882
foreach ( const QString& candidate, candidates )
884
lookupPrefix(candidate, filterPath, QString(), regExp, list,
885
relList, options & Recursive, options & NoDuplicates);
892
KStandardDirs::findAllResources( const char *type,
893
const QString& filter,
894
SearchOptions options ) const
897
return findAllResources(type, filter, options, relList);
900
// ####### KDE4: should this be removed, in favor of QDir::canonicalPath()?
901
// aseigo: QDir::canonicalPath returns QString() if the dir doesn't exist
902
// and this method is often used with the expectation for it to work
903
// even if the directory doesn't exist. so ... no, we can't drop this
906
KStandardDirs::realPath(const QString &dirname)
909
const QString strRet = realFilePath(dirname);
910
if (!strRet.endsWith(QLatin1Char('/')))
911
return strRet + QLatin1Char('/');
914
if (dirname.isEmpty() || (dirname.size() == 1 && dirname.at(0) == QLatin1Char('/')))
917
if (dirname.at(0) != QLatin1Char('/')) {
918
qWarning("realPath called with a relative path '%s', please fix", qPrintable(dirname));
922
char realpath_buffer[MAXPATHLEN + 1];
923
memset(realpath_buffer, 0, MAXPATHLEN + 1);
925
/* If the path contains symlinks, get the real name */
926
if (realpath( QFile::encodeName(dirname).constData(), realpath_buffer) != 0) {
927
// success, use result from realpath
928
int len = strlen(realpath_buffer);
929
realpath_buffer[len] = '/';
930
realpath_buffer[len+1] = 0;
931
return QFile::decodeName(realpath_buffer);
934
// Does not exist yet; resolve symlinks in parent dirs then.
935
// This ensures that once the directory exists, it will still be resolved
936
// the same way, so that the general rule that KStandardDirs always returns
937
// canonical paths stays true, and app code can compare paths more easily.
938
QString dir = dirname;
939
if (!dir.endsWith(QLatin1Char('/')))
940
dir += QLatin1Char('/');
942
while (!KStandardDirs::exists(dir)) {
943
//qDebug() << "does not exist:" << dir;
944
const int pos = dir.lastIndexOf(QLatin1Char('/'), -2);
945
Q_ASSERT(pos >= 0); // what? even "/" doesn't exist?
946
relative.prepend(dir.mid(pos+1)); // keep "subdir/"
947
dir = dir.left(pos+1);
948
Q_ASSERT(dir.endsWith(QLatin1Char('/')));
950
Q_ASSERT(!relative.isEmpty()); // infinite recursion ahead
951
if (!relative.isEmpty()) {
952
//qDebug() << "done, resolving" << dir << "and adding" << relative;
953
dir = realPath(dir) + relative;
959
// ####### KDE4: should this be removed, in favor of QDir::canonicalPath()?
960
// aseigo: QDir::canonicalPath returns QString() if the dir doesn't exist
961
// and this method is often used with the expectation for it to work
962
// even if the directory doesn't exist. so ... no, we can't drop this
965
KStandardDirs::realFilePath(const QString &filename)
968
LPCWSTR lpIn = (LPCWSTR)filename.utf16();
969
QVarLengthArray<WCHAR, MAX_PATH> buf(MAX_PATH);
970
DWORD len = GetFullPathNameW(lpIn, buf.size(), buf.data(), NULL);
971
if (len > (DWORD)buf.size()) {
973
len = GetFullPathNameW(lpIn, buf.size(), buf.data(), NULL);
977
return QString::fromUtf16((const unsigned short*)buf.data()).replace(QLatin1Char('\\'),QLatin1Char('/')).toLower();
979
char realpath_buffer[MAXPATHLEN + 1];
980
memset(realpath_buffer, 0, MAXPATHLEN + 1);
982
/* If the path contains symlinks, get the real name */
983
if (realpath( QFile::encodeName(filename).constData(), realpath_buffer) != 0) {
984
// success, use result from realpath
985
return QFile::decodeName(realpath_buffer);
993
void KStandardDirs::KStandardDirsPrivate::createSpecialResource(const char *type)
997
gethostname(hostname, 255);
998
const QString localkdedir = m_prefixes.first();
999
QString dir = localkdedir + QString::fromLatin1(type) + QLatin1Char('-') + QString::fromLocal8Bit(hostname);
1002
int result = readlink(QFile::encodeName(dir).constData(), link, 1023);
1003
bool relink = (result == -1) && (errno == ENOENT);
1007
if (!QDir::isRelativePath(QFile::decodeName(link)))
1009
KDE_struct_stat stat_buf;
1010
int res = KDE::lstat(QFile::decodeName(link), &stat_buf);
1011
if ((res == -1) && (errno == ENOENT))
1015
else if ((res == -1) || (!S_ISDIR(stat_buf.st_mode)))
1017
fprintf(stderr, "Error: \"%s\" is not a directory.\n", link);
1020
else if (stat_buf.st_uid != getuid())
1022
fprintf(stderr, "Error: \"%s\" is owned by uid %d instead of uid %d.\n", link, stat_buf.st_uid, getuid());
1030
if (!makeDir(dir, 0700))
1031
fprintf(stderr, "failed to create \"%s\"", qPrintable(dir));
1033
result = readlink(QFile::encodeName(dir).constData(), link, 1023);
1038
QString srv = findExe(QLatin1String("lnusertemp"), installPath("libexec"));
1040
srv = findExe(QLatin1String("lnusertemp"));
1043
if (system(QFile::encodeName(srv) + ' ' + type) == -1) {
1044
fprintf(stderr, "Error: unable to launch lnusertemp command" );
1046
result = readlink(QFile::encodeName(dir).constData(), link, 1023);
1053
dir = QFile::decodeName(link);
1055
dir = QDir::cleanPath(dir + QFile::decodeName(link));
1058
q->addResourceDir(type, dir + QLatin1Char('/'), false);
1061
QStringList KStandardDirs::resourceDirs(const char *type) const
1063
return d->resourceDirs(type, QString());
1066
QStringList KStandardDirs::KStandardDirsPrivate::resourceDirs(const char* type, const QString& subdirForRestrictions)
1068
QMutexLocker lock(&m_cacheMutex);
1069
const bool dataRestrictionActive = m_restrictionsActive
1070
&& (strcmp(type, "data") == 0)
1071
&& hasDataRestrictions(subdirForRestrictions);
1073
QMap<QByteArray, QStringList>::const_iterator dirCacheIt = m_dircache.constFind(type);
1075
QStringList candidates;
1077
if (dirCacheIt != m_dircache.constEnd() && !dataRestrictionActive) {
1078
//qDebug() << this << "resourceDirs(" << type << "), in cache already";
1079
candidates = *dirCacheIt;
1081
else // filling cache
1083
//qDebug() << this << "resourceDirs(" << type << "), not in cache";
1084
if (strcmp(type, "socket") == 0)
1085
createSpecialResource(type);
1086
else if (strcmp(type, "tmp") == 0)
1087
createSpecialResource(type);
1088
else if (strcmp(type, "cache") == 0)
1089
createSpecialResource(type);
1093
bool restrictionActive = false;
1094
if (m_restrictionsActive) {
1095
if (dataRestrictionActive)
1096
restrictionActive = true;
1097
if (m_restrictions.value("all", false))
1098
restrictionActive = true;
1099
else if (m_restrictions.value(type, false))
1100
restrictionActive = true;
1104
dirs = m_relatives.value(type);
1105
const QString typeInstallPath = installPath(type); // could be empty
1106
// better #ifdef incasesensitive_filesystem
1108
const QString installdir = typeInstallPath.isEmpty() ? QString() : realPath(typeInstallPath).toLower();
1109
const QString installprefix = installPath("kdedir").toLower();
1111
const QString installdir = typeInstallPath.isEmpty() ? QString() : realPath(typeInstallPath);
1112
const QString installprefix = installPath("kdedir");
1114
if (!dirs.isEmpty())
1118
for (QStringList::ConstIterator it = dirs.constBegin();
1119
it != dirs.constEnd(); ++it)
1121
if ((*it).startsWith(QLatin1Char('%'))) {
1122
// grab the "data" from "%data/apps"
1123
const int pos = (*it).indexOf(QLatin1Char('/'));
1124
QString rel = (*it).mid(1, pos - 1);
1125
QString rest = (*it).mid(pos + 1);
1126
const QStringList basedirs = resourceDirs(rel.toUtf8().constData(), subdirForRestrictions);
1127
for (QStringList::ConstIterator it2 = basedirs.begin();
1128
it2 != basedirs.end(); ++it2)
1131
const QString path = realPath( *it2 + rest ).toLower();
1133
const QString path = realPath( *it2 + rest );
1135
testdir.setPath(path);
1136
if ((local || testdir.exists()) && !candidates.contains(path))
1137
candidates.append(path);
1143
const QStringList *prefixList = 0;
1144
if (strncmp(type, "xdgdata-", 8) == 0)
1145
prefixList = &(xdgdata_prefixes);
1146
else if (strncmp(type, "xdgconf-", 8) == 0)
1147
prefixList = &(xdgconf_prefixes);
1149
prefixList = &m_prefixes;
1151
for (QStringList::ConstIterator pit = prefixList->begin();
1152
pit != prefixList->end();
1155
if((*pit)!=installprefix||installdir.isEmpty())
1157
for (QStringList::ConstIterator it = dirs.constBegin();
1158
it != dirs.constEnd(); ++it)
1160
if ((*it).startsWith(QLatin1Char('%')))
1163
const QString path = realPath( *pit + *it ).toLower();
1165
const QString path = realPath( *pit + *it );
1167
testdir.setPath(path);
1168
if (local && restrictionActive)
1170
if ((local || testdir.exists()) && !candidates.contains(path))
1171
candidates.append(path);
1177
// we have a custom install path, so use this instead of <installprefix>/<relative dir>
1178
testdir.setPath(installdir);
1179
if(testdir.exists() && ! candidates.contains(installdir))
1180
candidates.append(installdir);
1185
// make sure we find the path where it's installed
1186
if (!installdir.isEmpty()) {
1188
foreach (const QString &s, candidates) {
1189
if (installdir.startsWith(s)) {
1195
candidates.append(installdir);
1198
dirs = m_absolutes.value(type);
1199
if (!dirs.isEmpty())
1200
for (QStringList::ConstIterator it = dirs.constBegin();
1201
it != dirs.constEnd(); ++it)
1203
testdir.setPath(*it);
1204
if (testdir.exists()) {
1206
const QString filename = realPath( *it ).toLower();
1208
const QString filename = realPath( *it );
1210
if (!candidates.contains(filename)) {
1211
candidates.append(filename);
1216
// Insert result into the cache for next time.
1217
// Exception: data_subdir restrictions are per-subdir, so we can't store such results
1218
if (!dataRestrictionActive) {
1219
//kDebug() << this << "Inserting" << type << candidates << "into dircache";
1220
m_dircache.insert(type, candidates);
1225
kDebug(180) << "found dirs for resource" << type << ":" << candidates;
1232
static QStringList executableExtensions()
1234
QStringList ret = QString::fromLocal8Bit(qgetenv("PATHEXT")).split(QLatin1Char(';'));
1235
if (!ret.contains(QLatin1String(".exe"), Qt::CaseInsensitive)) {
1236
// If %PATHEXT% does not contain .exe, it is either empty, malformed, or distorted in ways that we cannot support, anyway.
1238
ret << QLatin1String(".exe")
1239
<< QLatin1String(".com")
1240
<< QLatin1String(".bat")
1241
<< QLatin1String(".cmd");
1247
QStringList KStandardDirs::systemPaths( const QString& pstr )
1254
p = QString::fromLocal8Bit( qgetenv( "PATH" ) );
1257
QString delimiters(QLatin1Char(KPATH_SEPARATOR));
1258
delimiters += QLatin1Char('\b');
1259
tokenize( tokens, p, delimiters );
1261
QStringList exePaths;
1263
// split path using : or \b as delimiters
1264
for( int i = 0; i < tokens.count(); i++ )
1266
exePaths << KShell::tildeExpand( tokens[ i ] );
1273
static QString getBundle( const QString& path, bool ignore )
1275
kDebug(180) << "getBundle(" << path << ", " << ignore << ") called";
1277
QString bundle = path;
1278
bundle += QLatin1String(".app/Contents/MacOS/") + bundle.section(QLatin1Char('/'), -1);
1279
info.setFile( bundle );
1281
if (file = fopen(info.absoluteFilePath().toUtf8().constData(), "r")) {
1284
if ((stat(info.absoluteFilePath().toUtf8().constData(), &_stat)) < 0) {
1287
if ( ignore || (_stat.st_mode & S_IXUSR) ) {
1288
if ( ((_stat.st_mode & S_IFMT) == S_IFREG) || ((_stat.st_mode & S_IFMT) == S_IFLNK) ) {
1289
kDebug(180) << "getBundle(): returning " << bundle;
1298
static QString checkExecutable( const QString& path, bool ignoreExecBit )
1301
QString bundle = getBundle( path, ignoreExecBit );
1302
if ( !bundle.isEmpty() ) {
1303
//kDebug(180) << "findExe(): returning " << bundle;
1307
QFileInfo info( path );
1308
QFileInfo orig = info;
1309
#if defined(Q_OS_DARWIN) || defined(Q_OS_MAC)
1311
if (file = fopen(orig.absoluteFilePath().toUtf8().constData(), "r")) {
1314
if ((stat(orig.absoluteFilePath().toUtf8().constData(), &_stat)) < 0) {
1317
if ( ignoreExecBit || (_stat.st_mode & S_IXUSR) ) {
1318
if ( ((_stat.st_mode & S_IFMT) == S_IFREG) || ((_stat.st_mode & S_IFMT) == S_IFLNK) ) {
1319
orig.makeAbsolute();
1320
return orig.filePath();
1326
if( info.exists() && info.isSymLink() )
1327
info = QFileInfo( info.canonicalFilePath() );
1328
if( info.exists() && ( ignoreExecBit || info.isExecutable() ) && info.isFile() ) {
1329
// return absolute path, but without symlinks resolved in order to prevent
1330
// problems with executables that work differently depending on name they are
1331
// run as (for example gunzip)
1332
orig.makeAbsolute();
1333
return orig.filePath();
1335
//kDebug(180) << "checkExecutable(): failed, returning empty string";
1340
QString KStandardDirs::findExe( const QString& appname,
1341
const QString& pstr,
1342
SearchOptions options )
1344
//kDebug(180) << "findExe(" << appname << ", pstr, " << ignoreExecBit << ") called";
1347
QStringList executable_extensions = executableExtensions();
1348
if (!executable_extensions.contains(appname.section(QLatin1Char('.'), -1, -1, QString::SectionIncludeLeadingSep), Qt::CaseInsensitive)) {
1350
foreach (const QString& extension, executable_extensions) {
1351
found_exe = findExe(appname + extension, pstr, options);
1352
if (!found_exe.isEmpty()) {
1361
// absolute or relative path?
1362
if (appname.contains(QDir::separator()))
1364
//kDebug(180) << "findExe(): absolute path given";
1365
QString path = checkExecutable(appname, options & IgnoreExecBit);
1369
//kDebug(180) << "findExe(): relative path given";
1371
QString p = installPath("libexec") + appname;
1372
QString result = checkExecutable(p, options & IgnoreExecBit);
1373
if (!result.isEmpty()) {
1374
//kDebug(180) << "findExe(): returning " << result;
1378
// Look into the KDE-specific bin dir ("exe" resource) in case KDE was installed into a custom
1379
// prefix, to make things easier ($PATH not required). But not if KDE is in /usr (#241763).
1380
p = installPath("exe");
1381
if (p != QLatin1String("/usr/")) {
1383
result = checkExecutable(p, options & IgnoreExecBit);
1384
if (!result.isEmpty()) {
1385
kDebug(180) << "findExe(): returning " << result;
1390
//kDebug(180) << "findExe(): checking system paths";
1391
const QStringList exePaths = systemPaths( pstr );
1392
for (QStringList::ConstIterator it = exePaths.begin(); it != exePaths.end(); ++it)
1394
p = (*it) + QLatin1Char('/');
1397
// Check for executable in this tokenized path
1398
result = checkExecutable(p, options & IgnoreExecBit);
1399
if (!result.isEmpty()) {
1400
//kDebug(180) << "findExe(): returning " << result;
1405
// If we reach here, the executable wasn't found.
1406
// So return empty string.
1408
//kDebug(180) << "findExe(): failed, nothing matched";
1412
int KStandardDirs::findAllExe( QStringList& list, const QString& appname,
1413
const QString& pstr, SearchOptions options )
1416
QStringList executable_extensions = executableExtensions();
1417
if (!executable_extensions.contains(appname.section(QLatin1Char('.'), -1, -1, QString::SectionIncludeLeadingSep), Qt::CaseInsensitive)) {
1419
foreach (const QString& extension, executable_extensions) {
1420
total += findAllExe (list, appname + extension, pstr, options);
1429
const QStringList exePaths = systemPaths( pstr );
1430
for (QStringList::ConstIterator it = exePaths.begin(); it != exePaths.end(); ++it)
1432
p = (*it) + QLatin1Char('/');
1436
QString bundle = getBundle( p, (options & IgnoreExecBit) );
1437
if ( !bundle.isEmpty() ) {
1438
//kDebug(180) << "findExe(): returning " << bundle;
1439
list.append( bundle );
1445
if( info.exists() && ( ( options & IgnoreExecBit ) || info.isExecutable())
1446
&& info.isFile() ) {
1451
return list.count();
1454
static inline QString equalizePath(QString &str)
1457
// filter pathes through QFileInfo to have always
1458
// the same case for drive letters
1461
return f.absoluteFilePath();
1467
static void tokenize(QStringList& tokens, const QString& str,
1468
const QString& delim)
1470
const int len = str.length();
1473
for(int index = 0; index < len; index++) {
1474
if (delim.contains(str[index])) {
1475
tokens.append(equalizePath(token));
1478
token += str[index];
1481
if (!token.isEmpty()) {
1482
tokens.append(equalizePath(token));
1486
#ifndef KDE_NO_DEPRECATED
1487
QString KStandardDirs::kde_default(const char *type)
1489
return QString(QLatin1Char('%')) + QString::fromLatin1(type) + QLatin1Char('/');
1493
QString KStandardDirs::saveLocation(const char *type,
1494
const QString& suffix,
1497
QMutexLocker lock(&d->m_cacheMutex);
1498
QString path = d->m_savelocations.value(type);
1501
QStringList dirs = d->m_relatives.value(type);
1502
if (dirs.isEmpty() && (
1503
(strcmp(type, "socket") == 0) ||
1504
(strcmp(type, "tmp") == 0) ||
1505
(strcmp(type, "cache") == 0) ))
1507
(void) resourceDirs(type); // Generate socket|tmp|cache resource.
1508
dirs = d->m_relatives.value(type); // Search again.
1510
if (!dirs.isEmpty())
1512
path = dirs.first();
1514
if (path.startsWith(QLatin1Char('%'))) {
1515
// grab the "data" from "%data/apps"
1516
const int pos = path.indexOf(QLatin1Char('/'));
1517
QString rel = path.mid(1, pos - 1);
1518
QString rest = path.mid(pos + 1);
1519
QString basepath = saveLocation(rel.toUtf8().constData());
1520
path = basepath + rest;
1523
// Check for existence of typed directory + suffix
1524
if (strncmp(type, "xdgdata-", 8) == 0) {
1525
path = realPath( localxdgdatadir() + path ) ;
1526
} else if (strncmp(type, "xdgconf-", 8) == 0) {
1527
path = realPath( localxdgconfdir() + path );
1529
path = realPath( localkdedir() + path );
1533
dirs = d->m_absolutes.value(type);
1534
if (dirs.isEmpty()) {
1535
qFatal("KStandardDirs: The resource type %s is not registered", type);
1537
path = realPath(dirs.first());
1541
d->m_savelocations.insert(type, path.endsWith(QLatin1Char('/')) ? path : path + QLatin1Char('/'));
1543
QString fullPath = path + suffix;
1546
if (KDE::stat(fullPath, &st) != 0 || !(S_ISDIR(st.st_mode))) {
1549
// Too much noise from kbuildsycoca4 -- it's fine if this happens from KConfig
1550
// when parsing global files without a local equivalent.
1551
//kDebug(180) << QString("save location %1 doesn't exist").arg(fullPath);
1555
if(!makeDir(fullPath, 0700)) {
1558
d->m_dircache.remove(type);
1560
if (!fullPath.endsWith(QLatin1Char('/')))
1561
fullPath += QLatin1Char('/');
1565
// KDE5: make the method const
1566
QString KStandardDirs::relativeLocation(const char *type, const QString &absPath)
1568
QString fullPath = absPath;
1569
int i = absPath.lastIndexOf(QLatin1Char('/'));
1571
fullPath = realFilePath(absPath); // Normalize
1574
const QStringList candidates = resourceDirs(type);
1576
for (QStringList::ConstIterator it = candidates.begin();
1577
it != candidates.end(); ++it) {
1578
if (fullPath.startsWith(*it)) {
1579
return fullPath.mid((*it).length());
1586
bool KStandardDirs::makeDir(const QString& dir, int mode)
1588
// we want an absolute path
1589
if (QDir::isRelativePath(dir))
1593
return QDir().mkpath(dir);
1595
QString target = dir;
1596
uint len = target.length();
1598
// append trailing slash if missing
1599
if (dir.at(len - 1) != QLatin1Char('/'))
1600
target += QLatin1Char('/');
1608
int pos = target.indexOf(QLatin1Char('/'), i);
1609
base += target.mid(i - 1, pos - i + 1);
1610
QByteArray baseEncoded = QFile::encodeName(base);
1611
// bail out if we encountered a problem
1612
if (KDE_stat(baseEncoded, &st) != 0)
1614
// Directory does not exist....
1615
// Or maybe a dangling symlink ?
1616
if (KDE_lstat(baseEncoded, &st) == 0)
1617
(void)unlink(baseEncoded); // try removing
1619
if (KDE_mkdir(baseEncoded, static_cast<mode_t>(mode)) != 0) {
1620
baseEncoded.prepend( "trying to create local folder " );
1621
perror(baseEncoded.constData());
1622
return false; // Couldn't create it :-(
1631
static QString readEnvPath(const char *env)
1635
c_path = qgetenv(env);
1636
if (c_path.isEmpty())
1640
QString retval = getWin32RegistryValue(HKEY_LOCAL_MACHINE, "Software\\kde", "KDEDIRS", &ok);
1644
c_path = retval.toAscii();
1647
return QDir::fromNativeSeparators(QFile::decodeName(c_path));
1651
static QString executablePrefix()
1653
char path_buffer[MAXPATHLEN + 1];
1654
path_buffer[MAXPATHLEN] = 0;
1655
int length = readlink ("/proc/self/exe", path_buffer, MAXPATHLEN);
1659
path_buffer[length] = '\0';
1661
QString path = QFile::decodeName(path_buffer);
1666
int pos = path.lastIndexOf(QLatin1Char('/')); // Skip filename
1669
pos = path.lastIndexOf(QLatin1Char('/'), pos - 1); // Skip last directory
1673
return path.left(pos);
1677
void KStandardDirs::addResourcesFrom_krcdirs()
1679
QString localFile = QDir::currentPath() + QLatin1String("/.krcdirs");
1680
if (!QFile::exists(localFile))
1683
QSettings iniFile(localFile, QSettings::IniFormat);
1684
iniFile.beginGroup(QString::fromLatin1("KStandardDirs"));
1685
const QStringList resources = iniFile.allKeys();
1686
foreach(const QString &key, resources)
1688
QDir path(iniFile.value(key).toString());
1692
if(path.makeAbsolute())
1693
addResourceDir(key.toAscii(), path.path(), false);
1697
void KStandardDirs::addKDEDefaults()
1699
addResourcesFrom_krcdirs();
1701
QStringList kdedirList;
1703
QString kdedirs = readEnvPath("KDEDIRS");
1705
if (!kdedirs.isEmpty())
1707
tokenize(kdedirList, kdedirs, QString(QLatin1Char(KPATH_SEPARATOR)));
1709
kdedirList.append(installPath("kdedir"));
1711
QString execPrefix(QFile::decodeName(EXEC_INSTALL_PREFIX));
1712
if (!execPrefix.isEmpty() && !kdedirList.contains(execPrefix))
1713
kdedirList.append(execPrefix);
1715
const QString linuxExecPrefix = executablePrefix();
1716
if ( !linuxExecPrefix.isEmpty() )
1717
kdedirList.append( linuxExecPrefix );
1720
// We treat root differently to prevent a "su" shell messing up the
1721
// file permissions in the user's home directory.
1722
QString localKdeDir = readEnvPath(getuid() ? "KDEHOME" : "KDEROOTHOME");
1723
if (!localKdeDir.isEmpty()) {
1724
if (!localKdeDir.endsWith(QLatin1Char('/')))
1725
localKdeDir += QLatin1Char('/');
1727
// TODO KDE5: make localKdeDir equal to localXdgDir (which is determined further below and
1728
// defaults to ~/.config) + '/' + $KDECONFIG (which would default to e.g. "KDE")
1729
// This would mean ~/.config/KDE/ by default, more xdg-compliant.
1731
#if defined(Q_WS_MACX)
1732
localKdeDir = QDir::homePath() + QLatin1String("/Library/Preferences/KDE/");
1733
#elif defined(Q_WS_WIN)
1735
WCHAR wPath[MAX_PATH+1];
1736
if ( SHGetFolderPathW(NULL, CSIDL_APPDATA, NULL, SHGFP_TYPE_CURRENT, wPath) == S_OK) {
1737
localKdeDir = QDir::fromNativeSeparators(QString::fromUtf16((const ushort *) wPath)) + QLatin1Char('/') + QString::fromLatin1(KDE_DEFAULT_HOME) + QLatin1Char('/');
1740
localKdeDir = QDir::homePath() + QLatin1Char('/') + QString::fromLatin1(KDE_DEFAULT_HOME) + QLatin1Char('/');
1745
localKdeDir = QDir::homePath() + QLatin1Char('/') + QString::fromLatin1(KDE_DEFAULT_HOME) + QLatin1Char('/');
1749
if (localKdeDir != QLatin1String("-/"))
1751
localKdeDir = KShell::tildeExpand(localKdeDir);
1752
addPrefix(localKdeDir);
1756
// Adds the "Contents" directory of the current application bundle to
1757
// the search path. This way bundled resources can be found.
1758
QDir bundleDir(mac_app_filename());
1759
if (bundleDir.dirName() == QLatin1String("MacOS")) { // just to be sure we're in a bundle
1761
// now dirName should be "Contents". In there we can find our normal
1762
// dir-structure, beginning with "share"
1763
addPrefix(bundleDir.absolutePath());
1767
QStringList::ConstIterator end(kdedirList.end());
1768
for (QStringList::ConstIterator it = kdedirList.constBegin();
1769
it != kdedirList.constEnd(); ++it)
1771
const QString dir = KShell::tildeExpand(*it);
1776
// begin XDG_CONFIG_XXX
1777
QStringList xdgdirList;
1778
QString xdgdirs = readEnvPath("XDG_CONFIG_DIRS");
1779
if (!xdgdirs.isEmpty())
1781
tokenize(xdgdirList, xdgdirs, QString(QLatin1Char(KPATH_SEPARATOR)));
1786
xdgdirList.append(QString::fromLatin1("/etc/xdg"));
1788
xdgdirList.append(installPath("kdedir") + QString::fromLatin1("etc/xdg"));
1790
xdgdirList.append(QFile::decodeName(KDESYSCONFDIR "/xdg"));
1794
QString localXdgDir = readEnvPath("XDG_CONFIG_HOME");
1795
if (!localXdgDir.isEmpty()) {
1796
if (!localXdgDir.endsWith(QLatin1Char('/')))
1797
localXdgDir += QLatin1Char('/');
1800
localXdgDir = QDir::homePath() + QString::fromLatin1("/Library/Preferences/XDG/");
1802
localXdgDir = QDir::homePath() + QString::fromLatin1("/.config/");
1806
localXdgDir = KShell::tildeExpand(localXdgDir);
1807
addXdgConfigPrefix(localXdgDir);
1809
for (QStringList::ConstIterator it = xdgdirList.constBegin();
1810
it != xdgdirList.constEnd(); ++it)
1812
QString dir = KShell::tildeExpand(*it);
1813
addXdgConfigPrefix(dir);
1815
// end XDG_CONFIG_XXX
1817
// begin XDG_DATA_XXX
1818
QStringList kdedirDataDirs;
1819
for (QStringList::ConstIterator it = kdedirList.constBegin();
1820
it != kdedirList.constEnd(); ++it) {
1822
if (!dir.endsWith(QLatin1Char('/')))
1823
dir += QLatin1Char('/');
1824
kdedirDataDirs.append(dir + QLatin1String("share/"));
1827
xdgdirs = readEnvPath("XDG_DATA_DIRS");
1828
if (!xdgdirs.isEmpty()) {
1829
tokenize(xdgdirList, xdgdirs, QString(QLatin1Char(KPATH_SEPARATOR)));
1830
// Ensure the kdedirDataDirs are in there too,
1831
// otherwise resourceDirs() will add kdedir/share/applications/kde4
1832
// as returned by installPath(), and that's incorrect.
1833
Q_FOREACH(const QString& dir, kdedirDataDirs) {
1834
if (!xdgdirList.contains(dir))
1835
xdgdirList.append(dir);
1838
xdgdirList = kdedirDataDirs;
1840
xdgdirList.append(QString::fromLatin1("/usr/local/share/"));
1841
xdgdirList.append(QString::fromLatin1("/usr/share/"));
1845
localXdgDir = readEnvPath("XDG_DATA_HOME");
1846
if (!localXdgDir.isEmpty())
1848
if (localXdgDir[localXdgDir.length()-1] != QLatin1Char('/'))
1849
localXdgDir += QLatin1Char('/');
1853
localXdgDir = QDir::homePath() + QLatin1String("/.local/share/");
1856
localXdgDir = KShell::tildeExpand(localXdgDir);
1857
addXdgDataPrefix(localXdgDir);
1859
for (QStringList::ConstIterator it = xdgdirList.constBegin();
1860
it != xdgdirList.constEnd(); ++it)
1862
QString dir = KShell::tildeExpand(*it);
1863
addXdgDataPrefix(dir);
1868
addResourceType("lib", 0, "lib" KDELIBSUFF "/");
1871
while (types_indices[index] != -1) {
1872
addResourceType(types_string + types_indices[index], 0, types_string + types_indices[index+1], true);
1875
addResourceType("exe", "lib", "kde4/libexec", true );
1877
addResourceDir("home", QDir::homePath(), false);
1879
addResourceType("autostart", "xdgconf-autostart", "/"); // merge them, start with xdg autostart
1880
addResourceType("autostart", NULL, "share/autostart"); // KDE ones are higher priority
1883
static QStringList lookupProfiles(const QString &mapFile)
1885
QStringList profiles;
1887
if (mapFile.isEmpty() || !QFile::exists(mapFile))
1889
profiles << QString::fromLatin1("default");
1893
struct passwd *pw = getpwuid(geteuid());
1896
profiles << QString::fromLatin1("default");
1897
return profiles; // Not good
1900
QByteArray user = pw->pw_name;
1902
gid_t sup_gids[512];
1903
int sup_gids_nr = getgroups(512, sup_gids);
1905
KConfig mapCfgFile(mapFile);
1906
KConfigGroup mapCfg(&mapCfgFile, "Users");
1907
if (mapCfg.hasKey(user.constData()))
1909
profiles = mapCfg.readEntry(user.constData(), QStringList());
1913
const KConfigGroup generalGrp(&mapCfgFile, "General");
1914
const QStringList groups = generalGrp.readEntry("groups", QStringList());
1916
const KConfigGroup groupsGrp(&mapCfgFile, "Groups");
1918
for( QStringList::ConstIterator it = groups.begin();
1919
it != groups.end(); ++it )
1921
QByteArray grp = (*it).toUtf8();
1922
// Check if user is in this group
1923
struct group *grp_ent = getgrnam(grp);
1924
if (!grp_ent) continue;
1925
gid_t gid = grp_ent->gr_gid;
1926
if (pw->pw_gid == gid)
1928
// User is in this group --> add profiles
1929
profiles += groupsGrp.readEntry(*it, QStringList());
1933
for(int i = 0; i < sup_gids_nr; i++)
1935
if (sup_gids[i] == gid)
1937
// User is in this group --> add profiles
1938
profiles += groupsGrp.readEntry(*it, QStringList());
1945
if (profiles.isEmpty())
1946
profiles << QString::fromLatin1("default");
1950
extern bool kde_kiosk_admin;
1952
bool KStandardDirs::addCustomized(KConfig *config)
1954
if (!d->m_checkRestrictions) // there are already customized entries
1955
return false; // we just quit and hope they are the right ones
1957
// save the numbers of config directories. If this changes,
1958
// we will return true to give KConfig a chance to reparse
1959
int configdirs = resourceDirs("config").count();
1963
// reading the prefixes in
1964
QString group = QLatin1String("Directories");
1965
KConfigGroup cg(config, group);
1967
QString kioskAdmin = cg.readEntry("kioskAdmin");
1968
if (!kioskAdmin.isEmpty() && !kde_kiosk_admin)
1970
int i = kioskAdmin.indexOf(QLatin1Char(':'));
1971
QString user = kioskAdmin.left(i);
1972
QString host = kioskAdmin.mid(i+1);
1975
char hostname[ 256 ];
1976
hostname[ 0 ] = '\0';
1977
if (!gethostname( hostname, 255 ))
1978
hostname[sizeof(hostname)-1] = '\0';
1980
if ((user == thisUser.loginName()) &&
1981
(host.isEmpty() || (host == QLatin1String(hostname))))
1983
kde_kiosk_admin = true;
1987
bool readProfiles = true;
1989
if (kde_kiosk_admin && !qgetenv("KDE_KIOSK_NO_PROFILES").isEmpty())
1990
readProfiles = false;
1992
QString userMapFile = cg.readEntry("userProfileMapFile");
1993
QString profileDirsPrefix = cg.readEntry("profileDirsPrefix");
1994
if (!profileDirsPrefix.isEmpty() && !profileDirsPrefix.endsWith(QLatin1Char('/')))
1995
profileDirsPrefix.append(QLatin1Char('/'));
1997
QStringList profiles;
1999
profiles = lookupProfiles(userMapFile);
2002
bool priority = false;
2005
KConfigGroup cg(config, group);
2006
const QStringList list = cg.readEntry("prefixes", QStringList());
2007
for (QStringList::ConstIterator it = list.begin(); it != list.end(); ++it)
2009
addPrefix(*it, priority);
2010
addXdgConfigPrefix(*it + QLatin1String("/etc/xdg"), priority);
2011
addXdgDataPrefix(*it + QLatin1String("/share"), priority);
2013
// If there are no prefixes defined, check if there is a directory
2014
// for this profile under <profileDirsPrefix>
2015
if (list.isEmpty() && !profile.isEmpty() && !profileDirsPrefix.isEmpty())
2017
QString dir = profileDirsPrefix + profile;
2018
addPrefix(dir, priority);
2019
addXdgConfigPrefix(dir + QLatin1String("/etc/xdg"), priority);
2020
addXdgDataPrefix(dir + QLatin1String("/share"), priority);
2023
// iterating over all entries in the group Directories
2024
// to find entries that start with dir_$type
2025
const QMap<QString, QString> entries = config->entryMap(group);
2026
for (QMap<QString, QString>::ConstIterator it2 = entries.begin();
2027
it2 != entries.end(); ++it2)
2029
const QString key = it2.key();
2030
if (key.startsWith(QLatin1String("dir_"))) {
2031
// generate directory list, there may be more than 1.
2032
QStringList dirs = (*it2).split(QString(QLatin1Char(',')));
2033
QStringList::Iterator sIt(dirs.begin());
2034
QString resType = key.mid(4);
2035
for (; sIt != dirs.end(); ++sIt)
2037
addResourceDir(resType.toLatin1(), *sIt, priority);
2041
if (profiles.isEmpty())
2043
profile = profiles.back();
2044
group = QString::fromLatin1("Directories-%1").arg(profile);
2045
profiles.pop_back();
2050
// Process KIOSK restrictions.
2051
if (!kde_kiosk_admin || qgetenv("KDE_KIOSK_NO_RESTRICTIONS").isEmpty())
2053
KConfigGroup cg(config, "KDE Resource Restrictions");
2054
const QMap<QString, QString> entries = cg.entryMap();
2055
for (QMap<QString, QString>::ConstIterator it2 = entries.begin();
2056
it2 != entries.end(); ++it2)
2058
const QString key = it2.key();
2059
if (!cg.readEntry(key, true))
2061
d->m_restrictionsActive = true;
2062
const QByteArray cKey = key.toLatin1();
2063
d->m_restrictions.insert(cKey, true);
2064
d->m_dircache.remove(cKey);
2065
d->m_savelocations.remove(cKey);
2070
// check if the number of config dirs changed
2071
bool configDirsChanged = (resourceDirs("config").count() != configdirs);
2072
// If the config dirs changed, we check kiosk restrictions again.
2073
d->m_checkRestrictions = configDirsChanged;
2074
// return true if the number of config dirs changed: reparse config file
2075
return configDirsChanged;
2078
QString KStandardDirs::localkdedir() const
2080
// Return the prefix to use for saving
2081
return d->m_prefixes.first();
2084
QString KStandardDirs::localxdgdatadir() const
2086
// Return the prefix to use for saving
2087
return d->xdgdata_prefixes.first();
2090
QString KStandardDirs::localxdgconfdir() const
2092
// Return the prefix to use for saving
2093
return d->xdgconf_prefixes.first();
2097
// just to make code more readable without macros
2098
QString KStandardDirs::locate( const char *type,
2099
const QString& filename, const KComponentData &cData)
2101
return cData.dirs()->findResource(type, filename);
2104
QString KStandardDirs::locateLocal( const char *type,
2105
const QString& filename, const KComponentData &cData)
2107
return locateLocal(type, filename, true, cData);
2110
QString KStandardDirs::locateLocal( const char *type,
2111
const QString& filename, bool createDir,
2112
const KComponentData &cData)
2114
// try to find slashes. If there are some, we have to
2115
// create the subdir first
2116
int slash = filename.lastIndexOf(QLatin1Char('/')) + 1;
2117
if (!slash) { // only one filename
2118
return cData.dirs()->saveLocation(type, QString(), createDir) + filename;
2121
// split path from filename
2122
QString dir = filename.left(slash);
2123
QString file = filename.mid(slash);
2124
return cData.dirs()->saveLocation(type, dir, createDir) + file;
2127
bool KStandardDirs::checkAccess(const QString& pathname, int mode)
2129
int accessOK = KDE::access( pathname, mode );
2130
if ( accessOK == 0 )
2131
return true; // OK, I can really access the file
2134
// if we want to write the file would be created. Check, if the
2135
// user may write to the directory to create the file.
2136
if ( (mode & W_OK) == 0 )
2137
return false; // Check for write access is not part of mode => bail out
2140
if (!KDE::access( pathname, F_OK)) // if it already exists
2143
//strip the filename (everything until '/' from the end
2144
QString dirName(pathname);
2145
int pos = dirName.lastIndexOf(QLatin1Char('/'));
2147
return false; // No path in argument. This is evil, we won't allow this
2148
else if ( pos == 0 ) // don't turn e.g. /root into an empty string
2151
dirName.truncate(pos); // strip everything starting from the last '/'
2153
accessOK = KDE::access( dirName, W_OK );
2154
// -?- Can I write to the accessed diretory
2155
if ( accessOK == 0 )