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 QPtrListIterator<Client> cit( e->m_clients );
01224 for ( ; cit.current(); ++cit )
01225 {
01226 Client* c = cit.current();
01227
01228 if (c->instance==0 || c->count==0) continue;
01229
01230 if (c->watchingStopped) {
01231
01232 if (event == Changed)
01233 c->pending |= event;
01234 else if (event == Created || event == Deleted)
01235 c->pending = event;
01236 continue;
01237 }
01238
01239 if (event == NoChange || event == Changed)
01240 event |= c->pending;
01241 c->pending = NoChange;
01242 if (event == NoChange) continue;
01243
01244 if (event & Deleted) {
01245 c->instance->setDeleted(path);
01246
01247 continue;
01248 }
01249
01250 if (event & Created) {
01251 c->instance->setCreated(path);
01252
01253 }
01254
01255 if (event & Changed)
01256 c->instance->setDirty(path);
01257 }
01258 }
01259
01260
01261 void KDirWatchPrivate::slotRemoveDelayed()
01262 {
01263 Entry* e;
01264 delayRemove = false;
01265 for(e=removeList.first();e;e=removeList.next())
01266 removeEntry(0, e->path, 0);
01267 removeList.clear();
01268 }
01269
01270
01271
01272
01273 void KDirWatchPrivate::slotRescan()
01274 {
01275 EntryMap::Iterator it;
01276
01277
01278
01279
01280 bool timerRunning = timer->isActive();
01281 if ( timerRunning )
01282 timer->stop();
01283
01284
01285
01286 delayRemove = true;
01287
01288 #ifdef HAVE_DNOTIFY
01289 QPtrList<Entry> dList, cList;
01290 #endif
01291
01292 if (rescan_all)
01293 {
01294
01295 it = m_mapEntries.begin();
01296 for( ; it != m_mapEntries.end(); ++it )
01297 (*it).dirty = true;
01298 rescan_all = false;
01299 }
01300 else
01301 {
01302
01303 it = m_mapEntries.begin();
01304 for( ; it != m_mapEntries.end(); ++it )
01305 if (((*it).m_mode == INotifyMode || (*it).m_mode == DNotifyMode) && (*it).dirty )
01306 (*it).propagate_dirty();
01307 }
01308
01309 it = m_mapEntries.begin();
01310 for( ; it != m_mapEntries.end(); ++it ) {
01311
01312 if (!(*it).isValid()) continue;
01313
01314 int ev = scanEntry( &(*it) );
01315
01316 #ifdef HAVE_DNOTIFY
01317 if ((*it).m_mode == DNotifyMode) {
01318 if ((*it).isDir && (ev == Deleted)) {
01319 dList.append( &(*it) );
01320
01321
01322 if ((*it).dn_fd) {
01323 ::close((*it).dn_fd);
01324 fd_Entry.remove((*it).dn_fd);
01325 (*it).dn_fd = 0;
01326 }
01327 }
01328
01329 else if ((*it).isDir && (ev == Created)) {
01330
01331 if ( (*it).dn_fd == 0) {
01332 cList.append( &(*it) );
01333 if (! useDNotify( &(*it) )) {
01334
01335 useStat( &(*it) );
01336 }
01337 }
01338 }
01339 }
01340 #endif
01341
01342 if ( ev != NoChange )
01343 emitEvent( &(*it), ev);
01344 }
01345
01346
01347 #ifdef HAVE_DNOTIFY
01348
01349 Entry* e;
01350 for(e=dList.first();e;e=dList.next())
01351 addEntry(0, QDir::cleanDirPath( e->path+"/.."), e, true);
01352
01353
01354 for(e=cList.first();e;e=cList.next())
01355 removeEntry(0, QDir::cleanDirPath( e->path+"/.."), e);
01356 #endif
01357
01358 if ( timerRunning )
01359 timer->start(freq);
01360
01361 QTimer::singleShot(0, this, SLOT(slotRemoveDelayed()));
01362 }
01363
01364 bool KDirWatchPrivate::isNoisyFile( const char * filename )
01365 {
01366
01367 if ( *filename == '.') {
01368 if (strncmp(filename, ".X.err", 6) == 0) return true;
01369 if (strncmp(filename, ".xsession-errors", 16) == 0) return true;
01370
01371
01372 if (strncmp(filename, ".fonts.cache", 12) == 0) return true;
01373 }
01374
01375 return false;
01376 }
01377
01378 #ifdef HAVE_FAM
01379 void KDirWatchPrivate::famEventReceived()
01380 {
01381 static FAMEvent fe;
01382
01383 delayRemove = true;
01384
01385 while(use_fam && FAMPending(&fc)) {
01386 if (FAMNextEvent(&fc, &fe) == -1) {
01387 kdWarning(7001) << "FAM connection problem, switching to polling."
01388 << endl;
01389 use_fam = false;
01390 delete sn; sn = 0;
01391
01392
01393 EntryMap::Iterator it;
01394 it = m_mapEntries.begin();
01395 for( ; it != m_mapEntries.end(); ++it )
01396 if ((*it).m_mode == FAMMode && (*it).m_clients.count()>0) {
01397 #ifdef HAVE_INOTIFY
01398 if (useINotify( &(*it) )) continue;
01399 #endif
01400 #ifdef HAVE_DNOTIFY
01401 if (useDNotify( &(*it) )) continue;
01402 #endif
01403 useStat( &(*it) );
01404 }
01405 }
01406 else
01407 checkFAMEvent(&fe);
01408 }
01409
01410 QTimer::singleShot(0, this, SLOT(slotRemoveDelayed()));
01411 }
01412
01413 void KDirWatchPrivate::checkFAMEvent(FAMEvent* fe)
01414 {
01415
01416 if ((fe->code == FAMExists) ||
01417 (fe->code == FAMEndExist) ||
01418 (fe->code == FAMAcknowledge)) return;
01419
01420 if ( isNoisyFile( fe->filename ) )
01421 return;
01422
01423 Entry* e = 0;
01424 EntryMap::Iterator it = m_mapEntries.begin();
01425 for( ; it != m_mapEntries.end(); ++it )
01426 if (FAMREQUEST_GETREQNUM(&( (*it).fr )) ==
01427 FAMREQUEST_GETREQNUM(&(fe->fr)) ) {
01428 e = &(*it);
01429 break;
01430 }
01431
01432
01433
01434 #if 0 // #88538
01435 kdDebug(7001) << "Processing FAM event ("
01436 << ((fe->code == FAMChanged) ? "FAMChanged" :
01437 (fe->code == FAMDeleted) ? "FAMDeleted" :
01438 (fe->code == FAMStartExecuting) ? "FAMStartExecuting" :
01439 (fe->code == FAMStopExecuting) ? "FAMStopExecuting" :
01440 (fe->code == FAMCreated) ? "FAMCreated" :
01441 (fe->code == FAMMoved) ? "FAMMoved" :
01442 (fe->code == FAMAcknowledge) ? "FAMAcknowledge" :
01443 (fe->code == FAMExists) ? "FAMExists" :
01444 (fe->code == FAMEndExist) ? "FAMEndExist" : "Unknown Code")
01445 << ", " << fe->filename
01446 << ", Req " << FAMREQUEST_GETREQNUM(&(fe->fr))
01447 << ")" << endl;
01448 #endif
01449
01450 if (!e) {
01451
01452
01453 return;
01454 }
01455
01456 if (e->m_status == NonExistent) {
01457 kdDebug(7001) << "FAM event for nonExistent entry " << e->path << endl;
01458 return;
01459 }
01460
01461
01462 e->dirty = true;
01463 if (!rescan_timer.isActive())
01464 rescan_timer.start(m_PollInterval, true);
01465
01466
01467 if (e->isDir)
01468 switch (fe->code)
01469 {
01470 case FAMDeleted:
01471
01472 if (!QDir::isRelativePath(fe->filename))
01473 {
01474
01475
01476 e->m_status = NonExistent;
01477 FAMCancelMonitor(&fc, &(e->fr) );
01478 kdDebug(7001) << "Cancelled FAMReq "
01479 << FAMREQUEST_GETREQNUM(&(e->fr))
01480 << " for " << e->path << endl;
01481
01482 addEntry(0, QDir::cleanDirPath( e->path+"/.."), e, true);
01483 }
01484 break;
01485
01486 case FAMCreated: {
01487
01488 Entry *sub_entry = e->m_entries.first();
01489 for(;sub_entry; sub_entry = e->m_entries.next())
01490 if (sub_entry->path == e->path + "/" + fe->filename) break;
01491 if (sub_entry && sub_entry->isDir) {
01492 QString path = e->path;
01493 removeEntry(0,e->path,sub_entry);
01494 sub_entry->m_status = Normal;
01495 if (!useFAM(sub_entry))
01496 #ifdef HAVE_INOTIFY
01497 if (!useINotify(sub_entry ))
01498 #endif
01499 useStat(sub_entry);
01500 }
01501 break;
01502 }
01503
01504 default:
01505 break;
01506 }
01507 }
01508 #else
01509 void KDirWatchPrivate::famEventReceived() {}
01510 #endif
01511
01512
01513 void KDirWatchPrivate::statistics()
01514 {
01515 EntryMap::Iterator it;
01516
01517 kdDebug(7001) << "Entries watched:" << endl;
01518 if (m_mapEntries.count()==0) {
01519 kdDebug(7001) << " None." << endl;
01520 }
01521 else {
01522 it = m_mapEntries.begin();
01523 for( ; it != m_mapEntries.end(); ++it ) {
01524 Entry* e = &(*it);
01525 kdDebug(7001) << " " << e->path << " ("
01526 << ((e->m_status==Normal)?"":"Nonexistent ")
01527 << (e->isDir ? "Dir":"File") << ", using "
01528 << ((e->m_mode == FAMMode) ? "FAM" :
01529 (e->m_mode == INotifyMode) ? "INotify" :
01530 (e->m_mode == DNotifyMode) ? "DNotify" :
01531 (e->m_mode == StatMode) ? "Stat" : "Unknown Method")
01532 << ")" << endl;
01533
01534 Client* c = e->m_clients.first();
01535 for(;c; c = e->m_clients.next()) {
01536 QString pending;
01537 if (c->watchingStopped) {
01538 if (c->pending & Deleted) pending += "deleted ";
01539 if (c->pending & Created) pending += "created ";
01540 if (c->pending & Changed) pending += "changed ";
01541 if (!pending.isEmpty()) pending = " (pending: " + pending + ")";
01542 pending = ", stopped" + pending;
01543 }
01544 kdDebug(7001) << " by " << c->instance->name()
01545 << " (" << c->count << " times)"
01546 << pending << endl;
01547 }
01548 if (e->m_entries.count()>0) {
01549 kdDebug(7001) << " dependent entries:" << endl;
01550 Entry* d = e->m_entries.first();
01551 for(;d; d = e->m_entries.next()) {
01552 kdDebug(7001) << " " << d->path << endl;
01553 }
01554 }
01555 }
01556 }
01557 }
01558
01559
01560
01561
01562
01563
01564 static KStaticDeleter<KDirWatch> sd_dw;
01565 KDirWatch* KDirWatch::s_pSelf = 0L;
01566
01567 KDirWatch* KDirWatch::self()
01568 {
01569 if ( !s_pSelf ) {
01570 sd_dw.setObject( s_pSelf, new KDirWatch );
01571 }
01572
01573 return s_pSelf;
01574 }
01575
01576 bool KDirWatch::exists()
01577 {
01578 return s_pSelf != 0;
01579 }
01580
01581 KDirWatch::KDirWatch (QObject* parent, const char* name)
01582 : QObject(parent,name)
01583 {
01584 if (!name) {
01585 static int nameCounter = 0;
01586
01587 nameCounter++;
01588 setName(QString("KDirWatch-%1").arg(nameCounter).ascii());
01589 }
01590
01591 if (!dwp_self)
01592 dwp_self = new KDirWatchPrivate;
01593 d = dwp_self;
01594 d->ref();
01595
01596 _isStopped = false;
01597 }
01598
01599 KDirWatch::~KDirWatch()
01600 {
01601 if (d) d->removeEntries(this);
01602 if ( d->deref() )
01603 {
01604
01605 delete d;
01606 dwp_self = 0L;
01607 }
01608 }
01609
01610
01611
01612 void KDirWatch::addDir( const QString& _path,
01613 bool watchFiles, bool recursive)
01614 {
01615 if (watchFiles || recursive) {
01616 kdDebug(7001) << "addDir - recursive/watchFiles not supported yet in KDE 3.x" << endl;
01617 }
01618 if (d) d->addEntry(this, _path, 0, true);
01619 }
01620
01621 void KDirWatch::addFile( const QString& _path )
01622 {
01623 if (d) d->addEntry(this, _path, 0, false);
01624 }
01625
01626 QDateTime KDirWatch::ctime( const QString &_path )
01627 {
01628 KDirWatchPrivate::Entry* e = d->entry(_path);
01629
01630 if (!e)
01631 return QDateTime();
01632
01633 QDateTime result;
01634 result.setTime_t(e->m_ctime);
01635 return result;
01636 }
01637
01638 void KDirWatch::removeDir( const QString& _path )
01639 {
01640 if (d) d->removeEntry(this, _path, 0);
01641 }
01642
01643 void KDirWatch::removeFile( const QString& _path )
01644 {
01645 if (d) d->removeEntry(this, _path, 0);
01646 }
01647
01648 bool KDirWatch::stopDirScan( const QString& _path )
01649 {
01650 if (d) {
01651 KDirWatchPrivate::Entry *e = d->entry(_path);
01652 if (e && e->isDir) return d->stopEntryScan(this, e);
01653 }
01654 return false;
01655 }
01656
01657 bool KDirWatch::restartDirScan( const QString& _path )
01658 {
01659 if (d) {
01660 KDirWatchPrivate::Entry *e = d->entry(_path);
01661 if (e && e->isDir)
01662
01663 return d->restartEntryScan(this, e, false);
01664 }
01665 return false;
01666 }
01667
01668 void KDirWatch::stopScan()
01669 {
01670 if (d) d->stopScan(this);
01671 _isStopped = true;
01672 }
01673
01674 void KDirWatch::startScan( bool notify, bool skippedToo )
01675 {
01676 _isStopped = false;
01677 if (d) d->startScan(this, notify, skippedToo);
01678 }
01679
01680
01681 bool KDirWatch::contains( const QString& _path ) const
01682 {
01683 KDirWatchPrivate::Entry* e = d->entry(_path);
01684 if (!e)
01685 return false;
01686
01687 KDirWatchPrivate::Client* c = e->m_clients.first();
01688 for(;c;c=e->m_clients.next())
01689 if (c->instance == this) return true;
01690
01691 return false;
01692 }
01693
01694 void KDirWatch::statistics()
01695 {
01696 if (!dwp_self) {
01697 kdDebug(7001) << "KDirWatch not used" << endl;
01698 return;
01699 }
01700 dwp_self->statistics();
01701 }
01702
01703
01704 void KDirWatch::setCreated( const QString & _file )
01705 {
01706 kdDebug(7001) << name() << " emitting created " << _file << endl;
01707 emit created( _file );
01708 }
01709
01710 void KDirWatch::setDirty( const QString & _file )
01711 {
01712 kdDebug(7001) << name() << " emitting dirty " << _file << endl;
01713 emit dirty( _file );
01714 }
01715
01716 void KDirWatch::setDeleted( const QString & _file )
01717 {
01718 kdDebug(7001) << name() << " emitting deleted " << _file << endl;
01719 emit deleted( _file );
01720 }
01721
01722 KDirWatch::Method KDirWatch::internalMethod()
01723 {
01724 #ifdef HAVE_FAM
01725 if (d->use_fam)
01726 return KDirWatch::FAM;
01727 #endif
01728 #ifdef HAVE_INOTIFY
01729 if (d->supports_inotify)
01730 return KDirWatch::INotify;
01731 #endif
01732 #ifdef HAVE_DNOTIFY
01733 if (d->supports_dnotify)
01734 return KDirWatch::DNotify;
01735 #endif
01736 return KDirWatch::Stat;
01737 }
01738
01739
01740 #include "kdirwatch.moc"
01741 #include "kdirwatch_p.moc"
01742
01743
01744
01745