-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 | |||
@@ -1,1442 +1,1443 @@ | |||
1 | // -*- c-basic-offset: 2 -*- | 1 | // -*- c-basic-offset: 2 -*- |
2 | /* This file is part of the KDE libraries | 2 | /* This file is part of the KDE libraries |
3 | Copyright (C) 1998 Sven Radej <sven@lisa.exp.univie.ac.at> | 3 | Copyright (C) 1998 Sven Radej <sven@lisa.exp.univie.ac.at> |
4 | 4 | ||
5 | This library is free software; you can redistribute it and/or | 5 | This library is free software; you can redistribute it and/or |
6 | modify it under the terms of the GNU Library General Public | 6 | modify it under the terms of the GNU Library General Public |
7 | License version 2 as published by the Free Software Foundation. | 7 | License version 2 as published by the Free Software Foundation. |
8 | 8 | ||
9 | This library is distributed in the hope that it will be useful, | 9 | This library is distributed in the hope that it will be useful, |
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
12 | Library General Public License for more details. | 12 | Library General Public License for more details. |
13 | 13 | ||
14 | You should have received a copy of the GNU Library General Public License | 14 | You should have received a copy of the GNU Library General Public License |
15 | along with this library; see the file COPYING.LIB. If not, write to | 15 | along with this library; see the file COPYING.LIB. If not, write to |
16 | the Free Software Foundation, Inc., 59 Temple Place - Suite 330, | 16 | the Free Software Foundation, Inc., 59 Temple Place - Suite 330, |
17 | Boston, MA 02111-1307, USA. | 17 | Boston, MA 02111-1307, USA. |
18 | */ | 18 | */ |
19 | 19 | ||
20 | /* | 20 | /* |
21 | Enhanced Version of the file for platform independent KDE tools. | 21 | Enhanced Version of the file for platform independent KDE tools. |
22 | Copyright (c) 2004 Ulf Schenk | 22 | Copyright (c) 2004 Ulf Schenk |
23 | 23 | ||
24 | $Id$ | 24 | $Id$ |
25 | */ | 25 | */ |
26 | 26 | ||
27 | 27 | ||
28 | // CHANGES: | 28 | // CHANGES: |
29 | // Februar 2002 - Add file watching and remote mount check for STAT | 29 | // Februar 2002 - Add file watching and remote mount check for STAT |
30 | // Mar 30, 2001 - Native support for Linux dir change notification. | 30 | // Mar 30, 2001 - Native support for Linux dir change notification. |
31 | // Jan 28, 2000 - Usage of FAM service on IRIX (Josef.Weidendorfer@in.tum.de) | 31 | // Jan 28, 2000 - Usage of FAM service on IRIX (Josef.Weidendorfer@in.tum.de) |
32 | // May 24. 1998 - List of times introduced, and some bugs are fixed. (sven) | 32 | // May 24. 1998 - List of times introduced, and some bugs are fixed. (sven) |
33 | // May 23. 1998 - Removed static pointer - you can have more instances. | 33 | // May 23. 1998 - Removed static pointer - you can have more instances. |
34 | // It was Needed for KRegistry. KDirWatch now emits signals and doesn't | 34 | // It was Needed for KRegistry. KDirWatch now emits signals and doesn't |
35 | // call (or need) KFM. No more URL's - just plain paths. (sven) | 35 | // call (or need) KFM. No more URL's - just plain paths. (sven) |
36 | // Mar 29. 1998 - added docs, stop/restart for particular Dirs and | 36 | // Mar 29. 1998 - added docs, stop/restart for particular Dirs and |
37 | // deep copies for list of dirs. (sven) | 37 | // deep copies for list of dirs. (sven) |
38 | // Mar 28. 1998 - Created. (sven) | 38 | // Mar 28. 1998 - Created. (sven) |
39 | 39 | ||
40 | 40 | ||
41 | //US #include <config.h> | 41 | //US #include <config.h> |
42 | 42 | ||
43 | #ifdef HAVE_DNOTIFY | 43 | #ifdef HAVE_DNOTIFY |
44 | #include <unistd.h> | 44 | #include <unistd.h> |
45 | #include <time.h> | 45 | #include <time.h> |
46 | #include <fcntl.h> | 46 | #include <fcntl.h> |
47 | #include <signal.h> | 47 | #include <signal.h> |
48 | #include <errno.h> | 48 | #include <errno.h> |
49 | #endif | 49 | #endif |
50 | 50 | ||
51 | #include <sys/stat.h> | 51 | #include <sys/stat.h> |
52 | #include <assert.h> | 52 | #include <assert.h> |
53 | #include <qdir.h> | 53 | #include <qdir.h> |
54 | #include <qfile.h> | 54 | #include <qfile.h> |
55 | #include <qintdict.h> | 55 | #include <qintdict.h> |
56 | #include <qptrlist.h> | 56 | #include <qptrlist.h> |
57 | #include <qsocketnotifier.h> | 57 | #include <qsocketnotifier.h> |
58 | #include <qstringlist.h> | 58 | #include <qstringlist.h> |
59 | #include <qtimer.h> | 59 | #include <qtimer.h> |
60 | 60 | ||
61 | #include <kapplication.h> | 61 | #include <kapplication.h> |
62 | #include <kdebug.h> | 62 | #include <kdebug.h> |
63 | #include <kconfig.h> | 63 | #include <kconfig.h> |
64 | #include <kconfigbase.h> | 64 | #include <kconfigbase.h> |
65 | #include <kglobal.h> | 65 | #include <kglobal.h> |
66 | #include <kstaticdeleter.h> | 66 | #include <kstaticdeleter.h> |
67 | 67 | ||
68 | #include "kdirwatch.h" | 68 | #include "kdirwatch.h" |
69 | #include "kdirwatch_p.h" | 69 | #include "kdirwatch_p.h" |
70 | //US #include "global.h" // KIO::probably_slow_mounted | 70 | //US #include "global.h" // KIO::probably_slow_mounted |
71 | 71 | ||
72 | #define NO_NOTIFY (time_t) 0 | 72 | #define NO_NOTIFY (time_t) 0 |
73 | 73 | ||
74 | static KDirWatchPrivate* dwp_self = 0; | 74 | static KDirWatchPrivate* dwp_self = 0; |
75 | 75 | ||
76 | #ifdef HAVE_DNOTIFY | 76 | #ifdef HAVE_DNOTIFY |
77 | 77 | ||
78 | #include <sys/utsname.h> | 78 | #include <sys/utsname.h> |
79 | 79 | ||
80 | static int dnotify_signal = 0; | 80 | static int dnotify_signal = 0; |
81 | 81 | ||
82 | /* DNOTIFY signal handler | 82 | /* DNOTIFY signal handler |
83 | * | 83 | * |
84 | * As this is called asynchronously, only a flag is set and | 84 | * As this is called asynchronously, only a flag is set and |
85 | * a rescan is requested. | 85 | * a rescan is requested. |
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 | } |
1111 | else | 1112 | else |
1112 | checkFAMEvent(&fe); | 1113 | checkFAMEvent(&fe); |
1113 | } | 1114 | } |
1114 | 1115 | ||
1115 | QTimer::singleShot(0, this, SLOT(slotRemoveDelayed())); | 1116 | QTimer::singleShot(0, this, SLOT(slotRemoveDelayed())); |
1116 | } | 1117 | } |
1117 | 1118 | ||
1118 | void KDirWatchPrivate::checkFAMEvent(FAMEvent* fe) | 1119 | void KDirWatchPrivate::checkFAMEvent(FAMEvent* fe) |
1119 | { | 1120 | { |
1120 | // Don't be too verbose ;-) | 1121 | // Don't be too verbose ;-) |
1121 | if ((fe->code == FAMExists) || | 1122 | if ((fe->code == FAMExists) || |
1122 | (fe->code == FAMEndExist) || | 1123 | (fe->code == FAMEndExist) || |
1123 | (fe->code == FAMAcknowledge)) return; | 1124 | (fe->code == FAMAcknowledge)) return; |
1124 | 1125 | ||
1125 | // $HOME/.X.err grows with debug output, so don't notify change | 1126 | // $HOME/.X.err grows with debug output, so don't notify change |
1126 | if ( *(fe->filename) == '.') { | 1127 | if ( *(fe->filename) == '.') { |
1127 | if (strncmp(fe->filename, ".X.err", 6) == 0) return; | 1128 | if (strncmp(fe->filename, ".X.err", 6) == 0) return; |
1128 | if (strncmp(fe->filename, ".xsession-errors", 16) == 0) return; | 1129 | if (strncmp(fe->filename, ".xsession-errors", 16) == 0) return; |
1129 | } | 1130 | } |
1130 | 1131 | ||
1131 | Entry* e = 0; | 1132 | Entry* e = 0; |
1132 | EntryMap::Iterator it = m_mapEntries.begin(); | 1133 | EntryMap::Iterator it = m_mapEntries.begin(); |
1133 | for( ; it != m_mapEntries.end(); ++it ) | 1134 | for( ; it != m_mapEntries.end(); ++it ) |
1134 | if (FAMREQUEST_GETREQNUM(&( (*it).fr )) == | 1135 | if (FAMREQUEST_GETREQNUM(&( (*it).fr )) == |
1135 | FAMREQUEST_GETREQNUM(&(fe->fr)) ) { | 1136 | FAMREQUEST_GETREQNUM(&(fe->fr)) ) { |
1136 | e = &(*it); | 1137 | e = &(*it); |
1137 | break; | 1138 | break; |
1138 | } | 1139 | } |
1139 | 1140 | ||
1140 | // Entry* e = static_cast<Entry*>(fe->userdata); | 1141 | // Entry* e = static_cast<Entry*>(fe->userdata); |
1141 | 1142 | ||
1142 | kdDebug(7001) << "Processing FAM event (" | 1143 | kdDebug(7001) << "Processing FAM event (" |
1143 | << ((fe->code == FAMChanged) ? "FAMChanged" : | 1144 | << ((fe->code == FAMChanged) ? "FAMChanged" : |
1144 | (fe->code == FAMDeleted) ? "FAMDeleted" : | 1145 | (fe->code == FAMDeleted) ? "FAMDeleted" : |
1145 | (fe->code == FAMStartExecuting) ? "FAMStartExecuting" : | 1146 | (fe->code == FAMStartExecuting) ? "FAMStartExecuting" : |
1146 | (fe->code == FAMStopExecuting) ? "FAMStopExecuting" : | 1147 | (fe->code == FAMStopExecuting) ? "FAMStopExecuting" : |
1147 | (fe->code == FAMCreated) ? "FAMCreated" : | 1148 | (fe->code == FAMCreated) ? "FAMCreated" : |
1148 | (fe->code == FAMMoved) ? "FAMMoved" : | 1149 | (fe->code == FAMMoved) ? "FAMMoved" : |
1149 | (fe->code == FAMAcknowledge) ? "FAMAcknowledge" : | 1150 | (fe->code == FAMAcknowledge) ? "FAMAcknowledge" : |
1150 | (fe->code == FAMExists) ? "FAMExists" : | 1151 | (fe->code == FAMExists) ? "FAMExists" : |
1151 | (fe->code == FAMEndExist) ? "FAMEndExist" : "Unknown Code") | 1152 | (fe->code == FAMEndExist) ? "FAMEndExist" : "Unknown Code") |
1152 | << ", " << fe->filename | 1153 | << ", " << fe->filename |
1153 | << ", Req " << FAMREQUEST_GETREQNUM(&(fe->fr)) | 1154 | << ", Req " << FAMREQUEST_GETREQNUM(&(fe->fr)) |
1154 | << ")" << endl; | 1155 | << ")" << endl; |
1155 | 1156 | ||
1156 | if (!e) { | 1157 | if (!e) { |
1157 | // this happens e.g. for FAMAcknowledge after deleting a dir... | 1158 | // this happens e.g. for FAMAcknowledge after deleting a dir... |
1158 | // kdDebug(7001) << "No entry for FAM event ?!" << endl; | 1159 | // kdDebug(7001) << "No entry for FAM event ?!" << endl; |
1159 | return; | 1160 | return; |
1160 | } | 1161 | } |
1161 | 1162 | ||
1162 | if (e->m_status == NonExistent) { | 1163 | if (e->m_status == NonExistent) { |
1163 | kdDebug(7001) << "FAM event for nonExistent entry " << e->path << endl; | 1164 | kdDebug(7001) << "FAM event for nonExistent entry " << e->path << endl; |
1164 | return; | 1165 | return; |
1165 | } | 1166 | } |
1166 | 1167 | ||
1167 | if (e->isDir) | 1168 | if (e->isDir) |
1168 | switch (fe->code) | 1169 | switch (fe->code) |
1169 | { | 1170 | { |
1170 | case FAMDeleted: | 1171 | case FAMDeleted: |
1171 | // file absolute: watched dir | 1172 | // file absolute: watched dir |
1172 | if (fe->filename[0] == '/') | 1173 | if (fe->filename[0] == '/') |
1173 | { | 1174 | { |
1174 | // a watched directory was deleted | 1175 | // a watched directory was deleted |
1175 | 1176 | ||
1176 | e->m_status = NonExistent; | 1177 | e->m_status = NonExistent; |
1177 | FAMCancelMonitor(&fc, &(e->fr) ); // needed ? | 1178 | FAMCancelMonitor(&fc, &(e->fr) ); // needed ? |
1178 | kdDebug(7001) << "Cancelled FAMReq " | 1179 | kdDebug(7001) << "Cancelled FAMReq " |
1179 | << FAMREQUEST_GETREQNUM(&(e->fr)) | 1180 | << FAMREQUEST_GETREQNUM(&(e->fr)) |
1180 | << " for " << e->path << endl; | 1181 | << " for " << e->path << endl; |
1181 | // Scan parent for a new creation | 1182 | // Scan parent for a new creation |
1182 | addEntry(0, QDir::cleanDirPath( e->path+"/.."), e, true); | 1183 | addEntry(0, QDir::cleanDirPath( e->path+"/.."), e, true); |
1183 | } | 1184 | } |
1184 | emitEvent(e, Deleted, QFile::decodeName(fe->filename)); | 1185 | emitEvent(e, Deleted, QFile::decodeName(fe->filename)); |
1185 | break; | 1186 | break; |
1186 | 1187 | ||
1187 | case FAMCreated: { | 1188 | case FAMCreated: { |
1188 | // check for creation of a directory we have to watch | 1189 | // check for creation of a directory we have to watch |
1189 | Entry *sub_entry = e->m_entries.first(); | 1190 | Entry *sub_entry = e->m_entries.first(); |
1190 | for(;sub_entry; sub_entry = e->m_entries.next()) | 1191 | for(;sub_entry; sub_entry = e->m_entries.next()) |
1191 | if (sub_entry->path == e->path + "/" + fe->filename) break; | 1192 | if (sub_entry->path == e->path + "/" + fe->filename) break; |
1192 | if (sub_entry && sub_entry->isDir) { | 1193 | if (sub_entry && sub_entry->isDir) { |
1193 | QString path = e->path; | 1194 | QString path = e->path; |
1194 | removeEntry(0,e->path,sub_entry); // <e> can be invalid here!! | 1195 | removeEntry(0,e->path,sub_entry); // <e> can be invalid here!! |
1195 | sub_entry->m_status = Normal; | 1196 | sub_entry->m_status = Normal; |
1196 | if (!useFAM(sub_entry)) | 1197 | if (!useFAM(sub_entry)) |
1197 | useStat(sub_entry); | 1198 | useStat(sub_entry); |
1198 | 1199 | ||
1199 | emitEvent(sub_entry, Created); | 1200 | emitEvent(sub_entry, Created); |
1200 | } | 1201 | } |
1201 | else emitEvent(e, Created, QFile::decodeName(fe->filename)); | 1202 | else emitEvent(e, Created, QFile::decodeName(fe->filename)); |
1202 | break; | 1203 | break; |
1203 | } | 1204 | } |
1204 | 1205 | ||
1205 | case FAMChanged: | 1206 | case FAMChanged: |
1206 | emitEvent(e, Changed, QFile::decodeName(fe->filename)); | 1207 | emitEvent(e, Changed, QFile::decodeName(fe->filename)); |
1207 | 1208 | ||
1208 | default: | 1209 | default: |
1209 | break; | 1210 | break; |
1210 | } | 1211 | } |
1211 | else switch (fe->code) | 1212 | else switch (fe->code) |
1212 | { | 1213 | { |
1213 | case FAMCreated: emitEvent(e, Created); | 1214 | case FAMCreated: emitEvent(e, Created); |
1214 | break; | 1215 | break; |
1215 | case FAMDeleted: emitEvent(e, Deleted); | 1216 | case FAMDeleted: emitEvent(e, Deleted); |
1216 | break; | 1217 | break; |
1217 | case FAMChanged: emitEvent(e, Changed); | 1218 | case FAMChanged: emitEvent(e, Changed); |
1218 | break; | 1219 | break; |
1219 | default: break; | 1220 | default: break; |
1220 | } | 1221 | } |
1221 | } | 1222 | } |
1222 | #else | 1223 | #else |
1223 | void KDirWatchPrivate::famEventReceived() {} | 1224 | void KDirWatchPrivate::famEventReceived() {} |
1224 | #endif | 1225 | #endif |
1225 | 1226 | ||
1226 | 1227 | ||
1227 | void KDirWatchPrivate::statistics() | 1228 | void KDirWatchPrivate::statistics() |
1228 | { | 1229 | { |
1229 | EntryMap::Iterator it; | 1230 | EntryMap::Iterator it; |
1230 | 1231 | ||
1231 | kdDebug(7001) << "Entries watched:" << endl; | 1232 | kdDebug(7001) << "Entries watched:" << endl; |
1232 | if (m_mapEntries.count()==0) { | 1233 | if (m_mapEntries.count()==0) { |
1233 | kdDebug(7001) << " None." << endl; | 1234 | kdDebug(7001) << " None." << endl; |
1234 | } | 1235 | } |
1235 | else { | 1236 | else { |
1236 | it = m_mapEntries.begin(); | 1237 | it = m_mapEntries.begin(); |
1237 | for( ; it != m_mapEntries.end(); ++it ) { | 1238 | for( ; it != m_mapEntries.end(); ++it ) { |
1238 | Entry* e = &(*it); | 1239 | Entry* e = &(*it); |
1239 | kdDebug(7001) << " " << e->path << " (" | 1240 | kdDebug(7001) << " " << e->path << " (" |
1240 | << ((e->m_status==Normal)?"":"Nonexistent ") | 1241 | << ((e->m_status==Normal)?"":"Nonexistent ") |
1241 | << (e->isDir ? "Dir":"File") << ", using " | 1242 | << (e->isDir ? "Dir":"File") << ", using " |
1242 | << ((e->m_mode == FAMMode) ? "FAM" : | 1243 | << ((e->m_mode == FAMMode) ? "FAM" : |
1243 | (e->m_mode == DNotifyMode) ? "DNotify" : | 1244 | (e->m_mode == DNotifyMode) ? "DNotify" : |
1244 | (e->m_mode == StatMode) ? "Stat" : "Unknown Method") | 1245 | (e->m_mode == StatMode) ? "Stat" : "Unknown Method") |
1245 | << ")" << endl; | 1246 | << ")" << endl; |
1246 | 1247 | ||
1247 | Client* c = e->m_clients.first(); | 1248 | Client* c = e->m_clients.first(); |
1248 | for(;c; c = e->m_clients.next()) { | 1249 | for(;c; c = e->m_clients.next()) { |
1249 | QString pending; | 1250 | QString pending; |
1250 | if (c->watchingStopped) { | 1251 | if (c->watchingStopped) { |
1251 | if (c->pending & Deleted) pending += "deleted "; | 1252 | if (c->pending & Deleted) pending += "deleted "; |
1252 | if (c->pending & Created) pending += "created "; | 1253 | if (c->pending & Created) pending += "created "; |
1253 | if (c->pending & Changed) pending += "changed "; | 1254 | if (c->pending & Changed) pending += "changed "; |
1254 | if (!pending.isEmpty()) pending = " (pending: " + pending + ")"; | 1255 | if (!pending.isEmpty()) pending = " (pending: " + pending + ")"; |
1255 | pending = ", stopped" + pending; | 1256 | pending = ", stopped" + pending; |
1256 | } | 1257 | } |
1257 | kdDebug(7001) << " by " << c->instance->name() | 1258 | kdDebug(7001) << " by " << c->instance->name() |
1258 | << " (" << c->count << " times)" | 1259 | << " (" << c->count << " times)" |
1259 | << pending << endl; | 1260 | << pending << endl; |
1260 | } | 1261 | } |
1261 | if (e->m_entries.count()>0) { | 1262 | if (e->m_entries.count()>0) { |
1262 | kdDebug(7001) << " dependent entries:" << endl; | 1263 | kdDebug(7001) << " dependent entries:" << endl; |
1263 | Entry* d = e->m_entries.first(); | 1264 | Entry* d = e->m_entries.first(); |
1264 | for(;d; d = e->m_entries.next()) { | 1265 | for(;d; d = e->m_entries.next()) { |
1265 | kdDebug(7001) << " " << d->path << endl; | 1266 | kdDebug(7001) << " " << d->path << endl; |
1266 | } | 1267 | } |
1267 | } | 1268 | } |
1268 | } | 1269 | } |
1269 | } | 1270 | } |
1270 | } | 1271 | } |
1271 | 1272 | ||
1272 | 1273 | ||
1273 | // | 1274 | // |
1274 | // Class KDirWatch | 1275 | // Class KDirWatch |
1275 | // | 1276 | // |
1276 | 1277 | ||
1277 | static KStaticDeleter<KDirWatch> sd_dw; | 1278 | static KStaticDeleter<KDirWatch> sd_dw; |
1278 | KDirWatch* KDirWatch::s_pSelf = 0L; | 1279 | KDirWatch* KDirWatch::s_pSelf = 0L; |
1279 | 1280 | ||
1280 | KDirWatch* KDirWatch::self() | 1281 | KDirWatch* KDirWatch::self() |
1281 | { | 1282 | { |
1282 | if ( !s_pSelf ) { | 1283 | if ( !s_pSelf ) { |
1283 | //US sd_dw.setObject( s_pSelf, new KDirWatch ); | 1284 | //US sd_dw.setObject( s_pSelf, new KDirWatch ); |
1284 | s_pSelf = sd_dw.setObject( new KDirWatch ); | 1285 | s_pSelf = sd_dw.setObject( new KDirWatch ); |
1285 | } | 1286 | } |
1286 | 1287 | ||
1287 | return s_pSelf; | 1288 | return s_pSelf; |
1288 | } | 1289 | } |
1289 | 1290 | ||
1290 | bool KDirWatch::exists() | 1291 | bool KDirWatch::exists() |
1291 | { | 1292 | { |
1292 | return s_pSelf != 0; | 1293 | return s_pSelf != 0; |
1293 | } | 1294 | } |
1294 | 1295 | ||
1295 | KDirWatch::KDirWatch (QObject* parent, const char* name) | 1296 | KDirWatch::KDirWatch (QObject* parent, const char* name) |
1296 | : QObject(parent,name) | 1297 | : QObject(parent,name) |
1297 | { | 1298 | { |
1298 | if (!name) { | 1299 | if (!name) { |
1299 | static int nameCounter = 0; | 1300 | static int nameCounter = 0; |
1300 | 1301 | ||
1301 | nameCounter++; | 1302 | nameCounter++; |
1302 | setName(QString("KDirWatch-%1").arg(nameCounter).ascii()); | 1303 | setName(QString("KDirWatch-%1").arg(nameCounter).ascii()); |
1303 | } | 1304 | } |
1304 | 1305 | ||
1305 | if (!dwp_self) | 1306 | if (!dwp_self) |
1306 | dwp_self = new KDirWatchPrivate; | 1307 | dwp_self = new KDirWatchPrivate; |
1307 | d = dwp_self; | 1308 | d = dwp_self; |
1308 | d->ref(); | 1309 | d->ref(); |
1309 | 1310 | ||
1310 | _isStopped = false; | 1311 | _isStopped = false; |
1311 | } | 1312 | } |
1312 | 1313 | ||
1313 | KDirWatch::~KDirWatch() | 1314 | KDirWatch::~KDirWatch() |
1314 | { | 1315 | { |
1315 | if (d) d->removeEntries(this); | 1316 | if (d) d->removeEntries(this); |
1316 | if ( d->deref() ) | 1317 | if ( d->deref() ) |
1317 | { | 1318 | { |
1318 | // delete it if it's the last one | 1319 | // delete it if it's the last one |
1319 | delete d; | 1320 | delete d; |
1320 | dwp_self = 0L; | 1321 | dwp_self = 0L; |
1321 | } | 1322 | } |
1322 | } | 1323 | } |
1323 | 1324 | ||
1324 | 1325 | ||
1325 | // TODO: add watchFiles/recursive support | 1326 | // TODO: add watchFiles/recursive support |
1326 | void KDirWatch::addDir( const QString& _path, | 1327 | void KDirWatch::addDir( const QString& _path, |
1327 | bool watchFiles, bool recursive) | 1328 | bool watchFiles, bool recursive) |
1328 | { | 1329 | { |
1329 | if (watchFiles || recursive) { | 1330 | if (watchFiles || recursive) { |
1330 | kdDebug(7001) << "addDir - recursive/watchFiles not supported in KDE 3.0" | 1331 | kdDebug(7001) << "addDir - recursive/watchFiles not supported in KDE 3.0" |
1331 | << endl; | 1332 | << endl; |
1332 | } | 1333 | } |
1333 | if (d) d->addEntry(this, _path, 0, true); | 1334 | if (d) d->addEntry(this, _path, 0, true); |
1334 | } | 1335 | } |
1335 | 1336 | ||
1336 | void KDirWatch::addFile( const QString& _path ) | 1337 | void KDirWatch::addFile( const QString& _path ) |
1337 | { | 1338 | { |
1338 | if (d) d->addEntry(this, _path, 0, false); | 1339 | if (d) d->addEntry(this, _path, 0, false); |
1339 | } | 1340 | } |
1340 | 1341 | ||
1341 | QDateTime KDirWatch::ctime( const QString &_path ) | 1342 | QDateTime KDirWatch::ctime( const QString &_path ) |
1342 | { | 1343 | { |
1343 | KDirWatchPrivate::Entry* e = d->entry(_path); | 1344 | KDirWatchPrivate::Entry* e = d->entry(_path); |
1344 | 1345 | ||
1345 | if (!e) | 1346 | if (!e) |
1346 | return QDateTime(); | 1347 | return QDateTime(); |
1347 | 1348 | ||
1348 | QDateTime result; | 1349 | QDateTime result; |
1349 | result.setTime_t(e->m_ctime); | 1350 | result.setTime_t(e->m_ctime); |
1350 | return result; | 1351 | return result; |
1351 | } | 1352 | } |
1352 | 1353 | ||
1353 | void KDirWatch::removeDir( const QString& _path ) | 1354 | void KDirWatch::removeDir( const QString& _path ) |
1354 | { | 1355 | { |
1355 | if (d) d->removeEntry(this, _path, 0); | 1356 | if (d) d->removeEntry(this, _path, 0); |
1356 | } | 1357 | } |
1357 | 1358 | ||
1358 | void KDirWatch::removeFile( const QString& _path ) | 1359 | void KDirWatch::removeFile( const QString& _path ) |
1359 | { | 1360 | { |
1360 | if (d) d->removeEntry(this, _path, 0); | 1361 | if (d) d->removeEntry(this, _path, 0); |
1361 | } | 1362 | } |
1362 | 1363 | ||
1363 | bool KDirWatch::stopDirScan( const QString& _path ) | 1364 | bool KDirWatch::stopDirScan( const QString& _path ) |
1364 | { | 1365 | { |
1365 | if (d) { | 1366 | if (d) { |
1366 | KDirWatchPrivate::Entry *e = d->entry(_path); | 1367 | KDirWatchPrivate::Entry *e = d->entry(_path); |
1367 | if (e && e->isDir) return d->stopEntryScan(this, e); | 1368 | if (e && e->isDir) return d->stopEntryScan(this, e); |
1368 | } | 1369 | } |
1369 | return false; | 1370 | return false; |
1370 | } | 1371 | } |
1371 | 1372 | ||
1372 | bool KDirWatch::restartDirScan( const QString& _path ) | 1373 | bool KDirWatch::restartDirScan( const QString& _path ) |
1373 | { | 1374 | { |
1374 | if (d) { | 1375 | if (d) { |
1375 | KDirWatchPrivate::Entry *e = d->entry(_path); | 1376 | KDirWatchPrivate::Entry *e = d->entry(_path); |
1376 | if (e && e->isDir) | 1377 | if (e && e->isDir) |
1377 | // restart without notifying pending events | 1378 | // restart without notifying pending events |
1378 | return d->restartEntryScan(this, e, false); | 1379 | return d->restartEntryScan(this, e, false); |
1379 | } | 1380 | } |
1380 | return false; | 1381 | return false; |
1381 | } | 1382 | } |
1382 | 1383 | ||
1383 | void KDirWatch::stopScan() | 1384 | void KDirWatch::stopScan() |
1384 | { | 1385 | { |
1385 | if (d) d->stopScan(this); | 1386 | if (d) d->stopScan(this); |
1386 | _isStopped = true; | 1387 | _isStopped = true; |
1387 | } | 1388 | } |
1388 | 1389 | ||
1389 | void KDirWatch::startScan( bool notify, bool skippedToo ) | 1390 | void KDirWatch::startScan( bool notify, bool skippedToo ) |
1390 | { | 1391 | { |
1391 | _isStopped = false; | 1392 | _isStopped = false; |
1392 | if (d) d->startScan(this, notify, skippedToo); | 1393 | if (d) d->startScan(this, notify, skippedToo); |
1393 | } | 1394 | } |
1394 | 1395 | ||
1395 | 1396 | ||
1396 | bool KDirWatch::contains( const QString& _path ) const | 1397 | bool KDirWatch::contains( const QString& _path ) const |
1397 | { | 1398 | { |
1398 | KDirWatchPrivate::Entry* e = d->entry(_path); | 1399 | KDirWatchPrivate::Entry* e = d->entry(_path); |
1399 | if (!e) | 1400 | if (!e) |
1400 | return false; | 1401 | return false; |
1401 | 1402 | ||
1402 | KDirWatchPrivate::Client* c = e->m_clients.first(); | 1403 | KDirWatchPrivate::Client* c = e->m_clients.first(); |
1403 | for(;c;c=e->m_clients.next()) | 1404 | for(;c;c=e->m_clients.next()) |
1404 | if (c->instance == this) return true; | 1405 | if (c->instance == this) return true; |
1405 | 1406 | ||
1406 | return false; | 1407 | return false; |
1407 | } | 1408 | } |
1408 | 1409 | ||
1409 | void KDirWatch::statistics() | 1410 | void KDirWatch::statistics() |
1410 | { | 1411 | { |
1411 | if (!dwp_self) { | 1412 | if (!dwp_self) { |
1412 | kdDebug(7001) << "KDirWatch not used" << endl; | 1413 | kdDebug(7001) << "KDirWatch not used" << endl; |
1413 | return; | 1414 | return; |
1414 | } | 1415 | } |
1415 | dwp_self->statistics(); | 1416 | dwp_self->statistics(); |
1416 | } | 1417 | } |
1417 | 1418 | ||
1418 | 1419 | ||
1419 | void KDirWatch::setCreated( const QString & _file ) | 1420 | void KDirWatch::setCreated( const QString & _file ) |
1420 | { | 1421 | { |
1421 | kdDebug(7001) << name() << " emitting created " << _file << endl; | 1422 | kdDebug(7001) << name() << " emitting created " << _file << endl; |
1422 | emit created( _file ); | 1423 | emit created( _file ); |
1423 | } | 1424 | } |
1424 | 1425 | ||
1425 | void KDirWatch::setDirty( const QString & _file ) | 1426 | void KDirWatch::setDirty( const QString & _file ) |
1426 | { | 1427 | { |
1427 | kdDebug(7001) << name() << " emitting dirty " << _file << endl; | 1428 | kdDebug(7001) << name() << " emitting dirty " << _file << endl; |
1428 | emit dirty( _file ); | 1429 | emit dirty( _file ); |
1429 | } | 1430 | } |
1430 | 1431 | ||
1431 | void KDirWatch::setDeleted( const QString & _file ) | 1432 | void KDirWatch::setDeleted( const QString & _file ) |
1432 | { | 1433 | { |
1433 | kdDebug(7001) << name() << " emitting deleted " << _file << endl; | 1434 | kdDebug(7001) << name() << " emitting deleted " << _file << endl; |
1434 | emit deleted( _file ); | 1435 | emit deleted( _file ); |
1435 | } | 1436 | } |
1436 | 1437 | ||
1437 | //US #include "kdirwatch.moc" | 1438 | //US #include "kdirwatch.moc" |
1438 | //US #include "kdirwatch_p.moc" | 1439 | //US #include "kdirwatch_p.moc" |
1439 | 1440 | ||
1440 | //sven | 1441 | //sven |
1441 | 1442 | ||
1442 | // vim: sw=2 ts=8 et | 1443 | // vim: sw=2 ts=8 et |