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