8#include "private/qcore_unix_p.h"
9#include "private/qsystemerror_p.h"
14#include <qscopeguard.h>
15#include <qsocketnotifier.h>
16#include <qvarlengtharray.h>
18#if defined(Q_OS_LINUX)
19#include <sys/syscall.h>
25#if defined(QT_NO_INOTIFY)
29#error "Should not get here."
32#include <linux/types.h>
35# define __NR_inotify_init 291
36# define __NR_inotify_add_watch 292
37# define __NR_inotify_rm_watch 293
38# define __NR_inotify_init1 332
39#elif defined(__x86_64__)
40# define __NR_inotify_init 253
41# define __NR_inotify_add_watch 254
42# define __NR_inotify_rm_watch 255
43# define __NR_inotify_init1 294
44#elif defined(__powerpc__) || defined(__powerpc64__)
45# define __NR_inotify_init 275
46# define __NR_inotify_add_watch 276
47# define __NR_inotify_rm_watch 277
48# define __NR_inotify_init1 318
49#elif defined (__ia64__)
50# define __NR_inotify_init 1277
51# define __NR_inotify_add_watch 1278
52# define __NR_inotify_rm_watch 1279
53# define __NR_inotify_init1 1318
54#elif defined (__s390__) || defined (__s390x__)
55# define __NR_inotify_init 284
56# define __NR_inotify_add_watch 285
57# define __NR_inotify_rm_watch 286
58# define __NR_inotify_init1 324
59#elif defined (__alpha__)
60# define __NR_inotify_init 444
61# define __NR_inotify_add_watch 445
62# define __NR_inotify_rm_watch 446
64#elif defined (__sparc__) || defined (__sparc64__)
65# define __NR_inotify_init 151
66# define __NR_inotify_add_watch 152
67# define __NR_inotify_rm_watch 156
68# define __NR_inotify_init1 322
69#elif defined (__arm__)
70# define __NR_inotify_init 316
71# define __NR_inotify_add_watch 317
72# define __NR_inotify_rm_watch 318
73# define __NR_inotify_init1 360
75# define __NR_inotify_init 290
76# define __NR_inotify_add_watch 291
77# define __NR_inotify_rm_watch 292
78# define __NR_inotify_init1 332
79#elif defined (__sh64__)
80# define __NR_inotify_init 318
81# define __NR_inotify_add_watch 319
82# define __NR_inotify_rm_watch 320
83# define __NR_inotify_init1 360
84#elif defined (__mips__)
85# define __NR_inotify_init 284
86# define __NR_inotify_add_watch 285
87# define __NR_inotify_rm_watch 286
88# define __NR_inotify_init1 329
89#elif defined (__hppa__)
90# define __NR_inotify_init 269
91# define __NR_inotify_add_watch 270
92# define __NR_inotify_rm_watch 271
93# define __NR_inotify_init1 314
94#elif defined (__avr32__)
95# define __NR_inotify_init 240
96# define __NR_inotify_add_watch 241
97# define __NR_inotify_rm_watch 242
99#elif defined (__mc68000__)
100# define __NR_inotify_init 284
101# define __NR_inotify_add_watch 285
102# define __NR_inotify_rm_watch 286
103# define __NR_inotify_init1 328
104#elif defined (__aarch64__)
105# define __NR_inotify_init1 26
106# define __NR_inotify_add_watch 27
107# define __NR_inotify_rm_watch 28
110# error "This architecture is not supported. Please see http://www.qt-project.org/"
113#if !defined(IN_CLOEXEC) && defined(O_CLOEXEC) && defined(__NR_inotify_init1)
114# define IN_CLOEXEC O_CLOEXEC
121static inline int syscall(...) {
return -1; }
124static inline int inotify_init()
126#ifdef __NR_inotify_init
127 return syscall(__NR_inotify_init);
129 return syscall(__NR_inotify_init1, 0);
133static inline int inotify_add_watch(
int fd,
const char *name, __u32 mask)
135 return syscall(__NR_inotify_add_watch, fd, name, mask);
138static inline int inotify_rm_watch(
int fd, __u32 wd)
140 return syscall(__NR_inotify_rm_watch, fd, wd);
144static inline int inotify_init1(
int flags)
146 return syscall(__NR_inotify_init1, flags);
153struct inotify_event {
161#define IN_ACCESS 0x00000001
162#define IN_MODIFY 0x00000002
163#define IN_ATTRIB 0x00000004
164#define IN_CLOSE_WRITE 0x00000008
165#define IN_CLOSE_NOWRITE 0x00000010
166#define IN_OPEN 0x00000020
167#define IN_MOVED_FROM 0x00000040
168#define IN_MOVED_TO 0x00000080
169#define IN_CREATE 0x00000100
170#define IN_DELETE 0x00000200
171#define IN_DELETE_SELF 0x00000400
172#define IN_MOVE_SELF 0x00000800
173#define IN_UNMOUNT 0x00002000
174#define IN_Q_OVERFLOW 0x00004000
175#define IN_IGNORED 0x00008000
177#define IN_CLOSE (IN_CLOSE_WRITE | IN_CLOSE_NOWRITE)
178#define IN_MOVE (IN_MOVED_FROM | IN_MOVED_TO)
187#include <sys/inotify.h>
190# if defined(Q_OS_ANDROID) && (__ANDROID_API__ < 21
)
191static inline int inotify_init1(
int flags)
193 return syscall(__NR_inotify_init1, flags);
201QInotifyFileSystemWatcherEngine *QInotifyFileSystemWatcherEngine::create(QObject *parent)
204#if defined(IN_CLOEXEC
)
205 fd = inotify_init1(IN_CLOEXEC);
212 return new QInotifyFileSystemWatcherEngine(fd, parent);
215QInotifyFileSystemWatcherEngine::QInotifyFileSystemWatcherEngine(
int fd, QObject *parent)
216 : QFileSystemWatcherEngine(parent),
218 notifier(fd, QSocketNotifier::Read,
this)
220 fcntl(inotifyFd, F_SETFD, FD_CLOEXEC);
221 QObject::connect(¬ifier, &QSocketNotifier::activated,
222 this, &QInotifyFileSystemWatcherEngine::readFromInotify);
225QInotifyFileSystemWatcherEngine::~QInotifyFileSystemWatcherEngine()
227 notifier.setEnabled(
false);
228 for (
int id : std::as_const(pathToID))
229 inotify_rm_watch(inotifyFd, id < 0 ? -id : id);
234QStringList QInotifyFileSystemWatcherEngine::addPaths(
const QStringList &paths,
236 QStringList *directories)
238 QStringList unhandled;
239 for (
const QString &path : paths) {
241 bool isDir = fi.isDir();
242 auto sg = qScopeGuard([&]{ unhandled.push_back(path); });
244 if (directories->contains(path))
247 if (files->contains(path))
251 int wd = inotify_add_watch(inotifyFd,
252 QFile::encodeName(path),
270 qErrnoWarning(
"inotify_add_watch(%ls) failed:", path.constData());
276 int id = isDir ? -wd : wd;
278 directories->append(path);
283 pathToID.insert(path, id);
284 idToPath.insert(id, path);
290QStringList QInotifyFileSystemWatcherEngine::removePaths(
const QStringList &paths,
292 QStringList *directories)
294 QStringList unhandled;
295 for (
const QString &path : paths) {
296 int id = pathToID.take(path);
298 auto sg = qScopeGuard([&]{ unhandled.push_back(path); });
304 auto path_range = idToPath.equal_range(id);
305 auto path_it = std::find(path_range.first, path_range.second, path);
306 if (path_it == idToPath.end())
309 const ssize_t num_elements = std::distance(path_range.first, path_range.second);
310 idToPath.erase(path_it);
313 if (num_elements == 1) {
314 int wd = id < 0 ? -id : id;
315 inotify_rm_watch(inotifyFd, wd);
321 directories->removeAll(path);
323 files->removeAll(path);
330void QInotifyFileSystemWatcherEngine::readFromInotify()
335 if (ioctl(inotifyFd, FIONREAD, (
char *) &buffSize) == -1 || buffSize == 0)
339 buffSize =
int(read(inotifyFd, buffer.data(), buffSize));
340 char *at = buffer.data();
341 char *
const end = at + buffSize;
343 QHash<
int, inotify_event *> eventForId;
345 inotify_event *event =
reinterpret_cast<inotify_event *>(at);
347 if (eventForId.contains(event->wd))
348 eventForId[event->wd]->mask |= event->mask;
350 eventForId.insert(event->wd, event);
352 at +=
sizeof(inotify_event) + event->len;
355 QHash<
int, inotify_event *>::const_iterator it = eventForId.constBegin();
356 while (it != eventForId.constEnd()) {
357 const inotify_event &event = **it;
363 QString path = getPathFromID(id);
364 if (path.isEmpty()) {
367 path = getPathFromID(id);
374 if ((event.mask & (IN_DELETE_SELF | IN_MOVE_SELF | IN_UNMOUNT)) != 0) {
375 pathToID.remove(path);
376 idToPath.remove(id, getPathFromID(id));
377 if (!idToPath.contains(id))
378 inotify_rm_watch(inotifyFd, event.wd);
381 emit directoryChanged(path,
true);
383 emit fileChanged(path,
true);
386 emit directoryChanged(path,
false);
388 emit fileChanged(path,
false);
393template <
typename Hash,
typename Key>
398 auto i = c.find(key);
399 const auto end = c.cend();
406 }
while (i != end && i.key() == key);
410QString QInotifyFileSystemWatcherEngine::getPathFromID(
int id)
const
412 auto i = find_last_in_equal_range(idToPath, id);
413 return i == idToPath.cend() ? QString() : i.value() ;
418#include "moc_qfilesystemwatcher_inotify_p.cpp"
Hash::const_iterator find_last_in_equal_range(const Hash &c, const Key &key)