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