2
* dirwatch_unix.cpp - detect changes of directory content
3
* Copyright (C) 2003 Justin Karneges
5
* This library is free software; you can redistribute it and/or
6
* modify it under the terms of the GNU Lesser General Public
7
* License as published by the Free Software Foundation; either
8
* version 2.1 of the License, or (at your option) any later version.
10
* This library is distributed in the hope that it will be useful,
11
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13
* Lesser General Public License for more details.
15
* You should have received a copy of the GNU Lesser General Public
16
* License along with this library; if not, write to the Free Software
17
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23
// A great many hints taken from KDE's KDirWatch system. Thank you KDE!
27
#include<qsocketnotifier.h>
28
#include<qvaluelist.h>
34
#include<sys/utsname.h>
36
#define DNOTIFY_SIGNAL (SIGRTMIN + 8)
41
static DWEntry * open(const QString &s)
43
int fd = ::open(QFile::encodeName(s), O_RDONLY);
47
int mask = DN_DELETE|DN_CREATE|DN_RENAME|DN_MULTISHOT|DN_MODIFY|DN_ATTRIB;
48
if(fcntl(fd, F_SETSIG, DNOTIFY_SIGNAL) == -1 || fcntl(fd, F_NOTIFY, mask) == -1) {
52
DWEntry *e = new DWEntry(s, fd);
63
QValueList<int> idList;
67
DWEntry(const QString &_dir, int _fd)
77
class DirWatchPlatform::Private : public QObject
86
QPtrList<DWEntry> list;
88
DirWatchPlatform *par;
91
Private(DirWatchPlatform *parent)
97
list.setAutoDelete(true);
101
bool supports_dnotify = true; // not guilty until proven guilty
103
int major, minor, patch;
105
supports_dnotify = false; // *shrug*
106
else if(sscanf(uts.release, "%d.%d.%d", &major, &minor, &patch) != 3)
107
supports_dnotify = false; // *shrug*
108
else if( major * 1000000 + minor * 1000 + patch < 2004019 ) // <2.4.19
109
supports_dnotify = false;
111
if(!supports_dnotify)
114
if(pipe(pipe_notify) == -1)
117
if(fcntl(pipe_notify[0], F_SETFL, O_NONBLOCK) == -1)
120
connect(&t, SIGNAL(timeout()), this, SLOT(slotNotify()));
122
sn = new QSocketNotifier(pipe_notify[0], QSocketNotifier::Read);
123
connect(sn, SIGNAL(activated(int)), this, SLOT(slotActivated()));
125
struct sigaction act;
126
act.sa_sigaction = dnotify_handler;
127
sigemptyset(&act.sa_mask);
128
act.sa_flags = SA_SIGINFO;
130
act.sa_flags |= SA_RESTART;
132
sigaction(DNOTIFY_SIGNAL, &act, NULL);
143
close(pipe_notify[0]);
144
close(pipe_notify[1]);
153
static void dnotify_handler(int, siginfo_t *si, void *)
160
//printf("dnotify_handler: fd=%d\n", fd);
162
DWEntry *e = self->findEntryByFd(fd);
167
// write a byte into the pipe
169
write(self->pipe_notify[1], &c, 1);
177
// clear out the pipe
180
int ret = read(pipe_notify[0], buf, 64);
185
// use a timer to combine multiple dnotify events into one
195
QPtrListIterator<DWEntry> it(list);
196
for(DWEntry *e; (e = it.current()); ++it) {
199
for(QValueList<int>::ConstIterator idi = e->idList.begin(); idi != e->idList.end(); ++idi) {
200
par->triggerDirChanged(*idi);
209
int addItem(const QString &s)
211
//printf("setting up DNOTIFY for [%s]\n", s.latin1());
213
DWEntry *e = findEntryByDir(s);
215
e = DWEntry::open(s);
220
int id = getUniqueId();
221
e->idList.append(id);
223
//printf("success (fd=%d)!\n", e->fd);
227
void removeItem(int id)
229
DWEntry *e = findEntryById(id);
232
e->idList.remove(id);
233
if(e->idList.isEmpty())
239
for(int n = 0;; ++n) {
240
QPtrListIterator<DWEntry> it(list);
242
for(DWEntry *e; (e = it.current()); ++it) {
243
for(QValueList<int>::ConstIterator idi = e->idList.begin(); idi != e->idList.end(); ++idi) {
257
DWEntry * findEntryByDir(const QString &s)
259
QPtrListIterator<DWEntry> it(list);
260
for(DWEntry *e; (e = it.current()); ++it) {
267
DWEntry * findEntryById(int id)
269
QPtrListIterator<DWEntry> it(list);
270
for(DWEntry *e; (e = it.current()); ++it) {
271
for(QValueList<int>::ConstIterator idi = e->idList.begin(); idi != e->idList.end(); ++idi) {
279
DWEntry * findEntryByFd(int fd)
281
QPtrListIterator<DWEntry> it(list);
282
for(DWEntry *e; (e = it.current()); ++it) {
292
DirWatchPlatform::Private *DirWatchPlatform::Private::self;
296
DirWatchPlatform::DirWatchPlatform()
302
DirWatchPlatform::~DirWatchPlatform()
307
bool DirWatchPlatform::init()
309
Private *p = new Private(this);
312
//printf("DirWatchPlatform::init() ok!\n");
317
//printf("DirWatchPlatform::init() fail!\n");
322
int DirWatchPlatform::addDir(const QString &s)
324
return d->addItem(s);
327
void DirWatchPlatform::removeDir(int id)
334
DirWatchPlatform::DirWatchPlatform():QObject(0) {}
335
DirWatchPlatform::~DirWatchPlatform() {}
336
bool DirWatchPlatform::init() { return false; }
337
int DirWatchPlatform::addDir(const QString &) { return -1; }
338
void DirWatchPlatform::removeDir(int) {}
342
#include"dirwatch_unix.moc"