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