summaryrefslogtreecommitdiff
path: root/libopie2
authormickeyl <mickeyl>2005-05-02 13:49:14 (UTC)
committer mickeyl <mickeyl>2005-05-02 13:49:14 (UTC)
commit8cbb0586482ec650d7ff4fa9b6a7390b8b050793 (patch) (side-by-side diff)
tree926c2fedf0f62a965362178620625e3ddc5171de /libopie2
parent3a86e1464fb00d3d9b9962bcabc1041d8a3d9343 (diff)
downloadopie-8cbb0586482ec650d7ff4fa9b6a7390b8b050793.zip
opie-8cbb0586482ec650d7ff4fa9b6a7390b8b050793.tar.gz
opie-8cbb0586482ec650d7ff4fa9b6a7390b8b050793.tar.bz2
Rewrite OFileNotification to use the upcoming inotify (kernel 2.6) interface instead of the deprecated dnotify
Diffstat (limited to 'libopie2') (more/less context) (ignore whitespace changes)
-rw-r--r--libopie2/opiecore/ofilenotify.cpp272
-rw-r--r--libopie2/opiecore/ofilenotify.h93
2 files changed, 139 insertions, 226 deletions
diff --git a/libopie2/opiecore/ofilenotify.cpp b/libopie2/opiecore/ofilenotify.cpp
index 2a9bb8c..c221e58 100644
--- a/libopie2/opiecore/ofilenotify.cpp
+++ b/libopie2/opiecore/ofilenotify.cpp
@@ -2,3 +2,3 @@
                This file is part of the Opie Project
- =. Copyright (C) 2004 Michael 'Mickey' Lauer <mickey@Vanille.de>
+ =. Copyright (C) 2004-2005 Michael 'Mickey' Lauer <mickey@Vanille.de>
.=l. Copyright (C) The Opie Team <opie-devel@handhelds.org>
@@ -9,4 +9,4 @@ _;:,     .>    :=|. This program is free software; you can
.="- .-=="i,     .._ License as published by the Free Software
-- .   .-<_>     .<> Foundation; either version 2 of the License,
-    ._= =}       : or (at your option) any later version.
+- .   .-<_>     .<> Foundation; version 2 of the License.
+    ._= =}       :
  .%`+i>       _;_.
@@ -35,2 +35,3 @@ using namespace Opie::Core;
#include <qobject.h>
+#include <qsocketnotifier.h>
#include <qsignal.h>
@@ -42,4 +43,5 @@ using namespace Opie::Core;
#include <sys/stat.h>
-#include <assert.h>
+#include <sys/ioctl.h>
#include <fcntl.h>
+#include <assert.h>
#include <string.h>
@@ -50,2 +52,7 @@ static QIntDict<OFileNotification> notification_list;
+QSocketNotifier* OFileNotification::_sn;
+int OFileNotification::_fd = -1;
+
+#define INOTIFY_DEVICE "/dev/inotify"
+
namespace Opie {
@@ -54,3 +61,3 @@ namespace Core {
OFileNotification::OFileNotification( QObject* parent, const char* name )
- :QObject( parent, name ), _active( false )
+ :QObject( parent, name ), _active( false ), _multi( true )
{
@@ -62,2 +69,3 @@ OFileNotification::~OFileNotification()
{
+ stop();
qDebug( "OFileNotification::~OFileNotification()" );
@@ -72,39 +80,5 @@ bool OFileNotification::isActive() const
-int OFileNotification::start( const QString& path, bool sshot, OFileNotificationType type )
+int OFileNotification::watch( const QString& path, bool sshot, OFileNotificationType type )
{
- _path = QString::null;
- _fd = 0;
- if ( _active ) stop();
- QString dirpath;
-
- // check if path exists and whether it is a file or a directory, if it exists at all
- int result = ::stat( (const char*) path, &_stat );
- if ( !(type & Create) && result == -1 )
- {
- qWarning( "OFileNotification::start(): Can't stat '%s': %s.", (const char*) path, strerror( errno ) );
- return -1;
- }
-
- // if it is not a directory, we need to find out in which directory the file is
- bool isDirectory = S_ISDIR( _stat.st_mode );
- if ( !isDirectory )
- {
- int slashpos;
- slashpos = path.findRev( '/' );
- if ( slashpos > 0 )
- {
- _path = path;
- dirpath = path.left( slashpos );
- }
- }
- else /* isDirectory */
- {
- qWarning( "FIXME FIXME FIXME = Directory Notification Not Yet Implemented!" );
- _path = path;
- dirpath = path;
- assert( 0 );
- }
-
- int fd = ::open( (const char*) dirpath, O_RDONLY );
- if ( fd != -1 )
+ if ( QFile::exists( path ) )
{
@@ -112,26 +86,24 @@ int OFileNotification::start( const QString& path, bool sshot, OFileNotification
{
- OFileNotification::registerSignalHandler();
+ OFileNotification::registerEventHandler();
}
- result = ::fcntl( fd, F_SETSIG, SIGRTMIN );
- if ( result == -1 )
- {
- qWarning( "OFileNotification::start(): Can't subscribe to '%s': %s.", (const char*) dirpath, strerror( errno ) );
- return -1;
- }
- if ( !sshot ) type = static_cast<OFileNotificationType>( (int) type | (int) Multi );
- result = ::fcntl( fd, F_NOTIFY, type );
- if ( result == -1 )
+ struct inotify_watch_request iwr;
+ ::memset( &iwr, 0, sizeof iwr );
+ iwr.name = const_cast<char*>( (const char*) path );
+ iwr.mask = type;
+
+ _wd = ::ioctl( OFileNotification::_fd, INOTIFY_WATCH, &iwr );
+
+ if ( _wd < 0 )
{
- qWarning( "OFileNotification::start(): Can't subscribe to '%s': %s.", (const char*) dirpath, strerror( errno ) );
+ qWarning( "OFileNotification::watch(): inotify can't watch '%s': %s.", (const char*) path, strerror( errno ) );
return -1;
}
- qDebug( "OFileNotification::start(): Subscribed for changes to %s (fd = %d, mask = 0x%0x)", (const char*) dirpath, fd, type );
- notification_list.insert( fd, this );
+
+ notification_list.insert( _wd, this );
+ _multi = !sshot;
_type = type;
- _fd = fd;
_active = true;
- ::memset( &_stat, 0, sizeof _stat );
- ::stat( _path, &_stat );
- return fd;
+ qDebug( "OFileNotification::watch(): watching '%s' [wd=%d].", (const char*) path, _wd );
+ return _wd;
}
@@ -139,3 +111,3 @@ int OFileNotification::start( const QString& path, bool sshot, OFileNotification
{
- qWarning( "OFileNotification::start(): Error with path '%s': %s.", (const char*) dirpath, strerror( errno ) );
+ qWarning( "OFileNotification::watch(): Can't watch '%s': %s.", (const char*) path, strerror( errno ) );
return -1;
@@ -147,16 +119,9 @@ void OFileNotification::stop()
{
- if ( !_active ) return;
-
- int result = ::fcntl( _fd, F_NOTIFY, 0 );
- if ( result == -1 )
- {
- qWarning( "OFileNotification::stop(): Can't remove subscription to '%s': %s.", (const char*) _path, strerror( errno ) );
- }
- else
+ notification_list.remove( _wd );
+ _path = QString::null;
+ _wd = 0;
+ _active = false;
+ if ( notification_list.isEmpty() )
{
- ::close( _fd );
- _type = Single;
- _path = QString::null;
- _fd = 0;
- _active = false;
+ OFileNotification::unregisterEventHandler();
}
@@ -177,5 +142,8 @@ QString OFileNotification::path() const
-int OFileNotification::fileno() const
+bool OFileNotification::activate()
{
- return _fd;
+ emit triggered();
+ _signal.activate();
+ if ( !_multi ) stop();
+ return true;
}
@@ -183,12 +151,7 @@ int OFileNotification::fileno() const
-bool OFileNotification::activate()
+void OFileNotification::singleShot( const QString& path, QObject* receiver, const char* member, OFileNotificationType type )
{
- if ( hasChanged() )
- {
- emit triggered();
- _signal.activate();
- return true;
- }
- else
- return false;
+ OFileNotification* ofn = new OFileNotification();
+ ofn->_signal.connect( receiver, member );
+ ofn->watch( path, true, type );
}
@@ -196,52 +159,41 @@ bool OFileNotification::activate()
-bool OFileNotification::hasChanged()
+void OFileNotification::inotifyEventHandler()
{
- bool c = false;
+ qWarning( "OFileNotification::__eventHandler(): reached." );
- struct stat newstat;
- ::memset( &newstat, 0, sizeof newstat );
- int result = ::stat( _path, &newstat ); // may fail if file has been renamed or deleted. that doesn't matter :)
+ char buffer[16384];
+ size_t buffer_i;
+ struct inotify_event *pevent, *event;
+ ssize_t r;
+ size_t event_size;
+ int count = 0;
- qDebug( "result of newstat call is %d (%s=%d)", result, result == -1 ? strerror( errno ) : "success", errno );
- qDebug( "stat.atime = %0lx, newstat.atime = %0lx", (long)_stat.st_atime, (long)newstat.st_atime );
- qDebug( "stat.mtime = %0lx, newstat.mtime = %0lx", (long)_stat.st_mtime, (long)newstat.st_mtime );
- qDebug( "stat.ctime = %0lx, newstat.ctime = %0lx", (long)_stat.st_ctime, (long)newstat.st_ctime );
+ r = ::read(_fd, buffer, 16384);
- if ( !c && (_type & Create) &&
- (long)_stat.st_atime == 0 && (long)_stat.st_mtime == 0 && (long)_stat.st_ctime == 0 &&
- (long)newstat.st_atime > 0 && (long)newstat.st_mtime > 0 && (long)newstat.st_ctime > 0)
- {
- qDebug( "OFileNotification::hasChanged(): file has been created" );
- c = true;
- }
- if ( !c && (_type & (Delete|Rename)) && (long)newstat.st_atime == 0 && (long)newstat.st_mtime == 0 && (long)newstat.st_ctime == 0)
- {
- qDebug( "OFileNotification::hasChanged(): file has been deleted or renamed" );
- c = true;
- }
- if ( !c && (_type & Access) && (long)_stat.st_atime < (long)newstat.st_atime )
- {
- qDebug( "OFileNotification::hasChanged(): atime changed" );
- c = true;
- }
- if ( !c && (_type & Modify) && (long)_stat.st_mtime < (long)newstat.st_mtime )
- {
- qDebug( "OFileNotification::hasChanged(): mtime changed" );
- c = true;
- }
- if ( !c && (_type & Attrib) && (long)_stat.st_ctime < (long)newstat.st_ctime )
+ if ( r <= 0 )
+ return;
+
+ buffer_i = 0;
+ while ( buffer_i < r )
{
- qDebug( "OFileNotification::hasChanged(): ctime changed" );
- c = true;
- }
+ /* Parse events and queue them ! */
+ pevent = (struct inotify_event *)&buffer[buffer_i];
+ event_size = sizeof(struct inotify_event) + pevent->len;
+ qDebug( "pevent->len = %d\n", pevent->len);
- return c;
-}
+ OFileNotification* fn = notification_list[ pevent->wd ];
+ if ( fn )
+ fn->activate();
+ else
+ assert( false );
+ //event = malloc(event_size);
+ //memmove(event, pevent, event_size);
+ //queue_enqueue(event, q);
+ buffer_i += event_size;
+ count++;
+ }
-void OFileNotification::singleShot( const QString& path, QObject* receiver, const char* member, OFileNotificationType type )
-{
- OFileNotification* ofn = new OFileNotification();
- ofn->_signal.connect( receiver, member );
- ofn->start( path, true, type );
+ qDebug( "received %d events...", count );
+ return;
}
@@ -249,56 +201,15 @@ void OFileNotification::singleShot( const QString& path, QObject* receiver, cons
-void OFileNotification::__signalHandler( int sig, siginfo_t *si, void *data )
+bool OFileNotification::registerEventHandler()
{
- Q_UNUSED( sig )
- Q_UNUSED( data )
- qWarning( "OFileNotification::__signalHandler(): reached." );
- int fd = si->si_fd;
- OFileNotification* fn = notification_list[fd];
- if ( fn )
- {
- // check if it really was the file (dnotify triggers on directory granularity, not file granularity)
- if ( !fn->activate() )
- {
- qDebug( "OFileNotification::__signalHandler(): false alarm ;) Restarting the trigger (if it was single)..." );
- if ( !(fn->type() & Multi ) )
- {
- int result = ::fcntl( fn->fileno(), F_NOTIFY, fn->type() );
- if ( result == -1 )
- {
- qWarning( "OFileNotification::__signalHandler(): Can't restart the trigger: %s.", strerror( errno ) );
- }
- }
- return;
- }
- #if 1
- if ( !(fn->type() & Multi) )
- {
- qDebug( "OFileNotification::__signalHandler(): '%d' was singleShot. Removing from list.", fd );
- notification_list.remove( fd );
- if ( notification_list.isEmpty() )
- {
- OFileNotification::unregisterSignalHandler();
- }
- }
- #endif
- }
- else
+ OFileNotification::_fd = ::open( INOTIFY_DEVICE, O_RDONLY );
+ if ( OFileNotification::_fd < 0 )
{
- qWarning( "OFileNotification::__signalHandler(): D'oh! Called without fd in notification_list. Race condition?" );
+ qWarning( "OFileNotification::registerEventHandler(): couldn't register event handler: %s", strerror( errno ) );
+ return false;
}
-}
+ OFileNotification::_sn = new QSocketNotifier( _fd, QSocketNotifier::Read, this, "inotify event" );
+ connect( OFileNotification::_sn, SIGNAL( activated(int) ), this, SLOT( inotifyEventHandler() ) );
-bool OFileNotification::registerSignalHandler()
-{
- struct sigaction act;
- act.sa_sigaction = OFileNotification::__signalHandler;
- ::sigemptyset( &act.sa_mask );
- act.sa_flags = SA_SIGINFO;
- if ( ::sigaction( SIGRTMIN, &act, NULL ) == -1 )
- {
- qWarning( "OFileNotification::registerSignalHandler(): couldn't register signal handler: %s", strerror( errno ) );
- return false;
- }
- qDebug( "OFileNotification::registerSignalHandler(): done" );
+ qDebug( "OFileNotification::registerEventHandler(): done" );
return true;
@@ -307,12 +218,7 @@ bool OFileNotification::registerSignalHandler()
-void OFileNotification::unregisterSignalHandler()
+void OFileNotification::unregisterEventHandler()
{
- struct sigaction act;
- act.sa_sigaction = ( void (*)(int, siginfo_t*, void*) ) SIG_DFL;
- ::sigemptyset( &act.sa_mask );
- if ( ::sigaction( SIGRTMIN, &act, NULL ) == -1 )
- {
- qWarning( "OFileNotification::unregisterSignalHandler(): couldn't deregister signal handler: %s", strerror( errno ) );
- }
- qDebug( "OFileNotification::unregisterSignalHandler(): done" );
+ if ( OFileNotification::_fd )
+ ::close( OFileNotification::_fd );
+ qDebug( "OFileNotification::unregisterEventHandler(): done" );
}
diff --git a/libopie2/opiecore/ofilenotify.h b/libopie2/opiecore/ofilenotify.h
index d820f7c..e3621cf 100644
--- a/libopie2/opiecore/ofilenotify.h
+++ b/libopie2/opiecore/ofilenotify.h
@@ -2,3 +2,3 @@
                This file is part of the Opie Project
- =. Copyright (C) 2004 Michael 'Mickey' Lauer <mickey@Vanille.de>
+ =. Copyright (C) 2004-2005 Michael 'Mickey' Lauer <mickey@Vanille.de>
.=l. Copyright (C) The Opie Team <opie-devel@handhelds.org>
@@ -9,4 +9,4 @@ _;:,     .>    :=|. This program is free software; you can
.="- .-=="i,     .._ License as published by the Free Software
-- .   .-<_>     .<> Foundation; either version 2 of the License,
-    ._= =}       : or (at your option) any later version.
+- .   .-<_>     .<> Foundation; version 2 of the License.
+    ._= =}       :
  .%`+i>       _;_.
@@ -35,3 +35,3 @@ _;:,     .>    :=|. This program is free software; you can
/* QT */
-#include <qobject.h>
+#include <qsocketnotifier.h>
#include <qsignal.h>
@@ -40,4 +40,3 @@ _;:,     .>    :=|. This program is free software; you can
/* STD */
-#include <signal.h>
-#include <fcntl.h>
+#include "inotify.h"
@@ -58,6 +57,14 @@ namespace Core {
* <li>Modify The file was modified (write,truncate)
- * <li>Create = The file was created in the directory
- * <li>Delete = The file was unlinked from directory
- * <li>Rename = The file was renamed
* <li>Attrib = The file had its attributes changed (chmod,chown,chgrp)
+ * <li>CloseWrite = Writable file was closed
+ * <li>CloseNoWrite = Unwritable file was closed
+ * <li>Open = File was opened
+ * <li>MovedFrom = File was moved from X
+ * <li>MovedTo = File was moved to Y
+ * <li>DeleteSubdir = Subdir was deleted
+ * <li>DeleteFile = Subfile was deleted
+ * <li>CreateSubdir = Subdir was created
+ * <li>CreateFile = Subfile was created
+ * <li>DeleteSelf = Self was deleted
+ * <li>Unmount = The backing filesystem was unmounted
* </ul>
@@ -66,10 +73,21 @@ namespace Core {
-enum OFileNotificationType { Single = 0x0000000,
- Multi = DN_MULTISHOT,
- Access = DN_ACCESS,
- Modify = DN_MODIFY,
- Create = DN_CREATE,
- Delete = DN_DELETE,
- Rename = DN_RENAME,
- Attrib = DN_ATTRIB };
+enum OFileNotificationType
+{
+ Access = IN_ACCESS,
+ Modify = IN_MODIFY,
+ Attrib = IN_ATTRIB,
+ CloseWrite = IN_CLOSE_WRITE,
+ CloseNoWrite = IN_CLOSE_NOWRITE,
+ Open = IN_OPEN,
+ MovedFrom = IN_MOVED_FROM,
+ MovedTo = IN_MOVED_TO,
+ DeleteSubdir = IN_DELETE_SUBDIR,
+ DeleteFile = IN_DELETE_FILE,
+ CreateSubdir = IN_CREATE_SUBDIR,
+ CreateFile = IN_CREATE_FILE,
+ DeleteSelf = IN_DELETE_SELF,
+ Unmount = IN_UNMOUNT,
+ _QueueOverflow = IN_Q_OVERFLOW, /* Internal, don't use this in client code */
+ _Ignored = IN_IGNORED, /* Internal, don't use this in client code */
+};
@@ -83,5 +101,5 @@ enum OFileNotificationType { Single = 0x0000000,
* This class allows to watch for events happening to files.
- * It uses the dnotify kernel interface which is a very efficient signalling interface.
+ * It uses the inotify kernel interface
*
- * @see <file:///usr/src/linux/Documentation/dnotify.txt>
+ * @see http://www.kernel.org/pub/linux/kernel/people/rml/inotify/
*
@@ -108,3 +126,3 @@ class OFileNotification : public QObject
* #include <opie2/oapplication.h>
- * #include <opie2/onitify.h>
+ * #include <opie2/ofilenotify.h>
* using namespace Opie::Core;
@@ -120,3 +138,3 @@ class OFileNotification : public QObject
*
- * This sample program automatically terminates when the file "/tmp/quite" has been created.
+ * This sample program automatically terminates when the file "/tmp/quit" has been created.
*
@@ -130,3 +148,3 @@ class OFileNotification : public QObject
**/
- int start( const QString& path, bool sshot = false, OFileNotificationType type = Modify );
+ int watch( const QString& path, bool sshot = false, OFileNotificationType type = Modify );
/**
@@ -144,6 +162,2 @@ class OFileNotification : public QObject
/**
- * @returns the UNIX file descriptor for the file being watched.
- **/
- int fileno() const;
- /**
* @returns if a file is currently being watched.
@@ -160,8 +174,10 @@ class OFileNotification : public QObject
bool activate();
- virtual bool hasChanged();
- static bool registerSignalHandler();
- static void unregisterSignalHandler();
- static void __signalHandler( int sig, siginfo_t *si, void *data );
+
+ private slots:
+ void inotifyEventHandler();
private:
+ bool registerEventHandler();
+ void unregisterEventHandler();
+
QString _path;
@@ -169,18 +185,9 @@ class OFileNotification : public QObject
QSignal _signal;
- int _fd;
bool _active;
- struct stat _stat;
-};
-
-#if 0
-
-class ODirectoryNotification : public OFileNotification
-{
-
- public:
- virtual bool hasChanged() { return true; };
+ bool _multi;
+ static QSocketNotifier* _sn;
+ int _wd; // inotify watch descriptor
+ static int _fd; // inotify device descriptor
};
-#endif
-
}