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