-rw-r--r-- | libopie2/opiecore/ofilenotify.cpp | 98 | ||||
-rw-r--r-- | libopie2/opiecore/ofilenotify.h | 4 |
2 files changed, 91 insertions, 11 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 | |||
@@ -40,6 +40,7 @@ using namespace Opie::Core; | |||
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> |
@@ -74,37 +75,69 @@ int OFileNotification::start( const QString& path, bool sshot, OFileNotification | |||
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 | } |
@@ -141,15 +174,48 @@ QString OFileNotification::path() const | |||
141 | return _path; | 174 | return _path; |
142 | } | 175 | } |
143 | 176 | ||
177 | |||
144 | int OFileNotification::fileno() const | 178 | int OFileNotification::fileno() const |
145 | { | 179 | { |
146 | return _fd; | 180 | return _fd; |
147 | } | 181 | } |
148 | 182 | ||
149 | void OFileNotification::activate() | 183 | |
184 | bool OFileNotification::activate() | ||
185 | { | ||
186 | if ( hasChanged() ) | ||
150 | { | 187 | { |
151 | emit triggered(); | 188 | emit triggered(); |
152 | _signal.activate(); | 189 | _signal.activate(); |
190 | return true; | ||
191 | } | ||
192 | else | ||
193 | return false; | ||
194 | } | ||
195 | |||
196 | |||
197 | bool 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 | ||
@@ -168,7 +234,20 @@ void OFileNotification::__signalHandler( int sig, siginfo_t *si, void *data ) | |||
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 | { |
@@ -209,7 +288,6 @@ void OFileNotification::unregisterSignalHandler() | |||
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 | } |
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 | |||
@@ -75,7 +75,8 @@ class OFileNotification : public QObject | |||
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 ); |
@@ -86,6 +87,7 @@ class OFileNotification : public QObject | |||
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 | } |