diff options
author | Javier S. Pedro <maemo@javispedro.com> | 2012-09-17 23:03:03 +0200 |
---|---|---|
committer | Javier S. Pedro <maemo@javispedro.com> | 2012-09-17 23:03:03 +0200 |
commit | c3a1946675855b299a2b36550cdf2c2f69d153aa (patch) | |
tree | f7adf66404cdc47994225b616bcaf082a07dd168 /distfoldd/watcher.cc | |
download | distfold-c3a1946675855b299a2b36550cdf2c2f69d153aa.tar.gz distfold-c3a1946675855b299a2b36550cdf2c2f69d153aa.zip |
initial import
Diffstat (limited to 'distfoldd/watcher.cc')
-rw-r--r-- | distfoldd/watcher.cc | 132 |
1 files changed, 132 insertions, 0 deletions
diff --git a/distfoldd/watcher.cc b/distfoldd/watcher.cc new file mode 100644 index 0000000..664ea58 --- /dev/null +++ b/distfoldd/watcher.cc @@ -0,0 +1,132 @@ +#include <QtCore/QDebug> + +#include <sys/errno.h> +#include <sys/fcntl.h> +#include <sys/inotify.h> + +#include "watcher.h" + + +Watcher::Watcher(const QString& path, QObject *parent) : + QObject(parent) +{ + _fd = inotify_init(); + fcntl(_fd, F_SETFL, O_NONBLOCK); + _buffer.resize(sizeof(struct inotify_event) + NAME_MAX + 1); + _mask = IN_CLOSE_WRITE | IN_CREATE | IN_DELETE | + IN_MOVED_FROM | IN_MOVED_TO | IN_ONLYDIR; + + _notifier = new QSocketNotifier(_fd, QSocketNotifier::Read, this); + connect(_notifier, SIGNAL(activated(int)), SLOT(readInotify())); + + QStringList l = scanDirs(QDir(path)); + foreach (const QString& s, l) { + addWatch(s); + } +} + +void Watcher::readInotify() +{ + inotify_event *event; + const ssize_t struct_size = sizeof(struct inotify_event); + ssize_t pos, nread; + + do { + nread = read(_fd, _buffer.data(), _buffer.size()); + if (nread < 0) { + int err = errno; + if (err == EWOULDBLOCK) return; + qWarning() << "Error while reading from inotify" << err; + } + + pos = 0; + while (pos + struct_size <= nread) { + event = reinterpret_cast<inotify_event*>(&(_buffer.data()[pos])); + if (event->wd == -1) { + // Special treatment + // TODO + continue; + } + + QString path = _watches[event->wd]; + QString name; + QString filePath = path; + if (event->len > 0) { + name = QString::fromLocal8Bit(event->name); + filePath += "/" + name; + } + + if (event->mask & (IN_CREATE|IN_MOVED_TO)) { + if (event->mask & IN_ISDIR) { + // TODO There might already be folders in here. + addWatch(filePath); + } + emit pathAdded(filePath); + } + if (event->mask & IN_CLOSE_WRITE) { + emit pathChanged(filePath); + } + if (event->mask & (IN_MOVED_FROM|IN_DELETE)) { + if (event->mask & IN_ISDIR) { + removeWatch(filePath); + } + emit pathRemoved(filePath); + } + + pos += struct_size + event->len; + } + } while (nread > 0); +} + +QStringList Watcher::scanDirs(const QDir &dir) +{ + Q_ASSERT(dir.isReadable()); + QStringList l(dir.absolutePath()); + QStringList sub_dirs = dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot); + + foreach (const QString& s, sub_dirs) { + const QString abs_path = dir.absoluteFilePath(s); + l << scanDirs(QDir(abs_path)); + } + + return l; +} + +void Watcher::addWatch(const QString& path) +{ + int wd = inotify_add_watch(_fd, path.toLocal8Bit().constData(), _mask); + if (wd == -1) { + qWarning() << "Failed to add watch for" << path; + return; + } + if (_watches.contains(wd)) { + qWarning() << "Watch for" << path << "was already setup"; + return; + } + + qDebug() << "Watching" << path; + _watches[wd] = path; + _dirs[path] = wd; +} + +void Watcher::removeWatch(const QString& path) +{ + if (!_dirs.contains(path)) { + qWarning() << "Watch for" << path << "not found"; + return; + } + int wd = _dirs[path]; + removeWatch(wd); +} + +void Watcher::removeWatch(int wd) +{ + if (!_watches.contains(wd)) { + qWarning() << "Watch" << wd << "not found"; + } + QString path = _watches[wd]; + qDebug() << "Unwatching" << path; + inotify_rm_watch(_fd, wd); + _dirs.remove(path); + _watches.remove(wd); +} |