summaryrefslogtreecommitdiffabout
Unidiff
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--microkde/kio/kio/kdirwatch.cpp3
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 */
90void KDirWatchPrivate::dnotify_handler(int, siginfo_t *si, void *) 90void 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
111static struct sigaction old_sigio_act; 111static 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 */
116void KDirWatchPrivate::dnotify_sigio_handler(int sig, siginfo_t *si, void *p) 116void 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
174KDirWatchPrivate::KDirWatchPrivate() 174KDirWatchPrivate::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 */
254KDirWatchPrivate::~KDirWatchPrivate() 254KDirWatchPrivate::~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
271void KDirWatchPrivate::slotActivated() 271void 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 */
284void KDirWatchPrivate::Entry::propagate_dirty() 284void 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...
299void KDirWatchPrivate::slotActivated() {} 299void 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 */
305void KDirWatchPrivate::Entry::addClient(KDirWatch* instance) 305void 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
325void KDirWatchPrivate::Entry::removeClient(KDirWatch* instance) 325void 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 */
341int KDirWatchPrivate::Entry::clients() 341int 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
352KDirWatchPrivate::Entry* KDirWatchPrivate::entry(const QString& _path) 352KDirWatchPrivate::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
372void KDirWatchPrivate::useFreq(Entry* e, int newFreq) 372void 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
387bool KDirWatchPrivate::useFAM(Entry* e) 387bool 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
442bool KDirWatchPrivate::useDNotify(Entry* e) 442bool 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
513bool KDirWatchPrivate::useStat(Entry* e) 513bool 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 */
544void KDirWatchPrivate::addEntry(KDirWatch* instance, const QString& _path, 544void 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
645void KDirWatchPrivate::removeEntry( KDirWatch* instance, 646void 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 */
731void KDirWatchPrivate::removeEntries( KDirWatch* instance ) 732void 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
762bool KDirWatchPrivate::stopEntryScan( KDirWatch* instance, Entry* e) 763bool 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
785bool KDirWatchPrivate::restartEntryScan( KDirWatch* instance, Entry* e, 786bool 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
831void KDirWatchPrivate::stopScan(KDirWatch* instance) 832void 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
839void KDirWatchPrivate::startScan(KDirWatch* instance, 840void 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
854void KDirWatchPrivate::resetList( KDirWatch* /*instance*/, 855void 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//
869int KDirWatchPrivate::scanEntry(Entry* e) 870int 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 */
936void KDirWatchPrivate::emitEvent(Entry* e, int event, const QString &fileName) 937void 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
981void KDirWatchPrivate::slotRemoveDelayed() 982void 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 */
993void KDirWatchPrivate::slotRescan() 994void 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
1087void KDirWatchPrivate::famEventReceived() 1088void 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 }