Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Toggle main menu visibility
Loading...
Searching...
No Matches
qfilesystemwatcher_kqueue.cpp
Go to the documentation of this file.
1
// Copyright (C) 2016 The Qt Company Ltd.
2
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
// Qt-Security score:significant reason:default
4
5
#
include
<
qplatformdefs
.
h
>
6
7
#
include
"qfilesystemwatcher.h"
8
#
include
"qfilesystemwatcher_kqueue_p.h"
9
#
include
"private/qcore_unix_p.h"
10
11
#
include
<
qdebug
.
h
>
12
#
include
<
qfile
.
h
>
13
#
include
<
qscopeguard
.
h
>
14
#
include
<
qsocketnotifier
.
h
>
15
#
include
<
qvarlengtharray
.
h
>
16
17
#
include
<
sys
/
types
.
h
>
18
#
include
<
sys
/
event
.
h
>
19
#
include
<
sys
/
stat
.
h
>
20
#
include
<
sys
/
time
.
h
>
21
#
include
<
fcntl
.
h
>
22
23
QT_BEGIN_NAMESPACE
24
25
// #define KEVENT_DEBUG
26
#
ifdef
KEVENT_DEBUG
27
#
define
DEBUG
qDebug
28
#
else
29
#
define
DEBUG
if
(
false
)
qDebug
30
#
endif
31
32
QKqueueFileSystemWatcherEngine *QKqueueFileSystemWatcherEngine::create(QObject *parent)
33
{
34
int
kqfd = kqueue();
35
if
(kqfd == -1)
36
return
0;
37
return
new
QKqueueFileSystemWatcherEngine(kqfd, parent);
38
}
39
40
QKqueueFileSystemWatcherEngine::QKqueueFileSystemWatcherEngine(
int
kqfd, QObject *parent)
41
: QFileSystemWatcherEngine(parent),
42
kqfd(kqfd),
43
notifier(kqfd, QSocketNotifier::Read,
this
)
44
{
45
connect(¬ifier, SIGNAL(activated(QSocketDescriptor)), SLOT(readFromKqueue()));
46
47
fcntl(kqfd, F_SETFD, FD_CLOEXEC);
48
}
49
50
QKqueueFileSystemWatcherEngine::~QKqueueFileSystemWatcherEngine()
51
{
52
notifier.setEnabled(
false
);
53
close(kqfd);
54
55
for
(
int
id : std::as_const(pathToID))
56
::close(id < 0 ? -id : id);
57
}
58
59
QStringList QKqueueFileSystemWatcherEngine::addPaths(
const
QStringList &paths,
60
QStringList *files,
61
QStringList *directories)
62
{
63
QStringList unhandled;
64
for
(
const
QString &path : paths) {
65
auto
sg = qScopeGuard([&]{unhandled.push_back(path);});
66
int
fd;
67
#
if
defined
(
O_EVTONLY
)
68
fd = qt_safe_open(QFile::encodeName(path), O_EVTONLY);
69
#
else
70
fd = qt_safe_open(QFile::encodeName(path), O_RDONLY);
71
#
endif
72
if
(fd == -1) {
73
perror(
"QKqueueFileSystemWatcherEngine::addPaths: open"
);
74
continue
;
75
}
76
if
(fd >= (
int
)FD_SETSIZE / 2 && fd < (
int
)FD_SETSIZE) {
77
int
fddup = qt_safe_dup(fd, FD_SETSIZE);
78
if
(fddup != -1) {
79
::close(fd);
80
fd = fddup;
81
}
82
}
83
84
QT_STATBUF st;
85
if
(QT_FSTAT(fd, &st) == -1) {
86
perror(
"QKqueueFileSystemWatcherEngine::addPaths: fstat"
);
87
::close(fd);
88
continue
;
89
}
90
int
id = (S_ISDIR(st.st_mode)) ? -fd : fd;
91
if
(id < 0) {
92
if
(directories->contains(path)) {
93
::close(fd);
94
continue
;
95
}
96
}
else
{
97
if
(files->contains(path)) {
98
::close(fd);
99
continue
;
100
}
101
}
102
103
struct
kevent kev;
104
EV_SET(&kev,
105
fd,
106
EVFILT_VNODE,
107
EV_ADD | EV_ENABLE | EV_CLEAR,
108
NOTE_DELETE | NOTE_WRITE | NOTE_EXTEND | NOTE_ATTRIB | NOTE_RENAME | NOTE_REVOKE,
109
0,
110
0);
111
if
(kevent(kqfd, &kev, 1, 0, 0, 0) == -1) {
112
perror(
"QKqueueFileSystemWatcherEngine::addPaths: kevent"
);
113
::close(fd);
114
continue
;
115
}
116
117
sg.dismiss();
118
119
if
(id < 0) {
120
DEBUG
() <<
"QKqueueFileSystemWatcherEngine: added directory path"
<< path;
121
directories->append(path);
122
}
else
{
123
DEBUG
() <<
"QKqueueFileSystemWatcherEngine: added file path"
<< path;
124
files->append(path);
125
}
126
127
pathToID.insert(path, id);
128
idToPath.insert(id, path);
129
}
130
131
return
unhandled;
132
}
133
134
QStringList QKqueueFileSystemWatcherEngine::removePaths(
const
QStringList &paths,
135
QStringList *files,
136
QStringList *directories)
137
{
138
if
(pathToID.isEmpty())
139
return
paths;
140
141
QStringList unhandled;
142
for
(
const
QString &path : paths) {
143
auto
sg = qScopeGuard([&]{unhandled.push_back(path);});
144
int
id = pathToID.take(path);
145
QString x = idToPath.take(id);
146
if
(x.isEmpty() || x != path)
147
continue
;
148
149
::close(id < 0 ? -id : id);
150
151
sg.dismiss();
152
153
if
(id < 0)
154
directories->removeAll(path);
155
else
156
files->removeAll(path);
157
}
158
159
return
unhandled;
160
}
161
162
void
QKqueueFileSystemWatcherEngine::readFromKqueue()
163
{
164
forever {
165
DEBUG
() <<
"QKqueueFileSystemWatcherEngine: polling for changes"
;
166
int
r;
167
struct
kevent kev;
168
struct
timespec ts = { 0, 0 };
// 0 ts, because we want to poll
169
QT_EINTR_LOOP(r, kevent(kqfd, 0, 0, &kev, 1, &ts));
170
if
(r < 0) {
171
perror(
"QKqueueFileSystemWatcherEngine: error during kevent wait"
);
172
return
;
173
}
else
if
(r == 0) {
174
// polling returned no events, so stop
175
break
;
176
}
else
{
177
int
fd = kev.ident;
178
179
DEBUG
() <<
"QKqueueFileSystemWatcherEngine: processing kevent"
<< kev.ident << kev.filter;
180
181
int
id = fd;
182
QString path = idToPath.value(id);
183
if
(path.isEmpty()) {
184
// perhaps a directory?
185
id = -id;
186
path = idToPath.value(id);
187
if
(path.isEmpty()) {
188
DEBUG
() <<
"QKqueueFileSystemWatcherEngine: received a kevent for a file we're not watching"
;
189
continue
;
190
}
191
}
192
if
(kev.filter != EVFILT_VNODE) {
193
DEBUG
() <<
"QKqueueFileSystemWatcherEngine: received a kevent with the wrong filter"
;
194
continue
;
195
}
196
197
if
((kev.fflags & (NOTE_DELETE | NOTE_REVOKE | NOTE_RENAME)) != 0) {
198
DEBUG
() << path <<
"removed, removing watch also"
;
199
200
pathToID.remove(path);
201
idToPath.remove(id);
202
::close(fd);
203
204
if
(id < 0)
205
emit directoryChanged(path,
true
);
206
else
207
emit fileChanged(path,
true
);
208
}
else
{
209
DEBUG
() << path <<
"changed"
;
210
211
if
(id < 0)
212
emit directoryChanged(path,
false
);
213
else
214
emit fileChanged(path,
false
);
215
}
216
}
217
218
}
219
}
220
221
QT_END_NAMESPACE
222
223
#
include
"moc_qfilesystemwatcher_kqueue_p.cpp"
DEBUG
#define DEBUG
Definition
qfilesystemwatcher_fsevents.mm:24
qtbase
src
corelib
io
qfilesystemwatcher_kqueue.cpp
Generated on
for Qt by
1.18.0