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