author | mickeyl <mickeyl> | 2004-04-19 13:56:14 (UTC) |
---|---|---|
committer | mickeyl <mickeyl> | 2004-04-19 13:56:14 (UTC) |
commit | 13b62b4e8c613b9f876bd70d519a2a85186dba7a (patch) (unidiff) | |
tree | c52e051c23dca89efc3bb3e468f9033d342f15e8 /libopie2 | |
parent | 2add0a39efab1af658ab3515090b31fba30df0d5 (diff) | |
download | opie-13b62b4e8c613b9f876bd70d519a2a85186dba7a.zip opie-13b62b4e8c613b9f876bd70d519a2a85186dba7a.tar.gz opie-13b62b4e8c613b9f876bd70d519a2a85186dba7a.tar.bz2 |
First milestone reached:
File notification now works for Access and Modify of existing files.
Next milestone: Rename and Attrib on existing files.
-rw-r--r-- | libopie2/opiecore/ofilenotify.cpp | 102 | ||||
-rw-r--r-- | libopie2/opiecore/ofilenotify.h | 4 |
2 files changed, 93 insertions, 13 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 | |||
@@ -37,12 +37,13 @@ using namespace Opie::Core; | |||
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 <fcntl.h> | 44 | #include <fcntl.h> |
44 | #include <string.h> | 45 | #include <string.h> |
45 | #include <errno.h> | 46 | #include <errno.h> |
46 | #include <unistd.h> | 47 | #include <unistd.h> |
47 | 48 | ||
48 | static QIntDict<OFileNotification> notification_list; | 49 | static QIntDict<OFileNotification> notification_list; |
@@ -71,43 +72,75 @@ bool OFileNotification::isActive() const | |||
71 | 72 | ||
72 | int OFileNotification::start( const QString& path, bool sshot, OFileNotificationType type ) | 73 | int OFileNotification::start( const QString& path, bool sshot, OFileNotificationType type ) |
73 | { | 74 | { |
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 | } |
111 | 144 | ||
112 | 145 | ||
113 | void OFileNotification::stop() | 146 | void OFileNotification::stop() |
@@ -138,21 +171,54 @@ OFileNotificationType OFileNotification::type() const | |||
138 | 171 | ||
139 | QString OFileNotification::path() const | 172 | QString OFileNotification::path() const |
140 | { | 173 | { |
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() | ||
150 | { | 185 | { |
151 | emit triggered(); | 186 | if ( hasChanged() ) |
152 | _signal.activate(); | 187 | { |
188 | emit triggered(); | ||
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 | ||
156 | void OFileNotification::singleShot( const QString& path, QObject* receiver, const char* member, OFileNotificationType type ) | 222 | void OFileNotification::singleShot( const QString& path, QObject* receiver, const char* member, OFileNotificationType type ) |
157 | { | 223 | { |
158 | OFileNotification* ofn = new OFileNotification(); | 224 | OFileNotification* ofn = new OFileNotification(); |
@@ -165,13 +231,26 @@ void OFileNotification::__signalHandler( int sig, siginfo_t *si, void *data ) | |||
165 | { | 231 | { |
166 | qWarning( "OFileNotification::__signalHandler(): reached." ); | 232 | qWarning( "OFileNotification::__signalHandler(): reached." ); |
167 | int fd = si->si_fd; | 233 | int fd = si->si_fd; |
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 | { |
175 | qDebug( "OFileNotification::__signalHandler(): '%d' was singleShot. Removing from list.", fd ); | 254 | qDebug( "OFileNotification::__signalHandler(): '%d' was singleShot. Removing from list.", fd ); |
176 | notification_list.remove( fd ); | 255 | notification_list.remove( fd ); |
177 | if ( notification_list.isEmpty() ) | 256 | if ( notification_list.isEmpty() ) |
@@ -206,13 +285,12 @@ bool OFileNotification::registerSignalHandler() | |||
206 | void OFileNotification::unregisterSignalHandler() | 285 | void OFileNotification::unregisterSignalHandler() |
207 | { | 286 | { |
208 | struct sigaction act; | 287 | struct sigaction act; |
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 | } |
216 | qDebug( "OFileNotification::unregisterSignalHandler(): done" ); | 294 | qDebug( "OFileNotification::unregisterSignalHandler(): done" ); |
217 | } | 295 | } |
218 | 296 | ||
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 | |||
@@ -72,23 +72,25 @@ class OFileNotification : public QObject | |||
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 | 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 ); |
82 | 83 | ||
83 | private: | 84 | private: |
84 | QString _path; | 85 | QString _path; |
85 | OFileNotificationType _type; | 86 | OFileNotificationType _type; |
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 | } |
92 | } | 94 | } |
93 | 95 | ||
94 | #endif | 96 | #endif |