kdecore Library API Documentation

kstandarddirs.cpp

00001 /* This file is part of the KDE libraries 00002 Copyright (C) 1999 Sirtaj Singh Kang <taj@kde.org> 00003 Copyright (C) 1999 Stephan Kulow <coolo@kde.org> 00004 Copyright (C) 1999 Waldo Bastian <bastian@kde.org> 00005 00006 This library is free software; you can redistribute it and/or 00007 modify it under the terms of the GNU Library General Public 00008 License version 2 as published by the Free Software Foundation. 00009 00010 This library is distributed in the hope that it will be useful, 00011 but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00013 Library General Public License for more details. 00014 00015 You should have received a copy of the GNU Library General Public License 00016 along with this library; see the file COPYING.LIB. If not, write to 00017 the Free Software Foundation, Inc., 59 Temple Place - Suite 330, 00018 Boston, MA 02111-1307, USA. 00019 */ 00020 00021 /* 00022 * Author: Stephan Kulow <coolo@kde.org> and Sirtaj Singh Kang <taj@kde.org> 00023 * Version: $Id: kstandarddirs.cpp,v 1.168.2.5 2004/07/16 16:47:31 waba Exp $ 00024 * Generated: Thu Mar 5 16:05:28 EST 1998 00025 */ 00026 00027 #include "config.h" 00028 00029 #include <stdlib.h> 00030 #include <assert.h> 00031 #include <errno.h> 00032 #ifdef HAVE_SYS_STAT_H 00033 #include <sys/stat.h> 00034 #endif 00035 #include <sys/types.h> 00036 #include <dirent.h> 00037 #include <pwd.h> 00038 #include <grp.h> 00039 00040 #include <qregexp.h> 00041 #include <qasciidict.h> 00042 #include <qdict.h> 00043 #include <qdir.h> 00044 #include <qfileinfo.h> 00045 #include <qstring.h> 00046 #include <qstringlist.h> 00047 00048 #include "kstandarddirs.h" 00049 #include "kconfig.h" 00050 #include "kdebug.h" 00051 #include "kinstance.h" 00052 #include "kshell.h" 00053 #include "ksimpleconfig.h" 00054 #include "kuser.h" 00055 #include <sys/param.h> 00056 #include <unistd.h> 00057 00058 template class QDict<QStringList>; 00059 00060 class KStandardDirs::KStandardDirsPrivate 00061 { 00062 public: 00063 KStandardDirsPrivate() 00064 : restrictionsActive(false), 00065 dataRestrictionActive(false) 00066 { } 00067 00068 bool restrictionsActive; 00069 bool dataRestrictionActive; 00070 QAsciiDict<bool> restrictions; 00071 QStringList xdgdata_prefixes; 00072 QStringList xdgconf_prefixes; 00073 }; 00074 00075 static const char* const types[] = {"html", "icon", "apps", "sound", 00076 "data", "locale", "services", "mime", 00077 "servicetypes", "config", "exe", 00078 "wallpaper", "lib", "pixmap", "templates", 00079 "module", "qtplugins", 00080 "xdgdata-apps", "xdgdata-dirs", "xdgconf-menu", 00081 "kcfg", 0 }; 00082 00083 static int tokenize( QStringList& token, const QString& str, 00084 const QString& delim ); 00085 00086 KStandardDirs::KStandardDirs( ) : addedCustoms(false) 00087 { 00088 d = new KStandardDirsPrivate; 00089 dircache.setAutoDelete(true); 00090 relatives.setAutoDelete(true); 00091 absolutes.setAutoDelete(true); 00092 savelocations.setAutoDelete(true); 00093 addKDEDefaults(); 00094 } 00095 00096 KStandardDirs::~KStandardDirs() 00097 { 00098 delete d; 00099 } 00100 00101 bool KStandardDirs::isRestrictedResource(const char *type, const QString& relPath) const 00102 { 00103 if (!d || !d->restrictionsActive) 00104 return false; 00105 00106 if (d->restrictions[type]) 00107 return true; 00108 00109 if (strcmp(type, "data")==0) 00110 { 00111 applyDataRestrictions(relPath); 00112 if (d->dataRestrictionActive) 00113 { 00114 d->dataRestrictionActive = false; 00115 return true; 00116 } 00117 } 00118 return false; 00119 } 00120 00121 void KStandardDirs::applyDataRestrictions(const QString &relPath) const 00122 { 00123 QString key; 00124 int i = relPath.find('/'); 00125 if (i != -1) 00126 key = "data_"+relPath.left(i); 00127 else 00128 key = "data_"+relPath; 00129 00130 if (d && d->restrictions[key.latin1()]) 00131 d->dataRestrictionActive = true; 00132 } 00133 00134 00135 QStringList KStandardDirs::allTypes() const 00136 { 00137 QStringList list; 00138 for (int i = 0; types[i] != 0; ++i) 00139 list.append(QString::fromLatin1(types[i])); 00140 return list; 00141 } 00142 00143 static void priorityAdd(QStringList &prefixes, const QString& dir, bool priority) 00144 { 00145 if (priority && !prefixes.isEmpty()) 00146 { 00147 // Add in front but behind $KDEHOME 00148 QStringList::iterator it = prefixes.begin(); 00149 it++; 00150 prefixes.insert(it, 1, dir); 00151 } 00152 else 00153 { 00154 prefixes.append(dir); 00155 } 00156 } 00157 00158 void KStandardDirs::addPrefix( const QString& _dir ) 00159 { 00160 addPrefix(_dir, false); 00161 } 00162 00163 void KStandardDirs::addPrefix( const QString& _dir, bool priority ) 00164 { 00165 if (_dir.isNull()) 00166 return; 00167 00168 QString dir = _dir; 00169 if (dir.at(dir.length() - 1) != '/') 00170 dir += '/'; 00171 00172 if (!prefixes.contains(dir)) { 00173 priorityAdd(prefixes, dir, priority); 00174 dircache.clear(); 00175 } 00176 } 00177 00178 void KStandardDirs::addXdgConfigPrefix( const QString& _dir ) 00179 { 00180 addXdgConfigPrefix(_dir, false); 00181 } 00182 00183 void KStandardDirs::addXdgConfigPrefix( const QString& _dir, bool priority ) 00184 { 00185 if (_dir.isNull()) 00186 return; 00187 00188 QString dir = _dir; 00189 if (dir.at(dir.length() - 1) != '/') 00190 dir += '/'; 00191 00192 if (!d->xdgconf_prefixes.contains(dir)) { 00193 priorityAdd(d->xdgconf_prefixes, dir, priority); 00194 dircache.clear(); 00195 } 00196 } 00197 00198 void KStandardDirs::addXdgDataPrefix( const QString& _dir ) 00199 { 00200 addXdgDataPrefix(_dir, false); 00201 } 00202 00203 void KStandardDirs::addXdgDataPrefix( const QString& _dir, bool priority ) 00204 { 00205 if (_dir.isNull()) 00206 return; 00207 00208 QString dir = _dir; 00209 if (dir.at(dir.length() - 1) != '/') 00210 dir += '/'; 00211 00212 if (!d->xdgdata_prefixes.contains(dir)) { 00213 priorityAdd(d->xdgdata_prefixes, dir, priority); 00214 dircache.clear(); 00215 } 00216 } 00217 00218 QString KStandardDirs::kfsstnd_prefixes() 00219 { 00220 return prefixes.join(":"); 00221 } 00222 00223 bool KStandardDirs::addResourceType( const char *type, 00224 const QString& relativename ) 00225 { 00226 return addResourceType(type, relativename, true); 00227 } 00228 00229 bool KStandardDirs::addResourceType( const char *type, 00230 const QString& relativename, 00231 bool priority ) 00232 { 00233 if (relativename.isNull()) 00234 return false; 00235 00236 QStringList *rels = relatives.find(type); 00237 if (!rels) { 00238 rels = new QStringList(); 00239 relatives.insert(type, rels); 00240 } 00241 QString copy = relativename; 00242 if (copy.at(copy.length() - 1) != '/') 00243 copy += '/'; 00244 if (!rels->contains(copy)) { 00245 if (priority) 00246 rels->prepend(copy); 00247 else 00248 rels->append(copy); 00249 dircache.remove(type); // clean the cache 00250 return true; 00251 } 00252 return false; 00253 } 00254 00255 bool KStandardDirs::addResourceDir( const char *type, 00256 const QString& absdir) 00257 { 00258 // KDE4: change priority to bring in line with addResourceType 00259 return addResourceDir(type, absdir, false); 00260 } 00261 00262 bool KStandardDirs::addResourceDir( const char *type, 00263 const QString& absdir, 00264 bool priority) 00265 { 00266 QStringList *paths = absolutes.find(type); 00267 if (!paths) { 00268 paths = new QStringList(); 00269 absolutes.insert(type, paths); 00270 } 00271 QString copy = absdir; 00272 if (copy.at(copy.length() - 1) != '/') 00273 copy += '/'; 00274 00275 if (!paths->contains(copy)) { 00276 if (priority) 00277 paths->prepend(copy); 00278 else 00279 paths->append(copy); 00280 dircache.remove(type); // clean the cache 00281 return true; 00282 } 00283 return false; 00284 } 00285 00286 QString KStandardDirs::findResource( const char *type, 00287 const QString& filename ) const 00288 { 00289 if (filename.at(0) == '/') 00290 return filename; // absolute dirs are absolute dirs, right? :-/ 00291 00292 #if 0 00293 kdDebug() << "Find resource: " << type << endl; 00294 for (QStringList::ConstIterator pit = prefixes.begin(); 00295 pit != prefixes.end(); 00296 pit++) 00297 { 00298 kdDebug() << "Prefix: " << *pit << endl; 00299 } 00300 #endif 00301 00302 QString dir = findResourceDir(type, filename); 00303 if (dir.isNull()) 00304 return dir; 00305 else return dir + filename; 00306 } 00307 00308 static Q_UINT32 updateHash(const QString &file, Q_UINT32 hash) 00309 { 00310 QCString cFile = QFile::encodeName(file); 00311 struct stat buff; 00312 if ((access(cFile, R_OK) == 0) && 00313 (stat( cFile, &buff ) == 0) && 00314 (S_ISREG( buff.st_mode ))) 00315 { 00316 hash = hash + (Q_UINT32) buff.st_ctime; 00317 } 00318 return hash; 00319 } 00320 00321 Q_UINT32 KStandardDirs::calcResourceHash( const char *type, 00322 const QString& filename, bool deep) const 00323 { 00324 Q_UINT32 hash = 0; 00325 00326 if (filename.at(0) == '/') 00327 { 00328 // absolute dirs are absolute dirs, right? :-/ 00329 return updateHash(filename, hash); 00330 } 00331 if (d && d->restrictionsActive && (strcmp(type, "data")==0)) 00332 applyDataRestrictions(filename); 00333 QStringList candidates = resourceDirs(type); 00334 QString fullPath; 00335 00336 for (QStringList::ConstIterator it = candidates.begin(); 00337 it != candidates.end(); it++) 00338 { 00339 hash = updateHash(*it + filename, hash); 00340 if (!deep && hash) 00341 return hash; 00342 } 00343 return hash; 00344 } 00345 00346 00347 QStringList KStandardDirs::findDirs( const char *type, 00348 const QString& reldir ) const 00349 { 00350 QDir testdir; 00351 QStringList list; 00352 if (reldir.startsWith("/")) 00353 { 00354 testdir.setPath(reldir); 00355 if (testdir.exists()) 00356 { 00357 if (reldir.endsWith("/")) 00358 list.append(reldir); 00359 else 00360 list.append(reldir+'/'); 00361 } 00362 return list; 00363 } 00364 00365 checkConfig(); 00366 00367 if (d && d->restrictionsActive && (strcmp(type, "data")==0)) 00368 applyDataRestrictions(reldir); 00369 QStringList candidates = resourceDirs(type); 00370 00371 for (QStringList::ConstIterator it = candidates.begin(); 00372 it != candidates.end(); it++) { 00373 testdir.setPath(*it + reldir); 00374 if (testdir.exists()) 00375 list.append(testdir.absPath() + '/'); 00376 } 00377 00378 return list; 00379 } 00380 00381 QString KStandardDirs::findResourceDir( const char *type, 00382 const QString& filename) const 00383 { 00384 #ifndef NDEBUG 00385 if (filename.isEmpty()) { 00386 kdWarning() << "filename for type " << type << " in KStandardDirs::findResourceDir is not supposed to be empty!!" << endl; 00387 return QString::null; 00388 } 00389 #endif 00390 00391 if (d && d->restrictionsActive && (strcmp(type, "data")==0)) 00392 applyDataRestrictions(filename); 00393 QStringList candidates = resourceDirs(type); 00394 QString fullPath; 00395 00396 for (QStringList::ConstIterator it = candidates.begin(); 00397 it != candidates.end(); it++) 00398 if (exists(*it + filename)) 00399 return *it; 00400 00401 #ifndef NDEBUG 00402 if(false && type != "locale") 00403 kdDebug() << "KStdDirs::findResDir(): can't find \"" << filename << "\" in type \"" << type << "\"." << endl; 00404 #endif 00405 00406 return QString::null; 00407 } 00408 00409 bool KStandardDirs::exists(const QString &fullPath) 00410 { 00411 struct stat buff; 00412 if (access(QFile::encodeName(fullPath), R_OK) == 0 && stat( QFile::encodeName(fullPath), &buff ) == 0) 00413 if (fullPath.at(fullPath.length() - 1) != '/') { 00414 if (S_ISREG( buff.st_mode )) 00415 return true; 00416 } else 00417 if (S_ISDIR( buff.st_mode )) 00418 return true; 00419 return false; 00420 } 00421 00422 static void lookupDirectory(const QString& path, const QString &relPart, 00423 const QRegExp &regexp, 00424 QStringList& list, 00425 QStringList& relList, 00426 bool recursive, bool unique) 00427 { 00428 QString pattern = regexp.pattern(); 00429 if (recursive || pattern.contains('?') || pattern.contains('*')) 00430 { 00431 // We look for a set of files. 00432 DIR *dp = opendir( QFile::encodeName(path)); 00433 if (!dp) 00434 return; 00435 00436 assert(path.at(path.length() - 1) == '/'); 00437 00438 struct dirent *ep; 00439 struct stat buff; 00440 00441 QString _dot("."); 00442 QString _dotdot(".."); 00443 00444 while( ( ep = readdir( dp ) ) != 0L ) 00445 { 00446 QString fn( QFile::decodeName(ep->d_name)); 00447 if (fn == _dot || fn == _dotdot || fn.at(fn.length() - 1).latin1() == '~') 00448 continue; 00449 00450 if (!recursive && !regexp.exactMatch(fn)) 00451 continue; // No match 00452 00453 QString pathfn = path + fn; 00454 if ( stat( QFile::encodeName(pathfn), &buff ) != 0 ) { 00455 kdDebug() << "Error stat'ing " << pathfn << " : " << perror << endl; 00456 continue; // Couldn't stat (e.g. no read permissions) 00457 } 00458 if ( recursive ) { 00459 if ( S_ISDIR( buff.st_mode )) { 00460 lookupDirectory(pathfn + '/', relPart + fn + '/', regexp, list, relList, recursive, unique); 00461 } 00462 if (!regexp.exactMatch(fn)) 00463 continue; // No match 00464 } 00465 if ( S_ISREG( buff.st_mode)) 00466 { 00467 if (!unique || !relList.contains(relPart + fn)) 00468 { 00469 list.append( pathfn ); 00470 relList.append( relPart + fn ); 00471 } 00472 } 00473 } 00474 closedir( dp ); 00475 } 00476 else 00477 { 00478 // We look for a single file. 00479 QString fn = pattern; 00480 QString pathfn = path + fn; 00481 struct stat buff; 00482 if ( stat( QFile::encodeName(pathfn), &buff ) != 0 ) 00483 return; // File not found 00484 if ( S_ISREG( buff.st_mode)) 00485 { 00486 if (!unique || !relList.contains(relPart + fn)) 00487 { 00488 list.append( pathfn ); 00489 relList.append( relPart + fn ); 00490 } 00491 } 00492 } 00493 } 00494 00495 static void lookupPrefix(const QString& prefix, const QString& relpath, 00496 const QString& relPart, 00497 const QRegExp &regexp, 00498 QStringList& list, 00499 QStringList& relList, 00500 bool recursive, bool unique) 00501 { 00502 if (relpath.isNull()) { 00503 lookupDirectory(prefix, relPart, regexp, list, 00504 relList, recursive, unique); 00505 return; 00506 } 00507 QString path; 00508 QString rest; 00509 00510 if (relpath.length()) 00511 { 00512 int slash = relpath.find('/'); 00513 if (slash < 0) 00514 rest = relpath.left(relpath.length() - 1); 00515 else { 00516 path = relpath.left(slash); 00517 rest = relpath.mid(slash + 1); 00518 } 00519 } 00520 00521 assert(prefix.at(prefix.length() - 1) == '/'); 00522 00523 struct stat buff; 00524 00525 if (path.contains('*') || path.contains('?')) { 00526 00527 QRegExp pathExp(path, true, true); 00528 DIR *dp = opendir( QFile::encodeName(prefix) ); 00529 if (!dp) { 00530 return; 00531 } 00532 00533 struct dirent *ep; 00534 00535 QString _dot("."); 00536 QString _dotdot(".."); 00537 00538 while( ( ep = readdir( dp ) ) != 0L ) 00539 { 00540 QString fn( QFile::decodeName(ep->d_name)); 00541 if (fn == _dot || fn == _dotdot || fn.at(fn.length() - 1) == '~') 00542 continue; 00543 00544 if (pathExp.search(fn) == -1) 00545 continue; // No match 00546 QString rfn = relPart+fn; 00547 fn = prefix + fn; 00548 if ( stat( QFile::encodeName(fn), &buff ) != 0 ) { 00549 kdDebug() << "Error statting " << fn << " : " << perror << endl; 00550 continue; // Couldn't stat (e.g. no permissions) 00551 } 00552 if ( S_ISDIR( buff.st_mode )) 00553 lookupPrefix(fn + '/', rest, rfn + '/', regexp, list, relList, recursive, unique); 00554 } 00555 00556 closedir( dp ); 00557 } else { 00558 // Don't stat, if the dir doesn't exist we will find out 00559 // when we try to open it. 00560 lookupPrefix(prefix + path + '/', rest, 00561 relPart + path + '/', regexp, list, 00562 relList, recursive, unique); 00563 } 00564 } 00565 00566 QStringList 00567 KStandardDirs::findAllResources( const char *type, 00568 const QString& filter, 00569 bool recursive, 00570 bool unique, 00571 QStringList &relList) const 00572 { 00573 QStringList list; 00574 QString filterPath; 00575 QString filterFile; 00576 00577 if (filter.length()) 00578 { 00579 int slash = filter.findRev('/'); 00580 if (slash < 0) 00581 filterFile = filter; 00582 else { 00583 filterPath = filter.left(slash + 1); 00584 filterFile = filter.mid(slash + 1); 00585 } 00586 } 00587 00588 checkConfig(); 00589 00590 QStringList candidates; 00591 if (filterPath.startsWith("/")) // absolute path 00592 { 00593 filterPath = filterPath.mid(1); 00594 candidates << "/"; 00595 } 00596 else 00597 { 00598 if (d && d->restrictionsActive && (strcmp(type, "data")==0)) 00599 applyDataRestrictions(filter); 00600 candidates = resourceDirs(type); 00601 } 00602 if (filterFile.isEmpty()) 00603 filterFile = "*"; 00604 00605 QRegExp regExp(filterFile, true, true); 00606 00607 for (QStringList::ConstIterator it = candidates.begin(); 00608 it != candidates.end(); it++) 00609 { 00610 lookupPrefix(*it, filterPath, "", regExp, list, 00611 relList, recursive, unique); 00612 } 00613 00614 return list; 00615 } 00616 00617 QStringList 00618 KStandardDirs::findAllResources( const char *type, 00619 const QString& filter, 00620 bool recursive, 00621 bool unique) const 00622 { 00623 QStringList relList; 00624 return findAllResources(type, filter, recursive, unique, relList); 00625 } 00626 00627 QString 00628 KStandardDirs::realPath(const QString &dirname) 00629 { 00630 char realpath_buffer[MAXPATHLEN + 1]; 00631 memset(realpath_buffer, 0, MAXPATHLEN + 1); 00632 00633 /* If the path contains symlinks, get the real name */ 00634 if (realpath( QFile::encodeName(dirname).data(), realpath_buffer) != 0) { 00635 // succes, use result from realpath 00636 int len = strlen(realpath_buffer); 00637 realpath_buffer[len] = '/'; 00638 realpath_buffer[len+1] = 0; 00639 return QFile::decodeName(realpath_buffer); 00640 } 00641 00642 return dirname; 00643 } 00644 00645 void KStandardDirs::createSpecialResource(const char *type) 00646 { 00647 char hostname[256]; 00648 hostname[0] = 0; 00649 gethostname(hostname, 255); 00650 QString dir = QString("%1%2-%3").arg(localkdedir()).arg(type).arg(hostname); 00651 char link[1024]; 00652 link[1023] = 0; 00653 int result = readlink(QFile::encodeName(dir).data(), link, 1023); 00654 bool relink = (result == -1) && (errno == ENOENT); 00655 if ((result > 0) && (link[0] == '/')) 00656 { 00657 link[result] = 0; 00658 struct stat stat_buf; 00659 int res = lstat(link, &stat_buf); 00660 if ((res == -1) && (errno == ENOENT)) 00661 { 00662 relink = true; 00663 } 00664 else if ((res == -1) || (!S_ISDIR(stat_buf.st_mode))) 00665 { 00666 fprintf(stderr, "Error: \"%s\" is not a directory.\n", link); 00667 relink = true; 00668 } 00669 else if (stat_buf.st_uid != getuid()) 00670 { 00671 fprintf(stderr, "Error: \"%s\" is owned by uid %d instead of uid %d.\n", link, stat_buf.st_uid, getuid()); 00672 relink = true; 00673 } 00674 } 00675 if (relink) 00676 { 00677 QString srv = findExe(QString::fromLatin1("lnusertemp"), KDEDIR+QString::fromLatin1("/bin")); 00678 if (srv.isEmpty()) 00679 srv = findExe(QString::fromLatin1("lnusertemp")); 00680 if (!srv.isEmpty()) 00681 { 00682 system(QFile::encodeName(srv)+" "+type); 00683 result = readlink(QFile::encodeName(dir).data(), link, 1023); 00684 } 00685 } 00686 if (result > 0) 00687 { 00688 link[result] = 0; 00689 if (link[0] == '/') 00690 dir = QFile::decodeName(link); 00691 else 00692 dir = QDir::cleanDirPath(dir+QFile::decodeName(link)); 00693 } 00694 addResourceDir(type, dir+'/'); 00695 } 00696 00697 QStringList KStandardDirs::resourceDirs(const char *type) const 00698 { 00699 QStringList *candidates = dircache.find(type); 00700 00701 if (!candidates) { // filling cache 00702 if (strcmp(type, "socket") == 0) 00703 const_cast<KStandardDirs *>(this)->createSpecialResource(type); 00704 else if (strcmp(type, "tmp") == 0) 00705 const_cast<KStandardDirs *>(this)->createSpecialResource(type); 00706 else if (strcmp(type, "cache") == 0) 00707 const_cast<KStandardDirs *>(this)->createSpecialResource(type); 00708 00709 QDir testdir; 00710 00711 candidates = new QStringList(); 00712 QStringList *dirs; 00713 00714 bool restrictionActive = false; 00715 if (d && d->restrictionsActive) 00716 { 00717 if (d->dataRestrictionActive) 00718 restrictionActive = true; 00719 else if (d->restrictions["all"]) 00720 restrictionActive = true; 00721 else if (d->restrictions[type]) 00722 restrictionActive = true; 00723 d->dataRestrictionActive = false; // Reset 00724 } 00725 00726 dirs = relatives.find(type); 00727 if (dirs) 00728 { 00729 bool local = true; 00730 const QStringList *prefixList = 0; 00731 if (strncmp(type, "xdgdata-", 8) == 0) 00732 prefixList = &(d->xdgdata_prefixes); 00733 else if (strncmp(type, "xdgconf-", 8) == 0) 00734 prefixList = &(d->xdgconf_prefixes); 00735 else 00736 prefixList = &prefixes; 00737 00738 for (QStringList::ConstIterator pit = prefixList->begin(); 00739 pit != prefixList->end(); 00740 pit++) 00741 { 00742 for (QStringList::ConstIterator it = dirs->begin(); 00743 it != dirs->end(); ++it) { 00744 QString path = realPath(*pit + *it); 00745 testdir.setPath(path); 00746 if (local && restrictionActive) 00747 continue; 00748 if ((local || testdir.exists()) && !candidates->contains(path)) 00749 candidates->append(path); 00750 } 00751 // UGLY HACK - Chris Cheney 00752 if (local && (!strcmp("config", type))) 00753 candidates->append("/etc/kde3/"); 00754 // 00755 local = false; 00756 } 00757 } 00758 dirs = absolutes.find(type); 00759 if (dirs) 00760 for (QStringList::ConstIterator it = dirs->begin(); 00761 it != dirs->end(); ++it) 00762 { 00763 testdir.setPath(*it); 00764 if (testdir.exists()) 00765 { 00766 QString filename = realPath(*it); 00767 if (!candidates->contains(filename)) 00768 candidates->append(filename); 00769 } 00770 } 00771 dircache.insert(type, candidates); 00772 } 00773 00774 #if 0 00775 kdDebug() << "found dirs for resource " << type << ":" << endl; 00776 for (QStringList::ConstIterator pit = candidates->begin(); 00777 pit != candidates->end(); 00778 pit++) 00779 { 00780 fprintf(stderr, "%s\n", (*pit).latin1()); 00781 } 00782 #endif 00783 00784 00785 return *candidates; 00786 } 00787 00788 QStringList KStandardDirs::systemPaths( const QString& pstr ) 00789 { 00790 QStringList tokens; 00791 QString p = pstr; 00792 00793 if( p.isNull() ) 00794 { 00795 p = getenv( "PATH" ); 00796 } 00797 00798 tokenize( tokens, p, ":\b" ); 00799 00800 QStringList exePaths; 00801 00802 // split path using : or \b as delimiters 00803 for( unsigned i = 0; i < tokens.count(); i++ ) 00804 { 00805 p = tokens[ i ]; 00806 00807 if ( p[ 0 ] == '~' ) 00808 { 00809 int len = p.find( '/' ); 00810 if ( len == -1 ) 00811 len = p.length(); 00812 if ( len == 1 ) 00813 { 00814 p.replace( 0, 1, QDir::homeDirPath() ); 00815 } 00816 else 00817 { 00818 QString user = p.mid( 1, len - 1 ); 00819 struct passwd *dir = getpwnam( user.local8Bit().data() ); 00820 if ( dir && strlen( dir->pw_dir ) ) 00821 p.replace( 0, len, QString::fromLocal8Bit( dir->pw_dir ) ); 00822 } 00823 } 00824 00825 exePaths << p; 00826 } 00827 00828 return exePaths; 00829 } 00830 00831 00832 QString KStandardDirs::findExe( const QString& appname, 00833 const QString& pstr, bool ignore) 00834 { 00835 QFileInfo info; 00836 00837 // absolute path ? 00838 if (appname.startsWith(QString::fromLatin1("/"))) 00839 { 00840 info.setFile( appname ); 00841 if( info.exists() && ( ignore || info.isExecutable() ) 00842 && info.isFile() ) { 00843 return appname; 00844 } 00845 return QString::null; 00846 } 00847 00848 QString p = QString("%1/%2").arg(__KDE_BINDIR).arg(appname); 00849 info.setFile( p ); 00850 if( info.exists() && ( ignore || info.isExecutable() ) 00851 && ( info.isFile() || info.isSymLink() ) ) { 00852 return p; 00853 } 00854 00855 QStringList exePaths = systemPaths( pstr ); 00856 for (QStringList::ConstIterator it = exePaths.begin(); it != exePaths.end(); it++) 00857 { 00858 p = (*it) + "/"; 00859 p += appname; 00860 00861 // Check for executable in this tokenized path 00862 info.setFile( p ); 00863 00864 if( info.exists() && ( ignore || info.isExecutable() ) 00865 && ( info.isFile() || info.isSymLink() ) ) { 00866 return p; 00867 } 00868 } 00869 00870 // If we reach here, the executable wasn't found. 00871 // So return empty string. 00872 00873 return QString::null; 00874 } 00875 00876 int KStandardDirs::findAllExe( QStringList& list, const QString& appname, 00877 const QString& pstr, bool ignore ) 00878 { 00879 QFileInfo info; 00880 QString p; 00881 list.clear(); 00882 00883 QStringList exePaths = systemPaths( pstr ); 00884 for (QStringList::ConstIterator it = exePaths.begin(); it != exePaths.end(); it++) 00885 { 00886 p = (*it) + "/"; 00887 p += appname; 00888 00889 info.setFile( p ); 00890 00891 if( info.exists() && (ignore || info.isExecutable()) 00892 && info.isFile() ) { 00893 list.append( p ); 00894 } 00895 } 00896 00897 return list.count(); 00898 } 00899 00900 static int tokenize( QStringList& tokens, const QString& str, 00901 const QString& delim ) 00902 { 00903 int len = str.length(); 00904 QString token = ""; 00905 00906 for( int index = 0; index < len; index++) 00907 { 00908 if ( delim.find( str[ index ] ) >= 0 ) 00909 { 00910 tokens.append( token ); 00911 token = ""; 00912 } 00913 else 00914 { 00915 token += str[ index ]; 00916 } 00917 } 00918 if ( token.length() > 0 ) 00919 { 00920 tokens.append( token ); 00921 } 00922 00923 return tokens.count(); 00924 } 00925 00926 QString KStandardDirs::kde_default(const char *type) { 00927 if (!strcmp(type, "data")) 00928 return "share/apps/"; 00929 if (!strcmp(type, "html")) 00930 return "share/doc/kde/HTML/"; 00931 if (!strcmp(type, "icon")) 00932 return "share/icons/"; 00933 if (!strcmp(type, "config")) 00934 return "share/config/"; 00935 if (!strcmp(type, "pixmap")) 00936 return "share/pixmaps/"; 00937 if (!strcmp(type, "apps")) 00938 return "share/applnk/"; 00939 if (!strcmp(type, "sound")) 00940 return "share/sounds/"; 00941 if (!strcmp(type, "locale")) 00942 return "share/locale/"; 00943 if (!strcmp(type, "services")) 00944 return "share/services/"; 00945 if (!strcmp(type, "servicetypes")) 00946 return "share/servicetypes/"; 00947 if (!strcmp(type, "mime")) 00948 return "share/mimelnk/"; 00949 if (!strcmp(type, "cgi")) 00950 return "lib/cgi-bin/"; 00951 if (!strcmp(type, "wallpaper")) 00952 return "share/wallpapers/"; 00953 if (!strcmp(type, "templates")) 00954 return "share/templates/"; 00955 if (!strcmp(type, "exe")) 00956 return "bin/"; 00957 if (!strcmp(type, "lib")) 00958 return "lib/"; 00959 if (!strcmp(type, "module")) 00960 return "lib/kde3/"; 00961 if (!strcmp(type, "qtplugins")) 00962 return "lib/kde3/plugins"; 00963 if (!strcmp(type, "xdgdata-apps")) 00964 return "applications/"; 00965 if (!strcmp(type, "xdgdata-dirs")) 00966 return "desktop-directories/"; 00967 if (!strcmp(type, "xdgconf-menu")) 00968 return "menus/"; 00969 if (!strcmp(type, "kcfg")) 00970 return "share/config.kcfg"; 00971 qFatal("unknown resource type %s", type); 00972 return QString::null; 00973 } 00974 00975 QString KStandardDirs::saveLocation(const char *type, 00976 const QString& suffix, 00977 bool create) const 00978 { 00979 checkConfig(); 00980 00981 QString *pPath = savelocations.find(type); 00982 if (!pPath) 00983 { 00984 QStringList *dirs = relatives.find(type); 00985 if (!dirs && ( 00986 (strcmp(type, "socket") == 0) || 00987 (strcmp(type, "tmp") == 0) || 00988 (strcmp(type, "cache") == 0) )) 00989 { 00990 (void) resourceDirs(type); // Generate socket|tmp|cache resource. 00991 dirs = relatives.find(type); // Search again. 00992 } 00993 if (dirs) 00994 { 00995 // Check for existence of typed directory + suffix 00996 if (strncmp(type, "xdgdata-", 8) == 0) 00997 pPath = new QString(realPath(localxdgdatadir() + dirs->last())); 00998 else if (strncmp(type, "xdgconf-", 8) == 0) 00999 pPath = new QString(realPath(localxdgconfdir() + dirs->last())); 01000 else 01001 pPath = new QString(realPath(localkdedir() + dirs->last())); 01002 } 01003 else { 01004 dirs = absolutes.find(type); 01005 if (!dirs) 01006 qFatal("KStandardDirs: The resource type %s is not registered", type); 01007 pPath = new QString(realPath(dirs->last())); 01008 } 01009 01010 savelocations.insert(type, pPath); 01011 } 01012 QString fullPath = *pPath + suffix; 01013 01014 struct stat st; 01015 if (stat(QFile::encodeName(fullPath), &st) != 0 || !(S_ISDIR(st.st_mode))) { 01016 if(!create) { 01017 #ifndef NDEBUG 01018 qDebug("save location %s doesn't exist", fullPath.latin1()); 01019 #endif 01020 return fullPath; 01021 } 01022 if(!makeDir(fullPath, 0700)) { 01023 qWarning("failed to create %s", fullPath.latin1()); 01024 return fullPath; 01025 } 01026 dircache.remove(type); 01027 } 01028 return fullPath; 01029 } 01030 01031 QString KStandardDirs::relativeLocation(const char *type, const QString &absPath) 01032 { 01033 QString fullPath = absPath; 01034 int i = absPath.findRev('/'); 01035 if (i != -1) 01036 { 01037 fullPath = realPath(absPath.left(i+1))+absPath.mid(i+1); // Normalize 01038 } 01039 01040 QStringList candidates = resourceDirs(type); 01041 01042 for (QStringList::ConstIterator it = candidates.begin(); 01043 it != candidates.end(); it++) 01044 if (fullPath.startsWith(*it)) 01045 { 01046 return fullPath.mid((*it).length()); 01047 } 01048 01049 return absPath; 01050 } 01051 01052 01053 bool KStandardDirs::makeDir(const QString& dir, int mode) 01054 { 01055 // we want an absolute path 01056 if (dir.at(0) != '/') 01057 return false; 01058 01059 QString target = dir; 01060 uint len = target.length(); 01061 01062 // append trailing slash if missing 01063 if (dir.at(len - 1) != '/') 01064 target += '/'; 01065 01066 QString base(""); 01067 uint i = 1; 01068 01069 while( i < len ) 01070 { 01071 struct stat st; 01072 int pos = target.find('/', i); 01073 base += target.mid(i - 1, pos - i + 1); 01074 QCString baseEncoded = QFile::encodeName(base); 01075 // bail out if we encountered a problem 01076 if (stat(baseEncoded, &st) != 0) 01077 { 01078 // Directory does not exist.... 01079 // Or maybe a dangling symlink ? 01080 if (lstat(baseEncoded, &st) == 0) 01081 (void)unlink(baseEncoded); // try removing 01082 01083 if ( mkdir(baseEncoded, (mode_t) mode) != 0) { 01084 perror("trying to create local folder"); 01085 return false; // Couldn't create it :-( 01086 } 01087 } 01088 i = pos + 1; 01089 } 01090 return true; 01091 } 01092 01093 static QString readEnvPath(const char *env) 01094 { 01095 QCString c_path = getenv(env); 01096 if (c_path.isEmpty()) 01097 return QString::null; 01098 return QFile::decodeName(c_path); 01099 } 01100 01101 void KStandardDirs::addKDEDefaults() 01102 { 01103 QStringList kdedirList; 01104 01105 // begin KDEDIRS 01106 QString kdedirs = readEnvPath("KDEDIRS"); 01107 if (!kdedirs.isEmpty()) 01108 { 01109 tokenize(kdedirList, kdedirs, ":"); 01110 } 01111 else 01112 { 01113 QString kdedir = readEnvPath("KDEDIR"); 01114 if (!kdedir.isEmpty()) 01115 { 01116 kdedir = KShell::tildeExpand(kdedir); 01117 kdedirList.append(kdedir); 01118 } 01119 } 01120 // UGLY HACK - Chris Cheney 01121 kdedirList.append("/usr/local"); 01122 // 01123 kdedirList.append(KDEDIR); 01124 01125 #ifdef __KDE_EXECPREFIX 01126 QString execPrefix(__KDE_EXECPREFIX); 01127 if (execPrefix!="NONE") 01128 kdedirList.append(execPrefix); 01129 #endif 01130 01131 // We treat root differently to prevent a "su" shell messing up the 01132 // file permissions in the user's home directory. 01133 QString localKdeDir = readEnvPath(getuid() ? "KDEHOME" : "KDEROOTHOME"); 01134 if (!localKdeDir.isEmpty()) 01135 { 01136 if (localKdeDir[localKdeDir.length()-1] != '/') 01137 localKdeDir += '/'; 01138 } 01139 else 01140 { 01141 localKdeDir = QDir::homeDirPath() + "/.kde/"; 01142 } 01143 01144 if (localKdeDir != "-/") 01145 { 01146 localKdeDir = KShell::tildeExpand(localKdeDir); 01147 addPrefix(localKdeDir); 01148 } 01149 01150 for (QStringList::ConstIterator it = kdedirList.begin(); 01151 it != kdedirList.end(); it++) 01152 { 01153 QString dir = KShell::tildeExpand(*it); 01154 addPrefix(dir); 01155 } 01156 // end KDEDIRS 01157 01158 // begin XDG_CONFIG_XXX 01159 QStringList xdgdirList; 01160 QString xdgdirs = readEnvPath("XDG_CONFIG_DIRS"); 01161 if (!xdgdirs.isEmpty()) 01162 { 01163 tokenize(xdgdirList, xdgdirs, ":"); 01164 } 01165 else 01166 { 01167 xdgdirList.clear(); 01168 xdgdirList.append("/etc/xdg"); 01169 xdgdirList.append(KDESYSCONFDIR "/xdg"); 01170 } 01171 01172 QString localXdgDir = readEnvPath("XDG_CONFIG_HOME"); 01173 if (!localXdgDir.isEmpty()) 01174 { 01175 if (localXdgDir[localXdgDir.length()-1] != '/') 01176 localXdgDir += '/'; 01177 } 01178 else 01179 { 01180 localXdgDir = QDir::homeDirPath() + "/.config/"; 01181 } 01182 01183 localXdgDir = KShell::tildeExpand(localXdgDir); 01184 addXdgConfigPrefix(localXdgDir); 01185 01186 for (QStringList::ConstIterator it = xdgdirList.begin(); 01187 it != xdgdirList.end(); it++) 01188 { 01189 QString dir = KShell::tildeExpand(*it); 01190 addXdgConfigPrefix(dir); 01191 } 01192 // end XDG_CONFIG_XXX 01193 01194 // begin XDG_DATA_XXX 01195 xdgdirs = readEnvPath("XDG_DATA_DIRS"); 01196 if (!xdgdirs.isEmpty()) 01197 { 01198 tokenize(xdgdirList, xdgdirs, ":"); 01199 } 01200 else 01201 { 01202 xdgdirList.clear(); 01203 for (QStringList::ConstIterator it = kdedirList.begin(); 01204 it != kdedirList.end(); it++) 01205 { 01206 QString dir = *it; 01207 if (dir[dir.length()-1] != '/') 01208 dir += '/'; 01209 xdgdirList.append(dir+"share/"); 01210 } 01211 01212 xdgdirList.append("/usr/local/share/"); 01213 xdgdirList.append("/usr/share/"); 01214 } 01215 01216 localXdgDir = readEnvPath("XDG_DATA_HOME"); 01217 if (!localXdgDir.isEmpty()) 01218 { 01219 if (localXdgDir[localXdgDir.length()-1] != '/') 01220 localXdgDir += '/'; 01221 } 01222 else 01223 { 01224 localXdgDir = QDir::homeDirPath() + "/.local/share/"; 01225 } 01226 01227 localXdgDir = KShell::tildeExpand(localXdgDir); 01228 addXdgDataPrefix(localXdgDir); 01229 01230 for (QStringList::ConstIterator it = xdgdirList.begin(); 01231 it != xdgdirList.end(); it++) 01232 { 01233 QString dir = KShell::tildeExpand(*it); 01234 addXdgDataPrefix(dir); 01235 } 01236 // end XDG_DATA_XXX 01237 01238 01239 uint index = 0; 01240 while (types[index] != 0) { 01241 addResourceType(types[index], kde_default(types[index])); 01242 index++; 01243 } 01244 01245 addResourceDir("home", QDir::homeDirPath()); 01246 } 01247 01248 void KStandardDirs::checkConfig() const 01249 { 01250 if (!addedCustoms && KGlobal::_instance && KGlobal::_instance->_config) 01251 const_cast<KStandardDirs*>(this)->addCustomized(KGlobal::_instance->_config); 01252 } 01253 01254 static QStringList lookupProfiles(const QString &mapFile) 01255 { 01256 QStringList profiles; 01257 01258 if (mapFile.isEmpty() || !QFile::exists(mapFile)) 01259 { 01260 profiles << "default"; 01261 return profiles; 01262 } 01263 01264 struct passwd *pw = getpwuid(geteuid()); 01265 if (!pw) 01266 { 01267 profiles << "default"; 01268 return profiles; // Not good 01269 } 01270 01271 QCString user = pw->pw_name; 01272 01273 KSimpleConfig mapCfg(mapFile, true); 01274 mapCfg.setGroup("Users"); 01275 if (mapCfg.hasKey(user.data())) 01276 { 01277 profiles = mapCfg.readListEntry(user.data()); 01278 return profiles; 01279 } 01280 01281 mapCfg.setGroup("General"); 01282 QStringList groups = mapCfg.readListEntry("groups"); 01283 01284 mapCfg.setGroup("Groups"); 01285 01286 for( QStringList::ConstIterator it = groups.begin(); 01287 it != groups.end(); ++it ) 01288 { 01289 QCString grp = (*it).utf8(); 01290 // Check if user is in this group 01291 struct group *grp_ent = getgrnam(grp); 01292 if (!grp_ent) continue; 01293 01294 char ** members = grp_ent->gr_mem; 01295 for(char * member; (member = *members); ++members) 01296 { 01297 if (user == member) 01298 { 01299 // User is in this group --> add profiles 01300 profiles += mapCfg.readListEntry(*it); 01301 break; 01302 } 01303 } 01304 } 01305 01306 if (profiles.isEmpty()) 01307 profiles << "default"; 01308 return profiles; 01309 } 01310 01311 extern bool kde_kiosk_admin; 01312 01313 bool KStandardDirs::addCustomized(KConfig *config) 01314 { 01315 if (addedCustoms) // there are already customized entries 01316 return false; // we just quit and hope they are the right ones 01317 01318 // save it for future calls - that will return 01319 addedCustoms = true; 01320 01321 // save the numbers of config directories. If this changes, 01322 // we will return true to give KConfig a chance to reparse 01323 uint configdirs = resourceDirs("config").count(); 01324 01325 // reading the prefixes in 01326 QString oldGroup = config->group(); 01327 QString group = QString::fromLatin1("Directories"); 01328 config->setGroup(group); 01329 01330 QString kioskAdmin = config->readEntry("kioskAdmin"); 01331 if (!kioskAdmin.isEmpty() && !kde_kiosk_admin) 01332 { 01333 int i = kioskAdmin.find(':'); 01334 QString user = kioskAdmin.left(i); 01335 QString host = kioskAdmin.mid(i+1); 01336 01337 KUser thisUser; 01338 char hostname[ 256 ]; 01339 hostname[ 0 ] = '\0'; 01340 if (!gethostname( hostname, 255 )) 01341 hostname[sizeof(hostname)-1] = '\0'; 01342 01343 if ((user == thisUser.loginName()) && 01344 (host.isEmpty() || (host == hostname))) 01345 { 01346 kde_kiosk_admin = true; 01347 } 01348 } 01349 01350 bool readProfiles = true; 01351 01352 if (kde_kiosk_admin && !QCString(getenv("KDE_KIOSK_NO_PROFILES")).isEmpty()) 01353 readProfiles = false; 01354 01355 QString userMapFile = config->readEntry("userProfileMapFile"); 01356 01357 QStringList profiles; 01358 if (readProfiles) 01359 profiles = lookupProfiles(userMapFile); 01360 01361 bool priority = false; 01362 while(true) 01363 { 01364 config->setGroup(group); 01365 QStringList list = config->readListEntry("prefixes"); 01366 for (QStringList::ConstIterator it = list.begin(); it != list.end(); it++) 01367 { 01368 addPrefix(*it, priority); 01369 addXdgConfigPrefix(*it+"/etc/xdg", priority); 01370 addXdgDataPrefix(*it+"/share", priority); 01371 } 01372 01373 // iterating over all entries in the group Directories 01374 // to find entries that start with dir_$type 01375 QMap<QString, QString> entries = config->entryMap(group); 01376 for (QMap<QString, QString>::ConstIterator it2 = entries.begin(); 01377 it2 != entries.end(); it2++) 01378 { 01379 QString key = it2.key(); 01380 if (key.startsWith("dir_")) { 01381 // generate directory list, there may be more than 1. 01382 QStringList dirs = QStringList::split(',', 01383 *it2); 01384 QStringList::Iterator sIt(dirs.begin()); 01385 QString resType = key.mid(4, key.length()); 01386 for (; sIt != dirs.end(); ++sIt) { 01387 addResourceDir(resType.latin1(), *sIt, priority); 01388 } 01389 } 01390 } 01391 if (profiles.isEmpty()) 01392 break; 01393 group = QString::fromLatin1("Directories-%1").arg(profiles.back()); 01394 profiles.pop_back(); 01395 priority = true; 01396 } 01397 01398 // Process KIOSK restrictions. 01399 if (!kde_kiosk_admin || QCString(getenv("KDE_KIOSK_NO_RESTRICTIONS")).isEmpty()) 01400 { 01401 config->setGroup("KDE Resource Restrictions"); 01402 QMap<QString, QString> entries = config->entryMap("KDE Resource Restrictions"); 01403 for (QMap<QString, QString>::ConstIterator it2 = entries.begin(); 01404 it2 != entries.end(); it2++) 01405 { 01406 QString key = it2.key(); 01407 if (!config->readBoolEntry(key, true)) 01408 { 01409 d->restrictionsActive = true; 01410 d->restrictions.insert(key.latin1(), &d->restrictionsActive); // Anything will do 01411 dircache.remove(key.latin1()); 01412 } 01413 } 01414 } 01415 01416 config->setGroup(oldGroup); 01417 01418 // return true if the number of config dirs changed 01419 return (resourceDirs("config").count() != configdirs); 01420 } 01421 01422 QString KStandardDirs::localkdedir() const 01423 { 01424 // Return the prefix to use for saving 01425 return prefixes.first(); 01426 } 01427 01428 QString KStandardDirs::localxdgdatadir() const 01429 { 01430 // Return the prefix to use for saving 01431 return d->xdgdata_prefixes.first(); 01432 } 01433 01434 QString KStandardDirs::localxdgconfdir() const 01435 { 01436 // Return the prefix to use for saving 01437 return d->xdgconf_prefixes.first(); 01438 } 01439 01440 // just to make code more readable without macros 01441 QString locate( const char *type, 01442 const QString& filename, const KInstance* inst ) 01443 { 01444 return inst->dirs()->findResource(type, filename); 01445 } 01446 01447 QString locateLocal( const char *type, 01448 const QString& filename, const KInstance* inst ) 01449 { 01450 return locateLocal(type, filename, true, inst); 01451 } 01452 01453 QString locateLocal( const char *type, 01454 const QString& filename, bool createDir, const KInstance* inst ) 01455 { 01456 // try to find slashes. If there are some, we have to 01457 // create the subdir first 01458 int slash = filename.findRev('/')+1; 01459 if (!slash) // only one filename 01460 return inst->dirs()->saveLocation(type, QString::null, createDir) + filename; 01461 01462 // split path from filename 01463 QString dir = filename.left(slash); 01464 QString file = filename.mid(slash); 01465 return inst->dirs()->saveLocation(type, dir, createDir) + file; 01466 }
KDE Logo
This file is part of the documentation for kdecore Library Version 3.2.3.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Mon Aug 30 22:53:33 2004 by doxygen 1.3.8 written by Dimitri van Heesch, © 1997-2003