KService

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

KDE's Doxygen guidelines are available online.