00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
#include "config.h"
00028
00029
#include <stdlib.h>
00030
#include <assert.h>
00031
#include <errno.h>
00032
#ifdef HAVE_SYS_STAT_H
00033
#include <sys/stat.h>
00034
#endif
00035
#include <sys/types.h>
00036
#include <dirent.h>
00037
#include <pwd.h>
00038
#include <grp.h>
00039
00040
#include <qregexp.h>
00041
#include <qasciidict.h>
00042
#include <qdict.h>
00043
#include <qdir.h>
00044
#include <qfileinfo.h>
00045
#include <qstring.h>
00046
#include <qstringlist.h>
00047
00048
#include "kstandarddirs.h"
00049
#include "kconfig.h"
00050
#include "kdebug.h"
00051
#include "kinstance.h"
00052
#include "kshell.h"
00053
#include "ksimpleconfig.h"
00054
#include "kuser.h"
00055
#include <sys/param.h>
00056
#include <unistd.h>
00057
00058
template class QDict<QStringList>;
00059
00060
class KStandardDirs::KStandardDirsPrivate
00061 {
00062
public:
00063 KStandardDirsPrivate()
00064 : restrictionsActive(false),
00065 dataRestrictionActive(false)
00066 { }
00067
00068
bool restrictionsActive;
00069
bool dataRestrictionActive;
00070
QAsciiDict<bool> restrictions;
00071
QStringList xdgdata_prefixes;
00072
QStringList xdgconf_prefixes;
00073 };
00074
00075
static const char*
const types[] = {
"html",
"icon",
"apps",
"sound",
00076
"data",
"locale",
"services",
"mime",
00077
"servicetypes",
"config",
"exe",
00078
"wallpaper",
"lib",
"pixmap",
"templates",
00079
"module",
"qtplugins",
00080
"xdgdata-apps",
"xdgdata-dirs",
"xdgconf-menu",
00081
"kcfg", 0 };
00082
00083
#if defined(__x86_64__) || defined(__s390x__) || defined(__powerpc64__) || defined(__sparc64__)
00084
# define LIBDIR_NAME "lib64"
00085
#else
00086
# define LIBDIR_NAME "lib"
00087
#endif
00088
00089
static int tokenize(
QStringList& token,
const QString& str,
00090
const QString& delim );
00091
00092 KStandardDirs::KStandardDirs( ) : addedCustoms(false)
00093 {
00094 d =
new KStandardDirsPrivate;
00095 dircache.setAutoDelete(
true);
00096 relatives.setAutoDelete(
true);
00097 absolutes.setAutoDelete(
true);
00098 savelocations.setAutoDelete(
true);
00099
addKDEDefaults();
00100 }
00101
00102 KStandardDirs::~KStandardDirs()
00103 {
00104
delete d;
00105 }
00106
00107 bool KStandardDirs::isRestrictedResource(
const char *type,
const QString& relPath)
const
00108
{
00109
if (!d || !d->restrictionsActive)
00110
return false;
00111
00112
if (d->restrictions[type])
00113
return true;
00114
00115
if (strcmp(type,
"data")==0)
00116 {
00117 applyDataRestrictions(relPath);
00118
if (d->dataRestrictionActive)
00119 {
00120 d->dataRestrictionActive =
false;
00121
return true;
00122 }
00123 }
00124
return false;
00125 }
00126
00127
void KStandardDirs::applyDataRestrictions(
const QString &relPath)
const
00128
{
00129
QString key;
00130
int i = relPath.find(
'/');
00131
if (i != -1)
00132 key =
"data_"+relPath.left(i);
00133
else
00134 key =
"data_"+relPath;
00135
00136
if (d && d->restrictions[key.latin1()])
00137 d->dataRestrictionActive =
true;
00138 }
00139
00140
00141 QStringList KStandardDirs::allTypes()
const
00142
{
00143
QStringList list;
00144
for (
int i = 0; types[i] != 0; ++i)
00145 list.append(QString::fromLatin1(types[i]));
00146
return list;
00147 }
00148
00149
static void priorityAdd(
QStringList &prefixes,
const QString& dir,
bool priority)
00150 {
00151
if (priority && !prefixes.isEmpty())
00152 {
00153
00154 QStringList::iterator it = prefixes.begin();
00155 it++;
00156 prefixes.insert(it, 1, dir);
00157 }
00158
else
00159 {
00160 prefixes.append(dir);
00161 }
00162 }
00163
00164 void KStandardDirs::addPrefix(
const QString& _dir )
00165 {
00166
addPrefix(_dir,
false);
00167 }
00168
00169
void KStandardDirs::addPrefix(
const QString& _dir,
bool priority )
00170 {
00171
if (_dir.isEmpty())
00172
return;
00173
00174
QString dir = _dir;
00175
if (dir.at(dir.length() - 1) !=
'/')
00176 dir +=
'/';
00177
00178
if (!prefixes.contains(dir)) {
00179 priorityAdd(prefixes, dir, priority);
00180 dircache.clear();
00181 }
00182 }
00183
00184 void KStandardDirs::addXdgConfigPrefix(
const QString& _dir )
00185 {
00186
addXdgConfigPrefix(_dir,
false);
00187 }
00188
00189
void KStandardDirs::addXdgConfigPrefix(
const QString& _dir,
bool priority )
00190 {
00191
if (_dir.isEmpty())
00192
return;
00193
00194
QString dir = _dir;
00195
if (dir.at(dir.length() - 1) !=
'/')
00196 dir +=
'/';
00197
00198
if (!d->xdgconf_prefixes.contains(dir)) {
00199 priorityAdd(d->xdgconf_prefixes, dir, priority);
00200 dircache.clear();
00201 }
00202 }
00203
00204 void KStandardDirs::addXdgDataPrefix(
const QString& _dir )
00205 {
00206
addXdgDataPrefix(_dir,
false);
00207 }
00208
00209
void KStandardDirs::addXdgDataPrefix(
const QString& _dir,
bool priority )
00210 {
00211
if (_dir.isEmpty())
00212
return;
00213
00214
QString dir = _dir;
00215
if (dir.at(dir.length() - 1) !=
'/')
00216 dir +=
'/';
00217
00218
if (!d->xdgdata_prefixes.contains(dir)) {
00219 priorityAdd(d->xdgdata_prefixes, dir, priority);
00220 dircache.clear();
00221 }
00222 }
00223
00224
QString KStandardDirs::kfsstnd_prefixes()
00225 {
00226
return prefixes.join(
":");
00227 }
00228
00229 bool KStandardDirs::addResourceType(
const char *type,
00230
const QString& relativename )
00231 {
00232
return addResourceType(type, relativename,
true);
00233 }
00234
bool KStandardDirs::addResourceType(
const char *type,
00235
const QString& relativename,
00236
bool priority )
00237 {
00238
if (relativename.isEmpty())
00239
return false;
00240
00241
QStringList *rels = relatives.find(type);
00242
if (!rels) {
00243 rels =
new QStringList();
00244 relatives.insert(type, rels);
00245 }
00246
QString copy = relativename;
00247
if (
copy.at(
copy.length() - 1) !=
'/')
00248
copy +=
'/';
00249
if (!rels->contains(copy)) {
00250
if (priority)
00251 rels->prepend(copy);
00252
else
00253 rels->append(copy);
00254 dircache.remove(type);
00255
return true;
00256 }
00257
return false;
00258 }
00259
00260 bool KStandardDirs::addResourceDir(
const char *type,
00261
const QString& absdir)
00262 {
00263
00264
return addResourceDir(type, absdir,
false);
00265 }
00266
00267
bool KStandardDirs::addResourceDir(
const char *type,
00268
const QString& absdir,
00269
bool priority)
00270 {
00271
QStringList *paths = absolutes.find(type);
00272
if (!paths) {
00273 paths =
new QStringList();
00274 absolutes.insert(type, paths);
00275 }
00276
QString copy = absdir;
00277
if (
copy.at(
copy.length() - 1) !=
'/')
00278
copy +=
'/';
00279
00280
if (!paths->contains(copy)) {
00281
if (priority)
00282 paths->prepend(copy);
00283
else
00284 paths->append(copy);
00285 dircache.remove(type);
00286
return true;
00287 }
00288
return false;
00289 }
00290
00291 QString KStandardDirs::findResource(
const char *type,
00292
const QString& filename )
const
00293
{
00294
if (filename.at(0) ==
'/')
00295
return filename;
00296
00297
#if 0
00298
kdDebug() <<
"Find resource: " << type <<
endl;
00299
for (QStringList::ConstIterator pit = prefixes.begin();
00300 pit != prefixes.end();
00301 pit++)
00302 {
00303 kdDebug() <<
"Prefix: " << *pit <<
endl;
00304 }
00305
#endif
00306
00307
QString dir =
findResourceDir(type, filename);
00308
if (dir.isEmpty())
00309
return dir;
00310
else return dir + filename;
00311 }
00312
00313
static Q_UINT32 updateHash(
const QString &file, Q_UINT32 hash)
00314 {
00315
QCString cFile = QFile::encodeName(file);
00316
struct stat buff;
00317
if ((access(cFile, R_OK) == 0) &&
00318 (stat( cFile, &buff ) == 0) &&
00319 (S_ISREG( buff.st_mode )))
00320 {
00321 hash = hash + (Q_UINT32) buff.st_ctime;
00322 }
00323
return hash;
00324 }
00325
00326 Q_UINT32
KStandardDirs::calcResourceHash(
const char *type,
00327
const QString& filename,
bool deep)
const
00328
{
00329 Q_UINT32 hash = 0;
00330
00331
if (filename.at(0) ==
'/')
00332 {
00333
00334
return updateHash(filename, hash);
00335 }
00336
if (d && d->restrictionsActive && (strcmp(type,
"data")==0))
00337 applyDataRestrictions(filename);
00338
QStringList candidates =
resourceDirs(type);
00339
QString fullPath;
00340
00341
for (QStringList::ConstIterator it = candidates.begin();
00342 it != candidates.end(); it++)
00343 {
00344 hash = updateHash(*it + filename, hash);
00345
if (!deep && hash)
00346
return hash;
00347 }
00348
return hash;
00349 }
00350
00351
00352 QStringList KStandardDirs::findDirs(
const char *type,
00353
const QString& reldir )
const
00354
{
00355
QDir testdir;
00356
QStringList list;
00357
if (reldir.startsWith(
"/"))
00358 {
00359 testdir.setPath(reldir);
00360
if (testdir.exists())
00361 {
00362
if (reldir.endsWith(
"/"))
00363 list.append(reldir);
00364
else
00365 list.append(reldir+
'/');
00366 }
00367
return list;
00368 }
00369
00370 checkConfig();
00371
00372
if (d && d->restrictionsActive && (strcmp(type,
"data")==0))
00373 applyDataRestrictions(reldir);
00374
QStringList candidates =
resourceDirs(type);
00375
00376
for (QStringList::ConstIterator it = candidates.begin();
00377 it != candidates.end(); it++) {
00378 testdir.setPath(*it + reldir);
00379
if (testdir.exists())
00380 list.append(testdir.absPath() +
'/');
00381 }
00382
00383
return list;
00384 }
00385
00386 QString KStandardDirs::findResourceDir(
const char *type,
00387
const QString& filename)
const
00388
{
00389
#ifndef NDEBUG
00390
if (filename.isEmpty()) {
00391 kdWarning() <<
"filename for type " << type <<
" in KStandardDirs::findResourceDir is not supposed to be empty!!" <<
endl;
00392
return QString::null;
00393 }
00394
#endif
00395
00396
if (d && d->restrictionsActive && (strcmp(type,
"data")==0))
00397 applyDataRestrictions(filename);
00398
QStringList candidates =
resourceDirs(type);
00399
QString fullPath;
00400
00401
for (QStringList::ConstIterator it = candidates.begin();
00402 it != candidates.end(); it++)
00403
if (
exists(*it + filename))
00404
return *it;
00405
00406
#ifndef NDEBUG
00407
if(
false && type !=
"locale")
00408 kdDebug() <<
"KStdDirs::findResDir(): can't find \"" << filename <<
"\" in type \"" << type <<
"\"." <<
endl;
00409
#endif
00410
00411
return QString::null;
00412 }
00413
00414 bool KStandardDirs::exists(
const QString &fullPath)
00415 {
00416
struct stat buff;
00417
if (access(QFile::encodeName(fullPath), R_OK) == 0 && stat( QFile::encodeName(fullPath), &buff ) == 0)
00418
if (fullPath.at(fullPath.length() - 1) !=
'/') {
00419
if (S_ISREG( buff.st_mode ))
00420
return true;
00421 }
else
00422
if (S_ISDIR( buff.st_mode ))
00423
return true;
00424
return false;
00425 }
00426
00427
static void lookupDirectory(
const QString& path,
const QString &relPart,
00428
const QRegExp ®exp,
00429
QStringList& list,
00430
QStringList& relList,
00431
bool recursive,
bool unique)
00432 {
00433
QString pattern = regexp.pattern();
00434
if (recursive || pattern.contains(
'?') || pattern.contains(
'*'))
00435 {
00436
00437 DIR *dp = opendir( QFile::encodeName(path));
00438
if (!dp)
00439
return;
00440
00441 assert(path.at(path.length() - 1) ==
'/');
00442
00443
struct dirent *ep;
00444
struct stat buff;
00445
00446
QString _dot(
".");
00447
QString _dotdot(
"..");
00448
00449
while( ( ep = readdir( dp ) ) != 0L )
00450 {
00451
QString fn( QFile::decodeName(ep->d_name));
00452
if (fn == _dot || fn == _dotdot || fn.at(fn.length() - 1).latin1() ==
'~')
00453
continue;
00454
00455
if (!recursive && !regexp.exactMatch(fn))
00456
continue;
00457
00458
QString pathfn = path + fn;
00459
if ( stat( QFile::encodeName(pathfn), &buff ) != 0 ) {
00460 kdDebug() <<
"Error stat'ing " << pathfn <<
" : " << perror <<
endl;
00461
continue;
00462 }
00463
if ( recursive ) {
00464
if ( S_ISDIR( buff.st_mode )) {
00465 lookupDirectory(pathfn +
'/', relPart + fn +
'/', regexp, list, relList, recursive, unique);
00466 }
00467
if (!regexp.exactMatch(fn))
00468
continue;
00469 }
00470
if ( S_ISREG( buff.st_mode))
00471 {
00472
if (!unique || !relList.contains(relPart + fn))
00473 {
00474 list.append( pathfn );
00475 relList.append( relPart + fn );
00476 }
00477 }
00478 }
00479 closedir( dp );
00480 }
00481
else
00482 {
00483
00484
QString fn = pattern;
00485
QString pathfn = path + fn;
00486
struct stat buff;
00487
if (
stat( QFile::encodeName(pathfn), &buff ) != 0 )
00488
return;
00489
if ( S_ISREG( buff.st_mode))
00490 {
00491
if (!unique || !relList.contains(relPart + fn))
00492 {
00493 list.append( pathfn );
00494 relList.append( relPart + fn );
00495 }
00496 }
00497 }
00498 }
00499
00500
static void lookupPrefix(
const QString& prefix,
const QString& relpath,
00501
const QString& relPart,
00502
const QRegExp ®exp,
00503
QStringList& list,
00504
QStringList& relList,
00505
bool recursive,
bool unique)
00506 {
00507
if (relpath.isEmpty()) {
00508 lookupDirectory(prefix, relPart, regexp, list,
00509 relList, recursive, unique);
00510
return;
00511 }
00512
QString path;
00513
QString rest;
00514
00515
if (relpath.length())
00516 {
00517
int slash = relpath.find(
'/');
00518
if (slash < 0)
00519 rest = relpath.left(relpath.length() - 1);
00520
else {
00521 path = relpath.left(slash);
00522 rest = relpath.mid(slash + 1);
00523 }
00524 }
00525
00526 assert(prefix.at(prefix.length() - 1) ==
'/');
00527
00528
struct stat buff;
00529
00530
if (path.contains(
'*') || path.contains(
'?')) {
00531
00532
QRegExp pathExp(path,
true,
true);
00533 DIR *dp = opendir( QFile::encodeName(prefix) );
00534
if (!dp) {
00535
return;
00536 }
00537
00538
struct dirent *ep;
00539
00540
QString _dot(
".");
00541
QString _dotdot(
"..");
00542
00543
while( ( ep = readdir( dp ) ) != 0L )
00544 {
00545
QString fn( QFile::decodeName(ep->d_name));
00546
if (fn == _dot || fn == _dotdot || fn.at(fn.length() - 1) ==
'~')
00547
continue;
00548
00549
if ( !pathExp.exactMatch(fn) )
00550
continue;
00551
QString rfn = relPart+fn;
00552 fn = prefix + fn;
00553
if (
stat( QFile::encodeName(fn), &buff ) != 0 ) {
00554 kdDebug() <<
"Error statting " << fn <<
" : " << perror <<
endl;
00555
continue;
00556 }
00557
if ( S_ISDIR( buff.st_mode ))
00558 lookupPrefix(fn +
'/', rest, rfn +
'/', regexp, list, relList, recursive, unique);
00559 }
00560
00561 closedir( dp );
00562 }
else {
00563
00564
00565 lookupPrefix(prefix + path +
'/', rest,
00566 relPart + path +
'/', regexp, list,
00567 relList, recursive, unique);
00568 }
00569 }
00570
00571
QStringList
00572 KStandardDirs::findAllResources(
const char *type,
00573
const QString& filter,
00574
bool recursive,
00575
bool unique,
00576
QStringList &relList)
const
00577
{
00578
QStringList list;
00579
QString filterPath;
00580
QString filterFile;
00581
00582
if (filter.length())
00583 {
00584
int slash = filter.findRev(
'/');
00585
if (slash < 0)
00586 filterFile = filter;
00587
else {
00588 filterPath = filter.left(slash + 1);
00589 filterFile = filter.mid(slash + 1);
00590 }
00591 }
00592
00593 checkConfig();
00594
00595
QStringList candidates;
00596
if (filterPath.startsWith(
"/"))
00597 {
00598 filterPath = filterPath.mid(1);
00599 candidates <<
"/";
00600 }
00601
else
00602 {
00603
if (d && d->restrictionsActive && (strcmp(type,
"data")==0))
00604 applyDataRestrictions(filter);
00605 candidates =
resourceDirs(type);
00606 }
00607
if (filterFile.isEmpty())
00608 filterFile =
"*";
00609
00610
QRegExp regExp(filterFile,
true,
true);
00611
00612
for (QStringList::ConstIterator it = candidates.begin();
00613 it != candidates.end(); it++)
00614 {
00615 lookupPrefix(*it, filterPath,
"", regExp, list,
00616 relList, recursive, unique);
00617 }
00618
00619
return list;
00620 }
00621
00622
QStringList
00623 KStandardDirs::findAllResources(
const char *type,
00624
const QString& filter,
00625
bool recursive,
00626
bool unique)
const
00627
{
00628
QStringList relList;
00629
return findAllResources(type, filter, recursive, unique, relList);
00630 }
00631
00632
QString
00633 KStandardDirs::realPath(
const QString &dirname)
00634 {
00635
char realpath_buffer[MAXPATHLEN + 1];
00636 memset(realpath_buffer, 0, MAXPATHLEN + 1);
00637
00638
00639
if (realpath( QFile::encodeName(dirname).data(), realpath_buffer) != 0) {
00640
00641
int len = strlen(realpath_buffer);
00642 realpath_buffer[len] =
'/';
00643 realpath_buffer[len+1] = 0;
00644
return QFile::decodeName(realpath_buffer);
00645 }
00646
00647
return dirname;
00648 }
00649
00650
void KStandardDirs::createSpecialResource(
const char *type)
00651 {
00652
char hostname[256];
00653 hostname[0] = 0;
00654 gethostname(hostname, 255);
00655
QString dir =
QString(
"%1%2-%3").arg(
localkdedir()).arg(type).arg(hostname);
00656
char link[1024];
00657 link[1023] = 0;
00658
int result = readlink(QFile::encodeName(dir).data(), link, 1023);
00659
bool relink = (result == -1) && (errno == ENOENT);
00660
if ((result > 0) && (link[0] ==
'/'))
00661 {
00662 link[result] = 0;
00663
struct stat stat_buf;
00664
int res = lstat(link, &stat_buf);
00665
if ((res == -1) && (errno == ENOENT))
00666 {
00667 relink =
true;
00668 }
00669
else if ((res == -1) || (!S_ISDIR(stat_buf.st_mode)))
00670 {
00671 fprintf(stderr,
"Error: \"%s\" is not a directory.\n", link);
00672 relink =
true;
00673 }
00674
else if (stat_buf.st_uid != getuid())
00675 {
00676 fprintf(stderr,
"Error: \"%s\" is owned by uid %d instead of uid %d.\n", link, stat_buf.st_uid, getuid());
00677 relink =
true;
00678 }
00679 }
00680
if (relink)
00681 {
00682
QString srv =
findExe(QString::fromLatin1(
"lnusertemp"), KDEDIR+QString::fromLatin1(
"/bin"));
00683
if (srv.isEmpty())
00684 srv =
findExe(QString::fromLatin1(
"lnusertemp"));
00685
if (!srv.isEmpty())
00686 {
00687 system(QFile::encodeName(srv)+
" "+type);
00688 result = readlink(QFile::encodeName(dir).data(), link, 1023);
00689 }
00690 }
00691
if (result > 0)
00692 {
00693
link[result] = 0;
00694
if (
link[0] ==
'/')
00695 dir = QFile::decodeName(link);
00696
else
00697 dir = QDir::cleanDirPath(dir+QFile::decodeName(link));
00698 }
00699
addResourceDir(type, dir+
'/');
00700 }
00701
00702 QStringList KStandardDirs::resourceDirs(
const char *type)
const
00703
{
00704
QStringList *candidates = dircache.find(type);
00705
00706
if (!candidates) {
00707
if (strcmp(type,
"socket") == 0)
00708 const_cast<KStandardDirs *>(
this)->createSpecialResource(type);
00709
else if (strcmp(type,
"tmp") == 0)
00710 const_cast<KStandardDirs *>(
this)->createSpecialResource(type);
00711
else if (strcmp(type,
"cache") == 0)
00712 const_cast<KStandardDirs *>(
this)->createSpecialResource(type);
00713
00714
QDir testdir;
00715
00716 candidates =
new QStringList();
00717 QStringList *dirs;
00718
00719
bool restrictionActive =
false;
00720
if (d && d->restrictionsActive)
00721 {
00722
if (d->dataRestrictionActive)
00723 restrictionActive =
true;
00724
else if (d->restrictions[
"all"])
00725 restrictionActive =
true;
00726
else if (d->restrictions[type])
00727 restrictionActive =
true;
00728 d->dataRestrictionActive =
false;
00729 }
00730
00731 dirs = relatives.find(type);
00732
if (dirs)
00733 {
00734
bool local =
true;
00735
const QStringList *prefixList = 0;
00736
if (strncmp(type,
"xdgdata-", 8) == 0)
00737 prefixList = &(d->xdgdata_prefixes);
00738
else if (strncmp(type,
"xdgconf-", 8) == 0)
00739 prefixList = &(d->xdgconf_prefixes);
00740
else
00741 prefixList = &prefixes;
00742
00743
for (QStringList::ConstIterator pit = prefixList->begin();
00744 pit != prefixList->end();
00745 pit++)
00746 {
00747
for (QStringList::ConstIterator it = dirs->begin();
00748 it != dirs->end(); ++it) {
00749
QString path =
realPath(*pit + *it);
00750 testdir.setPath(path);
00751
if (local && restrictionActive)
00752
continue;
00753
if ((local || testdir.exists()) && !candidates->contains(path))
00754 candidates->append(path);
00755 }
00756 local =
false;
00757 }
00758 }
00759 dirs = absolutes.find(type);
00760
if (dirs)
00761
for (QStringList::ConstIterator it = dirs->begin();
00762 it != dirs->end(); ++it)
00763 {
00764 testdir.setPath(*it);
00765
if (testdir.exists())
00766 {
00767
QString filename =
realPath(*it);
00768
if (!candidates->contains(filename))
00769 candidates->append(filename);
00770 }
00771 }
00772 dircache.insert(type, candidates);
00773 }
00774
00775
#if 0
00776
kdDebug() <<
"found dirs for resource " << type <<
":" <<
endl;
00777
for (QStringList::ConstIterator pit = candidates->begin();
00778 pit != candidates->end();
00779 pit++)
00780 {
00781 fprintf(stderr,
"%s\n", (*pit).latin1());
00782 }
00783
#endif
00784
00785
00786
return *candidates;
00787 }
00788
00789 QStringList KStandardDirs::systemPaths(
const QString& pstr )
00790 {
00791
QStringList tokens;
00792
QString p = pstr;
00793
00794
if( p.isNull() )
00795 {
00796 p = getenv(
"PATH" );
00797 }
00798
00799 tokenize( tokens, p,
":\b" );
00800
00801
QStringList exePaths;
00802
00803
00804
for(
unsigned i = 0; i < tokens.count(); i++ )
00805 {
00806 p = tokens[ i ];
00807
00808
if ( p[ 0 ] ==
'~' )
00809 {
00810
int len = p.find(
'/' );
00811
if ( len == -1 )
00812 len = p.length();
00813
if ( len == 1 )
00814 {
00815 p.replace( 0, 1, QDir::homeDirPath() );
00816 }
00817
else
00818 {
00819
QString user = p.mid( 1, len - 1 );
00820
struct passwd *dir = getpwnam( user.local8Bit().data() );
00821
if ( dir && strlen( dir->pw_dir ) )
00822 p.replace( 0, len, QString::fromLocal8Bit( dir->pw_dir ) );
00823 }
00824 }
00825
00826 exePaths << p;
00827 }
00828
00829
return exePaths;
00830 }
00831
00832
00833 QString KStandardDirs::findExe(
const QString& appname,
00834
const QString& pstr,
bool ignore)
00835 {
00836
QFileInfo info;
00837
00838
00839
if (appname.startsWith(QString::fromLatin1(
"/")))
00840 {
00841 info.setFile( appname );
00842
if( info.exists() && ( ignore || info.isExecutable() )
00843 && info.isFile() ) {
00844
return appname;
00845 }
00846
return QString::null;
00847 }
00848
00849
QString p =
QString(
"%1/%2").arg(__KDE_BINDIR).arg(appname);
00850 info.setFile( p );
00851
if( info.exists() && ( ignore || info.isExecutable() )
00852 && ( info.isFile() || info.isSymLink() ) ) {
00853
return p;
00854 }
00855
00856
QStringList exePaths =
systemPaths( pstr );
00857
for (QStringList::ConstIterator it = exePaths.begin(); it != exePaths.end(); it++)
00858 {
00859 p = (*it) +
"/";
00860 p += appname;
00861
00862
00863 info.setFile( p );
00864
00865
if( info.exists() && ( ignore || info.isExecutable() )
00866 && ( info.isFile() || info.isSymLink() ) ) {
00867
return p;
00868 }
00869 }
00870
00871
00872
00873
00874
return QString::null;
00875 }
00876
00877 int KStandardDirs::findAllExe(
QStringList& list,
const QString& appname,
00878
const QString& pstr,
bool ignore )
00879 {
00880
QFileInfo info;
00881
QString p;
00882 list.clear();
00883
00884
QStringList exePaths =
systemPaths( pstr );
00885
for (QStringList::ConstIterator it = exePaths.begin(); it != exePaths.end(); it++)
00886 {
00887 p = (*it) +
"/";
00888 p += appname;
00889
00890 info.setFile( p );
00891
00892
if( info.exists() && (ignore || info.isExecutable())
00893 && info.isFile() ) {
00894 list.append( p );
00895 }
00896 }
00897
00898
return list.count();
00899 }
00900
00901
static int tokenize(
QStringList& tokens,
const QString& str,
00902
const QString& delim )
00903 {
00904
int len = str.length();
00905
QString token =
"";
00906
00907
for(
int index = 0; index < len; index++)
00908 {
00909
if ( delim.find( str[ index ] ) >= 0 )
00910 {
00911 tokens.append( token );
00912 token =
"";
00913 }
00914
else
00915 {
00916 token += str[ index ];
00917 }
00918 }
00919
if ( token.length() > 0 )
00920 {
00921 tokens.append( token );
00922 }
00923
00924
return tokens.count();
00925 }
00926
00927 QString KStandardDirs::kde_default(
const char *type) {
00928
if (!strcmp(type,
"data"))
00929
return "share/apps/";
00930
if (!strcmp(type,
"html"))
00931
return "share/doc/HTML/";
00932
if (!strcmp(type,
"icon"))
00933
return "share/icons/";
00934
if (!strcmp(type,
"config"))
00935
return "share/config/";
00936
if (!strcmp(type,
"pixmap"))
00937
return "share/pixmaps/";
00938
if (!strcmp(type,
"apps"))
00939
return "share/applnk/";
00940
if (!strcmp(type,
"sound"))
00941
return "share/sounds/";
00942
if (!strcmp(type,
"locale"))
00943
return "share/locale/";
00944
if (!strcmp(type,
"services"))
00945
return "share/services/";
00946
if (!strcmp(type,
"servicetypes"))
00947
return "share/servicetypes/";
00948
if (!strcmp(type,
"mime"))
00949
return "share/mimelnk/";
00950
if (!strcmp(type,
"cgi"))
00951
return "cgi-bin/";
00952
if (!strcmp(type,
"wallpaper"))
00953
return "share/wallpapers/";
00954
if (!strcmp(type,
"templates"))
00955
return "share/templates/";
00956
if (!strcmp(type,
"exe"))
00957
return "bin/";
00958
if (!strcmp(type,
"lib"))
00959
return LIBDIR_NAME
"/";
00960
if (!strcmp(type,
"module"))
00961
return LIBDIR_NAME
"/kde3/";
00962
if (!strcmp(type,
"qtplugins"))
00963
return LIBDIR_NAME
"/kde3/plugins";
00964
if (!strcmp(type,
"xdgdata-apps"))
00965
return "applications/";
00966
if (!strcmp(type,
"xdgdata-dirs"))
00967
return "desktop-directories/";
00968
if (!strcmp(type,
"xdgconf-menu"))
00969
return "menus/";
00970
if (!strcmp(type,
"kcfg"))
00971
return "share/config.kcfg";
00972 qFatal(
"unknown resource type %s", type);
00973
return QString::null;
00974 }
00975
00976 QString KStandardDirs::saveLocation(
const char *type,
00977
const QString& suffix,
00978
bool create)
const
00979
{
00980 checkConfig();
00981
00982
QString *pPath = savelocations.find(type);
00983
if (!pPath)
00984 {
00985
QStringList *dirs = relatives.find(type);
00986
if (!dirs && (
00987 (strcmp(type,
"socket") == 0) ||
00988 (strcmp(type,
"tmp") == 0) ||
00989 (strcmp(type,
"cache") == 0) ))
00990 {
00991 (
void)
resourceDirs(type);
00992 dirs = relatives.find(type);
00993 }
00994
if (dirs)
00995 {
00996
00997
if (strncmp(type,
"xdgdata-", 8) == 0)
00998 pPath =
new QString(
realPath(
localxdgdatadir() + dirs->last()));
00999
else if (strncmp(type,
"xdgconf-", 8) == 0)
01000 pPath =
new QString(
realPath(
localxdgconfdir() + dirs->last()));
01001
else
01002 pPath =
new QString(
realPath(
localkdedir() + dirs->last()));
01003 }
01004
else {
01005 dirs = absolutes.find(type);
01006
if (!dirs)
01007 qFatal(
"KStandardDirs: The resource type %s is not registered", type);
01008 pPath =
new QString(
realPath(dirs->last()));
01009 }
01010
01011 savelocations.insert(type, pPath);
01012 }
01013
QString fullPath = *pPath + suffix;
01014
01015
struct stat st;
01016
if (stat(QFile::encodeName(fullPath), &st) != 0 || !(S_ISDIR(st.st_mode))) {
01017
if(!create) {
01018
#ifndef NDEBUG
01019
qDebug(
"save location %s doesn't exist", fullPath.latin1());
01020
#endif
01021
return fullPath;
01022 }
01023
if(!
makeDir(fullPath, 0700)) {
01024 qWarning(
"failed to create %s", fullPath.latin1());
01025
return fullPath;
01026 }
01027 dircache.remove(type);
01028 }
01029
return fullPath;
01030 }
01031
01032 QString KStandardDirs::relativeLocation(
const char *type,
const QString &absPath)
01033 {
01034
QString fullPath = absPath;
01035
int i = absPath.findRev(
'/');
01036
if (i != -1)
01037 {
01038 fullPath =
realPath(absPath.left(i+1))+absPath.mid(i+1);
01039 }
01040
01041
QStringList candidates =
resourceDirs(type);
01042
01043
for (QStringList::ConstIterator it = candidates.begin();
01044 it != candidates.end(); it++)
01045
if (fullPath.startsWith(*it))
01046 {
01047
return fullPath.mid((*it).length());
01048 }
01049
01050
return absPath;
01051 }
01052
01053
01054 bool KStandardDirs::makeDir(
const QString& dir,
int mode)
01055 {
01056
01057
if (dir.at(0) !=
'/')
01058
return false;
01059
01060
QString target = dir;
01061 uint len = target.length();
01062
01063
01064
if (dir.at(len - 1) !=
'/')
01065 target +=
'/';
01066
01067
QString base(
"");
01068 uint i = 1;
01069
01070
while( i < len )
01071 {
01072
struct stat st;
01073
int pos = target.find(
'/', i);
01074 base += target.mid(i - 1, pos - i + 1);
01075
QCString baseEncoded = QFile::encodeName(base);
01076
01077
if (stat(baseEncoded, &st) != 0)
01078 {
01079
01080
01081
if (lstat(baseEncoded, &st) == 0)
01082 (
void)unlink(baseEncoded);
01083
01084
if ( mkdir(baseEncoded, (mode_t) mode) != 0) {
01085 perror(
"trying to create local folder");
01086
return false;
01087 }
01088 }
01089 i = pos + 1;
01090 }
01091
return true;
01092 }
01093
01094
static QString readEnvPath(
const char *env)
01095 {
01096
QCString c_path = getenv(env);
01097
if (c_path.isEmpty())
01098
return QString::null;
01099
return QFile::decodeName(c_path);
01100 }
01101
01102
#ifdef __linux__
01103
static QString executablePrefix()
01104 {
01105
char path_buffer[MAXPATHLEN + 1];
01106 path_buffer[MAXPATHLEN] = 0;
01107
int length = readlink (
"/proc/self/exe", path_buffer, MAXPATHLEN);
01108
if (length == -1)
01109
return QString::null;
01110
01111 path_buffer[length] =
'\0';
01112
01113
QString path = QFile::decodeName(path_buffer);
01114
01115
if(path.isEmpty())
01116
return QString::null;
01117
01118
int pos = path.findRev(
'/');
01119
if(pos <= 0)
01120
return QString::null;
01121 pos = path.findRev(
'/', pos - 1);
01122
if(pos <= 0)
01123
return QString::null;
01124
01125
return path.left(pos);
01126 }
01127
#endif
01128
01129 void KStandardDirs::addKDEDefaults()
01130 {
01131
QStringList kdedirList;
01132
01133
01134
QString kdedirs = readEnvPath(
"KDEDIRS");
01135
if (!kdedirs.isEmpty())
01136 {
01137 tokenize(kdedirList, kdedirs,
":");
01138 }
01139
else
01140 {
01141
QString kdedir = readEnvPath(
"KDEDIR");
01142
if (!kdedir.isEmpty())
01143 {
01144 kdedir =
KShell::tildeExpand(kdedir);
01145 kdedirList.append(kdedir);
01146 }
01147 }
01148 kdedirList.append(KDEDIR);
01149
01150
#ifdef __KDE_EXECPREFIX
01151
QString execPrefix(__KDE_EXECPREFIX);
01152
if (execPrefix!=
"NONE")
01153 kdedirList.append(execPrefix);
01154
#endif
01155
#ifdef __linux__
01156
kdedirList.append(executablePrefix());
01157
#endif
01158
01159
01160
01161
QString localKdeDir = readEnvPath(getuid() ?
"KDEHOME" :
"KDEROOTHOME");
01162
if (!localKdeDir.isEmpty())
01163 {
01164
if (localKdeDir[localKdeDir.length()-1] !=
'/')
01165 localKdeDir +=
'/';
01166 }
01167
else
01168 {
01169 localKdeDir = QDir::homeDirPath() +
"/.kde/";
01170 }
01171
01172
if (localKdeDir !=
"-/")
01173 {
01174 localKdeDir =
KShell::tildeExpand(localKdeDir);
01175
addPrefix(localKdeDir);
01176 }
01177
01178
for (QStringList::ConstIterator it = kdedirList.begin();
01179 it != kdedirList.end(); it++)
01180 {
01181
QString dir =
KShell::tildeExpand(*it);
01182
addPrefix(dir);
01183 }
01184
01185
01186
01187
QStringList xdgdirList;
01188
QString xdgdirs = readEnvPath(
"XDG_CONFIG_DIRS");
01189
if (!xdgdirs.isEmpty())
01190 {
01191 tokenize(xdgdirList, xdgdirs,
":");
01192 }
01193
else
01194 {
01195 xdgdirList.clear();
01196 xdgdirList.append(
"/etc/xdg");
01197 xdgdirList.append(KDESYSCONFDIR
"/xdg");
01198 }
01199
01200
QString localXdgDir = readEnvPath(
"XDG_CONFIG_HOME");
01201
if (!localXdgDir.isEmpty())
01202 {
01203
if (localXdgDir[localXdgDir.length()-1] !=
'/')
01204 localXdgDir +=
'/';
01205 }
01206
else
01207 {
01208 localXdgDir = QDir::homeDirPath() +
"/.config/";
01209 }
01210
01211 localXdgDir =
KShell::tildeExpand(localXdgDir);
01212
addXdgConfigPrefix(localXdgDir);
01213
01214
for (QStringList::ConstIterator it = xdgdirList.begin();
01215 it != xdgdirList.end(); it++)
01216 {
01217
QString dir =
KShell::tildeExpand(*it);
01218
addXdgConfigPrefix(dir);
01219 }
01220
01221
01222
01223 xdgdirs = readEnvPath(
"XDG_DATA_DIRS");
01224
if (!xdgdirs.isEmpty())
01225 {
01226 tokenize(xdgdirList, xdgdirs,
":");
01227 }
01228
else
01229 {
01230 xdgdirList.clear();
01231
for (QStringList::ConstIterator it = kdedirList.begin();
01232 it != kdedirList.end(); it++)
01233 {
01234
QString dir = *it;
01235
if (dir[dir.length()-1] !=
'/')
01236 dir +=
'/';
01237 xdgdirList.append(dir+
"share/");
01238 }
01239
01240 xdgdirList.append(
"/usr/local/share/");
01241 xdgdirList.append(
"/usr/share/");
01242 }
01243
01244 localXdgDir = readEnvPath(
"XDG_DATA_HOME");
01245
if (!localXdgDir.isEmpty())
01246 {
01247
if (localXdgDir[localXdgDir.length()-1] !=
'/')
01248 localXdgDir +=
'/';
01249 }
01250
else
01251 {
01252 localXdgDir = QDir::homeDirPath() +
"/.local/share/";
01253 }
01254
01255 localXdgDir =
KShell::tildeExpand(localXdgDir);
01256
addXdgDataPrefix(localXdgDir);
01257
01258
for (QStringList::ConstIterator it = xdgdirList.begin();
01259 it != xdgdirList.end(); it++)
01260 {
01261
QString dir =
KShell::tildeExpand(*it);
01262
addXdgDataPrefix(dir);
01263 }
01264
01265
01266
01267 uint index = 0;
01268
while (types[index] != 0) {
01269
addResourceType(types[index],
kde_default(types[index]));
01270 index++;
01271 }
01272
01273
addResourceDir(
"home", QDir::homeDirPath());
01274 }
01275
01276
void KStandardDirs::checkConfig()
const
01277
{
01278
if (!addedCustoms && KGlobal::_instance && KGlobal::_instance->
_config)
01279 const_cast<KStandardDirs*>(
this)->addCustomized(KGlobal::_instance->_config);
01280 }
01281
01282
static QStringList lookupProfiles(
const QString &mapFile)
01283 {
01284
QStringList profiles;
01285
01286
if (mapFile.isEmpty() || !QFile::exists(mapFile))
01287 {
01288 profiles <<
"default";
01289
return profiles;
01290 }
01291
01292
struct passwd *pw = getpwuid(geteuid());
01293
if (!pw)
01294 {
01295 profiles <<
"default";
01296
return profiles;
01297 }
01298
01299
QCString user = pw->pw_name;
01300
01301 gid_t sup_gids[512];
01302
int sup_gids_nr = getgroups(512, sup_gids);
01303
01304
KSimpleConfig mapCfg(mapFile,
true);
01305 mapCfg.setGroup(
"Users");
01306
if (mapCfg.hasKey(user.data()))
01307 {
01308 profiles = mapCfg.readListEntry(user.data());
01309
return profiles;
01310 }
01311
01312 mapCfg.setGroup(
"General");
01313
QStringList groups = mapCfg.readListEntry(
"groups");
01314
01315 mapCfg.setGroup(
"Groups");
01316
01317
for( QStringList::ConstIterator it = groups.begin();
01318 it != groups.end(); ++it )
01319 {
01320
QCString grp = (*it).utf8();
01321
01322
struct group *grp_ent = getgrnam(grp);
01323
if (!grp_ent)
continue;
01324 gid_t gid = grp_ent->gr_gid;
01325
if (pw->pw_gid == gid)
01326 {
01327
01328 profiles += mapCfg.readListEntry(*it);
01329 }
01330
else
01331 {
01332
for(
int i = 0; i < sup_gids_nr; i++)
01333 {
01334
if (sup_gids[i] == gid)
01335 {
01336
01337 profiles += mapCfg.readListEntry(*it);
01338
break;
01339 }
01340 }
01341 }
01342 }
01343
01344
if (profiles.isEmpty())
01345 profiles <<
"default";
01346
return profiles;
01347 }
01348
01349
extern bool kde_kiosk_admin;
01350
01351 bool KStandardDirs::addCustomized(
KConfig *config)
01352 {
01353
if (addedCustoms)
01354
return false;
01355
01356
01357 addedCustoms =
true;
01358
01359
01360
01361 uint configdirs =
resourceDirs(
"config").count();
01362
01363
01364
QString oldGroup = config->
group();
01365
QString group = QString::fromLatin1(
"Directories");
01366 config->
setGroup(group);
01367
01368
QString kioskAdmin = config->
readEntry(
"kioskAdmin");
01369
if (!kioskAdmin.isEmpty() && !kde_kiosk_admin)
01370 {
01371
int i = kioskAdmin.find(
':');
01372
QString user = kioskAdmin.left(i);
01373
QString host = kioskAdmin.mid(i+1);
01374
01375
KUser thisUser;
01376
char hostname[ 256 ];
01377 hostname[ 0 ] =
'\0';
01378
if (!gethostname( hostname, 255 ))
01379 hostname[
sizeof(hostname)-1] =
'\0';
01380
01381
if ((user == thisUser.
loginName()) &&
01382 (host.isEmpty() || (host == hostname)))
01383 {
01384 kde_kiosk_admin =
true;
01385 }
01386 }
01387
01388
bool readProfiles =
true;
01389
01390
if (kde_kiosk_admin && !
QCString(getenv(
"KDE_KIOSK_NO_PROFILES")).isEmpty())
01391 readProfiles =
false;
01392
01393
QString userMapFile = config->
readEntry(
"userProfileMapFile");
01394
QString profileDirsPrefix = config->
readEntry(
"profileDirsPrefix");
01395
if (!profileDirsPrefix.isEmpty() && !profileDirsPrefix.endsWith(
"/"))
01396 profileDirsPrefix.append(
'/');
01397
01398
QStringList profiles;
01399
if (readProfiles)
01400 profiles = lookupProfiles(userMapFile);
01401
QString profile;
01402
01403
bool priority =
false;
01404
while(
true)
01405 {
01406 config->
setGroup(group);
01407
QStringList list = config->
readListEntry(
"prefixes");
01408
for (QStringList::ConstIterator it = list.begin(); it != list.end(); it++)
01409 {
01410
addPrefix(*it, priority);
01411
addXdgConfigPrefix(*it+
"/etc/xdg", priority);
01412
addXdgDataPrefix(*it+
"/share", priority);
01413 }
01414
01415
01416
if (list.isEmpty() && !profile.isEmpty() && !profileDirsPrefix.isEmpty())
01417 {
01418
QString dir = profileDirsPrefix + profile;
01419
addPrefix(dir, priority);
01420
addXdgConfigPrefix(dir+
"/etc/xdg", priority);
01421
addXdgDataPrefix(dir+
"/share", priority);
01422 }
01423
01424
01425
01426
QMap<QString, QString> entries = config->
entryMap(group);
01427
for (
QMap<QString, QString>::ConstIterator it2 = entries.begin();
01428 it2 != entries.end(); it2++)
01429 {
01430
QString key = it2.key();
01431
if (key.startsWith(
"dir_")) {
01432
01433
QStringList dirs = QStringList::split(
',',
01434 *it2);
01435 QStringList::Iterator sIt(dirs.begin());
01436
QString resType = key.mid(4, key.length());
01437
for (; sIt != dirs.end(); ++sIt) {
01438
addResourceDir(resType.latin1(), *sIt, priority);
01439 }
01440 }
01441 }
01442
if (profiles.isEmpty())
01443
break;
01444 profile = profiles.back();
01445 group = QString::fromLatin1(
"Directories-%1").arg(profile);
01446 profiles.pop_back();
01447 priority =
true;
01448 }
01449
01450
01451
if (!kde_kiosk_admin ||
QCString(getenv(
"KDE_KIOSK_NO_RESTRICTIONS")).isEmpty())
01452 {
01453 config->
setGroup(
"KDE Resource Restrictions");
01454
QMap<QString, QString> entries = config->
entryMap(
"KDE Resource Restrictions");
01455
for (
QMap<QString, QString>::ConstIterator it2 = entries.begin();
01456 it2 != entries.end(); it2++)
01457 {
01458
QString key = it2.key();
01459
if (!config->
readBoolEntry(key,
true))
01460 {
01461 d->restrictionsActive =
true;
01462 d->restrictions.insert(key.latin1(), &d->restrictionsActive);
01463 dircache.remove(key.latin1());
01464 }
01465 }
01466 }
01467
01468 config->
setGroup(oldGroup);
01469
01470
01471
return (
resourceDirs(
"config").count() != configdirs);
01472 }
01473
01474 QString KStandardDirs::localkdedir()
const
01475
{
01476
01477
return prefixes.first();
01478 }
01479
01480 QString KStandardDirs::localxdgdatadir()
const
01481
{
01482
01483
return d->xdgdata_prefixes.first();
01484 }
01485
01486 QString KStandardDirs::localxdgconfdir()
const
01487
{
01488
01489
return d->xdgconf_prefixes.first();
01490 }
01491
01492
01493
01494 QString locate(
const char *type,
01495
const QString& filename,
const KInstance* inst )
01496 {
01497
return inst->
dirs()->
findResource(type, filename);
01498 }
01499
01500 QString locateLocal(
const char *type,
01501
const QString& filename,
const KInstance* inst )
01502 {
01503
return locateLocal(type, filename,
true, inst);
01504 }
01505
01506 QString locateLocal(
const char *type,
01507
const QString& filename,
bool createDir,
const KInstance* inst )
01508 {
01509
01510
01511
int slash = filename.findRev(
'/')+1;
01512
if (!slash)
01513
return inst->
dirs()->
saveLocation(type, QString::null, createDir) + filename;
01514
01515
01516
QString dir = filename.left(slash);
01517
QString file = filename.mid(slash);
01518
return inst->
dirs()->
saveLocation(type, dir, createDir) + file;
01519 }