KService

ksycoca.cpp
1 /*
2  This file is part of the KDE libraries
3  SPDX-FileCopyrightText: 1999-2000 Waldo Bastian <[email protected]>
4  SPDX-FileCopyrightText: 2005-2009 David Faure <[email protected]>
5  SPDX-FileCopyrightText: 2008 Hamish Rodda <[email protected]>
6  SPDX-FileCopyrightText: 2020 Harald Sitter <[email protected]>
7 
8  SPDX-License-Identifier: LGPL-2.0-only
9 */
10 
11 #include "ksycoca.h"
12 #include "ksycoca_p.h"
13 #include "ksycocautils_p.h"
14 #include "ksycocatype.h"
15 #include "ksycocafactory_p.h"
16 #include <KConfigGroup>
17 #include <KSharedConfig>
18 #include "sycocadebug.h"
19 
20 #include <QStandardPaths>
21 #include <QDataStream>
22 #include <QCoreApplication>
23 #include <QFile>
24 #include <QFileInfo>
25 #include <QThread>
26 #include <QThreadStorage>
27 #include <QMetaMethod>
28 
29 #include <stdlib.h>
30 #include <fcntl.h>
31 #include <kmimetypefactory_p.h>
32 #include <kservicetypefactory_p.h>
33 #include <kservicegroupfactory_p.h>
34 #include <kservicefactory_p.h>
35 #include <QCryptographicHash>
36 
37 #include "kbuildsycoca_p.h"
38 #include "ksycocadevices_p.h"
39 
40 #ifdef Q_OS_UNIX
41 #include <utime.h>
42 #include <sys/time.h>
43 #endif
44 
52 #define KSYCOCA_VERSION 303
53 
54 #if HAVE_MADVISE || HAVE_MMAP
55 #include <sys/mman.h> // This #include was checked when looking for posix_madvise
56 #endif
57 
58 #ifndef MAP_FAILED
59 #define MAP_FAILED ((void *) -1)
60 #endif
61 
62 QDataStream &operator>>(QDataStream &in, KSycocaHeader &h) {
63  in >> h.prefixes >> h.timeStamp >> h.language >> h.updateSignature;
64  return in;
65 }
66 
67 // The following limitations are in place:
68 // Maximum length of a single string: 8192 bytes
69 // Maximum length of a string list: 1024 strings
70 // Maximum number of entries: 8192
71 //
72 // The purpose of these limitations is to limit the impact
73 // of database corruption.
74 
75 Q_DECLARE_OPERATORS_FOR_FLAGS(KSycocaPrivate::BehaviorsIfNotFound)
76 
77 KSycocaPrivate::KSycocaPrivate(KSycoca *q)
78  : databaseStatus(DatabaseNotOpen),
79  readError(false),
80  timeStamp(0),
81  m_databasePath(),
82  updateSig(0),
83  m_fileWatcher(new KDirWatch),
84  m_haveListeners(false),
85  q(q),
86  sycoca_size(0),
87  sycoca_mmap(nullptr),
88  m_mmapFile(nullptr),
89  m_device(nullptr),
90  m_mimeTypeFactory(nullptr),
91  m_serviceTypeFactory(nullptr),
92  m_serviceFactory(nullptr),
93  m_serviceGroupFactory(nullptr)
94 {
95 #ifdef Q_OS_WIN
96  /*
97  on windows we use KMemFile (QSharedMemory) to avoid problems
98  with mmap (can't delete a mmap'd file)
99  */
100  m_sycocaStrategy = StrategyMemFile;
101 #else
102  m_sycocaStrategy = StrategyMmap;
103 #endif
105  setStrategyFromString(config.readEntry("strategy"));
106 }
107 
108 void KSycocaPrivate::setStrategyFromString(const QString &strategy)
109 {
110  if (strategy == QLatin1String("mmap")) {
111  m_sycocaStrategy = StrategyMmap;
112  } else if (strategy == QLatin1String("file")) {
113  m_sycocaStrategy = StrategyFile;
114  } else if (strategy == QLatin1String("sharedmem")) {
115  m_sycocaStrategy = StrategyMemFile;
116  } else if (!strategy.isEmpty()) {
117  qCWarning(SYCOCA) << "Unknown sycoca strategy:" << strategy;
118  }
119 }
120 
121 bool KSycocaPrivate::tryMmap()
122 {
123 #if HAVE_MMAP
124  Q_ASSERT(!m_databasePath.isEmpty());
125  m_mmapFile = new QFile(m_databasePath);
126  const bool canRead = m_mmapFile->open(QIODevice::ReadOnly);
127  Q_ASSERT(canRead);
128  if (!canRead) {
129  return false;
130  }
131  fcntl(m_mmapFile->handle(), F_SETFD, FD_CLOEXEC);
132  sycoca_size = m_mmapFile->size();
133  void *mmapRet = mmap(nullptr, sycoca_size,
134  PROT_READ, MAP_SHARED,
135  m_mmapFile->handle(), 0);
136  /* POSIX mandates only MAP_FAILED, but we are paranoid so check for
137  null pointer too. */
138  if (mmapRet == MAP_FAILED || mmapRet == nullptr) {
139  qCDebug(SYCOCA).nospace() << "mmap failed. (length = " << sycoca_size << ")";
140  sycoca_mmap = nullptr;
141  return false;
142  } else {
143  sycoca_mmap = static_cast<const char *>(mmapRet);
144 #if HAVE_MADVISE
145  (void) posix_madvise(mmapRet, sycoca_size, POSIX_MADV_WILLNEED);
146 #endif // HAVE_MADVISE
147  return true;
148  }
149 #else
150  return false;
151 #endif // HAVE_MMAP
152 }
153 
155 {
156  return KSYCOCA_VERSION;
157 }
158 
159 class KSycocaSingleton
160 {
161 public:
162  KSycocaSingleton() { }
163  ~KSycocaSingleton() { }
164 
165  bool hasSycoca() const
166  {
167  return m_threadSycocas.hasLocalData();
168  }
169  KSycoca *sycoca()
170  {
171  if (!m_threadSycocas.hasLocalData()) {
172  m_threadSycocas.setLocalData(new KSycoca);
173  }
174  return m_threadSycocas.localData();
175  }
176  void setSycoca(KSycoca *s)
177  {
178  m_threadSycocas.setLocalData(s);
179  }
180 
181 private:
182  QThreadStorage<KSycoca *> m_threadSycocas;
183 };
184 
185 Q_GLOBAL_STATIC(KSycocaSingleton, ksycocaInstance)
186 
187 QString KSycocaPrivate::findDatabase()
188 {
189  Q_ASSERT(databaseStatus == DatabaseNotOpen);
190 
191  const QString path = KSycoca::absoluteFilePath();
192  const QFileInfo info(path);
193  if (info.isReadable()) {
194  if (m_haveListeners && m_fileWatcher) {
195  m_fileWatcher->addFile(path);
196  }
197  return path;
198  }
199  // Let's be notified when it gets created - by another process or by ourselves
200  if (m_fileWatcher) {
201  m_fileWatcher->addFile(path);
202  }
203  return QString();
204 }
205 
206 // Read-only constructor
207 // One instance per thread
209  : d(new KSycocaPrivate(this))
210 {
211  if (d->m_fileWatcher) {
212  // We always delete and recreate the DB, so KDirWatch normally emits created
213  connect(d->m_fileWatcher.get(), &KDirWatch::created, this, [this](){ d->slotDatabaseChanged(); });
214  // In some cases, KDirWatch only thinks the file was modified though
215  connect(d->m_fileWatcher.get(), &KDirWatch::dirty, this, [this]() { d->slotDatabaseChanged(); });
216  }
217 }
218 
219 bool KSycocaPrivate::openDatabase()
220 {
221  Q_ASSERT(databaseStatus == DatabaseNotOpen);
222 
223  delete m_device; m_device = nullptr;
224 
225  if (m_databasePath.isEmpty()) {
226  m_databasePath = findDatabase();
227  }
228 
229  bool result = true;
230  if (!m_databasePath.isEmpty()) {
231  qCDebug(SYCOCA) << "Opening ksycoca from" << m_databasePath;
232  m_dbLastModified = QFileInfo(m_databasePath).lastModified();
233  checkVersion();
234  } else { // No database file
235  //qCDebug(SYCOCA) << "Could not open ksycoca";
236  result = false;
237  }
238  return result;
239 }
240 
241 KSycocaAbstractDevice *KSycocaPrivate::device()
242 {
243  if (m_device) {
244  return m_device;
245  }
246 
247  KSycocaAbstractDevice *device = m_device;
248  Q_ASSERT(!m_databasePath.isEmpty());
249 #if HAVE_MMAP
250  if (m_sycocaStrategy == StrategyMmap && tryMmap()) {
251  device = new KSycocaMmapDevice(sycoca_mmap,
252  sycoca_size);
253  if (!device->device()->open(QIODevice::ReadOnly)) {
254  delete device; device = nullptr;
255  }
256  }
257 #endif
258 #ifndef QT_NO_SHAREDMEMORY
259  if (!device && m_sycocaStrategy == StrategyMemFile) {
260  device = new KSycocaMemFileDevice(m_databasePath);
261  if (!device->device()->open(QIODevice::ReadOnly)) {
262  delete device; device = nullptr;
263  }
264  }
265 #endif
266  if (!device) {
267  device = new KSycocaFileDevice(m_databasePath);
268  if (!device->device()->open(QIODevice::ReadOnly)) {
269  qCWarning(SYCOCA) << "Couldn't open" << m_databasePath << "even though it is readable? Impossible.";
270  //delete device; device = 0; // this would crash in the return statement...
271  }
272  }
273  if (device) {
274  m_device = device;
275  }
276  return m_device;
277 }
278 
279 QDataStream *&KSycocaPrivate::stream()
280 {
281  if (!m_device) {
282  if (databaseStatus == DatabaseNotOpen) {
283  checkDatabase(KSycocaPrivate::IfNotFoundRecreate);
284  }
285 
286  device(); // create m_device
287  }
288 
289  return m_device->stream();
290 }
291 
292 void KSycocaPrivate::slotDatabaseChanged()
293 {
294  // We don't have information anymore on what resources changed, so emit them all
295  changeList = QStringList() << QStringLiteral("services") << QStringLiteral("servicetypes") << QStringLiteral("xdgdata-mime") << QStringLiteral("apps");
296 
297  qCDebug(SYCOCA) << QThread::currentThread() << "got a notifyDatabaseChanged signal";
298  // KDirWatch tells us the database file changed
299  // We would have found out in the next call to ensureCacheValid(), but for
300  // now keep the call to closeDatabase, to help refcounting to 0 the old mmapped file earlier.
301  closeDatabase();
302  // Start monitoring the new file right away
303  m_databasePath = findDatabase();
304 
305  // Now notify applications
306  emit q->databaseChanged();
307  emit q->databaseChanged(changeList);
308 }
309 
310 KMimeTypeFactory *KSycocaPrivate::mimeTypeFactory()
311 {
312  if (!m_mimeTypeFactory) {
313  m_mimeTypeFactory = new KMimeTypeFactory(q);
314  }
315  return m_mimeTypeFactory;
316 }
317 
318 KServiceTypeFactory *KSycocaPrivate::serviceTypeFactory()
319 {
320  if (!m_serviceTypeFactory) {
321  m_serviceTypeFactory = new KServiceTypeFactory(q);
322  }
323  return m_serviceTypeFactory;
324 }
325 
326 KServiceFactory *KSycocaPrivate::serviceFactory()
327 {
328  if (!m_serviceFactory) {
329  m_serviceFactory = new KServiceFactory(q);
330  }
331  return m_serviceFactory;
332 }
333 
334 KServiceGroupFactory *KSycocaPrivate::serviceGroupFactory()
335 {
336  if (!m_serviceGroupFactory) {
337  m_serviceGroupFactory = new KServiceGroupFactory(q);
338  }
339  return m_serviceGroupFactory;
340 }
341 
342 // Add local paths to the list of dirs we got from the global database
343 void KSycocaPrivate::addLocalResourceDir(const QString &path)
344 {
345  // If any local path is more recent than the time the global sycoca was created, build a local sycoca.
346  allResourceDirs.insert(path, timeStamp);
347 }
348 
349 // Read-write constructor - only for KBuildSycoca
350 KSycoca::KSycoca(bool /* dummy */)
351  : d(new KSycocaPrivate(this))
352 {
353 }
354 
356 {
357  KSycoca *s = ksycocaInstance()->sycoca();
358  Q_ASSERT(s);
359  return s;
360 }
361 
362 KSycoca::~KSycoca()
363 {
364  d->closeDatabase();
365  delete d;
366  //if (ksycocaInstance.exists()
367  // && ksycocaInstance->self == this)
368  // ksycocaInstance->self = 0;
369 }
370 
371 bool KSycoca::isAvailable() // TODO KF6: make it non-static (mostly useful for unittests)
372 {
373  return self()->d->checkDatabase(KSycocaPrivate::IfNotFoundDoNothing);
374 }
375 
376 void KSycocaPrivate::closeDatabase()
377 {
378  delete m_device;
379  m_device = nullptr;
380 
381  // It is very important to delete all factories here
382  // since they cache information about the database file
383  // But other threads might be using them, so this class is
384  // refcounted, and deleted when the last thread is done with them
385  qDeleteAll(m_factories);
386  m_factories.clear();
387 
388  m_mimeTypeFactory = nullptr;
389  m_serviceFactory = nullptr;
390  m_serviceTypeFactory = nullptr;
391  m_serviceGroupFactory = nullptr;
392 
393 #if HAVE_MMAP
394  if (sycoca_mmap) {
395  // Solaris has munmap(char*, size_t) and everything else should
396  // be happy with a char* for munmap(void*, size_t)
397  munmap(const_cast<char *>(sycoca_mmap), sycoca_size);
398  sycoca_mmap = nullptr;
399  }
400  delete m_mmapFile; m_mmapFile = nullptr;
401 #endif
402 
403  databaseStatus = DatabaseNotOpen;
404  m_databasePath.clear();
405  timeStamp = 0;
406 }
407 
408 void KSycoca::addFactory(KSycocaFactory *factory)
409 {
410  d->addFactory(factory);
411 }
412 
413 #if KSERVICE_BUILD_DEPRECATED_SINCE(5, 0)
414 bool KSycoca::isChanged(const char *type)
415 {
416  return self()->d->changeList.contains(QString::fromLatin1(type));
417 }
418 #endif
419 
420 QDataStream *KSycoca::findEntry(int offset, KSycocaType &type)
421 {
422  QDataStream *str = stream();
423  Q_ASSERT(str);
424  //qCDebug(SYCOCA) << QString("KSycoca::_findEntry(offset=%1)").arg(offset,8,16);
425  str->device()->seek(offset);
426  qint32 aType;
427  *str >> aType;
428  type = KSycocaType(aType);
429  //qCDebug(SYCOCA) << QString("KSycoca::found type %1").arg(aType);
430  return str;
431 }
432 
433 KSycocaFactoryList *KSycoca::factories()
434 {
435  return d->factories();
436 }
437 
438 // Warning, checkVersion rewinds to the beginning of stream().
439 bool KSycocaPrivate::checkVersion()
440 {
441  QDataStream *m_str = device()->stream();
442  Q_ASSERT(m_str);
443  m_str->device()->seek(0);
444  qint32 aVersion;
445  *m_str >> aVersion;
446  if (aVersion < KSYCOCA_VERSION) {
447  qCDebug(SYCOCA) << "Found version" << aVersion << ", expecting version" << KSYCOCA_VERSION << "or higher.";
448  databaseStatus = BadVersion;
449  return false;
450  } else {
451  databaseStatus = DatabaseOK;
452  return true;
453  }
454 }
455 
456 // This is now completely useless. KF6: remove
457 extern KSERVICE_EXPORT bool kservice_require_kded;
458 KSERVICE_EXPORT bool kservice_require_kded = true;
459 
460 // If it returns true, we have a valid database and the stream has rewinded to the beginning
461 // and past the version number.
462 bool KSycocaPrivate::checkDatabase(BehaviorsIfNotFound ifNotFound)
463 {
464  if (databaseStatus == DatabaseOK) {
465  if (checkVersion()) { // we know the version is ok, but we must rewind the stream anyway
466  return true;
467  }
468  }
469 
470  closeDatabase(); // close the dummy one
471 
472  // Check if new database already available
473  if (openDatabase()) {
474  // Database exists, and version is ok, we can read it.
475 
476  if (qAppName() != QLatin1String(KBUILDSYCOCA_EXENAME) && ifNotFound != IfNotFoundDoNothing) {
477 
478  // Ensure it's uptodate, rebuild if needed
479  checkDirectories();
480 
481  // Don't check again for some time
482  m_lastCheck.start();
483  }
484 
485  return true;
486  }
487 
488  if (ifNotFound & IfNotFoundRecreate) {
489  return buildSycoca();
490  }
491 
492  return false;
493 }
494 
496 {
497  // Ensure we have a valid database (right version, and rewinded to beginning)
498  if (!d->checkDatabase(KSycocaPrivate::IfNotFoundRecreate)) {
499  return nullptr;
500  }
501 
502  QDataStream *str = stream();
503  Q_ASSERT(str);
504 
505  qint32 aId;
506  qint32 aOffset;
507  while (true) {
508  *str >> aId;
509  if (aId == 0) {
510  qCWarning(SYCOCA) << "Error, KSycocaFactory (id =" << int(id) << ") not found!";
511  break;
512  }
513  *str >> aOffset;
514  if (aId == id) {
515  //qCDebug(SYCOCA) << "KSycoca::findFactory(" << id << ") offset " << aOffset;
516  str->device()->seek(aOffset);
517  return str;
518  }
519  }
520  return nullptr;
521 }
522 
523 bool KSycoca::needsRebuild()
524 {
525  return d->needsRebuild();
526 }
527 
528 KSycocaHeader KSycocaPrivate::readSycocaHeader()
529 {
530  KSycocaHeader header;
531  // do not try to launch kbuildsycoca from here; this code is also called by kbuildsycoca.
532  if (!checkDatabase(KSycocaPrivate::IfNotFoundDoNothing)) {
533  return header;
534  }
535  QDataStream *str = stream();
536  qint64 oldPos = str->device()->pos();
537 
538  Q_ASSERT(str);
539  qint32 aId;
540  qint32 aOffset;
541  // skip factories offsets
542  while (true) {
543  *str >> aId;
544  if (aId) {
545  *str >> aOffset;
546  } else {
547  break; // just read 0
548  }
549  }
550  // We now point to the header
551  QStringList directoryList;
552  *str >> header >> directoryList;
554  for (int i = 0; i < directoryList.count(); ++i) {
555  qint64 mtime;
556  *str >> mtime;
557  allResourceDirs.insert(directoryList.at(i), mtime);
558  }
559 
560  str->device()->seek(oldPos);
561 
562  timeStamp = header.timeStamp;
563 
564  // for the useless public accessors. KF6: remove these two lines, the accessors and the vars.
565  language = header.language;
566  updateSig = header.updateSignature;
567 
568  return header;
569 }
570 
571 
572 class TimestampChecker
573 {
574 public:
575  TimestampChecker()
576  : m_now(QDateTime::currentDateTime())
577  {}
578 
579  // Check times of last modification of all directories on which ksycoca depends,
580  // If none of them is newer than the mtime we stored for that directory at the
581  // last rebuild, this means that there's no need to rebuild ksycoca.
582  bool checkTimestamps(const QMap<QString, qint64> &dirs)
583  {
584  Q_ASSERT(!dirs.isEmpty());
585  //qCDebug(SYCOCA) << "checking file timestamps";
586  for (auto it = dirs.begin(); it != dirs.end(); ++it) {
587  const QString dir = it.key();
588  const qint64 lastStamp = it.value();
589 
590  auto visitor = [&] (const QFileInfo &fi) {
591  const QDateTime mtime = fi.lastModified();
592  if (mtime.toMSecsSinceEpoch() > lastStamp) {
593  if (mtime > m_now) {
594  qCDebug(SYCOCA) << fi.filePath() << "has a modification time in the future" << mtime;
595  }
596  qCDebug(SYCOCA) << "timestamp changed:" << fi.filePath() << mtime << ">" << QDateTime::fromMSecsSinceEpoch(lastStamp);
597  // no need to continue search
598  return false;
599  }
600 
601  return true;
602  };
603 
604  if (!KSycocaUtilsPrivate::visitResourceDirectory(dir, visitor)) {
605  return false;
606  }
607  }
608  return true;
609  }
610 
611 private:
612  QDateTime m_now;
613 };
614 
615 void KSycocaPrivate::checkDirectories()
616 {
617  if (needsRebuild()) {
618  buildSycoca();
619  }
620 }
621 
622 bool KSycocaPrivate::needsRebuild()
623 {
624  if (!timeStamp && databaseStatus == DatabaseOK) {
625  (void) readSycocaHeader();
626  }
627  // these days timeStamp is really a "bool headerFound", the value itself doesn't matter...
628  // KF6: replace it with bool.
629  return timeStamp != 0 && !TimestampChecker().checkTimestamps(allResourceDirs);
630 }
631 
632 bool KSycocaPrivate::buildSycoca()
633 {
634  KBuildSycoca builder;
635  if (!builder.recreate()) {
636  return false; // error
637  }
638 
639  closeDatabase(); // close the dummy one
640 
641  // Ok, the new database should be here now, open it.
642  if (!openDatabase()) {
643  qCDebug(SYCOCA) << "Still no database...";
644  return false; // Still no database - uh oh
645  }
646  if (!checkVersion()) {
647  qCDebug(SYCOCA) << "Still outdated...";
648  return false; // Still outdated - uh oh
649  }
650  return true;
651 }
652 
653 #if KSERVICE_BUILD_DEPRECATED_SINCE(5, 15)
655 {
656  if (!d->timeStamp) {
657  (void) d->readSycocaHeader();
658  }
659  return d->timeStamp / 1000; // from ms to s
660 }
661 #endif
662 
663 #if KSERVICE_BUILD_DEPRECATED_SINCE(5, 15)
665 {
666  if (!d->timeStamp) {
667  (void) d->readSycocaHeader();
668  }
669  return d->updateSig;
670 }
671 #endif
672 
674 {
675  Q_UNUSED(type); // GlobalDatabase concept removed in 5.61
677  QString suffix = QLatin1Char('_') + QLocale().bcp47Name();
678 
679  const QByteArray ksycoca_env = qgetenv("KDESYCOCA");
680  if (ksycoca_env.isEmpty()) {
682  suffix += QLatin1Char('_') + QString::fromLatin1(pathHash.toBase64());
683  suffix.replace(QLatin1Char('/'), QLatin1Char('_'));
684 #ifdef Q_OS_WIN
685  suffix.replace(QLatin1Char(':'), QLatin1Char('_'));
686 #endif
687  const QString fileName = QLatin1String("ksycoca5") + suffix;
689  } else {
690  return QFile::decodeName(ksycoca_env);
691  }
692 }
693 
694 #if KSERVICE_BUILD_DEPRECATED_SINCE(5, 15)
696 {
697  if (d->language.isEmpty()) {
698  (void) d->readSycocaHeader();
699  }
700  return d->language;
701 }
702 #endif
703 
705 {
706  if (!d->timeStamp) {
707  (void) d->readSycocaHeader();
708  }
709  return d->allResourceDirs.keys();
710 }
711 
713 {
714  qCWarning(SYCOCA) << "ERROR: KSycoca database corruption!";
715  KSycoca *sycoca = self();
716  if (sycoca->d->readError) {
717  return;
718  }
719  sycoca->d->readError = true;
720  if (qAppName() != QLatin1String(KBUILDSYCOCA_EXENAME) && !sycoca->isBuilding()) {
721  // Rebuild the damned thing.
722  KBuildSycoca builder;
723  (void)builder.recreate();
724  }
725 }
726 
728 {
729  return false;
730 }
731 
733 {
734  ksycocaInstance->sycoca()->d->m_fileWatcher = nullptr;
735 }
736 
737 QDataStream *&KSycoca::stream()
738 {
739  return d->stream();
740 }
741 
742 void KSycoca::connectNotify(const QMetaMethod &signal)
743 {
744  if (signal.name() == "databaseChanged" && !d->m_haveListeners) {
745  d->m_haveListeners = true;
746  if (d->m_databasePath.isEmpty()) {
747  d->m_databasePath = d->findDatabase();
748  } else if (d->m_fileWatcher) {
749  d->m_fileWatcher->addFile(d->m_databasePath);
750  }
751  }
752 }
753 
754 void KSycoca::clearCaches()
755 {
756  if (ksycocaInstance.exists() && ksycocaInstance()->hasSycoca())
757  ksycocaInstance()->sycoca()->d->closeDatabase();
758 }
759 
760 extern KSERVICE_EXPORT int ksycoca_ms_between_checks;
761 KSERVICE_EXPORT int ksycoca_ms_between_checks = 1500;
762 
764 {
765  if (qAppName() == QLatin1String(KBUILDSYCOCA_EXENAME)) {
766  return;
767  }
768 
769  if (d->databaseStatus != KSycocaPrivate::DatabaseOK) {
770  if (!d->checkDatabase(KSycocaPrivate::IfNotFoundRecreate)) {
771  return;
772  }
773  }
774 
775  if (d->m_lastCheck.isValid() && d->m_lastCheck.elapsed() < ksycoca_ms_between_checks) {
776  return;
777  }
778  d->m_lastCheck.start();
779 
780  // Check if the file on disk was modified since we last checked it.
781  QFileInfo info(d->m_databasePath);
782  if (info.lastModified() == d->m_dbLastModified) {
783  // Check if the watched directories were modified, then the cache needs a rebuild.
784  d->checkDirectories();
785  return;
786  }
787 
788  // Close the database and forget all about what we knew.
789  // The next call to any public method will recreate
790  // everything that's needed.
791  d->closeDatabase();
792 }
void clear()
bool isReadable() const const
qint64 toMSecsSinceEpoch() const const
QString writableLocation(QStandardPaths::StandardLocation type)
QByteArray name() const const
virtual bool seek(qint64 pos)
QDataStream & operator>>(QDataStream &in, KDateTime::Spec &spec)
bool isEmpty() const const
static void disableAutoRebuild()
Disables automatic rebuilding of the cache on service file changes.
Definition: ksycoca.cpp:732
QString join(const QString &separator) const const
static bool isChanged(const char *type)
When you receive a "databaseChanged" signal, you can query here if a change has occurred in a specifi...
Definition: ksycoca.cpp:414
QDateTime fromMSecsSinceEpoch(qint64 msecs)
QString language()
Definition: ksycoca.cpp:695
QStringList standardLocations(QStandardPaths::StandardLocation type)
virtual qint64 pos() const const
KSharedConfigPtr config()
static bool isAvailable()
Definition: ksycoca.cpp:371
virtual bool isBuilding()
Definition: ksycoca.cpp:727
static int version()
Definition: ksycoca.cpp:154
QDataStream * findEntry(int offset, KSycocaType &type)
Definition: ksycoca.cpp:420
QDataStream * findFactory(KSycocaFactoryId id)
Definition: ksycoca.cpp:495
bool isEmpty() const const
quint32 updateSignature()
Definition: ksycoca.cpp:664
QMap::iterator end()
static void flagError()
A read error occurs.
Definition: ksycoca.cpp:712
QDateTime lastModified() const const
void created(const QString &path)
QMap::iterator begin()
quint32 timeStamp()
Definition: ksycoca.cpp:654
static KSharedConfig::Ptr openConfig(const QString &fileName=QString(), OpenFlags mode=FullConfig, QStandardPaths::StandardLocation type=QStandardPaths::GenericConfigLocation)
void addFactory(KSycocaFactory *)
Definition: ksycoca.cpp:408
QString & replace(int position, int n, QChar after)
QDateTime currentDateTime()
void insert(int i, const T &value)
QThread * currentThread()
DatabaseType
type of database
Definition: ksycoca.h:50
QString bcp47Name() const const
QByteArray hash(const QByteArray &data, QCryptographicHash::Algorithm method)
QString fromLatin1(const char *str, int size)
bool isEmpty() const const
QIODevice * device() const const
void dirty(const QString &path)
KSycocaFactoryId
Definition: ksycocatype.h:35
KSycoca()
Read-only database.
Definition: ksycoca.cpp:208
QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
static KSycoca * self()
Get or create the only instance of KSycoca (read-only)
Definition: ksycoca.cpp:355
QStringList allResourceDirs()
Definition: ksycoca.cpp:704
static QString absoluteFilePath(DatabaseType type=LocalDatabase)
Definition: ksycoca.cpp:673
QByteArray toBase64(QByteArray::Base64Options options) const const
QString decodeName(const QByteArray &localFileName)
void ensureCacheValid()
Ensures the ksycoca database is up to date.
Definition: ksycoca.cpp:763
QByteArray toUtf8() const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2020 The KDE developers.
Generated on Tue Oct 20 2020 22:53:28 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.