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