summaryrefslogtreecommitdiff
authormickeyl <mickeyl>2004-04-20 14:34:17 (UTC)
committer mickeyl <mickeyl>2004-04-20 14:34:17 (UTC)
commit3fb65729e122d85a27b2a6194f96e37eaed3edd1 (patch) (unidiff)
tree6168c3efa9a41dc5d56669ce0f36f58196b3dabb
parentccba33667c0152cb58a6d0502170b388889571c9 (diff)
downloadopie-3fb65729e122d85a27b2a6194f96e37eaed3edd1.zip
opie-3fb65729e122d85a27b2a6194f96e37eaed3edd1.tar.gz
opie-3fb65729e122d85a27b2a6194f96e37eaed3edd1.tar.bz2
2nd milestone reached: Notification now works with deleted, renamed, and
inode-modified files. Next milestone: Make it work for files which are not yet there (DN_CREATE)
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--libopie2/opiecore/ofilenotify.cpp15
-rw-r--r--libopie2/opiecore/ofilenotify.h10
2 files changed, 23 insertions, 2 deletions
diff --git a/libopie2/opiecore/ofilenotify.cpp b/libopie2/opiecore/ofilenotify.cpp
index de4c63b..270570e 100644
--- a/libopie2/opiecore/ofilenotify.cpp
+++ b/libopie2/opiecore/ofilenotify.cpp
@@ -139,142 +139,155 @@ int OFileNotification::start( const QString& path, bool sshot, OFileNotification
139 { 139 {
140 qWarning( "OFileNotification::start(): Error with path '%s': %s.", (const char*) dirpath, strerror( errno ) ); 140 qWarning( "OFileNotification::start(): Error with path '%s': %s.", (const char*) dirpath, strerror( errno ) );
141 return -1; 141 return -1;
142 } 142 }
143} 143}
144 144
145 145
146void OFileNotification::stop() 146void OFileNotification::stop()
147{ 147{
148 if ( !_active ) return; 148 if ( !_active ) return;
149 149
150 int result = ::fcntl( _fd, F_NOTIFY, 0 ); 150 int result = ::fcntl( _fd, F_NOTIFY, 0 );
151 if ( result == -1 ) 151 if ( result == -1 )
152 { 152 {
153 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 ) );
154 } 154 }
155 else 155 else
156 { 156 {
157 ::close( _fd ); 157 ::close( _fd );
158 _type = Single; 158 _type = Single;
159 _path = QString::null; 159 _path = QString::null;
160 _fd = 0; 160 _fd = 0;
161 _active = false; 161 _active = false;
162 } 162 }
163} 163}
164 164
165 165
166OFileNotificationType OFileNotification::type() const 166OFileNotificationType OFileNotification::type() const
167{ 167{
168 return _type; 168 return _type;
169} 169}
170 170
171 171
172QString OFileNotification::path() const 172QString OFileNotification::path() const
173{ 173{
174 return _path; 174 return _path;
175} 175}
176 176
177 177
178int OFileNotification::fileno() const 178int OFileNotification::fileno() const
179{ 179{
180 return _fd; 180 return _fd;
181} 181}
182 182
183 183
184bool OFileNotification::activate() 184bool OFileNotification::activate()
185{ 185{
186 if ( hasChanged() ) 186 if ( hasChanged() )
187 { 187 {
188 emit triggered(); 188 emit triggered();
189 _signal.activate(); 189 _signal.activate();
190 return true; 190 return true;
191 } 191 }
192 else 192 else
193 return false; 193 return false;
194} 194}
195 195
196 196
197bool OFileNotification::hasChanged() 197bool OFileNotification::hasChanged()
198{ 198{
199 bool c = false; 199 bool c = false;
200 200
201 struct stat newstat; 201 struct stat newstat;
202 ::memset( &newstat, 0, sizeof newstat ); 202 ::memset( &newstat, 0, sizeof newstat );
203 ::stat( _path, &newstat ); 203 int result = ::stat( _path, &newstat ); // may fail if file has been renamed or deleted. that doesn't matter :)
204 204
205 qDebug( "result of newstat call is %d (%s=%d)", result, strerror( errno ), errno );
205 qDebug( "stat.atime = %0lx, newstat.atime = %0lx", (long)_stat.st_atime, (long)newstat.st_atime ); 206 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 qDebug( "stat.mtime = %0lx, newstat.mtime = %0lx", (long)_stat.st_mtime, (long)newstat.st_mtime );
208 qDebug( "stat.ctime = %0lx, newstat.ctime = %0lx", (long)_stat.st_ctime, (long)newstat.st_ctime );
209
210 if ( !c && (_type & (Delete|Rename)) && (long)newstat.st_atime == 0 && (long)newstat.st_mtime == 0 && (long)newstat.st_ctime == 0)
211 {
212 qDebug( "OFileNotification::hasChanged(): file has been deleted or renamed" );
213 c = true;
214 }
207 if ( !c && (_type & Access) && (long)_stat.st_atime < (long)newstat.st_atime ) 215 if ( !c && (_type & Access) && (long)_stat.st_atime < (long)newstat.st_atime )
208 { 216 {
209 qDebug( "OFileNotification::hasChanged(): atime changed" ); 217 qDebug( "OFileNotification::hasChanged(): atime changed" );
210 c = true; 218 c = true;
211 } 219 }
212 if ( !c && (_type & Modify) && (long)_stat.st_mtime < (long)newstat.st_mtime ) 220 if ( !c && (_type & Modify) && (long)_stat.st_mtime < (long)newstat.st_mtime )
213 { 221 {
214 qDebug( "OFileNotification::hasChanged(): mtime changed" ); 222 qDebug( "OFileNotification::hasChanged(): mtime changed" );
215 c = true; 223 c = true;
216 } 224 }
225 if ( !c && (_type & Attrib) && (long)_stat.st_ctime < (long)newstat.st_ctime )
226 {
227 qDebug( "OFileNotification::hasChanged(): ctime changed" );
228 c = true;
229 }
217 230
218 return c; 231 return c;
219} 232}
220 233
221 234
222void OFileNotification::singleShot( const QString& path, QObject* receiver, const char* member, OFileNotificationType type ) 235void OFileNotification::singleShot( const QString& path, QObject* receiver, const char* member, OFileNotificationType type )
223{ 236{
224 OFileNotification* ofn = new OFileNotification(); 237 OFileNotification* ofn = new OFileNotification();
225 ofn->_signal.connect( receiver, member ); 238 ofn->_signal.connect( receiver, member );
226 ofn->start( path, true, type ); 239 ofn->start( path, true, type );
227} 240}
228 241
229 242
230void OFileNotification::__signalHandler( int sig, siginfo_t *si, void *data ) 243void OFileNotification::__signalHandler( int sig, siginfo_t *si, void *data )
231{ 244{
232 qWarning( "OFileNotification::__signalHandler(): reached." ); 245 qWarning( "OFileNotification::__signalHandler(): reached." );
233 int fd = si->si_fd; 246 int fd = si->si_fd;
234 OFileNotification* fn = notification_list[fd]; 247 OFileNotification* fn = notification_list[fd];
235 if ( fn ) 248 if ( fn )
236 { 249 {
237 // check if it really was the file (dnotify triggers on directory granularity, not file granularity) 250 // check if it really was the file (dnotify triggers on directory granularity, not file granularity)
238 if ( !fn->activate() ) 251 if ( !fn->activate() )
239 { 252 {
240 qDebug( "OFileNotification::__signalHandler(): false alarm ;) Restarting the trigger (if it was single)..." ); 253 qDebug( "OFileNotification::__signalHandler(): false alarm ;) Restarting the trigger (if it was single)..." );
241 if ( !(fn->type() & Multi ) ) 254 if ( !(fn->type() & Multi ) )
242 { 255 {
243 int result = ::fcntl( fn->fileno(), F_NOTIFY, fn->type() ); 256 int result = ::fcntl( fn->fileno(), F_NOTIFY, fn->type() );
244 if ( result == -1 ) 257 if ( result == -1 )
245 { 258 {
246 qWarning( "OFileNotification::__signalHandler(): Can't restart the trigger: %s.", strerror( errno ) ); 259 qWarning( "OFileNotification::__signalHandler(): Can't restart the trigger: %s.", strerror( errno ) );
247 } 260 }
248 } 261 }
249 return; 262 return;
250 } 263 }
251 #if 1 264 #if 1
252 if ( !(fn->type() & Multi) ) 265 if ( !(fn->type() & Multi) )
253 { 266 {
254 qDebug( "OFileNotification::__signalHandler(): '%d' was singleShot. Removing from list.", fd ); 267 qDebug( "OFileNotification::__signalHandler(): '%d' was singleShot. Removing from list.", fd );
255 notification_list.remove( fd ); 268 notification_list.remove( fd );
256 if ( notification_list.isEmpty() ) 269 if ( notification_list.isEmpty() )
257 { 270 {
258 OFileNotification::unregisterSignalHandler(); 271 OFileNotification::unregisterSignalHandler();
259 } 272 }
260 } 273 }
261 #endif 274 #endif
262 } 275 }
263 else 276 else
264 { 277 {
265 qWarning( "OFileNotification::__signalHandler(): D'oh! Called without fd in notification_list. Race condition?" ); 278 qWarning( "OFileNotification::__signalHandler(): D'oh! Called without fd in notification_list. Race condition?" );
266 } 279 }
267} 280}
268 281
269 282
270bool OFileNotification::registerSignalHandler() 283bool OFileNotification::registerSignalHandler()
271{ 284{
272 struct sigaction act; 285 struct sigaction act;
273 act.sa_sigaction = OFileNotification::__signalHandler; 286 act.sa_sigaction = OFileNotification::__signalHandler;
274 ::sigemptyset( &act.sa_mask ); 287 ::sigemptyset( &act.sa_mask );
275 act.sa_flags = SA_SIGINFO; 288 act.sa_flags = SA_SIGINFO;
276 if ( ::sigaction( SIGRTMIN, &act, NULL ) == -1 ) 289 if ( ::sigaction( SIGRTMIN, &act, NULL ) == -1 )
277 { 290 {
278 qWarning( "OFileNotification::registerSignalHandler(): couldn't register signal handler: %s", strerror( errno ) ); 291 qWarning( "OFileNotification::registerSignalHandler(): couldn't register signal handler: %s", strerror( errno ) );
279 return false; 292 return false;
280 } 293 }
diff --git a/libopie2/opiecore/ofilenotify.h b/libopie2/opiecore/ofilenotify.h
index 5315896..13b5a6b 100644
--- a/libopie2/opiecore/ofilenotify.h
+++ b/libopie2/opiecore/ofilenotify.h
@@ -15,83 +15,91 @@ _;:,     .>    :=|. This program is free software; you can
15   : ..    .:,     . . . without even the implied warranty of 15   : ..    .:,     . . . without even the implied warranty of
16   =_        +     =;=|` MERCHANTABILITY or FITNESS FOR A 16   =_        +     =;=|` MERCHANTABILITY or FITNESS FOR A
17 _.=:.       :    :=>`: PARTICULAR PURPOSE. See the GNU 17 _.=:.       :    :=>`: PARTICULAR PURPOSE. See the GNU
18..}^=.=       =       ; Library General Public License for more 18..}^=.=       =       ; Library General Public License for more
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#ifndef OFILENOTIFY_H 29#ifndef OFILENOTIFY_H
30#define OFILENOTIFY_H 30#define OFILENOTIFY_H
31#if defined (__GNUC__) && (__GNUC__ < 3) 31#if defined (__GNUC__) && (__GNUC__ < 3)
32#define _GNU_SOURCE 32#define _GNU_SOURCE
33#endif 33#endif
34 34
35/* QT */ 35/* QT */
36#include <qobject.h> 36#include <qobject.h>
37#include <qsignal.h> 37#include <qsignal.h>
38#include <qstring.h> 38#include <qstring.h>
39 39
40/* STD */ 40/* STD */
41#include <signal.h> 41#include <signal.h>
42#include <fcntl.h> 42#include <fcntl.h>
43 43
44namespace Opie { 44namespace Opie {
45namespace Core { 45namespace Core {
46 46
47enum OFileNotificationType { Single = 0x0000000, 47enum OFileNotificationType { Single = 0x0000000,
48 Multi = DN_MULTISHOT, 48 Multi = DN_MULTISHOT,
49 Access = DN_ACCESS, 49 Access = DN_ACCESS,
50 Modify = DN_MODIFY, 50 Modify = DN_MODIFY,
51 Create = DN_CREATE, 51 Create = DN_CREATE,
52 Delete = DN_DELETE, 52 Delete = DN_DELETE,
53 Rename = DN_RENAME, 53 Rename = DN_RENAME,
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 bool activate(); 78 bool activate();
79 bool hasChanged(); 79 virtual bool hasChanged();
80 static bool registerSignalHandler(); 80 static bool registerSignalHandler();
81 static void unregisterSignalHandler(); 81 static void unregisterSignalHandler();
82 static void __signalHandler( int sig, siginfo_t *si, void *data ); 82 static void __signalHandler( int sig, siginfo_t *si, void *data );
83 83
84 private: 84 private:
85 QString _path; 85 QString _path;
86 OFileNotificationType _type; 86 OFileNotificationType _type;
87 QSignal _signal; 87 QSignal _signal;
88 int _fd; 88 int _fd;
89 bool _active; 89 bool _active;
90 struct stat _stat; 90 struct stat _stat;
91}; 91};
92 92
93
94class ODirectoryNotification : public OFileNotification
95{
96 public:
97 virtual bool hasChanged() { return true; };
98};
99
100
93} 101}
94} 102}
95 103
96#endif 104#endif
97 105