Index: kdirwatch.cpp =================================================================== --- kdirwatch.cpp (revision 1007043) +++ kdirwatch.cpp (working copy) @@ -49,6 +49,7 @@ #include #include +#include #include #include #include @@ -134,6 +135,7 @@ statEntries( 0 ), m_ref( 0 ), delayRemove( false ), + m_delayedRelinkedEntry( NULL ), rescan_all( false ), rescan_timer() { @@ -735,6 +737,7 @@ #endif e->m_status = Normal; e->m_nlink = stat_buf.st_nlink; + e->m_ino = stat_buf.st_ino; } else { e->isDir = isDir; @@ -1031,6 +1034,7 @@ #endif e->m_status = Normal; e->m_nlink = stat_buf.st_nlink; + e->m_ino = stat_buf.st_ino; } else { e->m_ctime = invalid_ctime; @@ -1136,9 +1140,33 @@ #endif e->m_status = Normal; e->m_nlink = stat_buf.st_nlink; + e->m_ino = stat_buf.st_ino; return Created; } + if ( e->m_ctime != invalid_ctime && stat_buf.st_ino != e->m_ino ) { + kDebug(7001) << "checked hard link change for " << e->path; + int mask = IN_DELETE|IN_DELETE_SELF|IN_CREATE|IN_MOVE|IN_MOVE_SELF + |IN_DONT_FOLLOW|IN_MODIFY|IN_ATTRIB; + + inotify_rm_watch (m_inotify_fd, e->wd); + int wd = inotify_add_watch( m_inotify_fd, QFile::encodeName( e->path ), mask ); + if ( wd == -1 ) { + kDebug(7001) << "re-watch failed with errno " << errno; + m_delayedRelinkedEntry = e; + QTimer::singleShot( 200, this, SLOT(slotRewatchDelayed()) ); + return Changed; + + } else { + e->wd = wd; + e->m_ctime = stat_buf.st_ctime; + e->m_nlink = stat_buf.st_nlink; + e->m_ino = stat_buf.st_ino; + kDebug(7001) << "re-watch for " << e->path << " finished"; + return Changed; + } + } + #ifdef Q_OS_WIN stat_buf.st_ctime = stat_buf.st_mtime; #endif @@ -1228,6 +1256,38 @@ } } +void KDirWatchPrivate::slotRewatchDelayed() +{ + if ( m_delayedRelinkedEntry ) { + kDebug(7001) << "try re-watch for " << m_delayedRelinkedEntry->path; + + KDE_struct_stat stat_buf; + QByteArray tpath = QFile::encodeName(m_delayedRelinkedEntry->path); + int ret = KDE_stat(tpath, &stat_buf); + if ( ret ) { + if ( errno == ENOENT ) { + kDebug(7001) << strerror(errno); + } + return; + } + + int mask = IN_DELETE|IN_DELETE_SELF|IN_CREATE|IN_MOVE|IN_MOVE_SELF + |IN_DONT_FOLLOW|IN_MODIFY|IN_ATTRIB; + inotify_rm_watch( m_inotify_fd, m_delayedRelinkedEntry->wd ); + ret = inotify_add_watch( m_inotify_fd, QFile::encodeName( m_delayedRelinkedEntry->path ), + mask); + if ( !ret ) { + m_delayedRelinkedEntry->wd = ret; + emitEvent( m_delayedRelinkedEntry, Changed ); + kDebug(7001) << "re-watch for " << m_delayedRelinkedEntry->path << " successed"; + } else { + kDebug(7001) << "re-watch for " << m_delayedRelinkedEntry->path << " failed"; + } + + m_delayedRelinkedEntry = NULL; + } +} + // Remove entries which were marked to be removed void KDirWatchPrivate::slotRemoveDelayed() { @@ -1645,7 +1705,24 @@ void KDirWatch::addFile( const QString& _path ) { - if (d) d->addEntry(this, _path, 0, false); + if ( !d ) + return; + + //TODO: detect link change, ino change + KDirWatchPrivate::Entry* e = d->entry(_path); + if ( e ) { + KDE_struct_stat lstat_buf; + QByteArray tpath (QFile::encodeName(_path)); + if ( KDE_lstat(tpath, &lstat_buf) == 0 ) { + if ( S_ISREG(lstat_buf.st_mode) && e->m_status != KDirWatchPrivate::NonExistent + && lstat_buf.st_ino != e->m_ino ) { + kDebug(7001) << "detected an exist entry with different inode, delete watch first"; + d->removeEntry(this, _path, 0); + } + } + } + + d->addEntry(this, _path, 0, false); } QDateTime KDirWatch::ctime( const QString &_path ) const Index: kdirwatch_p.h =================================================================== --- kdirwatch_p.h (revision 1007043) +++ kdirwatch_p.h (working copy) @@ -136,6 +136,8 @@ time_t m_ctime; // the last observed link count int m_nlink; + // last observed inode ( considering hard link changes ) + ino_t m_ino; entryStatus m_status; entryMode m_mode; bool isDir; @@ -207,7 +209,8 @@ void inotifyEventReceived(); // for inotify void slotRemoveDelayed(); void fswEventReceived(const QString &path); // for QFileSystemWatcher - + void slotRewatchDelayed(); + public: QTimer timer; EntryMap m_mapEntries; @@ -223,6 +226,8 @@ QSet removeList; bool delayRemove; + Entry *m_delayedRelinkedEntry; + bool rescan_all; QTimer rescan_timer;