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

KDECore

kstandarddirs.cpp

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

KDECore

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

kdelibs

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