ksycoca.cpp
00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include "config.h"
00020
00021 #include "ksycoca.h"
00022 #include "ksycocatype.h"
00023 #include "ksycocafactory.h"
00024
00025 #include <qdatastream.h>
00026 #include <qfile.h>
00027 #include <qbuffer.h>
00028
00029 #include <kapplication.h>
00030 #include <dcopclient.h>
00031 #include <kglobal.h>
00032 #include <kdebug.h>
00033 #include <kprocess.h>
00034 #include <kstandarddirs.h>
00035
00036 #include <assert.h>
00037 #include <stdlib.h>
00038 #include <unistd.h>
00039 #include <fcntl.h>
00040
00041 #ifdef HAVE_SYS_MMAN_H
00042 #include <sys/mman.h>
00043 #endif
00044
00045 #ifndef MAP_FAILED
00046 #define MAP_FAILED ((void *) -1)
00047 #endif
00048
00049 template class QPtrList<KSycocaFactory>;
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059 struct KSycocaPrivate {
00060 KSycocaPrivate() {
00061 database = 0;
00062 readError = false;
00063 updateSig = 0;
00064 }
00065 QFile *database;
00066 QStringList changeList;
00067 QString language;
00068 bool readError;
00069 Q_UINT32 updateSig;
00070 };
00071
00072
00073 KSycoca::KSycoca()
00074 : DCOPObject("ksycoca"), m_lstFactories(0), m_str(0), bNoDatabase(false),
00075 m_sycoca_size(0), m_sycoca_mmap(0)
00076 {
00077 d = new KSycocaPrivate;
00078
00079 if (kapp && !kapp->dcopClient()->isAttached())
00080 {
00081 kapp->dcopClient()->attach();
00082 }
00083
00084
00085
00086
00087 openDatabase();
00088 _self = this;
00089 }
00090
00091 bool KSycoca::openDatabase( bool openDummyIfNotFound )
00092 {
00093 bool result = true;
00094
00095 m_sycoca_mmap = 0;
00096 m_str = 0;
00097 QString path;
00098 QCString ksycoca_env = getenv("KDESYCOCA");
00099 if (ksycoca_env.isEmpty())
00100 path = KGlobal::dirs()->saveLocation("tmp") + "ksycoca";
00101 else
00102 path = QFile::decodeName(ksycoca_env);
00103
00104 QFile *database = new QFile(path);
00105 if (database->open( IO_ReadOnly ))
00106 {
00107 fcntl(database->handle(), F_SETFD, FD_CLOEXEC);
00108 m_sycoca_size = database->size();
00109 #ifdef HAVE_MMAP
00110 m_sycoca_mmap = (const char *) mmap(0, m_sycoca_size,
00111 PROT_READ, MAP_SHARED,
00112 database->handle(), 0);
00113
00114
00115 if (m_sycoca_mmap == (const char*) MAP_FAILED || m_sycoca_mmap == 0)
00116 {
00117 kdDebug(7011) << "mmap failed. (length = " << m_sycoca_size << ")" << endl;
00118 #endif
00119 m_str = new QDataStream(database);
00120 #ifdef HAVE_MMAP
00121 }
00122 else
00123 {
00124 QByteArray b_array;
00125 b_array.setRawData(m_sycoca_mmap, m_sycoca_size);
00126 QBuffer *buffer = new QBuffer( b_array );
00127 buffer->open(IO_ReadWrite);
00128 m_str = new QDataStream( buffer);
00129 }
00130 #endif
00131 bNoDatabase = false;
00132 }
00133 else
00134 {
00135
00136 delete database;
00137 database = 0;
00138
00139 bNoDatabase = true;
00140 if (openDummyIfNotFound)
00141 {
00142
00143
00144 QBuffer *buffer = new QBuffer( QByteArray() );
00145 buffer->open(IO_ReadWrite);
00146 m_str = new QDataStream( buffer);
00147 (*m_str) << (Q_INT32) KSYCOCA_VERSION;
00148 (*m_str) << (Q_INT32) 0;
00149 }
00150 else
00151 {
00152 result = false;
00153 }
00154 }
00155 m_lstFactories = new KSycocaFactoryList();
00156 m_lstFactories->setAutoDelete( true );
00157 d->database = database;
00158 return result;
00159 }
00160
00161
00162 KSycoca::KSycoca( bool )
00163 : DCOPObject("ksycoca_building"), m_lstFactories(0), m_str(0), bNoDatabase(false),
00164 m_sycoca_size(0), m_sycoca_mmap(0)
00165 {
00166 d = new KSycocaPrivate;
00167 m_lstFactories = new KSycocaFactoryList();
00168 m_lstFactories->setAutoDelete( true );
00169 _self = this;
00170 }
00171
00172 static void delete_ksycoca_self() {
00173 if (KSycoca::_checkSelf())
00174 delete KSycoca::_self;
00175
00176 }
00177
00178 bool KSycoca::_checkSelf() {
00179 return (_self ? true : false);
00180 }
00181
00182 KSycoca * KSycoca::self()
00183 {
00184 if (!_self) {
00185 qAddPostRoutine(delete_ksycoca_self);
00186 _self = new KSycoca();
00187 }
00188 return _self;
00189 }
00190
00191 KSycoca::~KSycoca()
00192 {
00193 closeDatabase();
00194 delete d;
00195 _self = 0L;
00196 }
00197
00198 void KSycoca::closeDatabase()
00199 {
00200 QIODevice *device = 0;
00201 if (m_str)
00202 device = m_str->device();
00203 #ifdef HAVE_MMAP
00204 if (device && m_sycoca_mmap)
00205 {
00206 QBuffer *buf = (QBuffer *) device;
00207 buf->buffer().resetRawData(m_sycoca_mmap, m_sycoca_size);
00208
00209
00210 munmap((char*) m_sycoca_mmap, m_sycoca_size);
00211 m_sycoca_mmap = 0;
00212 }
00213 #endif
00214
00215 delete m_str;
00216 m_str = 0;
00217 delete device;
00218 if (d->database != device)
00219 delete d->database;
00220 device = 0;
00221 d->database = 0;
00222
00223
00224 delete m_lstFactories;
00225 m_lstFactories = 0L;
00226 }
00227
00228 void KSycoca::addFactory( KSycocaFactory *factory )
00229 {
00230 assert(m_lstFactories);
00231 m_lstFactories->append(factory);
00232 }
00233
00234 bool KSycoca::isChanged(const char *type)
00235 {
00236 return self()->d->changeList.contains(type);
00237 }
00238
00239 void KSycoca::notifyDatabaseChanged(const QStringList &changeList)
00240 {
00241 d->changeList = changeList;
00242
00243
00244
00245
00246
00247 closeDatabase();
00248
00249
00250 emit databaseChanged();
00251 }
00252
00253 QDataStream * KSycoca::findEntry(int offset, KSycocaType &type)
00254 {
00255 if ( !m_str )
00256 openDatabase();
00257
00258 m_str->device()->at(offset);
00259 Q_INT32 aType;
00260 (*m_str) >> aType;
00261 type = (KSycocaType) aType;
00262
00263 return m_str;
00264 }
00265
00266 bool KSycoca::checkVersion(bool abortOnError)
00267 {
00268 if ( !m_str )
00269 {
00270 if( !openDatabase(false ) )
00271 return false;
00272
00273
00274 assert(m_str);
00275 }
00276 m_str->device()->at(0);
00277 Q_INT32 aVersion;
00278 (*m_str) >> aVersion;
00279 if ( aVersion < KSYCOCA_VERSION )
00280 {
00281 kdWarning(7011) << "Found version " << aVersion << ", expecting version " << KSYCOCA_VERSION << " or higher." << endl;
00282 if (!abortOnError) return false;
00283 kdError(7011) << "Outdated database ! Stop kded and restart it !" << endl;
00284 abort();
00285 }
00286 return true;
00287 }
00288
00289 QDataStream * KSycoca::findFactory(KSycocaFactoryId id)
00290 {
00291
00292 if (bNoDatabase)
00293 {
00294 closeDatabase();
00295
00296 if ( !openDatabase(false ) )
00297 {
00298 static bool triedLaunchingKdeinit = false;
00299 if (!triedLaunchingKdeinit)
00300 {
00301 triedLaunchingKdeinit = true;
00302 kdDebug(7011) << "findFactory: we have no database.... launching kdeinit" << endl;
00303 KApplication::startKdeinit();
00304
00305 }
00306 if (!openDatabase(false))
00307 return 0L;
00308 }
00309 }
00310
00311 if (!checkVersion(false))
00312 {
00313 kdWarning(7011) << "Outdated database found" << endl;
00314 return 0L;
00315 }
00316 Q_INT32 aId;
00317 Q_INT32 aOffset;
00318 while(true)
00319 {
00320 (*m_str) >> aId;
00321
00322 if (aId == 0)
00323 {
00324 kdError(7011) << "Error, KSycocaFactory (id = " << int(id) << ") not found!" << endl;
00325 break;
00326 }
00327 (*m_str) >> aOffset;
00328 if (aId == id)
00329 {
00330
00331 m_str->device()->at(aOffset);
00332 return m_str;
00333 }
00334 }
00335 return 0;
00336 }
00337
00338 QString KSycoca::kfsstnd_prefixes()
00339 {
00340 if (bNoDatabase) return "";
00341 if (!checkVersion(false)) return "";
00342 Q_INT32 aId;
00343 Q_INT32 aOffset;
00344
00345 while(true)
00346 {
00347 (*m_str) >> aId;
00348 if ( aId )
00349 (*m_str) >> aOffset;
00350 else
00351 break;
00352 }
00353
00354 QString prefixes;
00355 KSycocaEntry::read(*m_str, prefixes);
00356 (*m_str) >> m_timeStamp;
00357 KSycocaEntry::read(*m_str, d->language);
00358 (*m_str) >> d->updateSig;
00359 return prefixes;
00360 }
00361
00362 Q_UINT32 KSycoca::timeStamp()
00363 {
00364 if (!m_timeStamp)
00365 (void) kfsstnd_prefixes();
00366 return m_timeStamp;
00367 }
00368
00369 Q_UINT32 KSycoca::updateSignature()
00370 {
00371 if (!m_timeStamp)
00372 (void) kfsstnd_prefixes();
00373 return d->updateSig;
00374 }
00375
00376 QString KSycoca::language()
00377 {
00378 if (d->language.isEmpty())
00379 (void) kfsstnd_prefixes();
00380 return d->language;
00381 }
00382
00383 QString KSycoca::determineRelativePath( const QString & _fullpath, const char *_resource )
00384 {
00385 QString sRelativeFilePath;
00386 QStringList dirs = KGlobal::dirs()->resourceDirs( _resource );
00387 QStringList::ConstIterator dirsit = dirs.begin();
00388 for ( ; dirsit != dirs.end() && sRelativeFilePath.isEmpty(); ++dirsit ) {
00389
00390 if ( _fullpath.find( *dirsit ) == 0 )
00391 sRelativeFilePath = _fullpath.mid( (*dirsit).length() );
00392 }
00393 if ( sRelativeFilePath.isEmpty() )
00394 kdFatal(7011) << QString("Couldn't find %1 in any %2 dir !!!").arg( _fullpath ).arg( _resource) << endl;
00395
00396
00397
00398 return sRelativeFilePath;
00399 }
00400
00401 KSycoca * KSycoca::_self = 0L;
00402
00403 void KSycoca::flagError()
00404 {
00405 qWarning("ERROR: KSycoca database corruption!");
00406 if (_self)
00407 {
00408 if (_self->d->readError)
00409 return;
00410 _self->d->readError = true;
00411 system("kbuildsycoca");
00412 }
00413 }
00414
00415 bool KSycoca::readError()
00416 {
00417 bool b = false;
00418 if (_self)
00419 {
00420 b = _self->d->readError;
00421 _self->d->readError = false;
00422 }
00423 return b;
00424 }
00425
00426 void KSycocaEntry::read( QDataStream &s, QString &str )
00427 {
00428 Q_UINT32 bytes;
00429 s >> bytes;
00430 if ( bytes > 8192 ) {
00431 if (bytes != 0xffffffff)
00432 KSycoca::flagError();
00433 str = QString::null;
00434 }
00435 else if ( bytes > 0 ) {
00436 int bt = bytes/2;
00437 str.setLength( bt );
00438 QChar* ch = (QChar *) str.unicode();
00439 char t[8192];
00440 char *b = t;
00441 s.readRawBytes( b, bytes );
00442 while ( bt-- ) {
00443 *ch++ = (ushort) (((ushort)b[0])<<8) | (uchar)b[1];
00444 b += 2;
00445 }
00446 } else {
00447 str = "";
00448 }
00449 }
00450
00451 void KSycocaEntry::read( QDataStream &s, QStringList &list )
00452 {
00453 list.clear();
00454 Q_UINT32 count;
00455 s >> count;
00456 if (count >= 1024)
00457 {
00458 KSycoca::flagError();
00459 return;
00460 }
00461 for(Q_UINT32 i = 0; i < count; i++)
00462 {
00463 QString str;
00464 read(s, str);
00465 list.append( str );
00466 if (s.atEnd())
00467 {
00468 KSycoca::flagError();
00469 return;
00470 }
00471 }
00472 }
00473
00474 void KSycoca::virtual_hook( int id, void* data )
00475 { DCOPObject::virtual_hook( id, data ); }
00476
00477 void KSycocaEntry::virtual_hook( int, void* )
00478 { }
00479
00480 #include "ksycoca.moc"
This file is part of the documentation for kdelibs Version 3.1.0.