Define QT_OPEN_LARGEFILE on Symbian + WinCE
[qt-netbsd.git] / src / corelib / io / qfilesystemwatcher_inotify.cpp
blob281b2dd91cfe68f8800bb6f7f35b399affe8f79c
1 /****************************************************************************
2 **
3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
6 **
7 ** This file is part of the QtCore module of the Qt Toolkit.
8 **
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** No Commercial Usage
11 ** This file contains pre-release code and may not be distributed.
12 ** You may use this file in accordance with the terms and conditions
13 ** contained in the Technology Preview License Agreement accompanying
14 ** this package.
16 ** GNU Lesser General Public License Usage
17 ** Alternatively, this file may be used under the terms of the GNU Lesser
18 ** General Public License version 2.1 as published by the Free Software
19 ** Foundation and appearing in the file LICENSE.LGPL included in the
20 ** packaging of this file. Please review the following information to
21 ** ensure the GNU Lesser General Public License version 2.1 requirements
22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 ** In addition, as a special exception, Nokia gives you certain additional
25 ** rights. These rights are described in the Nokia Qt LGPL Exception
26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 ** If you have questions regarding the use of this file, please contact
29 ** Nokia at qt-info@nokia.com.
38 ** $QT_END_LICENSE$
40 ****************************************************************************/
42 #include "qfilesystemwatcher.h"
43 #include "qfilesystemwatcher_inotify_p.h"
45 #ifndef QT_NO_FILESYSTEMWATCHER
47 #include "private/qcore_unix_p.h"
49 #include <qdebug.h>
50 #include <qfile.h>
51 #include <qfileinfo.h>
52 #include <qsocketnotifier.h>
53 #include <qvarlengtharray.h>
55 #include <sys/syscall.h>
56 #include <sys/ioctl.h>
57 #include <unistd.h>
58 #include <fcntl.h>
60 #if defined(QT_NO_INOTIFY)
61 #include <linux/types.h>
63 #if defined(__i386__)
64 # define __NR_inotify_init 291
65 # define __NR_inotify_add_watch 292
66 # define __NR_inotify_rm_watch 293
67 # define __NR_inotify_init1 332
68 #elif defined(__x86_64__)
69 # define __NR_inotify_init 253
70 # define __NR_inotify_add_watch 254
71 # define __NR_inotify_rm_watch 255
72 # define __NR_inotify_init1 294
73 #elif defined(__powerpc__) || defined(__powerpc64__)
74 # define __NR_inotify_init 275
75 # define __NR_inotify_add_watch 276
76 # define __NR_inotify_rm_watch 277
77 # define __NR_inotify_init1 318
78 #elif defined (__ia64__)
79 # define __NR_inotify_init 1277
80 # define __NR_inotify_add_watch 1278
81 # define __NR_inotify_rm_watch 1279
82 # define __NR_inotify_init1 1318
83 #elif defined (__s390__) || defined (__s390x__)
84 # define __NR_inotify_init 284
85 # define __NR_inotify_add_watch 285
86 # define __NR_inotify_rm_watch 286
87 # define __NR_inotify_init1 324
88 #elif defined (__alpha__)
89 # define __NR_inotify_init 444
90 # define __NR_inotify_add_watch 445
91 # define __NR_inotify_rm_watch 446
92 // no inotify_init1 for the Alpha
93 #elif defined (__sparc__) || defined (__sparc64__)
94 # define __NR_inotify_init 151
95 # define __NR_inotify_add_watch 152
96 # define __NR_inotify_rm_watch 156
97 # define __NR_inotify_init1 322
98 #elif defined (__arm__)
99 # define __NR_inotify_init 316
100 # define __NR_inotify_add_watch 317
101 # define __NR_inotify_rm_watch 318
102 # define __NR_inotify_init1 360
103 #elif defined (__sh__)
104 # define __NR_inotify_init 290
105 # define __NR_inotify_add_watch 291
106 # define __NR_inotify_rm_watch 292
107 # define __NR_inotify_init1 332
108 #elif defined (__sh64__)
109 # define __NR_inotify_init 318
110 # define __NR_inotify_add_watch 319
111 # define __NR_inotify_rm_watch 320
112 # define __NR_inotify_init1 360
113 #elif defined (__mips__)
114 # define __NR_inotify_init 284
115 # define __NR_inotify_add_watch 285
116 # define __NR_inotify_rm_watch 286
117 # define __NR_inotify_init1 329
118 #elif defined (__hppa__)
119 # define __NR_inotify_init 269
120 # define __NR_inotify_add_watch 270
121 # define __NR_inotify_rm_watch 271
122 # define __NR_inotify_init1 314
123 #elif defined (__avr32__)
124 # define __NR_inotify_init 240
125 # define __NR_inotify_add_watch 241
126 # define __NR_inotify_rm_watch 242
127 // no inotify_init1 for AVR32
128 #elif defined (__mc68000__)
129 # define __NR_inotify_init 284
130 # define __NR_inotify_add_watch 285
131 # define __NR_inotify_rm_watch 286
132 # define __NR_inotify_init1 328
133 #else
134 # error "This architecture is not supported. Please talk to qt-bugs@trolltech.com"
135 #endif
137 #if !defined(IN_CLOEXEC) && defined(O_CLOEXEC) && defined(__NR_inotify_init1)
138 # define IN_CLOEXEC O_CLOEXEC
139 #endif
141 QT_BEGIN_NAMESPACE
143 #ifdef QT_LINUXBASE
144 // ### the LSB doesn't standardize syscall, need to wait until glib2.4 is standardized
145 static inline int syscall(...) { return -1; }
146 #endif
148 static inline int inotify_init()
150 return syscall(__NR_inotify_init);
153 static inline int inotify_add_watch(int fd, const char *name, __u32 mask)
155 return syscall(__NR_inotify_add_watch, fd, name, mask);
158 static inline int inotify_rm_watch(int fd, __u32 wd)
160 return syscall(__NR_inotify_rm_watch, fd, wd);
163 #ifdef IN_CLOEXEC
164 static inline int inotify_init1(int flags)
166 return syscall(__NR_inotify_init1, flags);
168 #endif
170 // the following struct and values are documented in linux/inotify.h
171 extern "C" {
173 struct inotify_event {
174 __s32 wd;
175 __u32 mask;
176 __u32 cookie;
177 __u32 len;
178 char name[0];
181 #define IN_ACCESS 0x00000001
182 #define IN_MODIFY 0x00000002
183 #define IN_ATTRIB 0x00000004
184 #define IN_CLOSE_WRITE 0x00000008
185 #define IN_CLOSE_NOWRITE 0x00000010
186 #define IN_OPEN 0x00000020
187 #define IN_MOVED_FROM 0x00000040
188 #define IN_MOVED_TO 0x00000080
189 #define IN_CREATE 0x00000100
190 #define IN_DELETE 0x00000200
191 #define IN_DELETE_SELF 0x00000400
192 #define IN_MOVE_SELF 0x00000800
193 #define IN_UNMOUNT 0x00002000
194 #define IN_Q_OVERFLOW 0x00004000
195 #define IN_IGNORED 0x00008000
197 #define IN_CLOSE (IN_CLOSE_WRITE | IN_CLOSE_NOWRITE)
198 #define IN_MOVE (IN_MOVED_FROM | IN_MOVED_TO)
201 QT_END_NAMESPACE
203 // --------- inotify.h end ----------
205 #else /* QT_NO_INOTIFY */
207 #include <sys/inotify.h>
209 #endif
211 QT_BEGIN_NAMESPACE
213 QInotifyFileSystemWatcherEngine *QInotifyFileSystemWatcherEngine::create()
215 register int fd = -1;
216 #ifdef IN_CLOEXEC
217 fd = inotify_init1(IN_CLOEXEC);
218 #endif
219 if (fd == -1) {
220 fd = inotify_init();
221 if (fd == -1)
222 return 0;
223 ::fcntl(fd, F_SETFD, FD_CLOEXEC);
225 return new QInotifyFileSystemWatcherEngine(fd);
228 QInotifyFileSystemWatcherEngine::QInotifyFileSystemWatcherEngine(int fd)
229 : inotifyFd(fd)
231 fcntl(inotifyFd, F_SETFD, FD_CLOEXEC);
233 moveToThread(this);
236 QInotifyFileSystemWatcherEngine::~QInotifyFileSystemWatcherEngine()
238 foreach (int id, pathToID.values())
239 inotify_rm_watch(inotifyFd, id < 0 ? -id : id);
241 ::close(inotifyFd);
244 void QInotifyFileSystemWatcherEngine::run()
246 QSocketNotifier sn(inotifyFd, QSocketNotifier::Read, this);
247 connect(&sn, SIGNAL(activated(int)), SLOT(readFromInotify()));
248 (void) exec();
251 QStringList QInotifyFileSystemWatcherEngine::addPaths(const QStringList &paths,
252 QStringList *files,
253 QStringList *directories)
255 QMutexLocker locker(&mutex);
257 QStringList p = paths;
258 QMutableListIterator<QString> it(p);
259 while (it.hasNext()) {
260 QString path = it.next();
261 QFileInfo fi(path);
262 bool isDir = fi.isDir();
263 if (isDir) {
264 if (directories->contains(path))
265 continue;
266 } else {
267 if (files->contains(path))
268 continue;
271 int wd = inotify_add_watch(inotifyFd,
272 QFile::encodeName(path),
273 (isDir
274 ? (0
275 | IN_ATTRIB
276 | IN_MOVE
277 | IN_CREATE
278 | IN_DELETE
279 | IN_DELETE_SELF
281 : (0
282 | IN_ATTRIB
283 | IN_MODIFY
284 | IN_MOVE
285 | IN_MOVE_SELF
286 | IN_DELETE_SELF
287 )));
288 if (wd <= 0) {
289 perror("QInotifyFileSystemWatcherEngine::addPaths: inotify_add_watch failed");
290 continue;
293 it.remove();
295 int id = isDir ? -wd : wd;
296 if (id < 0) {
297 directories->append(path);
298 } else {
299 files->append(path);
302 pathToID.insert(path, id);
303 idToPath.insert(id, path);
306 start();
308 return p;
311 QStringList QInotifyFileSystemWatcherEngine::removePaths(const QStringList &paths,
312 QStringList *files,
313 QStringList *directories)
315 QMutexLocker locker(&mutex);
317 QStringList p = paths;
318 QMutableListIterator<QString> it(p);
319 while (it.hasNext()) {
320 QString path = it.next();
321 int id = pathToID.take(path);
322 QString x = idToPath.take(id);
323 if (x.isEmpty() || x != path)
324 continue;
326 int wd = id < 0 ? -id : id;
327 // qDebug() << "removing watch for path" << path << "wd" << wd;
328 inotify_rm_watch(inotifyFd, wd);
330 it.remove();
331 if (id < 0) {
332 directories->removeAll(path);
333 } else {
334 files->removeAll(path);
338 return p;
341 void QInotifyFileSystemWatcherEngine::stop()
343 QMetaObject::invokeMethod(this, "quit");
346 void QInotifyFileSystemWatcherEngine::readFromInotify()
348 QMutexLocker locker(&mutex);
350 // qDebug() << "QInotifyFileSystemWatcherEngine::readFromInotify";
352 int buffSize = 0;
353 ioctl(inotifyFd, FIONREAD, (char *) &buffSize);
354 QVarLengthArray<char, 4096> buffer(buffSize);
355 buffSize = read(inotifyFd, buffer.data(), buffSize);
356 const char *at = buffer.data();
357 const char * const end = at + buffSize;
359 QMap<int, inotify_event> eventForId;
360 while (at < end) {
361 const inotify_event *event = reinterpret_cast<const inotify_event *>(at);
363 if (eventForId.contains(event->wd))
364 eventForId[event->wd].mask |= event->mask;
365 else
366 eventForId.insert(event->wd, *event);
368 at += sizeof(inotify_event) + event->len;
371 QMap<int, inotify_event>::const_iterator it = eventForId.constBegin();
372 while (it != eventForId.constEnd()) {
373 inotify_event event = *it;
374 ++it;
376 // qDebug() << "inotify event, wd" << event.wd << "mask" << hex << event.mask;
378 int id = event.wd;
379 QString path = idToPath.value(id);
380 if (path.isEmpty()) {
381 // perhaps a directory?
382 id = -id;
383 path = idToPath.value(id);
384 if (path.isEmpty())
385 continue;
388 // qDebug() << "event for path" << path;
390 if ((event.mask & (IN_DELETE_SELF | IN_MOVE_SELF | IN_UNMOUNT)) != 0) {
391 pathToID.remove(path);
392 idToPath.remove(id);
393 inotify_rm_watch(inotifyFd, event.wd);
395 if (id < 0)
396 emit directoryChanged(path, true);
397 else
398 emit fileChanged(path, true);
399 } else {
400 if (id < 0)
401 emit directoryChanged(path, false);
402 else
403 emit fileChanged(path, false);
408 QT_END_NAMESPACE
410 #endif // QT_NO_FILESYSTEMWATCHER