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 const QStringList dirs = m_relatives.value(type); 01106 const QString typeInstallPath = installPath(type); // could be empty 01107 // better #ifdef incasesensitive_filesystem 01108 #ifdef Q_WS_WIN 01109 const QString installdir = typeInstallPath.isEmpty() ? QString() : realPath(typeInstallPath).toLower(); 01110 const QString installprefix = installPath("kdedir").toLower(); 01111 #else 01112 const QString installdir = typeInstallPath.isEmpty() ? QString() : realPath(typeInstallPath); 01113 const QString installprefix = installPath("kdedir"); 01114 #endif 01115 if (!dirs.isEmpty()) 01116 { 01117 bool local = true; 01118 01119 for (QStringList::ConstIterator it = dirs.constBegin(); 01120 it != dirs.constEnd(); ++it) 01121 { 01122 if ((*it).startsWith(QLatin1Char('%'))) { 01123 // grab the "data" from "%data/apps" 01124 const int pos = (*it).indexOf(QLatin1Char('/')); 01125 QString rel = (*it).mid(1, pos - 1); 01126 QString rest = (*it).mid(pos + 1); 01127 const QStringList basedirs = resourceDirs(rel.toUtf8().constData(), subdirForRestrictions); 01128 for (QStringList::ConstIterator it2 = basedirs.begin(); 01129 it2 != basedirs.end(); ++it2) 01130 { 01131 #ifdef Q_WS_WIN 01132 const QString path = realPath( *it2 + rest ).toLower(); 01133 #else 01134 const QString path = realPath( *it2 + rest ); 01135 #endif 01136 testdir.setPath(path); 01137 if ((local || testdir.exists()) && !candidates.contains(path)) 01138 candidates.append(path); 01139 local = false; 01140 } 01141 } 01142 } 01143 01144 const QStringList *prefixList = 0; 01145 if (strncmp(type, "xdgdata-", 8) == 0) 01146 prefixList = &(xdgdata_prefixes); 01147 else if (strncmp(type, "xdgconf-", 8) == 0) 01148 prefixList = &(xdgconf_prefixes); 01149 else 01150 prefixList = &m_prefixes; 01151 01152 for (QStringList::ConstIterator pit = prefixList->begin(); 01153 pit != prefixList->end(); 01154 ++pit) 01155 { 01156 if((*pit)!=installprefix||installdir.isEmpty()) 01157 { 01158 for (QStringList::ConstIterator it = dirs.constBegin(); 01159 it != dirs.constEnd(); ++it) 01160 { 01161 if ((*it).startsWith(QLatin1Char('%'))) 01162 continue; 01163 #ifdef Q_WS_WIN 01164 const QString path = realPath( *pit + *it ).toLower(); 01165 #else 01166 const QString path = realPath( *pit + *it ); 01167 #endif 01168 testdir.setPath(path); 01169 if (local && restrictionActive) 01170 continue; 01171 if ((local || testdir.exists()) && !candidates.contains(path)) 01172 candidates.append(path); 01173 } 01174 local = false; 01175 } 01176 else 01177 { 01178 // we have a custom install path, so use this instead of <installprefix>/<relative dir> 01179 testdir.setPath(installdir); 01180 if(testdir.exists() && ! candidates.contains(installdir)) 01181 candidates.append(installdir); 01182 } 01183 } 01184 } 01185 01186 // make sure we find the path where it's installed 01187 if (!installdir.isEmpty()) { 01188 bool ok = true; 01189 foreach (const QString &s, candidates) { 01190 if (installdir.startsWith(s)) { 01191 ok = false; 01192 break; 01193 } 01194 } 01195 if (ok) 01196 candidates.append(installdir); 01197 } 01198 01199 const QStringList absDirs = m_absolutes.value(type); 01200 for (QStringList::ConstIterator it = absDirs.constBegin(); 01201 it != absDirs.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 //kDebug(180) << "findExe(): checking system paths"; 01379 const QStringList exePaths = systemPaths( pstr ); 01380 for (QStringList::ConstIterator it = exePaths.begin(); it != exePaths.end(); ++it) 01381 { 01382 p = (*it) + QLatin1Char('/'); 01383 p += appname; 01384 01385 // Check for executable in this tokenized path 01386 result = checkExecutable(p, options & IgnoreExecBit); 01387 if (!result.isEmpty()) { 01388 //kDebug(180) << "findExe(): returning " << result; 01389 return result; 01390 } 01391 } 01392 01393 // Not found in PATH, look into the KDE-specific bin dir ("exe" resource) 01394 p = installPath("exe"); 01395 p += appname; 01396 result = checkExecutable(p, options & IgnoreExecBit); 01397 if (!result.isEmpty()) { 01398 //kDebug(180) << "findExe(): returning " << result; 01399 return result; 01400 } 01401 01402 // If we reach here, the executable wasn't found. 01403 // So return empty string. 01404 01405 //kDebug(180) << "findExe(): failed, nothing matched"; 01406 return QString(); 01407 } 01408 01409 int KStandardDirs::findAllExe( QStringList& list, const QString& appname, 01410 const QString& pstr, SearchOptions options ) 01411 { 01412 #ifdef Q_OS_WIN 01413 QStringList executable_extensions = executableExtensions(); 01414 if (!executable_extensions.contains(appname.section(QLatin1Char('.'), -1, -1, QString::SectionIncludeLeadingSep), Qt::CaseInsensitive)) { 01415 int total = 0; 01416 foreach (const QString& extension, executable_extensions) { 01417 total += findAllExe (list, appname + extension, pstr, options); 01418 } 01419 return total; 01420 } 01421 #endif 01422 QFileInfo info; 01423 QString p; 01424 list.clear(); 01425 01426 const QStringList exePaths = systemPaths( pstr ); 01427 for (QStringList::ConstIterator it = exePaths.begin(); it != exePaths.end(); ++it) 01428 { 01429 p = (*it) + QLatin1Char('/'); 01430 p += appname; 01431 01432 #ifdef Q_WS_MAC 01433 QString bundle = getBundle( p, (options & IgnoreExecBit) ); 01434 if ( !bundle.isEmpty() ) { 01435 //kDebug(180) << "findExe(): returning " << bundle; 01436 list.append( bundle ); 01437 } 01438 #endif 01439 01440 info.setFile( p ); 01441 01442 if( info.exists() && ( ( options & IgnoreExecBit ) || info.isExecutable()) 01443 && info.isFile() ) { 01444 list.append( p ); 01445 } 01446 } 01447 01448 return list.count(); 01449 } 01450 01451 static inline QString equalizePath(QString &str) 01452 { 01453 #ifdef Q_WS_WIN 01454 // filter pathes through QFileInfo to have always 01455 // the same case for drive letters 01456 QFileInfo f(str); 01457 if (f.isAbsolute()) 01458 return f.absoluteFilePath(); 01459 else 01460 #endif 01461 return str; 01462 } 01463 01464 static void tokenize(QStringList& tokens, const QString& str, 01465 const QString& delim) 01466 { 01467 const int len = str.length(); 01468 QString token; 01469 01470 for(int index = 0; index < len; index++) { 01471 if (delim.contains(str[index])) { 01472 tokens.append(equalizePath(token)); 01473 token.clear(); 01474 } else { 01475 token += str[index]; 01476 } 01477 } 01478 if (!token.isEmpty()) { 01479 tokens.append(equalizePath(token)); 01480 } 01481 } 01482 01483 #ifndef KDE_NO_DEPRECATED 01484 QString KStandardDirs::kde_default(const char *type) 01485 { 01486 return QString(QLatin1Char('%')) + QString::fromLatin1(type) + QLatin1Char('/'); 01487 } 01488 #endif 01489 01490 QString KStandardDirs::saveLocation(const char *type, 01491 const QString& suffix, 01492 bool create) const 01493 { 01494 QMutexLocker lock(&d->m_cacheMutex); 01495 QString path = d->m_savelocations.value(type); 01496 if (path.isEmpty()) 01497 { 01498 QStringList dirs = d->m_relatives.value(type); 01499 if (dirs.isEmpty() && ( 01500 (strcmp(type, "socket") == 0) || 01501 (strcmp(type, "tmp") == 0) || 01502 (strcmp(type, "cache") == 0) )) 01503 { 01504 (void) resourceDirs(type); // Generate socket|tmp|cache resource. 01505 dirs = d->m_relatives.value(type); // Search again. 01506 } 01507 if (!dirs.isEmpty()) 01508 { 01509 path = dirs.first(); 01510 01511 if (path.startsWith(QLatin1Char('%'))) { 01512 // grab the "data" from "%data/apps" 01513 const int pos = path.indexOf(QLatin1Char('/')); 01514 QString rel = path.mid(1, pos - 1); 01515 QString rest = path.mid(pos + 1); 01516 QString basepath = saveLocation(rel.toUtf8().constData()); 01517 path = basepath + rest; 01518 } else 01519 01520 // Check for existence of typed directory + suffix 01521 if (strncmp(type, "xdgdata-", 8) == 0) { 01522 path = realPath( localxdgdatadir() + path ) ; 01523 } else if (strncmp(type, "xdgconf-", 8) == 0) { 01524 path = realPath( localxdgconfdir() + path ); 01525 } else { 01526 path = realPath( localkdedir() + path ); 01527 } 01528 } 01529 else { 01530 dirs = d->m_absolutes.value(type); 01531 if (dirs.isEmpty()) { 01532 qFatal("KStandardDirs: The resource type %s is not registered", type); 01533 } else { 01534 path = realPath(dirs.first()); 01535 } 01536 } 01537 01538 d->m_savelocations.insert(type, path.endsWith(QLatin1Char('/')) ? path : path + QLatin1Char('/')); 01539 } 01540 QString fullPath = path + suffix; 01541 01542 KDE_struct_stat st; 01543 if (KDE::stat(fullPath, &st) != 0 || !(S_ISDIR(st.st_mode))) { 01544 if(!create) { 01545 #ifndef NDEBUG 01546 // Too much noise from kbuildsycoca4 -- it's fine if this happens from KConfig 01547 // when parsing global files without a local equivalent. 01548 //kDebug(180) << QString("save location %1 doesn't exist").arg(fullPath); 01549 #endif 01550 return fullPath; 01551 } 01552 if(!makeDir(fullPath, 0700)) { 01553 return fullPath; 01554 } 01555 d->m_dircache.remove(type); 01556 } 01557 if (!fullPath.endsWith(QLatin1Char('/'))) 01558 fullPath += QLatin1Char('/'); 01559 return fullPath; 01560 } 01561 01562 // KDE5: make the method const 01563 QString KStandardDirs::relativeLocation(const char *type, const QString &absPath) 01564 { 01565 QString fullPath = absPath; 01566 int i = absPath.lastIndexOf(QLatin1Char('/')); 01567 if (i != -1) { 01568 fullPath = realFilePath(absPath); // Normalize 01569 } 01570 01571 const QStringList candidates = resourceDirs(type); 01572 01573 for (QStringList::ConstIterator it = candidates.begin(); 01574 it != candidates.end(); ++it) { 01575 if (fullPath.startsWith(*it)) { 01576 return fullPath.mid((*it).length()); 01577 } 01578 } 01579 return absPath; 01580 } 01581 01582 01583 bool KStandardDirs::makeDir(const QString& dir, int mode) 01584 { 01585 // we want an absolute path 01586 if (QDir::isRelativePath(dir)) 01587 return false; 01588 01589 #ifdef Q_WS_WIN 01590 return QDir().mkpath(dir); 01591 #else 01592 QString target = dir; 01593 uint len = target.length(); 01594 01595 // append trailing slash if missing 01596 if (dir.at(len - 1) != QLatin1Char('/')) 01597 target += QLatin1Char('/'); 01598 01599 QString base; 01600 uint i = 1; 01601 01602 while( i < len ) 01603 { 01604 KDE_struct_stat st; 01605 int pos = target.indexOf(QLatin1Char('/'), i); 01606 base += target.mid(i - 1, pos - i + 1); 01607 QByteArray baseEncoded = QFile::encodeName(base); 01608 // bail out if we encountered a problem 01609 if (KDE_stat(baseEncoded, &st) != 0) 01610 { 01611 // Directory does not exist.... 01612 // Or maybe a dangling symlink ? 01613 if (KDE_lstat(baseEncoded, &st) == 0) 01614 (void)unlink(baseEncoded); // try removing 01615 01616 if (KDE_mkdir(baseEncoded, static_cast<mode_t>(mode)) != 0) { 01617 baseEncoded.prepend( "trying to create local folder " ); 01618 perror(baseEncoded.constData()); 01619 return false; // Couldn't create it :-( 01620 } 01621 } 01622 i = pos + 1; 01623 } 01624 return true; 01625 #endif 01626 } 01627 01628 static QString readEnvPath(const char *env) 01629 { 01630 QByteArray c_path; 01631 #ifndef _WIN32_WCE 01632 c_path = qgetenv(env); 01633 if (c_path.isEmpty()) 01634 return QString(); 01635 #else 01636 bool ok; 01637 QString retval = getWin32RegistryValue(HKEY_LOCAL_MACHINE, "Software\\kde", "KDEDIRS", &ok); 01638 if (!ok){ 01639 return QString(); 01640 } else { 01641 c_path = retval.toAscii(); 01642 } 01643 #endif 01644 return QDir::fromNativeSeparators(QFile::decodeName(c_path)); 01645 } 01646 01647 #ifdef __linux__ 01648 static QString executablePrefix() 01649 { 01650 char path_buffer[MAXPATHLEN + 1]; 01651 path_buffer[MAXPATHLEN] = 0; 01652 int length = readlink ("/proc/self/exe", path_buffer, MAXPATHLEN); 01653 if (length == -1) 01654 return QString(); 01655 01656 path_buffer[length] = '\0'; 01657 01658 QString path = QFile::decodeName(path_buffer); 01659 01660 if(path.isEmpty()) 01661 return QString(); 01662 01663 int pos = path.lastIndexOf(QLatin1Char('/')); // Skip filename 01664 if(pos <= 0) 01665 return QString(); 01666 pos = path.lastIndexOf(QLatin1Char('/'), pos - 1); // Skip last directory 01667 if(pos <= 0) 01668 return QString(); 01669 01670 return path.left(pos); 01671 } 01672 #endif 01673 01674 void KStandardDirs::addResourcesFrom_krcdirs() 01675 { 01676 QString localFile = QDir::currentPath() + QLatin1String("/.krcdirs"); 01677 if (!QFile::exists(localFile)) 01678 return; 01679 01680 QSettings iniFile(localFile, QSettings::IniFormat); 01681 iniFile.beginGroup(QString::fromLatin1("KStandardDirs")); 01682 const QStringList resources = iniFile.allKeys(); 01683 foreach(const QString &key, resources) 01684 { 01685 QDir path(iniFile.value(key).toString()); 01686 if (!path.exists()) 01687 continue; 01688 01689 if(path.makeAbsolute()) 01690 addResourceDir(key.toAscii(), path.path(), false); 01691 } 01692 } 01693 01694 void KStandardDirs::addKDEDefaults() 01695 { 01696 addResourcesFrom_krcdirs(); 01697 01698 QStringList kdedirList; 01699 // begin KDEDIRS 01700 QString kdedirs = readEnvPath("KDEDIRS"); 01701 01702 if (!kdedirs.isEmpty()) 01703 { 01704 tokenize(kdedirList, kdedirs, QString(QLatin1Char(KPATH_SEPARATOR))); 01705 } 01706 kdedirList.append(installPath("kdedir")); 01707 01708 QString execPrefix(QFile::decodeName(EXEC_INSTALL_PREFIX)); 01709 if (!execPrefix.isEmpty() && !kdedirList.contains(execPrefix)) 01710 kdedirList.append(execPrefix); 01711 #ifdef __linux__ 01712 const QString linuxExecPrefix = executablePrefix(); 01713 if ( !linuxExecPrefix.isEmpty() ) 01714 kdedirList.append( linuxExecPrefix ); 01715 #endif 01716 01717 // We treat root differently to prevent a "su" shell messing up the 01718 // file permissions in the user's home directory. 01719 QString localKdeDir = readEnvPath(getuid() ? "KDEHOME" : "KDEROOTHOME"); 01720 if (!localKdeDir.isEmpty()) { 01721 if (!localKdeDir.endsWith(QLatin1Char('/'))) 01722 localKdeDir += QLatin1Char('/'); 01723 } else { 01724 // TODO KDE5: make localKdeDir equal to localXdgDir (which is determined further below and 01725 // defaults to ~/.config) + '/' + $KDECONFIG (which would default to e.g. "KDE") 01726 // This would mean ~/.config/KDE/ by default, more xdg-compliant. 01727 01728 #if defined(Q_WS_MACX) 01729 localKdeDir = QDir::homePath() + QLatin1String("/Library/Preferences/KDE/"); 01730 #elif defined(Q_WS_WIN) 01731 #ifndef _WIN32_WCE 01732 WCHAR wPath[MAX_PATH+1]; 01733 if ( SHGetFolderPathW(NULL, CSIDL_APPDATA, NULL, SHGFP_TYPE_CURRENT, wPath) == S_OK) { 01734 localKdeDir = QDir::fromNativeSeparators(QString::fromUtf16((const ushort *) wPath)) + QLatin1Char('/') + QString::fromLatin1(KDE_DEFAULT_HOME) + QLatin1Char('/'); 01735 } else { 01736 #endif 01737 localKdeDir = QDir::homePath() + QLatin1Char('/') + QString::fromLatin1(KDE_DEFAULT_HOME) + QLatin1Char('/'); 01738 #ifndef _WIN32_WCE 01739 } 01740 #endif 01741 #else 01742 localKdeDir = QDir::homePath() + QLatin1Char('/') + QString::fromLatin1(KDE_DEFAULT_HOME) + QLatin1Char('/'); 01743 #endif 01744 } 01745 01746 if (localKdeDir != QLatin1String("-/")) 01747 { 01748 localKdeDir = KShell::tildeExpand(localKdeDir); 01749 addPrefix(localKdeDir); 01750 } 01751 01752 #ifdef Q_WS_MACX 01753 // Adds the "Contents" directory of the current application bundle to 01754 // the search path. This way bundled resources can be found. 01755 QDir bundleDir(mac_app_filename()); 01756 if (bundleDir.dirName() == QLatin1String("MacOS")) { // just to be sure we're in a bundle 01757 bundleDir.cdUp(); 01758 // now dirName should be "Contents". In there we can find our normal 01759 // dir-structure, beginning with "share" 01760 addPrefix(bundleDir.absolutePath()); 01761 } 01762 #endif 01763 01764 QStringList::ConstIterator end(kdedirList.end()); 01765 for (QStringList::ConstIterator it = kdedirList.constBegin(); 01766 it != kdedirList.constEnd(); ++it) 01767 { 01768 const QString dir = KShell::tildeExpand(*it); 01769 addPrefix(dir); 01770 } 01771 // end KDEDIRS 01772 01773 // begin XDG_CONFIG_XXX 01774 QStringList xdgdirList; 01775 QString xdgdirs = readEnvPath("XDG_CONFIG_DIRS"); 01776 if (!xdgdirs.isEmpty()) 01777 { 01778 tokenize(xdgdirList, xdgdirs, QString(QLatin1Char(KPATH_SEPARATOR))); 01779 } 01780 else 01781 { 01782 xdgdirList.clear(); 01783 xdgdirList.append(QString::fromLatin1("/etc/xdg")); 01784 #ifdef Q_WS_WIN 01785 xdgdirList.append(installPath("kdedir") + QString::fromLatin1("etc/xdg")); 01786 #else 01787 xdgdirList.append(QFile::decodeName(KDESYSCONFDIR "/xdg")); 01788 #endif 01789 } 01790 01791 QString localXdgDir = readEnvPath("XDG_CONFIG_HOME"); 01792 if (!localXdgDir.isEmpty()) { 01793 if (!localXdgDir.endsWith(QLatin1Char('/'))) 01794 localXdgDir += QLatin1Char('/'); 01795 } else { 01796 #ifdef Q_WS_MACX 01797 localXdgDir = QDir::homePath() + QString::fromLatin1("/Library/Preferences/XDG/"); 01798 #else 01799 localXdgDir = QDir::homePath() + QString::fromLatin1("/.config/"); 01800 #endif 01801 } 01802 01803 localXdgDir = KShell::tildeExpand(localXdgDir); 01804 addXdgConfigPrefix(localXdgDir); 01805 01806 for (QStringList::ConstIterator it = xdgdirList.constBegin(); 01807 it != xdgdirList.constEnd(); ++it) 01808 { 01809 QString dir = KShell::tildeExpand(*it); 01810 addXdgConfigPrefix(dir); 01811 } 01812 // end XDG_CONFIG_XXX 01813 01814 // begin XDG_DATA_XXX 01815 QStringList kdedirDataDirs; 01816 for (QStringList::ConstIterator it = kdedirList.constBegin(); 01817 it != kdedirList.constEnd(); ++it) { 01818 QString dir = *it; 01819 if (!dir.endsWith(QLatin1Char('/'))) 01820 dir += QLatin1Char('/'); 01821 kdedirDataDirs.append(dir + QLatin1String("share/")); 01822 } 01823 01824 xdgdirs = readEnvPath("XDG_DATA_DIRS"); 01825 if (!xdgdirs.isEmpty()) { 01826 tokenize(xdgdirList, xdgdirs, QString(QLatin1Char(KPATH_SEPARATOR))); 01827 // Ensure the kdedirDataDirs are in there too, 01828 // otherwise resourceDirs() will add kdedir/share/applications/kde4 01829 // as returned by installPath(), and that's incorrect. 01830 Q_FOREACH(const QString& dir, kdedirDataDirs) { 01831 if (!xdgdirList.contains(dir)) 01832 xdgdirList.append(dir); 01833 } 01834 } else { 01835 xdgdirList = kdedirDataDirs; 01836 #ifndef Q_WS_WIN 01837 xdgdirList.append(QString::fromLatin1("/usr/local/share/")); 01838 xdgdirList.append(QString::fromLatin1("/usr/share/")); 01839 #endif 01840 } 01841 01842 localXdgDir = readEnvPath("XDG_DATA_HOME"); 01843 if (!localXdgDir.isEmpty()) 01844 { 01845 if (localXdgDir[localXdgDir.length()-1] != QLatin1Char('/')) 01846 localXdgDir += QLatin1Char('/'); 01847 } 01848 else 01849 { 01850 localXdgDir = QDir::homePath() + QLatin1String("/.local/share/"); 01851 } 01852 01853 localXdgDir = KShell::tildeExpand(localXdgDir); 01854 addXdgDataPrefix(localXdgDir); 01855 01856 for (QStringList::ConstIterator it = xdgdirList.constBegin(); 01857 it != xdgdirList.constEnd(); ++it) 01858 { 01859 QString dir = KShell::tildeExpand(*it); 01860 addXdgDataPrefix(dir); 01861 } 01862 // end XDG_DATA_XXX 01863 01864 01865 addResourceType("lib", 0, "lib" KDELIBSUFF "/"); 01866 01867 addResourceType("qtplugins", "lib", "plugins"); 01868 01869 uint index = 0; 01870 while (types_indices[index] != -1) { 01871 addResourceType(types_string + types_indices[index], 0, types_string + types_indices[index+1], true); 01872 index+=2; 01873 } 01874 addResourceType("exe", "lib", "kde4/libexec", true ); 01875 01876 addResourceDir("home", QDir::homePath(), false); 01877 01878 addResourceType("autostart", "xdgconf-autostart", "/"); // merge them, start with xdg autostart 01879 addResourceType("autostart", NULL, "share/autostart"); // KDE ones are higher priority 01880 } 01881 01882 static QStringList lookupProfiles(const QString &mapFile) 01883 { 01884 QStringList profiles; 01885 01886 if (mapFile.isEmpty() || !QFile::exists(mapFile)) 01887 { 01888 profiles << QString::fromLatin1("default"); 01889 return profiles; 01890 } 01891 01892 struct passwd *pw = getpwuid(geteuid()); 01893 if (!pw) 01894 { 01895 profiles << QString::fromLatin1("default"); 01896 return profiles; // Not good 01897 } 01898 01899 QByteArray user = pw->pw_name; 01900 01901 gid_t sup_gids[512]; 01902 int sup_gids_nr = getgroups(512, sup_gids); 01903 01904 KConfig mapCfgFile(mapFile); 01905 KConfigGroup mapCfg(&mapCfgFile, "Users"); 01906 if (mapCfg.hasKey(user.constData())) 01907 { 01908 profiles = mapCfg.readEntry(user.constData(), QStringList()); 01909 return profiles; 01910 } 01911 01912 const KConfigGroup generalGrp(&mapCfgFile, "General"); 01913 const QStringList groups = generalGrp.readEntry("groups", QStringList()); 01914 01915 const KConfigGroup groupsGrp(&mapCfgFile, "Groups"); 01916 01917 for( QStringList::ConstIterator it = groups.begin(); 01918 it != groups.end(); ++it ) 01919 { 01920 QByteArray grp = (*it).toUtf8(); 01921 // Check if user is in this group 01922 struct group *grp_ent = getgrnam(grp); 01923 if (!grp_ent) continue; 01924 gid_t gid = grp_ent->gr_gid; 01925 if (pw->pw_gid == gid) 01926 { 01927 // User is in this group --> add profiles 01928 profiles += groupsGrp.readEntry(*it, QStringList()); 01929 } 01930 else 01931 { 01932 for(int i = 0; i < sup_gids_nr; i++) 01933 { 01934 if (sup_gids[i] == gid) 01935 { 01936 // User is in this group --> add profiles 01937 profiles += groupsGrp.readEntry(*it, QStringList()); 01938 break; 01939 } 01940 } 01941 } 01942 } 01943 01944 if (profiles.isEmpty()) 01945 profiles << QString::fromLatin1("default"); 01946 return profiles; 01947 } 01948 01949 extern bool kde_kiosk_admin; 01950 01951 bool KStandardDirs::addCustomized(KConfig *config) 01952 { 01953 if (!d->m_checkRestrictions) // there are already customized entries 01954 return false; // we just quit and hope they are the right ones 01955 01956 // save the numbers of config directories. If this changes, 01957 // we will return true to give KConfig a chance to reparse 01958 int configdirs = resourceDirs("config").count(); 01959 01960 if (true) 01961 { 01962 // reading the prefixes in 01963 QString group = QLatin1String("Directories"); 01964 KConfigGroup cg(config, group); 01965 01966 QString kioskAdmin = cg.readEntry("kioskAdmin"); 01967 if (!kioskAdmin.isEmpty() && !kde_kiosk_admin) 01968 { 01969 int i = kioskAdmin.indexOf(QLatin1Char(':')); 01970 QString user = kioskAdmin.left(i); 01971 QString host = kioskAdmin.mid(i+1); 01972 01973 KUser thisUser; 01974 char hostname[ 256 ]; 01975 hostname[ 0 ] = '\0'; 01976 if (!gethostname( hostname, 255 )) 01977 hostname[sizeof(hostname)-1] = '\0'; 01978 01979 if ((user == thisUser.loginName()) && 01980 (host.isEmpty() || (host == QLatin1String(hostname)))) 01981 { 01982 kde_kiosk_admin = true; 01983 } 01984 } 01985 01986 bool readProfiles = true; 01987 01988 if (kde_kiosk_admin && !qgetenv("KDE_KIOSK_NO_PROFILES").isEmpty()) 01989 readProfiles = false; 01990 01991 QString userMapFile = cg.readEntry("userProfileMapFile"); 01992 QString profileDirsPrefix = cg.readEntry("profileDirsPrefix"); 01993 if (!profileDirsPrefix.isEmpty() && !profileDirsPrefix.endsWith(QLatin1Char('/'))) 01994 profileDirsPrefix.append(QLatin1Char('/')); 01995 01996 QStringList profiles; 01997 if (readProfiles) 01998 profiles = lookupProfiles(userMapFile); 01999 QString profile; 02000 02001 bool priority = false; 02002 while(true) 02003 { 02004 KConfigGroup cg(config, group); 02005 const QStringList list = cg.readEntry("prefixes", QStringList()); 02006 for (QStringList::ConstIterator it = list.begin(); it != list.end(); ++it) 02007 { 02008 addPrefix(*it, priority); 02009 addXdgConfigPrefix(*it + QLatin1String("/etc/xdg"), priority); 02010 addXdgDataPrefix(*it + QLatin1String("/share"), priority); 02011 } 02012 // If there are no prefixes defined, check if there is a directory 02013 // for this profile under <profileDirsPrefix> 02014 if (list.isEmpty() && !profile.isEmpty() && !profileDirsPrefix.isEmpty()) 02015 { 02016 QString dir = profileDirsPrefix + profile; 02017 addPrefix(dir, priority); 02018 addXdgConfigPrefix(dir + QLatin1String("/etc/xdg"), priority); 02019 addXdgDataPrefix(dir + QLatin1String("/share"), priority); 02020 } 02021 02022 // iterating over all entries in the group Directories 02023 // to find entries that start with dir_$type 02024 const QMap<QString, QString> entries = config->entryMap(group); 02025 for (QMap<QString, QString>::ConstIterator it2 = entries.begin(); 02026 it2 != entries.end(); ++it2) 02027 { 02028 const QString key = it2.key(); 02029 if (key.startsWith(QLatin1String("dir_"))) { 02030 // generate directory list, there may be more than 1. 02031 const QStringList dirs = (*it2).split(QString(QLatin1Char(','))); 02032 QStringList::ConstIterator sIt(dirs.begin()); 02033 QString resType = key.mid(4); 02034 for (; sIt != dirs.end(); ++sIt) 02035 { 02036 addResourceDir(resType.toLatin1(), *sIt, priority); 02037 } 02038 } 02039 } 02040 if (profiles.isEmpty()) 02041 break; 02042 profile = profiles.back(); 02043 group = QString::fromLatin1("Directories-%1").arg(profile); 02044 profiles.pop_back(); 02045 priority = true; 02046 } 02047 } 02048 02049 // Process KIOSK restrictions. 02050 if (!kde_kiosk_admin || qgetenv("KDE_KIOSK_NO_RESTRICTIONS").isEmpty()) 02051 { 02052 KConfigGroup cg(config, "KDE Resource Restrictions"); 02053 const QMap<QString, QString> entries = cg.entryMap(); 02054 for (QMap<QString, QString>::ConstIterator it2 = entries.begin(); 02055 it2 != entries.end(); ++it2) 02056 { 02057 const QString key = it2.key(); 02058 if (!cg.readEntry(key, true)) 02059 { 02060 d->m_restrictionsActive = true; 02061 const QByteArray cKey = key.toLatin1(); 02062 d->m_restrictions.insert(cKey, true); 02063 d->m_dircache.remove(cKey); 02064 d->m_savelocations.remove(cKey); 02065 } 02066 } 02067 } 02068 02069 // check if the number of config dirs changed 02070 bool configDirsChanged = (resourceDirs("config").count() != configdirs); 02071 // If the config dirs changed, we check kiosk restrictions again. 02072 d->m_checkRestrictions = configDirsChanged; 02073 // return true if the number of config dirs changed: reparse config file 02074 return configDirsChanged; 02075 } 02076 02077 QString KStandardDirs::localkdedir() const 02078 { 02079 // Return the prefix to use for saving 02080 return d->m_prefixes.first(); 02081 } 02082 02083 QString KStandardDirs::localxdgdatadir() const 02084 { 02085 // Return the prefix to use for saving 02086 return d->xdgdata_prefixes.first(); 02087 } 02088 02089 QString KStandardDirs::localxdgconfdir() const 02090 { 02091 // Return the prefix to use for saving 02092 return d->xdgconf_prefixes.first(); 02093 } 02094 02095 02096 // just to make code more readable without macros 02097 QString KStandardDirs::locate( const char *type, 02098 const QString& filename, const KComponentData &cData) 02099 { 02100 return cData.dirs()->findResource(type, filename); 02101 } 02102 02103 QString KStandardDirs::locateLocal( const char *type, 02104 const QString& filename, const KComponentData &cData) 02105 { 02106 return locateLocal(type, filename, true, cData); 02107 } 02108 02109 QString KStandardDirs::locateLocal( const char *type, 02110 const QString& filename, bool createDir, 02111 const KComponentData &cData) 02112 { 02113 // try to find slashes. If there are some, we have to 02114 // create the subdir first 02115 int slash = filename.lastIndexOf(QLatin1Char('/')) + 1; 02116 if (!slash) { // only one filename 02117 return cData.dirs()->saveLocation(type, QString(), createDir) + filename; 02118 } 02119 02120 // split path from filename 02121 QString dir = filename.left(slash); 02122 QString file = filename.mid(slash); 02123 return cData.dirs()->saveLocation(type, dir, createDir) + file; 02124 } 02125 02126 bool KStandardDirs::checkAccess(const QString& pathname, int mode) 02127 { 02128 int accessOK = KDE::access( pathname, mode ); 02129 if ( accessOK == 0 ) 02130 return true; // OK, I can really access the file 02131 02132 // else 02133 // if we want to write the file would be created. Check, if the 02134 // user may write to the directory to create the file. 02135 if ( (mode & W_OK) == 0 ) 02136 return false; // Check for write access is not part of mode => bail out 02137 02138 02139 if (!KDE::access( pathname, F_OK)) // if it already exists 02140 return false; 02141 02142 //strip the filename (everything until '/' from the end 02143 QString dirName(pathname); 02144 int pos = dirName.lastIndexOf(QLatin1Char('/')); 02145 if ( pos == -1 ) 02146 return false; // No path in argument. This is evil, we won't allow this 02147 else if ( pos == 0 ) // don't turn e.g. /root into an empty string 02148 pos = 1; 02149 02150 dirName.truncate(pos); // strip everything starting from the last '/' 02151 02152 accessOK = KDE::access( dirName, W_OK ); 02153 // -?- Can I write to the accessed diretory 02154 if ( accessOK == 0 ) 02155 return true; // Yes 02156 else 02157 return false; // No 02158 } 02159
This file is part of the KDE documentation.
Documentation copyright © 1996-2019 The KDE developers.
Generated on Mon Jan 21 2019 12:28:12 by doxygen 1.7.5.1 written by Dimitri van Heesch, © 1997-2006
Documentation copyright © 1996-2019 The KDE developers.
Generated on Mon Jan 21 2019 12:28:12 by doxygen 1.7.5.1 written by Dimitri van Heesch, © 1997-2006
KDE's Doxygen guidelines are available online.