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