• Skip to content
  • Skip to link menu
KDE 4.1 API Reference
  • KDE API Reference
  • kdelibs
  • Sitemap
  • Contact Us
 

KDECore

kstandarddirs.cpp

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

KDECore

Skip menu "KDECore"
  • Main Page
  • Modules
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

kdelibs

Skip menu "kdelibs"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • Kate
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • KIO
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • Kross
  • KUtils
  • Nepomuk
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.5.6
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal