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
@@ -19,203 +19,281 @@ _;:,     .>    :=|. This program is free software; you can
19++=   -.     .`     .: details. 19++=   -.     .`     .: details.
20:     =  ...= . :.=- 20:     =  ...= . :.=-
21-.   .:....=;==+<; You should have received a copy of the GNU 21-.   .:....=;==+<; You should have received a copy of the GNU
22 -_. . .   )=.  = Library General Public License along with 22 -_. . .   )=.  = Library General Public License along with
23   --        :-=` this library; see the file COPYING.LIB. 23   --        :-=` this library; see the file COPYING.LIB.
24 If not, write to the Free Software Foundation, 24 If not, write to the Free Software Foundation,
25 Inc., 59 Temple Place - Suite 330, 25 Inc., 59 Temple Place - Suite 330,
26 Boston, MA 02111-1307, USA. 26 Boston, MA 02111-1307, USA.
27*/ 27*/
28 28
29#include "ofilenotify.h" 29#include "ofilenotify.h"
30using namespace Opie::Core; 30using namespace Opie::Core;
31 31
32/* OPIE */ 32/* OPIE */
33 33
34/* QT */ 34/* QT */
35#include <qobject.h> 35#include <qobject.h>
36#include <qsignal.h> 36#include <qsignal.h>
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;
49 50
50namespace Opie { 51namespace Opie {
51namespace Core { 52namespace Core {
52 53
53OFileNotification::OFileNotification( QObject* parent, const char* name ) 54OFileNotification::OFileNotification( QObject* parent, const char* name )
54 :QObject( parent, name ), _active( false ) 55 :QObject( parent, name ), _active( false )
55{ 56{
56 qDebug( "OFileNotification::OFileNotification()" ); 57 qDebug( "OFileNotification::OFileNotification()" );
57} 58}
58 59
59 60
60OFileNotification::~OFileNotification() 61OFileNotification::~OFileNotification()
61{ 62{
62 qDebug( "OFileNotification::~OFileNotification()" ); 63 qDebug( "OFileNotification::~OFileNotification()" );
63} 64}
64 65
65 66
66bool OFileNotification::isActive() const 67bool OFileNotification::isActive() const
67{ 68{
68 return _active; 69 return _active;
69} 70}
70 71
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()
114{ 147{
115 if ( !_active ) return; 148 if ( !_active ) return;
116 149
117 int result = ::fcntl( _fd, F_NOTIFY, 0 ); 150 int result = ::fcntl( _fd, F_NOTIFY, 0 );
118 if ( result == -1 ) 151 if ( result == -1 )
119 { 152 {
120 qWarning( "OFileNotification::stop(): Can't remove subscription to '%s': %s.", (const char*) _path, strerror( errno ) ); 153 qWarning( "OFileNotification::stop(): Can't remove subscription to '%s': %s.", (const char*) _path, strerror( errno ) );
121 } 154 }
122 else 155 else
123 { 156 {
124 ::close( _fd ); 157 ::close( _fd );
125 _type = Single; 158 _type = Single;
126 _path = QString::null; 159 _path = QString::null;
127 _fd = 0; 160 _fd = 0;
128 _active = false; 161 _active = false;
129 } 162 }
130} 163}
131 164
132 165
133OFileNotificationType OFileNotification::type() const 166OFileNotificationType OFileNotification::type() const
134{ 167{
135 return _type; 168 return _type;
136} 169}
137 170
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();
159 ofn->_signal.connect( receiver, member ); 225 ofn->_signal.connect( receiver, member );
160 ofn->start( path, true, type ); 226 ofn->start( path, true, type );
161} 227}
162 228
163 229
164void OFileNotification::__signalHandler( int sig, siginfo_t *si, void *data ) 230void 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() )
178 { 257 {
179 OFileNotification::unregisterSignalHandler(); 258 OFileNotification::unregisterSignalHandler();
180 } 259 }
181 } 260 }
182 #endif 261 #endif
183 } 262 }
184 else 263 else
185 { 264 {
186 qWarning( "OFileNotification::__signalHandler(): D'oh! Called without fd in notification_list. Race condition?" ); 265 qWarning( "OFileNotification::__signalHandler(): D'oh! Called without fd in notification_list. Race condition?" );
187 } 266 }
188} 267}
189 268
190 269
191bool OFileNotification::registerSignalHandler() 270bool OFileNotification::registerSignalHandler()
192{ 271{
193 struct sigaction act; 272 struct sigaction act;
194 act.sa_sigaction = OFileNotification::__signalHandler; 273 act.sa_sigaction = OFileNotification::__signalHandler;
195 ::sigemptyset( &act.sa_mask ); 274 ::sigemptyset( &act.sa_mask );
196 act.sa_flags = SA_SIGINFO; 275 act.sa_flags = SA_SIGINFO;
197 if ( ::sigaction( SIGRTMIN, &act, NULL ) == -1 ) 276 if ( ::sigaction( SIGRTMIN, &act, NULL ) == -1 )
198 { 277 {
199 qWarning( "OFileNotification::registerSignalHandler(): couldn't register signal handler: %s", strerror( errno ) ); 278 qWarning( "OFileNotification::registerSignalHandler(): couldn't register signal handler: %s", strerror( errno ) );
200 return false; 279 return false;
201 } 280 }
202 qDebug( "OFileNotification::registerSignalHandler(): done" ); 281 qDebug( "OFileNotification::registerSignalHandler(): done" );
203} 282}
204 283
205 284
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
219 297
220} 298}
221} 299}
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
@@ -54,42 +54,44 @@ enum OFileNotificationType { Single = 0x0000000,
54 Attrib = DN_ATTRIB }; 54 Attrib = DN_ATTRIB };
55 55
56class OFileNotification : public QObject 56class OFileNotification : public QObject
57{ 57{
58 Q_OBJECT 58 Q_OBJECT
59 59
60 public: 60 public:
61 OFileNotification( QObject* parent = 0, const char* name = 0 ); 61 OFileNotification( QObject* parent = 0, const char* name = 0 );
62 ~OFileNotification(); 62 ~OFileNotification();
63 63
64 static void singleShot( const QString& path, QObject* receiver, const char* member, OFileNotificationType type = Modify ); 64 static void singleShot( const QString& path, QObject* receiver, const char* member, OFileNotificationType type = Modify );
65 65
66 int start( const QString& path, bool sshot = false, OFileNotificationType type = Modify ); 66 int start( const QString& path, bool sshot = false, OFileNotificationType type = Modify );
67 void stop(); 67 void stop();
68 68
69 OFileNotificationType type() const; 69 OFileNotificationType type() const;
70 QString path() const; 70 QString path() const;
71 int fileno() const; 71 int fileno() const;
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
95 97