summaryrefslogtreecommitdiff
Unidiff
Diffstat (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
@@ -37,12 +37,13 @@ using namespace Opie::Core;
37#include <qintdict.h> 37#include <qintdict.h>
38#include <qdir.h> 38#include <qdir.h>
39 39
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>
46#include <unistd.h> 47#include <unistd.h>
47 48
48static QIntDict<OFileNotification> notification_list; 49static QIntDict<OFileNotification> notification_list;
@@ -71,43 +72,75 @@ bool OFileNotification::isActive() const
71 72
72int OFileNotification::start( const QString& path, bool sshot, OFileNotificationType type ) 73int OFileNotification::start( const QString& path, bool sshot, OFileNotificationType type )
73{ 74{
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}
111 144
112 145
113void OFileNotification::stop() 146void OFileNotification::stop()
@@ -138,21 +171,54 @@ OFileNotificationType OFileNotification::type() const
138 171
139QString OFileNotification::path() const 172QString OFileNotification::path() const
140{ 173{
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
156void OFileNotification::singleShot( const QString& path, QObject* receiver, const char* member, OFileNotificationType type ) 222void OFileNotification::singleShot( const QString& path, QObject* receiver, const char* member, OFileNotificationType type )
157{ 223{
158 OFileNotification* ofn = new OFileNotification(); 224 OFileNotification* ofn = new OFileNotification();
@@ -165,13 +231,26 @@ void OFileNotification::__signalHandler( int sig, siginfo_t *si, void *data )
165{ 231{
166 qWarning( "OFileNotification::__signalHandler(): reached." ); 232 qWarning( "OFileNotification::__signalHandler(): reached." );
167 int fd = si->si_fd; 233 int fd = si->si_fd;
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 {
175 qDebug( "OFileNotification::__signalHandler(): '%d' was singleShot. Removing from list.", fd ); 254 qDebug( "OFileNotification::__signalHandler(): '%d' was singleShot. Removing from list.", fd );
176 notification_list.remove( fd ); 255 notification_list.remove( fd );
177 if ( notification_list.isEmpty() ) 256 if ( notification_list.isEmpty() )
@@ -206,13 +285,12 @@ bool OFileNotification::registerSignalHandler()
206void OFileNotification::unregisterSignalHandler() 285void OFileNotification::unregisterSignalHandler()
207{ 286{
208 struct sigaction act; 287 struct sigaction act;
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 }
216 qDebug( "OFileNotification::unregisterSignalHandler(): done" ); 294 qDebug( "OFileNotification::unregisterSignalHandler(): done" );
217} 295}
218 296
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
@@ -72,23 +72,25 @@ class OFileNotification : public QObject
72 bool isActive() const; 72 bool isActive() const;
73 73
74 signals: 74 signals:
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 );
82 83
83 private: 84 private:
84 QString _path; 85 QString _path;
85 OFileNotificationType _type; 86 OFileNotificationType _type;
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}
92} 94}
93 95
94#endif 96#endif