• Skip to content
  • Skip to link menu
  • KDE API Reference
  • kdelibs-4.8.5 API Reference
  • KDE Home
  • Contact Us
 

KDECore

  • kdecore
  • kernel
kstandarddirs.cpp
Go to the documentation of this file.
1 /* This file is part of the KDE libraries
2  Copyright (C) 1999 Sirtaj Singh Kang <taj@kde.org>
3  Copyright (C) 1999,2007 Stephan Kulow <coolo@kde.org>
4  Copyright (C) 1999 Waldo Bastian <bastian@kde.org>
5  Copyright (C) 2009 David Faure <faure@kde.org>
6 
7  This library is free software; you can redistribute it and/or
8  modify it under the terms of the GNU Library General Public
9  License version 2 as published by the Free Software Foundation.
10 
11  This library is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  Library General Public License for more details.
15 
16  You should have received a copy of the GNU Library General Public License
17  along with this library; see the file COPYING.LIB. If not, write to
18  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19  Boston, MA 02110-1301, USA.
20 */
21 
22 /*
23  * Author: Stephan Kulow <coolo@kde.org> and Sirtaj Singh Kang <taj@kde.org>
24  * Generated: Thu Mar 5 16:05:28 EST 1998
25  */
26 
27 #include "kstandarddirs.h"
28 #include "kconfig.h"
29 #include "kconfiggroup.h"
30 #include "kdebug.h"
31 #include "kcomponentdata.h"
32 #include "kshell.h"
33 #include "kuser.h"
34 #include "kde_file.h"
35 #include "kkernel_win.h"
36 #include "kkernel_mac.h"
37 #include "klocale.h"
38 
39 #include <config.h>
40 #include <config-prefix.h>
41 #include <config-kstandarddirs.h>
42 
43 #include <stdlib.h>
44 #include <assert.h>
45 #include <errno.h>
46 #ifdef HAVE_SYS_STAT_H
47 #include <sys/stat.h>
48 #endif
49 #ifdef HAVE_UNISTD_H
50 #include <unistd.h>
51 #endif
52 #include <sys/param.h>
53 #include <sys/types.h>
54 #include <dirent.h>
55 #include <pwd.h>
56 #include <grp.h>
57 #ifdef Q_WS_WIN
58 #include <windows.h>
59 #ifdef _WIN32_WCE
60 #include <basetyps.h>
61 #endif
62 #ifdef Q_WS_WIN64
63 // FIXME: did not find a reliable way to fix with kdewin mingw header
64 #define interface struct
65 #endif
66 #include <shlobj.h>
67 #include <QtCore/QVarLengthArray>
68 #endif
69 
70 #include <QtCore/QMutex>
71 #include <QtCore/QRegExp>
72 #include <QtCore/QDir>
73 #include <QtCore/QFileInfo>
74 #include <QtCore/QSettings>
75 
76 class KStandardDirs::KStandardDirsPrivate
77 {
78 public:
79  KStandardDirsPrivate(KStandardDirs* qq)
80  : m_restrictionsActive(false),
81  m_checkRestrictions(true),
82  m_cacheMutex(QMutex::Recursive), // resourceDirs is recursive
83  q(qq)
84  { }
85 
86  bool hasDataRestrictions(const QString &relPath) const;
87  QStringList resourceDirs(const char* type, const QString& subdirForRestrictions);
88  void createSpecialResource(const char*);
89 
90  bool m_restrictionsActive : 1;
91  bool m_checkRestrictions : 1;
92  QMap<QByteArray, bool> m_restrictions;
93 
94  QStringList xdgdata_prefixes;
95  QStringList xdgconf_prefixes;
96  QStringList m_prefixes;
97 
98  // Directory dictionaries
99  QMap<QByteArray, QStringList> m_absolutes; // For each resource type, the list of absolute paths, from most local (most priority) to most global
100  QMap<QByteArray, QStringList> m_relatives; // Same with relative paths
101  // The search path is "all relative paths" < "all absolute paths", from most priority to least priority.
102 
103  // Caches (protected by mutex in const methods, cf ctor docu)
104  QMap<QByteArray, QStringList> m_dircache;
105  QMap<QByteArray, QString> m_savelocations;
106  QMutex m_cacheMutex;
107 
108  KStandardDirs* q;
109 };
110 
111 /* If you add a new resource type here, make sure to
112  * 1) regenerate using "kdesdk/scripts/generate_string_table.pl types < tmpfile" with the data below in tmpfile.
113  * 2) update the KStandardDirs class documentation
114  * 3) update the list in kde-config.cpp
115 
116 data
117 share/apps
118 html
119 share/doc/HTML
120 icon
121 share/icons
122 config
123 share/config
124 pixmap
125 share/pixmaps
126 apps
127 share/applnk
128 sound
129 share/sounds
130 locale
131 share/locale
132 services
133 share/kde4/services
134 servicetypes
135 share/kde4/servicetypes
136 mime
137 share/mimelnk
138 cgi
139 cgi-bin
140 wallpaper
141 share/wallpapers
142 templates
143 share/templates
144 exe
145 bin
146 module
147 %lib/kde4
148 qtplugins
149 %lib/kde4/plugins
150 kcfg
151 share/config.kcfg
152 emoticons
153 share/emoticons
154 xdgdata-apps
155 applications
156 xdgdata-icon
157 icons
158 xdgdata-pixmap
159 pixmaps
160 xdgdata-dirs
161 desktop-directories
162 xdgdata-mime
163 mime
164 xdgconf-menu
165 menus
166 xdgconf-autostart
167 autostart
168 */
169 
170 static const char types_string[] =
171  "data\0"
172  "share/apps\0"
173  "html\0"
174  "share/doc/HTML\0"
175  "icon\0"
176  "share/icons\0"
177  "config\0"
178  "share/config\0"
179  "pixmap\0"
180  "share/pixmaps\0"
181  "apps\0"
182  "share/applnk\0"
183  "sound\0"
184  "share/sounds\0"
185  "locale\0"
186  "share/locale\0"
187  "services\0"
188  "share/kde4/services\0"
189  "servicetypes\0"
190  "share/kde4/servicetypes\0"
191  "mime\0"
192  "share/mimelnk\0"
193  "cgi\0"
194  "cgi-bin\0"
195  "wallpaper\0"
196  "share/wallpapers\0"
197  "templates\0"
198  "share/templates\0"
199  "exe\0"
200  "bin\0"
201  "module\0"
202  "%lib/kde4\0"
203  "qtplugins\0"
204  "%lib/kde4/plugins\0"
205  "kcfg\0"
206  "share/config.kcfg\0"
207  "emoticons\0"
208  "share/emoticons\0"
209  "xdgdata-apps\0"
210  "applications\0"
211  "xdgdata-icon\0"
212  "icons\0"
213  "xdgdata-pixmap\0"
214  "pixmaps\0"
215  "xdgdata-dirs\0"
216  "desktop-directories\0"
217  "xdgdata-mime\0"
218  "xdgconf-menu\0"
219  "menus\0"
220  "xdgconf-autostart\0"
221  "autostart\0"
222  "\0";
223 
224 static const int types_indices[] = {
225  0, 5, 16, 21, 36, 41, 53, 60,
226  73, 80, 94, 99, 112, 118, 131, 138,
227  151, 160, 180, 193, 217, 222, 236, 240,
228  248, 258, 275, 285, 301, 305, 309, 316,
229  326, 336, 354, 359, 377, 387, 403, 416,
230  429, 442, 448, 463, 471, 484, 504, 217,
231  517, 530, 536, 554, -1
232 };
233 
234 static void tokenize(QStringList& token, const QString& str,
235  const QString& delim);
236 
237 KStandardDirs::KStandardDirs()
238  : d(new KStandardDirsPrivate(this))
239 {
240  addKDEDefaults();
241 }
242 
243 KStandardDirs::~KStandardDirs()
244 {
245  delete d;
246 }
247 
248 bool KStandardDirs::isRestrictedResource(const char *type, const QString& relPath) const
249 {
250  if (!d->m_restrictionsActive)
251  return false;
252 
253  if (d->m_restrictions.value(type, false))
254  return true;
255 
256  if (strcmp(type, "data")==0 && d->hasDataRestrictions(relPath))
257  return true;
258 
259  return false;
260 }
261 
262 bool KStandardDirs::KStandardDirsPrivate::hasDataRestrictions(const QString &relPath) const
263 {
264  QString key;
265  const int i = relPath.indexOf(QLatin1Char('/'));
266  if (i != -1)
267  key = QString::fromLatin1("data_") + relPath.left(i);
268  else
269  key = QString::fromLatin1("data_") + relPath;
270 
271  return m_restrictions.value(key.toLatin1(), false);
272 }
273 
274 
275 QStringList KStandardDirs::allTypes() const
276 {
277  QStringList list;
278  for (int i = 0; types_indices[i] != -1; i += 2)
279  list.append(QLatin1String(types_string + types_indices[i]));
280  // Those are added manually by addKDEDefaults
281  list.append(QString::fromLatin1("lib"));
282  //list.append(QString::fromLatin1("home")); // undocumented on purpose, said Waldo in r113855.
283 
284  // Those are handled by resourceDirs() itself
285  list.append(QString::fromLatin1("socket"));
286  list.append(QString::fromLatin1("tmp"));
287  list.append(QString::fromLatin1("cache"));
288  // Those are handled by installPath()
289  list.append(QString::fromLatin1("include"));
290 
291  // If you add anything here, make sure kde-config.cpp has a description for it.
292 
293  return list;
294 }
295 
296 static void priorityAdd(QStringList &prefixes, const QString& dir, bool priority)
297 {
298  if (priority && !prefixes.isEmpty())
299  {
300  // Add in front but behind $KDEHOME
301  QStringList::iterator it = prefixes.begin();
302  ++it;
303  prefixes.insert(it, dir);
304  }
305  else
306  {
307  prefixes.append(dir);
308  }
309 }
310 
311 void KStandardDirs::addPrefix( const QString& _dir )
312 {
313  addPrefix(_dir, false);
314 }
315 
316 void KStandardDirs::addPrefix( const QString& _dir, bool priority )
317 {
318  if (_dir.isEmpty())
319  return;
320 
321  QString dir = _dir;
322  if (dir.at(dir.length() - 1) != QLatin1Char('/'))
323  dir += QLatin1Char('/');
324 
325  if (!d->m_prefixes.contains(dir)) {
326  priorityAdd(d->m_prefixes, dir, priority);
327  d->m_dircache.clear();
328  }
329 }
330 
331 void KStandardDirs::addXdgConfigPrefix( const QString& _dir )
332 {
333  addXdgConfigPrefix(_dir, false);
334 }
335 
336 void KStandardDirs::addXdgConfigPrefix( const QString& _dir, bool priority )
337 {
338  if (_dir.isEmpty())
339  return;
340 
341  QString dir = _dir;
342  if (dir.at(dir.length() - 1) != QLatin1Char('/'))
343  dir += QLatin1Char('/');
344 
345  if (!d->xdgconf_prefixes.contains(dir)) {
346  priorityAdd(d->xdgconf_prefixes, dir, priority);
347  d->m_dircache.clear();
348  }
349 }
350 
351 void KStandardDirs::addXdgDataPrefix( const QString& _dir )
352 {
353  addXdgDataPrefix(_dir, false);
354 }
355 
356 void KStandardDirs::addXdgDataPrefix( const QString& _dir, bool priority )
357 {
358  if (_dir.isEmpty())
359  return;
360 
361  QString dir = _dir;
362  if (dir.at(dir.length() - 1) != QLatin1Char('/'))
363  dir += QLatin1Char('/');
364 
365  if (!d->xdgdata_prefixes.contains(dir)) {
366  priorityAdd(d->xdgdata_prefixes, dir, priority);
367  d->m_dircache.clear();
368  }
369 }
370 
371 QString KStandardDirs::kfsstnd_prefixes()
372 {
373  return d->m_prefixes.join(QString(QLatin1Char(KPATH_SEPARATOR)));
374 }
375 
376 QString KStandardDirs::kfsstnd_xdg_conf_prefixes()
377 {
378  return d->xdgconf_prefixes.join(QString(QLatin1Char(KPATH_SEPARATOR)));
379 }
380 
381 QString KStandardDirs::kfsstnd_xdg_data_prefixes()
382 {
383  return d->xdgdata_prefixes.join(QString(QLatin1Char(KPATH_SEPARATOR)));
384 }
385 
386 #ifndef KDE_NO_DEPRECATED
387 bool KStandardDirs::addResourceType( const char *type,
388  const QString& relativename,
389  bool priority )
390 {
391  return addResourceType( type, 0, relativename, priority);
392 }
393 #endif
394 
395 bool KStandardDirs::addResourceType( const char *type,
396  const char *basetype,
397  const QString& relativename,
398  bool priority )
399 {
400  if (relativename.isEmpty())
401  return false;
402 
403  QString copy = relativename;
404  if (basetype)
405  copy = QLatin1Char('%') + QString::fromLatin1(basetype) + QLatin1Char('/') + relativename;
406 
407  if (!copy.endsWith(QLatin1Char('/')))
408  copy += QLatin1Char('/');
409 
410  QByteArray typeBa = type;
411  QStringList& rels = d->m_relatives[typeBa]; // find or insert
412 
413  if (!rels.contains(copy)) {
414  if (priority)
415  rels.prepend(copy);
416  else
417  rels.append(copy);
418  // clean the caches
419  d->m_dircache.remove(typeBa);
420  d->m_savelocations.remove(typeBa);
421  return true;
422  }
423  return false;
424 }
425 
426 bool KStandardDirs::addResourceDir( const char *type,
427  const QString& absdir,
428  bool priority)
429 {
430  if (absdir.isEmpty() || !type)
431  return false;
432  // find or insert entry in the map
433  QString copy = absdir;
434  if (copy.at(copy.length() - 1) != QLatin1Char('/'))
435  copy += QLatin1Char('/');
436 
437  QByteArray typeBa = type;
438  QStringList &paths = d->m_absolutes[typeBa];
439  if (!paths.contains(copy)) {
440  if (priority)
441  paths.prepend(copy);
442  else
443  paths.append(copy);
444  // clean the caches
445  d->m_dircache.remove(typeBa);
446  d->m_savelocations.remove(typeBa);
447  return true;
448  }
449  return false;
450 }
451 
452 QString KStandardDirs::findResource( const char *type,
453  const QString& _filename ) const
454 {
455  if (!QDir::isRelativePath(_filename))
456  return !KGlobal::hasLocale() ? _filename // absolute dirs are absolute dirs, right? :-/
457  : KGlobal::locale()->localizedFilePath(_filename); // -- almost.
458 
459 #if 0
460  kDebug(180) << "Find resource: " << type;
461  for (QStringList::ConstIterator pit = m_prefixes.begin();
462  pit != m_prefixes.end();
463  ++pit)
464  {
465  kDebug(180) << "Prefix: " << *pit;
466  }
467 #endif
468 
469  QString filename(_filename);
470 #ifdef Q_OS_WIN
471  if(strcmp(type, "exe") == 0) {
472  if(!filename.endsWith(QLatin1String(".exe")))
473  filename += QLatin1String(".exe");
474  }
475 #endif
476  const QString dir = findResourceDir(type, filename);
477  if (dir.isEmpty())
478  return dir;
479  else
480  return !KGlobal::hasLocale() ? dir + filename
481  : KGlobal::locale()->localizedFilePath(dir + filename);
482 }
483 
484 static quint32 updateHash(const QString &file, quint32 hash)
485 {
486  KDE_struct_stat buff;
487  if ((KDE::access(file, R_OK) == 0) && (KDE::stat(file, &buff) == 0) && (S_ISREG(buff.st_mode))) {
488  hash = hash + static_cast<quint32>(buff.st_ctime);
489  }
490  return hash;
491 }
492 
493 quint32 KStandardDirs::calcResourceHash( const char *type,
494  const QString& filename,
495  SearchOptions options ) const
496 {
497  quint32 hash = 0;
498 
499  if (!QDir::isRelativePath(filename))
500  {
501  // absolute dirs are absolute dirs, right? :-/
502  return updateHash(filename, hash);
503  }
504  QStringList candidates = d->resourceDirs(type, filename);
505 
506  foreach ( const QString& candidate, candidates )
507  {
508  hash = updateHash(candidate + filename, hash);
509  if ( !( options & Recursive ) && hash ) {
510  return hash;
511  }
512  }
513  return hash;
514 }
515 
516 
517 QStringList KStandardDirs::findDirs( const char *type,
518  const QString& reldir ) const
519 {
520  QDir testdir;
521  QStringList list;
522  if (!QDir::isRelativePath(reldir))
523  {
524  testdir.setPath(reldir);
525  if (testdir.exists())
526  {
527  if (reldir.endsWith(QLatin1Char('/')))
528  list.append(reldir);
529  else
530  list.append(reldir+QLatin1Char('/'));
531  }
532  return list;
533  }
534 
535  const QStringList candidates = d->resourceDirs(type, reldir);
536 
537  for (QStringList::ConstIterator it = candidates.begin();
538  it != candidates.end(); ++it) {
539  testdir.setPath(*it + reldir);
540  if (testdir.exists())
541  list.append(testdir.absolutePath() + QLatin1Char('/'));
542  }
543 
544  return list;
545 }
546 
547 QString KStandardDirs::findResourceDir( const char *type,
548  const QString& _filename) const
549 {
550 #ifndef NDEBUG
551  if (_filename.isEmpty()) {
552  kWarning() << "filename for type " << type << " in KStandardDirs::findResourceDir is not supposed to be empty!!";
553  return QString();
554  }
555 #endif
556 
557  QString filename(_filename);
558 #ifdef Q_OS_WIN
559  if(strcmp(type, "exe") == 0) {
560  if(!filename.endsWith(QLatin1String(".exe")))
561  filename += QLatin1String(".exe");
562  }
563 #endif
564  const QStringList candidates = d->resourceDirs(type, filename);
565 
566  for (QStringList::ConstIterator it = candidates.begin();
567  it != candidates.end(); ++it) {
568  if (exists(*it + filename)) {
569  return *it;
570  }
571  }
572 
573 #ifndef NDEBUG
574  if(false && strcmp(type, "locale"))
575  kDebug(180) << "KStdDirs::findResDir(): can't find \"" << filename << "\" in type \"" << type << "\".";
576 #endif
577 
578  return QString();
579 }
580 
581 bool KStandardDirs::exists(const QString &fullPath)
582 {
583 #ifdef Q_OS_WIN
584  // access() and stat() give a stupid error message to the user
585  // if the path is not accessible at all (e.g. no disk in A:/ and
586  // we do stat("A:/.directory")
587  if (fullPath.endsWith(QLatin1Char('/')))
588  return QDir(fullPath).exists();
589  return QFileInfo(fullPath).exists();
590 #else
591  KDE_struct_stat buff;
592  QByteArray cFullPath = QFile::encodeName(fullPath);
593  if (access(cFullPath, R_OK) == 0 && KDE_stat( cFullPath, &buff ) == 0) {
594  if (!fullPath.endsWith(QLatin1Char('/'))) {
595  if (S_ISREG( buff.st_mode ))
596  return true;
597  } else
598  if (S_ISDIR( buff.st_mode ))
599  return true;
600  }
601  return false;
602 #endif
603 }
604 
605 static void lookupDirectory(const QString& path, const QString &relPart,
606  const QRegExp &regexp,
607  QStringList& list,
608  QStringList& relList,
609  bool recursive, bool unique)
610 {
611  const QString pattern = regexp.pattern();
612  if (recursive || pattern.contains(QLatin1Char('?')) || pattern.contains(QLatin1Char('*')))
613  {
614  if (path.isEmpty()) //for sanity
615  return;
616 #ifdef Q_WS_WIN
617  QString path_ = path + QLatin1String( "*.*" );
618  WIN32_FIND_DATA findData;
619  HANDLE hFile = FindFirstFile( (LPWSTR)path_.utf16(), &findData );
620  if( hFile == INVALID_HANDLE_VALUE )
621  return;
622  do {
623  const int len = wcslen( findData.cFileName );
624  if (!( findData.cFileName[0] == '.' &&
625  findData.cFileName[1] == '\0' ) &&
626  !( findData.cFileName[0] == '.' &&
627  findData.cFileName[1] == '.' &&
628  findData.cFileName[2] == '\0' ) &&
629  ( findData.cFileName[len-1] != '~' ) ) {
630  QString fn = QString::fromUtf16( (const unsigned short*)findData.cFileName );
631  if (!recursive && !regexp.exactMatch(fn))
632  continue; // No match
633  QString pathfn = path + fn;
634  bool bIsDir = ( ( findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) == FILE_ATTRIBUTE_DIRECTORY );
635  if ( recursive ) {
636  if ( bIsDir ) {
637  lookupDirectory(pathfn + QLatin1Char('/'),
638  relPart + fn + QLatin1Char('/'),
639  regexp, list, relList, recursive, unique);
640  }
641  if (!regexp.exactMatch(fn))
642  continue; // No match
643  }
644  if ( !bIsDir )
645  {
646  if ( !unique || !relList.contains(relPart + fn) )
647  {
648  list.append( pathfn );
649  relList.append( relPart + fn );
650  }
651  }
652  }
653  } while( FindNextFile( hFile, &findData ) != 0 );
654  FindClose( hFile );
655 #else
656  // We look for a set of files.
657  DIR *dp = opendir( QFile::encodeName(path));
658  if (!dp)
659  return;
660 
661  assert(path.endsWith(QLatin1Char('/')));
662 
663  struct dirent *ep;
664 
665  while( ( ep = readdir( dp ) ) != 0L )
666  {
667  QString fn( QFile::decodeName(ep->d_name));
668  if (fn == QString::fromLatin1(".") || fn == QString::fromLatin1("..") || fn.at(fn.length() - 1) == QLatin1Char('~'))
669  continue;
670 
671  if (!recursive && !regexp.exactMatch(fn))
672  continue; // No match
673 
674  bool isDir;
675  bool isReg;
676 
677  QString pathfn = path + fn;
678 #ifdef HAVE_DIRENT_D_TYPE
679  isDir = ep->d_type == DT_DIR;
680  isReg = ep->d_type == DT_REG;
681 
682  if (ep->d_type == DT_UNKNOWN || ep->d_type == DT_LNK)
683 #endif
684  {
685  KDE_struct_stat buff;
686  if ( KDE::stat( pathfn, &buff ) != 0 ) {
687  kDebug(180) << "Error stat'ing " << pathfn << " : " << perror;
688  continue; // Couldn't stat (e.g. no read permissions)
689  }
690  isReg = S_ISREG (buff.st_mode);
691  isDir = S_ISDIR (buff.st_mode);
692  }
693 
694  if ( recursive ) {
695  if ( isDir ) {
696  lookupDirectory(pathfn + QLatin1Char('/'), relPart + fn + QLatin1Char('/'), regexp, list, relList, recursive, unique);
697  }
698  if (!regexp.exactMatch(fn))
699  continue; // No match
700  }
701  if ( isReg )
702  {
703  if (!unique || !relList.contains(relPart + fn))
704  {
705  list.append( pathfn );
706  relList.append( relPart + fn );
707  }
708  }
709  }
710  closedir( dp );
711 #endif
712  }
713  else
714  {
715  // We look for a single file.
716  QString fn = pattern;
717  QString pathfn = path + fn;
718  KDE_struct_stat buff;
719  if ( KDE::stat( pathfn, &buff ) != 0 )
720  return; // File not found
721  if ( S_ISREG( buff.st_mode))
722  {
723  if (!unique || !relList.contains(relPart + fn))
724  {
725  list.append( pathfn );
726  relList.append( relPart + fn );
727  }
728  }
729  }
730 }
731 
732 static void lookupPrefix(const QString& prefix, const QString& relpath,
733  const QString& relPart,
734  const QRegExp &regexp,
735  QStringList& list,
736  QStringList& relList,
737  bool recursive, bool unique)
738 {
739  if (relpath.isEmpty()) {
740  if (recursive)
741  Q_ASSERT(prefix != QLatin1String("/")); // we don't want to recursively list the whole disk!
742  lookupDirectory(prefix, relPart, regexp, list,
743  relList, recursive, unique);
744  return;
745  }
746  QString path;
747  QString rest;
748 
749  int slash = relpath.indexOf(QLatin1Char('/'));
750  if (slash < 0)
751  rest = relpath.left(relpath.length() - 1);
752  else {
753  path = relpath.left(slash);
754  rest = relpath.mid(slash + 1);
755  }
756 
757  if (prefix.isEmpty()) //for sanity
758  return;
759 #ifndef Q_WS_WIN
760  // what does this assert check ?
761  assert(prefix.endsWith(QLatin1Char('/')));
762 #endif
763  if (path.contains(QLatin1Char('*')) || path.contains(QLatin1Char('?'))) {
764 
765  QRegExp pathExp(path, Qt::CaseSensitive, QRegExp::Wildcard);
766 
767 #ifdef Q_WS_WIN
768  QString prefix_ = prefix + QLatin1String( "*.*" );
769  WIN32_FIND_DATA findData;
770  HANDLE hFile = FindFirstFile( (LPWSTR)prefix_.utf16(), &findData );
771  if( hFile == INVALID_HANDLE_VALUE )
772  return;
773  do {
774  const int len = wcslen( findData.cFileName );
775  if (!( findData.cFileName[0] == '.' &&
776  findData.cFileName[1] == '\0' ) &&
777  !( findData.cFileName[0] == '.' &&
778  findData.cFileName[1] == '.' &&
779  findData.cFileName[2] == '\0' ) &&
780  ( findData.cFileName[len-1] != '~' ) ) {
781  const QString fn = QString::fromUtf16( (const unsigned short*)findData.cFileName );
782  if ( !pathExp.exactMatch(fn) )
783  continue; // No match
784  if ( ( findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) == FILE_ATTRIBUTE_DIRECTORY )
785  lookupPrefix(prefix + fn + QLatin1Char('/'),
786  rest, relPart + fn + QLatin1Char('/'),
787  regexp, list, relList, recursive, unique);
788  }
789  } while( FindNextFile( hFile, &findData ) != 0 );
790  FindClose( hFile );
791 #else
792  DIR *dp = opendir( QFile::encodeName(prefix) );
793  if (!dp) {
794  return;
795  }
796 
797  struct dirent *ep;
798 
799  while( ( ep = readdir( dp ) ) != 0L )
800  {
801  QString fn( QFile::decodeName(ep->d_name));
802  if (fn == QLatin1String(".") || fn == QLatin1String("..") || fn.at(fn.length() - 1) == QLatin1Char('~'))
803  continue;
804 
805  if ( !pathExp.exactMatch(fn) )
806  continue; // No match
807  QString rfn = relPart+fn;
808  fn = prefix + fn;
809 
810  bool isDir;
811 
812 #ifdef HAVE_DIRENT_D_TYPE
813  isDir = ep->d_type == DT_DIR;
814 
815  if (ep->d_type == DT_UNKNOWN || ep->d_type == DT_LNK)
816 #endif
817  {
818  QString pathfn = path + fn;
819  KDE_struct_stat buff;
820  if ( KDE::stat( fn, &buff ) != 0 ) {
821  kDebug(180) << "Error stat'ing " << fn << " : " << perror;
822  continue; // Couldn't stat (e.g. no read permissions)
823  }
824  isDir = S_ISDIR (buff.st_mode);
825  }
826  if ( isDir )
827  lookupPrefix(fn + QLatin1Char('/'), rest, rfn + QLatin1Char('/'), regexp, list, relList, recursive, unique);
828  }
829 
830  closedir( dp );
831 #endif
832  } else {
833  // Don't stat, if the dir doesn't exist we will find out
834  // when we try to open it.
835  lookupPrefix(prefix + path + QLatin1Char('/'), rest,
836  relPart + path + QLatin1Char('/'), regexp, list,
837  relList, recursive, unique);
838  }
839 }
840 
841 QStringList
842 KStandardDirs::findAllResources( const char *type,
843  const QString& filter,
844  SearchOptions options,
845  QStringList &relList) const
846 {
847  QString filterPath;
848  QString filterFile;
849 
850  if ( !filter.isEmpty() )
851  {
852  int slash = filter.lastIndexOf(QLatin1Char('/'));
853  if (slash < 0) {
854  filterFile = filter;
855  } else {
856  filterPath = filter.left(slash + 1);
857  filterFile = filter.mid(slash + 1);
858  }
859  }
860 
861  QStringList candidates;
862  if ( !QDir::isRelativePath(filter) ) // absolute path
863  {
864 #ifdef Q_OS_WIN
865  candidates << filterPath.left(3); //e.g. "C:\"
866  filterPath = filterPath.mid(3);
867 #else
868  candidates << QString::fromLatin1("/");
869  filterPath = filterPath.mid(1);
870 #endif
871  }
872  else
873  {
874  candidates = d->resourceDirs(type, filter);
875  }
876 
877  if (filterFile.isEmpty()) {
878  filterFile = QString(QLatin1Char('*'));
879  }
880 
881  QRegExp regExp(filterFile, Qt::CaseSensitive, QRegExp::Wildcard);
882 
883  QStringList list;
884  foreach ( const QString& candidate, candidates )
885  {
886  lookupPrefix(candidate, filterPath, QString(), regExp, list,
887  relList, options & Recursive, options & NoDuplicates);
888  }
889 
890  return list;
891 }
892 
893 QStringList
894 KStandardDirs::findAllResources( const char *type,
895  const QString& filter,
896  SearchOptions options ) const
897 {
898  QStringList relList;
899  return findAllResources(type, filter, options, relList);
900 }
901 
902 // ####### KDE4: should this be removed, in favor of QDir::canonicalPath()?
903 // aseigo: QDir::canonicalPath returns QString() if the dir doesn't exist
904 // and this method is often used with the expectation for it to work
905 // even if the directory doesn't exist. so ... no, we can't drop this
906 // yet
907 QString
908 KStandardDirs::realPath(const QString &dirname)
909 {
910 #ifdef Q_WS_WIN
911  const QString strRet = realFilePath(dirname);
912  if (!strRet.endsWith(QLatin1Char('/')))
913  return strRet + QLatin1Char('/');
914  return strRet;
915 #else
916  if (dirname.isEmpty() || (dirname.size() == 1 && dirname.at(0) == QLatin1Char('/')))
917  return dirname;
918 
919  if (dirname.at(0) != QLatin1Char('/')) {
920  qWarning("realPath called with a relative path '%s', please fix", qPrintable(dirname));
921  return dirname;
922  }
923 
924  char realpath_buffer[MAXPATHLEN + 1];
925  memset(realpath_buffer, 0, MAXPATHLEN + 1);
926 
927  /* If the path contains symlinks, get the real name */
928  if (realpath( QFile::encodeName(dirname).constData(), realpath_buffer) != 0) {
929  // success, use result from realpath
930  int len = strlen(realpath_buffer);
931  realpath_buffer[len] = '/';
932  realpath_buffer[len+1] = 0;
933  return QFile::decodeName(realpath_buffer);
934  }
935 
936  // Does not exist yet; resolve symlinks in parent dirs then.
937  // This ensures that once the directory exists, it will still be resolved
938  // the same way, so that the general rule that KStandardDirs always returns
939  // canonical paths stays true, and app code can compare paths more easily.
940  QString dir = dirname;
941  if (!dir.endsWith(QLatin1Char('/')))
942  dir += QLatin1Char('/');
943  QString relative;
944  while (!KStandardDirs::exists(dir)) {
945  //qDebug() << "does not exist:" << dir;
946  const int pos = dir.lastIndexOf(QLatin1Char('/'), -2);
947  Q_ASSERT(pos >= 0); // what? even "/" doesn't exist?
948  relative.prepend(dir.mid(pos+1)); // keep "subdir/"
949  dir = dir.left(pos+1);
950  Q_ASSERT(dir.endsWith(QLatin1Char('/')));
951  }
952  Q_ASSERT(!relative.isEmpty()); // infinite recursion ahead
953  if (!relative.isEmpty()) {
954  //qDebug() << "done, resolving" << dir << "and adding" << relative;
955  dir = realPath(dir) + relative;
956  }
957  return dir;
958 #endif
959 }
960 
961 // ####### KDE4: should this be removed, in favor of QDir::canonicalPath()?
962 // aseigo: QDir::canonicalPath returns QString() if the dir doesn't exist
963 // and this method is often used with the expectation for it to work
964 // even if the directory doesn't exist. so ... no, we can't drop this
965 // yet
966 QString
967 KStandardDirs::realFilePath(const QString &filename)
968 {
969 #ifdef Q_WS_WIN
970  LPCWSTR lpIn = (LPCWSTR)filename.utf16();
971  QVarLengthArray<WCHAR, MAX_PATH> buf(MAX_PATH);
972  DWORD len = GetFullPathNameW(lpIn, buf.size(), buf.data(), NULL);
973  if (len > (DWORD)buf.size()) {
974  buf.resize(len);
975  len = GetFullPathNameW(lpIn, buf.size(), buf.data(), NULL);
976  }
977  if (len == 0)
978  return QString();
979  return QString::fromUtf16((const unsigned short*)buf.data()).replace(QLatin1Char('\\'),QLatin1Char('/')).toLower();
980 #else
981  char realpath_buffer[MAXPATHLEN + 1];
982  memset(realpath_buffer, 0, MAXPATHLEN + 1);
983 
984  /* If the path contains symlinks, get the real name */
985  if (realpath( QFile::encodeName(filename).constData(), realpath_buffer) != 0) {
986  // success, use result from realpath
987  return QFile::decodeName(realpath_buffer);
988  }
989 
990  return filename;
991 #endif
992 }
993 
994 
995 void KStandardDirs::KStandardDirsPrivate::createSpecialResource(const char *type)
996 {
997  char hostname[256];
998  hostname[0] = 0;
999  gethostname(hostname, 255);
1000  const QString localkdedir = m_prefixes.first();
1001  QString dir = localkdedir + QString::fromLatin1(type) + QLatin1Char('-') + QString::fromLocal8Bit(hostname);
1002  char link[1024];
1003  link[1023] = 0;
1004  int result = readlink(QFile::encodeName(dir).constData(), link, 1023);
1005  bool relink = (result == -1) && (errno == ENOENT);
1006  if (result > 0)
1007  {
1008  link[result] = 0;
1009  if (!QDir::isRelativePath(QFile::decodeName(link)))
1010  {
1011  KDE_struct_stat stat_buf;
1012  int res = KDE::lstat(QFile::decodeName(link), &stat_buf);
1013  if ((res == -1) && (errno == ENOENT))
1014  {
1015  relink = true;
1016  }
1017  else if ((res == -1) || (!S_ISDIR(stat_buf.st_mode)))
1018  {
1019  fprintf(stderr, "Error: \"%s\" is not a directory.\n", link);
1020  relink = true;
1021  }
1022  else if (stat_buf.st_uid != getuid())
1023  {
1024  fprintf(stderr, "Error: \"%s\" is owned by uid %d instead of uid %d.\n", link, stat_buf.st_uid, getuid());
1025  relink = true;
1026  }
1027  }
1028  }
1029 #ifdef Q_WS_WIN
1030  if (relink)
1031  {
1032  if (!makeDir(dir, 0700))
1033  fprintf(stderr, "failed to create \"%s\"", qPrintable(dir));
1034  else
1035  result = readlink(QFile::encodeName(dir).constData(), link, 1023);
1036  }
1037 #else //UNIX
1038  if (relink)
1039  {
1040  QString srv = findExe(QLatin1String("lnusertemp"), installPath("libexec"));
1041  if (srv.isEmpty())
1042  srv = findExe(QLatin1String("lnusertemp"));
1043  if (!srv.isEmpty())
1044  {
1045  if (system(QByteArray(QFile::encodeName(srv) + ' ' + type)) == -1) {
1046  fprintf(stderr, "Error: unable to launch lnusertemp command" );
1047  }
1048  result = readlink(QFile::encodeName(dir).constData(), link, 1023);
1049  }
1050  }
1051  if (result > 0)
1052  {
1053  link[result] = 0;
1054  if (link[0] == '/')
1055  dir = QFile::decodeName(link);
1056  else
1057  dir = QDir::cleanPath(dir + QFile::decodeName(link));
1058  }
1059 #endif
1060  q->addResourceDir(type, dir + QLatin1Char('/'), false);
1061 }
1062 
1063 QStringList KStandardDirs::resourceDirs(const char *type) const
1064 {
1065  return d->resourceDirs(type, QString());
1066 }
1067 
1068 QStringList KStandardDirs::KStandardDirsPrivate::resourceDirs(const char* type, const QString& subdirForRestrictions)
1069 {
1070  QMutexLocker lock(&m_cacheMutex);
1071  const bool dataRestrictionActive = m_restrictionsActive
1072  && (strcmp(type, "data") == 0)
1073  && hasDataRestrictions(subdirForRestrictions);
1074 
1075  QMap<QByteArray, QStringList>::const_iterator dirCacheIt = m_dircache.constFind(type);
1076 
1077  QStringList candidates;
1078 
1079  if (dirCacheIt != m_dircache.constEnd() && !dataRestrictionActive) {
1080  //qDebug() << this << "resourceDirs(" << type << "), in cache already";
1081  candidates = *dirCacheIt;
1082  }
1083  else // filling cache
1084  {
1085  //qDebug() << this << "resourceDirs(" << type << "), not in cache";
1086  if (strcmp(type, "socket") == 0)
1087  createSpecialResource(type);
1088  else if (strcmp(type, "tmp") == 0)
1089  createSpecialResource(type);
1090  else if (strcmp(type, "cache") == 0)
1091  createSpecialResource(type);
1092 
1093  QDir testdir;
1094 
1095  bool restrictionActive = false;
1096  if (m_restrictionsActive) {
1097  if (dataRestrictionActive)
1098  restrictionActive = true;
1099  if (m_restrictions.value("all", false))
1100  restrictionActive = true;
1101  else if (m_restrictions.value(type, false))
1102  restrictionActive = true;
1103  }
1104 
1105  QStringList dirs;
1106  dirs = m_relatives.value(type);
1107  const QString typeInstallPath = installPath(type); // could be empty
1108 // better #ifdef incasesensitive_filesystem
1109 #ifdef Q_WS_WIN
1110  const QString installdir = typeInstallPath.isEmpty() ? QString() : realPath(typeInstallPath).toLower();
1111  const QString installprefix = installPath("kdedir").toLower();
1112 #else
1113  const QString installdir = typeInstallPath.isEmpty() ? QString() : realPath(typeInstallPath);
1114  const QString installprefix = installPath("kdedir");
1115 #endif
1116  if (!dirs.isEmpty())
1117  {
1118  bool local = true;
1119 
1120  for (QStringList::ConstIterator it = dirs.constBegin();
1121  it != dirs.constEnd(); ++it)
1122  {
1123  if ((*it).startsWith(QLatin1Char('%'))) {
1124  // grab the "data" from "%data/apps"
1125  const int pos = (*it).indexOf(QLatin1Char('/'));
1126  QString rel = (*it).mid(1, pos - 1);
1127  QString rest = (*it).mid(pos + 1);
1128  const QStringList basedirs = resourceDirs(rel.toUtf8().constData(), subdirForRestrictions);
1129  for (QStringList::ConstIterator it2 = basedirs.begin();
1130  it2 != basedirs.end(); ++it2)
1131  {
1132 #ifdef Q_WS_WIN
1133  const QString path = realPath( *it2 + rest ).toLower();
1134 #else
1135  const QString path = realPath( *it2 + rest );
1136 #endif
1137  testdir.setPath(path);
1138  if ((local || testdir.exists()) && !candidates.contains(path))
1139  candidates.append(path);
1140  local = false;
1141  }
1142  }
1143  }
1144 
1145  const QStringList *prefixList = 0;
1146  if (strncmp(type, "xdgdata-", 8) == 0)
1147  prefixList = &(xdgdata_prefixes);
1148  else if (strncmp(type, "xdgconf-", 8) == 0)
1149  prefixList = &(xdgconf_prefixes);
1150  else
1151  prefixList = &m_prefixes;
1152 
1153  for (QStringList::ConstIterator pit = prefixList->begin();
1154  pit != prefixList->end();
1155  ++pit)
1156  {
1157  if((*pit)!=installprefix||installdir.isEmpty())
1158  {
1159  for (QStringList::ConstIterator it = dirs.constBegin();
1160  it != dirs.constEnd(); ++it)
1161  {
1162  if ((*it).startsWith(QLatin1Char('%')))
1163  continue;
1164 #ifdef Q_WS_WIN
1165  const QString path = realPath( *pit + *it ).toLower();
1166 #else
1167  const QString path = realPath( *pit + *it );
1168 #endif
1169  testdir.setPath(path);
1170  if (local && restrictionActive)
1171  continue;
1172  if ((local || testdir.exists()) && !candidates.contains(path))
1173  candidates.append(path);
1174  }
1175  local = false;
1176  }
1177  else
1178  {
1179  // we have a custom install path, so use this instead of <installprefix>/<relative dir>
1180  testdir.setPath(installdir);
1181  if(testdir.exists() && ! candidates.contains(installdir))
1182  candidates.append(installdir);
1183  }
1184  }
1185  }
1186 
1187  // make sure we find the path where it's installed
1188  if (!installdir.isEmpty()) {
1189  bool ok = true;
1190  foreach (const QString &s, candidates) {
1191  if (installdir.startsWith(s)) {
1192  ok = false;
1193  break;
1194  }
1195  }
1196  if (ok)
1197  candidates.append(installdir);
1198  }
1199 
1200  dirs = m_absolutes.value(type);
1201  if (!dirs.isEmpty())
1202  for (QStringList::ConstIterator it = dirs.constBegin();
1203  it != dirs.constEnd(); ++it)
1204  {
1205  testdir.setPath(*it);
1206  if (testdir.exists()) {
1207 #ifdef Q_WS_WIN
1208  const QString filename = realPath( *it ).toLower();
1209 #else
1210  const QString filename = realPath( *it );
1211 #endif
1212  if (!candidates.contains(filename)) {
1213  candidates.append(filename);
1214  }
1215  }
1216  }
1217 
1218  // Insert result into the cache for next time.
1219  // Exception: data_subdir restrictions are per-subdir, so we can't store such results
1220  if (!dataRestrictionActive) {
1221  //kDebug() << this << "Inserting" << type << candidates << "into dircache";
1222  m_dircache.insert(type, candidates);
1223  }
1224  }
1225 
1226 #if 0
1227  kDebug(180) << "found dirs for resource" << type << ":" << candidates;
1228 #endif
1229 
1230  return candidates;
1231 }
1232 
1233 #ifdef Q_OS_WIN
1234 static QStringList executableExtensions()
1235 {
1236  QStringList ret = QString::fromLocal8Bit(qgetenv("PATHEXT")).split(QLatin1Char(';'));
1237  if (!ret.contains(QLatin1String(".exe"), Qt::CaseInsensitive)) {
1238  // If %PATHEXT% does not contain .exe, it is either empty, malformed, or distorted in ways that we cannot support, anyway.
1239  ret.clear();
1240  ret << QLatin1String(".exe")
1241  << QLatin1String(".com")
1242  << QLatin1String(".bat")
1243  << QLatin1String(".cmd");
1244  }
1245  return ret;
1246 }
1247 #endif
1248 
1249 QStringList KStandardDirs::systemPaths( const QString& pstr )
1250 {
1251  QStringList tokens;
1252  QString p = pstr;
1253 
1254  if( p.isEmpty() )
1255  {
1256  p = QString::fromLocal8Bit( qgetenv( "PATH" ) );
1257  }
1258 
1259  QString delimiters(QLatin1Char(KPATH_SEPARATOR));
1260  delimiters += QLatin1Char('\b');
1261  tokenize( tokens, p, delimiters );
1262 
1263  QStringList exePaths;
1264 
1265  // split path using : or \b as delimiters
1266  for( int i = 0; i < tokens.count(); i++ )
1267  {
1268  exePaths << KShell::tildeExpand( tokens[ i ] );
1269  }
1270 
1271  return exePaths;
1272 }
1273 
1274 #ifdef Q_WS_MAC
1275 static QString getBundle( const QString& path, bool ignore )
1276 {
1277  //kDebug(180) << "getBundle(" << path << ", " << ignore << ") called";
1278  QFileInfo info;
1279  QString bundle = path;
1280  bundle += QLatin1String(".app/Contents/MacOS/") + bundle.section(QLatin1Char('/'), -1);
1281  info.setFile( bundle );
1282  FILE *file;
1283  if (file = fopen(info.absoluteFilePath().toUtf8().constData(), "r")) {
1284  fclose(file);
1285  struct stat _stat;
1286  if ((stat(info.absoluteFilePath().toUtf8().constData(), &_stat)) < 0) {
1287  return QString();
1288  }
1289  if ( ignore || (_stat.st_mode & S_IXUSR) ) {
1290  if ( ((_stat.st_mode & S_IFMT) == S_IFREG) || ((_stat.st_mode & S_IFMT) == S_IFLNK) ) {
1291  //kDebug(180) << "getBundle(): returning " << bundle;
1292  return bundle;
1293  }
1294  }
1295  }
1296  return QString();
1297 }
1298 #endif
1299 
1300 static QString checkExecutable( const QString& path, bool ignoreExecBit )
1301 {
1302 #ifdef Q_WS_MAC
1303  QString bundle = getBundle( path, ignoreExecBit );
1304  if ( !bundle.isEmpty() ) {
1305  //kDebug(180) << "findExe(): returning " << bundle;
1306  return bundle;
1307  }
1308 #endif
1309  QFileInfo info( path );
1310  QFileInfo orig = info;
1311 #if defined(Q_OS_DARWIN) || defined(Q_OS_MAC)
1312  FILE *file;
1313  if (file = fopen(orig.absoluteFilePath().toUtf8().constData(), "r")) {
1314  fclose(file);
1315  struct stat _stat;
1316  if ((stat(orig.absoluteFilePath().toUtf8().constData(), &_stat)) < 0) {
1317  return QString();
1318  }
1319  if ( ignoreExecBit || (_stat.st_mode & S_IXUSR) ) {
1320  if ( ((_stat.st_mode & S_IFMT) == S_IFREG) || ((_stat.st_mode & S_IFMT) == S_IFLNK) ) {
1321  orig.makeAbsolute();
1322  return orig.filePath();
1323  }
1324  }
1325  }
1326  return QString();
1327 #else
1328  if( info.exists() && info.isSymLink() )
1329  info = QFileInfo( info.canonicalFilePath() );
1330  if( info.exists() && ( ignoreExecBit || info.isExecutable() ) && info.isFile() ) {
1331  // return absolute path, but without symlinks resolved in order to prevent
1332  // problems with executables that work differently depending on name they are
1333  // run as (for example gunzip)
1334  orig.makeAbsolute();
1335  return orig.filePath();
1336  }
1337  //kDebug(180) << "checkExecutable(): failed, returning empty string";
1338  return QString();
1339 #endif
1340 }
1341 
1342 QString KStandardDirs::findExe( const QString& appname,
1343  const QString& pstr,
1344  SearchOptions options )
1345 {
1346  //kDebug(180) << "findExe(" << appname << ", pstr, " << ignoreExecBit << ") called";
1347 
1348 #ifdef Q_OS_WIN
1349  QStringList executable_extensions = executableExtensions();
1350  if (!executable_extensions.contains(appname.section(QLatin1Char('.'), -1, -1, QString::SectionIncludeLeadingSep), Qt::CaseInsensitive)) {
1351  QString found_exe;
1352  foreach (const QString& extension, executable_extensions) {
1353  found_exe = findExe(appname + extension, pstr, options);
1354  if (!found_exe.isEmpty()) {
1355  return found_exe;
1356  }
1357  }
1358  return QString();
1359  }
1360 #endif
1361  QFileInfo info;
1362 
1363  // absolute or relative path?
1364  if (appname.contains(QDir::separator()))
1365  {
1366  //kDebug(180) << "findExe(): absolute path given";
1367  QString path = checkExecutable(appname, options & IgnoreExecBit);
1368  return path;
1369  }
1370 
1371  //kDebug(180) << "findExe(): relative path given";
1372 
1373  QString p = installPath("libexec") + appname;
1374  QString result = checkExecutable(p, options & IgnoreExecBit);
1375  if (!result.isEmpty()) {
1376  //kDebug(180) << "findExe(): returning " << result;
1377  return result;
1378  }
1379 
1380  //kDebug(180) << "findExe(): checking system paths";
1381  const QStringList exePaths = systemPaths( pstr );
1382  for (QStringList::ConstIterator it = exePaths.begin(); it != exePaths.end(); ++it)
1383  {
1384  p = (*it) + QLatin1Char('/');
1385  p += appname;
1386 
1387  // Check for executable in this tokenized path
1388  result = checkExecutable(p, options & IgnoreExecBit);
1389  if (!result.isEmpty()) {
1390  //kDebug(180) << "findExe(): returning " << result;
1391  return result;
1392  }
1393  }
1394 
1395  // Not found in PATH, look into the KDE-specific bin dir ("exe" resource)
1396  p = installPath("exe");
1397  p += appname;
1398  result = checkExecutable(p, options & IgnoreExecBit);
1399  if (!result.isEmpty()) {
1400  //kDebug(180) << "findExe(): returning " << result;
1401  return result;
1402  }
1403 
1404  // If we reach here, the executable wasn't found.
1405  // So return empty string.
1406 
1407  //kDebug(180) << "findExe(): failed, nothing matched";
1408  return QString();
1409 }
1410 
1411 int KStandardDirs::findAllExe( QStringList& list, const QString& appname,
1412  const QString& pstr, SearchOptions options )
1413 {
1414 #ifdef Q_OS_WIN
1415  QStringList executable_extensions = executableExtensions();
1416  if (!executable_extensions.contains(appname.section(QLatin1Char('.'), -1, -1, QString::SectionIncludeLeadingSep), Qt::CaseInsensitive)) {
1417  int total = 0;
1418  foreach (const QString& extension, executable_extensions) {
1419  total += findAllExe (list, appname + extension, pstr, options);
1420  }
1421  return total;
1422  }
1423 #endif
1424  QFileInfo info;
1425  QString p;
1426  list.clear();
1427 
1428  const QStringList exePaths = systemPaths( pstr );
1429  for (QStringList::ConstIterator it = exePaths.begin(); it != exePaths.end(); ++it)
1430  {
1431  p = (*it) + QLatin1Char('/');
1432  p += appname;
1433 
1434 #ifdef Q_WS_MAC
1435  QString bundle = getBundle( p, (options & IgnoreExecBit) );
1436  if ( !bundle.isEmpty() ) {
1437  //kDebug(180) << "findExe(): returning " << bundle;
1438  list.append( bundle );
1439  }
1440 #endif
1441 
1442  info.setFile( p );
1443 
1444  if( info.exists() && ( ( options & IgnoreExecBit ) || info.isExecutable())
1445  && info.isFile() ) {
1446  list.append( p );
1447  }
1448  }
1449 
1450  return list.count();
1451 }
1452 
1453 static inline QString equalizePath(QString &str)
1454 {
1455 #ifdef Q_WS_WIN
1456  // filter pathes through QFileInfo to have always
1457  // the same case for drive letters
1458  QFileInfo f(str);
1459  if (f.isAbsolute())
1460  return f.absoluteFilePath();
1461  else
1462 #endif
1463  return str;
1464 }
1465 
1466 static void tokenize(QStringList& tokens, const QString& str,
1467  const QString& delim)
1468 {
1469  const int len = str.length();
1470  QString token;
1471 
1472  for(int index = 0; index < len; index++) {
1473  if (delim.contains(str[index])) {
1474  tokens.append(equalizePath(token));
1475  token.clear();
1476  } else {
1477  token += str[index];
1478  }
1479  }
1480  if (!token.isEmpty()) {
1481  tokens.append(equalizePath(token));
1482  }
1483 }
1484 
1485 #ifndef KDE_NO_DEPRECATED
1486 QString KStandardDirs::kde_default(const char *type)
1487 {
1488  return QString(QLatin1Char('%')) + QString::fromLatin1(type) + QLatin1Char('/');
1489 }
1490 #endif
1491 
1492 QString KStandardDirs::saveLocation(const char *type,
1493  const QString& suffix,
1494  bool create) const
1495 {
1496  QMutexLocker lock(&d->m_cacheMutex);
1497  QString path = d->m_savelocations.value(type);
1498  if (path.isEmpty())
1499  {
1500  QStringList dirs = d->m_relatives.value(type);
1501  if (dirs.isEmpty() && (
1502  (strcmp(type, "socket") == 0) ||
1503  (strcmp(type, "tmp") == 0) ||
1504  (strcmp(type, "cache") == 0) ))
1505  {
1506  (void) resourceDirs(type); // Generate socket|tmp|cache resource.
1507  dirs = d->m_relatives.value(type); // Search again.
1508  }
1509  if (!dirs.isEmpty())
1510  {
1511  path = dirs.first();
1512 
1513  if (path.startsWith(QLatin1Char('%'))) {
1514  // grab the "data" from "%data/apps"
1515  const int pos = path.indexOf(QLatin1Char('/'));
1516  QString rel = path.mid(1, pos - 1);
1517  QString rest = path.mid(pos + 1);
1518  QString basepath = saveLocation(rel.toUtf8().constData());
1519  path = basepath + rest;
1520  } else
1521 
1522  // Check for existence of typed directory + suffix
1523  if (strncmp(type, "xdgdata-", 8) == 0) {
1524  path = realPath( localxdgdatadir() + path ) ;
1525  } else if (strncmp(type, "xdgconf-", 8) == 0) {
1526  path = realPath( localxdgconfdir() + path );
1527  } else {
1528  path = realPath( localkdedir() + path );
1529  }
1530  }
1531  else {
1532  dirs = d->m_absolutes.value(type);
1533  if (dirs.isEmpty()) {
1534  qFatal("KStandardDirs: The resource type %s is not registered", type);
1535  } else {
1536  path = realPath(dirs.first());
1537  }
1538  }
1539 
1540  d->m_savelocations.insert(type, path.endsWith(QLatin1Char('/')) ? path : path + QLatin1Char('/'));
1541  }
1542  QString fullPath = path + suffix;
1543 
1544  KDE_struct_stat st;
1545  if (KDE::stat(fullPath, &st) != 0 || !(S_ISDIR(st.st_mode))) {
1546  if(!create) {
1547 #ifndef NDEBUG
1548  // Too much noise from kbuildsycoca4 -- it's fine if this happens from KConfig
1549  // when parsing global files without a local equivalent.
1550  //kDebug(180) << QString("save location %1 doesn't exist").arg(fullPath);
1551 #endif
1552  return fullPath;
1553  }
1554  if(!makeDir(fullPath, 0700)) {
1555  return fullPath;
1556  }
1557  d->m_dircache.remove(type);
1558  }
1559  if (!fullPath.endsWith(QLatin1Char('/')))
1560  fullPath += QLatin1Char('/');
1561  return fullPath;
1562 }
1563 
1564 // KDE5: make the method const
1565 QString KStandardDirs::relativeLocation(const char *type, const QString &absPath)
1566 {
1567  QString fullPath = absPath;
1568  int i = absPath.lastIndexOf(QLatin1Char('/'));
1569  if (i != -1) {
1570  fullPath = realFilePath(absPath); // Normalize
1571  }
1572 
1573  const QStringList candidates = resourceDirs(type);
1574 
1575  for (QStringList::ConstIterator it = candidates.begin();
1576  it != candidates.end(); ++it) {
1577  if (fullPath.startsWith(*it)) {
1578  return fullPath.mid((*it).length());
1579  }
1580  }
1581  return absPath;
1582 }
1583 
1584 
1585 bool KStandardDirs::makeDir(const QString& dir, int mode)
1586 {
1587  // we want an absolute path
1588  if (QDir::isRelativePath(dir))
1589  return false;
1590 
1591 #ifdef Q_WS_WIN
1592  return QDir().mkpath(dir);
1593 #else
1594  QString target = dir;
1595  uint len = target.length();
1596 
1597  // append trailing slash if missing
1598  if (dir.at(len - 1) != QLatin1Char('/'))
1599  target += QLatin1Char('/');
1600 
1601  QString base;
1602  uint i = 1;
1603 
1604  while( i < len )
1605  {
1606  KDE_struct_stat st;
1607  int pos = target.indexOf(QLatin1Char('/'), i);
1608  base += target.mid(i - 1, pos - i + 1);
1609  QByteArray baseEncoded = QFile::encodeName(base);
1610  // bail out if we encountered a problem
1611  if (KDE_stat(baseEncoded, &st) != 0)
1612  {
1613  // Directory does not exist....
1614  // Or maybe a dangling symlink ?
1615  if (KDE_lstat(baseEncoded, &st) == 0)
1616  (void)unlink(baseEncoded); // try removing
1617 
1618  if (KDE_mkdir(baseEncoded, static_cast<mode_t>(mode)) != 0) {
1619  baseEncoded.prepend( "trying to create local folder " );
1620  perror(baseEncoded.constData());
1621  return false; // Couldn't create it :-(
1622  }
1623  }
1624  i = pos + 1;
1625  }
1626  return true;
1627 #endif
1628 }
1629 
1630 static QString readEnvPath(const char *env)
1631 {
1632  QByteArray c_path;
1633 #ifndef _WIN32_WCE
1634  c_path = qgetenv(env);
1635  if (c_path.isEmpty())
1636  return QString();
1637 #else
1638  bool ok;
1639  QString retval = getWin32RegistryValue(HKEY_LOCAL_MACHINE, "Software\\kde", "KDEDIRS", &ok);
1640  if (!ok){
1641  return QString();
1642  } else {
1643  c_path = retval.toAscii();
1644  }
1645 #endif
1646  return QDir::fromNativeSeparators(QFile::decodeName(c_path));
1647 }
1648 
1649 #ifdef __linux__
1650 static QString executablePrefix()
1651 {
1652  char path_buffer[MAXPATHLEN + 1];
1653  path_buffer[MAXPATHLEN] = 0;
1654  int length = readlink ("/proc/self/exe", path_buffer, MAXPATHLEN);
1655  if (length == -1)
1656  return QString();
1657 
1658  path_buffer[length] = '\0';
1659 
1660  QString path = QFile::decodeName(path_buffer);
1661 
1662  if(path.isEmpty())
1663  return QString();
1664 
1665  int pos = path.lastIndexOf(QLatin1Char('/')); // Skip filename
1666  if(pos <= 0)
1667  return QString();
1668  pos = path.lastIndexOf(QLatin1Char('/'), pos - 1); // Skip last directory
1669  if(pos <= 0)
1670  return QString();
1671 
1672  return path.left(pos);
1673 }
1674 #endif
1675 
1676 void KStandardDirs::addResourcesFrom_krcdirs()
1677 {
1678  QString localFile = QDir::currentPath() + QLatin1String("/.krcdirs");
1679  if (!QFile::exists(localFile))
1680  return;
1681 
1682  QSettings iniFile(localFile, QSettings::IniFormat);
1683  iniFile.beginGroup(QString::fromLatin1("KStandardDirs"));
1684  const QStringList resources = iniFile.allKeys();
1685  foreach(const QString &key, resources)
1686  {
1687  QDir path(iniFile.value(key).toString());
1688  if (!path.exists())
1689  continue;
1690 
1691  if(path.makeAbsolute())
1692  addResourceDir(key.toAscii(), path.path(), false);
1693  }
1694 }
1695 
1696 void KStandardDirs::addKDEDefaults()
1697 {
1698  addResourcesFrom_krcdirs();
1699 
1700  QStringList kdedirList;
1701  // begin KDEDIRS
1702  QString kdedirs = readEnvPath("KDEDIRS");
1703 
1704  if (!kdedirs.isEmpty())
1705  {
1706  tokenize(kdedirList, kdedirs, QString(QLatin1Char(KPATH_SEPARATOR)));
1707  }
1708  kdedirList.append(installPath("kdedir"));
1709 
1710  QString execPrefix(QFile::decodeName(EXEC_INSTALL_PREFIX));
1711  if (!execPrefix.isEmpty() && !kdedirList.contains(execPrefix))
1712  kdedirList.append(execPrefix);
1713 #ifdef __linux__
1714  const QString linuxExecPrefix = executablePrefix();
1715  if ( !linuxExecPrefix.isEmpty() )
1716  kdedirList.append( linuxExecPrefix );
1717 #endif
1718 
1719  // We treat root differently to prevent a "su" shell messing up the
1720  // file permissions in the user's home directory.
1721  QString localKdeDir = readEnvPath(getuid() ? "KDEHOME" : "KDEROOTHOME");
1722  if (!localKdeDir.isEmpty()) {
1723  if (!localKdeDir.endsWith(QLatin1Char('/')))
1724  localKdeDir += QLatin1Char('/');
1725  } else {
1726  // TODO KDE5: make localKdeDir equal to localXdgDir (which is determined further below and
1727  // defaults to ~/.config) + '/' + $KDECONFIG (which would default to e.g. "KDE")
1728  // This would mean ~/.config/KDE/ by default, more xdg-compliant.
1729 
1730 #if defined(Q_WS_MACX)
1731  localKdeDir = QDir::homePath() + QLatin1String("/Library/Preferences/KDE/");
1732 #elif defined(Q_WS_WIN)
1733 #ifndef _WIN32_WCE
1734  WCHAR wPath[MAX_PATH+1];
1735  if ( SHGetFolderPathW(NULL, CSIDL_APPDATA, NULL, SHGFP_TYPE_CURRENT, wPath) == S_OK) {
1736  localKdeDir = QDir::fromNativeSeparators(QString::fromUtf16((const ushort *) wPath)) + QLatin1Char('/') + QString::fromLatin1(KDE_DEFAULT_HOME) + QLatin1Char('/');
1737  } else {
1738 #endif
1739  localKdeDir = QDir::homePath() + QLatin1Char('/') + QString::fromLatin1(KDE_DEFAULT_HOME) + QLatin1Char('/');
1740 #ifndef _WIN32_WCE
1741  }
1742 #endif
1743 #else
1744  localKdeDir = QDir::homePath() + QLatin1Char('/') + QString::fromLatin1(KDE_DEFAULT_HOME) + QLatin1Char('/');
1745 #endif
1746  }
1747 
1748  if (localKdeDir != QLatin1String("-/"))
1749  {
1750  localKdeDir = KShell::tildeExpand(localKdeDir);
1751  addPrefix(localKdeDir);
1752  }
1753 
1754 #ifdef Q_WS_MACX
1755  // Adds the "Contents" directory of the current application bundle to
1756  // the search path. This way bundled resources can be found.
1757  QDir bundleDir(mac_app_filename());
1758  if (bundleDir.dirName() == QLatin1String("MacOS")) { // just to be sure we're in a bundle
1759  bundleDir.cdUp();
1760  // now dirName should be "Contents". In there we can find our normal
1761  // dir-structure, beginning with "share"
1762  addPrefix(bundleDir.absolutePath());
1763  }
1764 #endif
1765 
1766  QStringList::ConstIterator end(kdedirList.end());
1767  for (QStringList::ConstIterator it = kdedirList.constBegin();
1768  it != kdedirList.constEnd(); ++it)
1769  {
1770  const QString dir = KShell::tildeExpand(*it);
1771  addPrefix(dir);
1772  }
1773  // end KDEDIRS
1774 
1775  // begin XDG_CONFIG_XXX
1776  QStringList xdgdirList;
1777  QString xdgdirs = readEnvPath("XDG_CONFIG_DIRS");
1778  if (!xdgdirs.isEmpty())
1779  {
1780  tokenize(xdgdirList, xdgdirs, QString(QLatin1Char(KPATH_SEPARATOR)));
1781  }
1782  else
1783  {
1784  xdgdirList.clear();
1785  xdgdirList.append(QString::fromLatin1("/etc/xdg"));
1786 #ifdef Q_WS_WIN
1787  xdgdirList.append(installPath("kdedir") + QString::fromLatin1("etc/xdg"));
1788 #else
1789  xdgdirList.append(QFile::decodeName(KDESYSCONFDIR "/xdg"));
1790 #endif
1791  }
1792 
1793  QString localXdgDir = readEnvPath("XDG_CONFIG_HOME");
1794  if (!localXdgDir.isEmpty()) {
1795  if (!localXdgDir.endsWith(QLatin1Char('/')))
1796  localXdgDir += QLatin1Char('/');
1797  } else {
1798 #ifdef Q_WS_MACX
1799  localXdgDir = QDir::homePath() + QString::fromLatin1("/Library/Preferences/XDG/");
1800 #else
1801  localXdgDir = QDir::homePath() + QString::fromLatin1("/.config/");
1802 #endif
1803  }
1804 
1805  localXdgDir = KShell::tildeExpand(localXdgDir);
1806  addXdgConfigPrefix(localXdgDir);
1807 
1808  for (QStringList::ConstIterator it = xdgdirList.constBegin();
1809  it != xdgdirList.constEnd(); ++it)
1810  {
1811  QString dir = KShell::tildeExpand(*it);
1812  addXdgConfigPrefix(dir);
1813  }
1814  // end XDG_CONFIG_XXX
1815 
1816  // begin XDG_DATA_XXX
1817  QStringList kdedirDataDirs;
1818  for (QStringList::ConstIterator it = kdedirList.constBegin();
1819  it != kdedirList.constEnd(); ++it) {
1820  QString dir = *it;
1821  if (!dir.endsWith(QLatin1Char('/')))
1822  dir += QLatin1Char('/');
1823  kdedirDataDirs.append(dir + QLatin1String("share/"));
1824  }
1825 
1826  xdgdirs = readEnvPath("XDG_DATA_DIRS");
1827  if (!xdgdirs.isEmpty()) {
1828  tokenize(xdgdirList, xdgdirs, QString(QLatin1Char(KPATH_SEPARATOR)));
1829  // Ensure the kdedirDataDirs are in there too,
1830  // otherwise resourceDirs() will add kdedir/share/applications/kde4
1831  // as returned by installPath(), and that's incorrect.
1832  Q_FOREACH(const QString& dir, kdedirDataDirs) {
1833  if (!xdgdirList.contains(dir))
1834  xdgdirList.append(dir);
1835  }
1836  } else {
1837  xdgdirList = kdedirDataDirs;
1838 #ifndef Q_WS_WIN
1839  xdgdirList.append(QString::fromLatin1("/usr/local/share/"));
1840  xdgdirList.append(QString::fromLatin1("/usr/share/"));
1841 #endif
1842  }
1843 
1844  localXdgDir = readEnvPath("XDG_DATA_HOME");
1845  if (!localXdgDir.isEmpty())
1846  {
1847  if (localXdgDir[localXdgDir.length()-1] != QLatin1Char('/'))
1848  localXdgDir += QLatin1Char('/');
1849  }
1850  else
1851  {
1852  localXdgDir = QDir::homePath() + QLatin1String("/.local/share/");
1853  }
1854 
1855  localXdgDir = KShell::tildeExpand(localXdgDir);
1856  addXdgDataPrefix(localXdgDir);
1857 
1858  for (QStringList::ConstIterator it = xdgdirList.constBegin();
1859  it != xdgdirList.constEnd(); ++it)
1860  {
1861  QString dir = KShell::tildeExpand(*it);
1862  addXdgDataPrefix(dir);
1863  }
1864  // end XDG_DATA_XXX
1865 
1866 
1867  addResourceType("lib", 0, "lib" KDELIBSUFF "/");
1868 
1869  uint index = 0;
1870  while (types_indices[index] != -1) {
1871  addResourceType(types_string + types_indices[index], 0, types_string + types_indices[index+1], true);
1872  index+=2;
1873  }
1874  addResourceType("exe", "lib", "kde4/libexec", true );
1875 
1876  addResourceDir("home", QDir::homePath(), false);
1877 
1878  addResourceType("autostart", "xdgconf-autostart", "/"); // merge them, start with xdg autostart
1879  addResourceType("autostart", NULL, "share/autostart"); // KDE ones are higher priority
1880 }
1881 
1882 static QStringList lookupProfiles(const QString &mapFile)
1883 {
1884  QStringList profiles;
1885 
1886  if (mapFile.isEmpty() || !QFile::exists(mapFile))
1887  {
1888  profiles << QString::fromLatin1("default");
1889  return profiles;
1890  }
1891 
1892  struct passwd *pw = getpwuid(geteuid());
1893  if (!pw)
1894  {
1895  profiles << QString::fromLatin1("default");
1896  return profiles; // Not good
1897  }
1898 
1899  QByteArray user = pw->pw_name;
1900 
1901  gid_t sup_gids[512];
1902  int sup_gids_nr = getgroups(512, sup_gids);
1903 
1904  KConfig mapCfgFile(mapFile);
1905  KConfigGroup mapCfg(&mapCfgFile, "Users");
1906  if (mapCfg.hasKey(user.constData()))
1907  {
1908  profiles = mapCfg.readEntry(user.constData(), QStringList());
1909  return profiles;
1910  }
1911 
1912  const KConfigGroup generalGrp(&mapCfgFile, "General");
1913  const QStringList groups = generalGrp.readEntry("groups", QStringList());
1914 
1915  const KConfigGroup groupsGrp(&mapCfgFile, "Groups");
1916 
1917  for( QStringList::ConstIterator it = groups.begin();
1918  it != groups.end(); ++it )
1919  {
1920  QByteArray grp = (*it).toUtf8();
1921  // Check if user is in this group
1922  struct group *grp_ent = getgrnam(grp);
1923  if (!grp_ent) continue;
1924  gid_t gid = grp_ent->gr_gid;
1925  if (pw->pw_gid == gid)
1926  {
1927  // User is in this group --> add profiles
1928  profiles += groupsGrp.readEntry(*it, QStringList());
1929  }
1930  else
1931  {
1932  for(int i = 0; i < sup_gids_nr; i++)
1933  {
1934  if (sup_gids[i] == gid)
1935  {
1936  // User is in this group --> add profiles
1937  profiles += groupsGrp.readEntry(*it, QStringList());
1938  break;
1939  }
1940  }
1941  }
1942  }
1943 
1944  if (profiles.isEmpty())
1945  profiles << QString::fromLatin1("default");
1946  return profiles;
1947 }
1948 
1949 extern bool kde_kiosk_admin;
1950 
1951 bool KStandardDirs::addCustomized(KConfig *config)
1952 {
1953  if (!d->m_checkRestrictions) // there are already customized entries
1954  return false; // we just quit and hope they are the right ones
1955 
1956  // save the numbers of config directories. If this changes,
1957  // we will return true to give KConfig a chance to reparse
1958  int configdirs = resourceDirs("config").count();
1959 
1960  if (true)
1961  {
1962  // reading the prefixes in
1963  QString group = QLatin1String("Directories");
1964  KConfigGroup cg(config, group);
1965 
1966  QString kioskAdmin = cg.readEntry("kioskAdmin");
1967  if (!kioskAdmin.isEmpty() && !kde_kiosk_admin)
1968  {
1969  int i = kioskAdmin.indexOf(QLatin1Char(':'));
1970  QString user = kioskAdmin.left(i);
1971  QString host = kioskAdmin.mid(i+1);
1972 
1973  KUser thisUser;
1974  char hostname[ 256 ];
1975  hostname[ 0 ] = '\0';
1976  if (!gethostname( hostname, 255 ))
1977  hostname[sizeof(hostname)-1] = '\0';
1978 
1979  if ((user == thisUser.loginName()) &&
1980  (host.isEmpty() || (host == QLatin1String(hostname))))
1981  {
1982  kde_kiosk_admin = true;
1983  }
1984  }
1985 
1986  bool readProfiles = true;
1987 
1988  if (kde_kiosk_admin && !qgetenv("KDE_KIOSK_NO_PROFILES").isEmpty())
1989  readProfiles = false;
1990 
1991  QString userMapFile = cg.readEntry("userProfileMapFile");
1992  QString profileDirsPrefix = cg.readEntry("profileDirsPrefix");
1993  if (!profileDirsPrefix.isEmpty() && !profileDirsPrefix.endsWith(QLatin1Char('/')))
1994  profileDirsPrefix.append(QLatin1Char('/'));
1995 
1996  QStringList profiles;
1997  if (readProfiles)
1998  profiles = lookupProfiles(userMapFile);
1999  QString profile;
2000 
2001  bool priority = false;
2002  while(true)
2003  {
2004  KConfigGroup cg(config, group);
2005  const QStringList list = cg.readEntry("prefixes", QStringList());
2006  for (QStringList::ConstIterator it = list.begin(); it != list.end(); ++it)
2007  {
2008  addPrefix(*it, priority);
2009  addXdgConfigPrefix(*it + QLatin1String("/etc/xdg"), priority);
2010  addXdgDataPrefix(*it + QLatin1String("/share"), priority);
2011  }
2012  // If there are no prefixes defined, check if there is a directory
2013  // for this profile under <profileDirsPrefix>
2014  if (list.isEmpty() && !profile.isEmpty() && !profileDirsPrefix.isEmpty())
2015  {
2016  QString dir = profileDirsPrefix + profile;
2017  addPrefix(dir, priority);
2018  addXdgConfigPrefix(dir + QLatin1String("/etc/xdg"), priority);
2019  addXdgDataPrefix(dir + QLatin1String("/share"), priority);
2020  }
2021 
2022  // iterating over all entries in the group Directories
2023  // to find entries that start with dir_$type
2024  const QMap<QString, QString> entries = config->entryMap(group);
2025  for (QMap<QString, QString>::ConstIterator it2 = entries.begin();
2026  it2 != entries.end(); ++it2)
2027  {
2028  const QString key = it2.key();
2029  if (key.startsWith(QLatin1String("dir_"))) {
2030  // generate directory list, there may be more than 1.
2031  const QStringList dirs = (*it2).split(QString(QLatin1Char(',')));
2032  QStringList::ConstIterator sIt(dirs.begin());
2033  QString resType = key.mid(4);
2034  for (; sIt != dirs.end(); ++sIt)
2035  {
2036  addResourceDir(resType.toLatin1(), *sIt, priority);
2037  }
2038  }
2039  }
2040  if (profiles.isEmpty())
2041  break;
2042  profile = profiles.back();
2043  group = QString::fromLatin1("Directories-%1").arg(profile);
2044  profiles.pop_back();
2045  priority = true;
2046  }
2047  }
2048 
2049  // Process KIOSK restrictions.
2050  if (!kde_kiosk_admin || qgetenv("KDE_KIOSK_NO_RESTRICTIONS").isEmpty())
2051  {
2052  KConfigGroup cg(config, "KDE Resource Restrictions");
2053  const QMap<QString, QString> entries = cg.entryMap();
2054  for (QMap<QString, QString>::ConstIterator it2 = entries.begin();
2055  it2 != entries.end(); ++it2)
2056  {
2057  const QString key = it2.key();
2058  if (!cg.readEntry(key, true))
2059  {
2060  d->m_restrictionsActive = true;
2061  const QByteArray cKey = key.toLatin1();
2062  d->m_restrictions.insert(cKey, true);
2063  d->m_dircache.remove(cKey);
2064  d->m_savelocations.remove(cKey);
2065  }
2066  }
2067  }
2068 
2069  // check if the number of config dirs changed
2070  bool configDirsChanged = (resourceDirs("config").count() != configdirs);
2071  // If the config dirs changed, we check kiosk restrictions again.
2072  d->m_checkRestrictions = configDirsChanged;
2073  // return true if the number of config dirs changed: reparse config file
2074  return configDirsChanged;
2075 }
2076 
2077 QString KStandardDirs::localkdedir() const
2078 {
2079  // Return the prefix to use for saving
2080  return d->m_prefixes.first();
2081 }
2082 
2083 QString KStandardDirs::localxdgdatadir() const
2084 {
2085  // Return the prefix to use for saving
2086  return d->xdgdata_prefixes.first();
2087 }
2088 
2089 QString KStandardDirs::localxdgconfdir() const
2090 {
2091  // Return the prefix to use for saving
2092  return d->xdgconf_prefixes.first();
2093 }
2094 
2095 
2096 // just to make code more readable without macros
2097 QString KStandardDirs::locate( const char *type,
2098  const QString& filename, const KComponentData &cData)
2099 {
2100  return cData.dirs()->findResource(type, filename);
2101 }
2102 
2103 QString KStandardDirs::locateLocal( const char *type,
2104  const QString& filename, const KComponentData &cData)
2105 {
2106  return locateLocal(type, filename, true, cData);
2107 }
2108 
2109 QString KStandardDirs::locateLocal( const char *type,
2110  const QString& filename, bool createDir,
2111  const KComponentData &cData)
2112 {
2113  // try to find slashes. If there are some, we have to
2114  // create the subdir first
2115  int slash = filename.lastIndexOf(QLatin1Char('/')) + 1;
2116  if (!slash) { // only one filename
2117  return cData.dirs()->saveLocation(type, QString(), createDir) + filename;
2118  }
2119 
2120  // split path from filename
2121  QString dir = filename.left(slash);
2122  QString file = filename.mid(slash);
2123  return cData.dirs()->saveLocation(type, dir, createDir) + file;
2124 }
2125 
2126 bool KStandardDirs::checkAccess(const QString& pathname, int mode)
2127 {
2128  int accessOK = KDE::access( pathname, mode );
2129  if ( accessOK == 0 )
2130  return true; // OK, I can really access the file
2131 
2132  // else
2133  // if we want to write the file would be created. Check, if the
2134  // user may write to the directory to create the file.
2135  if ( (mode & W_OK) == 0 )
2136  return false; // Check for write access is not part of mode => bail out
2137 
2138 
2139  if (!KDE::access( pathname, F_OK)) // if it already exists
2140  return false;
2141 
2142  //strip the filename (everything until '/' from the end
2143  QString dirName(pathname);
2144  int pos = dirName.lastIndexOf(QLatin1Char('/'));
2145  if ( pos == -1 )
2146  return false; // No path in argument. This is evil, we won't allow this
2147  else if ( pos == 0 ) // don't turn e.g. /root into an empty string
2148  pos = 1;
2149 
2150  dirName.truncate(pos); // strip everything starting from the last '/'
2151 
2152  accessOK = KDE::access( dirName, W_OK );
2153  // -?- Can I write to the accessed diretory
2154  if ( accessOK == 0 )
2155  return true; // Yes
2156  else
2157  return false; // No
2158 }
2159 
This file is part of the KDE documentation.
Documentation copyright © 1996-2012 The KDE developers.
Generated on Fri Dec 7 2012 15:57:21 by doxygen 1.8.1 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

KDECore

Skip menu "KDECore"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members
  • Modules
  • Related Pages

kdelibs-4.8.5 API Reference

Skip menu "kdelibs-4.8.5 API Reference"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDEWebKit
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal