• 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             if((*pit)!=installprefix||installdir.isEmpty())
01000             {
01001                     for (QStringList::ConstIterator it = dirs.begin();
01002                          it != dirs.end(); ++it)
01003                     {
01004                         if ( (*it).startsWith('%'))
01005                             continue;
01006                         QString path = realPath( *pit + *it );
01007                         testdir.setPath(path);
01008                         if (local && restrictionActive)
01009                             continue;
01010                         if ((local || testdir.exists()) && !candidates.contains(path))
01011                             candidates.append(path);
01012                     }
01013                     local = false;
01014                 }
01015             else
01016             {
01017                     // we have a custom install path, so use this instead of <installprefix>/<relative dir>
01018                 testdir.setPath(installdir);
01019                     if(testdir.exists() && ! candidates.contains(installdir))
01020                         candidates.append(installdir);
01021             }
01022         }
01023         }
01024 
01025         // make sure we find the path where it's installed
01026         if (!installdir.isEmpty()) {
01027             bool ok = true;
01028             foreach (const QString &s, candidates) {
01029                 if (installdir.startsWith(s)) {
01030                     ok = false;
01031                     break;
01032                 }
01033             }
01034             if (ok)
01035                 candidates.append(installdir);
01036         }
01037 
01038         dirs = d->absolutes.value(type);
01039         if (!dirs.isEmpty())
01040             for (QStringList::ConstIterator it = dirs.begin();
01041                  it != dirs.end(); ++it)
01042             {
01043                 testdir.setPath(*it);
01044                 if (testdir.exists()) {
01045                     QString filename = realPath( *it );
01046                     if (!candidates.contains(filename)) {
01047                         candidates.append(filename);
01048                     }
01049                 }
01050             }
01051 
01052         d->dircache.insert(type, candidates);
01053     }
01054 
01055 #if 0
01056     kDebug(180) << "found dirs for resource " << type << ":";
01057     for (QStringList::ConstIterator pit = candidates.begin();
01058          pit != candidates.end();
01059          ++pit)
01060     {
01061         fprintf(stderr, "%s\n", qPrintable(*pit));
01062     }
01063 #endif
01064 
01065     return candidates;
01066 }
01067 
01068 QStringList KStandardDirs::systemPaths( const QString& pstr )
01069 {
01070     QStringList tokens;
01071     QString p = pstr;
01072 
01073     if( p.isEmpty() )
01074     {
01075         p = QString::fromLocal8Bit( qgetenv( "PATH" ) );
01076     }
01077 
01078     QString delimiters(QChar(KPATH_SEPARATOR));
01079     delimiters += "\b";
01080     tokenize( tokens, p, delimiters );
01081 
01082     QStringList exePaths;
01083 
01084     // split path using : or \b as delimiters
01085     for( int i = 0; i < tokens.count(); i++ )
01086     {
01087         exePaths << KShell::tildeExpand( tokens[ i ] );
01088     }
01089 
01090     return exePaths;
01091 }
01092 
01093 #ifdef Q_WS_MAC
01094 static QString getBundle( const QString& path, bool ignore )
01095 {
01096     kDebug(180) << "getBundle(" << path << ", " << ignore << ") called";
01097     QFileInfo info;
01098     QString bundle = path;
01099     bundle += ".app/Contents/MacOS/" + bundle.section('/', -1);
01100     info.setFile( bundle );
01101     if ( info.exists() && ( ignore || info.isExecutable() )
01102          && ( info.isFile() || info.isSymLink() ) ) {
01103         kDebug(180) << "getBundle(): returning " << bundle;
01104         return bundle;
01105     }
01106     return QString();
01107 }
01108 #endif
01109 
01110 static QString checkExecutable( const QString& path, bool ignoreExecBit )
01111 {
01112 #ifdef Q_WS_MAC
01113     QString bundle = getBundle( path, ignoreExecBit );
01114     if ( !bundle.isEmpty() ) {
01115         //kDebug(180) << "findExe(): returning " << bundle;
01116         return bundle;
01117     }
01118 #endif
01119     QFileInfo info( path );
01120     QFileInfo orig = info;
01121     if( info.exists() && info.isSymLink() ) 
01122         info = QFileInfo( info.canonicalFilePath() );
01123     if( info.exists() && ( ignoreExecBit || info.isExecutable() ) && info.isFile() ) {
01124         // return absolute path, but without symlinks resolved in order to prevent
01125         // problems with executables that work differently depending on name they are
01126         // run as (for example gunzip)
01127         orig.makeAbsolute();
01128         return orig.filePath();
01129     }
01130     //kDebug(180) << "checkExecutable(): failed, returning empty string";
01131     return QString();
01132 }
01133 
01134 QString KStandardDirs::findExe( const QString& appname,
01135                                 const QString& pstr,
01136                                 SearchOptions options )
01137 {
01138     //kDebug(180) << "findExe(" << appname << ", pstr, " << ignoreExecBit << ") called";
01139 
01140 #ifdef Q_WS_WIN
01141     QString real_appname = appname + ".exe";
01142 #else
01143     QString real_appname = appname;
01144 #endif
01145     QFileInfo info;
01146 
01147     // absolute or relative path?
01148     if (real_appname.contains(QDir::separator()))
01149     {
01150         //kDebug(180) << "findExe(): absolute path given";
01151         QString path = checkExecutable(real_appname, options & IgnoreExecBit);
01152         return path;
01153     }
01154 
01155     //kDebug(180) << "findExe(): relative path given";
01156 
01157     // Look in the default bin and libexec dirs. Maybe we should use the "exe" resource instead?
01158 
01159     QString p = installPath("libexec") + real_appname;
01160     QString result = checkExecutable(p, options & IgnoreExecBit);
01161     if (!result.isEmpty()) {
01162         //kDebug(180) << "findExe(): returning " << result;
01163         return result;
01164     }
01165 
01166     p = installPath("exe") + real_appname;
01167     result = checkExecutable(p, options & IgnoreExecBit);
01168     if (!result.isEmpty()) {
01169         //kDebug(180) << "findExe(): returning " << result;
01170         return result;
01171     }
01172 
01173     //kDebug(180) << "findExe(): checking system paths";
01174     const QStringList exePaths = systemPaths( pstr );
01175     for (QStringList::ConstIterator it = exePaths.begin(); it != exePaths.end(); ++it)
01176     {
01177         p = (*it) + '/';
01178         p += real_appname;
01179 
01180         // Check for executable in this tokenized path
01181         result = checkExecutable(p, options & IgnoreExecBit);
01182         if (!result.isEmpty()) {
01183             //kDebug(180) << "findExe(): returning " << result;
01184             return result;
01185         }
01186     }
01187 
01188     // If we reach here, the executable wasn't found.
01189     // So return empty string.
01190 
01191     //kDebug(180) << "findExe(): failed, nothing matched";
01192     return QString();
01193 }
01194 
01195 int KStandardDirs::findAllExe( QStringList& list, const QString& appname,
01196                                const QString& pstr, SearchOptions options )
01197 {
01198 #ifdef Q_WS_WIN
01199     QString real_appname = appname + ".exe";
01200 #else
01201     QString real_appname = appname;
01202 #endif
01203     QFileInfo info;
01204     QString p;
01205     list.clear();
01206 
01207     const QStringList exePaths = systemPaths( pstr );
01208     for (QStringList::ConstIterator it = exePaths.begin(); it != exePaths.end(); ++it)
01209     {
01210         p = (*it) + '/';
01211         p += real_appname;
01212 
01213 #ifdef Q_WS_MAC
01214         QString bundle = getBundle( p, (options & IgnoreExecBit) );
01215         if ( !bundle.isEmpty() ) {
01216             //kDebug(180) << "findExe(): returning " << bundle;
01217             list.append( bundle );
01218         }
01219 #endif
01220 
01221         info.setFile( p );
01222 
01223         if( info.exists() && ( ( options & IgnoreExecBit ) || info.isExecutable())
01224             && info.isFile() ) {
01225             list.append( p );
01226         }
01227     }
01228 
01229     return list.count();
01230 }
01231 
01232 static inline QString equalizePath(QString &str)
01233 {
01234 #ifdef Q_WS_WIN
01235     // filter pathes through QFileInfo to have always
01236     // the same case for drive letters
01237     QFileInfo f(str);
01238     if (f.isAbsolute())
01239         return f.absoluteFilePath();
01240     else
01241 #endif
01242         return str;
01243 }
01244 
01245 static int tokenize( QStringList& tokens, const QString& str,
01246                      const QString& delim )
01247 {
01248     int len = str.length();
01249     QString token = "";
01250 
01251     for( int index = 0; index < len; index++)
01252     {
01253         if ( delim.contains( str[ index ] ) )
01254         {
01255             tokens.append( equalizePath(token) );
01256             token = "";
01257         }
01258         else
01259         {
01260             token += str[ index ];
01261         }
01262     }
01263     if ( !token.isEmpty() )
01264     {
01265         tokens.append( equalizePath(token) );
01266     }
01267 
01268     return tokens.count();
01269 }
01270 
01271 QString KStandardDirs::kde_default(const char *type)
01272 {
01273     return QString('%') + type + '/';
01274 }
01275 
01276 QString KStandardDirs::saveLocation(const char *type,
01277                                     const QString& suffix,
01278                                     bool create) const
01279 {
01280     QString path = d->savelocations.value(type);
01281     if (path.isEmpty())
01282     {
01283         QStringList dirs = d->relatives.value(type);
01284         if (dirs.isEmpty() && (
01285                 (strcmp(type, "socket") == 0) ||
01286                 (strcmp(type, "tmp") == 0) ||
01287                 (strcmp(type, "cache") == 0) ))
01288         {
01289             (void) resourceDirs(type); // Generate socket|tmp|cache resource.
01290             dirs = d->relatives.value(type); // Search again.
01291         }
01292         if (!dirs.isEmpty())
01293         {
01294             path = dirs.last();
01295 
01296             if ( path.startsWith('%'))
01297             {
01298                 // grab the "data" from "%data/apps"
01299                 QString rel = path.mid(1, path.indexOf('/') - 1);
01300                 QString rest = path.mid(path.indexOf('/') + 1);
01301                 QString basepath = saveLocation(rel.toUtf8().constData());
01302                 path = basepath + rest;
01303             } else
01304 
01305                 // Check for existence of typed directory + suffix
01306                 if (strncmp(type, "xdgdata-", 8) == 0) {
01307                     path = realPath( localxdgdatadir() + path ) ;
01308                 } else if (strncmp(type, "xdgconf-", 8) == 0) {
01309                     path = realPath( localxdgconfdir() + path );
01310                 } else {
01311                     path = realPath( localkdedir() + path );
01312                 }
01313         }
01314         else {
01315             dirs = d->absolutes.value(type);
01316             if (dirs.isEmpty()) {
01317                 qFatal("KStandardDirs: The resource type %s is not registered", type);
01318             }
01319             path = realPath(dirs.last());
01320         }
01321 
01322         d->savelocations.insert(type, path.endsWith('/') ? path : path + '/');
01323     }
01324     QString fullPath = path + suffix;
01325 
01326     KDE_struct_stat st;
01327     if (KDE_stat(QFile::encodeName(fullPath), &st) != 0 || !(S_ISDIR(st.st_mode))) {
01328         if(!create) {
01329 #ifndef NDEBUG
01330             kDebug(180) << QString("save location %1 doesn't exist").arg(fullPath);
01331 #endif
01332             return fullPath;
01333         }
01334         if(!makeDir(fullPath, 0700)) {
01335             return fullPath;
01336         }
01337         d->dircache.remove(type);
01338     }
01339     if (!fullPath.endsWith('/'))
01340         fullPath += '/';
01341     return fullPath;
01342 }
01343 
01344 QString KStandardDirs::relativeLocation(const char *type, const QString &absPath)
01345 {
01346     QString fullPath = absPath;
01347     int i = absPath.lastIndexOf('/');
01348     if (i != -1) {
01349         fullPath = realFilePath(absPath); // Normalize
01350     }
01351 
01352     const QStringList candidates = resourceDirs(type);
01353 
01354     for (QStringList::ConstIterator it = candidates.begin();
01355          it != candidates.end(); ++it) {
01356         if (fullPath.startsWith(*it)) {
01357             return fullPath.mid((*it).length());
01358         }
01359     }
01360     return absPath;
01361 }
01362 
01363 
01364 bool KStandardDirs::makeDir(const QString& dir, int mode)
01365 {
01366     // we want an absolute path
01367     if (QDir::isRelativePath(dir))
01368         return false;
01369 
01370     QString target = dir;
01371     uint len = target.length();
01372 
01373     // append trailing slash if missing
01374     if (dir.at(len - 1) != '/')
01375         target += '/';
01376 
01377     QString base("");
01378     uint i = 1;
01379 
01380     while( i < len )
01381     {
01382         KDE_struct_stat st;
01383         int pos = target.indexOf('/', i);
01384         base += target.mid(i - 1, pos - i + 1);
01385         QByteArray baseEncoded = QFile::encodeName(base);
01386         // bail out if we encountered a problem
01387         if (KDE_stat(baseEncoded, &st) != 0)
01388         {
01389             // Directory does not exist....
01390             // Or maybe a dangling symlink ?
01391             if (KDE_lstat(baseEncoded, &st) == 0)
01392                 (void)unlink(baseEncoded); // try removing
01393 
01394             if (KDE_mkdir(baseEncoded, static_cast<mode_t>(mode)) != 0) {
01395                 baseEncoded.prepend( "trying to create local folder " );
01396                 perror(baseEncoded.constData());
01397                 return false; // Couldn't create it :-(
01398             }
01399         }
01400         i = pos + 1;
01401     }
01402     return true;
01403 }
01404 
01405 static QString readEnvPath(const char *env)
01406 {
01407     QByteArray c_path = qgetenv(env);
01408     if (c_path.isEmpty())
01409         return QString();
01410     return QDir::fromNativeSeparators(QFile::decodeName(c_path));
01411 }
01412 
01413 #ifdef __linux__
01414 static QString executablePrefix()
01415 {
01416     char path_buffer[MAXPATHLEN + 1];
01417     path_buffer[MAXPATHLEN] = 0;
01418     int length = readlink ("/proc/self/exe", path_buffer, MAXPATHLEN);
01419     if (length == -1)
01420         return QString();
01421 
01422     path_buffer[length] = '\0';
01423 
01424     QString path = QFile::decodeName(path_buffer);
01425 
01426     if(path.isEmpty())
01427         return QString();
01428 
01429     int pos = path.lastIndexOf('/'); // Skip filename
01430     if(pos <= 0)
01431         return QString();
01432     pos = path.lastIndexOf('/', pos - 1); // Skip last directory
01433     if(pos <= 0)
01434         return QString();
01435 
01436     return path.left(pos);
01437 }
01438 #endif
01439 
01440 void KStandardDirs::addResourcesFrom_krcdirs()
01441 {
01442     QString localFile = QDir::currentPath() + QDir::separator() + ".krcdirs";
01443     if (!QFile::exists(localFile))
01444         return;
01445 
01446     QSettings iniFile(localFile, QSettings::IniFormat);
01447     iniFile.beginGroup("KStandardDirs");
01448     const QStringList resources = iniFile.allKeys();
01449     foreach(const QString &key, resources)
01450     {
01451         QDir path(iniFile.value(key).toString());
01452         if (!path.exists())
01453             continue;
01454 
01455         if(path.makeAbsolute())
01456             addResourceDir(key.toAscii(), path.path(), false);
01457     }
01458 }
01459 
01460 void KStandardDirs::addKDEDefaults()
01461 {
01462     addResourcesFrom_krcdirs();
01463 
01464     QStringList kdedirList;
01465 
01466     // begin KDEDIRS
01467     QString kdedirs = readEnvPath("KDEDIRS");
01468     if (!kdedirs.isEmpty())
01469     {
01470         tokenize(kdedirList, kdedirs, QString(QChar(KPATH_SEPARATOR)));
01471     }
01472     kdedirList.append(installPath("kdedir"));
01473 
01474     QString execPrefix(EXEC_INSTALL_PREFIX);
01475     if (!execPrefix.isEmpty() && !kdedirList.contains(execPrefix))
01476         kdedirList.append(execPrefix);
01477 #ifdef __linux__
01478     const QString linuxExecPrefix = executablePrefix();
01479     if ( !linuxExecPrefix.isEmpty() )
01480         kdedirList.append( linuxExecPrefix );
01481 #endif
01482 
01483     // We treat root differently to prevent a "su" shell messing up the
01484     // file permissions in the user's home directory.
01485     QString localKdeDir = readEnvPath(getuid() ? "KDEHOME" : "KDEROOTHOME");
01486     if (!localKdeDir.isEmpty())
01487     {
01488         if (localKdeDir[localKdeDir.length()-1] != '/')
01489             localKdeDir += '/';
01490     }
01491     else
01492     {
01493 #ifdef Q_WS_MACX
01494         localKdeDir =  QDir::homePath() + QLatin1String("/Library/Preferences/KDE/");
01495 #else
01496         localKdeDir =  QDir::homePath() + QLatin1Char('/') + KDE_DEFAULT_HOME + QLatin1Char('/');
01497 #endif
01498     }
01499 
01500     if (localKdeDir != "-/")
01501     {
01502         localKdeDir = KShell::tildeExpand(localKdeDir);
01503         addPrefix(localKdeDir);
01504     }
01505 
01506 #ifdef Q_WS_MACX
01507     // Adds the "Contents" directory of the current application bundle to
01508     // the search path. This way bundled resources can be found.
01509     QDir bundleDir(mac_app_filename());
01510     if (bundleDir.dirName() == "MacOS") { // just to be sure we're in a bundle
01511         bundleDir.cdUp();
01512         // now dirName should be "Contents". In there we can find our normal
01513         // dir-structure, beginning with "share"
01514         addPrefix(bundleDir.absolutePath());
01515     }
01516 #endif
01517 
01518     QStringList::ConstIterator end(kdedirList.end());
01519     for (QStringList::ConstIterator it = kdedirList.begin();
01520          it != end; ++it)
01521     {
01522         const QString dir = KShell::tildeExpand(*it);
01523         addPrefix(dir);
01524     }
01525     // end KDEDIRS
01526 
01527     // begin XDG_CONFIG_XXX
01528     QStringList xdgdirList;
01529     QString xdgdirs = readEnvPath("XDG_CONFIG_DIRS");
01530     if (!xdgdirs.isEmpty())
01531     {
01532         tokenize(xdgdirList, xdgdirs, QString(QChar(KPATH_SEPARATOR)));
01533     }
01534     else
01535     {
01536         xdgdirList.clear();
01537         xdgdirList.append("/etc/xdg");
01538 #ifdef Q_WS_WIN
01539         xdgdirList.append(installPath("kdedir") + "etc/xdg");
01540 #else
01541         xdgdirList.append(KDESYSCONFDIR "/xdg");
01542 #endif
01543     }
01544 
01545     QString localXdgDir = readEnvPath("XDG_CONFIG_HOME");
01546     if (!localXdgDir.isEmpty())
01547     {
01548         if (localXdgDir[localXdgDir.length()-1] != '/')
01549             localXdgDir += '/';
01550     }
01551     else
01552     {
01553 #ifdef Q_WS_MACX
01554         localXdgDir =  QDir::homePath() + "/Library/Preferences/XDG/";
01555 #else
01556         localXdgDir =  QDir::homePath() + "/.config/";
01557 #endif
01558     }
01559 
01560     localXdgDir = KShell::tildeExpand(localXdgDir);
01561     addXdgConfigPrefix(localXdgDir);
01562 
01563     for (QStringList::ConstIterator it = xdgdirList.begin();
01564          it != xdgdirList.end(); ++it)
01565     {
01566         QString dir = KShell::tildeExpand(*it);
01567         addXdgConfigPrefix(dir);
01568     }
01569     // end XDG_CONFIG_XXX
01570 
01571     // begin XDG_DATA_XXX
01572     QStringList kdedirDataDirs;
01573     for (QStringList::ConstIterator it = kdedirList.begin();
01574          it != kdedirList.end(); ++it) {
01575         QString dir = *it;
01576         if (!dir.endsWith('/'))
01577             dir += '/';
01578         kdedirDataDirs.append(dir+"share/");
01579     }
01580 
01581     xdgdirs = readEnvPath("XDG_DATA_DIRS");
01582     if (!xdgdirs.isEmpty()) {
01583         tokenize(xdgdirList, xdgdirs, QString(QChar(KPATH_SEPARATOR)));
01584         // Ensure the kdedirDataDirs are in there too,
01585         // otherwise resourceDirs() will add kdedir/share/applications/kde4
01586         // as returned by installPath(), and that's incorrect.
01587         Q_FOREACH(const QString& dir, kdedirDataDirs) {
01588             if (!xdgdirList.contains(dir))
01589                 xdgdirList.append(dir);
01590         }
01591     } else {
01592         xdgdirList = kdedirDataDirs;
01593         xdgdirList.append("/usr/local/share/");
01594         xdgdirList.append("/usr/share/");
01595     }
01596 
01597     localXdgDir = readEnvPath("XDG_DATA_HOME");
01598     if (!localXdgDir.isEmpty())
01599     {
01600         if (localXdgDir[localXdgDir.length()-1] != '/')
01601             localXdgDir += '/';
01602     }
01603     else
01604     {
01605         localXdgDir = QDir::homePath() + "/.local/share/";
01606     }
01607 
01608     localXdgDir = KShell::tildeExpand(localXdgDir);
01609     addXdgDataPrefix(localXdgDir);
01610 
01611     for (QStringList::ConstIterator it = xdgdirList.begin();
01612          it != xdgdirList.end(); ++it)
01613     {
01614         QString dir = KShell::tildeExpand(*it);
01615         addXdgDataPrefix(dir);
01616     }
01617     // end XDG_DATA_XXX
01618 
01619 
01620     addResourceType("lib", 0, "lib" KDELIBSUFF "/");
01621 
01622     uint index = 0;
01623     while (types_indices[index] != -1) {
01624         addResourceType(types_string + types_indices[index], 0, types_string + types_indices[index+1], true);
01625         index+=2;
01626     }
01627     addResourceType("exe", "lib", "kde4/libexec", true );
01628 
01629     addResourceDir("home", QDir::homePath(), false);
01630 }
01631 
01632 static QStringList lookupProfiles(const QString &mapFile)
01633 {
01634     QStringList profiles;
01635 
01636     if (mapFile.isEmpty() || !QFile::exists(mapFile))
01637     {
01638         profiles << "default";
01639         return profiles;
01640     }
01641 
01642     struct passwd *pw = getpwuid(geteuid());
01643     if (!pw)
01644     {
01645         profiles << "default";
01646         return profiles; // Not good
01647     }
01648 
01649     QByteArray user = pw->pw_name;
01650 
01651     gid_t sup_gids[512];
01652     int sup_gids_nr = getgroups(512, sup_gids);
01653 
01654     KConfig mapCfgFile(mapFile);
01655     KConfigGroup mapCfg(&mapCfgFile, "Users");
01656     if (mapCfg.hasKey(user.constData()))
01657     {
01658         profiles = mapCfg.readEntry(user.constData(), QStringList());
01659         return profiles;
01660     }
01661 
01662     const KConfigGroup generalGrp(&mapCfgFile, "General");
01663     const QStringList groups = generalGrp.readEntry("groups", QStringList());
01664 
01665     const KConfigGroup groupsGrp(&mapCfgFile, "Groups");
01666 
01667     for( QStringList::ConstIterator it = groups.begin();
01668          it != groups.end(); ++it )
01669     {
01670         QByteArray grp = (*it).toUtf8();
01671         // Check if user is in this group
01672         struct group *grp_ent = getgrnam(grp);
01673         if (!grp_ent) continue;
01674         gid_t gid = grp_ent->gr_gid;
01675         if (pw->pw_gid == gid)
01676         {
01677             // User is in this group --> add profiles
01678             profiles += groupsGrp.readEntry(*it, QStringList());
01679         }
01680         else
01681         {
01682             for(int i = 0; i < sup_gids_nr; i++)
01683             {
01684                 if (sup_gids[i] == gid)
01685                 {
01686                     // User is in this group --> add profiles
01687                     profiles += groupsGrp.readEntry(*it, QStringList());
01688                     break;
01689                 }
01690             }
01691         }
01692     }
01693 
01694     if (profiles.isEmpty())
01695         profiles << "default";
01696     return profiles;
01697 }
01698 
01699 extern bool kde_kiosk_admin;
01700 
01701 bool KStandardDirs::addCustomized(KConfig *config)
01702 {
01703     if (!d->checkRestrictions) // there are already customized entries
01704         return false; // we just quit and hope they are the right ones
01705 
01706     // save the numbers of config directories. If this changes,
01707     // we will return true to give KConfig a chance to reparse
01708     int configdirs = resourceDirs("config").count();
01709 
01710     if (true)
01711     {
01712         // reading the prefixes in
01713         QString group = QLatin1String("Directories");
01714         KConfigGroup cg(config, group);
01715 
01716         QString kioskAdmin = cg.readEntry("kioskAdmin");
01717         if (!kioskAdmin.isEmpty() && !kde_kiosk_admin)
01718         {
01719             int i = kioskAdmin.indexOf(':');
01720             QString user = kioskAdmin.left(i);
01721             QString host = kioskAdmin.mid(i+1);
01722 
01723             KUser thisUser;
01724             char hostname[ 256 ];
01725             hostname[ 0 ] = '\0';
01726             if (!gethostname( hostname, 255 ))
01727                 hostname[sizeof(hostname)-1] = '\0';
01728 
01729             if ((user == thisUser.loginName()) &&
01730                 (host.isEmpty() || (host == hostname)))
01731             {
01732                 kde_kiosk_admin = true;
01733             }
01734         }
01735 
01736         bool readProfiles = true;
01737 
01738         if (kde_kiosk_admin && !qgetenv("KDE_KIOSK_NO_PROFILES").isEmpty())
01739             readProfiles = false;
01740 
01741         QString userMapFile = cg.readEntry("userProfileMapFile");
01742         QString profileDirsPrefix = cg.readEntry("profileDirsPrefix");
01743         if (!profileDirsPrefix.isEmpty() && !profileDirsPrefix.endsWith('/'))
01744             profileDirsPrefix.append("/");
01745 
01746         QStringList profiles;
01747         if (readProfiles)
01748             profiles = lookupProfiles(userMapFile);
01749         QString profile;
01750 
01751         bool priority = false;
01752         while(true)
01753         {
01754             KConfigGroup cg(config, group);
01755             const QStringList list = cg.readEntry("prefixes", QStringList());
01756             for (QStringList::ConstIterator it = list.begin(); it != list.end(); ++it)
01757             {
01758                 addPrefix(*it, priority);
01759                 addXdgConfigPrefix(*it+"/etc/xdg", priority);
01760                 addXdgDataPrefix(*it+"/share", priority);
01761             }
01762             // If there are no prefixes defined, check if there is a directory
01763             // for this profile under <profileDirsPrefix>
01764             if (list.isEmpty() && !profile.isEmpty() && !profileDirsPrefix.isEmpty())
01765             {
01766                 QString dir = profileDirsPrefix + profile;
01767                 addPrefix(dir, priority);
01768                 addXdgConfigPrefix(dir+"/etc/xdg", priority);
01769                 addXdgDataPrefix(dir+"/share", priority);
01770             }
01771 
01772             // iterating over all entries in the group Directories
01773             // to find entries that start with dir_$type
01774             const QMap<QString, QString> entries = config->entryMap(group);
01775             for (QMap<QString, QString>::ConstIterator it2 = entries.begin();
01776                  it2 != entries.end(); it2++)
01777             {
01778                 const QString key = it2.key();
01779                 if (key.startsWith("dir_")) {
01780                     // generate directory list, there may be more than 1.
01781                     QStringList dirs = (*it2).split(',');
01782                     QStringList::Iterator sIt(dirs.begin());
01783                     QString resType = key.mid(4);
01784                     for (; sIt != dirs.end(); ++sIt)
01785                     {
01786                         addResourceDir(resType.toLatin1(), *sIt, priority);
01787                     }
01788                 }
01789             }
01790             if (profiles.isEmpty())
01791                 break;
01792             profile = profiles.back();
01793             group = QString::fromLatin1("Directories-%1").arg(profile);
01794             profiles.pop_back();
01795             priority = true;
01796         }
01797     }
01798 
01799     // Process KIOSK restrictions.
01800     if (!kde_kiosk_admin || qgetenv("KDE_KIOSK_NO_RESTRICTIONS").isEmpty())
01801     {
01802         KConfigGroup cg(config, "KDE Resource Restrictions");
01803         const QMap<QString, QString> entries = cg.entryMap();
01804         for (QMap<QString, QString>::ConstIterator it2 = entries.begin();
01805              it2 != entries.end(); it2++)
01806         {
01807             const QString key = it2.key();
01808             if (!cg.readEntry(key, true))
01809             {
01810                 d->restrictionsActive = true;
01811                 d->restrictions.insert(key.toLatin1(), true);
01812                 d->dircache.remove(key.toLatin1());
01813             }
01814         }
01815     }
01816 
01817     // check if the number of config dirs changed
01818     bool configDirsChanged = (resourceDirs("config").count() != configdirs);
01819     // If the config dirs changed, we check kiosk restrictions again.
01820     d->checkRestrictions = configDirsChanged;
01821     // return true if the number of config dirs changed: reparse config file
01822     return configDirsChanged;
01823 }
01824 
01825 QString KStandardDirs::localkdedir() const
01826 {
01827     // Return the prefix to use for saving
01828     return d->prefixes.first();
01829 }
01830 
01831 QString KStandardDirs::localxdgdatadir() const
01832 {
01833     // Return the prefix to use for saving
01834     return d->xdgdata_prefixes.first();
01835 }
01836 
01837 QString KStandardDirs::localxdgconfdir() const
01838 {
01839     // Return the prefix to use for saving
01840     return d->xdgconf_prefixes.first();
01841 }
01842 
01843 
01844 // just to make code more readable without macros
01845 QString KStandardDirs::locate( const char *type,
01846                                const QString& filename, const KComponentData &cData)
01847 {
01848     return cData.dirs()->findResource(type, filename);
01849 }
01850 
01851 QString KStandardDirs::locateLocal( const char *type,
01852                                     const QString& filename, const KComponentData &cData)
01853 {
01854     return locateLocal(type, filename, true, cData);
01855 }
01856 
01857 QString KStandardDirs::locateLocal( const char *type,
01858                                     const QString& filename, bool createDir,
01859                                     const KComponentData &cData)
01860 {
01861     // try to find slashes. If there are some, we have to
01862     // create the subdir first
01863     int slash = filename.lastIndexOf('/')+1;
01864     if (!slash) { // only one filename
01865         return cData.dirs()->saveLocation(type, QString(), createDir) + filename;
01866     }
01867 
01868     // split path from filename
01869     QString dir = filename.left(slash);
01870     QString file = filename.mid(slash);
01871     return cData.dirs()->saveLocation(type, dir, createDir) + file;
01872 }
01873 
01874 bool KStandardDirs::checkAccess(const QString& pathname, int mode)
01875 {
01876     int accessOK = access( QFile::encodeName(pathname), mode );
01877     if ( accessOK == 0 )
01878         return true;  // OK, I can really access the file
01879 
01880     // else
01881     // if we want to write the file would be created. Check, if the
01882     // user may write to the directory to create the file.
01883     if ( (mode & W_OK) == 0 )
01884         return false;   // Check for write access is not part of mode => bail out
01885 
01886 
01887     if (!access( QFile::encodeName(pathname), F_OK)) // if it already exists
01888         return false;
01889 
01890     //strip the filename (everything until '/' from the end
01891     QString dirName(pathname);
01892     int pos = dirName.lastIndexOf('/');
01893     if ( pos == -1 )
01894         return false;   // No path in argument. This is evil, we won't allow this
01895     else if ( pos == 0 ) // don't turn e.g. /root into an empty string
01896         pos = 1;
01897 
01898     dirName.truncate(pos); // strip everything starting from the last '/'
01899 
01900     accessOK = access( QFile::encodeName(dirName), W_OK );
01901     // -?- Can I write to the accessed diretory
01902     if ( accessOK == 0 )
01903         return true;  // Yes
01904     else
01905         return false; // No
01906 }
01907 

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.4
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