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