diff options
author | Christian Kamm <mail@ckamm.de> | 2018-10-12 12:03:10 +0300 |
---|---|---|
committer | ckamm <mail@ckamm.de> | 2018-10-12 13:06:48 +0300 |
commit | 55cf407337a5db93511f1cb061165c53fa6dba6e (patch) | |
tree | 9cc826d82cf598c7923e2ba16a938d2b10dbade8 /src/gui/folderwatcher_linux.cpp | |
parent | d0815239807540c423c52282e57a5ed8ebfd41e2 (diff) |
Folderwatcher: On linux, fix paths after dir renames #6808
If a folder was renamed A -> B, the folder watcher for the inode
would be unaware and still report changes for A/foo. Now directory
renames in the watched folders are tracked and paths are updated
accordingly.
Diffstat (limited to 'src/gui/folderwatcher_linux.cpp')
-rw-r--r-- | src/gui/folderwatcher_linux.cpp | 64 |
1 files changed, 48 insertions, 16 deletions
diff --git a/src/gui/folderwatcher_linux.cpp b/src/gui/folderwatcher_linux.cpp index 5f6d580b1..d2fdb7d8d 100644 --- a/src/gui/folderwatcher_linux.cpp +++ b/src/gui/folderwatcher_linux.cpp @@ -31,6 +31,11 @@ FolderWatcherPrivate::FolderWatcherPrivate(FolderWatcher *p, const QString &path , _parent(p) , _folder(path) { + _wipePotentialRenamesSoon = new QTimer(this); + _wipePotentialRenamesSoon->setInterval(1000); + _wipePotentialRenamesSoon->setSingleShot(true); + connect(_wipePotentialRenamesSoon, &QTimer::timeout, this, &FolderWatcherPrivate::wipePotentialRenames); + _fd = inotify_init(); if (_fd != -1) { _socket.reset(new QSocketNotifier(_fd, QSocketNotifier::Read)); @@ -91,6 +96,17 @@ void FolderWatcherPrivate::inotifyRegisterPath(const QString &path) } } +void FolderWatcherPrivate::applyDirectoryRename(const FolderWatcherPrivate::Rename &rename) +{ + QString fromSlash = rename.from + "/"; + qCInfo(lcFolderWatcher) << "Applying rename from" << rename.from << "to" << rename.to; + for (auto &watch : _watches) { + if (watch == rename.from || watch.startsWith(fromSlash)) { + watch = rename.to + watch.mid(rename.from.size()); + } + } +} + void FolderWatcherPrivate::slotAddFolderRecursive(const QString &path) { int subdirs = 0; @@ -126,6 +142,11 @@ void FolderWatcherPrivate::slotAddFolderRecursive(const QString &path) } } +void FolderWatcherPrivate::wipePotentialRenames() +{ + _potentialRenames.clear(); +} + void FolderWatcherPrivate::slotReceivedNotification(int fd) { int len; @@ -154,33 +175,44 @@ void FolderWatcherPrivate::slotReceivedNotification(int fd) } } 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)) { + // iterate events in buffer + unsigned int ulen = len; + for (i = 0; i + sizeof(inotify_event) < ulen; i += sizeof(inotify_event) + (event ? event->len : 0)) { // cast an inotify_event event = (struct inotify_event *)&buffer[i]; if (event == NULL) { qCDebug(lcFolderWatcher) << "NULL event"; - i += sizeof(struct inotify_event); continue; } // Fire event for the path that was changed. - if (event->len > 0 && event->wd > -1) { - QByteArray fileName(event->name); - if (fileName.startsWith("._sync_") - || fileName.startsWith(".csync_journal.db") - || fileName.startsWith(".owncloudsync.log") - || fileName.startsWith(".sync_")) { + if (event->len == 0 || event->wd <= -1) + continue; + QByteArray fileName(event->name); + if (fileName.startsWith("._sync_") + || fileName.startsWith(".csync_journal.db") + || fileName.startsWith(".owncloudsync.log") + || fileName.startsWith(".sync_")) { + continue; + } + const QString p = _watches[event->wd] + '/' + fileName; + _parent->changeDetected(p); + + // Collect events to form complete renames where possible + // and apply directory renames to the cached paths. + if ((event->mask & (IN_MOVED_TO | IN_MOVED_FROM)) && (event->mask & IN_ISDIR) && event->cookie > 0) { + auto &rename = _potentialRenames[event->cookie]; + if (event->mask & IN_MOVED_TO) + rename.to = p; + if (event->mask & IN_MOVED_FROM) + rename.from = p; + if (!rename.from.isEmpty() && !rename.to.isEmpty()) { + applyDirectoryRename(rename); + _potentialRenames.remove(event->cookie); } else { - const QString p = _watches[event->wd] + '/' + fileName; - _parent->changeDetected(p); + _wipePotentialRenamesSoon->start(); } } - - // increment counter - i += sizeof(struct inotify_event) + event->len; } } |