KDELibs4Support

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

KDE's Doxygen guidelines are available online.