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