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