summaryrefslogtreecommitdiff
path: root/libopie2/opiecore/ofilenotify.cpp
Unidiff
Diffstat (limited to 'libopie2/opiecore/ofilenotify.cpp') (more/less context) (show whitespace changes)
-rw-r--r--libopie2/opiecore/ofilenotify.cpp114
1 files changed, 93 insertions, 21 deletions
diff --git a/libopie2/opiecore/ofilenotify.cpp b/libopie2/opiecore/ofilenotify.cpp
index 11d4f87..4264327 100644
--- a/libopie2/opiecore/ofilenotify.cpp
+++ b/libopie2/opiecore/ofilenotify.cpp
@@ -37,48 +37,66 @@ using namespace Opie::Core;
37#include <qsignal.h> 37#include <qsignal.h>
38#include <qintdict.h> 38#include <qintdict.h>
39#include <qdir.h> 39#include <qdir.h>
40 40
41/* STD */ 41/* STD */
42#include <sys/types.h> 42#include <sys/types.h>
43#include <sys/stat.h> 43#include <sys/stat.h>
44#include <sys/ioctl.h> 44#include <sys/ioctl.h>
45#include <fcntl.h> 45#include <fcntl.h>
46#include <assert.h> 46#include <assert.h>
47#include <string.h> 47#include <string.h>
48#include <errno.h> 48#include <errno.h>
49#include <unistd.h> 49#include <unistd.h>
50 50
51static QIntDict<OFileNotification> notification_list; 51static QIntDict<OFileNotification> notification_list;
52 52
53QSocketNotifier* OFileNotification::_sn; 53QSocketNotifier* OFileNotification::_sn;
54int OFileNotification::_fd = -1; 54int OFileNotification::_fd = -1;
55 55
56#define INOTIFY_DEVICE "/dev/inotify" 56#define INOTIFY_DEVICE "/dev/inotify"
57 57
58namespace Opie { 58namespace Opie {
59namespace Core { 59namespace Core {
60 60
61//=================================================================================================
62// OFileNotificationEvent
63//=================================================================================================
64OFileNotificationEvent::OFileNotificationEvent( OFileNotification* parent, int wd, unsigned int mask, unsigned int cookie, const QString& name )
65 :_parent( parent ), _wd( wd ), _mask( mask ), _cookie( cookie ), _name( name )
66{
67 qDebug( "OFileNotificationEvent()" );
68}
69
70
71OFileNotificationEvent::~OFileNotificationEvent()
72{
73 qDebug( "~OFileNotificationEvent()" );
74}
75
76//=================================================================================================
77// OFileNotification
78//=================================================================================================
61OFileNotification::OFileNotification( QObject* parent, const char* name ) 79OFileNotification::OFileNotification( QObject* parent, const char* name )
62 :QObject( parent, name ), _active( false ), _multi( true ) 80 :QObject( parent, name ), _active( false ), _multi( true )
63{ 81{
64 qDebug( "OFileNotification::OFileNotification()" ); 82 qDebug( "OFileNotification::OFileNotification()" );
65} 83}
66 84
67 85
68OFileNotification::~OFileNotification() 86OFileNotification::~OFileNotification()
69{ 87{
70 stop(); 88 stop();
71 qDebug( "OFileNotification::~OFileNotification()" ); 89 qDebug( "OFileNotification::~OFileNotification()" );
72} 90}
73 91
74 92
75bool OFileNotification::isActive() const 93bool OFileNotification::isActive() const
76{ 94{
77 return _active; 95 return _active;
78} 96}
79 97
80 98
81int OFileNotification::watch( const QString& path, bool sshot, OFileNotificationType type ) 99int OFileNotification::watch( const QString& path, bool sshot, OFileNotificationType type )
82{ 100{
83 // check if path exists and is a regular file 101 // check if path exists and is a regular file
84 struct stat s; 102 struct stat s;
@@ -131,104 +149,121 @@ void OFileNotification::stop()
131{ 149{
132 notification_list.remove( _wd ); 150 notification_list.remove( _wd );
133 _path = QString::null; 151 _path = QString::null;
134 _wd = 0; 152 _wd = 0;
135 _active = false; 153 _active = false;
136 if ( notification_list.isEmpty() ) 154 if ( notification_list.isEmpty() )
137 { 155 {
138 OFileNotification::unregisterEventHandler(); 156 OFileNotification::unregisterEventHandler();
139 } 157 }
140} 158}
141 159
142 160
143OFileNotificationType OFileNotification::type() const 161OFileNotificationType OFileNotification::type() const
144{ 162{
145 return _type; 163 return _type;
146} 164}
147 165
148 166
149QString OFileNotification::path() const 167QString OFileNotification::path() const
150{ 168{
151 return _path; 169 return _path;
152} 170}
153 171
154 172
155bool OFileNotification::activate() 173bool OFileNotification::activate( const OFileNotificationEvent* e )
156{ 174{
157 emit triggered( _path ); 175 qDebug( "OFileNotification::activate(): e = ( %s, %d, 0x%08x, %d, %s )", (const char*) _path, e->descriptor(), e->mask(), e->cookie(), (const char*) e->name() );
176
177 // dumb signal
158 _signal.activate(); 178 _signal.activate();
179
180 // generic signal
181 emit triggered( _path, e->mask(), e->name() );
182
183 // specialized signals
184 switch ( e->mask() )
185 {
186 case Access: emit accessed( _path ); break;
187 case Modify: emit modified( _path ); break;
188 case Attrib: emit attributed( _path); break;
189 case CloseWrite: emit closed( _path, true ); break;
190 case CloseNoWrite: emit closed( _path, false ); break;
191 case Open: emit opened( _path ); break;
192 case MovedFrom: emit movedFrom( _path, e->name() ); break;
193 case MovedTo: emit movedTo( _path, e->name() ); break;
194 case DeleteSubdir: emit deletedSubdir( _path, e->name() ); break;
195 case DeleteFile: emit deletedFile( _path, e->name() ); break;
196 case CreateSubdir: emit createdSubdir( _path, e->name() ); break;
197 case CreateFile: emit createdFile( _path, e->name() ); break;
198 case DeleteSelf: emit deleted( _path ); break;
199 case Unmount: emit unmounted( _path ); break;
200 default: assert( 0 );
201 }
202
159 if ( !_multi ) stop(); 203 if ( !_multi ) stop();
204
160 return true; 205 return true;
161} 206}
162 207
163 208
164bool OFileNotification::singleShot( const QString& path, QObject* receiver, const char* member, OFileNotificationType type ) 209bool OFileNotification::singleShot( const QString& path, QObject* receiver, const char* member, OFileNotificationType type )
165{ 210{
166 OFileNotification* ofn = new OFileNotification(); 211 OFileNotification* ofn = new OFileNotification();
167 ofn->_signal.connect( receiver, member ); 212 ofn->_signal.connect( receiver, member );
168 return ofn->watch( path, true, type ) != -1; 213 return ofn->watch( path, true, type ) != -1;
169} 214}
170 215
171 216
172void OFileNotification::inotifyEventHandler() 217void OFileNotification::inotifyEventHandler()
173{ 218{
174 qWarning( "OFileNotification::__eventHandler(): reached." ); 219 qDebug( "OFileNotification::inotifyEventHandler(): reached." );
175 220
176 char buffer[16384]; 221 char buffer[16384];
177 size_t buffer_i; 222 size_t buffer_i;
178 struct inotify_event *pevent, *event; 223 struct inotify_event *pevent, *event;
179 ssize_t r; 224 ssize_t r;
180 size_t event_size; 225 size_t event_size;
181 int count = 0; 226 int count = 0;
182 227
183 r = ::read(_fd, buffer, 16384); 228 r = ::read(_fd, buffer, 16384);
184 229
185 if ( r <= 0 ) 230 if ( r <= 0 )
186 return; 231 return;
187 232
188 buffer_i = 0; 233 buffer_i = 0;
189 while ( buffer_i < r ) 234 while ( buffer_i < r )
190 { 235 {
191 /* Parse events and queue them ! */
192 pevent = (struct inotify_event *)&buffer[buffer_i]; 236 pevent = (struct inotify_event *)&buffer[buffer_i];
193 event_size = sizeof(struct inotify_event) + pevent->len; 237 event_size = sizeof(struct inotify_event) + pevent->len;
194 qDebug( "pevent->len = %d\n", pevent->len); 238 OFileNotificationEvent* e = new OFileNotificationEvent( notification_list[ pevent->wd ], pevent->wd, pevent->mask,
195 239 pevent->cookie, pevent->len ? pevent->name : 0 );
196 OFileNotification* fn = notification_list[ pevent->wd ]; 240 e->activate();
197 if ( fn )
198 fn->activate();
199 else
200 assert( false );
201
202 //event = malloc(event_size);
203 //memmove(event, pevent, event_size);
204 //queue_enqueue(event, q);
205 buffer_i += event_size; 241 buffer_i += event_size;
206 count++; 242 count++;
207 } 243 }
208 244
209 qDebug( "received %d events...", count ); 245 qDebug( "OFileNotification::inotifyEventHandler(): processed %d events", count );
210 return;
211} 246}
212 247
213 248
214bool OFileNotification::registerEventHandler() 249bool OFileNotification::registerEventHandler()
215{ 250{
216 OFileNotification::_fd = ::open( INOTIFY_DEVICE, O_RDONLY ); 251 OFileNotification::_fd = ::open( INOTIFY_DEVICE, O_RDONLY );
217 if ( OFileNotification::_fd < 0 ) 252 if ( OFileNotification::_fd < 0 )
218 { 253 {
219 qWarning( "OFileNotification::registerEventHandler(): couldn't register event handler: %s", strerror( errno ) ); 254 qWarning( "OFileNotification::registerEventHandler(): couldn't register event handler: %s", strerror( errno ) );
220 return false; 255 return false;
221 } 256 }
222 257
223 OFileNotification::_sn = new QSocketNotifier( _fd, QSocketNotifier::Read, this, "inotify event" ); 258 OFileNotification::_sn = new QSocketNotifier( _fd, QSocketNotifier::Read, this, "inotify event" );
224 connect( OFileNotification::_sn, SIGNAL( activated(int) ), this, SLOT( inotifyEventHandler() ) ); 259 connect( OFileNotification::_sn, SIGNAL( activated(int) ), this, SLOT( inotifyEventHandler() ) );
225 260
226 qDebug( "OFileNotification::registerEventHandler(): done" ); 261 qDebug( "OFileNotification::registerEventHandler(): done" );
227 return true; 262 return true;
228} 263}
229 264
230 265
231void OFileNotification::unregisterEventHandler() 266void OFileNotification::unregisterEventHandler()
232{ 267{
233 if ( _sn ) delete _sn; 268 if ( _sn ) delete _sn;
234 if ( OFileNotification::_fd ) 269 if ( OFileNotification::_fd )
@@ -241,38 +276,75 @@ void OFileNotification::unregisterEventHandler()
241//================================================================================================= 276//=================================================================================================
242ODirNotification::ODirNotification( QObject* parent, const char* name ) 277ODirNotification::ODirNotification( QObject* parent, const char* name )
243 :QObject( parent, name ) 278 :QObject( parent, name )
244{ 279{
245 qDebug( "ODirNotification::ODirNotification()" ); 280 qDebug( "ODirNotification::ODirNotification()" );
246} 281}
247 282
248 283
249ODirNotification::~ODirNotification() 284ODirNotification::~ODirNotification()
250{ 285{
251 qDebug( "ODirNotification::~ODirNotification()" ); 286 qDebug( "ODirNotification::~ODirNotification()" );
252} 287}
253 288
254 289
255int ODirNotification::watch( const QString& path, bool sshot, OFileNotificationType type, int recurse ) 290int ODirNotification::watch( const QString& path, bool sshot, OFileNotificationType type, int recurse )
256{ 291{
257 qDebug( "ODirNotification::watch( %s, %d, 0x%08x, %d )", (const char*) path, sshot, type, recurse ); 292 qDebug( "ODirNotification::watch( %s, %d, 0x%08x, %d )", (const char*) path, sshot, type, recurse );
258 293
259 if ( recurse == 0 ) 294 if ( recurse == 0 )
260 { 295 {
261 OFileNotification* fn = new OFileNotification( this, "ODirNotification delegate" ); 296 OFileNotification* fn = new OFileNotification( this, "ODirNotification delegate" );
262 int result = fn->startWatching( path, sshot, type ); 297 int result = fn->startWatching( path, sshot, type );
263 if ( result != -1 ) 298 if ( result != -1 )
264 { 299 {
265 connect( fn, SIGNAL( triggered( const QString& ) ), this, SIGNAL( triggered( const QString& ) ) ); 300 connect( fn, SIGNAL( triggered( const QString&, unsigned int, const QString& ) ), this, SIGNAL( triggered( const QString&, unsigned int, const QString& ) ) );
266 return result; 301 connect( fn, SIGNAL( accessed( const QString& ) ), this, SIGNAL( accessed( const QString& ) ) );
302 connect( fn, SIGNAL( modified( const QString& ) ), this, SIGNAL( modified( const QString& ) ) );
303 connect( fn, SIGNAL( attributed( const QString& ) ), this, SIGNAL( attributed( const QString& ) ) );
304 connect( fn, SIGNAL( closed( const QString&, bool ) ), this, SIGNAL( closed( const QString&, bool ) ) );
305 connect( fn, SIGNAL( opened( const QString& ) ), this, SIGNAL( opened( const QString& ) ) );
306 connect( fn, SIGNAL( movedTo( const QString&, const QString& ) ), this, SIGNAL( movedTo( const QString&, const QString& ) ) );
307 connect( fn, SIGNAL( movedFrom( const QString&, const QString& ) ), this, SIGNAL( movedFrom( const QString&, const QString& ) ) );
308 connect( fn, SIGNAL( deletedSubdir( const QString&, const QString& ) ), this, SIGNAL( deletedSubdir( const QString&, const QString& ) ) );
309 connect( fn, SIGNAL( deletedFile( const QString&, const QString& ) ), this, SIGNAL( deletedFile( const QString&, const QString& ) ) );;
310 connect( fn, SIGNAL( createdSubdir( const QString&, const QString& ) ), this, SIGNAL( createdSubdir( const QString&, const QString& ) ) );
311 connect( fn, SIGNAL( createdFile( const QString&, const QString& ) ), this, SIGNAL( createdFile( const QString&, const QString& ) ) );
312 connect( fn, SIGNAL( deleted( const QString& ) ), this, SIGNAL( deleted( const QString& ) ) );
313 connect( fn, SIGNAL( unmounted( const QString& ) ), this, SIGNAL( unmounted( const QString& ) ) );
267 } 314 }
315 return result;
268 } 316 }
269 else 317 else
270 { 318 {
271 qDebug( "ODirNotification::watch(), recursion not yet implemented... :)" ); 319
272 return -1; 320 return 1;
273 } 321 }
274} 322}
275 323
324
325// void ODirNotification::subdirCreated( const QString& name )
326
327
328/*
329 Love-Trowbridge recursive directory scanning algorithm:
330
331 Step 1. Start at initial directory foo. Add watch.
332
333 Step 2. Setup handlers for watch created in Step 1.
334 Specifically, ensure that a directory created
335 in foo will result in a handled CREATE_SUBDIR
336 event.
337
338 Step 3. Read the contents of foo.
339
340 Step 4. For each subdirectory of foo read in step 3, repeat
341 step 1.
342
343 Step 5. For any CREATE_SUBDIR event on bar, if a watch is
344 not yet created on bar, repeat step 1 on bar.
345*/
346
347
276} // namespace Ui 348} // namespace Ui
277 349
278} // namespace Opie 350} // namespace Opie