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