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