summaryrefslogtreecommitdiffabout
authorzautrix <zautrix>2004-08-08 12:30:41 (UTC)
committer zautrix <zautrix>2004-08-08 12:30:41 (UTC)
commit75138e84a2271f8929478853151a6ed4a73fb2cc (patch) (side-by-side diff)
tree804b3277bf2e4c4e371611677481803f527bf90e
parent4cc869512488b72304c7cbb5526c6f4cc957e677 (diff)
downloadkdepimpi-75138e84a2271f8929478853151a6ed4a73fb2cc.zip
kdepimpi-75138e84a2271f8929478853151a6ed4a73fb2cc.tar.gz
kdepimpi-75138e84a2271f8929478853151a6ed4a73fb2cc.tar.bz2
Fixed kdirwatch
Diffstat (more/less context) (show whitespace changes)
-rw-r--r--microkde/kio/kio/kdirwatch.cpp3
1 files changed, 2 insertions, 1 deletions
diff --git a/microkde/kio/kio/kdirwatch.cpp b/microkde/kio/kio/kdirwatch.cpp
index 98d24e0..1596d1f 100644
--- a/microkde/kio/kio/kdirwatch.cpp
+++ b/microkde/kio/kio/kdirwatch.cpp
@@ -406,385 +406,386 @@ bool KDirWatchPrivate::useFAM(Entry* e)
kdDebug(7001) << " Setup FAM (Req "
<< FAMREQUEST_GETREQNUM(&(e->fr))
<< ") for " << e->path << endl;
}
}
else {
if (e->m_status == NonExistent) {
// If the file does not exist we watch the directory
addEntry(0, QFileInfo(e->path).dirPath(true), e, true);
}
else {
int res = FAMMonitorFile(&fc, QFile::encodeName(e->path),
&(e->fr), e);
if (res<0) {
e->m_mode = UnknownMode;
use_fam=false;
return false;
}
kdDebug(7001) << " Setup FAM (Req "
<< FAMREQUEST_GETREQNUM(&(e->fr))
<< ") for " << e->path << endl;
}
}
// handle FAM events to avoid deadlock
// (FAM sends back all files in a directory when monitoring)
famEventReceived();
return true;
}
#endif
#ifdef HAVE_DNOTIFY
// setup DNotify notification, returns false if not possible
bool KDirWatchPrivate::useDNotify(Entry* e)
{
e->dn_fd = 0;
if (!supports_dnotify) return false;
e->m_mode = DNotifyMode;
if (e->isDir) {
e->dn_dirty = false;
if (e->m_status == Normal) {
int fd = open(QFile::encodeName(e->path).data(), O_RDONLY);
// Migrate fd to somewhere above 128. Some libraries have
// constructs like:
// fd = socket(...)
// if (fd > ARBITRARY_LIMIT)
// return error;
//
// Since programs might end up using a lot of KDirWatch objects
// for a rather long time the above braindamage could get
// triggered.
//
// By moving the kdirwatch fd's to > 128, calls like socket() will keep
// returning fd's < ARBITRARY_LIMIT for a bit longer.
int fd2 = fcntl(fd, F_DUPFD, 128);
if (fd2 >= 0)
{
close(fd);
fd = fd2;
}
if (fd<0) {
e->m_mode = UnknownMode;
return false;
}
int mask = DN_DELETE|DN_CREATE|DN_RENAME|DN_MULTISHOT;
// if dependant is a file watch, we check for MODIFY & ATTRIB too
for(Entry* dep=e->m_entries.first();dep;dep=e->m_entries.next())
if (!dep->isDir) { mask |= DN_MODIFY|DN_ATTRIB; break; }
if(fcntl(fd, F_SETSIG, dnotify_signal) < 0 ||
fcntl(fd, F_NOTIFY, mask) < 0) {
kdDebug(7001) << "Not using Linux Directory Notifications."
<< endl;
supports_dnotify = false;
::close(fd);
e->m_mode = UnknownMode;
return false;
}
fd_Entry.replace(fd, e);
e->dn_fd = fd;
kdDebug(7001) << " Setup DNotify (fd " << fd
<< ") for " << e->path << endl;
}
else { // NotExisting
addEntry(0, QDir::cleanDirPath(e->path+"/.."), e, true);
}
}
else { // File
// we always watch the directory (DNOTIFY can't watch files alone)
// this notifies us about changes of files therein
addEntry(0, QFileInfo(e->path).dirPath(true), e, true);
}
return true;
}
#endif
bool KDirWatchPrivate::useStat(Entry* e)
{
//US we have no KIO::probably_slow_mounted. So disable this part
//US if (KIO::probably_slow_mounted(e->path))
//US useFreq(e, m_nfsPollInterval);
//US else
useFreq(e, m_PollInterval);
if (e->m_mode != StatMode) {
e->m_mode = StatMode;
statEntries++;
if ( statEntries == 1 ) {
// if this was first STAT entry (=timer was stopped)
timer->start(freq); // then start the timer
kdDebug(7001) << " Started Polling Timer, freq " << freq << endl;
}
}
kdDebug(7001) << " Setup Stat (freq " << e->freq
<< ") for " << e->path << endl;
return true;
}
/* If <instance> !=0, this KDirWatch instance wants to watch at <_path>,
* providing in <isDir> the type of the entry to be watched.
* Sometimes, entries are dependant on each other: if <sub_entry> !=0,
* this entry needs another entry to watch himself (when notExistent).
*/
void KDirWatchPrivate::addEntry(KDirWatch* instance, const QString& _path,
Entry* sub_entry, bool isDir)
{
QString path = _path;
if (path.startsWith("/dev/") || (path == "/dev"))
return; // Don't even go there.
if ( path.length() > 1 && path.right(1) == "/" )
path.truncate( path.length() - 1 );
EntryMap::Iterator it = m_mapEntries.find( path );
if ( it != m_mapEntries.end() )
{
if (sub_entry) {
(*it).m_entries.append(sub_entry);
kdDebug(7001) << "Added already watched Entry " << path
<< " (for " << sub_entry->path << ")" << endl;
#ifdef HAVE_DNOTIFY
Entry* e = &(*it);
if( e->dn_fd > 0 ) {
int mask = DN_DELETE|DN_CREATE|DN_RENAME|DN_MULTISHOT;
// if dependant is a file watch, we check for MODIFY & ATTRIB too
for(Entry* dep=e->m_entries.first();dep;dep=e->m_entries.next())
if (!dep->isDir) { mask |= DN_MODIFY|DN_ATTRIB; break; }
if( fcntl(e->dn_fd, F_NOTIFY, mask) < 0) { // shouldn't happen
::close(e->dn_fd);
e->m_mode = UnknownMode;
fd_Entry.remove(e->dn_fd);
e->dn_fd = 0;
useStat( e );
}
}
#endif
}
else {
(*it).addClient(instance);
kdDebug(7001) << "Added already watched Entry " << path
<< " (now " << (*it).clients() << " clients)"
<< QString(" [%1]").arg(instance->name()) << endl;
}
return;
}
// we have a new path to watch
struct stat stat_buf;
bool exists = (stat(QFile::encodeName(path), &stat_buf) == 0);
Entry newEntry;
m_mapEntries.insert( path, newEntry );
// the insert does a copy, so we have to use <e> now
Entry* e = &(m_mapEntries[path]);
if (exists) {
- e->isDir = S_ISDIR(stat_buf.st_mode);
+ QFileInfo fi ( path );
+ e->isDir = fi.isDir();
if (e->isDir && !isDir)
qWarning("KDirWatch: %s is a directory. Use addDir!", path.ascii());
else if (!e->isDir && isDir)
qWarning("KDirWatch: %s is a file. Use addFile!", path.ascii());
e->m_ctime = stat_buf.st_ctime;
e->m_status = Normal;
e->m_nlink = stat_buf.st_nlink;
}
else {
e->isDir = isDir;
e->m_ctime = invalid_ctime;
e->m_status = NonExistent;
e->m_nlink = 0;
}
e->path = path;
if (sub_entry)
e->m_entries.append(sub_entry);
else
e->addClient(instance);
kdDebug(7001) << "Added " << (e->isDir ? "Dir ":"File ") << path
<< (e->m_status == NonExistent ? " NotExisting" : "")
<< (sub_entry ? QString(" for %1").arg(sub_entry->path) : QString(""))
<< (instance ? QString(" [%1]").arg(instance->name()) : QString(""))
<< endl;
// now setup the notification method
e->m_mode = UnknownMode;
e->msecLeft = 0;
#if defined(HAVE_FAM)
if (useFAM(e)) return;
#endif
#ifdef HAVE_DNOTIFY
if (useDNotify(e)) return;
#endif
useStat(e);
}
void KDirWatchPrivate::removeEntry( KDirWatch* instance,
const QString& _path, Entry* sub_entry )
{
Entry* e = entry(_path);
if (!e) {
kdWarning(7001) << "KDirWatch::removeDir can't handle '" << _path << "'" << endl;
return;
}
if (sub_entry)
e->m_entries.removeRef(sub_entry);
else
e->removeClient(instance);
if (e->m_clients.count() || e->m_entries.count())
return;
if (delayRemove) {
// removeList is allowed to contain any entry at most once
if (removeList.findRef(e)==-1)
removeList.append(e);
// now e->isValid() is false
return;
}
#ifdef HAVE_FAM
if (e->m_mode == FAMMode) {
if ( e->m_status == Normal) {
FAMCancelMonitor(&fc, &(e->fr) );
kdDebug(7001) << "Cancelled FAM (Req "
<< FAMREQUEST_GETREQNUM(&(e->fr))
<< ") for " << e->path << endl;
}
else {
if (e->isDir)
removeEntry(0, QDir::cleanDirPath(e->path+"/.."), e);
else
removeEntry(0, QFileInfo(e->path).dirPath(true), e);
}
}
#endif
#ifdef HAVE_DNOTIFY
if (e->m_mode == DNotifyMode) {
if (!e->isDir) {
removeEntry(0, QFileInfo(e->path).dirPath(true), e);
}
else { // isDir
// must close the FD.
if ( e->m_status == Normal) {
if (e->dn_fd) {
::close(e->dn_fd);
fd_Entry.remove(e->dn_fd);
kdDebug(7001) << "Cancelled DNotify (fd " << e->dn_fd
<< ") for " << e->path << endl;
e->dn_fd = 0;
}
}
else {
removeEntry(0, QDir::cleanDirPath(e->path+"/.."), e);
}
}
}
#endif
if (e->m_mode == StatMode) {
statEntries--;
if ( statEntries == 0 ) {
timer->stop(); // stop timer if lists are empty
kdDebug(7001) << " Stopped Polling Timer" << endl;
}
}
kdDebug(7001) << "Removed " << (e->isDir ? "Dir ":"File ") << e->path
<< (sub_entry ? QString(" for %1").arg(sub_entry->path) : QString(""))
<< (instance ? QString(" [%1]").arg(instance->name()) : QString(""))
<< endl;
m_mapEntries.remove( e->path ); // <e> not valid any more
}
/* Called from KDirWatch destructor:
* remove <instance> as client from all entries
*/
void KDirWatchPrivate::removeEntries( KDirWatch* instance )
{
QPtrList<Entry> list;
int minfreq = 3600000;
// put all entries where instance is a client in list
EntryMap::Iterator it = m_mapEntries.begin();
for( ; it != m_mapEntries.end(); ++it ) {
Client* c = (*it).m_clients.first();
for(;c;c=(*it).m_clients.next())
if (c->instance == instance) break;
if (c) {
c->count = 1; // forces deletion of instance as client
list.append(&(*it));
}
else if ( (*it).m_mode == StatMode && (*it).freq < minfreq )
minfreq = (*it).freq;
}
for(Entry* e=list.first();e;e=list.next())
removeEntry(instance, e->path, 0);
if (minfreq > freq) {
// we can decrease the global polling frequency
freq = minfreq;
if (timer->isActive()) timer->changeInterval(freq);
kdDebug(7001) << "Poll Freq now " << freq << " msec" << endl;
}
}
// instance ==0: stop scanning for all instances
bool KDirWatchPrivate::stopEntryScan( KDirWatch* instance, Entry* e)
{
int stillWatching = 0;
Client* c = e->m_clients.first();
for(;c;c=e->m_clients.next()) {
if (!instance || instance == c->instance)
c->watchingStopped = true;
else if (!c->watchingStopped)
stillWatching += c->count;
}
kdDebug(7001) << instance->name() << " stopped scanning " << e->path
<< " (now " << stillWatching << " watchers)" << endl;
if (stillWatching == 0) {
// if nobody is interested, we don't watch
e->m_ctime = invalid_ctime; // invalid
// e->m_status = Normal;
}
return true;
}
// instance ==0: start scanning for all instances
bool KDirWatchPrivate::restartEntryScan( KDirWatch* instance, Entry* e,
bool notify)
{
int wasWatching = 0, newWatching = 0;
Client* c = e->m_clients.first();
for(;c;c=e->m_clients.next()) {