Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/nextcloud/desktop.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Molkentin <danimo@owncloud.com>2014-07-11 02:31:24 +0400
committerDaniel Molkentin <danimo@owncloud.com>2014-07-11 13:07:31 +0400
commitdf3c3bca025a7cdb5f20e55fc2ecc37618e7cc8d (patch)
tree22fa58b5a09ec9f93ad376dce2edd6272483fc1a /src/gui/folderwatcher_linux.cpp
parentd1b991e1984ef0c4ed803c5c5ead1ce3bfe00266 (diff)
Split into three separate projects: library, gui and cmd
Diffstat (limited to 'src/gui/folderwatcher_linux.cpp')
-rw-r--r--src/gui/folderwatcher_linux.cpp213
1 files changed, 213 insertions, 0 deletions
diff --git a/src/gui/folderwatcher_linux.cpp b/src/gui/folderwatcher_linux.cpp
new file mode 100644
index 000000000..4d75047dc
--- /dev/null
+++ b/src/gui/folderwatcher_linux.cpp
@@ -0,0 +1,213 @@
+/*
+ * Copyright (C) by Klaas Freitag <freitag@owncloud.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include "config.h"
+
+#include <sys/inotify.h>
+
+#include "folder.h"
+#include "folderwatcher_linux.h"
+
+#include <cerrno>
+#include <QDebug>
+#include <QStringList>
+#include <QObject>
+#include <QVarLengthArray>
+
+namespace Mirall {
+
+FolderWatcherPrivate::FolderWatcherPrivate(FolderWatcher *p, const QString& path)
+ : QObject(),
+ _parent(p),
+ _folder(path)
+{
+ _fd = inotify_init();
+ if (_fd != -1) {
+ _socket.reset( new QSocketNotifier(_fd, QSocketNotifier::Read) );
+ connect(_socket.data(), SIGNAL(activated(int)), SLOT(slotReceivedNotification(int)));
+ } else {
+ qDebug() << Q_FUNC_INFO << "notify_init() failed: " << strerror(errno);
+ }
+
+ QMetaObject::invokeMethod(this, "slotAddFolderRecursive", Q_ARG(QString, path));
+
+}
+
+FolderWatcherPrivate::~FolderWatcherPrivate()
+{
+
+}
+
+// attention: result list passed by reference!
+bool FolderWatcherPrivate::findFoldersBelow( const QDir& dir, QStringList& fullList )
+{
+ bool ok = true;
+ if( !(dir.exists() && dir.isReadable()) ) {
+ qDebug() << "Non existing path coming in: " << dir.absolutePath();
+ ok = false;
+ } else {
+ QStringList nameFilter;
+ nameFilter << QLatin1String("*");
+ QDir::Filters filter = QDir::Dirs | QDir::NoDotAndDotDot|QDir::NoSymLinks;
+ const QStringList pathes = dir.entryList(nameFilter, filter);
+
+ QStringList::const_iterator constIterator;
+ for (constIterator = pathes.constBegin(); constIterator != pathes.constEnd();
+ ++constIterator) {
+ const QString fullPath(dir.path()+QLatin1String("/")+(*constIterator));
+ fullList.append(fullPath);
+ ok = findFoldersBelow(QDir(fullPath), fullList);
+ }
+ }
+
+ return ok;
+}
+
+void FolderWatcherPrivate::inotifyRegisterPath(const QString& path)
+{
+ if( !path.isEmpty()) {
+ int wd = inotify_add_watch(_fd, path.toUtf8().constData(),
+ IN_CLOSE_WRITE | IN_ATTRIB | IN_MOVE |
+ IN_CREATE |IN_DELETE | IN_DELETE_SELF |
+ IN_MOVE_SELF |IN_UNMOUNT |IN_ONLYDIR |
+ IN_DONT_FOLLOW );
+ if( wd > -1 ) {
+ _watches.insert(wd, path);
+ }
+ }
+}
+
+void FolderWatcherPrivate::slotAddFolderRecursive(const QString &path)
+{
+ int subdirs = 0;
+ qDebug() << "(+) Watcher:" << path;
+
+ QDir inPath(path);
+ inotifyRegisterPath(inPath.absolutePath());
+
+ const QStringList watchedFolders = _watches.values();
+
+ QStringList allSubfolders;
+ if( !findFoldersBelow(QDir(path), allSubfolders)) {
+ qDebug() << "Could not traverse all sub folders";
+ }
+ // qDebug() << "currently watching " << watchedFolders;
+ QStringListIterator subfoldersIt(allSubfolders);
+ while (subfoldersIt.hasNext()) {
+ QString subfolder = subfoldersIt.next();
+ // qDebug() << " (**) subfolder: " << subfolder;
+ QDir folder (subfolder);
+ if (folder.exists() && !watchedFolders.contains(folder.absolutePath())) {
+ subdirs++;
+ if( _parent->pathIsIgnored(subfolder) ) {
+ qDebug() << "* Not adding" << folder.path();
+ continue;
+ }
+ inotifyRegisterPath(folder.absolutePath());
+ } else {
+ qDebug() << " `-> discarded:" << folder.path();
+ }
+ }
+
+ if (subdirs >0) {
+ qDebug() << " `-> and" << subdirs << "subdirectories";
+ }
+}
+
+void FolderWatcherPrivate::slotReceivedNotification(int fd)
+{
+ int len;
+ struct inotify_event* event;
+ int i;
+ int error;
+ QVarLengthArray<char, 2048> buffer(2048);
+
+ do {
+ len = read(fd, buffer.data(), buffer.size());
+ error = errno;
+ /**
+ * From inotify documentation:
+ *
+ * The behavior when the buffer given to read(2) is too
+ * small to return information about the next event
+ * depends on the kernel version: in kernels before 2.6.21,
+ * read(2) returns 0; since kernel 2.6.21, read(2) fails with
+ * the error EINVAL.
+ */
+ if (len < 0 && error == EINVAL)
+ {
+ // double the buffer size
+ buffer.resize(buffer.size() * 2);
+ /* and try again ... */
+ continue;
+ }
+ } while (false);
+
+ // reset counter
+ i = 0;
+ // while there are enough events in the buffer
+ while(i + sizeof(struct inotify_event) < static_cast<unsigned int>(len)) {
+ // cast an inotify_event
+ event = (struct inotify_event*)&buffer[i];
+ // with the help of watch descriptor, retrieve, corresponding INotify
+ if (event == NULL) {
+ qDebug() << "NULL event";
+ i += sizeof(struct inotify_event);
+ continue;
+ }
+
+ // fire event
+ // Note: The name of the changed file and stuff could be taken from
+ // the event data structure. That does not happen yet.
+ if (event->len > 0 && event->wd > -1) {
+ // qDebug() << Q_FUNC_INFO << event->name;
+ if (QByteArray(event->name).startsWith(".csync") ||
+ QByteArray(event->name).startsWith(".owncloudsync.log")) {
+ // qDebug() << "ignore journal";
+ } else {
+ const QString p = _watches[event->wd];
+ _parent->changeDetected(p);
+ }
+ }
+
+ // increment counter
+ i += sizeof(struct inotify_event) + event->len;
+ }
+
+}
+
+void FolderWatcherPrivate::addPath(const QString& path)
+{
+ slotAddFolderRecursive(path);
+}
+
+void FolderWatcherPrivate::removePath(const QString& path)
+{
+ int wid = -1;
+ // Remove the inotify watch.
+ QHash<int, QString>::const_iterator i = _watches.constBegin();
+
+ while (i != _watches.constEnd()) {
+ if( i.value() == path ) {
+ wid = i.key();
+ break;
+ }
+ ++i;
+ }
+ if( wid > -1 ) {
+ inotify_rm_watch(_fd, wid);
+ _watches.remove(wid);
+ }
+}
+
+} // ns mirall