00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044 #include "kdirwatch.h"
00045 #include "kdirwatch_p.h"
00046
00047 #include <config-kdirwatch.h>
00048 #include <config.h>
00049
00050 #include <sys/stat.h>
00051 #include <assert.h>
00052 #include <QtCore/QDir>
00053 #include <QtCore/QFile>
00054 #include <QtCore/QSocketNotifier>
00055 #include <QtCore/QTimer>
00056
00057 #include <kapplication.h>
00058 #include <kdebug.h>
00059 #include <kconfig.h>
00060 #include <kglobal.h>
00061 #include <kde_file.h>
00062 #include <kconfiggroup.h>
00063 #include "kmountpoint.h"
00064
00065 #include <stdlib.h>
00066
00067
00068 #include <sys/ioctl.h>
00069
00070
00071 #include <sys/utsname.h>
00072
00073 #define NO_NOTIFY (time_t) 0
00074
00075 static KDirWatchPrivate* dwp_self = 0;
00076 static KDirWatchPrivate* createPrivate() {
00077 if (!dwp_self)
00078 dwp_self = new KDirWatchPrivate;
00079 return dwp_self;
00080 }
00081
00082
00083
00084 static KDirWatchPrivate::WatchMethod methodFromString(const QString& method) {
00085 if (method == "Fam") {
00086 return KDirWatchPrivate::Fam;
00087 } else if (method == "Stat") {
00088 return KDirWatchPrivate::Stat;
00089 } else if (method == "QFSWatch") {
00090 return KDirWatchPrivate::QFSWatch;
00091 } else {
00092 #ifdef Q_OS_WIN
00093 return KDirWatchPrivate::QFSWatch;
00094 #elif defined(Q_OS_FREEBSD)
00095 return KDirWatchPrivate::Stat;
00096 #else
00097 return KDirWatchPrivate::INotify;
00098 #endif
00099 }
00100 }
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124
00125
00126
00127
00128
00129
00130
00131 KDirWatchPrivate::KDirWatchPrivate()
00132 : timer(),
00133 freq( 3600000 ),
00134 statEntries( 0 ),
00135 m_ref( 0 ),
00136 delayRemove( false ),
00137 rescan_all( false ),
00138 rescan_timer()
00139 {
00140 timer.setObjectName( "KDirWatchPrivate::timer" );
00141 connect (&timer, SIGNAL(timeout()), this, SLOT(slotRescan()));
00142
00143 KConfigGroup config(KGlobal::config(), "DirWatch");
00144 m_nfsPollInterval = config.readEntry("NFSPollInterval", 5000);
00145 m_PollInterval = config.readEntry("PollInterval", 500);
00146
00147 QString method = config.readEntry("PreferredMethod", "inotify");
00148 m_preferredMethod = methodFromString(method);
00149
00150
00151 m_nfsPreferredMethod = methodFromString(config.readEntry("nfsPreferredMethod", method));
00152
00153 QStringList availableMethods;
00154
00155 availableMethods << "Stat";
00156
00157
00158 rescan_timer.setObjectName( "KDirWatchPrivate::rescan_timer" );
00159 rescan_timer.setSingleShot( true );
00160 connect(&rescan_timer, SIGNAL(timeout()), this, SLOT(slotRescan()));
00161
00162 #ifdef HAVE_FAM
00163
00164 if (FAMOpen(&fc) ==0) {
00165 availableMethods << "FAM";
00166 use_fam=true;
00167 sn = new QSocketNotifier( FAMCONNECTION_GETFD(&fc),
00168 QSocketNotifier::Read, this);
00169 connect( sn, SIGNAL(activated(int)),
00170 this, SLOT(famEventReceived()) );
00171 }
00172 else {
00173 kDebug(7001) << "Can't use FAM (fam daemon not running?)";
00174 use_fam=false;
00175 }
00176 #endif
00177
00178 #ifdef HAVE_SYS_INOTIFY_H
00179 supports_inotify = true;
00180
00181 m_inotify_fd = inotify_init();
00182
00183 if ( m_inotify_fd <= 0 ) {
00184 kDebug(7001) << "Can't use Inotify, kernel doesn't support it";
00185 supports_inotify = false;
00186 }
00187
00188 {
00189 struct utsname uts;
00190 int major, minor, patch;
00191 if (uname(&uts) < 0)
00192 supports_inotify = false;
00193 else if (sscanf(uts.release, "%d.%d.%d", &major, &minor, &patch) != 3)
00194 supports_inotify = false;
00195 else if( major * 1000000 + minor * 1000 + patch < 2006014 ) {
00196 kDebug(7001) << "Can't use INotify, Linux kernel too old";
00197 supports_inotify = false;
00198 }
00199 }
00200
00201 if ( supports_inotify ) {
00202 availableMethods << "INotify";
00203 fcntl(m_inotify_fd, F_SETFD, FD_CLOEXEC);
00204
00205 mSn = new QSocketNotifier( m_inotify_fd, QSocketNotifier::Read, this );
00206 connect( mSn, SIGNAL(activated( int )),
00207 this, SLOT( inotifyEventReceived() ) );
00208 }
00209 #endif
00210 #ifdef HAVE_QFILESYSTEMWATCHER
00211 availableMethods << "QFileSystemWatcher";
00212 fsWatcher = new KFileSystemWatcher();
00213 connect(fsWatcher, SIGNAL(directoryChanged(QString)), this, SLOT(fswEventReceived(QString)));
00214 connect(fsWatcher, SIGNAL(fileChanged(QString)), this, SLOT(fswEventReceived(QString)));
00215 #endif
00216 kDebug(7001) << "Available methods: " << availableMethods;
00217 }
00218
00219
00220 KDirWatchPrivate::~KDirWatchPrivate()
00221 {
00222 timer.stop();
00223
00224
00225 removeEntries(0);
00226
00227 #ifdef HAVE_FAM
00228 if (use_fam) {
00229 FAMClose(&fc);
00230 }
00231 #endif
00232 #ifdef HAVE_SYS_INOTIFY_H
00233 if ( supports_inotify )
00234 ::close( m_inotify_fd );
00235 #endif
00236 #ifdef HAVE_QFILESYSTEMWATCHER
00237 delete fsWatcher;
00238 #endif
00239 }
00240
00241 void KDirWatchPrivate::inotifyEventReceived()
00242 {
00243
00244 #ifdef HAVE_SYS_INOTIFY_H
00245 if ( !supports_inotify )
00246 return;
00247
00248 int pending = -1;
00249 int offset = 0;
00250 char buf[4096];
00251 assert( m_inotify_fd > -1 );
00252 ioctl( m_inotify_fd, FIONREAD, &pending );
00253
00254 while ( pending > 0 ) {
00255
00256 if ( pending > (int)sizeof( buf ) )
00257 pending = sizeof( buf );
00258
00259 pending = read( m_inotify_fd, buf, pending);
00260
00261 while ( pending > 0 ) {
00262 struct inotify_event *event = (struct inotify_event *) &buf[offset];
00263 pending -= sizeof( struct inotify_event ) + event->len;
00264 offset += sizeof( struct inotify_event ) + event->len;
00265
00266 QString path;
00267 QByteArray cpath(event->name, event->len);
00268 if(event->len)
00269 path = QFile::decodeName ( cpath );
00270
00271 if ( path.length() && isNoisyFile( cpath ) )
00272 continue;
00273
00274
00275
00276
00277 for ( EntryMap::Iterator it = m_mapEntries.begin();
00278 it != m_mapEntries.end(); ) {
00279 Entry* e = &( *it );
00280 ++it;
00281 if ( e->wd == event->wd ) {
00282 e->dirty = true;
00283
00284 if( event->mask & IN_DELETE_SELF) {
00285 kDebug(7001) << "-->got deleteself signal for" << e->path;
00286 e->m_status = NonExistent;
00287 if (e->isDir)
00288 addEntry(0, QDir::cleanPath(e->path+"/.."), e, true);
00289 else
00290 addEntry(0, QFileInfo(e->path).absolutePath(), e, true);
00291 }
00292 if ( event->mask & IN_IGNORED ) {
00293 e->wd = 0;
00294 }
00295 if ( event->mask & (IN_CREATE|IN_MOVED_TO) ) {
00296 Entry* sub_entry = e->findSubEntry(e->path + '/' + path);
00297
00298 if (sub_entry ) {
00299 removeEntry(0, e, sub_entry);
00300
00301
00302
00303
00304
00305
00306
00307
00308
00309 if(!useINotify(sub_entry))
00310 useStat(sub_entry);
00311 sub_entry->dirty = true;
00312 }
00313 else if ((e->isDir) && (!e->m_clients.empty())) {
00314
00315 const QString tpath = e->path + QLatin1Char('/') + path;
00316 bool isDir = false;
00317 const QList<Client *> clients = e->clientsForFileOrDir(tpath, &isDir);
00318 Q_FOREACH(Client *client, clients) {
00319
00320
00321 if (isDir) {
00322 addEntry(client->instance, tpath, 0, isDir,
00323 isDir ? client->m_watchModes : KDirWatch::WatchDirOnly);
00324 }
00325 }
00326 if (!clients.isEmpty()) {
00327 emitEvent(e, Created, e->path+'/'+path);
00328 kDebug(7001).nospace() << clients.count() << " instance(s) monitoring the new "
00329 << (isDir ? "dir " : "file ") << tpath;
00330 }
00331 }
00332 }
00333 if (event->mask & (IN_DELETE|IN_MOVED_FROM)) {
00334 if ((e->isDir) && (!e->m_clients.empty())) {
00335 Client* client = 0;
00336
00337
00338
00339
00340 KDE_struct_stat stat_buf;
00341 QString tpath = e->path + QLatin1Char('/') + path;
00342
00343
00344 KDirWatch::WatchModes flag = KDirWatch::WatchSubDirs | KDirWatch::WatchFiles;
00345 if (KDE::stat(tpath, &stat_buf) == 0) {
00346 bool isDir = S_ISDIR(stat_buf.st_mode);
00347 flag = isDir ? KDirWatch::WatchSubDirs : KDirWatch::WatchFiles;
00348 }
00349 int counter = 0;
00350 Q_FOREACH(client, e->m_clients) {
00351 if (client->m_watchModes & flag) {
00352 counter++;
00353 }
00354 }
00355 if (counter != 0) {
00356 emitEvent (e, Deleted, e->path+'/'+path);
00357 }
00358 }
00359 }
00360 if (event->mask & (IN_MODIFY|IN_ATTRIB)) {
00361 if ((e->isDir) && (!e->m_clients.empty())) {
00362
00363
00364
00365
00366
00367
00368
00369
00370
00371
00372
00373
00374
00375
00376
00377 e->m_pendingFileChanges.append(e->path+'/'+path);
00378 }
00379 }
00380
00381 if (!rescan_timer.isActive())
00382 rescan_timer.start(m_PollInterval);
00383
00384 break;
00385 }
00386 }
00387 }
00388 }
00389 #endif
00390 }
00391
00392
00393
00394
00395
00396 void KDirWatchPrivate::Entry::propagate_dirty()
00397 {
00398 foreach(Entry *sub_entry, m_entries)
00399 {
00400 if (!sub_entry->dirty)
00401 {
00402 sub_entry->dirty = true;
00403 sub_entry->propagate_dirty();
00404 }
00405 }
00406 }
00407
00408
00409
00410
00411
00412 void KDirWatchPrivate::Entry::addClient(KDirWatch* instance,
00413 KDirWatch::WatchModes watchModes)
00414 {
00415 if (instance == 0)
00416 return;
00417
00418 foreach(Client* client, m_clients) {
00419 if (client->instance == instance) {
00420 client->count++;
00421 client->m_watchModes = watchModes;
00422 return;
00423 }
00424 }
00425
00426 Client* client = new Client;
00427 client->instance = instance;
00428 client->count = 1;
00429 client->watchingStopped = instance->isStopped();
00430 client->pending = NoChange;
00431 client->m_watchModes = watchModes;
00432
00433 m_clients.append(client);
00434 }
00435
00436 void KDirWatchPrivate::Entry::removeClient(KDirWatch* instance)
00437 {
00438 QList<Client *>::iterator it = m_clients.begin();
00439 const QList<Client *>::iterator end = m_clients.end();
00440 for ( ; it != end ; ++it ) {
00441 Client* client = *it;
00442 if (client->instance == instance) {
00443 client->count--;
00444 if (client->count == 0) {
00445 m_clients.erase(it);
00446 delete client;
00447 }
00448 return;
00449 }
00450 }
00451 }
00452
00453
00454 int KDirWatchPrivate::Entry::clients()
00455 {
00456 int clients = 0;
00457 foreach(Client* client, m_clients)
00458 clients += client->count;
00459
00460 return clients;
00461 }
00462
00463 QList<KDirWatchPrivate::Client *> KDirWatchPrivate::Entry::clientsForFileOrDir(const QString& tpath, bool* isDir) const
00464 {
00465 QList<Client *> ret;
00466 KDE_struct_stat stat_buf;
00467 if (KDE::stat(tpath, &stat_buf) == 0) {
00468 *isDir = S_ISDIR(stat_buf.st_mode);
00469 const KDirWatch::WatchModes flag =
00470 *isDir ? KDirWatch::WatchSubDirs : KDirWatch::WatchFiles;
00471 Q_FOREACH(Client *client, this->m_clients) {
00472 if (client->m_watchModes & flag) {
00473 ret.append(client);
00474 }
00475 }
00476 } else {
00477
00478
00479 }
00480
00481
00482 return ret;
00483 }
00484
00485 KDirWatchPrivate::Entry* KDirWatchPrivate::entry(const QString& _path)
00486 {
00487
00488 if (_path.isEmpty() || QDir::isRelativePath(_path)) {
00489 return 0;
00490 }
00491
00492 QString path (_path);
00493
00494 if ( path.length() > 1 && path.endsWith( QLatin1Char( '/' ) ) )
00495 path.truncate( path.length() - 1 );
00496
00497 EntryMap::Iterator it = m_mapEntries.find( path );
00498 if ( it == m_mapEntries.end() )
00499 return 0;
00500 else
00501 return &(*it);
00502 }
00503
00504
00505 void KDirWatchPrivate::useFreq(Entry* e, int newFreq)
00506 {
00507 e->freq = newFreq;
00508
00509
00510 if (e->freq < freq) {
00511 freq = e->freq;
00512 if (timer.isActive()) timer.start(freq);
00513 kDebug(7001) << "Global Poll Freq is now" << freq << "msec";
00514 }
00515 }
00516
00517
00518 #if defined(HAVE_FAM)
00519
00520 bool KDirWatchPrivate::useFAM(Entry* e)
00521 {
00522 if (!use_fam) return false;
00523
00524
00525
00526 famEventReceived();
00527
00528 e->m_mode = FAMMode;
00529 e->dirty = false;
00530
00531 if (e->isDir) {
00532 if (e->m_status == NonExistent) {
00533
00534 addEntry(0, QDir::cleanPath(e->path+"/.."), e, true);
00535 }
00536 else {
00537 int res =FAMMonitorDirectory(&fc, QFile::encodeName(e->path),
00538 &(e->fr), e);
00539 if (res<0) {
00540 e->m_mode = UnknownMode;
00541 use_fam=false;
00542 delete sn; sn = 0;
00543 return false;
00544 }
00545 kDebug(7001).nospace() << " Setup FAM (Req " << FAMREQUEST_GETREQNUM(&(e->fr))
00546 << ") for " << e->path;
00547 }
00548 }
00549 else {
00550 if (e->m_status == NonExistent) {
00551
00552 addEntry(0, QFileInfo(e->path).absolutePath(), e, true);
00553 }
00554 else {
00555 int res = FAMMonitorFile(&fc, QFile::encodeName(e->path),
00556 &(e->fr), e);
00557 if (res<0) {
00558 e->m_mode = UnknownMode;
00559 use_fam=false;
00560 delete sn; sn = 0;
00561 return false;
00562 }
00563
00564 kDebug(7001).nospace() << " Setup FAM (Req " << FAMREQUEST_GETREQNUM(&(e->fr))
00565 << ") for " << e->path;
00566 }
00567 }
00568
00569
00570
00571 famEventReceived();
00572
00573 return true;
00574 }
00575 #endif
00576
00577 #ifdef HAVE_SYS_INOTIFY_H
00578
00579 bool KDirWatchPrivate::useINotify( Entry* e )
00580 {
00581
00582
00583 e->wd = 0;
00584 e->dirty = false;
00585
00586 if (!supports_inotify) return false;
00587
00588 e->m_mode = INotifyMode;
00589
00590 if ( e->m_status == NonExistent ) {
00591 addEntry(0, QDir::cleanPath(e->path+"/.."), e, true);
00592 return true;
00593 }
00594
00595
00596 int mask = IN_DELETE|IN_DELETE_SELF|IN_CREATE|IN_MOVE|IN_MOVE_SELF|IN_DONT_FOLLOW|IN_MOVED_FROM|IN_MODIFY|IN_ATTRIB;
00597
00598 if ( ( e->wd = inotify_add_watch( m_inotify_fd,
00599 QFile::encodeName( e->path ), mask) ) > 0)
00600 {
00601
00602 return true;
00603 }
00604
00605 return false;
00606 }
00607 #endif
00608 #ifdef HAVE_QFILESYSTEMWATCHER
00609 bool KDirWatchPrivate::useQFSWatch(Entry* e)
00610 {
00611 e->m_mode = QFSWatchMode;
00612 e->dirty = false;
00613
00614 if ( e->m_status == NonExistent ) {
00615 addEntry( 0, QDir::cleanPath( e->path + "/.." ), e, true );
00616 return true;
00617 }
00618
00619 fsWatcher->addPath( e->path );
00620 return true;
00621 }
00622 #endif
00623
00624 bool KDirWatchPrivate::useStat(Entry* e)
00625 {
00626 KMountPoint::Ptr mp = KMountPoint::currentMountPoints().findByPath(e->path);
00627 const bool slow = mp ? mp->probablySlow() : false;
00628 if (slow)
00629 useFreq(e, m_nfsPollInterval);
00630 else
00631 useFreq(e, m_PollInterval);
00632
00633 if (e->m_mode != StatMode) {
00634 e->m_mode = StatMode;
00635 statEntries++;
00636
00637 if ( statEntries == 1 ) {
00638
00639 timer.start(freq);
00640 kDebug(7001) << " Started Polling Timer, freq " << freq;
00641 }
00642 }
00643
00644 kDebug(7001) << " Setup Stat (freq " << e->freq << ") for " << e->path;
00645
00646 return true;
00647 }
00648
00649
00650
00651
00652
00653
00654
00655 void KDirWatchPrivate::addEntry(KDirWatch* instance, const QString& _path,
00656 Entry* sub_entry, bool isDir, KDirWatch::WatchModes watchModes)
00657 {
00658 QString path (_path);
00659 if (path.isEmpty()
00660 #ifndef Q_WS_WIN
00661 || path.startsWith("/dev/") || (path == "/dev")
00662 #endif
00663 )
00664 return;
00665
00666 if ( path.length() > 1 && path.endsWith( QLatin1Char( '/' ) ) )
00667 path.truncate( path.length() - 1 );
00668
00669 EntryMap::Iterator it = m_mapEntries.find( path );
00670 if ( it != m_mapEntries.end() )
00671 {
00672 if (sub_entry) {
00673 (*it).m_entries.append(sub_entry);
00674 kDebug(7001) << "Added already watched Entry" << path
00675 << "(for" << sub_entry->path << ")";
00676 #ifdef HAVE_SYS_INOTIFY_H
00677 Entry* e = &(*it);
00678 if( (e->m_mode == INotifyMode) && (e->wd > 0) ) {
00679 int mask = IN_DELETE|IN_DELETE_SELF|IN_CREATE|IN_MOVE|IN_MOVE_SELF|IN_DONT_FOLLOW;
00680 if(!e->isDir)
00681 mask |= IN_MODIFY|IN_ATTRIB;
00682 else
00683 mask |= IN_ONLYDIR;
00684
00685 inotify_rm_watch (m_inotify_fd, e->wd);
00686 e->wd = inotify_add_watch( m_inotify_fd, QFile::encodeName( e->path ),
00687 mask);
00688 }
00689 #endif
00690 }
00691 else {
00692 (*it).addClient(instance, watchModes);
00693 kDebug(7001) << "Added already watched Entry" << path
00694 << "(now" << (*it).clients() << "clients)"
00695 << QString("[%1]").arg(instance->objectName());
00696 }
00697 return;
00698 }
00699
00700
00701
00702 KDE_struct_stat stat_buf;
00703 bool exists = (KDE::stat(path, &stat_buf) == 0);
00704
00705 EntryMap::iterator newIt = m_mapEntries.insert( path, Entry() );
00706
00707 Entry* e = &(*newIt);
00708
00709 if (exists) {
00710 e->isDir = S_ISDIR(stat_buf.st_mode);
00711
00712 if (e->isDir && !isDir) {
00713 KDE::lstat(path, &stat_buf);
00714 if (S_ISLNK(stat_buf.st_mode))
00715
00716 e->isDir = false;
00717 else
00718 qWarning() << "KDirWatch:" << path << "is a directory. Use addDir!";
00719 } else if (!e->isDir && isDir)
00720 qWarning("KDirWatch: %s is a file. Use addFile!", qPrintable(path));
00721
00722 if (!e->isDir && ( watchModes != KDirWatch::WatchDirOnly)) {
00723 qWarning() << "KDirWatch:" << path << "is a file. You can't use recursive or "
00724 "watchFiles options";
00725 watchModes = KDirWatch::WatchDirOnly;
00726 }
00727
00728 #ifdef Q_OS_WIN
00729
00730 e->m_ctime = stat_buf.st_mtime;
00731 #else
00732 e->m_ctime = stat_buf.st_ctime;
00733 #endif
00734 e->m_status = Normal;
00735 e->m_nlink = stat_buf.st_nlink;
00736 }
00737 else {
00738 e->isDir = isDir;
00739 e->m_ctime = invalid_ctime;
00740 e->m_status = NonExistent;
00741 e->m_nlink = 0;
00742 }
00743
00744 e->path = path;
00745 if (sub_entry)
00746 e->m_entries.append(sub_entry);
00747 else
00748 e->addClient(instance, watchModes);
00749
00750 kDebug(7001).nospace() << "Added " << (e->isDir ? "Dir " : "File ") << path
00751 << (e->m_status == NonExistent ? " NotExisting" : "")
00752 << " for " << (sub_entry ? sub_entry->path : "")
00753 << " [" << (instance ? instance->objectName() : "") << "]";
00754
00755
00756 e->m_mode = UnknownMode;
00757 e->msecLeft = 0;
00758
00759 if ( isNoisyFile( QFile::encodeName( path ) ) )
00760 return;
00761
00762 if (exists && e->isDir && (watchModes != KDirWatch::WatchDirOnly)) {
00763 QFlags<QDir::Filter> filters = QDir::NoDotAndDotDot;
00764
00765 if ((watchModes & KDirWatch::WatchSubDirs) &&
00766 (watchModes & KDirWatch::WatchFiles)) {
00767 filters |= (QDir::Dirs|QDir::Files);
00768 } else if (watchModes & KDirWatch::WatchSubDirs) {
00769 filters |= QDir::Dirs;
00770 } else if (watchModes & KDirWatch::WatchFiles) {
00771 filters |= QDir::Files;
00772 }
00773
00774 #if defined(HAVE_SYS_INOTIFY_H)
00775 if (e->m_mode == INotifyMode || (e->m_mode == UnknownMode && m_preferredMethod == INotify) )
00776 {
00777 kDebug (7001) << "Ignoring WatchFiles directive - this is implicit with inotify";
00778
00779
00780
00781 filters &= ~QDir::Files;
00782 }
00783 #endif
00784
00785 QDir basedir (e->path);
00786 const QFileInfoList contents = basedir.entryInfoList(filters);
00787 for (QFileInfoList::const_iterator iter = contents.constBegin();
00788 iter != contents.constEnd(); ++iter)
00789 {
00790 const QFileInfo &fileInfo = *iter;
00791
00792 bool isDir = fileInfo.isDir() && !fileInfo.isSymLink();
00793
00794 addEntry (instance, fileInfo.absoluteFilePath(), 0, isDir,
00795 isDir ? watchModes : KDirWatch::WatchDirOnly);
00796 }
00797 }
00798
00799
00800
00801
00802
00803
00804
00805
00806
00807 WatchMethod preferredMethod = m_preferredMethod;
00808 if (m_nfsPreferredMethod != m_preferredMethod) {
00809 KMountPoint::Ptr mountPoint = KMountPoint::currentMountPoints().findByPath(e->path);
00810 if (mountPoint && mountPoint->probablySlow()) {
00811 preferredMethod = m_nfsPreferredMethod;
00812 }
00813 }
00814
00815
00816 bool entryAdded = false;
00817 switch (preferredMethod) {
00818 #if defined(HAVE_FAM)
00819 case Fam: entryAdded = useFAM(e); break;
00820 #endif
00821 #if defined(HAVE_SYS_INOTIFY_H)
00822 case INotify: entryAdded = useINotify(e); break;
00823 #endif
00824 #if defined(HAVE_QFILESYSTEMWATCHER)
00825 case QFSWatch: entryAdded = useQFSWatch(e); break;
00826 #endif
00827 case Stat: entryAdded = useStat(e); break;
00828 default: break;
00829 }
00830
00831
00832 if (!entryAdded) {
00833 #if defined(HAVE_SYS_INOTIFY_H)
00834 if (useINotify(e)) return;
00835 #endif
00836 #if defined(HAVE_FAM)
00837 if (useFAM(e)) return;
00838 #endif
00839 #if defined(HAVE_QFILESYSTEMWATCHER)
00840 if (useQFSWatch(e)) return;
00841 #endif
00842 useStat(e);
00843 }
00844 }
00845
00846
00847 void KDirWatchPrivate::removeEntry(KDirWatch* instance,
00848 const QString& _path,
00849 Entry* sub_entry)
00850 {
00851
00852 Entry* e = entry(_path);
00853 if (!e) {
00854 kWarning(7001) << "doesn't know" << _path;
00855 return;
00856 }
00857
00858 removeEntry(instance, e, sub_entry);
00859 }
00860
00861 void KDirWatchPrivate::removeEntry(KDirWatch* instance,
00862 Entry* e,
00863 Entry* sub_entry)
00864 {
00865 removeList.remove(e);
00866
00867 if (sub_entry)
00868 e->m_entries.removeAll(sub_entry);
00869 else
00870 e->removeClient(instance);
00871
00872 if (e->m_clients.count() || e->m_entries.count())
00873 return;
00874
00875 if (delayRemove) {
00876 removeList.insert(e);
00877
00878 return;
00879 }
00880
00881 #ifdef HAVE_FAM
00882 if (e->m_mode == FAMMode) {
00883 if ( e->m_status == Normal) {
00884 FAMCancelMonitor(&fc, &(e->fr) );
00885 kDebug(7001).nospace() << "Cancelled FAM (Req " << FAMREQUEST_GETREQNUM(&(e->fr))
00886 << ") for " << e->path;
00887 }
00888 else {
00889 if (e->isDir)
00890 removeEntry(0, QDir::cleanPath(e->path+"/.."), e);
00891 else
00892 removeEntry(0, QFileInfo(e->path).absolutePath(), e);
00893 }
00894 }
00895 #endif
00896
00897 #ifdef HAVE_SYS_INOTIFY_H
00898 if (e->m_mode == INotifyMode) {
00899 if ( e->m_status == Normal ) {
00900 (void) inotify_rm_watch( m_inotify_fd, e->wd );
00901 kDebug(7001).nospace() << "Cancelled INotify (fd " << m_inotify_fd << ", "
00902 << e->wd << ") for " << e->path;
00903 }
00904 else {
00905 if (e->isDir)
00906 removeEntry(0, QDir::cleanPath(e->path+"/.."), e);
00907 else
00908 removeEntry(0, QFileInfo(e->path).absolutePath(), e);
00909 }
00910 }
00911 #endif
00912
00913 #ifdef HAVE_QFILESYSTEMWATCHER
00914 if (e->m_mode == QFSWatchMode) {
00915 fsWatcher->removePath(e->path);
00916 }
00917 #endif
00918 if (e->m_mode == StatMode) {
00919 statEntries--;
00920 if ( statEntries == 0 ) {
00921 timer.stop();
00922 kDebug(7001) << " Stopped Polling Timer";
00923 }
00924 }
00925
00926
00927
00928
00929 m_mapEntries.remove( e->path );
00930 }
00931
00932
00933
00934
00935
00936 void KDirWatchPrivate::removeEntries( KDirWatch* instance )
00937 {
00938 int minfreq = 3600000;
00939
00940 QStringList pathList;
00941
00942 EntryMap::Iterator it = m_mapEntries.begin();
00943 for( ; it != m_mapEntries.end(); ++it ) {
00944 Client* c = 0;
00945 foreach(Client* client, (*it).m_clients) {
00946 if (client->instance == instance) {
00947 c = client;
00948 break;
00949 }
00950 }
00951 if (c) {
00952 c->count = 1;
00953 pathList.append((*it).path);
00954 }
00955 else if ( (*it).m_mode == StatMode && (*it).freq < minfreq )
00956 minfreq = (*it).freq;
00957 }
00958
00959 foreach(const QString &path, pathList)
00960 removeEntry(instance, path, 0);
00961
00962 if (minfreq > freq) {
00963
00964 freq = minfreq;
00965 if (timer.isActive()) timer.start(freq);
00966 kDebug(7001) << "Poll Freq now" << freq << "msec";
00967 }
00968 }
00969
00970
00971 bool KDirWatchPrivate::stopEntryScan( KDirWatch* instance, Entry* e)
00972 {
00973 int stillWatching = 0;
00974 foreach(Client* client, e->m_clients) {
00975 if (!instance || instance == client->instance)
00976 client->watchingStopped = true;
00977 else if (!client->watchingStopped)
00978 stillWatching += client->count;
00979 }
00980
00981 kDebug(7001) << (instance ? instance->objectName() : "all")
00982 << "stopped scanning" << e->path << "(now"
00983 << stillWatching << "watchers)";
00984
00985 if (stillWatching == 0) {
00986
00987 if ( e->m_mode != INotifyMode ) {
00988 e->m_ctime = invalid_ctime;
00989 e->m_status = NonExistent;
00990 }
00991
00992 }
00993 return true;
00994 }
00995
00996
00997 bool KDirWatchPrivate::restartEntryScan( KDirWatch* instance, Entry* e,
00998 bool notify)
00999 {
01000 int wasWatching = 0, newWatching = 0;
01001 foreach(Client* client, e->m_clients) {
01002 if (!client->watchingStopped)
01003 wasWatching += client->count;
01004 else if (!instance || instance == client->instance) {
01005 client->watchingStopped = false;
01006 newWatching += client->count;
01007 }
01008 }
01009 if (newWatching == 0)
01010 return false;
01011
01012 kDebug(7001) << (instance ? instance->objectName() : "all")
01013 << "restarted scanning" << e->path
01014 << "(now" << wasWatching+newWatching << "watchers)";
01015
01016
01017
01018 int ev = NoChange;
01019 if (wasWatching == 0) {
01020 if (!notify) {
01021 KDE_struct_stat stat_buf;
01022 bool exists = (KDE::stat(e->path, &stat_buf) == 0);
01023 if (exists) {
01024 #ifdef Q_OS_WIN
01025
01026 e->m_ctime = stat_buf.st_mtime;
01027 #else
01028 e->m_ctime = stat_buf.st_ctime;
01029 #endif
01030 e->m_status = Normal;
01031 e->m_nlink = stat_buf.st_nlink;
01032 }
01033 else {
01034 e->m_ctime = invalid_ctime;
01035 e->m_status = NonExistent;
01036 e->m_nlink = 0;
01037 }
01038 }
01039 e->msecLeft = 0;
01040 ev = scanEntry(e);
01041 }
01042 emitEvent(e,ev);
01043
01044 return true;
01045 }
01046
01047
01048 void KDirWatchPrivate::stopScan(KDirWatch* instance)
01049 {
01050 EntryMap::Iterator it = m_mapEntries.begin();
01051 for( ; it != m_mapEntries.end(); ++it )
01052 stopEntryScan(instance, &(*it));
01053 }
01054
01055
01056 void KDirWatchPrivate::startScan(KDirWatch* instance,
01057 bool notify, bool skippedToo )
01058 {
01059 if (!notify)
01060 resetList(instance,skippedToo);
01061
01062 EntryMap::Iterator it = m_mapEntries.begin();
01063 for( ; it != m_mapEntries.end(); ++it )
01064 restartEntryScan(instance, &(*it), notify);
01065
01066
01067 }
01068
01069
01070
01071 void KDirWatchPrivate::resetList( KDirWatch* , bool skippedToo )
01072 {
01073 EntryMap::Iterator it = m_mapEntries.begin();
01074 for( ; it != m_mapEntries.end(); ++it ) {
01075
01076 foreach(Client* client, (*it).m_clients) {
01077 if (!client->watchingStopped || skippedToo)
01078 client->pending = NoChange;
01079 }
01080 }
01081 }
01082
01083
01084
01085 int KDirWatchPrivate::scanEntry(Entry* e)
01086 {
01087 #ifdef HAVE_FAM
01088 if (e->m_mode == FAMMode) {
01089
01090 if(!e->dirty) return NoChange;
01091 e->dirty = false;
01092 }
01093 #endif
01094
01095
01096 if (e->m_mode == UnknownMode) return NoChange;
01097
01098 #if defined( HAVE_SYS_INOTIFY_H )
01099 if (e->m_mode == DNotifyMode || e->m_mode == INotifyMode ) {
01100
01101 if(!e->dirty) return NoChange;
01102 e->dirty = false;
01103 }
01104 #endif
01105
01106 #if defined( HAVE_QFILESYSTEMWATCHER )
01107 if (e->m_mode == QFSWatchMode ) {
01108
01109 if(!e->dirty) return NoChange;
01110 e->dirty = false;
01111 }
01112 #endif
01113
01114 if (e->m_mode == StatMode) {
01115
01116
01117
01118
01119 e->msecLeft -= freq;
01120 if (e->msecLeft>0) return NoChange;
01121 e->msecLeft += e->freq;
01122 }
01123
01124 KDE_struct_stat stat_buf;
01125 bool exists = (KDE::stat(e->path, &stat_buf) == 0);
01126 if (exists) {
01127
01128 if (e->m_status == NonExistent) {
01129 #ifdef Q_OS_WIN
01130
01131 e->m_ctime = stat_buf.st_mtime;
01132 #else
01133 e->m_ctime = stat_buf.st_ctime;
01134 #endif
01135 e->m_status = Normal;
01136 e->m_nlink = stat_buf.st_nlink;
01137 return Created;
01138 }
01139
01140 #ifdef Q_OS_WIN
01141 stat_buf.st_ctime = stat_buf.st_mtime;
01142 #endif
01143 if ( (e->m_ctime != invalid_ctime) &&
01144 ((stat_buf.st_ctime != e->m_ctime) ||
01145 (stat_buf.st_nlink != (nlink_t) e->m_nlink))
01146 #if defined( HAVE_QFILESYSTEMWATCHER )
01147
01148
01149
01150 ||(e->m_mode == QFSWatchMode )
01151 #endif
01152 ) {
01153 e->m_ctime = stat_buf.st_ctime;
01154 e->m_nlink = stat_buf.st_nlink;
01155 return Changed;
01156 }
01157
01158 return NoChange;
01159 }
01160
01161
01162
01163 if (e->m_ctime == invalid_ctime) {
01164 e->m_nlink = 0;
01165 e->m_status = NonExistent;
01166 return NoChange;
01167 }
01168
01169 e->m_ctime = invalid_ctime;
01170 e->m_nlink = 0;
01171 e->m_status = NonExistent;
01172
01173 return Deleted;
01174 }
01175
01176
01177
01178
01179
01180 void KDirWatchPrivate::emitEvent(const Entry* e, int event, const QString &fileName)
01181 {
01182 QString path (e->path);
01183 if (!fileName.isEmpty()) {
01184 if (!QDir::isRelativePath(fileName))
01185 path = fileName;
01186 else
01187 #ifdef Q_OS_UNIX
01188 path += '/' + fileName;
01189 #elif defined(Q_WS_WIN)
01190
01191 path += QDir::currentPath().left(2) + '/' + fileName;
01192 #endif
01193 }
01194
01195 foreach(Client* c, e->m_clients)
01196 {
01197 if (c->instance==0 || c->count==0) continue;
01198
01199 if (c->watchingStopped) {
01200
01201 if (event == Changed)
01202 c->pending |= event;
01203 else if (event == Created || event == Deleted)
01204 c->pending = event;
01205 continue;
01206 }
01207
01208 if (event == NoChange || event == Changed)
01209 event |= c->pending;
01210 c->pending = NoChange;
01211 if (event == NoChange) continue;
01212
01213 if (event & Deleted) {
01214 c->instance->setDeleted(path);
01215
01216 continue;
01217 }
01218
01219 if (event & Created) {
01220 c->instance->setCreated(path);
01221
01222 }
01223
01224 if (event & Changed)
01225 c->instance->setDirty(path);
01226 }
01227 }
01228
01229
01230 void KDirWatchPrivate::slotRemoveDelayed()
01231 {
01232 delayRemove = false;
01233
01234
01235
01236 while (!removeList.isEmpty()) {
01237 Entry* entry = *removeList.begin();
01238 removeEntry(0, entry, 0);
01239 }
01240 }
01241
01242
01243
01244
01245 void KDirWatchPrivate::slotRescan()
01246 {
01247 EntryMap::Iterator it;
01248
01249
01250
01251
01252 bool timerRunning = timer.isActive();
01253 if ( timerRunning )
01254 timer.stop();
01255
01256
01257
01258 delayRemove = true;
01259
01260 if (rescan_all)
01261 {
01262
01263 it = m_mapEntries.begin();
01264 for( ; it != m_mapEntries.end(); ++it )
01265 (*it).dirty = true;
01266 rescan_all = false;
01267 }
01268 else
01269 {
01270
01271 it = m_mapEntries.begin();
01272 for( ; it != m_mapEntries.end(); ++it )
01273 if (((*it).m_mode == INotifyMode || (*it).m_mode == DNotifyMode) && (*it).dirty )
01274 (*it).propagate_dirty();
01275 }
01276
01277 #ifdef HAVE_SYS_INOTIFY_H
01278 QList<Entry*> dList, cList;
01279 #endif
01280
01281 it = m_mapEntries.begin();
01282 for( ; it != m_mapEntries.end(); ++it ) {
01283
01284 if (!(*it).isValid()) continue;
01285
01286 int ev = scanEntry( &(*it) );
01287
01288 #ifdef HAVE_SYS_INOTIFY_H
01289 if ((*it).m_mode == INotifyMode) {
01290 if ( ev == Deleted ) {
01291 addEntry(0, QDir::cleanPath( ( *it ).path+"/.."), &*it, true);
01292 }
01293 }
01294 if ((*it).m_mode == INotifyMode && ev == Created && (*it).wd == 0) {
01295 cList.append( &(*it) );
01296 if (! useINotify( &(*it) )) {
01297 useStat( &(*it) );
01298 }
01299 }
01300
01301 if ((*it).isDir)
01302 {
01303
01304
01305
01306
01307 QList<QString> pendingFileChanges = (*it).m_pendingFileChanges.toSet().toList();
01308 Q_FOREACH(QString changedFilename, pendingFileChanges )
01309 {
01310 emitEvent(&(*it), Changed, changedFilename);
01311 }
01312 (*it).m_pendingFileChanges.clear();
01313 }
01314 #endif
01315
01316 if ( ev != NoChange )
01317 emitEvent( &(*it), ev);
01318 }
01319
01320 if ( timerRunning )
01321 timer.start(freq);
01322
01323 #ifdef HAVE_SYS_INOTIFY_H
01324
01325 Q_FOREACH(Entry* e, cList)
01326 removeEntry(0, QDir::cleanPath( e->path+"/.."), e);
01327 #endif
01328
01329 QTimer::singleShot(0, this, SLOT(slotRemoveDelayed()));
01330 }
01331
01332 bool KDirWatchPrivate::isNoisyFile( const char * filename )
01333 {
01334
01335 if ( *filename == '.') {
01336 if (strncmp(filename, ".X.err", 6) == 0) return true;
01337 if (strncmp(filename, ".xsession-errors", 16) == 0) return true;
01338
01339
01340 if (strncmp(filename, ".fonts.cache", 12) == 0) return true;
01341 }
01342
01343 return false;
01344 }
01345
01346 #ifdef HAVE_FAM
01347 void KDirWatchPrivate::famEventReceived()
01348 {
01349 static FAMEvent fe;
01350
01351 delayRemove = true;
01352
01353
01354
01355 while(use_fam && FAMPending(&fc)) {
01356 if (FAMNextEvent(&fc, &fe) == -1) {
01357 kWarning(7001) << "FAM connection problem, switching to polling.";
01358 use_fam = false;
01359 delete sn; sn = 0;
01360
01361
01362 EntryMap::Iterator it;
01363 it = m_mapEntries.begin();
01364 for( ; it != m_mapEntries.end(); ++it )
01365 if ((*it).m_mode == FAMMode && (*it).m_clients.count()>0) {
01366 #ifdef HAVE_SYS_INOTIFY_H
01367 if (useINotify( &(*it) )) continue;
01368 #endif
01369 useStat( &(*it) );
01370 }
01371 }
01372 else
01373 checkFAMEvent(&fe);
01374 }
01375
01376 QTimer::singleShot(0, this, SLOT(slotRemoveDelayed()));
01377 }
01378
01379 void KDirWatchPrivate::checkFAMEvent(FAMEvent* fe)
01380 {
01381
01382
01383
01384 if ((fe->code == FAMExists) ||
01385 (fe->code == FAMEndExist) ||
01386 (fe->code == FAMAcknowledge)) return;
01387
01388 if ( isNoisyFile( fe->filename ) )
01389 return;
01390
01391 Entry* e = 0;
01392 EntryMap::Iterator it = m_mapEntries.begin();
01393 for( ; it != m_mapEntries.end(); ++it )
01394 if (FAMREQUEST_GETREQNUM(&( (*it).fr )) ==
01395 FAMREQUEST_GETREQNUM(&(fe->fr)) ) {
01396 e = &(*it);
01397 break;
01398 }
01399
01400
01401
01402 #if 0 // #88538
01403 kDebug(7001) << "Processing FAM event ("
01404 << ((fe->code == FAMChanged) ? "FAMChanged" :
01405 (fe->code == FAMDeleted) ? "FAMDeleted" :
01406 (fe->code == FAMStartExecuting) ? "FAMStartExecuting" :
01407 (fe->code == FAMStopExecuting) ? "FAMStopExecuting" :
01408 (fe->code == FAMCreated) ? "FAMCreated" :
01409 (fe->code == FAMMoved) ? "FAMMoved" :
01410 (fe->code == FAMAcknowledge) ? "FAMAcknowledge" :
01411 (fe->code == FAMExists) ? "FAMExists" :
01412 (fe->code == FAMEndExist) ? "FAMEndExist" : "Unknown Code")
01413 << ", " << fe->filename
01414 << ", Req " << FAMREQUEST_GETREQNUM(&(fe->fr)) << ")";
01415 #endif
01416
01417 if (!e) {
01418
01419
01420 return;
01421 }
01422
01423 if (e->m_status == NonExistent) {
01424 kDebug(7001) << "FAM event for nonExistent entry " << e->path;
01425 return;
01426 }
01427
01428
01429 e->dirty = true;
01430 if (!rescan_timer.isActive())
01431 rescan_timer.start(m_PollInterval);
01432
01433
01434 if (e->isDir)
01435 switch (fe->code)
01436 {
01437 case FAMDeleted:
01438
01439 if (!QDir::isRelativePath(fe->filename))
01440 {
01441
01442
01443 e->m_status = NonExistent;
01444 FAMCancelMonitor(&fc, &(e->fr) );
01445 kDebug(7001) << "Cancelled FAMReq"
01446 << FAMREQUEST_GETREQNUM(&(e->fr))
01447 << "for" << e->path;
01448
01449 addEntry(0, QDir::cleanPath( e->path+"/.."), e, true);
01450 }
01451 break;
01452
01453 case FAMCreated: {
01454
01455 QString tpath(e->path + QLatin1Char('/') + fe->filename);
01456
01457 Entry* sub_entry = e->findSubEntry(tpath);
01458 if (sub_entry && sub_entry->isDir) {
01459 removeEntry(0, e, sub_entry);
01460 sub_entry->m_status = Normal;
01461 if (!useFAM(sub_entry)) {
01462 #ifdef HAVE_SYS_INOTIFY_H
01463 if (!useINotify(sub_entry ))
01464 #endif
01465 useStat(sub_entry);
01466 }
01467 }
01468 else if ((sub_entry == 0) && (!e->m_clients.empty())) {
01469 bool isDir = false;
01470 const QList<Client *> clients = e->clientsForFileOrDir(tpath, &isDir);
01471 Q_FOREACH(Client *client, clients) {
01472 addEntry (client->instance, tpath, 0, isDir,
01473 isDir ? client->m_watchModes : KDirWatch::WatchDirOnly);
01474 }
01475
01476 if (!clients.isEmpty()) {
01477 emitEvent(e, Created, tpath);
01478
01479 QString msg (QString::number(clients.count()));
01480 msg += " instance/s monitoring the new ";
01481 msg += (isDir ? "dir " : "file ") + tpath;
01482 kDebug(7001) << msg;
01483 }
01484 }
01485 }
01486 break;
01487 default:
01488 break;
01489 }
01490 }
01491 #else
01492 void KDirWatchPrivate::famEventReceived()
01493 {
01494 kWarning (7001) << "Fam event received but FAM is not supported";
01495 }
01496 #endif
01497
01498
01499 void KDirWatchPrivate::statistics()
01500 {
01501 EntryMap::Iterator it;
01502
01503 kDebug(7001) << "Entries watched:";
01504 if (m_mapEntries.count()==0) {
01505 kDebug(7001) << " None.";
01506 }
01507 else {
01508 it = m_mapEntries.begin();
01509 for( ; it != m_mapEntries.end(); ++it ) {
01510 Entry* e = &(*it);
01511 kDebug(7001) << " " << e->path << " ("
01512 << ((e->m_status==Normal)?"":"Nonexistent ")
01513 << (e->isDir ? "Dir":"File") << ", using "
01514 << ((e->m_mode == FAMMode) ? "FAM" :
01515 (e->m_mode == INotifyMode) ? "INotify" :
01516 (e->m_mode == DNotifyMode) ? "DNotify" :
01517 (e->m_mode == QFSWatchMode) ? "QFSWatch" :
01518 (e->m_mode == StatMode) ? "Stat" : "Unknown Method")
01519 << ")";
01520
01521 foreach(Client* c, e->m_clients) {
01522 QString pending;
01523 if (c->watchingStopped) {
01524 if (c->pending & Deleted) pending += "deleted ";
01525 if (c->pending & Created) pending += "created ";
01526 if (c->pending & Changed) pending += "changed ";
01527 if (!pending.isEmpty()) pending = " (pending: " + pending + ')';
01528 pending = ", stopped" + pending;
01529 }
01530 kDebug(7001) << " by " << c->instance->objectName()
01531 << " (" << c->count << " times)" << pending;
01532 }
01533 if (e->m_entries.count()>0) {
01534 kDebug(7001) << " dependent entries:";
01535 foreach(Entry *d, e->m_entries) {
01536 kDebug(7001) << " " << d->path;
01537 }
01538 }
01539 }
01540 }
01541 }
01542
01543 #ifdef HAVE_QFILESYSTEMWATCHER
01544
01545 void KDirWatchPrivate::fswEventReceived(const QString &path)
01546 {
01547 EntryMap::Iterator it;
01548 it = m_mapEntries.find(path);
01549 if(it != m_mapEntries.end()) {
01550 Entry entry = *it;
01551 Entry *e = &entry;
01552 e->dirty = true;
01553 int ev = scanEntry(e);
01554 if (ev != NoChange)
01555 emitEvent(e, ev);
01556 if(ev == Deleted) {
01557 if (e->isDir)
01558 addEntry(0, QDir::cleanPath(e->path + "/.."), e, true);
01559 else
01560 addEntry(0, QFileInfo(e->path).absolutePath(), e, true);
01561 } else
01562 if (ev == Changed && e->isDir && e->m_entries.count()) {
01563 Entry* sub_entry = 0;
01564 Q_FOREACH(sub_entry, e->m_entries) {
01565 if(e->isDir) {
01566 if (QFileInfo(sub_entry->path).isDir())
01567 break;
01568 } else {
01569 if (QFileInfo(sub_entry->path).isFile())
01570 break;
01571 }
01572 }
01573 if (sub_entry) {
01574 removeEntry(0, e, sub_entry);
01575
01576
01577
01578
01579 if(!useQFSWatch(sub_entry))
01580 #ifdef HAVE_SYS_INOTIFY_H
01581 if(!useINotify(sub_entry))
01582 #endif
01583 useStat(sub_entry);
01584 fswEventReceived(sub_entry->path);
01585 }
01586 }
01587 }
01588 }
01589 #else
01590 void KDirWatchPrivate::fswEventReceived(const QString &path)
01591 {
01592 Q_UNUSED(path);
01593 kWarning (7001) << "QFileSystemWatcher event received but QFileSystemWatcher is not supported";
01594 }
01595 #endif // HAVE_QFILESYSTEMWATCHER
01596
01597
01598
01599
01600
01601 K_GLOBAL_STATIC(KDirWatch, s_pKDirWatchSelf)
01602 KDirWatch* KDirWatch::self()
01603 {
01604 return s_pKDirWatchSelf;
01605 }
01606
01607 bool KDirWatch::exists()
01608 {
01609 return s_pKDirWatchSelf != 0;
01610 }
01611
01612 KDirWatch::KDirWatch (QObject* parent)
01613 : QObject(parent), d(createPrivate())
01614 {
01615 static int nameCounter = 0;
01616
01617 nameCounter++;
01618 setObjectName(QString("KDirWatch-%1").arg(nameCounter) );
01619
01620 d->ref();
01621
01622 d->_isStopped = false;
01623 }
01624
01625 KDirWatch::~KDirWatch()
01626 {
01627 d->removeEntries(this);
01628 if ( d->deref() )
01629 {
01630
01631 delete d;
01632 dwp_self = 0;
01633 }
01634 }
01635
01636 void KDirWatch::addDir( const QString& _path, WatchModes watchModes)
01637 {
01638 if (d) d->addEntry(this, _path, 0, true, watchModes);
01639 }
01640
01641 void KDirWatch::addFile( const QString& _path )
01642 {
01643 if (d) d->addEntry(this, _path, 0, false);
01644 }
01645
01646 QDateTime KDirWatch::ctime( const QString &_path ) const
01647 {
01648 KDirWatchPrivate::Entry* e = d->entry(_path);
01649
01650 if (!e)
01651 return QDateTime();
01652
01653 QDateTime result;
01654 result.setTime_t(e->m_ctime);
01655 return result;
01656 }
01657
01658 void KDirWatch::removeDir( const QString& _path )
01659 {
01660 if (d) d->removeEntry(this, _path, 0);
01661 }
01662
01663 void KDirWatch::removeFile( const QString& _path )
01664 {
01665 if (d) d->removeEntry(this, _path, 0);
01666 }
01667
01668 bool KDirWatch::stopDirScan( const QString& _path )
01669 {
01670 if (d) {
01671 KDirWatchPrivate::Entry *e = d->entry(_path);
01672 if (e && e->isDir) return d->stopEntryScan(this, e);
01673 }
01674 return false;
01675 }
01676
01677 bool KDirWatch::restartDirScan( const QString& _path )
01678 {
01679 if (d) {
01680 KDirWatchPrivate::Entry *e = d->entry(_path);
01681 if (e && e->isDir)
01682
01683 return d->restartEntryScan(this, e, false);
01684 }
01685 return false;
01686 }
01687
01688 void KDirWatch::stopScan()
01689 {
01690 if (d) {
01691 d->stopScan(this);
01692 d->_isStopped = true;
01693 }
01694 }
01695
01696 bool KDirWatch::isStopped()
01697 {
01698 return d->_isStopped;
01699 }
01700
01701 void KDirWatch::startScan( bool notify, bool skippedToo )
01702 {
01703 if (d) {
01704 d->_isStopped = false;
01705 d->startScan(this, notify, skippedToo);
01706 }
01707 }
01708
01709
01710 bool KDirWatch::contains( const QString& _path ) const
01711 {
01712 KDirWatchPrivate::Entry* e = d->entry(_path);
01713 if (!e)
01714 return false;
01715
01716 foreach(KDirWatchPrivate::Client* client, e->m_clients) {
01717 if (client->instance == this)
01718 return true;
01719 }
01720
01721 return false;
01722 }
01723
01724 void KDirWatch::statistics()
01725 {
01726 if (!dwp_self) {
01727 kDebug(7001) << "KDirWatch not used";
01728 return;
01729 }
01730 dwp_self->statistics();
01731 }
01732
01733
01734 void KDirWatch::setCreated( const QString & _file )
01735 {
01736 kDebug(7001) << objectName() << "emitting created" << _file;
01737 emit created( _file );
01738 }
01739
01740 void KDirWatch::setDirty( const QString & _file )
01741 {
01742 kDebug(7001) << objectName() << "emitting dirty" << _file;
01743 emit dirty( _file );
01744 }
01745
01746 void KDirWatch::setDeleted( const QString & _file )
01747 {
01748 kDebug(7001) << objectName() << "emitting deleted" << _file;
01749 emit deleted( _file );
01750 }
01751
01752 KDirWatch::Method KDirWatch::internalMethod()
01753 {
01754 #ifdef HAVE_FAM
01755 if (d->use_fam)
01756 return KDirWatch::FAM;
01757 #endif
01758 #ifdef HAVE_SYS_INOTIFY_H
01759 if (d->supports_inotify)
01760 return KDirWatch::INotify;
01761 #endif
01762 return KDirWatch::Stat;
01763 }
01764
01765
01766 #include "kdirwatch.moc"
01767 #include "kdirwatch_p.moc"
01768
01769
01770
01771