• Skip to content
  • Skip to link menu
KDE 4.3 API Reference
  • KDE API Reference
  • kdelibs
  • Sitemap
  • Contact Us
 

KDED

kbuildsycoca.cpp

Go to the documentation of this file.
00001 // -*- c-basic-offset: 3 -*-
00002 /*  This file is part of the KDE libraries
00003  *  Copyright (C) 1999 David Faure <faure@kde.org>
00004  *  Copyright (C) 2002-2003 Waldo Bastian <bastian@kde.org>
00005  *
00006  *  This library is free software; you can redistribute it and/or
00007  *  modify it under the terms of the GNU Library General Public
00008  *  License version 2 as published by the Free Software Foundation;
00009  *
00010  *  This library is distributed in the hope that it will be useful,
00011  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013  *  Library General Public License for more details.
00014  *
00015  *  You should have received a copy of the GNU Library General Public License
00016  *  along with this library; see the file COPYING.LIB.  If not, write to
00017  *  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00018  *  Boston, MA 02110-1301, USA.
00019  **/
00020 
00021 #include "kbuildsycoca.h"
00022 #include "ksycoca_p.h"
00023 #include "kresourcelist.h"
00024 #include "vfolder_menu.h"
00025 
00026 #include <config.h>
00027 
00028 #include <kservice.h>
00029 #include <kmimetype.h>
00030 #include "kbuildservicetypefactory.h"
00031 #include "kbuildmimetypefactory.h"
00032 #include "kbuildservicefactory.h"
00033 #include "kbuildservicegroupfactory.h"
00034 #include "kbuildprotocolinfofactory.h"
00035 #include "kctimefactory.h"
00036 #include <ktemporaryfile.h>
00037 #include <QtCore/QDataStream>
00038 #include <QtCore/QDir>
00039 #include <QtCore/QEventLoop>
00040 #include <QtCore/QFile>
00041 #include <QtCore/QTimer>
00042 #include <QtDBus/QtDBus>
00043 #include <errno.h>
00044 
00045 #include <assert.h>
00046 #include <kapplication.h>
00047 #include <kglobal.h>
00048 #include <kdebug.h>
00049 #include <kdirwatch.h>
00050 #include <kstandarddirs.h>
00051 #include <ksavefile.h>
00052 #include <klocale.h>
00053 #include <kaboutdata.h>
00054 #include <kcmdlineargs.h>
00055 #include <kcrash.h>
00056 #include <kmemfile.h>
00057 
00058 #ifdef KBUILDSYCOCA_GUI // KBUILDSYCOCA_GUI is used on win32 to build
00059                         // GUI version of kbuildsycoca, so-called "kbuildsycocaw".
00060 # include <qlabel.h>
00061 # include <kmessagebox.h>
00062   bool silent;
00063   bool showprogress;
00064 #endif
00065 
00066 #include <stdlib.h>
00067 #include <unistd.h>
00068 #include <time.h>
00069 #include <memory> // auto_ptr
00070 
00071 typedef QHash<QString, KSycocaEntry::Ptr> KBSEntryDict;
00072 typedef QList<KSycocaEntry::List> KSycocaEntryListList;
00073 
00074 static quint32 newTimestamp = 0;
00075 
00076 static KBuildServiceFactory *g_bsf = 0;
00077 static KBuildServiceGroupFactory *g_bsgf = 0;
00078 static KSycocaFactory *g_factory = 0;
00079 static KCTimeInfo *g_ctimeInfo = 0;
00080 static QHash<QString, quint32> *g_ctimeDict = 0;
00081 static QByteArray g_resource = 0;
00082 static KBSEntryDict *g_entryDict = 0;
00083 static KBSEntryDict *g_serviceGroupEntryDict = 0;
00084 static KSycocaEntryListList *g_allEntries = 0;
00085 static QStringList *g_changeList = 0;
00086 static QStringList *g_allResourceDirs = 0;
00087 static bool g_changed = false;
00088 static KSycocaEntry::List g_tempStorage;
00089 static VFolderMenu *g_vfolder = 0;
00090 
00091 static const char *cSycocaPath = 0;
00092 
00093 static bool bGlobalDatabase = false;
00094 static bool bMenuTest = false;
00095 
00096 void crashHandler(int)
00097 {
00098    // If we crash while reading sycoca, we delete the database
00099    // in an attempt to recover.
00100    if (cSycocaPath)
00101       unlink(cSycocaPath);
00102 }
00103 
00104 static QString sycocaPath()
00105 {
00106   return KSycoca::absoluteFilePath(bGlobalDatabase ? KSycoca::GlobalDatabase : KSycoca::LocalDatabase);
00107 }
00108 
00109 KBuildSycoca::KBuildSycoca()
00110   : KSycoca( true )
00111 {
00112 }
00113 
00114 KBuildSycoca::~KBuildSycoca()
00115 {
00116 
00117 }
00118 
00119 KSycocaEntry::Ptr KBuildSycoca::createEntry(const QString &file, bool addToFactory)
00120 {
00121    quint32 timeStamp = g_ctimeInfo->ctime(file);
00122    if (!timeStamp)
00123    {
00124       timeStamp = KGlobal::dirs()->calcResourceHash( g_resource, file,
00125                                                      KStandardDirs::Recursive);
00126    }
00127    KSycocaEntry::Ptr entry;
00128    if (g_allEntries)
00129    {
00130       assert(g_ctimeDict);
00131       quint32 oldTimestamp = g_ctimeDict->value( file, 0 );
00132 
00133       if (timeStamp && (timeStamp == oldTimestamp))
00134       {
00135          // Re-use old entry
00136          if (g_factory == g_bsgf) // Strip .directory from service-group entries
00137          {
00138             entry = g_entryDict->value(file.left(file.length()-10));
00139          } else {
00140             entry = g_entryDict->value(file);
00141          }
00142          // remove from g_ctimeDict; if g_ctimeDict is not empty
00143          // after all files have been processed, it means
00144          // some files were removed since last time
00145          g_ctimeDict->remove( file );
00146       }
00147       else if (oldTimestamp)
00148       {
00149          g_changed = true;
00150          kDebug(7021) << "modified:" << file;
00151       }
00152       else
00153       {
00154          g_changed = true;
00155          kDebug(7021) << "new:" << file;
00156       }
00157    }
00158    g_ctimeInfo->addCTime(file, timeStamp );
00159    if (!entry)
00160    {
00161       // Create a new entry
00162       entry = g_factory->createEntry( file, g_resource );
00163    }
00164    if ( entry && entry->isValid() )
00165    {
00166       if (addToFactory)
00167          g_factory->addEntry(entry);
00168       else
00169          g_tempStorage.append(entry);
00170       return entry;
00171    }
00172    return KSycocaEntry::Ptr();
00173 }
00174 
00175 // Callback for VFolderMenu
00176 void KBuildSycoca::slotCreateEntry(const QString &file, KService::Ptr *service)
00177 {
00178    KSycocaEntry::Ptr entry = createEntry(file, false);
00179    *service = KService::Ptr::staticCast( entry );
00180 }
00181 
00182 // returns false if the database is up to date
00183 bool KBuildSycoca::build()
00184 {
00185   typedef QLinkedList<KBSEntryDict *> KBSEntryDictList;
00186   KBSEntryDictList entryDictList;
00187   KBSEntryDict *serviceEntryDict = 0;
00188 
00189   // Convert for each factory the entryList to a Dict.
00190   int i = 0;
00191   // For each factory
00192   for (KSycocaFactoryList::Iterator factory = factories()->begin();
00193        factory != factories()->end();
00194        ++factory)
00195   {
00196      KBSEntryDict *entryDict = new KBSEntryDict;
00197      if (g_allEntries)
00198      {
00199          const KSycocaEntry::List list = (*g_allEntries)[i++];
00200          for( KSycocaEntry::List::const_iterator it = list.begin();
00201             it != list.end();
00202             ++it)
00203          {
00204             entryDict->insert( (*it)->entryPath(), *it );
00205          }
00206      }
00207      if ((*factory) == g_bsf)
00208         serviceEntryDict = entryDict;
00209      else if ((*factory) == g_bsgf)
00210         g_serviceGroupEntryDict = entryDict;
00211      entryDictList.append(entryDict);
00212   }
00213 
00214   QStringList allResources; // we could use QSet<QString> - does order matter?
00215   // For each factory
00216   for (KSycocaFactoryList::Iterator factory = factories()->begin();
00217        factory != factories()->end();
00218        ++factory)
00219   {
00220     // For each resource the factory deals with
00221     const KSycocaResourceList *list = (*factory)->resourceList();
00222     if (!list) continue;
00223 
00224     for( KSycocaResourceList::ConstIterator it1 = list->constBegin();
00225          it1 != list->constEnd();
00226          ++it1 )
00227     {
00228       KSycocaResource res = (*it1);
00229       if (!allResources.contains(res.resource))
00230          allResources.append(res.resource);
00231     }
00232   }
00233 
00234   g_ctimeInfo = new KCTimeInfo(); // This is a build factory too, don't delete!!
00235   bool uptodate = true;
00236   // For all resources
00237   for( QStringList::ConstIterator it1 = allResources.constBegin();
00238        it1 != allResources.constEnd();
00239        ++it1 )
00240   {
00241      g_changed = false;
00242      g_resource = (*it1).toLatin1();
00243 
00244      QStringList relFiles;
00245 
00246      (void) KGlobal::dirs()->findAllResources( g_resource,
00247                                                QString(),
00248                                                KStandardDirs::Recursive |
00249                                                KStandardDirs::NoDuplicates,
00250                                                relFiles);
00251 
00252 
00253      // Now find all factories that use this resource....
00254      // For each factory
00255      KBSEntryDictList::const_iterator ed_it = entryDictList.begin();
00256      const KBSEntryDictList::const_iterator ed_end = entryDictList.end();
00257      KSycocaFactoryList::const_iterator it = factories()->constBegin();
00258      const KSycocaFactoryList::const_iterator end = factories()->constEnd();
00259      for ( ; it != end; ++it, ++ed_it )
00260      {
00261         g_factory = (*it);
00262         // g_ctimeInfo gets created after the initial loop, so it has no entryDict.
00263         g_entryDict = ed_it == ed_end ? 0 : *ed_it;
00264     // For each resource the factory deals with
00265         const KSycocaResourceList *list = g_factory->resourceList();
00266         if (!list) continue;
00267 
00268         for( KSycocaResourceList::ConstIterator it2 = list->constBegin();
00269              it2 != list->constEnd();
00270              ++it2 )
00271         {
00272            KSycocaResource res = (*it2);
00273            if (res.resource != (*it1)) continue;
00274 
00275            // For each file in the resource
00276            for( QStringList::ConstIterator it3 = relFiles.constBegin();
00277                 it3 != relFiles.constEnd();
00278                 ++it3 )
00279            {
00280                // Check if file matches filter
00281                if ((*it3).endsWith(res.extension))
00282                    createEntry(*it3, true);
00283            }
00284         }
00285      }
00286      if (g_changed || !g_allEntries)
00287      {
00288         uptodate = false;
00289         g_changeList->append(g_resource);
00290      }
00291   }
00292 
00293   bool result = !uptodate || (g_ctimeDict && !g_ctimeDict->isEmpty());
00294 
00295   if (result || bMenuTest)
00296   {
00297      g_resource = "apps";
00298      g_factory = g_bsf;
00299      g_entryDict = serviceEntryDict;
00300      g_changed = false;
00301 
00302      g_vfolder = new VFolderMenu(g_bsf);
00303      if (!m_trackId.isEmpty())
00304         g_vfolder->setTrackId(m_trackId);
00305 
00306      connect(g_vfolder, SIGNAL(newService(const QString &, KService::Ptr *)),
00307              this, SLOT(slotCreateEntry(const QString &, KService::Ptr *)));
00308 
00309      VFolderMenu::SubMenu *kdeMenu = g_vfolder->parseMenu("applications.menu", true);
00310 
00311      KServiceGroup::Ptr entry = g_bsgf->addNew("/", kdeMenu->directoryFile, KServiceGroup::Ptr(), false);
00312      entry->setLayoutInfo(kdeMenu->layoutList);
00313      createMenu(QString(), QString(), kdeMenu);
00314 
00315      (void) existingResourceDirs();
00316      *g_allResourceDirs += g_vfolder->allDirectories();
00317 
00318      disconnect(g_vfolder, SIGNAL(newService(const QString &, KService::Ptr *)),
00319                 this, SLOT(slotCreateEntry(const QString &, KService::Ptr *)));
00320 
00321      if (g_changed || !g_allEntries)
00322      {
00323         uptodate = false;
00324         g_changeList->append(g_resource);
00325      }
00326      if (bMenuTest) {
00327          result = false;
00328      }
00329   }
00330 
00331   qDeleteAll(entryDictList);
00332   return result;
00333 }
00334 
00335 void KBuildSycoca::createMenu(const QString &caption_, const QString &name_, VFolderMenu::SubMenu *menu)
00336 {
00337   QString caption = caption_;
00338   QString name = name_;
00339   foreach (VFolderMenu::SubMenu *subMenu, menu->subMenus)
00340   {
00341      QString subName = name+subMenu->name+'/';
00342 
00343      QString directoryFile = subMenu->directoryFile;
00344      if (directoryFile.isEmpty())
00345         directoryFile = subName+".directory";
00346      quint32 timeStamp = g_ctimeInfo->ctime(directoryFile);
00347      if (!timeStamp) {
00348         timeStamp = KGlobal::dirs()->calcResourceHash( g_resource, directoryFile,
00349                                                        KStandardDirs::Recursive );
00350      }
00351 
00352      KServiceGroup::Ptr entry;
00353      if (g_allEntries)
00354      {
00355         quint32 oldTimestamp = g_ctimeDict->value( directoryFile, 0 );
00356 
00357         if (timeStamp && (timeStamp == oldTimestamp))
00358         {
00359             KSycocaEntry::Ptr group = g_serviceGroupEntryDict->value(subName);
00360             if ( group )
00361             {
00362                 entry = KServiceGroup::Ptr::staticCast( group );
00363                 if (entry->directoryEntryPath() != directoryFile)
00364                     entry = 0; // Can't reuse this one!
00365             }
00366         }
00367      }
00368      g_ctimeInfo->addCTime(directoryFile, timeStamp);
00369 
00370      entry = g_bsgf->addNew(subName, subMenu->directoryFile, entry, subMenu->isDeleted);
00371      entry->setLayoutInfo(subMenu->layoutList);
00372      if (! (bMenuTest && entry->noDisplay()) )
00373         createMenu(caption + entry->caption() + '/', subName, subMenu);
00374   }
00375   if (caption.isEmpty())
00376      caption += '/';
00377   if (name.isEmpty())
00378      name += '/';
00379   foreach (const KService::Ptr &p, menu->items)
00380   {
00381      if (bMenuTest)
00382      {
00383         if (!menu->isDeleted && !p->noDisplay())
00384            printf("%s\t%s\t%s\n", qPrintable( caption ), qPrintable( p->menuId() ), qPrintable( KStandardDirs::locate("apps", p->entryPath() ) ) );
00385      }
00386      else
00387      {
00388         g_bsgf->addNewEntryTo( name, p );
00389      }
00390   }
00391 }
00392 
00393 bool KBuildSycoca::recreate()
00394 {
00395   QString path(sycocaPath());
00396 
00397   // KSaveFile first writes to a temp file.
00398   // Upon finalize() it moves the stuff to the right place.
00399   KSaveFile database(path);
00400   bool openedOK = database.open();
00401   if (!openedOK && database.error() == QFile::PermissionsError && QFile::exists(path))
00402   {
00403     QFile::remove( path );
00404     openedOK = database.open();
00405   }
00406   if (!openedOK)
00407   {
00408     fprintf(stderr, "kbuildsycoca4: ERROR creating database '%s'! %s\n",
00409       path.toLocal8Bit().data(), database.errorString().toLocal8Bit().data());
00410 #ifdef KBUILDSYCOCA_GUI // KBUILDSYCOCA_GUI is used on win32 to build
00411                         // GUI version of kbuildsycoca, so-called "kbuildsycocaw".
00412     if (!silent)
00413       KMessageBox::error(0, i18n("Error creating database '%1'.\nCheck that the permissions are correct on the directory and the disk is not full.\n", path.toLocal8Bit().data()), i18n("KBuildSycoca"));
00414 #endif
00415     return false;
00416   }
00417 
00418   QDataStream* str = new QDataStream(&database);
00419   str->setVersion(QDataStream::Qt_3_1);
00420 
00421   kDebug(7021).nospace() << "Recreating ksycoca file (" << path << ", version " << KSycoca::version() << ")";
00422 
00423   // It is very important to build the servicetype one first
00424   // Both are registered in KSycoca, no need to keep the pointers
00425   KSycocaFactory *stf = new KBuildServiceTypeFactory;
00426   KBuildMimeTypeFactory *mtf = new KBuildMimeTypeFactory;
00427   g_bsgf = new KBuildServiceGroupFactory();
00428   g_bsf = new KBuildServiceFactory(stf, mtf, g_bsgf);
00429   (void) new KBuildProtocolInfoFactory();
00430 
00431   if( build()) // Parse dirs
00432   {
00433     save(str); // Save database
00434     if (str->status() != QDataStream::Ok) // ######## TODO: does this detect write errors, e.g. disk full?
00435       database.abort(); // Error
00436     delete str;
00437     str = 0;
00438     if (!database.finalize())
00439     {
00440       fprintf(stderr, "kbuildsycoca4: ERROR writing database '%s'!\n", database.fileName().toLocal8Bit().data());
00441       fprintf(stderr, "kbuildsycoca4: Disk full?\n");
00442 #ifdef KBUILDSYCOCA_GUI
00443       if (!silent)
00444         KMessageBox::error(0, i18n("Error writing database '%1'.\nCheck that the permissions are correct on the directory and the disk is not full.\n", path.toLocal8Bit().data()), i18n("KBuildSycoca"));
00445 #endif
00446       return false;
00447     }
00448   }
00449   else
00450   {
00451     delete str;
00452     str = 0;
00453     database.abort();
00454     if (bMenuTest)
00455        return true;
00456     kDebug(7021) << "Database is up to date";
00457   }
00458 
00459   if (!bGlobalDatabase)
00460   {
00461     // update the timestamp file
00462     QString stamppath = path + "stamp";
00463     QFile ksycocastamp(stamppath);
00464     ksycocastamp.open( QIODevice::WriteOnly );
00465     QDataStream str( &ksycocastamp );
00466     str.setVersion(QDataStream::Qt_3_1);
00467     str << newTimestamp;
00468     str << existingResourceDirs();
00469     if (g_vfolder)
00470         str << g_vfolder->allDirectories(); // Extra resource dirs
00471   }
00472   if (d->m_sycocaStrategy == KSycocaPrivate::StrategyMemFile)
00473      KMemFile::fileContentsChanged(path);
00474 
00475   return true;
00476 }
00477 
00478 void KBuildSycoca::save(QDataStream* str)
00479 {
00480    // Write header (#pass 1)
00481    str->device()->seek(0);
00482 
00483    (*str) << (qint32) KSycoca::version();
00484    KSycocaFactory * servicetypeFactory = 0;
00485    KBuildMimeTypeFactory * mimeTypeFactory = 0;
00486    KBuildServiceFactory * serviceFactory = 0;
00487    for(KSycocaFactoryList::Iterator factory = factories()->begin();
00488        factory != factories()->end();
00489        ++factory)
00490    {
00491       qint32 aId;
00492       qint32 aOffset;
00493       aId = (*factory)->factoryId();
00494       if ( aId == KST_KServiceTypeFactory )
00495          servicetypeFactory = *factory;
00496       else if ( aId == KST_KMimeTypeFactory )
00497          mimeTypeFactory = static_cast<KBuildMimeTypeFactory *>( *factory );
00498       else if ( aId == KST_KServiceFactory )
00499          serviceFactory = static_cast<KBuildServiceFactory *>( *factory );
00500       aOffset = (*factory)->offset(); // not set yet, so always 0
00501       (*str) << aId;
00502       (*str) << aOffset;
00503    }
00504    (*str) << (qint32) 0; // No more factories.
00505    // Write KDEDIRS
00506    (*str) << KGlobal::dirs()->kfsstnd_prefixes();
00507    (*str) << newTimestamp;
00508    (*str) << KGlobal::locale()->language();
00509    (*str) << KGlobal::dirs()->calcResourceHash("services", "update_ksycoca",
00510                                                  KStandardDirs::Recursive );
00511    (*str) << (*g_allResourceDirs);
00512 
00513    // Calculate per-servicetype/mimetype data
00514    mimeTypeFactory->parseSubclasses();
00515    serviceFactory->postProcessServices();
00516 
00517    // Here so that it's the last debug message
00518    kDebug(7021) << "Saving";
00519 
00520    // Write factory data....
00521    for(KSycocaFactoryList::Iterator factory = factories()->begin();
00522        factory != factories()->end();
00523        ++factory)
00524    {
00525       (*factory)->save(*str);
00526       if (str->status() != QDataStream::Ok) // ######## TODO: does this detect write errors, e.g. disk full?
00527          return; // error
00528    }
00529 
00530    int endOfData = str->device()->pos();
00531 
00532    // Write header (#pass 2)
00533    str->device()->seek(0);
00534 
00535    (*str) << (qint32) KSycoca::version();
00536    for(KSycocaFactoryList::Iterator factory = factories()->begin();
00537        factory != factories()->end(); ++factory)
00538    {
00539       qint32 aId;
00540       qint32 aOffset;
00541       aId = (*factory)->factoryId();
00542       aOffset = (*factory)->offset();
00543       (*str) << aId;
00544       (*str) << aOffset;
00545    }
00546    (*str) << (qint32) 0; // No more factories.
00547 
00548    // Jump to end of database
00549    str->device()->seek(endOfData);
00550 }
00551 
00552 bool KBuildSycoca::checkDirTimestamps( const QString& dirname, const QDateTime& stamp, bool top )
00553 {
00554    if( top )
00555    {
00556       QFileInfo inf( dirname );
00557       if( inf.lastModified() > stamp ) {
00558          kDebug( 7021 ) << "timestamp changed:" << dirname;
00559          return false;
00560       }
00561    }
00562    QDir dir( dirname );
00563    const QFileInfoList list = dir.entryInfoList( QDir::NoFilter, QDir::Unsorted );
00564    if (list.isEmpty())
00565       return true;
00566 
00567    foreach ( const QFileInfo& fi, list ) {
00568       if( fi.fileName() == "." || fi.fileName() == ".." )
00569          continue;
00570       if( fi.lastModified() > stamp )
00571       {
00572          kDebug( 7201 ) << "timestamp changed:" << fi.filePath();
00573          return false;
00574       }
00575       if( fi.isDir() && !checkDirTimestamps( fi.filePath(), stamp, false ))
00576             return false;
00577    }
00578    return true;
00579 }
00580 
00581 // check times of last modification of all files on which ksycoca depens,
00582 // and also their directories
00583 // if all of them are older than the timestamp in file ksycocastamp, this
00584 // means that there's no need to rebuild ksycoca
00585 bool KBuildSycoca::checkTimestamps( quint32 timestamp, const QStringList &dirs )
00586 {
00587    kDebug( 7021 ) << "checking file timestamps";
00588    QDateTime stamp;
00589    stamp.setTime_t( timestamp );
00590    for( QStringList::ConstIterator it = dirs.begin();
00591         it != dirs.end();
00592         ++it )
00593    {
00594       if( !checkDirTimestamps( *it, stamp, true ))
00595             return false;
00596    }
00597    kDebug( 7021 ) << "timestamps check ok";
00598    return true;
00599 }
00600 
00601 QStringList KBuildSycoca::existingResourceDirs()
00602 {
00603    static QStringList* dirs = NULL;
00604    if( dirs != NULL )
00605        return *dirs;
00606    dirs = new QStringList;
00607    g_allResourceDirs = new QStringList;
00608    // these are all resources cached by ksycoca
00609    QStringList resources;
00610    resources += KBuildServiceTypeFactory::resourceTypes();
00611    resources += KBuildMimeTypeFactory::resourceTypes();
00612    resources += KBuildServiceGroupFactory::resourceTypes();
00613    resources += KBuildServiceFactory::resourceTypes();
00614    resources += KBuildProtocolInfoFactory::resourceTypes();
00615    while( !resources.empty())
00616    {
00617       QString res = resources.front();
00618       *dirs += KGlobal::dirs()->resourceDirs( res.toLatin1());
00619       resources.removeAll( res );
00620    }
00621 
00622    *g_allResourceDirs = *dirs;
00623 
00624    for( QStringList::Iterator it = dirs->begin();
00625         it != dirs->end(); )
00626    {
00627       QFileInfo inf( *it );
00628       if( !inf.exists() || !inf.isReadable() )
00629          it = dirs->erase( it );
00630       else
00631          ++it;
00632    }
00633    return *dirs;
00634 }
00635 
00636 static const char appFullName[] = "org.kde.kbuildsycoca";
00637 static const char appName[] = "kbuildsycoca4";
00638 static const char appVersion[] = "1.1";
00639 
00640 extern "C" KDE_EXPORT int kdemain(int argc, char **argv)
00641 {
00642    KAboutData d(appName, "kdelibs4", ki18n("KBuildSycoca"), appVersion,
00643                 ki18n("Rebuilds the system configuration cache."),
00644                 KAboutData::License_GPL, ki18n("(c) 1999-2002 KDE Developers"));
00645    d.addAuthor(ki18n("David Faure"), ki18n("Author"), "faure@kde.org");
00646    d.addAuthor(ki18n("Waldo Bastian"), ki18n("Author"), "bastian@kde.org");
00647 
00648    KCmdLineOptions options;
00649    options.add("nosignal", ki18n("Do not signal applications to update"));
00650    options.add("noincremental", ki18n("Disable incremental update, re-read everything"));
00651    options.add("checkstamps", ki18n("Check file timestamps"));
00652    options.add("nocheckfiles", ki18n("Disable checking files (dangerous)"));
00653    options.add("global", ki18n("Create global database"));
00654    options.add("menutest", ki18n("Perform menu generation test run only"));
00655    options.add("track <menu-id>", ki18n("Track menu id for debug purposes"));
00656 #ifdef KBUILDSYCOCA_GUI
00657    options.add("silent", ki18n("Silent - work without windows and stderr"));
00658    options.add("showprogress", ki18n("Show progress information (even if 'silent' mode is on)"));
00659 #endif
00660 
00661    KCmdLineArgs::init(argc, argv, &d);
00662    KCmdLineArgs::addCmdLineOptions(options);
00663    KCmdLineArgs *args = KCmdLineArgs::parsedArgs();
00664    bGlobalDatabase = args->isSet("global");
00665    bMenuTest = args->isSet("menutest");
00666 
00667    if (bGlobalDatabase)
00668    {
00669      setenv("KDEHOME", "-", 1);
00670      setenv("KDEROOTHOME", "-", 1);
00671    }
00672 
00673 #ifdef KBUILDSYCOCA_GUI
00674    KApplication k;
00675 #else
00676    KApplication k(false);
00677 #endif
00678    k.disableSessionManagement();
00679 
00680 #ifdef KBUILDSYCOCA_GUI
00681    silent = args->isSet("silent");
00682    showprogress = args->isSet("showprogress");
00683    QLabel progress( QString("<p><br><nobr>    %1    </nobr><br>").arg( i18n("Reloading KDE configuration, please wait...") ), 0, "", Qt::WType_Dialog | Qt::WStyle_DialogBorder  | Qt::WStyle_Customize| Qt::WStyle_Title );
00684    QString capt = i18n("KDE Configuration Manager");
00685    if (!silent) {
00686      if (KMessageBox::No == KMessageBox::questionYesNo(0, i18n("Do you want to reload KDE configuration?"), capt, i18nc("Reload KDE configuration messagebox", "Reload"), i18n("Do Not Reload")))
00687        return 0;
00688    }
00689    if (!silent || showprogress) {
00690      progress.setCaption( capt );
00691      progress.show();
00692    }
00693 #endif
00694 
00695    KCrash::setCrashHandler(KCrash::defaultCrashHandler);
00696    KCrash::setEmergencySaveFunction(crashHandler);
00697    KCrash::setApplicationName(QString(appName));
00698 
00699    // force generating of KLocale object. if not, the database will get
00700    // be translated
00701    KGlobal::locale();
00702    KGlobal::dirs()->addResourceType("app-reg", 0, "share/application-registry" );
00703 
00704    while(QDBusConnection::sessionBus().isConnected())
00705    {
00706      // kapp registered already, but with the PID in the name.
00707      // We need to re-register without it, to detect already-running kbuildsycoca instances.
00708      if (QDBusConnection::sessionBus().interface()->registerService(appFullName, QDBusConnectionInterface::QueueService)
00709          != QDBusConnectionInterface::ServiceQueued)
00710      {
00711        break; // Go
00712      }
00713      fprintf(stderr, "Waiting for already running %s to finish.\n", appName);
00714 
00715      QEventLoop eventLoop;
00716      QObject::connect(QDBusConnection::sessionBus().interface(), SIGNAL(serviceRegistered(QString)),
00717                       &eventLoop, SLOT(quit()));
00718      eventLoop.exec( QEventLoop::ExcludeUserInputEvents );
00719    }
00720    fprintf(stderr, "%s running...\n", appName);
00721 
00722    bool checkfiles = bGlobalDatabase || args->isSet("checkfiles");
00723 
00724    bool incremental = !bGlobalDatabase && args->isSet("incremental") && checkfiles;
00725    if (incremental || !checkfiles)
00726    {
00727      KSycoca::disableAutoRebuild(); // Prevent deadlock
00728      QString current_language = KGlobal::locale()->language();
00729      QString ksycoca_language = KSycoca::self()->language();
00730      quint32 current_update_sig = KGlobal::dirs()->calcResourceHash("services", "update_ksycoca",
00731                                                                     KStandardDirs::Recursive );
00732      quint32 ksycoca_update_sig = KSycoca::self()->updateSignature();
00733      QString current_prefixes = KGlobal::dirs()->kfsstnd_prefixes();
00734      QString ksycoca_prefixes = KSycoca::self()->kfsstnd_prefixes();
00735 
00736      if ((current_update_sig != ksycoca_update_sig) ||
00737          (current_language != ksycoca_language) ||
00738          (current_prefixes != ksycoca_prefixes) ||
00739          (KSycoca::self()->timeStamp() == 0))
00740      {
00741         incremental = false;
00742         checkfiles = true;
00743         KBuildSycoca::clearCaches();
00744      }
00745    }
00746 
00747    g_changeList = new QStringList;
00748 
00749    bool checkstamps = incremental && args->isSet("checkstamps") && checkfiles;
00750    quint32 filestamp = 0;
00751    QStringList oldresourcedirs;
00752    if( checkstamps && incremental )
00753    {
00754        QString path = sycocaPath()+"stamp";
00755        QByteArray qPath = QFile::encodeName(path);
00756        cSycocaPath = qPath.data(); // Delete timestamps on crash
00757        QFile ksycocastamp(path);
00758        if( ksycocastamp.open( QIODevice::ReadOnly ))
00759        {
00760            QDataStream str( &ksycocastamp );
00761            str.setVersion(QDataStream::Qt_3_1);
00762 
00763            if (!str.atEnd())
00764                str >> filestamp;
00765            if (!str.atEnd())
00766            {
00767                str >> oldresourcedirs;
00768                if( oldresourcedirs != KBuildSycoca::existingResourceDirs())
00769                    checkstamps = false;
00770            }
00771            else
00772            {
00773                checkstamps = false;
00774            }
00775            if (!str.atEnd())
00776            {
00777                QStringList extraResourceDirs;
00778                str >> extraResourceDirs;
00779                oldresourcedirs += extraResourceDirs;
00780            }
00781        }
00782        else
00783        {
00784            checkstamps = false;
00785        }
00786        cSycocaPath = 0;
00787    }
00788 
00789    newTimestamp = (quint32) time(0);
00790 
00791    if( checkfiles && ( !checkstamps || !KBuildSycoca::checkTimestamps( filestamp, oldresourcedirs )))
00792    {
00793       QByteArray qSycocaPath = QFile::encodeName(sycocaPath());
00794       cSycocaPath = qSycocaPath.data();
00795 
00796       g_allEntries = 0;
00797       g_ctimeDict = 0;
00798       if (incremental)
00799       {
00800          kDebug(7021) << "Reusing existing ksycoca";
00801          KSycoca::self();
00802          KSycocaFactoryList *factories = new KSycocaFactoryList;
00803          g_allEntries = new KSycocaEntryListList;
00804          g_ctimeDict = new QHash<QString, quint32>;
00805 
00806          // Must be in same order as in KBuildSycoca::recreate()!
00807          factories->append( new KServiceTypeFactory );
00808          factories->append( new KMimeTypeFactory );
00809          factories->append( new KServiceGroupFactory );
00810          factories->append( new KServiceFactory );
00811          factories->append( new KProtocolInfoFactory );
00812 
00813          // For each factory
00814      for (KSycocaFactoryList::Iterator factory = factories->begin();
00815           factory != factories->end(); ++factory)
00816          {
00817              const KSycocaEntry::List list = (*factory)->allEntries();
00818              g_allEntries->append( list );
00819          }
00820          delete factories; factories = 0;
00821          KCTimeInfo *ctimeInfo = new KCTimeInfo;
00822          ctimeInfo->fillCTimeDict(*g_ctimeDict);
00823       }
00824       cSycocaPath = 0;
00825 
00826       KBuildSycoca *sycoca = new KBuildSycoca; // Build data base (deletes oldSycoca)
00827       if (args->isSet("track"))
00828          sycoca->setTrackId(args->getOption("track"));
00829       if (!sycoca->recreate()) {
00830 #ifdef KBUILDSYCOCA_GUI
00831         if (!silent || showprogress)
00832           progress.close();
00833 #endif
00834         return -1;
00835       }
00836 
00837       if (bGlobalDatabase)
00838       {
00839         // These directories may have been created with 0700 permission
00840         // better delete them if they are empty
00841         QString applnkDir = KGlobal::dirs()->saveLocation("apps", QString(), false);
00842         ::rmdir(QFile::encodeName(applnkDir));
00843         QString servicetypesDir = KGlobal::dirs()->saveLocation("servicetypes", QString(), false);
00844         ::rmdir(QFile::encodeName(servicetypesDir));
00845       }
00846    }
00847 
00848    if (args->isSet("signal"))
00849    {
00850      // Notify ALL applications that have a ksycoca object, using a signal
00851      QDBusMessage signal = QDBusMessage::createSignal("/", "org.kde.KSycoca", "notifyDatabaseChanged" );
00852      signal << *g_changeList;
00853 
00854      if (QDBusConnection::sessionBus().isConnected()) {
00855         kDebug() << "Emitting notifyDatabaseChanged" << *g_changeList;
00856        QDBusConnection::sessionBus().send(signal);
00857        qApp->processEvents(); // make sure the dbus signal is sent before we quit.
00858      }
00859    }
00860 
00861 #ifdef KBUILDSYCOCA_GUI
00862    if (!silent) {
00863      progress.close();
00864      KMessageBox::information(0, i18n("Configuration information reloaded successfully."), capt);
00865    }
00866 #endif
00867    return 0;
00868 }
00869 
00870 #include "kbuildsycoca.moc"

KDED

Skip menu "KDED"
  • Main Page
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Class Members
  • Related Pages

kdelibs

Skip menu "kdelibs"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • Kate
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.6.1
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal