• 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 <tdeprocess.h>
34#include <tdestandarddirs.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#if defined(Q_OS_SOLARIS) && !defined(__dilos__)
46extern "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
56template 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
66class KSycocaPrivate {
67public:
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
83int KSycoca::version()
84{
85 return TDESYCOCA_VERSION;
86}
87
88// Read-only constructor
89KSycoca::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 (tdeApp && !tdeApp->dcopClient()->isAttached())
96 {
97 tdeApp->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
107bool 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
199KSycoca::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
209static void delete_tdesycoca_self() {
210 delete KSycoca::_self;
211}
212
213KSycoca * KSycoca::self()
214{
215 if (!_self) {
216 tqAddPostRoutine(delete_tdesycoca_self);
217 _self = new KSycoca();
218 }
219 return _self;
220}
221
222KSycoca::~KSycoca()
223{
224 closeDatabase();
225 delete d;
226 _self = 0L;
227}
228
229void KSycoca::closeDatabase()
230{
231 TQIODevice *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 (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
261void KSycoca::addFactory( KSycocaFactory *factory )
262{
263 assert(m_lstFactories);
264 m_lstFactories->append(factory);
265}
266
267bool KSycoca::isChanged(const char *type)
268{
269 return self()->d->changeList.contains(type);
270}
271
272void 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
286TQDataStream * 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
299bool 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
322TQDataStream * 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
371TQString 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
396TQ_UINT32 KSycoca::timeStamp()
397{
398 if (!m_timeStamp)
399 (void) kfsstnd_prefixes();
400 return m_timeStamp;
401}
402
403TQ_UINT32 KSycoca::updateSignature()
404{
405 if (!m_timeStamp)
406 (void) kfsstnd_prefixes();
407 return d->updateSig;
408}
409
410TQString KSycoca::language()
411{
412 if (d->language.isEmpty())
413 (void) kfsstnd_prefixes();
414 return d->language;
415}
416
417TQStringList KSycoca::allResourceDirs()
418{
419 if (!m_timeStamp)
420 (void) kfsstnd_prefixes();
421 return d->allResourceDirs;
422}
423
424TQString 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
442KSycoca * KSycoca::_self = 0L;
443
444void 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
458void KSycoca::disableAutoRebuild()
459{
460 d->autoRebuild = false;
461}
462
463bool 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
474void 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
499void 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
522void KSycoca::virtual_hook( int id, void* data )
523{ DCOPObject::virtual_hook( id, data ); }
524
525void KSycocaEntry::virtual_hook( int, void* )
526{ /*BASE::virtual_hook( id, data );*/ }
527
528#include "tdesycoca.moc"
DCOPObject
KSycocaEntry::KSycocaType
KSycocaType
A KSycocaType is a code (out of the KSycocaType enum) assigned to each class type derived from KSycoc...
Definition: tdesycocatype.h:31
KSycocaEntry::read
static void read(TQDataStream &s, TQString &str)
Safe demarshalling functions.
Definition: tdesycoca.cpp:474
KSycocaFactoryList
This, instead of a typedef, allows to declare "class ..." in header files.
Definition: tdesycocafactory.h:138
TDEGlobal::dirs
static TDEStandardDirs * dirs()
Returns the application standard dirs object.
Definition: tdeglobal.cpp:58
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: tdestandarddirs.cpp:1099
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: tdestandarddirs.cpp:795
TDEGlobal::kdFatal
kdbgstream kdFatal(int area=0)
Returns a fatal error stream.
Definition: kdebug.cpp:378
TDEGlobal::kdWarning
kdbgstream kdWarning(int area=0)
Returns a warning stream.
Definition: kdebug.cpp:376
TDEGlobal::kdError
kdbgstream kdError(int area=0)
Returns an error stream.
Definition: kdebug.cpp:374
TDEGlobal::kdDebug
kdbgstream kdDebug(int area=0)
Returns a debug stream.
Definition: kdebug.cpp:371
TDEGlobal::endl
kdbgstream & endl(kdbgstream &s)
Prints an "\n".
Definition: kdebug.h:430
TDEStandardDirs::locate
TQString locate(const char *type, const TQString &filename, const TDEInstance *instance=TDEGlobal::instance())
Definition: tdestandarddirs.cpp:1689

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
  • tdeabc
  • tdecmshell
  • tdecore
  • tdefx
  • tdehtml
  • tdeinit
  • tdeio
  •   bookmarks
  •   httpfilter
  •   kpasswdserver
  •   kssl
  •   tdefile
  •   tdeio
  •   tdeioexec
  • tdeioslave
  •   http
  • tdemdi
  •   tdemdi
  • tdenewstuff
  • tdeparts
  • tdeprint
  • tderandr
  • tderesources
  • tdespell2
  • tdesu
  • tdeui
  • tdeunittest
  • tdeutils
  • tdewallet
Generated for tdecore by doxygen 1.9.4
This website is maintained by Timothy Pearson.