[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