Linux real time indexer: fix monitoring inactive under topdirs members which were symbolic links

This commit is contained in:
Jean-Francois Dockes 2022-09-22 08:57:40 +02:00
parent cbcefc1517
commit 9e0018034c

View File

@ -1,6 +1,6 @@
#include "autoconfig.h" #include "autoconfig.h"
#ifdef RCL_MONITOR #ifdef RCL_MONITOR
/* Copyright (C) 2006-2021 J.F.Dockes /* Copyright (C) 2006-2022 J.F.Dockes
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or * the Free Software Foundation; either version 2 of the License, or
@ -44,7 +44,6 @@
* http://code.google.com/p/simplefilewatcher/ also MIT licensed. * http://code.google.com/p/simplefilewatcher/ also MIT licensed.
*/ */
#include "autoconfig.h" #include "autoconfig.h"
#include <errno.h> #include <errno.h>
@ -69,7 +68,7 @@ public:
RclMonitor() {} RclMonitor() {}
virtual ~RclMonitor() {} virtual ~RclMonitor() {}
virtual bool addWatch(const string& path, bool isDir) = 0; virtual bool addWatch(const string& path, bool isDir, bool follow = false) = 0;
virtual bool getEvent(RclMonEvent& ev, int msecs = -1) = 0; virtual bool getEvent(RclMonEvent& ev, int msecs = -1) = 0;
virtual bool ok() const = 0; virtual bool ok() const = 0;
// Does this monitor generate 'exist' events at startup? // Does this monitor generate 'exist' events at startup?
@ -106,6 +105,10 @@ public:
MONDEB("walkerCB: processone " << fn << " m_mon " << m_mon << MONDEB("walkerCB: processone " << fn << " m_mon " << m_mon <<
" m_mon->ok " << (m_mon ? m_mon->ok() : false) << "\n"); " m_mon->ok " << (m_mon ? m_mon->ok() : false) << "\n");
// We set the watch follow links flag for the topdir only.
bool initfollow = m_initfollow;
m_initfollow = false;
if (flg == FsTreeWalker::FtwDirEnter || flg == FsTreeWalker::FtwDirReturn) { if (flg == FsTreeWalker::FtwDirEnter || flg == FsTreeWalker::FtwDirReturn) {
m_config->setKeyDir(fn); m_config->setKeyDir(fn);
// Set up skipped patterns for this subtree. // Set up skipped patterns for this subtree.
@ -128,7 +131,7 @@ public:
if (!m_mon || !m_mon->ok()) if (!m_mon || !m_mon->ok())
return FsTreeWalker::FtwError; return FsTreeWalker::FtwError;
// We do nothing special if addWatch fails for a reasonable reason // We do nothing special if addWatch fails for a reasonable reason
if (!m_mon->isRecursive() && !m_mon->addWatch(fn, true)) { if (!m_mon->isRecursive() && !m_mon->addWatch(fn, true, initfollow)) {
if (m_mon->saved_errno != EACCES && m_mon->saved_errno != ENOENT) { if (m_mon->saved_errno != EACCES && m_mon->saved_errno != ENOENT) {
LOGINF("walkerCB: addWatch failed\n"); LOGINF("walkerCB: addWatch failed\n");
return FsTreeWalker::FtwError; return FsTreeWalker::FtwError;
@ -160,6 +163,7 @@ private:
RclMonitor *m_mon; RclMonitor *m_mon;
RclMonEventQueue *m_queue; RclMonEventQueue *m_queue;
FsTreeWalker& m_walker; FsTreeWalker& m_walker;
bool m_initfollow{true};
}; };
static bool rclMonAddTopWatches( static bool rclMonAddTopWatches(
@ -185,11 +189,12 @@ static bool rclMonAddTopWatches(
} else { } else {
walker.setOpts(FsTreeWalker::FtwOptNone); walker.setOpts(FsTreeWalker::FtwOptNone);
} }
if (path_isdir(dir, follow)) { // We always follow links for the topdirs members, and only use the config for subdirs
LOGDEB("rclMonRcvRun: walking " << dir << "\n"); if (path_isdir(dir, true)) {
LOGDEB("rclMonRcvRun: walking " << dir << " monrecurs " << mon->isRecursive() << "\n");
// If the fs watcher is recursive, we add the watches for the topdirs here, and walk the // If the fs watcher is recursive, we add the watches for the topdirs here, and walk the
// tree just for generating initial events. // tree just for generating initial events.
if (mon->isRecursive() && !mon->addWatch(dir, true)) { if (mon->isRecursive() && !mon->addWatch(dir, true, true)) {
if (mon->saved_errno != EACCES && mon->saved_errno != ENOENT) { if (mon->saved_errno != EACCES && mon->saved_errno != ENOENT) {
LOGERR("rclMonAddTopWatches: addWatch failed for [" << dir << "]\n"); LOGERR("rclMonAddTopWatches: addWatch failed for [" << dir << "]\n");
return false; return false;
@ -205,7 +210,8 @@ static bool rclMonAddTopWatches(
} else { } else {
// We have to special-case regular files which are part of the topdirs list because the // We have to special-case regular files which are part of the topdirs list because the
// tree walker only adds watches for directories // tree walker only adds watches for directories
if (!mon->addWatch(dir, false)) { MONDEB("rclMonRcvRun: adding watch for non dir topdir " << dir << "\n");
if (!mon->addWatch(dir, false, true)) {
LOGSYSERR("rclMonRcvRun", "addWatch", dir); LOGSYSERR("rclMonRcvRun", "addWatch", dir);
} }
} }
@ -349,10 +355,10 @@ class RclFAM : public RclMonitor {
public: public:
RclFAM(); RclFAM();
virtual ~RclFAM(); virtual ~RclFAM();
virtual bool addWatch(const string& path, bool isdir); virtual bool addWatch(const string& path, bool isdir, bool follow) override;
virtual bool getEvent(RclMonEvent& ev, int msecs = -1); virtual bool getEvent(RclMonEvent& ev, int msecs = -1) override;
bool ok() const {return m_ok;} bool ok() override const {return m_ok;}
virtual bool generatesExist() const {return true;} virtual bool generatesExist() override const {return true;}
private: private:
bool m_ok; bool m_ok;
@ -410,7 +416,7 @@ static void onalrm(int sig)
{ {
longjmp(jbuf, 1); longjmp(jbuf, 1);
} }
bool RclFAM::addWatch(const string& path, bool isdir) bool RclFAM::addWatch(const string& path, bool isdir, bool)
{ {
if (!ok()) if (!ok())
return false; return false;
@ -579,9 +585,9 @@ public:
close(); close();
} }
virtual bool addWatch(const string& path, bool isdir); virtual bool addWatch(const string& path, bool isdir, bool follow) override;
virtual bool getEvent(RclMonEvent& ev, int msecs = -1); virtual bool getEvent(RclMonEvent& ev, int msecs = -1) override;
bool ok() const {return m_ok;} bool ok() const override {return m_ok;}
private: private:
bool m_ok; bool m_ok;
@ -630,11 +636,12 @@ const char *RclIntf::event_name(int code)
}; };
} }
bool RclIntf::addWatch(const string& path, bool) bool RclIntf::addWatch(const string& path, bool, bool follow)
{ {
if (!ok()) if (!ok()) {
return false; return false;
MONDEB("RclIntf::addWatch: adding " << path << "\n"); }
MONDEB("RclIntf::addWatch: adding " << path << " follow " << follow << "\n");
// CLOSE_WRITE is covered through MODIFY. CREATE is needed for mkdirs // CLOSE_WRITE is covered through MODIFY. CREATE is needed for mkdirs
uint32_t mask = IN_MODIFY | IN_CREATE uint32_t mask = IN_MODIFY | IN_CREATE
| IN_MOVED_FROM | IN_MOVED_TO | IN_DELETE | IN_MOVED_FROM | IN_MOVED_TO | IN_DELETE
@ -643,7 +650,7 @@ bool RclIntf::addWatch(const string& path, bool)
// set, and now it is... // set, and now it is...
| IN_ATTRIB | IN_ATTRIB
#ifdef IN_DONT_FOLLOW #ifdef IN_DONT_FOLLOW
| IN_DONT_FOLLOW | (follow ? 0 : IN_DONT_FOLLOW)
#endif #endif
#ifdef IN_EXCL_UNLINK #ifdef IN_EXCL_UNLINK
| IN_EXCL_UNLINK | IN_EXCL_UNLINK
@ -652,8 +659,7 @@ bool RclIntf::addWatch(const string& path, bool)
int wd; int wd;
if ((wd = inotify_add_watch(m_fd, path.c_str(), mask)) < 0) { if ((wd = inotify_add_watch(m_fd, path.c_str(), mask)) < 0) {
saved_errno = errno; saved_errno = errno;
LOGERR("RclIntf::addWatch: inotify_add_watch failed. errno " << LOGSYSERR("RclIntf::addWatch", "inotify_add_watch", path);
saved_errno << "\n");
if (errno == ENOSPC) { if (errno == ENOSPC) {
LOGERR("RclIntf::addWatch: ENOSPC error may mean that you should " LOGERR("RclIntf::addWatch: ENOSPC error may mean that you should "
"increase the inotify kernel constants. See inotify(7)\n"); "increase the inotify kernel constants. See inotify(7)\n");
@ -820,7 +826,7 @@ public:
FileWatchListener *Listener{nullptr}; FileWatchListener *Listener{nullptr};
bool Recursive; bool Recursive;
std::string DirName; std::string DirName;
std::string OldFileName; std::string OldFileName;
HANDLE DirHandle{nullptr}; HANDLE DirHandle{nullptr};
// do NOT make this bigger than 64K because it will fail if the folder being watched is on the // do NOT make this bigger than 64K because it will fail if the folder being watched is on the
@ -871,12 +877,12 @@ class RclMonitorWin32 : public RclMonitor, public FileWatchListener {
public: public:
virtual ~RclMonitorWin32() {} virtual ~RclMonitorWin32() {}
virtual bool addWatch(const string& path, bool /*isDir*/) override { virtual bool addWatch(const string& path, bool /*isDir*/, bool /*follow*/) override {
MONDEB("RclMonitorWin32::addWatch: " << path << "\n"); MONDEB("RclMonitorWin32::addWatch: " << path << "\n");
return m_fswatcher.addWatch(path, this, true) != -1; return m_fswatcher.addWatch(path, this, true) != -1;
} }
virtual bool getEvent(RclMonEvent& ev, int msecs = -1) { virtual bool getEvent(RclMonEvent& ev, int msecs = -1) override {
PRETEND_USE(msecs); PRETEND_USE(msecs);
if (!m_events.empty()) { if (!m_events.empty()) {
ev = m_events.front(); ev = m_events.front();