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

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
  • KDEWebKit
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.7.3
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