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 "kstandarddirs.h"
00028 #include "kconfig.h"
00029 #include "kconfiggroup.h"
00030 #include "kdebug.h"
00031 #include "kcomponentdata.h"
00032 #include "kshell.h"
00033 #include "kuser.h"
00034 #include "kde_file.h"
00035 #include "kkernel_win.h"
00036 #include "kkernel_mac.h"
00037 #include "klocale.h"
00038
00039 #include <config.h>
00040 #include <config-prefix.h>
00041 #include <config-kstandarddirs.h>
00042
00043 #include <stdlib.h>
00044 #include <assert.h>
00045 #include <errno.h>
00046 #ifdef HAVE_SYS_STAT_H
00047 #include <sys/stat.h>
00048 #endif
00049 #ifdef HAVE_UNISTD_H
00050 #include <unistd.h>
00051 #endif
00052 #include <sys/param.h>
00053 #include <sys/types.h>
00054 #include <dirent.h>
00055 #include <pwd.h>
00056 #include <grp.h>
00057 #ifdef Q_WS_WIN
00058 #include <windows.h>
00059 #include <shlobj.h>
00060 #include <QtCore/QVarLengthArray>
00061 #endif
00062
00063 #include <QtCore/QMutex>
00064 #include <QtCore/QRegExp>
00065 #include <QtCore/QDir>
00066 #include <QtCore/QFileInfo>
00067 #include <QtCore/QSettings>
00068
00069 class KStandardDirs::KStandardDirsPrivate
00070 {
00071 public:
00072 KStandardDirsPrivate(KStandardDirs* qq)
00073 : m_restrictionsActive(false),
00074 m_checkRestrictions(true),
00075 m_cacheMutex(QMutex::Recursive),
00076 q(qq)
00077 { }
00078
00079 bool hasDataRestrictions(const QString &relPath) const;
00080 QStringList resourceDirs(const char* type, const QString& subdirForRestrictions);
00081 void createSpecialResource(const char*);
00082
00083 bool m_restrictionsActive : 1;
00084 bool m_checkRestrictions : 1;
00085 QMap<QByteArray, bool> m_restrictions;
00086
00087 QStringList xdgdata_prefixes;
00088 QStringList xdgconf_prefixes;
00089 QStringList m_prefixes;
00090
00091
00092 QMap<QByteArray, QStringList> m_absolutes;
00093 QMap<QByteArray, QStringList> m_relatives;
00094
00095
00096 QMap<QByteArray, QStringList> m_dircache;
00097 QMap<QByteArray, QString> m_savelocations;
00098 QMutex m_cacheMutex;
00099
00100 KStandardDirs* q;
00101 };
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124
00125
00126
00127
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139
00140
00141
00142
00143
00144
00145
00146
00147
00148
00149
00150
00151
00152
00153
00154
00155
00156
00157
00158
00159
00160
00161
00162 static const char types_string[] =
00163 "data\0"
00164 "share/apps\0"
00165 "html\0"
00166 "share/doc/HTML\0"
00167 "icon\0"
00168 "share/icons\0"
00169 "config\0"
00170 "share/config\0"
00171 "pixmap\0"
00172 "share/pixmaps\0"
00173 "apps\0"
00174 "share/applnk\0"
00175 "sound\0"
00176 "share/sounds\0"
00177 "locale\0"
00178 "share/locale\0"
00179 "services\0"
00180 "share/kde4/services\0"
00181 "servicetypes\0"
00182 "share/kde4/servicetypes\0"
00183 "mime\0"
00184 "share/mimelnk\0"
00185 "cgi\0"
00186 "cgi-bin\0"
00187 "wallpaper\0"
00188 "share/wallpapers\0"
00189 "templates\0"
00190 "share/templates\0"
00191 "exe\0"
00192 "bin\0"
00193 "module\0"
00194 "%lib/kde4\0"
00195 "qtplugins\0"
00196 "%lib/kde4/plugins\0"
00197 "kcfg\0"
00198 "share/config.kcfg\0"
00199 "emoticons\0"
00200 "share/emoticons\0"
00201 "xdgdata-apps\0"
00202 "applications\0"
00203 "xdgdata-icon\0"
00204 "icons\0"
00205 "xdgdata-pixmap\0"
00206 "pixmaps\0"
00207 "xdgdata-dirs\0"
00208 "desktop-directories\0"
00209 "xdgdata-mime\0"
00210 "xdgconf-menu\0"
00211 "menus\0"
00212 "xdgconf-autostart\0"
00213 "autostart\0"
00214 "\0";
00215
00216 static const int types_indices[] = {
00217 0, 5, 16, 21, 36, 41, 53, 60,
00218 73, 80, 94, 99, 112, 118, 131, 138,
00219 151, 160, 180, 193, 217, 222, 236, 240,
00220 248, 258, 275, 285, 301, 305, 309, 316,
00221 326, 336, 354, 359, 377, 387, 403, 416,
00222 429, 442, 448, 463, 471, 484, 504, 217,
00223 517, 530, 536, 554, -1
00224 };
00225
00226 static int tokenize( QStringList& token, const QString& str,
00227 const QString& delim );
00228
00229 KStandardDirs::KStandardDirs()
00230 : d(new KStandardDirsPrivate(this))
00231 {
00232 addKDEDefaults();
00233 }
00234
00235 KStandardDirs::~KStandardDirs()
00236 {
00237 delete d;
00238 }
00239
00240 bool KStandardDirs::isRestrictedResource(const char *type, const QString& relPath) const
00241 {
00242 if (!d->m_restrictionsActive)
00243 return false;
00244
00245 if (d->m_restrictions.value(type, false))
00246 return true;
00247
00248 if (strcmp(type, "data")==0 && d->hasDataRestrictions(relPath))
00249 return true;
00250
00251 return false;
00252 }
00253
00254 bool KStandardDirs::KStandardDirsPrivate::hasDataRestrictions(const QString &relPath) const
00255 {
00256 QString key;
00257 const int i = relPath.indexOf('/');
00258 if (i != -1)
00259 key = "data_" + relPath.left(i);
00260 else
00261 key = "data_" + relPath;
00262
00263 return m_restrictions.value(key.toLatin1(), false);
00264 }
00265
00266
00267 QStringList KStandardDirs::allTypes() const
00268 {
00269 QStringList list;
00270 for (int i = 0; types_indices[i] != -1; i += 2)
00271 list.append(QLatin1String(types_string + types_indices[i]));
00272
00273 list.append("lib");
00274
00275
00276
00277 list.append("socket");
00278 list.append("tmp");
00279 list.append("cache");
00280
00281 list.append("include");
00282
00283
00284
00285 return list;
00286 }
00287
00288 static void priorityAdd(QStringList &prefixes, const QString& dir, bool priority)
00289 {
00290 if (priority && !prefixes.isEmpty())
00291 {
00292
00293 QStringList::iterator it = prefixes.begin();
00294 it++;
00295 prefixes.insert(it, dir);
00296 }
00297 else
00298 {
00299 prefixes.append(dir);
00300 }
00301 }
00302
00303 void KStandardDirs::addPrefix( const QString& _dir )
00304 {
00305 addPrefix(_dir, false);
00306 }
00307
00308 void KStandardDirs::addPrefix( const QString& _dir, bool priority )
00309 {
00310 if (_dir.isEmpty())
00311 return;
00312
00313 QString dir = _dir;
00314 if (dir.at(dir.length() - 1) != '/')
00315 dir += '/';
00316
00317 if (!d->m_prefixes.contains(dir)) {
00318 priorityAdd(d->m_prefixes, dir, priority);
00319 d->m_dircache.clear();
00320 }
00321 }
00322
00323 void KStandardDirs::addXdgConfigPrefix( const QString& _dir )
00324 {
00325 addXdgConfigPrefix(_dir, false);
00326 }
00327
00328 void KStandardDirs::addXdgConfigPrefix( const QString& _dir, bool priority )
00329 {
00330 if (_dir.isEmpty())
00331 return;
00332
00333 QString dir = _dir;
00334 if (dir.at(dir.length() - 1) != '/')
00335 dir += '/';
00336
00337 if (!d->xdgconf_prefixes.contains(dir)) {
00338 priorityAdd(d->xdgconf_prefixes, dir, priority);
00339 d->m_dircache.clear();
00340 }
00341 }
00342
00343 void KStandardDirs::addXdgDataPrefix( const QString& _dir )
00344 {
00345 addXdgDataPrefix(_dir, false);
00346 }
00347
00348 void KStandardDirs::addXdgDataPrefix( const QString& _dir, bool priority )
00349 {
00350 if (_dir.isEmpty())
00351 return;
00352
00353 QString dir = _dir;
00354 if (dir.at(dir.length() - 1) != '/')
00355 dir += '/';
00356
00357 if (!d->xdgdata_prefixes.contains(dir)) {
00358 priorityAdd(d->xdgdata_prefixes, dir, priority);
00359 d->m_dircache.clear();
00360 }
00361 }
00362
00363 QString KStandardDirs::kfsstnd_prefixes()
00364 {
00365 return d->m_prefixes.join(QString(QChar(KPATH_SEPARATOR)));
00366 }
00367
00368 QString KStandardDirs::kfsstnd_xdg_conf_prefixes()
00369 {
00370 return d->xdgconf_prefixes.join(QString(QChar(KPATH_SEPARATOR)));
00371 }
00372
00373 QString KStandardDirs::kfsstnd_xdg_data_prefixes()
00374 {
00375 return d->xdgdata_prefixes.join(QString(QChar(KPATH_SEPARATOR)));
00376 }
00377
00378 bool KStandardDirs::addResourceType( const char *type,
00379 const QString& relativename,
00380 bool priority )
00381 {
00382 return addResourceType( type, 0, relativename, priority);
00383 }
00384
00385 bool KStandardDirs::addResourceType( const char *type,
00386 const char *basetype,
00387 const QString& relativename,
00388 bool priority )
00389 {
00390 if (relativename.isEmpty())
00391 return false;
00392
00393 QString copy = relativename;
00394 if (basetype)
00395 copy = QString('%') + basetype + '/' + relativename;
00396
00397 if (!copy.endsWith('/'))
00398 copy += '/';
00399
00400 QStringList& rels = d->m_relatives[type];
00401
00402 if (!rels.contains(copy)) {
00403 if (priority)
00404 rels.prepend(copy);
00405 else
00406 rels.append(copy);
00407 d->m_dircache.remove(type);
00408 return true;
00409 }
00410 return false;
00411 }
00412
00413 bool KStandardDirs::addResourceDir( const char *type,
00414 const QString& absdir,
00415 bool priority)
00416 {
00417 if (absdir.isEmpty() || !type)
00418 return false;
00419
00420 QString copy = absdir;
00421 if (copy.at(copy.length() - 1) != '/')
00422 copy += '/';
00423
00424 QStringList &paths = d->m_absolutes[type];
00425 if (!paths.contains(copy)) {
00426 if (priority)
00427 paths.prepend(copy);
00428 else
00429 paths.append(copy);
00430 d->m_dircache.remove(type);
00431 return true;
00432 }
00433 return false;
00434 }
00435
00436 QString KStandardDirs::findResource( const char *type,
00437 const QString& _filename ) const
00438 {
00439 if (!QDir::isRelativePath(_filename))
00440 return !KGlobal::hasLocale() ? _filename
00441 : KGlobal::locale()->localizedFilePath(_filename);
00442
00443 #if 0
00444 kDebug(180) << "Find resource: " << type;
00445 for (QStringList::ConstIterator pit = m_prefixes.begin();
00446 pit != m_prefixes.end();
00447 ++pit)
00448 {
00449 kDebug(180) << "Prefix: " << *pit;
00450 }
00451 #endif
00452
00453 QString filename(_filename);
00454 #ifdef Q_OS_WIN
00455 if(strcmp(type, "exe") == 0) {
00456 if(!filename.endsWith(QLatin1String(".exe")))
00457 filename += QLatin1String(".exe");
00458 }
00459 #endif
00460 const QString dir = findResourceDir(type, filename);
00461 if (dir.isEmpty())
00462 return dir;
00463 else
00464 return !KGlobal::hasLocale() ? dir + filename
00465 : KGlobal::locale()->localizedFilePath(dir + filename);
00466 }
00467
00468 static quint32 updateHash(const QString &file, quint32 hash)
00469 {
00470 KDE_struct_stat buff;
00471 if ((KDE::access(file, R_OK) == 0) && (KDE::stat(file, &buff) == 0) && (S_ISREG(buff.st_mode))) {
00472 hash = hash + static_cast<quint32>(buff.st_ctime);
00473 }
00474 return hash;
00475 }
00476
00477 quint32 KStandardDirs::calcResourceHash( const char *type,
00478 const QString& filename,
00479 SearchOptions options ) const
00480 {
00481 quint32 hash = 0;
00482
00483 if (!QDir::isRelativePath(filename))
00484 {
00485
00486 return updateHash(filename, hash);
00487 }
00488 QStringList candidates = d->resourceDirs(type, filename);
00489
00490 foreach ( const QString& candidate, candidates )
00491 {
00492 hash = updateHash(candidate + filename, hash);
00493 if ( !( options & Recursive ) && hash ) {
00494 return hash;
00495 }
00496 }
00497 return hash;
00498 }
00499
00500
00501 QStringList KStandardDirs::findDirs( const char *type,
00502 const QString& reldir ) const
00503 {
00504 QDir testdir;
00505 QStringList list;
00506 if (!QDir::isRelativePath(reldir))
00507 {
00508 testdir.setPath(reldir);
00509 if (testdir.exists())
00510 {
00511 if (reldir.endsWith('/'))
00512 list.append(reldir);
00513 else
00514 list.append(reldir+'/');
00515 }
00516 return list;
00517 }
00518
00519 const QStringList candidates = d->resourceDirs(type, reldir);
00520
00521 for (QStringList::ConstIterator it = candidates.begin();
00522 it != candidates.end(); ++it) {
00523 testdir.setPath(*it + reldir);
00524 if (testdir.exists())
00525 list.append(testdir.absolutePath() + '/');
00526 }
00527
00528 return list;
00529 }
00530
00531 QString KStandardDirs::findResourceDir( const char *type,
00532 const QString& _filename) const
00533 {
00534 #ifndef NDEBUG
00535 if (_filename.isEmpty()) {
00536 kWarning() << "filename for type " << type << " in KStandardDirs::findResourceDir is not supposed to be empty!!";
00537 return QString();
00538 }
00539 #endif
00540
00541 QString filename(_filename);
00542 #ifdef Q_OS_WIN
00543 if(strcmp(type, "exe") == 0) {
00544 if(!filename.endsWith(QLatin1String(".exe")))
00545 filename += QLatin1String(".exe");
00546 }
00547 #endif
00548 const QStringList candidates = d->resourceDirs(type, filename);
00549
00550 for (QStringList::ConstIterator it = candidates.begin();
00551 it != candidates.end(); ++it) {
00552 if (exists(*it + filename)) {
00553 return *it;
00554 }
00555 }
00556
00557 #ifndef NDEBUG
00558 if(false && strcmp(type, "locale"))
00559 kDebug(180) << "KStdDirs::findResDir(): can't find \"" << filename << "\" in type \"" << type << "\".";
00560 #endif
00561
00562 return QString();
00563 }
00564
00565 bool KStandardDirs::exists(const QString &fullPath)
00566 {
00567 #ifdef Q_OS_WIN
00568
00569
00570
00571 if (fullPath.endsWith('/'))
00572 return QDir(fullPath).exists();
00573 return QFileInfo(fullPath).exists();
00574 #else
00575 KDE_struct_stat buff;
00576 QByteArray cFullPath = QFile::encodeName(fullPath);
00577 if (access(cFullPath, R_OK) == 0 && KDE_stat( cFullPath, &buff ) == 0) {
00578 if (!fullPath.endsWith('/')) {
00579 if (S_ISREG( buff.st_mode ))
00580 return true;
00581 } else
00582 if (S_ISDIR( buff.st_mode ))
00583 return true;
00584 }
00585 return false;
00586 #endif
00587 }
00588
00589 static void lookupDirectory(const QString& path, const QString &relPart,
00590 const QRegExp ®exp,
00591 QStringList& list,
00592 QStringList& relList,
00593 bool recursive, bool unique)
00594 {
00595 const QString pattern = regexp.pattern();
00596 if (recursive || pattern.contains('?') || pattern.contains('*'))
00597 {
00598 if (path.isEmpty())
00599 return;
00600 #ifdef Q_WS_WIN
00601 QString path_ = path + QLatin1String( "*.*" );
00602 WIN32_FIND_DATA findData;
00603 HANDLE hFile = FindFirstFile( (LPWSTR)path_.utf16(), &findData );
00604 if( hFile == INVALID_HANDLE_VALUE )
00605 return;
00606 do {
00607 const int len = wcslen( findData.cFileName );
00608 if (!( findData.cFileName[0] == '.' &&
00609 findData.cFileName[1] == '\0' ) &&
00610 !( findData.cFileName[0] == '.' &&
00611 findData.cFileName[1] == '.' &&
00612 findData.cFileName[2] == '\0' ) &&
00613 ( findData.cFileName[len-1] != '~' ) ) {
00614 QString fn = QString::fromUtf16( (const unsigned short*)findData.cFileName );
00615 if (!recursive && !regexp.exactMatch(fn))
00616 continue;
00617 QString pathfn = path + fn;
00618 bool bIsDir = ( ( findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) == FILE_ATTRIBUTE_DIRECTORY );
00619 if ( recursive ) {
00620 if ( bIsDir ) {
00621 lookupDirectory(pathfn + '/', relPart + fn + '/', regexp, list, relList, recursive, unique);
00622 }
00623 if (!regexp.exactMatch(fn))
00624 continue;
00625 }
00626 if ( !bIsDir )
00627 {
00628 if ( !unique || !relList.contains(relPart + fn) )
00629 {
00630 list.append( pathfn );
00631 relList.append( relPart + fn );
00632 }
00633 }
00634 }
00635 } while( FindNextFile( hFile, &findData ) != 0 );
00636 FindClose( hFile );
00637 #else
00638
00639 DIR *dp = opendir( QFile::encodeName(path));
00640 if (!dp)
00641 return;
00642
00643 assert(path.at(path.length() - 1) == '/');
00644
00645 struct dirent *ep;
00646
00647 while( ( ep = readdir( dp ) ) != 0L )
00648 {
00649 QString fn( QFile::decodeName(ep->d_name));
00650 if (fn == "." || fn == ".." || fn.at(fn.length() - 1).toLatin1() == '~')
00651 continue;
00652
00653 if (!recursive && !regexp.exactMatch(fn))
00654 continue;
00655
00656 bool isDir;
00657 bool isReg;
00658
00659 QString pathfn = path + fn;
00660 #ifdef HAVE_DIRENT_D_TYPE
00661 isDir = ep->d_type == DT_DIR;
00662 isReg = ep->d_type == DT_REG;
00663
00664 if (ep->d_type == DT_UNKNOWN || ep->d_type == DT_LNK)
00665 #endif
00666 {
00667 KDE_struct_stat buff;
00668 if ( KDE::stat( pathfn, &buff ) != 0 ) {
00669 kDebug(180) << "Error stat'ing " << pathfn << " : " << perror;
00670 continue;
00671 }
00672 isReg = S_ISREG (buff.st_mode);
00673 isDir = S_ISDIR (buff.st_mode);
00674 }
00675
00676 if ( recursive ) {
00677 if ( isDir ) {
00678 lookupDirectory(pathfn + '/', relPart + fn + '/', regexp, list, relList, recursive, unique);
00679 }
00680 if (!regexp.exactMatch(fn))
00681 continue;
00682 }
00683 if ( isReg )
00684 {
00685 if (!unique || !relList.contains(relPart + fn))
00686 {
00687 list.append( pathfn );
00688 relList.append( relPart + fn );
00689 }
00690 }
00691 }
00692 closedir( dp );
00693 #endif
00694 }
00695 else
00696 {
00697
00698 QString fn = pattern;
00699 QString pathfn = path + fn;
00700 KDE_struct_stat buff;
00701 if ( KDE::stat( pathfn, &buff ) != 0 )
00702 return;
00703 if ( S_ISREG( buff.st_mode))
00704 {
00705 if (!unique || !relList.contains(relPart + fn))
00706 {
00707 list.append( pathfn );
00708 relList.append( relPart + fn );
00709 }
00710 }
00711 }
00712 }
00713
00714 static void lookupPrefix(const QString& prefix, const QString& relpath,
00715 const QString& relPart,
00716 const QRegExp ®exp,
00717 QStringList& list,
00718 QStringList& relList,
00719 bool recursive, bool unique)
00720 {
00721 if (relpath.isEmpty()) {
00722 if (recursive)
00723 Q_ASSERT(prefix != "/");
00724 lookupDirectory(prefix, relPart, regexp, list,
00725 relList, recursive, unique);
00726 return;
00727 }
00728 QString path;
00729 QString rest;
00730
00731 int slash = relpath.indexOf('/');
00732 if (slash < 0)
00733 rest = relpath.left(relpath.length() - 1);
00734 else {
00735 path = relpath.left(slash);
00736 rest = relpath.mid(slash + 1);
00737 }
00738
00739 if (prefix.isEmpty())
00740 return;
00741 assert(prefix.at(prefix.length() - 1) == '/');
00742 if (path.contains('*') || path.contains('?')) {
00743
00744 QRegExp pathExp(path, Qt::CaseSensitive, QRegExp::Wildcard);
00745
00746 #ifdef Q_WS_WIN
00747 QString prefix_ = prefix + QLatin1String( "*.*" );
00748 WIN32_FIND_DATA findData;
00749 HANDLE hFile = FindFirstFile( (LPWSTR)prefix_.utf16(), &findData );
00750 if( hFile == INVALID_HANDLE_VALUE )
00751 return;
00752 do {
00753 const int len = wcslen( findData.cFileName );
00754 if (!( findData.cFileName[0] == '.' &&
00755 findData.cFileName[1] == '\0' ) &&
00756 !( findData.cFileName[0] == '.' &&
00757 findData.cFileName[1] == '.' &&
00758 findData.cFileName[2] == '\0' ) &&
00759 ( findData.cFileName[len-1] != '~' ) ) {
00760 const QString fn = QString::fromUtf16( (const unsigned short*)findData.cFileName );
00761 if ( !pathExp.exactMatch(fn) )
00762 continue;
00763 if ( ( findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) == FILE_ATTRIBUTE_DIRECTORY )
00764 lookupPrefix(prefix + fn + '/', rest, relPart + fn + '/',
00765 regexp, list, relList, recursive, unique);
00766 }
00767 } while( FindNextFile( hFile, &findData ) != 0 );
00768 FindClose( hFile );
00769 #else
00770 DIR *dp = opendir( QFile::encodeName(prefix) );
00771 if (!dp) {
00772 return;
00773 }
00774
00775 struct dirent *ep;
00776
00777 while( ( ep = readdir( dp ) ) != 0L )
00778 {
00779 QString fn( QFile::decodeName(ep->d_name));
00780 if (fn == "." || fn == ".." || fn.at(fn.length() - 1) == '~')
00781 continue;
00782
00783 if ( !pathExp.exactMatch(fn) )
00784 continue;
00785 QString rfn = relPart+fn;
00786 fn = prefix + fn;
00787
00788 bool isDir;
00789
00790 #ifdef HAVE_DIRENT_D_TYPE
00791 isDir = ep->d_type == DT_DIR;
00792
00793 if (ep->d_type == DT_UNKNOWN || ep->d_type == DT_LNK)
00794 #endif
00795 {
00796 QString pathfn = path + fn;
00797 KDE_struct_stat buff;
00798 if ( KDE::stat( fn, &buff ) != 0 ) {
00799 kDebug(180) << "Error stat'ing " << fn << " : " << perror;
00800 continue;
00801 }
00802 isDir = S_ISDIR (buff.st_mode);
00803 }
00804 if ( isDir )
00805 lookupPrefix(fn + '/', rest, rfn + '/', regexp, list, relList, recursive, unique);
00806 }
00807
00808 closedir( dp );
00809 #endif
00810 } else {
00811
00812
00813 lookupPrefix(prefix + path + '/', rest,
00814 relPart + path + '/', regexp, list,
00815 relList, recursive, unique);
00816 }
00817 }
00818
00819 QStringList
00820 KStandardDirs::findAllResources( const char *type,
00821 const QString& filter,
00822 SearchOptions options,
00823 QStringList &relList) const
00824 {
00825 QString filterPath;
00826 QString filterFile;
00827
00828 if ( !filter.isEmpty() )
00829 {
00830 int slash = filter.lastIndexOf('/');
00831 if (slash < 0) {
00832 filterFile = filter;
00833 } else {
00834 filterPath = filter.left(slash + 1);
00835 filterFile = filter.mid(slash + 1);
00836 }
00837 }
00838
00839 QStringList candidates;
00840 if ( !QDir::isRelativePath(filter) )
00841 {
00842 #ifdef Q_OS_WIN
00843 candidates << filterPath.left(3);
00844 filterPath = filterPath.mid(3);
00845 #else
00846 candidates << "/";
00847 filterPath = filterPath.mid(1);
00848 #endif
00849 }
00850 else
00851 {
00852 candidates = d->resourceDirs(type, filter);
00853 }
00854
00855 if (filterFile.isEmpty()) {
00856 filterFile = "*";
00857 }
00858
00859 QRegExp regExp(filterFile, Qt::CaseSensitive, QRegExp::Wildcard);
00860
00861 QStringList list;
00862 foreach ( const QString& candidate, candidates )
00863 {
00864 lookupPrefix(candidate, filterPath, "", regExp, list,
00865 relList, options & Recursive, options & NoDuplicates);
00866 }
00867
00868 return list;
00869 }
00870
00871 QStringList
00872 KStandardDirs::findAllResources( const char *type,
00873 const QString& filter,
00874 SearchOptions options ) const
00875 {
00876 QStringList relList;
00877 return findAllResources(type, filter, options, relList);
00878 }
00879
00880
00881
00882
00883
00884
00885 QString
00886 KStandardDirs::realPath(const QString &dirname)
00887 {
00888 #ifdef Q_WS_WIN
00889 const QString strRet = realFilePath(dirname);
00890 if ( !strRet.endsWith('/') )
00891 return strRet + '/';
00892 return strRet;
00893 #else
00894 char realpath_buffer[MAXPATHLEN + 1];
00895 memset(realpath_buffer, 0, MAXPATHLEN + 1);
00896
00897
00898 if (realpath( QFile::encodeName(dirname).constData(), realpath_buffer) != 0) {
00899
00900 int len = strlen(realpath_buffer);
00901 realpath_buffer[len] = '/';
00902 realpath_buffer[len+1] = 0;
00903 return QFile::decodeName(realpath_buffer);
00904 }
00905
00906 if ( !dirname.endsWith('/') )
00907 return dirname + '/';
00908 return dirname;
00909 #endif
00910 }
00911
00912
00913
00914
00915
00916
00917 QString
00918 KStandardDirs::realFilePath(const QString &filename)
00919 {
00920 #ifdef Q_WS_WIN
00921 LPCWSTR lpIn = (LPCWSTR)filename.utf16();
00922 QVarLengthArray<WCHAR, MAX_PATH> buf(MAX_PATH);
00923 DWORD len = GetFullPathNameW(lpIn, buf.size(), buf.data(), NULL);
00924 if (len > (DWORD)buf.size()) {
00925 buf.resize(len);
00926 len = GetFullPathNameW(lpIn, buf.size(), buf.data(), NULL);
00927 }
00928 if (len == 0)
00929 return QString();
00930 return QString::fromUtf16((const unsigned short*)buf.data()).replace('\\','/').toLower();
00931 #else
00932 char realpath_buffer[MAXPATHLEN + 1];
00933 memset(realpath_buffer, 0, MAXPATHLEN + 1);
00934
00935
00936 if (realpath( QFile::encodeName(filename).constData(), realpath_buffer) != 0) {
00937
00938 return QFile::decodeName(realpath_buffer);
00939 }
00940
00941 return filename;
00942 #endif
00943 }
00944
00945
00946 void KStandardDirs::KStandardDirsPrivate::createSpecialResource(const char *type)
00947 {
00948 char hostname[256];
00949 hostname[0] = 0;
00950 gethostname(hostname, 255);
00951 const QString localkdedir = m_prefixes.first();
00952 QString dir = QString("%1%2-%3").arg(localkdedir).arg(type).arg(hostname);
00953 char link[1024];
00954 link[1023] = 0;
00955 int result = readlink(QFile::encodeName(dir).constData(), link, 1023);
00956 bool relink = (result == -1) && (errno == ENOENT);
00957 if (result > 0)
00958 {
00959 link[result] = 0;
00960 if (!QDir::isRelativePath(link))
00961 {
00962 KDE_struct_stat stat_buf;
00963 int res = KDE::lstat(link, &stat_buf);
00964 if ((res == -1) && (errno == ENOENT))
00965 {
00966 relink = true;
00967 }
00968 else if ((res == -1) || (!S_ISDIR(stat_buf.st_mode)))
00969 {
00970 fprintf(stderr, "Error: \"%s\" is not a directory.\n", link);
00971 relink = true;
00972 }
00973 else if (stat_buf.st_uid != getuid())
00974 {
00975 fprintf(stderr, "Error: \"%s\" is owned by uid %d instead of uid %d.\n", link, stat_buf.st_uid, getuid());
00976 relink = true;
00977 }
00978 }
00979 }
00980 #ifdef Q_WS_WIN
00981 if (relink)
00982 {
00983 if (!makeDir(dir, 0700))
00984 fprintf(stderr, "failed to create \"%s\"", qPrintable(dir));
00985 else
00986 result = readlink(QFile::encodeName(dir).data(), link, 1023);
00987 }
00988 #else //UNIX
00989 if (relink)
00990 {
00991 QString srv = findExe(QLatin1String("lnusertemp"), installPath("libexec"));
00992 if (srv.isEmpty())
00993 srv = findExe(QLatin1String("lnusertemp"));
00994 if (!srv.isEmpty())
00995 {
00996 if (system(QFile::encodeName(srv) + ' ' + type) == -1) {
00997 fprintf(stderr, "Error: unable to launch lnusertemp command" );
00998 }
00999 result = readlink(QFile::encodeName(dir).constData(), link, 1023);
01000 }
01001 }
01002 if (result > 0)
01003 {
01004 link[result] = 0;
01005 if (link[0] == '/')
01006 dir = QFile::decodeName(link);
01007 else
01008 dir = QDir::cleanPath(dir+QFile::decodeName(link));
01009 }
01010 #endif
01011 q->addResourceDir(type, dir+'/', false);
01012 }
01013
01014 QStringList KStandardDirs::resourceDirs(const char *type) const
01015 {
01016 return d->resourceDirs(type, QString());
01017 }
01018
01019 QStringList KStandardDirs::KStandardDirsPrivate::resourceDirs(const char* type, const QString& subdirForRestrictions)
01020 {
01021 QMutexLocker lock(&m_cacheMutex);
01022 const bool dataRestrictionActive = m_restrictionsActive
01023 && (strcmp(type, "data") == 0)
01024 && hasDataRestrictions(subdirForRestrictions);
01025
01026 QMap<QByteArray, QStringList>::const_iterator dirCacheIt = m_dircache.constFind(type);
01027
01028 QStringList candidates;
01029
01030 if (dirCacheIt != m_dircache.constEnd() && !dataRestrictionActive) {
01031
01032 candidates = *dirCacheIt;
01033 }
01034 else
01035 {
01036
01037 if (strcmp(type, "socket") == 0)
01038 createSpecialResource(type);
01039 else if (strcmp(type, "tmp") == 0)
01040 createSpecialResource(type);
01041 else if (strcmp(type, "cache") == 0)
01042 createSpecialResource(type);
01043
01044 QDir testdir;
01045
01046 bool restrictionActive = false;
01047 if (m_restrictionsActive) {
01048 if (dataRestrictionActive)
01049 restrictionActive = true;
01050 if (m_restrictions.value("all", false))
01051 restrictionActive = true;
01052 else if (m_restrictions.value(type, false))
01053 restrictionActive = true;
01054 }
01055
01056 QStringList dirs;
01057 dirs = m_relatives.value(type);
01058 const QString typeInstallPath = installPath(type);
01059
01060 #ifdef Q_WS_WIN
01061 const QString installdir = typeInstallPath.isEmpty() ? QString() : realPath(typeInstallPath).toLower();
01062 const QString installprefix = installPath("kdedir").toLower();
01063 #else
01064 const QString installdir = typeInstallPath.isEmpty() ? QString() : realPath(typeInstallPath);
01065 const QString installprefix = installPath("kdedir");
01066 #endif
01067 if (!dirs.isEmpty())
01068 {
01069 bool local = true;
01070
01071 for (QStringList::ConstIterator it = dirs.constBegin();
01072 it != dirs.constEnd(); ++it)
01073 {
01074 if ( (*it).startsWith('%'))
01075 {
01076
01077 const int pos = (*it).indexOf('/');
01078 QString rel = (*it).mid(1, pos - 1);
01079 QString rest = (*it).mid(pos + 1);
01080 const QStringList basedirs = resourceDirs(rel.toUtf8().constData(), subdirForRestrictions);
01081 for (QStringList::ConstIterator it2 = basedirs.begin();
01082 it2 != basedirs.end(); ++it2)
01083 {
01084 #ifdef Q_WS_WIN
01085 const QString path = realPath( *it2 + rest ).toLower();
01086 #else
01087 const QString path = realPath( *it2 + rest );
01088 #endif
01089 testdir.setPath(path);
01090 if ((local || testdir.exists()) && !candidates.contains(path))
01091 candidates.append(path);
01092 local = false;
01093 }
01094 }
01095 }
01096
01097 const QStringList *prefixList = 0;
01098 if (strncmp(type, "xdgdata-", 8) == 0)
01099 prefixList = &(xdgdata_prefixes);
01100 else if (strncmp(type, "xdgconf-", 8) == 0)
01101 prefixList = &(xdgconf_prefixes);
01102 else
01103 prefixList = &m_prefixes;
01104
01105 for (QStringList::ConstIterator pit = prefixList->begin();
01106 pit != prefixList->end();
01107 ++pit)
01108 {
01109
01110
01111 if((*pit)!=installprefix||installdir.isEmpty()||!strcmp("exe", type))
01112 {
01113 for (QStringList::ConstIterator it = dirs.constBegin();
01114 it != dirs.constEnd(); ++it)
01115 {
01116 if ( (*it).startsWith('%'))
01117 continue;
01118 #ifdef Q_WS_WIN
01119 const QString path = realPath( *pit + *it ).toLower();
01120 #else
01121 const QString path = realPath( *pit + *it );
01122 #endif
01123 testdir.setPath(path);
01124 if (local && restrictionActive)
01125 continue;
01126 if ((local || testdir.exists()) && !candidates.contains(path))
01127 candidates.append(path);
01128 }
01129
01130
01131
01132 if (local && !strcmp("config", type))
01133 candidates.append("/etc/kde/");
01134 local = false;
01135 }
01136 else
01137 {
01138
01139 testdir.setPath(installdir);
01140 if(testdir.exists() && ! candidates.contains(installdir))
01141 candidates.append(installdir);
01142 }
01143 }
01144 }
01145
01146
01147 if (!installdir.isEmpty()) {
01148 bool ok = true;
01149 foreach (const QString &s, candidates) {
01150 if (installdir.startsWith(s)) {
01151 ok = false;
01152 break;
01153 }
01154 }
01155 if (ok)
01156 candidates.append(installdir);
01157 }
01158
01159 dirs = m_absolutes.value(type);
01160 if (!dirs.isEmpty())
01161 for (QStringList::ConstIterator it = dirs.constBegin();
01162 it != dirs.constEnd(); ++it)
01163 {
01164 testdir.setPath(*it);
01165 if (testdir.exists()) {
01166 #ifdef Q_WS_WIN
01167 const QString filename = realPath( *it ).toLower();
01168 #else
01169 const QString filename = realPath( *it );
01170 #endif
01171 if (!candidates.contains(filename)) {
01172 candidates.append(filename);
01173 }
01174 }
01175 }
01176
01177
01178
01179 if (!dataRestrictionActive) {
01180
01181 m_dircache.insert(type, candidates);
01182 }
01183 }
01184
01185 #if 0
01186 kDebug(180) << "found dirs for resource" << type << ":" << candidates;
01187 #endif
01188
01189 return candidates;
01190 }
01191
01192 QStringList KStandardDirs::systemPaths( const QString& pstr )
01193 {
01194 QStringList tokens;
01195 QString p = pstr;
01196
01197 if( p.isEmpty() )
01198 {
01199 p = QString::fromLocal8Bit( qgetenv( "PATH" ) );
01200 }
01201
01202 QString delimiters(QChar(KPATH_SEPARATOR));
01203 delimiters += "\b";
01204 tokenize( tokens, p, delimiters );
01205
01206 QStringList exePaths;
01207
01208
01209 for( int i = 0; i < tokens.count(); i++ )
01210 {
01211 exePaths << KShell::tildeExpand( tokens[ i ] );
01212 }
01213
01214 return exePaths;
01215 }
01216
01217 #ifdef Q_WS_MAC
01218 static QString getBundle( const QString& path, bool ignore )
01219 {
01220 kDebug(180) << "getBundle(" << path << ", " << ignore << ") called";
01221 QFileInfo info;
01222 QString bundle = path;
01223 bundle += ".app/Contents/MacOS/" + bundle.section('/', -1);
01224 info.setFile( bundle );
01225 if ( info.exists() && ( ignore || info.isExecutable() )
01226 && ( info.isFile() || info.isSymLink() ) ) {
01227 kDebug(180) << "getBundle(): returning " << bundle;
01228 return bundle;
01229 }
01230 return QString();
01231 }
01232 #endif
01233
01234 static QString checkExecutable( const QString& path, bool ignoreExecBit )
01235 {
01236 #ifdef Q_WS_MAC
01237 QString bundle = getBundle( path, ignoreExecBit );
01238 if ( !bundle.isEmpty() ) {
01239
01240 return bundle;
01241 }
01242 #endif
01243 QFileInfo info( path );
01244 QFileInfo orig = info;
01245 if( info.exists() && info.isSymLink() )
01246 info = QFileInfo( info.canonicalFilePath() );
01247 if( info.exists() && ( ignoreExecBit || info.isExecutable() ) && info.isFile() ) {
01248
01249
01250
01251 orig.makeAbsolute();
01252 return orig.filePath();
01253 }
01254
01255 return QString();
01256 }
01257
01258 QString KStandardDirs::findExe( const QString& appname,
01259 const QString& pstr,
01260 SearchOptions options )
01261 {
01262
01263
01264 #ifdef Q_WS_WIN
01265 QString real_appname = appname + QLatin1String(".exe");
01266 #else
01267 QString real_appname = appname;
01268 #endif
01269 QFileInfo info;
01270
01271
01272 if (real_appname.contains(QDir::separator()))
01273 {
01274
01275 QString path = checkExecutable(real_appname, options & IgnoreExecBit);
01276 return path;
01277 }
01278
01279
01280
01281
01282
01283 QString p = installPath("libexec") + real_appname;
01284 QString result = checkExecutable(p, options & IgnoreExecBit);
01285 if (!result.isEmpty()) {
01286
01287 return result;
01288 }
01289
01290 p = installPath("exe") + real_appname;
01291 result = checkExecutable(p, options & IgnoreExecBit);
01292 if (!result.isEmpty()) {
01293
01294 return result;
01295 }
01296
01297
01298 const QStringList exePaths = systemPaths( pstr );
01299 for (QStringList::ConstIterator it = exePaths.begin(); it != exePaths.end(); ++it)
01300 {
01301 p = (*it) + '/';
01302 p += real_appname;
01303
01304
01305 result = checkExecutable(p, options & IgnoreExecBit);
01306 if (!result.isEmpty()) {
01307
01308 return result;
01309 }
01310 }
01311
01312
01313
01314
01315
01316 return QString();
01317 }
01318
01319 int KStandardDirs::findAllExe( QStringList& list, const QString& appname,
01320 const QString& pstr, SearchOptions options )
01321 {
01322 #ifdef Q_WS_WIN
01323 QString real_appname = appname + ".exe";
01324 #else
01325 QString real_appname = appname;
01326 #endif
01327 QFileInfo info;
01328 QString p;
01329 list.clear();
01330
01331 const QStringList exePaths = systemPaths( pstr );
01332 for (QStringList::ConstIterator it = exePaths.begin(); it != exePaths.end(); ++it)
01333 {
01334 p = (*it) + '/';
01335 p += real_appname;
01336
01337 #ifdef Q_WS_MAC
01338 QString bundle = getBundle( p, (options & IgnoreExecBit) );
01339 if ( !bundle.isEmpty() ) {
01340
01341 list.append( bundle );
01342 }
01343 #endif
01344
01345 info.setFile( p );
01346
01347 if( info.exists() && ( ( options & IgnoreExecBit ) || info.isExecutable())
01348 && info.isFile() ) {
01349 list.append( p );
01350 }
01351 }
01352
01353 return list.count();
01354 }
01355
01356 static inline QString equalizePath(QString &str)
01357 {
01358 #ifdef Q_WS_WIN
01359
01360
01361 QFileInfo f(str);
01362 if (f.isAbsolute())
01363 return f.absoluteFilePath();
01364 else
01365 #endif
01366 return str;
01367 }
01368
01369 static int tokenize( QStringList& tokens, const QString& str,
01370 const QString& delim )
01371 {
01372 int len = str.length();
01373 QString token;
01374
01375 for( int index = 0; index < len; index++)
01376 {
01377 if ( delim.contains( str[ index ] ) )
01378 {
01379 tokens.append( equalizePath(token) );
01380 token.clear();
01381 }
01382 else
01383 {
01384 token += str[ index ];
01385 }
01386 }
01387 if ( !token.isEmpty() )
01388 {
01389 tokens.append( equalizePath(token) );
01390 }
01391
01392 return tokens.count();
01393 }
01394
01395 QString KStandardDirs::kde_default(const char *type)
01396 {
01397 return QString('%') + type + '/';
01398 }
01399
01400 QString KStandardDirs::saveLocation(const char *type,
01401 const QString& suffix,
01402 bool create) const
01403 {
01404 QMutexLocker lock(&d->m_cacheMutex);
01405 QString path = d->m_savelocations.value(type);
01406 if (path.isEmpty())
01407 {
01408 QStringList dirs = d->m_relatives.value(type);
01409 if (dirs.isEmpty() && (
01410 (strcmp(type, "socket") == 0) ||
01411 (strcmp(type, "tmp") == 0) ||
01412 (strcmp(type, "cache") == 0) ))
01413 {
01414 (void) resourceDirs(type);
01415 dirs = d->m_relatives.value(type);
01416 }
01417 if (!dirs.isEmpty())
01418 {
01419 path = dirs.last();
01420
01421 if ( path.startsWith('%'))
01422 {
01423
01424 const int pos = path.indexOf('/');
01425 QString rel = path.mid(1, pos - 1);
01426 QString rest = path.mid(pos + 1);
01427 QString basepath = saveLocation(rel.toUtf8().constData());
01428 path = basepath + rest;
01429 } else
01430
01431
01432 if (strncmp(type, "xdgdata-", 8) == 0) {
01433 path = realPath( localxdgdatadir() + path ) ;
01434 } else if (strncmp(type, "xdgconf-", 8) == 0) {
01435 path = realPath( localxdgconfdir() + path );
01436 } else {
01437 path = realPath( localkdedir() + path );
01438 }
01439 }
01440 else {
01441 dirs = d->m_absolutes.value(type);
01442 if (dirs.isEmpty()) {
01443 qFatal("KStandardDirs: The resource type %s is not registered", type);
01444 }
01445 path = realPath(dirs.last());
01446 }
01447
01448 d->m_savelocations.insert(type, path.endsWith('/') ? path : path + '/');
01449 }
01450 QString fullPath = path + suffix;
01451
01452 KDE_struct_stat st;
01453 if (KDE::stat(fullPath, &st) != 0 || !(S_ISDIR(st.st_mode))) {
01454 if(!create) {
01455 #ifndef NDEBUG
01456
01457
01458
01459 #endif
01460 return fullPath;
01461 }
01462 if(!makeDir(fullPath, 0700)) {
01463 return fullPath;
01464 }
01465 d->m_dircache.remove(type);
01466 }
01467 if (!fullPath.endsWith('/'))
01468 fullPath += '/';
01469 return fullPath;
01470 }
01471
01472
01473 QString KStandardDirs::relativeLocation(const char *type, const QString &absPath)
01474 {
01475 QString fullPath = absPath;
01476 int i = absPath.lastIndexOf('/');
01477 if (i != -1) {
01478 fullPath = realFilePath(absPath);
01479 }
01480
01481 const QStringList candidates = resourceDirs(type);
01482
01483 for (QStringList::ConstIterator it = candidates.begin();
01484 it != candidates.end(); ++it) {
01485 if (fullPath.startsWith(*it)) {
01486 return fullPath.mid((*it).length());
01487 }
01488 }
01489 return absPath;
01490 }
01491
01492
01493 bool KStandardDirs::makeDir(const QString& dir, int mode)
01494 {
01495
01496 if (QDir::isRelativePath(dir))
01497 return false;
01498
01499 #ifdef Q_WS_WIN
01500 return QDir().mkpath(dir);
01501 #else
01502 QString target = dir;
01503 uint len = target.length();
01504
01505
01506 if (dir.at(len - 1) != '/')
01507 target += '/';
01508
01509 QString base;
01510 uint i = 1;
01511
01512 while( i < len )
01513 {
01514 KDE_struct_stat st;
01515 int pos = target.indexOf('/', i);
01516 base += target.mid(i - 1, pos - i + 1);
01517 QByteArray baseEncoded = QFile::encodeName(base);
01518
01519 if (KDE_stat(baseEncoded, &st) != 0)
01520 {
01521
01522
01523 if (KDE_lstat(baseEncoded, &st) == 0)
01524 (void)unlink(baseEncoded);
01525
01526 if (KDE_mkdir(baseEncoded, static_cast<mode_t>(mode)) != 0) {
01527 baseEncoded.prepend( "trying to create local folder " );
01528 perror(baseEncoded.constData());
01529 return false;
01530 }
01531 }
01532 i = pos + 1;
01533 }
01534 return true;
01535 #endif
01536 }
01537
01538 static QString readEnvPath(const char *env)
01539 {
01540 QByteArray c_path = qgetenv(env);
01541 if (c_path.isEmpty())
01542 return QString();
01543 return QDir::fromNativeSeparators(QFile::decodeName(c_path));
01544 }
01545
01546 #ifdef __linux__
01547 static QString executablePrefix()
01548 {
01549 char path_buffer[MAXPATHLEN + 1];
01550 path_buffer[MAXPATHLEN] = 0;
01551 int length = readlink ("/proc/self/exe", path_buffer, MAXPATHLEN);
01552 if (length == -1)
01553 return QString();
01554
01555 path_buffer[length] = '\0';
01556
01557 QString path = QFile::decodeName(path_buffer);
01558
01559 if(path.isEmpty())
01560 return QString();
01561
01562 int pos = path.lastIndexOf('/');
01563 if(pos <= 0)
01564 return QString();
01565 pos = path.lastIndexOf('/', pos - 1);
01566 if(pos <= 0)
01567 return QString();
01568
01569 return path.left(pos);
01570 }
01571 #endif
01572
01573 void KStandardDirs::addResourcesFrom_krcdirs()
01574 {
01575 QString localFile = QDir::currentPath() + "/.krcdirs";
01576 if (!QFile::exists(localFile))
01577 return;
01578
01579 QSettings iniFile(localFile, QSettings::IniFormat);
01580 iniFile.beginGroup("KStandardDirs");
01581 const QStringList resources = iniFile.allKeys();
01582 foreach(const QString &key, resources)
01583 {
01584 QDir path(iniFile.value(key).toString());
01585 if (!path.exists())
01586 continue;
01587
01588 if(path.makeAbsolute())
01589 addResourceDir(key.toAscii(), path.path(), false);
01590 }
01591 }
01592
01593 void KStandardDirs::addKDEDefaults()
01594 {
01595 addResourcesFrom_krcdirs();
01596
01597 QStringList kdedirList;
01598
01599
01600 QString kdedirs = readEnvPath("KDEDIRS");
01601 if (!kdedirs.isEmpty())
01602 {
01603 tokenize(kdedirList, kdedirs, QString(QChar(KPATH_SEPARATOR)));
01604 }
01605 kdedirList.append(installPath("kdedir"));
01606
01607 QString execPrefix(EXEC_INSTALL_PREFIX);
01608 if (!execPrefix.isEmpty() && !kdedirList.contains(execPrefix))
01609 kdedirList.append(execPrefix);
01610 #ifdef __linux__
01611 const QString linuxExecPrefix = executablePrefix();
01612 if ( !linuxExecPrefix.isEmpty() )
01613 kdedirList.append( linuxExecPrefix );
01614 #endif
01615
01616
01617
01618 QString localKdeDir = readEnvPath(getuid() ? "KDEHOME" : "KDEROOTHOME");
01619 if (!localKdeDir.isEmpty())
01620 {
01621 if (localKdeDir[localKdeDir.length()-1] != '/')
01622 localKdeDir += '/';
01623 }
01624 else
01625 {
01626 #if defined(Q_WS_MACX)
01627 localKdeDir = QDir::homePath() + QLatin1String("/Library/Preferences/KDE/");
01628 #elif defined(Q_WS_WIN)
01629 WCHAR wPath[MAX_PATH+1];
01630 if ( SHGetFolderPathW(NULL, CSIDL_APPDATA, NULL, SHGFP_TYPE_CURRENT, wPath) == S_OK) {
01631 localKdeDir = QDir::fromNativeSeparators(QString::fromUtf16((const ushort *) wPath)) + QLatin1Char('/') + KDE_DEFAULT_HOME + QLatin1Char('/');
01632 } else {
01633 localKdeDir = QDir::homePath() + QLatin1Char('/') + KDE_DEFAULT_HOME + QLatin1Char('/');
01634 }
01635 #else
01636 localKdeDir = QDir::homePath() + QLatin1Char('/') + KDE_DEFAULT_HOME + QLatin1Char('/');
01637 #endif
01638 }
01639
01640 if (localKdeDir != "-/")
01641 {
01642 localKdeDir = KShell::tildeExpand(localKdeDir);
01643 addPrefix(localKdeDir);
01644 }
01645
01646 #ifdef Q_WS_MACX
01647
01648
01649 QDir bundleDir(mac_app_filename());
01650 if (bundleDir.dirName() == "MacOS") {
01651 bundleDir.cdUp();
01652
01653
01654 addPrefix(bundleDir.absolutePath());
01655 }
01656 #endif
01657
01658 QStringList::ConstIterator end(kdedirList.end());
01659 for (QStringList::ConstIterator it = kdedirList.constBegin();
01660 it != kdedirList.constEnd(); ++it)
01661 {
01662 const QString dir = KShell::tildeExpand(*it);
01663 addPrefix(dir);
01664 }
01665
01666
01667
01668 QStringList xdgdirList;
01669 QString xdgdirs = readEnvPath("XDG_CONFIG_DIRS");
01670 if (!xdgdirs.isEmpty())
01671 {
01672 tokenize(xdgdirList, xdgdirs, QString(QChar(KPATH_SEPARATOR)));
01673 }
01674 else
01675 {
01676 xdgdirList.clear();
01677 xdgdirList.append("/etc/xdg");
01678 #ifdef Q_WS_WIN
01679 xdgdirList.append(installPath("kdedir") + "etc/xdg");
01680 #else
01681 xdgdirList.append(KDESYSCONFDIR "/xdg");
01682 #endif
01683 }
01684
01685 QString localXdgDir = readEnvPath("XDG_CONFIG_HOME");
01686 if (!localXdgDir.isEmpty())
01687 {
01688 if (localXdgDir[localXdgDir.length()-1] != '/')
01689 localXdgDir += '/';
01690 }
01691 else
01692 {
01693 #ifdef Q_WS_MACX
01694 localXdgDir = QDir::homePath() + "/Library/Preferences/XDG/";
01695 #else
01696 localXdgDir = QDir::homePath() + "/.config/";
01697 #endif
01698 }
01699
01700 localXdgDir = KShell::tildeExpand(localXdgDir);
01701 addXdgConfigPrefix(localXdgDir);
01702
01703 for (QStringList::ConstIterator it = xdgdirList.constBegin();
01704 it != xdgdirList.constEnd(); ++it)
01705 {
01706 QString dir = KShell::tildeExpand(*it);
01707 addXdgConfigPrefix(dir);
01708 }
01709
01710
01711
01712 QStringList kdedirDataDirs;
01713 for (QStringList::ConstIterator it = kdedirList.constBegin();
01714 it != kdedirList.constEnd(); ++it) {
01715 QString dir = *it;
01716 if (!dir.endsWith('/'))
01717 dir += '/';
01718 kdedirDataDirs.append(dir+"share/");
01719 }
01720
01721 xdgdirs = readEnvPath("XDG_DATA_DIRS");
01722 if (!xdgdirs.isEmpty()) {
01723 tokenize(xdgdirList, xdgdirs, QString(QChar(KPATH_SEPARATOR)));
01724
01725
01726
01727 Q_FOREACH(const QString& dir, kdedirDataDirs) {
01728 if (!xdgdirList.contains(dir))
01729 xdgdirList.append(dir);
01730 }
01731 } else {
01732 xdgdirList = kdedirDataDirs;
01733 #ifndef Q_WS_WIN
01734 xdgdirList.append("/usr/local/share/");
01735 xdgdirList.append("/usr/share/");
01736 #endif
01737 }
01738
01739 localXdgDir = readEnvPath("XDG_DATA_HOME");
01740 if (!localXdgDir.isEmpty())
01741 {
01742 if (localXdgDir[localXdgDir.length()-1] != '/')
01743 localXdgDir += '/';
01744 }
01745 else
01746 {
01747 localXdgDir = QDir::homePath() + "/.local/share/";
01748 }
01749
01750 localXdgDir = KShell::tildeExpand(localXdgDir);
01751 addXdgDataPrefix(localXdgDir);
01752
01753 for (QStringList::ConstIterator it = xdgdirList.constBegin();
01754 it != xdgdirList.constEnd(); ++it)
01755 {
01756 QString dir = KShell::tildeExpand(*it);
01757 addXdgDataPrefix(dir);
01758 }
01759
01760
01761
01762 addResourceType("lib", 0, "lib" KDELIBSUFF "/");
01763
01764 uint index = 0;
01765 while (types_indices[index] != -1) {
01766 addResourceType(types_string + types_indices[index], 0, types_string + types_indices[index+1], true);
01767 index+=2;
01768 }
01769 addResourceType("exe", 0, "libexec/kde4", true );
01770
01771 addResourceDir("home", QDir::homePath(), false);
01772
01773 addResourceType("autostart", "xdgconf-autostart", "/");
01774 addResourceType("autostart", NULL, "share/autostart");
01775 }
01776
01777 static QStringList lookupProfiles(const QString &mapFile)
01778 {
01779 QStringList profiles;
01780
01781 if (mapFile.isEmpty() || !QFile::exists(mapFile))
01782 {
01783 profiles << "default";
01784 return profiles;
01785 }
01786
01787 struct passwd *pw = getpwuid(geteuid());
01788 if (!pw)
01789 {
01790 profiles << "default";
01791 return profiles;
01792 }
01793
01794 QByteArray user = pw->pw_name;
01795
01796 gid_t sup_gids[512];
01797 int sup_gids_nr = getgroups(512, sup_gids);
01798
01799 KConfig mapCfgFile(mapFile);
01800 KConfigGroup mapCfg(&mapCfgFile, "Users");
01801 if (mapCfg.hasKey(user.constData()))
01802 {
01803 profiles = mapCfg.readEntry(user.constData(), QStringList());
01804 return profiles;
01805 }
01806
01807 const KConfigGroup generalGrp(&mapCfgFile, "General");
01808 const QStringList groups = generalGrp.readEntry("groups", QStringList());
01809
01810 const KConfigGroup groupsGrp(&mapCfgFile, "Groups");
01811
01812 for( QStringList::ConstIterator it = groups.begin();
01813 it != groups.end(); ++it )
01814 {
01815 QByteArray grp = (*it).toUtf8();
01816
01817 struct group *grp_ent = getgrnam(grp);
01818 if (!grp_ent) continue;
01819 gid_t gid = grp_ent->gr_gid;
01820 if (pw->pw_gid == gid)
01821 {
01822
01823 profiles += groupsGrp.readEntry(*it, QStringList());
01824 }
01825 else
01826 {
01827 for(int i = 0; i < sup_gids_nr; i++)
01828 {
01829 if (sup_gids[i] == gid)
01830 {
01831
01832 profiles += groupsGrp.readEntry(*it, QStringList());
01833 break;
01834 }
01835 }
01836 }
01837 }
01838
01839 if (profiles.isEmpty())
01840 profiles << "default";
01841 return profiles;
01842 }
01843
01844 extern bool kde_kiosk_admin;
01845
01846 bool KStandardDirs::addCustomized(KConfig *config)
01847 {
01848 if (!d->m_checkRestrictions)
01849 return false;
01850
01851
01852
01853 int configdirs = resourceDirs("config").count();
01854
01855 if (true)
01856 {
01857
01858 QString group = QLatin1String("Directories");
01859 KConfigGroup cg(config, group);
01860
01861 QString kioskAdmin = cg.readEntry("kioskAdmin");
01862 if (!kioskAdmin.isEmpty() && !kde_kiosk_admin)
01863 {
01864 int i = kioskAdmin.indexOf(':');
01865 QString user = kioskAdmin.left(i);
01866 QString host = kioskAdmin.mid(i+1);
01867
01868 KUser thisUser;
01869 char hostname[ 256 ];
01870 hostname[ 0 ] = '\0';
01871 if (!gethostname( hostname, 255 ))
01872 hostname[sizeof(hostname)-1] = '\0';
01873
01874 if ((user == thisUser.loginName()) &&
01875 (host.isEmpty() || (host == hostname)))
01876 {
01877 kde_kiosk_admin = true;
01878 }
01879 }
01880
01881 bool readProfiles = true;
01882
01883 if (kde_kiosk_admin && !qgetenv("KDE_KIOSK_NO_PROFILES").isEmpty())
01884 readProfiles = false;
01885
01886 QString userMapFile = cg.readEntry("userProfileMapFile");
01887 QString profileDirsPrefix = cg.readEntry("profileDirsPrefix");
01888 if (!profileDirsPrefix.isEmpty() && !profileDirsPrefix.endsWith('/'))
01889 profileDirsPrefix.append("/");
01890
01891 QStringList profiles;
01892 if (readProfiles)
01893 profiles = lookupProfiles(userMapFile);
01894 QString profile;
01895
01896 bool priority = false;
01897 while(true)
01898 {
01899 KConfigGroup cg(config, group);
01900 const QStringList list = cg.readEntry("prefixes", QStringList());
01901 for (QStringList::ConstIterator it = list.begin(); it != list.end(); ++it)
01902 {
01903 addPrefix(*it, priority);
01904 addXdgConfigPrefix(*it+"/etc/xdg", priority);
01905 addXdgDataPrefix(*it+"/share", priority);
01906 }
01907
01908
01909 if (list.isEmpty() && !profile.isEmpty() && !profileDirsPrefix.isEmpty())
01910 {
01911 QString dir = profileDirsPrefix + profile;
01912 addPrefix(dir, priority);
01913 addXdgConfigPrefix(dir+"/etc/xdg", priority);
01914 addXdgDataPrefix(dir+"/share", priority);
01915 }
01916
01917
01918
01919 const QMap<QString, QString> entries = config->entryMap(group);
01920 for (QMap<QString, QString>::ConstIterator it2 = entries.begin();
01921 it2 != entries.end(); ++it2)
01922 {
01923 const QString key = it2.key();
01924 if (key.startsWith("dir_")) {
01925
01926 QStringList dirs = (*it2).split(',');
01927 QStringList::Iterator sIt(dirs.begin());
01928 QString resType = key.mid(4);
01929 for (; sIt != dirs.end(); ++sIt)
01930 {
01931 addResourceDir(resType.toLatin1(), *sIt, priority);
01932 }
01933 }
01934 }
01935 if (profiles.isEmpty())
01936 break;
01937 profile = profiles.back();
01938 group = QString::fromLatin1("Directories-%1").arg(profile);
01939 profiles.pop_back();
01940 priority = true;
01941 }
01942 }
01943
01944
01945 if (!kde_kiosk_admin || qgetenv("KDE_KIOSK_NO_RESTRICTIONS").isEmpty())
01946 {
01947 KConfigGroup cg(config, "KDE Resource Restrictions");
01948 const QMap<QString, QString> entries = cg.entryMap();
01949 for (QMap<QString, QString>::ConstIterator it2 = entries.begin();
01950 it2 != entries.end(); ++it2)
01951 {
01952 const QString key = it2.key();
01953 if (!cg.readEntry(key, true))
01954 {
01955 d->m_restrictionsActive = true;
01956 d->m_restrictions.insert(key.toLatin1(), true);
01957 d->m_dircache.remove(key.toLatin1());
01958 }
01959 }
01960 }
01961
01962
01963 bool configDirsChanged = (resourceDirs("config").count() != configdirs);
01964
01965 d->m_checkRestrictions = configDirsChanged;
01966
01967 return configDirsChanged;
01968 }
01969
01970 QString KStandardDirs::localkdedir() const
01971 {
01972
01973 return d->m_prefixes.first();
01974 }
01975
01976 QString KStandardDirs::localxdgdatadir() const
01977 {
01978
01979 return d->xdgdata_prefixes.first();
01980 }
01981
01982 QString KStandardDirs::localxdgconfdir() const
01983 {
01984
01985 return d->xdgconf_prefixes.first();
01986 }
01987
01988
01989
01990 QString KStandardDirs::locate( const char *type,
01991 const QString& filename, const KComponentData &cData)
01992 {
01993 return cData.dirs()->findResource(type, filename);
01994 }
01995
01996 QString KStandardDirs::locateLocal( const char *type,
01997 const QString& filename, const KComponentData &cData)
01998 {
01999 return locateLocal(type, filename, true, cData);
02000 }
02001
02002 QString KStandardDirs::locateLocal( const char *type,
02003 const QString& filename, bool createDir,
02004 const KComponentData &cData)
02005 {
02006
02007
02008 int slash = filename.lastIndexOf('/')+1;
02009 if (!slash) {
02010 return cData.dirs()->saveLocation(type, QString(), createDir) + filename;
02011 }
02012
02013
02014 QString dir = filename.left(slash);
02015 QString file = filename.mid(slash);
02016 return cData.dirs()->saveLocation(type, dir, createDir) + file;
02017 }
02018
02019 bool KStandardDirs::checkAccess(const QString& pathname, int mode)
02020 {
02021 int accessOK = KDE::access( pathname, mode );
02022 if ( accessOK == 0 )
02023 return true;
02024
02025
02026
02027
02028 if ( (mode & W_OK) == 0 )
02029 return false;
02030
02031
02032 if (!KDE::access( pathname, F_OK))
02033 return false;
02034
02035
02036 QString dirName(pathname);
02037 int pos = dirName.lastIndexOf('/');
02038 if ( pos == -1 )
02039 return false;
02040 else if ( pos == 0 )
02041 pos = 1;
02042
02043 dirName.truncate(pos);
02044
02045 accessOK = KDE::access( dirName, W_OK );
02046
02047 if ( accessOK == 0 )
02048 return true;
02049 else
02050 return false;
02051 }
02052