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