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