summaryrefslogtreecommitdiff
authormickeyl <mickeyl>2004-04-20 15:22:04 (UTC)
committer mickeyl <mickeyl>2004-04-20 15:22:04 (UTC)
commit78b24a190d51a21cceded6d7869e256441aa6262 (patch) (unidiff)
treecc77a9c413eaa74add0aed3b3934f96712eb8263
parent3fb65729e122d85a27b2a6194f96e37eaed3edd1 (diff)
downloadopie-78b24a190d51a21cceded6d7869e256441aa6262.zip
opie-78b24a190d51a21cceded6d7869e256441aa6262.tar.gz
opie-78b24a190d51a21cceded6d7869e256441aa6262.tar.bz2
OFileNotifier now also supports watching for files which aren't existing yet
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--libopie2/opiecore/ofilenotify.cpp11
1 files changed, 9 insertions, 2 deletions
diff --git a/libopie2/opiecore/ofilenotify.cpp b/libopie2/opiecore/ofilenotify.cpp
index 270570e..5f2a1cc 100644
--- a/libopie2/opiecore/ofilenotify.cpp
+++ b/libopie2/opiecore/ofilenotify.cpp
@@ -1,312 +1,319 @@
1/* 1/*
2                This file is part of the Opie Project 2                This file is part of the Opie Project
3 =. Copyright (C) 2004 Michael 'Mickey' Lauer <mickey@Vanille.de> 3 =. Copyright (C) 2004 Michael 'Mickey' Lauer <mickey@Vanille.de>
4 .=l. Copyright (C) The Opie Team <opie-devel@handhelds.org> 4 .=l. Copyright (C) The Opie Team <opie-devel@handhelds.org>
5          .>+-= 5          .>+-=
6_;:,     .>    :=|. This program is free software; you can 6_;:,     .>    :=|. This program is free software; you can
7.> <`_,   >  .   <= redistribute it and/or modify it under 7.> <`_,   >  .   <= redistribute it and/or modify it under
8:`=1 )Y*s>-.--   : the terms of the GNU Library General Public 8:`=1 )Y*s>-.--   : the terms of the GNU Library General Public
9.="- .-=="i,     .._ License as published by the Free Software 9.="- .-=="i,     .._ License as published by the Free Software
10- .   .-<_>     .<> Foundation; either version 2 of the License, 10- .   .-<_>     .<> Foundation; either version 2 of the License,
11    ._= =}       : or (at your option) any later version. 11    ._= =}       : or (at your option) any later version.
12   .%`+i>       _;_. 12   .%`+i>       _;_.
13   .i_,=:_.      -<s. This program is distributed in the hope that 13   .i_,=:_.      -<s. This program is distributed in the hope that
14    +  .  -:.       = it will be useful, but WITHOUT ANY WARRANTY; 14    +  .  -:.       = it will be useful, but WITHOUT ANY WARRANTY;
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#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 <assert.h>
44#include <fcntl.h> 44#include <fcntl.h>
45#include <string.h> 45#include <string.h>
46#include <errno.h> 46#include <errno.h>
47#include <unistd.h> 47#include <unistd.h>
48 48
49static QIntDict<OFileNotification> notification_list; 49static QIntDict<OFileNotification> notification_list;
50 50
51namespace Opie { 51namespace Opie {
52namespace Core { 52namespace Core {
53 53
54OFileNotification::OFileNotification( QObject* parent, const char* name ) 54OFileNotification::OFileNotification( QObject* parent, const char* name )
55 :QObject( parent, name ), _active( false ) 55 :QObject( parent, name ), _active( false )
56{ 56{
57 qDebug( "OFileNotification::OFileNotification()" ); 57 qDebug( "OFileNotification::OFileNotification()" );
58} 58}
59 59
60 60
61OFileNotification::~OFileNotification() 61OFileNotification::~OFileNotification()
62{ 62{
63 qDebug( "OFileNotification::~OFileNotification()" ); 63 qDebug( "OFileNotification::~OFileNotification()" );
64} 64}
65 65
66 66
67bool OFileNotification::isActive() const 67bool OFileNotification::isActive() const
68{ 68{
69 return _active; 69 return _active;
70} 70}
71 71
72 72
73int OFileNotification::start( const QString& path, bool sshot, OFileNotificationType type ) 73int OFileNotification::start( const QString& path, bool sshot, OFileNotificationType type )
74{ 74{
75 _path = QString::null; 75 _path = QString::null;
76 _fd = 0; 76 _fd = 0;
77 if ( _active ) stop(); 77 if ( _active ) stop();
78 QString dirpath; 78 QString dirpath;
79 79
80 // check if path exists and whether it is a file or a directory, if it exists at all 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 ); 81 int result = ::stat( (const char*) path, &_stat );
82 if ( result == -1 ) 82 if ( !(type & Create) && result == -1 )
83 { 83 {
84 qWarning( "OFileNotification::start(): Can't stat '%s': %s.", (const char*) path, strerror( errno ) ); 84 qWarning( "OFileNotification::start(): Can't stat '%s': %s.", (const char*) path, strerror( errno ) );
85 return -1; 85 return -1;
86 } 86 }
87 87
88 // if it is not a directory, we need to find out in which directory the file is 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 ); 89 bool isDirectory = S_ISDIR( _stat.st_mode );
90 if ( !isDirectory ) 90 if ( !isDirectory )
91 { 91 {
92 int slashpos; 92 int slashpos;
93 slashpos = path.findRev( '/' ); 93 slashpos = path.findRev( '/' );
94 if ( slashpos > 0 ) 94 if ( slashpos > 0 )
95 { 95 {
96 _path = path; 96 _path = path;
97 dirpath = path.left( slashpos ); 97 dirpath = path.left( slashpos );
98 } 98 }
99 } 99 }
100 else /* isDirectory */ 100 else /* isDirectory */
101 { 101 {
102 qWarning( "FIXME FIXME FIXME = Directory Notification Not Yet Implemented!" ); 102 qWarning( "FIXME FIXME FIXME = Directory Notification Not Yet Implemented!" );
103 _path = path; 103 _path = path;
104 dirpath = path; 104 dirpath = path;
105 assert( 0 ); 105 assert( 0 );
106 } 106 }
107 107
108 int fd = ::open( (const char*) dirpath, O_RDONLY ); 108 int fd = ::open( (const char*) dirpath, O_RDONLY );
109 if ( fd != -1 ) 109 if ( fd != -1 )
110 { 110 {
111 if ( notification_list.isEmpty() ) 111 if ( notification_list.isEmpty() )
112 { 112 {
113 OFileNotification::registerSignalHandler(); 113 OFileNotification::registerSignalHandler();
114 } 114 }
115 115
116 result = ::fcntl( fd, F_SETSIG, SIGRTMIN ); 116 result = ::fcntl( fd, F_SETSIG, SIGRTMIN );
117 if ( result == -1 ) 117 if ( result == -1 )
118 { 118 {
119 qWarning( "OFileNotification::start(): Can't subscribe to '%s': %s.", (const char*) dirpath, strerror( errno ) ); 119 qWarning( "OFileNotification::start(): Can't subscribe to '%s': %s.", (const char*) dirpath, strerror( errno ) );
120 return -1; 120 return -1;
121 } 121 }
122 if ( !sshot ) (int) type |= (int) Multi; 122 if ( !sshot ) (int) type |= (int) Multi;
123 result = ::fcntl( fd, F_NOTIFY, type ); 123 result = ::fcntl( fd, F_NOTIFY, type );
124 if ( result == -1 ) 124 if ( result == -1 )
125 { 125 {
126 qWarning( "OFileNotification::start(): Can't subscribe to '%s': %s.", (const char*) dirpath, strerror( errno ) ); 126 qWarning( "OFileNotification::start(): Can't subscribe to '%s': %s.", (const char*) dirpath, strerror( errno ) );
127 return -1; 127 return -1;
128 } 128 }
129 qDebug( "OFileNotification::start(): Subscribed for changes to %s (fd = %d, mask = 0x%0x)", (const char*) dirpath, fd, type ); 129 qDebug( "OFileNotification::start(): Subscribed for changes to %s (fd = %d, mask = 0x%0x)", (const char*) dirpath, fd, type );
130 notification_list.insert( fd, this ); 130 notification_list.insert( fd, this );
131 _type = type; 131 _type = type;
132 _fd = fd; 132 _fd = fd;
133 _active = true; 133 _active = true;
134 ::memset( &_stat, 0, sizeof _stat ); 134 ::memset( &_stat, 0, sizeof _stat );
135 ::stat( _path, &_stat ); 135 ::stat( _path, &_stat );
136 return fd; 136 return fd;
137 } 137 }
138 else 138 else
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 int result = ::stat( _path, &newstat ); // may fail if file has been renamed or deleted. that doesn't matter :) 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( "result of newstat call is %d (%s=%d)", result, result == -1 ? strerror( errno ) : "success", errno );
206 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 );
207 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 ); 208 qDebug( "stat.ctime = %0lx, newstat.ctime = %0lx", (long)_stat.st_ctime, (long)newstat.st_ctime );
209 209
210 if ( !c && (_type & Create) &&
211 (long)_stat.st_atime == 0 && (long)_stat.st_mtime == 0 && (long)_stat.st_ctime == 0 &&
212 (long)newstat.st_atime > 0 && (long)newstat.st_mtime > 0 && (long)newstat.st_ctime > 0)
213 {
214 qDebug( "OFileNotification::hasChanged(): file has been created" );
215 c = true;
216 }
210 if ( !c && (_type & (Delete|Rename)) && (long)newstat.st_atime == 0 && (long)newstat.st_mtime == 0 && (long)newstat.st_ctime == 0) 217 if ( !c && (_type & (Delete|Rename)) && (long)newstat.st_atime == 0 && (long)newstat.st_mtime == 0 && (long)newstat.st_ctime == 0)
211 { 218 {
212 qDebug( "OFileNotification::hasChanged(): file has been deleted or renamed" ); 219 qDebug( "OFileNotification::hasChanged(): file has been deleted or renamed" );
213 c = true; 220 c = true;
214 } 221 }
215 if ( !c && (_type & Access) && (long)_stat.st_atime < (long)newstat.st_atime ) 222 if ( !c && (_type & Access) && (long)_stat.st_atime < (long)newstat.st_atime )
216 { 223 {
217 qDebug( "OFileNotification::hasChanged(): atime changed" ); 224 qDebug( "OFileNotification::hasChanged(): atime changed" );
218 c = true; 225 c = true;
219 } 226 }
220 if ( !c && (_type & Modify) && (long)_stat.st_mtime < (long)newstat.st_mtime ) 227 if ( !c && (_type & Modify) && (long)_stat.st_mtime < (long)newstat.st_mtime )
221 { 228 {
222 qDebug( "OFileNotification::hasChanged(): mtime changed" ); 229 qDebug( "OFileNotification::hasChanged(): mtime changed" );
223 c = true; 230 c = true;
224 } 231 }
225 if ( !c && (_type & Attrib) && (long)_stat.st_ctime < (long)newstat.st_ctime ) 232 if ( !c && (_type & Attrib) && (long)_stat.st_ctime < (long)newstat.st_ctime )
226 { 233 {
227 qDebug( "OFileNotification::hasChanged(): ctime changed" ); 234 qDebug( "OFileNotification::hasChanged(): ctime changed" );
228 c = true; 235 c = true;
229 } 236 }
230 237
231 return c; 238 return c;
232} 239}
233 240
234 241
235void OFileNotification::singleShot( const QString& path, QObject* receiver, const char* member, OFileNotificationType type ) 242void OFileNotification::singleShot( const QString& path, QObject* receiver, const char* member, OFileNotificationType type )
236{ 243{
237 OFileNotification* ofn = new OFileNotification(); 244 OFileNotification* ofn = new OFileNotification();
238 ofn->_signal.connect( receiver, member ); 245 ofn->_signal.connect( receiver, member );
239 ofn->start( path, true, type ); 246 ofn->start( path, true, type );
240} 247}
241 248
242 249
243void OFileNotification::__signalHandler( int sig, siginfo_t *si, void *data ) 250void OFileNotification::__signalHandler( int sig, siginfo_t *si, void *data )
244{ 251{
245 qWarning( "OFileNotification::__signalHandler(): reached." ); 252 qWarning( "OFileNotification::__signalHandler(): reached." );
246 int fd = si->si_fd; 253 int fd = si->si_fd;
247 OFileNotification* fn = notification_list[fd]; 254 OFileNotification* fn = notification_list[fd];
248 if ( fn ) 255 if ( fn )
249 { 256 {
250 // check if it really was the file (dnotify triggers on directory granularity, not file granularity) 257 // check if it really was the file (dnotify triggers on directory granularity, not file granularity)
251 if ( !fn->activate() ) 258 if ( !fn->activate() )
252 { 259 {
253 qDebug( "OFileNotification::__signalHandler(): false alarm ;) Restarting the trigger (if it was single)..." ); 260 qDebug( "OFileNotification::__signalHandler(): false alarm ;) Restarting the trigger (if it was single)..." );
254 if ( !(fn->type() & Multi ) ) 261 if ( !(fn->type() & Multi ) )
255 { 262 {
256 int result = ::fcntl( fn->fileno(), F_NOTIFY, fn->type() ); 263 int result = ::fcntl( fn->fileno(), F_NOTIFY, fn->type() );
257 if ( result == -1 ) 264 if ( result == -1 )
258 { 265 {
259 qWarning( "OFileNotification::__signalHandler(): Can't restart the trigger: %s.", strerror( errno ) ); 266 qWarning( "OFileNotification::__signalHandler(): Can't restart the trigger: %s.", strerror( errno ) );
260 } 267 }
261 } 268 }
262 return; 269 return;
263 } 270 }
264 #if 1 271 #if 1
265 if ( !(fn->type() & Multi) ) 272 if ( !(fn->type() & Multi) )
266 { 273 {
267 qDebug( "OFileNotification::__signalHandler(): '%d' was singleShot. Removing from list.", fd ); 274 qDebug( "OFileNotification::__signalHandler(): '%d' was singleShot. Removing from list.", fd );
268 notification_list.remove( fd ); 275 notification_list.remove( fd );
269 if ( notification_list.isEmpty() ) 276 if ( notification_list.isEmpty() )
270 { 277 {
271 OFileNotification::unregisterSignalHandler(); 278 OFileNotification::unregisterSignalHandler();
272 } 279 }
273 } 280 }
274 #endif 281 #endif
275 } 282 }
276 else 283 else
277 { 284 {
278 qWarning( "OFileNotification::__signalHandler(): D'oh! Called without fd in notification_list. Race condition?" ); 285 qWarning( "OFileNotification::__signalHandler(): D'oh! Called without fd in notification_list. Race condition?" );
279 } 286 }
280} 287}
281 288
282 289
283bool OFileNotification::registerSignalHandler() 290bool OFileNotification::registerSignalHandler()
284{ 291{
285 struct sigaction act; 292 struct sigaction act;
286 act.sa_sigaction = OFileNotification::__signalHandler; 293 act.sa_sigaction = OFileNotification::__signalHandler;
287 ::sigemptyset( &act.sa_mask ); 294 ::sigemptyset( &act.sa_mask );
288 act.sa_flags = SA_SIGINFO; 295 act.sa_flags = SA_SIGINFO;
289 if ( ::sigaction( SIGRTMIN, &act, NULL ) == -1 ) 296 if ( ::sigaction( SIGRTMIN, &act, NULL ) == -1 )
290 { 297 {
291 qWarning( "OFileNotification::registerSignalHandler(): couldn't register signal handler: %s", strerror( errno ) ); 298 qWarning( "OFileNotification::registerSignalHandler(): couldn't register signal handler: %s", strerror( errno ) );
292 return false; 299 return false;
293 } 300 }
294 qDebug( "OFileNotification::registerSignalHandler(): done" ); 301 qDebug( "OFileNotification::registerSignalHandler(): done" );
295} 302}
296 303
297 304
298void OFileNotification::unregisterSignalHandler() 305void OFileNotification::unregisterSignalHandler()
299{ 306{
300 struct sigaction act; 307 struct sigaction act;
301 act.sa_sigaction = ( void (*)(int, siginfo_t*, void*) ) SIG_DFL; 308 act.sa_sigaction = ( void (*)(int, siginfo_t*, void*) ) SIG_DFL;
302 ::sigemptyset( &act.sa_mask ); 309 ::sigemptyset( &act.sa_mask );
303 if ( ::sigaction( SIGRTMIN, &act, NULL ) == -1 ) 310 if ( ::sigaction( SIGRTMIN, &act, NULL ) == -1 )
304 { 311 {
305 qWarning( "OFileNotification::unregisterSignalHandler(): couldn't deregister signal handler: %s", strerror( errno ) ); 312 qWarning( "OFileNotification::unregisterSignalHandler(): couldn't deregister signal handler: %s", strerror( errno ) );
306 } 313 }
307 qDebug( "OFileNotification::unregisterSignalHandler(): done" ); 314 qDebug( "OFileNotification::unregisterSignalHandler(): done" );
308} 315}
309 316
310 317
311} 318}
312} 319}