• Skip to content
  • Skip to link menu
Trinity API Reference
  • Trinity API Reference
  • tdecore
 

tdecore

  • tdecore
tdesycoca.cpp
1 /* This file is part of the KDE libraries
2  * Copyright (C) 1999-2000 Waldo Bastian <bastian@kde.org>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License version 2 as published by the Free Software Foundation;
7  *
8  * This library is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11  * Library General Public License for more details.
12  *
13  * You should have received a copy of the GNU Library General Public License
14  * along with this library; see the file COPYING.LIB. If not, write to
15  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
16  * Boston, MA 02110-1301, USA.
17  **/
18 
19 #include "config.h"
20 
21 #include "tdesycoca.h"
22 #include "tdesycocatype.h"
23 #include "tdesycocafactory.h"
24 
25 #include <tqdatastream.h>
26 #include <tqfile.h>
27 #include <tqbuffer.h>
28 
29 #include <tdeapplication.h>
30 #include <dcopclient.h>
31 #include <tdeglobal.h>
32 #include <kdebug.h>
33 #include <kprocess.h>
34 #include <kstandarddirs.h>
35 
36 #include <assert.h>
37 #include <stdlib.h>
38 #include <unistd.h>
39 #include <fcntl.h>
40 
41 #ifdef HAVE_SYS_MMAN_H
42 #include <sys/mman.h>
43 #endif
44 
45 #ifdef Q_OS_SOLARIS
46 extern "C"
47 {
48  extern int madvise(caddr_t, size_t, int);
49 }
50 #endif
51 
52 #ifndef MAP_FAILED
53 #define MAP_FAILED ((void *) -1)
54 #endif
55 
56 template class TQPtrList<KSycocaFactory>;
57 
58 // The following limitations are in place:
59 // Maximum length of a single string: 8192 bytes
60 // Maximum length of a string list: 1024 strings
61 // Maximum number of entries: 8192
62 //
63 // The purpose of these limitations is to limit the impact
64 // of database corruption.
65 
66 class KSycocaPrivate {
67 public:
68  KSycocaPrivate() {
69  database = 0;
70  readError = false;
71  updateSig = 0;
72  autoRebuild = true;
73  }
74  TQFile *database;
75  TQStringList changeList;
76  TQString language;
77  bool readError;
78  bool autoRebuild;
79  TQ_UINT32 updateSig;
80  TQStringList allResourceDirs;
81 };
82 
83 int KSycoca::version()
84 {
85  return TDESYCOCA_VERSION;
86 }
87 
88 // Read-only constructor
89 KSycoca::KSycoca()
90  : DCOPObject("tdesycoca"), m_lstFactories(0), m_str(0), m_barray(0), bNoDatabase(false),
91  m_sycoca_size(0), m_sycoca_mmap(0), m_timeStamp(0)
92 {
93  d = new KSycocaPrivate;
94  // Register app as able to receive DCOP messages
95  if (kapp && !kapp->dcopClient()->isAttached())
96  {
97  kapp->dcopClient()->attach();
98  }
99  // We register with DCOP _before_ we try to open the database.
100  // This way we can be relative sure that the KDE framework is
101  // up and running (tdeinit, dcopserver, klaucnher, kded) and
102  // that the database is up to date.
103  openDatabase();
104  _self = this;
105 }
106 
107 bool KSycoca::openDatabase( bool openDummyIfNotFound )
108 {
109  bool result = true;
110 
111  m_sycoca_mmap = 0;
112  m_str = 0;
113  m_barray = 0;
114  TQString path;
115  TQCString tdesycoca_env = getenv("TDESYCOCA");
116  if (tdesycoca_env.isEmpty())
117  path = TDEGlobal::dirs()->saveLocation("cache") + "tdesycoca";
118  else
119  path = TQFile::decodeName(tdesycoca_env);
120 
121  kdDebug(7011) << "Trying to open tdesycoca from " << path << endl;
122  TQFile *database = new TQFile(path);
123  bool bOpen = database->open( IO_ReadOnly );
124  if (!bOpen)
125  {
126  path = locate("services", "tdesycoca");
127  if (!path.isEmpty())
128  {
129  kdDebug(7011) << "Trying to open global tdesycoca from " << path << endl;
130  delete database;
131  database = new TQFile(path);
132  bOpen = database->open( IO_ReadOnly );
133  }
134  }
135 
136  if (bOpen)
137  {
138  fcntl(database->handle(), F_SETFD, FD_CLOEXEC);
139  m_sycoca_size = database->size();
140 #ifdef HAVE_MMAP
141  m_sycoca_mmap = (const char *) mmap(0, m_sycoca_size,
142  PROT_READ, MAP_SHARED,
143  database->handle(), 0);
144  /* POSIX mandates only MAP_FAILED, but we are paranoid so check for
145  null pointer too. */
146  if (m_sycoca_mmap == (const char*) MAP_FAILED || m_sycoca_mmap == 0)
147  {
148  kdDebug(7011) << "mmap failed. (length = " << m_sycoca_size << ")" << endl;
149 #endif
150  m_str = new TQDataStream(database);
151 #ifdef HAVE_MMAP
152  }
153  else
154  {
155 #ifdef HAVE_MADVISE
156  (void) madvise((char*)m_sycoca_mmap, m_sycoca_size, MADV_WILLNEED);
157 #endif
158  m_barray = new TQByteArray();
159  m_barray->setRawData(m_sycoca_mmap, m_sycoca_size);
160  TQBuffer *buffer = new TQBuffer( *m_barray );
161  buffer->open(IO_ReadWrite);
162  m_str = new TQDataStream( buffer);
163  }
164 #endif
165  bNoDatabase = false;
166  }
167  else
168  {
169  kdDebug(7011) << "Could not open tdesycoca" << endl;
170 
171  // No database file
172  delete database;
173  database = 0;
174 
175  bNoDatabase = true;
176  if (openDummyIfNotFound)
177  {
178  // We open a dummy database instead.
179  //kdDebug(7011) << "No database, opening a dummy one." << endl;
180  TQBuffer *buffer = new TQBuffer();
181  buffer->setBuffer(TQByteArray());
182  buffer->open(IO_ReadWrite);
183  m_str = new TQDataStream( buffer);
184  (*m_str) << (TQ_INT32) TDESYCOCA_VERSION;
185  (*m_str) << (TQ_INT32) 0;
186  }
187  else
188  {
189  result = false;
190  }
191  }
192  m_lstFactories = new KSycocaFactoryList();
193  m_lstFactories->setAutoDelete( true );
194  d->database = database;
195  return result;
196 }
197 
198 // Read-write constructor - only for KBuildSycoca
199 KSycoca::KSycoca( bool /* dummy */ )
200  : DCOPObject("tdesycoca_building"), m_lstFactories(0), m_str(0), m_barray(0), bNoDatabase(false),
201  m_sycoca_size(0), m_sycoca_mmap(0)
202 {
203  d = new KSycocaPrivate;
204  m_lstFactories = new KSycocaFactoryList();
205  m_lstFactories->setAutoDelete( true );
206  _self = this;
207 }
208 
209 static void delete_tdesycoca_self() {
210  delete KSycoca::_self;
211 }
212 
213 KSycoca * KSycoca::self()
214 {
215  if (!_self) {
216  tqAddPostRoutine(delete_tdesycoca_self);
217  _self = new KSycoca();
218  }
219  return _self;
220 }
221 
222 KSycoca::~KSycoca()
223 {
224  closeDatabase();
225  delete d;
226  _self = 0L;
227 }
228 
229 void KSycoca::closeDatabase()
230 {
231  QIODevice *device = 0;
232  if (m_str)
233  device = m_str->device();
234 #ifdef HAVE_MMAP
235  if (device && m_sycoca_mmap)
236  {
237  TQBuffer *buf = static_cast<TQBuffer*>(device);
238  buf->buffer().resetRawData(m_sycoca_mmap, m_sycoca_size);
239  // Solaris has munmap(char*, size_t) and everything else should
240  // be happy with a char* for munmap(void*, size_t)
241  munmap((char*) m_sycoca_mmap, m_sycoca_size);
242  m_sycoca_mmap = 0;
243  }
244 #endif
245 
246  delete m_str;
247  m_str = 0;
248  delete device;
249  if (TQT_TQIODEVICE(d->database) != device)
250  delete d->database;
251  if (m_barray) delete m_barray;
252  m_barray = 0;
253  device = 0;
254  d->database = 0;
255  // It is very important to delete all factories here
256  // since they cache information about the database file
257  delete m_lstFactories;
258  m_lstFactories = 0L;
259 }
260 
261 void KSycoca::addFactory( KSycocaFactory *factory )
262 {
263  assert(m_lstFactories);
264  m_lstFactories->append(factory);
265 }
266 
267 bool KSycoca::isChanged(const char *type)
268 {
269  return self()->d->changeList.contains(type);
270 }
271 
272 void KSycoca::notifyDatabaseChanged(const TQStringList &changeList)
273 {
274  d->changeList = changeList;
275  //kdDebug(7011) << "got a notifyDatabaseChanged signal !" << endl;
276  // kded tells us the database file changed
277  // Close the database and forget all about what we knew
278  // The next call to any public method will recreate
279  // everything that's needed.
280  closeDatabase();
281 
282  // Now notify applications
283  emit databaseChanged();
284 }
285 
286 TQDataStream * KSycoca::findEntry(int offset, KSycocaType &type)
287 {
288  if ( !m_str )
289  openDatabase();
290  //kdDebug(7011) << TQString("KSycoca::_findEntry(offset=%1)").arg(offset,8,16) << endl;
291  m_str->device()->at(offset);
292  TQ_INT32 aType;
293  (*m_str) >> aType;
294  type = (KSycocaType) aType;
295  //kdDebug(7011) << TQString("KSycoca::found type %1").arg(aType) << endl;
296  return m_str;
297 }
298 
299 bool KSycoca::checkVersion(bool abortOnError)
300 {
301  if ( !m_str )
302  {
303  if( !openDatabase(false /* don't open dummy db if not found */) )
304  return false; // No database found
305 
306  // We should never get here... if a database was found then m_str shouldn't be 0L.
307  assert(m_str);
308  }
309  m_str->device()->at(0);
310  TQ_INT32 aVersion;
311  (*m_str) >> aVersion;
312  if ( aVersion < TDESYCOCA_VERSION )
313  {
314  kdWarning(7011) << "Found version " << aVersion << ", expecting version " << TDESYCOCA_VERSION << " or higher." << endl;
315  if (!abortOnError) return false;
316  kdError(7011) << "Outdated database ! Stop kded and restart it !" << endl;
317  abort();
318  }
319  return true;
320 }
321 
322 TQDataStream * KSycoca::findFactory(KSycocaFactoryId id)
323 {
324  // The constructor found no database, but we want one
325  if (bNoDatabase)
326  {
327  closeDatabase(); // close the dummy one
328  // Check if new database already available
329  if ( !openDatabase(false /* no dummy one*/) )
330  {
331  static bool triedLaunchingKdeinit = false;
332  if (!triedLaunchingKdeinit) // try only once
333  {
334  triedLaunchingKdeinit = true;
335  kdDebug(7011) << "findFactory: we have no database.... launching tdeinit" << endl;
336  TDEApplication::startKdeinit();
337  // Ok, the new database should be here now, open it.
338  }
339  if (!openDatabase(false))
340  return 0L; // Still no database - uh oh
341  }
342  }
343  // rewind and check
344  if (!checkVersion(false))
345  {
346  kdWarning(7011) << "Outdated database found" << endl;
347  return 0L;
348  }
349  TQ_INT32 aId;
350  TQ_INT32 aOffset;
351  while(true)
352  {
353  (*m_str) >> aId;
354  //kdDebug(7011) << TQString("KSycoca::findFactory : found factory %1").arg(aId) << endl;
355  if (aId == 0)
356  {
357  kdError(7011) << "Error, KSycocaFactory (id = " << int(id) << ") not found!" << endl;
358  break;
359  }
360  (*m_str) >> aOffset;
361  if (aId == id)
362  {
363  //kdDebug(7011) << TQString("KSycoca::findFactory(%1) offset %2").arg((int)id).arg(aOffset) << endl;
364  m_str->device()->at(aOffset);
365  return m_str;
366  }
367  }
368  return 0;
369 }
370 
371 TQString KSycoca::kfsstnd_prefixes()
372 {
373  if (bNoDatabase) return "";
374  if (!checkVersion(false)) return "";
375  TQ_INT32 aId;
376  TQ_INT32 aOffset;
377  // skip factories offsets
378  while(true)
379  {
380  (*m_str) >> aId;
381  if ( aId )
382  (*m_str) >> aOffset;
383  else
384  break; // just read 0
385  }
386  // We now point to the header
387  TQString prefixes;
388  KSycocaEntry::read(*m_str, prefixes);
389  (*m_str) >> m_timeStamp;
390  KSycocaEntry::read(*m_str, d->language);
391  (*m_str) >> d->updateSig;
392  KSycocaEntry::read(*m_str, d->allResourceDirs);
393  return prefixes;
394 }
395 
396 TQ_UINT32 KSycoca::timeStamp()
397 {
398  if (!m_timeStamp)
399  (void) kfsstnd_prefixes();
400  return m_timeStamp;
401 }
402 
403 TQ_UINT32 KSycoca::updateSignature()
404 {
405  if (!m_timeStamp)
406  (void) kfsstnd_prefixes();
407  return d->updateSig;
408 }
409 
410 TQString KSycoca::language()
411 {
412  if (d->language.isEmpty())
413  (void) kfsstnd_prefixes();
414  return d->language;
415 }
416 
417 TQStringList KSycoca::allResourceDirs()
418 {
419  if (!m_timeStamp)
420  (void) kfsstnd_prefixes();
421  return d->allResourceDirs;
422 }
423 
424 TQString KSycoca::determineRelativePath( const TQString & _fullpath, const char *_resource )
425 {
426  TQString sRelativeFilePath;
427  TQStringList dirs = TDEGlobal::dirs()->resourceDirs( _resource );
428  TQStringList::ConstIterator dirsit = dirs.begin();
429  for ( ; dirsit != dirs.end() && sRelativeFilePath.isEmpty(); ++dirsit ) {
430  // might need canonicalPath() ...
431  if ( _fullpath.find( *dirsit ) == 0 ) // path is dirs + relativePath
432  sRelativeFilePath = _fullpath.mid( (*dirsit).length() ); // skip appsdirs
433  }
434  if ( sRelativeFilePath.isEmpty() )
435  kdFatal(7011) << TQString(TQString("Couldn't find %1 in any %2 dir !!!").arg( _fullpath ).arg( _resource)) << endl;
436  //else
437  // debug code
438  //kdDebug(7011) << sRelativeFilePath << endl;
439  return sRelativeFilePath;
440 }
441 
442 KSycoca * KSycoca::_self = 0L;
443 
444 void KSycoca::flagError()
445 {
446  tqWarning("ERROR: KSycoca database corruption!");
447  if (_self)
448  {
449  if (_self->d->readError)
450  return;
451  _self->d->readError = true;
452  if (_self->d->autoRebuild)
453  if(system("tdebuildsycoca") < 0) // Rebuild the damned thing.
454  tqWarning("ERROR: Running KSycoca failed.");
455  }
456 }
457 
458 void KSycoca::disableAutoRebuild()
459 {
460  d->autoRebuild = false;
461 }
462 
463 bool KSycoca::readError()
464 {
465  bool b = false;
466  if (_self)
467  {
468  b = _self->d->readError;
469  _self->d->readError = false;
470  }
471  return b;
472 }
473 
474 void KSycocaEntry::read( TQDataStream &s, TQString &str )
475 {
476  TQ_UINT32 bytes;
477  s >> bytes; // read size of string
478  if ( bytes > 8192 ) { // null string or too big
479  if (bytes != 0xffffffff)
480  KSycoca::flagError();
481  str = TQString::null;
482  }
483  else if ( bytes > 0 ) { // not empty
484  int bt = bytes/2;
485  str.setLength( bt );
486  TQChar* ch = (TQChar *) str.unicode();
487  char t[8192];
488  char *b = t;
489  s.readRawBytes( b, bytes );
490  while ( bt-- ) {
491  *ch++ = (ushort) (((ushort)b[0])<<8) | (uchar)b[1];
492  b += 2;
493  }
494  } else {
495  str = "";
496  }
497 }
498 
499 void KSycocaEntry::read( TQDataStream &s, TQStringList &list )
500 {
501  list.clear();
502  TQ_UINT32 count;
503  s >> count; // read size of list
504  if (count >= 1024)
505  {
506  KSycoca::flagError();
507  return;
508  }
509  for(TQ_UINT32 i = 0; i < count; i++)
510  {
511  TQString str;
512  read(s, str);
513  list.append( str );
514  if (s.atEnd())
515  {
516  KSycoca::flagError();
517  return;
518  }
519  }
520 }
521 
522 void KSycoca::virtual_hook( int id, void* data )
523 { DCOPObject::virtual_hook( id, data ); }
524 
525 void KSycocaEntry::virtual_hook( int, void* )
526 { /*BASE::virtual_hook( id, data );*/ }
527 
528 #include "tdesycoca.moc"
KSycocaFactoryList
This, instead of a typedef, allows to declare "class ..." in header files.
Definition: tdesycocafactory.h:137
TDEGlobal::kdError
kdbgstream kdError(int area=0)
Definition: kdebug.cpp:372
TDEStandardDirs::resourceDirs
TQStringList resourceDirs(const char *type) const
This function is used internally by almost all other function as it serves and fills the directories ...
Definition: kstandarddirs.cpp:795
TDEGlobal::kdDebug
kdbgstream kdDebug(int area=0)
Definition: kdebug.cpp:369
KSycocaEntry::KSycocaType
KSycocaType
Definition: tdesycocatype.h:31
TDEGlobal::dirs
static TDEStandardDirs * dirs()
Returns the application standard dirs object.
Definition: tdeglobal.cpp:58
KSycocaEntry::read
static void read(TQDataStream &s, TQString &str)
Safe demarshalling functions.
Definition: tdesycoca.cpp:474
TDEGlobal::kdWarning
kdbgstream kdWarning(int area=0)
Definition: kdebug.cpp:374
TDEStandardDirs::saveLocation
TQString saveLocation(const char *type, const TQString &suffix=TQString::null, bool create=true) const
Finds a location to save files into for the given type in the user's home directory.
Definition: kstandarddirs.cpp:1099
TDEGlobal::kdFatal
kdbgstream kdFatal(int area=0)
Definition: kdebug.cpp:376
DCOPObject
TDEStandardDirs::locate
TQString locate(const char *type, const TQString &filename, const TDEInstance *instance=TDEGlobal::instance())
Definition: kstandarddirs.cpp:1689
TDEGlobal::endl
kdbgstream & endl(kdbgstream &s)
Definition: kdebug.h:430

tdecore

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

tdecore

Skip menu "tdecore"
  • arts
  • dcop
  • dnssd
  • interfaces
  •   kspeech
  •     interface
  •     library
  •   tdetexteditor
  • kate
  • kded
  • kdoctools
  • kimgio
  • kjs
  • libtdemid
  • libtdescreensaver
  •     tdecore
  • tdeabc
  • tdecmshell
  • tdecore
  • tdefx
  • tdehtml
  • tdeinit
  • tdeio
  •   bookmarks
  •   httpfilter
  •   kpasswdserver
  •   kssl
  • tdeioslave
  •   http
  •   tdefile
  •   tdeio
  •   tdeioexec
  • tdemdi
  •   tdemdi
  • tdenewstuff
  • tdeparts
  • tdeprint
  • tderandr
  • tderesources
  • tdespell2
  • tdesu
  • tdeui
  • tdeunittest
  • tdeutils
  • tdewallet
Generated for tdecore by doxygen 1.8.8
This website is maintained by Timothy Pearson.