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