summaryrefslogtreecommitdiff
path: root/libopie2/opiecore
Unidiff
Diffstat (limited to 'libopie2/opiecore') (more/less context) (ignore whitespace changes)
-rw-r--r--libopie2/opiecore/ofilenotify.cpp102
-rw-r--r--libopie2/opiecore/ofilenotify.h4
2 files changed, 93 insertions, 13 deletions
diff --git a/libopie2/opiecore/ofilenotify.cpp b/libopie2/opiecore/ofilenotify.cpp
index bcfb1aa..de4c63b 100644
--- a/libopie2/opiecore/ofilenotify.cpp
+++ b/libopie2/opiecore/ofilenotify.cpp
@@ -40,6 +40,7 @@ using namespace Opie::Core;
40/* STD */ 40/* STD */
41#include <sys/types.h> 41#include <sys/types.h>
42#include <sys/stat.h> 42#include <sys/stat.h>
43#include <assert.h>
43#include <fcntl.h> 44#include <fcntl.h>
44#include <string.h> 45#include <string.h>
45#include <errno.h> 46#include <errno.h>
@@ -74,37 +75,69 @@ int OFileNotification::start( const QString& path, bool sshot, OFileNotification
74 _path = QString::null; 75 _path = QString::null;
75 _fd = 0; 76 _fd = 0;
76 if ( _active ) stop(); 77 if ( _active ) stop();
78 QString dirpath;
77 79
78 int fd = ::open( (const char*) path, O_RDONLY ); 80 // check if path exists and whether it is a file or a directory, if it exists at all
81 int result = ::stat( (const char*) path, &_stat );
82 if ( result == -1 )
83 {
84 qWarning( "OFileNotification::start(): Can't stat '%s': %s.", (const char*) path, strerror( errno ) );
85 return -1;
86 }
87
88 // if it is not a directory, we need to find out in which directory the file is
89 bool isDirectory = S_ISDIR( _stat.st_mode );
90 if ( !isDirectory )
91 {
92 int slashpos;
93 slashpos = path.findRev( '/' );
94 if ( slashpos > 0 )
95 {
96 _path = path;
97 dirpath = path.left( slashpos );
98 }
99 }
100 else /* isDirectory */
101 {
102 qWarning( "FIXME FIXME FIXME = Directory Notification Not Yet Implemented!" );
103 _path = path;
104 dirpath = path;
105 assert( 0 );
106 }
107
108 int fd = ::open( (const char*) dirpath, O_RDONLY );
79 if ( fd != -1 ) 109 if ( fd != -1 )
80 { 110 {
81 if ( notification_list.isEmpty() ) 111 if ( notification_list.isEmpty() )
82 { 112 {
83 OFileNotification::registerSignalHandler(); 113 OFileNotification::registerSignalHandler();
84 } 114 }
85 int result = ::fcntl( fd, F_SETSIG, SIGRTMIN ); 115
116 result = ::fcntl( fd, F_SETSIG, SIGRTMIN );
86 if ( result == -1 ) 117 if ( result == -1 )
87 { 118 {
88 qWarning( "OFileNotification::start(): Can't subscribe to '%s': %s.", (const char*) path, strerror( errno ) ); 119 qWarning( "OFileNotification::start(): Can't subscribe to '%s': %s.", (const char*) dirpath, strerror( errno ) );
89 return -1; 120 return -1;
90 } 121 }
91 if ( !sshot ) (int) type |= (int) Multi; 122 if ( !sshot ) (int) type |= (int) Multi;
92 result = ::fcntl( fd, F_NOTIFY, type ); 123 result = ::fcntl( fd, F_NOTIFY, type );
93 if ( result == -1 ) 124 if ( result == -1 )
94 { 125 {
95 qWarning( "OFileNotification::start(): Can't subscribe to '%s': %s.", (const char*) path, strerror( errno ) ); 126 qWarning( "OFileNotification::start(): Can't subscribe to '%s': %s.", (const char*) dirpath, strerror( errno ) );
96 return -1; 127 return -1;
97 } 128 }
98 qDebug( "OFileNotification::start(): Subscribed for changes to %s (fd = %d, mask = 0x%0x)", (const char*) path, fd, type ); 129 qDebug( "OFileNotification::start(): Subscribed for changes to %s (fd = %d, mask = 0x%0x)", (const char*) dirpath, fd, type );
99 notification_list.insert( fd, this ); 130 notification_list.insert( fd, this );
100 _type = type; 131 _type = type;
101 _path = path;
102 _fd = fd; 132 _fd = fd;
133 _active = true;
134 ::memset( &_stat, 0, sizeof _stat );
135 ::stat( _path, &_stat );
103 return fd; 136 return fd;
104 } 137 }
105 else 138 else
106 { 139 {
107 qWarning( "OFileNotification::start(): Error with path '%s': %s.", (const char*) path, strerror( errno ) ); 140 qWarning( "OFileNotification::start(): Error with path '%s': %s.", (const char*) dirpath, strerror( errno ) );
108 return -1; 141 return -1;
109 } 142 }
110} 143}
@@ -141,15 +174,48 @@ QString OFileNotification::path() const
141 return _path; 174 return _path;
142} 175}
143 176
177
144int OFileNotification::fileno() const 178int OFileNotification::fileno() const
145{ 179{
146 return _fd; 180 return _fd;
147} 181}
148 182
149void OFileNotification::activate() 183
184bool OFileNotification::activate()
150{ 185{
151 emit triggered(); 186 if ( hasChanged() )
152 _signal.activate(); 187 {
188 emit triggered();
189 _signal.activate();
190 return true;
191 }
192 else
193 return false;
194}
195
196
197bool OFileNotification::hasChanged()
198{
199 bool c = false;
200
201 struct stat newstat;
202 ::memset( &newstat, 0, sizeof newstat );
203 ::stat( _path, &newstat );
204
205 qDebug( "stat.atime = %0lx, newstat.atime = %0lx", (long)_stat.st_atime, (long)newstat.st_atime );
206 qDebug( "stat.mtime = %0lx, newstat.mtime = %0lx", (long)_stat.st_mtime, (long)newstat.st_mtime );
207 if ( !c && (_type & Access) && (long)_stat.st_atime < (long)newstat.st_atime )
208 {
209 qDebug( "OFileNotification::hasChanged(): atime changed" );
210 c = true;
211 }
212 if ( !c && (_type & Modify) && (long)_stat.st_mtime < (long)newstat.st_mtime )
213 {
214 qDebug( "OFileNotification::hasChanged(): mtime changed" );
215 c = true;
216 }
217
218 return c;
153} 219}
154 220
155 221
@@ -168,7 +234,20 @@ void OFileNotification::__signalHandler( int sig, siginfo_t *si, void *data )
168 OFileNotification* fn = notification_list[fd]; 234 OFileNotification* fn = notification_list[fd];
169 if ( fn ) 235 if ( fn )
170 { 236 {
171 fn->activate(); 237 // check if it really was the file (dnotify triggers on directory granularity, not file granularity)
238 if ( !fn->activate() )
239 {
240 qDebug( "OFileNotification::__signalHandler(): false alarm ;) Restarting the trigger (if it was single)..." );
241 if ( !(fn->type() & Multi ) )
242 {
243 int result = ::fcntl( fn->fileno(), F_NOTIFY, fn->type() );
244 if ( result == -1 )
245 {
246 qWarning( "OFileNotification::__signalHandler(): Can't restart the trigger: %s.", strerror( errno ) );
247 }
248 }
249 return;
250 }
172 #if 1 251 #if 1
173 if ( !(fn->type() & Multi) ) 252 if ( !(fn->type() & Multi) )
174 { 253 {
@@ -209,7 +288,6 @@ void OFileNotification::unregisterSignalHandler()
209 act.sa_sigaction = ( void (*)(int, siginfo_t*, void*) ) SIG_DFL; 288 act.sa_sigaction = ( void (*)(int, siginfo_t*, void*) ) SIG_DFL;
210 ::sigemptyset( &act.sa_mask ); 289 ::sigemptyset( &act.sa_mask );
211 if ( ::sigaction( SIGRTMIN, &act, NULL ) == -1 ) 290 if ( ::sigaction( SIGRTMIN, &act, NULL ) == -1 )
212 if ( ::sigaction( SIGRTMIN, &act, NULL ) == -1 )
213 { 291 {
214 qWarning( "OFileNotification::unregisterSignalHandler(): couldn't deregister signal handler: %s", strerror( errno ) ); 292 qWarning( "OFileNotification::unregisterSignalHandler(): couldn't deregister signal handler: %s", strerror( errno ) );
215 } 293 }
diff --git a/libopie2/opiecore/ofilenotify.h b/libopie2/opiecore/ofilenotify.h
index 3bc141d..5315896 100644
--- a/libopie2/opiecore/ofilenotify.h
+++ b/libopie2/opiecore/ofilenotify.h
@@ -75,7 +75,8 @@ class OFileNotification : public QObject
75 void triggered(); 75 void triggered();
76 76
77 protected: 77 protected:
78 void activate(); 78 bool activate();
79 bool hasChanged();
79 static bool registerSignalHandler(); 80 static bool registerSignalHandler();
80 static void unregisterSignalHandler(); 81 static void unregisterSignalHandler();
81 static void __signalHandler( int sig, siginfo_t *si, void *data ); 82 static void __signalHandler( int sig, siginfo_t *si, void *data );
@@ -86,6 +87,7 @@ class OFileNotification : public QObject
86 QSignal _signal; 87 QSignal _signal;
87 int _fd; 88 int _fd;
88 bool _active; 89 bool _active;
90 struct stat _stat;
89}; 91};
90 92
91} 93}