[prev in list] [next in list] [prev in thread] [next in thread]
List: kde-core-devel
Subject: [PATCH] kdirwatch problem of detecting hard link change
From: sycao <sycao () redflag-linux ! com>
Date: 2009-08-07 5:23:48
Message-ID: 4A7BBA64.7080602 () redflag-linux ! com
[Download RAW message or body]
sonald wrote:
> the problem comes up when I traced the problem when using kcmshell4 clock
> to set timezone, which is when you changed timezone second time,
> the setting just lost. I found the real problem is that
> KDirWatch loses watch on /etc/localtime.
>
> I can reproduce the watch lose very easily:
> # inotifywait -m /etc/localtime
> # zic -l Asia/Shanghai
> # zic -l Asia/Muscat
> # touch /etc/localtime
>
> After Change timezone to Muscat, subsequent changes to /etc/localtime
> won't be watched. because KDirWatch use inotify (I'm using a linux distro),
> which monitoring file with respect to inode , not dir entry.
> zic relinked ( hardlink ) /etc/localtime, so inotify just told attrib
> change ( st_nlink change ) of the original file.
>
> I post the patch a few months ago, and it seems that problem still exists
> int KDE 4.3 RC, so I post here to see if it can make some help.
>
> Sian Cao
>
>
>
Hi, all
I sent this patch for a long time, and no one review it yet. but this is
really a problem.
Sian Cao
["kio-kdirwatch-relink.patch" (text/plain)]
Index: kdirwatch.cpp
===================================================================
--- kdirwatch.cpp (revision 1007043)
+++ kdirwatch.cpp (working copy)
@@ -49,6 +49,7 @@
#include <sys/stat.h>
#include <assert.h>
+#include <errno.h>
#include <QtCore/QDir>
#include <QtCore/QFile>
#include <QtCore/QSocketNotifier>
@@ -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<Entry *> removeList;
bool delayRemove;
+ Entry *m_delayedRelinkedEntry;
+
bool rescan_all;
QTimer rescan_timer;
[prev in list] [next in list] [prev in thread] [next in thread]
Configure |
About |
News |
Add a list |
Sponsored by KoreLogic