-rw-r--r-- | microkde/kio/kio/kdirwatch.cpp | 3 |
1 files changed, 2 insertions, 1 deletions
diff --git a/microkde/kio/kio/kdirwatch.cpp b/microkde/kio/kio/kdirwatch.cpp index 98d24e0..1596d1f 100644 --- a/microkde/kio/kio/kdirwatch.cpp +++ b/microkde/kio/kio/kdirwatch.cpp | |||
@@ -86,1025 +86,1026 @@ static int dnotify_signal = 0; | |||
86 | * This is done by writing into a pipe to trigger a QSocketNotifier | 86 | * This is done by writing into a pipe to trigger a QSocketNotifier |
87 | * watching on this pipe: a timer is started and after a timeout, | 87 | * watching on this pipe: a timer is started and after a timeout, |
88 | * the rescan is done. | 88 | * the rescan is done. |
89 | */ | 89 | */ |
90 | void KDirWatchPrivate::dnotify_handler(int, siginfo_t *si, void *) | 90 | void KDirWatchPrivate::dnotify_handler(int, siginfo_t *si, void *) |
91 | { | 91 | { |
92 | // write might change errno, we have to save it and restore it | 92 | // write might change errno, we have to save it and restore it |
93 | // (Richard Stevens, Advanced programming in the Unix Environment) | 93 | // (Richard Stevens, Advanced programming in the Unix Environment) |
94 | int saved_errno = errno; | 94 | int saved_errno = errno; |
95 | 95 | ||
96 | Entry* e = (dwp_self) ? dwp_self->fd_Entry.find(si->si_fd) :0; | 96 | Entry* e = (dwp_self) ? dwp_self->fd_Entry.find(si->si_fd) :0; |
97 | 97 | ||
98 | // kdDebug(7001) << "DNOTIFY Handler: fd " << si->si_fd << " path " | 98 | // kdDebug(7001) << "DNOTIFY Handler: fd " << si->si_fd << " path " |
99 | // << QString(e ? e->path:"unknown") << endl; | 99 | // << QString(e ? e->path:"unknown") << endl; |
100 | 100 | ||
101 | if(!e || e->dn_fd != si->si_fd) { | 101 | if(!e || e->dn_fd != si->si_fd) { |
102 | qDebug("fatal error in KDirWatch"); | 102 | qDebug("fatal error in KDirWatch"); |
103 | } else | 103 | } else |
104 | e->dn_dirty = true; | 104 | e->dn_dirty = true; |
105 | 105 | ||
106 | char c = 0; | 106 | char c = 0; |
107 | write(dwp_self->mPipe[1], &c, 1); | 107 | write(dwp_self->mPipe[1], &c, 1); |
108 | errno = saved_errno; | 108 | errno = saved_errno; |
109 | } | 109 | } |
110 | 110 | ||
111 | static struct sigaction old_sigio_act; | 111 | static struct sigaction old_sigio_act; |
112 | /* DNOTIFY SIGIO signal handler | 112 | /* DNOTIFY SIGIO signal handler |
113 | * | 113 | * |
114 | * When the kernel queue for the dnotify_signal overflows, a SIGIO is send. | 114 | * When the kernel queue for the dnotify_signal overflows, a SIGIO is send. |
115 | */ | 115 | */ |
116 | void KDirWatchPrivate::dnotify_sigio_handler(int sig, siginfo_t *si, void *p) | 116 | void KDirWatchPrivate::dnotify_sigio_handler(int sig, siginfo_t *si, void *p) |
117 | { | 117 | { |
118 | // write might change errno, we have to save it and restore it | 118 | // write might change errno, we have to save it and restore it |
119 | // (Richard Stevens, Advanced programming in the Unix Environment) | 119 | // (Richard Stevens, Advanced programming in the Unix Environment) |
120 | int saved_errno = errno; | 120 | int saved_errno = errno; |
121 | 121 | ||
122 | if (dwp_self) | 122 | if (dwp_self) |
123 | dwp_self->rescan_all = true; | 123 | dwp_self->rescan_all = true; |
124 | 124 | ||
125 | char c = 0; | 125 | char c = 0; |
126 | write(dwp_self->mPipe[1], &c, 1); | 126 | write(dwp_self->mPipe[1], &c, 1); |
127 | 127 | ||
128 | errno = saved_errno; | 128 | errno = saved_errno; |
129 | 129 | ||
130 | // Call previous signal handler | 130 | // Call previous signal handler |
131 | if (old_sigio_act.sa_flags & SA_SIGINFO) | 131 | if (old_sigio_act.sa_flags & SA_SIGINFO) |
132 | { | 132 | { |
133 | if (old_sigio_act.sa_sigaction) | 133 | if (old_sigio_act.sa_sigaction) |
134 | (*old_sigio_act.sa_sigaction)(sig, si, p); | 134 | (*old_sigio_act.sa_sigaction)(sig, si, p); |
135 | } | 135 | } |
136 | else | 136 | else |
137 | { | 137 | { |
138 | if ((old_sigio_act.sa_handler != SIG_DFL) && | 138 | if ((old_sigio_act.sa_handler != SIG_DFL) && |
139 | (old_sigio_act.sa_handler != SIG_IGN)) | 139 | (old_sigio_act.sa_handler != SIG_IGN)) |
140 | (*old_sigio_act.sa_handler)(sig); | 140 | (*old_sigio_act.sa_handler)(sig); |
141 | } | 141 | } |
142 | } | 142 | } |
143 | #endif | 143 | #endif |
144 | 144 | ||
145 | 145 | ||
146 | // | 146 | // |
147 | // Class KDirWatchPrivate (singleton) | 147 | // Class KDirWatchPrivate (singleton) |
148 | // | 148 | // |
149 | 149 | ||
150 | /* All entries (files/directories) to be watched in the | 150 | /* All entries (files/directories) to be watched in the |
151 | * application (coming from multiple KDirWatch instances) | 151 | * application (coming from multiple KDirWatch instances) |
152 | * are registered in a single KDirWatchPrivate instance. | 152 | * are registered in a single KDirWatchPrivate instance. |
153 | * | 153 | * |
154 | * At the moment, the following methods for file watching | 154 | * At the moment, the following methods for file watching |
155 | * are supported: | 155 | * are supported: |
156 | * - Polling: All files to be watched are polled regularly | 156 | * - Polling: All files to be watched are polled regularly |
157 | * using stat (more precise: QFileInfo.lastModified()). | 157 | * using stat (more precise: QFileInfo.lastModified()). |
158 | * The polling frequency is determined from global kconfig | 158 | * The polling frequency is determined from global kconfig |
159 | * settings, defaulting to 500 ms for local directories | 159 | * settings, defaulting to 500 ms for local directories |
160 | * and 5000 ms for remote mounts | 160 | * and 5000 ms for remote mounts |
161 | * - FAM (File Alternation Monitor): first used on IRIX, SGI | 161 | * - FAM (File Alternation Monitor): first used on IRIX, SGI |
162 | * has ported this method to LINUX. It uses a kernel part | 162 | * has ported this method to LINUX. It uses a kernel part |
163 | * (IMON, sending change events to /dev/imon) and a user | 163 | * (IMON, sending change events to /dev/imon) and a user |
164 | * level damon (fam), to which applications connect for | 164 | * level damon (fam), to which applications connect for |
165 | * notification of file changes. For NFS, the fam damon | 165 | * notification of file changes. For NFS, the fam damon |
166 | * on the NFS server machine is used; if IMON is not built | 166 | * on the NFS server machine is used; if IMON is not built |
167 | * into the kernel, fam uses polling for local files. | 167 | * into the kernel, fam uses polling for local files. |
168 | * - DNOTIFY: In late LINUX 2.3.x, directory notification was | 168 | * - DNOTIFY: In late LINUX 2.3.x, directory notification was |
169 | * introduced. By opening a directory, you can request for | 169 | * introduced. By opening a directory, you can request for |
170 | * UNIX signals to be sent to the process when a directory | 170 | * UNIX signals to be sent to the process when a directory |
171 | * is changed. | 171 | * is changed. |
172 | */ | 172 | */ |
173 | 173 | ||
174 | KDirWatchPrivate::KDirWatchPrivate() | 174 | KDirWatchPrivate::KDirWatchPrivate() |
175 | { | 175 | { |
176 | timer = new QTimer(this); | 176 | timer = new QTimer(this); |
177 | connect (timer, SIGNAL(timeout()), this, SLOT(slotRescan())); | 177 | connect (timer, SIGNAL(timeout()), this, SLOT(slotRescan())); |
178 | freq = 3600000; // 1 hour as upper bound | 178 | freq = 3600000; // 1 hour as upper bound |
179 | statEntries = 0; | 179 | statEntries = 0; |
180 | delayRemove = false; | 180 | delayRemove = false; |
181 | m_ref = 0; | 181 | m_ref = 0; |
182 | 182 | ||
183 | //US KConfigGroup config(KGlobal::config(), QCString("DirWatch")); | 183 | //US KConfigGroup config(KGlobal::config(), QCString("DirWatch")); |
184 | //US m_nfsPollInterval = config.readNumEntry("NFSPollInterval", 5000); | 184 | //US m_nfsPollInterval = config.readNumEntry("NFSPollInterval", 5000); |
185 | //US m_PollInterval = config.readNumEntry("PollInterval", 500); | 185 | //US m_PollInterval = config.readNumEntry("PollInterval", 500); |
186 | KConfig *config = KGlobal::config(); | 186 | KConfig *config = KGlobal::config(); |
187 | KConfigGroupSaver saver( config, QCString("DirWatch") ); | 187 | KConfigGroupSaver saver( config, QCString("DirWatch") ); |
188 | 188 | ||
189 | m_nfsPollInterval = config->readNumEntry("NFSPollInterval", 5000); | 189 | m_nfsPollInterval = config->readNumEntry("NFSPollInterval", 5000); |
190 | m_PollInterval = config->readNumEntry("PollInterval", 500); | 190 | m_PollInterval = config->readNumEntry("PollInterval", 500); |
191 | 191 | ||
192 | 192 | ||
193 | QString available("Stat"); | 193 | QString available("Stat"); |
194 | 194 | ||
195 | #ifdef HAVE_FAM | 195 | #ifdef HAVE_FAM |
196 | // It's possible that FAM server can't be started | 196 | // It's possible that FAM server can't be started |
197 | if (FAMOpen(&fc) ==0) { | 197 | if (FAMOpen(&fc) ==0) { |
198 | available += ", FAM"; | 198 | available += ", FAM"; |
199 | use_fam=true; | 199 | use_fam=true; |
200 | sn = new QSocketNotifier( FAMCONNECTION_GETFD(&fc), | 200 | sn = new QSocketNotifier( FAMCONNECTION_GETFD(&fc), |
201 | QSocketNotifier::Read, this); | 201 | QSocketNotifier::Read, this); |
202 | connect( sn, SIGNAL(activated(int)), | 202 | connect( sn, SIGNAL(activated(int)), |
203 | this, SLOT(famEventReceived()) ); | 203 | this, SLOT(famEventReceived()) ); |
204 | } | 204 | } |
205 | else { | 205 | else { |
206 | kdDebug(7001) << "Can't use FAM (fam daemon not running?)" << endl; | 206 | kdDebug(7001) << "Can't use FAM (fam daemon not running?)" << endl; |
207 | use_fam=false; | 207 | use_fam=false; |
208 | } | 208 | } |
209 | #endif | 209 | #endif |
210 | 210 | ||
211 | #ifdef HAVE_DNOTIFY | 211 | #ifdef HAVE_DNOTIFY |
212 | supports_dnotify = true; // not guilty until proven guilty | 212 | supports_dnotify = true; // not guilty until proven guilty |
213 | rescan_all = false; | 213 | rescan_all = false; |
214 | struct utsname uts; | 214 | struct utsname uts; |
215 | int major, minor, patch; | 215 | int major, minor, patch; |
216 | if (uname(&uts) < 0) | 216 | if (uname(&uts) < 0) |
217 | supports_dnotify = false; // *shrug* | 217 | supports_dnotify = false; // *shrug* |
218 | else if (sscanf(uts.release, "%d.%d.%d", &major, &minor, &patch) != 3) | 218 | else if (sscanf(uts.release, "%d.%d.%d", &major, &minor, &patch) != 3) |
219 | supports_dnotify = false; // *shrug* | 219 | supports_dnotify = false; // *shrug* |
220 | else if( major * 1000000 + minor * 1000 + patch < 2004019 ) { // <2.4.19 | 220 | else if( major * 1000000 + minor * 1000 + patch < 2004019 ) { // <2.4.19 |
221 | kdDebug(7001) << "Can't use DNotify, Linux kernel too old" << endl; | 221 | kdDebug(7001) << "Can't use DNotify, Linux kernel too old" << endl; |
222 | supports_dnotify = false; | 222 | supports_dnotify = false; |
223 | } | 223 | } |
224 | 224 | ||
225 | if( supports_dnotify ) { | 225 | if( supports_dnotify ) { |
226 | available += ", DNotify"; | 226 | available += ", DNotify"; |
227 | 227 | ||
228 | pipe(mPipe); | 228 | pipe(mPipe); |
229 | fcntl(mPipe[0], F_SETFD, FD_CLOEXEC); | 229 | fcntl(mPipe[0], F_SETFD, FD_CLOEXEC); |
230 | fcntl(mPipe[1], F_SETFD, FD_CLOEXEC); | 230 | fcntl(mPipe[1], F_SETFD, FD_CLOEXEC); |
231 | mSn = new QSocketNotifier( mPipe[0], QSocketNotifier::Read, this); | 231 | mSn = new QSocketNotifier( mPipe[0], QSocketNotifier::Read, this); |
232 | connect(mSn, SIGNAL(activated(int)), this, SLOT(slotActivated())); | 232 | connect(mSn, SIGNAL(activated(int)), this, SLOT(slotActivated())); |
233 | connect(&mTimer, SIGNAL(timeout()), this, SLOT(slotRescan())); | 233 | connect(&mTimer, SIGNAL(timeout()), this, SLOT(slotRescan())); |
234 | struct sigaction act; | 234 | struct sigaction act; |
235 | act.sa_sigaction = KDirWatchPrivate::dnotify_handler; | 235 | act.sa_sigaction = KDirWatchPrivate::dnotify_handler; |
236 | sigemptyset(&act.sa_mask); | 236 | sigemptyset(&act.sa_mask); |
237 | act.sa_flags = SA_SIGINFO; | 237 | act.sa_flags = SA_SIGINFO; |
238 | #ifdef SA_RESTART | 238 | #ifdef SA_RESTART |
239 | act.sa_flags |= SA_RESTART; | 239 | act.sa_flags |= SA_RESTART; |
240 | #endif | 240 | #endif |
241 | if( dnotify_signal == 0 ) | 241 | if( dnotify_signal == 0 ) |
242 | dnotify_signal = SIGRTMIN + 8; | 242 | dnotify_signal = SIGRTMIN + 8; |
243 | sigaction(dnotify_signal, &act, NULL); | 243 | sigaction(dnotify_signal, &act, NULL); |
244 | 244 | ||
245 | act.sa_sigaction = KDirWatchPrivate::dnotify_sigio_handler; | 245 | act.sa_sigaction = KDirWatchPrivate::dnotify_sigio_handler; |
246 | sigaction(SIGIO, &act, &old_sigio_act); | 246 | sigaction(SIGIO, &act, &old_sigio_act); |
247 | } | 247 | } |
248 | #endif | 248 | #endif |
249 | 249 | ||
250 | kdDebug(7001) << "Available methods: " << available << endl; | 250 | kdDebug(7001) << "Available methods: " << available << endl; |
251 | } | 251 | } |
252 | 252 | ||
253 | /* This should never be called, but doesn't harm */ | 253 | /* This should never be called, but doesn't harm */ |
254 | KDirWatchPrivate::~KDirWatchPrivate() | 254 | KDirWatchPrivate::~KDirWatchPrivate() |
255 | { | 255 | { |
256 | timer->stop(); | 256 | timer->stop(); |
257 | 257 | ||
258 | /* remove all entries being watched */ | 258 | /* remove all entries being watched */ |
259 | removeEntries(0); | 259 | removeEntries(0); |
260 | 260 | ||
261 | #ifdef HAVE_FAM | 261 | #ifdef HAVE_FAM |
262 | if (use_fam) { | 262 | if (use_fam) { |
263 | FAMClose(&fc); | 263 | FAMClose(&fc); |
264 | kdDebug(7001) << "KDirWatch deleted (FAM closed)" << endl; | 264 | kdDebug(7001) << "KDirWatch deleted (FAM closed)" << endl; |
265 | } | 265 | } |
266 | #endif | 266 | #endif |
267 | 267 | ||
268 | } | 268 | } |
269 | 269 | ||
270 | #ifdef HAVE_DNOTIFY | 270 | #ifdef HAVE_DNOTIFY |
271 | void KDirWatchPrivate::slotActivated() | 271 | void KDirWatchPrivate::slotActivated() |
272 | { | 272 | { |
273 | char dummy_buf[100]; | 273 | char dummy_buf[100]; |
274 | read(mPipe[0], &dummy_buf, 100); | 274 | read(mPipe[0], &dummy_buf, 100); |
275 | 275 | ||
276 | if (!mTimer.isActive()) | 276 | if (!mTimer.isActive()) |
277 | mTimer.start(200, true); | 277 | mTimer.start(200, true); |
278 | } | 278 | } |
279 | 279 | ||
280 | /* In DNOTIFY mode, only entries which are marked dirty are scanned. | 280 | /* In DNOTIFY mode, only entries which are marked dirty are scanned. |
281 | * We first need to mark all yet nonexistant, but possible created | 281 | * We first need to mark all yet nonexistant, but possible created |
282 | * entries as dirty... | 282 | * entries as dirty... |
283 | */ | 283 | */ |
284 | void KDirWatchPrivate::Entry::propagate_dirty() | 284 | void KDirWatchPrivate::Entry::propagate_dirty() |
285 | { | 285 | { |
286 | Entry* sub_entry; | 286 | Entry* sub_entry; |
287 | for(sub_entry = m_entries.first(); sub_entry; sub_entry = m_entries.next()) | 287 | for(sub_entry = m_entries.first(); sub_entry; sub_entry = m_entries.next()) |
288 | { | 288 | { |
289 | if (!sub_entry->dn_dirty) | 289 | if (!sub_entry->dn_dirty) |
290 | { | 290 | { |
291 | sub_entry->dn_dirty = true; | 291 | sub_entry->dn_dirty = true; |
292 | sub_entry->propagate_dirty(); | 292 | sub_entry->propagate_dirty(); |
293 | } | 293 | } |
294 | } | 294 | } |
295 | } | 295 | } |
296 | 296 | ||
297 | #else // !HAVE_DNOTIFY | 297 | #else // !HAVE_DNOTIFY |
298 | // slots always have to be defined... | 298 | // slots always have to be defined... |
299 | void KDirWatchPrivate::slotActivated() {} | 299 | void KDirWatchPrivate::slotActivated() {} |
300 | #endif | 300 | #endif |
301 | 301 | ||
302 | /* A KDirWatch instance is interested in getting events for | 302 | /* A KDirWatch instance is interested in getting events for |
303 | * this file/Dir entry. | 303 | * this file/Dir entry. |
304 | */ | 304 | */ |
305 | void KDirWatchPrivate::Entry::addClient(KDirWatch* instance) | 305 | void KDirWatchPrivate::Entry::addClient(KDirWatch* instance) |
306 | { | 306 | { |
307 | Client* client = m_clients.first(); | 307 | Client* client = m_clients.first(); |
308 | for(;client; client = m_clients.next()) | 308 | for(;client; client = m_clients.next()) |
309 | if (client->instance == instance) break; | 309 | if (client->instance == instance) break; |
310 | 310 | ||
311 | if (client) { | 311 | if (client) { |
312 | client->count++; | 312 | client->count++; |
313 | return; | 313 | return; |
314 | } | 314 | } |
315 | 315 | ||
316 | client = new Client; | 316 | client = new Client; |
317 | client->instance = instance; | 317 | client->instance = instance; |
318 | client->count = 1; | 318 | client->count = 1; |
319 | client->watchingStopped = instance->isStopped(); | 319 | client->watchingStopped = instance->isStopped(); |
320 | client->pending = NoChange; | 320 | client->pending = NoChange; |
321 | 321 | ||
322 | m_clients.append(client); | 322 | m_clients.append(client); |
323 | } | 323 | } |
324 | 324 | ||
325 | void KDirWatchPrivate::Entry::removeClient(KDirWatch* instance) | 325 | void KDirWatchPrivate::Entry::removeClient(KDirWatch* instance) |
326 | { | 326 | { |
327 | Client* client = m_clients.first(); | 327 | Client* client = m_clients.first(); |
328 | for(;client; client = m_clients.next()) | 328 | for(;client; client = m_clients.next()) |
329 | if (client->instance == instance) break; | 329 | if (client->instance == instance) break; |
330 | 330 | ||
331 | if (client) { | 331 | if (client) { |
332 | client->count--; | 332 | client->count--; |
333 | if (client->count == 0) { | 333 | if (client->count == 0) { |
334 | m_clients.removeRef(client); | 334 | m_clients.removeRef(client); |
335 | delete client; | 335 | delete client; |
336 | } | 336 | } |
337 | } | 337 | } |
338 | } | 338 | } |
339 | 339 | ||
340 | /* get number of clients */ | 340 | /* get number of clients */ |
341 | int KDirWatchPrivate::Entry::clients() | 341 | int KDirWatchPrivate::Entry::clients() |
342 | { | 342 | { |
343 | int clients = 0; | 343 | int clients = 0; |
344 | Client* client = m_clients.first(); | 344 | Client* client = m_clients.first(); |
345 | for(;client; client = m_clients.next()) | 345 | for(;client; client = m_clients.next()) |
346 | clients += client->count; | 346 | clients += client->count; |
347 | 347 | ||
348 | return clients; | 348 | return clients; |
349 | } | 349 | } |
350 | 350 | ||
351 | 351 | ||
352 | KDirWatchPrivate::Entry* KDirWatchPrivate::entry(const QString& _path) | 352 | KDirWatchPrivate::Entry* KDirWatchPrivate::entry(const QString& _path) |
353 | { | 353 | { |
354 | // we only support absolute paths | 354 | // we only support absolute paths |
355 | if (_path.left(1) != "/") { | 355 | if (_path.left(1) != "/") { |
356 | return 0; | 356 | return 0; |
357 | } | 357 | } |
358 | 358 | ||
359 | QString path = _path; | 359 | QString path = _path; |
360 | 360 | ||
361 | if ( path.length() > 1 && path.right(1) == "/" ) | 361 | if ( path.length() > 1 && path.right(1) == "/" ) |
362 | path.truncate( path.length() - 1 ); | 362 | path.truncate( path.length() - 1 ); |
363 | 363 | ||
364 | EntryMap::Iterator it = m_mapEntries.find( path ); | 364 | EntryMap::Iterator it = m_mapEntries.find( path ); |
365 | if ( it == m_mapEntries.end() ) | 365 | if ( it == m_mapEntries.end() ) |
366 | return 0; | 366 | return 0; |
367 | else | 367 | else |
368 | return &(*it); | 368 | return &(*it); |
369 | } | 369 | } |
370 | 370 | ||
371 | // set polling frequency for a entry and adjust global freq if needed | 371 | // set polling frequency for a entry and adjust global freq if needed |
372 | void KDirWatchPrivate::useFreq(Entry* e, int newFreq) | 372 | void KDirWatchPrivate::useFreq(Entry* e, int newFreq) |
373 | { | 373 | { |
374 | e->freq = newFreq; | 374 | e->freq = newFreq; |
375 | 375 | ||
376 | // a reasonable frequency for the global polling timer | 376 | // a reasonable frequency for the global polling timer |
377 | if (e->freq < freq) { | 377 | if (e->freq < freq) { |
378 | freq = e->freq; | 378 | freq = e->freq; |
379 | if (timer->isActive()) timer->changeInterval(freq); | 379 | if (timer->isActive()) timer->changeInterval(freq); |
380 | kdDebug(7001) << "Global Poll Freq is now " << freq << " msec" << endl; | 380 | kdDebug(7001) << "Global Poll Freq is now " << freq << " msec" << endl; |
381 | } | 381 | } |
382 | } | 382 | } |
383 | 383 | ||
384 | 384 | ||
385 | #if defined(HAVE_FAM) | 385 | #if defined(HAVE_FAM) |
386 | // setup FAM notification, returns false if not possible | 386 | // setup FAM notification, returns false if not possible |
387 | bool KDirWatchPrivate::useFAM(Entry* e) | 387 | bool KDirWatchPrivate::useFAM(Entry* e) |
388 | { | 388 | { |
389 | if (!use_fam) return false; | 389 | if (!use_fam) return false; |
390 | 390 | ||
391 | e->m_mode = FAMMode; | 391 | e->m_mode = FAMMode; |
392 | 392 | ||
393 | if (e->isDir) { | 393 | if (e->isDir) { |
394 | if (e->m_status == NonExistent) { | 394 | if (e->m_status == NonExistent) { |
395 | // If the directory does not exist we watch the parent directory | 395 | // If the directory does not exist we watch the parent directory |
396 | addEntry(0, QDir::cleanDirPath(e->path+"/.."), e, true); | 396 | addEntry(0, QDir::cleanDirPath(e->path+"/.."), e, true); |
397 | } | 397 | } |
398 | else { | 398 | else { |
399 | int res =FAMMonitorDirectory(&fc, QFile::encodeName(e->path), | 399 | int res =FAMMonitorDirectory(&fc, QFile::encodeName(e->path), |
400 | &(e->fr), e); | 400 | &(e->fr), e); |
401 | if (res<0) { | 401 | if (res<0) { |
402 | e->m_mode = UnknownMode; | 402 | e->m_mode = UnknownMode; |
403 | use_fam=false; | 403 | use_fam=false; |
404 | return false; | 404 | return false; |
405 | } | 405 | } |
406 | kdDebug(7001) << " Setup FAM (Req " | 406 | kdDebug(7001) << " Setup FAM (Req " |
407 | << FAMREQUEST_GETREQNUM(&(e->fr)) | 407 | << FAMREQUEST_GETREQNUM(&(e->fr)) |
408 | << ") for " << e->path << endl; | 408 | << ") for " << e->path << endl; |
409 | } | 409 | } |
410 | } | 410 | } |
411 | else { | 411 | else { |
412 | if (e->m_status == NonExistent) { | 412 | if (e->m_status == NonExistent) { |
413 | // If the file does not exist we watch the directory | 413 | // If the file does not exist we watch the directory |
414 | addEntry(0, QFileInfo(e->path).dirPath(true), e, true); | 414 | addEntry(0, QFileInfo(e->path).dirPath(true), e, true); |
415 | } | 415 | } |
416 | else { | 416 | else { |
417 | int res = FAMMonitorFile(&fc, QFile::encodeName(e->path), | 417 | int res = FAMMonitorFile(&fc, QFile::encodeName(e->path), |
418 | &(e->fr), e); | 418 | &(e->fr), e); |
419 | if (res<0) { | 419 | if (res<0) { |
420 | e->m_mode = UnknownMode; | 420 | e->m_mode = UnknownMode; |
421 | use_fam=false; | 421 | use_fam=false; |
422 | return false; | 422 | return false; |
423 | } | 423 | } |
424 | 424 | ||
425 | kdDebug(7001) << " Setup FAM (Req " | 425 | kdDebug(7001) << " Setup FAM (Req " |
426 | << FAMREQUEST_GETREQNUM(&(e->fr)) | 426 | << FAMREQUEST_GETREQNUM(&(e->fr)) |
427 | << ") for " << e->path << endl; | 427 | << ") for " << e->path << endl; |
428 | } | 428 | } |
429 | } | 429 | } |
430 | 430 | ||
431 | // handle FAM events to avoid deadlock | 431 | // handle FAM events to avoid deadlock |
432 | // (FAM sends back all files in a directory when monitoring) | 432 | // (FAM sends back all files in a directory when monitoring) |
433 | famEventReceived(); | 433 | famEventReceived(); |
434 | 434 | ||
435 | return true; | 435 | return true; |
436 | } | 436 | } |
437 | #endif | 437 | #endif |
438 | 438 | ||
439 | 439 | ||
440 | #ifdef HAVE_DNOTIFY | 440 | #ifdef HAVE_DNOTIFY |
441 | // setup DNotify notification, returns false if not possible | 441 | // setup DNotify notification, returns false if not possible |
442 | bool KDirWatchPrivate::useDNotify(Entry* e) | 442 | bool KDirWatchPrivate::useDNotify(Entry* e) |
443 | { | 443 | { |
444 | e->dn_fd = 0; | 444 | e->dn_fd = 0; |
445 | if (!supports_dnotify) return false; | 445 | if (!supports_dnotify) return false; |
446 | 446 | ||
447 | e->m_mode = DNotifyMode; | 447 | e->m_mode = DNotifyMode; |
448 | 448 | ||
449 | if (e->isDir) { | 449 | if (e->isDir) { |
450 | e->dn_dirty = false; | 450 | e->dn_dirty = false; |
451 | if (e->m_status == Normal) { | 451 | if (e->m_status == Normal) { |
452 | int fd = open(QFile::encodeName(e->path).data(), O_RDONLY); | 452 | int fd = open(QFile::encodeName(e->path).data(), O_RDONLY); |
453 | // Migrate fd to somewhere above 128. Some libraries have | 453 | // Migrate fd to somewhere above 128. Some libraries have |
454 | // constructs like: | 454 | // constructs like: |
455 | // fd = socket(...) | 455 | // fd = socket(...) |
456 | // if (fd > ARBITRARY_LIMIT) | 456 | // if (fd > ARBITRARY_LIMIT) |
457 | // return error; | 457 | // return error; |
458 | // | 458 | // |
459 | // Since programs might end up using a lot of KDirWatch objects | 459 | // Since programs might end up using a lot of KDirWatch objects |
460 | // for a rather long time the above braindamage could get | 460 | // for a rather long time the above braindamage could get |
461 | // triggered. | 461 | // triggered. |
462 | // | 462 | // |
463 | // By moving the kdirwatch fd's to > 128, calls like socket() will keep | 463 | // By moving the kdirwatch fd's to > 128, calls like socket() will keep |
464 | // returning fd's < ARBITRARY_LIMIT for a bit longer. | 464 | // returning fd's < ARBITRARY_LIMIT for a bit longer. |
465 | int fd2 = fcntl(fd, F_DUPFD, 128); | 465 | int fd2 = fcntl(fd, F_DUPFD, 128); |
466 | if (fd2 >= 0) | 466 | if (fd2 >= 0) |
467 | { | 467 | { |
468 | close(fd); | 468 | close(fd); |
469 | fd = fd2; | 469 | fd = fd2; |
470 | } | 470 | } |
471 | if (fd<0) { | 471 | if (fd<0) { |
472 | e->m_mode = UnknownMode; | 472 | e->m_mode = UnknownMode; |
473 | return false; | 473 | return false; |
474 | } | 474 | } |
475 | 475 | ||
476 | int mask = DN_DELETE|DN_CREATE|DN_RENAME|DN_MULTISHOT; | 476 | int mask = DN_DELETE|DN_CREATE|DN_RENAME|DN_MULTISHOT; |
477 | // if dependant is a file watch, we check for MODIFY & ATTRIB too | 477 | // if dependant is a file watch, we check for MODIFY & ATTRIB too |
478 | for(Entry* dep=e->m_entries.first();dep;dep=e->m_entries.next()) | 478 | for(Entry* dep=e->m_entries.first();dep;dep=e->m_entries.next()) |
479 | if (!dep->isDir) { mask |= DN_MODIFY|DN_ATTRIB; break; } | 479 | if (!dep->isDir) { mask |= DN_MODIFY|DN_ATTRIB; break; } |
480 | 480 | ||
481 | if(fcntl(fd, F_SETSIG, dnotify_signal) < 0 || | 481 | if(fcntl(fd, F_SETSIG, dnotify_signal) < 0 || |
482 | fcntl(fd, F_NOTIFY, mask) < 0) { | 482 | fcntl(fd, F_NOTIFY, mask) < 0) { |
483 | 483 | ||
484 | kdDebug(7001) << "Not using Linux Directory Notifications." | 484 | kdDebug(7001) << "Not using Linux Directory Notifications." |
485 | << endl; | 485 | << endl; |
486 | supports_dnotify = false; | 486 | supports_dnotify = false; |
487 | ::close(fd); | 487 | ::close(fd); |
488 | e->m_mode = UnknownMode; | 488 | e->m_mode = UnknownMode; |
489 | return false; | 489 | return false; |
490 | } | 490 | } |
491 | 491 | ||
492 | fd_Entry.replace(fd, e); | 492 | fd_Entry.replace(fd, e); |
493 | e->dn_fd = fd; | 493 | e->dn_fd = fd; |
494 | 494 | ||
495 | kdDebug(7001) << " Setup DNotify (fd " << fd | 495 | kdDebug(7001) << " Setup DNotify (fd " << fd |
496 | << ") for " << e->path << endl; | 496 | << ") for " << e->path << endl; |
497 | } | 497 | } |
498 | else { // NotExisting | 498 | else { // NotExisting |
499 | addEntry(0, QDir::cleanDirPath(e->path+"/.."), e, true); | 499 | addEntry(0, QDir::cleanDirPath(e->path+"/.."), e, true); |
500 | } | 500 | } |
501 | } | 501 | } |
502 | else { // File | 502 | else { // File |
503 | // we always watch the directory (DNOTIFY can't watch files alone) | 503 | // we always watch the directory (DNOTIFY can't watch files alone) |
504 | // this notifies us about changes of files therein | 504 | // this notifies us about changes of files therein |
505 | addEntry(0, QFileInfo(e->path).dirPath(true), e, true); | 505 | addEntry(0, QFileInfo(e->path).dirPath(true), e, true); |
506 | } | 506 | } |
507 | 507 | ||
508 | return true; | 508 | return true; |
509 | } | 509 | } |
510 | #endif | 510 | #endif |
511 | 511 | ||
512 | 512 | ||
513 | bool KDirWatchPrivate::useStat(Entry* e) | 513 | bool KDirWatchPrivate::useStat(Entry* e) |
514 | { | 514 | { |
515 | //US we have no KIO::probably_slow_mounted. So disable this part | 515 | //US we have no KIO::probably_slow_mounted. So disable this part |
516 | //US if (KIO::probably_slow_mounted(e->path)) | 516 | //US if (KIO::probably_slow_mounted(e->path)) |
517 | //US useFreq(e, m_nfsPollInterval); | 517 | //US useFreq(e, m_nfsPollInterval); |
518 | //US else | 518 | //US else |
519 | useFreq(e, m_PollInterval); | 519 | useFreq(e, m_PollInterval); |
520 | 520 | ||
521 | if (e->m_mode != StatMode) { | 521 | if (e->m_mode != StatMode) { |
522 | e->m_mode = StatMode; | 522 | e->m_mode = StatMode; |
523 | statEntries++; | 523 | statEntries++; |
524 | 524 | ||
525 | if ( statEntries == 1 ) { | 525 | if ( statEntries == 1 ) { |
526 | // if this was first STAT entry (=timer was stopped) | 526 | // if this was first STAT entry (=timer was stopped) |
527 | timer->start(freq); // then start the timer | 527 | timer->start(freq); // then start the timer |
528 | kdDebug(7001) << " Started Polling Timer, freq " << freq << endl; | 528 | kdDebug(7001) << " Started Polling Timer, freq " << freq << endl; |
529 | } | 529 | } |
530 | } | 530 | } |
531 | 531 | ||
532 | kdDebug(7001) << " Setup Stat (freq " << e->freq | 532 | kdDebug(7001) << " Setup Stat (freq " << e->freq |
533 | << ") for " << e->path << endl; | 533 | << ") for " << e->path << endl; |
534 | 534 | ||
535 | return true; | 535 | return true; |
536 | } | 536 | } |
537 | 537 | ||
538 | 538 | ||
539 | /* If <instance> !=0, this KDirWatch instance wants to watch at <_path>, | 539 | /* If <instance> !=0, this KDirWatch instance wants to watch at <_path>, |
540 | * providing in <isDir> the type of the entry to be watched. | 540 | * providing in <isDir> the type of the entry to be watched. |
541 | * Sometimes, entries are dependant on each other: if <sub_entry> !=0, | 541 | * Sometimes, entries are dependant on each other: if <sub_entry> !=0, |
542 | * this entry needs another entry to watch himself (when notExistent). | 542 | * this entry needs another entry to watch himself (when notExistent). |
543 | */ | 543 | */ |
544 | void KDirWatchPrivate::addEntry(KDirWatch* instance, const QString& _path, | 544 | void KDirWatchPrivate::addEntry(KDirWatch* instance, const QString& _path, |
545 | Entry* sub_entry, bool isDir) | 545 | Entry* sub_entry, bool isDir) |
546 | { | 546 | { |
547 | QString path = _path; | 547 | QString path = _path; |
548 | if (path.startsWith("/dev/") || (path == "/dev")) | 548 | if (path.startsWith("/dev/") || (path == "/dev")) |
549 | return; // Don't even go there. | 549 | return; // Don't even go there. |
550 | 550 | ||
551 | if ( path.length() > 1 && path.right(1) == "/" ) | 551 | if ( path.length() > 1 && path.right(1) == "/" ) |
552 | path.truncate( path.length() - 1 ); | 552 | path.truncate( path.length() - 1 ); |
553 | 553 | ||
554 | EntryMap::Iterator it = m_mapEntries.find( path ); | 554 | EntryMap::Iterator it = m_mapEntries.find( path ); |
555 | if ( it != m_mapEntries.end() ) | 555 | if ( it != m_mapEntries.end() ) |
556 | { | 556 | { |
557 | if (sub_entry) { | 557 | if (sub_entry) { |
558 | (*it).m_entries.append(sub_entry); | 558 | (*it).m_entries.append(sub_entry); |
559 | kdDebug(7001) << "Added already watched Entry " << path | 559 | kdDebug(7001) << "Added already watched Entry " << path |
560 | << " (for " << sub_entry->path << ")" << endl; | 560 | << " (for " << sub_entry->path << ")" << endl; |
561 | #ifdef HAVE_DNOTIFY | 561 | #ifdef HAVE_DNOTIFY |
562 | Entry* e = &(*it); | 562 | Entry* e = &(*it); |
563 | if( e->dn_fd > 0 ) { | 563 | if( e->dn_fd > 0 ) { |
564 | int mask = DN_DELETE|DN_CREATE|DN_RENAME|DN_MULTISHOT; | 564 | int mask = DN_DELETE|DN_CREATE|DN_RENAME|DN_MULTISHOT; |
565 | // if dependant is a file watch, we check for MODIFY & ATTRIB too | 565 | // if dependant is a file watch, we check for MODIFY & ATTRIB too |
566 | for(Entry* dep=e->m_entries.first();dep;dep=e->m_entries.next()) | 566 | for(Entry* dep=e->m_entries.first();dep;dep=e->m_entries.next()) |
567 | if (!dep->isDir) { mask |= DN_MODIFY|DN_ATTRIB; break; } | 567 | if (!dep->isDir) { mask |= DN_MODIFY|DN_ATTRIB; break; } |
568 | if( fcntl(e->dn_fd, F_NOTIFY, mask) < 0) { // shouldn't happen | 568 | if( fcntl(e->dn_fd, F_NOTIFY, mask) < 0) { // shouldn't happen |
569 | ::close(e->dn_fd); | 569 | ::close(e->dn_fd); |
570 | e->m_mode = UnknownMode; | 570 | e->m_mode = UnknownMode; |
571 | fd_Entry.remove(e->dn_fd); | 571 | fd_Entry.remove(e->dn_fd); |
572 | e->dn_fd = 0; | 572 | e->dn_fd = 0; |
573 | useStat( e ); | 573 | useStat( e ); |
574 | } | 574 | } |
575 | } | 575 | } |
576 | #endif | 576 | #endif |
577 | } | 577 | } |
578 | else { | 578 | else { |
579 | (*it).addClient(instance); | 579 | (*it).addClient(instance); |
580 | kdDebug(7001) << "Added already watched Entry " << path | 580 | kdDebug(7001) << "Added already watched Entry " << path |
581 | << " (now " << (*it).clients() << " clients)" | 581 | << " (now " << (*it).clients() << " clients)" |
582 | << QString(" [%1]").arg(instance->name()) << endl; | 582 | << QString(" [%1]").arg(instance->name()) << endl; |
583 | } | 583 | } |
584 | return; | 584 | return; |
585 | } | 585 | } |
586 | 586 | ||
587 | // we have a new path to watch | 587 | // we have a new path to watch |
588 | 588 | ||
589 | struct stat stat_buf; | 589 | struct stat stat_buf; |
590 | bool exists = (stat(QFile::encodeName(path), &stat_buf) == 0); | 590 | bool exists = (stat(QFile::encodeName(path), &stat_buf) == 0); |
591 | 591 | ||
592 | Entry newEntry; | 592 | Entry newEntry; |
593 | m_mapEntries.insert( path, newEntry ); | 593 | m_mapEntries.insert( path, newEntry ); |
594 | // the insert does a copy, so we have to use <e> now | 594 | // the insert does a copy, so we have to use <e> now |
595 | Entry* e = &(m_mapEntries[path]); | 595 | Entry* e = &(m_mapEntries[path]); |
596 | 596 | ||
597 | if (exists) { | 597 | if (exists) { |
598 | e->isDir = S_ISDIR(stat_buf.st_mode); | 598 | QFileInfo fi ( path ); |
599 | e->isDir = fi.isDir(); | ||
599 | 600 | ||
600 | if (e->isDir && !isDir) | 601 | if (e->isDir && !isDir) |
601 | qWarning("KDirWatch: %s is a directory. Use addDir!", path.ascii()); | 602 | qWarning("KDirWatch: %s is a directory. Use addDir!", path.ascii()); |
602 | else if (!e->isDir && isDir) | 603 | else if (!e->isDir && isDir) |
603 | qWarning("KDirWatch: %s is a file. Use addFile!", path.ascii()); | 604 | qWarning("KDirWatch: %s is a file. Use addFile!", path.ascii()); |
604 | 605 | ||
605 | e->m_ctime = stat_buf.st_ctime; | 606 | e->m_ctime = stat_buf.st_ctime; |
606 | e->m_status = Normal; | 607 | e->m_status = Normal; |
607 | e->m_nlink = stat_buf.st_nlink; | 608 | e->m_nlink = stat_buf.st_nlink; |
608 | } | 609 | } |
609 | else { | 610 | else { |
610 | e->isDir = isDir; | 611 | e->isDir = isDir; |
611 | e->m_ctime = invalid_ctime; | 612 | e->m_ctime = invalid_ctime; |
612 | e->m_status = NonExistent; | 613 | e->m_status = NonExistent; |
613 | e->m_nlink = 0; | 614 | e->m_nlink = 0; |
614 | } | 615 | } |
615 | 616 | ||
616 | e->path = path; | 617 | e->path = path; |
617 | if (sub_entry) | 618 | if (sub_entry) |
618 | e->m_entries.append(sub_entry); | 619 | e->m_entries.append(sub_entry); |
619 | else | 620 | else |
620 | e->addClient(instance); | 621 | e->addClient(instance); |
621 | 622 | ||
622 | kdDebug(7001) << "Added " << (e->isDir ? "Dir ":"File ") << path | 623 | kdDebug(7001) << "Added " << (e->isDir ? "Dir ":"File ") << path |
623 | << (e->m_status == NonExistent ? " NotExisting" : "") | 624 | << (e->m_status == NonExistent ? " NotExisting" : "") |
624 | << (sub_entry ? QString(" for %1").arg(sub_entry->path) : QString("")) | 625 | << (sub_entry ? QString(" for %1").arg(sub_entry->path) : QString("")) |
625 | << (instance ? QString(" [%1]").arg(instance->name()) : QString("")) | 626 | << (instance ? QString(" [%1]").arg(instance->name()) : QString("")) |
626 | << endl; | 627 | << endl; |
627 | 628 | ||
628 | 629 | ||
629 | // now setup the notification method | 630 | // now setup the notification method |
630 | e->m_mode = UnknownMode; | 631 | e->m_mode = UnknownMode; |
631 | e->msecLeft = 0; | 632 | e->msecLeft = 0; |
632 | 633 | ||
633 | #if defined(HAVE_FAM) | 634 | #if defined(HAVE_FAM) |
634 | if (useFAM(e)) return; | 635 | if (useFAM(e)) return; |
635 | #endif | 636 | #endif |
636 | 637 | ||
637 | #ifdef HAVE_DNOTIFY | 638 | #ifdef HAVE_DNOTIFY |
638 | if (useDNotify(e)) return; | 639 | if (useDNotify(e)) return; |
639 | #endif | 640 | #endif |
640 | 641 | ||
641 | useStat(e); | 642 | useStat(e); |
642 | } | 643 | } |
643 | 644 | ||
644 | 645 | ||
645 | void KDirWatchPrivate::removeEntry( KDirWatch* instance, | 646 | void KDirWatchPrivate::removeEntry( KDirWatch* instance, |
646 | const QString& _path, Entry* sub_entry ) | 647 | const QString& _path, Entry* sub_entry ) |
647 | { | 648 | { |
648 | Entry* e = entry(_path); | 649 | Entry* e = entry(_path); |
649 | if (!e) { | 650 | if (!e) { |
650 | kdWarning(7001) << "KDirWatch::removeDir can't handle '" << _path << "'" << endl; | 651 | kdWarning(7001) << "KDirWatch::removeDir can't handle '" << _path << "'" << endl; |
651 | return; | 652 | return; |
652 | } | 653 | } |
653 | 654 | ||
654 | if (sub_entry) | 655 | if (sub_entry) |
655 | e->m_entries.removeRef(sub_entry); | 656 | e->m_entries.removeRef(sub_entry); |
656 | else | 657 | else |
657 | e->removeClient(instance); | 658 | e->removeClient(instance); |
658 | 659 | ||
659 | if (e->m_clients.count() || e->m_entries.count()) | 660 | if (e->m_clients.count() || e->m_entries.count()) |
660 | return; | 661 | return; |
661 | 662 | ||
662 | if (delayRemove) { | 663 | if (delayRemove) { |
663 | // removeList is allowed to contain any entry at most once | 664 | // removeList is allowed to contain any entry at most once |
664 | if (removeList.findRef(e)==-1) | 665 | if (removeList.findRef(e)==-1) |
665 | removeList.append(e); | 666 | removeList.append(e); |
666 | // now e->isValid() is false | 667 | // now e->isValid() is false |
667 | return; | 668 | return; |
668 | } | 669 | } |
669 | 670 | ||
670 | #ifdef HAVE_FAM | 671 | #ifdef HAVE_FAM |
671 | if (e->m_mode == FAMMode) { | 672 | if (e->m_mode == FAMMode) { |
672 | if ( e->m_status == Normal) { | 673 | if ( e->m_status == Normal) { |
673 | FAMCancelMonitor(&fc, &(e->fr) ); | 674 | FAMCancelMonitor(&fc, &(e->fr) ); |
674 | kdDebug(7001) << "Cancelled FAM (Req " | 675 | kdDebug(7001) << "Cancelled FAM (Req " |
675 | << FAMREQUEST_GETREQNUM(&(e->fr)) | 676 | << FAMREQUEST_GETREQNUM(&(e->fr)) |
676 | << ") for " << e->path << endl; | 677 | << ") for " << e->path << endl; |
677 | } | 678 | } |
678 | else { | 679 | else { |
679 | if (e->isDir) | 680 | if (e->isDir) |
680 | removeEntry(0, QDir::cleanDirPath(e->path+"/.."), e); | 681 | removeEntry(0, QDir::cleanDirPath(e->path+"/.."), e); |
681 | else | 682 | else |
682 | removeEntry(0, QFileInfo(e->path).dirPath(true), e); | 683 | removeEntry(0, QFileInfo(e->path).dirPath(true), e); |
683 | } | 684 | } |
684 | } | 685 | } |
685 | #endif | 686 | #endif |
686 | 687 | ||
687 | #ifdef HAVE_DNOTIFY | 688 | #ifdef HAVE_DNOTIFY |
688 | if (e->m_mode == DNotifyMode) { | 689 | if (e->m_mode == DNotifyMode) { |
689 | if (!e->isDir) { | 690 | if (!e->isDir) { |
690 | removeEntry(0, QFileInfo(e->path).dirPath(true), e); | 691 | removeEntry(0, QFileInfo(e->path).dirPath(true), e); |
691 | } | 692 | } |
692 | else { // isDir | 693 | else { // isDir |
693 | // must close the FD. | 694 | // must close the FD. |
694 | if ( e->m_status == Normal) { | 695 | if ( e->m_status == Normal) { |
695 | if (e->dn_fd) { | 696 | if (e->dn_fd) { |
696 | ::close(e->dn_fd); | 697 | ::close(e->dn_fd); |
697 | fd_Entry.remove(e->dn_fd); | 698 | fd_Entry.remove(e->dn_fd); |
698 | 699 | ||
699 | kdDebug(7001) << "Cancelled DNotify (fd " << e->dn_fd | 700 | kdDebug(7001) << "Cancelled DNotify (fd " << e->dn_fd |
700 | << ") for " << e->path << endl; | 701 | << ") for " << e->path << endl; |
701 | e->dn_fd = 0; | 702 | e->dn_fd = 0; |
702 | 703 | ||
703 | } | 704 | } |
704 | } | 705 | } |
705 | else { | 706 | else { |
706 | removeEntry(0, QDir::cleanDirPath(e->path+"/.."), e); | 707 | removeEntry(0, QDir::cleanDirPath(e->path+"/.."), e); |
707 | } | 708 | } |
708 | } | 709 | } |
709 | } | 710 | } |
710 | #endif | 711 | #endif |
711 | 712 | ||
712 | if (e->m_mode == StatMode) { | 713 | if (e->m_mode == StatMode) { |
713 | statEntries--; | 714 | statEntries--; |
714 | if ( statEntries == 0 ) { | 715 | if ( statEntries == 0 ) { |
715 | timer->stop(); // stop timer if lists are empty | 716 | timer->stop(); // stop timer if lists are empty |
716 | kdDebug(7001) << " Stopped Polling Timer" << endl; | 717 | kdDebug(7001) << " Stopped Polling Timer" << endl; |
717 | } | 718 | } |
718 | } | 719 | } |
719 | 720 | ||
720 | kdDebug(7001) << "Removed " << (e->isDir ? "Dir ":"File ") << e->path | 721 | kdDebug(7001) << "Removed " << (e->isDir ? "Dir ":"File ") << e->path |
721 | << (sub_entry ? QString(" for %1").arg(sub_entry->path) : QString("")) | 722 | << (sub_entry ? QString(" for %1").arg(sub_entry->path) : QString("")) |
722 | << (instance ? QString(" [%1]").arg(instance->name()) : QString("")) | 723 | << (instance ? QString(" [%1]").arg(instance->name()) : QString("")) |
723 | << endl; | 724 | << endl; |
724 | m_mapEntries.remove( e->path ); // <e> not valid any more | 725 | m_mapEntries.remove( e->path ); // <e> not valid any more |
725 | } | 726 | } |
726 | 727 | ||
727 | 728 | ||
728 | /* Called from KDirWatch destructor: | 729 | /* Called from KDirWatch destructor: |
729 | * remove <instance> as client from all entries | 730 | * remove <instance> as client from all entries |
730 | */ | 731 | */ |
731 | void KDirWatchPrivate::removeEntries( KDirWatch* instance ) | 732 | void KDirWatchPrivate::removeEntries( KDirWatch* instance ) |
732 | { | 733 | { |
733 | QPtrList<Entry> list; | 734 | QPtrList<Entry> list; |
734 | int minfreq = 3600000; | 735 | int minfreq = 3600000; |
735 | 736 | ||
736 | // put all entries where instance is a client in list | 737 | // put all entries where instance is a client in list |
737 | EntryMap::Iterator it = m_mapEntries.begin(); | 738 | EntryMap::Iterator it = m_mapEntries.begin(); |
738 | for( ; it != m_mapEntries.end(); ++it ) { | 739 | for( ; it != m_mapEntries.end(); ++it ) { |
739 | Client* c = (*it).m_clients.first(); | 740 | Client* c = (*it).m_clients.first(); |
740 | for(;c;c=(*it).m_clients.next()) | 741 | for(;c;c=(*it).m_clients.next()) |
741 | if (c->instance == instance) break; | 742 | if (c->instance == instance) break; |
742 | if (c) { | 743 | if (c) { |
743 | c->count = 1; // forces deletion of instance as client | 744 | c->count = 1; // forces deletion of instance as client |
744 | list.append(&(*it)); | 745 | list.append(&(*it)); |
745 | } | 746 | } |
746 | else if ( (*it).m_mode == StatMode && (*it).freq < minfreq ) | 747 | else if ( (*it).m_mode == StatMode && (*it).freq < minfreq ) |
747 | minfreq = (*it).freq; | 748 | minfreq = (*it).freq; |
748 | } | 749 | } |
749 | 750 | ||
750 | for(Entry* e=list.first();e;e=list.next()) | 751 | for(Entry* e=list.first();e;e=list.next()) |
751 | removeEntry(instance, e->path, 0); | 752 | removeEntry(instance, e->path, 0); |
752 | 753 | ||
753 | if (minfreq > freq) { | 754 | if (minfreq > freq) { |
754 | // we can decrease the global polling frequency | 755 | // we can decrease the global polling frequency |
755 | freq = minfreq; | 756 | freq = minfreq; |
756 | if (timer->isActive()) timer->changeInterval(freq); | 757 | if (timer->isActive()) timer->changeInterval(freq); |
757 | kdDebug(7001) << "Poll Freq now " << freq << " msec" << endl; | 758 | kdDebug(7001) << "Poll Freq now " << freq << " msec" << endl; |
758 | } | 759 | } |
759 | } | 760 | } |
760 | 761 | ||
761 | // instance ==0: stop scanning for all instances | 762 | // instance ==0: stop scanning for all instances |
762 | bool KDirWatchPrivate::stopEntryScan( KDirWatch* instance, Entry* e) | 763 | bool KDirWatchPrivate::stopEntryScan( KDirWatch* instance, Entry* e) |
763 | { | 764 | { |
764 | int stillWatching = 0; | 765 | int stillWatching = 0; |
765 | Client* c = e->m_clients.first(); | 766 | Client* c = e->m_clients.first(); |
766 | for(;c;c=e->m_clients.next()) { | 767 | for(;c;c=e->m_clients.next()) { |
767 | if (!instance || instance == c->instance) | 768 | if (!instance || instance == c->instance) |
768 | c->watchingStopped = true; | 769 | c->watchingStopped = true; |
769 | else if (!c->watchingStopped) | 770 | else if (!c->watchingStopped) |
770 | stillWatching += c->count; | 771 | stillWatching += c->count; |
771 | } | 772 | } |
772 | 773 | ||
773 | kdDebug(7001) << instance->name() << " stopped scanning " << e->path | 774 | kdDebug(7001) << instance->name() << " stopped scanning " << e->path |
774 | << " (now " << stillWatching << " watchers)" << endl; | 775 | << " (now " << stillWatching << " watchers)" << endl; |
775 | 776 | ||
776 | if (stillWatching == 0) { | 777 | if (stillWatching == 0) { |
777 | // if nobody is interested, we don't watch | 778 | // if nobody is interested, we don't watch |
778 | e->m_ctime = invalid_ctime; // invalid | 779 | e->m_ctime = invalid_ctime; // invalid |
779 | // e->m_status = Normal; | 780 | // e->m_status = Normal; |
780 | } | 781 | } |
781 | return true; | 782 | return true; |
782 | } | 783 | } |
783 | 784 | ||
784 | // instance ==0: start scanning for all instances | 785 | // instance ==0: start scanning for all instances |
785 | bool KDirWatchPrivate::restartEntryScan( KDirWatch* instance, Entry* e, | 786 | bool KDirWatchPrivate::restartEntryScan( KDirWatch* instance, Entry* e, |
786 | bool notify) | 787 | bool notify) |
787 | { | 788 | { |
788 | int wasWatching = 0, newWatching = 0; | 789 | int wasWatching = 0, newWatching = 0; |
789 | Client* c = e->m_clients.first(); | 790 | Client* c = e->m_clients.first(); |
790 | for(;c;c=e->m_clients.next()) { | 791 | for(;c;c=e->m_clients.next()) { |
791 | if (!c->watchingStopped) | 792 | if (!c->watchingStopped) |
792 | wasWatching += c->count; | 793 | wasWatching += c->count; |
793 | else if (!instance || instance == c->instance) { | 794 | else if (!instance || instance == c->instance) { |
794 | c->watchingStopped = false; | 795 | c->watchingStopped = false; |
795 | newWatching += c->count; | 796 | newWatching += c->count; |
796 | } | 797 | } |
797 | } | 798 | } |
798 | if (newWatching == 0) | 799 | if (newWatching == 0) |
799 | return false; | 800 | return false; |
800 | 801 | ||
801 | kdDebug(7001) << instance->name() << " restarted scanning " << e->path | 802 | kdDebug(7001) << instance->name() << " restarted scanning " << e->path |
802 | << " (now " << wasWatching+newWatching << " watchers)" << endl; | 803 | << " (now " << wasWatching+newWatching << " watchers)" << endl; |
803 | 804 | ||
804 | // restart watching and emit pending events | 805 | // restart watching and emit pending events |
805 | 806 | ||
806 | int ev = NoChange; | 807 | int ev = NoChange; |
807 | if (wasWatching == 0) { | 808 | if (wasWatching == 0) { |
808 | if (!notify) { | 809 | if (!notify) { |
809 | struct stat stat_buf; | 810 | struct stat stat_buf; |
810 | bool exists = (stat(QFile::encodeName(e->path), &stat_buf) == 0); | 811 | bool exists = (stat(QFile::encodeName(e->path), &stat_buf) == 0); |
811 | if (exists) { | 812 | if (exists) { |
812 | e->m_ctime = stat_buf.st_ctime; | 813 | e->m_ctime = stat_buf.st_ctime; |
813 | e->m_status = Normal; | 814 | e->m_status = Normal; |
814 | e->m_nlink = stat_buf.st_nlink; | 815 | e->m_nlink = stat_buf.st_nlink; |
815 | } | 816 | } |
816 | else { | 817 | else { |
817 | e->m_ctime = invalid_ctime; | 818 | e->m_ctime = invalid_ctime; |
818 | e->m_status = NonExistent; | 819 | e->m_status = NonExistent; |
819 | e->m_nlink = 0; | 820 | e->m_nlink = 0; |
820 | } | 821 | } |
821 | } | 822 | } |
822 | e->msecLeft = 0; | 823 | e->msecLeft = 0; |
823 | ev = scanEntry(e); | 824 | ev = scanEntry(e); |
824 | } | 825 | } |
825 | emitEvent(e,ev); | 826 | emitEvent(e,ev); |
826 | 827 | ||
827 | return true; | 828 | return true; |
828 | } | 829 | } |
829 | 830 | ||
830 | // instance ==0: stop scanning for all instances | 831 | // instance ==0: stop scanning for all instances |
831 | void KDirWatchPrivate::stopScan(KDirWatch* instance) | 832 | void KDirWatchPrivate::stopScan(KDirWatch* instance) |
832 | { | 833 | { |
833 | EntryMap::Iterator it = m_mapEntries.begin(); | 834 | EntryMap::Iterator it = m_mapEntries.begin(); |
834 | for( ; it != m_mapEntries.end(); ++it ) | 835 | for( ; it != m_mapEntries.end(); ++it ) |
835 | stopEntryScan(instance, &(*it)); | 836 | stopEntryScan(instance, &(*it)); |
836 | } | 837 | } |
837 | 838 | ||
838 | 839 | ||
839 | void KDirWatchPrivate::startScan(KDirWatch* instance, | 840 | void KDirWatchPrivate::startScan(KDirWatch* instance, |
840 | bool notify, bool skippedToo ) | 841 | bool notify, bool skippedToo ) |
841 | { | 842 | { |
842 | if (!notify) | 843 | if (!notify) |
843 | resetList(instance,skippedToo); | 844 | resetList(instance,skippedToo); |
844 | 845 | ||
845 | EntryMap::Iterator it = m_mapEntries.begin(); | 846 | EntryMap::Iterator it = m_mapEntries.begin(); |
846 | for( ; it != m_mapEntries.end(); ++it ) | 847 | for( ; it != m_mapEntries.end(); ++it ) |
847 | restartEntryScan(instance, &(*it), notify); | 848 | restartEntryScan(instance, &(*it), notify); |
848 | 849 | ||
849 | // timer should still be running when in polling mode | 850 | // timer should still be running when in polling mode |
850 | } | 851 | } |
851 | 852 | ||
852 | 853 | ||
853 | // clear all pending events, also from stopped | 854 | // clear all pending events, also from stopped |
854 | void KDirWatchPrivate::resetList( KDirWatch* /*instance*/, | 855 | void KDirWatchPrivate::resetList( KDirWatch* /*instance*/, |
855 | bool skippedToo ) | 856 | bool skippedToo ) |
856 | { | 857 | { |
857 | EntryMap::Iterator it = m_mapEntries.begin(); | 858 | EntryMap::Iterator it = m_mapEntries.begin(); |
858 | for( ; it != m_mapEntries.end(); ++it ) { | 859 | for( ; it != m_mapEntries.end(); ++it ) { |
859 | 860 | ||
860 | Client* c = (*it).m_clients.first(); | 861 | Client* c = (*it).m_clients.first(); |
861 | for(;c;c=(*it).m_clients.next()) | 862 | for(;c;c=(*it).m_clients.next()) |
862 | if (!c->watchingStopped || skippedToo) | 863 | if (!c->watchingStopped || skippedToo) |
863 | c->pending = NoChange; | 864 | c->pending = NoChange; |
864 | } | 865 | } |
865 | } | 866 | } |
866 | 867 | ||
867 | // Return event happened on <e> | 868 | // Return event happened on <e> |
868 | // | 869 | // |
869 | int KDirWatchPrivate::scanEntry(Entry* e) | 870 | int KDirWatchPrivate::scanEntry(Entry* e) |
870 | { | 871 | { |
871 | #ifdef HAVE_FAM | 872 | #ifdef HAVE_FAM |
872 | // we do not stat entries using FAM | 873 | // we do not stat entries using FAM |
873 | if (e->m_mode == FAMMode) return NoChange; | 874 | if (e->m_mode == FAMMode) return NoChange; |
874 | #endif | 875 | #endif |
875 | 876 | ||
876 | // Shouldn't happen: Ignore "unknown" notification method | 877 | // Shouldn't happen: Ignore "unknown" notification method |
877 | if (e->m_mode == UnknownMode) return NoChange; | 878 | if (e->m_mode == UnknownMode) return NoChange; |
878 | 879 | ||
879 | #ifdef HAVE_DNOTIFY | 880 | #ifdef HAVE_DNOTIFY |
880 | if (e->m_mode == DNotifyMode) { | 881 | if (e->m_mode == DNotifyMode) { |
881 | // we know nothing has changed, no need to stat | 882 | // we know nothing has changed, no need to stat |
882 | if(!e->dn_dirty) return NoChange; | 883 | if(!e->dn_dirty) return NoChange; |
883 | e->dn_dirty = false; | 884 | e->dn_dirty = false; |
884 | } | 885 | } |
885 | #endif | 886 | #endif |
886 | 887 | ||
887 | if (e->m_mode == StatMode) { | 888 | if (e->m_mode == StatMode) { |
888 | // only scan if timeout on entry timer happens; | 889 | // only scan if timeout on entry timer happens; |
889 | // e.g. when using 500msec global timer, a entry | 890 | // e.g. when using 500msec global timer, a entry |
890 | // with freq=5000 is only watched every 10th time | 891 | // with freq=5000 is only watched every 10th time |
891 | 892 | ||
892 | e->msecLeft -= freq; | 893 | e->msecLeft -= freq; |
893 | if (e->msecLeft>0) return NoChange; | 894 | if (e->msecLeft>0) return NoChange; |
894 | e->msecLeft += e->freq; | 895 | e->msecLeft += e->freq; |
895 | } | 896 | } |
896 | 897 | ||
897 | struct stat stat_buf; | 898 | struct stat stat_buf; |
898 | bool exists = (stat(QFile::encodeName(e->path), &stat_buf) == 0); | 899 | bool exists = (stat(QFile::encodeName(e->path), &stat_buf) == 0); |
899 | if (exists) { | 900 | if (exists) { |
900 | 901 | ||
901 | if (e->m_status == NonExistent) { | 902 | if (e->m_status == NonExistent) { |
902 | e->m_ctime = stat_buf.st_ctime; | 903 | e->m_ctime = stat_buf.st_ctime; |
903 | e->m_status = Normal; | 904 | e->m_status = Normal; |
904 | e->m_nlink = stat_buf.st_nlink; | 905 | e->m_nlink = stat_buf.st_nlink; |
905 | return Created; | 906 | return Created; |
906 | } | 907 | } |
907 | 908 | ||
908 | if ( (e->m_ctime != invalid_ctime) && | 909 | if ( (e->m_ctime != invalid_ctime) && |
909 | ((stat_buf.st_ctime != e->m_ctime) || | 910 | ((stat_buf.st_ctime != e->m_ctime) || |
910 | // (stat_buf.st_nlink != (nlink_t) e->m_nlink)) ) { | 911 | // (stat_buf.st_nlink != (nlink_t) e->m_nlink)) ) { |
911 | (stat_buf.st_nlink != e->m_nlink)) ) { | 912 | (stat_buf.st_nlink != e->m_nlink)) ) { |
912 | e->m_ctime = stat_buf.st_ctime; | 913 | e->m_ctime = stat_buf.st_ctime; |
913 | e->m_nlink = stat_buf.st_nlink; | 914 | e->m_nlink = stat_buf.st_nlink; |
914 | return Changed; | 915 | return Changed; |
915 | } | 916 | } |
916 | 917 | ||
917 | return NoChange; | 918 | return NoChange; |
918 | } | 919 | } |
919 | 920 | ||
920 | // dir/file doesn't exist | 921 | // dir/file doesn't exist |
921 | 922 | ||
922 | if (e->m_ctime == invalid_ctime) | 923 | if (e->m_ctime == invalid_ctime) |
923 | return NoChange; | 924 | return NoChange; |
924 | 925 | ||
925 | e->m_ctime = invalid_ctime; | 926 | e->m_ctime = invalid_ctime; |
926 | e->m_nlink = 0; | 927 | e->m_nlink = 0; |
927 | e->m_status = NonExistent; | 928 | e->m_status = NonExistent; |
928 | 929 | ||
929 | return Deleted; | 930 | return Deleted; |
930 | } | 931 | } |
931 | 932 | ||
932 | /* Notify all interested KDirWatch instances about a given event on an entry | 933 | /* Notify all interested KDirWatch instances about a given event on an entry |
933 | * and stored pending events. When watching is stopped, the event is | 934 | * and stored pending events. When watching is stopped, the event is |
934 | * added to the pending events. | 935 | * added to the pending events. |
935 | */ | 936 | */ |
936 | void KDirWatchPrivate::emitEvent(Entry* e, int event, const QString &fileName) | 937 | void KDirWatchPrivate::emitEvent(Entry* e, int event, const QString &fileName) |
937 | { | 938 | { |
938 | QString path = e->path; | 939 | QString path = e->path; |
939 | if (!fileName.isEmpty()) { | 940 | if (!fileName.isEmpty()) { |
940 | if (fileName[0] == '/') | 941 | if (fileName[0] == '/') |
941 | path = fileName; | 942 | path = fileName; |
942 | else | 943 | else |
943 | path += "/" + fileName; | 944 | path += "/" + fileName; |
944 | } | 945 | } |
945 | 946 | ||
946 | Client* c = e->m_clients.first(); | 947 | Client* c = e->m_clients.first(); |
947 | for(;c;c=e->m_clients.next()) { | 948 | for(;c;c=e->m_clients.next()) { |
948 | if (c->instance==0 || c->count==0) continue; | 949 | if (c->instance==0 || c->count==0) continue; |
949 | 950 | ||
950 | if (c->watchingStopped) { | 951 | if (c->watchingStopped) { |
951 | // add event to pending... | 952 | // add event to pending... |
952 | if (event == Changed) | 953 | if (event == Changed) |
953 | c->pending |= event; | 954 | c->pending |= event; |
954 | else if (event == Created || event == Deleted) | 955 | else if (event == Created || event == Deleted) |
955 | c->pending = event; | 956 | c->pending = event; |
956 | continue; | 957 | continue; |
957 | } | 958 | } |
958 | // not stopped | 959 | // not stopped |
959 | if (event == NoChange || event == Changed) | 960 | if (event == NoChange || event == Changed) |
960 | event |= c->pending; | 961 | event |= c->pending; |
961 | c->pending = NoChange; | 962 | c->pending = NoChange; |
962 | if (event == NoChange) continue; | 963 | if (event == NoChange) continue; |
963 | 964 | ||
964 | if (event & Deleted) { | 965 | if (event & Deleted) { |
965 | c->instance->setDeleted(path); | 966 | c->instance->setDeleted(path); |
966 | // emit only Deleted event... | 967 | // emit only Deleted event... |
967 | continue; | 968 | continue; |
968 | } | 969 | } |
969 | 970 | ||
970 | if (event & Created) { | 971 | if (event & Created) { |
971 | c->instance->setCreated(path); | 972 | c->instance->setCreated(path); |
972 | // possible emit Change event after creation | 973 | // possible emit Change event after creation |
973 | } | 974 | } |
974 | 975 | ||
975 | if (event & Changed) | 976 | if (event & Changed) |
976 | c->instance->setDirty(path); | 977 | c->instance->setDirty(path); |
977 | } | 978 | } |
978 | } | 979 | } |
979 | 980 | ||
980 | // Remove entries which were marked to be removed | 981 | // Remove entries which were marked to be removed |
981 | void KDirWatchPrivate::slotRemoveDelayed() | 982 | void KDirWatchPrivate::slotRemoveDelayed() |
982 | { | 983 | { |
983 | Entry* e; | 984 | Entry* e; |
984 | delayRemove = false; | 985 | delayRemove = false; |
985 | for(e=removeList.first();e;e=removeList.next()) | 986 | for(e=removeList.first();e;e=removeList.next()) |
986 | removeEntry(0, e->path, 0); | 987 | removeEntry(0, e->path, 0); |
987 | removeList.clear(); | 988 | removeList.clear(); |
988 | } | 989 | } |
989 | 990 | ||
990 | /* Scan all entries to be watched for changes. This is done regularly | 991 | /* Scan all entries to be watched for changes. This is done regularly |
991 | * when polling and once after a DNOTIFY signal. This is NOT used by FAM. | 992 | * when polling and once after a DNOTIFY signal. This is NOT used by FAM. |
992 | */ | 993 | */ |
993 | void KDirWatchPrivate::slotRescan() | 994 | void KDirWatchPrivate::slotRescan() |
994 | { | 995 | { |
995 | EntryMap::Iterator it; | 996 | EntryMap::Iterator it; |
996 | 997 | ||
997 | // People can do very long things in the slot connected to dirty(), | 998 | // People can do very long things in the slot connected to dirty(), |
998 | // like showing a message box. We don't want to keep polling during | 999 | // like showing a message box. We don't want to keep polling during |
999 | // that time, otherwise the value of 'delayRemove' will be reset. | 1000 | // that time, otherwise the value of 'delayRemove' will be reset. |
1000 | bool timerRunning = timer->isActive(); | 1001 | bool timerRunning = timer->isActive(); |
1001 | if ( timerRunning ) | 1002 | if ( timerRunning ) |
1002 | timer->stop(); | 1003 | timer->stop(); |
1003 | 1004 | ||
1004 | // We delay deletions of entries this way. | 1005 | // We delay deletions of entries this way. |
1005 | // removeDir(), when called in slotDirty(), can cause a crash otherwise | 1006 | // removeDir(), when called in slotDirty(), can cause a crash otherwise |
1006 | delayRemove = true; | 1007 | delayRemove = true; |
1007 | 1008 | ||
1008 | #ifdef HAVE_DNOTIFY | 1009 | #ifdef HAVE_DNOTIFY |
1009 | QPtrList<Entry> dList, cList; | 1010 | QPtrList<Entry> dList, cList; |
1010 | 1011 | ||
1011 | // for DNotify method, | 1012 | // for DNotify method, |
1012 | if (rescan_all) | 1013 | if (rescan_all) |
1013 | { | 1014 | { |
1014 | // mark all as dirty | 1015 | // mark all as dirty |
1015 | it = m_mapEntries.begin(); | 1016 | it = m_mapEntries.begin(); |
1016 | for( ; it != m_mapEntries.end(); ++it ) | 1017 | for( ; it != m_mapEntries.end(); ++it ) |
1017 | (*it).dn_dirty = true; | 1018 | (*it).dn_dirty = true; |
1018 | rescan_all = false; | 1019 | rescan_all = false; |
1019 | } | 1020 | } |
1020 | else | 1021 | else |
1021 | { | 1022 | { |
1022 | // progate dirty flag to dependant entries (e.g. file watches) | 1023 | // progate dirty flag to dependant entries (e.g. file watches) |
1023 | it = m_mapEntries.begin(); | 1024 | it = m_mapEntries.begin(); |
1024 | for( ; it != m_mapEntries.end(); ++it ) | 1025 | for( ; it != m_mapEntries.end(); ++it ) |
1025 | if ( ((*it).m_mode == DNotifyMode) && (*it).dn_dirty ) | 1026 | if ( ((*it).m_mode == DNotifyMode) && (*it).dn_dirty ) |
1026 | (*it).propagate_dirty(); | 1027 | (*it).propagate_dirty(); |
1027 | } | 1028 | } |
1028 | 1029 | ||
1029 | #endif | 1030 | #endif |
1030 | 1031 | ||
1031 | it = m_mapEntries.begin(); | 1032 | it = m_mapEntries.begin(); |
1032 | for( ; it != m_mapEntries.end(); ++it ) { | 1033 | for( ; it != m_mapEntries.end(); ++it ) { |
1033 | // we don't check invalid entries (i.e. remove delayed) | 1034 | // we don't check invalid entries (i.e. remove delayed) |
1034 | if (!(*it).isValid()) continue; | 1035 | if (!(*it).isValid()) continue; |
1035 | 1036 | ||
1036 | int ev = scanEntry( &(*it) ); | 1037 | int ev = scanEntry( &(*it) ); |
1037 | 1038 | ||
1038 | #ifdef HAVE_DNOTIFY | 1039 | #ifdef HAVE_DNOTIFY |
1039 | if ((*it).m_mode == DNotifyMode) { | 1040 | if ((*it).m_mode == DNotifyMode) { |
1040 | if ((*it).isDir && (ev == Deleted)) { | 1041 | if ((*it).isDir && (ev == Deleted)) { |
1041 | dList.append( &(*it) ); | 1042 | dList.append( &(*it) ); |
1042 | 1043 | ||
1043 | // must close the FD. | 1044 | // must close the FD. |
1044 | if ((*it).dn_fd) { | 1045 | if ((*it).dn_fd) { |
1045 | ::close((*it).dn_fd); | 1046 | ::close((*it).dn_fd); |
1046 | fd_Entry.remove((*it).dn_fd); | 1047 | fd_Entry.remove((*it).dn_fd); |
1047 | (*it).dn_fd = 0; | 1048 | (*it).dn_fd = 0; |
1048 | } | 1049 | } |
1049 | } | 1050 | } |
1050 | 1051 | ||
1051 | else if ((*it).isDir && (ev == Created)) { | 1052 | else if ((*it).isDir && (ev == Created)) { |
1052 | // For created, but yet without DNOTIFYing ... | 1053 | // For created, but yet without DNOTIFYing ... |
1053 | if ( (*it).dn_fd == 0) { | 1054 | if ( (*it).dn_fd == 0) { |
1054 | cList.append( &(*it) ); | 1055 | cList.append( &(*it) ); |
1055 | if (! useDNotify( &(*it) )) { | 1056 | if (! useDNotify( &(*it) )) { |
1056 | // if DNotify setup fails... | 1057 | // if DNotify setup fails... |
1057 | useStat( &(*it) ); | 1058 | useStat( &(*it) ); |
1058 | } | 1059 | } |
1059 | } | 1060 | } |
1060 | } | 1061 | } |
1061 | } | 1062 | } |
1062 | #endif | 1063 | #endif |
1063 | 1064 | ||
1064 | if ( ev != NoChange ) | 1065 | if ( ev != NoChange ) |
1065 | emitEvent( &(*it), ev); | 1066 | emitEvent( &(*it), ev); |
1066 | } | 1067 | } |
1067 | 1068 | ||
1068 | 1069 | ||
1069 | #ifdef HAVE_DNOTIFY | 1070 | #ifdef HAVE_DNOTIFY |
1070 | // Scan parent of deleted directories for new creation | 1071 | // Scan parent of deleted directories for new creation |
1071 | Entry* e; | 1072 | Entry* e; |
1072 | for(e=dList.first();e;e=dList.next()) | 1073 | for(e=dList.first();e;e=dList.next()) |
1073 | addEntry(0, QDir::cleanDirPath( e->path+"/.."), e, true); | 1074 | addEntry(0, QDir::cleanDirPath( e->path+"/.."), e, true); |
1074 | 1075 | ||
1075 | // Remove watch of parent of new created directories | 1076 | // Remove watch of parent of new created directories |
1076 | for(e=cList.first();e;e=cList.next()) | 1077 | for(e=cList.first();e;e=cList.next()) |
1077 | removeEntry(0, QDir::cleanDirPath( e->path+"/.."), e); | 1078 | removeEntry(0, QDir::cleanDirPath( e->path+"/.."), e); |
1078 | #endif | 1079 | #endif |
1079 | 1080 | ||
1080 | if ( timerRunning ) | 1081 | if ( timerRunning ) |
1081 | timer->start(freq); | 1082 | timer->start(freq); |
1082 | 1083 | ||
1083 | QTimer::singleShot(0, this, SLOT(slotRemoveDelayed())); | 1084 | QTimer::singleShot(0, this, SLOT(slotRemoveDelayed())); |
1084 | } | 1085 | } |
1085 | 1086 | ||
1086 | #ifdef HAVE_FAM | 1087 | #ifdef HAVE_FAM |
1087 | void KDirWatchPrivate::famEventReceived() | 1088 | void KDirWatchPrivate::famEventReceived() |
1088 | { | 1089 | { |
1089 | static FAMEvent fe; | 1090 | static FAMEvent fe; |
1090 | 1091 | ||
1091 | delayRemove = true; | 1092 | delayRemove = true; |
1092 | 1093 | ||
1093 | while(use_fam && FAMPending(&fc)) { | 1094 | while(use_fam && FAMPending(&fc)) { |
1094 | if (FAMNextEvent(&fc, &fe) == -1) { | 1095 | if (FAMNextEvent(&fc, &fe) == -1) { |
1095 | kdWarning(7001) << "FAM connection problem, switching to polling." | 1096 | kdWarning(7001) << "FAM connection problem, switching to polling." |
1096 | << endl; | 1097 | << endl; |
1097 | use_fam = false; | 1098 | use_fam = false; |
1098 | delete sn; sn = 0; | 1099 | delete sn; sn = 0; |
1099 | 1100 | ||
1100 | // Replace all FAMMode entries with DNotify/Stat | 1101 | // Replace all FAMMode entries with DNotify/Stat |
1101 | EntryMap::Iterator it; | 1102 | EntryMap::Iterator it; |
1102 | it = m_mapEntries.begin(); | 1103 | it = m_mapEntries.begin(); |
1103 | for( ; it != m_mapEntries.end(); ++it ) | 1104 | for( ; it != m_mapEntries.end(); ++it ) |
1104 | if ((*it).m_mode == FAMMode && (*it).m_clients.count()>0) { | 1105 | if ((*it).m_mode == FAMMode && (*it).m_clients.count()>0) { |
1105 | #ifdef HAVE_DNOTIFY | 1106 | #ifdef HAVE_DNOTIFY |
1106 | if (useDNotify( &(*it) )) continue; | 1107 | if (useDNotify( &(*it) )) continue; |
1107 | #endif | 1108 | #endif |
1108 | useStat( &(*it) ); | 1109 | useStat( &(*it) ); |
1109 | } | 1110 | } |
1110 | } | 1111 | } |