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

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
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.5.7
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